บทที่ 12 ปฏิบัติการรวม: pipeline ครบสาย, rollback และ DORA metrics
แผนบริหารการสอนประจำบทที่ 12
หัวข้อเนื้อหา
- 12.1 ภาพรวม pipeline ครบสาย
- 12.2 rollback ด้วย release เดิม
- 12.3 ข้อจำกัดของการ rollback ด้วยมือ
- 12.4 วัดผลงานการส่งมอบด้วย DORA metrics
- 12.5 โจทย์ Capstone
- 12.6 แยกความล้มเหลวของ pipeline ออกจากความล้มเหลวของบริการ
- 12.7 เวลาเกิดผลกระทบ เวลาเห็นสัญญาณ และเวลากู้คืน
- 12.8 rollback โค้ดไม่ได้ย้อนฐานข้อมูลเสมอไป
- 12.9 ทบทวนเหตุเพื่อเปลี่ยนระบบ ไม่หยุดที่หาคนผิด
- ปฏิบัติการที่ 12 ปฏิบัติการรวม: ส่งมอบ พัง และกู้คืน (Lab A–D)
วัตถุประสงค์เชิงพฤติกรรม
เมื่อศึกษาบทนี้และทำปฏิบัติการครบถ้วนแล้ว ผู้เรียนสามารถปฏิบัติได้ตามผลลัพธ์การเรียนรู้ต่อไปนี้ โดยแต่ละข้อมีงานที่ใช้วัดผลกำกับไว้
| รหัส | ผลลัพธ์การเรียนรู้ | วัดจาก | CLO ของรายวิชา |
|---|---|---|---|
| 12.1 | ใช้งาน workflow ครบสาย commit → test → scan → build → deploy บน repository ของทีม | งานข้อ 1 | CLO2 |
| 12.2 | rollback ไป image tag ก่อนหน้าเมื่อเวอร์ชันใหม่พัง และบันทึกเวลาที่ใช้กู้ระบบ | งานข้อ 2 | CLO2 |
| 12.3 | อธิบายการเลือก Git workflow, ขั้นของ pipeline และการใช้ container ของทีม ต่อโจทย์ความต้องการที่ผู้สอนกำหนด | งานข้อ 3 | CLO1 |
| 12.4 | ผ่านจุดตรวจความปลอดภัยครั้งที่ 4 (ตรวจ repository) (ไม่มีรหัสผ่าน มีการสแกน มี review) | งานข้อ 4 | CLO4 |
CLO ที่เกี่ยวข้อง (ข้อความจากหลักสูตร):
- CLO1 สามารถนำความต้องการและสถาปัตยกรรมการส่งมอบซอฟต์แวร์ที่กำหนดมาใช้ โดยอธิบาย Git workflow, CI/CD pipeline flow และการใช้ Containerization ได้อย่างเหมาะสมกับบริบทของงาน
- CLO2 สามารถกำหนดค่าและใช้งาน DevOps workflow ที่กำหนดมา เพื่อให้กระบวนการพัฒนา–ทดสอบ–ส่งมอบซอฟต์แวร์เป็นไปอย่างถูกต้องและมีประสิทธิภาพ
- CLO4 ผู้เรียนแสดงออกถึงความรับผิดชอบและความใฝ่รู้ในการเรียนรู้เทคโนโลยีและเครื่องมือใหม่ที่เกี่ยวข้องกับ DevOps โดยศึกษาค้นคว้าด้วยตนเองจากแหล่งข้อมูลที่เชื่อถือได้ และปฏิบัติตามแนวปฏิบัติด้านความปลอดภัยและคุณภาพของระบบ
บทนี้ไม่มีเครื่องมือใหม่ เป็นการใช้ทุกส่วนที่สร้างมาตั้งแต่บทที่ 2 ร่วมกันภายใต้สถานการณ์ที่ระบบพังจริง งานข้อ 3 เป็นหลักฐาน CLO1 รายบุคคลที่ครอบคลุมทั้งสามเรื่องของ CLO1 และงานข้อ 4 เป็นการตรวจ repository ครั้งสุดท้ายของ CLO4
วิธีสอนและกิจกรรมการเรียนการสอน
- บรรยายทบทวนตามหัวข้อ 12.1–12.5 โดยเริ่มจากให้ทีมวาดเส้นทางของ commit หนึ่งรายการจนถึงหน้าเว็บบนเครื่องปลายทาง และใช้คำถามตรวจความเข้าใจท้ายหัวข้อเป็นกิจกรรมอภิปรายเป็นคู่
- ปฏิบัติการ Lab A และ C ตามลำดับ ระหว่างนั้นผู้สอนปล่อยเวอร์ชันที่มีปัญหาเข้าระบบของแต่ละทีมโดยไม่แจ้งล่วงหน้า ทีมต้องตรวจพบและกู้ระบบตาม Lab B
- สอบปากเปล่ารายบุคคลแบบหมุนเวียนทีมละ 10 นาที (Lab D) ระหว่างที่ทีมอื่นทำ Lab A–C
- มอบหมายแบบฝึกหัดท้ายบท (ปรับปรุง RUNBOOK) Learning Log ครั้งที่ 12 และการเตรียม Capstone
สื่อการเรียนการสอน
- เอกสารประกอบการสอนบทที่ 12 (บทความนี้) และหน้ารวมรายวิชา 10306343
- repository ทีม
devops-appที่ผ่าน M10 จากบทที่ 11 เครื่องปลายทางที่รันระบบชุดdevops-prodและ self-hosted runner จากบทที่ 8 - The Twelve-Factor App หัวข้อ V. Build, release, run และ DORA guide หัวข้อ software delivery performance metrics
- แบบฟอร์มสอบปากเปล่าและ rubric CLO1 (ผู้สอนเตรียม)
การวัดผลและการประเมินผล
กำหนดส่ง: ก่อนเริ่มเรียนบทที่ 13 เพราะ Capstone ในบทที่ 13 ใช้ pipeline และ RUNBOOK จากบทนี้ และบทที่ 1–13 เป็นบทที่นับคะแนน
| ข้อ | งาน | หลักฐาน | ผลลัพธ์ | CLO |
|---|---|---|---|---|
| 1 | M11 pipeline ครบสาย | ลิงก์ pull request ของตนเองที่ merge แล้ว (Lab A) · ลิงก์ run ของ CD สำหรับ v0.5.2 ที่ผ่านทุก job ใน run เดียว และใน log มีขั้น test, scan, push และ deploy ที่ผ่าน | 12.1 | CLO2 |
| 2 | บันทึก rollback | RUNBOOK.md บน main ที่มีบันทึกเหตุการณ์ของ Lab B · ลิงก์ run ของ CD ที่ล้ม และ run ของ Rollback ที่ผ่าน · เวลาที่พบปัญหา เวลาที่กู้เสร็จ และเวลากู้เป็นนาที | 12.2 | CLO2 |
| 3 | สอบปากเปล่ารายบุคคล | คำตอบปากเปล่าในชั้นเรียน (ผู้สอนบันทึกในแบบฟอร์ม) | 12.3 | CLO1 |
| 4 | จุดตรวจความปลอดภัยครั้งที่ 4 (ตรวจ repository) | ผลรัน scripts/check-secrets.sh บน main · ภาพหน้าตั้งค่า branch protection ของ main ที่บังคับ review และ required status check test กับ image-scan · รายการ pull request ที่ merge ในบทที่ 10–12 พร้อมสถานะ review (Lab C.2) | 12.4 | CLO4 |
| 5 | ตาราง DORA metrics | docs/dora.md บน main ที่กรอกค่าครบ | — | ประกอบงานข้อ 3 และ Capstone |
| 6 | Learning Log ครั้งที่ 12 | ตอบ 4 หัวข้อ: สิ่งที่เรียนในบทนี้ · คำสั่งหรือข้อความ error ที่พบและแก้อย่างไร · แหล่งที่ใช้ค้นหาคำตอบ (ระบุลิงก์เอกสารทางการอย่างน้อย 1 แหล่ง) · ขั้นตอนใดใน RUNBOOK ที่ทีมทำช้าที่สุดและจะปรับอย่างไร | — | บันทึกสะท้อนการเรียนรู้ ไม่มีหมวดคะแนน portfolio แยก |
ประเมินงานแต่ละข้อจากหลักฐานของข้อนั้นโดยตรง ไม่ตัดสิทธิ์รับคะแนนของอีกข้อเพราะ milestone หรือจุดตรวจอื่นยังไม่ผ่าน งานที่ยังทำไม่ได้ให้บันทึกปัญหาและหลักฐานที่มีตามจริง
เกณฑ์ให้คะแนน
| ข้อ | ผ่าน | ยังไม่ผ่าน |
|---|---|---|
| 1 | ทุก job ของ CD ผ่านใน run เดียว · หน้าเว็บบนเครื่องปลายทางแสดง v0.5.2 | มี job ที่ถูกข้าม หรือ deploy ด้วยมือแทน workflow |
| 2 | ระบบกลับมาตอบ health ด้วยเวอร์ชันก่อนหน้าผ่าน workflow Rollback หรือทางสำรองใน RUNBOOK · บันทึกเวลาครบทั้งสองจุดและคำนวณเวลากู้ถูกต้อง | ระบบยังไม่กลับมา หรือไม่มีบันทึกเวลา หรือแก้ด้วยการ build เวอร์ชันใหม่แทนการกลับไป release เดิม |
| 5 | กรอกตัวชี้วัดทั้งสองพร้อมข้อมูลดิบที่ตรวจสอบย้อนกลับไปยัง run ได้ | ไม่มีข้อมูลดิบ |
| 6 | ตอบครบ 4 หัวข้อ และมีลิงก์เอกสารทางการ | ขาดหัวข้อ หรือไม่มีแหล่งอ้างอิง |
ข้อ 3 ใช้ rubric CLO1 3 ระดับ เกณฑ์ผ่านคือระดับ 2 ขึ้นไปสำหรับทุกคนในทีม
| ระดับ | พฤติกรรมที่สังเกตได้ |
|---|---|
| 3 ดี | อธิบายลำดับและเหตุผลในบริบทของทีมได้ และเปรียบเทียบทางเลือกอย่างน้อย 2 ทางพร้อมข้อดีข้อเสีย (เช่น GitHub flow กับ GitFlow, rollback ด้วย tag เดิมกับ build ใหม่) |
| 2 ผ่าน | อธิบายลำดับขั้นและเหตุผลของการเลือกได้ถูกต้องในบริบทของทีมและโจทย์ที่ได้รับ |
| 1 ยังไม่ผ่าน | ท่องนิยามทั่วไปได้ แต่เชื่อมกับ repository และ pipeline ของทีมไม่ได้ |
ข้อ 4 ใช้ rubric CLO4 3 ระดับ เกณฑ์ผ่านคือผ่านทั้งสามรายการ (ไม่มีรหัสผ่าน มีการสแกน มี review)
| ระดับ | พฤติกรรมที่สังเกตได้ |
|---|---|
| 3 ดี | ผ่านทั้งสามรายการ และพบปัญหาหรือข้อจำกัดของการตรวจเองก่อนถูกตรวจ (เช่น สคริปต์รายงานผิด หรือ pull request ที่ merge โดยไม่มี review) พร้อมแก้และอ้างแหล่งข้อมูลทางการ |
| 2 ผ่าน | ผ่านทั้งสามรายการ และอ้างแหล่งข้อมูลทางการอย่างน้อย 1 แหล่งในบันทึก |
| 1 ยังไม่ผ่าน | ไม่ผ่านรายการใดรายการหนึ่ง หรือทำเฉพาะเมื่อถูกสั่ง |
เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ
การคิดคะแนนฉบับปัจจุบัน
มติผู้สอน 28 ต.ค. 2569: เข้าเรียน 10% · ใบงานบทที่ 1–13 รวม 40% · FP 20% · FW 20% · โครงงาน 10% ส่วนบทที่ 14–15 ฝึกเพื่อรับข้อเสนอแนะ ไม่นับคะแนน
ใบงาน C12-WS01 มีคะแนนดิบเต็ม 40 คะแนน แยกตามผลลัพธ์ด้านล่าง ระบบนำไปรวมในหมวดใบงาน 40% โดยไม่เพิ่มคะแนน milestone, portfolio หรือจุดตรวจเป็นหมวดแยก
| ผลลัพธ์ | หลักฐานตามงานส่ง | คะแนนดิบเต็ม |
|---|---|---|
| LLO12.1 | งานข้อ 1 | 10 |
| LLO12.2 | งานข้อ 2 | 10 |
| LLO12.3 | งานข้อ 3 | 10 |
| LLO12.4 | งานข้อ 4 | 10 |
ประเมินงานแต่ละข้อจากหลักฐานของข้อนั้นโดยตรง ไม่ตัดสิทธิ์รับคะแนนของอีกข้อเพราะ milestone หรือจุดตรวจอื่นยังไม่ผ่าน งานที่ยังทำไม่ได้ให้บันทึกปัญหาและหลักฐานที่มีตามจริง
ใช้เกณฑ์ความถูกต้อง เหตุผล และหลักฐานที่ระบุในงานแต่ละข้อประกอบการประเมินราย LLO งานเตรียมพื้นและ Learning Log ที่ไม่มีรหัส LLO ใช้ให้ข้อเสนอแนะ ไม่เพิ่มคะแนนดิบให้ใบงาน
บทนำ
ตลอดบทที่ 2–11 ทีมสร้างส่วนประกอบของการส่งมอบซอฟต์แวร์ทีละส่วน ตั้งแต่ Git และ pull request, CI, Docker, Compose, CD, Nginx, การสแกนช่องโหว่ ไปจนถึงประตูตรวจ health บทนี้ใช้ทุกส่วนร่วมกันเป็นครั้งแรกในสถานการณ์ที่ใกล้ของจริง ทีมออกเวอร์ชันผ่าน pipeline ครบสาย แล้วรับมือกับเวอร์ชันที่พังซึ่งผู้สอนปล่อยเข้าระบบโดยไม่แจ้งล่วงหน้า ทีมต้องตรวจพบ กู้ระบบด้วยการกลับไปใช้ release เดิม และบันทึกเวลาที่ใช้ จากนั้นวัดผลงานของทีมด้วย DORA metrics ตรวจ repository ครั้งสุดท้าย และสอบปากเปล่ารายบุคคล
ความสำคัญ: ระบบทุกระบบพังได้ ทีมที่ดีไม่ใช่ทีมที่ไม่เคยพัง แต่เป็นทีมที่รู้ตัวเร็วและกู้ได้เร็วด้วยขั้นตอนที่ฝึกไว้แล้ว เวลากู้ระบบจึงเป็นหนึ่งในตัวชี้วัดหลักของงาน DevOps และ RUNBOOK ที่ทีมเขียนในบทนี้เป็นเอกสารที่ใช้ได้จริงในวันที่ระบบพัง
ความเชื่อมโยงกับบทอื่น: บทนี้ใช้ผลผลิตจากบทที่ 2–11 ทั้งหมด โดยเฉพาะ workflow CD และ scripts/deploy.sh จากบทที่ 8 การสแกนและ GitHub Secrets จากบทที่ 10 และประตูตรวจ health กับการกู้ระบบด้วยมือจากบทที่ 11 ผลผลิตของบทนี้ถูกใช้ต่อตามตารางต่อไปนี้
| สิ่งที่ได้จากบทนี้ | ใช้ต่อในบท |
|---|---|
workflow Rollback และ RUNBOOK.md | 13 (Capstone: rollback หากจำเป็น) · 15 (เทียบกับ rollback ของ Kubernetes) |
docs/dora.md | 13 (นำเสนอผลงานของทีม) |
| ผลสอบปากเปล่าและผลตรวจ repository | คะแนนรวมบทที่ 13 |
ความรู้พื้นฐาน เครื่องมือ และรุ่นซอฟต์แวร์
ความรู้พื้นฐาน: ทุกบทก่อนหน้า โดยเฉพาะการออกเวอร์ชันด้วย tag (บทที่ 8) และการอ่าน log ของ run ที่ล้ม (บทที่ 5)
เครื่องมือ: repository ทีมที่ตรงกับ main ล่าสุด เครื่องปลายทางที่ self-hosted runner ทำงานอยู่ สิทธิ์เรียก workflow ด้วยมือ (Run workflow) ในหน้า Actions และ GitHub CLI (gh) สำหรับ Lab C (ไม่บังคับ)
รุ่นซอฟต์แวร์ที่ใช้ทดสอบ:
| ซอฟต์แวร์ | รุ่นที่ทดสอบ |
|---|---|
| Docker Engine และ Docker Compose | 29.8.2 และ v5.5.1 ทดสอบเมื่อ 19 ต.ค. 2569 |
| actionlint | 1.7.12 (ตรวจ rollback.yml) |
| GitHub CLI | ตรวจรายชื่อฟิลด์ของ gh run list และ gh pr list จากคำสั่ง --help เท่านั้น |
| image | image จำลองเดียวกับบทที่ 6–11 |
| แอป | devops-app 0.5.0 → 0.5.2 และเวอร์ชันพัง 0.6.0 |
ผู้เขียนทดสอบการ deploy เวอร์ชันพัง การ rollback และการวัดช่วงที่ระบบไม่ตอบ บนเครื่องจำลองด้วย scripts/deploy.sh ที่ข้ามขั้น pull จาก registry และใช้ image ที่สร้างไว้ในเครื่อง workflow Rollback, การเรียก workflow ด้วยมือ, self-hosted runner และคำสั่ง gh ที่อ่านข้อมูลจาก GitHub ยังไม่ได้ทดสอบบน GitHub จริง เวลากู้ระบบในตัวอย่างจึงไม่รวมเวลารอคิวของ workflow และเวลาดึง image
ค่าใช้จ่ายและข้อมูลลับ: ไม่มีค่าใช้จ่ายเพิ่ม workflow Rollback ใช้ secret PROD_POSTGRES_PASSWORD ตัวเดียวกับบทที่ 10 ห้ามแนบรหัสผ่านหรือเนื้อหาของ ~/devops-deploy/.env ใน RUNBOOK RUNBOOK อยู่ใน repository ซึ่งทุกคนที่มีสิทธิ์อ่าน repository อ่านได้
12.1 ภาพรวม pipeline ครบสาย
ตารางต่อไปนี้สรุปเส้นทางของ commit หนึ่งรายการจนถึงหน้าเว็บบนเครื่องปลายทาง และปัญหาที่แต่ละขั้นจับได้
| ขั้น | ทำที่ | จับปัญหาอะไร | มาจากบท |
|---|---|---|---|
| pull request และ review | GitHub | ความผิดพลาดที่คนเห็น การเปลี่ยนแปลงที่ไม่ผ่านการตกลง | 3 |
| test และ smoke test | ci.yml job test | พฤติกรรมของแอปผิดจากที่คาด | 5 |
| สแกน image | ci.yml job image-scan และ cd.yml ก่อน push | ช่องโหว่ระดับ CRITICAL ที่มีรุ่นแก้แล้ว | 10 |
| build และ push | cd.yml job build-push | build ไม่ผ่าน | 6, 8 |
| deploy | cd.yml job deploy บน self-hosted runner | container เริ่มไม่ได้ (up --wait) | 7, 8 |
| ประตูตรวจ health | scripts/deploy.sh | ผู้ใช้เข้าแอปเวอร์ชันใหม่ผ่าน proxy ไม่ได้ | 11 |
ระดับที่ 1: ลำดับใน workflow CD ของทีมคือ test → build → scan → push → deploy การสแกนจึงเกิดหลัง build เสมอ เพราะต้องมี image ก่อนจึงสแกนได้ แต่เกิดก่อน push เพื่อไม่ให้ image ที่มีช่องโหว่ไปถึง registry
ระดับที่ 2: แต่ละขั้นจับปัญหาคนละชนิด ไม่มีขั้นใดจับได้ทุกอย่าง เวอร์ชันพังใน Lab B ของบทนี้ผ่าน test เพราะโค้ดอ่านไฟล์ที่มีอยู่ใน repository ผ่านการสแกนเพราะไม่มีช่องโหว่ใหม่ แต่ container เริ่มไม่ได้เพราะไฟล์นั้นไม่ถูกคัดลอกเข้า image ปัญหานี้จึงถูกจับได้ที่ขั้น deploy เท่านั้น
ระดับที่ 3: ขั้นที่อยู่ท้ายสายจับปัญหาได้ช้าและแพงกว่าขั้นต้นสาย ปัญหาที่หลุดถึงขั้น deploy ทำให้ระบบจริงหยุด ส่วนปัญหาที่จับได้ใน pull request ไม่มีผู้ใช้คนใดได้รับผลกระทบ เมื่อพบปัญหาที่หลุดถึงท้ายสาย ทีมควรถามต่อว่าจะเพิ่มการตรวจที่ต้นสายได้หรือไม่ ซึ่งเป็นแนวคิด Shift Left จากบทที่ 10
คำถามตรวจความเข้าใจ 12.1: ระบุขั้นที่จะจับปัญหาต่อไปนี้ได้เป็นขั้นแรก (1) ลบ USER node ออกจาก Dockerfile (2) แก้ /api/items ให้คืนรายการว่าง (3) ตั้ง proxy_pass ผิดพอร์ต (4) commit ไฟล์ .env
12.2 rollback ด้วย release เดิม
The Twelve-Factor App แยกการส่งมอบเป็นสามช่วง คือ build, release และ run โดย release แต่ละครั้งมีรหัสเฉพาะ (เช่น เวลาที่ออก หรือเลขที่เพิ่มขึ้น) และแก้ไขไม่ได้ การเปลี่ยนแปลงใด ๆ ต้องสร้าง release ใหม่ (12factor.net: V. Build, release, run) ในระบบของทีม release หนึ่งชุดคือ image ที่ tag ด้วยเลขเวอร์ชันใน registry รวมกับค่าตั้งของเครื่องปลายทาง
| วิธีกู้ระบบ | สิ่งที่เกิดขึ้น | เหมาะเมื่อ |
|---|---|---|
| rollback ไป release เดิม | deploy image tag ก่อนหน้าที่มีอยู่แล้วใน registry โดยไม่ build ใหม่ | ต้องการให้ระบบกลับมาเร็วที่สุด |
| roll forward ด้วยการแก้แล้วออกเวอร์ชันใหม่ | แก้โค้ด ผ่าน pull request และ pipeline ครบสาย | รู้สาเหตุแน่ชัดและแก้ได้เร็ว หรือ release เดิมใช้ไม่ได้แล้ว |
workflow Rollback ที่ทีมเพิ่มใน Lab A รับเลขเวอร์ชันจากผู้เรียกใช้ checkout โค้ดของ tag นั้น แล้วเรียก scripts/deploy.sh ด้วยเลขเวอร์ชันเดิม จึงได้ทั้ง image และไฟล์ค่าตั้ง (compose.yaml, nginx/) ของ release นั้นครบชุด
ระดับที่ 1: ผลการทดสอบบนเครื่องจำลองหลังเวอร์ชัน 0.6.0 ทำให้แอปหยุด การ deploy เวอร์ชัน 0.5.2 กลับไปใช้เวลาประมาณ 7 วินาที (ไม่รวมเวลาดึง image และเวลารอคิวของ workflow) และหน้าแรกกลับมาแสดง DevOps App (team 01) v0.5.2
ระดับที่ 2: การกด Re-run บน run เก่าของ workflow CD ไม่ใช่ rollback ที่ดี เพราะ job build-push จะ build image ใหม่แล้ว push ทับ tag เดิม image ที่ได้อาจต่างจากเดิม เช่น ได้ base image รุ่นใหม่กว่า ซึ่งขัดกับหลักที่ว่า release แก้ไขไม่ได้ (ข้อสรุปจากการอ่าน cd.yml ของทีม ยังไม่ได้ทดสอบบน GitHub) workflow Rollback แยกต่างหากจึงไม่มีขั้น build เลย
ระดับที่ 3: rollback กลับไป release เดิมได้เฉพาะเมื่อ release เดิมยังใช้กับสภาพแวดล้อมปัจจุบันได้ ถ้าเวอร์ชันใหม่เปลี่ยนโครงสร้างฐานข้อมูลแล้ว เวอร์ชันเดิมอาจอ่านข้อมูลใหม่ไม่ได้ แอปของรายวิชายังไม่ใช้ฐานข้อมูลจึงไม่พบปัญหานี้ แต่ระบบจริงต้องออกแบบการเปลี่ยนแปลงฐานข้อมูลให้ย้อนกลับได้ก่อนออกเวอร์ชัน
คำถามตรวจความเข้าใจ 12.2: สมาชิกคนหนึ่งเสนอให้ rollback ด้วยการ revert commit ล่าสุดบน main แล้วออก tag ใหม่ เปรียบเทียบวิธีนี้กับการเรียก workflow Rollback ในด้านเวลาที่ระบบกลับมาและความแน่นอนของผลลัพธ์
12.3 ข้อจำกัดของการ rollback ด้วยมือ
ระบบของทีมรันแอปเพียง container เดียว การ deploy ทุกครั้งจึงหยุด container เดิมแล้วสร้าง container ใหม่ ผลการทดสอบส่ง request ไปที่ /health ทุก 0.1 วินาทีระหว่าง deploy เวอร์ชันปกติ ได้ 200 จำนวน 149 ครั้ง และ 502 จำนวน 1 ครั้ง แม้ deploy ที่สำเร็จก็ยังมีช่วงสั้น ๆ ที่ระบบไม่ตอบ
| ข้อจำกัด | ผลที่เกิด | Kubernetes ช่วยอย่างไร (บทที่ 14–15) |
|---|---|---|
| container เดียว | มีช่วงไม่ตอบทุกครั้งที่ deploy | rolling update ค่อย ๆ แทน Pod ทีละส่วน ค่าเริ่มต้น maxUnavailable 25% และ maxSurge 25% (Kubernetes: Deployments) |
| ต้องมีคนสังเกตและสั่ง rollback | ระบบหยุดจนกว่าจะมีคนลงมือ | kubectl rollout undo deployment/<name> สั่ง rollback ได้ด้วยคำสั่งเดียว และ kubectl rollout status ติดตามความคืบหน้าของ rollout ได้ (เอกสารเดียวกัน) |
| container ที่ตายไม่ถูกเริ่มใหม่อัตโนมัติ (ระบบของทีมไม่ได้ตั้ง restart policy) | ต้องมีคนเริ่มใหม่ | self-healing เริ่ม container ใหม่และสร้าง Pod ทดแทนให้ครบจำนวน (Kubernetes: Self-Healing) |
ระดับที่ 1: ใน Lab B ระบบหยุดตั้งแต่ container ของเวอร์ชันพังแทนที่ container เดิม จนถึงตอนที่ทีม rollback เสร็จ เวลาส่วนใหญ่ไม่ใช่เวลาที่เครื่องทำงาน แต่เป็นเวลาที่คนใช้สังเกต ตัดสินใจ และหาเลขเวอร์ชันที่ต้องกลับไป RUNBOOK ที่ชัดเจนจึงลดเวลากู้ได้มากกว่าการทำให้สคริปต์เร็วขึ้น
ระดับที่ 2: ในเวอร์ชันพังของ Lab B คำสั่ง up --wait รายงาน dependency failed to start: container devops-prod-app-1 exited (1) และ run ล้มก่อนถึงประตูตรวจ health แต่ container เดิมถูกหยุดไปแล้ว การรู้ว่า deploy ล้มจึงยังไม่ใช่การป้องกันระบบ การป้องกันจริงต้องเริ่ม container ใหม่ให้พร้อมก่อนหยุด container เดิม ซึ่งเป็นสิ่งที่ rolling update ทำ
ระดับที่ 3: การทำให้ rollback อัตโนมัติด้วย workflow (เช่น เรียก Rollback ทันทีเมื่อ deploy ล้ม) ฟังดูง่าย แต่ต้องตอบให้ได้ว่าจะกลับไปเวอร์ชันใด จะทำอย่างไรถ้า rollback ล้มเอง และจะรู้ได้อย่างไรว่าเวอร์ชันเดิมยังใช้ได้ คำถามเหล่านี้คือเหตุผลที่บทนี้ให้คนตัดสินใจตาม RUNBOOK ก่อน และเรียนกลไกอัตโนมัติของ Kubernetes ในบทที่ 14–15
คำถามตรวจความเข้าใจ 12.3: จากผลการวัดที่ได้ 502 หนึ่งครั้งจาก 150 ครั้งระหว่าง deploy ปกติ ถ้าทีม deploy วันละ 10 ครั้ง และระบบรับ request สม่ำเสมอ จะกระทบ SLI ตามนิยามในบทที่ 11 อย่างไร และควรแก้ที่ใด
12.4 วัดผลงานการส่งมอบด้วย DORA metrics
DORA (DevOps Research and Assessment) เผยแพร่ตัวชี้วัดผลงานการส่งมอบซอฟต์แวร์ที่ใช้กันแพร่หลาย (DORA: Software delivery performance metrics) บทนี้ใช้สองตัวชี้วัดที่วัดได้จากประวัติของ GitHub Actions
| ตัวชี้วัด | ความหมาย | วัดจากระบบของทีม |
|---|---|---|
| Deployment frequency | ความถี่ที่ส่งมอบการเปลี่ยนแปลงถึงระบบจริง | นับเหตุการณ์ deploy ที่เกิดจริงต่อสัปดาห์ เชื่อมกับ run และ release ไม่นับ CI หรือ run ซ้ำเป็น deploy โดยอัตโนมัติ |
| Failed deployment recovery time | เวลาที่ใช้กู้บริการจาก deployment ที่ล้มเหลวและต้องแทรกแซง | บันทึกจุดเริ่มผลกระทบและเวลายืนยันว่ากลับมา ใช้ run เป็นหลักฐานประกอบ หากมีเพียงเวลา run ให้ระบุว่าเป็นค่าประมาณตามหัวข้อ 12.7 |
GitHub CLI ดึงประวัติ run ได้ (รายชื่อฟิลด์ตรวจจาก gh run list --help ส่วนผลจริงยังไม่ได้ทดสอบกับ repository บน GitHub)
gh run list --workflow cd.yml --limit 50 --json headBranch,conclusion,createdAt,updatedAt,url
gh run list --workflow rollback.yml --limit 20 --json conclusion,createdAt,updatedAt,urlระดับที่ 1: สำหรับ run ที่เกิดจากการ push tag ฟิลด์ headBranch จะเป็นชื่อ tag เช่น v0.5.2 ซึ่งใช้จับคู่ run กับเวอร์ชันได้ (พฤติกรรมของฟิลด์นี้กับ tag ยังไม่ได้ทดสอบ ถ้าไม่ใช่ ให้ดูชื่อ tag จากหน้าเว็บของ run) ถ้าไม่ได้ติดตั้ง GitHub CLI ให้นับจากหน้า Actions โดยตรง
ระดับที่ 2: ตัวเลขทั้งสองต้องอ่านคู่กัน ทีมที่ deploy บ่อยแต่กู้ระบบช้าอาจทำให้ผู้ใช้เดือดร้อนมากกว่าทีมที่ deploy น้อย ส่วนทีมที่กู้เร็วจะกล้า deploy บ่อยขึ้นเพราะความเสียหายของแต่ละครั้งน้อย
ระดับที่ 3: ข้อมูลของทีมในรายวิชามีไม่กี่ run ตัวเลขจึงไม่มีความหมายทางสถิติ จุดประสงค์ของ Lab C คือฝึกนิยามวิธีนับให้ชัดเจนและตรวจสอบย้อนกลับได้ ไม่ใช่เปรียบเทียบตัวเลขระหว่างทีม การเปรียบเทียบระหว่างทีมยังกระตุ้นให้แต่ละทีมนับแบบที่ทำให้ตัวเลขดูดี ซึ่งทำลายประโยชน์ของการวัด
คำถามตรวจความเข้าใจ 12.4: ทีมหนึ่งนับ deployment frequency จากจำนวน tag ทั้งหมดที่สร้าง รวม tag ที่ run ล้ม อธิบายว่าการนับนี้ผิดอย่างไร และจะทำให้อ่านตัวชี้วัดทั้งสองผิดอย่างไร
12.5 โจทย์ Capstone
Capstone ในบทที่ 13 ไม่ใช่การออกแบบระบบใหม่ แต่เป็นการใช้และอธิบาย pipeline ที่ทีมสะสมมาต่อโจทย์ที่ได้รับในวันนำเสนอ
| หัวข้อ | รายละเอียด |
|---|---|
| เวลา | ทีมละไม่เกิน 15 นาที |
| โจทย์ | ผู้สอนให้โจทย์ในวันนำเสนอ เช่น เพิ่ม endpoint ใหม่ หรือแก้ bug ที่กำหนด |
| สิ่งที่ต้องทำ | สร้าง branch และ pull request → ผ่าน CI → merge → ออกเวอร์ชัน → deploy ผ่าน CD → แสดงผลบนเครื่องปลายทาง → อธิบาย |
| ถ้าเวอร์ชันใหม่พัง | rollback ตาม RUNBOOK ระหว่างนำเสนอ |
| การอธิบาย | สมาชิกทุกคนต้องอธิบายส่วนใดส่วนหนึ่งได้ ผู้สอนเลือกผู้ตอบเอง |
ระดับที่ 1: สิ่งที่ต้องพร้อมก่อนวันนำเสนอคือ pipeline ที่ผ่านทุก job บน main เครื่องปลายทางและ runner ที่ทำงาน secret ที่ตั้งครบ และ RUNBOOK ที่ทุกคนเคยอ่าน
ระดับที่ 2: โจทย์ถูกออกแบบให้ทำได้ในเวลาไม่กี่นาทีถ้า pipeline พร้อม เวลาส่วนใหญ่ของทีมที่ไม่พร้อมมักหมดไปกับการแก้ runner ที่หยุด secret ที่หาย หรือ package.json ที่เวอร์ชันไม่ตรงกับ tag การซ้อมทั้งสายหนึ่งครั้งก่อนวันนำเสนอจึงสำคัญกว่าการเพิ่มความสามารถใหม่
ระดับที่ 3: ทีมที่ rollback ระหว่างนำเสนอได้อย่างเป็นขั้นตอนแสดงความพร้อมในการดูแลระบบได้ดีกว่าทีมที่ไม่เคยพัง เพราะสิ่งที่ประเมินคือการใช้และอธิบาย pipeline ไม่ใช่ความสมบูรณ์ของแอป
คำถามตรวจความเข้าใจ 12.5: ระบุ 3 สิ่งที่ทีมของตนต้องตรวจในวันก่อนนำเสนอ และคำสั่งหรือหน้าที่ใช้ตรวจแต่ละสิ่ง
เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ
12.6 แยกความล้มเหลวของ pipeline ออกจากความล้มเหลวของบริการ
pipeline ล้มกับบริการเสียเป็นเหตุการณ์ที่อาจเกิดแยกกันได้ หาก test ล้มก่อน build ระบบ production เดิมอาจยังให้บริการปกติ ในทางกลับกัน workflow อาจจบสำเร็จแล้วแต่บริการใหม่มี bug ที่ test ไม่ครอบคลุม การนับ workflow ที่มีสีแดงทั้งหมดเป็น failed deployment จึงทำให้ข้อมูลผิด ต้องระบุว่าการเปลี่ยนถึง production หรือไม่และต้องมีการแทรกแซงเพื่อกู้บริการหรือไม่
ตัวอย่างต่อไปนี้เป็นข้อมูลสมมติของบริการเดียวในหนึ่งสัปดาห์ มี CI runs 20 รายการ ในจำนวนนี้ test ล้ม 4 รายการก่อน deploy มี deployment ที่เกิดขึ้นจริง 8 ครั้ง และมี 2 ครั้งที่ต้องรีบ rollback หรือ hotfix อัตรา change fail ตามข้อมูลนี้คือ 2 / 8 = 25% ไม่ใช่ 4 / 20 = 20% เพราะชุดหลังวัดความล้มเหลวของ CI ซึ่งเป็นคนละคำถาม
ถ้ามี deployment อีก 1 ครั้งที่เป็นงานฉุกเฉินจาก incident ต้องบันทึกว่าเป็น unplanned deployment ด้วย เพื่อใช้วิเคราะห์ deployment rework rate ตามนิยามปัจจุบันของ DORA ตัวชี้วัดแต่ละตัวต้องประกาศช่วงเวลา ตัวตั้ง และตัวหารอย่างสม่ำเสมอ และใช้เพื่อปรับปรุงบริการของทีม ไม่ใช้แข่งขันด้วยการนับกิจกรรมที่ไม่สร้างคุณค่า (DORA: Software delivery performance metrics)
ตัวอย่างที่ไม่ถูกต้องคือเพิ่มจำนวน deploy ที่ไม่มีการเปลี่ยนเพียงเพื่อให้ deployment frequency สูงขึ้น ตัวเลขเพิ่มแต่ไม่ได้แสดงว่าการส่งมอบการเปลี่ยนที่มีประโยชน์ดีขึ้น ต้องพิจารณาร่วมกับเวลาส่งมอบ ความไม่เสถียร และบริบทของบริการ การใช้ตัวชี้วัดตัวเดียวเป็นเป้าหมายอาจชักนำให้ปรับวิธีนับแทนการปรับระบบ
12.7 เวลาเกิดผลกระทบ เวลาเห็นสัญญาณ และเวลากู้คืน
เส้นเวลาที่ชัดช่วยไม่ให้รายงาน recovery time สั้นเกินจริง สมมติว่า deploy เริ่ม 10:00 ระบบเริ่มให้ผลผิด 10:02 alert ดัง 10:05 ทีมตัดสิน rollback 10:09 คำสั่ง rollback จบ 10:11 และตรวจผ่านเส้นทางผู้ใช้ยืนยันว่ากลับมาปกติ 10:13 ช่วงคำสั่งทำงานคือ 2 นาที แต่ช่วงผลกระทบถึงยืนยันการกู้คือ 11 นาที ทั้งสองค่ามีประโยชน์แต่ตอบคนละคำถาม
ตัวอย่างที่ผิดคือจับเวลาเฉพาะ docker compose up แล้วรายงานว่าเวลากู้ระบบทั้งหมดเท่ากับเวลาคำสั่ง ขั้นตอนของคน การรอคิว workflow การดึง image และการตรวจผลอาจใช้เวลามากกว่า หากระบบไม่มีหลักฐานเวลาเริ่มผลกระทบ ควรระบุเวลาแรกที่ตรวจพบและข้อจำกัด แทนการสร้างค่าที่ดูแม่นยำโดยไม่มีข้อมูล
การเก็บข้อมูลควรใช้เวลาอ้างอิงที่เทียบกันได้ ระบุ timezone และเก็บ release, workflow run, log และผลตรวจปลายทางที่สัมพันธ์กัน นาฬิกาของเครื่องที่ต่างกันอาจทำให้เหตุการณ์ดูสลับลำดับ จึงควรตรวจความคลาดเคลื่อนก่อนสรุปเชิงเวลา การเก็บ timestamp ไม่ครบเป็นข้อจำกัดของข้อมูล ไม่ควรถูกเติมด้วยการคาดเดา
runbook ที่ดีระบุเงื่อนไขเริ่มกู้ release เป้าหมายที่เคยใช้ได้ ผู้ดำเนินการ คำสั่งหรือ workflow จุดตรวจหลังทำ และเงื่อนไขหยุดเมื่อกู้ไม่สำเร็จ คำแนะนำเพียง “กลับเวอร์ชันเก่า” ยังไม่พอ เพราะไม่บอกว่าเก่ารุ่นใด ใช้กับข้อมูลปัจจุบันได้หรือไม่ และตัดสินว่ากลับมาปกติจากอะไร
12.8 rollback โค้ดไม่ได้ย้อนฐานข้อมูลเสมอไป
ตัวอย่างในส่วนนี้เป็นระบบสมมติที่ขยายจากแอปของรายวิชาเพื่ออธิบายข้อจำกัด ไม่ใช่คำสั่งให้เพิ่ม schema migration ลงงานเดิม สมมติรุ่น A อ่านคอลัมน์ name ส่วนรุ่น B เปลี่ยนไปอ่าน display_name และ migration ลบ name ทันที หาก B มี bug แล้ว deploy image A กลับ A จะอ่านคอลัมน์ที่ไม่มีอยู่ การเก็บ image เก่าไว้จึงไม่รับประกันว่าจะ rollback ใช้งานได้
แนวทางที่ลดความเสี่ยงคือแยกการขยาย การย้าย และการถอนโครงสร้างออกจากกัน เช่น เพิ่มคอลัมน์ใหม่โดยยังเก็บของเดิม ปรับแอปให้อ่านหรือเขียนตามช่วงเปลี่ยนผ่าน ตรวจและย้ายข้อมูล แล้วค่อยถอนของเดิมเมื่อแน่ใจว่าไม่มีรุ่นที่พึ่งอยู่ แต่ละขั้นต้องออกแบบตามฐานข้อมูลและสัญญาของระบบจริง ไม่ควรใช้ตัวอย่างนี้เป็น migration สำเร็จรูป
ตัวอย่างที่ไม่ถูกต้องคือ restore backup ฐานข้อมูลเก่าทับข้อมูลล่าสุดทุกครั้งที่ rollback โค้ด โดยไม่พิจารณารายการที่ผู้ใช้เพิ่งสร้าง วิธีนี้อาจทำให้ข้อมูลใหม่สูญหาย การย้อนข้อมูลเป็นการตัดสินใจที่ต่างจากการเปลี่ยน image ต้องมีแผนรับความเสียหาย การคืนข้อมูล การประสานผู้เกี่ยวข้อง และการตรวจความครบถ้วนตามระบบนั้น
อีกกรณีคือรุ่นเก่ามีช่องโหว่ที่ต้องห้ามกลับไปใช้ แม้เคยทำงานปกติ การ roll forward ด้วยรุ่นแก้อาจเหมาะสมกว่า ต้องเลือกจากความเข้ากันได้ ความเสี่ยงและเวลาจริง ไม่ยึดว่า rollback ถูกต้องทุกสถานการณ์ ข้อมูล release record จากบทที่ 8 กับรายงานสแกนจากบทที่ 10 ช่วยให้ตัดสินได้โดยมีหลักฐาน
12.9 ทบทวนเหตุเพื่อเปลี่ยนระบบ ไม่หยุดที่หาคนผิด
การทบทวนเหตุควรแยก trigger, เงื่อนไขที่เอื้อ และช่องว่างของการตรวจ สมมติ trigger คือแก้พอร์ตผิด เงื่อนไขที่เอื้อคือค่าเดียวกันถูกเขียนซ้ำหลายไฟล์ และช่องว่างคือ smoke test เรียกแอปตรงโดยไม่ผ่าน proxy การสรุปว่า “คนแก้ไม่ระวัง” ไม่อธิบายว่าทำไมระบบยอมให้ความผิดพลาดถึงผู้ใช้และเหตุใดจึงตรวจช้า
แนวคิด blameless postmortem ของ Google SRE เน้นการเรียนรู้จากเหตุและกำหนดงานปรับปรุงที่มีผลต่อระบบ (Google SRE: Postmortem Culture) ไม่ได้หมายความว่าไม่ต้องมีผู้รับผิดชอบงาน แต่หมายถึงการอธิบายจากข้อมูลและบริบทที่มี ณ เวลาตัดสินใจ เพื่อให้ทีมเปิดเผยปัญหาและปรับมาตรการได้
ตัวอย่าง action item ที่ไม่ชัดคือ “ทดสอบให้มากขึ้น” เพราะตรวจไม่ได้ว่าเสร็จเมื่อใด ตัวอย่างที่ดีกว่าคือ “เพิ่ม smoke test ผ่าน Nginx สำหรับ /health และ endpoint หลัก โดยทดสอบให้จับกรณีพอร์ตผิดได้ พร้อมกำหนดเจ้าของและวันตรวจผล” งานนี้มีขอบเขตและหลักฐานยอมรับที่สัมพันธ์กับเหตุ
อีก action item คือ “ทำ rollback อัตโนมัติ” ซึ่งยังต้องแตกคำถามว่าจะตรวจความเสียหายจากอะไร กลับ release ใด ป้องกันสอง run แข่งกันอย่างไร และทำอย่างไรเมื่อการกู้ล้ม การเพิ่มระบบอัตโนมัติโดยไม่ตอบคำถามเหล่านี้อาจทำให้ความผิดพลาดเกิดเร็วขึ้น การสาธิต Capstone จึงควรแสดงทั้งเส้นทางปกติ เส้นทางผิด และวิธีตัดสินจากหลักฐาน ไม่หยุดเพียงภาพ workflow สีเขียว
กรณีอธิบายต่อเนื่อง: release ใหม่มีปัญหาแต่ run เก่าใช้เป็น rollback ไม่ได้
ข้อมูลสมมติเริ่มจาก release A ใช้ image digest D1 กับค่าตั้ง C1 และผ่านการตรวจแล้ว ต่อมา release B ใช้ D2 กับ C2 และเกิด 502 หลัง deploy ทีมมีสามทางเลือกคือสร้าง A ใหม่จากซอร์ส กด rerun ของ workflow เก่า หรือ deploy D1 กับค่าตั้งที่เข้ากันได้ ทางเลือกเหล่านี้ไม่เท่ากันในด้านเวลารอและความแน่นอนของผลผลิต
การสร้าง A ใหม่ต้องผ่านขั้น build อีกครั้ง หาก base image หรือ dependency ภายนอกเปลี่ยน อาจได้ digest D3 แม้ checkout commit เดิม การกด rerun ที่ยังมี job build-push จึงอาจทำให้ tag เดิมชี้ D3 ด้วย ไม่ใช่การนำ D1 กลับมา ความผิดอยู่ที่สับสนระหว่าง “สร้างจาก source เดิม” กับ “นำ artifact เดิมกลับมาใช้”
วิธีที่ตรงกับการ rollback artifact คือระบุ D1 ที่เคยใช้งานได้ ตรวจว่ายังเข้ากับ config และข้อมูลปัจจุบัน แล้วเรียกกระบวนการ deploy ที่ไม่ build ใหม่ จากนั้นยืนยันทั้ง digest ที่รันและ request ที่ผู้ใช้เข้าถึง ถ้าปัญหาอยู่ที่ C2 การกลับเฉพาะ image โดยยังใช้ค่าตั้งผิดอาจไม่ช่วย จึงต้องมี release record ที่แยกแต่เชื่อม artifact กับ config
เส้นเวลาจำลองกำหนดว่า B เริ่มส่งผลผิด 14:00 ทีมเห็น alert 14:03 เลือก D1 ได้ 14:06 เริ่มกู้ 14:07 คำสั่งจบ 14:09 และตรวจเส้นทางผู้ใช้ผ่าน 14:11 ช่วงผลกระทบถึงการยืนยันคือ 11 นาที ช่วงจาก alert ถึงเลือก release คือ 3 นาที และช่วงคำสั่งทำงานคือ 2 นาที หากต้องลดเวลากู้ครั้งถัดไป การทำให้สคริปต์เร็วขึ้นเพียงหนึ่งวินาทีไม่แตะเวลาค้นข้อมูลและตัดสินใจที่มากกว่า
ตัวอย่างข้อสรุปที่ไม่ถูกต้องคือ “ผู้ปฏิบัติช้า” โดยไม่มีข้อมูลว่าทำไมเลือก D1 ใช้เวลานาน หาก package มีแต่ชื่อ tag ที่เคยถูกเขียนทับ หรือ runbook ไม่บอกว่าค่าตั้งใดต้องกลับ ปัญหาอยู่ที่การจัดการ release ด้วย งานปรับปรุงที่ตรงเหตุคือเก็บ digest อัตโนมัติ บันทึก config version และมีเกณฑ์เลือก last known good ที่ตรวจซ้ำได้
ผลหลัง rollback ยังต้องติดตามต่อ สมมติ 502 หายแต่คำขอหลักยังตอบ 500 เพราะ schema ไม่เข้ากัน การเห็นหน้าแรกกลับมาจึงไม่พอ ควรใช้ชุด smoke tests ที่สัมพันธ์กับบริการสำคัญและขอบเขตผลกระทบ หากไม่สามารถกู้ด้วย D1 ได้ ต้องมีเงื่อนไขหยุดและส่งต่อการตัดสิน roll forward แทนการสลับรุ่นไปมาโดยไม่มีเกณฑ์
การบันทึกเหตุนี้ควรแสดงทั้งสิ่งที่ทราบและยังไม่ทราบ เช่น ทราบว่า C2 ชี้พอร์ตผิดจาก log ของ proxy แต่ยังไม่ได้วัดผลของการเปลี่ยน timeout การระบุข้อจำกัดทำให้ทีมถัดไปไม่เข้าใจว่าทุกข้อเสนอได้รับการทดสอบแล้ว และช่วยให้การทบทวนหลังเหตุไม่เติมเหตุผลย้อนหลังเกินหลักฐาน
ปฏิบัติการที่ 12 ปฏิบัติการรวม: ส่งมอบ พัง และกู้คืน
ปฏิบัติการนี้ประกอบด้วย Lab A–D Lab A เตรียมเครื่องมือกู้ระบบและออกเวอร์ชันผ่าน pipeline ครบสาย Lab B เกิดขึ้นเมื่อผู้สอนปล่อยเวอร์ชันพังเข้าระบบของทีม Lab C วัดผลงานและตรวจ repository และ Lab D คือการสอบปากเปล่าที่ผู้สอนเรียกทีละทีม การเปลี่ยนแปลงที่เข้า repository ใน Lab A แบ่งผู้รับผิดชอบดังนี้ เพื่อให้ทุกคนมี pull request ของตนเองใน milestone M11
| pull request | branch | Lab | ผู้รับผิดชอบ | ผู้ตรวจทาน |
|---|---|---|---|---|
| เพิ่ม workflow Rollback | ops/rollback-workflow | A.1 | สมาชิกคนที่ 1 | สมาชิกคนที่ 2 |
เพิ่ม RUNBOOK.md | docs/runbook | A.2 | สมาชิกคนที่ 2 | สมาชิกคนที่ 3 |
เพิ่ม docs/dora.md และปรับเวอร์ชันเป็น 0.5.2 | docs/dora | A.3 | สมาชิกคนที่ 3 | สมาชิกคนที่ 1 |
เมื่อ merge ครบแล้วหัวหน้าทีมออกเวอร์ชัน v0.5.2 ตามบทที่ 8 (เวอร์ชัน 0.5.1 ถูกใช้ไปแล้วกับเวอร์ชันพังใน Lab D.3 ของบทที่ 11) แต่ละ Lab แบ่งเป็นส่วน ฝึกตามตัวอย่าง และส่วน ตัดสินใจเอง (A.4, B.3 และ C.3)
ผลลัพธ์ของการ deploy เวอร์ชันพัง การ rollback และสคริปต์ตรวจความลับได้จากการรันจริงบนเครื่องจำลองตามที่ระบุในบทนำ ผลบน GitHub Actions (หน้า Run workflow, เวลาในคิว, ข้อความใน log ของ runner) ผู้เขียนยังไม่ได้ทดสอบ
Lab A: pipeline ครบสาย
สถานการณ์: ก่อนที่ระบบจะพัง ทีมต้องมีเครื่องมือกู้ระบบที่ใช้ได้ทันที มีขั้นตอนที่ทุกคนรู้ และมีเวอร์ชันล่าสุดที่ผ่าน pipeline ครบสายสำหรับกลับไปใช้
เป้าหมาย: เพิ่ม workflow Rollback, RUNBOOK และตาราง DORA แล้วออก v0.5.2 ที่ผ่านทุก job ใน run เดียว (LLO 12.1)
ฝึกตามตัวอย่าง
A.1 workflow Rollback (สมาชิกคนที่ 1)
cd ~/devops-app
git switch main
git pull
git switch -c ops/rollback-workflow
nano .github/workflows/rollback.ymlname: Rollback
on:
workflow_dispatch:
inputs:
tag:
description: 'เวอร์ชันที่ต้องการกลับไปใช้ เช่น 0.5.2 (ไม่มี v นำหน้า)'
required: true
type: string
jobs:
rollback:
runs-on: self-hosted
permissions:
contents: read
packages: read
steps:
- name: Checkout the release
uses: actions/checkout@v6
with:
ref: v${{ inputs.tag }}
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy previous version
env:
TAG: ${{ inputs.tag }}
POSTGRES_PASSWORD: ${{ secrets.PROD_POSTGRES_PASSWORD }}
run: bash scripts/deploy.sh "$TAG"| ส่วน | หน้าที่ |
|---|---|
workflow_dispatch กับ inputs.tag | เรียกด้วยมือจากหน้า Actions พร้อมช่องให้กรอกเวอร์ชัน |
ref: v${{ inputs.tag }} | checkout โค้ดและไฟล์ค่าตั้งของ release นั้น |
| ไม่มีขั้น build | ใช้ image ที่มีอยู่แล้วใน registry ตามหลัก release แก้ไขไม่ได้ (หัวข้อ 12.2) |
env: TAG: ${{ inputs.tag }} แล้วใช้ "$TAG" ใน run | ส่งค่าที่ผู้ใช้กรอกผ่านตัวแปรสภาพแวดล้อม ไม่แทรกลงในคำสั่งโดยตรง |
actionlint .github/workflows/rollback.yml
git add .github/workflows/rollback.yml
git commit -m "ops: add manual rollback workflow"
git push -u origin ops/rollback-workflow(ทดสอบแล้ว) actionlint และ check-jsonschema กับ schema ของ GitHub workflow ผ่าน
A.2 RUNBOOK (สมาชิกคนที่ 2) สร้าง RUNBOOK.md ที่ root ของ repository ตามแม่แบบต่อไปนี้ แล้วเติมข้อมูลของทีมในส่วนที่อยู่ในวงเล็บมุม
# RUNBOOK: devops-app
## ระบบ
- เครื่องปลายทาง: <ชื่อหรือที่อยู่เครื่อง> · ระบบชุด `devops-prod` · หน้าเว็บ `http://<เครื่องปลายทาง>/`
- ตรวจสุขภาพ: `curl -fsS http://<เครื่องปลายทาง>/health` ต้องได้ `"status":"ok"` และเวอร์ชันที่ deploy ล่าสุด
- ผู้รับผิดชอบเวรสัปดาห์นี้: <ชื่อ>
## อาการที่ต้องเริ่มขั้นตอนนี้
- run ของ CD ล้มที่ขั้น `Deploy with Compose`
- หน้าเว็บหรือ `/health` ตอบ 5xx หรือไม่ตอบ
## ขั้นตอน rollback
1. บันทึกเวลาที่พบปัญหา
2. หาเวอร์ชันล่าสุดที่ทำงานได้จากหน้า Actions (run ของ CD ที่ผ่านครั้งล่าสุด)
3. เปิด Actions → Rollback → Run workflow ใส่เวอร์ชันนั้น (ไม่มี v นำหน้า)
4. รอให้ run ผ่าน แล้วตรวจ `/health` ว่าเป็นเวอร์ชันที่เลือก
5. บันทึกเวลาที่ระบบกลับมา แจ้งทีม แล้วเปิด issue หาสาเหตุ
ทางสำรองเมื่อใช้ GitHub Actions ไม่ได้ (บนเครื่องปลายทาง)
```bash
cd ~/devops-app
git fetch --tags
git switch --detach v<เวอร์ชัน>
read -rs POSTGRES_PASSWORD && export POSTGRES_PASSWORD
bash scripts/deploy.sh <เวอร์ชัน>
unset POSTGRES_PASSWORD
git switch main
```
## บันทึกเหตุการณ์
| วันที่ | เวอร์ชันที่พัง | อาการ | พบเมื่อ | กู้เสร็จเมื่อ | เวลากู้ (นาที) | กลับไปเวอร์ชัน |
| --- | --- | --- | --- | --- | --- | --- |git switch main
git pull
git switch -c docs/runbook
nano RUNBOOK.md
bash scripts/check-secrets.sh; echo "exit=$?"== ไฟล์ .env ที่เคยถูก commit ==
== บรรทัดที่เคยถูกเพิ่มและเข้าข่ายความลับ ==
+read -rs POSTGRES_PASSWORD && export POSTGRES_PASSWORD
+unset POSTGRES_PASSWORD
ผล: พบร่องรอยที่ต้องตรวจสอบ
exit=1ผลการทดสอบพบว่าสคริปต์จากบทที่ 9 รายงานบรรทัดในทางสำรองของ RUNBOOK เพราะมีคำว่า PASSWORD ทั้งที่ไม่มีรหัสผ่านจริง นี่คือการรายงานผิด (false positive) ซึ่งต้องจัดการก่อน merge มิฉะนั้นการตรวจ repository ใน Lab C จะไม่ผ่าน ให้เพิ่มรูปแบบของสองคำสั่งนี้ในตัวแปร ALLOW ของ scripts/check-secrets.sh
ALLOW='\$\{|change-me|secrets\.|read -rs |unset 'bash scripts/check-secrets.sh; echo "exit=$?"
shellcheck scripts/check-secrets.sh
git add RUNBOOK.md scripts/check-secrets.sh
git commit -m "docs: add RUNBOOK, allow read/unset in secret check"
git push -u origin docs/runbook(ทดสอบแล้ว) หลังแก้ สคริปต์จบด้วย ผล: ไม่พบร่องรอยความลับตามรูปแบบที่ค้น และ exit=0 และยังพบ +POSTGRES_PASSWORD=Sup3rS3cret! ใน repository ตัวอย่างที่เคย commit .env ตามเดิม
A.3 ตาราง DORA และเวอร์ชัน 0.5.2 (สมาชิกคนที่ 3)
git switch main
git pull
git switch -c docs/dora
mkdir -p docs
nano docs/dora.md
npm version 0.5.2 --no-git-tag-version
npm test
git add docs/dora.md package.json package-lock.json
git commit -m "docs: add DORA metrics table, bump 0.5.2"
git push -u origin docs/doraเนื้อหาของ docs/dora.md
# DORA metrics ของทีม
ช่วงเวลา: <วันที่เริ่ม> ถึง <วันที่สิ้นสุด> · แหล่งข้อมูล: ประวัติ run ของ workflow CD และ Rollback
| ตัวชี้วัด | วิธีนับ | ค่า |
| --- | --- | --- |
| Deployment frequency | จำนวน run ของ CD ที่ผ่านทุก job หารด้วยจำนวนสัปดาห์ | |
| Failed deployment recovery time | เวลาจาก run ของ CD ที่ล้มที่ขั้น deploy ถึง run ที่ทำให้ระบบกลับมา (ค่าเฉลี่ยหรือค่ากลาง) | |
## ข้อมูลดิบ
| run | เวอร์ชัน | เริ่ม | ผล | หมายเหตุ |
| --- | --- | --- | --- | --- |npm version 0.5.2 ระบุเลขเวอร์ชันตรง ๆ แทน patch เพราะ main ยังเป็น 0.5.0 และ 0.5.1 ถูกใช้ไปแล้ว (ทดสอบแล้วว่า patch จาก 0.5.0 ได้ 0.5.1 ซึ่งจะชนกับ tag เดิม)
A.4 ออกเวอร์ชันและตรวจครบสาย (หัวหน้าทีม หลัง merge ครบ)
git switch main
git pull
git tag v0.5.2
git push origin v0.5.2ผลลัพธ์ที่คาดหวัง: run ของ CD ผ่านทั้ง job test, build-push และ deploy ใน run เดียว บรรทัดท้ายของขั้น deploy คือ deploy สำเร็จ: เวอร์ชัน 0.5.2 ตอบ health ผ่าน proxy และหน้าแรกบนเครื่องปลายทางแสดง v0.5.2 (ผลจากเครื่องจำลอง: DevOps App (team 01) v0.5.2)
ตัดสินใจเอง A.4: ซ้อม rollback หนึ่งครั้งก่อนเกิดเหตุจริง โดยเลือกว่าจะซ้อมแบบใด (ก) เรียก workflow Rollback ไปที่ 0.5.0 แล้วเรียกอีกครั้งไปที่ 0.5.2 หรือ (ข) ซ้อมทางสำรองบนเครื่องปลายทางตาม RUNBOOK บันทึกเวลาที่ใช้ ขั้นตอนที่ติดขัด และสิ่งที่แก้ใน RUNBOOK หลังซ้อม ลงในคำอธิบาย pull request ใหม่ที่ปรับ RUNBOOK
ผลลัพธ์ที่คาดหวัง A.4: เวลาที่ใช้ซ้อม รายการสิ่งที่ติดขัด และ RUNBOOK ฉบับปรับที่ merge แล้ว ระบบกลับมาที่ 0.5.2 หลังซ้อม
จุดตรวจ A: มีลิงก์ run ของ v0.5.2 ที่ผ่านทุก job และสมาชิกทุกคนเปิด RUNBOOK บน main แล้วอธิบายขั้นตอนได้
ปัญหาที่พบบ่อย
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
| ไม่เห็นปุ่ม Run workflow ของ Rollback | ไฟล์ workflow ยังไม่อยู่บน branch หลัก หรือไม่มีสิทธิ์เขียน repository | merge ops/rollback-workflow ก่อน และตรวจสิทธิ์ |
| Rollback ล้มที่ขั้น checkout ด้วย ref ไม่พบ | กรอก v0.5.2 ซึ่งทำให้ ref เป็น vv0.5.2 หรือ tag ไม่มีอยู่ | กรอกเลขเวอร์ชันไม่มี v |
npm version patch ได้ 0.5.1 ซึ่งชน tag เดิม | main ยังเป็น 0.5.0 | ระบุเลขตรง ๆ ด้วย npm version 0.5.2 --no-git-tag-version |
| deploy ล้มเพราะ version ไม่ตรง | สร้าง tag ก่อน merge pull request ที่ปรับเวอร์ชัน | ลบ tag (git push --delete origin v0.5.2 และ git tag -d v0.5.2) แล้วสร้างใหม่หลัง merge |
เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ
Lab B: เวอร์ชันพังและ rollback ตาม RUNBOOK
สถานการณ์: ระหว่างที่ทีมทำ Lab C ผู้สอนจะปล่อยเวอร์ชันใหม่เข้าระบบของทีมโดยไม่แจ้งล่วงหน้า เวอร์ชันนั้นผ่าน test และการสแกน แต่ทำให้ระบบใช้งานไม่ได้ ทีมต้องตรวจพบและกู้ระบบให้เร็วที่สุด
เป้าหมาย: ตรวจพบความผิดปกติ rollback ไปเวอร์ชันก่อนหน้าตาม RUNBOOK บันทึกเวลา และหาสาเหตุ (LLO 12.2)
ฝึกตามตัวอย่าง
B.1 เฝ้าระวัง (สมาชิกทุกคน ตลอด Lab C) เปิดหน้า Actions ของ repository ไว้ และตรวจหน้าเว็บเป็นระยะ
curl -s -o /dev/null -w "%{http_code}\n" --max-time 10 http://<เครื่องปลายทาง>/healthสัญญาณที่บอกว่ามีเหตุคือ run ใหม่ของ CD ที่ไม่มีใครในทีมสร้าง หรือ curl ไม่ได้ 200 ผลการทดสอบบนเครื่องจำลองหลังเวอร์ชันพังเข้าระบบ คำสั่งนี้ได้ 000 (รอครบ 10 วินาทีโดยไม่มีคำตอบ) ส่วน container ของแอปมีสถานะ Exited (1)
B.2 กู้ระบบตาม RUNBOOK ผู้รับผิดชอบเวรเริ่มขั้นตอนใน RUNBOOK ทันที ขั้นแรกคือบันทึกเวลาที่พบ แล้วเรียก workflow Rollback ไปที่เวอร์ชันล่าสุดที่ทำงานได้ ระหว่างรอ สมาชิกคนอื่นเปิด log ของ run ที่ล้มเพื่อหาสาเหตุ
ผลการทดสอบบนเครื่องจำลอง: การ deploy เวอร์ชันพังได้ข้อความ
Container devops-prod-app-1 Error dependency app failed to start
dependency failed to start: container devops-prod-app-1 exited (1)และการ deploy เวอร์ชัน 0.5.2 กลับไปได้
== ตรวจ health ผ่าน proxy: http://localhost/health
{"status":"ok","version":"0.5.2"}
deploy สำเร็จ: เวอร์ชัน 0.5.2 ตอบ health ผ่าน proxyหลังระบบกลับมา บันทึกแถวใหม่ในตารางบันทึกเหตุการณ์ของ RUNBOOK.md ผ่าน pull request
ผลลัพธ์ที่คาดหวัง: run ของ Rollback ผ่าน /health ตอบเวอร์ชัน 0.5.2 และ RUNBOOK มีบันทึกเหตุการณ์พร้อมเวลากู้เป็นนาที
ตัดสินใจเอง B.3: หาสาเหตุที่แท้จริงของเวอร์ชันพังจาก log ของ run ที่ล้ม log ของ container (docker compose -p devops-prod logs app บนเครื่องปลายทาง) และ diff ของ commit ที่ผู้สอน tag ไว้ (git fetch --tags แล้ว git show <tag>) อธิบายว่าเหตุใดปัญหานี้ผ่าน test และการสแกน แล้วเลือกวิธีป้องกันไม่ให้เกิดซ้ำอย่างน้อย 1 วิธีที่เพิ่มใน pipeline ได้ ทดลองบนเครื่องของตนเองว่าวิธีนั้นจับปัญหานี้ได้ และเขียนผลในคำอธิบาย issue
ผลลัพธ์ที่คาดหวัง B.3: สาเหตุที่อ้างบรรทัดใน log และ diff ได้ วิธีป้องกันพร้อมผลทดลองที่แสดงว่าจับได้
จุดตรวจ B: ระบบกลับมาที่เวอร์ชันก่อนหน้า บันทึกเวลาครบ และมี issue หาสาเหตุ
ปัญหาที่พบบ่อย
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
Rollback ค้างที่ Waiting for a runner | self-hosted runner ไม่ทำงาน | ใช้ทางสำรองใน RUNBOOK บนเครื่องปลายทาง แล้วค่อยตรวจ runner |
Rollback ล้มที่ขั้น deploy ด้วย missing a value | secret PROD_POSTGRES_PASSWORD หายหรือชื่อผิด | ตรวจด้วย gh secret list |
| rollback สำเร็จแต่ภายหลังระบบพังอีก | มีคน push tag ของเวอร์ชันพังซ้ำ หรือ CD ของ tag ใหม่ทำงานทับ | ประสานในทีมว่าห้ามออก tag จนกว่าจะแก้สาเหตุ |
| ทีมพยายามแก้โค้ดก่อน rollback | ต้องการแก้ให้จบในครั้งเดียว | กู้ระบบก่อนเสมอ แล้วจึงหาสาเหตุ (หัวข้อ 12.2) |
ห้ามเปิดก่อนจบ Lab B
Lab C: DORA metrics และจุดตรวจความปลอดภัยครั้งที่ 4
สถานการณ์: ก่อน Capstone ทีมต้องสรุปผลงานการส่งมอบที่ผ่านมาเป็นตัวเลข และยืนยันว่า repository ผ่านแนวปฏิบัติด้านความปลอดภัยและคุณภาพครบ
เป้าหมาย: กรอก docs/dora.md จากประวัติ run และตรวจ repository ครบสามรายการ (LLO 12.4)
ฝึกตามตัวอย่าง
C.1 รวบรวมข้อมูล DORA (สมาชิกคนที่ 3 ร่วมกับทีม)
gh run list --workflow cd.yml --limit 50 --json headBranch,conclusion,createdAt,updatedAt,url
gh run list --workflow rollback.yml --limit 20 --json conclusion,createdAt,updatedAt,urlกรอกข้อมูลดิบทุก run ลงในตารางของ docs/dora.md แล้วคำนวณตัวชี้วัดตามวิธีนับที่เขียนไว้ ถ้าไม่ได้ติดตั้ง gh ให้คัดลอกข้อมูลจากหน้า Actions โดยตรง ผู้เขียนยังไม่ได้รันสองคำสั่งนี้กับ repository บน GitHub
C.2 จุดตรวจความปลอดภัยครั้งที่ 4 (ตรวจ repository) (สมาชิกทุกคน แต่ละคนตรวจและบันทึกผลของตนเอง)
| รายการ | วิธีตรวจ | ผ่านเมื่อ |
|---|---|---|
| ไม่มีรหัสผ่าน | bash scripts/check-secrets.sh บน main ล่าสุด | ผล: ไม่พบร่องรอยความลับตามรูปแบบที่ค้น |
| มีการสแกน | Settings → Branches ของ main และ ci.yml | required status check มีทั้ง test และ image-scan และ exit-code เป็น '1' |
| มี review | gh pr list --state merged --limit 30 --json number,title,reviewDecision,mergedAt | pull request ที่ merge ในบทที่ 10–12 มี reviewDecision เป็น APPROVED ทุกรายการ |
รายชื่อฟิลด์ของ gh pr list ตรวจจาก gh pr list --help ค่า APPROVED ของ reviewDecision เขียนจากความรู้ทั่วไปเกี่ยวกับ GitHub ยังไม่ได้ทดสอบ ถ้าไม่ได้ใช้ gh ให้ตรวจแท็บ Conversation ของแต่ละ pull request
ตัดสินใจเอง C.3: ตาราง DORA ของทีมมีข้อมูลน้อยและมีเหตุการณ์ที่สร้างขึ้นใน Lab B ให้ระบุอย่างน้อย 2 เหตุผลที่ตัวเลขนี้ไม่ควรใช้ตัดสินคุณภาพของทีม แล้วเสนอว่าถ้าทีมดูแลระบบนี้ต่ออีกหนึ่งภาคเรียน จะเก็บข้อมูลอะไรเพิ่มเพื่อให้ตัวชี้วัดน่าเชื่อถือขึ้น โดยอ้าง DORA guide
ผลลัพธ์ที่คาดหวัง C.3: เหตุผลอย่างน้อย 2 ข้อ และข้อเสนอที่อ้างแหล่งข้อมูล เขียนไว้ท้าย docs/dora.md
จุดตรวจ C: docs/dora.md บน main มีข้อมูลดิบและตัวชี้วัด สมาชิกทุกคนมีผลตรวจครบสามรายการ
ปัญหาที่พบบ่อย
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
gh: To get started with GitHub CLI, please run: gh auth login | ยังไม่ได้เข้าสู่ระบบ GitHub CLI | gh auth login หรือใช้หน้า Actions แทน |
| pull request บางรายการ merge โดยไม่มี review | branch protection ยังไม่บังคับ review หรือผู้ดูแลข้ามกติกา | รายงานตามจริงในผลตรวจ แล้วปรับ branch protection ให้บังคับ review |
image-scan ไม่อยู่ในรายการ required status check | ยังไม่ได้เพิ่มหลังบทที่ 10 | เพิ่มที่ Settings → Branches ตามบทที่ 5 |
เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ
Lab D: สอบปากเปล่ารายบุคคล
สถานการณ์: ผู้สอนเรียกทีมละ 10 นาทีระหว่างที่ทีมอื่นทำ Lab A–C ผู้สอนให้โจทย์ความต้องการสั้น ๆ แล้วถามสมาชิกแต่ละคนให้อธิบายว่า Git workflow, ขั้นของ pipeline และการใช้ container ของทีมรองรับโจทย์นั้นอย่างไร
เป้าหมาย: อธิบายการเลือกของทีมต่อโจทย์ที่ได้รับ โดยอ้างสิ่งที่อยู่ใน repository จริง (LLO 12.3)
การเตรียมตัว
- เปิด repository ของทีม หน้า Actions และ
RUNBOOK.mdไว้บนจอระหว่างสอบ ผู้สอนอาจขอให้ชี้ไฟล์หรือ run ที่ใช้ประกอบคำตอบ - ทบทวนใบงาน CLO1 ของบทที่ 3, 5, 6 และ 8 ซึ่งเป็นพื้นของคำถาม
- ฝึกตอบโดยเชื่อมกับระบบของทีม ไม่ใช่นิยามทั่วไป เช่น แทนที่จะตอบว่า "CI คือการรวมโค้ดบ่อย ๆ" ให้ตอบว่า "pull request ของทีมต้องผ่าน job
testและimage-scanก่อน merge เพราะ..." - เตรียมเปรียบเทียบทางเลือกอย่างน้อยหนึ่งเรื่อง เช่น เหตุใดทีมใช้ GitHub flow ไม่ใช้ GitFlow หรือเหตุใด rollback ด้วย tag เดิมดีกว่า build ใหม่ ตาม rubric CLO1 ระดับ 3
ตัวอย่างรูปแบบโจทย์ (โจทย์จริงผู้สอนกำหนดในวันสอบ): "ผู้ใช้ต้องการให้แก้ข้อความหน้าแรกด่วนภายใน 30 นาที โดยระบบต้องไม่หยุดเกิน 1 นาที" ผู้สอนอาจถามคนที่ 1 เรื่อง branch และ pull request คนที่ 2 เรื่องขั้นของ pipeline ที่การแก้นี้ต้องผ่าน และคนที่ 3 เรื่อง image และการ deploy
เก็บกวาดเมื่อจบปฏิบัติการ
ตรวจว่าเครื่องปลายทางรันเวอร์ชัน 0.5.2 (หรือเวอร์ชันที่ทีม roll forward แล้ว) และหน้าเว็บตอบ 200 ลบ branch ที่ merge แล้วและ branch instructor/broken-0.6.0 (หลังผู้สอนอนุญาต) โดยเก็บ tag v0.6.0 ไว้เป็นบันทึก เวอร์ชันถัดไปของทีมจึงเป็น 0.6.1 ขึ้นไป บนเครื่องของตนเองหยุดระบบด้วย docker compose -f compose.yaml -f compose.monitoring.yaml down (ไม่มี -v)
สรุป
pipeline ของทีมประกอบด้วยขั้นที่จับปัญหาคนละชนิด ตั้งแต่ review, test, การสแกน image, การ build และ push ไปจนถึงการ deploy และประตูตรวจ health ไม่มีขั้นใดจับได้ทุกปัญหา ปัญหาที่หลุดถึงท้ายสายทำให้ระบบจริงหยุด ทีมจึงต้องมีทั้งการตรวจหลายชั้นและขั้นตอนกู้ระบบที่ฝึกไว้แล้ว
release แต่ละชุดมีรหัสเฉพาะและแก้ไขไม่ได้ rollback ที่ดีจึงเป็นการกลับไปใช้ image tag เดิมที่เคยทำงานโดยไม่ build ใหม่ workflow Rollback ของทีมทำเช่นนั้นด้วยการ checkout tag เดิมและเรียก scripts/deploy.sh ส่วน RUNBOOK ลดเวลาที่คนใช้ตัดสินใจ ซึ่งเป็นส่วนใหญ่ของเวลากู้ระบบ ระบบที่รันแอปเพียง container เดียวมีข้อจำกัด คือมีช่วงไม่ตอบทุกครั้งที่ deploy และต้องมีคนสั่ง rollback ซึ่ง rolling update และ self-healing ของ Kubernetes ในบทที่ 14–15 ช่วยแก้ได้
DORA metrics วัดผลงานการส่งมอบ บทนี้ใช้ deployment frequency และ failed deployment recovery time ที่นับได้จากประวัติ run ตัวเลขสองตัวต้องอ่านคู่กัน และวิธีนับต้องชัดเจนและตรวจสอบย้อนกลับได้ Capstone ในบทที่ 13 คือการใช้และอธิบาย pipeline นี้ต่อโจทย์ในวันนำเสนอ
สิ่งที่ส่งต่อไปยังโครงงานและ Capstone
| สิ่งที่ได้ | นำไปใช้ที่ |
|---|---|
| pipeline ครบสายที่ผ่านทุก job (M11) | บทที่ 13 Capstone |
workflow Rollback และ RUNBOOK.md พร้อมบันทึกเหตุการณ์ | บทที่ 13 rollback ระหว่างนำเสนอ · บทที่ 15 เทียบกับ kubectl rollout undo |
docs/dora.md | บทที่ 13 นำเสนอผลงานของทีม |
scripts/check-secrets.sh ที่ยกเว้น read -rs และ unset | ทุกครั้งที่ตรวจ repository |
| วิธีป้องกันจาก Lab B.3 | ปรับ pipeline ก่อน Capstone |
| Learning Log ครั้งที่ 12 | portfolio ที่ส่งในบทที่ 13 |
สรุปคำสั่งในบทนี้
| คำสั่งหรือค่าตั้ง | หน้าที่ |
|---|---|
on: workflow_dispatch: inputs: | workflow ที่เรียกด้วยมือพร้อมช่องกรอกค่า |
actions/checkout กับ ref: v${{ inputs.tag }} | checkout โค้ดของ tag ที่ระบุ |
npm version 0.5.2 --no-git-tag-version | ตั้งเลขเวอร์ชันตรง ๆ โดยไม่สร้าง tag |
git switch --detach vX.Y.Z | สลับไปยังโค้ดของ tag เพื่อ deploy ด้วยมือ |
docker compose -p devops-prod logs app | ดู log ของแอปบนเครื่องปลายทาง |
gh run list --workflow cd.yml --json ... | ดึงประวัติ run ของ workflow |
gh pr list --state merged --json number,reviewDecision | ตรวจสถานะ review ของ pull request ที่ merge แล้ว |
gh secret list | ตรวจรายชื่อ secret ของ repository |
แบบฝึกหัดท้ายบท
ตอนที่ 1 ฝึกทบทวน
ชุด FP10306343-P12 จำนวน 12 ข้อ ข้อละ 1 คะแนน รวม 12 คะแนน ครอบคลุม pipeline ครบสาย (commit → test → scan → build → deploy), การ rollback ด้วย release เดิม, การคำนวณ Failed Deployment Recovery Time, สถาปัตยกรรมความพร้อมใช้งานสูง, จุดตรวจความปลอดภัยครั้งที่ 4 และตัวชี้วัด DORA metrics
เข้าสู่ระบบห้องเรียนด้วยบัญชีที่ลงทะเบียนในรายวิชา 10306343 แล้วตอบคำถามให้ครบ ระบบตรวจคำตอบและแสดงคำอธิบายเพื่อทบทวน เมื่อทำครบและส่งผล ระบบจะบันทึกคะแนนไว้กับบัญชีของผู้เรียน สามารถทำซ้ำเพื่อทบทวนได้ ส่วนคะแนนที่นำไปรวมในรายวิชาเป็นไปตามเกณฑ์และกำหนดส่งในสมุดคะแนน
แบบฝึกหัดเพิ่มเติมสำหรับอภิปรายและเขียนตอบ
แบบฝึกหัดแบ่งเป็นสามกลุ่ม ได้แก่ ความเข้าใจ การประยุกต์ และการวิเคราะห์ปัญหา แต่ละข้อระบุผลลัพธ์การเรียนรู้ที่ฝึก ข้อ ข1 คือการปรับปรุง RUNBOOK ตามแผนการสอน
ก. ความเข้าใจ
- ก1 (LLO 12.2) อธิบายความหมายของ "release แก้ไขไม่ได้" ตาม The Twelve-Factor App และผลต่อวิธี rollback ของทีม
- ก2 (LLO 12.1) เรียงลำดับขั้นใน workflow CD ของทีม และระบุว่าขั้นใดใช้ GitHub-hosted runner ขั้นใดใช้ self-hosted runner พร้อมเหตุผล
- ก3 (LLO 12.3) อธิบายว่าเหตุใดทีมจึงใช้ GitHub flow กับโครงงานนี้ โดยอ้างขนาดทีมและความถี่ในการออกเวอร์ชัน
ข. การประยุกต์
- ข1 (LLO 12.2) ปรับปรุง
RUNBOOK.mdของทีมจากประสบการณ์ใน Lab B ให้มีอย่างน้อย (1) วิธีตรวจว่าเวอร์ชันใดเป็นเวอร์ชันล่าสุดที่ทำงานได้ (2) สิ่งที่ต้องทำเมื่อ workflow Rollback ล้มเอง (3) รายชื่อผู้ติดต่อและช่องทางแจ้งทีม ส่งเป็น pull request - ข2 (LLO 12.2) จากบันทึกต่อไปนี้ คำนวณเวลากู้ระบบเป็นนาที และ failed deployment recovery time เฉลี่ยของทั้งสองเหตุการณ์
| เหตุการณ์ | run ของ CD ที่ล้มเริ่ม | ทีมพบปัญหา | run ของ Rollback ผ่าน |
|---|---|---|---|
| 1 | 10:02 | 10:05 | 10:11 |
| 2 | 14:40 | 14:58 | 15:03 |
- ข3 (LLO 12.1) เขียนขั้นของ workflow ที่รัน container จาก image ที่เพิ่ง build แล้วเรียก
/healthก่อน push เพื่อป้องกันปัญหาแบบ Lab B (เขียนเป็น YAML ของหนึ่งขั้นหรือสองขั้น)
ค. การวิเคราะห์ปัญหา
- ค1 (LLO 12.2) ระหว่าง Lab B สมาชิกคนหนึ่งเรียก Rollback ไปที่
0.5.1เพราะเป็นเลขก่อนหน้า 0.6.0 วิเคราะห์ผลที่จะเกิด และเสนอการปรับ RUNBOOK เพื่อกันความผิดพลาดนี้ - ค2 (LLO 12.4) ผลตรวจ repository ของทีมหนึ่งผ่านรายการ "ไม่มีรหัสผ่าน" แต่สมาชิกพบว่าในบทที่ 10 เคยแก้
ALLOWจนรวมคำว่าPASSWORDทั้งคำ วิเคราะห์ว่าผลตรวจนี้ยังเชื่อถือได้หรือไม่ และควรทำอะไร - ค3 (LLO 12.3) ลูกค้าต้องการระบบที่ไม่หยุดเลยระหว่าง deploy วิเคราะห์ว่า pipeline และ Compose ของทีมรองรับได้หรือไม่ โดยอ้างผลวัดในหัวข้อ 12.3 และเสนอทางเลือกพร้อมข้อดีข้อเสียอย่างน้อย 2 ทาง
เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ
การศึกษาค้นคว้าเพิ่มเติม
- อ่าน The Twelve-Factor App: V. Build, release, run แล้วบันทึกใน Learning Log ว่า release ของทีมประกอบด้วยอะไรบ้าง
- อ่าน DORA: Software delivery performance metrics แล้วระบุตัวชี้วัดอื่นที่ไม่ได้ใช้ในบทนี้ และวิธีที่ทีมจะวัดได้ เพื่อตอบ Lab C.3
- อ่าน Kubernetes: Deployments ส่วน rolling update และ rollback เพื่อเตรียมบทที่ 14–15
- ซ้อม Capstone ทั้งสายหนึ่งครั้ง: ทำการเปลี่ยนแปลงเล็ก ๆ ผ่าน pull request ออกเวอร์ชัน และ rollback ตาม RUNBOOK
- ทำแบบฝึกหัดท้ายบทให้ครบ ส่งงานข้อ 1, 2, 4, 5 และเขียน Learning Log ครั้งที่ 12
เอกสารอ้างอิง
แหล่งข้อมูลเพิ่มเติมสำหรับตัวอย่างและกรณีอธิบาย
ตรวจเอกสารออนไลน์เมื่อ 23 ตุลาคม 2569 ตัวเลขและเหตุการณ์ที่ระบุว่าสมมติใช้เพื่ออธิบายกลไก ไม่ใช่ผลทดลองหรือสถิติขององค์กรจริง
เอกสารอ้างอิงของเนื้อหาเดิม
- 12factor.net. (n.d.). The twelve-factor app: V. Build, release, run. https://12factor.net/build-release-run
- DORA. (n.d.). DORA's software delivery performance metrics. https://dora.dev/guides/dora-metrics-four-keys/
- Kubernetes Documentation. (n.d.). Deployments. https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Kubernetes Documentation. (n.d.). Kubernetes self-healing. https://kubernetes.io/docs/concepts/architecture/self-healing/