Bake로 Compose 프로젝트 빌드하기
Bake로 Compose 프로젝트 빌드하기 (Building Compose projects with Bake)
Bake를 사용해 Docker Compose 프로젝트를 위한 프로덕션 등급 이미지를 빌드하는 방법을 설명하는 가이드예요.
출처: 문서
본문
이 가이드는 여러 서비스를 가진 Docker Compose 프로젝트의 이미지를 빌드하기 위해 Bake를 사용하는 방법을 탐구해요.
Docker Buildx Bake는 Docker Compose가 런타임 스택을 정의하는 것처럼 빌드에 대한 선언적 구성을 가능하게 하는 빌드 오케스트레이션 도구예요. Docker Compose를 사용해 로컬 개발용 서비스를 띄우는 프로젝트의 경우, Bake는 프로젝트에 프로덕션 준비가 된 빌드 구성을 매끄럽게 확장하는 방법을 제공해요.
사전 요구사항 (Prerequisites)
이 가이드는 다음에 익숙하다고 가정해요:
- Docker Compose
- Multi-stage builds
- Multi-platform builds
방향 (Orientation)
이 가이드는 Bake로 확장할 수 있는 Docker Compose를 사용하는 모노레포의 예시로 dvdksn/example-voting-app 저장소를 사용할 거예요.
$ git clone https://github.com/dvdksn/example-voting-app.git
$ cd example-voting-app
이 저장소는 compose.yaml 파일에서 애플리케이션을 실행하기 위한 런타임 구성을 Docker Compose로 정의해요. 이 앱은 다음 서비스로 구성돼요:
| 서비스 | 설명 |
|---|---|
vote |
두 옵션 사이에서 투표할 수 있게 하는 Python 프론트-엔드 웹 앱. |
result |
투표 결과를 실시간으로 보여주는 Node.js 웹 앱. |
worker |
투표를 소비하고 데이터베이스에 저장하는 .NET 워커. |
db |
Docker 볼륨으로 백업되는 Postgres 데이터베이스. |
redis |
새 투표를 수집하는 Redis 인스턴스. |
seed |
데이터베이스에 mock 데이터를 시딩하는 유틸리티 컨테이너. |
vote, result, worker 서비스는 이 저장소의 코드에서 빌드되는 반면, db와 redis는 Docker Hub에서 기존 Postgres와 Redis 이미지를 사용해요. seed 서비스는 프론트-엔드 서비스에 요청을 호출해 테스트 목적으로 데이터베이스를 채우는 유틸리티예요.
Compose로 빌드하기 (Build with Compose)
Docker Compose 프로젝트를 띄우면 build 속성을 정의한 서비스는 서비스가 시작되기 전에 자동으로 빌드돼요. 예시 저장소의 vote 서비스 빌드 구성은 다음과 같아요:
services:
vote:
build:
context: ./vote # Build context
target: dev # Dockerfile stage
vote, result, worker 서비스 모두 빌드 구성이 지정되어 있어요. docker compose up을 실행하면 이 서비스들의 빌드가 트리거돼요.
Compose를 서비스 이미지 빌드에만 사용할 수도 있다는 것을 알고 있나요? docker compose build 명령은 Compose 파일에 지정된 빌드 구성을 사용해 빌드를 호출하게 해줘요. 예를 들어 이 구성으로 vote 서비스를 빌드하려면 다음을 실행하세요:
$ docker compose build vote
서비스 이름을 생략하면 모든 서비스를 한 번에 빌드할 수 있어요:
$ docker compose build
docker compose build 명령은 서비스를 실행하지 않고 이미지만 빌드하면 될 때 유용해요.
Compose 파일 형식은 빌드 구성을 정의하기 위한 많은 속성을 지원해요. 예를 들어 이미지의 태그 이름을 지정하려면 서비스에 image 속성을 설정하세요.
services:
vote:
image: username/vote
build:
context: ./vote
target: dev
#...
result:
image: username/result
build:
context: ./result
#...
worker:
image: username/worker
build:
context: ./worker
#...
docker compose build를 실행하면 Docker Hub에 푸시할 수 있는 정규화된 이미지 이름을 가진 세 개의 서비스 이미지가 만들어져요.
build 속성은 빌드 구성을 위한 광범위한 옵션을 지원해요. 하지만 프로덕션 등급 이미지는 로컬 개발에 사용되는 이미지와 종종 다르죠. Compose 파일을 로컬 빌드에 바람직하지 않을 수 있는 빌드 구성으로 어지럽히지 않으려면, Bake를 사용해 릴리즈용 이미지를 빌드해 프로덕션 빌드를 로컬 빌드와 분리하는 것을 고려하세요. 이 접근 방식은 우려 사항을 분리해요: 로컬 개발에는 Compose를, 프로덕션 준비 빌드에는 Bake를 사용하면서도 서비스 정의와 기본 빌드 구성을 재사용해요.
Bake로 빌드하기 (Build with Bake)
Compose처럼 Bake도 구성 파일에서 프로젝트의 빌드 정의를 파싱해요. Bake는 HashiCorp Configuration Language (HCL), JSON, Docker Compose YAML 형식을 지원해요. Bake를 여러 파일과 함께 사용하면 적용 가능한 모든 구성 파일을 찾아 하나의 통합된 빌드 구성으로 병합해요. Compose 파일에 정의된 빌드 옵션은 Bake 파일에 지정된 옵션에 의해 확장되거나 경우에 따라 재정의돼요.
다음 섹션은 프로덕션을 위해 Compose 파일에 정의된 빌드 옵션을 Bake로 확장하는 방법을 탐구해요.
빌드 구성 보기 (View the build configuration)
Bake는 서비스의 build 속성에서 자동으로 빌드 구성을 만들어요. 주어진 Compose 파일의 빌드 구성을 보려면 Bake에서 --print 플래그를 사용하세요. 이 플래그는 빌드 구성을 평가하고 빌드 정의를 JSON 형식으로 출력해요.
$ docker buildx bake --print
JSON 형식의 출력은 실행될 그룹과 그 그룹의 모든 타깃을 보여줘요. 그룹은 빌드의 모음이고, 타깃은 단일 빌드를 나타내요.
{
"group": {
"default": {
"targets": [
"vote",
"result",
"worker",
"seed"
]
}
},
"target": {
"result": {
"context": "result",
"dockerfile": "Dockerfile",
},
"seed": {
"context": "seed-data",
"dockerfile": "Dockerfile",
},
"vote": {
"context": "vote",
"dockerfile": "Dockerfile",
"target": "dev",
},
"worker": {
"context": "worker",
"dockerfile": "Dockerfile",
}
}
}
보시다시피 Bake는 네 개의 타깃을 포함하는 default 그룹을 만들었어요:
seedvoteresultworker
이 그룹은 Compose 파일에서 자동으로 만들어져요; 빌드 구성을 포함하는 모든 서비스가 여기에 포함돼요. Bake로 이 서비스 그룹을 빌드하려면 다음을 실행하세요:
$ docker buildx bake
빌드 그룹 사용자 지정 (Customize the build group)
Bake가 실행하는 기본 빌드 그룹을 재정의하는 것부터 시작하세요. 현재 기본 그룹은 데이터베이스에 mock 데이터를 채우는 데만 사용되는 Compose 서비스인 seed 타깃을 포함해요. 이 타깃은 프로덕션 이미지를 만들지 않으므로 빌드 그룹에 포함될 필요가 없어요.
Bake가 사용하는 빌드 구성을 사용자 지정하려면 compose.yaml 파일 옆 저장소 루트에 docker-bake.hcl이라는 새 파일을 만드세요.
$ touch docker-bake.hcl
Bake 파일을 열고 다음 구성을 추가하세요:
group "default" {
targets = ["vote", "result", "worker"]
}
파일을 저장하고 Bake 정의를 다시 출력하세요.
$ docker buildx bake --print
JSON 출력은 default 그룹이 원하는 타깃만 포함함을 보여줘요.
{
"group": {
"default": {
"targets": ["vote", "result", "worker"]
}
},
"target": {
"result": {
"context": "result",
"dockerfile": "Dockerfile",
"tags": ["username/result"]
},
"vote": {
"context": "vote",
"dockerfile": "Dockerfile",
"tags": ["username/vote"],
"target": "dev"
},
"worker": {
"context": "worker",
"dockerfile": "Dockerfile",
"tags": ["username/worker"]
}
}
}
여기서 각 타깃의 빌드 구성(컨텍스트, 태그 등)은 compose.yaml 파일에서 가져와요. 그룹은 docker-bake.hcl 파일로 정의돼요.
타깃 사용자 지정 (Customize targets)
Compose 파일은 현재 vote 서비스의 빌드 타깃으로 dev 스테이지를 정의해요. 그것은 로컬 개발에서 실행할 이미지에 적절한데, dev 스테이지는 추가 개발 의존성과 구성을 포함하기 때문이에요. 하지만 프로덕션 이미지에서는 final 이미지를 타깃으로 하고 싶을 거예요.
vote 서비스가 사용하는 타깃 스테이지를 수정하려면 Bake 파일에 다음 구성을 추가하세요:
target "vote" {
target = "final"
}
이렇게 하면 Bake로 빌드를 실행할 때 Compose 파일에 지정된 target 속성이 다른 값으로 재정의돼요. Compose 파일의 다른 빌드 옵션(태그, 컨텍스트)은 수정되지 않아요. docker buildx bake --print vote로 vote 타깃의 빌드 구성을 검사해 확인할 수 있어요:
{
"group": {
"default": {
"targets": ["vote"]
}
},
"target": {
"vote": {
"context": "vote",
"dockerfile": "Dockerfile",
"tags": ["username/vote"],
"target": "final"
}
}
}
추가 빌드 기능 (Additional build features)
프로덕션 등급 빌드는 개발 빌드와 종종 다른 특성을 가져요. 프로덕션 이미지에 추가하고 싶을 만한 것들의 몇 가지 예시는 다음과 같아요:
- Multi-platform: 로컬 개발의 경우 이미지가 그냥 자기 머신에서 실행될 것이므로 로컬 플랫폼에 대해서만 빌드하면 돼요. 하지만 레지스트리에 푸시되는 이미지의 경우, 특히
arm64와amd64에 대해 여러 플랫폼으로 빌드하는 것이 좋은 경우가 많아요. - Attestations: Attestations는 이미지가 어떻게 만들어졌고 어떤 구성 요소를 포함하는지 설명하는 이미지에 첨부된 매니페스트예요. 이미지에 attestation을 첨부하면 이미지가 소프트웨어 공급망 모범 사례를 따르도록 도와줘요.
- Annotations: Annotations는 이미지에 대한 설명 메타데이터를 제공해요. 임의의 정보를 기록해 이미지에 첨부하려면 annotation을 사용하세요. 이는 소비자와 도구가 이미지의 출처, 내용, 사용 방법을 이해하는 데 도움이 돼요.
팁: 이러한 추가 빌드 옵션을 Compose 파일에 직접 정의하지 않는 이유는 무엇일까요?
Compose 파일 형식의
build속성은 모든 빌드 기능을 지원하지 않아요. 또한 multi-platform 빌드 같은 일부 기능은 서비스를 빌드하는 시간을 크게 늘릴 수 있어요. 로컬 개발에서는 빌드 단계를 간단하고 빠르게 유지하고, 출시 빌드용 기능은 아껴 두는 것이 좋아요.
Bake로 빌드하는 이미지에 이러한 속성을 추가하려면 Bake 파일을 다음과 같이 업데이트하세요:
group "default" {
targets = ["vote", "result", "worker"]
}
target "_common" {
annotations = ["org.opencontainers.image.authors=username"]
platforms = ["linux/amd64", "linux/arm64"]
attest = [
"type=provenance,mode=max",
"type=sbom"
]
}
target "vote" {
inherits = ["_common"]
target = "final"
}
target "result" {
inherits = ["_common"]
}
target "worker" {
inherits = ["_common"]
}
이것은 이미지에 multi-platform 지원, annotations, attestations를 추가하기 위한 재사용 가능한 빌드 구성을 정의하는 새 _common 타깃을 정의해요. 재사용 가능한 타깃은 빌드 타깃에 의해 상속되어요.
이 변경으로 Bake로 프로젝트를 빌드하면 linux/amd64와 linux/arm64 아키텍처에 대한 세 개의 multi-platform 이미지 세트가 만들어져요. 각 이미지는 작성자 annotation으로 꾸며지고 SBOM과 provenance attestation 레코드를 모두 포함해요.
결론 (Conclusions)
이 가이드에서 보여준 패턴은 Docker Compose를 사용하는 프로젝트에서 프로덕션 준비가 된 Docker 이미지를 관리하는 유용한 접근 방식을 제공해요. Bake를 사용하면 Buildx와 BuildKit의 모든 강력한 기능에 접근할 수 있고, 개발 및 빌드 구성을 합리적인 방식으로 분리하는 데도 도움이 돼요.
더 읽을거리 (Further reading)
Bake 사용 방법에 대한 자세한 내용은 다음 리소스를 확인하세요:
- Bake documentation
- Building with Bake from a Compose file
- Bake file reference
- Mastering multi-platform builds, testing, and more with Docker Buildx Bake
- Bake GitHub Action