Published on

เรียนรู้ Go - สร้าง Docker image สำหรับโปรเจค Go

เรียนรู้ Go หัดทำ API ด้วย gin
เรียนรู้ Go หัดทำ API ด้วย gin

เดี๋ยววันนี้เราจะมาเขียน 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

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 --from=stage /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

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 --from=builder /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 ครับ!

Reference