docker 교과서 Chapter 3
목록#
- 도커 허브에 공유된 이미지 사용하기
- Dockerfile 작성하기
- 컨테이너 이미지 빌드하기
- 도커 이미지와 이미지 레이어 이해하기
- 이미지 레이어 캐시를 이용한 Dockefile 스크립트 최적화
Docker Run 할때 -e
또는 --env
플래그#
environment variable을 컨테이너 시작시 넣어줄 수도 있다.
docker container run --name <name> --env [<key>=<value>] diamol/ch03-web-ping
Why Dockerfile?#
dockerfile 작성을 해야 하는 이유는 뭐지?
dockerfile → docker image , 즉 애플리케이션을 패키징(빌드) 하기 위한 스크립트 파일을 의미.
FROM
ENV
WORKDIR
COPY
CMD
Docker Image Layer#
docker image layer라는게 있다고? dockerfile 하나가 이미지 레이어 하나를 차지한다고?
docker image history
명령어를 사용하면 내가 빌드한 이미지의 레이어를 출력해준다.
도커파일의 각 명령어 한줄마다 이미지 레이어가 한 줄씩 쌓인다. 아래는 docker image history web-ping
명령을 사용하여 실습 중 빌드한 이미지의 레이어를 복기한다:
$ docker image history web-ping
IMAGE CREATED CREATED BY SIZE COMMENT
218b62931576 5 minutes ago /bin/sh -c #(nop) CMD ["node" "/web-ping/ap… 0B
5f46ff96c655 5 minutes ago /bin/sh -c #(nop) COPY file:a2087c9a71052e4e… 846B
0184d8697d3c 5 minutes ago /bin/sh -c #(nop) WORKDIR /web-ping 0B
9f258f86775d 5 minutes ago /bin/sh -c #(nop) ENV INTERVAL=3000 0B
b3d33740b138 5 minutes ago /bin/sh -c #(nop) ENV METHOD=HEAD 0B
5b1ecca41c3f 5 minutes ago /bin/sh -c #(nop) ENV TARGET=blog.sixeyed.c… 0B
9dfa73010b19 5 years ago /bin/sh -c #(nop) CMD ["node"] 0B
<missing> 5 years ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
<missing> 5 years ago /bin/sh -c #(nop) COPY file:238737301d473041… 116B
<missing> 5 years ago /bin/sh -c apk add --no-cache --virtual .bui… 5.1MB
<missing> 5 years ago /bin/sh -c #(nop) ENV YARN_VERSION=1.16.0 0B
<missing> 5 years ago /bin/sh -c addgroup -g 1000 node && addu… 64.7MB
<missing> 5 years ago /bin/sh -c #(nop) ENV NODE_VERSION=10.16.0 0B
<missing> 5 years ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 5 years ago /bin/sh -c #(nop) ADD file:a86aea1f3a7d68f6a… 5.53MB
Dockerfile의 FROM
명령이 이미지 레이어 중 가장 큰 사이즈를 차지한다. FROM 은 기반 명령어를 설정하는 것으로, 이 위에 올라온 모든 JS 파일들은 불과 몇 KB에 불과한다. 그러니까 우리는 컨테이너 하나를 만든다고 Node 환경을 새로 올리지 않는다는 것이다.
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
web-ping latest 424363da0993 21 minutes ago 75.5MB
diamol/ch03-web-ping latest bfce5d697312 3 years ago 75.5MB
여기에서 SIZE가 75.5MB씩 두개가 되는데 실제로 차지하는 용량을 확인해보면...
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 2 75.49MB 75.49MB (99%)
Containers 2 0 0B 0B
Local Volumes 2 0 50.11MB 50.11MB (100%)
Build Cache 6 0 0B 0B
TYPE IMAGES
쪽만 보면 되는데, 이미지에 75.49MB만을 사용하고 있는 것으로 알 수 있다. 즉 같은 레이어를 공유하고 있다고 볼 수 있다. 만약 다른 node.js 이미지를 빌드한다면 최상위 레이어 이미지의 사이즈만 추가될 것이다. 멋진 말로 "같은 기반 레이어를 공유하는 애플리케이션의 숫자가 많을 수록 절약된다."
도커 이미지 레이어 캐시를 이용한 Dockerfile 스크립트 최적화#
app.js 파일 하나만 변경하고 다른 이미지를 하나 생성해보자.
$ docker image build -t web-ping:v2 .
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Sending build context to Docker daemon 5.12kB
Step 1/7 : FROM diamol/node
---> 9dfa73010b19
Step 2/7 : ENV TARGET="blog.sixeyed.com"
---> Using cache
---> 5b1ecca41c3f
Step 3/7 : ENV METHOD="HEAD"
---> Using cache
---> b3d33740b138
Step 4/7 : ENV INTERVAL="3000"
---> Using cache
---> 9f258f86775d
Step 5/7 : WORKDIR /web-ping
---> Using cache
---> 0184d8697d3c
Step 6/7 : COPY app.js .
---> 1228aaacf7bb
Step 7/7 : CMD ["node", "/web-ping/app.js"]
---> Running in 29f74ab575da
---> Removed intermediate container 29f74ab575da
---> fba79c20e7aa
Successfully built fba79c20e7aa
Successfully tagged web-ping:v2
Step 2,3,4,5 단계가 모두 cache를 사용했음을 알 수 있다. Step 6,7 단계는 새로운 레이어가 만들어졌다. CMD 인스트럭션이 변경되었기 때문에 캐시 미스가 발생했고, 그 이후 단계를 모두 새 레이어에서 실행된다.
[!note] Dockefile은 명령이 순서대로 실행되기 위해서 존재하지 않는다. 레이어의 순서를 보장하기 위하여 존재한다.
[!question] 레이어를 최대한 많이 공유하기 위해선 어떻게 해야하나요?
Dockerfile 인스트럭션 중 자주 변경되지 않는 명령을 앞으로 배치하고 자주 수정되는 인스트럭션을 뒤에 배치하면 됩니다. 이미지 레이어는 수정이 발생한 시점부터 분기하게 되는데, 그 뒤에 인스트럭션이 동일하더라도 이전 인스트럭션에서 차이가 발생하면 그 위 레이어들은 캐시를 참조하지 않기 때문입니다.
문제: 아래의 Dockerfile을 최적화하세요#
FROM diamol/node
ENV TARGET="blog.sixeyed.com"
ENV METHOD="HEAD"
ENV INTERVAL="3000"
WORKDIR /web-ping
COPY app.js .
CMD ["node", "/web-ping/app.js"]
- COPY 인스트럭션이 자주 바뀔 수 있기 때문에 가장 높은 레이어로 옮긴다. (코드의 마지막으로)
- CMD 인스트럭션은 거의 바뀌지 않을 것이기 때문에 FROM 뒤에 초반부에 배치하자.
- ENV는 한 번에 여러개를 정의할 수 있기 때문에 레이어 개수를 줄인다.
FROM diamol/node
CMD ["node", "/web-ping/app.js"]
ENV TARGET="blog.sixeyed.com"
ENV METHOD="HEAD"
ENV INTERVAL="3000"
WORKDIR /web-ping
COPY app.js .
3.6 연습문제#
Dockerfile을 사용하지 않고 수동으로 컨테이너를 만들어보세요.
알아야 할 명령어
docker container commit
: Create a new image from a container's changesdocker container run -it