CI/CD 流程範本
Prompt 目標
指導 AI 建立完整的 CI/CD 流程,包含持續整合、持續部署和基礎設施即程式碼。
角色設定
你是一位資深 DevOps 工程師,具備豐富的 CI/CD 流程設計和實作經驗,熟悉各種自動化部署工具和雲端平台。
任務描述
請協助我為 {專案名稱} 建立完整的 CI/CD 流程。
專案 DevOps 背景
- 專案名稱: {填入專案名稱}
- 應用架構: {填入應用架構,如:微服務、單體應用}
- 技術棧: {填入技術棧}
- 部署平台: {填入目標平台,如:AWS、Azure、GCP、Kubernetes}
- 團隊規模: {填入團隊人數}
- 發布頻率: {填入預期發布頻率}
CI/CD 設計要求
請按照以下結構設計 CI/CD 流程:
1. 持續整合設計
- 原始碼管理策略
- 建置流程設計
- 自動化測試整合
- 程式碼品質門檻
2. 持續部署設計
- 部署策略選擇
- 環境管理規劃
- 發布流程設計
- 回退機制設計
3. 基礎設施管理
- 基礎設施即程式碼
- 環境配置管理
- 監控和告警設置
- 安全性配置
4. 自動化工具整合
- CI/CD 工具選擇
- 容器化策略
- 編排工具配置
- 工具鏈整合
5. 品質和安全
- 程式碼掃描整合
- 漏洞檢測流程
- 合規性檢查
- 稽核日誌管理
6. 監控和運維
- 應用程式監控
- 基礎設施監控
- 日誌聚合分析
- 事件響應流程
輸出格式
# {專案名稱} CI/CD 流程設計
## 1. 流程概覽
### 1.1 CI/CD 流程圖開發者提交程式碼 ↓ 程式碼品質檢查 ↓ 自動化建置 ↓ 自動化測試 ↓ 安全掃描檢查 ↓ 部署到測試環境 ↓ 整合測試執行 ↓ 部署到預生產環境 ↓ 使用者驗收測試 ↓ 部署到生產環境 ↓ 監控和回饋
### 1.2 分支策略
**採用策略:** GitFlow
**分支結構:**
- `main`: 生產環境程式碼
- `develop`: 開發整合分支
- `feature/*`: 功能開發分支
- `release/*`: 發布準備分支
- `hotfix/*`: 緊急修正分支
### 1.3 部署策略
**選擇策略:** 藍綠部署 (Blue-Green Deployment)
**優勢:**
- 零停機時間部署
- 快速回退能力
- 完整的預生產驗證
- 風險最小化
## 2. 持續整合流程
### 2.1 GitHub Actions 工作流程
#### 主要建置流程
```yaml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
env:
JAVA_VERSION: '17'
NODE_VERSION: '18'
DOCKER_REGISTRY: your-registry.com
jobs:
code-quality:
name: 程式碼品質檢查
runs-on: ubuntu-latest
steps:
- name: Checkout 程式碼
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 設定 Java
uses: actions/setup-java@v3
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
- name: 快取 Maven 相依性
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
- name: 執行 CheckStyle
run: mvn checkstyle:check
- name: 執行 SpotBugs
run: mvn spotbugs:check
- name: SonarQube 掃描
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn sonar:sonar
unit-tests:
name: 單元測試
runs-on: ubuntu-latest
needs: code-quality
steps:
- name: Checkout 程式碼
uses: actions/checkout@v4
- name: 設定 Java
uses: actions/setup-java@v3
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
- name: 執行單元測試
run: mvn test
- name: 產生測試報告
run: mvn jacoco:report
- name: 上傳覆蓋率報告
uses: codecov/codecov-action@v3
with:
file: target/site/jacoco/jacoco.xml
build-and-push:
name: 建置和推送映像檔
runs-on: ubuntu-latest
needs: [code-quality, unit-tests]
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout 程式碼
uses: actions/checkout@v4
- name: 設定 Java
uses: actions/setup-java@v3
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
- name: 建置應用程式
run: mvn clean package -DskipTests
- name: 設定 Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 登入 Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: 提取中繼資料
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY }}/myapp
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: 建置和推送 Docker 映像檔
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
security-scan:
name: 安全性掃描
runs-on: ubuntu-latest
needs: build-and-push
steps:
- name: 執行 Trivy 漏洞掃描
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ needs.build-and-push.outputs.image-tag }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: 上傳 Trivy 掃描結果
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
deploy-test:
name: 部署到測試環境
runs-on: ubuntu-latest
needs: [build-and-push, security-scan]
if: github.ref == 'refs/heads/develop'
environment: test
steps:
- name: 部署到測試環境
run: |
echo "部署映像檔 ${{ needs.build-and-push.outputs.image-tag }} 到測試環境"
# 實際部署邏輯
integration-tests:
name: 整合測試
runs-on: ubuntu-latest
needs: deploy-test
steps:
- name: Checkout 程式碼
uses: actions/checkout@v4
- name: 設定 Java
uses: actions/setup-java@v3
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'temurin'
- name: 執行整合測試
run: mvn verify -Dgroups=integration
env:
TEST_BASE_URL: https://test.myapp.com
deploy-production:
name: 部署到生產環境
runs-on: ubuntu-latest
needs: [build-and-push, security-scan]
if: github.ref == 'refs/heads/main'
environment: production
steps:
- name: 部署到生產環境
run: |
echo "部署映像檔 ${{ needs.build-and-push.outputs.image-tag }} 到生產環境"
# 實際部署邏輯2.2 品質門檻設定
SonarQube 品質門檻
quality_gate:
conditions:
- metric: coverage
operator: GREATER_THAN
value: 80
- metric: duplicated_lines_density
operator: LESS_THAN
value: 3
- metric: maintainability_rating
operator: LESS_THAN
value: 3
- metric: reliability_rating
operator: LESS_THAN
value: 3
- metric: security_rating
operator: LESS_THAN
value: 33. 容器化配置
3.1 Dockerfile 最佳實務
# 多階段建置 Dockerfile
# 建置階段
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
# 執行階段
FROM eclipse-temurin:17-jre-alpine AS runtime
# 建立非 root 使用者
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
# 安裝必要的套件
RUN apk add --no-cache curl jq
# 設定工作目錄
WORKDIR /app
# 複製應用程式
COPY --from=build /app/target/*.jar app.jar
# 變更擁有者
RUN chown -R appuser:appgroup /app
# 切換到非 root 使用者
USER appuser
# 健康檢查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 暴露埠口
EXPOSE 8080
# 啟動應用程式
ENTRYPOINT ["java", "-jar", "app.jar"]3.2 Docker Compose 開發環境
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=development
- DB_HOST=postgres
- REDIS_HOST=redis
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myuser -d myapp"]
interval: 30s
timeout: 10s
retries: 3
networks:
- app-network
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge4. Kubernetes 部署配置
4.1 應用程式部署配置
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
version: "1.0"
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: your-registry.com/myapp:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: DB_HOST
value: "postgres-service"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
volumeMounts:
- name: config-volume
mountPath: /app/config
volumes:
- name: config-volume
configMap:
name: myapp-config
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
---
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- myapp.example.com
secretName: myapp-tls
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 804.2 Helm Chart 配置
# Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for MyApp
type: application
version: 0.1.0
appVersion: "1.0.0"
# values.yaml
replicaCount: 3
image:
repository: your-registry.com/myapp
pullPolicy: IfNotPresent
tag: "latest"
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.example.com
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 250m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80
monitoring:
enabled: true
serviceMonitor:
enabled: true5. 基礎設施即程式碼
5.1 Terraform 配置
# main.tf
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "myapp-terraform-state"
key = "prod/terraform.tfstate"
region = "ap-southeast-1"
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
Project = var.project_name
ManagedBy = "Terraform"
}
}
}
# VPC 配置
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "${var.project_name}-vpc"
cidr = var.vpc_cidr
azs = var.availability_zones
private_subnets = var.private_subnet_cidrs
public_subnets = var.public_subnet_cidrs
enable_nat_gateway = true
enable_vpn_gateway = false
tags = {
Environment = var.environment
}
}
# EKS 叢集
module "eks" {
source = "terraform-aws-modules/eks/aws"
cluster_name = "${var.project_name}-eks"
cluster_version = "1.27"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
eks_managed_node_groups = {
main = {
min_size = 1
max_size = 5
desired_size = 3
instance_types = ["t3.medium"]
capacity_type = "ON_DEMAND"
}
}
tags = {
Environment = var.environment
}
}
# RDS 資料庫
resource "aws_db_instance" "main" {
identifier = "${var.project_name}-db"
engine = "postgres"
engine_version = "15.3"
instance_class = "db.t3.micro"
allocated_storage = 20
max_allocated_storage = 100
db_name = var.db_name
username = var.db_username
password = var.db_password
vpc_security_group_ids = [aws_security_group.rds.id]
db_subnet_group_name = aws_db_subnet_group.main.name
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "sun:04:00-sun:05:00"
skip_final_snapshot = false
final_snapshot_identifier = "${var.project_name}-db-final-snapshot"
tags = {
Name = "${var.project_name}-database"
}
}5.2 Ansible Playbook
# deploy.yml
---
- name: 部署應用程式到 Kubernetes
hosts: localhost
gather_facts: false
vars:
app_name: myapp
namespace: production
image_tag: "{{ ansible_env.IMAGE_TAG | default('latest') }}"
tasks:
- name: 建立 namespace
kubernetes.core.k8s:
name: "{{ namespace }}"
api_version: v1
kind: Namespace
state: present
- name: 套用 ConfigMap
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ app_name }}-config"
namespace: "{{ namespace }}"
data:
application.properties: |
server.port=8080
spring.datasource.url=jdbc:postgresql://postgres-service:5432/myapp
logging.level.com.myapp=INFO
- name: 部署應用程式
kubernetes.core.k8s:
state: present
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ app_name }}"
namespace: "{{ namespace }}"
spec:
replicas: 3
selector:
matchLabels:
app: "{{ app_name }}"
template:
metadata:
labels:
app: "{{ app_name }}"
spec:
containers:
- name: "{{ app_name }}"
image: "your-registry.com/{{ app_name }}:{{ image_tag }}"
ports:
- containerPort: 8080
- name: 等待部署完成
kubernetes.core.k8s_info:
api_version: apps/v1
kind: Deployment
name: "{{ app_name }}"
namespace: "{{ namespace }}"
wait: true
wait_condition:
type: Progressing
status: "True"
reason: NewReplicaSetAvailable
wait_timeout: 6006. 監控和告警
6.1 Prometheus 配置
# prometheus-config.yaml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'myapp'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- "alert_rules.yml"6.2 告警規則
# alert_rules.yml
groups:
- name: myapp.rules
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "高錯誤率檢測"
description: "應用程式錯誤率超過 10%"
- alert: HighCPUUsage
expr: cpu_usage_percent > 80
for: 10m
labels:
severity: warning
annotations:
summary: "CPU 使用率過高"
description: "CPU 使用率超過 80%"
- alert: LowDiskSpace
expr: disk_free_percent < 20
for: 5m
labels:
severity: critical
annotations:
summary: "磁碟空間不足"
description: "可用磁碟空間少於 20%"7. 安全性配置
7.1 安全掃描流程
# security-scan.yml
name: 安全性掃描
on:
schedule:
- cron: '0 2 * * *' # 每日凌晨 2 點執行
push:
branches: [ main ]
jobs:
dependency-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 執行 OWASP Dependency Check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'myapp'
path: '.'
format: 'ALL'
- name: 上傳掃描結果
uses: actions/upload-artifact@v3
with:
name: dependency-check-report
path: reports/
docker-security-scan:
runs-on: ubuntu-latest
steps:
- name: 執行 Docker 安全掃描
run: |
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image your-registry.com/myapp:latest7.2 Kubernetes 安全政策
# security-policy.yaml
apiVersion: v1
kind: SecurityContextConstraints
metadata:
name: myapp-scc
allowHostDirVolumePlugin: false
allowHostIPC: false
allowHostNetwork: false
allowHostPID: false
allowHostPorts: false
allowPrivilegedContainer: false
allowedCapabilities: []
defaultAddCapabilities: []
requiredDropCapabilities:
- KILL
- MKNOD
- SETUID
- SETGID
runAsUser:
type: MustRunAsRange
uidRangeMin: 1001
uidRangeMax: 2000
seLinuxContext:
type: MustRunAs
volumes:
- configMap
- downwardAPI
- emptyDir
- persistentVolumeClaim
- projected
- secret
## CI/CD 最佳實務
### 流程設計原則
- **快速回饋**: 盡早發現問題
- **自動化優先**: 減少人工干預
- **漸進式部署**: 降低部署風險
- **可觀測性**: 全面監控和日誌
### 安全性考量
- **最小權限原則**: 只給予必要的權限
- **密鑰管理**: 使用專用的密鑰管理服務
- **映像檔掃描**: 定期掃描容器映像檔
- **網路隔離**: 適當的網路分段
### 效能最佳化
- **平行執行**: 平行化測試和建置步驟
- **快取策略**: 有效利用建置快取
- **增量建置**: 只建置變更的部分
- **資源管理**: 合理分配運算資源
## 品質檢查清單
- [ ] CI/CD 流程設計完整
- [ ] 自動化測試整合完善
- [ ] 安全掃描機制健全
- [ ] 部署策略合理可行
- [ ] 監控告警配置完整
- [ ] 回退機制設計明確
- [ ] 環境配置管理規範
- [ ] 文檔和培訓完整
- [ ] 效能和可靠性達標
- [ ] 合規性要求滿足
## 使用範例
### 部署命令範例
```bash
# 手動觸發部署
gh workflow run "CI/CD Pipeline" --ref main
# 使用 Helm 部署
helm upgrade --install myapp ./helm-chart \
--namespace production \
--set image.tag=v1.2.3
# 使用 kubectl 部署
kubectl apply -f k8s/manifests/ -n production
# 檢查部署狀態
kubectl rollout status deployment/myapp -n production監控指令範例
# 查看應用程式日誌
kubectl logs -f deployment/myapp -n production
# 查看 Pod 狀態
kubectl get pods -l app=myapp -n production
# 查看資源使用情況
kubectl top pods -n production注意事項
- 確保 CI/CD 流程的安全性和穩定性
- 建立完善的測試和驗收機制
- 實作有效的監控和告警系統
- 定期檢視和最佳化流程效率
- 培養團隊的 DevOps 技能和文化
- 建立清楚的故障排除和回復程序