免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

openEuler 上容器化部署 GitLab:从环境准备到运维实践

openEuler 上容器化部署 GitLab:从环境准备到运维实践 上个月帮团队搭一套内部代码托管平台手头的服务器只有 2C4G系统装的是 openEuler 22.03 SP3。当时方案基本没啥悬念openEuler GitLab 容器化部署。系统版本选好之后GitLab 用 rpm 包虽然也能装但升级、回滚、迁移每一项都折磨人容器化之后至少这些麻烦事能少一大半。这篇文章把我从零开始的完整过程、每条命令为什么这么写、以及中途踩过的坑都记录下来适合想在 openEuler 上快速自建 GitLab 的运维和开发同学参考尤其是跟我一样手头资源不宽裕、又想跑得稳的这种情况。我会尽量把每一步的操作逻辑讲透让你照着做能跑通换成别的发行版也知道要怎么变通。1. 为什么是openEuler GitLab 容器而不是 rpm 直接装1.1 rpm 包安装的隐藏成本很多人第一次装 GitLab第一反应就是去找 rpm 包。GitLab 官方其实提供了 RPM 仓库openEuler 兼容 CentOS 的包格式理论上可以直接用。但实际整一遍之后你会发现rpm 方式有一堆隐藏成本GitLab 的依赖特别多redis、postgresql、nginx、sidekiq、puma 这些组件一起装上系统被塞得满满当当升级的时候要停服务、备份、替换包、改配置任何一个环节出错都可能让数据访问出问题一旦这台机器坏了把整个 GitLab 环境迁移到新机器是个大工程各种组件版本、配置路径、权限关系都要重新对齐系统里其他服务如果也在用 redis 或者 postgresql版本冲突基本躲不掉。我见过太多人在这上面耗时一整天最后 GitLab 还是起不来。1.2 容器化到底解决了什么用容器方式跑 GitLab本质上就是把一个运行环境打包成了一个标准单元。GitLab 官方提供的gitlab/gitlab-ce镜像omnibus 方案把所有组件都整合在了一个容器里外部需要关心的只有三层数据卷/etc/gitlab配置文件/var/log/gitlab日志/var/opt/gitlabGit 仓库、数据库、备份文件等实际数据这三层数据卷挂到宿主机之后升级就是停旧容器、换新镜像、重新启动数据完全不受影响。迁移就是打包数据目录到新机器原样启动。这种操作范式对人力的节省是实打实的。另外容器还天然做了资源隔离和回收。GitLab 是出了名的吃内存装在系统里卸载不干净而容器方式想清掉直接docker stop docker rm就结束了系统干干净净。1.3 我选的版本与技术路线GitLab 的版本节奏是大版本每季度一个用最新版往往撞上各种新特性的调整。我这次选择的是GitLab CE 16.x 版本线具体 tag 用的是16.11.2-ce.0。16.x 整体稳定Web 界面、CI/CD 能力都比较成熟内存占用也相对可控。技术路线拆开看是这样操作系统openEuler 22.03 LTS SP3容器引擎Docker CE社区版编排描述docker-compose现在直接是docker compose子命令GitLabgitlab/gitlab-ce 社区版镜像数据挂载宿主机/data/gitlab下按 config、logs、data 三个子目录持久化这套组合的好处是openEuler 兼容 CentOS 的包管理方式安装 Docker CE 很顺docker compose 的 YAML 文件一眼能看懂后续维护也简单。2. openEuler 22.03 环境准备从 dnf 仓库到 Docker 引擎2.1 用 dnf 把基础依赖装齐openEuler 22.03 默认包管理器是 dnf装依赖比 yum 时代体验好不少。首先更新一下索引和系统包让环境进入到最新状态dnf makecache dnf -y update这里有个建议不要跳过makecache。新装系统里 dnf 的缓存可能是旧的仓库元数据更新一下能避免某些包因为版本不对而装不上。接着安装一些常用工具比如vim、lsof、net-tools、tar、chrony等dnf -y install vim lsof net-tools tar chrony systemctl enable --now chronyd chronyc sourceschrony是时间同步工具很多人容易忽视但 GitLab 的 Git 提交时间、HTTPS 证书校验、备份时间戳全依赖系统时钟。时钟一旦偏移GitLab 后台容易出现响应时间异常之类的诡异问题。所以时间同步一定要在装 GitLab 之前搞定。2.2 安装 Docker CE 仓库与引擎openEuler 的官方源里其实也有 docker 相关的包但版本通常偏旧。我们要装的是 Docker CE直接用 Docker 官方 CentOS 仓库就行因为 openEuler 对这个仓库的兼容性做得很好。执行下面这段dnf -y install dnf-plugins-core dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo仓库配好之后执行安装dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin可以看到我特意把docker-buildx-plugin和docker-compose-plugin一起装了。新版 Docker 已经不再建议单独装 docker-compose 二进制而是用docker compose这个内置子命令少装一个依赖少一个版本坑。装完启动 Dockersystemctl enable --now docker systemctl status docker --no-pager正常情况下会显示active (running)。用docker version确认一下 Server 和 Client 版本一致基本就绪。2.3 容器镜像加速与拉取策略Docker 装好之后从 Docker Hub 拉 GitLab 镜像在国内网络环境下通常会比较慢因为镜像仓库服务在国外。这个问题的解决办法是给 Docker 配置国内镜像加速器。修改/etc/docker/daemon.json{ registry-mirrors: [ https://docker.m.daocloud.io, https://docker.1ms.run ], data-root: /data/docker }这里有个顺手做的操作把 Docker 的数据目录从系统的/var/lib/docker挪到了/data/docker。因为 GitLab 镜像本身就有 1GB 多容器运行后产生的层还会继续增长如果系统盘容量本来就不宽裕数据目录放独立数据盘能避免后面磁盘被镜像撑爆的尴尬。改完重启 Dockersystemctl restart docker docker info | grep -A 3 Registry Mirrors看到加速器地址已经生效就可以拉镜像了docker pull gitlab/gitlab-ce:16.11.2-ce.0首次拉取建议耐心等镜像比较大如果中途断了可以重复执行命令Docker 会在已有层的基础上继续不用重新拉。3. 启动 GitLab 容器之前先把目录和参数想清楚3.1 数据目录规划很多新手上来就是一行docker run参数堆得乱七八糟后面根本没法维护。我更建议先把目录结构规划好做成 compose 文件以后启动、升级只要docker compose up -d一条命令搞定。我的目录规划是这样/data/gitlab/ ├── config/ # GitLab 配置文件 ├── logs/ # 所有子组件日志 └── data/ # Git 仓库、数据库文件、备份这样做的意义将来如果要迁移只需要打包/data/gitlab这一个目录不用考虑容器本身将来如果容器崩溃宿主机上的数据完全不受影响换个镜像重新拉起即可。3.2 docker-compose 文件逐行解读在/data/gitlab/下创建docker-compose.yml内容如下version: 3.8 services: gitlab: image: gitlab/gitlab-ce:16.11.2-ce.0 container_name: gitlab restart: always hostname: git.example.internal environment: TZ: Asia/Shanghai GITLAB_OMNIBUS_CONFIG: | external_url http://git.example.internal:8080 gitlab_rails[gitlab_shell_ssh_port] 2222 gitlab_rails[time_zone] Asia/Shanghai puma[worker_processes] 2 sidekiq[max_concurrency] 5 postgresql[shared_buffers] 256MB prometheus[enable] false grafana[enable] false gitlab_rails[initial_root_password] YourStrongPassw0rd! ports: - 8080:80 - 8443:443 - 2222:22 volumes: - /data/gitlab/config:/etc/gitlab - /data/gitlab/logs:/var/log/gitlab - /data/gitlab/data:/var/opt/gitlab shm_size: 256m乍一看配置不少但每个字段其实都有明确的作用。3.3 关键参数背后的逻辑hostname容器内部的主机名会作为 GitLab 生成 clone 地址的默认域名兜底。如果你的 GitLab 是内网 IP 访问这里可以直接写内网 IP或者写一个后面能改的占位域名等配置阶段再统一调整。external_url对外访问地址GitLab 的 nginx 和 Rails 都会根据这个来生成页面里的链接。这里我写成http://git.example.internal:8080是因为宿主机把容器的 80 端口映射到了宿主机的 8080外部用户访问的是 8080 端口。gitlab_rails[gitlab_shell_ssh_port] 2222告诉 GitLab SSH 服务跑在宿主机的 2222 端口上这样项目的 SSH clone 地址才会显示成ssh://git主机地址:2222/group/repo.git否则它会默认给 22 端口。puma[worker_processes] 2puma worker 数默认是 CPU 核数加 12C 的机器默认 3 个。GitLab 16 用 puma 接管了原来的 unicornworker 数直接决定内存占用我手动压到 2。sidekiq[max_concurrency] 5sidekiq 是 GitLab 后台异步任务的处理进程默认并发数可以到 25对内存很不友好5 对于小团队完全够用。prometheus[enable] false和grafana[enable] false内置监控组件很占内存小内存机器直接关掉需要监控另想办法。postgresql[shared_buffers] 256MB数据库共享缓存默认是机器内存的四分之一对 4G 机器来说默认 1GB 偏大手动限到 256MB。shm_size: 256m给容器 /dev/shm 共享内存设一个合理值。GitLab 内部的 nginx 代理和 puma 会用到共享内存太小会报No space left on device。restart: always宿主机重启或者 Docker 服务重启后容器自动拉起。initial_root_password只会在首次初始化时生效给 root 用户设置一个临时密码。注意要包含大小写字母和数字否则 GitLab 的密码策略校验会拒绝。compose 文件写好后启动就是两条命令的事cd /data/gitlab docker compose up -d4. 初次启动等待、健康检查与初始化配置4.1 容器启动与健康检查容器启动后docker ps看不到 healthy 状态因为它会先执行一段漫长的初始化。第一次启动时 GitLab 会运行gitlab-ctl reconfigure期间要配置数据库、编译一些静态资源五分钟左右是正常的。查看启动日志docker logs -f gitlab当你看到类似下面这样的输出时说明初始化进入了尾声Running handlers: Running handlers complete gitlab Reconfigured!此时再用docker ps看STATUS 列通常会从starting变成(healthy)如果还是starting再等一两分钟即可。别急着马上打开页面nginx 可能还在做最后一轮预热。4.2 修改 external_url 和基本安全设置初次访问之前我建议先把几个基础配置打磨好免得以后项目建多了再改影响旧链接。进入容器直接编辑/etc/gitlab/gitlab.rbdocker exec -it gitlab bash vi /etc/gitlab/gitlab.rb因为我用了GITLAB_OMNIBUS_CONFIG环境变量容器启动时这些配置已经生效。但有些场景下大家喜欢直接编辑 gitlab.rb我需要提醒一点两种方式不要混用环境变量方式改起来简单但 gitlab.rb 里改了更容易被环境变量覆盖二选一即可。我这边是以环境变量为主的所以只需要确认几个关键点external_url是否已经设置成http://git.example.internal:8080gitlab_rails[gitlab_shell_ssh_port]是否为 2222如果调整了配置在容器里执行gitlab-ctl reconfigure gitlab-ctl restart另外强烈建议在管理界面关闭用户自助注册。项目托管平台一般只服务内部成员开放注册只会引来垃圾账号。路径是Admin 区域从右上角头像进入→ Settings → General → Sign-up restrictions取消勾选 Sign-up enabled。4.3 root 初始密码与首次登录GitLab 17 之前的版本首次启动后会生成一个初始密码文件docker exec -it gitlab cat /etc/gitlab/initial_root_password内容长这样# WARNING: This value is valid only for the following 24 hours... Password: xxxxx注意文件里白纸黑字写了这个密码只在首次启动后 24 小时内有效之后文件会被自动删除。所以要么第一时间登录改密码要么干脆用我在环境变量里写的initial_root_password直接登录。如果两者都错过了也不用慌可以用 Rails 控制台重置docker exec -it gitlab bash gitlab-rails console进入 console 后执行user User.find_by_username(root) user.password NewStrongPassw0rd! user.password_confirmation NewStrongPassw0rd! user.save!退出控制台后新密码立即生效。4.4 第一次创建项目和 SSH 克隆登录后新建一个测试项目看看 clone 地址是否正常显示。正常情况下页面上会出现两种地址HTTPhttp://git.example.internal:8080/root/demo.gitSSHssh://gitgit.example.internal:2222/root/demo.git如果 SSH 地址端口不对多半是gitlab_shell_ssh_port没生效回到配置里检查。然后在本机配置 SSH 密钥ssh-keygen -t ed25519 -C yourmailexample.com cat ~/.ssh/id_ed25519.pub把公钥内容粘贴到 GitLab 的 Preferences → SSH Keys 里然后就能直接克隆了git clone ssh://gitgit.example.internal:2222/root/demo.git如果克隆时提示Permission denied (publickey)先确认密钥是否已经添加到 GitLab以及当前用户是不是用了正确的私钥文件。可以把ssh -T gitgit.example.internal -p 2222跑一下看看服务端返回什么。5. 4G 内存下的 GitLab 优化与踩坑排查链路5.1 内存占用分析与调优GitLab 官方建议内存至少 4GB但对一个真正跑起来的实例来说4GB 是很紧张的。启动完成后我第一时间观察了内存docker stats --no-stream初始阶段登录和后台任务刚起来内存占用在 1.8GB 左右稳定一会儿后在 2.2GB 左右。如果再叠加系统本身和其他服务2C4G 的机器压力不小。我采用了一套组合拳来控制内存。第一是前面配置里已经做过的关掉 Prometheus 和 Grafana限制 puma worker 和 sidekiq 并发。第二是开启系统 swap防止瞬时冲高导致 OOMfallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo /swapfile none swap sw 0 0 /etc/fstab这么做不是为了让 GitLab 跑得更快而是防止高峰时内存瞬间耗尽被系统 OOM killer 直接杀掉容器。有了 swap 打底最坏情况只是磁盘换页变慢服务不会闪断。如果以后团队规模变大、活跃用户增多内存还是不够的话再考虑升到 8G或者把容器里的postgresql单独拆出去。对于小团队内部托管这样配置是性价比最高的方案。5.2 容器反复重启的一个隐蔽原因启动后我遇到过容器隔几分钟就被重启一次的情况docker logs里看不出明显的错误信息全是 nginx 或 puma 的启动日志。刚开始以为是 puma worker 数设太低导致探活失败后来排查到真正原因是共享内存不足。GitLab 的 nginx 和 puma 都会大量使用 /dev/shm 作为临时缓冲默认情况下 Docker 给容器的共享内存只有 64MB在页面访问量稍有波动时很容易打满。解决办法就是我前面提到过的在 compose 文件里加shm_size: 256m。加上之后容器非常稳定再也没出现自动重启。这是一个很典型的排查链路从日志往外走、方向走错了半天的坑。后来我把自己写的排查顺序固定成了先docker stats看资源层再docker logs看应用层最后再看配置变更历史。资源层的问题往往被日志层的表象盖住一定要先从下往上排除。5.3 防火墙与安全组在云服务器上部署除了系统防火墙还要检查云平台的安全组规则。openEuler 默认的 firewalld 可能是开着的需要显式放行端口systemctl status firewalld firewall-cmd --permanent --add-port8080/tcp firewall-cmd --permanent --add-port2222/tcp firewall-cmd --reload firewall-cmd --list-ports如果你是在云平台买的机器安全组里也要把 8080 和 2222 端口放出来否则客户端访问直接超时。注意安全组和系统防火墙是两层任何一层没放行都连不上。5.4 openEuler 特有的 SELinux 相关坑openEuler 默认开启了 SELinux并且处于 enforcing 模式。大部分情况下 Docker 容器挂载数据卷读写是没问题的但在某些场景下比如容器内要读取宿主机备份文件、或者执行跨目录的恢复操作时会碰到Permission denied这类错误。如果排查之后确认是 SELinux 拦截最直接的临时验证方法是把 SELinux 切到 permissive 模式再看setenforce 0注意这不是为了关掉安全机制而是用来快速定位问题。如果切到 permissive 之后问题消失说明确实是 SELinux 策略的问题。然后你可以决定长期保持 permissive或者用下面命令给目录打上 container 相关标签semanage fcontext -a -t container_file_t /data/gitlab(/.*)? restorecon -Rv /data/gitlab我自己在实际生产环境更倾向于保持 SELinux permissive 模式对内网小团队 GitLab数据屏蔽主要靠防火墙和账号体系SELinux 带来的额外安全收益有限却可能给运维排查增加不少成本。当然如果你所在的单位有等保或安全合规要求那就保留 enforcing 并按需打标签这需要按实际情况来。6. 备份、升级与迁移的日常运维要点6.1 备份的两种姿势容器化 GitLab 的备份有两种常用方式。第一种是官方提供的gitlab-backup命令用来备份 Git 仓库、数据库、附件等关键数据docker exec -t gitlab gitlab-backup create备份默认输出在容器内的/var/opt/gitlab/backups对应宿主机就是/data/gitlab/data/backups。建议再把这目录同步到异地或者对象存储避免机器损坏时数据一起丢。第二种方式是整目录快照把整个/data/gitlab打包。这种方式适合做迁移或者机器级快照恢复起来也更直接。但注意在做备份前最好让 GitLab 暂时进入只读或者低写入状态或者至少避开业务高峰期否则备份出来的数据可能是不一致的。6.2 升级流程容器化升级的流程我已经验证过核心就是三句话备份、换镜像、重启。完整流程如下# 1. 备份 docker exec -t gitlab gitlab-backup create # 2. 停旧容器 docker stop gitlab docker rm gitlab # 3. 拉新版镜像 docker pull gitlab/gitlab-ce:17.0.0-ce.0 # 4. 修改 compose 文件中的 image tag # 5. 重新启动 docker compose up -d升级后访问页面如果出现 502 或者长时间无响应别急容器启动时又会在后台跑一遍 reconfigure 和数据库迁移这个过程取决于数据量大小几分钟到十几分钟都正常。升级 GitLab 跨大版本时官方要求逐个大版本升级不能从 16 直接跳到 18。比如从 16 升到 17再升 18避免数据库结构不兼容。6.3 迁移到新机器迁移本质上就是数据目录搬家。在新机器上装好 Docker把/data/gitlab整个拷贝过去再放一份相同的 compose 文件启动即可rsync -avP /data/gitlab root新机器IP:/data/ ssh root新机器IP cd /data/gitlab docker compose up -d由于数据都在数据卷里容器本身的 hostname、环境变量等参数只要保持和原来一致迁移后系统就能无缝接续。我经历过几次直接把数据目录 rsync 到新环境然后拉起的操作都没有问题。6.4 一个小技巧定时备份脚本最后分享一个我一直在用的定时备份脚本。不管多自动化备份必须落到定时任务里人在忙碌时最容易忘的恰恰是最重要的事#!/bin/bash BACKUP_DIR/data/gitlab/data/backups DATE$(date %Y%m%d_%H%M) docker exec -t gitlab gitlab-backup create # 保留最近7天备份其余清理 find $BACKUP_DIR -name *gitlab_backup.tar -mtime 7 -delete把它写到/usr/local/bin/gitlab-backup.sh并设置可执行权限然后添加 crontabchmod x /usr/local/bin/gitlab-backup.sh crontab -e # 每天凌晨3点执行备份 0 3 * * * /usr/local/bin/gitlab-backup.sh注意一点如果备份文件非常大而磁盘空间有限建议先压缩再清理或者直接 rsync 到另一台机器不要让备份在本地堆太久。根据我个人的实际操作体验openEuler 22.03 这套环境搭配 GitLab 容器化部署最舒服的地方在于数据目录清晰、升级迁移方便、出了问题也容易回滚。如果你也是小团队自建代码托管平台手头资源有限完全可以直接照着我这篇的方式跑起来。最后再强调一句任何大动作之前先做备份做好备份整个系统的容错能力会完全不一样。
返回列表