香港服务器搭建GitLab自托管 + CI/CD流水线:从代码提交到自动部署全流程配置
GitHub Actions 虽然方便,但代码和 CI/CD 流程都在 GitHub 服务器上运行,对代码保密性有要求的企业不适合。在香港服务器上自托管 GitLab CE(社区版,免费),既保证代码私密性,又获得完整的 CI/CD 能力,且 GitLab 内置的 Container Registry、Issue 追踪、Code Review 工具让研发团队无需额外工具。
一、GitLab CE 系统要求
| 用户规模 | 最低配置 | 推荐配置 |
|---|---|---|
| 1~10 人团队 | 4核8G | 4核16G |
| 10~50 人团队 | 8核16G | 16核32G |
| 50~200 人团队 | 16核32G | 32核64G |
二、Docker Compose 部署 GitLab
<code"># /opt/gitlab/docker-compose.yml
version: '3.8'
services:
gitlab:
image: gitlab/gitlab-ce:17.3.0-ce.0
container_name: gitlab
restart: unless-stopped
hostname: gitlab.yourdomain.com
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.yourdomain.com'
# HTTPS 配置(使用已有证书)
nginx['ssl_certificate'] = '/etc/gitlab/ssl/gitlab.crt'
nginx['ssl_certificate_key'] = '/etc/gitlab/ssl/gitlab.key'
nginx['redirect_http_to_https'] = true
# 邮件配置(用于用户注册、通知)
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.gmail.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "gitlab@yourdomain.com"
gitlab_rails['smtp_password'] = "app_password"
gitlab_rails['smtp_tls'] = false
gitlab_rails['smtp_starttls_auto'] = true
gitlab_rails['gitlab_email_from'] = "gitlab@yourdomain.com"
# 性能调优(4核8G 服务器)
puma['worker_processes'] = 3
sidekiq['max_concurrency'] = 10
postgresql['shared_buffers'] = "512MB"
# 禁用不需要的服务(节省资源)
prometheus_monitoring['enable'] = false
grafana['enable'] = false
# 注册限制(仅允许邀请注册)
gitlab_rails['gitlab_signup_enabled'] = false
ports:
- "80:80"
- "443:443"
- "22:22" # SSH Git 操作
volumes:
- /opt/gitlab/config:/etc/gitlab
- /opt/gitlab/logs:/var/log/gitlab
- /opt/gitlab/data:/var/opt/gitlab
- /etc/letsencrypt/live/gitlab.yourdomain.com/fullchain.pem:/etc/gitlab/ssl/gitlab.crt:ro
- /etc/letsencrypt/live/gitlab.yourdomain.com/privkey.pem:/etc/gitlab/ssl/gitlab.key:ro
shm_size: '256m'<code"># 首次启动(约3~5分钟) cd /opt/gitlab && docker compose up -d # 查看启动进度 docker logs -f gitlab | grep "gitlab Reconfigured" # 获取初始 root 密码 docker exec gitlab grep 'Password:' /etc/gitlab/initial_root_password # 访问 https://gitlab.yourdomain.com,使用 root 账号登录
三、注册 GitLab Runner
<code"># 在另一台服务器(或同台)安装 GitLab Runner curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | bash apt install -y gitlab-runner # 在 GitLab 界面获取 Runner 注册 Token: # Settings → CI/CD → Runners → New project runner # 注册 Runner(Docker 执行器) gitlab-runner register \ --url "https://gitlab.yourdomain.com" \ --token "your_runner_token" \ --executor "docker" \ --docker-image "alpine:latest" \ --description "hk-docker-runner" \ --tag-list "docker,hk" \ --run-untagged true \ --locked false # 查看 Runner 状态 gitlab-runner status gitlab-runner list
四、CI/CD 流水线配置(.gitlab-ci.yml)
<code"># .gitlab-ci.yml(放在项目根目录)
stages:
- test
- build
- deploy
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
DEPLOY_HOST: "root@香港服务器IP"
# ── 阶段1:代码测试 ──
test:unit:
stage: test
image: python:3.12-slim
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .pip-cache/
script:
- pip install -r requirements.txt --cache-dir .pip-cache
- pytest tests/ -v --cov=app --cov-report=xml
coverage: '/TOTAL.*\s+(\d+%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
# ── 阶段2:构建 Docker 镜像 ──
build:docker:
stage: build
image: docker:24
services:
- docker:24-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
# 同时打 latest 标签
- docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
rules:
- if: $CI_COMMIT_BRANCH == "main"
# ── 阶段3:部署到生产服务器 ──
deploy:production:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
# SSH 私钥从 GitLab CI/CD Variables 读取(不硬编码)
- echo "$DEPLOY_SSH_KEY" | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
- ssh-keyscan -H 香港服务器IP >> ~/.ssh/known_hosts
script:
- |
ssh $DEPLOY_HOST "
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY &&
docker pull $IMAGE_TAG &&
docker stop myapp 2>/dev/null || true &&
docker rm myapp 2>/dev/null || true &&
docker run -d --name myapp \
--restart unless-stopped \
-p 127.0.0.1:8000:8000 \
--env-file /opt/myapp/.env \
$IMAGE_TAG &&
sleep 5 &&
curl -sf http://localhost:8000/health && echo '部署成功 ✓'
"
environment:
name: production
url: https://yourdomain.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual # 生产部署需要人工确认五、在 GitLab 界面配置 CI/CD 变量
「项目 → Settings → CI/CD → Variables」中添加:
| 变量名 | 值 | 是否加密 |
|---|---|---|
| DEPLOY_SSH_KEY | 部署用 SSH 私钥内容 | ✅ Masked + Protected |
| DATABASE_URL | 生产数据库连接字符串 | ✅ Masked |
| STRIPE_SECRET_KEY | Stripe 密钥 | ✅ Masked |
六、流水线效果展示
<code">
代码推送到 main 分支
│
▼
✅ test:unit(约 2 分钟)
├── 单元测试通过(98% 覆盖率)
└── 覆盖率报告上传到 GitLab
│
▼
✅ build:docker(约 3 分钟)
├── 构建 Docker 镜像
└── 推送到 GitLab Container Registry
│
▼
⏸️ deploy:production(等待手动确认)
└── 点击「Run」→ 自动 SSH 到香港服务器 → 拉取新镜像 → 重启容器 → 健康检查
七、总结
GitLab 自托管将代码仓库、CI/CD、镜像仓库集于一身,数据完全在自己的香港服务器上,满足代码保密和合规要求。CI/CD 流水线将「人工测试→人工构建→人工部署」的重复劳动完全自动化,开发团队专注于写代码,其余交给流水线处理。