เริ่มต้น CI ด้วย GitHub Actions: คู่มือลงมือทำจริงใน 6 ขั้นตอน
เริ่มต้น CI ด้วย GitHub Actions: คู่มือลงมือทำจริงใน 6 ขั้นตอน
ทีมที่รวมโค้ดกันบ่อยแต่ไม่มีระบบตรวจอัตโนมัติ จะเจอปัญหาเดิมซ้ำ ๆ คือโค้ดพังหลุดเข้า main และ "ที่เครื่องผมรันได้" บทความนี้พาคุณตั้ง Continuous Integration ตัวแรกด้วย GitHub Actions บน repo จริง ใช้เวลาประมาณ 10 นาที
สารบัญ
- CI คืออะไร และแก้ปัญหาอะไร
- GitHub Actions และศัพท์ที่ต้องรู้
- ภาพรวม 6 ขั้นตอนที่จะทำ
- ขั้นที่ 1–2 สร้าง branch และไฟล์ workflow
- ขั้นที่ 3 เขียนไฟล์ ci.yml ฉบับเต็ม
- ขั้นที่ 4–5 push เปิด PR และอ่านผลใน Actions
- ขั้นที่ 6 ตั้ง required check แล้วทดสอบว่าบล็อกได้จริง
- ปัญหาที่พบบ่อยและวิธีแก้
- แนวปฏิบัติที่ดี
- สรุป
สิ่งที่ต้องเตรียม
| รายการ | รายละเอียด |
|---|---|
| บัญชี GitHub | ใช้บัญชีฟรีได้ Actions มีโควตาให้ repo สาธารณะแบบไม่จำกัด |
| สิทธิ์บน repo | ต้อง push ได้ และถ้าจะตั้ง branch protection ต้องเป็น admin |
| โปรเจกต์ Node.js | มี package.json และรัน npm test ได้ (ตัวอย่างในบทความใช้ Node.js) |
| Git บนเครื่อง | ตรวจด้วย git --version |
หมายเหตุ ถ้าโปรเจกต์ของคุณเป็น Python, Go หรือ Java แนวคิดทุกขั้นตอนเหมือนกันทั้งหมด เปลี่ยนเฉพาะ action ที่ใช้ติดตั้งภาษาและคำสั่งใน
run:เท่านั้น
1. CI คืออะไร และแก้ปัญหาอะไร
Continuous Integration (CI) คือแนวทางที่นักพัฒนารวมโค้ดเข้าสู่ที่กลางบ่อย ๆ และทุกครั้งที่รวม จะมีระบบ build และ test อัตโนมัติทำงานทันที เพื่อจับปัญหาให้เร็วที่สุด
วงจรพื้นฐานมีสี่จังหวะ: push โค้ด → build อัตโนมัติ → รัน test → รายงานผล
เปรียบเทียบให้เห็นภาพ:
| ไม่มี CI | มี CI |
|---|---|
| ตรวจด้วยมือ ลืมรัน test บ่อย | ทุก PR ถูก build + test อัตโนมัติ |
| โค้ดพังหลุดเข้า main | โค้ดพังถูกบล็อกก่อนเข้า main |
| "ที่เครื่องผมรันได้" แต่ที่อื่นพัง | รันในสภาพแวดล้อมสะอาดเหมือนกันทุกครั้ง |
| รวมโค้ดทีเดียวตอนท้าย = integration hell | รวมทีละนิด ปัญหาเล็กและแก้ง่าย |
จุดที่ CI ทำงานใน GitHub Flow คือตอน เปิดหรืออัปเดต Pull Request — build/test ทุกครั้งก่อนโค้ดจะถูกรวมเข้า main จึงทำหน้าที่เป็น "ยาม" ที่คอยกันโค้ดเสีย
2. GitHub Actions และศัพท์ที่ต้องรู้
GitHub Actions คือระบบ CI/CD ที่มากับ GitHub ในตัว เราเขียน workflow เป็นไฟล์ YAML เก็บไว้ใน repo แล้ว GitHub จะรันให้อัตโนมัติเมื่อเกิดเหตุการณ์ที่กำหนด — ไม่ต้องตั้งเซิร์ฟเวอร์เอง
| ศัพท์ | ความหมาย |
|---|---|
| Workflow | กระบวนการอัตโนมัติทั้งชุด เก็บเป็นไฟล์ .yml |
| Event | ตัวกระตุ้นให้ workflow ทำงาน เช่น push, pull_request |
| Job | กลุ่มของงานที่รันบน runner เดียวกัน |
| Step | ขั้นตอนย่อยใน job (รันคำสั่ง หรือเรียก action) |
| Action | ชิ้นงานสำเร็จรูปที่นำมาใช้ซ้ำได้ เช่น actions/checkout |
| Runner | เครื่องเสมือนที่รันงานให้ เช่น ubuntu-latest |
Event ที่ใช้บ่อย:
push— เมื่อ push โค้ดขึ้น branchpull_request— เมื่อเปิดหรืออัปเดต PRschedule— ตามเวลาที่กำหนดด้วย cronworkflow_dispatch— กดรันเองจากหน้าเว็บ
3. ภาพรวม 6 ขั้นตอนที่จะทำ
| # | ขั้นตอน | ผลลัพธ์ที่ได้ |
|---|---|---|
| 1 | เตรียม repo | โปรเจกต์ที่รัน npm test ผ่านบนเครื่อง |
| 2 | สร้าง branch | branch ใหม่ชื่อ add-ci แยกจาก main |
| 3 | เขียน ci.yml | ไฟล์ workflow ใน .github/workflows/ |
| 4 | push + เปิด PR | Pull Request ที่ชี้ไปยัง main |
| 5 | ดูผลใน Actions | เห็น log ทีละ step และแก้เมื่อขึ้นแดง |
| 6 | ตั้ง required check | ปุ่ม Merge ถูกบล็อกจนกว่า CI จะเขียว |
4. ขั้นที่ 1–2 สร้าง branch และไฟล์ workflow
4.1 แยก branch ใหม่ก่อนเสมอ
อย่าแก้บน main โดยตรง เพราะเราต้องการให้ CI ตรวจงานผ่าน Pull Request
git checkout main
git pull
git checkout -b add-ciผลลัพธ์ที่ควรเห็น:
Switched to a new branch 'add-ci'4.2 สร้างโฟลเดอร์และไฟล์ workflow
GitHub มองหา workflow ที่ .github/workflows/ เท่านั้น วางผิดที่จะไม่ถูกรัน
mkdir -p .github/workflows
touch .github/workflows/ci.yml
ls .github/workflowsci.ymlเคล็ดลับ ชื่อไฟล์จะเป็นอะไรก็ได้ แต่ต้องนามสกุล
.ymlหรือ.yamlและอยู่ใต้.github/workflows/เท่านั้น
4.3 ทางเลือก: สร้างผ่านหน้าเว็บ GitHub
ถ้ายังไม่ถนัดบรรทัดคำสั่ง เปิดหน้า repo → แท็บ Actions → เลือก set up a workflow yourself GitHub จะสร้างไฟล์ให้ในตำแหน่งที่ถูกต้องพร้อมเทมเพลตเริ่มต้น
5. ขั้นที่ 3 เขียนไฟล์ ci.yml ฉบับเต็ม
คัดลอกไฟล์นี้ไปใช้ได้ทันทีกับโปรเจกต์ Node.js แล้วปรับชื่อคำสั่งให้ตรงกับ package.json ของคุณ
name: CI
on:
pull_request:
branches: [ main ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run buildอ่านทีละส่วน
| ส่วน | ทำอะไร |
|---|---|
name / on | ตั้งชื่อ workflow และกำหนดให้ทริกเกอร์เมื่อเปิดหรืออัปเดต PR ที่ปลายทางเป็น main |
jobs.build-and-test | นิยาม job หนึ่งตัว ชื่อนี้จะไปปรากฏเป็นชื่อ status check บน PR |
runs-on: ubuntu-latest | ขอ runner เครื่องเสมือน Ubuntu ล่าสุดจาก GitHub |
actions/checkout@v4 | ดึงซอร์สโค้ดของ repo ลงมาไว้บน runner ถ้าไม่มีขั้นนี้ runner จะว่างเปล่า |
actions/setup-node@v4 | ติดตั้ง Node.js 20 และเปิด cache ให้ npm เพื่อให้รอบถัดไปเร็วขึ้น |
npm ci | ติดตั้ง dependency แบบ clean ตาม package-lock.json เป๊ะ ๆ (ต่างจาก npm install) |
npm run lint / npm test / npm run build | ตรวจสไตล์ รันเทสต์ และสร้าง production build ตามลำดับ |
สำคัญ step ทำงานเรียงจากบนลงล่าง ถ้า step ใดล้ม job จะหยุดทันทีและ step ที่เหลือจะไม่ถูกรัน นี่คือเหตุผลที่เราเรียง
lint → test → buildจากเร็วไปช้า
ปรับให้เข้ากับภาษาอื่น
Python
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt
- run: pytestGo
- uses: actions/setup-go@v5
with:
go-version: "1.22"
- run: go test ./...
- run: go build ./...6. ขั้นที่ 4–5 push เปิด PR และอ่านผลใน Actions
6.1 Commit และ push
git add .github/workflows/ci.yml
git commit -m "ci: add build and test workflow"
git push -u origin add-ciGit จะพิมพ์ลิงก์สำหรับเปิด PR กลับมาให้:
remote: Create a pull request for 'add-ci' on GitHub by visiting:
remote: https://github.com/<user>/<repo>/pull/new/add-ciหรือเปิด PR จากบรรทัดคำสั่งด้วย GitHub CLI:
gh pr create --fillhttps://github.com/<user>/<repo>/pull/76.2 ดู workflow ทำงาน
เมื่อ PR ถูกเปิด workflow จะเริ่มรันทันที เปิดแท็บ Actions หรือกดที่ status check บน PR เพื่อดูความคืบหน้าทีละ step
CI / build-and-test
✓ Set up job 2s
✓ actions/checkout@v4 4s
✓ actions/setup-node@v4 9s
✓ npm ci 23s
✓ npm run lint 7s
✕ npm test 12s6.3 อ่าน log เมื่อขึ้นแดง
- คลิกที่ step ที่ล้ม (ตัวอย่างข้างบนคือ
npm test) - เลื่อนหา บรรทัดแรก ที่ขึ้น
errorหรือFAIL— นั่นคือสาเหตุจริง บรรทัดที่ตามมามักเป็นผลพวง - แก้โค้ดบนเครื่อง แล้ว
git pushซ้ำบน branch เดิม - workflow จะรันใหม่อัตโนมัติทุกครั้งที่มี commit ใหม่บน branch ของ PR
7. ขั้นที่ 6 ตั้ง required check แล้วทดสอบว่าบล็อกได้จริง
CI จะมีพลังก็ต่อเมื่อ บังคับใช้ มิฉะนั้นทุกคนก็ merge ข้ามได้อยู่ดี
7.1 ตั้ง branch protection
- เปิด Settings ของ repo แล้วเลือก Branches
- กด Add branch protection rule
- ใส่ Branch name pattern เป็น
main - ติ๊ก Require status checks to pass before merging
- ค้นหาและเลือก build-and-test จากรายการ (ชื่อนี้มาจาก key ใต้
jobs:ในไฟล์ YAML) - กด Create เพื่อบันทึกกฎ
ถ้าหา
build-and-testไม่เจอในรายการ แปลว่า check นั้นยังไม่เคยรันบน repo นี้เลย ให้เปิด PR หนึ่งครั้งให้ workflow รันจบก่อน แล้วกลับมาตั้งค่าใหม่
7.2 ทดสอบว่าบล็อกได้จริง
นี่คือขั้นที่คนส่วนใหญ่ข้าม แต่เป็นขั้นที่พิสูจน์ว่าระบบทำงาน
- แก้เทสต์ให้ล้มหนึ่งข้อโดยตั้งใจ
git pushขึ้น PR เดิม- สังเกตว่า GitHub แสดง Some checks were not successful และปุ่ม Merge ถูกปิด
- แก้กลับให้เทสต์ผ่าน แล้ว push ซ้ำ จนขึ้น All checks have passed
| สถานะบน PR | ความหมาย | merge ได้ไหม |
|---|---|---|
| 🟡 กำลังรัน | workflow ยังทำงานไม่เสร็จ | ยัง |
| ✅ All checks have passed | build/test ผ่านทั้งหมด | ได้ |
| ❌ Some checks were not successful | มี step ล้ม คลิกดู log ได้ | ไม่ได้ ถ้าตั้ง required |
8. ปัญหาที่พบบ่อยและวิธีแก้
| อาการ | สาเหตุที่พบบ่อย | วิธีแก้ |
|---|---|---|
| workflow ไม่รันเลย | ไฟล์ไม่ได้อยู่ใน .github/workflows/ หรือนามสกุลผิด | ย้ายไฟล์ให้ถูกที่และใช้ .yml |
| workflow ไม่รันบน PR | ตั้ง on: push อย่างเดียว | เพิ่ม pull_request: ใน on: |
npm ci ล้ม | ไม่มี package-lock.json หรือไม่ตรงกับ package.json | commit lock file ขึ้น repo และรัน npm install ให้ตรงกันก่อน |
| YAML error | ใช้ tab แทน space หรือย่อหน้าไม่ตรง | YAML ห้ามใช้ tab ใช้ space สองตัวต่อระดับ |
| CI ช้ามาก | ติดตั้ง dependency ใหม่ทุกครั้ง | ใส่ cache: npm ใน setup-node |
| หา required check ไม่เจอ | check ยังไม่เคยรัน | เปิด PR ให้ workflow รันจบหนึ่งครั้งก่อน |
npm run lint ล้มทั้งที่ยังไม่มี script | package.json ไม่มี script ชื่อนั้น | ลบ step นั้นออก หรือเพิ่ม script ใน package.json |
9. แนวปฏิบัติที่ดี
- เริ่มจากง่าย — แค่ build + test ก็มีคุณค่ามหาศาลแล้ว อย่าพยายามใส่ทุกอย่างตั้งแต่วันแรก
- ทำให้ CI เร็ว — เปิด cache และเรียง step จากเร็วไปช้า ถ้า CI ใช้เวลาเกิน 10 นาที คนจะเริ่มเลี่ยงมัน
- ตั้งเป็น required check — CI ที่ merge ข้ามได้ ไม่ต่างจากไม่มี CI
- แก้ CI แดงทันที — อย่าปล่อยให้ main พังค้างไว้ เพราะทุกคนจะติดตามไปด้วย
- ให้ชื่อ job สื่อความหมาย — ชื่อ job คือชื่อ status check ที่ทุกคนเห็นบน PR
- ตรึงเวอร์ชัน action — ใช้
@v4ไม่ใช่@mainเพื่อไม่ให้ workflow พังเองจากการอัปเดตต้นทาง
10. สรุป
| ประเด็น | ใจความ |
|---|---|
| CI | รวมโค้ดบ่อย + ตรวจอัตโนมัติ เพื่อจับปัญหาเร็วและกัน main พัง |
| GitHub Actions | เขียน workflow YAML ใน .github/workflows/ แล้วมันรันให้เอง |
| Status checks | ผลเขียว/แดงบน PR และ required check ที่บังคับก่อน merge |
แนวคิดสำคัญของทั้งหมดนี้คือ ให้เครื่องตรวจงานซ้ำ ๆ แทนเรา ทีมจะส่งงานได้เร็วขึ้นโดยไม่เสียคุณภาพ
ขั้นถัดไป: Docker Images & Registries — สร้าง image, จัดการ tag และ push ขึ้น registry เพื่อต่อยอด CI ไปสู่ CD