引言
在现代软件开发中,DevOps已经成为提升开发效率和产品质量的关键实践。持续集成/持续部署(CI/CD)作为DevOps的核心组成部分,能够显著缩短软件交付周期,提高部署频率和质量。本文将详细介绍如何搭建一个完整的CI/CD流水线,整合Docker容器化技术、Jenkins自动化部署工具和Kubernetes集群管理平台,实现从代码提交到应用部署的全流程自动化。
什么是CI/CD
CI/CD是持续集成(Continuous Integration)和持续部署(Continuous Deployment)的缩写。持续集成是指开发人员频繁地将代码变更合并到主分支,并通过自动化测试验证变更的正确性。持续部署则是指在通过所有测试后,自动将应用部署到生产环境。
CI/CD的核心价值
- 提高交付速度:自动化流程减少人工干预,加快部署周期
- 提升软件质量:自动化测试确保每次变更都经过验证
- 降低部署风险:标准化流程减少人为错误
- 增强团队协作:清晰的流程和反馈机制促进团队沟通
环境准备
在开始搭建CI/CD流水线之前,我们需要准备相应的环境和工具。
系统要求
# 基础环境要求
- Linux/Windows/macOS系统
- Docker引擎(19.03+)
- Kubernetes集群(1.18+)
- Jenkins服务器(2.300+)
- Git版本控制系统
安装Docker
# Ubuntu/Debian系统安装Docker
sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker
安装Kubernetes集群
# 使用kubeadm安装Kubernetes集群
sudo apt update && sudo apt install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# 初始化集群
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
# 配置kubectl
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
安装Jenkins
# 使用Docker安装Jenkins
docker run -d \
--name jenkins \
--restart=unless-stopped \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts
# 获取初始密码
docker logs jenkins
Docker镜像构建
Docker容器化是CI/CD流程中的重要环节。我们将创建一个简单的Web应用并构建Docker镜像。
创建示例应用
// app.js - 简单的Node.js应用
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({
message: 'Hello from Docker CI/CD pipeline!',
timestamp: new Date().toISOString()
});
});
app.get('/health', (req, res) => {
res.status(200).json({ status: 'healthy' });
});
app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`);
});
module.exports = app;
// package.json
{
"name": "docker-cicd-demo",
"version": "1.0.0",
"description": "Docker CI/CD demo application",
"main": "app.js",
"scripts": {
"start": "node app.js",
"test": "jest"
},
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"jest": "^28.0.0"
}
}
编写Dockerfile
# Dockerfile
FROM node:16-alpine
# 设置工作目录
WORKDIR /app
# 复制package文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 创建非root用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# 启动应用
CMD ["npm", "start"]
构建和推送Docker镜像
# 构建镜像
docker build -t myapp:latest .
# 标签镜像
docker tag myapp:latest myregistry.com/myapp:latest
# 推送到镜像仓库
docker push myregistry.com/myapp:latest
Jenkins配置
Jenkins作为CI/CD的核心工具,需要进行相应的配置来支持自动化流程。
安装必要插件
# 在Jenkins Web界面安装以下插件
- Docker Pipeline
- Kubernetes
- Git
- Pipeline
- Blue Ocean
- Docker
配置Docker Registry
// Jenkinsfile - 完整的CI/CD流水线定义
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'myregistry.com'
DOCKER_IMAGE_NAME = 'myapp'
KUBE_NAMESPACE = 'default'
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/your-repo/app.git'
}
}
stage('Build') {
steps {
script {
docker.build("${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${env.BUILD_NUMBER}")
}
}
}
stage('Test') {
steps {
script {
docker.image("${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${env.BUILD_NUMBER}").inside {
sh 'npm test'
}
}
}
}
stage('Push') {
steps {
script {
docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-registry-credentials') {
docker.image("${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${env.BUILD_NUMBER}").push()
}
}
}
}
stage('Deploy') {
steps {
script {
deployToKubernetes()
}
}
}
}
post {
success {
echo 'Pipeline completed successfully!'
}
failure {
echo 'Pipeline failed!'
}
}
}
def deployToKubernetes() {
def deployment = """
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: ${DOCKER_REGISTRY}/${DOCKER_IMAGE_NAME}:${env.BUILD_NUMBER}
ports:
- containerPort: 3000
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
"""
sh "echo '${deployment}' | kubectl apply -f -"
}
Jenkins Pipeline配置
// 简化版Jenkinsfile
pipeline {
agent any
tools {
maven 'Maven-3.8.1'
jdk 'JDK-11'
}
environment {
MAVEN_HOME = tool 'Maven-3.8.1'
JAVA_HOME = tool 'JDK-11'
REGISTRY = 'docker.io'
IMAGE_NAME = 'myapp'
}
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
post {
success {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Build Docker Image') {
steps {
script {
docker.build("${REGISTRY}/${IMAGE_NAME}:${env.BUILD_NUMBER}")
}
}
}
stage('Push to Registry') {
steps {
script {
docker.withRegistry("https://${REGISTRY}", 'dockerhub-credentials') {
docker.image("${REGISTRY}/${IMAGE_NAME}:${env.BUILD_NUMBER}").push()
}
}
}
}
stage('Deploy to Kubernetes') {
steps {
script {
def kubeconfig = readYaml file: 'kubeconfig.yaml'
withKubeConfig([credentialsId: 'kubeconfig-credentials']) {
sh "kubectl set image deployment/myapp-deployment myapp=${REGISTRY}/${IMAGE_NAME}:${env.BUILD_NUMBER}"
}
}
}
}
}
}
Kubernetes集群管理
Kubernetes作为容器编排平台,负责管理容器化应用的部署、扩展和运维。
创建Deployment配置
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myregistry.com/myapp:latest
ports:
- containerPort: 3000
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 3000
type: LoadBalancer
配置Ingress控制器
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80
配置资源限制和监控
# resource-limits.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256Mi
type: Container
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-quota
spec:
hard:
requests.memory: "1Gi"
limits.memory: "2Gi"
安全最佳实践
安全是CI/CD流程中不可忽视的重要环节。
密钥管理
# 使用Kubernetes Secret管理敏感信息
kubectl create secret generic docker-registry-credentials \
--from-literal=username=your-username \
--from-literal=password=your-password
# Jenkins凭据管理
# 在Jenkins中配置Docker Registry凭据
安全扫描
# 使用Trivy进行镜像安全扫描
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myregistry.com/myapp:latest
# 使用Clair进行容器镜像漏洞扫描
docker run -d --name clair \
-p 6060:6060 \
quay.io/coreos/clair:v2.1.0
网络安全
# NetworkPolicy配置
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: myapp-network-policy
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
ports:
- protocol: TCP
port: 3000
egress:
- to:
- namespaceSelector:
matchLabels:
name: backend
ports:
- protocol: TCP
port: 53
监控和日志
完善的监控和日志系统对于CI/CD流程的运维至关重要。
集成Prometheus监控
# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'kubernetes-pods'
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_port]
action: replace
target_label: __address__
regex: (.+):(.+)
replacement: $1:$2
集成ELK日志系统
# elasticsearch-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: elasticsearch
spec:
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
ports:
- containerPort: 9200
env:
- name: discovery.type
value: "single-node"
性能优化
构建缓存优化
# 优化的Dockerfile
FROM node:16-alpine
# 设置工作目录
WORKDIR /app
# 先复制package文件,利用Docker缓存
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 启动应用
CMD ["npm", "start"]
Jenkins流水线优化
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/your-repo/app.git'
}
}
stage('Build') {
steps {
script {
// 使用并行构建提高效率
parallel {
stage('Build Frontend') {
steps {
sh 'npm run build'
}
}
stage('Build Backend') {
steps {
sh 'mvn clean package'
}
}
}
}
}
}
stage('Test') {
steps {
script {
// 并行测试执行
parallel {
stage('Unit Tests') {
steps {
sh 'npm test'
}
}
stage('Integration Tests') {
steps {
sh 'npm run integration-test'
}
}
}
}
}
}
}
}
故障排除和维护
常见问题解决
# 检查Jenkins服务状态
systemctl status jenkins
# 查看Docker容器状态
docker ps -a
# 检查Kubernetes集群状态
kubectl get nodes
kubectl get pods
kubectl get services
# 查看Jenkins日志
journalctl -u jenkins
自动化维护脚本
#!/bin/bash
# cleanup.sh - 清理过期资源的脚本
# 清理过期的Docker镜像
docker image prune -a -f
# 清理过期的Jenkins构建
# 需要通过Jenkins API实现
# 清理Kubernetes中的过期Pod
kubectl delete pods --selector=app=myapp --grace-period=0 --force
echo "Cleanup completed"
总结
通过本文的详细介绍,我们成功搭建了一个完整的Docker + Jenkins + Kubernetes CI/CD流水线。这个流水线涵盖了从代码提交、构建测试到自动化部署的完整流程,实现了DevOps的核心价值。
关键要点回顾
- 环境准备:正确配置Docker、Kubernetes和Jenkins环境
- 容器化:使用Dockerfile构建应用镜像并推送至镜像仓库
- 自动化部署:通过Jenkins Pipeline实现自动化构建和部署
- 集群管理:使用Kubernetes管理容器化应用的部署和运维
- 安全实践:实施安全最佳实践保护CI/CD流程
- 监控日志:建立完善的监控和日志系统
- 性能优化:通过各种优化技术提升流水线效率
未来扩展
这个CI/CD流水线还可以进一步扩展:
- 集成更多的测试框架和质量检查工具
- 实现蓝绿部署或金丝雀发布策略
- 集成A/B测试和流量管理
- 实现更复杂的多环境部署策略
- 集成机器学习模型的自动化部署
通过持续优化和完善这个CI/CD流水线,团队可以显著提升软件交付效率和质量,实现真正的DevOps自动化部署。

评论 (0)