Cấu hình GitHub Actions cho dự án Serverless và Edge
Bước đầu tiên là thiết lập file workflow trong thư mục .github/workflows của repository. File này sẽ đóng vai trò là điểm khởi đầu cho toàn bộ pipeline, kích hoạt khi có sự kiện push hoặc pull_request.
Tại sao: Để đảm bảo mọi thay đổi code đều trải qua quy trình kiểm tra tự động trước khi được phép deploy lên môi trường sản xuất, tránh đưa lỗi vào hệ thống.
Kết quả mong đợi: GitHub Actions hiển thị workflow mới trong tab Actions, sẵn sàng chạy khi bạn push code.
Tạo file workflow với đường dẫn đầy đủ: .github/workflows/ci-cd.yml. Nội dung file bao gồm các job: build, test, security-scan, deploy-openfaas, deploy-cloudflare.
name: Serverless & Edge CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}/openfaas-func
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_WORKER_NAME: my-edge-worker
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build OpenFaaS Function
uses: docker/build-push-action@v5
with:
context: ./functions/hello-wasm
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run Unit Tests
run: |
cd functions/hello-wasm
go test -v ./...
security-scan:
runs-on: ubuntu-latest
needs: build-and-test
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.23.0
with:
image-ref: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
deploy-openfaas:
runs-on: ubuntu-latest
needs: security-scan
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to OpenFaaS (Canary)
run: |
echo "Deploying function with tag ${{ github.sha }}"
# Giả định script deploy-canary.sh đã được chuẩn bị ở bước sau
./scripts/deploy-canary.sh ${{ env.IMAGE_NAME }} ${{ github.sha }}
deploy-cloudflare:
runs-on: ubuntu-latest
needs: security-scan
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Setup Wrangler
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
- name: Deploy Worker
run: |
cd workers/edge-proxy
wrangler deploy
Kết quả mong đợi: Workflow hiển thị trạng thái thành công (green checkmark) cho tất cả các job, và image Docker được đẩy lên GHCR.
Xây dựng pipeline tự động build, test và deploy OpenFaaS functions
Chúng ta cần chuẩn bị cấu trúc thư mục và script để pipeline có thể tìm thấy và build function cụ thể. OpenFaaS sử dụng Dockerfile đặc biệt, và pipeline cần tự động tạo image và deploy vào cluster.
Tại sao: Tự động hóa quá trình này giúp giảm thiểu lỗi con người khi cấu hình deployment manifest và đảm bảo versioning chính xác qua Git commit hash.
Kết quả mong đợi: Function mới được tạo và chạy trên OpenFaaS Gateway với tag version tương ứng với commit.
Trước hết, cấu trúc thư mục dự án cần có folder functions chứa source code và scripts chứa logic deploy. Dưới đây là ví dụ về file Dockerfile trong thư mục function để đảm bảo tính tương thích với OpenFaaS.
FROM openfaas/of-watchdog:0.11.2 as watchdog
FROM python:3.9-slim
# Copy watchdog
COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
RUN chmod +x /usr/bin/fwatchdog
ENV fprocess="/home/openfaas/function" \
HOME=/home/openfaas \
faas_home=/home/openfaas \
watchdog_timeout=0 \
function_timeout=1s \
watchdog_host=0.0.0.0 \
watchdog_port=8080 \
read_timeout=1s \
write_timeout=1s
ENV HOME=$faas_home
RUN mkdir -p $HOME
WORKDIR $HOME
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN chmod +x $fprocess
EXPOSE 8080
CMD ["fwatchdog"]
Kết quả mong đợi: Image Docker được build thành công, có thể chạy độc lập và lắng nghe port 8080 cho OpenFaaS.
Tiếp theo, tạo script scripts/deploy-canary.sh để xử lý logic deploy. Script này sẽ tạo deployment mới với replica nhỏ cho version mới, trong khi giữ version cũ.
#!/bin/bash
set -e
IMAGE_NAME=$1
TAG=$2
FUNCTION_NAME=${IMAGE_NAME##*/} # Extract function name from image name
NAMESPACE="openfaas-fn"
# Deploy Canary (1 replica)
cat
Kết quả mong đợi: Kubernetes tạo ra deployment mới với label version canary, traffic bắt đầu được chuyển một phần sang version mới.
Verify kết quả bằng cách xem deployment và service:
kubectl get deploy -n openfaas-fn
kubectl get svc -n openfaas-fn
Bạn sẽ thấy 2 deployment (stable và canary) và service đang trỏ đến canary (hoặc đang cân bằng tải nếu cấu hình Ingress phức tạp hơn).
Tự động deploy Cloudflare Workers khi có thay đổi code
Cloudflare Workers yêu cầu cấu hình file wrangler.toml để định nghĩa tên worker, runtime và các binding. Pipeline GitHub Actions sẽ sử dụng wrangler-action để thực thi lệnh deploy.
Tại sao: Workers cần được deploy lên mạng lưới Edge của Cloudflare ngay lập tức để áp dụng thay đổi logic, không cần qua bước build image Docker nặng nề.
Kết quả mong đợi: Worker được cập nhật trên Cloudflare Dashboard và URL worker trỏ đến phiên bản code mới nhất.
Tạo file cấu hình workers/edge-proxy/wrangler.toml với nội dung đầy đủ:
name = "my-edge-worker"
main = "src/index.ts"
compatibility_date = "2023-09-21"
# Cấu hình binding với OpenFaaS backend
[vars]
OPENFAAS_GATEWAY_URL = "https://your-openfaas-domain.com"
# Nếu dùng D1 hoặc KV, khai báo ở đây
# [d1_databases]
# MY_DB = { binding = "DB", database_name = "my-database", database_id = "..." }
# Cấu hình route (nếu dùng Custom Domain)
# [[routes]]
# pattern = "api.yourdomain.com/*"
# zone_id = "..."
# Cấu hình environment (staging/production)
# [env.production]
# name = "my-edge-worker-prod"
Kết quả mong đợi: Wrangler nhận diện được cấu hình, sẵn sàng để deploy.
File source code workers/edge-proxy/src/index.ts mẫu:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise {
const url = new URL(request.url);
// Logic Edge: Routing, Auth, Caching
if (url.pathname.startsWith('/api/edge-only')) {
return new Response('Handled by Edge Worker', { status: 200 });
}
// Proxy to OpenFaaS for heavy computation
if (url.pathname.startsWith('/api/function')) {
const backendUrl = env.OPENFAAS_GATEWAY_URL + url.pathname;
const response = await fetch(backendUrl, {
method: request.method,
headers: request.headers,
body: request.body,
});
// Add edge-specific headers
const newHeaders = new Headers(response.headers);
newHeaders.set('X-Edge-Processed', 'true');
return new Response(response.body, {
status: response.status,
headers: newHeaders,
});
}
return new Response('Not Found', { status: 404 });
},
}
Kết quả mong đợi: Code TypeScript được biên dịch và upload lên Cloudflare, sẵn sàng xử lý request.
Verify kết quả bằng cách gọi API:
curl -v https://my-edge-worker.your-subdomain.workers.dev/api/edge-only
Bạn sẽ thấy response "Handled by Edge Worker" ngay lập tức sau khi deploy thành công.
Triển khai chiến lược Canary Deployment cho các function mới
Chiến lược Canary Deployment yêu cầu phân luồng traffic từ Service/Ingress sang các version khác nhau. Trong môi trường Kubernetes, chúng ta thường sử dụng Argo Rollouts hoặc Istio, nhưng để đơn giản hóa cho OpenFaaS, ta sẽ dùng logic cập nhật Service Selector dần dần hoặc dùng Ingress Controller hỗ trợ canary (như Nginx Ingress với annotation).
Tại sao: Để giảm thiểu rủi ro khi deploy version mới có lỗi, chỉ 10-20% traffic được chuyển sang version mới để test thực tế trước khi rollout toàn bộ.
Kết quả mong đợi: 10% traffic đi đến version canary, 90% đi đến version stable. Nếu canary lỗi, pipeline tự động rollback.
Cấu hình Ingress với annotation cho Nginx Ingress Controller để hỗ trợ Canary:
cat
Kết quả mong đợi: Ingress Controller nhận diện annotation canary và phân chia 10% traffic sang service my-function-canary.
Để tự động hóa quá trình tăng tỷ lệ traffic (từ 10% lên 100%), ta cần thêm script hoặc dùng Argo Rollouts. Dưới đây là script đơn giản scripts/promote-canary.sh để chuyển toàn bộ traffic sang version mới sau khi kiểm tra ổn định.
#!/bin/bash
set -e
FUNCTION_NAME=$1
NAMESPACE="openfaas-fn"
# Bước 1: Xóa annotation canary trên Ingress (chuyển về stable)
kubectl annotate ingress openfaas-canary-ingress -n ${NAMESPACE} nginx.ingress.kubernetes.io/canary- -
# Bước 2: Update Service stable trỏ đến version mới
kubectl patch service ${FUNCTION_NAME} -n ${NAMESPACE} -p '{"spec":{"selector":{"version":"stable"}}}'
# Bước 3: Xóa deployment canary cũ
kubectl delete deployment ${FUNCTION_NAME}-canary -n ${NAMESPACE}
# Bước 4: Đổi label của deployment canary hiện tại thành stable
kubectl label deployment ${FUNCTION_NAME} -n ${NAMESPACE} version=stable --overwrite
echo "Canary promoted to Stable successfully."
Kết quả mong đợi: Toàn bộ traffic chuyển sang version mới, deployment canary bị xóa hoặc đổi tên thành stable.
Verify kết quả bằng cách quan sát logs của function và traffic pattern:
kubectl logs -f deployment/${FUNCTION_NAME} -n openfaas-fn
Bạn sẽ thấy logs bắt đầu nhận tất cả request thay vì chỉ 10%.
Tích hợp Security Scanning (Trivy/Snyk) vào pipeline CI
Bảo mật phải được tích hợp ngay từ giai đoạn build (Shift Left). Chúng ta sẽ sử dụng Trivy để quét vulnerability trong Docker image và Snyk (hoặc Trivy cho code) để quét source code.
Tại sao: Để phát hiện lỗ hổng bảo mật (CVE) trong thư viện dependencies hoặc OS base image trước khi image được đẩy lên registry, ngăn chặn các attack vector tiềm tàng.
Kết quả mong đợi: Pipeline bị dừng (fail) nếu phát hiện vulnerability mức độ CRITICAL hoặc HIGH, không cho phép deploy lên môi trường production.
Cấu hình job security-scan trong file .github/workflows/ci-cd.yml (đã có ở phần đầu) sử dụng Trivy để quét image Docker đã build.
Tuy nhiên, để quét source code (SBOM và dependencies) trước khi build, ta thêm bước quét vào job build-and-test:
- name: Scan Dependencies with Trivy
run: |
docker run --rm -v $(pwd):/scan aquasec/trivy:latest fs /scan
Kết quả mong đợi: Trivy in ra danh sách các vulnerability trong thư mục source code của project.
Để chặn pipeline khi có lỗi nghiêm trọng, cấu hình Trivy để exit code != 0 khi tìm thấy Critical/High:
- name: Run Trivy vulnerability scanner (Blocker)
uses: aquasecurity/trivy-action@0.23.0
with:
image-ref: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}'
format: 'table'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Force fail if vulnerabilities found
Kết quả mong đợi: Nếu tìm thấy lỗi Critical hoặc High, job này sẽ fail (màu đỏ), và các job tiếp theo (deploy) sẽ không chạy.
Để verify kết quả quét, vào tab Security -> Vulnerability alerts trên GitHub. Hoặc xem output logs của job security-scan trong workflow run.
gh run view --log --job security-scan
Bạn sẽ thấy bảng chi tiết các CVE, package bị ảnh hưởng và mức độ nghiêm trọng.
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng Serverless và Edge Computing an toàn với OpenFaaS, Cloudflare Workers và Wasm trên hạ tầng Kubernetes
« Phần 8: Giám sát, Logging và Tracing trong môi trường Hybrid
Phần 10: Troubleshooting nâng cao và các mẹo tối ưu hóa hiệu năng »