แผนการเรียนรู้
/

สัปดาห์ที่ 6: บทนำสู่ Continuous Integration (CI)

เปลี่ยนการรวมโค้ดที่ยุ่งยากให้เป็นเรื่องอัตโนมัติ เพื่อคุณภาพซอฟต์แวร์ที่ดียิ่งขึ้น

หัวข้อ

  • Theory: Continuous Integration (CI) คืออะไร? ประโยชน์และแนวปฏิบัติ
  • Process: ขั้นตอนหลักของ CI (Build, Test, Static Analysis)
  • Tools: รู้จักเครื่องมือ CI ยอดนิยม (Jenkins, GitLab CI/CD, GitHub Actions)
  • Mechanism: การใช้ Git Hooks เพื่อเริ่มกระบวนการ CI
DevOps Course: Week 6
devops loop

ปัญหาก่อนมี CI: "Integration Hell"

เมื่อ Developer หลายคนทำงานแยกกันเป็นเวลานาน แล้วมา "รวมร่าง" กันทีเดียวตอนจบ

💀 อาการที่พบ

  • Merge Conflicts มหาศาล แก้กันเป็นวัน
  • Bug โผล่ตอน Deploy (Works on my machine)
  • ไม่รู้ว่าโค้ดใครทำพัง
  • เสียเวลารอ Feedback นานเกินไป
🔥

Continuous Integration (CI) คืออะไร?

แนวปฏิบัติในการพัฒนาซอฟต์แวร์ที่นักพัฒนาจะทำการ รวมโค้ด (Merge) เข้าสู่ Shared Repository บ่อยๆ (อย่างน้อยวันละครั้ง)

หัวใจสำคัญของ CI :

  • Automated Build: ทุกการ Merge ต้องถูก Build โดยอัตโนมัติ
  • Automated Test: ต้องผ่านการทดสอบ (Unit/Integration Test) ทันที
  • Fast Feedback: รู้ผลทันทีว่าผ่านหรือพัง ผ่าน Dashboard หรือ Notification

วงจรการทำงานของ CI (Workflow)

👨‍💻

1. Code

Dev commits code to Git

⚙️

2. Build

CI Server compiles code

🧪

3. Test

Run automated tests & Static Analysis

📊

4. Report

Pass/Fail Notification

ประโยชน์ของการทำ CI

🐛

Detect Bugs Early

เจอ Bug ทันทีที่ commit ไม่ต้องรอไปเจอตอน production

📉

Reduce Integration Risk

การรวมโค้ดทีละนิดบ่อยๆ ง่ายกว่าการรวมก้อนใหญ่ทีเดียว

🚀

Faster Delivery

เมื่อกระบวนการทดสอบเป็นอัตโนมัติ เราก็ปล่อยของได้เร็วขึ้น

🤝

Better Communication

ทีมสื่อสารกันผ่านโค้ดและการแจ้งเตือน ลดความสับสน

องค์ประกอบสำคัญ (Key Elements)

การทำ CI ไม่ใช่แค่การลงเครื่องมือ แต่ต้องมีองค์ประกอบเหล่านี้

1. Version Control System (VCS)

ต้องมีศูนย์กลางเก็บโค้ด เช่น Git (GitHub, GitLab, Bitbucket) เพื่อจัดการ Source Code

2. Automated Build

สคริปต์ที่สามารถ Compile, Link, หรือ Package โค้ดได้ด้วยคำสั่งเดียว (เช่น npm build, docker build)

3. Automated Testing

สิ่งที่ขาดไม่ได้! ถ้าไม่มี Test ก็ไม่ใช่ CI (Unit Test, Integration Test)

แนวปฏิบัติที่ดี (CI Best Practices)

  • Commit Early, Commit Often: อย่าดองโค้ดไว้นาน ให้ commit บ่อยๆ เพื่อให้ CI ทำงาน
  • Don't Commit Broken Code: รัน Test ในเครื่องตัวเอง (Local) ให้ผ่านก่อน Push
  • Fix Broken Build Immediately: ถ้า CI แดง (Fail) ต้องรีบแก้ทันที เป็น Priority สูงสุด
  • Keep the Build Fast: กระบวนการ CI ไม่ควรนานเกินไป (เช่น ไม่ควรเกิน 10-15 นาที) เพื่อให้ Feedback เร็ว
  • Build in a Clean Environment: ทุก Build ควรเริ่มจากสภาพแวดล้อมที่สะอาด (Clean Slate) เพื่อป้องกัน "Works on my machine"

ขั้นตอนที่ 1: Build (การประกอบร่าง)

เป้าหมาย: เปลี่ยน Source Code ให้เป็น Executable Artifact ที่พร้อมรัน

กิจกรรมหลัก:

  • Compile Code (สำหรับภาษาอย่าง Java, C++, Go)
  • Resolve Dependencies (npm install, pip install)
  • Package Application (สร้าง JAR, WAR, หรือ Docker Image)

$ npm install

$ npm run build

... Creating optimized production build ...

$ docker build -t my-app:v1 .

ขั้นตอนที่ 2: Automated Testing

กระดูกสันหลังของ CI คือการทดสอบอัตโนมัติ เพื่อรับประกันคุณภาพ

E2E Tests (Slow/Expensive)
Integration Tests
Unit Tests (Fast/Cheap)

Unit Tests: ทดสอบฟังก์ชันย่อยๆ แยกกัน (ควรมีเยอะที่สุด)

Integration Tests: ทดสอบการทำงานร่วมกันระหว่าง Module/Database

*CI Server จะรัน Test เหล่านี้ทุกครั้ง ถ้า Test ไม่ผ่าน = Build Failed (ห้าม Merge!)

ขั้นตอนที่ 3: Static Analysis

การตรวจสอบโค้ดโดยไม่ต้องรันโปรแกรม (Code Quality & Security)

Code Style (Linting)

ตรวจสอบรูปแบบการเขียนโค้ดให้เป็นมาตรฐานเดียวกัน (เช่น ESLint, Pylint)

Bug Detection

ค้นหาจุดที่อาจก่อให้เกิด Bug เช่น ตัวแปรที่ไม่ได้ใช้, Infinite Loop

Security Scanning (SAST)

ค้นหาช่องโหว่ความปลอดภัยเบื้องต้นในโค้ด (เช่น Hardcoded Password)

Feedback Mechanism (การแจ้งผล)

CI ที่ดีต้องแจ้งผลเร็วและชัดเจน เพื่อให้ Developer แก้ไขได้ทันที

  • Dashboards: หน้าจอแสดงสถานะของทุก Build (เขียว/แดง)
  • Notifications: แจ้งเตือนผ่าน Email, Slack, หรือ Microsoft Teams
  • Pull Request Checks: บล็อกการ Merge ถ้า CI ยังไม่ผ่าน (GitHub Checks)
"Broken Build คือเรื่องปกติ แต่การปล่อยให้ Broken นานๆ คือปัญหา"

สรุปกระบวนการ CI

1. Dev Commit
➡️
2. CI Triggered
➡️
3. Build
➡️
4. Static Analysis
➡️
5. Test
➡️
6. Feedback

ถัดไปเราจะมาดู "เครื่องมือ" ที่ทำให้กระบวนการเหล่านี้เป็นจริง

เครื่องมือ CI ยอดนิยม (Popular Tools)

🤵

Jenkins

รุ่นเก๋า, Open Source, ปรับแต่งได้สูงมาก แต่ดูแลยาก

🐱

GitHub Actions

มาแรง, Integrate กับ GitHub แน่นปึ้ก, ฟรีสำหรับ Public Repo

🦊

GitLab CI

All-in-one platform, ดีเยี่ยมสำหรับองค์กรที่ใช้ GitLab, มี Auto DevOps

Jenkins: The Automation Server

จุดเด่น

  • Huge Ecosystem: มี Plugins เป็นพัน (1000+) รองรับเกือบทุก tool
  • Flexible: เขียน Pipeline เป็น Code (Groovy) ได้
  • Self-Hosted: ติดตั้งใน Server ตัวเองได้ (Privacy & Control)

ข้อสังเกต

  • Maintenance: ต้องดูแล Server เอง (Patch, Update)
  • UI: หน้าตาอาจดูเก่ากว่า tool สมัยใหม่
  • Complexity: การตั้งค่าอาจซับซ้อนสำหรับมือใหม่

GitLab CI/CD: Seamless Integration

เป็นส่วนหนึ่งของ GitLab ทำให้ Code และ Pipeline อยู่ที่เดียวกัน ไม่ต้อง setup แยก

  • .gitlab-ci.yml: กำหนด Pipeline ด้วยไฟล์ YAML ใน repo เลย
  • GitLab Runner: ตัวรัน Job ที่ติดตั้งง่าย รองรับ Docker
  • Auto DevOps: ตรวจจับและสร้าง Pipeline ให้อัตโนมัติ (สำหรับโปรเจกต์มาตรฐาน)

GitHub Actions: Workflow Automation

Automation Tool ที่มาพร้อมกับ GitHub ที่เราจะเน้นใน Lab นี้

Core Concepts

  • Workflow: กระบวนการอัตโนมัติ (ไฟล์ .yml ใน .github/workflows)
  • Event: ตัวกระตุ้น (เช่น push, pull_request)
  • Job: งานที่รันในเครื่องเดียวกัน (Runner)
  • Action: คำสั่งสำเร็จรูปที่คนอื่นเขียนไว้ให้ใช้ (Marketplace)

# .github/workflows/ci.yml

name:

CI Pipeline

on:

[push]

jobs:

  build-test:

    runs-on: ubuntu-latest

    steps:

      - uses: actions/checkout@v2

      - run: npm install

      - run: npm test

เปรียบเทียบเครื่องมือ (Comparison)

Feature Jenkins GitLab CI GitHub Actions
Hosting Self-hosted Cloud / Self-hosted Cloud / Self-hosted
Configuration Jenkinsfile (Groovy) YAML (.gitlab-ci.yml) YAML (Workflows)
Difficulty High (Setup/Plugins) Medium Low (Easy to start)
Ecosystem Massive Plugin Library Integrated in GitLab Huge Marketplace

Git Hooks: จุดเริ่มต้นของ Automation

Git Hooks คือสคริปต์ที่ Git จะเรียกใช้งาน (Fire) เมื่อมีเหตุการณ์สำคัญเกิดขึ้น เช่น ก่อน Commit หรือหลัง Push

Client-Side Hooks

  • pre-commit: รันก่อน commit (ใช้ตรวจ Lint, Format code)
  • commit-msg: ตรวจรูปแบบข้อความ commit

Server-Side Hooks

  • pre-receive: รันเมื่อ server ได้รับ push (ใช้ปฏิเสธการ push ที่ไม่ผ่านกฎ)
  • post-receive: รันหลัง push เสร็จ (ใช้ trigger CI server)

Local Automation: Pre-commit Hook

ป้องกัน "Bad Code" ไม่ให้เข้าสู่ Repo ตั้งแต่เครื่อง Developer

# .git/hooks/pre-commit

#!/bin/sh

echo "Running pre-commit checks..."


# Run Linter

npm run lint

if

[ $? -ne 0 ];

then

  echo "Lint failed! Commit rejected."

  exit 1 # Non-zero exit blocks the commit

fi

Tip: ใช้ framework อย่าง pre-commit หรือ husky (สำหรับ JS) จะจัดการง่ายกว่าเขียน shell script เอง

Webhooks: สะพานเชื่อมสู่ CI Server

Git Server (GitHub/GitLab) ส่งสัญญาณบอก CI Server ว่า "มีโค้ดใหม่มาแล้วนะ!"

🐱
GitHub

Event: Push

HTTP POST (Payload)
🤖
CI Server

Action: Start Build

Note: GitHub Actions ไม่ต้องตั้ง Webhook เอง เพราะมัน Integrated กันอยู่แล้ว แต่ถ้าใช้ Jenkins ต้องตั้งค่า Webhook ใน GitHub Repo setting

ภารกิจ: CI for Full-Stack App 🛠️

เราจะสร้าง Automated Pipeline ให้กับโปรเจกต์ Resume Hub ที่มีทั้ง Backend (Django) และ Frontend (React)

🎯 เป้าหมาย (Objectives)

  • Backend Pipeline: ติดตั้ง Dependencies, รัน Linter, และรัน Unit Tests ของ Django
  • Frontend Pipeline: ติดตั้ง Node Modules, Build Project, และตรวจสอบว่าไม่มี Error
  • Monorepo Strategy: ตั้งค่าให้ CI ทำงานแยกกัน (แก้ Frontend ไม่ต้องรัน Test Backend)

Step 1: Prepare Project

เตรียม Source Code จาก GitHub (Branch wk05)

# 1. ไปที่ GitHub และ Fork Repository นี้:

https://github.com/wichitpaulsombat/djrepo


# 2. Clone Repository ของคุณลงเครื่อง (เปลี่ยน YOUR_USER)

$ git clone -b wk05 https://github.com/YOUR_USER/djrepo.git

$ cd djrepo


# 3. ตรวจสอบโครงสร้างไฟล์ (ควรเจอ folder backend/ และ frontend/)

$ ls -F

backend/ frontend/ docker-compose.yaml ...

กลยุทธ์สำหรับ Monorepo

เนื่องจากเราเก็บโค้ดทั้ง 2 ส่วนไว้ใน Repo เดียว เราควรกำหนด Paths Filter เพื่อประหยัดทรัพยากร

Backend Workflow

ทำงานเมื่อมีการแก้ไขไฟล์ในโฟลเดอร์ backend/** เท่านั้น

Frontend Workflow

ทำงานเมื่อมีการแก้ไขไฟล์ในโฟลเดอร์ frontend/** เท่านั้น

👉 เราจะสร้างไฟล์ Workflow แยกกัน 2 ไฟล์: django.yml และ react.yml

Step 2: สร้าง Django Workflow (1/2)

สร้างไฟล์ .github/workflows/django.yml

name: Django CI

on:

  push:

    branches: [ "wk05" ]

    paths:

      - "backend/**" # ทำงานเฉพาะเมื่อแก้ backend

  pull_request:

    branches: [ "wk05" ]

    paths:

      - "backend/**"


jobs:

  build-test:

    runs-on: ubuntu-latest

    defaults:

      run:

        working-directory: ./backend # เข้าไปใน folder backend เสมอ

Step 2: เพิ่ม Steps (2/2)

ต่อจากไฟล์เดิม เพิ่มขั้นตอนการติดตั้งและทดสอบ

    steps:

    - uses: actions/checkout@v4


    - name: Set up Python

      uses: actions/setup-python@v5

      with:

        python-version: "3.11"


    - name: Install Dependencies

      run: |

        python -m pip install --upgrade pip

        pip install -r requirements.txt


    - name: Run Tests

      run: |

        python manage.py test

ℹ️ Note: เนื่องจากเรากำหนด defaults.run.working-directory ไว้แล้ว คำสั่ง pip และ manage.py จะรันในโฟลเดอร์ backend โดยอัตโนมัติ

Step 3: สร้าง React Workflow (1/2)

สร้างไฟล์ .github/workflows/react.yml

name: React CI

on:

  push:

    branches: [ "wk05" ]

    paths:

      - "frontend/**" # เฉพาะไฟล์ Frontend

  pull_request:

    branches: [ "wk05" ]

    paths:

      - "frontend/**"


jobs:

  build:

    runs-on: ubuntu-latest

    defaults:

      run:

        working-directory: ./frontend

Step 3: เพิ่ม Steps (2/2)

    steps:

    - uses: actions/checkout@v4


    - name: Set up Node.js

      uses: actions/setup-node@v4

      with:

        node-version: "18"

        cache: "npm"

        cache-dependency-path: frontend/package-lock.json


    - name: Install Dependencies

      run: npm ci


    - name: Build

      run: npm run build

      env:

        CI: false # ป้องกัน build fail จาก warning เล็กน้อย (Optional)

✨ Highlight: การใช้ cache: "npm" จะช่วยให้การติดตั้ง dependencies ในรอบถัดไปเร็วขึ้นมาก

Step 4: Commit และ Push

เมื่อสร้างไฟล์ Workflow ทั้งสองเสร็จแล้ว ให้ส่งขึ้น GitHub

# ตรวจสอบสถานะ

$ git status


# Add files

$ git add .github/workflows/


# Commit

$ git commit -m "Add CI pipelines for Backend and Frontend"


# Push to wk05 branch

$ git push origin wk05

Step 5: ตรวจสอบผลลัพธ์ (Verification)

1. เปิด GitHub Repository ของคุณ

2. ไปที่แท็บ Actions

3. คุณควรเห็น Workflows ทั้ง Django CI และ React CI กำลังทำงาน (หรือทำงานเสร็จแล้ว)

✅ Success

ถ้าโค้ดไม่มี Error ไฟจะเขียว

❌ Failure

ถ้า Build พัง หรือ Test ไม่ผ่าน

Step 6: ทดสอบ Path Filtering

ลองแก้ไขไฟล์เฉพาะส่วน Frontend เพื่อดูว่า Backend CI จะไม่ทำงาน

# แก้ไขไฟล์ Frontend เล็กน้อย

แก้ไข frontend/src/App.jsx (เช่นเปลี่ยนข้อความ)


$ git add frontend/src/App.jsx

$ git commit -m "Update frontend text"

$ git push origin wk05

👀 สังเกตที่แท็บ Actions: ควรจะมีแค่ React CI เท่านั้นที่ทำงาน ส่วน Django CI จะนิ่งสนิท (Skipped) นี่คือข้อดีของการทำ Path Filtering!

Advanced: เพิ่ม Linter (Optional)

เพิ่มคุณภาพโค้ดด้วยการตรวจจับ Syntax Error อัตโนมัติ

Django (flake8)

เพิ่มใน django.yml:

- name: Lint with flake8
  run: |
    pip install flake8
    # stop the build if there are Python syntax errors
    flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
              
React (ESLint)

เพิ่มใน react.yml (ก่อน build):

- name: Lint
  run: npm run lint
              

ความปลอดภัย: Branch Protection Rules

บังคับให้ CI ผ่านก่อน Merge (Best Practice)

1. ไปที่ Settings ของ Repository > Branches

2. คลิก Add branch protection rule

3. Branch name pattern: wk05 (หรือ main)

4. ติคถูกที่ Require status checks to pass before merging

5. ค้นหาและเลือก build-test (จาก Django) และ build (จาก React)

6. กด Create

ผลลัพธ์: ถ้าใครเปิด Pull Request เข้ามาแล้ว Test พัง ปุ่ม Merge จะกดไม่ได้! 🛡️

แก้ปัญหา (Troubleshooting)

Error: requirements.txt not found

สาเหตุ: ไม่ได้ตั้ง working-directory หรือ path ผิด

แก้: เช็ค defaults.run.working-directory: ./backend

Error: npm ci failed

สาเหตุ: ไม่มี package-lock.json ใน repo

แก้: รัน npm install ในเครื่องแล้ว push ไฟล์ lock ขึ้นไปก่อน

React Build Fail (Warnings)

สาเหตุ: React Treat Warnings as Errors ใน CI

แก้: เพิ่ม env CI: false ใน step build

🎉

Lab Complete!

คุณได้สร้างระบบ CI เต็มรูปแบบสำหรับ Modern Web Application แล้ว

Automated Testing & Building
Monorepo Optimized Workflow