基于Docker + Jenkins + GitLab CI 的DevOps自动化部署实践

Nina740
Nina740 2026-02-26T14:01:09+08:00
0 0 3

引言:为什么需要CI/CD?——从“手动发布”到“自动交付”

在现代软件开发中,快速迭代、持续交付已成为企业竞争力的核心要素。然而,在传统的开发流程中,代码提交后往往需要人工干预完成构建、测试、打包、部署等环节,不仅效率低下,还容易因人为失误导致生产环境故障。

问题示例:某团队每周发布一次版本,每次发布前需手动执行以下操作:

  • 拉取最新代码
  • 手动编译项目
  • 执行单元测试与集成测试
  • 构建 Docker 镜像
  • 上传镜像至私有仓库
  • 登录服务器,停止旧服务,启动新容器
  • 验证服务是否正常运行

整个过程耗时约1.5小时,且一旦出错,排查成本极高。

为解决上述痛点,CI/CD(持续集成 / 持续部署) 成为现代 DevOps 实践的基石。它通过自动化流水线将代码变更快速、安全地交付到生产环境。

本文将以一个典型的 Web 应用项目为例,深入讲解如何基于 Docker 容器化技术Jenkins 自动化引擎GitLab CI/CD 平台,构建一套完整、可复用、高可用的自动化部署体系。我们将覆盖从代码提交到生产上线的全流程,并提供真实可运行的配置示例和最佳实践建议。

一、架构设计:整体系统拓扑与组件职责

1.1 整体架构图(文字描述)

[开发者] → [GitLab 仓库] → [GitLab CI/CD Pipeline] 
                         ↓
               [Jenkins CI/CD Server]
                         ↓
           [Docker Registry (e.g., Harbor)] 
                         ↓
         [Kubernetes / Docker Compose / VM] → [Production]

1.2 核心组件说明

组件 职责
GitLab 代码托管平台 + 内置 CI/CD 引擎,用于触发流水线、管理变量、存储日志
Jenkins 可扩展的 CI/CD 引擎,负责执行复杂任务(如多阶段构建、审批流、灰度发布)
Docker 应用容器化工具,将应用及其依赖打包成标准化镜像
Docker Registry 私有镜像仓库(如 Harbor、ECR、ACR),用于存储和分发镜像
目标部署环境 Kubernetes 集群、虚拟机或 Docker Compose 环境,承载最终运行的服务

架构优势

  • 解耦性好:各组件独立部署,便于维护与扩展。
  • 灵活性强:可按需选择使用 GitLab CI 或 Jenkins,甚至两者结合。
  • 安全性高:敏感信息(如密钥)可通过 Jenkins Credentials Store 管理。

二、前置准备:环境搭建与权限配置

2.1 服务器资源规划

建议至少三台服务器:

服务器角色 推荐配置 用途
GitLab Server 4vCPU, 8GB RAM, 100GB SSD 代码托管与 CI/CD 触发
Jenkins Server 8vCPU, 16GB RAM, 200GB SSD CI/CD 主控节点
Docker Registry Server 4vCPU, 8GB RAM, 500GB SSD 存储镜像
Target Deployment Host(s) 2vCPU, 4GB RAM, 100GB SSD 生产运行环境

💡 建议使用 Linux(Ubuntu 22.04 LTS / CentOS 7+)作为操作系统。

2.2 安装与配置核心组件

2.2.1 安装 GitLab(Omnibus 版本)

# Ubuntu 22.04
sudo apt update && sudo apt install -y curl openssh-server ca-certificates
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
sudo apt install -y gitlab-ee

# 启动并配置
sudo gitlab-ctl reconfigure
sudo gitlab-ctl restart

访问 http://<your-gitlab-ip>,设置管理员密码并初始化。

2.2.2 安装 Jenkins

# 添加 Jenkins GPG Key
wget -qO - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -

# 添加源
echo deb https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list

# 安装
sudo apt update
sudo apt install -y jenkins

# 启动
sudo systemctl enable jenkins
sudo systemctl start jenkins

默认端口为 8080,首次启动需通过 /var/lib/jenkins/secrets/initialAdminPassword 获取初始密码。

2.2.3 部署 Harbor(私有 Docker Registry)

# 安装 Helm
curl -fsSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

# 添加 Harbor Chart
helm repo add harbor https://helm.goharbor.io
helm repo update

# 部署 Harbor(以单机模式)
helm install harbor harbor/harbor \
  --namespace harbor \
  --create-namespace \
  --set expose.type=ingress \
  --set expose.ingress.hosts.core=harbor.example.com \
  --set hostname=harbor.example.com \
  --set credentials.adminPassword="Harbor123!" \
  --set externalURL=https://harbor.example.com

⚠️ 注意:需提前配置 DNS 将 harbor.example.com 解析到该服务器 IP。

三、项目结构与基础配置文件

假设我们有一个简单的 Node.js Express 项目,目录结构如下:

my-web-app/
├── .gitlab-ci.yml          # GitLab CI 配置文件
├── Jenkinsfile              # Jenkins 流水线定义(可选)
├── docker-compose.yml       # 本地测试部署
├── Dockerfile               # 容器化构建脚本
├── app.js                   # 主应用逻辑
├── package.json             # 依赖清单
└── test/
    └── unit.test.js         # 单元测试

3.1 Dockerfile(关键:构建可移植镜像)

# Dockerfile
FROM node:18-alpine AS base

WORKDIR /app

# 复制 package.json
COPY package*.json ./

# 安装依赖(减少缓存失效)
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 3000

# 启动命令
CMD ["node", "app.js"]

✅ 最佳实践:

  • 使用 npm ci 而非 npm install,确保一致性。
  • 使用 Alpine 镜像减小体积。
  • 分层构建,利用缓存机制提升构建速度。

3.2 docker-compose.yml(本地测试环境)

version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
    volumes:
      - ./logs:/app/logs
    restart: unless-stopped

启动方式:

docker-compose up -d

访问 http://localhost:3000 即可验证服务正常。

四、GitLab CI/CD 流水线配置详解

4.1 .gitlab-ci.yml 示例(轻量级流水线)

stages:
  - build
  - test
  - push-image
  - deploy

variables:
  IMAGE_NAME: registry.harbor.example.com/myapp/web-app
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

# 构建阶段:编译并生成镜像
build:
  stage: build
  image: docker:20.10.13
  services:
    - docker:dind
  script:
    - docker build -t ${IMAGE_NAME}:${IMAGE_TAG} .
    - docker login -u $DOCKER_USER -p $DOCKER_PASSWORD registry.harbor.example.com
  only:
    - main
  cache:
    key: docker-cache
    paths:
      - ~/.npm
    policy: pull-push

# 测试阶段:运行单元测试
test:
  stage: test
  image: node:18-alpine
  script:
    - npm install
    - npm run test
  artifacts:
    reports:
      junit: test/results.xml
  allow_failure: false

# 推送镜像到私有仓库
push-image:
  stage: push-image
  image: docker:20.10.13
  services:
    - docker:dind
  script:
    - docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${IMAGE_NAME}:latest
    - docker push ${IMAGE_NAME}:${IMAGE_TAG}
    - docker push ${IMAGE_NAME}:latest
  only:
    - main
  environment: production
  when: manual  # 手动触发,防止误推

# 部署到生产环境(通过 SSH)
deploy-production:
  stage: deploy
  image: alpine:latest
  script:
    - apk add --no-cache openssh-client
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh -o StrictHostKeyChecking=no user@prod-server << 'EOF'
        cd /opt/web-app
        docker stop web || true
        docker rm web || true
        docker rmi registry.harbor.example.com/myapp/web-app:${CI_COMMIT_SHORT_SHA} || true
        docker pull registry.harbor.example.com/myapp/web-app:${CI_COMMIT_SHORT_SHA}
        docker run -d --name web \
          -p 3000:3000 \
          -e NODE_ENV=production \
          registry.harbor.example.com/myapp/web-app:${CI_COMMIT_SHORT_SHA}
      EOF
  only:
    - main
  environment: production
  when: manual

4.2 GitLab CI 变量管理(安全策略)

在 GitLab 项目 Settings → CI/CD → Variables 中添加以下变量:

变量名 类型
DOCKER_USER admin Plain text
DOCKER_PASSWORD Harbor123! Secret
SSH_PRIVATE_KEY -----BEGIN RSA PRIVATE KEY-----... Secret
PROD_SERVER_IP 192.168.1.100 Plain text

🔒 重要提醒

  • 所有密码类变量必须设为 Secret
  • SSH_PRIVATE_KEY 必须是完整的私钥内容(含换行符),不可使用文件路径。
  • 使用 when: manual 控制部署节奏,避免频繁误操作。

五、Jenkins 流水线深度实践(复杂场景支持)

虽然 GitLab CI 已经足够强大,但在复杂场景下(如多环境审批、蓝绿部署、灰度发布),仍推荐使用 Jenkins。

5.1 Jenkinsfile(声明式流水线)

pipeline {
    agent any

    environment {
        DOCKER_REGISTRY = 'registry.harbor.example.com'
        APP_NAME = 'web-app'
        IMAGE_TAG = "${env.BUILD_ID}"
        PROD_HOST = 'user@192.168.1.100'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build & Test') {
            steps {
                sh 'npm install'
                sh 'npm run test:ci' // 生成 JUnit 报告
                archiveArtifacts artifacts: 'test/results.xml', pattern: false
            }
        }

        stage('Build Docker Image') {
            steps {
                script {
                    def dockerImage = docker.build("${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG}")
                    dockerImage.push()
                }
            }
        }

        stage('Approval - Production Deploy') {
            steps {
                input message: '确认部署到生产环境?',
                       ok: 'Deploy Now',
                       cancel: 'Cancel Deployment'
            }
        }

        stage('Deploy to Production') {
            steps {
                script {
                    def cmd = """
                        ssh -o StrictHostKeyChecking=no ${env.PROD_HOST} '
                            cd /opt/web-app &&
                            docker stop web || true &&
                            docker rm web || true &&
                            docker rmi ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG} || true &&
                            docker pull ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG} &&
                            docker run -d --name web \\
                              -p 3000:3000 \\
                              -e NODE_ENV=production \\
                              ${env.DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG}
                        '
                    """
                    sh cmd
                }
            }
        }
    }

    post {
        success {
            mail to: 'dev-team@example.com',
                 subject: "✅ Build Success: ${env.BUILD_ID}",
                 body: "Application deployed successfully!"
        }
        failure {
            mail to: 'dev-team@example.com',
                 subject: "❌ Build Failed: ${env.BUILD_ID}",
                 body: "Check Jenkins logs for details."
        }
    }
}

5.2 Jenkins 插件推荐

插件名称 功能说明
Pipeline 支持 Groovy 编写的声明式流水线
Docker Pipeline 提供 docker.build, docker.push 等 DSL
Credentials Binding 安全读取用户名/密码
Email Extension 发送邮件通知
Blue Ocean 可视化流水线界面

安装路径:Jenkins → Manage Plugins → Available Plugins

5.3 Jenkins 安全配置(最佳实践)

  1. 启用安全认证
    • 设置 Jenkins URL 为 https://jenkins.example.com
    • 启用 LDAP / GitHub OAuth 认证
  2. 最小权限原则
    • 为不同团队分配不同角色(Read, Build, Admin)
  3. 敏感信息保护
    • 使用 Credentials Store 存储密钥
    • 在 Jenkinsfile 中使用 withCredentials 绑定凭证
withCredentials([usernamePassword(
    credentialsId: 'harbor-credentials',
    usernameVariable: 'DOCKER_USER',
    passwordVariable: 'DOCKER_PASS'
)]) {
    sh "docker login -u $DOCKER_USER -p $DOCKER_PASS registry.harbor.example.com"
}

六、高级功能拓展:灰度发布与滚动更新

6.1 灰度发布策略(基于标签路由)

在生产环境中,可采用灰度发布降低风险。例如:

# docker-compose.prod.yml
version: '3.8'

services:
  web:
    image: registry.harbor.example.com/myapp/web-app:v1.2.0
    labels:
      - "traefik.http.routers.web.middlewares=gray-middleware@file"
    networks:
      - app-net

  web-gray:
    image: registry.harbor.example.com/myapp/web-app:v1.2.0
    labels:
      - "traefik.http.routers.gray.rule=Headers(`X-User-ID`, `12345`)"
    networks:
      - app-net

配合 Traefik 反向代理实现用户级灰度分流。

6.2 滚动更新(Rolling Update)配置

# docker-compose.yml (for production)
version: '3.8'

services:
  web:
    image: registry.harbor.example.com/myapp/web-app:${TAG}
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
      rollback_config:
        parallelism: 1
        delay: 10s
    ports:
      - "3000:3000"

📌 优点:

  • 服务不中断
  • 逐步替换实例
  • 出现问题可快速回滚

七、监控与日志收集(运维视角)

7.1 日志聚合方案(ELK Stack)

  • Filebeat:采集 Jenkins/GitLab/应用日志
  • Logstash:解析日志格式
  • Elasticsearch:索引存储
  • Kibana:可视化分析

部署示例(简化版):

version: '3'
services:
  elasticsearch:
    image: elasticsearch:8.7.0
    environment:
      - discovery.type=single-node
    volumes:
      - esdata:/usr/share/elasticsearch/data

  kibana:
    image: kibana:8.7.0
    depends_on:
      - elasticsearch
    ports:
      - "5601:5601"

  filebeat:
    image: docker.elastic.co/beats/filebeat:8.7.0
    volumes:
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml
      - /var/log:/var/log
    command: >
      filebeat -c /usr/share/filebeat/filebeat.yml
      -e

volumes:
  esdata:

7.2 Jenkins 与 GitLab 日志保留策略

平台 日志保留周期 清理策略
Jenkins 30 天 通过 Retention Time 配置
GitLab CI 90 天 项目设置中可调整

✅ 建议开启日志归档并定期导出备份。

八、总结与最佳实践清单

8.1 关键成功要素

要素 说明
基础设施即代码(IaC) 使用 Ansible/Terraform 管理服务器配置
镜像签名与扫描 使用 Trivy、Clair 对镜像进行漏洞扫描
流水线版本化 .gitlab-ci.ymlJenkinsfile 提交至 Git
失败自动重试 在 Jenkins/GitLab 中配置 retry 机制
变更追踪与审计 所有部署操作记录在日志中,可追溯

8.2 推荐工具链组合

场景 推荐工具
轻量级项目 GitLab CI + Docker + Docker Compose
大型企业 Jenkins + Harbor + Kubernetes + Argo CD
微服务架构 GitLab CI + Jenkins Pipeline + Istio + Prometheus

九、结语:迈向真正的 DevOps 之路

通过本实践,我们实现了从代码提交到生产部署的全流程自动化。这不仅显著提升了交付效率(从数小时缩短至几分钟),更增强了系统的稳定性与可追溯性。

记住一句话
“自动化不是目的,而是手段;真正的目标是让工程师专注创造价值,而不是重复劳动。”

未来,随着云原生生态的发展,我们可以进一步引入 ArgoCDTektonFlux 等现代化工具,构建更智能、自愈的 CI/CD 系统。

但无论工具如何演进,清晰的流程设计、完善的监控体系、持续的安全意识,永远是 DevOps 成功的基石。

📌 附录:一键部署脚本(Bash)

#!/bin/bash
# deploy-all.sh —— 快速部署整套 CI/CD 环境

# 检查依赖
command -v docker >/dev/null || { echo "Docker not installed"; exit 1; }

# 启动 Harbor
helm install harbor harbor/harbor \
  --namespace harbor \
  --create-namespace \
  --set hostname=harbor.example.com \
  --set credentials.adminPassword="Harbor123!"

# 启动 Jenkins
docker run -d --name jenkins \
  -p 8080:8080 \
  -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  jenkins/jenkins:lts

echo "✅ All components deployed! Access:"
echo "   Jenkins: http://localhost:8080"
echo "   Harbor: https://harbor.example.com"

📝 使用前请根据实际网络环境修改域名和密码。

🌐 参考资料

📌 作者:资深 DevOps 工程师
📅 最后更新:2025年4月5日
🔖 标签:DevOps, Docker, Jenkins, GitLab CI, 自动化部署

相关推荐
广告位招租

相似文章

    评论 (0)

    0/2000