Skip to content
Tayakorn
devUpdated 2026-07-13Free

CI/CD Handbook

CI/CD 0 → Hero จาก commit สู่ production อัตโนมัติ — pipeline, jobs, artifacts, matrix, secrets, กลยุทธ์ deploy, rollback และความปลอดภัย แบบไม่ผูกเครื่องมือ

#ci-cd#github-actions#devops#pipeline#deployment#automation
Contents

เข้าใจ CI/CD 0 → Hero — จาก commit สู่ production อัตโนมัติ (CI/CD Handbook · 14 บท · 5 ระดับ) · เล่มต่อจาก Git 0 → Hero — พาคุณจากคนไม่เคยตั้ง pipeline ไปจนออกแบบสายการส่งมอบซอฟต์แวร์ที่อัตโนมัติ ปลอดภัย และเชื่อถือได้ เน้นแนวคิดและเหตุผลที่ไม่ผูกกับเครื่องมือใดเครื่องมือหนึ่ง พร้อมตัวอย่าง YAML จริงและเทียบหลายแพลตฟอร์ม

  • ต่อจาก: Git 0 → Hero
  • เวลาอ่าน: ~90 นาที
  • ภาษา: ไทย พร้อมไดอะแกรม

LEVEL 0 · ปูพื้นจากศูนย์

CI/CD คืออะไร & ทำไมต้องมี#

ในเล่ม Git คุณเรียนวิธีบันทึกและรวมโค้ดของหลายคนเข้าด้วยกัน แต่มีคำถามที่ค้างอยู่: หลังจาก git push แล้ว ใครเป็นคนตรวจว่าโค้ดที่เพิ่งรวมเข้ามายัง build ได้ เทสต์ผ่าน และไม่ทำของเดิมพัง? ถ้าคำตอบคือ "คนในทีมต้องมานั่งตรวจเองทุกครั้ง" นั่นคือจุดที่ทุกอย่างเริ่มช้าและพลาดง่าย CI/CD คือการยกงานตรวจสอบและส่งมอบทั้งหมดนั้นให้ เครื่องทำอัตโนมัติทุกครั้งที่โค้ดเปลี่ยน

ตัวย่อสองชุดนี้แยกเป็นสองเรื่องที่ต่อเนื่องกัน:

  • CI — Continuous Integration (การรวมโค้ดอย่างต่อเนื่อง): รวมงานของทุกคนเข้าสายหลักบ่อย ๆ แล้วให้ระบบ build + test อัตโนมัติทันที เพื่อจับปัญหาให้เร็วที่สุด
  • CD — Continuous Delivery / Deployment (การส่งมอบ/ปล่อยขึ้นใช้งานอย่างต่อเนื่อง): เมื่อโค้ดผ่าน CI แล้ว ก็ แพ็กและส่งขึ้นไปใช้งานจริงอัตโนมัติ หรือเตรียมให้พร้อมกดปล่อยได้ทันที

1.1 ปัญหาที่ CI เกิดมาเพื่อแก้ — "integration hell"

ลองนึกถึงทีมที่แต่ละคนแยกไปเขียนฟีเจอร์ของตัวเองคนละ branch เป็นเวลาหนึ่งเดือน โดยไม่รวมกลับเลย พอถึงวันรวม (integrate) ทุกคนพบว่าโค้ดชนกันเต็มไปหมด สมมติฐานไม่ตรงกัน ของที่เคยทำงานกลับพัง — ต้องเสียเวลาเป็นสัปดาห์แก้ "วันรวมร่าง" นี้คือสิ่งที่เรียกว่า integration hell

CI พลิกปัญหานี้ด้วยหลักง่าย ๆ ข้อเดียว: ถ้าการรวมเจ็บ ก็รวมให้บ่อยขึ้นจนมันไม่เจ็บ รวมวันละหลายครั้ง ทีละนิด แล้วให้เครื่องตรวจทุกครั้ง ปัญหาจะถูกจับตั้งแต่ยังเล็กและรู้ทันทีว่าเกิดจาก commit ไหน

รวมนาน ๆ ครั้งปัญหากองสะสมจนระเบิดทีเดียว💥merge ครั้งใหญ่ = นรกContinuous Integrationรวมบ่อย ตรวจทุกครั้ง จับปัญหาตั้งแต่เล็กพังตรงนี้ → รู้ทันทีแก้แค่ commit เดียว
FIG 1.1 ยิ่งเว้นช่วงรวมโค้ดนาน ปัญหายิ่งกองทับกันจนแก้ยาก · CI ทำให้ทุก commit ถูกตรวจทันที ความพังถูกจำกัดวงให้เล็กและชี้ตัวการได้ตรงจุด

1.2 หัวใจคือ "วงจรป้อนกลับที่สั้น"

คุณค่าที่แท้จริงของ CI/CD ไม่ใช่ "ความอัตโนมัติ" เอง แต่คือ ความเร็วของวงจรป้อนกลับ (feedback loop) — ระยะเวลาตั้งแต่คุณเขียนโค้ดผิด จนถึงตอนที่มีคน/อะไรบางอย่างบอกคุณว่ามันผิด ยิ่งวงจรนี้สั้น ค่าแก้ยิ่งถูก เพราะคุณยังจำได้ว่าเพิ่งแก้อะไรไป และบั๊กยังไม่ทันแพร่ไปไหน

บั๊กถูกจับเมื่อค่าใช้จ่ายในการแก้
ตอนเขียน (ในเครื่องตัวเอง)แทบฟรี — แก้ทันที
ตอน CI รันหลัง push (ไม่กี่นาทีต่อมา)ถูก — ยังจำ context ได้
ตอน reviewer หรือ QA เจอ (วันต่อมา)ปานกลาง — ต้องวนกลับมาคิดใหม่
ตอนลูกค้าเจอบน productionแพงที่สุด — กระทบจริง + เร่งแก้

CI/CD คือเครื่องจักรที่ดัน "จุดที่จับบั๊กได้" ให้ขยับขึ้นไปบนสุดของตารางนี้ให้มากที่สุด

🧭 CI/CD ต่อยอดจาก Git โดยตรง — ทุกอย่างในเล่มนี้เริ่มทำงานจากเหตุการณ์ใน Git ที่คุณเรียนมาแล้ว — git push และการเปิด Pull Request คือ "ทริกเกอร์" ที่ปลุก pipeline ให้ตื่นขึ้นมาทำงาน ถ้ายังไม่แม่นเรื่อง branch กับ PR แนะนำให้ทบทวนบทที่ 4–5 และ 10 ของเล่ม Git ก่อน

สรุปบทที่ 1 — CI = รวมโค้ดบ่อย ๆ แล้วให้เครื่อง build+test ทุกครั้ง · CD = ส่ง/ปล่อยขึ้นใช้งานอัตโนมัติเมื่อผ่าน CI · เกิดมาเพื่อฆ่า "integration hell" ด้วยการรวมถี่จนไม่เจ็บ · หัวใจคือ วงจรป้อนกลับที่สั้น — จับบั๊กยิ่งเร็ว ยิ่งถูก · pipeline ถูกปลุกโดยเหตุการณ์ใน Git เช่น push และ PR

แบบจำลองความคิดหลัก#

บทนี้สำคัญที่สุดในเล่ม เช่นเดียวกับบทที่ 2 ของเล่ม Git ถ้าคุณเข้าใจสองแนวคิดต่อไปนี้ — กายวิภาคของ pipeline และ เส้นแบ่งสามระดับของ CI/CD — รายละเอียด YAML ที่เหลือทั้งเล่มจะกลายเป็นเรื่องเดาได้ ไม่ใช่เรื่องท่องจำ

2.1 Pipeline คือสายพานประกอบอัตโนมัติ

แก่นของ CI/CD คือ pipeline — ชุดขั้นตอนที่ทำงานเรียงต่อกันโดยอัตโนมัติเมื่อมีเหตุการณ์มากระตุ้น มองมันเป็นสายพานในโรงงาน: โค้ดดิบเข้าทางหนึ่ง ผ่านสถานีตรวจและประกอบทีละสถานี แล้วออกอีกทางเป็นซอฟต์แวร์ที่พร้อมใช้งาน ทุกแพลตฟอร์ม (GitHub Actions, GitLab CI, Jenkins, CircleCI) ใช้คำศัพท์ต่างกันแต่โครงสร้างเดียวกันนี้เสมอ:

Eventpush / PRWorkflow / PipelineJob: testruns-on: runner (เครื่อง)step: checkout → setup → teststep รันเรียงกันบนเครื่องเดียวJob: deployneeds: test (รอ test ผ่านก่อน)step: build → push imagestep: deploy → ตรวจสุขภาพ
FIG 2.1 ลำดับชั้น: event ปลุก → workflow (ทั้ง pipeline) → ประกอบด้วยหลาย job (รันขนานกันได้ แต่ละอันบน runner ของตัวเอง) → แต่ละ job มีหลาย step ที่รันเรียงกันบนเครื่องเดียว

จำลำดับชั้นนี้ไว้ให้แม่น เพราะมันคือโครงของทุกอย่าง:

ชั้นคืออะไรกฎสำคัญ
Event (trigger)เหตุการณ์ที่ปลุก pipelinepush, PR, tag, ตามเวลา, กดเอง
Workflow / Pipelineทั้งกระบวนการ เขียนไว้ในไฟล์ YAMLหนึ่งไฟล์ = หนึ่ง pipeline
Jobกลุ่มงานที่รันบนเครื่องหนึ่งเครื่องหลาย job รันขนานกันโดยปริยาย
Stepคำสั่งย่อยในแต่ละ jobstep รันเรียงกัน แชร์พื้นที่ทำงาน
Runnerเครื่อง (จริง/เสมือน) ที่รัน jobเริ่มสะอาดทุกครั้ง ไม่มีของค้าง

2.2 เส้นแบ่งสามระดับ: Integration → Delivery → Deployment

คนสับสน "CD" มากที่สุด เพราะมันย่อได้สองคำที่ต่างกัน ความจริงคือมันคือ สามขั้นที่ซ้อนกันเป็นชั้น ๆ แต่ละขั้นเพิ่มความอัตโนมัติขึ้นไปอีกระดับ:

ContinuousIntegrationbuild + test ทุก commitอัตโนมัติ"โค้ดยังดีอยู่ไหม?"ContinuousDeliveryCI + แพ็กพร้อมปล่อยแต่ "กดปล่อย" เอง 🟡"พร้อมปล่อยทุกเมื่อ"ContinuousDeploymentDelivery + ปล่อยขึ้น prodอัตโนมัติเต็มรูปแบบ ⚡"ผ่าน = ขึ้นจริงเลย"
FIG 2.2 แต่ละขั้นครอบขั้นก่อนหน้าไว้ทั้งหมด · ความต่างเดียวระหว่าง Delivery กับ Deployment คือ มี “มนุษย์กดปุ่ม” คั่นก่อนขึ้น production หรือไม่

เส้นแบ่งที่ต้องจำให้ขึ้นใจ: Continuous Delivery = ระบบทำให้ "พร้อมปล่อย" อัตโนมัติ แต่การกดปล่อยจริงเป็นการตัดสินใจของคน ส่วน Continuous Deployment = ตัดมนุษย์ออกจากสมการ ผ่าน CI/ทดสอบเมื่อไรก็ขึ้น production เมื่อนั้นทันที ทีมส่วนใหญ่เริ่มจาก Delivery แล้วค่อยขยับไป Deployment เมื่อความเชื่อมั่นในชุดทดสอบสูงพอ (ลงลึกในบทที่ 9)

2.3 หลักการที่อยู่เบื้องหลังทั้งหมด

ก่อนลงรายละเอียด จำหลักสามข้อนี้ไว้ มันคือ "ทำไม" ที่อยู่ใต้ทุกคำสั่งในเล่ม:

  • ทำซ้ำได้เสมอ (reproducible) — pipeline เริ่มจากเครื่องสะอาดทุกครั้ง สิ่งที่ผ่านบน CI ต้องผ่านเหมือนกันไม่ว่าใครรัน "มันรันได้บนเครื่องผม" จึงไม่ใช่ข้ออ้างอีกต่อไป
  • เร็วเข้าไว้ (fast feedback) — pipeline ที่ใช้เวลา 40 นาทีคือ pipeline ที่ไม่มีใครรอดู ความเร็วคือฟีเจอร์
  • ล้มให้ดัง (fail loud) — เมื่อมีอะไรพัง ต้องหยุดและแจ้งทันที ไม่ใช่ปล่อยผ่านเงียบ ๆ แล้วให้ของเสียไหลขึ้น production

สรุปบทที่ 2 — pipeline = สายพานอัตโนมัติ มีลำดับชั้น event → workflow → job (ขนาน) → step (เรียง) บน runner · CI/CD คือสามชั้นซ้อนกัน: Integration (build+test) ⊂ Delivery (พร้อมปล่อย กดเอง) ⊂ Deployment (ขึ้น prod อัตโนมัติ) · เส้นแบ่ง Delivery/Deployment คือ "มีคนกดปุ่มไหม" · หลักการใต้ทุกอย่าง: ทำซ้ำได้ · เร็ว · ล้มให้ดัง

LEVEL 1 · พื้นฐานที่ใช้จริง

Pipeline แรกของคุณ#

ทฤษฎีพอแล้ว มาเขียน pipeline จริงกัน เราจะใช้ GitHub Actions เป็นตัวอย่างหลักตลอดเล่ม เพราะใกล้กับเล่ม Git ที่สุดและเริ่มฟรีได้ทันที แต่ทุกแนวคิดย้ายไปแพลตฟอร์มอื่นได้ (บทที่ 14 เทียบให้ครบ) — โครงสร้างเปลี่ยน แต่ความคิดเหมือนเดิม

3.1 ไฟล์เดียวที่ปลุกทุกอย่าง

ใน GitHub Actions คุณแค่สร้างไฟล์ YAML ไว้ในโฟลเดอร์ .github/workflows/ แล้ว push ขึ้นไป — GitHub จะเห็นและเริ่มรันให้เองทันที ไม่ต้องตั้งค่าเซิร์ฟเวอร์อะไรเลย นี่คือ pipeline ที่สมบูรณ์ที่สุดเท่าที่ใช้งานได้จริง:

# .github/workflows/ci.yml
name: CI
on:                          # เมื่อไรให้รัน — นี่คือ "trigger"
  push:
    branches: [main]
  pull_request:             # รันตอนเปิด/อัปเดต PR ด้วย

jobs:
  test:                       # ชื่อ job (ตั้งเองได้)
    runs-on: ubuntu-latest    # รันบนเครื่อง Linux ที่ GitHub เตรียมให้
    steps:
      - uses: actions/checkout@v4      # 1. ดึงโค้ด repo ลงมาในเครื่อง runner
      - uses: actions/setup-node@v4     # 2. ติดตั้ง Node.js
        with:
          node-version: 20
      - run: npm ci                    # 3. ติดตั้ง dependencies
      - run: npm test                  # 4. รันชุดทดสอบ — ถ้าพัง pipeline แดงทันที

3.2 อ่าน YAML นี้ทีละชั้น

ทุกบรรทัดแมปกับลำดับชั้นในบทที่ 2 ตรง ๆ:

  • on: คือ event/trigger — บอกว่าให้ปลุก pipeline เมื่อ push เข้า main หรือเมื่อมี PR
  • jobs: ใต้นั้นคือรายการ job — ตอนนี้มีตัวเดียวชื่อ test
  • runs-on: เลือก runner — เครื่องเปล่า ๆ ที่ GitHub สร้างใหม่ให้ทุกครั้ง
  • steps: คือ step ที่รันเรียงจากบนลงล่าง มีสองแบบ: uses: เรียกใช้ "action" สำเร็จรูปที่คนอื่นเขียนไว้ และ run: สั่ง shell command ตรง ๆ

หัวใจอยู่ที่ step สุดท้าย: ถ้า npm test คืน exit code ไม่เป็นศูนย์ (เทสต์ตก) step นั้นล้มเหลว job ก็ล้มเหลว และ pipeline ขึ้นสถานะแดง — บน PR คุณจะเห็นเครื่องหมาย ✕ ทันที นี่แหละคือ "fail loud" ในทางปฏิบัติ

3.3 การเริ่มสะอาดทุกครั้งคือฟีเจอร์ ไม่ใช่บั๊ก

สังเกตว่าทำไมต้องมี checkout และ setup-node ทุกครั้ง — เพราะ runner เกิดใหม่จากศูนย์ทุกการรัน ไม่มีโค้ด ไม่มี Node ติดมาก่อน นี่คือสิ่งที่ทำให้ pipeline "ทำซ้ำได้": ไม่มีของค้างจากการรันก่อนหน้ามาปนเปื้อนผล สิ่งที่ผ่านวันนี้จะผ่านเหมือนกันในอีกหกเดือน

🧭 ลองเองได้ใน 2 นาที — เอา repo ที่มี npm test อยู่แล้ว สร้างไฟล์ .github/workflows/ci.yml ตามด้านบน แล้ว git addcommitpush เปิดแท็บ Actions บน GitHub คุณจะเห็น pipeline เริ่มหมุนทันที — นี่คือ git push จากเล่มที่แล้ว ที่ตอนนี้ "เกิดอะไรต่อ" แล้วจริง ๆ

สรุปบทที่ 3 — pipeline = ไฟล์ YAML ใน .github/workflows/ · on: กำหนด trigger, jobs:steps: กำหนดงาน · step มีสองแบบ uses: (action สำเร็จรูป) และ run: (คำสั่ง shell) · runner เริ่มสะอาดทุกครั้งจึงต้อง checkout/setup ใหม่ — ความสะอาดนี้คือรากของการทำซ้ำได้ · เทสต์ตก = exit code ไม่เป็นศูนย์ = pipeline แดง

Jobs · Steps · Runners#

บทที่แล้วมี job เดียว pipeline จริงมักมีหลาย job ที่ต้องประสานกัน เข้าใจกฎการทำงานร่วมของ job/step/runner แล้ว คุณจะออกแบบ pipeline ที่ทั้งเร็วและถูกต้องได้

4.1 กฎทองสองข้อ: job ขนาน · step เรียง

นี่คือจุดที่มือใหม่พลาดบ่อยที่สุด ขอย้ำให้ชัด:

  • หลาย job รันขนานกันโดยปริยาย และแต่ละ job อยู่บน runner คนละเครื่อง สะอาดแยกกัน — job หนึ่งสร้างไฟล์ไว้ อีก job มองไม่เห็น เพราะคนละเครื่อง
  • step ภายใน job เดียวกันรันเรียงกัน บนเครื่องเดียว และ แชร์พื้นที่ทำงาน (workspace) — step แรกติดตั้งของไว้ step ถัดไปใช้ได้ทันที

ผลที่ตามมาในทางปฏิบัติ: งานที่ต้อง "ส่งของต่อกัน" ให้ใส่เป็น step ใน job เดียว ส่วนงานที่อิสระต่อกัน (เช่น เทสต์ frontend กับ backend) ให้แยกเป็นคนละ job จะได้รันพร้อมกัน เร็วขึ้น

4.2 needs — บังคับลำดับเมื่อ job ต้องพึ่งกัน

บางที job ต้องรอกัน เช่น deploy ต้องรอ test ผ่านก่อน ใช้ needs: เพื่อสร้างความสัมพันธ์นั้น — มันเปลี่ยน job ที่เคยขนานให้กลายเป็นกราฟลำดับ (เหมือนสาย commit ในเล่ม Git):

lintตรวจสไตล์โค้ดtestรันชุดทดสอบขนานกัน (ไม่มี needs)buildneeds: [lint, test]deployneeds: build
FIG 4.1 lint กับ test ไม่พึ่งใครจึงรันพร้อมกัน · build ใส่ needs: [lint, test] จึงรอให้ทั้งสองผ่านก่อน · ถ้า job ที่ถูก needs ล้มเหลว job ที่รออยู่จะถูกข้าม (ไม่รัน) ทันที
jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [ ... รัน linter ... ]
  test:
    runs-on: ubuntu-latest
    steps: [ ... รันเทสต์ ... ]
  build:
    needs: [lint, test]      # รอ lint และ test ผ่านทั้งคู่ก่อน
    runs-on: ubuntu-latest
    steps: [ ... build โปรเจกต์ ... ]

4.3 Runner — เครื่องที่ลงมือทำจริง

Runner คือเครื่อง (จริงหรือเสมือน) ที่รับ job ไปรันจริง มีสองแบบใหญ่ ๆ ซึ่งเราจะลงลึกในบทที่ 13:

  • Hosted runner — แพลตฟอร์มเตรียมให้ (เช่น ubuntu-latest, windows-latest) เกิดใหม่สะอาดทุกครั้ง ไม่ต้องดูแล เหมาะกับงานทั่วไป
  • Self-hosted runner — เครื่องของคุณเองที่ลงโปรแกรม runner ไว้ ใช้เมื่อต้องการฮาร์ดแวร์พิเศษ (GPU), เข้าถึงเครือข่ายภายใน, หรือคุมค่าใช้จ่าย

สรุปบทที่ 4 — หลาย job รันขนานบน runner แยกเครื่องสะอาด · step ใน job เดียวรันเรียงและแชร์ workspace · needs: สร้างลำดับเมื่อ job ต้องพึ่งกัน และข้าม job ถัดไปถ้าตัวที่พึ่งล้ม · runner มี hosted (สะดวก) และ self-hosted (คุมเอง) · needs คุมลำดับ ไม่ได้ส่งไฟล์ — ส่งไฟล์ข้าม job ต้องใช้ artifact

Build · Test · Lint — สามเสาหลักของ CI#

CI ที่ดีไม่ได้วัดที่ "มี pipeline" แต่วัดที่ "ตรวจอะไรบ้าง" สามเสาหลักต่อไปนี้คือด่านมาตรฐานที่ทุก pipeline ควรมี เรียงจากเร็ว/ถูกไปช้า/แพง เพื่อให้ "ล้มเร็ว" — ด่านที่ถูกที่สุดควรล้มก่อน

5.1 Lint — ด่านที่ถูกและเร็วที่สุด

Lint คือการตรวจรูปแบบและกลิ่นของโค้ดโดยไม่ต้องรัน เช่น ตัวแปรที่ประกาศแล้วไม่ใช้, การจัดรูปแบบไม่สม่ำเสมอ, รูปแบบที่เสี่ยงบั๊ก มันเร็วมาก (วินาที) จึงควรเป็นด่านแรก ๆ — ไม่มีเหตุผลที่จะปล่อยให้เทสต์ที่ใช้เวลา 5 นาทีรันไปก่อน ทั้งที่โค้ดมี syntax ผิดที่ lint จับได้ใน 3 วินาที

5.2 Test — หัวใจของ CI

เทสต์อัตโนมัติคือสิ่งที่ทำให้ CI มีความหมาย เพราะมันคือสิ่งที่ "ตอบแทนคุณ" ว่าการเปลี่ยนแปลงไม่ทำของเดิมพัง โดยทั่วไปแบ่งเป็นชั้น ๆ ตามต้นทุน/ความเร็ว เรียกว่า testing pyramid:

ชั้นตรวจอะไรความเร็ว / จำนวน
Unitฟังก์ชัน/หน่วยเล็กที่สุด แยกเดี่ยวเร็วมาก · มีเยอะที่สุด
Integrationหลายส่วนทำงานร่วมกัน (เช่น โค้ด + ฐานข้อมูล)ปานกลาง · มีพอประมาณ
End-to-End (E2E)ทั้งระบบเหมือนผู้ใช้จริงกดใช้งานช้า/เปราะ · มีน้อยที่สุด

หลักคือ มี unit test เยอะ ๆ (เร็ว ถูก) เป็นฐาน แล้วมี E2E น้อย ๆ (ช้า แพง) ไว้บนยอด pipeline ฉลาด ๆ จะรัน unit ก่อนเพื่อล้มเร็ว แล้วค่อยลงทุนรัน E2E เมื่อชั้นล่างผ่านแล้ว

5.3 Build — พิสูจน์ว่ามันประกอบเป็นของจริงได้

การ build (คอมไพล์/แพ็ก) ใน CI พิสูจน์ว่าโค้ดไม่ใช่แค่ "เทสต์ผ่าน" แต่ "ประกอบออกมาเป็น artifact ที่ deploy ได้จริง" สำหรับภาษาที่คอมไพล์ ขั้นนี้จับ type error และปัญหา dependency ได้ ส่วนงานยุคใหม่มักจบที่การสร้าง container image ที่จะถูกส่งต่อไป deploy ในฝั่ง CD

5.4 เชื่อม CI กลับเข้า Git: status check & branch protection

นี่คือจุดที่ CI กับ Git บรรจบกันอย่างทรงพลัง ผลของ pipeline (เขียว/แดง) จะแสดงเป็น status check บน Pull Request และคุณตั้ง branch protection ให้ main ได้ว่า "ห้าม merge PR เข้ามาถ้า CI ยังไม่เขียว" — เท่ากับเปลี่ยน "ควรรันเทสต์นะ" (วินัยที่คนลืม) ให้เป็น "ระบบไม่ยอมให้ผ่านถ้าเทสต์ตก" (กฎที่บังคับเอง)

🧭 ต่อจากบทที่ 10 ของเล่ม Git — จำ Pull Request ได้ไหม — branch protection คือสิ่งที่เปลี่ยน PR จาก "ที่ขอให้รีวิว" ให้กลายเป็น "ประตูที่มีด่านอัตโนมัติเฝ้า" ทีมจริงจังมักบังคับทั้งสองอย่าง: ต้องมีคนรีวิวอนุมัติ และ CI ต้องเขียว ถึงจะกดปุ่ม merge ได้

สรุปบทที่ 5 — สามเสาหลัก เรียงจากถูก/เร็วไปแพง/ช้า: lint → test → build ให้ด่านถูกล้มก่อน · เทสต์เป็นพีระมิด: unit เยอะ (ฐาน) E2E น้อย (ยอด) · build พิสูจน์ว่าประกอบเป็น artifact จริงได้ · ผูก CI กลับเข้า Git ด้วย status check + branch protection เพื่อบังคับว่า "CI ไม่เขียว = merge ไม่ได้"

LEVEL 2 · ระดับกลาง

Artifacts & Caching#

สองคำนี้คือ "fetch กับ pull" แห่งโลก CI/CD — ฟังดูคล้ายกันจนคนสับสนตลอด แต่จุดประสงค์ต่างกันสิ้นเชิง เข้าใจเส้นแบ่งนี้แล้ว pipeline ของคุณจะทั้งเร็วขึ้นและส่งของต่อกันได้ถูกต้อง

Artifact — ส่ง "ผลงาน" ข้าม jobjob: buildสร้าง dist/job: deployเอา dist/ ไปใช้upload → download"ของจริงที่ต้องส่งต่อ"Cache — ใช้ซ้ำข้าม "การรัน"รันครั้งที่ 1โหลด deps 90sรันครั้งที่ 2ใช้ cache 5sเก็บ node_modules/ ไว้"ของชั่วคราวเพื่อความเร็ว — หายได้ไม่เป็นไร"
FIG 6.1 artifact ส่งผลลัพธ์ที่ “ต้องใช้ต่อ” ข้าม job ในการรันเดียวกัน · cache เก็บของที่ “สร้างใหม่ได้” ไว้ใช้ซ้ำข้ามการรัน เพื่อความเร็วล้วน ๆ

6.1 Artifact — ผลงานที่ต้องส่งต่อ

จำกับดักจากบทที่ 4: job คนละเครื่อง ส่งไฟล์หากันเองไม่ได้ artifact คือสะพานนั้น — job build "upload" ผลลัพธ์ (เช่นโฟลเดอร์ dist/ หรือไฟล์ .jar) ขึ้นที่เก็บกลาง แล้ว job deploy "download" กลับลงมาใช้ artifact เป็น ของที่มีคุณค่า ต้องเก็บไว้ใช้ต่อ และมักดาวน์โหลดมาดูภายหลังได้ด้วย

# ใน job build — อัปโหลดผลลัพธ์
- uses: actions/upload-artifact@v4
  with:
    name: dist
    path: dist/
# ใน job deploy — ดาวน์โหลดกลับมา
- uses: actions/download-artifact@v4
  with:
    name: dist

6.2 Cache — ความเร็วที่ทิ้งได้

การติดตั้ง dependencies (npm, pip, Maven) ซ้ำทุกครั้งเสียเวลามาก ทั้งที่มันแทบไม่เปลี่ยน cache แก้ตรงนี้: เก็บโฟลเดอร์ที่ "สร้างใหม่ได้" (เช่น node_modules/) ไว้ใช้ซ้ำในการรันครั้งหน้า ต่างจาก artifact ตรงที่ cache หายได้โดยไม่กระทบความถูกต้อง — แค่ทำให้ช้าลง pipeline ก็ยังรันได้เหมือนเดิม

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}   # key เปลี่ยนเมื่อ lock เปลี่ยน

เคล็ดอยู่ที่ cache key: ผูกกับ hash ของไฟล์ lock — ถ้า dependencies ไม่เปลี่ยน key เดิม ใช้ cache เดิม เร็วปรู๊ด; ถ้า lock เปลี่ยน key เปลี่ยน CI สร้าง cache ใหม่ให้ ไม่มีทางใช้ของเก่าผิดเวอร์ชัน

ArtifactCache
เพื่ออะไรส่งผลลัพธ์ข้าม job / เก็บไว้ดูเร่งความเร็วด้วยการใช้ซ้ำ
ถ้าหายไปpipeline พัง— เพราะ deploy ไม่มีของแค่ช้าลง — สร้างใหม่ได้
ขอบเขตภายในการรันเดียว (ข้าม job)ข้ามการรัน (ข้ามเวลา)

สรุปบทที่ 6artifact = ส่ง "ผลงานที่ต้องใช้ต่อ" ข้าม job (build→deploy) ถ้าหาย pipeline พัง · cache = เก็บ "ของที่สร้างใหม่ได้" (deps) ไว้ใช้ซ้ำข้ามการรันเพื่อความเร็ว ถ้าหายแค่ช้าลง · cache key ผูกกับ hash ของ lock file เพื่อกันใช้ของเก่าผิดเวอร์ชัน

Matrix & การขนานงาน#

ถ้าโปรแกรมของคุณต้องทำงานได้บน Node 18, 20 และ 22 ทั้งบน Linux และ Windows คุณจะเขียน job ซ้ำกัน 6 อันไหม? ไม่ต้อง — matrix คือเครื่องมือที่สร้างชุด job ขนานให้อัตโนมัติจากการประกาศมิติเพียงไม่กี่บรรทัด

7.1 Matrix — ทดสอบหลายมิติพร้อมกัน

matrixnode × osขยายเป็น 3 × 2 = 6 job รันพร้อมกันทั้งหมดnode18 · ubuntunode20 · ubuntunode22 · ubuntunode18 · windowsnode20 · windowsnode22 · windowsแต่ละช่องคือ job อิสระบน runner ของตัวเอง — ตกช่องไหนรู้ทันทีว่าพังที่ combination ไหน
FIG 7.1 ประกาศสองมิติ CI ขยายเป็นทุกคู่ผสม (cartesian product) แล้วรันขนานกันหมด · ครอบคลุมหลายสภาพแวดล้อมโดยเขียนครั้งเดียว
jobs:
  test:
    strategy:
      fail-fast: false          # ช่องหนึ่งตก ไม่ยกเลิกช่องอื่น — เห็นภาพครบ
      matrix:
        node: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}     # แต่ละ job หยิบค่าจากช่องของตัวเอง
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

7.2 fail-fast — เห็นภาพครบ หรือ ประหยัดทรัพยากร

fail-fast: true (ค่าเริ่มต้น) หมายถึง "พอช่องใดช่องหนึ่งตก ให้ยกเลิกช่องที่เหลือทันที" — ประหยัดเวลา/เครื่อง เหมาะตอนแค่อยากรู้ว่า "ผ่านหรือไม่ผ่าน" ส่วน fail-fast: false ปล่อยให้ทุกช่องรันจบ เหมาะตอน debug เพราะคุณอยากเห็นว่า พังเฉพาะ Windows + Node 18 หรือพังทุกที่ — ข้อมูลนี้ชี้ต้นตอได้ทันที

7.3 ความเร็วรวมของ pipeline

เพราะ job ขนานกัน เวลารวมของ pipeline ไม่ใช่ผลบวกของทุก job แต่เท่ากับ เส้นทางที่ยาวที่สุด (critical path) เหมือนหลายคนช่วยกันทำงานพร้อมกัน งานเสร็จเมื่อคนที่ช้าที่สุดเสร็จ การออกแบบ pipeline ให้เร็วจึงเป็นเรื่องของ "แตกงานอิสระให้ขนานกันให้มากที่สุด แล้วไล่บีบ job ที่อยู่บนเส้นทางวิกฤต"

สรุปบทที่ 7matrix ขยายมิติที่ประกาศ (เช่น node × os) เป็นชุด job ขนานอัตโนมัติ ครอบคลุมหลายสภาพแวดล้อมด้วยโค้ดครั้งเดียว · fail-fast: false ให้ทุกช่องรันจบเพื่อเห็นภาพครบตอน debug · เวลารวมของ pipeline = เส้นทางที่ยาวที่สุด ไม่ใช่ผลบวก — เร่งได้ด้วยการขนานงานอิสระ

Secrets & ตัวแปร#

pipeline ที่ deploy จริงต้องใช้ความลับ: รหัส API, token, รหัสฐานข้อมูล แต่ความลับเหล่านี้ ห้ามอยู่ในโค้ดเด็ดขาด เพราะทุกอย่างใน Git ถูกบันทึกถาวรและกระจายไปทุก clone (จำคำเตือนเรื่อง .env ในบทที่ 3 ของเล่ม Git ได้ไหม) บทนี้คือวิธีจัดการความลับให้ถูกต้อง

8.1 ตัวแปรกับความลับ — ต่างกันที่ "ความไว"

Variable (ตัวแปรธรรมดา)Secret (ความลับ)
เก็บอะไรค่าที่ไม่ลับ เช่น ชื่อ environment, region, ระดับ logค่าที่รั่วไม่ได้ เช่น token, รหัสผ่าน, private key
มองเห็นไหมเห็นในล็อกได้ตามปกติถูก mask เป็น *** ในล็อกอัตโนมัติ
เก็บที่ไหนในไฟล์ YAML หรือ settings ก็ได้ใน secret store ของแพลตฟอร์มเท่านั้น

8.2 ใช้ secret อย่างถูกวิธี

คุณตั้งค่า secret ไว้ใน settings ของ repo (ไม่ใช่ในไฟล์) แล้วอ้างถึงด้วยไวยากรณ์พิเศษ — ค่าจริงจะถูกฉีดเข้ามาตอนรันเท่านั้น และถูกปิดบังในล็อก:

steps:
  - run: ./deploy.sh
    env:
      API_TOKEN: ${{ secrets.API_TOKEN }}    # ดึงจาก secret store, mask อัตโนมัติ
      DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

กลไกการ mask สำคัญมาก: ต่อให้สคริปต์ของคุณเผลอ echo ค่า secret ออกมา แพลตฟอร์มจะแทนที่ด้วย *** ในล็อกให้ก่อนแสดง — เป็นตาข่ายกันพลาดชั้นสุดท้าย (แต่อย่าพึ่งมันแทนความระมัดระวัง)

8.3 ขอบเขตและการสืบทอด

แพลตฟอร์มสมัยใหม่ให้ตั้ง secret ได้หลายระดับ: ระดับ organization (ใช้ร่วมหลาย repo), ระดับ repo, และระดับ environment (เช่น secret ของ production แยกจาก staging — บทที่ 10) หลักคือ ให้สิทธิ์น้อยที่สุดเท่าที่จำเป็น: secret ของ production ไม่ควรเข้าถึงได้จาก pipeline ของ branch ทดลอง

สรุปบทที่ 8 — ความลับห้ามอยู่ในโค้ด/Git เด็ดขาด · variable = ค่าไม่ลับ (เห็นในล็อกได้), secret = ค่าไว (mask เป็น *** อัตโนมัติ เก็บใน secret store) · อ้างด้วย ${{ secrets.X }} ฉีดเข้าตอนรันเท่านั้น · ตั้ง secret หลายระดับและให้สิทธิ์น้อยที่สุด · ระวัง PR จาก fork เข้าถึง secret — ช่องโหว่ pwn request

LEVEL 3 · เข้าสู่ CD

CI → CD: Delivery vs Deployment#

ถึงครึ่งหลังของเล่ม — เราข้ามจาก "ตรวจว่าโค้ดดี" (CI) ไปสู่ "ส่งโค้ดขึ้นใช้งานจริง" (CD) บทนี้ปักหมุดเส้นแบ่งที่บทที่ 2 เกริ่นไว้ ให้ชัดถึงระดับปฏิบัติ เพราะการเลือกผิดระหว่าง Delivery กับ Deployment คือการเลือกระดับความเสี่ยงที่ทีมรับได้

9.1 เส้นแบ่งเดียว: ใครเป็นคนกดปุ่มขึ้น production

CItestbuildartifactเหมือนกันทั้งสองแบบ จนถึงตรงนี้👤 อนุมัติมนุษย์กดปุ่ม(manual gate)productionContinuous Delivery — "พร้อมเสมอ แต่คนเลือกเวลาปล่อย"productionขึ้นทันที ⚡Continuous Deployment — "ผ่าน CI = ขึ้น production เอง ไม่มีคนคั่น"
FIG 9.1 สองแบบใช้ CI/build ชุดเดียวกัน · Delivery แทรก “ประตูอนุมัติของมนุษย์” ก่อน production · Deployment ตัดประตูนั้นออก ผ่านเมื่อไรขึ้นเมื่อนั้น

9.2 แล้วควรเลือกแบบไหน

Continuous DeliveryContinuous Deployment
การขึ้น prodอัตโนมัติถึงประตู แล้วคนกดอนุมัติอัตโนมัติทั้งเส้น ไม่มีคนคั่น
ต้องการความเชื่อมั่นปานกลาง + จังหวะที่คนคุมชุดทดสอบ + monitoring ที่เชื่อมั่นสูงมาก
เหมาะกับระบบที่ปล่อยผิดแล้วกระทบหนัก, มีข้อบังคับเว็บ/บริการที่ปล่อยถี่ ๆ และ rollback ได้เร็ว
ความถี่ปล่อยเมื่อทีมพร้อม (วัน/สัปดาห์)หลายครั้งต่อวันได้

คำแนะนำเชิงปฏิบัติ: เริ่มที่ Continuous Delivery เกือบทุกครั้ง ปล่อยให้ pipeline เตรียมทุกอย่างให้พร้อมโดยอัตโนมัติ แต่คงปุ่มที่มนุษย์กดไว้ก่อน เมื่อคุณ deploy ด้วยปุ่มนั้นหลายสิบครั้งจนไม่เคยมีเซอร์ไพรส์ และมี monitoring/rollback ที่ไว้ใจได้ ค่อยตัดปุ่มออกเพื่อก้าวสู่ Continuous Deployment — การก้าวข้ามนี้ควรมาจากความเชื่อมั่นที่พิสูจน์แล้ว ไม่ใช่ความมักง่าย

9.3 สิ่งที่ทำให้ Deployment เต็มรูปแบบเป็นไปได้

การปล่อยขึ้น prod อัตโนมัติจะปลอดภัยก็ต่อเมื่อมีตาข่ายรองรับครบ: ชุดทดสอบครอบคลุมพอจะเชื่อได้, monitoring ที่จับได้ทันทีเมื่อ prod เริ่มเพี้ยน, ความสามารถ rollback อัตโนมัติเมื่อสุขภาพระบบตก (บทที่ 11), และกลยุทธ์ปล่อยที่จำกัดวงความเสียหาย (เช่น canary) ขาดตาข่ายเหล่านี้ Continuous Deployment ก็คือการวิ่งโดยไม่มีเบรก

สรุปบทที่ 9 — Delivery และ Deployment ใช้ CI/build ชุดเดียวกัน ต่างกันที่ มี "ประตูอนุมัติของมนุษย์" ก่อนขึ้น prod หรือไม่ · Delivery = พร้อมเสมอ คนเลือกเวลาปล่อย, Deployment = ผ่าน CI แล้วขึ้นเอง · เริ่มที่ Delivery ก่อน แล้วค่อยขยับเมื่อความเชื่อมั่นพิสูจน์แล้ว · Deployment เต็มรูปต้องมี test + monitoring + rollback + กลยุทธ์ปล่อยรองรับ

Environments & การ Deploy#

"production" ไม่ใช่ที่เดียวที่โค้ดไป โค้ดเดินผ่านหลายสภาพแวดล้อม (environment) ก่อนถึงผู้ใช้จริง บทนี้คือวิธีจัดสภาพแวดล้อมเหล่านั้นให้เป็นทางเดินที่มีด่านป้องกัน

10.1 บันไดของ environment

dev / previewdeploy อัตโนมัติstagingเหมือน prod ไว้ทดสอบจริงproductionผู้ใช้จริง🔒 gateต้องอนุมัติ + secret ของ prod แยกต่างหาก
FIG 10.1 โค้ดไต่บันได dev → staging → production · staging ตั้งให้เหมือน prod มากที่สุดเพื่อจับปัญหาก่อนถึงผู้ใช้ · ประตูป้องกันคั่นก่อน prod
  • dev / preview — deploy อัตโนมัติทุก branch/PR ไว้ลองของ พังได้ ไม่กระทบใคร
  • staging — ตั้งให้เหมือน production มากที่สุด (ข้อมูล โครงสร้าง การตั้งค่าใกล้เคียง) เพื่อจับปัญหาที่จะเกิดบนจริง ก่อนมันเกิดจริง
  • production — ของจริง มีด่านป้องกันแน่นหนาที่สุด

10.2 Environment protection — ด่านก่อน production

แพลตฟอร์มให้ผูกกฎป้องกันกับแต่ละ environment สิ่งเหล่านี้คือ "ประตูอนุมัติ" จากบทที่ 9 ในรูปธรรม:

  • required reviewers — ต้องมีคนที่กำหนดกดอนุมัติ ก่อน job ที่ deploy เข้า prod จะเริ่มทำงาน
  • wait timer — หน่วงเวลาก่อน deploy ให้มีช่วงยกเลิกได้ทัน
  • branch restriction — เฉพาะ main (หรือ tag ที่กำหนด) เท่านั้นที่ deploy เข้า prod ได้
  • scoped secrets — secret ของ prod ผูกกับ environment นี้ pipeline จาก branch อื่นแตะไม่ได้
jobs:
  deploy-prod:
    needs: build
    runs-on: ubuntu-latest
    environment: production      # ผูกกับ environment "production" — กฎป้องกันมีผลทันที
    steps:
      - uses: actions/download-artifact@v4
        with: {name: dist}
      - run: ./deploy.sh production
        env:
          DEPLOY_KEY: ${{ secrets.PROD_DEPLOY_KEY }}

เมื่อ job นี้ผูก environment: production ที่มี required reviewer แล้ว มันจะ หยุดรอ ที่หน้า Actions จนกว่าจะมีคนกดอนุมัติ — นี่แหละคือ "ปุ่มที่มนุษย์กด" ในบทที่ 9 ที่ทำงานจริง

🧭 ทำไม staging ต้องเหมือน prod — บั๊กที่แพงที่สุดคือบั๊กที่ "โผล่เฉพาะบน prod" — มักเกิดเพราะ staging ต่างจาก prod (เวอร์ชัน, ข้อมูล, ตัวแปร) ยิ่ง staging เหมือน prod เท่าไร โอกาสที่ prod จะเซอร์ไพรส์ยิ่งน้อยลงเท่านั้น ลงทุนทำ staging ให้เหมือนคุ้มเสมอ

สรุปบทที่ 10 — โค้ดไต่บันได dev → staging → production · staging ตั้งให้เหมือน prod เพื่อจับบั๊กก่อนถึงผู้ใช้ · ผูก job กับ environment: เพื่อเปิดกฎป้องกัน: required reviewer, wait timer, branch restriction, scoped secret · job ที่ผูก environment ที่ต้องอนุมัติจะหยุดรอคนกด — ปุ่มของบทที่ 9 ในทางปฏิบัติ

กลยุทธ์ Deploy & Rollback#

"deploy" ไม่ได้มีแบบเดียว วิธีที่คุณเปลี่ยนจากเวอร์ชันเก่าเป็นใหม่บน production กำหนดว่า ถ้าเวอร์ชันใหม่มีปัญหา จะมีผู้ใช้กี่คนที่เจอ และคุณถอยกลับได้เร็วแค่ไหน นี่คือหัวใจของ CD ที่ปลอดภัย

11.1 สี่กลยุทธ์หลัก

กลยุทธ์ทำอย่างไรแลกอะไร
Recreateดับเวอร์ชันเก่าทั้งหมด แล้วเปิดใหม่ง่ายสุด แต่มีช่วง downtime
Rollingทยอยเปลี่ยนเครื่องทีละกลุ่มไม่ดับ แต่ช่วงเปลี่ยนมีสองเวอร์ชันปนกัน
Blue-Greenยกชุดใหม่ขึ้นคู่ขนาน แล้วสลับ traffic ทีเดียวrollback ไวมาก แต่ใช้ทรัพยากร 2 เท่าชั่วคราว
Canaryปล่อยให้ผู้ใช้ส่วนน้อยก่อน เฝ้าดู แล้วค่อยขยายจำกัดวงความเสียหายดีสุด แต่ซับซ้อนสุด
Blue-Green — สลับทีเดียวBLUEv.เก่า (รับงานอยู่)GREENv.ใหม่ (อุ่นเครื่องรอ)routerเสียบ router ไป GREEN ทีเดียว · พังก็เสียบกลับ BLUE ทันทีCanary — ค่อย ๆ เพิ่ม5%25%50%100%เฝ้า metric ทุกขั้น · ผิดปกติเมื่อไรหยุด+ถอยทันทีผู้ใช้ที่เจอบั๊กถูกจำกัดไว้แค่สัดส่วนเล็ก ๆ
FIG 11.1 Blue-Green เก็บชุดเก่าไว้ครบ สลับ/ถอยได้ทันที · Canary ปล่อยทีละน้อยพร้อมเฝ้า metric จำกัดจำนวนผู้ใช้ที่กระทบถ้าเวอร์ชันใหม่มีปัญหา

11.2 Rollback — แผนถอยที่ต้องมีก่อนเดินหน้า

กฎเหล็กของ CD: อย่า deploy อะไรที่คุณถอยกลับไม่ได้ ความสามารถ rollback ที่เร็วและเชื่อถือได้ คือสิ่งที่ทำให้กล้าปล่อยบ่อย เพราะ "ปล่อยแล้วพัง" ไม่ใช่หายนะ แค่กด/รันถอยกลับเวอร์ชันก่อนหน้า Blue-Green ทำ rollback ได้แทบจะทันที (เสียบ router กลับ) ส่วนระบบที่ดีจะ rollback อัตโนมัติ เมื่อ health check หรือ metric หลังปล่อยตก โดยไม่ต้องรอคนสังเกต

สรุปบทที่ 11 — สี่กลยุทธ์: recreate (ง่าย มี downtime), rolling (ทยอย ไม่ดับ), blue-green (ยกคู่ขนาน สลับ/ถอยไว), canary (ปล่อยทีละน้อย จำกัดวงดีสุด) · กฎเหล็ก: อย่า deploy สิ่งที่ถอยกลับไม่ได้ — rollback ที่ไว (อัตโนมัติยิ่งดี) คือเหตุผลที่กล้าปล่อยบ่อย · ทำ DB migration แบบเข้ากันได้สองทางเพื่อให้ถอยได้เสมอ

LEVEL 4 · ระดับเทพ

ความปลอดภัยของ Pipeline#

pipeline ของคุณมีกุญแจสู่ production มันจึงเป็น เป้าหมายการโจมตีชั้นดี — เจาะ pipeline ได้ เท่ากับเจาะทุกอย่างที่มันเข้าถึง บทนี้คือหลักการทำให้ pipeline แข็งแกร่ง ซึ่งเป็นทักษะที่แยกมือสมัครเล่นออกจากมืออาชีพ

12.1 Supply chain — โค้ดที่คุณไม่ได้เขียนแต่ให้สิทธิ์เต็ม

ทุก uses: someone/action@v4 คือการรันโค้ดของคนอื่นในสภาพแวดล้อมที่เข้าถึง secret ของคุณ ถ้าเจ้าของ action นั้นถูกแฮ็กหรือกลายเป็นคนร้าย เขารันอะไรใน pipeline คุณก็ได้ ป้องกันด้วย:

  • ปักหมุดเป็น commit SHA ไม่ใช่ tag — uses: actions/checkout@a1b2c3d... เพราะ tag อย่าง @v4 ถูกย้ายไปชี้โค้ดร้ายได้ แต่ SHA ผูกกับเนื้อหาตายตัว (หลักการ SHA จากบทที่ 2 ของเล่ม Git ตรง ๆ)
  • ใช้เฉพาะ action ที่เชื่อถือได้ และตรวจก่อนอัปเกรด
  • ล็อกเวอร์ชัน dependencies ด้วย lock file เสมอ

12.2 สิทธิ์น้อยที่สุด (least privilege)

โดยปริยาย token ของ pipeline มักได้สิทธิ์กว้างเกินจำเป็น จงหดให้เหลือเท่าที่ใช้จริง งานที่แค่รันเทสต์ไม่ควรมีสิทธิ์เขียน repo:

permissions:
  contents: read        # อ่านโค้ดได้พอ ไม่ให้สิทธิ์เขียนโดยไม่จำเป็น

หลักคิด: ถ้า pipeline ถูกเจาะ ความเสียหายถูกจำกัดด้วยสิทธิ์ที่มันมี — ให้น้อย เสียหายน้อย

12.3 OIDC — เลิกเก็บกุญแจถาวร

วิธีเก่าคือเก็บ credential ระยะยาวของ cloud ไว้เป็น secret ซึ่งถ้ารั่วก็ใช้ได้ตลอดจนกว่าจะเพิกถอน วิธีใหม่คือ OIDC (OpenID Connect): pipeline แลก "ตัวตนที่ cloud เชื่อถือ" เป็น credential ชั่วคราวที่หมดอายุในไม่กี่นาที สำหรับการรันครั้งนั้นโดยเฉพาะ ไม่มีกุญแจถาวรให้รั่วอีกต่อไป — นี่คือมาตรฐานที่ทีมจริงจังขยับไปใช้

สรุปบทที่ 12 — pipeline คือเป้าโจมตีเพราะถือกุญแจสู่ prod · ปักหมุด action ด้วย commit SHA ไม่ใช่ tag (ผูกเนื้อหาตายตัวเหมือน SHA ใน Git) · ให้ สิทธิ์น้อยที่สุด เพื่อจำกัดความเสียหายเมื่อถูกเจาะ · ใช้ OIDC แทน credential ถาวรเพื่อเลิกเก็บกุญแจที่รั่วได้ · กันโค้ดจาก fork ไม่ให้แตะ secret/สิทธิ์

Runners & ความเร็วของ Pipeline#

เมื่อทีมโตและ pipeline รันวันละหลายร้อยครั้ง สองเรื่องกลายเป็นปัญหาจริง: เครื่องที่รัน (runner) และเวลาที่ใช้ บทนี้คือมุมมองวิศวกรรมของการ scale CI/CD

13.1 Hosted vs Self-hosted — เลือกอย่างมีเหตุผล

Hosted runnerSelf-hosted runner
ใครดูแลแพลตฟอร์ม — เกิดใหม่สะอาดทุกครั้งคุณเอง — ติดตั้ง/อัปเดต/รักษาความปลอดภัย
เหมาะเมื่องานทั่วไป เริ่มเร็ว ไม่อยากดูแลต้องการ GPU/ฮาร์ดแวร์พิเศษ, เข้าถึงเน็ตภายใน, คุมต้นทุนสเกลใหญ่
ความเสี่ยงต่ำสูงถ้าใช้กับ public repo — โค้ดจาก PR อาจฝังตัวในเครื่องที่ใช้ซ้ำ

13.2 ทำให้ pipeline เร็วขึ้น

pipeline ช้าคือ pipeline ที่บั่นทอนทุกคน เครื่องมือเร่งความเร็วเรียงตามผลที่ได้:

  • ขนานงาน — แตก job อิสระให้รันพร้อมกัน (บทที่ 7) ลดเส้นทางวิกฤต
  • cache — เลิกติดตั้ง dependencies ซ้ำ (บทที่ 6)
  • ล้มเร็ว — เรียงด่านถูก/เร็ว (lint) ไว้หน้า ด่านแพง (E2E) ไว้หลัง (บทที่ 5)
  • รันเฉพาะที่เปลี่ยน — ใน monorepo ใหญ่ ตรวจเฉพาะส่วนที่ถูกแก้ด้วย path filter แทนการรันทั้งหมด
  • shallow clonegit clone --depth 1 ดึงแค่ commit ล่าสุด (ตรงกับบทที่ 15 ของเล่ม Git) ลดเวลา checkout repo ใหญ่

13.3 ทำ pipeline เป็นโค้ดที่ดูแลได้

เมื่อ workflow เยอะขึ้น มันก็คือโค้ดเบสอีกชุดที่ต้องดูแล หลีกเลี่ยงการก๊อป YAML ซ้ำไปมาด้วย reusable workflow และ composite action — แยกขั้นตอนที่ใช้ซ้ำออกเป็นชิ้นกลางแล้วเรียกใช้ เหมือนแยกฟังก์ชันในโค้ดทั่วไป pipeline ที่ดีถูกรีวิว เวอร์ชัน และรีแฟกเตอร์เหมือนโค้ด production

สรุปบทที่ 13 — hosted runner สะดวกและสะอาดทุกครั้ง, self-hosted ใช้เมื่อต้องการฮาร์ดแวร์/เครือข่ายพิเศษ แต่ อันตรายกับ public repo — ใช้เป็น ephemeral และแยกเครือข่าย · เร่งความเร็ว: ขนานงาน + cache + ล้มเร็ว + รันเฉพาะที่เปลี่ยน + shallow clone · จัดการ workflow เป็นโค้ดด้วย reusable workflow/composite action

เทียบแพลตฟอร์ม & บทสรุป#

ตลอดเล่มเราใช้ GitHub Actions เป็นตัวอย่าง แต่ย้ำมาตลอดว่าแนวคิดข้ามแพลตฟอร์มได้ บทสุดท้ายนี้พิสูจน์คำกล่าวนั้น แล้วม้วนทุกอย่างกลับมาเป็นแก่นที่ถือกลับไปใช้ได้จริง

14.1 คำเดียวกัน คนละชื่อ

ทุกแพลตฟอร์มมีลำดับชั้นเดียวกับบทที่ 2 เปลี่ยนแค่คำศัพท์และรูปแบบไฟล์:

แนวคิดGitHub ActionsGitLab CIJenkins
ไฟล์นิยาม.github/workflows/*.yml.gitlab-ci.ymlJenkinsfile
หน่วยรวมworkflowpipelinepipeline
กลุ่มงานjobjob (จัดกลุ่มด้วย stage)stage
เครื่องรันrunnerrunneragent / node
ของสำเร็จรูปactiontemplate / includeplugin / shared library

นี่คือเหตุผลที่เล่มนี้เน้น "แนวคิด" — เรียนกลไกหนึ่งครั้ง ย้ายแพลตฟอร์มเมื่อไรก็แค่เรียนคำศัพท์ใหม่ ไม่ต้องเรียนวิธีคิดใหม่ CircleCI, Azure Pipelines, Travis และอื่น ๆ ก็เข้าแม่พิมพ์เดียวกันนี้

14.2 หลักปฏิบัติที่ดี — รวมทั้งเล่ม

  • เก็บ pipeline ไว้กับโค้ด (pipeline-as-code) เวอร์ชันคู่กัน รีวิวคู่กัน
  • เร็วและล้มเร็ว — ด่านถูกอยู่หน้า ขนานงานให้มาก cache ให้พอ
  • บังคับด้วยระบบ ไม่ใช่วินัย — branch protection ทำให้ "CI ไม่เขียว = merge ไม่ได้"
  • เริ่มที่ Delivery คงปุ่มมนุษย์ไว้ก่อน แล้วค่อยขยับสู่ Deployment เมื่อความเชื่อมั่นพิสูจน์แล้ว
  • ถอยได้เสมอ — ไม่ deploy สิ่งที่ rollback ไม่ได้ migration เข้ากันได้สองทาง
  • ความปลอดภัยไม่ใช่ของเสริม — pin SHA, least privilege, OIDC, กันโค้ด fork แตะ secret

14.3 บทสรุปทั้งเล่ม — แก่นที่ถือกลับไป

ถ้าจำได้แค่ไม่กี่อย่างจากเล่มนี้ ขอให้เป็นสิ่งเหล่านี้ เพราะทุกเทคนิคงอกออกมาจากมัน:

  • CI/CD มีค่าเพราะมัน ย่นวงจรป้อนกลับ — จับปัญหายิ่งเร็ว ยิ่งถูก
  • ทุก pipeline คือ event → workflow → job (ขนาน) → step (เรียง) บน runner — โครงเดียวข้ามทุกเครื่องมือ
  • CI/CD คือ สามชั้นซ้อนกัน Integration ⊂ Delivery ⊂ Deployment เส้นแบ่งคือ "มีคนกดปุ่มไหม"
  • ความปลอดภัยและ ความสามารถถอยกลับ คือสิ่งที่ทำให้ "ปล่อยบ่อย" เป็นเรื่องกล้าทำ ไม่ใช่เรื่องเสี่ยง
  • pipeline คือ โค้ด — เวอร์ชัน รีวิว และดูแลมันด้วยมาตรฐานเดียวกับโค้ด production

🧭 เส้นทางต่อจากนี้ — วิธีเก่งขึ้นจริงคือลงมือ: เอา repo ทดลองใส่ ci.yml ง่าย ๆ จากบทที่ 3 แล้วค่อย ๆ เติมทีละชั้น — เพิ่ม matrix, cache, แล้ว deploy ขึ้น environment ฟรีสักที่ จากนั้นลองพังมันดู (ทำเทสต์ให้ตก, ทำ deploy ให้ล้ม) เพื่อเห็นว่า fail loud กับ rollback ทำงานอย่างไร — pipeline ที่คุณเคยทำพังและกู้คืนเอง สอนได้ลึกกว่าทุกคู่มือ

สรุปบทที่ 14 — ทุกแพลตฟอร์มใช้ลำดับชั้นเดียวกัน ต่างแค่คำศัพท์/ไฟล์ — เรียนแนวคิดครั้งเดียวย้ายได้หมด · หลักปฏิบัติ: pipeline-as-code, เร็ว+ล้มเร็ว, บังคับด้วยระบบ, เริ่มที่ Delivery, ถอยได้เสมอ, ความปลอดภัยมาก่อน · แก่น: ย่นวงจรป้อนกลับ · โครง event→job→step · สามชั้น CI/CD · ถอยได้+ปลอดภัย · pipeline คือโค้ด — เท่านี้คุณก็จาก 0 ถึง Hero ของ CI/CD แล้ว

— จบหลักสูตร —


CI/CD 0 → Hero — จาก commit สู่ production อัตโนมัติ · เล่มต่อจาก Git 0 → Hero · เขียนเป็นภาษาไทย พร้อมไดอะแกรมทุกหัวข้อ

วิธีใช้ให้คุ้ม: อ่านไล่ระดับ Level 0–1 ก่อนเพื่อจับแบบจำลองความคิด แล้วลงมือสร้าง pipeline จริงควบคู่ไปทีละบท · ตัวอย่างยึด GitHub Actions แต่ทุกแนวคิดย้ายไป GitLab CI / Jenkins / CircleCI ได้ (บทที่ 14)