基于GitLab、Docker及私有镜像仓库的部署自动化方案咨询
这问题我熟,结合你现有的技术栈,有几个非常靠谱的自动化部署方案,按推荐程度排序给你拆解:
既然你已经在用 GitLab CI 构建推送镜像,那直接把部署环节加到 CI 流程里是成本最低的方案,核心思路是让 GitLab Runner 通过 SSH 连接生产服务器,执行部署命令。
具体步骤:
配置生产服务器的 SSH 访问权限
- 在 GitLab Runner 所在机器(或用 GitLab 共享 Runner 的话,直接生成密钥对)生成 SSH 密钥:
ssh-keygen -t ed25519 -C "gitlab-ci-deploy" - 将公钥内容添加到生产服务器的
~/.ssh/authorized_keys文件中 - 将私钥添加到 GitLab 项目的 CI/CD 变量里(路径:项目 Settings → CI/CD → Variables),命名比如
PROD_SSH_KEY,记得勾选「Protect variable」和「Mask variable」
- 在 GitLab Runner 所在机器(或用 GitLab 共享 Runner 的话,直接生成密钥对)生成 SSH 密钥:
编写 CI 部署 Job
在你的.gitlab-ci.yml里新增deploy阶段,依赖之前的build和push阶段,示例代码如下:stages: - build - push - deploy # 你的构建、推送镜像 Job 保持不变... deploy_to_prod: stage: deploy only: - master # 只在 master 分支提交后触发 script: # 安装 SSH 客户端(如果 Runner 镜像里没有的话) - 'which ssh-agent || (apt-get update -y && apt-get install openssh-client -y)' # 启动 SSH 代理并加载私钥 - eval $(ssh-agent -s) - echo "$PROD_SSH_KEY" | tr -d '\r' | ssh-add - # 配置 SSH 信任生产服务器 - mkdir -p ~/.ssh - chmod 700 ~/.ssh - ssh-keyscan -H 你的生产服务器IP/域名 >> ~/.ssh/known_hosts - chmod 644 ~/.ssh/known_hosts # 远程执行部署命令 - ssh 生产服务器用户名@你的生产服务器IP " # 停止旧容器(容器不存在时不报错) docker stop your-app-container || true; # 删除旧容器(容器不存在时不报错) docker rm your-app-container || true; # 拉取最新镜像(用CI_COMMIT_SHA做标签,避免缓存问题) docker pull 你的私有Registry地址/your-app:$CI_COMMIT_SHA; # 启动新容器 docker run -d --name your-app-container -p 80:80 你的私有Registry地址/your-app:$CI_COMMIT_SHA "
关键细节提醒:
- 用
|| true保证容器未运行时,命令不会导致 CI 流水线失败 - 镜像标签用
$CI_COMMIT_SHA(GitLab 内置变量,对应当前提交的哈希值),比用latest更可靠,能精准追踪部署版本 - 确保生产服务器能访问你的私有 Docker Registry(内网环境一般没问题,外网的话要给生产服务器配置 Registry 拉取凭证)
如果你的生产环境以后要扩缩容、做滚动更新或者多服务管理,提前用 Kubernetes 配合 GitLab CD 是更长远的方案。
具体步骤:
在生产服务器搭建轻量 Kubernetes 集群
单节点的话可以用 K3s、MicroK8s 这类轻量发行版,几分钟就能装好;多节点就用标准 Kubernetes。GitLab 集成 Kubernetes 集群
在 GitLab 项目的 Infrastructure → Kubernetes clusters 里添加你的集群,GitLab 会自动配置好kubectl访问权限。编写 Kubernetes 部署配置
新建k8s/deployment.yaml文件,用变量替换镜像标签:apiVersion: apps/v1 kind: Deployment metadata: name: your-app spec: replicas: 1 selector: matchLabels: app: your-app template: metadata: labels: app: your-app spec: containers: - name: your-app image: 你的私有Registry地址/your-app:$CI_COMMIT_SHA ports: - containerPort: 80CI 里添加部署 Job
在.gitlab-ci.yml里新增部署 Job,用kubectl应用配置:deploy_to_prod: stage: deploy only: - master script: - kubectl apply -f k8s/deployment.yaml
优势:
- Kubernetes 会自动处理容器的停止、拉取、启动,还能配置滚动更新,避免服务 downtime
- 后续加节点、扩缩容、配置服务发现都很方便
- GitLab 内置的 Kubernetes 集成能自动管理集群凭证,不用手动维护 SSH 密钥
如果你的团队不想让 GitLab 直接访问生产服务器(比如严格的网络隔离政策),可以用 Webhook 触发生产服务器的本地部署脚本。
具体步骤:
在生产服务器搭建 Webhook 服务
用 Python Flask/Go/Node.js 写一个简单的 Web 服务,监听 POST 请求,比如:from flask import Flask, request import subprocess import hmac hashlib app = Flask(__name__) WEBHOOK_SECRET = "你的密钥" def verify_signature(payload, signature): # 验证 GitLab 发送的签名,防止恶意请求 secret = bytes(WEBHOOK_SECRET, 'utf-8') digest = hmac.new(secret, payload, hashlib.sha256).hexdigest() return hmac.compare_digest(f'sha256={digest}', signature) @app.route('/deploy', methods=['POST']) def deploy(): if not verify_signature(request.data, request.headers.get('X-Gitlab-Token')): return "Invalid signature", 403 # 执行部署脚本 subprocess.run(['/path/to/your/deploy.sh'], check=True) return "Deploy started", 200 if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)在 GitLab 配置 Webhook
进入项目 Settings → Integrations,添加 Webhook:- URL 填
http://你的生产服务器IP:8080/deploy - 触发事件选「Pipeline succeeded」
- Secret token 填你刚才设置的密钥
- 勾选「Enable SSL verification」(如果用 HTTPS 的话)
- URL 填
编写生产服务器上的部署脚本
deploy.sh#!/bin/bash docker stop your-app-container || true docker rm your-app-container || true docker pull 你的私有Registry地址/your-app:$(curl -s http://gitlab-api-url/projects/你的项目ID/repository/commits/master | jq -r '.id') docker run -d --name your-app-container -p 80:80 你的私有Registry地址/your-app:刚才获取的SHA值
优势:
- GitLab 和生产服务器完全隔离,生产服务器不用暴露 SSH 端口
- 可以在 Webhook 服务里加更复杂的权限验证、日志记录
内容的提问来源于stack exchange,提问作者hopsey

