Docker 建置與推送管線

DevOps
7 個節點 · 6 條連接devops
ex-docker-build-push.osop.yaml
# Docker Build, Scan, and Push Pipeline
# Multi-stage build with vulnerability scanning and multi-registry push
osop_version: "2.0"
id: docker-build-push
name: "Docker 建置與推送管線"

nodes:
  - id: checkout
    type: cicd
    purpose: Check out source code and determine build metadata
    subtype: github-actions
    runtime:
      platform: github-actions
      trigger: push
      branches: [main, "release/*"]
    outputs: [commit_sha, branch, build_tag]

  - id: lint_dockerfile
    type: cli
    purpose: Lint Dockerfile for best practices using hadolint
    runtime:
      command: "hadolint Dockerfile --format json"
    inputs: [commit_sha]
    outputs: [lint_result]
    timeout_sec: 30

  - id: build_image
    type: cli
    purpose: Build multi-platform Docker image with BuildKit layer caching
    runtime:
      command: |
        docker buildx build \
          --platform linux/amd64,linux/arm64 \
          --cache-from type=registry,ref=${REGISTRY}/app:cache \
          --cache-to type=registry,ref=${REGISTRY}/app:cache,mode=max \
          --tag ${REGISTRY}/app:${build_tag} \
          --tag ${REGISTRY}/app:latest \
          --file Dockerfile \
          --load .
    inputs: [lint_result, build_tag]
    outputs: [image_id, image_digest]
    timeout_sec: 600
    explain: |
      Uses BuildKit for efficient caching and multi-platform support.
      Both amd64 and arm64 images are built in a single pass.

  - id: trivy_scan
    type: cli
    purpose: Scan built image for CVEs and misconfigurations using Trivy
    runtime:
      command: "trivy image --severity HIGH,CRITICAL --format json --exit-code 1 ${REGISTRY}/app:${build_tag}"
    inputs: [image_id]
    outputs: [scan_report, vulnerability_count]
    timeout_sec: 300
    retry_policy:
      max_retries: 2
      backoff_sec: 10

  - id: sign_image
    type: cli
    purpose: Sign the container image with Cosign for supply chain integrity
    runtime:
      command: "cosign sign --key cosign.key ${REGISTRY}/app@${image_digest}"
    inputs: [image_digest]
    outputs: [signature]
    security:
      credentials: [COSIGN_PRIVATE_KEY, COSIGN_PASSWORD]
    timeout_sec: 60

  - id: push_registries
    type: cli
    purpose: Push signed image to ECR and GitHub Container Registry
    runtime:
      command: |
        docker push ${REGISTRY}/app:${build_tag} &&
        docker tag ${REGISTRY}/app:${build_tag} ghcr.io/org/app:${build_tag} &&
        docker push ghcr.io/org/app:${build_tag}
    inputs: [signature, image_id]
    outputs: [push_digest_ecr, push_digest_ghcr]
    security:
      credentials: [AWS_ECR_TOKEN, GHCR_TOKEN]
    timeout_sec: 300

  - id: deploy_staging
    type: cli
    purpose: Update staging Kubernetes deployment with new image tag
    runtime:
      command: "kubectl set image deployment/app app=${REGISTRY}/app:${build_tag} -n staging"
    inputs: [push_digest_ecr]
    outputs: [rollout_status]
    timeout_sec: 180

edges:
  - from: checkout
    to: lint_dockerfile
    mode: sequential

  - from: lint_dockerfile
    to: build_image
    mode: sequential

  - from: build_image
    to: trivy_scan
    mode: sequential

  - from: trivy_scan
    to: sign_image
    mode: conditional
    condition: "vulnerability_count.critical == 0"

  - from: sign_image
    to: push_registries
    mode: sequential

  - from: push_registries
    to: deploy_staging
    mode: sequential