Docker Scout를 GitHub Actions와 통합하기

Docker Scout를 GitHub Actions와 통합하기

다음 예시는 GitHub Actions로 Docker Scout 워크플로를 설정하는 방법을 보여 줘요. Pull request로 트리거된 action은 이미지를 빌드하고 Docker Scout를 사용해 새 버전을 프로덕션에서 실행 중인 해당 이미지 버전과 비교해요.

이 워크플로는 docker/scout-action GitHub Action을 사용해 docker scout compare 명령을 실행해 pull request의 이미지가 프로덕션에서 실행하는 이미지와 어떻게 비교되는지 시각화해요.

사전 요구사항 (Prerequisites)

  • 이 예시는 Docker Hub나 다른 레지스트리에 Docker Scout를 활성화한 기존 이미지 저장소가 있다고 가정해요.
  • 이 예시는 환경(environments)을 사용해 pull request에서 빌드한 이미지를 production이라는 환경의 다른 버전의 같은 이미지와 비교해요.

단계 (Steps)

먼저 이미지를 빌드하도록 GitHub Action 워크플로를 설정하세요. 이는 여기서 Docker Scout에 특화된 게 아니지만, 비교할 무언가를 갖기 위해 이미지를 빌드해야 해요.

GitHub Actions YAML 파일에 다음을 추가하세요.

name: Docker

on:
  push:
    tags: ["*"]
    branches:
      - "main"
  pull_request:
    branches: ["**"]

env:
  # 레지스트리 호스트 이름 (Hostname of your registry)
  REGISTRY: docker.io
  # 호스트 이름과 태그 없는 이미지 저장소 (Image repository, without hostname and tag)
  IMAGE_NAME: ${{ github.repository }}
  SHA: ${{ github.event.pull_request.head.sha || github.event.after }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    steps:
      # 컨테이너 레지스트리에 인증 (Authenticate to the container registry)
      - name: Authenticate to registry ${{ env.REGISTRY }}
        uses: docker/login-action@v4
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_TOKEN }}
      
      - name: Setup Docker buildx
        uses: docker/setup-buildx-action@v4

      # Docker용 메타데이터(tags, labels) 추출 (Extract metadata (tags, labels) for Docker)
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@v6
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          labels: |
            org.opencontainers.image.revision=${{ env.SHA }}
          tags: |
            type=edge,branch=$repo.default_branch
            type=semver,pattern=v{{version}}
            type=sha,prefix=,suffix=,format=short

      # Buildx로 Docker 이미지 빌드·push (Build and push Docker image with Buildx)
      # (PR에서는 push하지 말고 load함)
      - name: Build and push Docker image
        id: build-and-push
        uses: docker/build-push-action@v7
        with:
          sbom: ${{ github.event_name != 'pull_request' }}
          provenance: ${{ github.event_name != 'pull_request' }}
          push: ${{ github.event_name != 'pull_request' }}
          load: ${{ github.event_name == 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

이것은 다음을 수행하는 워크플로 단계를 만들어요.

  1. Docker Buildx 설정.
  2. 레지스트리에 인증.
  3. Git 참조와 GitHub 이벤트에서 메타데이터 추출.
  4. Docker 이미지를 빌드하고 레지스트리로 push.

[!NOTE]

Scout compare 단계는 pull request에서만 실행돼요 (if: github.event_name == 'pull_request'). 그 빌드는 load: true를 설정하고 sbom/provenance를 꺼서 이미지가 러너의 로컬 저장소에 들어갈 수 있게 해요.

push 이벤트에서는 같은 작업이 SBOM과 provenance를 켜고 레지스트리로 push해요. PR 경로에서는 그 인증(또는 멀티 플랫폼 빌드)을 활성화하지 마세요 — 그 이미지는 로컬로 로드할 수 없어서 compare가 검사할 게 없게 되요.

이 설정을 끝냈으면 이미지 비교를 실행하기 위해 다음 단계를 추가할 수 있어요.

      # Docker Hub가 레지스트리이고 이미 인증했다면 이 단계는 건너뛸 수 있음
      - name: Authenticate to Docker
        uses: docker/login-action@v4
        with:
          username: ${{ secrets.DOCKER_USER }}
          password: ${{ secrets.DOCKER_PAT }}

      # pull request에서 빌드한 이미지를 프로덕션의 것과 비교
      - name: Docker Scout
        id: docker-scout
        if: ${{ github.event_name == 'pull_request' }}
        uses: docker/scout-action@v1
        with:
          command: compare
          image: ${{ steps.meta.outputs.tags }}
          to-env: production
          ignore-unchanged: true
          only-severities: critical,high
          github-token: ${{ secrets.GITHUB_TOKEN }}

compare 명령은 이미지를 분석하고 정책 준수를 평가하며, 결과를 production 환경의 해당 이미지와 교차 참조해요. 이 예시는 critical과 high 심각도 취약점만 포함하고, 두 이미지 모두에 존재하는 취약점은 제외해 변경된 것만 보여 줘요.

GitHub Action은 기본적으로 pull request 댓글에 비교 결과를 출력해요.

Policies 섹션을 펼치면 두 이미지 사이의 정책 준수 차이를 볼 수 있어요. 이 예시의 새 이미지가 완전히 준수하지는 않지만, 출력은 새 이미지의 입장이 베이스라인보다 개선됐음을 보여 줘요.