404 Not Found

404 Not Found


nginx

Comprehensive Hands-On: Deploying the OrderFlow Project

Deployment is the last mile—CI/CD automation, K8s orchestration, and monitoring and alerts ensure a seamless journey for applications from development to production.

1. What You'll Learn


2. A True Story of a DevOps Engineer

(1) Pain Point: Manual deployment is like stepping on a landmine

Bob manually deployed OrderFlow to production: locally mvn packagedocker build → pushed the image → kubectl apply → checked health status. The entire process takes 30 minutes and is prone to errors: forgetting to update the configuration, pushing the wrong image version, or old Pods not shutting down gracefully during rolling updates, resulting in 502 errors.

(2) CI/CD Solutions

One-Stop Service for Automated Production Lines:

100%
graph LR
    A["Git Push"] --> B["GitHub Actions<br/>Build + Test"]
    B --> C["Docker Build<br/>+ Push to Registry"]
    C --> D["K8s Rolling<br/>Deploy"]
    D --> E["Health Check<br/>+ Smoke Test"]
    E --> F["Monitor<br/>Grafana"]

(3) Revenue

After Bob set up CI/CD, code pushes triggered automatic deployments, completing the process from code to production in 5 minutes. With HPA handling automatic scaling and Prometheus handling automatic alerts, Bob went from being a "firefighter" to a "monitoring observer."


3. CI/CD Pipeline

(1) ▶ Example: GitHub Actions Workflow

YAML
# .github/workflows/deploy.yml
name: OrderFlow CI/CD

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: registry.example.com
  IMAGE_NAME: orderflow-service

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'

    - name: Run tests
      run: mvn verify -B

    - name: Build Docker image
      run: docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .

    - name: Login to Registry
      run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin

    - name: Push image
      run: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
    - uses: actions/checkout@v4

    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/orderflow \
          orderflow=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
          -n orderflow
        kubectl rollout status deployment/orderflow -n orderflow --timeout=300s

    - name: Smoke test
      run: |
        sleep 10
        curl -sf https://api.orderflow.example.com/actuator/health | grep '"status":"UP"'

Output:

TEXT
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp
Pipeline Stage Operation Failure Handling
Build + Test mvn verify Block Deployment
Docker Build Multi-stage Image Build Block Deployment
Push Registry Push to Image Repository Retry 3 times
K8s Deploy kubectl set image + rollout Automatic rollback
Smoke Test Health Check Validation Rollback + Notification

4. K8s Production Deployment

(1) ▶ Example: Production-Grade Deployment + HPA

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orderflow
  namespace: orderflow
spec:
  replicas: 3
  selector:
    matchLabels: { app: orderflow }
  strategy:
    rollingUpdate: { maxUnavailable: 0, maxSurge: 1 }
  template:
    metadata:
      labels: { app: orderflow }
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: orderflow
        image: registry.example.com/orderflow-service:latest
        ports:
        - { containerPort: 8080 }
        - { containerPort: 8081 }
        envFrom:
        - configMapRef: { name: orderflow-config }
        - secretRef: { name: orderflow-secrets }
        resources:
          requests: { memory: "512Mi", cpu: "250m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        lifecycle:
          preStop:
            exec:
              command: ["sh", "-c", "sleep 10"]
        livenessProbe:
          httpGet: { path: /actuator/health/liveness, port: 8080 }
          initialDelaySeconds: 60
          periodSeconds: 30
        readinessProbe:
          httpGet: { path: /actuator/health/readiness, port: 8080 }
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: orderflow-hpa
  namespace: orderflow
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: orderflow
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

Output:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
K8s Production Configuration Value Reason
maxUnavailable: 0 Zero Downtime Always Maintain the Target Number of Copies
terminationGracePeriodSeconds: 60 Close gracefully Waiting for requests to be cleared
preStop: sleep 10 Delayed Termination K8s Continues to Drain Traffic Even After Being Removed from the Service
resources.requests/limits Configure QoS Guarantee Resource Allocation + Limit Overages

(2) ▶ Example: Ingress + TLS

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orderflow-ingress
  namespace: orderflow
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts: [api.orderflow.example.com]
    secretName: orderflow-tls
  rules:
  - host: api.orderflow.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: { name: orderflow, port: { number: 80 } }

Output:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created

5. Observability Launch

(1) ▶ Example: Prometheus + AlertManager

YAML
# prometheus.yml
scrape_configs:
- job_name: orderflow
  metrics_path: /actuator/prometheus
  scrape_interval: 15s
  kubernetes_sd_configs:
  - role: pod
    namespaces:
      names: [orderflow]
  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_label_app]
    action: keep
    regex: orderflow

Output:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
YAML
# alert_rules.yml
groups:
- name: orderflow-slo
  rules:
  - alert: SLOErrorRateExceeded
    expr: |
      sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m]))
      / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m])) > 0.001
    for: 5m
    labels: { severity: critical }
    annotations:
      summary: "OrderFlow error rate exceeds SLO (0.1%)"

  - alert: SLOLatencyExceeded
    expr: |
      histogram_quantile(0.99,
        sum(rate(http_server_requests_seconds_bucket{namespace="orderflow"}[5m])) by (le))
      > 0.1
    for: 5m
    labels: { severity: warning }
    annotations:
      summary: "OrderFlow P99 latency exceeds SLO (100ms)"

(2) ▶ Example: Grafana SLO Dashboard Metrics

Dashboard PromQL SLO Target
P99 Latency histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{namespace="orderflow"}[5m])) by (le)) < 100 ms
Error Rate sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m])) < 0.1%
Availability 1 - (sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m]))) > 99.9%
Order Throughput rate(orderflow_orders_created_total[1m]) * 60 > 100/min

6. Production Safety Enhancements

(1) ▶ Example: NetworkPolicy + Pod Security

YAML
# NetworkPolicy: restrict access
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: orderflow-netpol
  namespace: orderflow
spec:
  podSelector:
    matchLabels: { app: orderflow }
  policyTypes: [Ingress]
  ingress:
  - from:
    - namespaceSelector:
        matchLabels: { name: ingress-nginx }
    ports:
    - { port: 8080, protocol: TCP }
  - from:
    - namespaceSelector:
        matchLabels: { name: monitoring }
    ports:
    - { port: 8081, protocol: TCP }
---
# Pod security: run as non-root
apiVersion: v1
kind: LimitRange
metadata:
  name: orderflow-limits
  namespace: orderflow
spec:
  limits:
  - type: Container
    default:
      memory: "1Gi"
      cpu: "500m"
    defaultRequest:
      memory: "256Mi"
      cpu: "100m"

Output:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
Security Hardening Item Measure Description
Non-root Execution Dockerfile USER appuser Preventing Container Escape
NetworkPolicy Restrict Inbound Sources Allow Only Ingress and Monitoring Access
Secret Encryption etcd Encryption Configuration Preventing Secrets from Being Stored in Plain Text
TLS cert-manager automatic certificates encrypted transmission
Resource Limits LimitRange Prevent Resource Contention

7. Comprehensive Example: Complete Deployment Checklist for OrderFlow

YAML
# k8s/orderflow-complete.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: orderflow
  labels: { name: orderflow }

---
apiVersion: v1
kind: ConfigMap
metadata: { name: orderflow-config, namespace: orderflow }
data:
  SPRING_PROFILES_ACTIVE: "prod"
  DB_HOST: "mysql.orderflow.svc.cluster.local"
  REDIS_HOST: "redis.orderflow.svc.cluster.local"
  MANAGEMENT_SERVER_PORT: "8081"

---
apiVersion: v1
kind: Secret
metadata: { name: orderflow-secrets, namespace: orderflow }
type: Opaque
data:
  DB_PASSWORD: <base64-encoded>
  REDIS_PASSWORD: <base64-encoded>
  JWT_PRIVATE_KEY: <base64-encoded>

---
apiVersion: apps/v1
kind: Deployment
metadata: { name: orderflow, namespace: orderflow }
spec:
  replicas: 3
  selector: { matchLabels: { app: orderflow } }
  strategy: { rollingUpdate: { maxUnavailable: 0, maxSurge: 1 } }
  template:
    metadata: { labels: { app: orderflow } }
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: orderflow
        image: registry.example.com/orderflow-service:1.0.0
        ports: [{ containerPort: 8080 }, { containerPort: 8081 }]
        envFrom:
        - { configMapRef: { name: orderflow-config } }
        - { secretRef: { name: orderflow-secrets } }
        resources:
          requests: { memory: "512Mi", cpu: "250m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        lifecycle:
          preStop: { exec: { command: ["sh", "-c", "sleep 10"] } }
        livenessProbe:
          httpGet: { path: /actuator/health/liveness, port: 8080 }
          initialDelaySeconds: 60; periodSeconds: 30
        readinessProbe:
          httpGet: { path: /actuator/health/readiness, port: 8080 }
          initialDelaySeconds: 30; periodSeconds: 10

---
apiVersion: v1
kind: Service
metadata: { name: orderflow, namespace: orderflow }
spec:
  selector: { app: orderflow }
  ports:
  - { name: http, port: 80, targetPort: 8080 }
  - { name: management, port: 8081, targetPort: 8081 }

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: orderflow-hpa, namespace: orderflow }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: orderflow }
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - { type: Resource, resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } } }

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orderflow-ingress
  namespace: orderflow
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - { hosts: [api.orderflow.example.com], secretName: orderflow-tls }
  rules:
  - host: api.orderflow.example.com
    http:
      paths:
      - { path: /, pathType: Prefix, backend: { service: { name: orderflow, port: { number: 80 } } } }

❓ FAQ

Q Which should I choose, GitHub Actions or Jenkins?
A GitHub Actions integrates with the GitHub ecosystem and is easy to configure, making it suitable for small and medium-sized projects. Jenkins offers more powerful features but is more complex to configure, making it suitable for large enterprises. If you already have a GitHub repository, we recommend using GitHub Actions.
Q How can we ensure zero downtime during rolling updates?
A 1) maxUnavailable=0; 2) Use readinessProbe to ensure Pods are ready before being added to the Service; 3) Set preStop sleep 10 to allow K8s time to drain requests after the Pod is removed from the Service; 4) Apply the configuration server.shutdown=graceful.
Q How should I set the minReplicas and maxReplicas for HPA?
A minReplicas = the number of replicas required for normal load (OrderFlow = 3); maxReplicas = the estimated peak load (OrderFlow = 10). Adjust based on historical monitoring data. The recommended target CPU utilization is 70%.
Q What are the best practices for secret management?
A 1) K8s Secrets + etcd encryption (basic approach); 2) External Secrets Operator + AWS Secrets Manager/Vault (recommended approach); 3) Sealed Secrets (GitOps-friendly). Do not commit Secrets in plain text to Git.
Q How do I implement blue-green or canary deployments?
A K8s does not natively support blue-green or canary deployments; tools such as Istio or Argo Rollouts are required. Argo Rollouts supports canary (gradual traffic migration) and blue-green (instantaneous switchover), with validation via Prometheus.
Q What should monitoring alerts in a production environment cover?
A Three main categories: 1) SLO alerts (P99 latency, error rate, availability); 2) Resource alerts (CPU > 80%, memory > 85%, disk > 90%); 3) Business alerts (abnormal drop in order volume, decline in payment success rate).

📖 Summary


📝 Exercises

  1. Basic Problem (Difficulty: ⭐): Write a GitHub Actions workflow to automatically test and build a Docker image after code is pushed.

  2. Advanced Exercise (Difficulty: ⭐⭐): Write a complete K8s production deployment YAML (Deployment + Service + Ingress + HPA + ConfigMap + Secret) to implement rolling updates with zero downtime.

  3. Challenge (Difficulty: ⭐⭐⭐): Set up a complete observability system (Prometheus + Grafana + AlertManager + Jaeger), configure SLO dashboards and alert rules, and simulate a failure to test alerting and automatic recovery capabilities.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏