
มี 4 อย่างที่ผมแนะนำสำหรับคนที่ต้องการสร้าง Container ให้ดี ซึ่งมันจะทำให้ container นั้นมีขนาดเล็กลง และปลอดภัยมากขึ้น
1. Smaller Base image
ในตอนสร้าง 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 ก็เลือกกันเอาเองว่าจะใช้อันไหน 🙂
2. Multi-stage builds
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 คือ
- ทำการติดตั้ง node_module แล้ว build reatjs ออกมาให้เป็น static ไฟล์
- นำ static ไฟล์ที่ได้มา ไปใช้งานบน nginx เพื่อให้สามารถเข้ามาดูเว็บได้
ซึ่งตอนสุดท้าย Docker image ตัวนี้เราจะได้เป็น nginx:1.15-alpine
ที่มีไฟล์ reactjs แบบ static ไฟล์อยู่นั้นเอง
ศึกษาเพิ่มเติม: https://docs.docker.com/develop/develop-images/multistage-build/
3. Use of .dockerignore file
ในการ 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/
4. Containers as a Non-Root User
โดยเริ่มต้น 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 เราได้ ก็ไม่สามารถใช้คำสั่งสำคัญๆ ของระบบได้เช่นกัน