มี 4 อย่างที่ผมแนะนำสำหรับคนที่ต้องการสร้าง Container ให้ดี ซึ่งมันจะทำให้ container นั้นมีขนาดเล็กลง และปลอดภัยมากขึ้น
ในตอนสร้าง Dockerfile ให้เราเลือก image ที่มีขนาดเล็กมาใช้เพื่อที่ container เราจะได้เล็กตามไปด้วย โดยส่วนใหญ่ให้สังเกตุ tag ของ image นั้นๆ จะมี alpine มาให้เลือกใช้ ซึ่งมันเป็น Linux ที่มีขนาดเล็ก เช่น Nodejs image
$ docker image ls
node 12 1f560ce4ce7e 7 weeks ago 918MB
node 12-alpine d8b74300d554 8 weeks ago 89.6MB
สังเกตุว่าถ้าเราเอา node:12
มาใช้ขนาดมันคือ 918MB แม่เจ้า…
แต่ถ้าเราเลือก node:12-alpine
จะเหลือขนาด 89.6MB ก็เลือกกันเอาเองว่าจะใช้อันไหน 🙂
Multi-stage builds เป็น feature หนึ่งของ dockerfile ที่ทำให้เราสามารถ build docker ได้หลายๆ ชุดคำสั่งภายในไฟล์เดียว แล้วเอาชุดคำสั่งสุดท้ายมาใช้งาน
อาจจะยังไม่เข้าใจ ผมจะให้ดูโค็ดตัวอย่างละกันในการทำ reactjs ในรูปแบบ dockerfile เพื่อนำไปใช้งานได้เลย
# Stage 0, "build-stage", based on Node.js, to build and compile the frontend
FROM node:12-alpine as build-stage
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY ./ /app/
RUN npm run build
# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
FROM nginx:1.15-alpine
COPY --from=build-stage /app/build/ /usr/share/nginx/html
สังเกตุว่าเราสามารถใส่ FROM
ได้ 2 อันใน Dockerfile ซึ่งปกติจะทำไม่ได้ ในกรณีนี้เราจะทำ 2 stage คือ
ซึ่งตอนสุดท้าย Docker image ตัวนี้เราจะได้เป็น nginx:1.15-alpine
ที่มีไฟล์ reactjs แบบ static ไฟล์อยู่นั้นเอง
ศึกษาเพิ่มเติม: https://docs.docker.com/develop/develop-images/multistage-build/
ในการ COPY ไฟล์เข้ามาใน docker image นั้นเราควรเลือกเฉพาะไฟล์ที่สำคัญสำหรับงานเราเท่านั้น เพื่อให้ image มีขนาดเล็กลง ซึ่งโดยปกติเราจะเขียน dockerfile กันแบบนี้
FROM node:12-alpine
COPY ./ /app/
การเขียน COPY ./ /app/
คือการเอาไฟล์ทั้งหมดเข้ามาใน docker image แต่หากเราไม่อยากได้ไฟล์บ้างอันละ ทำไง?
ก็เขียน .dockerignore
ช่วยสิ วิธีเขียนจะเหมือนกับ .gitignore
เลย และให้วางอยู่ในตำแหน่งกับ Dockerfile
$ ls -a
. .. .dockerignore .eslintrc.json .gitignore Dockerfile README.md index.js package.json src/
ตัวอย่างการเขียน
$ cat .dockerignore
Dockerfile
README.md
.git/
โดยเริ่มต้น Docker image จะใช้ root user ในการใช้งาน ทำให้ถ้าใครสามารถเข้ามายัง container นี้ได้ก็สามารถใช้ได้ทุกคำสั่ง และสิ่งนี้เป็นสิ่งที่อันตรายมาก มันจะทำให้ container ที่เรานำไปใช้งานไม่ค่อยปลอดภัย
วิธีแก้ไขคือให้เราใช้ user อื่นในการใช้งาน container นั้น โดยมีวิธีเขียน dockerfile ดังนี้
FROM node:12-alpine
# Create a group and user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Tell docker that all future commands should run as the appuser user
USER appuser
CMD [ "node", "index.js" ]
เพียงเท่านั้น node ของเราจะถูกเรียกใช้โดย appuser และหากมีใครเข้ามายัง container เราได้ ก็ไม่สามารถใช้คำสั่งสำคัญๆ ของระบบได้เช่นกัน