2024. 4. 7. 10:20ㆍDocker
이 챕터에서는 다음을 다룹니다.
- The goals of Docker image pipelines
- Patterns for building images and using metadata to help consumers use your image
- Common approaches for testing that images are configured correctly and secure
- Patterns for tagging images so they can be identified and delivered to consumers
- Patterns for publishing images to runtime environments and registries
8장에서 Dockerfile과 docker build 명령어를 사용하여 Docker 이미지를 자동으로 빌드하는 방법을 배웠습니다. 그러나 이미지를 빌드하는 것은 작동 가능하고 신뢰할 수 있는 이미지를 제공하기 위한 더 긴 프로세스에서 중요한 단계 중 하나일 뿐입니다.
이미지 게시자는 예상되는 운영 조건에서 이미지가 제대로 작동하는지 확인하기 위해 테스트를 수행해야 합니다. 이미지를 생성한 결과물이 이러한 테스트를 통과할수록 그 정확성에 대한 신뢰도가 높아집니다. 그 후, 이미지는 최종적으로 태그가 지정되고 소비를 위해 레지스트리에 게시될 수 있습니다. 소비자는 이미 중요한 요구 사항이 검증되었음을 알고 이러한 이미지를 자신 있게 배포할 수 있습니다.
이미지 자료 준비, 이미지 빌드, 테스트, 그리고 최종적으로 이미지를 레지스트리에 게시하는 이 단계들은 이미지 빌드 파이프라인(image build pipeline)이라고 합니다. 파이프라인은 소프트웨어 작성자가 업데이트를 신속히 게시하고 새로운 기능과 수정 사항을 컨슈머에게 효율적으로 전달할 수 있도록 돕습니다.
10.1 Goals of an image build pipeline
이 컨택스트에서 파이프라인은 아티팩트를 빌드, 테스트, 게시하여 런타임 환경에 배포할 수 있도록 프로세스를 자동화합니다. 그림 10.1은 파이프라인에서 소프트웨어나 기타 아티팩트를 빌드하는 고수준의 프로세스를 보여줍니다. 이 과정은 지속적 통합(CI) 관행을 사용하는 사람들에게 익숙할 것이며, Docker 이미지에만 국한되지 않습니다.
사람들은 종종 Jenkins, Travis CI, Drone과 같은 지속적 통합(CI) 시스템을 사용하여 빌드 파이프라인을 자동화합니다. 특정 파이프라인 모델링 기술과 관계없이, 빌드 파이프라인의 목표는 소스 정의에서 배포 가능한 아티팩트를 생성하는 데 있어 일관된 엄격한 관행을 적용하는 것입니다. 파이프라인에서 사용되는 특정 도구 간의 차이는 단순히 구현 세부 사항에 불과합니다. Docker 이미지를 위한 CI 프로세스는 다른 소프트웨어 아티팩트의 CI 프로세스와 유사하며, 그림 10.2와 같은 형태를 띱니다.
Docker 이미지를 빌드할 때 이 과정은 다음 단계를 포함합니다:
- 이미지를 정의하는 소스 코드와 빌드 스크립트의 깨끗한 복사본을 체크아웃하여 이미지의 소스와 빌드에 사용된 프로세스를 명확히 합니다.
- 애플리케이션 패키지와 런타임 라이브러리와 같이 이미지에 포함될 아티팩트를 가져오거나 생성합니다.
- Dockerfile을 사용하여 이미지를 빌드합니다.
- 이미지가 의도한 대로 구조화되고 작동하는지 확인합니다.
- (선택 사항) 이미지에 알려진 취약점이 포함되지 않았는지 확인합니다.
- 이미지를 쉽게 소비할 수 있도록 태그를 지정합니다.
- 이미지를 레지스트리나 다른 배포 채널에 게시합니다.
애플리케이션 아티팩트는 소프트웨어 작성자가 생성한 런타임 스크립트, 바이너리(.exe, .tgz, .zip), 그리고 설정 파일입니다. 이 이미지 빌드 프로세스는 애플리케이션 아티팩트가 이미 빌드, 테스트, 그리고 이미지에 포함되기 위해 아티팩트 리포지토리에 게시되었다고 가정합니다. 애플리케이션 아티팩트는 컨테이너 내부에서 빌드될 수 있으며, 이는 많은 최신 CI 시스템이 작동하는 방식입니다.
이 장의 연습에서는 컨테이너를 사용하여 애플리케이션을 빌드하고, 해당 애플리케이션 아티팩트를 애플리케이션을 실행하는 Docker 이미지로 패키징하는 방법을 보여줍니다. 빌드 프로세스는 UNIX 유사 환경에서 사용할 수 있는 작고 일반적인 도구 세트를 사용하여 구현할 것입니다. 이 파이프라인의 개념과 기본 커맨드는 조직의 자체 도구로 쉽게 이전할 수 있을 것입니다.
10.2 Patterns for building images
컨테이너를 사용하여 애플리케이션과 이미지를 빌드하는 데에는 여러 가지 패턴이 있습니다. 여기서는 가장 인기 있는 세 가지 패턴에 대해 논의합니다:
- All-in-One: 애플리케이션을 빌드하고 실행하기 위해 하나의 올인원 이미지를 사용합니다.
- Build Plus Runtime: 빌드 이미지와 별도로 슬림한 런타임 이미지를 사용하여 컨테이너화된 애플리케이션을 빌드합니다.
- Build Plus Multiple Runtimes: 멀티스테이지 빌드에서 디버깅 및 기타 보조 용도를 위한 변형을 포함한 슬림한 런타임 이미지를 사용합니다.
특정 소비 사례에 적합한 이미지를 생성하기 위해 다양한 빌드 패턴이 발전해왔습니다. 이 컨텍스트에서 성숙도는 패턴을 적용하는 조직이 아니라, 이미지를 빌드하는 데 사용되는 설계와 프로세스를 의미합니다.
이미지가 내부 실험이나 휴대 가능한 개발 환경으로 사용될 경우, All-in-One 패턴이 가장 적합할 수 있습니다. 반면, 상업적으로 라이선스가 부여되고 지원되는 서버를 배포할 경우, Build Plus Runtime 패턴이 더 적합할 가능성이 높습니다.
단일 소프트웨어 게시 조직에서도 자신들이 사용하고 배포하는 이미지를 빌드하기 위해 여러 패턴을 종종 사용합니다. 여기서 설명된 패턴을 적용하고 수정하여 자신의 이미지 빌드 및 전달 문제를 해결하세요.
10.2.1 All-in-one images
All-in-One 이미지는 애플리케이션을 빌드하고 실행하는 데 필요한 모든 도구를 포함합니다. 이러한 도구에는 소프트웨어 개발 키트(SDK), 패키지 관리자, 공유 라이브러리, 언어별 빌드 도구 또는 기타 바이너리 도구가 포함될 수 있습니다. 이 유형의 이미지는 디폴트 애플리케이션 런타임 설정을 포함하는 경우가 많습니다. All-in-One 이미지는 애플리케이션을 컨테이너화하는 가장 간단한 방법으로, 특히 많은 종속성을 가진 개발 환경이나 "레거시" 애플리케이션을 컨테이너화할 때 유용합니다.
All-in-One 패턴을 사용하여 인기 있는 Spring Boot 프레임워크를 활용한 간단한 Java 웹 서버를 빌드해 보겠습니다. 다음은 빌드 도구와 함께 애플리케이션을 이미지로 빌드하는 All-in-One Dockerfile입니다.
FROM maven:3.6-jdk-11
ENV WORKDIR=/project
RUN mkdir -p ${WORKDIR}
COPY . ${WORKDIR}
WORKDIR ${WORKDIR}
RUN mvn -f pom.xml clean verify
RUN cp ${WORKDIR}/target/ch10-0.1.0.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
https://github.com/dockerinaction/ch10_patterns-for-building-images.git 리포지토리를 클론하고 다음과 같이 프로젝트를 빌드하세요:
$ docker image build -t dockerinaction/ch10:all-in-one \
> --file all-in-one.df .
이 Dockerfile에서는 커뮤니티 Maven 3.6 이미지를 베이스 이미지로 사용하며, 이 이미지는 OpenJDK 11도 포함하고 있습니다. Dockerfile은 간단한 Java 웹 서버를 빌드하며, 애플리케이션 아티팩트를 이미지에 추가합니다. 이미지 정의는 이미 빌드된 애플리케이션 아티팩트를 java 커맨드로 실행하는 ENTRYPOINT로 끝납니다. 이는 가능한 가장 간단한 작업 방식으로, "보세요, 우리의 애플리케이션을 컨테이너화할 수 있습니다!"라고 시연하기에 적합한 접근법입니다.
All-in-One 이미지는 단점도 있습니다. 애플리케이션 실행에 필요한 것보다 더 많은 도구를 포함하고 있기 때문에, 공격자들에게 애플리케이션을 악용할 더 많은 기회를 제공하며, 광범위한 개발 및 운영 요구 사항의 변경을 수용하기 위해 이미지를 더 자주 업데이트해야 할 수도 있습니다. 또한, All-in-One 이미지는 크기가 커지는 경향이 있어 종종 500MB 이상이 됩니다. 예제에서 사용된 maven:3.6-jdk-11 베이스 이미지는 처음부터 614MB이며, 최종 이미지는 708MB입니다. 대규모 또는 매우 빈번한 릴리스가 아니라면 이 문제는 비교적 무해하지만, 큰 이미지는 이미지 배포 메커니즘에 더 큰 부담을 줄 수 있습니다.
10.2.2 Separate build and runtime images
All-in-One 패턴은 빌드 이미지와 런타임 이미지를 분리하여 개선할 수 있습니다. 구체적으로, 이 접근법에서는 애플리케이션 빌드와 테스트 도구를 포함한 이미지를 하나 생성하고, 애플리케이션 실행에 필요한 것만 포함하는 이미지를 별도로 만듭니다.
Maven 컨테이너를 사용하여 애플리케이션을 빌드할 수 있습니다:
$ docker container run -it --rm \
> -v "$(pwd)":/project/ \
> -w /project/ \
> maven:3.6-jdk-11 \
> mvn clean verify
Maven은 애플리케이션 아티팩트를 컴파일하고 프로젝트의 target 디렉토리에 패키징합니다:
$ ls -la target/ch10-0.1.0.jar
-rw-r--r-- 1 user group 16142344 Jul 2 15:17 target/ch10-0.1.0.jar
이 접근법에서는 Public Maven 이미지를 기반으로 생성된 컨테이너를 사용하여 애플리케이션을 빌드합니다. All-in-One 패턴에서처럼 빌드 이미지에 아티팩트를 저장하는 대신, 볼륨 마운트를 통해 애플리케이션 아티팩트를 호스트 파일 시스템에 출력합니다. 런타임 이미지는 OpenJDK 10을 기반으로 한 간단한 Dockerfile을 사용하여 애플리케이션 아티팩트를 이미지에 COPY하여 생성됩니다:
FROM openjdk:11-jdk-slim
COPY target/ch10-0.1.0.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
런타임 이미지를 빌드합니다:
$ docker image build -t dockerinaction/ch10:simple-runtime \
> --file simple-runtime.df
웹 서버 이미지를 실행시킵니다:
docker container run --rm -it -p 8080:8080 dockerinaction/ch10:simple-runtime
애플리케이션은 이전의 All-in-One 예제와 마찬가지로 실행됩니다. 하지만 이 접근법에서는 Maven과 같은 빌드 관련 도구 및 중간 아티팩트가 더 이상 런타임 이미지에 포함되지 않습니다. 결과적으로 런타임 이미지는 훨씬 더 작아졌습니다(401MB 대 708MB) 그리고 공격 표면도 줄어들었습니다.
이 패턴은 이제 많은 CI 도구에서 지원되고 권장됩니다. 이러한 지원은 일반적으로 단계별로 사용할 Docker 이미지를 위생적인 실행 환경으로 지정하거나, 컨테이너화된 빌드 에이전트를 실행하고 해당 단계에 할당하는 기능으로 제공됩니다.
10.2.3 Variations of runtime image via multi-stage builds
빌드 및 운영 경험이 성숙해짐에 따라 디버깅, 전문화된 테스트, 또는 프로파일링과 같은 사용 사례를 지원하기 위해 애플리케이션 이미지의 작은 변형을 만드는 것이 유용하다고 느낄 수 있습니다. 이러한 사용 사례는 종종 전문화된 도구를 추가하거나 애플리케이션 이미지를 변경해야 합니다.
멀티스테이지 빌드를 사용하면 애플리케이션 이미지와 전문화된 이미지를 동기화하고 이미지 정의의 중복을 방지할 수 있습니다.
이 섹션에서는 8장에서 소개한 FROM 커맨드의 멀티스테이지 기능을 사용하여 전문화된 이미지를 만드는 Build Plus Multiple Runtimes 패턴에 초점을 맞춥니다.
애플리케이션 이미지를 기반으로 디버그 변형을 만들어 보겠습니다. 계층 구조는 그림 10.4와 같습니다.
이 장의 예제 리포지토리에 있는 multi-stage-runtime.df는 이 계층 구조를 구현합니다:
#The app-image build target defines the application image
FROM openjdk:11-jdk-slim as app-image <--- app-image build stage
starts from openjdk.
ARG BUILD_ID=unknown
ARG BUILD_DATE=unknown
ARG VCS_REF=unknown
LABEL org.label-schema.version="${BUILD_ID}" \
org.label-schema.build-date="${BUILD_DATE}" \
org.label-schema.vcs-ref="${VCS_REF}" \
org.label-schema.name="ch10" \
org.label-schema.schema-version="1.0rc1"
COPY multi-stage-runtime.df /Dockerfile
COPY target/ch10-0.1.0.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
FROM app-image as app-image-debug <--- app-image-debug stage
inherits and adds to the
app-image.
#COPY needed debugging tools into image
ENTRYPOINT ["sh"]
FROM app-image as default <--- default stage ensures app-image
is produced by default.
메인 애플리케이션 이미지의 빌드 단계는 openjdk:11-jdk-slim에서 시작되도록 선언되었으며, app-image라는 이름이 지정됩니다:
# The app-image build target defines the application image
FROM openjdk:11-jdk-slim as app-image
…
빌드 단계에 이름을 지정하는 것은 두 가지 중요한 목적을 가집니다.
첫째, 단계 이름을 통해 Dockerfile 내의 다른 빌드 단계가 해당 단계를 쉽게 참조할 수 있습니다.
둘째, 빌드 프로세스에서 그 이름을 빌드 타겟(build target)으로 지정하여 특정 단계를 빌드할 수 있습니다.
빌드 단계의 이름은 Dockerfile 컨텍스트 내에서만 로컬로 사용되며, 이미지 태그 지정에는 영향을 미치지 않습니다.
디버깅을 지원하는 빌드 단계를 Dockerfile에 추가하여 애플리케이션 이미지의 변형을 정의해 보겠습니다:
FROM app-image as app-image-debug <--- Uses app-image as the
base for the debug image
#COPY needed debugging tools into image
ENTRYPOINT ["sh"]
디버그 애플리케이션 이미지 정의는 app-image를 베이스 이미지로 지정하며, 사소한 변경 사항을 적용하는 방법을 보여줍니다. 이 경우, 변경 사항은 애플리케이션을 실행하는 대신 셸을 실행하도록 이미지의 ENTRYPOINT를 재구성하는 것입니다. 디버그 이미지는 이외의 모든 부분에서 메인 애플리케이션 이미지와 동일합니다.
docker image build 커맨드는 Dockerfile에 정의된 빌드 단계 수와 상관없이 단일 이미지를 생성합니다. 그러나 빌드 커맨드의 --target 옵션을 사용하면 빌드할 단계를 선택할 수 있습니다. Dockerfile에 여러 빌드 단계를 정의할 경우, 빌드하려는 이미지를 명시적으로 지정하는 것이 가장 좋습니다. 디버그 이미지를 빌드하려면 docker build를 실행하고 app-image-debug 단계를 대상으로 지정하세요.
$ docker image build -t dockerinaction/ch10:multi-stage-runtime-debug \
> -f multi-stage-runtime.df \
> --target=app-image-debug .
빌드 프로세스는 디버그 이미지를 생성하기 위해 app-image-debug 단계와 그에 의존하는 app-image 단계를 실행합니다.
Dockerfile에서 여러 단계를 정의하고 빌드 타겟을 지정하지 않은 상태로 이미지를 빌드하면, Docker는 Dockerfile에서 마지막으로 정의된 단계에서 이미지를 빌드합니다.
Dockerfile의 메인 빌드 단계에서 이미지를 빌드하려면, Dockerfile의 마지막에 간단한 빌드 단계를 추가하면 됩니다:
# Ensure app-image is the default image built with this Dockerfile
FROM app-image as default
이 FROM 문은 app-image를 기반으로 하는 default라는 새로운 빌드 단계를 정의합니다.
default 단계는 app-image에서 생성된 마지막 레이어에 아무것도 추가하지 않으므로, app-image와 동일합니다.
이제 이미지를 생성하거나 밀접하게 관련된 이미지 패밀리를 생성하는 여러 패턴을 살펴보았으니, 배포와 운영 프로세스를 용이하게 하기 위해 이미지와 함께 캡처해야 할 메타데이터에 대해 논의해보겠습니다.
10.3 Record metadata at image build time
8장에서 설명된 바와 같이, 이미지는 LABEL 커맨드를 통해 컨슈머와 운영자에게 유용한 메타데이터로 주석을 달 수 있습니다. 이미지에 다음 데이터를 최소한 포함하도록 라벨을 사용하는 것이 좋습니다:
- 애플리케이션 이름
- 애플리케이션 버전
- 빌드 날짜와 시간
- 버전 관리 시스템 커밋 식별자
이미지 라벨 외에도, 이미지를 빌드하는 데 사용된 Dockerfile과 소프트웨어 패키지 매니페스트를 이미지 파일 시스템에 추가하는 것을 고려하십시오.
이 모든 정보는 배포를 오케스트레이션하고 문제를 디버깅할 때 매우 유용합니다. 오케스트레이터는 메타데이터를 감사 로그에 기록하여 추적 가능성을 제공할 수 있습니다. 배포 도구는 빌드 시간이나 버전 관리 시스템(VCS) 커밋 식별자를 사용하여 서비스 배포의 구성을 시각화할 수 있습니다. 이미지 소스 Dockerfile을 포함하면 컨테이너 내부에서 문제를 디버깅하는 사람들이 빠르게 참조할 수 있습니다. 오케스트레이터와 보안 도구는 이미지의 아키텍처적 역할이나 보안 프로파일을 설명하는 다른 메타데이터를 사용하여 컨테이너의 실행 위치나 권한을 결정하는 데 유용할 수 있습니다.
Docker 커뮤니티의 Label Schema 프로젝트는 http://label-schema.org/에서 일반적으로 사용되는 라벨을 정의했습니다. 라벨 스키마와 Dockerfile에서 빌드 아규먼트를 사용하여 권장 메타데이터를 표현하는 방식은 다음과 같습니다.
FROM openjdk:11-jdk-slim
ARG BUILD_ID=unknown
ARG BUILD_DATE=unknown
ARG VCS_REF=unknown
LABEL org.label-schema.version="${BUILD_ID}" \
org.label-schema.build-date="${BUILD_DATE}" \
org.label-schema.vcs-ref="${VCS_REF}" \
org.label-schema.name="ch10" \
org.label-schema.schema-version="1.0rc1"
COPY multi-stage-runtime.df /Dockerfile
COPY target/ch10-0.1.0.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
우리의 빌드 프로세스는 메타데이터 수집, 애플리케이션 아티팩트 빌드, 이미지 빌드와 같은 단계가 추가되면서 더 복잡해졌습니다. 이제 오랜 시간 검증된 빌드 도구인 make를 사용해 빌드 프로세스를 오케스트레이션해 봅시다.
10.3.1 Orchestrating the build with make
make는 프로그램을 빌드하는 데 널리 사용되는 도구로, 빌드 프로세스의 각 단계 간의 종속성을 이해합니다. 빌드 프로세스 작성자는 각 단계를 Makefile에 기술하며, make는 이를 해석하고 실행하여 빌드를 완료합니다. make는 유연한 쉘과 같은 실행 환경을 제공하므로 거의 모든 종류의 빌드 단계를 구현할 수 있습니다.
make가 표준 쉘 스크립트보다 가지는 주요 이점은 사용자가 단계 간의 제어 흐름을 직접 구현하는 대신, 단계 간의 종속성을 선언한다는 점입니다. 이러한 단계는 rule이라고 하며, 각 rule은 target 이름으로 식별됩니다. 다음은 make 규칙의 일반적인 형식입니다:
(1)target . . . : prerequisites . . . (2)
recipe command 1 (3)
recipe command 2
. . .
(1) target은 rule을 식별하는 논리적 이름 또는 해당 rule에 의해 생성된 파일 이름을 나타냅니다.
(2) prerequisites(전제조건)은 이 target을 빌드하기 전에 빌드해야 할 target들의 선택적 목록입니다.
(3) recipe 섹션은 target을 빌드하는 데 사용되는 커맨드 목록을 포함합니다.
make 커맨드를 실행하면, 각 rule에 선언된 prerequisites으로부터 의존성 그래프를 생성합니다. 이 커맨드는 해당 그래프를 사용하여 지정된 target을 빌드하기 위한 단계 순서를 계산합니다. make에는 여기서 다루지 않는 여러 기능과 특이점이 있지만, 더 자세한 내용은 GNU Make 매뉴얼에서 확인할 수 있습니다.
특히 주의할 점은 make가 공백 문자에 민감하다는 점입니다. 특히 들여쓰기에서 사용하는 탭(tab)과 변수 선언 시의 공백(space)에 매우 민감합니다.
직접 입력하는 대신 이 장의 소스 리포지토리에 제공된 Makefile을 사용하는 것이 가장 쉬울 것입니다. make의 기초를 익혔으니, 이제 Docker 이미지를 빌드하는 작업으로 돌아갑시다.
Windows에서 빌드하기
Windows를 사용 중이라면, 이 예제에서 사용된 make와 기타 여러 명령어들이 환경에서 사용할 수 없을 가능성이 높습니다. 가장 간단한 해결책은 로컬 또는 클라우드에서 Linux 가상 머신을 사용하는 것입니다.
Docker를 사용하여 Windows에서 소프트웨어를 개발할 계획이라면, Windows Subsystem for Linux(WSL 또는 WSL2)와 Docker for Windows를 사용하는 것도 고려해야 합니다.
다음은 메타데이터를 수집한 후 애플리케이션 아티팩트와 이미지를 빌드, 테스트, 태그하는 작업을 수행하는 Makefile입니다:
# if BUILD_ID is unset, compute metadata that will be used in builds
ifeq ($(strip $(BUILD_ID)),)
VCS_REF := $(shell git rev-parse --short HEAD)
BUILD_TIME_EPOCH := $(shell date +"%s")
BUILD_TIME_RFC_3339 := \
$(shell date -u -r $(BUILD_TIME_EPOCH) '+%Y-%m-%dT%I:%M:%SZ')
BUILD_TIME_UTC := \
$(shell date -u -r $(BUILD_TIME_EPOCH) +'%Y%m%d-%H%M%S')
BUILD_ID := $(BUILD_TIME_UTC)-$(VCS_REF)
endif
ifeq ($(strip $(TAG)),)
TAG := unknown
endif
.PHONY: clean
clean:
@echo "Cleaning"
rm -rf target
.PHONY: metadata
metadata:
@echo "Gathering Metadata"
@echo BUILD_TIME_EPOCH IS $(BUILD_TIME_EPOCH)
@echo BUILD_TIME_RFC_3339 IS $(BUILD_TIME_RFC_3339)
@echo BUILD_TIME_UTC IS $(BUILD_TIME_UTC)
@echo BUILD_ID IS $(BUILD_ID)
target/ch10-0.1.0.jar:
@echo "Building App Artifacts"
docker run -it --rm -v "$(shell pwd)":/project/ -w /project/ \
maven:3.6-jdk-11 \
mvn clean verify
.PHONY: app-artifacts
app-artifacts: target/ch10-0.1.0.jar
.PHONY: lint-dockerfile
lint-dockerfile:
@set -e
@echo "Linting Dockerfile"
docker container run --rm -i hadolint/hadolint:v1.15.0 < \
multi-stage-runtime.df
.PHONY: app-image
app-image: app-artifacts metadata lint-dockerfile
@echo "Building App Image"
docker image build -t dockerinaction/ch10:$(BUILD_ID) \
-f multi-stage-runtime.df \
--build-arg BUILD_ID='$(BUILD_ID)' \
--build-arg BUILD_DATE='$(BUILD_TIME_RFC_3339)' \
--build-arg VCS_REF='$(VCS_REF)' \
.
@echo "Built App Image. BUILD_ID: $(BUILD_ID)"
.PHONY: app-image-debug
app-image-debug: app-image
@echo "Building Debug App Image"
docker image build -t dockerinaction/ch10:$(BUILD_ID)-debug \
-f multi-stage-runtime.df \
--target=app-image-debug \
--build-arg BUILD_ID='$(BUILD_ID)' \
--build-arg BUILD_DATE='$(BUILD_TIME_RFC_3339)' \
--build-arg VCS_REF='$(VCS_REF)' \
.
@echo "Built Debug App Image. BUILD_ID: $(BUILD_ID)"
.PHONY: image-tests
image-tests:
@echo "Testing image structure"
docker container run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(shell pwd)/structure-tests.yaml:/structure-tests.yaml \
gcr.io/gcp-runtimes/container-structure-test:v1.6.0 test \
--image dockerinaction/ch10:$(BUILD_ID) \
--config /structure-tests.yaml
.PHONY: inspect-image-labels
inspect-image-labels:
docker image inspect --format '{{ json .Config.Labels }}' \
dockerinaction/ch10:$(BUILD_ID) | jq
.PHONY: tag
tag:
@echo "Tagging Image"
docker image tag dockerinaction/ch10:$(BUILD_ID)\
dockerinaction/ch10:$(TAG)
.PHONY: all
all: app-artifacts app-image image-tests
이 Makefile은 논의된 각 빌드 단계(메타데이터 수집, 애플리케이션 빌드, 이미지 빌드 및 테스트, 태깅)를 위한 target을 정의합니다. app-image와 같은 target은 다른 target에 의존성을 가지므로, 단계가 올바른 순서로 실행되도록 보장합니다. 빌드 메타데이터는 모든 단계에 필수적이므로, BUILD_ID가 제공되지 않으면 자동으로 생성됩니다.
이 Makefile은 로컬에서 실행하거나, 지속적 통합(CI) 또는 지속적 배포(CD) 시스템 내에서 사용할 수 있는 이미지 파이프라인을 구현합니다. 애플리케이션 아티팩트와 이미지를 빌드하려면 app-image target을 실행하면 됩니다.
make app-image
애플리케이션 아티팩트를 생성하는 과정에서는 의존성이 검색되고 코드가 컴파일되면서 많은 출력이 발생할 것입니다. 그러나 애플리케이션 빌드가 성공하면 아래와 같은 메시지가 출력되어 성공 여부를 나타냅니다:
[INFO] ------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------
그 직후, "메타데이터 수집(Gathering Metadata)" 메시지가 출력되며, 이어서 이번 빌드에 대한 메타데이터가 표시됩니다:
BUILD_TIME_EPOCH IS 1562106748
BUILD_TIME_RFC_3339 IS 2019-07-02T10:32:28Z
BUILD_TIME_UTC IS 20190702-223228
BUILD_ID IS 20190702-223228-ade3d65
빌드 프로세스의 다음 단계는 이미지에 대한 첫 번째 품질 보증(QA) 단계입니다. 아래와 같은 메시지가 출력될 것입니다:
Linting Dockerfile
docker container run --rm -i hadolint/hadolint:v1.15.0 < multi-stage
runtime . df
이미지를 빌드하기 전에 Dockerfile은 hadolint라는 린팅 도구에 의해 분석됩니다.
hadolint는 Dockerfile이 모범 사례를 따르고 일반적인 실수를 식별하도록 검사합니다.
다른 품질 보증(QA) 관행과 마찬가지로, 린터가 문제를 보고할 경우 이미지 빌드 파이프라인을 중단하도록 선택할 수 있습니다.
hadolint는 Dockerfile을 추상 구문 트리(Abstract Syntax Tree)로 분석하므로, 정규 표현식을 기반으로 한 접근법보다 더 깊고 복잡한 분석을 수행할 수 있습니다.
이 도구는 다음과 같은 문제를 식별합니다:
- 잘못 지정되거나 사용 중단된 Dockerfile 명령.
- FROM 커맨드에서 태그를 생략한 경우.
- apt, apk, pip, npm과 같은 패키지 관리자를 사용할 때의 일반적인 실수.
- RUN 커맨드에서 지정된 기타 커맨드의 문제.
Dockerfile 린팅이 완료되면 app-image 타겟이 실행되어 애플리케이션 이미지를 빌드합니다.
docker image build 커맨드는 성공 시 다음과 비슷한 출력으로 성공을 알립니다:
Successfully built 79b61fb87b96
Successfully tagged dockerinaction/ch10:20190702-223619-ade3d65
Built App Image. BUILD_ID: 20190702-223619-ade3d65
이 빌드 프로세스에서는 각 애플리케이션 이미지가 빌드 시점의 시간과 현재 Git 커밋 해시를 기반으로 계산된 BUILD_ID로 태그됩니다.
이 경우, 새로운 Docker 이미지는 리포지토리 이름과 BUILD_ID(예: 20190702-223619-ade3d65)로 태그됩니다.
태그 20190702-223619-ade3d65는 이제 dockerinaction/ch10 이미지 리포지토리에서 Docker 이미지 ID 79b61fb87b96을 식별합니다.
이러한 스타일의 BUILD_ID는 빌드 시점의 정확한 시간(wall clock time)과 버전 기록(version history)을 높은 정밀도로 식별할 수 있도록 합니다.
이미지 빌드 시간을 기록하는 것은 중요한 관행입니다. 사람들은 시간에 익숙하며, 많은 이미지 빌드 과정에서 소프트웨어 패키지 관리자 업데이트 또는 빌드마다 결과가 달라질 수 있는 작업을 수행하기 때문입니다.
또한 버전 제어 ID(예: 7c5fd3d)를 포함하면, 이미지를 빌드하는 데 사용된 원본 자료로 쉽게 돌아갈 수 있는 편리한 참조 포인터를 제공합니다.
이후 단계에서는 BUILD_ID를 활용하게 됩니다.
BUILD_ID를 터미널에서 쉽게 사용할 수 있도록 하려면 app-image 빌드 단계 출력의 마지막 줄에서 복사하여 셸에 변수로 export하는 것이 좋습니다.
export BUILD_ID=20190702-223619-ade3d65
이미지에 추가된 메타데이터는 다음 커맨드를 통해 라벨을 검사하여 확인할 수 있습니다:
make inspect-image-labels BUILD_ID=20190702-223619-ade3d65
또는, BUILD_ID 태그를 export한 경우에는 다음 커맨드를 사용할 수 있습니다:
make inspect-image-labels BUILD_ID=$BUILD_ID
이 커맨드는 docker image inspect를 사용하여 이미지의 라벨을 표시합니다:
{
"org.label-schema.build-date": "2019-07-02T10:36:19Z",
"org.label-schema.name": "ch10",
"org.label-schema.schema-version": "1.0rc1",
"org.label-schema.vcs-ref": "ade3d65",
"org.label-schema.version": "20190702-223619-ade3d65"
}
이미지는 고유한 BUILD_ID 태그를 가지고 있으며, 이는 이후의 전달 프로세스에서도 이미지를 편리하게 식별할 수 있게 해줍니다.
다음 섹션에서는 이미지가 올바르게 생성되었고 배포 준비가 되었는지 확인하기 위한 테스트 방법을 살펴보겠습니다.
이미지 퍼블리셔는 빌드 파이프라인에서 생성된 아티팩트에 대한 신뢰를 구축하기 위해 여러 기법을 사용할 수 있습니다.
이전 섹션에서 설명한 Dockerfile 린팅 단계는 품질 보증의 한 기법에 해당하지만, 여기서 더 나아갈 수 있습니다.
Docker 이미지 형식의 주요 장점 중 하나는 이미지 메타데이터와 파일 시스템을 도구로 쉽게 분석할 수 있다는 점입니다.
예를 들어, 이미지를 테스트하여 애플리케이션에 필요한 파일이 포함되어 있는지, 해당 파일이 적절한 권한을 가지고 있는지, 그리고 주요 프로그램을 실행하여 올바르게 작동하는지 확인할 수 있습니다.
Docker 이미지를 검사하여 추적 가능성 및 배포 메타데이터가 추가되었는지 확인할 수도 있습니다.
보안에 민감한 사용자는 이미지를 스캔하여 취약점을 탐지할 수 있습니다.
퍼블리셔는 이러한 단계 중 하나라도 실패하면 이미지 전달 프로세스를 중단할 수 있으며, 이러한 단계를 통해 퍼블리시된 이미지의 품질을 크게 향상시킬 수 있습니다.
Docker 이미지의 구성 검증을 위해 널리 사용되는 도구 중 하나는 Google의 Container Structure Test (CST) 도구입니다.
CST는 이미지(또는 이미지 tarball)가 다음 조건을 충족하는지 확인할 수 있습니다:
- 원하는 파일 권한과 소유권을 가진 파일이 포함되어 있는지.
- 명령어가 예상된 출력으로 실행되는지.
- 특정 메타데이터(예: 라벨 또는 명령)가 포함되어 있는지.
이러한 검사 중 많은 부분은 Chef Inspec 또는 Serverspec 같은 전통적인 시스템 구성 검사 도구로도 수행할 수 있습니다.
그러나 CST는 이미지 내부에 별도의 도구나 라이브러리를 포함하지 않아도 동작하며, 임의의 이미지를 대상으로 작동하므로 컨테이너 환경에 더 적합한 접근 방식을 제공합니다.
이제 다음 설정을 사용하여 CST를 실행함으로써 애플리케이션 아티팩트가 올바른 권한을 가지고 있는지, 그리고 Java의 올바른 버전이 설치되어 있는지 검증해 보겠습니다.
schemaVersion: "2.0.0"
# Verify the expected version of Java is available and executable
commandTests:
- name: "java version"
command: "java"
args: ["-version"]
exitCode: 0
# OpenJDK java -version stderr will include a line like:
# OpenJDK Runtime Environment 18.9 (build 11.0.3+7)
expectedError: ["OpenJDK Runtime Environment.*build 11\\..*"]
# Verify the application archive is readable and owned by root
fileExistenceTests:
- name: 'application archive'
path: '/app.jar'
shouldExist: true
permissions: '-rw-r--r--'
uid: 0
gid: 0
먼저, 이 구성은 CST가 Java를 호출하여 버전 정보를 출력하도록 지시합니다.
OpenJDK Java 런타임은 버전 정보를 stderr에 출력하므로, CST는 해당 문자열을 OpenJDK Runtime Environment.*build 11\..* 정규식과 비교하도록 설정됩니다.
애플리케이션이 특정 Java 버전에서 실행되도록 보장해야 하는 경우, 정규식을 더 구체적으로 작성하고 기본 이미지를 해당 버전에 맞게 업데이트할 수 있습니다.
둘째, CST는 애플리케이션 아카이브가 /app.jar 경로에 있으며, 소유자가 root이고, 모든 사용자가 읽을 수 있는지 확인합니다.
파일 소유권과 권한을 검증하는 작업은 기본적으로 보일 수 있지만, 프로그램이 실행되지 않거나 읽을 수 없거나 실행 가능 경로(PATH)에 없어서 발생하는 "보이지 않는" 버그를 방지하는 데 도움을 줍니다.
이전에 빌드한 이미지에 대해 다음 커맨드를 실행하여 이미지 테스트를 수행하십시오:
make image-tests BUILD_ID=$BUILD_ID
이 커맨드는 성공적인 결과를 출력해야 합니다:
Testing image structure
docker container run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /Users/dia/structure-tests.yaml:/structure-tests.yaml \
gcr.io/gcp-runtimes/container-structure-test:v1.6.0 test \
--image dockerinaction/ch10:20181230-181226-61ceb6d \
--config /structure-tests.yaml
=============================================
====== Test file: structure-tests.yaml ======
=============================================
INFO: stderr: openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment 18.9 (build 11.0.3+7)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.3+7, mixed mode)
=== RUN: Command Test: java version
--- PASS
stderr: openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment 18.9 (build 11.0.3+7)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.3+7, mixed mode)
INFO: File Existence Test: application archive
=== RUN: File Existence Test: application archive
--- PASS
=============================================
================== RESULTS ==================
=============================================
Passes: 2
Failures: 0
Total tests: 2
PASS
많은 이미지 작성자는 이미지를 게시하기 전에 취약점 스캔을 수행하고, 중요한 취약점이 발견되면 전달 프로세스를 중단하기를 원합니다.
여기서는 이러한 시스템이 어떻게 작동하며, 일반적으로 이미지 빌드 파이프라인에 어떻게 통합되는지 간단히 개요를 제공합니다.
상업 및 커뮤니티 소스에서 사용할 수 있는 여러 이미지 취약점 스캐닝 솔루션이 있습니다.
이미지 취약점 스캐닝의 일반적인 작동 방식
- 경량 스캐닝 클라이언트:
- 이미지 빌드 파이프라인에서 실행되는 경량 클라이언트 프로그램에 의존.
- 스캔 방식:
- 이미지의 콘텐츠를 검사하고, 소프트웨어 패키지 메타데이터 및 파일 시스템 내용을 취약점 데이터와 비교.
- 취약점 데이터 소스:
- 중앙화된 취약점 데이터베이스 또는 API에서 데이터를 가져와 비교.
제한 사항
- 대부분의 스캐닝 시스템은 서비스를 사용하려면 공급업체에 등록해야 합니다.
- 이로 인해 이번 이미지 빌드 워크플로우에는 특정 도구를 통합하지는 않습니다.
추가 가능성
- 스캐닝 도구를 선택한 후, 빌드 프로세스에 또 다른 타겟을 추가하여 쉽게 통합할 수 있습니다.
10.5 Patterns for tagging images
이미지가 테스트를 거쳐 다음 배포 단계에서 배포 준비가 완료되었다고 판단되면,
사용자가 이미지를 쉽게 찾고 사용할 수 있도록 태그를 추가해야 합니다.
이미지 태그를 지정하는 여러 방식이 존재하며, 일부는 특정 소비 패턴에 더 적합합니다.
가장 중요한 이미지 태그 지정의 특징은 다음과 같습니다:
- 태그는 특정 콘텐츠 기반 주소의 이미지 ID를 가리키는 사람이 읽을 수 있는 문자열입니다.
- 하나의 이미지 ID에 여러 태그를 지정할 수 있습니다.
- 태그는 변경 가능하며, 리포지토리 내에서 다른 이미지로 이동하거나 완전히 제거될 수 있습니다.
이러한 모든 기능을 활용하여 조직에 적합한 태그 지정 방식을 구성할 수 있지만,
단일 방식만 존재하거나 정해진 하나의 방법만 있는 것은 아닙니다.
특정 태그 지정 방식은 특정 소비 패턴에 적합하지만, 다른 패턴에는 적합하지 않을 수 있습니다.
10.5.1 Background
Docker 이미지 태그는 변경 가능(mutability)합니다.
이미지 리포지토리 소유자는 태그를 특정 이미지 ID에서 제거하거나, 다른 ID로 이동할 수 있습니다.
이미지 태그 변경은 보통 시리즈 내에서 가장 최신 이미지를 식별하는 데 사용됩니다.
Docker 커뮤니티에서는 latest 태그를 이미지 리포지토리의 가장 최신 빌드를 식별하는 데 광범위하게 사용합니다.
그러나 latest 태그는 무엇을 의미하는지에 대해 명확한 합의가 없어 많은 혼란을 초래합니다.
리포지토리나 조직에 따라, 다음과 같은 대답이 모두 latest 태그의 의미로 유효할 수 있습니다:
- CI 시스템에서 빌드된, 소스 컨트롤 브랜치와 상관없는 가장 최근의 이미지.
- CI 시스템에서 빌드된, 메인 release 브랜치의 가장 최근 이미지.
- stable release 브랜치에서 빌드되고, 모든 작성자의 테스트를 통과한 가장 최근 이미지.
- active 개발 브랜치에서 빌드되고, 모든 작성자의 테스트를 통과한 가장 최근 이미지.
- Nothing! 작성자가 latest 태그가 지정된 이미지를 푸시하지 않았거나 최근에 푸시하지 않은 경우.
latest를 정의하려고 시도하는 것만으로도 많은 질문을 유발할 수 있습니다.
이미지 릴리스 태그 지정 방식을 채택할 때, 해당 태그가 무엇을 의미하는지, 의미하지 않는지를 명확히 지정해야 합니다.
또한 태그가 변경 가능하기 때문에, 컨슈머가 이미 머신에 존재하는 태그에 대한 업데이트를 받을 때 이미지를 다시 풀(Pull) 해야 하는지, 그리고 그 시점을 결정해야 합니다.
일반적인 태그 및 배포 방식
- 고유 태그를 사용한 지속적 배포 (Continuous delivery with unique tags)
- 파이프라인이 고유한 태그를 가진 단일 이미지를 배포 단계로 전달(promote)합니다.
- 환경별 아티팩트를 사용한 지속적 배포 (Continuous delivery with environment-specific artifacts)
- 파이프라인이 환경별 아티팩트를 생성하고, 이를 개발, 스테이징, 프로덕션 환경으로 전달합니다.
- 시맨틱 버저닝 (Semantic versioning)
- 이미지에 Major.Minor.Patch 방식으로 태그를 지정하여 릴리스에서 변경 수준을 나타내고 게시합니다.
(예: v1.2.3, v2.0.0)
- 이미지에 Major.Minor.Patch 방식으로 태그를 지정하여 릴리스에서 변경 수준을 나타내고 게시합니다.
10.5.2 Continuous delivery with unique tags
고유 태그(Unique Tags) 방식은 애플리케이션의 지속적 배포(Continuous Delivery)를 지원하는 일반적이고 간단한 방법으로, 그림 10.5에 설명되어 있습니다.
이 방식에서는 이미지가 고유한 BUILD_ID 태그를 사용하여 빌드되고 특정 환경에 배포됩니다.
사람이나 자동화된 시스템이 해당 애플리케이션 버전이 다음 환경으로 promote될 준비가 되었다고 판단하면,
고유 태그를 사용하여 그 환경에 배포를 실행합니다.
![](https://blog.kakaocdn.net/dn/bGd2zo/btsKZBVGSIO/PMlQRH6eLu39GhLqTcqT7k/img.png)
이 방식은 구현이 간단하며, 브랜칭 없이 선형 릴리스 모델(linear release model)을 사용하는 애플리케이션의 지속적 배포(Continuous Delivery)를 지원합니다.
그러나 이 방식의 주요 단점은 사람들이 latest나 dev 태그를 사용할 수 없는 대신, 정확한 빌드 식별자(precise build identifiers)를 다뤄야 한다는 점입니다.
이미지에는 여러 번 태그를 지정할 수 있기 때문에, 대부분 팀은 가장 최근의 이미지를 쉽게 소비할 수 있도록 latest와 같은 추가 태그를 적용하고 게시합니다.
10.5.3 Configuration image per deployment stage
일부 조직은 소프트웨어 릴리스를 배포 단계별로 구분된 아티팩트로 패키징합니다.
이러한 패키지는 통합 테스트를 위해 내부 전용 환경(예: dev, stage)에 배포됩니다.
소프트웨어가 내부 환경에서 테스트를 완료하면, 프로덕션 패키지가 프로덕션 환경에 배포됩니다.
각 환경에 대해 별도의 Docker 이미지를 생성할 수도 있습니다.
이 경우, 각 이미지는 애플리케이션 아티팩트와 환경별 구성(configuration)을 포함하게 됩니다.
그러나 이는 안티패턴(antipattern)으로 간주됩니다.
이 방식에서는 주요 배포 아티팩트가 여러 번 빌드되며, 보통 프로덕션 이전 단계에서 충분히 테스트되지 않습니다.
더 나은 방식
여러 환경에 배포를 지원하는 더 나은 방법은 두 가지 종류의 이미지를 생성하는 것입니다:
- 일반적이고 환경과 무관한 애플리케이션 이미지
- 특정 환경에 종속되지 않은 애플리케이션 아티팩트를 포함.
- 환경별 구성 이미지
- 각 환경에 대한 구성 파일을 포함하는 이미지 세트.
(예: dev, stage, prod 환경 각각에 대해 별도 이미지 생성).
- 각 환경에 대한 구성 파일을 포함하는 이미지 세트.
![](https://blog.kakaocdn.net/dn/cijUE4/btsKYBIPltg/xjTADWbTUcQgZcTU51XyfK/img.png)
일반적인 애플리케이션 이미지와 환경별 구성 이미지는 동시에 빌드되고 동일한 BUILD_ID로 태그 지정되어야 합니다.
배포 프로세스는 지속적 배포(Continuous Delivery) 사례에서 설명한 대로, BUILD_ID를 사용하여 배포할 소프트웨어와 구성을 식별합니다.
배포 시 두 개의 컨테이너가 생성됩니다:
- 먼저, 환경별 구성 이미지로부터 **구성 컨테이너(configuration container)**가 생성됩니다.
- 이후, 일반 애플리케이션 이미지로부터 **애플리케이션 컨테이너(application container)**가 생성되며, 이 컨테이너는 구성 컨테이너의 파일 시스템을 **볼륨(volume)**으로 마운트합니다.
구성 컨테이너의 파일 시스템에서 환경별 파일을 사용하는 것은 애플리케이션 오케스트레이션 패턴으로 널리 사용되며, 12-factor 애플리케이션 원칙의 변형 중 하나입니다.
(참고: 12-factor.net)
12장에서, Docker가 환경별 구성을 보조 이미지 없이 오케스트레이션의 first-class 기능으로 지원하는 방법을 살펴볼 것입니다.
이 접근법은 소프트웨어 작성자와 운영자가 환경별 변화를 지원하면서도,
- 원본 소스에 대한 추적 가능성(traceability)을 유지하고,
- 단순한 배포 워크플로우를 보존할 수 있도록 해줍니다.
10.5.4 Semantic versioning
Major.Minor.Patch 형식의 버전 번호를 사용하여 아티팩트를 versioning하는 데 널리 사용되는 방식입니다.
시맨틱 버저닝 사양은 소프트웨어 변경 사항에 따라 다음을 증가시켜야 한다고 정의합니다:
- Major 버전: 호환되지 않는 API 변경을 할 때 증가.
- Minor 버전: 이전 버전과 호환되는 방식으로 기능을 추가할 때 증가.
- Patch 버전: 이전 버전과 호환되는 버그 수정을 할 때 증가.
시맨틱 버저닝은 이미지 의존성을 업데이트할 때,
소비자가 어떤 종류의 변경 사항을 예상할 수 있는지 관리하는 데 도움을 줍니다.
이미지를 다수의 소비자에게 배포하거나, 오랜 기간 동안 여러 릴리스 스트림을 유지해야 하는 작성자는
시맨틱 버저닝 또는 유사한 방식을 선호하는 경우가 많습니다.
시맨틱 버저닝은 많은 사람이 의존하는 기본 운영 체제, 언어 런타임, 또는 데이터베이스와 같은 이미지를 위한 좋은 선택입니다.
![](https://blog.kakaocdn.net/dn/XiZAx/btsKZPsAAJ0/pi6TchXG0Vx56bfWzJIepk/img.png)
이미지를 dev와 stage 환경에서 테스트한 후,
최근 빌드된 예제 애플리케이션을 고객에게 version 1.0.0으로 릴리스하려고 한다고 가정해봅시다.
이 경우, BUILD_ID를 사용하여 이미지를 식별하고 1.0.0 태그로 태깅할 수 있습니다:
make tag BUILD_ID=$BUILD_ID TAG=1.0.0
이미지를 버전 1.0.0으로 태깅하면, 소프트웨어의 운영에서 하위 호환성을 유지할 준비가 되었음을 알리는 신호가 됩니다.
이미지를 태깅한 후에는 이를 레지스트리(registry)에 푸시하여 배포할 수 있습니다.
또한, 여러 레지스트리에 게시하는 것을 선택할 수도 있습니다.
- 내부 사용을 목적으로 한 이미지를 private으로 유지하려면 내부용 레지스트리에 게시하고,
- 공식 릴리스만 고객 소비를 위해 public 레지스트리에 게시할 수 있습니다.
어떤 방식으로 이미지를 promote할지 결정하더라도, 프로모트 파이프라인은 시맨틱 태그(latest, dev, 7)를
고유한 태그 또는 콘텐츠 기반 식별자(content-addressable identifier)로 변환하여 해당 이미지를 배포해야 합니다.
이 방식은 프로모트 중에 태그가 다른 이미지로 이동되는 경우에도, 프로모트하기로 결정된 이미지를 배포하도록 보장합니다.
이는 단순히 배포 시점에 태그와 연결된 이미지가 아닌, 처음 결정된 고유 이미지를 정확히 배포할 수 있도록 합니다.
Summary
이 장에서는 Docker 이미지를 빌드하고 게시할 때 사용하는 공통 목표, 패턴, 기법을 다뤘습니다.
이 장에서 설명된 옵션들은 이미지 전달 프로세스를 만들 때 사용할 수 있는 다양한 선택지를 보여줍니다.
이를 기반으로 여러분은 애플리케이션을 Docker 이미지로 전달하기 위해 적합한 옵션을 탐색하고, 선택하며, 맞춤화할 수 있을 것입니다.
이 장의 핵심 포인트는 다음과 같습니다:
- 이미지 빌드 파이프라인은 다른 소프트웨어 및 인프라 빌드 파이프라인과 마찬가지로 Docker 이미지의 품질을 보장하기 위한 구조와 목표를 가지고 있습니다.
- 버그, 보안 문제, 이미지 구성 문제를 감지하는 도구가 존재하며, 이를 이미지 빌드 파이프라인에 쉽게 통합할 수 있습니다.
- make와 같은 빌드 도구를 사용하여 이미지 빌드 프로세스를 코드화하고, 이 프로세스를 로컬 개발 및 CI/CD 과정에 통합하세요.
- Docker 이미지 정의를 구성하는 여러 패턴이 존재합니다.
이러한 패턴은 애플리케이션 빌드 및 배포 문제(예: 공격 표면, 이미지 크기, 복잡도 등)에서 각각의 장단점을 제공합니다. - 이미지의 소스 및 빌드 과정에 대한 정보는 이미지 메타데이터로 기록하여,
배포 시 추적, 디버깅, 오케스트레이션 활동을 지원할 수 있어야 합니다. - Docker 이미지 태그는 소프트웨어를 컨슈머에게 전달하기 위한 기반을 제공합니다.
이는 private 서비스 배포에서의 지속적 전달(Continuous Delivery)부터,
시맨틱 버저닝을 통해 public 레지스트리에 오랜 기간 유지되는 릴리스를 게시하는 데까지 다양하게 활용될 수 있습니다.
'Docker' 카테고리의 다른 글
Docker Redis (0) | 2024.04.07 |
---|---|
11 Services with Docker and Compose (0) | 2024.04.07 |
9 Public and privatesoftware distribution (0) | 2024.04.07 |
8 Building images automatically with Dockerfiles (0) | 2024.04.04 |
7 Packaging software in images (0) | 2024.04.03 |