สรุป Best Practices for writing Dockerfiles - Kanapakan/MoodMent-Project-SW-dev-tool GitHub Wiki

สรุป Best practices for writing Dockerfiles

Docker สร้าง image โดยอัตโนมัติโดยอ่าน instructions จาก Dockerfile ซึ่งเป็นไฟล์ข้อความที่มีคำสั่งในการสร้าง image

Dockerfile ยึดตามรูปแบบเฉพาะและชุดคำสั่งที่ได้จาก Dockerfile reference

# syntax=docker/dockerfile:1
FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py

แต่ละคำสั่งสร้าง 1 layer

  • FROM สร้าง layer จาก ubuntu:18.04 Docker image
  • COPY เพิ่มไฟล์ Docker client’s จาก directory ปัจจุบันของคุณ
  • RUN สร้าง application ของคุณด้วย make
  • CMD ระบุ command ที่จะ run ภายใน container

General guidelines and recommendations

Create ephemeral containers

  • image ที่กำหนดโดย Dockerfile ควรสร้างคอนเทนเนอร์ที่สามารถหยุดและลบได้ จากนั้นสร้างใหม่และแทนที่ด้วยการตั้งค่าและการกำหนดค่าขั้นต่ำที่แน่นอน

Understand build context

  • เมื่อใช้คำสั่ง docker build command, directory การทำงานปัจจุบันจะเรียกว่า the build context
  • โดยปกติ dockerfile จะถือว่าอยู่ที่นี่ แต่คุณสามารถระบุตำแหน่งอื่นได้ด้วย file flag (-f) ไม่ว่า dockerfile จะอยู่ที่ใด all recursive contents ของไฟล์และ directory ใน directory ปัจจุบันจะถูกส่งไปยัง Docker daemon

Pipe Dockerfile through

Docker มีความสามารถในการสร้าง image โดย piping Dockerfile ผ่าน stdin ด้วย local หรือ remote build context

  • ใช้สร้าง image โดยใช้ dockerfile จาก stdi โดยไม่ต้องส่งไฟล์เพิ่มเติม เป็น build context
  • ใช้สร้าง image โดยใช้ไฟล์ใน local filesystem ของคุณ แต่ใช้ Dockerfile จาก stdin
  • ใช้สร้าง image โดยใช้ไฟล์จาก remote git repository โดยใช้ Dockerfile จาก stdin
  • ใช้กรณีที่ต้องการสร้าง image จากที่เก็บที่ไม่มี Dockerfile หรือสร้าง custom Dockerfile โดยไม่ต้อง maintain fork of the repository ของคุณ

Exclude with .dockerignore

  • หากต้องการแยกไฟล์ที่เกี่ยวข้องกับ build ให้ใช้ไฟล์ .dockerignore ไฟล์นี้ support exclusion patterns คล้ายกับ .gitignore files

Use multi-stage builds

  • ช่วยลดขนาดของ final image ได้อย่างมาก โดยไม่ต้องพยายามลดจำนวน layers และ files เนื่องจาก image ถูกสร้างขึ้นในระหว่างขั้นตอนสุดท้ายของกระบวนการ build จึงสามารถย่อขนาด image layer โดยใช้ cache build

Don’t install unnecessary packages

  • เพื่อลดความซับซ้อนของ dependencies, ขนาดไฟล์ และเวลาที่ใช้ในการ build ให้หลีกเลี่ยงการติดตั้ง package พิเศษหรือ package ที่ไม่จำเป็น

Decouple applications

  • แต่ละ container ควรมีเพียงภาระงานเดียว การแยก application ออกเป็นหลาย container ทำให้ง่ายต่อการ scale horizontally และ reuse containers
  • การจำกัด container แต่ละ container ไว้ที่กระบวนการเดียว เป็นเรื่องที่ดี
  • หาก container พึ่งพากันและกัน คุณสามารถใช้ Docker container networks เพื่อให้แน่ใจว่า container เหล่านี้สามารถ communicate กันได้

Minimize the number of layers

  • ใน Docker versions เก่า เป็นเรื่องสำคัญที่ควรลดจำนวน layer ใน images ให้น้อยที่สุด เพื่อประสิทธิภาพที่ดี

Sort multi-line arguments

  • การเปลี่ยนแปลงในภายหลังง่ายขึ้นด้วยการ Sort multi-line arguments วิธีนี้ช่วยหลีกเลี่ยงความซ้ำซ้อนของ package และทำให้รายการ update ง่ายขึ้นมาก นอกจากนี้ยังทำให้ PRs อ่านและทบทวนได้ง่ายขึ้นมาก การเว้นวรรคก่อนแบ็กสแลช \ ก็ช่วยได้เช่นกัน

Leverage build cache

  • เมื่อสร้าง image Docker จะดำเนินการตามคำแนะนำใน Dockerfile โดยดำเนินการตามลำดับที่ระบุ เมื่อตรวจสอบแต่ละคำสั่งแล้ว Docker จะค้นหา image ที่มีอยู่ใน cache ซึ่งสามารถนำมาใช้ซ้ำได้ แทนที่จะสร้าง image ใหม่

สรุป Best practices for writing Dockerfiles ที่นำมาใช้ในทีม

1. Use multi-stage builds

FROM node:lts-alpine AS builder
WORKDIR /usr/src/front-end
COPY package.json .
RUN yarn install
COPY . .
RUN ["yarn", "build"]

FROM nginx:1.14.2-alpine AS production
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=0 /usr/src/front-end/build /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]

มีการทำ Multi-stages builds โดยแบ่ง Dockerfile เป็น 2 ส่วน คือ ส่วนสำหรับ Build และ ส่วนที่คัดลอกไฟล์ที่ Build นั้นไปใช้งาน

2. Exclude with .dockerignore

เพื่อให้ไฟล์ที่ไม่เกี่ยวข้อง หรือไฟล์ที่มีขนาดใหญ่ จะไม่ต้องเสียเวลาอ่านเข้าไปใน context ซึ่งจะทำให้สร้าง image ได้เร็วขึ้น และไม่นำไฟล์ที่ไม่จำเป็นที่ต้อง run ขึ้นไป

3. Don’t install unnecessary packages

ลบหรือไม่ติดตั้งแพคเกจที่ไม่จำเป็นต้องใช้งานในการรันโปรแกรม เพื่อลดความซับซ้อนของ dependencies, ขนาดไฟล์ และเวลาที่ใช้ในการ build