컨테이너 이미지 빌드

이 페이지에서는 Docker 이미지를 빌드하고 저장하도록 Cloud Build를 구성하는 방법을 설명합니다. Cloud Build를 처음 사용하는 경우 먼저 빠른 시작빌드 구성 개요를 읽어보세요.

Cloud Build는 태스크를 실행하기 위해 Cloud Build 구성 파일에서 참조할 수 있는 사전 빌드된 이미지를 제공합니다. 이러한 이미지는 Google Cloud에서 지원되고 유지보수됩니다. 지원되는 사전 빌드된 Docker 이미지를 사용하여 Docker 명령어를 실행하고 Docker 이미지를 빌드할 수 있습니다.

시작하기 전에

이 페이지의 지침은 사용자가 Docker에 익숙하다고 가정합니다. 또한 다음 사항도 적용됩니다.

  • Dockerfile과 함께 애플리케이션 소스 코드를 준비합니다.
  • Artifact Registry에서 이미지 저장을 위해 Docker 저장소를 준비하거나 새 저장소를 만듭니다.
  • 이 페이지의 gcloud 명령어를 사용하려면 Google Cloud CLI를 설치합니다.
  • 이미지를 실행하려면 Docker를 설치합니다.
  • cosign으로 이미지를 서명하려면 서비스 간 액세스 승인의 안내에 따라 사용자 지정 서비스 계정을 만들고 ID 토큰을 생성하는 데 필요한 권한을 부여합니다.

빌드 구성 파일로 빌드

빌드 구성 파일을 사용하여 Docker 이미지를 빌드하려면 다음 안내를 따릅니다.

  1. 애플리케이션 소스 코드가 포함된 동일한 디렉터리에서 cloudbuild.yaml 또는 cloudbuild.json이라는 이름의 파일을 만듭니다.
  2. 빌드 구성 파일에서 다음 안내를 따릅니다.

    • name 필드를 추가하고 사전 빌드된 Docker 이미지를 지정합니다. 사전 빌드된 이미지는 gcr.io/cloud-builders/docker에 저장됩니다. 아래 구성 파일 예시에서 name 필드는 args 필드로 표시된 태스크를 수행하기 위해 사전 빌드된 Docker 이미지가 Cloud Build에 사용되도록 지정합니다.
    • args 필드에서 이미지를 빌드하기 위한 인수를 추가합니다.

      YAML

      steps:
      - name: 'gcr.io/cloud-builders/docker'
        args: [ 'build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME', '.' ]
      

      JSON

      {
       "steps": [
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": [
              "build",
              "-t",
              "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME",
              "."
             ]
         }
         ]
       }
      

      위의 빌드 구성의 자리표시자 값을 다음으로 바꿉니다.

    • LOCATION: Artifact Registry에 있는 Docker 저장소의 리전 또는 멀티 리전 위치입니다.

    • PROJECT_ID: Google Cloud 프로젝트 ID입니다.

    • REPOSITORY: Artifact Registry에 있는 Docker 저장소의 이름입니다.

    • IMAGE_NAME: 컨테이너 이미지의 이름입니다.

      Dockerfile과 소스 코드가 다른 디렉터리에 있다면 args 필드의 인수 목록에 -fDockerfile 경로를 추가합니다.

      YAML

      steps:
      - name: 'gcr.io/cloud-builders/docker'
        args: [ 'build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME', '-f', 'DOCKERFILE_PATH', '.' ]
      

      JSON

      {
       "steps": [
        {
            "name": "gcr.io/cloud-builders/docker",
            "args": [
              "build",
              "-t",
              "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME", '-f', 'DOCKERFILE_PATH', "."
             ]
         }
         ]
       }
      

      위의 빌드 구성의 자리표시자 값을 다음으로 바꿉니다.

      • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
      • PROJECT_ID: Google Cloud 프로젝트 ID입니다.
      • REPOSITORY: Artifact Registry 저장소의 이름입니다.
      • IMAGE_NAME: 컨테이너 이미지의 이름입니다.
      • DOCKERFILE_PATH: Dockerfile의 경로입니다.
  3. 빌드 구성 파일을 사용하여 빌드를 시작합니다.

    gcloud builds submit --config CONFIG_FILE_PATH SOURCE_DIRECTORY
    

    위의 명령어에서 자리표시자 값을 다음으로 바꿉니다.

    • CONFIG_FILE_PATH: 빌드 구성 파일의 경로입니다.
    • SOURCE_DIRECTORY: 소스 코드의 경로 또는 URL입니다.

    gcloud builds submit 명령어에서 CONFIG_FILE_PATHSOURCE_DIRECTORY를 지정하지 않으면 Cloud Build는 구성 파일과 소스 코드가 현재 작업 중인 디렉터리에 있다고 간주합니다.

Dockerfile로 빌드

Cloud Build에서는 Dockerfile을 사용하여 Docker 이미지를 빌드할 수 있습니다. 별도의 빌드 구성 파일이 필요하지 않습니다.

Dockerfile을 사용하여 빌드하려면 소스 코드 및 Dockerfile이 포함된 디렉터리에서 다음 명령어를 실행합니다.

    gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME

위의 명령어에서 자리표시자 값을 다음으로 바꿉니다.

  • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
  • PROJECT_ID: Google Cloud 프로젝트 ID입니다.
  • REPOSITORY: Artifact Registry 저장소의 이름입니다.
  • IMAGE_NAME: 컨테이너 이미지의 이름입니다.

Google Cloud 빌드팩으로 빌드

Cloud Build를 사용하면 Dockerfile 또는 빌드 구성 파일 없이 이미지를 빌드할 수 있습니다. Google Cloud 빌드팩을 사용하여 이 작업을 수행할 수 있습니다.

빌드팩을 사용하여 빌드하려면 소스 코드가 있는 디렉터리에서 다음 명령어를 실행합니다.

    gcloud builds submit --pack builder=BUILDPACK_BUILDER, \
        env=ENVIRONMENT_VARIABLE, \
        image=IMAGE_NAME

위 명령어의 자리표시자 값을 다음으로 바꿉니다.

  • BUILDPACK_BUILDER: 사용할 빌드팩 빌더입니다. 빌더를 지정하지 않으면 Cloud Build가 기본적으로 gcr.io/buildpacks/builder를 사용합니다.
  • ENVIRONMENT_VARIABLE: 빌드의 모든 환경 변수입니다.
  • IMAGE: Artifact Registry에 있는 이미지의 URL입니다. 이미지 URL은 LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME 형식이어야 합니다.

다음은 몇 가지 명령어 예시입니다.

  • 기본 gcr.io/buildpacks/builder를 사용하여 빌드를 실행하여 us-docker.pkg.dev/gcb-docs-project/containers/gke/hello-app 이미지를 만듭니다.

      gcloud builds submit --pack image=us-docker.pkg.dev/gcb-docs-project/containers/gke/hello-app
    
  • ^--^를 구분자로 사용하여 여러 환경 변수를 빌드에 전달합니다. 이스케이프 인수에 대한 자세한 내용은 gcloud topic escaping을 참조하세요.

      gcloud builds submit --pack \
          ^--^image=gcr.io/my-project/myimage--env=GOOGLE_ENTRYPOINT='java -jar target/myjar.jar',GOOGLE_RUNTIME_VERSION='3.1.301'
    

빌드팩을 사용하도록 트리거 구성: 명령줄을 사용한 빌드 외에도 빌드팩을 사용하여 이미지를 자동으로 빌드하도록 트리거를 구성할 수 있습니다. 자세한 내용은 빌드 트리거 만들기 및 관리를 참조하세요.

Artifact Registry에서 이미지를 저장하는 여러 방법

다음 방법 중 하나로 빌드된 이미지를 저장하도록 Cloud Build를 구성할 수 있습니다.

  • images 사용 - 빌드가 완료된 후 이미지를 Artifact Registry에 저장합니다.
  • docker push 명령어 사용 - 빌드가 진행되는 동안 이미지를 Artifact Registry에 저장합니다.

images 필드와 Docker push 명령어의 차이점은 images 필드를 사용하면 저장된 이미지가 빌드 결과에 표시된다는 점입니다. Google Cloud Console의 빌드에 대한 빌드 설명 페이지, Build.get()의 결과, gcloud builds list의 결과가 여기에 포함됩니다. 그러나 Docker push 명령어를 사용하여 빌드된 이미지를 저장하면 이미지가 빌드 결과에 표시되지 않습니다.

빌드가 진행되는 동안 이미지를 저장하고 빌드 결과에 이미지를 표시하려면 빌드 구성 파일에 Docker push 명령어와 images 필드를 모두 사용합니다.

빌드가 완료된 후 컨테이너 이미지를 Artifact Registry에 저장하려면 다음 안내를 따르세요.

  1. 대상 저장소가 없으면 새 저장소를 만듭니다.
  2. 애플리케이션 소스 코드와 Dockerfile이 포함된 동일한 디렉터리에서 cloudbuild.yaml 또는 cloudbuild.json이라는 파일을 만듭니다.
  3. 빌드 구성 파일에서 이미지 빌드를 위한 빌드 단계를 추가하고 빌드된 이미지를 지정하는 images 필드를 추가합니다. 그러면 Artifact Registry에 이미지가 저장됩니다. 다음 스니펫은 이미지를 빌드하고 이를 Artifact Registry에 저장하기 위한 빌드 구성을 보여줍니다.

    YAML

    steps:
    - name: 'gcr.io/cloud-builders/docker'
      args: [ 'build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME', '.' ]
    images: ['LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME']
    

    JSON

    {
    "steps": [
    {
        "name": "gcr.io/cloud-builders/docker",
        "args": [
            "build",
            "-t",
            "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME",
            "."
        ]
    }
    ],
    "images": [
        "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME"
    ]
    }
    

    각 항목의 의미는 다음과 같습니다.

    • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
    • PROJECT_ID: Google Cloud 프로젝트 ID입니다.
    • REPOSITORY: Artifact Registry 저장소의 이름입니다.
    • IMAGE_NAME: 컨테이너 이미지의 이름입니다.
  4. 빌드 구성 파일을 사용하여 빌드를 시작합니다.

    gcloud builds submit --config CONFIG_FILE_PATH SOURCE_DIRECTORY
    

    각 항목의 의미는 다음과 같습니다.

    • CONFIG_FILE_PATH는 빌드 구성 파일의 경로입니다.
    • SOURCE_DIRECTORY는 소스 코드의 경로 또는 URL입니다.

빌드 진행 중에 Artifact Registry에 이미지를 저장하려면 다음 안내를 따르세요.

  1. 애플리케이션 소스 코드와 Dockerfile이 포함된 동일한 디렉터리에서 cloudbuild.yaml 또는 cloudbuild.json이라는 파일을 만듭니다.

  2. 빌드 구성 파일에서 이미지를 빌드하기 위한 docker 빌드 단계를 추가한 후 또 다른 docker 빌드 단계를 추가하고 push 명령어를 호출하기 위한 인수를 전달합니다.

    YAML

    steps:
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME', '.']
    - name: 'gcr.io/cloud-builders/docker'
      args: ['push', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME']
    

    JSON

    {
      "steps": [
       {
          "name": "gcr.io/cloud-builders/docker",
          "args": [
              "build",
              "-t",
              "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME",
              "."
           ]
       },
       {
           "name": "gcr.io/cloud-builders/docker",
           "args": [
              "push",
              "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME"
            ]
       }
      ]
    }
    

    각 항목의 의미는 다음과 같습니다.

    • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
    • PROJECT_ID: Google Cloud 프로젝트 ID입니다.
    • REPOSITORY: Artifact Registry 저장소의 이름입니다.
    • IMAGE_NAME: 컨테이너 이미지의 이름입니다.
  3. 빌드 구성 파일을 사용하여 빌드를 시작합니다.

    gcloud builds submit --config CONFIG_FILE_PATH SOURCE_DIRECTORY
    

    각 항목의 의미는 다음과 같습니다.

    • CONFIG_FILE_PATH는 빌드 구성 파일의 경로입니다.
    • SOURCE_DIRECTORY는 소스 코드의 경로 또는 URL입니다.

빌드 중에 이미지를 저장하고 이미지를 빌드 결과에 표시하려면 다음 안내를 따르세요.

  1. 애플리케이션 소스 코드와 Dockerfile이 포함된 동일한 디렉터리에서 cloudbuild.yaml 또는 cloudbuild.json이라는 파일을 만듭니다.
  2. 빌드 구성 파일에서 이미지 빌드 단계 후에 Docker push 명령어 호출 단계를 추가한 후 images 필드를 추가합니다.

    YAML

    steps:
    - name: 'gcr.io/cloud-builders/docker'
      args: ['build', '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME', '.']
    - name: 'gcr.io/cloud-builders/docker'
      args: ['push', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME']
    images: ['LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME']
    

    JSON

    {
        "steps": [
       {
           "name": "gcr.io/cloud-builders/docker",
           "args": [
               "build",
               "-t",
               "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME",
               "."
            ]
       },
       {
           "name": "gcr.io/cloud-builders/docker",
           "args": [
               "push",
               "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME"
            ]
       }
       ],
        "images": [
           "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME"
        ]
    }
    

    각 항목의 의미는 다음과 같습니다.

    • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
    • PROJECT_ID: Google Cloud 프로젝트 ID입니다.
    • REPOSITORY: Artifact Registry 저장소의 이름입니다.
    • IMAGE_NAME: 컨테이너 이미지의 이름입니다.
  3. 빌드 구성 파일을 사용하여 빌드를 시작합니다.

    gcloud builds submit --config CONFIG_FILE_PATH SOURCE_DIRECTORY
    

    각 항목의 의미는 다음과 같습니다.

    • CONFIG_FILE_PATH는 빌드 구성 파일의 경로입니다.
    • SOURCE_DIRECTORY는 소스 코드의 경로 또는 URL입니다.

cosign으로 컨테이너 이미지 서명

Artifact Registry에 이미지를 저장하는 경우 cosign 도구를 사용하여 빌드를 시작하는 데 사용되는 서비스 계정 레코드를 만들어 보안을 강화할 수 있습니다. OpenID Connect(OIDC) 표준에서 지원되는 감사관은 이 레코드를 사용하여 신뢰할 수 있는 서비스 계정을 통해 이미지가 빌드되었는지 확인합니다.

다음 단계에서는 cloudbuild.yaml 구성 파일을 사용하여 ID 토큰을 가져오고 컨테이너 이미지에 서명하는 방법을 보여줍니다.

YAML

  steps:
  - name: 'gcr.io/cloud-builders/docker'
    id: 'tag-and-push'
    script: |
      #!/bin/sh
      set -e
      docker build -t $_IMAGE .
      docker push "$_IMAGE"
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'generate-token-and-get-digest'
    script: |
      #!/bin/sh
      set -e
      gcloud auth print-identity-token --audiences=sigstore > token
      gcloud container images describe "$_IMAGE" \
        --format="value(image_summary.fully_qualified_digest)" > image_with_digest
  - name: 'gcr.io/projectsigstore/cosign'
    id: 'sign-image'
    script: |
      #!/busybox/sh
      cosign sign --identity-token=$(cat token) $(cat image_with_digest) -y
    env:
    - 'SIGSTORE_NO_CACHE=true'
  service_account: '$_SERVICE_ACCOUNT'
  artifacts:
    images:
    - $_IMAGE
  substitutions:
    _IMAGE: 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME'
    _SERVICE_ACCOUNT_ID: 'SERVICE_ACCOUNT_ID'
    _SERVICE_ACCOUNT: projects/${PROJECT_ID}/serviceAccounts/${_SERVICE_ACCOUNT_ID}
  options:
    env:
    - '_IMAGE=$_IMAGE'
    dynamic_substitutions: true
    logging: CLOUD_LOGGING_ONLY

JSON

    {
        "steps": [
            {
                "name": "gcr.io/cloud-builders/docker",
                "id": "tag-and-push",
                "script": "#!/bin/sh set -e \ndocker build -t $_IMAGE . \ndocker push \"$_IMAGE\""
            },
            {
                "name": "gcr.io/cloud-builders/gcloud",
                "id": "generate-token-and-get-digest",
                "script": "#!/bin/sh set -e \ngcloud auth print-identity-token --audiences=sigstore > token \ngcloud container images describe \"$_IMAGE\" --format=\"value(image_summary.fully_qualified_digest)\" > image_with_digest"
            },
            {
                "name": "gcr.io/projectsigstore/cosign",
                "id": "sign-image",
                "script": "#!/busybox/sh cosign sign --identity-token=$(cat token) $(cat image_with_digest) -y",
                "env": [
                    "SIGSTORE_NO_CACHE=true"
                ]
            }
        ],
        "service_account": "$_SERVICE_ACCOUNT",
        "artifacts": {
            "images": [
                "$_IMAGE"
            ]
        },
        "substitutions": {
            "_IMAGE": "LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME",
            "_SERVICE_ACCOUNT_ID": "SERVICE_ACCOUNT_ID",
            "_SERVICE_ACCOUNT": "projects/${PROJECT_ID}/serviceAccounts/${_SERVICE_ACCOUNT_ID}"
        },
        "options": {
            "env": [
                "_IMAGE=$_IMAGE"
            ],
            "dynamic_substitutions": true,
            "logging": "CLOUD_LOGGING_ONLY"
        }
    }

각 항목의 의미는 다음과 같습니다.

  • LOCATIONus-east1 또는 us와 같이 이미지가 저장된 저장소의 리전 또는 멀티 리전 위치입니다.

  • PROJECT_ID: Google Cloud 프로젝트 ID입니다.

  • REPOSITORY는 이미지가 저장된 저장소의 이름입니다.

  • IMAGE_NAME는 이미지의 이름입니다.

  • SERVICE_ACCOUNT_ID는 빌드를 실행하려는 사용자 지정 서비스 계정의 이메일 주소입니다. 예를 들어 서비스 계정 이메일 주소는 service-account-name@project-id.iam.gserviceaccount.com과 같습니다.

서명을 확인하려면 로컬 머신에 cosign을 설치한 후 cosign verify 명령어를 실행합니다.

cosign verify \
--certificate-identity=SERVICE_ACCOUNT_ID \
--certificate-oidc-issuer=https://accounts.google.com \
IMAGE

각 항목의 의미는 다음과 같습니다.

  • SERVICE_ACCOUNT_ID는 컨테이너 이미지를 빌드하는 데 사용되어야 하는 신뢰할 수 있는 서비스 계정의 이메일 주소입니다.
  • IMAGE는 sha256 이미지 다이제스트를 포함하는 전체 이미지 이름입니다.

Docker 이미지 실행

빌드한 이미지가 예상대로 작동하는지 확인하려면 Docker를 사용하여 이미지를 실행하면 됩니다.

  1. Artifact Registry와 상호 작용할 때 Artifact Registry 사용자 인증 정보를 사용하도록 Docker를 구성합니다. (이 작업은 한 번만 실행하면 됩니다.) gcloud 사용자 인증 정보 도우미를 사용해서 다음 명령어로 인증을 수행합니다.

    gcloud auth configure-docker HOSTNAME-LIST
    

    여기서 HOSTNAME-LIST는 사용자 인증 정보 도우미 구성에 추가할 저장소 호스트 이름의 쉼표로 구분된 목록입니다.

    예를 들어 us-central1asia-northeast1 리전을 추가하려면 다음 명령어를 실행합니다.

    gcloud auth configure-docker us-central1-docker.pkg.dev,asia-northeast1-docker.pkg.dev
    
  2. 이전에 빌드한 Docker 이미지를 실행합니다.

    docker run LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME
    

    각 항목의 의미는 다음과 같습니다.

    • LOCATION: 저장소의 리전 또는 멀티 리전 위치입니다.
    • PROJECT_ID: Google Cloud 프로젝트 ID입니다.
    • REPOSITORY: Artifact Registry 저장소의 이름입니다.
    • IMAGE_NAME: 컨테이너 이미지의 이름입니다.

    다음과 비슷한 출력이 표시됩니다.

    Hello, world! The time is Fri Feb  2 16:09:54 UTC 2018.
    

다음 단계