CI/CD DevOps Automation

CI/CD Pipeline — ส่ง Code ขึ้น Production แบบอัตโนมัติCI/CD Pipeline — Shipping Code to Production Automatically

By Anirach Mingkhwan DevOps & Vibe Coding 2026 · 15 min read
CI/CD Pipeline — ส่ง Code ขึ้น Production แบบอัตโนมัติ
ในบทความนี้
  1. CI/CD คืออะไร?
  2. Pipeline คืออะไร?
  3. แต่ละขั้นตอนทำอะไรบ้าง?
  4. ตัวอย่าง Pipeline จริงด้วย GitHub Actions
  5. เครื่องมือ CI/CD ยอดนิยม
  6. Best Practices
  7. เปรียบเทียบ: ก่อน vs หลังใช้ CI/CD
  8. สรุป
In this post
  1. What is CI/CD?
  2. What is a Pipeline?
  3. What Does Each Stage Do?
  4. A Real Pipeline with GitHub Actions
  5. Popular CI/CD Tools
  6. Best Practices
  7. Compared: Before vs After CI/CD
  8. Summary

จากโพสต์ที่แล้วเราได้พูดถึง Git Branching ว่าแตก branch ยังไง merge กลับยังไง แล้วก็มี branching strategy แบบไหนบ้าง แต่พอ merge เสร็จแล้ว... แล้วยังไงต่อ?

ถ้าต้อง build เอง test เอง deploy เอง ทุกครั้งที่มี code ใหม่ มันก็เหนื่อยและเสี่ยงพลาดมาก ยิ่งทีมใหญ่ขึ้น deploy บ่อยขึ้น ยิ่งวุ่น

นี่คือที่มาของ CI/CD Pipeline — ระบบที่จัดการทุกอย่างตั้งแต่ code เข้า repo จนถึง deploy ขึ้น production ให้เราแบบอัตโนมัติ


CI/CD คืออะไร?

CI/CD ย่อมาจาก 2 คำที่ทำงานเสริมกัน — CI ทำให้ทีม integrate code ได้ถี่ขึ้นโดยไม่ "ตีกัน" ส่วน CD ทำให้ code ที่ผ่าน test แล้วถึงมือ user ได้เร็วที่สุด ทั้งสองรวมกันเปลี่ยน deployment จาก "เหตุการณ์ใหญ่น่ากลัว" เป็น "กิจวัตรธรรมดา":

CI — Continuous Integration

"รวม code บ่อยๆ ทดสอบอัตโนมัติทุกครั้ง"

หลักการคือ developer ทุกคนควร merge code เข้า main branch อย่างน้อยวันละครั้ง — ยิ่ง integrate บ่อย ยิ่งเจอ conflict เล็ก แก้ง่าย ถ้าปล่อยให้ branch แยกนานเป็นสัปดาห์ merge ทีเดียว conflict จะใหญ่มาก ทุกครั้งที่ push ระบบจะ:

  1. ดึง code มา build อัตโนมัติ
  2. รัน test ทั้งหมด
  3. แจ้งผลว่า ✅ ผ่าน หรือ ❌ ไม่ผ่าน

ถ้าไม่มี CI → developer push code → ไม่มีใครรู้ว่าพังจนกว่าจะไป deploy จริง 💀

CD — Continuous Delivery / Continuous Deployment

Continuous Delivery: code ที่ผ่าน test แล้ว พร้อม deploy ได้ทันที แต่ยังต้องกดปุ่ม deploy เอง เหมาะกับทีมที่ต้อง compliance review หรือต้องการ manual approval ก่อน release

Continuous Deployment: code ที่ผ่าน test แล้ว deploy ขึ้น production อัตโนมัติเลย ไม่ต้องกดอะไร — ทุก commit ที่ผ่าน pipeline จะถึงมือ user ทันที! Netflix, Facebook, Google ใช้แบบนี้ แต่ต้องมี test coverage สูงมากจึงจะ confident พอ

ทั้งสองแบบมีข้อดี — Delivery ปลอดภัยกว่า (มี human gate) ส่วน Deployment เร็วกว่า (feedback loop สั้นมาก) เลือกตาม risk tolerance ของทีมและ business

Continuous Integration
build + test อัตโนมัติ
→
Continuous Delivery
พร้อม deploy แต่กดเอง
→
Continuous Deployment
deploy อัตโนมัติ ไม่ต้องทำอะไร

Pipeline คืออะไร?

Pipeline คือลำดับขั้นตอนที่ทำงานต่อเนื่องกันอัตโนมัติ ตั้งแต่ code เข้า repo จนถึง deploy ขึ้น production ลองนึกภาพโรงงานผลิตรถยนต์: วัตถุดิบเข้า → ประกอบชิ้นส่วน → ตรวจสอบคุณภาพ → ทาสี → ส่งมอบ ถ้าชิ้นส่วนไม่ผ่านตรวจ สายพานหยุดทันที — ไม่ส่งของเสียถึงลูกค้า CI/CD pipeline ทำเหมือนกัน:

Source
code
→
Build
compile
→
Test
verify
→
Stage
preview
→
Deploy
prod

ถ้าขั้นตอนใด fail → pipeline หยุดทันที → แจ้ง developer → ไม่มี code พังหลุดไป production


แต่ละขั้นตอนทำอะไรบ้าง?

Pipeline ทั่วไปมี 5 ขั้นตอน — แต่ละขั้นตอนทำหน้าที่เฉพาะและเป็น "quality gate" ที่ต้องผ่านก่อนไปขั้นถัดไป ยิ่ง pipeline มี gate เยอะ ยิ่งมั่นใจว่า code ที่ถึง production มีคุณภาพ:

1. Source — รับ Code เข้ามา

Pipeline เริ่มทำงานเมื่อมี trigger event — ส่วนใหญ่คือ git push แต่สามารถตั้งได้หลายแบบ ยิ่ง trigger อัตโนมัติมากเท่าไหร่ developer ยิ่งไม่ต้องจำว่า "ต้องทำอะไรก่อน deploy":

  • Push code ขึ้น branch
  • เปิด Pull Request
  • Merge เข้า main
  • ตั้งเวลา (cron schedule)
# ตัวอย่าง GitHub Actions trigger
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

2. Build — สร้างโปรเจกต์

ขั้นตอน Build คือการ compile code, ติดตั้ง dependencies, และสร้าง artifacts (เช่น Docker image, JAR file, JS bundle) ที่พร้อม deploy ถ้า build fail แสดงว่า code มีปัญหาพื้นฐาน (syntax error, missing dependency) ต้องแก้ก่อน ตัวอย่างสิ่งที่เกิดขึ้น:

  • npm install → ติดตั้ง packages
  • npm run build → compile TypeScript, bundle React, etc.
  • สร้าง Docker image
  • สร้าง artifact (.jar, .whl, binary)
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run build

ถ้า build fail → มักเป็นเพราะ:

  • Syntax error
  • Missing dependency
  • Version conflict

3. Test — ทดสอบ

ขั้นตอนสำคัญที่สุด — ถ้าไม่มี test ก็ไม่ต่างจากการ deploy แบบลุ้นดวง 🎲 automated tests จะรันทุกครั้งที่มี push โดยไม่ต้องพึ่ง "ความขยัน" ของ developer ถ้า test fail → pipeline หยุด → code ไม่หลุดไป production

ระดับของ Test:

ระดับทดสอบอะไรความเร็วตัวอย่าง
Unit Testฟังก์ชันเดี่ยวๆเร็วมาก (วินาที)calculate(2,3) ต้องได้ 5
Integration Testหลายส่วนทำงานร่วมกันปานกลางAPI + Database
E2E Testทั้งระบบจากมุม userช้า (นาที)กด Login → เห็น Dashboard
- run: npm test          # Unit tests
- run: npm run test:e2e  # E2E tests
- run: npm run lint      # Code style check
- run: npm audit         # Security check

Testing Pyramid:

E2E Tests น้อย แต่ครอบคลุม
Integration Tests ปานกลาง
Unit Tests เยอะที่สุด เร็วที่สุด

4. Stage — Preview ก่อน Deploy จริง

Staging คือ environment ที่เหมือน production ทุกอย่าง (same config, same data structure, same infrastructure) แต่ยังไม่ใช่ของจริง — เป็น "ซ้อมรบ" ก่อนรบจริง ช่วยเจอปัญหาที่ test อัตโนมัติจับไม่ได้ เช่น performance issues, UI bugs, integration problems:

ประโยชน์:

  • ทดสอบกับ data ที่เหมือนจริง
  • ให้ QA team หรือ PM มา review ได้
  • ตรวจจับปัญหาที่ test อัตโนมัติจับไม่ได้

5. Deploy — ขึ้น Production

ขั้นตอนสุดท้าย — code ไปถึงมือ user จริงๆ! วิธี deploy มีหลายแบบ แต่ละแบบมี trade-off ด้าน risk, speed, และ complexity การเลือกวิธีที่เหมาะสมขึ้นอยู่กับ business requirements:

วิธี deploy ที่นิยม:

Rolling Update

Rolling Update
Server 1:
v1
→
v2
✅
Server 2:
v1
→
v2
✅ (ทีละเครื่อง)
Server 3:
v1
→
v2
✅

Blue-Green Deployment

Before Switch
Blue (v1):
← traffic อยู่ที่นี่
Green (v2):
deploy ใหม่ที่นี่
After Switch
Blue (v1):
standby
Green (v2):
← traffic มาที่นี่แล้ว ✅

Canary Deployment

Phase 1 — ทดสอบ
v1 (90%):
90%
v2 (10%):
10%
← ทดสอบกับ user จริงส่วนน้อย
Phase 2 — ค่อยๆเพิ่ม
v1 (50%):
50%
v2 (50%):
50%
Phase 3 — เสร็จสมบูรณ์
v2 (100%):
100% ✅

ตัวอย่าง Pipeline จริงด้วย GitHub Actions

มาดู pipeline จริงที่ใช้ GitHub Actions — CI/CD tool ที่ built-in มากับ GitHub ฟรี แค่สร้างไฟล์ YAML ใน .github/workflows/ ก็ได้ pipeline อัตโนมัติ ตัวอย่างด้านล่างครอบคลุมทั้ง build, test, deploy:

name: CI/CD Pipeline

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

jobs:
  # ===== CI =====
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Build
        run: npm run build

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

      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  # ===== CD =====
  deploy:
    needs: build-and-test    # รอ CI ผ่านก่อน
    if: github.ref == 'refs/heads/main'  # deploy เฉพาะ main
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Deploy to production
        run: |
          echo "Deploying to production..."
          # คำสั่ง deploy จริงๆ เช่น:
          # ssh user@server 'cd /app && git pull && npm ci && pm2 restart all'
          # หรือ docker push + kubectl apply

เครื่องมือ CI/CD ยอดนิยม

มี CI/CD tools หลายตัว — แต่ละตัวเด่นคนละด้าน GitHub Actions (ง่าย, ฟรีสำหรับ public repos), GitLab CI (ครบจบในที่เดียว), Jenkins (flexible สุด แต่ต้อง maintain เอง), CircleCI (เร็ว, cloud-native) เลือกตามทีมและ ecosystem:

เครื่องมือประเภทจุดเด่นเหมาะกับ
GitHub ActionsCloudใช้ง่าย, ฟรีสำหรับ public repoโปรเจกต์บน GitHub
GitLab CI/CDCloud/Self-hostedPipeline ดี, มี container registryองค์กรที่ใช้ GitLab
JenkinsSelf-hostedPlugin เยอะ, ปรับแต่งได้มากองค์กรใหญ่
CircleCICloudเร็ว, config ง่ายStartup/ทีมเล็ก
ArgoCDSelf-hostedGitOps สำหรับ Kubernetesทีมที่ใช้ K8s

Best Practices

มี pipeline ดีไม่พอ — ต้อง "ดูแล" pipeline ด้วย เหมือนรถยนต์ที่ต้อง service ประจำ ถ้าปล่อยให้ pipeline ช้า, test ไม่ครอบคลุม, หรือ secrets hardcode สุดท้าย pipeline จะกลายเป็นภาระแทนที่จะช่วย:

1. Keep Pipeline Fast ⚡

Pipeline ที่ช้าเกินไป developer จะไม่อยากรอ → เริ่มข้าม CI → ค่อยๆ เลิกใช้ → เสียประโยชน์ทั้งหมด ทำให้เร็วด้วย: parallel jobs, caching dependencies, เลือกรันเฉพาะ test ที่เกี่ยวข้อง, ใช้ incremental builds

เป้าหมาย:

  • Build + Unit Test: < 5 นาที
  • ทั้ง pipeline: < 15 นาที
เคล็ดลับ: cache dependencies, รัน test แบบ parallel, แยก slow test ออก

2. Test ให้ครอบคลุม 🧪

Test coverage ต่ำ = pipeline ที่ให้ความมั่นใจเทียม — code ผ่าน pipeline แต่พังใน production ตั้งเป้า coverage 80%+ และเขียน tests ตาม Testing Pyramid:

  • ตั้งเป้า code coverage > 80%
  • มี unit test สำหรับ business logic ที่สำคัญ
  • อย่าลืม edge case และ error handling

3. Fail Fast, Fix Fast 🔴

เรียง pipeline จากเร็วไปช้า (lint → unit test → integration → E2E) เพื่อให้ fail เร็วที่สุด ถ้า lint fail ใน 10 วินาทีดีกว่ารอ E2E test 15 นาทีแล้ว fail เมื่อ fail แล้วต้องแก้ทันที — อย่าปล่อยให้ pipeline แดงค้าง:

  • ถ้า pipeline fail → แก้เป็นอันดับแรก ก่อนทำอย่างอื่น
  • อย่าปล่อยให้ pipeline แดงค้าง → ทีมจะชินกับ "แดงก็แดง"

4. ใช้ Environment Variables สำหรับ Secrets 🔐

อย่า hardcode passwords, API keys, tokens ใน code หรือ pipeline YAML — ใช้ GitHub Secrets, Vault, หรือ environment variables แทน secrets ที่เข้า Git จะอยู่ใน history ตลอดไป:

# ❌ อย่าทำ
- run: mysql -u root -p mypassword123

# ✅ ทำแบบนี้
- run: mysql -u $DB_USER -p $DB_PASSWORD
  env:
    DB_USER: ${{ secrets.DB_USER }}
    DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

5. ทำให้ Pipeline เหมือนกันทุก Environment 🔄

Development → Staging → Production ควรใช้ pipeline เดียวกัน ต่างกันแค่ config (database URL, API keys, feature flags) ถ้าแต่ละ environment ใช้ pipeline ต่างกัน จะเจอปัญหา "staging ผ่านแต่ production พัง" — ใช้ Docker + environment variables ทำให้ environment ต่างกันแค่ config ไม่ใช่ infrastructure


เปรียบเทียบ: ก่อน vs หลังใช้ CI/CD

ตารางด้านล่างแสดงความแตกต่างที่ชัดเจนระหว่าง manual deployment กับ CI/CD — จะเห็นว่า CI/CD ลดทั้ง risk, เวลา, และ human error ได้มหาศาล:

ก่อน CI/CDหลัง CI/CD
Buildทำมือ, "ลืม build"อัตโนมัติทุก push
Test"เดี๋ยว test ทีหลัง"test ทุกครั้ง ถ้าไม่ผ่านหยุดเลย
DeploySSH เข้าเซิร์ฟเวอร์ ลาก file ด้วยมือกดปุ่มเดียว หรืออัตโนมัติ
Bug พบตอนไหนตอน user โทรมาด่าตอน pipeline fail (ก่อน deploy)
ความมั่นใจ"หวังว่าจะไม่พัง" 🤞"test ผ่านแล้ว มั่นใจ" ✅
Deploy frequencyเดือนละครั้ง (กลัวพัง)วันละหลายครั้ง

สรุป

  • CI (Continuous Integration) = build + test อัตโนมัติทุกครั้งที่ push code
  • CD (Continuous Delivery/Deployment) = deploy อัตโนมัติ (หรือกึ่งอัตโนมัติ) ไป production
  • Pipeline = ลำดับขั้นตอน: Source → Build → Test → Stage → Deploy
  • ถ้าขั้นตอนใด fail → pipeline หยุด → ไม่มี code พังหลุดไป production
  • เลือกเครื่องมือตามทีมและโปรเจกต์: GitHub Actions เหมาะสำหรับเริ่มต้น
  • Pipeline เร็ว + test ครอบคลุม + fix fast = DevOps ที่ดี

ในโพสต์หน้าเราจะมาพูดถึง Docker — เครื่องมือที่ทำให้ "It works on my machine" กลายเป็นเรื่องในอดีต! 🐳🐕

In the previous post we talked about Git Branching — how to cut a branch, how to merge it back, and what branching strategies are out there. But once the merge is done... what happens next?

If you have to build it yourself, test it yourself and deploy it yourself every time new code lands, the work is exhausting and easy to get wrong. The bigger the team and the more often you deploy, the messier it gets.

This is where the CI/CD Pipeline comes in — a system that handles everything automatically, from the moment code enters the repo to the moment it goes live on production.


What is CI/CD?

CI/CD is short for two ideas that reinforce each other — CI lets a team integrate code more often without stepping on each other's toes, while CD gets tested code into users' hands as fast as possible. Together they turn deployment from "a big scary event" into "an ordinary routine":

CI — Continuous Integration

"Merge often, test automatically every time"

The principle is that every developer should merge into the main branch at least once a day — the more often you integrate, the smaller each conflict is and the easier it is to fix. Let a branch drift for a week and then merge it all at once, and the conflict will be enormous. Every time you push, the system will:

  1. Pull the code and build it automatically
  2. Run the whole test suite
  3. Report the result: ✅ passed or ❌ failed

Without CI → a developer pushes code → nobody finds out it is broken until the real deploy 💀

CD — Continuous Delivery / Continuous Deployment

Continuous Delivery: code that has passed its tests is ready to deploy immediately, but someone still has to press the deploy button. This suits teams that need a compliance review or want manual approval before a release.

Continuous Deployment: code that has passed its tests goes straight to production automatically — nobody presses anything, and every commit that clears the pipeline reaches users at once! Netflix, Facebook and Google work this way, but it takes very high test coverage before you can be that confident.

Both have their merits — Delivery is safer (there is a human gate) while Deployment is faster (a very short feedback loop). Choose according to the risk tolerance of your team and your business.

Continuous Integration
automatic build + test
→
Continuous Delivery
ready to deploy, but you press it
→
Continuous Deployment
deploys itself, nothing to do

What is a Pipeline?

A pipeline is a sequence of steps that run automatically one after another, from the moment code enters the repo to the moment it is deployed to production. Picture a car factory: raw materials arrive → parts are assembled → quality is inspected → paint is applied → the car is delivered. If a part fails inspection, the line stops immediately — no defective goods reach the customer. A CI/CD pipeline does exactly the same:

Source
code
→
Build
compile
→
Test
verify
→
Stage
preview
→
Deploy
prod

If any step fails → the pipeline stops immediately → the developer is notified → no broken code slips through to production.


What Does Each Stage Do?

A typical pipeline has 5 stages — each with its own job, and each a "quality gate" that must be cleared before the next one begins. The more gates a pipeline has, the more confident you can be that the code reaching production is sound:

1. Source — Taking the Code In

The pipeline starts when a trigger event fires — usually a git push, but you can configure several kinds. The more that triggers automatically, the less a developer has to remember about "what to do before deploying":

  • Pushing code to a branch
  • Opening a Pull Request
  • Merging into main
  • A schedule (cron)
# GitHub Actions trigger example
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

2. Build — Assembling the Project

The Build stage is where you compile the code, install dependencies and produce artifacts (a Docker image, a JAR file, a JS bundle) that are ready to deploy. If the build fails, the code has a fundamental problem (a syntax error, a missing dependency) that must be fixed first. Here is what typically happens:

  • npm install → install packages
  • npm run build → compile TypeScript, bundle React, etc.
  • Build the Docker image
  • Produce the artifact (.jar, .whl, binary)
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run build

When a build fails, it is usually because of:

  • A syntax error
  • A missing dependency
  • A version conflict

3. Test — Verification

The most important stage of all — without tests, deploying is no different from rolling the dice 🎲. Automated tests run on every push without leaning on any developer's "diligence". If a test fails → the pipeline stops → the code never reaches production.

The levels of testing:

LevelWhat it testsSpeedExample
Unit TestA single functionVery fast (seconds)calculate(2,3) must return 5
Integration TestSeveral parts working togetherModerateAPI + Database
E2E TestThe whole system from the user's sideSlow (minutes)Click Login → see the Dashboard
- run: npm test          # Unit tests
- run: npm run test:e2e  # E2E tests
- run: npm run lint      # Code style check
- run: npm audit         # Security check

Testing Pyramid:

E2E Tests few, but broad
Integration Tests a moderate number
Unit Tests the most, and the fastest

4. Stage — A Preview Before the Real Deploy

Staging is an environment identical to production in every respect (same config, same data structure, same infrastructure) but not yet the real thing — a dress rehearsal before opening night. It catches the problems automated tests cannot, such as performance issues, UI bugs and integration problems:

What it gives you:

  • Testing against realistic data
  • A place for the QA team or the PM to review
  • Catching problems that automated tests miss

5. Deploy — Going to Production

The final stage — the code reaches real users at last! There are several ways to deploy, each with its own trade-off between risk, speed and complexity. Which one fits depends on your business requirements:

The popular deployment strategies:

Rolling Update

Rolling Update
Server 1:
v1
→
v2
✅
Server 2:
v1
→
v2
✅ (one machine at a time)
Server 3:
v1
→
v2
✅

Blue-Green Deployment

Before Switch
Blue (v1):
← traffic lives here
Green (v2):
deploy the new build here
After Switch
Blue (v1):
standby
Green (v2):
← traffic has moved here ✅

Canary Deployment

Phase 1 — Trial
v1 (90%):
90%
v2 (10%):
10%
← tried on a small slice of real users
Phase 2 — Ramping Up
v1 (50%):
50%
v2 (50%):
50%
Phase 3 — Complete
v2 (100%):
100% ✅

A Real Pipeline with GitHub Actions

Let us look at a real pipeline built on GitHub Actions — the CI/CD tool built into GitHub, free of charge. Create one YAML file in .github/workflows/ and you have an automated pipeline. The example below covers build, test and deploy:

name: CI/CD Pipeline

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

jobs:
  # ===== CI =====
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Build
        run: npm run build

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

      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  # ===== CD =====
  deploy:
    needs: build-and-test    # wait for CI to pass first
    if: github.ref == 'refs/heads/main'  # deploy main only
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Deploy to production
        run: |
          echo "Deploying to production..."
          # the real deploy command, for example:
          # ssh user@server 'cd /app && git pull && npm ci && pm2 restart all'
          # or docker push + kubectl apply

Popular CI/CD Tools

There are many CI/CD tools, and each is strong in a different direction — GitHub Actions (simple, free for public repos), GitLab CI (everything in one place), Jenkins (the most flexible, but you maintain it yourself), CircleCI (fast, cloud-native). Choose to fit your team and your ecosystem:

ToolTypeStrengthBest for
GitHub ActionsCloudEasy to use, free for public reposProjects already on GitHub
GitLab CI/CDCloud/Self-hostedStrong pipelines, built-in container registryOrganizations on GitLab
JenkinsSelf-hostedHuge plugin ecosystem, highly customizableLarge organizations
CircleCICloudFast, simple configStartups / small teams
ArgoCDSelf-hostedGitOps for KubernetesTeams running K8s

Best Practices

Having a good pipeline is not enough — you have to look after it, the way a car needs regular servicing. Let the pipeline get slow, let the tests go thin, let secrets be hardcoded, and eventually the pipeline becomes a burden instead of a help:

1. Keep Pipeline Fast ⚡

If the pipeline is too slow, developers will not want to wait → they start skipping CI → they gradually stop using it → and the whole benefit is lost. Make it fast with parallel jobs, cached dependencies, running only the relevant tests, and incremental builds.

Targets:

  • Build + Unit Test: < 5 minutes
  • The whole pipeline: < 15 minutes
Tip: cache dependencies, run tests in parallel, split the slow tests out

2. Test Thoroughly 🧪

Low test coverage gives you a pipeline that offers false confidence — the code clears the pipeline and then breaks in production. Aim for 80%+ coverage and write your tests along the Testing Pyramid:

  • Aim for code coverage > 80%
  • Have unit tests for the business logic that matters
  • Do not forget edge cases and error handling

3. Fail Fast, Fix Fast 🔴

Order the pipeline from fast to slow (lint → unit test → integration → E2E) so that failures surface as early as possible. A lint failure after 10 seconds beats waiting 15 minutes for an E2E test to fail. And once something fails, fix it immediately — never leave the pipeline sitting red:

  • If the pipeline fails → fix it first, before anything else
  • Never leave the pipeline red → the team gets used to "red is just how it looks"

4. Use Environment Variables for Secrets 🔐

Never hardcode passwords, API keys or tokens in your code or your pipeline YAML — use GitHub Secrets, Vault, or environment variables instead. A secret that reaches Git stays in the history forever:

# ❌ Don't
- run: mysql -u root -p mypassword123

# ✅ Do this
- run: mysql -u $DB_USER -p $DB_PASSWORD
  env:
    DB_USER: ${{ secrets.DB_USER }}
    DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

5. Keep the Pipeline Identical Across Environments 🔄

Development → Staging → Production should all run the same pipeline, differing only in config (database URL, API keys, feature flags). If each environment uses a different pipeline, you will meet the classic "it passed in staging but production broke" — use Docker plus environment variables so that the environments differ only in configuration, not in infrastructure.


Compared: Before vs After CI/CD

The table below sets the two side by side — manual deployment against CI/CD — and shows how enormously CI/CD cuts risk, time and human error:

Before CI/CDAfter CI/CD
BuildBy hand, and "oops, forgot to build"Automatic on every push
Test"I'll test it later"Tested every time; a failure stops everything
DeploySSH into the server and drag files across by handOne button, or fully automatic
When bugs turn upWhen a user phones in to yell at youWhen the pipeline fails (before the deploy)
Confidence"I hope it doesn't break" 🤞"The tests passed — I'm confident" ✅
Deploy frequencyOnce a month (too afraid it will break)Several times a day

Summary

  • CI (Continuous Integration) = automatic build + test on every code push
  • CD (Continuous Delivery/Deployment) = automatic (or semi-automatic) deployment to production
  • Pipeline = the sequence of stages: Source → Build → Test → Stage → Deploy
  • If any stage fails → the pipeline stops → no broken code slips through to production
  • Choose the tool that fits your team and project: GitHub Actions is a good place to start
  • A fast pipeline + thorough tests + fixing fast = good DevOps

In the next post we will talk about Docker — the tool that turned "it works on my machine" into a thing of the past! 🐳🐕

บทความจากซีรีส์ DevOps & Vibe Coding 2026A post from the DevOps & Vibe Coding 2026 series
← Previous
Git Branching — แตกกิ่งก้านสาขาให้เป็นระบบ
Next →
Docker Containers vs VMs — ต่างกันยังไง ใช้ตัวไหนดี?