CI/CD Pipeline คืออะไร? สอน DevOps ตั้งแต่ GitHub Actions Jenkins GitLab CI จนถึง Deploy อัตโนมัติ 2026

· tech · 3400 words
CI/CD Pipeline คืออะไร? สอน DevOps ตั้งแต่ GitHub Actions Jenkins GitLab CI จนถึง Deploy อัตโนมัติ 2026

ในโลกของการพัฒนาซอฟต์แวร์สมัยใหม่ การส่งมอบแอปพลิเคชันที่มีคุณภาพสูงอย่างรวดเร็วและต่อเนื่องเป็นสิ่งที่ทุกองค์กรต้องการ CI/CD Pipeline คือหัวใจสำคัญของ DevOps ที่ช่วยให้ทีมพัฒนาสามารถ Build Test และ Deploy แอปพลิเคชันได้แบบอัตโนมัติ ลดความผิดพลาดจากการทำด้วยมือ และเร่งความเร็วในการส่งมอบซอฟต์แวร์ บทความนี้จะพาคุณเรียนรู้ CI/CD อย่างครบถ้วนตั้งแต่แนวคิดพื้นฐานจนถึงการนำไปใช้งานจริงกับเครื่องมือยอดนิยม

CI/CD คืออะไร?

CI/CD เป็นคำย่อที่รวมสามแนวคิดสำคัญเข้าด้วยกัน ได้แก่ Continuous Integration (CI) Continuous Delivery (CD) และ Continuous Deployment (CD) แต่ละแนวคิดมีความหมายและจุดประสงค์ที่แตกต่างกัน แต่ทำงานร่วมกันเป็นกระบวนการต่อเนื่อง

Continuous Integration (CI)

Continuous Integration คือแนวปฏิบัติที่นักพัฒนาทุกคนในทีม Merge โค้ดของตัวเองเข้ากับ Repository หลักอย่างสม่ำเสมอ (อย่างน้อยวันละครั้ง) ทุกครั้งที่ Merge จะมีการ Build และ Test อัตโนมัติเพื่อตรวจจับข้อผิดพลาดให้เร็วที่สุด แนวคิดนี้เกิดจากปัญหา "Integration Hell" ในอดีตที่แต่ละคนพัฒนาโค้ดแยกกันเป็นเวลานาน แล้วพอมารวมกันก็เกิด Conflict มากมาย CI แก้ปัญหานี้ด้วยการ Integrate บ่อยๆ ทำให้ปัญหาถูกพบเร็วและแก้ไขง่าย

Continuous Delivery (CD)

Continuous Delivery เป็นการต่อยอดจาก CI โดยทำให้โค้ดที่ผ่านการ Test แล้วพร้อมที่จะ Deploy ไปยัง Production ได้ตลอดเวลา ทุกการเปลี่ยนแปลงจะผ่าน Pipeline อัตโนมัติที่ครอบคลุม Build Test และ Staging Deployment แต่การ Deploy ไปยัง Production ยังต้องได้รับการอนุมัติจากคน (Manual Approval) ก่อน ทำให้ทีมมีความมั่นใจว่าสามารถ Deploy ได้ทุกเมื่อที่ต้องการ

Continuous Deployment (CD)

Continuous Deployment เป็นขั้นสูงสุดของ CI/CD ทุกการเปลี่ยนแปลงที่ผ่าน Pipeline ทั้งหมดจะถูก Deploy ไปยัง Production โดยอัตโนมัติ ไม่ต้องมีการอนุมัติจากคน ต้องมีระบบ Test ที่ครอบคลุมและน่าเชื่อถือมาก รวมถึงระบบ Monitoring และ Rollback อัตโนมัติ องค์กรระดับโลกเช่น Netflix Amazon และ Google ใช้แนวทางนี้ ทำให้สามารถ Deploy ได้หลายร้อยถึงหลายพันครั้งต่อวัน

ทำไม CI/CD ถึงสำคัญ

CI/CD เป็นหัวใจของวัฒนธรรม DevOps ที่รวม Development และ Operations เข้าด้วยกัน ความสำคัญของ CI/CD มีหลายมิติ

เพิ่มความเร็วในการ Release - จากเดิมที่อาจ Release ทุก 3-6 เดือน CI/CD ช่วยให้ Release ได้ทุกสัปดาห์หรือทุกวัน ทำให้ส่งมอบ Feature ใหม่ให้ผู้ใช้ได้เร็วขึ้น ตอบสนองต่อ Feedback ได้ทันที และแข่งขันในตลาดได้ดีขึ้น

ลดความเสี่ยง - การ Deploy บ่อยๆ ด้วยการเปลี่ยนแปลงเล็กๆ มีความเสี่ยงน้อยกว่าการ Deploy ครั้งใหญ่ที่มีการเปลี่ยนแปลงมาก ถ้ามีปัญหาก็หาสาเหตุได้ง่ายและแก้ไขได้เร็ว

เพิ่มคุณภาพ - Automated Testing ทุกขั้นตอนทำให้มั่นใจว่าโค้ดที่ Deploy ผ่านการทดสอบอย่างละเอียด ลดโอกาสที่ Bug จะหลุดไปถึง Production

ลดงาน Manual - การทำทุกอย่างอัตโนมัติช่วยลดเวลาที่นักพัฒนาต้องใช้ในการ Build Test และ Deploy ด้วยมือ ทำให้มีเวลามากขึ้นในการเขียนโค้ดและพัฒนาฟีเจอร์ใหม่

Feedback Loop ที่เร็วขึ้น - นักพัฒนาจะรู้ผลลัพธ์ภายในไม่กี่นาทีว่าโค้ดที่เขียนมีปัญหาหรือไม่ ทำให้แก้ไขได้ทันทีขณะที่ยังจำบริบทของโค้ดอยู่ แทนที่จะต้องกลับมาแก้ปัญหาที่เขียนไว้เมื่อหลายสัปดาห์ก่อน

CI/CD Pipeline Stages

CI/CD Pipeline ทั่วไปประกอบด้วยหลายขั้นตอนที่ทำงานต่อเนื่องกัน

Source Stage - เริ่มต้นเมื่อมีการเปลี่ยนแปลงใน Source Code Repository เช่น Push โค้ดใหม่ สร้าง Pull Request หรือ Merge เข้า Main Branch ระบบ CI/CD จะตรวจจับการเปลี่ยนแปลงนี้และเริ่ม Pipeline อัตโนมัติ การใช้ Git Version Control อย่างถูกต้องจึงเป็นพื้นฐานสำคัญของ CI/CD

Build Stage - Compile โค้ด สร้าง Artifact เช่น JAR WAR Docker Image หรือ Binary ที่พร้อม Deploy ขั้นตอนนี้ยังรวมถึงการ Download Dependencies และ Resolve Libraries ต่างๆ

Test Stage - รัน Automated Tests หลายระดับเพื่อตรวจสอบคุณภาพของโค้ด ตั้งแต่ Unit Test Integration Test จนถึง End-to-End Test และ Security Scan ขั้นตอนนี้เป็นหัวใจของ Pipeline เพราะเป็นตัวกำหนดว่าโค้ดมีคุณภาพเพียงพอที่จะ Deploy หรือไม่

Deploy Stage - Deploy แอปพลิเคชันไปยัง Environment ต่างๆ ตามลำดับ เช่น Development Staging และ Production แต่ละ Environment มีจุดประสงค์ที่แตกต่างกัน Development สำหรับทดสอบระหว่างพัฒนา Staging สำหรับทดสอบก่อน Production และ Production สำหรับผู้ใช้จริง

GitHub Actions - CI/CD สำหรับทุกคน

GitHub Actions เป็นบริการ CI/CD ที่ Built-in มากับ GitHub ใช้ Workflow Files ในรูปแบบ YAML ที่เก็บใน Repository เดียวกับโค้ด ทำให้จัดการ Pipeline ได้ง่ายและเป็น Version Controlled

โครงสร้าง Workflow

GitHub Actions Workflow ประกอบด้วย Triggers (เมื่อไหร่ที่จะรัน) Jobs (งานที่ต้องทำ) Steps (ขั้นตอนภายใน Job) และ Actions (หน่วยงานที่ Reusable ได้) Workflow ไฟล์จะถูกเก็บไว้ใน .github/workflows/ directory

# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Run Linter
        run: npm run lint

      - name: Run Unit Tests
        run: npm test -- --coverage

      - name: Upload Coverage
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Login to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - name: Deploy to Production
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.DEPLOY_KEY }}
          script: |
            cd /app
            docker compose pull
            docker compose up -d --remove-orphans
            docker system prune -f

GitHub Actions Secrets

Secrets เป็นวิธีที่ปลอดภัยในการเก็บข้อมูลลับ เช่น API Keys Passwords และ SSH Keys ใน GitHub Actions สามารถตั้งค่าได้ที่ Repository Settings ข้อมูล Secrets จะถูก Encrypt และจะไม่ปรากฏใน Logs เด็ดขาด สามารถใช้ได้ทั้ง Repository Secrets และ Environment Secrets สำหรับ Environment ที่ต่างกัน เช่น staging และ production

Reusable Workflows

GitHub Actions รองรับ Reusable Workflows ที่สามารถแชร์ Workflow ระหว่าง Repositories ได้ ช่วยลดการเขียนโค้ดซ้ำซ้อนและทำให้ Pipeline มีมาตรฐานเดียวกันทั้งองค์กร สามารถ Publish เป็น Custom Actions ใน GitHub Marketplace ได้อีกด้วย

Jenkins - CI/CD Server ยอดนิยม

Jenkins เป็น Open Source CI/CD Server ที่ได้รับความนิยมมายาวนาน มี Plugin มากกว่า 1,800 ตัว รองรับเกือบทุก Technology Stack มีความยืดหยุ่นสูงแต่ต้องจัดการ Infrastructure เอง เหมาะสำหรับองค์กรที่ต้องการควบคุมทุกอย่างและมีทีม DevOps ดูแล

Jenkinsfile (Pipeline as Code)

Jenkins Pipeline สามารถเขียนเป็นโค้ดใน Jenkinsfile ซึ่งเก็บใน Repository ร่วมกับ Source Code ทำให้ Pipeline เป็น Version Controlled และ Review ได้เหมือนโค้ดทั่วไป Jenkinsfile มีสองรูปแบบคือ Declarative Pipeline (แนะนำ) และ Scripted Pipeline

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any

    environment {
        DOCKER_REGISTRY = 'registry.example.com'
        APP_NAME = 'my-web-app'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install Dependencies') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }

        stage('Test') {
            parallel {
                stage('Unit Tests') {
                    steps {
                        sh 'npm run test:unit'
                    }
                }
                stage('Integration Tests') {
                    steps {
                        sh 'npm run test:integration'
                    }
                }
            }
            post {
                always {
                    junit 'test-results/**/*.xml'
                    publishHTML(target: [
                        reportDir: 'coverage',
                        reportFiles: 'index.html',
                        reportName: 'Coverage Report'
                    ])
                }
            }
        }

        stage('Build Docker Image') {
            when { branch 'main' }
            steps {
                script {
                    def image = docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}")
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-creds') {
                        image.push()
                        image.push('latest')
                    }
                }
            }
        }

        stage('Deploy to Staging') {
            when { branch 'main' }
            steps {
                sh '''
                    kubectl set image deployment/${APP_NAME}                         ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}                         --namespace=staging
                    kubectl rollout status deployment/${APP_NAME} --namespace=staging
                '''
            }
        }

        stage('Deploy to Production') {
            when { branch 'main' }
            input {
                message 'Deploy to Production?'
                ok 'Yes, Deploy!'
            }
            steps {
                sh '''
                    kubectl set image deployment/${APP_NAME}                         ${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}                         --namespace=production
                    kubectl rollout status deployment/${APP_NAME} --namespace=production
                '''
            }
        }
    }

    post {
        success {
            slackSend(channel: '#deployments', message: "SUCCESS: ${APP_NAME} v${BUILD_NUMBER}")
        }
        failure {
            slackSend(channel: '#deployments', message: "FAILED: ${APP_NAME} v${BUILD_NUMBER}")
        }
    }
}

Jenkins Plugins ที่สำคัญ

Jenkins มี Plugin Ecosystem ที่ใหญ่มาก Plugin ที่สำคัญ ได้แก่ Blue Ocean (UI สมัยใหม่สำหรับ Pipeline) Docker Pipeline (Build และ Push Docker Images) Kubernetes Plugin (รัน Jenkins Agent บน K8s) Credentials Plugin (จัดการข้อมูลลับ) และ Pipeline Utility Steps (เครื่องมือเสริมสำหรับ Pipeline)

GitLab CI/CD

GitLab CI/CD เป็นระบบ CI/CD ที่ Built-in มากับ GitLab Platform ใช้ไฟล์ .gitlab-ci.yml ในการกำหนด Pipeline มีข้อได้เปรียบคือ Integration กับ GitLab ทุก Feature เช่น Issue Tracking Merge Request Container Registry และ Security Scanning ได้อย่างไร้รอยต่อ

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

# ── Test Stage ──
unit-test:
  stage: test
  image: node:20-alpine
  cache:
    key: $CI_COMMIT_REF_SLUG
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run lint
    - npm test -- --coverage
  coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      junit: test-results/junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

security-scan:
  stage: test
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker run --rm aquasec/trivy image $DOCKER_IMAGE
  allow_failure: true

# ── Build Stage ──
build-image:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  only:
    - main
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE -t $CI_REGISTRY_IMAGE:latest .
    - docker push $DOCKER_IMAGE
    - docker push $CI_REGISTRY_IMAGE:latest

# ── Deploy Stage ──
deploy-staging:
  stage: deploy
  image: bitnami/kubectl:latest
  only:
    - main
  environment:
    name: staging
    url: https://staging.example.com
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE --namespace=staging
    - kubectl rollout status deployment/app --namespace=staging

deploy-production:
  stage: deploy
  image: bitnami/kubectl:latest
  only:
    - main
  environment:
    name: production
    url: https://example.com
  when: manual
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE --namespace=production
    - kubectl rollout status deployment/app --namespace=production

GitLab Runners

GitLab Runner เป็น Agent ที่รัน CI/CD Jobs ให้ GitLab สามารถติดตั้งบนเครื่องของตัวเอง (Self-hosted) หรือใช้ Shared Runners ที่ GitLab.com มีให้ Runner มีหลาย Executor เช่น Shell Docker Kubernetes และ Virtual Machine ทำให้ยืดหยุ่นในการกำหนดสภาพแวดล้อมการรัน

Automated Testing ใน CI/CD

การทดสอบอัตโนมัติเป็นส่วนที่สำคัญที่สุดของ CI/CD Pipeline หากไม่มีการทดสอบที่ดี การ Deploy อัตโนมัติก็ไม่มีความหมาย เพราะอาจส่ง Bug ไปยัง Production ได้ การทดสอบแบ่งออกเป็นหลายระดับตาม Testing Pyramid

Unit Tests - ทดสอบหน่วยที่เล็กที่สุดของโค้ด เช่น Function หรือ Method ต้องรันเร็ว (มิลลิวินาที) ไม่พึ่งพาระบบภายนอก ควรครอบคลุม 70-80% ของโค้ด Unit Test เป็นฐานของ Testing Pyramid ควรมีมากที่สุด

Integration Tests - ทดสอบการทำงานร่วมกันระหว่าง Components เช่น API กับ Database Service กับ Service ใช้เวลารันนานกว่า Unit Test แต่ให้ความมั่นใจว่า Components ทำงานร่วมกันได้ถูกต้อง

End-to-End (E2E) Tests - ทดสอบทั้งระบบจากมุมมองของผู้ใช้ เช่น เปิดเบราว์เซอร์ กรอกฟอร์ม กดปุ่ม ตรวจผลลัพธ์ ใช้เครื่องมือเช่น Cypress Playwright หรือ Selenium ใช้เวลารันนานที่สุด ควรมีจำนวนไม่มากแต่ครอบคลุม Critical Path

Security Scanning - ตรวจหาช่องโหว่ด้านความปลอดภัยในโค้ดและ Dependencies เครื่องมือเช่น Trivy Snyk OWASP Dependency-Check SonarQube ช่วยตรวจจับ Vulnerabilities ก่อนที่จะ Deploy ไปยัง Production ควรเป็นส่วนหนึ่งของ Pipeline ทุก Pipeline

Performance Testing - ทดสอบประสิทธิภาพของแอปพลิเคชันภายใต้ Load ต่างๆ ใช้เครื่องมือเช่น k6 JMeter Locust เพื่อตรวจสอบว่าแอปพลิเคชันสามารถรองรับจำนวนผู้ใช้ที่คาดหวังได้

Deployment Strategies

การเลือก Deployment Strategy ที่เหมาะสมมีผลอย่างมากต่อ Downtime ความเสี่ยง และประสบการณ์ของผู้ใช้ แต่ละ Strategy มีข้อดีข้อเสียที่แตกต่างกัน

Rolling Update

Rolling Update เป็นวิธีที่ใช้บ่อยที่สุด โดยค่อยๆ แทนที่ Instance เก่าด้วย Instance ใหม่ทีละตัว ระหว่างการ Update จะมีทั้ง Version เก่าและใหม่ทำงานพร้อมกัน ข้อดีคือไม่มี Downtime และใช้ทรัพยากรเพิ่มเติมน้อย ข้อเสียคือระหว่าง Update ผู้ใช้อาจเห็นพฤติกรรมที่ไม่สม่ำเสมอเพราะใช้คนละ Version เป็น Default Strategy ของ Kubernetes Deployment

Blue-Green Deployment

Blue-Green Deployment มี Environment สองชุดที่เหมือนกันทุกประการ (Blue และ Green) ณ เวลาหนึ่ง จะมีเพียงชุดเดียวที่รับ Traffic จริง เมื่อต้องการ Deploy Version ใหม่ จะ Deploy ไปที่ Environment ที่ไม่ได้ใช้ ทดสอบให้เรียบร้อย แล้วสลับ Traffic ไป ถ้ามีปัญหาก็สลับกลับทันที ข้อดีคือ Zero Downtime และ Rollback เร็วมาก ข้อเสียคือใช้ทรัพยากรเป็นสองเท่า

Canary Deployment

Canary Deployment ค่อยๆ เปิดให้ผู้ใช้ส่วนน้อย (เช่น 5%) ใช้ Version ใหม่ก่อน Monitor ดูว่ามีปัญหาหรือไม่ ถ้าไม่มีก็ค่อยๆ เพิ่มเป็น 25% 50% 100% ข้อดีคือความเสี่ยงต่ำมาก สามารถทดสอบกับผู้ใช้จริงได้ ข้อเสียคือซับซ้อนในการตั้งค่าและต้องมี Traffic Management ที่ดี ใช้ร่วมกับ Service Mesh เช่น Istio หรือ Linkerd

Container-based CI/CD

การใช้ Container ใน CI/CD Pipeline ทำให้สภาพแวดล้อมการ Build และ Test สม่ำเสมอทุกครั้ง ไม่ว่าจะรันบนเครื่องใด ลดปัญหา "Works on my machine" ได้อย่างสมบูรณ์ เรียนรู้เพิ่มเติมเกี่ยวกับ Docker ได้ที่ Docker Container Guide

ใน Pipeline ที่ใช้ Container แต่ละ Step จะรันใน Container ที่กำหนด Image ไว้ เช่น Step ที่ Build Node.js App จะรันใน node Image Step ที่ Build Docker Image จะรันใน docker Image ทำให้แต่ละ Step มี Dependencies ที่ถูกต้องเสมอ

เมื่อใช้ร่วมกับ Kubernetes สามารถ Deploy Container ที่ Build จาก Pipeline ไปยัง K8s Cluster ได้โดยตรง ทำให้ได้ End-to-End Automation ตั้งแต่ Code Commit จนถึง Production Deployment

# Multi-stage Dockerfile สำหรับ CI/CD
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Stage 2: Test
FROM builder AS tester
RUN npm ci  # install dev dependencies too
RUN npm test

# Stage 3: Production
FROM node:20-alpine AS production
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/main.js"]

Infrastructure as Code (IaC)

Infrastructure as Code เป็นแนวปฏิบัติที่จัดการ Infrastructure ด้วยโค้ด แทนที่จะตั้งค่าด้วยมือผ่าน Console หรือ CLI ทำให้ Infrastructure เป็น Version Controlled Repeatable และ Testable เหมือนกับ Application Code

Terraform

Terraform พัฒนาโดย HashiCorp เป็นเครื่องมือ IaC ที่ใช้ HCL (HashiCorp Configuration Language) สามารถจัดการทรัพยากรบน Cloud Provider ทุกเจ้า เช่น AWS GCP Azure รวมถึง SaaS Services ต่างๆ Terraform ใช้แนวคิด Declarative คือกำหนดสถานะที่ต้องการ แล้ว Terraform จะจัดการให้ถึงสถานะนั้น

# Terraform - สร้าง Kubernetes Cluster บน AWS EKS
provider "aws" {
  region = "ap-southeast-1"
}

module "eks" {
  source          = "terraform-aws-modules/eks/aws"
  version         = "~> 20.0"
  cluster_name    = "my-app-cluster"
  cluster_version = "1.30"
  vpc_id          = module.vpc.vpc_id
  subnet_ids      = module.vpc.private_subnets

  eks_managed_node_groups = {
    default = {
      min_size     = 2
      max_size     = 10
      desired_size = 3
      instance_types = ["t3.medium"]
    }
  }
}

Ansible

Ansible เป็นเครื่องมือ Configuration Management ที่ใช้ YAML (Playbooks) ในการกำหนดค่าเซิร์ฟเวอร์ ไม่ต้องติดตั้ง Agent บนเครื่องเป้าหมาย ใช้ SSH ในการเชื่อมต่อ เรียนรู้เพิ่มเติมเกี่ยวกับ Linux System Administration เพื่อเข้าใจการจัดการเซิร์ฟเวอร์

Monitoring และ Observability

หลังจาก Deploy แล้ว การ Monitor แอปพลิเคชันและ Infrastructure เป็นสิ่งจำเป็น Observability ประกอบด้วยสามเสาหลัก คือ Logging Metrics และ Tracing

Logging - เก็บ Log จากทุก Component ในระบบ ใช้ Centralized Logging เช่น ELK Stack (Elasticsearch Logstash Kibana) หรือ Loki + Grafana เพื่อรวม Log จากทุกที่ไว้ที่เดียว ทำให้ค้นหาและวิเคราะห์ปัญหาได้ง่าย Structured Logging ในรูปแบบ JSON เป็นแนวปฏิบัติที่ดีเพราะ Parse ได้ง่าย

Metrics - เก็บตัวเลขที่บอกสถานะของระบบ เช่น CPU Usage Memory Usage Request Count Response Time Error Rate ใช้เครื่องมือเช่น Prometheus + Grafana สำหรับเก็บและแสดงผล Metrics ตั้ง Alerting Rules เพื่อแจ้งเตือนเมื่อมีค่าผิดปกติ

Distributed Tracing - ติดตาม Request ตั้งแต่เข้าระบบจนออก ผ่านทุก Service ที่เกี่ยวข้อง ช่วยหาว่า Bottleneck อยู่ที่ไหน Service ไหนใช้เวลานาน ใช้เครื่องมือเช่น Jaeger OpenTelemetry หรือ Zipkin มีประโยชน์มากในระบบ Microservices ที่มีหลาย Services ทำงานร่วมกัน

Post-deployment Monitoring - หลัง Deploy ทุกครั้ง ควร Monitor อย่างใกล้ชิด ดู Error Rate Response Time Latency ตั้ง Automated Rollback ถ้าค่า Metric เกิน Threshold ใช้ SLO (Service Level Objective) เป็นตัวกำหนดมาตรฐานคุณภาพ

Best Practices สำหรับ CI/CD

Pipeline as Code - เก็บ Pipeline Configuration ใน Repository เดียวกับ Source Code ทำให้ Pipeline เป็น Version Controlled สามารถ Review ผ่าน Pull Request ได้ และทุกคนในทีมเห็นและเข้าใจ Pipeline เหมือนกัน

Fast Feedback - Pipeline ควรให้ผลลัพธ์เร็วที่สุด ตั้งเป้าให้ CI Pipeline เสร็จภายใน 10 นาที ใช้ Parallel Testing Cache Dependencies และ Incremental Builds เพื่อเร่งความเร็ว ถ้า Pipeline ช้า นักพัฒนาจะไม่อยากรอและอาจข้าม Process

Trunk-based Development - ทุกคน Merge โค้ดเข้า Main Branch บ่อยๆ (อย่างน้อยวันละครั้ง) ใช้ Feature Flags แทน Long-lived Feature Branches ลด Merge Conflicts และทำให้ CI ทำงานได้อย่างมีประสิทธิภาพ

Environment Parity - ทำให้ทุก Environment (Development Staging Production) เหมือนกันมากที่สุด ใช้ Container และ IaC เพื่อให้มั่นใจว่า Environment ทุกตัวถูกสร้างจากโค้ดเดียวกัน ลดปัญหา "Works in staging but not in production"

Security First - ใส่ Security Scanning ใน Pipeline ตั้งแต่ต้น (Shift Left Security) ตรวจ Dependencies ที่มีช่องโหว่ สแกน Container Image ตรวจ Secrets ที่หลุดเข้ามาใน Code ใช้ Least Privilege Principle สำหรับ Service Accounts ที่ Pipeline ใช้

ข้อผิดพลาดที่พบบ่อย

Pipeline ที่ช้าเกินไป - Pipeline ที่ใช้เวลานานเกินไปทำให้นักพัฒนาหงุดหงิดและอาจข้าม CI/CD แก้โดย Parallel Testing Cache Dependencies เลือกรัน Test ที่เกี่ยวข้องกับการเปลี่ยนแปลงเท่านั้น และใช้ Incremental Build

Flaky Tests - Test ที่ผ่านบ้างไม่ผ่านบ้างโดยไม่มีเหตุผล ทำให้เสียความเชื่อมั่นใน Pipeline ต้องจัดการ Flaky Tests อย่างจริงจัง ไม่ว่าจะเป็นการแก้ไขหรือย้ายไปรันแยก อย่าปล่อยให้ Flaky Tests สะสมจนไม่มีใครสนใจผลลัพธ์ของ Pipeline

ไม่มี Rollback Plan - ทุก Deployment ควรมีแผน Rollback ที่ชัดเจนและทดสอบแล้ว ไม่ว่าจะเป็น kubectl rollout undo การสลับ Blue-Green หรือการ Revert Git Commit สิ่งสำคัญคือต้องซ้อม Rollback เป็นประจำ ไม่ใช่แค่มีแผนแต่ไม่เคยทดสอบ

Hardcoded Secrets ใน Pipeline - ไม่ควรฝัง Password API Key หรือข้อมูลลับใดๆ ใน Pipeline Code ใช้ Secret Management ของ CI/CD Tool เช่น GitHub Secrets Jenkins Credentials GitLab CI Variables แทน

ไม่มี Monitoring หลัง Deploy - Deploy แล้วจบไม่ใช่วิธีที่ดี ต้องมี Post-deployment Monitoring เพื่อตรวจจับปัญหาที่อาจเกิดขึ้นหลัง Deploy เช่น Memory Leak Performance Degradation หรือ Error ที่เกิดจาก Edge Case

คำถามที่พบบ่อย (FAQ)

CI/CD ต่างจาก DevOps อย่างไร?

DevOps เป็นวัฒนธรรมและแนวปฏิบัติที่ครอบคลุมกว้างกว่า รวมถึงการทำงานร่วมกันระหว่าง Dev และ Ops การ Automate ทุกอย่าง Monitoring และอื่นๆ ส่วน CI/CD เป็นส่วนหนึ่งของ DevOps ที่เน้นเรื่องการ Build Test และ Deploy อัตโนมัติ

ควรเริ่มต้น CI/CD อย่างไร?

เริ่มจากง่ายๆ ก่อน เขียน Unit Test สำหรับโค้ดที่มีอยู่ ตั้ง CI Pipeline ที่รัน Test อัตโนมัติทุกครั้งที่ Push โค้ด จากนั้นค่อยเพิ่ม Stage ทีละขั้น เช่น Build Docker Image Deploy to Staging และ Deploy to Production ไม่ต้องพยายามทำทุกอย่างพร้อมกันตั้งแต่ต้น

GitHub Actions vs Jenkins vs GitLab CI เลือกตัวไหนดี?

ขึ้นอยู่กับบริบท ถ้าใช้ GitHub อยู่แล้วก็เริ่มด้วย GitHub Actions เพราะ Integration ดีและฟรีสำหรับ Public Repos ถ้าต้องการความยืดหยุ่นสูงสุดและมีทีม DevOps ดูแลก็ใช้ Jenkins ถ้าใช้ GitLab อยู่แล้วก็ใช้ GitLab CI เพราะทุกอย่างอยู่ในที่เดียว

CI/CD จำเป็นต้องใช้ Container หรือไม่?

ไม่จำเป็น แต่แนะนำอย่างยิ่ง Container ช่วยให้สภาพแวดล้อมการ Build สม่ำเสมอ ไม่ขึ้นกับเครื่องที่รัน ถ้ายังไม่พร้อมใช้ Container ก็เริ่มด้วยการรัน Pipeline บน VM หรือ Bare Metal ก่อนได้

ต้องมี Test Coverage เท่าไหร่จึงจะ Deploy อัตโนมัติได้?

ไม่มีตัวเลขที่ตายตัว แต่โดยทั่วไปควรมี Coverage อย่างน้อย 70-80% สำหรับ Unit Test และมี Integration Test ที่ครอบคลุม Critical Path ทั้งหมด สิ่งสำคัญกว่า Coverage คือคุณภาพของ Test ต้องทดสอบ Business Logic ที่สำคัญจริงๆ ไม่ใช่แค่เพิ่ม Coverage Number

สรุป

CI/CD Pipeline เป็นพื้นฐานที่ขาดไม่ได้ของการพัฒนาซอฟต์แวร์สมัยใหม่ ช่วยให้ทีมส่งมอบซอฟต์แวร์ที่มีคุณภาพได้อย่างรวดเร็วและต่อเนื่อง ไม่ว่าจะเลือกใช้ GitHub Actions Jenkins หรือ GitLab CI หัวใจสำคัญอยู่ที่การ Automate ทุกขั้นตอนตั้งแต่ Build Test จนถึง Deploy และ Monitor เริ่มต้นด้วย Pipeline ที่เรียบง่าย แล้วค่อยๆ เพิ่มความซับซ้อนตามความต้องการ สิ่งสำคัญคือการเริ่มทำตั้งแต่วันนี้ เพราะ CI/CD ไม่ใช่เรื่องของอนาคต แต่เป็นมาตรฐานของปัจจุบัน