- Published on
เรียนรู้ Go - สร้าง Docker image สำหรับโปรเจค Go
เดี๋ยววันนี้เราจะมาเขียน Dockerfile กันครับ โดยเจมส์จะขออ้างอิงค์จากโปรเจค Go ของบทความก่อนหน้านี้เน้อครับ สำหรับคุณผู้อ่านที่ยังไม่ได้อ่าน สามารถย้อนกลับไปอ่านดูได้เน้อครับ เรียนรู้ Go หัดทำ API ด้วย gin
มาเริ่มกันเลย
สร้างแบบธรรมดา
ขั้นแรกให้เราสร้าง Dockerfile ในโปรเจค go ของเราขึ้นมาครับ แล้วใส่โค้ดลงไปดังนี้เน้อครับ
FROM golang:1.22-alpine
WORKDIR /app
COPY . .
RUN go build -o /main main.go
EXPOSE 2000
ENTRYPOINT [ "/main" ]
คือ เราจะสร้าง Dockerfile เตรียมไว้สำหรับ build เป็น Docker image ครับ
ขั้นตอนต่อมาคือเราจะสร้าง Docker image โดยใช้คำสั่งดังนี้ครับ
docker build -t simple-todo .
เมื่อสร้างเรียบร้อยแล้ว เรามาลองดูขนาดของ Docker image กันครับว่ามีขนาดเท่าไร โดยใช้คำสั่ง
docker images
ของเจมส์จะแสดงเป็นประมาณนี้ครับ
REPOSITORY TAG IMAGE ID CREATED SIZE
simple-todo latest 3d11b228a44f 3 minutes ago 561MB
เราสามารถ Run Project ที่อยู่ใน Docker image นี้ได้ โดยการใช้คำสั่ง
docker run -p 2000:2000 simple-todo
สร้างแบบ Multistage
เดี๋ยวเราจะมาสร้าง Dockerfile อีกแบบ โดยทำแบบ multistage ครับ
ขั้นแรกเดี๋ยวเราจะสร้าง Dockerfile ขึ้นมาอีกอัน ชื่อ multistage.Dockerfile
FROM golang:1.22-alpine as stage
WORKDIR /app
COPY . .
RUN go build -o /main main.go
EXPOSE 2000
FROM alpine
WORKDIR /
COPY /main /main
EXPOSE 2000
ENTRYPOINT [ "/main" ]
ขั้นตอนต่อมาคือเราจะสร้าง Docker image โดยใช้คำสั่งดังนี้ครับ
docker build -f ./multistage.Dockerfile -t multistage-simple-todo .
ถ้าหากไม่มีอะไรผิดพลาด เมื่อลองใช้คำสั่ง docker images
จะแสดงประมาณนี้ครับ
REPOSITORY TAG IMAGE ID CREATED SIZE
multistage-simple-todo latest 815b7e41d971 26 seconds ago 20.1MB
simple-todo latest 3d11b228a44f 14 minutes ago 561MB
จะพบว่าขนาดของ Docker image เหลือแค่ 20.1MB
ซึ่ง Docker image อันแรกที่เราทำมีขนาด 561MB
สร้างแบบ multistage ที่ลดขนาดแบบสุด ๆ (ใช้ Chat GPT ช่วย ^^)
เดี๋ยวเราจะมาสร้าง Dockerfile อีกอันครับ ชื่อ prod.Dockerfile
FROM golang:1.22-alpine as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags="-s -w" -o main .
FROM scratch
WORKDIR /
COPY /app/main .
EXPOSE 2000
ENTRYPOINT ["/main"]
ขั้นตอนต่อมาคือเราจะสร้าง Docker image โดยใช้คำสั่งดังนี้ครับ
docker build -f ./prod.Dockerfile -t prod-simple-todo .
แล้วมาลองใช้คำสั่ง docker images
กันอีกครั้งครับ จะพบว่าจะแสดงประมาณนี้ครับ
REPOSITORY TAG IMAGE ID CREATED SIZE
prod-simple-todo latest cc59223c3fc8 2 minutes ago 7.73MB
multistage-simple-todo latest 6a397d05fc3b 3 minutes ago 20.1MB
simple-todo latest 38b2d21d3f9b 4 minutes ago 561MB
จะเห็นว่าขนาดของ docker image ของ prod-simple-todo
เหลือแค่ 7.73MB
สิ่งที่น่ารู้สำหรับ prod.Dockerfile
คือ
CGO_ENABLED=0
เป็นการปิดการใช้งาน CGO ซึ่งเป็นฟีเจอร์ใน Go ที่ใช้สำหรับการเรียกใช้โค้ด C จาก Go การปิด CGO ทำให้สามารถสร้างไฟล์ไบนารีที่เป็นแบบ statically linked ซึ่งไม่ต้องการการพึ่งพาไลบรารีภายนอกในระบบเป้าหมาย
GOOS=linux
คือ ตั้งค่าระบบปฏิบัติการเป้าหมายเป็น Linux
go build
เป็นคำสั่งสำหรับคอมไพล์โค้ด Go
-a
บังคับให้คอมไพล์โค้ดและไลบรารีทั้งหมดใหม่ แม้ว่าไม่มีการเปลี่ยนแปลง
-installsuffix cgo
เพิ่ม suffix ให้กับชื่อไดเร็กทอรีไลบรารี เพื่อแยกแยะจากการ build แบบใช้ CGO
-ldflags="-s -w"
เป็นการตั้งค่า linker flags
-s
ลบตารางสัญลักษณ์จาก executable เพื่อลดขนาดไฟล์
-w
ลบข้อมูล debug เพื่อลดขนาดไฟล์เพิ่มเติม
-o
main กำหนดชื่อไฟล์ output ที่สร้างขึ้นมาเป็น main
.
ระบุว่าให้คอมไพล์โค้ดจากไดเร็กทอรีปัจจุบัน
FROM scratch
คือ scratch image เป็น base image ที่เล็กที่สุด เนื่องจากไม่มีอะไรใน image เลย
ในส่วนสิ่งที่น่ารู้เกี่ยวกับ
prod.Dockerfile
อันนี้เจมส์ลองสอบถาม ChatGPT และหาข้อมูลเพิ่มเติม
เย้ ! หวังว่าบทความนี้จะมีประโยชน์กับคุณผู้อ่านทุกท่านเน้อครับ หากส่วนไหนผิดพลาดประการใด ก็ขออภัยมา ณ ที่นี้ด้วยเน้อครับ หากคุณผู้อ่านมีส่วนไหนแนะนำ สามารถพิมพ์ทิ้งไว้ได้ในคอมเม้นท์เน้อครับ
Happy Coding ครับ!