Docker + Kubernetes + Jenkins 实现CI/CD自动化部署流水线

DeadLaugh
DeadLaugh 2026-02-06T09:08:05+08:00
0 0 2

引言

在现代软件开发中,持续集成和持续部署(CI/CD)已经成为提升团队交付效率、保证代码质量的关键实践。本文将详细介绍如何使用Docker、Kubernetes和Jenkins构建一个完整的CI/CD自动化部署流水线,帮助开发者快速实现从代码提交到生产环境部署的全流程自动化。

什么是CI/CD

CI/CD(Continuous Integration/Continuous Delivery)是一套软件开发实践,通过自动化流程来提高软件交付的质量和速度。其中:

  • 持续集成(CI):开发者频繁地将代码变更合并到主分支,并通过自动化测试确保代码质量
  • 持续部署(CD):在代码通过测试后,自动将其部署到生产环境或预发布环境

技术栈概述

Docker容器化技术

Docker是容器化技术的代表,它允许我们将应用程序及其依赖打包成轻量级、可移植的容器。Docker的优势包括:

  • 环境一致性
  • 快速启动和部署
  • 资源隔离和优化
  • 版本控制和镜像管理

Kubernetes集群编排

Kubernetes(简称k8s)是容器编排平台,用于自动化部署、扩展和管理容器化应用程序。其核心功能包括:

  • 自动化部署和回滚
  • 服务发现和负载均衡
  • 弹性伸缩
  • 存储编排
  • 自我修复能力

Jenkins自动化构建工具

Jenkins是一个开源的持续集成和持续交付工具,提供了丰富的插件生态系统。它支持:

  • 多种构建触发方式
  • 灵活的流水线配置
  • 丰富的报告和监控功能
  • 集成各种开发工具

环境准备

系统要求

在开始之前,请确保满足以下环境要求:

# Docker版本要求
docker --version
# 推荐版本:Docker CE 20.10+

# Kubernetes集群要求
kubectl version
# 推荐版本:Kubernetes 1.20+

# Jenkins要求
jenkins --version
# 推荐版本:Jenkins 2.300+

基础环境搭建

1. 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

2. Kubernetes集群搭建

# 使用kubeadm搭建单节点集群(测试环境)
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

# 安装Flannel网络插件
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

3. 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 exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Docker容器化应用

创建示例应用

我们以一个简单的Node.js应用为例来演示整个流程:

// app.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.json({
    message: 'Hello from Docker + Kubernetes + Jenkins CI/CD!',
    timestamp: new Date().toISOString(),
    version: '1.0.0'
  });
});

app.get('/health', (req, res) => {
  res.status(200).json({ status: 'healthy' });
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
// package.json
{
  "name": "docker-k8s-jenkins-demo",
  "version": "1.0.0",
  "description": "Demo application for CI/CD pipeline",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "express": "^4.18.0"
  },
  "engines": {
    "node": ">=12.0.0"
  }
}

编写Dockerfile

# Dockerfile
FROM node:16-alpine

# 设置工作目录
WORKDIR /app

# 复制package.json和package-lock.json
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 创建非root用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# 暴露端口
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# 启动应用
CMD ["npm", "start"]

构建和推送Docker镜像

# 构建Docker镜像
docker build -t myapp:latest .

# 登录到Docker Hub(如果使用)
docker login

# 标签镜像
docker tag myapp:latest your-username/myapp:latest

# 推送到仓库
docker push your-username/myapp:latest

Kubernetes部署配置

创建命名空间

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: ci-cd-demo
  labels:
    name: ci-cd-demo

部署应用配置

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  namespace: ci-cd-demo
  labels:
    app: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: your-username/myapp:latest
        ports:
        - containerPort: 3000
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

服务配置

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: ci-cd-demo
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 3000
    protocol: TCP
  type: LoadBalancer

配置文件应用

# 应用配置
kubectl apply -f namespace.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# 查看部署状态
kubectl get pods -n ci-cd-demo
kubectl get svc -n ci-cd-demo

Jenkins流水线配置

安装必要插件

在Jenkins中安装以下核心插件:

  • Docker Pipeline
  • Kubernetes Continuous Deploy
  • Git Plugin
  • Pipeline: GitHub Groovy Libraries

创建流水线项目

1. 简单的Pipeline脚本

// Jenkinsfile
pipeline {
    agent any
    
    environment {
        DOCKER_IMAGE = 'your-username/myapp'
        KUBE_NAMESPACE = 'ci-cd-demo'
    }
    
    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', url: 'https://github.com/your-username/myapp.git'
            }
        }
        
        stage('Build Docker Image') {
            steps {
                script {
                    docker.build("${DOCKER_IMAGE}:${env.BUILD_NUMBER}")
                }
            }
        }
        
        stage('Push to Registry') {
            steps {
                script {
                    docker.withRegistry('https://index.docker.io/v1/', 'docker-hub-credentials') {
                        docker.image("${DOCKER_IMAGE}:${env.BUILD_NUMBER}").push()
                    }
                }
            }
        }
        
        stage('Deploy to Kubernetes') {
            steps {
                script {
                    withKubeConfig([credentialsId: 'k8s-config']) {
                        sh """
                            kubectl set image deployment/myapp-deployment myapp=${DOCKER_IMAGE}:${env.BUILD_NUMBER} -n ${KUBE_NAMESPACE}
                        """
                    }
                }
            }
        }
        
        stage('Verify Deployment') {
            steps {
                script {
                    withKubeConfig([credentialsId: 'k8s-config']) {
                        sh """
                            kubectl rollout status deployment/myapp-deployment -n ${KUBE_NAMESPACE}
                        """
                    }
                }
            }
        }
    }
    
    post {
        success {
            echo 'Pipeline completed successfully!'
        }
        failure {
            echo 'Pipeline failed!'
        }
    }
}

2. 增强版Pipeline脚本

// Jenkinsfile - 增强版
pipeline {
    agent any
    
    environment {
        DOCKER_IMAGE = 'your-username/myapp'
        KUBE_NAMESPACE = 'ci-cd-demo'
        REGISTRY_URL = 'https://index.docker.io/v1/'
        GIT_COMMIT = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
                echo "Building commit: ${GIT_COMMIT}"
            }
        }
        
        stage('Unit Tests') {
            steps {
                script {
                    sh 'npm install'
                    sh 'npm test'
                }
            }
            post {
                success {
                    echo 'Unit tests passed!'
                }
                failure {
                    error 'Unit tests failed!'
                }
            }
        }
        
        stage('Build Docker Image') {
            steps {
                script {
                    def dockerImage = docker.build("${DOCKER_IMAGE}:${GIT_COMMIT}")
                    echo "Docker image built: ${DOCKER_IMAGE}:${GIT_COMMIT}"
                }
            }
        }
        
        stage('Push to Registry') {
            steps {
                script {
                    docker.withRegistry(REGISTRY_URL, 'docker-hub-credentials') {
                        docker.image("${DOCKER_IMAGE}:${GIT_COMMIT}").push()
                        docker.image("${DOCKER_IMAGE}:latest").push()
                    }
                }
            }
        }
        
        stage('Deploy to Staging') {
            steps {
                script {
                    withKubeConfig([credentialsId: 'k8s-staging-config']) {
                        sh """
                            kubectl set image deployment/myapp-deployment myapp=${DOCKER_IMAGE}:${GIT_COMMIT} -n ${KUBE_NAMESPACE}
                        """
                        sh "kubectl rollout status deployment/myapp-deployment -n ${KUBE_NAMESPACE}"
                    }
                }
            }
        }
        
        stage('Integration Tests') {
            steps {
                script {
                    // 这里可以添加集成测试逻辑
                    echo 'Running integration tests...'
                    // 示例:等待应用启动后进行测试
                    sh 'sleep 30'
                }
            }
        }
        
        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                script {
                    withKubeConfig([credentialsId: 'k8s-prod-config']) {
                        sh """
                            kubectl set image deployment/myapp-deployment myapp=${DOCKER_IMAGE}:${GIT_COMMIT} -n ${KUBE_NAMESPACE}
                        """
                        sh "kubectl rollout status deployment/myapp-deployment -n ${KUBE_NAMESPACE}"
                    }
                }
            }
        }
    }
    
    post {
        always {
            echo 'Pipeline execution completed'
        }
        success {
            echo 'Pipeline completed successfully!'
            slackSend channel: '#deployments', message: "✅ Deployment successful for ${env.JOB_NAME} #${env.BUILD_NUMBER}"
        }
        failure {
            echo 'Pipeline failed!'
            slackSend channel: '#deployments', message: "❌ Deployment failed for ${env.JOB_NAME} #${env.BUILD_NUMBER}"
        }
    }
}

Jenkins配置说明

1. 凭据管理

在Jenkins中配置必要的凭据:

  • Docker Hub凭据(用于推送镜像)
  • Kubernetes配置凭据(用于访问集群)
# 创建Jenkins凭据的示例命令
# 在Jenkins界面中通过Manage Jenkins -> Manage Credentials进行配置

2. 系统配置

在Jenkins系统配置中添加:

  • Docker Daemon URL
  • Kubernetes API URL
  • 集群认证信息

自动化测试集成

单元测试配置

// test/app.test.js
const request = require('supertest');
const app = require('../app');

describe('API Tests', () => {
  test('should return welcome message', async () => {
    const response = await request(app)
      .get('/')
      .expect(200)
      .expect('Content-Type', /json/);
    
    expect(response.body.message).toBe('Hello from Docker + Kubernetes + Jenkins CI/CD!');
  });

  test('should return health status', async () => {
    const response = await request(app)
      .get('/health')
      .expect(200);
    
    expect(response.body.status).toBe('healthy');
  });
});
// package.json - 添加测试脚本
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch"
  },
  "devDependencies": {
    "jest": "^28.0.0",
    "supertest": "^6.0.0"
  }
}

测试覆盖率报告

// jest.config.js
module.exports = {
  collectCoverageFrom: [
    'src/**/*.{js,jsx}',
    '!src/index.js',
    '!src/server.js'
  ],
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov'],
  testEnvironment: 'node'
};

监控和日志管理

Prometheus监控配置

# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: ci-cd-demo
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
    
    scrape_configs:
    - job_name: 'kubernetes-pods'
      kubernetes_sd_configs:
      - role: pod
      
    - job_name: 'myapp'
      static_configs:
      - targets: ['myapp-service.ci-cd-demo.svc.cluster.local:80']

日志收集配置

# fluentd-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
  namespace: ci-cd-demo
data:
  fluent.conf: |
    <source>
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/fluentd-containers.log.pos
      tag kubernetes.*
      read_from_head true
      <parse>
        @type json
      </parse>
    </source>
    
    <match **>
      @type stdout
    </match>

安全最佳实践

容器安全扫描

# 使用Trivy进行安全扫描
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image your-username/myapp:latest

# 或者使用Clair进行扫描
docker run -d --name clair -p 6060:6060 quay.io/coreos/clair:v2.1.0

权限控制

# rbac.yaml - Kubernetes RBAC配置
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa
  namespace: ci-cd-demo

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: ci-cd-demo
  name: jenkins-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "update"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-role-binding
  namespace: ci-cd-demo
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: ci-cd-demo
roleRef:
  kind: Role
  name: jenkins-role
  apiGroup: rbac.authorization.k8s.io

性能优化建议

镜像优化

# 优化后的Dockerfile
FROM node:16-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:16-alpine

WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .

# 使用非root用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

CMD ["npm", "start"]

资源限制优化

# deployment.yaml - 优化资源配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  namespace: ci-cd-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: your-username/myapp:latest
        ports:
        - containerPort: 3000
        resources:
          requests:
            memory: "64Mi"
            cpu: "50m"
          limits:
            memory: "128Mi"
            cpu: "100m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3

故障排除和调试

常见问题排查

# 检查Pod状态
kubectl get pods -n ci-cd-demo

# 查看Pod详细信息
kubectl describe pod <pod-name> -n ci-cd-demo

# 查看日志
kubectl logs <pod-name> -n ci-cd-demo

# 检查部署状态
kubectl rollout status deployment/myapp-deployment -n ci-cd-demo

# 检查服务状态
kubectl get svc -n ci-cd-demo

Jenkins流水线调试

// 添加调试信息到Pipeline
stage('Debug Info') {
    steps {
        script {
            sh 'echo "Current branch: ${BRANCH_NAME}"'
            sh 'echo "Build number: ${BUILD_NUMBER}"'
            sh 'echo "Workspace: ${WORKSPACE}"'
            sh 'pwd'
            sh 'ls -la'
        }
    }
}

高级功能扩展

蓝绿部署策略

# blue-green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
  namespace: ci-cd-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: myapp
        image: your-username/myapp:v1.0.0
        ports:
        - containerPort: 3000

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
  namespace: ci-cd-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    metadata:
      labels:
        app: myapp
        version: green
    spec:
      containers:
      - name: myapp
        image: your-username/myapp:v2.0.0
        ports:
        - containerPort: 3000

---
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: ci-cd-demo
spec:
  selector:
    app: myapp
    version: green  # 默认指向green版本
  ports:
  - port: 80
    targetPort: 3000

回滚机制

stage('Rollback') {
    steps {
        script {
            withKubeConfig([credentialsId: 'k8s-config']) {
                sh """
                    kubectl rollout undo deployment/myapp-deployment -n ${KUBE_NAMESPACE}
                """
            }
        }
    }
}

总结

通过本文的详细演示,我们成功构建了一个完整的CI/CD自动化部署流水线,涵盖了从代码提交到生产环境部署的全流程。这个流水线具有以下特点:

  1. 容器化部署:使用Docker实现应用的标准化打包和部署
  2. 集群编排:利用Kubernetes实现高可用、可扩展的应用部署
  3. 自动化构建:通过Jenkins实现完整的CI/CD流程自动化
  4. 安全可靠:包含安全扫描、权限控制等最佳实践
  5. 监控告警:集成监控和日志收集功能

这个自动化流水线能够显著提升团队的开发效率,减少人为错误,确保软件交付的质量和速度。通过持续优化和完善,可以进一步扩展功能,满足更复杂的业务需求。

在实际使用中,建议根据具体的项目需求和环境特点进行相应的调整和优化,同时建立完善的监控和告警机制,确保系统的稳定运行。

相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000