→ From Coder to Shipper
From Coder to Shipper · DevOps

CI/CD — build, test & deploy tự động

Bạn push một lần, máy tự build app, tự test, tự ship — không cần người, không còn 'để tối mình làm'.

← / → để chuyển slide · chuyển EN/VI bên dưới

Vấn đề

Ship là công việc thủ công và đáng sợ

Trước CI/CD, mỗi lần deploy là một sự kiện: có người phải nhớ các bước, làm theo thứ tự, rồi cầu may.

Thủ công, mỗi lần đều vậy

Restart server? Thay file? Chạy migration? Công thức nằm trong đầu một người và trong wiki chẳng ai cập nhật.

Test bị bỏ khi gấp

'Chạy trên máy mình rồi, chắc ổn.' Khi deadline dồn dập, bước test là thứ đầu tiên biến mất lặng lẽ.

Người dùng phát hiện lỗi

Người đầu tiên thấy bug là khách hàng, trên production, lúc 2 giờ sáng. Không phải test, không phải đồng đội.

'Để tối mình deploy'

Deployment tích lũy, thay đổi to dần, và mỗi lần ship mang theo nhiều rủi ro hơn cần.

Ý tưởng

CI/CD trong một hơi

CI/CD = một pipeline tự động: hễ code thay đổi, máy tự build, tự test, tự deploy — cùng một cách, mỗi lần.

Pipeline — băng chuyền

Một công thức các bước chạy tự động trên máy cloud. Bạn push code; băng chuyền lo phần còn lại.

CI — Tích hợp liên tục

Mỗi commit: build app và chạy test. Lỗi bị bắt trong vài phút, không phải vài tuần.

CD — Bàn giao / Triển khai liên tục

Khi test pass, đưa kết quả lên staging hay production — tự động, hoặc một cú click.

Một push = một lần chạy

Không cần 'ngày deploy'. Mỗi push vào repo đều kích hoạt cùng một pipeline — nhỏ, thường xuyên, nhàm chán. Nhàm chán là tốt.

CI/CD · hai nửa

CI vs CD — kiểm tra trước, ship sau

Hai ý tưởng, một pipeline. CI hỏi 'có an toàn không?'; CD nói 'làm cho xong'.

CI — cổng chất lượng

Build + test mỗi commit. Ngay khi thay đổi của bạn làm hỏng gì đó, pipeline đỏ và deploy dừng lại.

Mục tiêu: thay đổi nhỏ và thường xuyên; lỗi bị bắt trong vài phút.

CD — làn đường ship

Pipeline pass thì kết thúc bằng deployment: bản mới lên staging (hoặc thẳng tới production). Luôn cùng một con đường.

Mục tiêu: app luôn có thể deploy bất kỳ lúc nào — vì nó vừa được làm vậy.

Dòng chảy cốt lõi

push → build → test → deploy

Một push vào repo, máy chạy dọc băng chuyền từ trái sang phải. Bước nào đỏ là dừng tất cả.

Bạn
git push — một lệnh, một commit
rồi bạn đóng laptop lại
→
Pipeline — chạy trên cloud
1checkout — tải đúng commit đó
2install — cài deps từ requirements.txt
3test — toàn bộ bộ test
4build — app → image docker
5deploy — image mới lên server
→
Kết quả
✅ green — live trong vài phút
❌ red — deploy dừng, bạn nhận được lỗi
Nó làm gì

Năm việc, không cần người

Giữa 'git push' và 'đã live', máy làm bốn việc này — mỗi lần đều vậy, cùng một thứ tự.

1 · Checkout — lấy code

Máy tải đúng commit bạn push — cùng byte, cùng phiên bản, không còn cảnh 'biết là phiên bản nào nữa'.

2 · Install — chuẩn bị nhà bếp

Một máy sạch cài Python và dependencies từ requirements.txt. Không còn 'chạy trên máy mình' để viện cớ.

3 · Test — cổng chất lượng

Bộ test chạy. Một test fail = pipeline đỏ = không có gì được ship. Đây là CI đang làm việc.

4 · Build + deploy — việc ship

App thành image container, và image mới được deploy lên server. Staging trước, production sau — tự động.

Thực tế · một lần chạy xanh

Pipeline pass trông thế nào

Đây là toàn bộ việc 'deploy' — một log tự cuộn trong khi bạn làm chuyện khác.

ops@vps — zsh
Run #142 · build-test-deploy · branch: main
✓ 1. Checkout code (3s)
✓ 2. Install dependencies (41s)
✓ 3. Run tests (27s) — 128 passed
✓ 4. Build docker image (55s)
✓ 5. Deploy to staging (12s)
Pipeline finished green — staging is running the new version.
Thực tế · một lần chạy đỏ

Và lần chạy cứu bạn

Một test fail — nên code xấu không bao giờ tới server. Bạn nhận lỗi sau vài phút, thay vì khách hàng gọi lúc 2 giờ sáng.

ops@vps — zsh
Run #143 · build-test-deploy · branch: main
✓ 1. Checkout code (3s)
✓ 2. Install dependencies (40s)
✗ 3. Run tests (21s) — 127 passed, 1 failed
FAILED test_login.py::test_empty_password — ValueError
Deploy step skipped — the bad code never left the pipeline.
01
Phần 1 · Pipeline đầu tiên

Viết pipeline đầu tiên

Trên GitHub, toàn bộ phép màu nằm trong một file: vài dòng YAML mô tả các bước.

Phần 1 · file

Cả một pipeline trong 15 dòng YAML

File này nằm trong repo tại .github/workflows/. GitHub tự chạy nó mỗi khi bạn push vào main.

.github/workflows/deploy.yml
# runs automatically on every push
name: build-test-deploy
on:
  push:
    branches: [main]

jobs:
  ship:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4         # 1. get the code
      - run: pip install -r requirements.txt  # 2. deps
      - run: pytest                       # 3. test
      - run: docker build -t myapp .      # 4. build image
      - run: ./deploy.sh                  # 5. ship it

on: push = khi nào · jobs = làm gì · steps = theo thứ tự nào.

Phần 1 · cách đọc

Ba từ để đọc được nó

Mọi workflow GitHub Actions đều chỉ là ba ý này. Phần còn lại là từ vựng.

on: — công tắc

'Chạy khi nào?' on: push = mỗi lần push vào repo. Các lựa chọn khác: theo lịch, khi có pull request, khi có tag.

jobs: — việc gì

Job là một khối việc đặt tên chạy trên máy mới — runs-on: ubuntu-latest. Ở đây, một job tên ship làm mọi thứ.

steps: — thứ tự

Các lệnh theo thứ tự từ trên xuống: - uses: chạy bước có sẵn (checkout), - run: chạy một lệnh shell. Bước fail đầu tiên dừng hết phần còn lại.

Phần 1 · bước cuối

Bước deploy, nhìn kỹ

Bước cuối làm phần nhàm chán — viết một lần, tự chạy mãi mãi.

deploy.sh
# deploy.sh — runs on the server
docker pull myapp:latest      # newest image
docker stop web || true
docker rm web || true
docker run -d --name web -p 8080:5000 myapp:latest
curl -fsS http://127.0.0.1:8080/health

Dừng container cũ, khởi động cái mới, gõ cửa kiểm tra nó có trả lời không.

Phần 1 · hộp công cụ

Ba công cụ bạn thực sự sẽ gặp

Cùng một ý tưởng, mỗi nơi một chỗ. Khóa này dùng GitHub Actions — mấy cái còn lại chỉ để bạn nhận ra khi gặp ngoài đời.

Công cụNó sống ở đâuCần biết gì
GitHub ActionsGitHub — nơi đặt repo của khóa học nàyFile YAML trong repo (.github/workflows/). Miễn phí cho repo public. Lựa chọn của khóa học.
GitLab CIGitLab — cloud hoặc tự hostCùng ý tưởng, cấu hình trong một file .gitlab-ci.yml. Phổ biến ở những nơi tự host.
JenkinsServer của bạn — lão làngChương trình bạn tự cài, đã có từ khoảng 2011. Pipeline viết bằng code hoặc UI. Vẫn có mặt ở khắp các công ty lớn.
Phần hái quả

Vì sao team không quay lại

Không chỉ vì tốc độ. Mà vì xóa bỏ cả một dạng khoảnh khắc đáng sợ của con người.

Không còn 'để tối mình deploy'

Deploy do pipeline thực hiện, không do lịch của một người hùng. Bạn push; băng chuyền lo phần còn lại.

Mọi thay đổi đi cùng một con đường

Cùng các bước, cùng máy, cùng thứ tự — cho cả sửa 3 dòng lẫn tính năng lớn. Lặp lại giết chết 'chạy trên máy mình'.

Phản hồi nhanh, rẻ

Push → xanh hay đỏ sau vài phút. Bạn biết thay đổi của mình làm hỏng gì trước khi người dùng kịp biết.

Thay đổi nhỏ, tự tin lớn

Vì ship nhàm chán và tự động, thay đổi được giữ nhỏ và thường xuyên. Đó là cách team ship hằng ngày mà không sợ.

Toàn cảnh

Băng chuyền từ 'tôi đã push' tới 'đã live'

Một câu về cả chủ đề: máy chạy băng chuyền, bạn chỉ việc push.

💻

Bạn

git push

bước người duy nhất
push→
🏭

GitHub Actions

checkout → install → test → build → deploy

băng chuyền
→vài phút
🚀

Server

bản mới đã live

tự động · đã test · lặp lại được

push → pipeline → live. Không còn ngày deploy, không còn bước quên, không còn 'chạy trên máy mình'.

git push. Đó là toàn bộ việc của bạn bây giờ.

push → build → test → deploy, mỗi lần thay đổi. Băng chuyền chạy; bạn ship.