编者按:本文转载自公众号运维识堂,已经联系作者取得转载授权。
GitLab 在发展的十余年中,在国内积累了大量的 CE 用户,但是很多 CE 用户并不会跟随 GitLab 的发版节奏(月度发版)进行版本升级,在 GitLab 已经发布 16.4 版本的情况下,还有大量的用户使用 10 以下的版本。下面文章的作者就讲述了将使用源码编译安装的 GitLab 9.x 版本进行升级的过程,中间涉及了数据库的切换(从 Mysql 到 Postgres)、数据的备份和恢复、容器的操作等,过程虽然“看似简单”,但是却需要深厚的技术储备以及强大的信心才能完成这些操作,而且从测试验证到上生产历时两个月。对于很多运维人员来讲,下面的升级流程从测试环境到上生产环境都是一个极其大的挑战,如果出现问题,就可能导致企业内部的源代码托管平台不可用,影响公司的软件研发。
从另外一个角度来讲,这也是使用 CE 版带来的技术债,很多 CE 用户,担心升级过程出问题,秉承“不动就不出问题”的原则,一直在使用老旧版本,这样极容易导致产品不仅无法获取到最新的功能特性,还可能由于老旧版本存在的安全漏洞,容易让 GitLab 遭受外部攻击,长此以往,就造成了“升级是找死,不升级是等死”的困境。
其实,企业用户应该尽量使用企业版本(EE),除了能及时获取最新功能,还能享受企业级的服务支持,原厂服务轻松搞定产品升级、安全问题修复等,不仅能够将运维人员从升级恐惧症中解脱出来,还能利用最新的功能特性提升研发效率。
从 2019 年开始,SonarQube 和 GitLab 相继宣布不在提供对 MySQL 方式存储数据的支持(Consider removing support for MySQL)。由于 Oracle 和 SQL Server 都是收费的商业数据库,而 PostgreSQL 则是开源的,加之最近几年针对 PostgreSQL 的创新不断和 ChatGPT 的火热,Postgres 再次进入我的 TODO 列表。从云厂 RDS Postgres 插件列表和几个开源项目(比如:Neon: Serverless Postgres:无服务的 Postgres,timescaledb:基于 Postgres 的时序数据库扩展,FerretDB:将 MongoDB 协议转化为 SQL 使用 Postgres 作为存储后端)以及像这种基于 PostgreSQL 构建由 LLM 驱动的专属 ChatBot(其中用到的 pgvector)AI 应用场景。可见 Postgres 的火爆,所以想一探究竟。
因为 Postgres 在未来肯定是必须需要去了解和使用的,因为它已经变成很多开源软件的首选或者说默认数据库,所以到了必须要学习的地步。看完 PostgreSQL 教程,顿时想起之前 GitLab 迁移失败的痛苦经历(因为数据量大,一次测试 3 个小时没了,时间成本太高,以及一次次失败带来的压力让人精神崩溃)。最终在多次失败后不断总结原因,终于找到问题以及可能的解决办法。
因为最开始搭建的代码库是基于 GitLab 9.0.6 源代码部署并且采用外置 RDS MySQL 5.6 搭建,日常维护也就是扩盘或者升级 CPU 和内存,6 年从未升级过 GitLab(主要还是怕升级影响近千人的日常工作,又不是不能用何必自找麻烦呢)。一年前尝试做过升级测试,也咨询过厂商和社区(能搞这方面的人是真的少),最终失败(一个字穷)。现在回过头来看,还是没有认真看官方给的文档,从一开始升级思路就错了(下面给正确的解法)。
因为从 GitLab 12.1 开始不在支持 MySQL 数据库,所以必须完成 MySQL 到 Postgres 的迁移。由于官方给的一体包(Omnibus GitLab Packages)默认就采用的 Postgres 数据库,为了后面版本升级方便,所以需要优先将当前版本的数据库迁移到 Postgres 上,下面主要分享 MySQL 迁移 Postgres 核心流程。
源代码安装的备份方式
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
# 注意:备份时注意磁盘空间,备份后会在备份目录产生一个带时间戳的 tar 包文件
file: /data/gitlab/migrate/docker-compose.yml
version: '3'
services:
pgloader:
image: seanly/toolset:pgloader
tty: true
volumes:
- ./:/ws
restart: always
security_opt:
- seccomp:unconfined
mysql:
image: seanly/dbextra:mysql-5.7.35
restart: unless-stopped
volumes:
- ./mysql-data:/var/lib/mysql
- ./:/ws
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: 'gitlabhq_production'
healthcheck:
test: mysql --user=root --password=$$MYSQL_ROOT_PASSWORD -e "SHOW DATABASES;"
interval: 3s
timeout: 1s
retries: 5
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --max_allowed_packet=512M
postgres:
image: postgres:11-alpine
restart: always
environment:
- POSTGRES_USER=gitlab
- POSTGRES_PASSWORD=gitlab123
- POSTGRES_DB=gitlabhq_production
volumes:
- ./postgres-data:/var/lib/postgresql/data
- ./:/ws
healthcheck:
test: pg_isready -U gitlab -h 127.0.0.1
interval: 5s
file: /data/gitlab/migrate/gitlab.loader
LOAD DATABASE
FROM mysql://root:root123@mysql:3306/gitlabhq_production
INTO pgsql://gitlab:gitlab123@postgres:5432/gitlabhq_production
WITH include no drop, truncate, disable triggers, create no tables,
create no indexes, preserve index names, no foreign keys,
data only,
workers = 8, concurrency = 16,
batch rows = 100000, batch size = 512MB, multiple readers per thread, rows per range = 500000
SET MySQL PARAMETERS
net_read_timeout = '90',
net_write_timeout = '180'
ALTER SCHEMA 'gitlabhq_production' RENAME TO 'public'
;
执行命令 docker-compose up -d
启动容器。
# 1. 将备份文件拷贝到新主机,假设存储在 /data/gitlab/backup 目录
# 2. 从 TIMESTAMP_gitlab_backup.tar 包获取 db/database.sql.gz
cd /data/gitlab/backup
tar xf TIMESTAMP_gitlab_backup.tar db
gunzip db/database.sql.gz
# /data/gitlab/backup/db/database.sql 就是 MySQL 的备份
mv /data/gitlab/backup/db/database.sql /data/gitlab/migrate/mysql_database.sql
这一步很关键,为了确保后面的升级成功,所以需要完整的一个空的数据库结构,数据可以通过 MySQL 库迁移。处理方式是通过容器初始化一个版本,然后备份里面的 Postgres。
file: /data/gitalab/migrate/gitlab/docker-compose.yml
version: '3'
services:
gitlab:
image: 'gitlab/gitlab-ce:9.0.6-ce.0'
restart: always
volumes:
- './:/ws'
shm_size: '256m'
启动容器并备份数据库
cd /data/gitalab/migrate/gitlab
docker-compose up -d
docker-compose exec gitlab bash
# 容器内部
su - gitlab-psql
pg_dump -U gitlab-psql -h /var/opt/gitlab/postgresql -d gitlabhq_production -f /ws/gitlab_backup.sql
exit
# 容器外部
docker-compose down
mv gitlab_backup.sql /data/gitalab/migrate/
cd /data/gitalab/migrate/
docker-compose exec mysql bash
# 进入 msyql 容器
mysql -u root -p gitlabhq_production < /ws/mysql_database.sql
# 输入密码 root123
cd /data/gitalab/migrate/
docker-compose exec postgres bash
# 进入 postgres 容器
psql -U gitlab -d gitlabhq_production -f /ws/gitlab_backup.sql
docker-compose exec pgloader pgloader /ws/gitlab.loader
cd /data/gitalab/migrate/
docker-compose exec postgres bash
# 进入容器
pg_dump -U gitlab -d gitlabhq_production -f /ws/database.sql
exit
# 退出容器
mv /data/gitalab/migrate/database.sql /data/gitlab/backup/db/database.sql
cd /data/gitlab/backup/
# 打包 sql 为 sql.gz
gzip db/database.sql
# 更新备份包的 db/database.sql.gz
tar rf TIMESTAMP_gitlab_backup.tar db/database.sql.gz
file: /data/gitlab/test-upgrade/docker-compose.yml
version: '3'
services:
gitlab:
image: 'gitlab/gitlab-ce:9.0.6-ce.0'
restart: always
ports:
- '80:80'
- '443:443'
- '2222:22'
volumes:
- './config:/etc/gitlab'
- './data:/var/opt/gitlab'
- '/data/backup:/var/opt/gitlab/backups'
shm_size: '256m'
mkdir -p /data/gitlab/test-upgrade/{data/backup,config}
cp -r /data/gitlab/backup/TIMESTAMP_gitlab_backup.tar /data/gitlab/test-upgrade/backup/
docker-compose up -d
docker-compose exec gitlab bash
# 进入容器
gitlab-rake gitlab:backup:restore RAILS_ENV=production BACKUP=${TIMESTAMP}
# 退出容器
docker-compose logs -f
版本升级方式很简单,版本选择请看官方升级路径,通过修改 docker-compose.yml
里面的镜像版本,然后执行 docker-compose up -d
进行版本升级。
虽然升级验证过程痛苦,但是学习到的东西也挺多。现在回看整个过程最关键的地方是只需要将 MySQL 数据通过 pgloader 迁移到GitLab Postgres 的数据库中,其他都是标准升级流程,再借助容器屏蔽工具对环境的依赖。
极狐GitLab 是 GitLab 面向国内用户推出的一体化 DevOps 平台。GitLab 作为极狐GitLab 的上游,意味着极狐GitLab 拥有和 GitLab 同等的功能,而且极狐GitLab 还针对国内用户开发了中专门面向国内企业的功能特性,比如和微信、钉钉、飞书的集成等。
极狐GitLab 本土化运营团队能够为国内企业用户提供专业的企业级服务支持,目前已经帮助数百家企业实现了 DevOps 的落地实践。极狐GitLab 专业的服务能力能够帮助企业实现 GitLab/极狐GitLab 的平滑升级。