
ในยุคดิจิทัลที่ความเร็วคือกุญแจสำคัญสู่ความสำเร็จ การพัฒนาซอฟต์แวร์ก็ต้องปรับตัวให้รวดเร็วและมีประสิทธิภาพมากยิ่งขึ้นครับ กระบวนการ Continuous Integration (CI) และ Continuous Delivery/Deployment (CD) จึงเข้ามามีบทบาทอย่างยิ่งในการช่วยให้ทีมพัฒนาสามารถส่งมอบซอฟต์แวร์คุณภาพสูงออกสู่ตลาดได้อย่างต่อเนื่องและแม่นยำ และเมื่อพูดถึงเครื่องมือที่เข้ามาช่วยให้ CI/CD เป็นเรื่องง่ายและทรงพลังสำหรับโปรเจกต์ที่อยู่บน GitHub ก็คงหนีไม่พ้น GitHub Actions ครับ
บทความนี้จะพาคุณเจาะลึก GitHub Actions อย่างละเอียด ตั้งแต่พื้นฐานของ CI/CD, การทำความเข้าใจส่วนประกอบของ GitHub Actions, การสร้าง Pipeline สำหรับโปรเจกต์จริง, ไปจนถึงเทคนิคขั้นสูงและการดูแลรักษา เพื่อให้คุณสามารถนำไปประยุกต์ใช้กับโปรเจกต์ของคุณได้อย่างมั่นใจครับ ไม่ว่าคุณจะเป็นนักพัฒนา, DevOps Engineer หรือผู้ที่สนใจในกระบวนการพัฒนาซอฟต์แวร์ บทความนี้คือคู่มือฉบับสมบูรณ์สำหรับคุณครับ
สารบัญ
- ทำความเข้าใจพื้นฐาน CI/CD
- เจาะลึก GitHub Actions: หัวใจของการทำงานอัตโนมัติ
- การออกแบบ CI/CD Pipeline ด้วย GitHub Actions สำหรับโปรเจกต์จริง
- ฟีเจอร์และเทคนิคขั้นสูงของ GitHub Actions
- Secrets: การจัดการข้อมูลสำคัญอย่างปลอดภัย
- Environments: การจัดการสภาพแวดล้อมการทำงาน
- Reusable Workflows: ลดความซ้ำซ้อนด้วย Workflow ที่นำกลับมาใช้ใหม่ได้
- Matrix Strategies: การทดสอบข้ามแพลตฟอร์มและเวอร์ชัน
- Caching Dependencies: เพิ่มความเร็วในการทำงาน
- Artifacts: การส่งผ่านข้อมูลระหว่าง Job
- Self-Hosted Runners: รัน Workflow บนเซิร์ฟเวอร์ส่วนตัว
- Conditional Steps/Jobs: ควบคุม Flow การทำงานอย่างชาญฉลาด
- การดูแลและแก้ไขปัญหา GitHub Actions Pipeline
- เปรียบเทียบ GitHub Actions กับ CI/CD Tools อื่นๆ
- คำถามที่พบบ่อย (FAQ)
- สรุปและ Call-to-Action
ทำความเข้าใจพื้นฐาน CI/CD
ก่อนที่เราจะดำดิ่งสู่โลกของ GitHub Actions เรามาทำความเข้าใจแนวคิดหลักของ CI/CD กันก่อนนะครับ เพราะนี่คือรากฐานสำคัญที่จะทำให้เราเห็นภาพรวมและคุณค่าของสิ่งที่เรากำลังจะสร้างขึ้นมาครับ
Continuous Integration (CI) คืออะไร?
Continuous Integration (CI) คือหลักปฏิบัติในการพัฒนาซอฟต์แวร์ที่ทีมพัฒนาจะรวมโค้ดที่เขียนขึ้นเข้ากับ Repository หลัก (main/master branch) บ่อยครั้งที่สุดเท่าที่จะทำได้ โดยปกติแล้วคือวันละหลายๆ ครั้งครับ เมื่อโค้ดถูกรวมเข้าไป ระบบ CI จะทำการ สร้าง (build) และ ทดสอบ (test) โค้ดนั้นโดยอัตโนมัติ เพื่อตรวจหาข้อผิดพลาดหรือความขัดแย้งที่อาจเกิดขึ้นได้ตั้งแต่เนิ่นๆ ครับ
ประโยชน์ของ CI:
- ตรวจพบข้อผิดพลาดได้เร็ว: การรวมโค้ดบ่อยๆ ทำให้ปัญหาถูกค้นพบได้เร็วกว่าการรวมโค้ดครั้งใหญ่ในภายหลัง
- ลดความขัดแย้งของโค้ด: การรวมโค้ดเล็กๆ น้อยๆ บ่อยๆ ช่วยลดโอกาสและความซับซ้อนในการแก้ไขความขัดแย้ง (merge conflicts)
- มั่นใจในคุณภาพโค้ด: ทุกครั้งที่มีการรวมโค้ด ระบบจะรันการทดสอบอัตโนมัติ (Unit Tests, Integration Tests) ทำให้มั่นใจว่าโค้ดที่รวมเข้าไปยังคงทำงานได้อย่างถูกต้อง
- ทีมทำงานร่วมกันได้ดีขึ้น: สมาชิกในทีมเห็นการเปลี่ยนแปลงของโค้ดได้รวดเร็ว และได้รับ Feedback ทันที
Continuous Delivery (CD) และ Continuous Deployment คืออะไร?
หลังจากขั้นตอน CI ที่มั่นใจว่าโค้ดทำงานได้ถูกต้องแล้ว ขั้นตอนต่อไปคือการส่งมอบซอฟต์แวร์ ซึ่งแบ่งออกเป็นสองระดับย่อยคือ Continuous Delivery และ Continuous Deployment ครับ
Continuous Delivery (CD):
Continuous Delivery คือการขยายขีดความสามารถของ CI ไปอีกขั้นครับ โดยหลังจากที่โค้ดผ่านการ Build และ Test ในขั้นตอน CI แล้ว ระบบจะเตรียมโค้ดให้พร้อมสำหรับการ Deploy ไปยัง Production Environment ได้ตลอดเวลา แต่การ Deploy จริงๆ จะยังคงต้องอาศัยการตัดสินใจของมนุษย์ เช่น การกดปุ่มเพื่อ Deploy ครับ นั่นหมายความว่าทีมสามารถส่งมอบซอฟต์แวร์เวอร์ชันใหม่ได้ทุกเมื่อที่ต้องการ โดยที่กระบวนการทั้งหมดตั้งแต่ต้นจนจบถูกทำให้เป็นอัตโนมัติเกือบทั้งหมดแล้ว
Continuous Deployment (CD):
Continuous Deployment คือระดับสูงสุดของการส่งมอบซอฟต์แวร์ครับ โดยขยายจาก Continuous Delivery ด้วยการทำให้ การ Deploy ไปยัง Production Environment เป็นไปโดยอัตโนมัติทั้งหมด หากโค้ดผ่านการทดสอบทั้งหมดในขั้นตอน CI และ CD (Delivery) แล้ว โค้ดนั้นจะถูก Deploy ขึ้นสู่ Production โดยอัตโนมัติทันทีโดยไม่ต้องมีการแทรกแซงจากมนุษย์เลยครับ วิธีนี้ช่วยให้ลูกค้าได้รับฟีเจอร์ใหม่ๆ และการแก้ไขข้อผิดพลาดได้รวดเร็วที่สุด
ประโยชน์ของ CD:
- ส่งมอบซอฟต์แวร์ได้รวดเร็ว: ลดเวลาที่ใช้ในการนำฟีเจอร์ใหม่หรือการแก้ไขข้อผิดพลาดไปสู่ผู้ใช้
- ลดความเสี่ยงในการ Deploy: การ Deploy บ่อยๆ ในขนาดเล็กๆ ทำให้ปัญหาที่อาจเกิดขึ้นมีขอบเขตจำกัดและแก้ไขได้ง่ายกว่า
- Feedback Loop ที่รวดเร็ว: ทีมได้รับ Feedback จากผู้ใช้ได้เร็วขึ้น ทำให้สามารถปรับปรุงผลิตภัณฑ์ได้อย่างต่อเนื่อง
- เพิ่มความน่าเชื่อถือ: กระบวนการที่เป็นอัตโนมัติและสม่ำเสมอช่วยลดความผิดพลาดที่เกิดจากมนุษย์
ทำไมต้อง CI/CD? ประโยชน์ที่คุณจะได้รับ
การนำ CI/CD มาใช้ในกระบวนการพัฒนาซอฟต์แวร์นั้นมีประโยชน์มหาศาลครับ ไม่ใช่แค่การทำให้งานเสร็จเร็วขึ้นเท่านั้น แต่ยังช่วยยกระดับคุณภาพของผลิตภัณฑ์และประสิทธิภาพของทีมโดยรวมอีกด้วยครับ
- เพิ่มความเร็วในการส่งมอบ (Speed to Market): ช่วยให้คุณนำฟีเจอร์ใหม่ๆ หรือการแก้ไขข้อผิดพลาดไปสู่ผู้ใช้ได้เร็วกว่าคู่แข่ง ซึ่งเป็นสิ่งสำคัญในตลาดที่มีการแข่งขันสูง
- ลดความผิดพลาดและข้อบกพร่อง: การทดสอบอัตโนมัติและกระบวนการที่สม่ำเสมอช่วยลดข้อผิดพลาดที่อาจเล็ดลอดไปถึง Production ได้อย่างมากครับ
- ปรับปรุงคุณภาพซอฟต์แวร์: ด้วยการ Feedback ที่รวดเร็วและต่อเนื่อง ทีมสามารถแก้ไขปัญหาและปรับปรุงคุณภาพโค้ดได้ตลอดเวลา
- ลดต้นทุนการดำเนินงาน: การทำงานอัตโนมัติช่วยลดเวลาและแรงงานที่ต้องใช้ในงานซ้ำๆ ทำให้ทีมสามารถโฟกัสกับงานที่สร้างมูลค่าได้มากขึ้น
- สร้างความน่าเชื่อถือและความมั่นใจ: ทีมมีความมั่นใจมากขึ้นในการส่งมอบซอฟต์แวร์ เนื่องจากรู้ว่าทุกการเปลี่ยนแปลงได้ผ่านการทดสอบมาอย่างดีแล้ว
- เพิ่มความโปร่งใส: ทุกคนในทีมสามารถเห็นสถานะของ Pipeline ได้ ทำให้ทราบว่าโค้ดเวอร์ชันล่าสุดอยู่ในขั้นตอนใดและมีปัญหาอะไรเกิดขึ้นบ้าง
เจาะลึก GitHub Actions: หัวใจของการทำงานอัตโนมัติ
เมื่อเราเข้าใจหลักการของ CI/CD แล้ว ก็ถึงเวลามาทำความรู้จักกับเครื่องมือที่จะช่วยให้หลักการเหล่านี้เป็นจริงได้บน GitHub นั่นคือ GitHub Actions ครับ
GitHub Actions คืออะไร?
GitHub Actions คือแพลตฟอร์มสำหรับ Workflow Automation ที่ถูกผสานรวมเข้ากับ GitHub โดยตรงครับ มันช่วยให้คุณสามารถสร้างกระบวนการอัตโนมัติต่างๆ ได้ภายใน Repository ของคุณเอง ไม่ว่าจะเป็นการสร้าง (Build), ทดสอบ (Test), Deploy ซอฟต์แวร์ หรือแม้แต่การจัดการโปรเจกต์อื่นๆ ที่เกี่ยวข้องกับโค้ดของคุณครับ
หัวใจสำคัญของ GitHub Actions คือการกำหนด Workflows ที่จะทำงานโดยอัตโนมัติเมื่อเกิด Events ที่คุณกำหนดไว้ เช่น เมื่อมีการ Push โค้ด, สร้าง Pull Request, หรือแม้กระทั่งกำหนดเวลาให้ทำงานครับ
ส่วนประกอบสำคัญของ GitHub Actions
การทำความเข้าใจส่วนประกอบหลักของ GitHub Actions จะช่วยให้คุณออกแบบและสร้าง Workflow ได้อย่างมีประสิทธิภาพครับ
-
Workflow:
คือกระบวนการอัตโนมัติที่คุณกำหนดขึ้นมาครับ Workflow ถูกเขียนด้วยภาษา YAML และจัดเก็บไว้ในไดเรกทอรี
.github/workflows/ภายใน Repository ของคุณครับ Workflow หนึ่งๆ สามารถประกอบด้วยหนึ่งหรือหลาย Job ครับ# .github/workflows/ci.yml name: CI Pipeline on: [push, pull_request] # กำหนด Event ที่จะเรียก Workflow นี้ jobs: build_and_test: # หนึ่ง Job runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install dependencies run: npm ci - name: Run tests run: npm test -
Event:
คือเหตุการณ์ที่เกิดขึ้นใน Repository ของคุณ ซึ่งจะ trigger ให้ Workflow ทำงานครับ ตัวอย่าง Event เช่น:
push: เมื่อมีการ Push โค้ดไปยัง Branch ที่กำหนดpull_request: เมื่อมีการสร้างหรืออัปเดต Pull Requestschedule: กำหนดเวลาให้ Workflow ทำงานเป็นประจำ (เช่น ทุกวันตอนเที่ยงคืน)workflow_dispatch: อนุญาตให้รัน Workflow ด้วยตนเองผ่าน GitHub UI หรือ GitHub APIrelease: เมื่อมีการสร้าง Release ใหม่
on: push: branches: - main pull_request: branches: - main schedule: - cron: '0 0 * * *' # รันทุกวันตอนเที่ยงคืน UTC workflow_dispatch: # อนุญาตให้รันด้วยตนเอง -
Job:
คือชุดของ Step ที่จะถูก execute บน Runner ตัวเดียวกันครับ Workflow หนึ่งๆ สามารถมีได้หลาย Job และ Job เหล่านี้สามารถทำงานพร้อมกัน (parallel) หรือเรียงลำดับกัน (sequential) ก็ได้ โดยคุณสามารถกำหนด dependencies ระหว่าง Job ได้ด้วยคีย์เวิร์ด
needsครับjobs: build: runs-on: ubuntu-latest steps: - name: Build project run: npm run build deploy: runs-on: ubuntu-latest needs: build # Job 'deploy' จะทำงานหลังจาก Job 'build' เสร็จสิ้นและสำเร็จ steps: - name: Deploy to server run: echo "Deploying..." -
Runner:
คือเซิร์ฟเวอร์ที่ GitHub Actions ใช้ในการรัน Job ของคุณครับ GitHub มี Runner ให้เลือกใช้หลายประเภท (เช่น
ubuntu-latest,windows-latest,macos-latest) หรือคุณจะใช้ Self-Hosted Runner ของคุณเองก็ได้ครับ -
Step:
คือคำสั่งหรือ Action ที่จะถูกรันภายใน Job ครับ แต่ละ Step จะทำหน้าที่เฉพาะอย่าง เช่น การ checkout โค้ด, ติดตั้ง dependency, รัน script, หรือเรียกใช้ Action ที่มีอยู่แล้วครับ
steps: - uses: actions/checkout@v4 # Step ที่ใช้ Action เพื่อ checkout โค้ด - name: Run a one-line script # Step ที่รันคำสั่ง bash run: echo Hello, world! - name: Run a multi-line script run: | echo Add other actions to build, echo test, and deploy your project. -
Action:
คือแอปพลิเคชันที่สามารถนำกลับมาใช้ใหม่ได้ ซึ่งทำหน้าที่เฉพาะอย่างครับ Action สามารถเป็น JavaScript, Docker Container หรือ Composite Action ที่รวมหลาย Step เข้าไว้ด้วยกันก็ได้ครับ มี Action มากมายให้เลือกใช้ใน GitHub Marketplace หรือคุณจะสร้าง Action ของตัวเองก็ได้ครับ ตัวอย่าง Action ที่พบบ่อยเช่น
actions/checkout@v4,actions/setup-node@v4ครับ
ทำไมต้องเลือก GitHub Actions?
GitHub Actions มีข้อดีหลายประการที่ทำให้มันเป็นตัวเลือกที่น่าสนใจสำหรับการทำ CI/CD ครับ
- ผสานรวมกับ GitHub ได้อย่างราบรื่น: เนื่องจากเป็นส่วนหนึ่งของ GitHub โดยตรง ทำให้การตั้งค่าและการจัดการ Workflow ง่ายดายและเข้าถึงได้จาก Repository ของคุณเลยครับ
- มี Actions ให้เลือกใช้มากมาย: GitHub Marketplace มี Actions นับพันให้เลือกใช้สำหรับงานหลากหลายประเภท ไม่ว่าจะเป็นการ Build, Test, Deploy ไปยัง Cloud Providers ต่างๆ ทำให้คุณไม่ต้องเขียนทุกอย่างตั้งแต่เริ่มต้นครับ
- ปรับแต่งได้สูง: ด้วยภาษา YAML ที่ยืดหยุ่น คุณสามารถสร้าง Workflow ที่ซับซ้อนและปรับแต่งให้เข้ากับความต้องการเฉพาะของโปรเจกต์คุณได้อย่างเต็มที่ครับ
- ฟรีสำหรับ Public Repository: GitHub Actions ให้บริการฟรีสำหรับ Public Repository และมีโควต้าฟรีจำนวนหนึ่งสำหรับ Private Repository ซึ่งเป็นจุดเริ่มต้นที่ดีสำหรับโปรเจกต์ขนาดเล็กถึงกลางครับ
- Infrastructure as Code (IaC): Workflow ของคุณถูกจัดเก็บเป็นโค้ดใน Repository ทำให้สามารถติดตามการเปลี่ยนแปลง, ทำเวอร์ชันคอนโทรล, และทบทวนโค้ดได้เหมือนกับโค้ดโปรเจกต์หลักของคุณครับ
- รองรับหลากหลายภาษาและแพลตฟอร์ม: ไม่ว่าโปรเจกต์ของคุณจะใช้ Node.js, Python, Java, .NET, Go, Ruby หรือ Docker, Kubernetes, GitHub Actions ก็สามารถรองรับได้แทบทั้งหมดครับ
การออกแบบ CI/CD Pipeline ด้วย GitHub Actions สำหรับโปรเจกต์จริง
การสร้าง CI/CD Pipeline ด้วย GitHub Actions ไม่ได้ซับซ้อนอย่างที่คิดครับ แต่การออกแบบที่ดีจะช่วยให้ Pipeline ของคุณมีประสิทธิภาพ, บำรุงรักษาง่าย และปลอดภัยครับ
การวางแผนและพิจารณาก่อนสร้าง Pipeline
ก่อนที่จะเริ่มเขียน Workflow YAML มีหลายสิ่งที่ต้องพิจารณาครับ
- ประเภทของโปรเจกต์:
- Web Application (Frontend/Backend): มักจะเกี่ยวข้องกับการ Build โค้ด, รัน Unit/Integration Tests, Linting, การสร้าง Docker Image และการ Deploy ไปยัง Web Server หรือ Container Orchestration System (เช่น Kubernetes, ECS)
- Mobile Application: อาจเกี่ยวข้องกับการ Build APK/IPA, การรัน UI Tests, และการ Deploy ไปยัง App Store หรือ TestFlight
- Library/Package: เน้นการ Build, Test, และ Publish ไปยัง Package Registry (เช่น npm, PyPI, Maven Central)
- เทคโนโลยีที่ใช้:
ภาษาโปรแกรม (Node.js, Python, Java), Framework (React, Angular, Spring Boot, Django), Database (PostgreSQL, MongoDB), Containerization (Docker), Orchestration (Kubernetes)
- สภาพแวดล้อม (Environments):
คุณมีกี่สภาพแวดล้อม? (Development, Staging, Production) การ Deploy ไปยังแต่ละ Environment อาจมีเงื่อนไขและขั้นตอนที่แตกต่างกันครับ
- กลยุทธ์การ Deploy:
คุณต้องการ Deploy แบบไหน? (Rolling Update, Blue/Green Deployment, Canary Release) ซึ่งอาจส่งผลต่อความซับซ้อนของ Pipeline ในส่วน CD ครับ
- ความปลอดภัย:
คุณจะจัดการกับข้อมูลสำคัญ (API Keys, Credentials) อย่างไร? GitHub Actions มี Secrets สำหรับเรื่องนี้ครับ
โครงสร้างไฟล์ Workflow YAML
ไฟล์ Workflow จะอยู่ในไดเรกทอรี .github/workflows/ ครับ ชื่อไฟล์เป็นอะไรก็ได้ เช่น ci.yml, deploy.yml หรือ main.yml ครับ
# .github/workflows/your-workflow-name.yml
name: Your Workflow Name # ชื่อ Workflow ที่จะแสดงใน GitHub UI
on: # กำหนด Event ที่จะ Trigger Workflow
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop
workflow_dispatch: # อนุญาตให้รันด้วยตนเอง
jobs: # กำหนด Job ต่างๆ ที่จะรัน
job-name-1:
runs-on: ubuntu-latest # Runner ที่จะใช้
steps: # ขั้นตอนต่างๆ ใน Job นี้
- uses: actions/checkout@v4 # Action สำหรับ checkout โค้ด
- name: Your Step 1
run: echo "Hello from Job 1, Step 1"
- name: Your Step 2
run: echo "Hello from Job 1, Step 2"
job-name-2:
runs-on: ubuntu-latest
needs: job-name-1 # Job นี้จะรันหลังจาก job-name-1 สำเร็จ
steps:
- name: Your Step 3
run: echo "Hello from Job 2, Step 3"
ตัวอย่างที่ 1: CI/CD สำหรับ Web Application (Node.js + React + Docker)
ตัวอย่างนี้จะแสดง Pipeline สำหรับโปรเจกต์ Web Application ที่ใช้ Node.js (สำหรับ Backend) และ React (สำหรับ Frontend) โดยใช้ Docker ในการสร้าง Image และ Push ไปยัง GitHub Container Registry (GHCR) ครับ
สมมติว่าโครงสร้างโปรเจกต์ของเราเป็นดังนี้ครับ:
.
├── .github/
│ └── workflows/
│ └── main-ci-cd.yml
├── client/ # React frontend
│ ├── package.json
│ ├── Dockerfile (สำหรับ frontend)
│ └── ...
├── server/ # Node.js backend (Express)
│ ├── package.json
│ ├── Dockerfile (สำหรับ backend)
│ └── ...
├── docker-compose.yml
└── README.md
เราจะสร้าง Workflow เดียวเพื่อจัดการทั้ง CI และ CD ครับ
ขั้นตอน CI: Build, Test, Lint, Docker Image Build
ในส่วน CI เราจะทำการ Linting, Testing และ Building ทั้ง Frontend และ Backend รวมถึงการสร้าง Docker Image สำหรับแต่ละส่วนครับ
# .github/workflows/main-ci-cd.yml
name: Fullstack CI/CD Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: # อนุญาตให้รันด้วยตนเอง
env:
NODE_VERSION: '18' # กำหนดเวอร์ชัน Node.js
# กำหนดชื่อ Image และ Tag สำหรับ GHCR
FRONTEND_IMAGE_NAME: 'fullstack-app-frontend'
BACKEND_IMAGE_NAME: 'fullstack-app-backend'
DOCKER_REGISTRY: ghcr.io/${{ github.repository_owner }}
jobs:
# --- CI Jobs ---
lint-test-frontend:
name: Lint & Test Frontend
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: client/package-lock.json
- name: Install Frontend Dependencies
working-directory: ./client
run: npm ci
- name: Run Frontend Lint
working-directory: ./client
run: npm run lint
- name: Run Frontend Tests
working-directory: ./client
run: npm test -- --coverage # รันพร้อมรายงาน Coverage
- name: Archive Test Reports
uses: actions/upload-artifact@v4
if: always() # อัปโหลดเสมอแม้ Test ไม่ผ่าน
with:
name: frontend-test-reports
path: ./client/coverage
lint-test-backend:
name: Lint & Test Backend
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: server/package-lock.json
- name: Install Backend Dependencies
working-directory: ./server
run: npm ci
- name: Run Backend Lint
working-directory: ./server
run: npm run lint
- name: Run Backend Tests
working-directory: ./server
run: npm test -- --coverage # รันพร้อมรายงาน Coverage
- name: Archive Test Reports
uses: actions/upload-artifact@v4
if: always()
with:
name: backend-test-reports
path: ./server/coverage
build-docker-images:
name: Build & Tag Docker Images
runs-on: ubuntu-latest
needs: [lint-test-frontend, lint-test-backend] # รันหลังจาก CI Jobs อื่นๆ สำเร็จ
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # ใช้ GITHUB_TOKEN ที่ GitHub สร้างให้
- name: Build and push Frontend Docker image
uses: docker/build-push-action@v5
with:
context: ./client
file: ./client/Dockerfile
push: false # ตอนนี้ยังไม่ push แค่ build
tags: ${{ env.DOCKER_REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:latest,${{ env.DOCKER_REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push Backend Docker image
uses: docker/build-push-action@v5
with:
context: ./server
file: ./server/Dockerfile
push: false # ตอนนี้ยังไม่ push แค่ build
tags: ${{ env.DOCKER_REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:latest,${{ env.DOCKER_REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Save Docker Images as Artifacts (Optional, for debugging/manual checks)
run: |
docker save ${{ env.DOCKER_REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:latest -o frontend.tar
docker save ${{ env.DOCKER_REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:latest -o backend.tar
if: always()
- name: Upload Docker Images Artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: docker-images
path: |
frontend.tar
backend.tar
คำอธิบาย Workflow CI:
name: ชื่อ Workflowon: กำหนดให้ Workflow ทำงานเมื่อมีการ Push ไปยังmainหรือมีการสร้าง/อัปเดต Pull Request ไปยังmainหรือเมื่อสั่งรันด้วยตนเองenv: กำหนดตัวแปรสภาพแวดล้อมที่ใช้ได้ทั่ว Workflowjobs:lint-test-frontendและlint-test-backend: สอง Job นี้จะทำงานพร้อมกัน (parallel) เพื่อทำการ Lint และ Test โค้ด Frontend และ Backend ตามลำดับ- ในแต่ละ Job จะมีการใช้
actions/checkout@v4เพื่อดึงโค้ด,actions/setup-node@v4เพื่อตั้งค่า Node.js และจัดการ cache ของ npm dependencies เพื่อความเร็ว npm run lintและnpm testถูกรันในไดเรกทอรีที่ถูกต้องโดยใช้working-directoryactions/upload-artifact@v4ใช้สำหรับอัปโหลดรายงานการทดสอบ (coverage reports) เป็น Artifact เพื่อให้สามารถดาวน์โหลดไปตรวจสอบได้ในภายหลังbuild-docker-images: Job นี้จะรันหลังจากlint-test-frontendและlint-test-backendสำเร็จเท่านั้น- มีการใช้
docker/setup-buildx-action@v3เพื่อตั้งค่า Docker Buildx ซึ่งช่วยให้ Build Docker Image ได้อย่างมีประสิทธิภาพ docker/login-action@v3ใช้ในการ Login ไปยัง GitHub Container Registry (GHCR) โดยใช้GITHUB_TOKENซึ่งเป็น Secret ที่ GitHub สร้างให้โดยอัตโนมัติdocker/build-push-action@v5ใช้ในการ Build Docker Image สำหรับทั้ง Frontend และ Backend โดยมีการ Tag Image ด้วยlatestและ${{ github.sha }}(Commit SHA) เพื่อระบุเวอร์ชันpush: falseในขั้นตอนนี้หมายความว่าเราแค่ Build Image แต่ยังไม่ Push ไปยัง Registry ทันที (จะทำในขั้นตอน CD)- มีการใช้
cache-fromและcache-toเพื่อใช้ GitHub Actions Cache ในการเร่งความเร็วการ Build Docker Image - มีการบันทึก Docker Image เป็นไฟล์ .tar และอัปโหลดเป็น Artifact เพื่อให้สามารถดาวน์โหลดไปตรวจสอบหรือใช้งานแบบ Manual ได้ครับ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ GitHub Container Registry คุณสามารถ อ่านเพิ่มเติม ได้ครับ
ขั้นตอน CD: Push Docker Image ไปยัง GitHub Container Registry (GHCR)
หลังจากที่ Docker Image ถูก Build และผ่านการตรวจสอบในขั้นตอน CI แล้ว เราจะทำการ Push Image เหล่านั้นไปยัง GHCR ครับ
# .github/workflows/main-ci-cd.yml (ต่อจากด้านบน)
push-docker-images-to-ghcr:
name: Push Docker Images to GHCR
runs-on: ubuntu-latest
needs: build-docker-images # รันหลังจาก build-docker-images สำเร็จ
if: github.ref == 'refs/heads/main' && github.event_name == 'push' # เฉพาะเมื่อมีการ push ไปที่ main branch เท่านั้น
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get Docker Images from Artifacts
uses: actions/download-artifact@v4
with:
name: docker-images
path: . # ดาวน์โหลดไปยัง root directory
- name: Load Frontend Docker Image
run: docker load --input frontend.tar
- name: Load Backend Docker Image
run: docker load --input backend.tar
- name: Push Frontend Docker image to GHCR
run: |
docker push ${{ env.DOCKER_REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:latest
docker push ${{ env.DOCKER_REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:${{ github.sha }}
- name: Push Backend Docker image to GHCR
run: |
docker push ${{ env.DOCKER_REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:latest
docker push ${{ env.DOCKER_REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:${{ github.sha }}
คำอธิบาย Workflow CD:
push-docker-images-to-ghcr: Job นี้จะรันหลังจากbuild-docker-imagesสำเร็จif: github.ref == 'refs/heads/main' && github.event_name == 'push': นี่คือเงื่อนไขสำคัญที่ทำให้ Job นี้รันเฉพาะเมื่อมีการ Push โค้ดไปยังmainbranch เท่านั้น ซึ่งเป็นหลักการของ Continuous Delivery ที่จะ Push Image ที่พร้อมใช้ไปยัง Registry เมื่อโค้ดในmainถูกอัปเดต- มีการ Login ไปยัง GHCR อีกครั้ง
actions/download-artifact@v4ใช้เพื่อดาวน์โหลด Docker Images ที่ถูก Build ไว้ใน Job ก่อนหน้า (ซึ่งถูกอัปโหลดเป็น Artifact)- ใช้
docker loadเพื่อโหลด Image จากไฟล์ .tar กลับเข้ามาใน Docker Daemon - จากนั้นใช้
docker pushเพื่อ Push Image ทั้ง Frontend และ Backend ไปยัง GHCR
การ Deploy ไปยัง Server (แนวคิดและการประยุกต์ใช้)
การ Deploy จริงๆ ไปยัง Server หรือ Cloud Provider นั้นมีความซับซ้อนและหลากหลายขึ้นอยู่กับ Infrastructure ของคุณครับ แต่หลักการคือคุณจะสร้าง Job อีกตัวที่รันหลังจาก push-docker-images-to-ghcr สำเร็จครับ
ตัวอย่างแนวคิดสำหรับการ Deploy (ไม่ได้ใส่โค้ดเต็มเพื่อความกระชับ แต่ให้แนวคิดครับ):
# .github/workflows/main-ci-cd.yml (ต่อจากด้านบน)
deploy-to-staging:
name: Deploy to Staging Environment
runs-on: ubuntu-latest
needs: push-docker-images-to-ghcr
environment:
name: Staging # ใช้ GitHub Environments
if: github.ref == 'refs/heads/main' && github.event_name == 'push' # Deploy เมื่อ push ไป main
steps:
- name: Deploy using SSH
uses: appleboy/[email protected]
with:
host: ${{ secrets.STAGING_SSH_HOST }}
username: ${{ secrets.STAGING_SSH_USERNAME }}
key: ${{ secrets.STAGING_SSH_KEY }}
script: |
# คำสั่ง SSH เพื่อดึง Docker Image ล่าสุดจาก GHCR และรันบนเซิร์ฟเวอร์
docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.FRONTEND_IMAGE_NAME }}:latest
docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.BACKEND_IMAGE_NAME }}:latest
# สั่งรัน Docker Compose หรือ Kubernetes manifest
# เช่น docker-compose pull && docker-compose up -d
# หรือ kubectl apply -f kubernetes-manifests/
echo "Deployment to Staging complete!"
deploy-to-production:
name: Deploy to Production Environment
runs-on: ubuntu-latest
needs: deploy-to-staging # รันหลังจาก Staging สำเร็จ
environment:
name: Production # ใช้ GitHub Environments
if: github.ref == 'refs/heads/main' && github.event_name == 'push' && github.event.before == '0000000000000000000000000000000000000000' # ตัวอย่างเงื่อนไขสำหรับ Manual deployment to Production
# หรืออาจใช้ workflow_dispatch เพื่อให้ Deploy Production แบบ Manual
steps:
- name: Deploy to Production
# ขั้นตอนการ Deploy ที่คล้ายกับ Staging แต่อาจมีขั้นตอนการอนุมัติเพิ่มเติม
# เช่น ใช้ AWS ECS, Kubernetes, Azure Web Apps
run: echo "Manual approval required for Production deployment."
แนวคิดการ Deploy:
- การใช้ SSH: สำหรับเซิร์ฟเวอร์ทั่วไป คุณสามารถใช้ Action เช่น
appleboy/ssh-actionเพื่อ SSH เข้าไปในเซิร์ฟเวอร์และรันคำสั่ง Docker pull/run หรือ Docker Compose ได้โดยตรง - Cloud Provider Specific Actions: หากคุณใช้บริการ Cloud เช่น AWS ECS/EKS, Google Kubernetes Engine (GKE), Azure Kubernetes Service (AKS) หรือ Azure Web Apps จะมี Actions เฉพาะสำหรับบริการเหล่านั้น เช่น
aws-actions/amazon-ecs-deploy-task@v1,google-github-actions/deploy-cloudrun@v1ซึ่งจะทำให้การ Deploy ง่ายขึ้นมากครับ - GitHub Environments: ใช้เพื่อจัดการกับสภาพแวดล้อมต่างๆ เช่น Staging, Production ซึ่งคุณสามารถกำหนดกฎการป้องกัน (protection rules) เช่น การต้องมีการอนุมัติจากผู้ดูแลก่อนการ Deploy ไปยัง Production ได้ครับ
ตัวอย่างที่ 2: CI/CD สำหรับ Python Library (Test และ Publish ไปยัง PyPI)
ตัวอย่างนี้จะแสดง Pipeline สำหรับ Python Library ที่จะทำการ Lint, Test และ Build Package จากนั้น Publish ไปยัง PyPI (Python Package Index) เมื่อมีการ Push Tag ใหม่ครับ
สมมติว่าโครงสร้างโปรเจกต์ของเราเป็นดังนี้:
.
├── .github/
│ └── workflows/
│ └── python-publish.yml
├── my_python_lib/ # โค้ดไลบรารี
│ ├── __init__.py
│ └── main.py
├── tests/
│ └── test_main.py
├── pyproject.toml # สำหรับ Build และ Metadata
├── README.md
└── LICENSE
ขั้นตอน CI: Lint, Test, Build Python Package
# .github/workflows/python-publish.yml
name: Python Package CI/CD
on:
push:
branches: [ main ]
tags: # Trigger เมื่อมีการ push tag (สำหรับ CD)
- 'v*' # เช่น v1.0.0, v1.0.1
pull_request:
branches: [ main ]
workflow_dispatch:
env:
PYTHON_VERSION: '3.9' # กำหนดเวอร์ชัน Python
jobs:
build_and_test:
name: Build and Test Python Package
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install poetry # หรือ setuptools, wheel
poetry install --no-root # ติดตั้ง dependencies ที่ระบุใน pyproject.toml
- name: Run Linting (Flake8)
run: |
pip install flake8
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Run Tests (pytest)
run: poetry run pytest
- name: Build Python Package
run: poetry build
# หรือ python -m build
- name: Upload distribution artifacts
uses: actions/upload-artifact@v4
with:
name: python-package-dist
path: dist/ # โฟลเดอร์ที่เก็บ .whl และ .tar.gz
คำอธิบาย Workflow CI:
on.tags: - 'v*': นอกจาก push/pull_request แล้ว เรายังกำหนดให้ Workflow ทำงานเมื่อมีการ Push Tag ที่ขึ้นต้นด้วย ‘v’ (เช่น v1.0.0) ซึ่งจะใช้สำหรับ Trigger การ Publish ในขั้นตอน CD ครับactions/setup-python@v5: ใช้ในการตั้งค่าสภาพแวดล้อม Python- มีการติดตั้ง
poetry(หรือ build tools อื่นๆ) เพื่อจัดการ dependency และ Build Package - รัน
flake8สำหรับ Linting และpytestสำหรับ Unit Tests poetry build: คำสั่งสำหรับ Build Python Package (สร้างไฟล์ .whl และ .tar.gz)actions/upload-artifact@v4: อัปโหลดไฟล์ Package ที่ Build ได้เป็น Artifact เพื่อให้ Job ถัดไปสามารถนำไปใช้ได้
ขั้นตอน CD: Publish Package ไปยัง PyPI
Job นี้จะรันเฉพาะเมื่อมีการ Push Tag (ตามที่ระบุใน on.tags) และจะทำการ Publish Package ที่ Build ไว้ไปยัง PyPI ครับ
# .github/workflows/python-publish.yml (ต่อจากด้านบน)
publish-to-pypi:
name: Publish Python Package to PyPI
runs-on: ubuntu-latest
needs: build_and_test # รันหลังจาก Job build_and_test สำเร็จ
# เงื่อนไข: รันเฉพาะเมื่อเป็น Event push และเป็น Tag ที่ขึ้นต้นด้วย 'v'
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
environment:
name: PyPI # ใช้ GitHub Environment เพื่อจัดการ Secrets และ Protection Rules
steps:
- name: Download distribution artifacts
uses: actions/download-artifact@v4
with:
name: python-package-dist
path: dist/
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }} # ใช้ Secret ที่เก็บ PyPI API Token
คำอธิบาย Workflow CD:
needs: build_and_test: Job นี้จะรันหลังจาก Jobbuild_and_testสำเร็จif: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v'): เงื่อนไขสำคัญเพื่อให้ Job นี้ทำงานเฉพาะเมื่อมีการ Push Tag ที่ขึ้นต้นด้วย ‘v’ เท่านั้นครับenvironment: name: PyPI: ใช้ GitHub Environment ชื่อ “PyPI” ซึ่งสามารถกำหนด Protection Rules ได้ เช่น การต้องมีการอนุมัติก่อน Publish หรือการจำกัดว่าใครมีสิทธิ์ Deploy ได้actions/download-artifact@v4: ดาวน์โหลดไฟล์ Package ที่ Build ไว้จาก Artifactpypa/gh-action-pypi-publish@release/v1: Action ที่สะดวกมากสำหรับการ Publish Python Package ไปยัง PyPI ครับpassword: ${{ secrets.PYPI_API_TOKEN }}: ใช้ Secret ที่ชื่อPYPI_API_TOKENซึ่งคุณต้องสร้างและเก็บไว้ใน Repository Settings เพื่อให้ Action สามารถ Authenticate กับ PyPI ได้อย่างปลอดภัยครับ
ฟีเจอร์และเทคนิคขั้นสูงของ GitHub Actions
GitHub Actions มีฟีเจอร์และเทคนิคขั้นสูงมากมายที่ช่วยให้คุณสร้าง Pipeline ที่ซับซ้อน, มีประสิทธิภาพ และปลอดภัยมากยิ่งขึ้นครับ
Secrets: การจัดการข้อมูลสำคัญอย่างปลอดภัย
ใน Pipeline ของคุณ มักจะต้องมีการเข้าถึงข้อมูลสำคัญ เช่น API Keys, Database Credentials, Private SSH Keys หรือ Token ต่างๆ ครับ การเก็บข้อมูลเหล่านี้ไว้ใน Workflow YAML โดยตรงเป็นสิ่งที่ไม่ปลอดภัยอย่างยิ่งครับ
GitHub Secrets ช่วยให้คุณสามารถจัดเก็บข้อมูลที่ละเอียดอ่อนเหล่านี้ได้อย่างปลอดภัย โดยข้อมูลจะถูกเข้ารหัสและจะไม่แสดงใน Log ของ Workflow ครับ คุณสามารถเข้าถึง Secrets ได้ผ่านตัวแปร ${{ secrets.YOUR_SECRET_NAME }} ใน Workflow ของคุณครับ
วิธีการใช้งาน:
- ไปที่ Repository ของคุณ > Settings > Secrets and variables > Actions.
- คลิก “New repository secret” หรือ “New environment secret” (หากใช้ Environments)
- ตั้งชื่อ Secret (เช่น
PYPI_API_TOKEN,AWS_ACCESS_KEY_ID) และใส่ค่าเข้าไป - ใน Workflow ของคุณ สามารถเรียกใช้ได้โดย
${{ secrets.PYPI_API_TOKEN }}
ข้อควรจำ: Secrets จะถูกเปิดเผยต่อ Job ที่รันเท่านั้น และไม่ควรถูกพิมพ์ออกมาใน Log โดยตรงครับ
Environments: การจัดการสภาพแวดล้อมการทำงาน
GitHub Environments ช่วยให้คุณสามารถกำหนดกฎการป้องกัน (protection rules) และตัวแปรเฉพาะสำหรับสภาพแวดล้อมการ Deploy ต่างๆ (เช่น Development, Staging, Production) ได้ครับ
ประโยชน์:
- Protection Rules: กำหนดให้ต้องมีการอนุมัติจากผู้ดูแลก่อน Deploy, กำหนดเวลาที่สามารถ Deploy ได้, หรือจำกัด Branch ที่สามารถ Deploy ไปยัง Environment นั้นๆ ได้
- Environment Secrets: จัดเก็บ Secret ที่ใช้เฉพาะสำหรับ Environment นั้นๆ ทำให้มีความปลอดภัยมากขึ้น และแยก Secret ออกจากกันได้ชัดเจน
- Environment Variables: กำหนดตัวแปรเฉพาะสำหรับ Environment นั้นๆ
วิธีการใช้งาน:
- ไปที่ Repository ของคุณ > Settings > Environments.
- คลิก “New environment” และตั้งชื่อ (เช่น
Staging,Production) - กำหนด Protection Rules และเพิ่ม Environment Secrets/Variables
- ใน Workflow ของคุณ ให้ระบุ
environmentสำหรับ Job นั้นๆ:jobs: deploy-to-production: runs-on: ubuntu-latest environment: name: Production url: https://your-production-app.com # สามารถระบุ URL ได้ steps: # ...
Reusable Workflows: ลดความซ้ำซ้อนด้วย Workflow ที่นำกลับมาใช้ใหม่ได้
หากคุณมีหลาย Repository หรือหลายโปรเจกต์ที่ใช้ CI/CD Pipeline ที่คล้ายคลึงกัน การคัดลอกและวาง Workflow YAML ไปมาเป็นสิ่งที่ไม่ดีครับ Reusable Workflows ช่วยให้คุณสามารถสร้าง Workflow ที่เป็น Template และเรียกใช้จาก Workflow อื่นๆ ได้ ทำให้โค้ดของคุณเป็นระเบียบ, บำรุงรักษาง่าย และลดความซ้ำซ้อนครับ
วิธีการใช้งาน:
- สร้าง Workflow หลัก (เช่น
.github/workflows/callable-workflow.yml) ที่คุณต้องการนำกลับมาใช้ใหม่ - กำหนด
on: workflow_callและระบุinputsและoutputsที่ Workflow นี้จะรับและส่งกลับไป - ใน Workflow อื่นๆ คุณสามารถเรียกใช้ Workflow นี้ได้โดยใช้
uses: ./.github/workflows/callable-workflow.yml@mainหรือuses: owner/repo/.github/workflows/callable-workflow.yml@main# .github/workflows/main-workflow.yml name: Main Workflow Calling Reusable on: [push] jobs: call-build-test: uses: ./.github/workflows/callable-workflow.yml # เรียกใช้ Workflow ใน Repo เดียวกัน with: node-version: '18' working-directory: 'my-app' secrets: my-api-key: ${{ secrets.MY_API_KEY }} # ส่ง secrets ผ่านไปให้
Matrix Strategies: การทดสอบข้ามแพลตฟอร์มและเวอร์ชัน
บ่อยครั้งที่เราต้องการทดสอบโค้ดของเรากับหลายๆ เวอร์ชันของภาษาโปรแกรม, หลายๆ ระบบปฏิบัติการ หรือหลายๆ Dependency ครับ Matrix Strategy ช่วยให้คุณสามารถรัน Job เดียวกันหลายๆ ครั้ง โดยใช้ค่าตัวแปรที่แตกต่างกันไปในแต่ละครั้ง ทำให้การทดสอบครอบคลุมและมีประสิทธิภาพมากขึ้นครับ
วิธีการใช้งาน:
jobs:
test:
runs-on: ${{ matrix.os }} # Runner จะเปลี่ยนไปตามค่า os
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: ['16', '18', '20']
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
จากตัวอย่างนี้ Workflow จะรันทั้งหมด 2 (OS) x 3 (Node.js versions) = 6 Job แยกกันครับ
Caching Dependencies: เพิ่มความเร็วในการทำงาน
การติดตั้ง dependency (เช่น npm install, pip install, composer install) อาจใช้เวลานานในแต่ละครั้งที่ Workflow รันครับ GitHub Actions Cache ช่วยให้คุณสามารถเก็บไฟล์ที่ใช้บ่อย (เช่น โฟลเดอร์ node_modules, pip cache) ไว้ใน Cache และดึงกลับมาใช้ใหม่ในการรันครั้งถัดไป ทำให้ประหยัดเวลาได้อย่างมากครับ
วิธีการใช้งาน:
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm' # เปิดใช้งาน cache สำหรับ npm
cache-dependency-path: package-lock.json # ไฟล์ที่จะใช้ในการสร้าง key ของ cache
- name: Install dependencies
run: npm ci
Action เช่น actions/setup-node, actions/setup-python มักจะมีพารามิเตอร์ cache ให้ใช้ได้โดยตรง หรือคุณสามารถใช้ actions/cache@v4 โดยตรงได้ครับ
Artifacts: การส่งผ่านข้อมูลระหว่าง Job
Artifacts คือไฟล์หรือโฟลเดอร์ที่คุณสร้างขึ้นใน Job หนึ่ง และต้องการนำไปใช้ใน Job อื่น หรือต้องการเก็บไว้เพื่อดาวน์โหลดในภายหลังครับ ตัวอย่างเช่น คุณอาจ Build ไฟล์ Frontend ใน Job แรก และต้องการนำไฟล์เหล่านั้นไป Deploy ใน Job ที่สอง หรือเก็บรายงานการทดสอบไว้เพื่อการตรวจสอบครับ
วิธีการใช้งาน:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Build Frontend
run: npm run build
- name: Upload Build Artifact
uses: actions/upload-artifact@v4
with:
name: web-dist
path: build/ # โฟลเดอร์ที่เก็บไฟล์ที่ Build ได้
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Download Build Artifact
uses: actions/download-artifact@v4
with:
name: web-dist
path: ./dist # โฟลเดอร์ที่จะเก็บไฟล์ที่ดาวน์โหลดมา
- name: Deploy to server
run: echo "Deploying files from ./dist"
Self-Hosted Runners: รัน Workflow บนเซิร์ฟเวอร์ส่วนตัว
โดยปกติ GitHub Actions จะรัน Job ของคุณบน Runner ที่ GitHub จัดเตรียมไว้ให้ครับ แต่ในบางกรณี คุณอาจต้องการรัน Job บนเซิร์ฟเวอร์ของคุณเอง (เช่น เพื่อเข้าถึงทรัพยากรภายในเครือข่าย, ใช้ Hardware เฉพาะทาง, หรือประหยัดค่าใช้จ่าย) ซึ่งสามารถทำได้โดยใช้ Self-Hosted Runners ครับ
ประโยชน์:
- เข้าถึงทรัพยากรภายในเครือข่ายส่วนตัว (VPC)
- ใช้ Hardware ที่มีประสิทธิภาพสูงหรือเฉพาะทาง
- ควบคุมสภาพแวดล้อมการรันได้อย่างเต็มที่
- อาจประหยัดค่าใช้จ่ายสำหรับโปรเจกต์ที่มีการรัน Workflow บ่อยครั้ง
วิธีการใช้งาน:
- ติดตั้ง GitHub Actions Runner application บนเซิร์ฟเวอร์ของคุณ (Linux, Windows, macOS)
- Runner จะลงทะเบียนกับ GitHub Repository หรือ Organization ของคุณ
- ใน Workflow YAML คุณสามารถระบุ Runner ที่คุณต้องการใช้ได้:
jobs: my-custom-job: runs-on: [self-hosted, linux, x64] # ระบุ labels ของ Self-Hosted Runner steps: # ...
คุณสามารถ อ่านเพิ่มเติม เกี่ยวกับการตั้งค่า Self-Hosted Runners ได้ที่เอกสารของ GitHub ครับ
Conditional Steps/Jobs: ควบคุม Flow การทำงานอย่างชาญฉลาด
บางครั้งคุณอาจต้องการให้ Step หรือ Job บางอย่างทำงานภายใต้เงื่อนไขเฉพาะเท่านั้น เช่น Deploy ไป Production เฉพาะเมื่อโค้ดอยู่ใน Branch main เท่านั้น Conditional statements ช่วยให้คุณควบคุม Flow การทำงานของ Workflow ได้อย่างยืดหยุ่น
วิธีการใช้งาน:
ใช้คีย์เวิร์ด if ซึ่งรับ Expression ที่เป็น Boolean ครับ
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Only run on main branch
if: github.ref == 'refs/heads/main'
run: echo "This step runs only on main branch"
deploy-production:
runs-on: ubuntu-latest
needs: build
if: success() && github.ref == 'refs/heads/main' # รันถ้า build สำเร็จและอยู่ใน main branch
steps:
# ...
Expression ที่ใช้ใน if สามารถใช้ฟังก์ชันต่างๆ เช่น startsWith(), contains(), success(), failure(), always() ได้ครับ
การดูแลและแก้ไขปัญหา GitHub Actions Pipeline
การสร้าง Pipeline ไม่ได้จบแค่การเขียน YAML ให้รันได้ครั้งแรกครับ การดูแลรักษาและแก้ไขปัญหาเมื่อเกิดขึ้นเป็นส่วนสำคัญที่จะทำให้ Pipeline ของคุณทำงานได้อย่างราบรื่นและยั่งยืนครับ
การอ่านและวิเคราะห์ Log
เมื่อ Workflow ล้มเหลว หรือไม่ทำงานตามที่คุณคาดหวัง สิ่งแรกที่ควรทำคือการตรวจสอบ Log ครับ
- ไปที่ Repository ของคุณ > Actions tab.
- คลิกที่ Workflow run ที่คุณต้องการตรวจสอบ
- คุณจะเห็นรายการ Job และ Step ทั้งหมด คลิกที่ Job หรือ Step ที่มีเครื่องหมาย “x” หรือเครื่องหมายเตือน
- Log จะแสดงรายละเอียดของสิ่งที่เกิดขึ้นใน Step นั้นๆ ซึ่งมักจะบอกสาเหตุของปัญหาได้อย่างชัดเจนครับ
เคล็ดลับ: มองหาข้อความ Error, Warning หรือ Stack Trace ที่บ่งชี้ถึงปัญหาครับ บางครั้งปัญหาอาจเกิดจาก Dependency ที่ติดตั้งไม่สำเร็จ, คำสั่งผิดพลาด, หรือการเข้าถึงสิทธิ์ที่ไม่เพียงพอครับ
การ Debug Workflow
บางครั้ง Log ก็ไม่ได้บอกทุกอย่างครับ หากต้องการ Debug Workflow ที่ซับซ้อน อาจต้องใช้วิธีการเพิ่มเติม:
- เพิ่ม
echoหรือprint: ใส่คำสั่งecho(ใน Bash) หรือprint()(ใน Python) เข้าไปใน Step เพื่อดูค่าตัวแปรหรือสถานะการทำงานในช่วงต่างๆ - รัน Workflow ซ้ำ (Re-run jobs): คุณสามารถรัน Job หรือ Workflow ที่ล้มเหลวซ้ำได้โดยตรงจาก GitHub UI ซึ่งมีประโยชน์มากเมื่อคุณแก้ไขโค้ดใน Workflow แล้วต้องการทดสอบทันที
- ใช้
workflow_dispatch: หากต้องการทดสอบ Workflow ที่ยังไม่พร้อมจะ Trigger ด้วย Push/PR ให้ใช้workflow_dispatchเพื่อรันด้วยตนเองและสามารถใส่ Input parameters ได้ด้วย - ใช้
debugflag: สำหรับ Action บางตัว อาจมี debug flag ที่ช่วยให้แสดงรายละเอียด Log มากขึ้น - ตรวจสอบ GitHub Status Page: บางครั้งปัญหาอาจไม่ได้เกิดจาก Workflow ของคุณ แต่อาจเกิดจากปัญหาของ GitHub Actions เอง ตรวจสอบได้ที่ githubstatus.com ครับ
Best Practices สำหรับ GitHub Actions Pipeline
เพื่อให้ Pipeline ของคุณมีประสิทธิภาพ, ปลอดภัย และบำรุงรักษาง่าย ควรปฏิบัติตาม Best Practices เหล่านี้ครับ
- ความปลอดภัย:
- ใช้ Secrets อย่างถูกวิธี: อย่า hardcode ข้อมูลสำคัญใน Workflow YAML ใช้ GitHub Secrets เสมอ
- จำกัดสิทธิ์ (Least Privilege): ให้สิทธิ์แก่ GitHub Actions Token (
GITHUB_TOKEN) เท่าที่จำเป็นเท่านั้น (โดยค่าเริ่มต้น GitHub จะให้สิทธิ์ที่เหมาะสมอยู่แล้ว แต่คุณสามารถปรับแต่งได้) - ตรวจสอบ Action ที่ใช้: ใช้ Action จากแหล่งที่เชื่อถือได้ (เช่น
actions/*จาก GitHub หรือ Action ที่มีชื่อเสียง) และระบุเวอร์ชันของ Action (เช่นactions/checkout@v4) เพื่อหลีกเลี่ยงการเปลี่ยนแปลงที่ไม่คาดคิด - ใช้ Environments: สำหรับการ Deploy ไปยัง Staging/Production เพื่อเพิ่ม Protection Rules
- ประสิทธิภาพ:
- ใช้ Caching: สำหรับ Dependency ที่ใช้
- ใช้ Caching: สำหรับ Dependency ที่ใช้