Learn Docker In A Month Of Lunches - 04. Packaging Applications From Source Code Into Docker Images
title: Learn Docker In A Month Of Lunches - 04. Packaging Applications From Source Code Into Docker Images
date: 2023-03-29
tags:
- Docker
Introduction
GDSC에서 기존에 진행하던 HTTP 스터디 종료 이후, Docker 스터디를 이어서 진행하게 되었다.
실습 내용을 위주로 작성한다. 서적에는 각 내용에 대한 더욱 자세한 설명이 포함되어 있으니 포스팅에 적지 않은 자세한 내용은 서적을 보거나 검색 등을 추천한다.
Purpose
Dockerfile에서의 Multi Stage에 대해 학습한다.
Build Server And Dockerfile
Container 기술 도입 이전에는 Build만을 위한 별도의 Server가 필요하였다.
다양한 Build 툴과 버전이 존재하며, 각 조직에서는 통일된 툴과 버전을 이용해야 한다.
Build Server가 없다면 이러한 것을 관리하기 어렵기에 Build Server를 두지만, 이를 위한 추가 Resource가 필요하다.
이러한 문제는 Container 기술 덕분에 쉽게 해결되었다.
아직 학습하지 않은 내용이 존재하지만 간단하게 살펴본다.
총 3가지의 Stage로 나누어진 Dockerfile이다. Build Stage, Test Stage, 마지막 실행 Stage로 구성이 된다.
첫 Build Stage에서 Build 작업을 진행한다. Build와 관련된 것들은 해당 Image에만 존재하면 된다.
이후, Test Stage에서는 Build Stage의 결과물을 복사하여 Test를 진행한다. Build와 관련된 것들은 필요하지 않으며, Test에 관련된 것들만 있으면 된다.
마지막 실행 Stage에서는 Test Stage의 결과물을 가져온다. 실행을 위한 무언가만 필요하기에 해당 Image의 크기는 단일 Image에 비하면 매우 작아진다.
3가지의 Stage로 구분하였으며, 3개의 Image로 구분되어 있다. 각 Image는 독립적이며, 마지막에 살펴본 Dockerfile의 경우 두 Image에 대한 의존성을 가진다고 볼 수 있다.
별도의 작업이 필요하다면 해당 작업만 진행하는 Image를 구성한 후, 마지막 Image에 하나의 Stage만 추가해주면 된다.
또한 단 하나의 Directive만 실패하더라도 Build 자체가 실패하기에 안전하다고 볼 수 있다.
App Walkthrough
Java, Node.js, Go 3가지의 언어로 구성된 Container를 실행한다.
Dockerfile만 구성하였다면 관련된 패키지가 없더라도 Build 및 실행이 가능하다는 내용이다.
실습 위주로 빠르게 살펴본다.
Java Source
각 Container는 격리되어 있기에 서로 통신할 수 없다.
하지만 Container간의 통신이 필요한 경우가 있을 것이며, 이를 위해 Docker Network를 구성하면 Container간의 통신이 가능하다.
우선 새로운 Docker Network를 생성한다.
docker network create nat
Network 지정을 하지 않는다면 bridge
Driver의 bridge
Network에 연결이 되나, 여기서는 별도의 Network를 이용한다.
해당 Network를 이용하려면 Container 실행 시 --network 옵션에서 명시하면 된다.
위에서 생성한 nat
Network에 새로운 Image를 띄운다.
cd diamol/ch04/exercises/image-of-the-day
docker image build -t image-of-the-day .
docker container run --name iotd -d -p 800:80 --network nat image-of-the-day
이후 http://localhost:800/image
에 들어가면 NASA의 Image of the day
사진을 JSON 방식으로 출력하는 것을 확인할 수 있다.
해당 Container를 계속 이용할 것이니 종료하지 않고 실습을 이어간다.
Node.js Source
cd ../access-log
docker image build -t access-log .
docker container run --name accesslog -d -p 801:80 --network nat access-log
/access-log
로 POST Request가 들어올 때마다 Count가 증가하는 소스이다.
Go Source
cd ../image-gallery
docker image build -t image-gallery .
docker container run -d -p 802:80 --network nat image-gallery
Go로 구성된 소스지만 간단하기에 Go를 모르더라도 소스를 대강 파악할 수 있다.image-of-the-day
Image를 실행한 iotd
Container로부터 URL을 가져와 이를 출력한 후, access-log
Image를 실행한 accesslog
Container에 POST 요청을 보내는 소스이다.
각 Container와 통신을 하는 소스이기에 이전의 Container를 종료하지 않아야 정상적인 실행 확인이 가능하다.
소스에서는 POST Request를 1회만 보내지만, Web에서 확인해보면 Count가 2씩 올라가는 것을 확인할 수 있었다.
Multi-Stage Dockerfile
여러 Stage로 구성된 Dockerfile은 단일 Stage에 비하면 아래의 장점이 존재한다.
- Standardization - 어떠한 환경을 사용하더라도 실습을 정상적으로 따라올 수 있었을 것이다. 동일한 Docker를 이용하며 세부 작업은 Docker 내부에서 이루어지기에 문제가 없다. 이 덕분에 새로운 팀원이 들어오더라도 Docker 하나만으로 다른 팀원과 동일한 환경을 구성할 수 있다.
- Performance - 각 Stage별로 Cache가 구성이 된다. 중간의 무언가가 바뀌었을 경우, 해당 Stage의 남은 작업을 다시 진행한다. 다음 Stage는 변동이 없다면 다시 Cache를 이용하기에 빠른 Build가 가능하다.
- Small Image - 단일 Stage라면 다양한 툴이 포함되어 있기에 Image 자체의 크기가 매우 커진다. 하지만 첫 Multi Stage 예제처럼 구성할 경우, Test Stage까지의 것들은 Image 결과물에 포함되지 않는다. 최종적으로 만들어진 Image는 단일 Stage의 Image에 비하면 크기가 매우 작아진다.
Lab
diamol/ch04-lab
에서 진행한다.
주어진 Dockerfile
은 단일 Stage로, Ubuntu에서 Build 시 832MB의 크기를 가진다.
Dockerfile의 구성만 바꾸어 해당 용량을 20MB 이하로 줄인다. 서적에서는 15MB라고 되어있으나, 17MB가 한계였기에 이에 근접하면 목적을 이루었다고 볼 수 있다.
Solution
FROM diamol/golang AS builder
WORKDIR web
COPY main.go .
RUN go build -o /web/server
RUN chmod +x /web/server
FROM diamol/base
ENV USER=sixeyed
EXPOSE 80
CMD ["/web/server"]
WORKDIR web
COPY --from=builder /web/server .
COPY index.html .
Build와 실행, 두 Stage로 분리하였다.index.html
은 Web 실행 시 필요하기에 실행 Stage에서 복사해주어야 한다.CMD
는 최종적으로 Image를 실행할 때 사용되며, EXPOSE 및 ENV 또한 실행 Stage에 적합하다고 판단하여 실행 Stage로 옮겼다.
실행 Stage 또한 기반 Image가 필요하며, 이전에 사용하였던 diamol/base
를 사용하였다.
Build Stage의 결과물과 Local의 index.html
을 복사해주면 된다.
Stage를 나누어 기존의 방대한 Image를 20MB 이하로 줄일 수 있었다.
Conclusion
Dockerfile에서의 Multi Stage에 대해 알아보았다.
이번 Chapter는 이론적인 부분이 더욱 강조된 느낌이다. 관련 내용을 더 찾아보는 것이 좋을 것 같다.