GitHub Actions — คู่มือ CI/CD Pipeline ฉบับสมบูรณ์สำหรับ Production 2026
ถ้าคุณยัง deploy ด้วยการ SSH เข้า server แล้ว git pull ด้วยมือ หรือ copy ไฟล์ผ่าน FTP — คุณกำลังเสี่ยงกับ human error ที่อาจทำให้ production ล่มได้ทุกเมื่อ GitHub Actions คือ CI/CD platform ที่ built-in มากับ GitHub ใช้ฟรีสำหรับ public repos และมี free tier 2,000 minutes/month สำหรับ private repos ไม่ต้องติดตั้งอะไรเพิ่ม ไม่ต้อง manage Jenkins server แค่สร้างไฟล์ YAML ก็มี CI/CD pipeline ที่ทำงานอัตโนมัติทันที
ผมย้ายจาก Jenkins มาใช้ GitHub Actions ตั้งแต่ปี 2020 ตอนนี้ดูแล workflows กว่า 50 repositories ทั้ง build, test, deploy, infrastructure provisioning และ scheduled tasks บทความนี้จะแชร์ทุกอย่างตั้งแต่พื้นฐานจนถึงเทคนิคขั้นสูงที่ใช้ใน production จริง
สิ่งที่จะได้เรียนรู้:
- GitHub Actions Architecture — Workflows, Jobs, Steps
- Triggers — เมื่อไหร่ควรรัน CI/CD
- Build + Test Pipeline สำหรับทุกภาษา
- Docker Build + Push to Registry
- Deploy to Kubernetes, AWS, VPS
- Secrets Management
- Matrix Strategy — Test หลาย versions พร้อมกัน
- Reusable Workflows
- Self-hosted Runners
- Security Best Practices
GitHub Actions Architecture
GitHub Actions มี 3 ระดับ:
- Workflow — ไฟล์ YAML ที่กำหนดว่าจะทำอะไร เมื่อไหร่ อยู่ใน
.github/workflows/ - Job — กลุ่มของ steps ที่รันบน runner เดียวกัน jobs สามารถรัน parallel หรือ sequential ได้
- Step — คำสั่งเดียว เช่น checkout code, run tests, deploy
# .github/workflows/ci.yml
name: CI Pipeline # ← Workflow name
on: # ← Trigger
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs: # ← Jobs
test: # ← Job name
runs-on: ubuntu-latest # ← Runner
steps: # ← Steps
- uses: actions/checkout@v4
- name: Run tests
run: npm test
Triggers — เมื่อไหร่ควรรัน
# Push to specific branches
on:
push:
branches: [main, develop, 'release/**']
paths:
- 'src/**'
- 'package.json'
paths-ignore:
- '**.md'
- 'docs/**'
# Pull Request
on:
pull_request:
types: [opened, synchronize, reopened]
# Schedule (cron)
on:
schedule:
- cron: '0 2 * * 1' # ทุกวันจันทร์ตี 2
# Manual trigger
on:
workflow_dispatch:
inputs:
environment:
description: 'Deploy to environment'
required: true
type: choice
options: [staging, production]
version:
description: 'Version to deploy'
required: true
type: string
# Tag/Release
on:
push:
tags: ['v*']
release:
types: [published]
🎬 วิดีโอที่เกี่ยวข้อง — YouTube @icafefx
Complete CI/CD Pipeline — Node.js
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# ═══════════════════════════════════
# Job 1: Lint + Type Check
# ═══════════════════════════════════
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run type-check
# ═══════════════════════════════════
# Job 2: Unit Tests (Matrix)
# ═══════════════════════════════════
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
fail-fast: false
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports: ['6379:6379']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
env:
DATABASE_URL: postgresql://test:test@localhost:5432/testdb
REDIS_URL: redis://localhost:6379
- name: Upload coverage
if: matrix.node-version == 20
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
# ═══════════════════════════════════
# Job 3: Build Docker Image
# ═══════════════════════════════════
build:
needs: [lint, test]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=semver,pattern={{version}}
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ═══════════════════════════════════
# Job 4: Deploy to Staging (auto)
# ═══════════════════════════════════
deploy-staging:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes
uses: azure/k8s-deploy@v5
with:
manifests: k8s/staging/
images: ${{ needs.build.outputs.image-tag }}
namespace: staging
- name: Smoke Test
run: |
sleep 30
curl -f https://staging.example.com/health || exit 1
# ═══════════════════════════════════
# Job 5: Deploy to Production (manual approval)
# ═══════════════════════════════════
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production # ← ต้อง approve ใน GitHub
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes
uses: azure/k8s-deploy@v5
with:
manifests: k8s/production/
images: ${{ needs.build.outputs.image-tag }}
namespace: production
strategy: canary
percentage: 20
- name: Health Check
run: |
for i in {1..10}; do
curl -f https://app.example.com/health && break
sleep 10
done
Deploy to VPS via SSH
deploy-vps:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
echo "✅ Deployed at $(date)"
(อ้างอิง: go fiber ci cd automation pipeline)
Deploy to AWS (ECS/Lambda)
deploy-aws:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions
aws-region: ap-southeast-1
# ECS
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster production \
--service myapp \
--force-new-deployment
# Lambda
- name: Deploy Lambda
run: |
aws lambda update-function-code \
--function-name myfunction \
--image-uri ${{ needs.build.outputs.image-tag }}
ผู้เชี่ยวชาญแนะนำ - siamlancard
แนะนำ: | | |
Secrets Management
# ❌ ห้ามทำ — hardcode secrets
env:
API_KEY: sk-1234567890
# ✅ ใช้ GitHub Secrets
env:
API_KEY: ${{ secrets.API_KEY }}
# ✅ ใช้ OIDC สำหรับ AWS (ไม่ต้องเก็บ access keys)
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-southeast-1
# ✅ ใช้ Environment secrets (แยกตาม environment)
# Settings → Environments → production → Add secret
Reusable Workflows
# .github/workflows/reusable-deploy.yml
name: Reusable Deploy
on:
workflow_call:
inputs:
environment:
required: true
type: string
image-tag:
required: true
type: string
secrets:
KUBE_CONFIG:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- name: Deploy
run: |
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig
kubectl --kubeconfig=kubeconfig set image deployment/app \
app=${{ inputs.image-tag }} -n ${{ inputs.environment }}
# เรียกใช้จาก workflow อื่น
jobs:
deploy-staging:
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: staging
image-tag: ghcr.io/myorg/myapp:abc123
secrets:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG_STAGING }}
Self-hosted Runners
# ติดตั้ง self-hosted runner (Linux)
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.314.1.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.314.1/actions-runner-linux-x64-2.314.1.tar.gz
tar xzf ./actions-runner-linux-x64-2.314.1.tar.gz
./config.sh --url https://github.com/myorg/myrepo --token YOUR_TOKEN
sudo ./svc.sh install
sudo ./svc.sh start
# ใช้ self-hosted runner
jobs:
build:
runs-on: self-hosted # ← ใช้ runner ของเรา
steps:
- uses: actions/checkout@v4
- run: make build
ใช้ self-hosted runners เมื่อ:
- ต้องการ hardware พิเศษ (GPU, ARM)
- ต้อง access internal network
- ต้องการ build เร็วขึ้น (SSD, more CPU)
- ใช้ minutes เกิน free tier
สำหรับรายละเอียดเพิ่มเติม ดู python httpx ci cd automation pipeline
Security Best Practices
- Pin action versions ด้วย SHA — ไม่ใช่ tag ที่อาจถูกเปลี่ยน
- ใช้ least privilege permissions
- ใช้ OIDC แทน long-lived credentials
- Review third-party actions ก่อนใช้
- ใช้ Environment protection rules สำหรับ production
- Enable branch protection — require PR review + status checks
# Pin ด้วย SHA (ปลอดภัยกว่า tag)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Least privilege permissions
permissions:
contents: read
packages: write
# ไม่ให้ permissions อื่นที่ไม่จำเป็น
หากสนใจเพิ่มเติม อ่านได้ที่ typescript trpc ci cd automation pipeline
Troubleshooting
ปัญหา 1: Workflow ไม่ trigger
# ตรวจสอบ:
# 1. ไฟล์อยู่ใน .github/workflows/ ไหม
# 2. YAML syntax ถูกต้องไหม (ใช้ actionlint ตรวจ)
# 3. Branch/path filter ตรงไหม
# 4. Workflow ถูก disable ไหม (Actions tab → Enable)
ปัญหา 2: Cache ไม่ทำงาน
# ใช้ actions/cache อย่างถูกต้อง
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
ปัญหา 3: Timeout
# ตั้ง timeout สำหรับ job
jobs:
test:
timeout-minutes: 30 # default 360 minutes!
runs-on: ubuntu-latest
ผมเคยเขียนเรื่องที่เกี่ยวข้องไว้ใน aws step functions ci cd automation pipeline
คำถามที่พบบ่อย (FAQ)
Q: GitHub Actions ฟรีไหม?
A: Public repos ฟรีไม่จำกัด Private repos ได้ 2,000 minutes/month (free plan) ถ้าเกินจ่าย $0.008/minute
Q: GitHub Actions กับ GitLab CI ต่างกันอย่างไร?
A: คล้ายกันมาก GitHub Actions มี marketplace ของ actions ที่ใหญ่กว่า GitLab CI มี built-in container registry และ DevOps features มากกว่า เลือกตามที่ใช้ Git hosting
Q: ใช้กับ monorepo ได้ไหม?
A: ได้ ใช้ paths filter เพื่อ trigger เฉพาะ package ที่เปลี่ยน หรือใช้ tools เช่น Turborepo, Nx
Q: ทำ rollback ยังไง?
A: ใช้ workflow_dispatch trigger ให้ deploy version เก่า หรือ revert commit แล้ว push
Q: Artifacts เก็บได้นานแค่ไหน?
A: Default 90 วัน ปรับได้ใน Settings → Actions → General
สรุป — เริ่มใช้ GitHub Actions วันนี้
GitHub Actions เป็น CI/CD platform ที่ง่ายที่สุดในการเริ่มต้น ไม่ต้องติดตั้งอะไร ไม่ต้อง manage server แค่สร้างไฟล์ YAML ก็มี pipeline ที่ build, test, deploy อัตโนมัติ เริ่มจาก lint + test ก่อน จากนั้นเพิ่ม Docker build + deploy ภายใน 1 ชั่วโมงคุณจะมี CI/CD pipeline ที่ทำงานจริง
ถ้ามีคำถาม สอบถามได้ที่ SiamCafe Forum ครับ
💡 เรียนรู้เพิ่มเติม: | | — จาก ผู้เชี่ยวชาญประสบการณ์กว่า 13 ปี
🎬 ดูวิดีโอเพิ่มเติม
เรียนรู้ IT, Forex Trading และเทคนิค Server จากประสบการณ์จริง 30 ปี