คำสั่งต่างๆ ที่ถูกเขียนใน Dockerfile จะทำให้ตอนสร้าง Docker image ขึ้นมามีขนาดใหญ่ขึ้นเรื่อยๆ ซึ่งวิธีการที่จะช่วยให้มันเล็กลงได้ก็คือ การเขียนคำสั่งทั้งหมดไว้เป็นคำสั่งเดียว ซึ่งมันเป็นวิธีที่ง่าย และเห็นผลชัดเจนมากในการลดขนาด Docker image
เรามาดูกันว่าถ้าเราเขียน Dockerfile โดยมีหลายคำสั่งระบบ Docker จะทำงานยังไง
FROM debian:stable
WORKDIR /var/www
RUN apt-get update
RUN apt-get -y --no-install-recommends install curl
RUN apt-get -y --no-install-recommends install ca-certificates
RUN apt-get purge -y curl
RUN apt-get purge -y ca-certificates
RUN apt-get autoremove -y
RUN apt-get clean
ในแต่ละคำสั่งที่เกิดขึ้นตั้งแต่ FROM
, WORKDIR
และ RUN
อีกหลายครั้ง docker จะทำการสร้าง Layer ไว้เพื่อประโยชน์ในการทำ Caching
$ docker build -t docker-tip .
Sending build context to Docker daemon 2.048kB
Step 1/9 : FROM debian:stable
stable: Pulling from library/debian
6a75cf7ef35e: Pull complete
Digest: sha256:6a3ead8cbca86c3c28c5f32d250df9203f7cb939ed07ac6925d7a7a788554911
Status: Downloaded newer image for debian:stable
---> f5356914cf3c
Step 2/9 : WORKDIR /var/www
---> Running in 1175c44beb96
Removing intermediate container 1175c44beb96
---> 76f0fce3f20a
Step 3/9 : RUN apt-get update
---> Running in 21d144f3a15a
Get:2 http://cdn-fastly.deb.debian.org/debian stable InRelease [118 kB]
...
...
...
Step 9/9 : RUN apt-get clean
---> Running in 5e941426cb57
Removing intermediate container 5e941426cb57
---> f152781a040d
Successfully built f152781a040d
Successfully tagged docker-tip:latest
สังเกตุว่ามันจะทำงานตามคำสั่งที่เราเขียนไว้ โดยแบ่งเป็น Step 1/9:
จนถึง Step 9/9:
ซึ่งพวกนี้ได้มีการทำ Caching ไว้แล้ว หากเรามีการแก้ไขเพียงบ้างคำสั่ง แล้วสั่ง build
ใหม่ มันก็จะเรียกเฉพาะ Step ที่มีการแก้ไขมาทำงานพอ ทำให้การ Build เร็วขึ้น
$ docker history docker-tip:latest
IMAGE CREATED CREATED BY SIZE COMMENT
f152781a040d 5 minutes ago /bin/sh -c apt-get clean 0B
2084ae6a31b4 5 minutes ago /bin/sh -c apt-get autoremove -y 1.01MB
bd1a0e5247d0 5 minutes ago /bin/sh -c apt-get purge -y ca-certificates 1.83MB
418b55128fc5 5 minutes ago /bin/sh -c apt-get purge -y curl 1.04MB
839356141e5d 5 minutes ago /bin/sh -c apt-get -y --no-install-recommend… 3.74MB
75c17e8eacd8 6 minutes ago /bin/sh -c apt-get -y --no-install-recommend… 10.6MB
4f94ae71ba4a 6 minutes ago /bin/sh -c apt-get update 17.1MB
76f0fce3f20a 6 minutes ago /bin/sh -c #(nop) WORKDIR /var/www 0B
f5356914cf3c 8 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 8 days ago /bin/sh -c #(nop) ADD file:bd22a8f9357bbfdeb… 114MB
ลองดูขนาดในแต่ละ Layer ว่ามีขนาดเท่าไร และสุดท้ายขนาด docker image ที่ได้ก็คือ
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-tip latest f152781a040d 7 minutes ago 149MB
คราวนี้เราจะลองลดขนาด docker image ให้เล็กโดยการรวมคำสั่ง RUN
ให้เหลืออันเดียวดู
FROM debian:stable
WORKDIR /var/www
RUN apt-get update && \
apt-get -y --no-install-recommends install curl \
ca-certificates && \
curl https://raw.githubusercontent.com/gadiener/docker-images-size-benchmark/master/main.go -o main.go && \
apt-get purge -y curl \
ca-certificates && \
apt-get autoremove -y && \
apt-get clean
มาลอง Build กัน
$ docker build -t docker-tip:shrinking .
ตรวจดูหน่อยว่าขนาดเป็นยังไงบ้าง
$ docker history docker-tip:shrinking
IMAGE CREATED CREATED BY SIZE COMMENT
de2242244ff6 About a minute ago /bin/sh -c apt-get update && apt-get -y --… 18.9MB
76f0fce3f20a 11 minutes ago /bin/sh -c #(nop) WORKDIR /var/www 0B
f5356914cf3c 8 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 8 days ago /bin/sh -c #(nop) ADD file:bd22a8f9357bbfdeb… 114MB
เปรียบเทียบให้เห็นชัดๆ ไปเลย
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-tip shrinking de2242244ff6 5 seconds ago 133MB
docker-tip latest f152781a040d 9 minutes ago 149MB
จะเห็นว่าเพียงเรารวมคำสั่งต่างๆ ของ RUN ไว้เป็นคำสั่งเดียวก็ทำให้ขนาด Docker image ของเราลดลงไปถึง 149MB-133MB = 16MB
ผมจะทำแบบนี้ทุกครั้ง ถ้าในช่วงที่กำลังเขียน Dockerfile อยู่นั้นให้ก็ให้แยก RUN
ออกเป็นแต่ละคำสั่งได้ เพื่อถ้ามันมี error ตอนไหนเราจะได้รู้ว่าคำสั่งไหนผิด และเป็นการ Debug ไปในตัว จนเมื่อเราโอเคแล้วค่อยเขียนรวมเป็นอันเดียว จบปะ!!!