
ในโลกของการพัฒนาซอฟต์แวร์ที่เปลี่ยนแปลงอย่างรวดเร็วในปัจจุบัน ประสิทธิภาพ ความน่าเชื่อถือ และความสามารถในการส่งมอบโค้ดใหม่ๆ สู่ผู้ใช้งานได้อย่างต่อเนื่อง คือหัวใจสำคัญของความสำเร็จครับ หนึ่งในแนวทางปฏิบัติที่ดีที่สุดที่ช่วยให้ทีมพัฒนาซอฟต์แวร์บรรลุเป้าหมายเหล่านี้ได้คือ CI/CD Pipeline หรือกระบวนการ Continuous Integration และ Continuous Delivery/Deployment นั่นเองครับ และเมื่อพูดถึงการสร้าง CI/CD Pipeline ที่ทรงพลัง ใช้งานง่าย และผสานรวมกับกระบวนการทำงานของนักพัฒนาได้อย่างไร้รอยต่อ GitHub Actions คือเครื่องมือที่โดดเด่นและเป็นที่นิยมอย่างมากในหมู่ชุมชนนักพัฒนาครับ
บทความนี้จะพาคุณเจาะลึกถึงแก่นแท้ของ CI/CD Pipeline ด้วย GitHub Actions ตั้งแต่แนวคิดพื้นฐาน ไปจนถึงการสร้าง Workflow ที่ซับซ้อน เทคนิคขั้นสูง และแนวทางปฏิบัติที่ดีที่สุด เพื่อให้คุณสามารถนำไปประยุกต์ใช้ในการพัฒนาโปรเจกต์ของคุณได้อย่างเต็มศักยภาพ ไม่ว่าคุณจะเป็นนักพัฒนาหน้าใหม่ที่เพิ่งเริ่มต้นเรียนรู้ CI/CD หรือนักพัฒนาที่มีประสบการณ์ที่ต้องการยกระดับ Pipeline ของคุณให้ดียิ่งขึ้น บทความนี้จะมีข้อมูลเชิงลึกและตัวอย่างที่ใช้งานได้จริงให้คุณได้ศึกษาอย่างละเอียดแน่นอนครับ
มาเริ่มต้นการเดินทางสู่การสร้าง CI/CD Pipeline ที่มีประสิทธิภาพด้วย GitHub Actions ไปพร้อมกันเลยครับ!
สารบัญ
- ทำความเข้าใจ CI/CD Pipeline คืออะไร และทำไมถึงสำคัญ?
- ทำความรู้จัก GitHub Actions: หัวใจของ CI/CD ในโลก GitHub
- เจาะลึกแนวคิดหลักของ GitHub Actions
- สร้าง CI/CD Pipeline แรกของคุณด้วย GitHub Actions (ตัวอย่าง Node.js)
- เทคนิคขั้นสูงสำหรับ GitHub Actions
- Matrix Strategies: การทดสอบข้ามสภาพแวดล้อม
- Caching Dependencies: เพิ่มความเร็วให้ Workflow
- Environment Variables และ Secrets
- Reusable Workflows: การสร้าง Workflow ที่นำกลับมาใช้ซ้ำได้
- Self-Hosted Runners: รัน Workflow ในโครงสร้างพื้นฐานของคุณ
- Deployment Environments และ Manual Approvals
- Monorepos และ Path Filtering
- แนวทางปฏิบัติที่ดีที่สุดสำหรับ CI/CD ด้วย GitHub Actions
- GitHub Actions เปรียบเทียบกับเครื่องมือ CI/CD อื่นๆ
- กรณีศึกษาและการใช้งานจริง
- คำถามที่พบบ่อย (FAQ)
- สรุปและ Call-to-Action
ทำความเข้าใจ CI/CD Pipeline คืออะไร และทำไมถึงสำคัญ?
ก่อนที่เราจะดำดิ่งเข้าสู่โลกของ GitHub Actions เรามาทำความเข้าใจแนวคิดพื้นฐานของ CI/CD Pipeline กันก่อนครับ เพราะนี่คือรากฐานสำคัญที่จะทำให้เราเข้าใจถึงประโยชน์และวิธีการใช้งาน GitHub Actions ได้อย่างมีประสิทธิภาพสูงสุดครับ
Continuous Integration (CI) คืออะไร?
Continuous Integration (CI) คือแนวทางปฏิบัติในการพัฒนาซอฟต์แวร์ที่ให้นักพัฒนาแต่ละคนผสานรวมโค้ดของตนเข้ากับ Repository กลางบ่อยครั้ง โดยปกติจะหลายครั้งต่อวันครับ การผสานรวมแต่ละครั้งจะถูกตรวจสอบโดยการ Build อัตโนมัติและรันการทดสอบอัตโนมัติ (Automated Tests) เพื่อตรวจจับข้อผิดพลาดตั้งแต่เนิ่นๆ ครับ
วัตถุประสงค์หลักของ CI:
- ลดปัญหาการผสานรวม (Integration Hell): เมื่อนักพัฒนาทำงานแยกกันเป็นเวลานาน การรวมโค้ดเข้าด้วยกันในภายหลังมักจะนำไปสู่ความขัดแย้งที่ซับซ้อนและใช้เวลานานในการแก้ไขครับ CI ช่วยให้การรวมโค้ดเกิดขึ้นบ่อยขึ้นในชิ้นเล็กๆ ทำให้ปัญหาที่เกิดขึ้นถูกตรวจพบและแก้ไขได้ง่ายและรวดเร็วขึ้นครับ
- ตรวจจับข้อผิดพลาดตั้งแต่เนิ่นๆ: การ Build และ Test อัตโนมัติทุกครั้งที่มีการ Commit โค้ด ช่วยให้สามารถระบุ Bug หรือปัญหาที่เกิดจากการผสานรวมได้ทันที ซึ่งช่วยลดต้นทุนและเวลาในการแก้ไขเมื่อเทียบกับการค้นพบ Bug ในขั้นตอนที่ล่าช้ากว่าครับ
- ปรับปรุงคุณภาพโค้ด: การมีชุดการทดสอบอัตโนมัติที่ครอบคลุมและทำงานอย่างสม่ำเสมอ เป็นการรับประกันว่าโค้ดที่ผสานรวมเข้ามานั้นมีคุณภาพตามมาตรฐานที่กำหนดครับ
Continuous Delivery (CD) และ Continuous Deployment (CD) คืออะไร?
หลังจากขั้นตอน CI ที่โค้ดถูกรวม ทดสอบ และ Build เรียบร้อยแล้ว ขั้นตอนต่อไปคือการส่งมอบซอฟต์แวร์ไปยังสภาพแวดล้อมที่พร้อมใช้งานครับ ซึ่งมีอยู่สองแนวคิดที่คล้ายกันแต่มีความแตกต่างที่สำคัญคือ Continuous Delivery และ Continuous Deployment ครับ
Continuous Delivery (CD)
Continuous Delivery (CD) คือการต่อยอดจาก CI โดยทำให้มั่นใจว่าโค้ดที่ผ่านการทดสอบและ Build แล้วจะสามารถนำไป Deploy ได้ทุกเมื่อครับ หมายความว่าหลังจากการ Build และทดสอบสำเร็จ ซอฟต์แวร์จะถูกแพ็กเกจและจัดเตรียมไว้ในสถานะที่พร้อมสำหรับการ Deploy ไปยังสภาพแวดล้อม Production ได้ตลอดเวลา แต่การ Deploy ไปยัง Production นั้นยังคงต้องอาศัยการตัดสินใจหรือการอนุมัติจากมนุษย์ (Manual Approval) ครับ
เป้าหมายของ Continuous Delivery:
- ลดความเสี่ยงในการ Deploy: การเตรียมพร้อมสำหรับการ Deploy ตลอดเวลาช่วยลดความเสี่ยงที่เกี่ยวข้องกับการ Deploy เนื่องจากกระบวนการทั้งหมดถูกทำให้เป็นอัตโนมัติและทดสอบแล้วครับ
- เพิ่มความยืดหยุ่น: ทีมสามารถตัดสินใจ Deploy เมื่อใดก็ได้ที่ต้องการ เช่น เมื่อมีฟีเจอร์ใหม่พร้อม หรือเมื่อต้องการแก้ไข Bug ด่วนครับ
Continuous Deployment (CD)
Continuous Deployment (CD) คือขั้นสูงสุดของ CI/CD ครับ มันคือการต่อยอดจาก Continuous Delivery โดยทำให้กระบวนการทั้งหมดเป็นอัตโนมัติอย่างสมบูรณ์ รวมถึงการ Deploy โค้ดที่ผ่านการทดสอบและ Build แล้วไปยังสภาพแวดล้อม Production โดยอัตโนมัติ โดยไม่มีการแทรกแซงจากมนุษย์เลย ครับ การเปลี่ยนแปลงทุกอย่างที่ผ่านการทดสอบอัตโนมัติจะถูกปล่อยออกสู่ผู้ใช้งานจริงทันทีครับ
เป้าหมายของ Continuous Deployment:
- ความเร็วสูงสุดในการส่งมอบ: ช่วยให้ฟีเจอร์ใหม่ๆ หรือการแก้ไข Bug สามารถส่งมอบถึงมือผู้ใช้งานได้อย่างรวดเร็วที่สุดครับ
- ลดการทำงานซ้ำซ้อน: ขจัดความจำเป็นในการทำงานที่ต้องทำซ้ำๆ ด้วยมือ ซึ่งช่วยลดข้อผิดพลาดที่เกิดจากมนุษย์ได้ครับ
ความแตกต่างหลักอยู่ตรงที่ว่า Continuous Delivery ยังคงต้องมี “คน” ตัดสินใจว่าจะ Deploy เมื่อไหร่ แต่ Continuous Deployment นั้น “ระบบ” จะ Deploy ให้เองทันทีที่ทุกอย่างผ่านครับ
ประโยชน์ของการใช้ CI/CD Pipeline
การนำ CI/CD Pipeline มาใช้ในกระบวนการพัฒนาซอฟต์แวร์นำมาซึ่งประโยชน์มากมาย ดังนี้ครับ
- เพิ่มความเร็วในการส่งมอบ (Faster Time to Market): ด้วยกระบวนการอัตโนมัติที่รวดเร็วและต่อเนื่อง ทีมสามารถปล่อยฟีเจอร์ใหม่ๆ หรือการแก้ไข Bug ออกสู่ผู้ใช้งานได้บ่อยขึ้นและรวดเร็วขึ้นครับ
- ปรับปรุงคุณภาพและความน่าเชื่อถือ (Improved Quality and Reliability): การทดสอบอัตโนมัติอย่างสม่ำเสมอช่วยตรวจจับข้อผิดพลาดได้ตั้งแต่เนิ่นๆ ลดโอกาสที่จะมี Bug หลุดรอดไปถึง Production ทำให้ซอฟต์แวร์มีคุณภาพและน่าเชื่อถือมากขึ้นครับ
- ลดความเสี่ยง (Reduced Risk): การ Deploy การเปลี่ยนแปลงเล็กๆ บ่อยๆ มีความเสี่ยงน้อยกว่าการ Deploy การเปลี่ยนแปลงครั้งใหญ่ๆ ครับ หากเกิดปัญหา การย้อนกลับ (Rollback) ก็ทำได้ง่ายขึ้นครับ
- ลดต้นทุน (Reduced Costs): แม้จะมีการลงทุนเริ่มต้นในการตั้งค่า แต่ในระยะยาว CI/CD ช่วยลดเวลาและทรัพยากรที่ใช้ในการแก้ไข Bug และการจัดการการ Deploy ครับ
- เพิ่มประสิทธิภาพของทีม (Increased Team Efficiency): นักพัฒนาสามารถมุ่งเน้นไปที่การเขียนโค้ดและสร้างสรรค์สิ่งใหม่ๆ ได้เต็มที่ โดยไม่ต้องกังวลกับกระบวนการ Build และ Deploy ที่น่าเบื่อและซ้ำซากครับ
- ข้อเสนอแนะที่รวดเร็ว (Faster Feedback Loop): ทีมจะได้รับข้อเสนอแนะเกี่ยวกับคุณภาพของโค้ดและการทำงานของฟีเจอร์ใหม่ๆ ได้อย่างรวดเร็ว ทำให้สามารถปรับปรุงและแก้ไขได้ทันท่วงทีครับ
ทำความรู้จัก GitHub Actions: หัวใจของ CI/CD ในโลก GitHub
เมื่อเราเข้าใจแนวคิดของ CI/CD แล้ว ก็ถึงเวลาที่จะมาทำความรู้จักกับ GitHub Actions ซึ่งเป็นเครื่องมือที่จะช่วยให้เราสร้าง CI/CD Pipeline เหล่านี้ได้อย่างง่ายดายและมีประสิทธิภาพครับ
GitHub Actions คือแพลตฟอร์มสำหรับ Automation ที่มีอยู่ใน GitHub โดยตรง ช่วยให้คุณสามารถสร้าง Workflow ที่สามารถตอบสนองต่อเหตุการณ์ต่างๆ ใน Repository ของคุณได้ เช่น การ Push โค้ด, การสร้าง Pull Request, การออก Release ใหม่ หรือแม้แต่การตั้งเวลาให้ทำงานเป็นประจำครับ ด้วย GitHub Actions คุณสามารถ Automate ได้เกือบทุกอย่างในวงจรการพัฒนาซอฟต์แวร์ของคุณ ตั้งแต่การ Build, Test, และ Deploy ไปจนถึงการจัดการโปรเจกต์และการสื่อสารในทีมครับ
GitHub Actions ทำงานอย่างไร?
หัวใจของ GitHub Actions คือไฟล์ YAML ที่กำหนด Workflow ซึ่งประกอบด้วยชุดของ Jobs ที่จะถูกเรียกใช้เมื่อมี Event ที่กำหนดไว้เกิดขึ้นครับ Workflow เหล่านี้จะถูกรันบน Runner ซึ่งเป็นเครื่องจักรเสมือนที่ GitHub จัดหาให้ หรือคุณจะใช้ Self-hosted Runner ของคุณเองก็ได้ครับ ในแต่ละ Job จะประกอบด้วย Steps ซึ่งเป็นคำสั่งหรือ Actions ที่จะดำเนินการตามลำดับครับ
ลองนึกภาพว่าคุณ Push โค้ดไปยัง Repository ของคุณครับ
- Event: GitHub ตรวจจับการ Push โค้ดนี้
- Workflow: GitHub ตรวจสอบไฟล์ Workflow (`.github/workflows/*.yml`) ของคุณ และพบว่ามี Workflow หนึ่งที่ถูกกำหนดให้ทำงานเมื่อมี Event ประเภท `push` เกิดขึ้น
- Jobs: Workflow นั้นเริ่มทำงาน และเรียกใช้ Jobs ที่กำหนดไว้ภายใน (เช่น Job สำหรับ Build, Job สำหรับ Test)
- Steps & Actions: แต่ละ Job จะมี Steps และ Actions ที่ถูกกำหนดไว้ ซึ่งจะทำงานตามลำดับที่ระบุ เช่น Step สำหรับ Checkout โค้ด, Step สำหรับติดตั้ง Dependencies, Step สำหรับรันการทดสอบ
- Runner: Jobs เหล่านี้จะถูกรันบน Runner (Virtual Machine) ที่ถูกสร้างขึ้นมาเฉพาะสำหรับ Workflow นั้นๆ ครับ
- Output: เมื่อ Jobs ทั้งหมดเสร็จสิ้น คุณจะเห็นผลลัพธ์ในแท็บ “Actions” บน GitHub Repository ของคุณครับ
องค์ประกอบหลักของ GitHub Actions
เพื่อให้เข้าใจ GitHub Actions ได้อย่างลึกซึ้งยิ่งขึ้น เรามาดูองค์ประกอบหลักๆ ที่สำคัญกันครับ
- Workflow: ไฟล์ YAML ที่กำหนดกระบวนการอัตโนมัติทั้งหมด มันคือพิมพ์เขียวของ CI/CD Pipeline ของคุณครับ
- Event: เหตุการณ์ที่ทริกเกอร์ให้ Workflow ทำงาน เช่น
push,pull_request,issue_comment,scheduleครับ - Job: ชุดของ Steps ที่จะถูกรันบน Runner ตัวเดียวกัน Jobs สามารถรันแบบขนาน (Parallel) หรือเรียงลำดับ (Sequential) กันได้ครับ
- Step: หน่วยย่อยที่สุดของการทำงานภายใน Job ซึ่งอาจเป็น Shell command หรือ Action ที่นำมาใช้ซ้ำได้ครับ
- Action: แอปพลิเคชันที่นำกลับมาใช้ซ้ำได้ ซึ่งเป็นส่วนประกอบพื้นฐานของ Step ที่ทำงานบางอย่าง เช่น
actions/checkoutเพื่อดึงโค้ด หรือactions/setup-nodeเพื่อตั้งค่า Node.js ครับ - Runner: เซิร์ฟเวอร์ที่ติดตั้ง GitHub Actions Runner application และรอรับ Job เพื่อรันครับ สามารถเป็น GitHub-hosted runner (VM ที่ GitHub จัดหาให้) หรือ Self-hosted runner (VM ที่คุณจัดการเอง) ครับ
เจาะลึกแนวคิดหลักของ GitHub Actions
เรามาทำความเข้าใจแนวคิดหลักเหล่านี้ให้ละเอียดขึ้น เพื่อให้สามารถออกแบบและสร้าง Workflow ที่มีประสิทธิภาพได้ครับ
Workflow
Workflow คือไฟล์ YAML ที่เก็บอยู่ในไดเรกทอรี .github/workflows/ ภายใน Repository ของคุณครับ ชื่อไฟล์จะเป็นอะไรก็ได้ที่คุณต้องการ เช่น ci.yml, deploy.yml เป็นต้น
โครงสร้างพื้นฐานของ Workflow:
name: My First Workflow # ชื่อ Workflow
on: [push, pull_request] # Events ที่จะทริกเกอร์ Workflow
jobs: # ชุดของ Jobs
build: # ชื่อ Job แรก
runs-on: ubuntu-latest # Runner ที่ใช้รัน Job นี้
steps: # ชุดของ Steps ภายใน Job
- uses: actions/checkout@v4 # Action สำหรับ checkout โค้ด
- run: echo "Hello, world!" # Shell command
แต่ละ Workflow จะมี name (เป็นทางเลือกแต่แนะนำ) และ on ที่ระบุ Events ที่จะทริกเกอร์ Workflow ครับ
Events (ทริกเกอร์)
Events คือเหตุการณ์ที่เกิดขึ้นใน Repository ของคุณที่สามารถทริกเกอร์ Workflow ได้ครับ GitHub Actions รองรับ Events หลากหลายรูปแบบ:
push: เมื่อมีการ Push โค้ดไปยัง Branch ที่กำหนดpull_request: เมื่อมีการสร้าง, เปิด, อัปเดต Pull Requestschedule: ตั้งเวลาให้ Workflow ทำงานตามช่วงเวลาที่กำหนด (ใช้ Cron syntax)workflow_dispatch: อนุญาตให้รัน Workflow ด้วยตนเองจาก GitHub UIrelease: เมื่อมีการสร้าง, เผยแพร่, อัปเดต Releaseissue_comment: เมื่อมี Comment ถูกเพิ่มใน Issue หรือ Pull Request- และอื่นๆ อีกมากมาย
คุณสามารถระบุ Event ได้โดยตรง หรือระบุเงื่อนไขเพิ่มเติม เช่น Branch ที่ต้องการให้ Workflow ทำงานครับ
on:
push:
branches:
- main # จะทำงานเมื่อมีการ push ไปยัง branch "main" เท่านั้น
pull_request:
branches:
- main # จะทำงานเมื่อมีการสร้าง PR เข้าสู่ branch "main"
schedule:
- cron: '0 0 * * *' # รันทุกวันเวลาเที่ยงคืน UTC
workflow_dispatch: # อนุญาตให้รันด้วยตนเอง
Jobs
Job คือชุดของ Steps ที่ทำงานเป็นกลุ่มบน Runner ตัวเดียวกันครับ ทุก Step ใน Job จะแชร์สภาพแวดล้อมเดียวกันและเข้าถึงไฟล์ที่สร้างขึ้นโดย Step ก่อนหน้าได้ครับ
คุณสมบัติสำคัญของ Job:
runs-on: ระบุประเภทของ Runner ที่ Job จะรัน เช่นubuntu-latest,windows-latest,macos-latestหรือชื่อของ self-hosted runner group ครับsteps: ลิสต์ของ Steps ที่จะทำงานตามลำดับneeds: ระบุ Job อื่นๆ ที่ Job นี้ต้องรอให้เสร็จก่อน ทำให้สามารถสร้าง Job ที่ทำงานแบบเรียงลำดับได้ครับif: กำหนดเงื่อนไขว่า Job จะทำงานหรือไม่outputs: กำหนดค่าที่ Job สามารถส่งออกไปให้ Job อื่นๆ ที่ขึ้นอยู่กับ Job นี้ได้
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building..."
test:
needs: build # Job 'test' จะรันหลังจาก 'build' เสร็จสิ้น
runs-on: ubuntu-latest
steps:
- run: echo "Testing..."
deploy:
needs: [build, test] # Job 'deploy' จะรันหลังจาก 'build' และ 'test' เสร็จสิ้น
if: github.ref == 'refs/heads/main' # จะ deploy เฉพาะเมื่อ push ไปที่ main branch
runs-on: ubuntu-latest
steps:
- run: echo "Deploying..."
Steps
Step คือหน่วยที่เล็กที่สุดของงานใน Workflow ครับ แต่ละ Step สามารถเป็นได้ทั้ง Shell command หรือ Action ที่นำมาใช้ซ้ำได้ครับ
คุณสมบัติสำคัญของ Step:
name: ชื่อที่แสดงใน UI ของ GitHub Actions (เป็นทางเลือกแต่แนะนำ)run: สั่งให้ Runner รัน Shell command (เช่นnpm install,python script.py)uses: ใช้ Action ที่มีอยู่แล้ว เช่นactions/checkout@v4with: ส่งค่า Input ให้กับ Action ที่ใช้env: กำหนด Environment Variables เฉพาะสำหรับ Step นั้น
steps:
- name: Checkout repository # ชื่อ Step
uses: actions/checkout@v4 # ใช้ Action จาก GitHub Marketplace
- name: Install dependencies
run: npm install # รัน Shell command
- name: Run tests
run: npm test
env:
NODE_ENV: test # กำหนด Environment Variable สำหรับ Step นี้
Actions
Actions คือแอปพลิเคชันที่นำกลับมาใช้ซ้ำได้ ซึ่งเป็นส่วนประกอบพื้นฐานของ Step ครับ Actions สามารถช่วยให้คุณทำงานทั่วไปได้ง่ายขึ้น เช่น การ Checkout โค้ด, การตั้งค่าสภาพแวดล้อม (Node.js, Python, Java), การอัปโหลด Artifacts เป็นต้น
Actions มีหลายประเภท:
- GitHub-provided Actions: Actions ที่ GitHub สร้างและดูแล เช่น
actions/checkout,actions/setup-node - Community Actions: Actions ที่สร้างโดยชุมชนนักพัฒนาและเผยแพร่ใน GitHub Marketplace
- Custom Actions: คุณสามารถสร้าง Actions ของคุณเองได้ด้วย JavaScript หรือ Docker ครับ
การใช้ Action ทำได้โดยระบุ uses: owner/repo@ref หรือ uses: ./path/to/action (สำหรับ Custom Action ใน Repository เดียวกัน) ครับ
steps:
- uses: actions/checkout@v4 # ใช้ Action 'checkout' เวอร์ชัน 4
- uses: actions/setup-node@v4
with:
node-version: '20' # ส่ง input 'node-version' ให้กับ Action
Runners
Runner คือเซิร์ฟเวอร์ที่ติดตั้งแอปพลิเคชัน GitHub Actions Runner และรอรับ Job เพื่อรันครับ
- GitHub-hosted runners:
- เป็น VM ที่ GitHub จัดหาให้และจัดการเอง
- มีหลายระบบปฏิบัติการให้เลือก (
ubuntu-latest,windows-latest,macos-latest) - เป็นตัวเลือกเริ่มต้นและสะดวกสบายที่สุดสำหรับการใช้งานทั่วไป
- มีทรัพยากรจำกัดและอาจมีค่าใช้จ่ายเมื่อใช้งานเกินโควต้าฟรี
- Self-hosted runners:
- เป็นเซิร์ฟเวอร์หรือ VM ที่คุณติดตั้งและจัดการเอง
- เหมาะสำหรับกรณีที่ต้องการทรัพยากรเฉพาะ, สภาพแวดล้อมที่กำหนดเอง, หรือเข้าถึงเครือข่ายส่วนตัว
- คุณต้องดูแลการบำรุงรักษาและการอัปเดตเอง
คุณระบุ Runner ที่ต้องการใช้ด้วย runs-on ใน Job ครับ
jobs:
build:
runs-on: ubuntu-latest # ใช้ GitHub-hosted Ubuntu runner
deploy:
runs-on: self-hosted # ใช้ self-hosted runner
Contexts
Contexts คือชุดของข้อมูลที่ GitHub Actions จัดเตรียมไว้ให้คุณสามารถเข้าถึงข้อมูลต่างๆ ที่เกี่ยวข้องกับ Workflow, Job, Runner, Event และอื่นๆ ได้ครับ คุณสามารถใช้ Contexts เพื่อเข้าถึงข้อมูลในรูปแบบของ Expression โดยใช้ไวยากรณ์ ${{ <context.property> }}
Contexts ที่พบบ่อย:
github: ข้อมูลเกี่ยวกับ Repository, Event ที่ทริกเกอร์, Commits, Pull Requests ครับenv: Environment Variables ที่กำหนดไว้job: ข้อมูลเกี่ยวกับ Job ปัจจุบันsteps: ข้อมูลเกี่ยวกับ Steps ที่ผ่านมา รวมถึง Outputs ด้วยrunner: ข้อมูลเกี่ยวกับ Runner ที่กำลังทำงานอยู่secrets: ค่าความลับที่ถูกจัดเก็บไว้อย่างปลอดภัย
steps:
- name: Print branch name
run: echo "Current branch is ${{ github.ref_name }}"
- name: Check if it's a pull request
if: github.event_name == 'pull_request'
run: echo "This is a Pull Request!"
Secrets
Secrets คือค่าความลับที่คุณต้องการใช้ใน Workflow ของคุณ เช่น API keys, รหัสผ่าน, SSH private keys ครับ GitHub จะจัดเก็บ Secrets อย่างปลอดภัยและไม่เปิดเผยใน Logs ของ Workflow ครับ
คุณสามารถกำหนด Secrets ได้ที่:
- ระดับ Repository: Settings > Secrets and variables > Actions
- ระดับ Environment: สำหรับการ Deploy ไปยัง Environment ที่เฉพาะเจาะจง
- ระดับ Organization: สำหรับ Secrets ที่ใช้ร่วมกันในหลาย Repository
การเข้าถึง Secret ทำได้โดยใช้ Context secrets ครับ
steps:
- name: Deploy to production
run: deploy-script.sh
env:
API_KEY: ${{ secrets.MY_API_KEY }} # ใช้ Secret ที่ชื่อ MY_API_KEY
ข้อควรระวัง: อย่า Hardcode Secrets ลงในไฟล์ Workflow ของคุณเด็ดขาดครับ และระมัดระวังในการแสดง Secrets ใน Logs ครับ
สร้าง CI/CD Pipeline แรกของคุณด้วย GitHub Actions (ตัวอย่าง Node.js)
มาถึงส่วนที่น่าตื่นเต้นที่สุดครับ เราจะมาสร้าง CI/CD Pipeline ที่ใช้งานได้จริงสำหรับแอปพลิเคชัน Node.js อย่างง่ายๆ ครับ Pipeline นี้จะประกอบด้วย:
- CI (Continuous Integration):
- Checkout โค้ด
- ติดตั้ง Dependencies
- รัน Linting เพื่อตรวจสอบคุณภาพโค้ด
- รัน Unit Tests
- Build แอปพลิเคชัน
- อัปโหลด Artifacts (ไฟล์ที่ Build แล้ว)
- CD (Continuous Delivery/Deployment):
- ดาวน์โหลด Artifacts ที่ Build ไว้
- จำลองขั้นตอนการ Deploy ไปยังเซิร์ฟเวอร์หรือบริการคลาวด์
การเตรียมความพร้อม
ก่อนอื่น ให้คุณสร้าง GitHub Repository ใหม่ (หรือใช้ Repository ที่มีอยู่แล้ว) และสร้างโปรเจกต์ Node.js อย่างง่ายๆ ขึ้นมาครับ
ตัวอย่างโครงสร้างโปรเจกต์ Node.js (package.json):
{
"name": "my-node-app",
"version": "1.0.0",
"description": "A simple Node.js app for CI/CD demo",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "jest",
"lint": "eslint .",
"build": "echo \"Building app...\" && mkdir -p dist && cp index.js dist/index.js && cp package.json dist/package.json"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"eslint": "^8.56.0",
"jest": "^29.7.0"
}
}
ไฟล์ index.js (แอปพลิเคชัน Express อย่างง่าย):
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello from CI/CD Node.js App!');
});
app.get('/health', (req, res) => {
res.status(200).send('OK');
});
if (require.main === module) {
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`);
});
}
module.exports = app; // Export for testing
ไฟล์ .eslintrc.js (สำหรับ ESLint):
module.exports = {
env: {
node: true,
commonjs: true,
es2021: true,
jest: true // Add jest environment for test files
},
extends: 'eslint:recommended',
parserOptions: {
ecmaVersion: 12
},
rules: {
// Add custom rules here if needed
}
};
ไฟล์ jest.config.js (สำหรับ Jest):
module.exports = {
testEnvironment: 'node',
};
ไฟล์ index.test.js (สำหรับ Unit Test):
const request = require('supertest');
const app = require('./index'); // Import your Express app
describe('GET /', () => {
test('It should respond with "Hello from CI/CD Node.js App!"', async () => {
const response = await request(app).get('/');
expect(response.statusCode).toBe(200);
expect(response.text).toBe('Hello from CI/CD Node.js App!');
});
});
describe('GET /health', () => {
test('It should respond with "OK" and status 200', async () => {
const response = await request(app).get('/health');
expect(response.statusCode).toBe(200);
expect(response.text).toBe('OK');
});
});
หลังจากสร้างไฟล์เหล่านี้แล้ว ให้ Push โค้ดไปยัง GitHub Repository ของคุณครับ
สร้าง Workflow สำหรับ Continuous Integration (CI)
สร้างไฟล์ชื่อ .github/workflows/node-ci-cd.yml ใน Repository ของคุณครับ
name: Node.js CI/CD Pipeline
on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: '20' # Specify the Node.js version you want to use
cache: 'npm' # Cache npm dependencies to speed up subsequent runs
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run unit tests
run: npm test
- name: Build application
run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: node-app-build
path: dist # The directory containing your built application
retention-days: 7 # How long to keep the artifact
มาทำความเข้าใจแต่ละ Step ใน Workflow นี้กันครับ:
1. Checkout repository code
- name: Checkout repository code
uses: actions/checkout@v4
Step นี้ใช้ actions/checkout@v4 เพื่อดึงโค้ดจาก Repository ของคุณไปยัง Runner ครับ นี่คือ Step แรกที่เกือบทุก Workflow จำเป็นต้องมีครับ
2. Setup Node.js environment
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
เราใช้ actions/setup-node@v4 เพื่อติดตั้ง Node.js เวอร์ชัน 20 บน Runner ครับ Parameter cache: 'npm' จะช่วยให้ GitHub Actions แคช Dependencies ของ npm ซึ่งจะช่วยลดเวลาในการติดตั้ง Dependencies ในการรัน Workflow ครั้งถัดไปได้อย่างมากครับ
3. Install dependencies
- name: Install dependencies
run: npm ci
คำสั่ง npm ci (Clean Install) จะติดตั้ง Dependencies ตามที่ระบุใน package-lock.json (หรือ npm-shrinkwrap.json) เพื่อให้มั่นใจว่าการติดตั้ง Dependencies มีความสอดคล้องกันทุกครั้งครับ ซึ่งแตกต่างจาก npm install ที่อาจอัปเดตเวอร์ชันของ Dependencies ได้ครับ
4. Run ESLint และ 5. Run unit tests
- name: Run ESLint
run: npm run lint
- name: Run unit tests
run: npm test
Step เหล่านี้จะรันคำสั่ง npm run lint และ npm test ตามที่กำหนดไว้ใน package.json ของคุณครับ นี่คือส่วนสำคัญของ CI ที่ช่วยตรวจสอบคุณภาพโค้ดและค้นหาข้อผิดพลาดตั้งแต่เนิ่นๆ ครับ หาก Step ใด Step หนึ่งล้มเหลว Workflow จะถูกหยุดและแสดงสถานะ Failed ครับ
6. Build application
- name: Build application
run: npm run build
คำสั่ง npm run build จะถูกรันเพื่อสร้างไฟล์ที่พร้อมสำหรับ Production ครับ ในตัวอย่างของเราคือการคัดลอกไฟล์ index.js และ package.json ไปยังโฟลเดอร์ dist ครับ ในโปรเจกต์จริง คุณอาจมี Webpack, Rollup หรือ Transpiler อื่นๆ ที่ทำงานใน Step นี้ครับ
7. Upload build artifact
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: node-app-build
path: dist
retention-days: 7
หลังจาก Build แอปพลิเคชันเสร็จแล้ว เราจะใช้ actions/upload-artifact@v4 เพื่ออัปโหลดไฟล์ที่ Build แล้ว (ในโฟลเดอร์ dist) เป็น Artifact ครับ Artifact คือไฟล์หรือโฟลเดอร์ที่ถูกสร้างขึ้นระหว่าง Workflow และสามารถดาวน์โหลดได้หลังจาก Workflow เสร็จสิ้น หรือนำไปใช้ใน Job อื่นๆ ได้ครับ retention-days กำหนดระยะเวลาที่จะเก็บ Artifact ไว้ครับ
เมื่อคุณ Commit และ Push ไฟล์ node-ci-cd.yml นี้ไปยัง GitHub Repository ของคุณ GitHub Actions จะตรวจจับ Event push และรัน Workflow นี้ทันทีครับ คุณสามารถดูสถานะและความคืบหน้าได้ในแท็บ “Actions” ของ Repository ครับ
สร้าง Workflow สำหรับ Continuous Delivery/Deployment (CD)
เราจะเพิ่ม Job ที่สองเข้าไปในไฟล์ node-ci-cd.yml เดิม เพื่อจัดการส่วนของ CD ครับ Job นี้จะขึ้นอยู่กับ Job build_and_test เพื่อให้แน่ใจว่าการ Deploy จะเกิดขึ้นเฉพาะเมื่อ Build และ Test สำเร็จเท่านั้นครับ
name: Node.js CI/CD Pipeline
on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop
jobs:
build_and_test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@v4
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run unit tests
run: npm test
- name: Build application
run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: node-app-build
path: dist
retention-days: 7
deploy:
needs: build_and_test # This job depends on 'build_and_test' job
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # Deploy only on push to 'main' branch
# Optional: Use deployment environments for manual approvals and environment-specific secrets
# environment:
# name: Production
# url: https://your-app.com # URL to the deployed application
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: node-app-build
path: ./app-to-deploy # Directory to download the artifact to
- name: List downloaded files (for verification)
run: ls -R ./app-to-deploy
- name: Simulate deployment
run: |
echo "Simulating deployment to production server..."
echo "Deploying artifact from ./app-to-deploy to your server..."
# In a real scenario, this is where your actual deployment logic would go.
# Examples:
# - Using SCP to copy files to an SSH server:
# sshpass -p "${{ secrets.SSH_PASSWORD }}" scp -r ./app-to-deploy/* user@your-server-ip:/var/www/html/
# - Using AWS S3 Sync for static sites:
# aws s3 sync ./app-to-deploy/ s3://your-s3-bucket/
# - Using a cloud provider's CLI (e.g., gcloud, az, vercel):
# vercel deploy ./app-to-deploy --prod --token=${{ secrets.VERCEL_TOKEN }}
# - Triggering a webhook or API call to your deployment service
echo "Deployment simulated successfully!"
มาทำความเข้าใจ Job deploy กันครับ:
needs: build_and_test: Job นี้จะทำงานก็ต่อเมื่อ Jobbuild_and_testทำงานสำเร็จแล้วเท่านั้นครับruns-on: ubuntu-latest: Job นี้จะรันบน GitHub-hosted Ubuntu runner ครับif: github.ref == 'refs/heads/main': นี่คือเงื่อนไขสำคัญครับ เราต้องการให้ Deploy เฉพาะเมื่อมีการ Push โค้ดไปยัง Branchmainเท่านั้น เพื่อป้องกันการ Deploy โค้ดที่ยังไม่สมบูรณ์ครับgithub.refจะให้ค่าเป็นrefs/heads/<branch-name>ครับenvironment(Optional): คุณสามารถกำหนดenvironmentได้เพื่อวัตถุประสงค์ในการติดตามการ Deploy, การกำหนดค่าความลับเฉพาะสภาพแวดล้อม และการเพิ่ม Manual Approvals ครับ อ่านเพิ่มเติมเกี่ยวกับ Environments
1. Download build artifact
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: node-app-build
path: ./app-to-deploy
Step นี้ใช้ actions/download-artifact@v4 เพื่อดาวน์โหลด Artifact ที่เราอัปโหลดไว้ใน Job build_and_test ครับ โดยจะถูกดาวน์โหลดไปยังโฟลเดอร์ ./app-to-deploy บน Runner ครับ
2. การนำไป Deploy จริง (ตัวอย่างแนวคิด)
- name: Simulate deployment
run: |
echo "Simulating deployment to production server..."
echo "Deploying artifact from ./app-to-deploy to your server..."
# ... (ตัวอย่างโค้ดจริงสำหรับการ Deploy) ...
echo "Deployment simulated successfully!"
นี่คือหัวใจของกระบวนการ Deploy ครับ ในตัวอย่างนี้ เราได้ใส่เพียงคำสั่ง echo เพื่อจำลองว่ากำลัง Deploy อยู่ครับ
ในสถานการณ์จริง คุณจะต้องใส่คำสั่งหรือ Action ที่เหมาะสมกับการ Deploy แอปพลิเคชันของคุณครับ ตัวอย่างเช่น:
- Static Site (เช่น React, Vue, Angular) ไปยัง S3/Netlify/Vercel:
# For AWS S3 aws s3 sync ./app-to-deploy/ s3://your-s3-bucket-name/ --delete # For Vercel npm install -g vercel vercel deploy ./app-to-deploy --prod --token=${{ secrets.VERCEL_TOKEN }} - Node.js Backend ไปยัง EC2/VPS ผ่าน SSH:
# ต้องติดตั้ง sshpass หรือใช้ SSH key ที่ปลอดภัยกว่า # ติดตั้ง sshpass (ในกรณีที่จำเป็น) # sudo apt-get update && sudo apt-get install -y sshpass # Deploy ผ่าน SSH (ต้องตั้งค่า SSH_USERNAME, SSH_HOST, SSH_PASSWORD หรือ SSH_PRIVATE_KEY ใน GitHub Secrets) # ใช้ rsync เพื่อคัดลอกไฟล์ rsync -avz --delete ./app-to-deploy/ ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }}:/var/www/your-app/ # รันคำสั่งบนเซิร์ฟเวอร์เพื่อรีสตาร์ทแอป ssh ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_HOST }} "cd /var/www/your-app && npm install --production && pm2 restart your-app-name"หมายเหตุ: การใช้รหัสผ่านผ่าน Environment Variable เช่น
SSH_PASSWORDไม่ใช่วิธีที่ปลอดภัยที่สุดครับ ควรใช้ SSH Key และตั้งค่า Key ใน Secrets แทนครับ - Containerized App (Docker) ไปยัง Docker Hub และ Kubernetes:
# Build Docker image docker build -t your-docker-id/my-node-app:latest ./app-to-deploy # Login to Docker Hub echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin # Push Docker image docker push your-docker-id/my-node-app:latest # Deploy to Kubernetes (using kubectl) # kubectl apply -f kubernetes/deployment.yaml
เมื่อคุณ Commit และ Push การเปลี่ยนแปลงนี้ไปยัง Branch main Workflow ของคุณจะรันทั้ง Job build_and_test และ Job deploy ตามลำดับครับ
เทคนิคขั้นสูงสำหรับ GitHub Actions
GitHub Actions มีความสามารถที่หลากหลายและยืดหยุ่นมากครับ นอกจากพื้นฐานแล้ว ยังมีเทคนิคขั้นสูงอีกหลายอย่างที่จะช่วยให้ Workflow ของคุณมีประสิทธิภาพ ปลอดภัย และจัดการได้ง่ายขึ้นครับ
Matrix Strategies: การทดสอบข้ามสภาพแวดล้อม
Matrix Strategy ช่วยให้คุณสามารถรัน Job เดียวกันหลายๆ ครั้ง โดยใช้ชุดของตัวแปรที่แตกต่างกันไปครับ มีประโยชน์อย่างมากสำหรับการทดสอบแอปพลิเคชันของคุณกับ Node.js หลายเวอร์ชัน, ระบบปฏิบัติการหลายประเภท หรือแม้กระทั่ง Browser หลายตัวครับ
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [18, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }} on ${{ matrix.os }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
ในตัวอย่างนี้ Job test จะถูกรัน 4 ครั้ง (2 OS x 2 Node.js versions) ทำให้มั่นใจได้ว่าแอปพลิเคชันของคุณทำงานได้ดีในหลายสภาพแวดล้อมครับ
Caching Dependencies: เพิ่มความเร็วให้ Workflow
การติดตั้ง Dependencies เช่น npm install, pip install, หรือ composer install มักใช้เวลานานครับ GitHub Actions มี Action actions/cache@v3 ที่ช่วยให้คุณแคช Dependencies เหล่านี้ได้ ทำให้ Workflow รันได้เร็วขึ้นอย่างมากในการรันครั้งถัดไปครับ
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # ใช้ cache built-in ของ setup-node action
# หรือใช้ actions/cache@v3 สำหรับกรณีที่ซับซ้อนกว่า
# - name: Cache dependencies
# uses: actions/cache@v3
# with:
# path: ~/.npm # หรือ node_modules สำหรับ Yarn/pnpm
# key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
# restore-keys: |
# ${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
การเลือกใช้ cache: 'npm' ใน setup-node action เป็นวิธีที่ง่ายและแนะนำสำหรับโปรเจกต์ Node.js ครับ หากต้องการแคชที่ซับซ้อนขึ้นสำหรับภาษาอื่น หรือต้องการปรับแต่ง Path การแคช คุณสามารถใช้ actions/cache@v3 ได้โดยตรงครับ
Environment Variables และ Secrets
เราได้กล่าวถึง Secrets ไปแล้วก่อนหน้านี้ว่าเป็นวิธีที่ปลอดภัยในการจัดเก็บข้อมูลที่ละเอียดอ่อนครับ นอกจากนี้ คุณยังสามารถกำหนด Environment Variables ได้ในระดับต่างๆ ครับ
- ระดับ Workflow: ใช้
env:ที่ระดับบนสุดของ Workflow - ระดับ Job: ใช้
env:ภายใน Job - ระดับ Step: ใช้
env:ภายใน Step
name: Env and Secrets Demo
on: [push]
env:
GLOBAL_VAR: "This is a global variable"
jobs:
my_job:
runs-on: ubuntu-latest
env:
JOB_VAR: "This is a job variable"
steps:
- name: Print variables
run: |
echo "Global var: ${{ env.GLOBAL_VAR }}"
echo "Job var: ${{ env.JOB_VAR }}"
echo "Secret: ${{ secrets.MY_SECRET }}" # เข้าถึง secret
env:
STEP_VAR: "This is a step variable" # กำหนด env เฉพาะ step
# สามารถ override env ระดับที่สูงกว่าได้
JOB_VAR: "Overridden job variable"
การใช้ Environment Variables ช่วยให้ Workflow ของคุณยืดหยุ่นและปรับแต่งได้ง่าย โดยไม่ต้องแก้ไขโค้ด Workflow ครับ
Reusable Workflows: การสร้าง Workflow ที่นำกลับมาใช้ซ้ำได้
เมื่อโปรเจกต์ของคุณเติบโตขึ้น คุณอาจพบว่ามี Workflow หลายตัวที่มี Steps หรือ Jobs ที่คล้ายกันครับ Reusable Workflows ช่วยให้คุณสามารถสร้าง Workflow ที่สามารถเรียกใช้จาก Workflow อื่นๆ ได้ ทำให้โค้ด Workflow ของคุณ DRY (Don’t Repeat Yourself) และง่ายต่อการบำรุงรักษาครับ
ตัวอย่าง: Workflow ที่เรียกใช้ได้ (.github/workflows/callable-build.yml)
name: Callable Build & Test
on:
workflow_call: # กำหนดให้ Workflow นี้สามารถถูกเรียกใช้ได้
inputs:
node-version:
required: true
type: string
description: 'Node.js version to use'
outputs:
build-output:
description: "Path to the built artifact"
value: ${{ jobs.build.outputs.artifact-path }}
secrets:
NPM_TOKEN:
required: false
jobs:
build:
runs-on: ubuntu-latest
outputs:
artifact-path: ${{ steps.upload.outputs.artifact-path }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- name: Install dependencies
run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # ใช้ secret ที่ส่งมา
- name: Run tests
run: npm test
- name: Build application
run: npm run build
- name: Upload build artifact
id: upload # กำหนด id ให้ step เพื่อเข้าถึง outputs
uses: actions/upload-artifact@v4
with:
name: node-app-build-${{ github.run_id }}
path: dist
retention-days: 7
env:
artifact-path: dist # กำหนด output ของ step นี้
ตัวอย่าง: Workflow ที่เรียกใช้ Reusable Workflow (.github/workflows/main-ci-cd.yml)
name: Main CI/CD Pipeline
on:
push:
branches: [main]
jobs:
ci:
uses: ./.github/workflows/callable-build.yml # เรียกใช้ Reusable Workflow
with:
node-version: '20'
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # ส่ง secret ไปยัง Reusable Workflow
deploy:
needs: ci
runs-on: ubuntu-latest
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: node-app-build-${{ github.run_id }}
path: ./app-to-deploy
- name: Deploy to production
run: echo "Deploying from ${{ github.workspace }}/app-to-deploy"
# ... your deployment logic ...
Reusable Workflows ช่วยให้คุณสามารถสร้าง Component ของ Workflow ที่เป็นมาตรฐานและนำกลับมาใช้ได้ทั่วทั้ง Organization หรือ Repository ของคุณครับ อ่านเพิ่มเติมเกี่ยวกับการสร้าง Reusable Workflows
Self-Hosted Runners: รัน Workflow ในโครงสร้างพื้นฐานของคุณ
ในบางกรณี คุณอาจต้องการรัน Workflow บนเครื่องของคุณเองแทนที่จะใช้ GitHub-hosted runners ครับ เช่น:
- ต้องการฮาร์ดแวร์เฉพาะ: GPU สำหรับ Machine Learning, CPU ที่มีประสิทธิภาพสูง
- ต้องการสภาพแวดล้อมที่กำหนดเอง: ซอฟต์แวร์เฉพาะ, การตั้งค่าเครือข่ายพิเศษ
- เข้าถึงทรัพยากรภายในเครือข่ายส่วนตัว: ฐานข้อมูล, เซิร์ฟเวอร์ภายในองค์กร
- ลดค่าใช้จ่าย: หากคุณมีการใช้งาน GitHub Actions จำนวนมาก การใช้ Self-hosted runners อาจคุ้มค่ากว่า
การตั้งค่า Self-hosted runner ประกอบด้วยการติดตั้งแอปพลิเคชัน GitHub Actions Runner บนเครื่อง Linux, Windows หรือ macOS ของคุณ และลงทะเบียนกับ GitHub ครับ จากนั้นคุณสามารถระบุ runs-on: self-hosted หรือใช้ Label ที่กำหนดเอง เช่น runs-on: [self-hosted, linux, x64, my-custom-label] ใน Job ของคุณได้ครับ
ข้อควรพิจารณา: คุณต้องรับผิดชอบในการบำรุงรักษา, อัปเดต, และความปลอดภัยของ Self-hosted runner ของคุณเองครับ
Deployment Environments และ Manual Approvals
สำหรับกระบวนการ Continuous Delivery ที่ต้องการการตรวจสอบหรืออนุมัติก่อนการ Deploy ไปยัง Production GitHub Actions มีฟีเจอร์ Deployment Environments ครับ
คุณสามารถกำหนด Environment เช่น “Staging”, “Production” ใน Repository Settings ได้ครับ สำหรับแต่ละ Environment คุณสามารถ:
- กำหนดผู้ตรวจสอบ (Reviewers): กำหนดให้บุคคลหรือทีมบางคนต้องอนุมัติก่อนที่ Workflow จะ Deploy ไปยัง Environment นั้นๆ
- กำหนดเวลาป้องกัน (Wait Timer): กำหนดให้ Workflow รอเป็นระยะเวลาหนึ่งก่อนที่จะ Deploy
- กำหนด Secrets เฉพาะ Environment: Secrets ที่จะถูกเปิดเผยเฉพาะเมื่อ Deploy ไปยัง Environment นั้นๆ เท่านั้น
การใช้ใน Workflow:
jobs:
deploy-to-production:
runs-on: ubuntu-latest
environment:
name: Production # กำหนด Environment ที่จะ Deploy
url: https://your-production-app.com # URL ของแอปที่ถูก deploy
steps:
- name: Deploy to production
run: echo "Deploying to production with approval..."
env:
PROD_API_KEY: ${{ secrets.PROD_API_KEY }} # ใช้ Secret เฉพาะ Production
เมื่อ Workflow นี้ถูกทริกเกอร์และถึง Job deploy-to-production หากมีการกำหนด Reviewers ไว้ Workflow จะหยุดรอการอนุมัติก่อนดำเนินการต่อครับ
Monorepos และ Path Filtering
ใน Monorepo ที่มีโปรเจกต์หลายตัวใน Repository เดียวกัน คุณอาจไม่ต้องการให้ Workflow ทั้งหมดรันเมื่อมีการเปลี่ยนแปลงเพียงส่วนเล็กๆ ของโค้ดครับ GitHub Actions รองรับ Path Filtering ซึ่งช่วยให้คุณกำหนดได้ว่า Workflow จะรันเมื่อมีการเปลี่ยนแปลงใน Path ที่กำหนดเท่านั้นครับ
on:
push:
paths:
- 'services/frontend/**' # Workflow นี้จะทำงานเมื่อโค้ดในโฟลเดอร์ frontend เปลี่ยนแปลง
- '.github/workflows/frontend-ci.yml' # และเมื่อไฟล์ workflow นี้เปลี่ยนแปลงด้วย
pull_request:
paths:
- 'services/frontend/**'
คุณยังสามารถใช้ Conditional logic ใน Jobs หรือ Steps เพื่อตรวจสอบว่า Path ใดเปลี่ยนแปลงไป และรันส่วนที่เกี่ยวข้องเท่านั้นได้ครับ
แนวทางปฏิบัติที่ดีที่สุดสำหรับ CI/CD ด้วย GitHub Actions
เพื่อให้ GitHub Actions Pipeline ของคุณมีประสิทธิภาพ ปลอดภัย และจัดการได้ง่าย มีแนวทางปฏิบัติที่ดีที่สุดบางอย่างที่คุณควรพิจารณาครับ
ความปลอดภัย
- ใช้ Secrets อย่างระมัดระวัง:
- อย่า Hardcode Secrets ใน Workflow ของคุณครับ
- ใช้ Secrets ใน GitHub Actions และจำกัดสิทธิ์การเข้าถึงให้เฉพาะ Workflow หรือ Environment ที่จำเป็นเท่านั้น
- หลีกเลี่ยงการแสดง Secrets ใน Logs ของ Workflow (GitHub Actions จะเซ็นเซอร์โดยอัตโนมัติ แต่ควรระมัดระวังการสร้าง Output ที่อาจเปิดเผย Secret)
- จำกัดสิทธิ์ของ Access Token: GitHub Actions จะสร้าง
GITHUB_TOKENสำหรับแต่ละ Workflow ครับ คุณสามารถกำหนดสิทธิ์ (permissions) ของ Token นี้ได้ในระดับ Workflow หรือ Job เพื่อให้มีสิทธิ์น้อยที่สุดเท่าที่จำเป็น (Least Privilege) ครับ - ตรวจสอบ Actions ของบุคคลที่สาม: ก่อนใช้ Actions จาก GitHub Marketplace ให้ตรวจสอบผู้สร้าง, จำนวนการใช้งาน, รีวิว, และโค้ดของ Action นั้นๆ เพื่อความปลอดภัยครับ
- พินเวอร์ชันของ Actions: ใช้เวอร์ชันที่แน่นอนของ Actions (เช่น
@v4หรือ@commit_hash) แทนที่จะใช้@latestเพื่อหลีกเลี่ยงการเปลี่ยนแปลงที่ไม่คาดคิดครับ - ใช้ Environments และ Manual Approvals: โดยเฉพาะสำหรับการ Deploy ไปยัง Production เพื่อเพิ่มชั้นความปลอดภัยและการตรวจสอบครับ
ประสิทธิภาพ
- ใช้ Caching อย่างมีประสิทธิภาพ: แคช Dependencies, Build artifacts เพื่อลดเวลาในการรัน Workflow ครับ
- รัน Jobs แบบขนาน: หาก Jobs ไม่ได้ขึ้นต่อกัน ให้รันแบบขนานเพื่อประหยัดเวลาครับ
- ใช้ Self-hosted runners สำหรับงานหนัก: หากคุณมีงานที่ต้องใช้ทรัพยากรสูง หรือต้องการฮาร์ดแวร์เฉพาะ Self-hosted runners อาจเป็นทางเลือกที่ดีกว่าครับ
- Path Filtering ใน Monorepos: รัน Workflow เฉพาะเมื่อมีการเปลี่ยนแปลงในส่วนที่เกี่ยวข้องเท่านั้นครับ
- ลดขนาด Docker Images: หากคุณ Build Docker Images พยายามทำให้ Image มีขนาดเล็กที่สุดเพื่อลดเวลาในการ Build และ Push ครับ
ความสามารถในการบำรุงรักษา
- ตั้งชื่อ Workflow, Jobs, และ Steps ที่สื่อความหมาย: เพื่อให้ง่ายต่อการทำความเข้าใจว่าแต่ละส่วนทำอะไรครับ
- ใช้ Reusable Workflows: เพื่อหลีกเลี่ยงการทำซ้ำโค้ดและสร้าง Workflow ที่เป็นมาตรฐานครับ
- แบ่ง Workflow ออกเป็นไฟล์ย่อยๆ: หาก Workflow ของคุณมีขนาดใหญ่และซับซ้อนเกินไป อาจพิจารณาแบ่งเป็น Workflow ย่อยๆ หรือใช้ Reusable Workflows ครับ
- เพิ่ม Comments: อธิบาย Logic ที่ซับซ้อนหรือเงื่อนไขพิเศษในไฟล์ YAML ครับ