Dockerfile로 컨테이너 개발

1. 개요

Docker는 애플리케이션을 개발, 출시, 실행하는 데 사용하는 개방형 플랫폼입니다. Docker를 사용하면 인프라에서 애플리케이션을 분리하고 인프라를 관리형 애플리케이션처럼 취급할 수 있습니다. Docker는 코드를 더욱 빠르게 출시, 테스트, 배포하고 코드 작성과 실행 주기를 단축하는 데 도움이 됩니다.

이는 Docker가 커널 컨테이너화 기능을 애플리케이션 관리 및 배포를 지원하는 워크플로 및 도구와 결합하기 때문입니다.

Docker 컨테이너는 Kubernetes에서 직접 사용할 수 있으므로 Kubernetes Engine에서 쉽게 실행할 수 있습니다. Docker의 핵심 내용을 학습하면 Kubernetes 및 컨테이너 애플리케이션 개발을 시작하는 데 필요한 기술을 갖출 수 있습니다.

과정 내용

이 실습에서는 다음 작업을 진행하는 방법을 학습합니다.

  • 샘플 애플리케이션용 Dockerfile 만들기
  • 이미지 빌드
  • 이미지를 로컬에서 컨테이너로 실행
  • 컨테이너 동작 변경
  • 이미지를 Artifact Registry로 내보내기

기본 요건

이 실습은 입문용입니다. Docker 및 컨테이너 사용 경험이 거의 없거나 전혀 없는 사용자를 대상으로 합니다. Cloud Shell 및 명령줄을 잘 안다면 좋지만 필수 사항은 아닙니다.

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
  • 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유해야 하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud Console은 고유한 문자열을 자동으로 생성합니다. 일반적으로 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID를 참조해야 하며(일반적으로 PROJECT_ID로 식별됨), 마음에 들지 않는 경우 임의로 다시 생성하거나 직접 지정해서 사용할 수 있는지 확인하세요. 프로젝트가 생성되면 프로젝트 ID가 '고정'됩니다.
  • 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참조하세요.
  1. 다음으로 Cloud 리소스/API를 사용하려면 Cloud Console에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼을 마친 후 비용이 결제되지 않도록 리소스를 종료하려면 Codelab의 끝에 있는 '삭제' 안내를 따르세요. Google Cloud 새 사용자에게는 미화 $300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

2. 샘플 애플리케이션

이 실습을 용이하게 하기 위해 샘플 애플리케이션이 제공되었습니다. 이 섹션에서는 소스 코드를 검색하고 기본 형식으로 애플리케이션을 빌드한 후 컨테이너화 프로세스를 진행합니다.

소스 코드

이 실습의 소스 코드는 GoogleCloudPlatform/container-developer-workshop 저장소에서 샘플 애플리케이션 문서와 함께 제공됩니다.

git 구성

git config --global user.name ${USER}
git config --global user.email ${USER}@qwiklabs.net

샘플 애플리케이션 Cloud Source Repository 클론

gcloud source repos clone sample-app ${HOME}/sample-app &&
cd ${HOME}/sample-app &&
git checkout main

출력

Cloning into '/home/student_03_49720296e995/sample-app'...
remote: Finding sources: 100% (16/16)
remote: Total 16 (delta 0), reused 16 (delta 0)
Receiving objects: 100% (16/16), 47.23 KiB | 681.00 KiB/s, done.
warning: remote HEAD refers to nonexistent ref, unable to checkout.

Project [qwiklabs-gcp-02-4327c4e03d82] repository [sample-app] was cloned to [/home/student_03_49720296e995/sample-app].
Branch 'main' set up to track remote branch 'main' from 'origin'.
Switched to a new branch 'main'

샘플 애플리케이션 빌드

cd ${HOME}/sample-app
./mvnw compile

출력

[INFO] Scanning for projects...
...
[INFO] Compiling 1 source file to /home/student_03_49720296e995/sample-app/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.080 s
[INFO] Finished at: 2022-02-23T17:14:30Z
[INFO] ------------------------------------------------------------------------

샘플 애플리케이션 실행

cd ${HOME}/sample-app
./mvnw exec:java

출력

[INFO] Scanning for projects...
...
Listening at http://localhost:8080

실행 중인 애플리케이션 미리보기

  • Cloud Shell 웹 미리보기 버튼을 클릭합니다.
  • 포트 8080에서 미리보기를 클릭합니다.

완료했으면 다음 단계를 따르세요.

  • Cloud Shell에서 Ctrl + C를 눌러 실행 중인 애플리케이션을 중지합니다.

3. Dockerfile

Dockerfile로 애플리케이션 컨테이너화

애플리케이션을 컨테이너에 패키징하는 한 가지 방법은 Dockerfile을 사용하는 것입니다. Dockerfile은 컨테이너 이미지를 조합하는 방법을 데몬에 지시하는 스크립트와 유사합니다. 자세한 내용은 Dockerfile 참조 문서를 확인하세요.

샘플 애플리케이션 저장소에서 빈 Dockerfile을 만듭니다.

touch ${HOME}/sample-app/Dockerfile

원하는 편집기에서 Dockerfile을 엽니다.

vi ${HOME}/sample-app/Dockerfile

시작 이미지 선택

Dockerfile 메서드를 사용하여 컨테이너를 빌드하려면 컨테이너를 조합하기 위해 애플리케이션에 대한 직접적인 지식이 필요합니다. Dockerfile을 만드는 첫 번째 단계는 이미지의 기반으로 사용할 이미지를 선택하는 것입니다.이 이미지는 신뢰할 수 있는 소스(주로 회사)에서 유지관리하고 게시하는 상위 또는 기본 이미지여야 합니다.

FROM 명령어는 새 빌드 단계를 초기화하고 후속 순차 명령어의 기본 이미지를 설정합니다. 따라서 FROM 명령어는 일반적으로 Dockerfile의 첫 번째 명령어이며 변수를 지원하는 선택적 ARG 명령어 앞에만 붙을 수 있습니다.

구문: FROM <image>[:<tag> | @<digest>] [AS <name>]

이미지 형식은 <image>:<tag> 또는 <image>@<digest>입니다. 태그 또는 다이제스트를 지정하지 않으면 기본적으로 :latest 태그가 사용됩니다. <image>의 형식은 이미지를 저장하는 데 사용되는 레지스트리에 따라 다릅니다. Artifact Registry의 경우 <image> 형식은 <region>-docker.pkg.dev/<project ID>/<repository name>/<image name>:<image tag>입니다.

이 실습에서는 공개 openjdk:11.0-jdk 이미지를 사용합니다. Dockerfile에 다음 줄을 추가합니다.

FROM openjdk:11.0-jdk

작업 디렉터리 설정

WORKDIR 명령어는 Dockerfile에서 따르는 모든 순차적 명령어의 작업 디렉터리를 설정합니다. 자세한 내용은 Dockerfile 참조 문서의 WORKDIR 섹션을 참조하세요.

구문: WORKDIR <path>

이 실습에서는 /app 디렉터리를 WORKDIR로 사용합니다. Dockerfile 하단에 다음 줄을 추가합니다.

WORKDIR /app

애플리케이션 파일 복사

COPY 명령어는 <source> 위치의 디렉터리나 파일을 이미지 파일 시스템의 <destination> 경로로 복사합니다. 여러 개의 <source> 리소스를 지정할 수 있으며 모두 빌드 컨텍스트를 기준으로 합니다. 빌드 컨텍스트는 빌드 섹션에서 자세히 설명합니다. 자세한 내용은 Dockerfile 참조 문서의 복사 섹션을 참조하세요.

구문: COPY <source>... <destination>

이 실습에서는 저장소에 있는 모든 파일을 이미지 파일 시스템에 복사하고 Dockerfile 하단에 다음 줄을 추가합니다.

COPY . /app

애플리케이션 컴파일

RUN 명령어는 현재 이미지 상단의 새 이미지 레이어에서 명령어를 실행하고 결과를 커밋합니다. 그 결과로 커밋된 이미지는 Dockerfile의 순차적 단계에 사용됩니다. 자세한 내용은 Dockerfile 참조 문서의 실행 섹션을 참조하세요.

구문: RUN <command>

이 실습에서는 Maven을 사용하여 애플리케이션을 JAR 파일로 컴파일하고 Dockerfile 하단에 다음 줄을 추가합니다.

RUN ./mvnw compile assembly:single

애플리케이션 시작

CMD 명령어는 실행 중인 컨테이너의 기본 명령어를 제공합니다. Dockerfile에는 CMD 명령어가 하나만 있을 수 있습니다. 두 개 이상의 CMD가 지정된 경우 마지막 CMD만 적용됩니다. CMD 및 ENTRYPOINT 명령을 모두 사용하여 사용할 수 있는 고급 기능이 있지만 이 실습에서는 다루지 않습니다. 자세한 내용은 Dockerfile 참조 문서의 CMD 섹션을 참조하세요.

구문: CMD ["executable","param1","param2"]

이 실습에서는 컴파일한 JAR 파일을 실행하고 Dockerfile 하단에 다음 줄을 추가합니다.

CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

최종 Dockerfile

최종 Dockerfile은

FROM openjdk:11.0-jdk
WORKDIR /app
COPY . /app
RUN ./mvnw compile assembly:single
CMD ["java","-jar","/app/target/sample-app-1.0.0-jar-with-dependencies.jar"]

Dockerfile을 로컬로 커밋

cd ${HOME}/sample-app
git add Dockerfile
git commit -m "Added Dockerfile"

4. 빌드

이제 docker build 명령어를 사용하여 Dockerfile에서 이미지를 빌드합니다. 이 명령어는 Dockerfile의 안내에 따라 Docker 데몬에 이미지를 빌드하도록 지시합니다. 자세한 내용은 docker 빌드 참조 문서를 확인하세요.

이미지 빌드

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker build --tag sample-app:${IMAGE_TAG} .

출력

Sending build context to Docker daemon  221.2kB
Step 1/4 : FROM openjdk:11.0-jdk
11.0-jdk: Pulling from library/openjdk
0c6b8ff8c37e: Pull complete
412caad352a3: Pull complete
e6d3e61f7a50: Pull complete
461bb1d8c517: Pull complete
e442ee9d8dd9: Pull complete
542c9fe4a7ba: Pull complete
41de18d1833d: Pull complete
Digest: sha256:d72b1b9e94e07278649d91c635e34737ae8f181c191b771bde6816f9bb4bd08a
Status: Downloaded newer image for openjdk:11.0-jdk
---> 2924126f1829
Step 2/4 : WORKDIR /app
---> Running in ea037abb273d
Removing intermediate container ea037abb273d
---> bd9b6d078082
Step 3/4 : COPY . /app
---> b9aec2b5de51
Step 4/4 : RUN ./mvnw compile jar:jar
---> Running in 3f5ff737b7fd
[INFO] Scanning for projects...
...
[INFO] Building jar: /app/target/sample-app-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  22.952 s
[INFO] Finished at: 2022-02-23T18:09:08Z
[INFO] ------------------------------------------------------------------------
Removing intermediate container 331443caebd3
---> 152f65cc441e
Step 5/5 : CMD ["java", "-jar", "/app/target/sample-app-1.0.0.jar"]
---> Running in 3d595a72231c
Removing intermediate container 3d595a72231c
---> 0e40d7548cab
Successfully built 0e40d7548cab
Successfully tagged sample-app:aaa8895

5. 실행

컨테이너 이미지를 성공적으로 빌드한 후 이제 애플리케이션을 실행하고 Docker run 명령어를 사용하여 예상대로 작동하는지 확인할 수 있게 되었습니다. 이 명령어는 테스트 또는 디버깅을 위해 명령 프롬프트의 전경에서 컨테이너를 실행합니다. 자세한 내용은 Docker 실행 참조 문서를 참조하세요.

이미지를 사용하여 컨테이너 실행

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG}

출력

Listening at http://localhost:8080

컨테이너에서 실행 중인 애플리케이션 미리보기

  • Cloud Shell 웹 미리보기 버튼을 클릭합니다.
  • 포트 8080에서 미리보기를 클릭합니다.
  • Cloud Shell에서 Ctrl + C를 눌러 컨테이너를 중지합니다.

컨테이너 동작 변경

Docker Run을 실행하면 Dockerfile의 기본 구성이 사용됩니다. 이 동작을 수정하기 위한 지침과 매개변수를 추가할 수 있습니다.

TRACE 로깅 사용 설정

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
  --rm \
  -p 8080:8080 \
  sample-app:${IMAGE_TAG} \
  java -Dorg.slf4j.simpleLogger.defaultLogLevel=trace -jar /app/target/sample-app-1.0.0-jar-with-dependencies.jar

컨테이너에서 실행 중인 애플리케이션 미리보기

  • Cloud Shell 웹 미리보기 버튼을 클릭합니다.
  • 포트 8080에서 미리보기를 클릭합니다.
  • Cloud Shell 탭으로 전환하면
  • Cloud Shell에서 Ctrl + C를 눌러 컨테이너를 중지합니다.

포트 변경

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
docker run \
--rm \
-e PORT=8081 \
-p 8081:8081 \
sample-app:${IMAGE_TAG}

컨테이너에서 실행 중인 애플리케이션 미리보기

  • Cloud Shell 웹 미리보기 버튼을 클릭합니다.
  • 포트 변경을 클릭합니다.
  • 8081을 입력하세요.
  • 변경 및 미리보기를 클릭합니다.
  • Cloud Shell에서 Ctrl + C를 눌러 컨테이너를 중지합니다.

6. 푸시

컨테이너 이미지가 제대로 실행되고 있다고 확신하고 이 컨테이너를 다른 환경이나 다른 사용자가 실행할 수 있도록 하려면 이미지를 공유 저장소로 푸시해야 합니다. 이 작업은 자동화된 빌드 파이프라인의 일부로 발생해야 하지만 테스트 환경에는 이미 저장소가 구성되어 있으므로 이미지를 수동으로 푸시할 수 있습니다.

sample-app 저장소에 Dockerfile 커밋 푸시

cd ${HOME}/sample-app
export IMAGE_TAG=$(git rev-parse --short HEAD)
git push

이미지에 Artifact Registry 태그 지정

docker tag sample-app:${IMAGE_TAG} \
    us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

Artifact Registry의 사용자 인증 정보 구성

gcloud auth configure-docker us-central1-docker.pkg.dev

메시지가 표시되면 Do you want to continue (Y/n)?에서 y로 답변하고 Enter 키를 누릅니다.

이미지를 Artifact Registry로 내보내기

docker push us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/apps/sample-app:${IMAGE_TAG}

출력

 The push refers to repository [us-central1-docker.pkg.dev/qwiklabs-gcp-04-b47ced695a3c/apps/sample-app]
  453b97f86449: Pushed
  e86791aa0382: Pushed
  d404c7ee0850: Pushed
  fe4f44af763d: Pushed
  7c072cee6a29: Pushed
  1e5fdc3d671c: Pushed
  613ab28cf833: Pushed
  bed676ceab7a: Pushed
  6398d5cccd2c: Pushed
  0b0f2f2f5279: Pushed
  aaa8895: digest: sha256:459de00f86f159cc63f98687f7c9563fd65a2eb9bcc71c23dda3351baf13607a size: 2424

7. 축하합니다.

축하합니다. Codelab을 완료했습니다.

학습한 내용

  • 샘플 애플리케이션용 Dockerfile 만들기
  • 이미지 빌드
  • 로컬에서 컨테이너로 이미지 실행
  • 컨테이너 동작 변경
  • 이미지를 Artifact Registry로 푸시함