ข้ามไปยังเนื้อหา

GitHub Actions CI

การ build และ push image ด้วยมือเป็นสิ่งที่ผิดพลาดได้ง่าย CI pipeline ช่วยให้ทุก merge ไปยัง main branch สร้าง image ที่ผ่านการทดสอบ, มี tag, และเผยแพร่แล้ว — โดยไม่ต้องทำขั้นตอนด้วยมือ

GitHub Actions เป็นตัวเลือกที่นิยมที่สุดสำหรับโปรเจกต์บน GitHub ทีม Docker เผยแพร่ action อย่างเป็นทางการสี่ตัวที่ทำให้เรื่องนี้ง่ายขึ้นมาก:

Actionจุดประสงค์
docker/login-actionAuthenticate กับ registry ใด ๆ
docker/setup-buildx-actionเปิดใช้ BuildKit (multi-platform, cache mounts)
docker/metadata-actionสร้าง tag และ label จาก Git metadata
docker/build-push-actionBuild และ push ในขั้นตอนเดียว

Credentials ของ registry ต้องไม่ปรากฏใน repository เด็ดขาด เก็บไว้เป็น encrypted repository secrets:

  1. ไปที่ repository → Settings → Secrets and variables → Actions → New repository secret
  2. เพิ่ม DOCKERHUB_USERNAME และ DOCKERHUB_TOKEN (ใช้ Docker Hub access token ไม่ใช่รหัสผ่าน)

Workflow ด้านล่างอ้างอิงค่าเหล่านี้ผ่าน ${{ secrets.DOCKERHUB_USERNAME }} และ ${{ secrets.DOCKERHUB_TOKEN }} — GitHub Actions จะแทนที่ค่าจริงตอน runtime และซ่อนไว้ใน log

สร้าง .github/workflows/docker.yml ใน repository ของคุณ:

name: Build and push Docker image
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # needed if pushing to GHCR
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: acme/api-server
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-,format=short
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

หากต้องการ push ไป GitHub Container Registry ให้เปลี่ยน login step และชื่อ image:

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

และอัปเดตค่า images: ใน metadata-action:

images: ghcr.io/${{ github.repository }}

GITHUB_TOKEN ถูกเตรียมโดย GitHub Actions โดยอัตโนมัติ — ไม่ต้องสร้าง secret ด้วยมือ

สำหรับ git tag v2.1.0 metadata action จะสร้าง:

acme/api-server:2.1.0
acme/api-server:2.1
acme/api-server:latest
acme/api-server:sha-abc1234

เมื่อ push บน branch ธรรมดา (ไม่มี semver tag) จะมีเฉพาะ sha- tag และชื่อ branch — latest จะถูกตั้งค่าเฉพาะเมื่อมี tagged release เท่านั้น

บรรทัด cache-from: type=gha และ cache-to: type=gha,mode=max ใช้ GitHub Actions cache เก็บ BuildKit layer ระหว่าง run ซึ่งสามารถลดเวลา build ได้ 70-90% สำหรับ layer ที่ไม่เปลี่ยนแปลง

  • push: ${{ github.event_name != 'pull_request' }} — build ทุก PR เพื่อตรวจสอบ แต่ push เฉพาะเมื่อ merge เข้า main
  • setup-buildx-action เปิดใช้ BuildKit (layer cache, multi-platform, --mount ใน RUN)
  • ห้ามใส่ credentials ตรง ๆ ใน YAML file ใช้ secrets.* เสมอ
ตัวเลือกBenefitCost
Push ไป Docker Hub ด้วย login-actionEcosystem ใหญ่ pull ได้จากทุกที่ต้องสร้างและหมุนเวียน DOCKERHUB_TOKEN เอง และผูกกับ rate limit ของ Docker Hub
Push ไป GHCR ด้วย GITHUB_TOKENไม่ต้องสร้าง secret เพิ่ม permission ผูกกับ repository โดยอัตโนมัติToken มีอายุแค่ในระหว่าง job ใช้ pull นอก workflow ไม่ได้ตรง ๆ และผูกกับ GitHub เป็นหลัก
  • Hardcode credentials ไว้ตรง ๆ ใน workflow YAML แทนที่จะอ้างอิงผ่าน secrets.*
  • ใช้รหัสผ่านธรรมดาแทน access token ใน docker/login-action
  • ไม่จำกัด permissions: ของ job ทำให้ GITHUB_TOKEN มีสิทธิ์กว้างเกินความจำเป็น
  • ฝัง credentials ไว้ใน Dockerfile layer (เช่น ผ่าน ARG ที่มี token) แทนที่จะใช้ BuildKit build secrets

💡 ตัวอย่างจากของจริง

docker/build-push-action เป็น GitHub Action มาตรฐานที่ทีมทั่ววงการใช้ build และ push image ใน CI แทบทุก workflow ที่เกี่ยวกับ Docker บน GitHub Actions จะพึ่งพา action ตัวนี้ร่วมกับ setup-buildx-action และ metadata-action

เหตุใดจึงใช้ `push: ${{ github.event_name != 'pull_request' }}` ใน build-push-action?
docker/metadata-action สร้างอะไรจาก git tag เช่น v2.1.0?
ควรเก็บ Docker Hub credentials ไว้ที่ใดใน GitHub Actions workflow?
docker/setup-buildx-action มีจุดประสงค์อะไรใน CI workflow?