มหาวิทยาลัยมหามกุฏราชวิทยาลัย · ระบบสาธิต (Demo)
ข้ามไปยังเนื้อหา

เอกสาร CI/CD Pipeline

งวดที่ 2 · ส่งมอบ

ดาวน์โหลด .md

เอกสาร CI/CD Pipeline

อ้างอิง TOR: ข้อ 4.6.3 (CI/CD บน GitHub พร้อมการย้อนกลับ — Rollback) ไฟล์: .github/workflows/ci-cd.yml (GitHub Actions) ร่วมกับ Helm chart infra/helm/mbu-buddhist-ai/ ฉบับ: 1.0 — วันที่ 3 ตุลาคม พ.ศ. 2569

สถานะ: ไฟล์ workflow ส่งมอบแล้วและผ่านการตรวจโครงสร้างอัตโนมัติ (tests/unit/infra-yaml.test.ts — parse YAML, ลำดับ job, trigger, Node 22, deploy-prod ตรวจ tag บน main) แต่ ยังไม่ได้รันบน GitHub Actions จริง ในรอบสาธิต เพราะ sandbox ไม่ได้ push ไปยัง GitHub repository ที่ตั้งค่า secrets/environments และไม่มีคลัสเตอร์ Kubernetes ข้อ 4.6.3 จึงมีสถานะ partial ในหน้า /tor ข้อสังเกตที่ต้องแก้ก่อนเปิดใช้อยู่ในหัวข้อ 8


1. ภาพรวม

flowchart LR
  T["push / pull_request / workflow_dispatch / tag v*"] --> L["1. lint"]
  L --> TE["2. test<br/>(vitest + coverage gate)"]
  TE --> S["3. security<br/>(npm audit + pentest-lite)"]
  S --> B["4. build<br/>(next build + images*)"]
  B --> E["5. e2e<br/>(Playwright Chromium)"]
  E --> D1["6. deploy-dev<br/>develop → mbu-dev"]
  E --> D2["7. deploy-test<br/>release/* → mbu-test"]
  E --> D3["8. deploy-prod<br/>tag v* บน main → mbu-prod<br/>(ต้องอนุมัติ)"]
  D1 & D2 & D3 -. ล้มเหลว .-> RB["helm --atomic / helm rollback"]

* build/push container image และงาน deploy ทำงานเฉพาะเมื่อเป็น push และตั้ง repository variable DEPLOY_ENABLED = "true"

2. Trigger และ Branch

เหตุการณ์เงื่อนไขงานที่รัน
pushbranch main, develop, release/** หรือ tag v*lint → test → security → build → e2e (+ deploy ตาม branch/tag)
pull_requestเข้า main หรือ developlint → test → security → build → e2e (ไม่ deploy)
workflow_dispatchสั่งรันด้วยมือlint → test → security → build → e2e
Branch/Tagสภาพแวดล้อมNamespacevaluesURL ของ environment
developdevmbu-devvalues-dev.yamlhttps://dev.dhammaverse.mbu.ac.th
release/*test (SIT/UAT)mbu-testvalues-test.yamlhttps://test.dhammaverse.mbu.ac.th
tag v* (ต้องอยู่บน main)prodmbu-prodvalues-prod.yamlhttps://dhammaverse.mbu.ac.th

Concurrency: ci-cd-${{ github.ref }} — ยกเลิกรอบเก่าเฉพาะ pull request; งาน deploy แต่ละ environment มี concurrency group ของตัวเอง (deploy-dev/deploy-test/deploy-prod) และไม่ยกเลิกงานที่กำลัง deploy Permissions เริ่มต้น: contents: read (งาน build เพิ่ม packages: write สำหรับ ghcr.io)

3. ตัวแปรสภาพแวดล้อมระดับ workflow

ตัวแปรค่าหมายเหตุ
NODE_VERSION22
NEXT_TELEMETRY_DISABLED1
DATABASE_URLfile:./test.dbSQLite แยกไฟล์สำหรับ CI
AUTH_SECRETค่าเฉพาะ CI (ไม่ใช่ความลับจริง)
LLM_PROVIDERmockงานทดสอบทุกงานใช้ Mock LLM — pipeline ไม่อ่าน/ไม่เก็บคีย์ LLM
ADMIN_IP_ALLOWLISTlocalhost
NEXT_PUBLIC_BASE_URLhttp://localhost:3000
HELM_VERSIONv3.16.4
HELM_RELEASE / HELM_CHARTmbu-buddhist-ai / infra/helm/mbu-buddhist-ai
IMAGE_REGISTRYghcr.io

DATA_ENCRYPTION_KEY สร้างใหม่แบบสุ่มในแต่ละงานด้วย openssl rand -base64 32 (step “Generate CI-only encryption key”)

4. รายละเอียดทุก Job และ Step

4.1 Job lint — Lint (timeout 15 นาที)

#Stepคำสั่ง/การทำงาน
1Checkoutactions/checkout@v4
2Setup Node.js 22actions/setup-node@v4 (cache npm)
3Install dependenciesnpm ci
4Generate Prisma clientnpx prisma generate
5ESLintnpm run lint
6TypeScript type checknpx tsc --noEmit
7Setup Helmazure/setup-helm@v4 (v3.16.4)
8Helm lint + template (dev / test / prod)วนทั้ง 3 environment: helm lint และ helm template ด้วย values.yaml + values-<env>.yaml

4.2 Job test — Test (unit + API, coverage gate) (needs: lint, 30 นาที)

#Stepคำสั่ง/การทำงาน
1–3Checkout / Setup Node / Installเหมือน lint
4Generate CI-only encryption keyเขียน DATA_ENCRYPTION_KEY ลง $GITHUB_ENV
5Prepare database (migrate + seed)npx prisma generate && npx prisma migrate deploy && npx prisma db seed
6Vitest + coverage gate (≥ 80%)npx vitest run --coverage — เกณฑ์ใน vitest.config.ts: lines/functions/statements ≥80%, branches ≥75% ของ src/domain + src/application; ต่ำกว่าเกณฑ์ = งานล้มเหลว
7Upload coverage reportactions/upload-artifact@v4 → artifact coverage-report (coverage/, เก็บ 14 วัน, ทำเสมอ)

หมายเหตุ: step นี้เรียก npx vitest run --coverage โดยตรง จึงไม่ได้ตั้ง OPENAPI_COVERAGE=1 ชั้นตรวจการเรียก API จริงขณะรัน (runtime) จึงไม่ทำงานใน CI — ชั้น static (tests/api/openapi-coverage.test.ts) ยังทำงาน (ดูข้อเสนอในหัวข้อ 8)

4.3 Job security — Security (npm audit + pentest-lite) (needs: test, 30 นาที)

#Stepคำสั่ง/การทำงาน
1–3Checkout / Setup Node / Install
4npm audit (fail on High/Critical)npm audit --audit-level=high
5Generate CI-only encryption key
6Prepare database (migrate + seed)
7Start dev server (background)PORT=3000 nohup npm run dev, รอ GET /api/health สูงสุด 120 วินาที (ไม่ขึ้น = แสดง log และล้มเหลว)
8Vulnerability scan reportnpx tsx scripts/security/npm-audit-report.ts → docs/deliverables/vulnerability-scan-report.md
9Pentest-lite (8 เคส OWASP)npx tsx scripts/security/pentest-lite.ts (env BASE_URL=http://localhost:3000) → docs/deliverables/pentest-report.md — ดูหัวข้อ 8: ไฟล์สคริปต์นี้ไม่มีใน repository
10Stop dev serverkill ตาม dev-server.pid (ทำเสมอ)
11Upload security reportsartifact security-reports (รายงาน 2 ฉบับ + dev-server.log, เก็บ 30 วัน)

4.4 Job build — Build (needs: security, 30 นาที, packages: write)

#Stepคำสั่ง/การทำงาน
1–3Checkout / Setup Node / Install
4Generate CI-only encryption key
5Prepare database (migrate + seed)
6Next.js production buildnpm run build
7Log in to container registry (ghcr.io)docker/login-action@v3 ด้วย GITHUB_TOKEN — เฉพาะ push + DEPLOY_ENABLED == 'true'
8Build & push images (8 services)วน identity chat ai-orchestrator retrieval ingestion evaluation config report: docker build -f services/<svc>/Dockerfile → push ghcr.io/mbu-ac-th/mbu-<svc>-service:<SHA> และ tag ตาม git tag เมื่อเป็น release — เงื่อนไขเดียวกับ step 7 (ยังไม่มี Dockerfile — หัวข้อ 8)

4.5 Job e2e — E2E (Playwright / Chromium) (needs: build, 45 นาที)

#Stepคำสั่ง/การทำงาน
1–3Checkout / Setup Node / Install
4Install Chromium for Playwrightnpx playwright install --with-deps chromium แล้วตั้ง CHROMIUM_PATH เป็น executable ของ Playwright (runner ของ CI เป็นเครื่องเปล่า ต่างจาก sandbox ที่ใช้ Chromium ของระบบ)
5Generate CI-only encryption key
6Prepare database (migrate + seed)
7Playwright testsnpx playwright test — playwright.config.ts เปิด dev server เอง (webServer), 3 viewport, retry 1 ครั้งเมื่อ CI
8Upload Playwright reportartifact playwright-report (playwright-report/, test-results/, เก็บ 14 วัน, ทำเสมอ)

หมายเหตุ: playwright.config.ts ใช้พอร์ต E2E_PORT (ค่าเริ่มต้น 3210) และ job นี้ไม่ได้ตั้ง E2E_PORT จึงเปิด dev server ที่ 3210

4.6 Job deploy-dev — Deploy → dev (mbu-dev) (needs: build, e2e, 30 นาที)

เงื่อนไข: push + refs/heads/develop + DEPLOY_ENABLED == 'true'; environment dev; env KUBE_NAMESPACE=mbu-dev, VALUES_FILE=values-dev.yaml, IMAGE_TAG=<commit SHA>, SMOKE_URL=vars.SMOKE_URL

#Stepการทำงาน
1Checkout
2Setup Helmv3.16.4
3Configure kubeconfig (secret KUBE_CONFIG)ไม่มี secret = ล้มเหลวพร้อมข้อความ; ถอด base64 ลง $RUNNER_TEMP/kube/config (chmod 600) แล้วตั้ง KUBECONFIG
4Record current Helm revision (ใช้ย้อนกลับ)helm status -o json → .version เก็บเป็น output revision (ว่าง = ติดตั้งครั้งแรก)
5Helm upgrade (atomic)helm upgrade --install … --create-namespace -f values.yaml -f values-dev.yaml --set global.image.tag=$IMAGE_TAG --atomic --wait --timeout 10m --history-max 10
6Smoke testkubectl get deploy,hpa,ingress -l app.kubernetes.io/instance=… และ curl -fsS --retry 10 ไปที่ SMOKE_URL (ไม่ตั้ง = ข้ามการเรียก health)
7Rollback (helm rollback) on failureเมื่อ step ก่อนหน้าล้มเหลวและ upgrade ไม่ถูกข้าม: แสดง helm history; ติดตั้งครั้งแรก = ไม่มีอะไรย้อน (--atomic ถอนให้แล้ว); ถ้า upgrade สำเร็จแต่ smoke test ล้ม หรือสถานะ release ไม่ใช่ deployed → helm rollback <release> <revision เดิม> --wait --timeout 5m

4.7 Job deploy-test — Deploy → test (mbu-test)

เหมือน deploy-dev ทุก step ต่างกันที่เงื่อนไข startsWith(github.ref, 'refs/heads/release/'), environment test, KUBE_NAMESPACE=mbu-test, VALUES_FILE=values-test.yaml — ใช้สำหรับ SIT/UAT ร่วมกับมหาวิทยาลัย

4.8 Job deploy-prod — Deploy → prod (mbu-prod) (45 นาที)

เงื่อนไข: push + startsWith(github.ref, 'refs/tags/v') + DEPLOY_ENABLED == 'true'; environment prod (ตั้ง Required reviewers ให้มหาวิทยาลัยอนุมัติก่อนขึ้นระบบจริง); IMAGE_TAG=<ชื่อ tag>

#Stepการทำงาน
1Checkout (full history)fetch-depth: 0
2Verify tag is on maingit merge-base --is-ancestor $GITHUB_SHA origin/main — ไม่อยู่บน main = ยกเลิก
3–7Setup Helm / Configure kubeconfig / Record revision / Helm upgrade (atomic, timeout 15m) / Smoke testเหมือน deploy-dev
8Rollback (helm rollback) on failureเหมือน deploy-dev

5. Secrets และ Variables ที่ต้องตั้งใน GitHub

ชื่อประเภทระดับใช้ในหมายเหตุ
DEPLOY_ENABLEDVariableRepositorybuild (images), deploy-*ตั้ง "true" เพื่อเปิดงาน build image และ deploy (ค่าเริ่มต้นปิด)
KUBE_CONFIGSecretEnvironment dev / test / prod (แยกกัน)deploy-*kubeconfig เข้ารหัส base64 ควรใช้ ServiceAccount ที่มีสิทธิ์เฉพาะ namespace นั้น
(ทางเลือก) OIDC—Environmentdeploy-*แนะนำสำหรับ prod: เพิ่ม permissions: id-token: write และแทน step kubeconfig ด้วย action ของผู้ให้บริการ (AWS EKS / Azure AKS / GCP GKE) — ไม่ต้องเก็บ credential ระยะยาว
SMOKE_URLVariableEnvironment (ไม่บังคับ)deploy-*เช่น https://dhammaverse.mbu.ac.th/api/health
GITHUB_TOKENSecret อัตโนมัติ—buildpush ไป ghcr.io (ไม่ต้องตั้งเพิ่ม)

คีย์ LLM (Typhoon/อื่น ๆ) ไม่อยู่ใน GitHub — มหาวิทยาลัยใส่เองใน Kubernetes Secret mbu-buddhist-ai-secrets ของแต่ละ namespace (TOR 4.6.1)

6. Artifacts

ArtifactJobเนื้อหาเก็บ
coverage-reporttestcoverage/ (text-summary, json-summary, HTML)14 วัน
security-reportssecurityvulnerability-scan-report.md, pentest-report.md, dev-server.log30 วัน
playwright-reporte2eplaywright-report/, test-results/ (รวม e2e-results.json)14 วัน

7. กลไกการย้อนกลับ (Rollback)

ระดับกลไก
อัตโนมัติขณะ deployhelm upgrade --atomic --wait — pod ไม่พร้อมภายใน timeout หรือ upgrade ล้มเหลว Helm ย้อน revision เดิมให้ (ติดตั้งครั้งแรกจะถอนการติดตั้ง)
อัตโนมัติหลัง deploystep “Rollback (helm rollback) on failure” ย้อนไป revision ที่บันทึกก่อน deploy เมื่อ smoke test ล้มเหลวหรือ release ไม่อยู่สถานะ deployed
ด้วยมือhelm history mbu-buddhist-ai -n <ns> → helm rollback mbu-buddhist-ai <rev> -n <ns> --wait (เก็บ 10 revision) หรือ re-run pipeline ของ tag/commit ก่อนหน้า (image tag = commit SHA/ชื่อ tag จึงย้อนเวอร์ชันได้แน่นอน)
ระดับการตั้งค่าในแอปsnapshot ของ AI config และเวอร์ชัน prompt ย้อนกลับได้ทันทีโดยไม่ต้อง deploy
ระดับข้อมูลกู้คืนจากไฟล์สำรอง (/documents/backup-restore-guide) เมื่อ migration ทำให้ข้อมูลเสีย

8. ข้อสังเกตจากการตรวจ repository (ต้องดำเนินการก่อนเปิดใช้ pipeline จริง)

#ประเด็นผลกระทบแนวทาง
1step Pentest-lite เรียก scripts/security/pentest-lite.ts แต่ ไม่มีไฟล์นี้ใน repository (scripts/security/ มีเพียง lib.ts, npm-audit-report.ts) — สอดคล้องกับที่การทดสอบเจาะระบบไม่ได้ดำเนินการในรอบนี้ตามคำสั่งของผู้ว่าจ้างjob security จะล้มเหลวที่ step นี้ และหยุด job ถัดไปจัดทำสคริปต์ทดสอบความปลอดภัยอัตโนมัติก่อนเปิดใช้ หรือนำ step ออก/ตั้ง continue-on-error ชั่วคราวพร้อมบันทึกเหตุผล
2step Build & push images อ้าง services/<svc>/Dockerfile ซึ่ง ยังไม่มี (ระบบสาธิตเป็น Next.js แอปเดียว)เมื่อตั้ง DEPLOY_ENABLED=true งาน build จะล้มเหลวแยก service และเพิ่ม Dockerfile ตาม /documents/deployment-guide หัวข้อ 5.5 (หรือเริ่มจาก image แอปเดียว)
3job test ไม่ได้ตั้ง OPENAPI_COVERAGE=1ชั้น runtime ของ openapi-coverage ไม่ทำงานใน CIเปลี่ยน step เป็น npm run test:coverage
4Prisma datasource ยังเป็น SQLiteprisma migrate deploy บน Production (PostgreSQL) ยังใช้ไม่ได้สร้าง migration สำหรับ PostgreSQL ก่อน deploy production
5ยังไม่มี step migrate ฐานข้อมูลใน deploy-*schema ไม่อัปเดตอัตโนมัติเพิ่ม Helm hook/Job prisma migrate deploy ก่อนอัปเกรด

9. วิธีเปิดใช้งาน (สรุป)

  1. push repository ไปยัง GitHub ขององค์กรมหาวิทยาลัย และตั้ง branch protection (main, develop) ให้ต้องผ่าน workflow ก่อน merge
  2. แก้ข้อสังเกตในหัวข้อ 8
  3. สร้าง environments dev, test, prod พร้อม secret KUBE_CONFIG (หรือ OIDC) และ variable SMOKE_URL; ตั้ง Required reviewers ที่ prod
  4. เตรียมคลัสเตอร์/Secret/DNS ตาม /documents/deployment-guide
  5. ตั้ง repository variable DEPLOY_ENABLED = "true"
  6. ทดสอบลำดับ: push develop → ตรวจ mbu-dev; สร้าง release/x.y → UAT บน mbu-test; merge เข้า main แล้วสร้าง tag vX.Y.Z → อนุมัติ → mbu-prod
  7. ทดลอง rollback โดยจงใจให้ smoke test ล้มเหลวบน mbu-dev อย่างน้อย 1 ครั้งและบันทึกผล

10. การตรวจไฟล์ pipeline ในเครื่อง

npx vitest run tests/unit/infra-yaml.test.ts     # parse YAML + ตรวจโครงสร้าง workflow และ Helm chart
# ถ้ามี helm ในเครื่อง
for e in dev test prod; do helm lint infra/helm/mbu-buddhist-ai -f infra/helm/mbu-buddhist-ai/values.yaml -f infra/helm/mbu-buddhist-ai/values-$e.yaml; done