Giới thiệu
Gần đây, tôi đã thực hiện một dự án giúp tôi ôn lại những khái niệm quan trọng về CI/CD, containerization và infrastructure as code. Trong bài viết này, tôi sẽ chia sẻ kinh nghiệm, công nghệ sử dụng, những khó khăn gặp phải và bài học rút ra từ dự án. Bài viết này không chỉ tập trung vào công cụ mà còn vào khả năng thiết kế, xây dựng và tích hợp các công cụ và giải pháp hiện đại, cũng như hiểu cách và khi nào nên sử dụng chúng.
Dự Án
Mục tiêu của tôi là đơn giản: xây dựng một API bằng Python với Flask trả về các câu nói động lực ngẫu nhiên, container hóa nó với Docker và cấu hình để triển khai tự động bằng GitHub Actions và Terraform trên một nhà cung cấp cloud.
Kết quả cuối cùng là một pipeline thực hiện:
- Xây dựng hình ảnh Docker của ứng dụng.
- Tự động triển khai trên nhà cung cấp cloud.
- Cung cấp hạ tầng thông qua Terraform.
Tất cả những điều này sẽ được kích hoạt mỗi khi có commit vào nhánh main
.
Công Nghệ Sử Dụng
- Python + Flask – để xây dựng API.
- Docker – để đóng gói ứng dụng và đảm bảo khả năng di động.
- GitHub Actions – để tạo pipeline CI/CD.
- Terraform – để quản lý hạ tầng như mã.
- Cloud – nhà cung cấp dịch vụ lưu trữ và triển khai.
Cấu Trúc Cơ Bản Của API
Dưới đây là mã nguồn đơn giản để minh họa cấu trúc ứng dụng:
python
# app/advice.py
from flask import Flask, jsonify
import random
app = Flask(__name__)
frases = [
"Acredite em você!",
"Você é capaz de mais do que imagina.",
"Persistência leva ao sucesso.",
"Cada erro é uma oportunidade de aprendizado."
]
@app.route("/")
def home():
return jsonify({"message": "Chào mừng bạn đến với API Câu Nói Động Lực!"})
@app.route("/frase")
def frase():
return jsonify({"frase": random.choice(frases)})
@app.errorhandler(404)
def not_found(error):
return jsonify({"error": "Đường dẫn không tồn tại"}), 404
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80)
Dockerfile Để Container Hóa
Hình ảnh được xây dựng từ một base Python và mở cổng 80:
dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ .
EXPOSE 80
CMD ["python", "advice.py"]
Để kiểm tra cục bộ:
bash
docker build -t api-advice .
docker run -p 80:80 api-advice
Workflow Của GitHub Actions
Workflow được cấu hình để chạy trên nhánh main
với các luồng riêng biệt để thực hiện build, test và deploy:
yaml
name: CI Pipeline
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Build hình ảnh Docker
run: docker build -t test-image:latest .
- name: Chạy kiểm tra trong container
run: |
docker run --rm -d -p 80:80 --name test-container test-image:latest
sleep 5
curl -f http://localhost/ || exit 1
curl -f http://localhost/frase || exit 1
curl -s -o /dev/null -w "%{http_code}" http://localhost/inexistente | grep -q "404" && echo "404 OK" || exit 1
docker stop test-container
- name: Kiểm tra đã vượt qua ✅
run: echo "Tất cả các bài kiểm tra đã thành công!"
Action cho Infra
yaml
name: Provisionar Infraestrutura Render
on:
push:
branches: [infra]
jobs:
terraform:
runs-on: ubuntu-latest
environment: render
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.12.2
- name: Terraform Init
working-directory: infra
run: terraform init
- name: Terraform Plan
working-directory: infra
env:
TF_VAR_cloud_api_key: ${{ secrets.SECRET_API_KEY }}
TF_VAR_cloud_owner_id: ${{ secrets.SECRET_OWNER_ID }}
run: terraform plan -out=tfplan
- name: Terraform Apply
working-directory: infra
env:
TF_VAR_cloud_api_key: ${{ secrets.SECRET_API_KEY }}
TF_VAR_cloud_owner_id: ${{ secrets.SECRET_OWNER_ID }}
run: terraform apply -auto-approve
Mã Terraform Cho Cloud
Trong thư mục infra/
, tôi đã cấu hình các tài nguyên cho nhà cung cấp tương ứng:
hcl
tf_version ">= 0.12"
provider "cloud" {
api_key = var.cloud_api_key
}
resource "cloud_service" "api" {
name = "api-advice"
type = "web_service"
plan = "starter"
env = "docker"
branch = "main"
repo = "https://github.com/seu-usuario/seu-repo"
}
Những Bài Học Chính
1. Containerization với Docker
Tôi đã ôn lại việc tạo một hình ảnh Docker cho ứng dụng Flask, mở cổng 80 và cấu hình đúng CMD
để khởi động server. Tôi cũng đã thử nghiệm gọi API bằng curl
để xác nhận tính năng hoạt động trong container.
2. Tự Động Hóa Với GitHub Actions
Tôi đã cấu hình một workflow thực hiện:
- Xây dựng hình ảnh Docker.
- Tự động xuất bản ứng dụng trên nhà cung cấp cloud.
- Cung cấp hạ tầng với Terraform.
3. Hạ Tầng Như Mã Với Terraform
Tôi đã củng cố lại khái niệm về tổ chức tệp tin (main.tf
, variables.tf
, outputs.tf
, terraform.tfvars
) và các thực hành tốt khi sử dụng biến và outputs.
4. Cấu Trúc Dự Án
Giữ sự tách biệt giữa mã ứng dụng và mã hạ tầng giúp dễ dàng duy trì hơn.
Những Khó Khăn Gặp Phải
- Ôn lại Terraform: Đã một thời gian tôi không làm việc với Terraform, vì vậy tôi cần ôn lại tài liệu chính thức để nhớ lại cú pháp đúng của các mô-đun và đảm bảo tương thích với các phiên bản hiện tại.
- Tìm Hiểu Nhà Cung Cấp: Vì tôi chưa biết nhà cung cấp được định nghĩa cho dự án này, tôi đã mất thêm thời gian để hiểu cách thức thực hiện triển khai tự động từ các commit trên nhánh
main
.
Công Cụ Hỗ Trợ
Trong quá trình phát triển, tôi đã sử dụng một số công cụ AI giúp tăng tốc độ học tập:
- ChatGPT (OpenAI): để giải đáp thắc mắc và đề xuất giải pháp.
- GitHub Copilot: để đẩy nhanh quá trình viết mã và các tệp cấu hình.
- Claude Sonnet 3.7 (Anthropic): để xem xét và đề xuất cải tiến về tổ chức dự án.
Kết Luận
Dự án này không chỉ là việc tạo ra một API đơn giản — nó còn là bài tập thực tế về tích hợp giữa phát triển, tự động hóa và hạ tầng. Tôi đã ôn lại những khái niệm quan trọng và học hỏi những quy trình làm việc mới với các công cụ hiện đại như Render.
Nếu bạn đang bắt đầu với CI/CD, tôi khuyến nghị mạnh mẽ việc tạo ra một dự án từ đầu, tích hợp Docker, Terraform và một pipeline triển khai tự động. Kinh nghiệm thực tiễn là không thể thay thế.
Tách Biệt Các Pipeline
Tôi đã tạo ra hai workflow riêng biệt:
- Pipeline CI (
ci.yml
): chịu trách nhiệm xây dựng hình ảnh Docker và chạy các bài kiểm tra tự động đơn giản (bao gồm kiểm tra đường dẫn và trạng thái HTTP). Việc triển khai tại Render được kích hoạt tự động qua tích hợp của Render với GitHub ngay khi có push vào nhánhmain
. - Pipeline Hạ Tầng (
infra.yml
): dành riêng cho việc cung cấp hạ tầng thông qua Terraform, kích hoạt bởi các push vào nhánhinfra
.
Việc tách biệt này đảm bảo tổ chức tốt hơn, dễ dàng trong việc khắc phục sự cố và cho phép phát triển từng phần của quy trình một cách độc lập.