ข้ามไปยังเนื้อหา
บทความทั้งหมด

คอมไพล์แอปพลิเคชัน Go ด้วย Docker: ชุดเครื่องมือที่พกพาได้และแยกขาดจากเครื่องโฮสต์

โดย Ghazi Triki · อ่าน 7 นาที

คอมไพล์แอปพลิเคชัน Go ด้วย Docker
ในบทความนี้

เลิกติดตั้ง Go บนเครื่องโฮสต์ ไม่มี GOPATH รก ไม่มีปัญหา "เครื่องผมใช้ได้" และไม่มีเวอร์ชันคลาดเคลื่อน นี่คือรูปแบบเดียวกับที่เราใช้เขียนเอเจนต์ Java ใหม่สำหรับรายงาน BigBlueButton Learning Analytics และสร้าง Piler Go Agent ที่ปลอดภัย ต่อไปนี้คือวิธีส่งมอบไบนารีแบบสแตติกด้วย Docker เพียงอย่างเดียว

โดย Ghazi Triki, RIADVICE

ปัญหาของคำแนะนำว่า "ติดตั้ง Go ไปเลย"

ขณะที่เราดูแลเอเจนต์ที่พัฒนาด้วย Java สำหรับรายงาน BigBlueButton Learning Analytics เราเผชิญกับ "นรกของการพึ่งพา" (dependency hell) แบบคลาสสิก การย้ายมาใช้ Go ให้คำมั่นว่าจะเรียบง่ายขึ้น แต่จะเป็นจริงได้ก็ต่อเมื่อเราไม่ทำผิดซ้ำรอยเดิม เราต้องการกระบวนการบิลด์ที่แยกขาดจากสภาพแวดล้อมภายนอก (hermetic) ได้ไม่แพ้ไบนารีที่สร้างขึ้น

ทุกทีมย่อมต้องเจออุปสรรคเหล่านี้ในที่สุด

  • เวอร์ชันคลาดเคลื่อน Ahmed ใช้ 1.24, Omar ใช้ 1.26 และเซิร์ฟเวอร์ใช้งานจริงใช้ 1.25 การเปลี่ยนแปลงเล็กน้อยในคอมไพเลอร์ทำให้บิลด์ล้มเหลว แต่เกิดขึ้นกับ Ahmed เท่านั้น
  • เครื่องโฮสต์รก GOPATH, GOMODCACHE และเครื่องมือที่ติดตั้งแบบโกลบอล (staticcheck, gofumpt) แตกต่างกันไปในแต่ละเครื่อง
  • การรับคนใหม่เข้าทีมติดขัด วิศวกรใหม่ใช้เวลาวันแรกทั้งวันไปกับตัวแปรสภาพแวดล้อมและชุดเครื่องมือ C สำหรับ cgo

ที่ RIADVICE เราให้คุณค่ากับวินัยและความเป็นระเบียบ เราต้องการกระบวนการบิลด์ที่สะท้อนสิ่งนั้น คือสะอาด คาดการณ์ได้ และใช้ร่วมกันได้

คำตอบมาตรฐานคือ "ใช้ Docker" แต่บทแนะนำส่วนใหญ่สอนเพียงวิธีสร้าง อิมเมจคอนเทนเนอร์ ไม่ได้สอนวิธีได้มาซึ่ง ไบนารีธรรมดาที่ลิงก์แบบสแตติกบนเครื่องโฮสต์ ซึ่งเป็นสิ่งที่คุณต้องใช้จริงสำหรับบริการ systemd หรือการปรับใช้ในเครือข่ายที่แยกขาด (air-gapped) โดยไม่ต้องติดตั้งคอมไพเลอร์ Go ไว้ในเครื่องเลย

Shell
docker run --rm -v "$(pwd):/app" -w /app golang:1.26.5-trixie \
    go build -o dist/myapp ./cmd/myapp

อิมเมจ golang อย่างเป็นทางการทำหน้าที่เป็นคอมไพเลอร์ ซอร์สโค้ดของคุณถูกเมานต์แบบ bind ไว้ที่ /app ไบนารีจะถูกเขียนลงที่ dist/myapp บนเครื่องโฮสต์ เมื่อคำสั่งทำงานเสร็จ คอนเทนเนอร์จะถูกทำลาย (--rm) เครื่องโฮสต์ของคุณจึงสะอาดเหมือนเดิม

ประสบการณ์จริง: จาก BigBlueButton สู่ Piler

นี่ไม่ใช่แค่ทฤษฎี เราใช้รูปแบบนี้กับโครงการสำคัญสองโครงการ

  1. รายงาน BigBlueButton Learning Analytics: เราเขียนเอเจนต์ Java ขนาดใหญ่ใหม่เป็นไบนารี Go ที่มีขนาดเล็ก การบิลด์ด้วย Docker ทำให้เราคอมไพล์ให้ตรงกับสภาพแวดล้อม Debian ของเซิร์ฟเวอร์ BBB ได้ทุกประการ โดยไม่ต้องมีสภาพแวดล้อมนั้นบนแล็ปท็อปของเรา
  2. Piler Go Agent: สำหรับโซลูชันจัดเก็บอีเมลถาวรของเรา เราสร้างเอเจนต์ที่เสริมความแข็งแกร่งด้านความปลอดภัย กระบวนการบิลด์ต้องปลอดภัยพอ ๆ กับตัวโค้ด ด้วยการตรึงคอมไพเลอร์ไว้กับ SHA ที่ระบุ เราจึงมั่นใจได้ว่าทุกบิตในไบนารีตรวจสอบที่มาได้

เหตุใดวิธีนี้จึงดีกว่าการติดตั้ง Go

ประเด็นgo install บนเครื่องโฮสต์docker run golang:...
เวอร์ชัน Goเวอร์ชันที่ติดตั้งไว้ล่าสุดตรึงไว้ และเหมือนกันสำหรับทุกคน
GOPATH / แคชทำให้ ~/go รกเลเยอร์คอนเทนเนอร์ที่แยกขาด
ชุดเครื่องมือ cgoต้องตั้งค่าบนเครื่องโฮสต์รวมอยู่ในอิมเมจอย่างเป็นทางการ
ความสอดคล้องกับ CI"เครื่องผมใช้ได้"อิมเมจเดียวกัน ได้ไบนารีเดียวกัน
Makefile
BINARY := mini-api
DIST := dist

# Version metadata derived from git
VERSION    := $(shell tmp=$$(git describe --tags --always --dirty 2>/dev/null) && echo "$${tmp#v}" || echo dev)
COMMIT     := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
BRANCH     := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)
BUILD_DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -X example.com/mini-api/internal/version.Version=$(VERSION) \
           -X example.com/mini-api/internal/version.Commit=$(COMMIT) \
           -X example.com/mini-api/internal/version.Branch=$(BRANCH) \
           -X example.com/mini-api/internal/version.BuildDate=$(BUILD_DATE)

# Pinned toolchain image
GO_IMAGE := golang:1.26.5-trixie

# Run any command inside the Go toolchain container
define run_in_docker
    docker run --rm -v "$(PWD):/app" -w /app $(GO_IMAGE)
endef

.PHONY: build test lint

build:
    @mkdir -p $(DIST)
    $(call run_in_docker) bash -c 'CGO_ENABLED=0 go build -buildvcs=false -ldflags="$(LDFLAGS)" -o $(DIST)/$(BINARY) ./cmd/$(BINARY)'
    @echo "Built $(DIST)/$(BINARY) (version $(VERSION))"

test:
    $(call run_in_docker) go test -race ./...

lint:
    $(call run_in_docker) go vet ./...

Makefile: ต้นทางของวินัย

เราใช้ Makefile เพื่อกำหนดขั้นตอนการบิลด์ให้เป็นลายลักษณ์อักษร สังเกตว่า GO_IMAGE ถูกตรึงไว้กับเวอร์ชันที่ระบุ เราไม่ใช้ latest เด็ดขาด

รายละเอียดทางเทคนิคที่สำคัญ

1. CGO_ENABLED=0 สำหรับไบนารีแบบสแตติก

สำหรับเอเจนต์ของ Piler เราต้องการไบนารีที่รันได้ทุกที่ ตั้งแต่ Debian รุ่นใหม่ไปจนถึงเซิร์ฟเวอร์รุ่นเก่า การปิด CGO ทำให้ไบนารีมีทุกสิ่งที่ต้องใช้ในตัว โดยไม่พึ่งพาไลบรารีของเครื่องโฮสต์แบบไดนามิก

2. -ldflags -X เพื่อระบุที่มา

ไบนารีของคุณควรบอกได้อย่างแม่นยำว่ามาจากที่ใด เราแทรกคอมมิต git และวันที่บิลด์ไว้ในขั้นตอนการลิงก์ ซึ่งมีความสำคัญอย่างยิ่งในการดีบักเอเจนต์ BigBlueButton บนคลัสเตอร์ต่าง ๆ หลายสิบแห่ง

3. การตรึงอิมเมจคอมไพเลอร์

วัฒนธรรมของเราเชื่อมั่นในความสม่ำเสมอ การตรึง golang:1.26.5-trixie แทนการใช้ latest หมายความว่า หาก Ahmed บิลด์ไบนารีในวันนี้ และ Omar บิลด์อีกครั้งในอีกหกเดือน ผลลัพธ์จะเหมือนกันทุกบิต

บทสรุป

คอมไพเลอร์เป็นเครื่องมือ และเช่นเดียวกับเครื่องมือทุกชนิด ควรถูกเก็บไว้ในที่ของมัน การย้ายชุดเครื่องมือ Go เข้าไปไว้ใน Docker ช่วยให้เรากำจัดข้อบกพร่องประเภท "เครื่องผมใช้ได้" ไปได้ทั้งหมด และทำให้การรับวิศวกรใหม่ทุกคนที่เข้าร่วม RIADVICE ง่ายขึ้น

ไม่ว่าคุณจะเขียนเอเจนต์ Java ใหม่หรือสร้าง API ที่ปลอดภัยสำหรับ Piler รูปแบบนี้มอบวินัยและความน่าเชื่อถือที่ระบบใช้งานจริงต้องการ


Ghazi Triki เป็นผู้ก่อตั้ง RIADVICE เราสร้างระบบเชื่อมต่อที่มีประสิทธิภาพสูงและปลอดภัยสำหรับ BigBlueButton, Piler และอื่น ๆ มาร่วมสร้างสิ่งที่ยอดเยี่ยมไปด้วยกัน

🔗 ดาวน์โหลด golang-docker-boilerplate บน GitHub

แชร์บทความนี้

  • ZcaleRight 1.0.0 พร้อมให้บริการทั่วไป
    BigBlueButton · อ่าน 2 นาที

    ZcaleRight 1.0.0: บริหารเซิร์ฟเวอร์สิบเครื่องได้ง่ายเหมือนเครื่องเดียว

    ZcaleRight จัดสรรการประชุม BigBlueButton ในระบบใช้งานจริงมาตั้งแต่ปี 2019 วันนี้รุ่น 1.0.0 พร้อมให้บริการทั่วไป: เผยแพร่ความสามารถทั้ง 69 รายการอย่างเปิดเผย มีคู่มือในตัวผลิตภัณฑ์ มีข้อตกลงระดับการให้บริการรองรับ และมีเว็บไซต์ของตนเอง

  • Open Source · อ่าน 7 นาที

    เปิดตัว Sukarix 0.4.0: ระบบคิว Redis ปริมาณงานสูงสำหรับไปป์ไลน์ที่รับโหลดหนักในการใช้งานจริง

    การรัน Lua แบบอะตอมมิก การตัดรายการซ้ำด้วยการตรวจสอบสมาชิกในตัว การบันทึกความคืบหน้าแบบมีโครงสร้าง และ Dependency Injection แบบเข้มงวด: Sukarix 0.4.0 มอบขีดความสามารถระดับองค์กรโดยไม่ทำให้เฟรมเวิร์กอุ้ยอ้าย และขับเคลื่อนไปป์ไลน์ BigBlueButton Analytics แบบเรียลไทม์ของเรา

  • จากเจ็ดปีเหลือเจ็ดวัน
    Education · อ่าน 5 นาที

    จาก 7 ปีเหลือ 7 วันด้วย Agentic AI

    หากคุณเคยเห็นสเปรดชีต COCOMO II คาดการณ์ระยะเวลา 33 เดือนตามปฏิทินสำหรับโครงการที่ทีมของคุณส่งมอบได้ภายในสองสปรินต์ คุณย่อมรู้ปัญหาอยู่แล้ว: แบบจำลองการประมาณการถูกปรับเทียบไว้สำหรับโลกที่ไม่มีอยู่อีกต่อไป