✔️ Docker Cache
ubuntu 이미지를 httpd 서비스 이미지로 만드는 Dockerfile이다.
vagrant@docker ~/image-build/myweb-ubuntu cat Dockerfile
FROM ubuntu:focal
RUN apt update; DEBIAN_FORNTEND=noninteractive apt install tzdata
RUN ln -sf /bin/share/zoneinfo/Asia/Seoul /etc/localtime
RUN apt install -y apache2
COPY index.html /var/www/html/index.html
EXPOSE 80/tcp
CMD ["/usr/sbin/apache2ctl", "-DFOREGROUND"]
- FROM
- RUN
- RUN
- RUN
- COPY
- EXPOSE
- CMD
Dockerfile 내부에서 Instruction의 순서는 위와 같다.
1) 조금 더 자세히 풀어보면 먼저 이미지를 가지고(FROM) 내부적으로 컨테이너를 만든다.
2) RUN을 실행하여 명령을 실행하고 이것을 다시 내부적으로 commit하여 이미지를 만든다.
3) 그 이미지를 가지고 다시 컨테이너를 만들어 이미지를 만드는 작업을 반복한다.
이때 컨테이너 → 이미지 → 컨테이너 → 이미지 전체 과정 자체가 caching되어 있다.
vagrant@docker ~/image-build/myweb-ubuntu docker build -t myweb:ubuntu .
Sending build context to Docker daemon 3.072kB
Step 1/7 : FROM ubuntu:focal
---> 53df61775e88
Step 2/7 : RUN apt update; DEBIAN_FORNTEND=noninteractive apt install tzdata
---> Using cache
---> 306963bfd891
Step 3/7 : RUN ln -sf /bin/share/zoneinfo/Asia/Seoul /etc/localtime
---> Using cache
---> 167995344e09
Step 4/7 : RUN apt install -y apache2
---> Using cache
---> 798010181f77
Step 5/7 : COPY index.html /var/www/html/index.html
---> Using cache
---> a139f844faee
Step 6/7 : EXPOSE 80/tcp
---> Using cache
---> c0896df2102a
Step 7/7 : CMD ["/usr/sbin/apache2ctl", "-DFOREGROUND"]
---> Using cache
---> f9fb5c255b69
Successfully built f9fb5c255b69
Successfully tagged myweb:ubuntu
이미 한번 빌드한 이미지를 다시 빌드하면 작업이 금방 끝난다.
그리고 작업 내용을 보면 Using cache
라는 내용을 볼 수 있다.
이는 빌드 과정 자체가 로컬에 저장되어 있어 따로 실행하지 않는다는 것이다.
그렇다면 index.html 파일을 조금 수정하고 빌드하면 어떻게 될까?
현재 상황은 이미지 빌드 과정이 이미 캐싱되어 있고 Dockerfile의 코드 변경은 없는 상태다.
경우의 수는 2가지 중에 하나가 될 것이다.
1) 이미 캐싱되어 있는 정보기 때문에 다시 빌드하지 않을 것이다. → 이는 의도한 대로 작동한 것이 아니다.
왜냐하면 index.html 파일의 내용을 바꾸었고 최신 파일로 교체되기를 원했기 때문이다.
2) 다시 빌드한다.
실제로 빌드해보자
vagrant@docker ~/image-build/myweb-ubuntu docker build -t myweb:ubuntu .
Sending build context to Docker daemon 3.072kB
Step 1/7 : FROM ubuntu:focal
---> 53df61775e88
Step 2/7 : RUN apt update; DEBIAN_FORNTEND=noninteractive apt install tzdata
---> Using cache
---> 306963bfd891
Step 3/7 : RUN ln -sf /bin/share/zoneinfo/Asia/Seoul /etc/localtime
---> Using cache
---> 167995344e09
Step 4/7 : RUN apt install -y apache2
---> Using cache
---> 798010181f77
Step 5/7 : COPY index.html /var/www/html/index.html
---> 18de092978ee
Step 6/7 : EXPOSE 80/tcp
---> Running in bf696699cb3f
Removing intermediate container bf696699cb3f
---> bf165fe249d2
Step 7/7 : CMD ["/usr/sbin/apache2ctl", "-DFOREGROUND"]
---> Running in b4a2953c91e5
Removing intermediate container b4a2953c91e5
---> cf69a6f1e262
Successfully built cf69a6f1e262
Successfully tagged myweb:ubuntu
방금전의 빌드 과정과 비교해보면 5/7 단계인 COPY Instruction에서는 cache를 사용하지 않는다.
도커는 이미지를 빌드할 때 파일의 hash값을 확인한다.
hash값은 파일의 내용에 따라 정해지는데 파일의 내용이 바뀌었으므로 기존의 hash값과 다르다.
때문에 빌드를 다시 진행한다.
만약 빌드 과정에서 네번째 작업에서 오류가 났다고 가정해보자.
오류가 나면 빌드를 더 이상 진행하지 않지만 두번째, 세번째는 이미 정상적으로 빌드했기 때문에 캐싱이 되어 있다.
그래서 오류를 해결 후 다시 빌드하면 두번째, 세번째 작업은 캐싱되어 있는 것을 그대로 사용하게 된다.
vagrant@docker ~/image-build/myweb-ubuntu docker history myweb:ubuntu
IMAGE CREATED CREATED BY SIZE COMMENT
cf69a6f1e262 2 minutes ago /bin/sh -c #(nop) CMD ["/usr/sbin/apache2ct… 0B
bf165fe249d2 2 minutes ago /bin/sh -c #(nop) EXPOSE 80/tcp 0B
18de092978ee 2 minutes ago /bin/sh -c #(nop) COPY file:6af65fa07569781f… 29B
798010181f77 34 minutes ago /bin/sh -c apt install -y apache2 111MB
167995344e09 35 minutes ago /bin/sh -c ln -sf /bin/share/zoneinfo/Asia/S… 30B
306963bfd891 35 minutes ago /bin/sh -c apt update; DEBIAN_FORNTEND=nonin… 39.5MB
53df61775e88 11 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 11 days ago /bin/sh -c #(nop) ADD file:7009ad0ee0bbe5ed7… 72.8MB
해당 이미지는 커스텀한 이미지이므로 빌드 과정을 모두 저장하고 있다.
지금 당장은 아니지만 두달쯤 후에 아파치의 최신 버전이 나와 이미지를 다시 빌드해야 한다고 해보자
새로운 패키지가 나왓다면 해당 인덱스 정보를 가지고 와야한다.
하지만 빌드 과정 자체가 캐싱되어 있어 새롭게 가져오지 않는다.
centos는 yum 명령을 내릴 때마다 최신 패키지 목록을 가져오기 때문에 상관없지만
ubuntu는 apt update를 할 때만 최신 패키지 목록을 가져온다.
우리가 도커 이미지를 사용할 때는 특정 목적이 있지 않는한 latest 태그를 사용하지 않는 것이 좋다고 했다.
Dockerfile 안에서 패키지 설치 명령을 작성할 때도 마찬가지이다. 특정 version으로 작성해야 한다.
하지만 apt update 빌드 과정은 캐싱되어 있으므로 version을 명시한다고 해서 새로운 버전이 설치된다는 보장이 없다.
그렇지만 적어도 오류는 발생한다.
현재 가지고 있는 패키지 목록에서는 이 버전이 없다라는 오류가 발생한다.
그리고 우리는 그 오류를 해결하면 된다.
따라서 최소한 버전을 붙여주는 것이 좋고 어떻게 Dockerfile에서 apt update를 다시 실행할 것인가를 강구해야 한다.
이에 대한 방법은 2가지이다.
1) ONBUILD 인스트럭션 - 빌드할 때 마다 실행할 인스트럭션 지정
ONBUILD RUN apt update : docker build 마다 apt update를 진행한다.
2) docker build 옵션에서 --no-cache
옵션을 사용한다.
모든 레이어에 캐싱을 적용하지 않으므로 빌드 시간이 오래 걸린다.
시간 절약의 면에서는 ONBUILD
를 사용하는 것이 좋을 수 있다.
'DevOps > Docker' 카테고리의 다른 글
[Docker] multistage-build (멀티 스테이지 빌드) (0) | 2022.05.12 |
---|---|
[Docker] Alpine Linux (알파인 리눅스) (0) | 2022.05.11 |
[Docker] ubuntu 이미지로 httpd 서비스 이미지 만들기 ( + Timezone 세팅) (0) | 2022.05.11 |
[Docker] Shell(쉘) 변수 (0) | 2022.05.11 |
[Docker] Dockerfile로 이미지 빌드하기 (0) | 2022.05.11 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!