DevOps 2026: Docker + GitHub Actions CI/CD Pipeline cho Web Dev từ Zero đến Deploy

3 tháng trước · 8 phút đọc
CI/CD là gì và tại sao bạn cần ngay bây giờ
Mình nhớ hồi mới làm web, deploy app là cả một "nghi lễ": SSH vào server, git pull, npm install, restart service, rồi cầu trời không có lỗi. Mỗi lần mất 20-30 phút. Nếu lỗi thì lại làm từ đầu.
CI/CD (Continuous Integration / Continuous Deployment) giải quyết đúng cái đó. Bạn push code lên GitHub - mọi thứ còn lại tự động: build Docker image, chạy test, deploy lên server. Tổng thời gian? dưới 5 phút.
Từ push code đến production - không cần SSH thủ công
Tại sao 2026 lại quan trọng hơn bao giờ hết? Vì phần lớn công ty tuyển dụng web developer hiện yêu cầu ít nhất hiểu biết cơ bản về CI/CD và containerization. Biết Docker + GitHub Actions không còn là "bonus" - nó là baseline.
Bài này mình sẽ đi từ đầu: giải thích khái niệm, viết Dockerfile, setup GitHub Actions workflow, rồi deploy lên server thật. Không lý thuyết suông.
Docker: đóng gói app một lần, chạy ở đâu cũng được
Docker giải quyết bài toán cổ điển: "code chạy trên máy mình nhưng không chạy trên server". Thay vì cài môi trường trực tiếp lên server, bạn đóng gói toàn bộ app - code, dependencies, runtime - vào một image. Server chỉ cần Docker là chạy được.
Mình sẽ lấy ví dụ với một app Node.js đơn giản:
Copy package.json trước giúp cache layer - build nhanh hơn nhiều lần sau
Tại sao copy package*.json trước rồi mới copy code? Docker build theo từng layer. Nếu package.json không đổi, layer npm ci sẽ được cache lại - build lần sau nhanh hơn nhiều. Đây là trick mà nhiều người mới hay bỏ qua.
Một số lưu ý quan trọng:
- Dùng
node:alpinethay vìnode:latest- image nhẹ hơn 920-930 MB (Docker Official Node.js Images 2024 Analysis) - Dùng
npm cithay vìnpm installtrong production - đảm bảo version chính xác theopackage-lock.json - Tạo file
.dockerignoređể không copynode_modulesvào image:
node_modules
.git
.env
*.log
Build và test local trước:
Nếu bạn chưa quen với Docker và muốn có nền tảng vững hơn, khóa Devops for Engineers cover Docker từ cơ bản đến thực tế - kể cả Linux và networking cần thiết đi kèm.
GitHub Actions: tự động hóa mọi thứ khi push code
GitHub Actions là CI/CD engine được tích hợp thẳng vào GitHub - không cần tool ngoài, không cần server riêng để chạy pipeline. Bạn viết workflow dạng YAML, GitHub tự chạy khi có sự kiện (push, pull request, v.v.).
Cấu trúc một workflow cơ bản:
Workflow tự chạy mỗi khi push lên branch main - không cần làm gì thêm
Phần quan trọng nhất là Secrets. Bạn không bao giờ để credential trực tiếp trong file YAML. Vào repo GitHub → Settings → Secrets and variables → Actions, thêm:
DOCKER_USERNAME: username Docker HubDOCKER_TOKEN: access token Docker Hub (không phải password)SERVER_HOST: IP hoặc domain serverSERVER_USER: username SSH (thường làubuntuhoặcroot)SERVER_SSH_KEY: private key SSH
Workflow này làm 4 việc theo thứ tự: checkout code → build Docker image → push lên Docker Hub → SSH vào server, pull image mới và restart container. Toàn bộ tự động, bạn chỉ cần git push.
Thêm test vào pipeline: không pass test thì không deploy
Deploy không có test giống như tung code lên production rồi cầu nguyện. Một pipeline tốt phải chặn deploy nếu test fail.
Thêm job test trước job deploy:
needs: test là chìa khóa - deploy bị block nếu test fail
Keyword needs: test là phần quan trọng nhất. Nó tạo dependency giữa các job: build-and-deploy chỉ chạy khi test pass. Nếu có bất kỳ test nào fail, pipeline dừng lại, bạn nhận thông báo qua email, deploy không xảy ra.
Thực tế mình hay thêm vào:
- Unit test:
npm testhoặcjest - Lint:
eslintđể catch lỗi syntax và code style - Type check:
tsc --noEmitnếu dùng TypeScript - Security audit:
npm audit --audit-level=high
Mỗi bước thêm vào mất thêm 1-2 phút run time, nhưng đánh đổi bằng việc không bao giờ push bug lên production. Đáng.
Cấu trúc project hoàn chỉnh và chạy thử end-to-end
Giờ gom lại toàn bộ. Cấu trúc thư mục project với CI/CD setup đầy đủ:
my-app/
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions workflow
├── src/
│ ├── server.js
│ └── __tests__/
│ └── server.test.js
├── Dockerfile
├── .dockerignore
├── package.json
└── package-lock.json
Một Dockerfile production-ready hơn với multi-stage build:
Multi-stage build: stage 1 build, stage 2 chỉ giữ output - image production nhỏ hơn nhiều
Multi-stage build giúp image production không chứa dev dependencies và source code gốc - chỉ có build output. Kết quả image nhỏ hơn và an toàn hơn.
Flow hoàn chỉnh khi bạn làm việc hàng ngày:
- Code feature mới ở local
- Viết test cho feature đó
git push origin main(hoặc tạo PR)- GitHub Actions tự build Docker image
- Chạy test - nếu fail, báo ngay qua email
- Nếu pass, push image lên Docker Hub và deploy lên server
- Bạn refresh browser và thấy feature mới
Toàn bộ từ bước 3 đến bước 7 mất khoảng 3-7 phút mà bạn không cần làm gì.
Tải về workflow template đầy đủ để dùng ngay: Tải GitHub Actions workflow template
Một số lỗi phổ biến và cách tránh
Mình đã mắc hầu hết những lỗi này. Liệt kê ra để bạn không phải học theo cách đau đớn.
1. Để credential trong code
Tuyệt đối không commit .env file hoặc hardcode password/token vào deploy.yml. Dùng GitHub Secrets cho tất cả credential nhạy cảm. Nhiều người bị leak AWS key vì quên điều này.
2. Không có rollback plan
Deploy xong mới phát hiện lỗi thì sao? Đặt tag version cho Docker image thay vì chỉ dùng latest:
Khi cần rollback, chỉ cần docker run yourusername/my-app:[commit-sha-cũ].
3. Container bị restart nhưng data bị mất
Nếu app có data cần persist (uploads, SQLite file, v.v.), phải dùng Docker volume:
Volume mount giữ data khi container restart hoặc update
4. Không giới hạn resource cho container
Một container có thể ăn hết RAM server nếu có bug. Thêm limits:
5. Workflow chạy quá lâu
Cache Docker layers và npm để pipeline nhanh hơn:
Giờ bạn đã có đủ nền tảng để setup CI/CD pipeline hoàn chỉnh. Bước tiếp:
- Tạo repo mới, thêm Dockerfile và
.github/workflows/deploy.yml - Setup secrets trong GitHub repo settings
- Push code và xem pipeline chạy lần đầu
Gặp lỗi ở bước nào cứ drop comment. Mình sẽ trả lời.
