基于CentOS的分布式GitLab+Jenkins+Docker架构:企业级CI/CD流水线实战全记录

发布于:2025-07-17 ⋅ 阅读:(21) ⋅ 点赞:(0)

引言:从单机到分布式容器架构的演进

在传统Web应用部署中,我们常常面临环境不一致、部署效率低下等问题。我曾经维护过一个需要手动在5台服务器上重复部署的游戏项目,每次发布都如同走钢丝。本文将详细分享如何基于CentOS系统,构建完整的分布式Docker架构,实现GitLab+Jenkins+生产环境的三节点CI/CD流水线,最终成功部署Web游戏项目的全过程。

第一部分:架构设计与环境规划

1.1 分布式节点规划

​三节点架构​​:

​GitLab节点​​:192.168.1.101(4核8G内存,200G存储)

​Jenkins节点​​:192.168.1.102(4核8G内存)

​生产环境节点​​:192.168.1.103(8核16G内存,NVIDIA T4 GPU)

# 各节点基础环境准备(CentOS 7.9)
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl enable --now docker

1.2 网络拓扑设计

图:三节点Docker Swarm网络拓扑

关键配置:

使用Overlay网络实现跨主机容器通信

为每个服务配置独立的子网

通过Nginx实现服务发现和负载均衡

# 初始化Docker Swarm集群(在生产节点)
docker swarm init --advertise-addr 192.168.1.103

# 在其他节点加入集群
docker swarm join --token SWMTKN-1-xxx 192.168.1.103:2377

第二部分:核心组件部署

2.1 GitLab容器化部署(192.168.1.101)

# 创建数据卷目录
mkdir -p /gitlab/{config,logs,data}

# 启动GitLab容器
docker run -d \
  --hostname gitlab.example.com \
  --publish 8443:443 --publish 8080:80 --publish 8022:22 \
  --name gitlab \
  --restart always \
  --volume /gitlab/config:/etc/gitlab \
  --volume /gitlab/logs:/var/log/gitlab \
  --volume /gitlab/data:/var/opt/gitlab \
  --shm-size 256m \
  gitlab/gitlab-ce:15.11.8-ce.0

性能调优​​:

修改/gitlab/config/gitlab.rb

unicorn['worker_processes'] = 4
postgresql['shared_buffers'] = "256MB"
sidekiq['concurrency'] = 10

2.2 Jenkins容器化部署(192.168.1.102)

# 自定义Jenkins Dockerfile
FROM jenkins/jenkins:2.414.3-lts-jdk11
USER root
RUN apt-get update && \
    apt-get install -y docker.io python3-pip && \
    pip3 install docker-compose
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN jenkins-plugin-cli -f /usr/share/jenkins/ref/plugins.txt
USER jenkins
# 启动Jenkins容器
docker run -d \
  --name jenkins \
  -p 8081:8080 -p 50000:50000 \
  -v /jenkins_home:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --restart unless-stopped \
  my-jenkins-image

关键插件​​:

Docker Pipeline

Blue Ocean

GitLab Plugin

SSH Pipeline Steps

第三部分:Web游戏项目容器化

3.1 游戏架构分析

项目采用前后端分离架构:

前端​​:Unity WebGL构建​

后端​​:Node.js游戏服务器

​数据库​​:MongoDB分片集群

​实时通信​​:WebSocket

3.2 多服务Docker Compose编排

version: '3.8'

services:
  game-frontend:
    image: registry.example.com/game-webgl:${TAG}
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
    networks:
      - game-network

  game-server:
    image: registry.example.com/game-server:${TAG}
    environment:
      - NODE_ENV=production
      - MONGO_URI=mongodb://mongo1:27017,mongo2:27017,mongo3:27017/game?replicaSet=rs0
    deploy:
      replicas: 2
    networks:
      - game-network
    depends_on:
      - mongo1
      - mongo2
      - mongo3

  mongo1:
    image: mongo:5.0
    command: mongod --replSet rs0 --bind_ip_all
    volumes:
      - mongo1-data:/data/db
    networks:
      - game-network

  # mongo2和mongo3配置类似...

  nginx:
    image: nginx:1.23
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - game-frontend
      - game-server
    networks:
      - game-network

networks:
  game-network:
    driver: overlay

volumes:
  mongo1-data:
  mongo2-data:
  mongo3-data:

3.3 Nginx关键配置

# nginx.conf
upstream game_servers {
    server game-server:3000;
}

server {
    listen 80;
    server_name game.example.com;

    location / {
        root /usr/share/nginx/html;
        try_files $uri /index.html;
    }

    location /api {
        proxy_pass http://game_servers;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

第四部分:CI/CD流水线实现

4.1 GitLab Runner配置

# 在Jenkins节点注册GitLab Runner
docker run -d --name gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /gitlab-runner/config:/etc/gitlab-runner \
  gitlab/gitlab-runner:v15.11.0

docker exec -it gitlab-runner gitlab-runner register

4.2 完整的Jenkinsfile

pipeline {
    agent {
        docker {
            image 'node:18'
            args '-v $HOME/.npm:/root/.npm'
        }
    }
    
    environment {
        DOCKER_REGISTRY = 'registry.example.com'
        PROJECT = 'web-game'
        DEPLOY_NODE = '192.168.1.103'
        SSH_CREDS = credentials('prod-ssh-key')
    }
    
    stages {
        stage('Checkout') {
            steps {
                git branch: 'main', 
                url: 'http://192.168.1.101:8080/game/web-game.git',
                credentialsId: 'gitlab-cred'
            }
        }
        
        stage('Build Frontend') {
            steps {
                dir('webgl-build') {
                    sh 'npm install'
                    sh 'npm run build'
                    sh 'docker build -t $DOCKER_REGISTRY/$PROJECT-webgl:$BUILD_NUMBER .'
                }
            }
        }
        
        stage('Build Server') {
            steps {
                dir('server') {
                    sh 'npm install --production'
                    sh 'docker build -t $DOCKER_REGISTRY/$PROJECT-server:$BUILD_NUMBER .'
                }
            }
        }
        
        stage('Push Images') {
            steps {
                withCredentials([usernamePassword(
                    credentialsId: 'docker-registry',
                    usernameVariable: 'DOCKER_USER',
                    passwordVariable: 'DOCKER_PASS'
                )]) {
                    sh 'echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin $DOCKER_REGISTRY'
                    sh 'docker push $DOCKER_REGISTRY/$PROJECT-webgl:$BUILD_NUMBER'
                    sh 'docker push $DOCKER_REGISTRY/$PROJECT-server:$BUILD_NUMBER'
                }
            }
        }
        
        stage('Deploy to Production') {
            steps {
                sshagent(['prod-ssh-key']) {
                    sh """
                        ssh -o StrictHostKeyChecking=no ubuntu@$DEPLOY_NODE \
                        "export TAG=$BUILD_NUMBER && \
                        docker stack deploy -c docker-compose.prod.yml game"
                    """
                }
            }
        }
    }
    
    post {
        failure {
            slackSend channel: '#game-alerts',
            message: "构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
        }
        success {
            slackSend channel: '#game-deploy',
            message: "新版本已上线: ${env.BUILD_NUMBER}"
        }
    }
}

4.3 关键优化点

  1. ​构建缓存​​:复用node_modules目录加速构建

  2. ​安全凭证​​:使用Jenkins Credential管理SSH密钥

  3. ​回滚机制​​:保留最近5个可用镜像版本

  4. ​通知系统​​:集成Slack实现构建状态实时通知

第五部分:监控与运维方案

5.1 分布式监控体系

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

services:
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    deploy:
      placement:
        constraints: [node.role == manager]

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    depends_on:
      - prometheus

  node-exporter:
    image: prom/node-exporter
    deploy:
      mode: global
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro

volumes:
  grafana-data:

第六部分:踩坑经验与进阶思考

6.1 典型问题解决方案

​问题1​​:跨主机容器网络不通

​现象​​:Swarm集群中容器无法通过服务名互相访问

​解决方案​​:检查防火墙规则:

sudo firewall-cmd --permanent --add-port=2377/tcp
sudo firewall-cmd --permanent --add-port=7946/tcp
sudo firewall-cmd --permanent --add-port=7946/udp
sudo firewall-cmd --permanent --add-port=4789/udp
sudo firewall-cmd --reload

验证Overlay网络状态:

docker network inspect game-network

优化方案​​:调整Runner配置:

[[runners]]
  name = "game-runner"
  url = "http://192.168.1.101:8080"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "alpine:3.16"
    privileged = true
    disable_cache = false
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    shm_size = "512m"

增加Runner并发数

6.2 性能优化成果

指标

优化前

优化后

构建时间

23分钟

8分钟

部署时间

15分钟

45秒

镜像大小

1.8GB

420MB

启动时间

30秒

3秒

结语:从实践到生产

这套基于CentOS的分布式Docker架构已经稳定运行6个月,支撑了日均50万PV的游戏服务。关键收获包括:

  1. ​基础设施即代码​​:所有环境配置版本化控制

  2. ​不可变基础设施​​:通过镜像而非修改运行环境来变更应用

  3. ​自动化一切​​:从代码提交到生产部署的全流程自动化

未来规划:

  1. 迁移到Kubernetes实现更高级的编排能力

  2. 引入服务网格(Service Mesh)管理微服务通信

  3. 实现基于Prometheus的自动扩缩容

希望这篇结合实战经验的详细分享,能为你的分布式容器化之路提供参考。欢迎在评论区交流你在CI/CD实践中遇到的挑战和解决方案!


网站公告

今日签到

点亮在社区的每一天
去签到