GitLab (Docker) 常用命令及解决方案清单
本清单基于解决 GitLab CE 18.4.0 Docker 容器中 PostgreSQL 数据损坏、数据恢复、外部数据库迁移等实际问题的经验整理。
一、数据库损坏修复
1. 定位损坏对象
sql
-- 进入数据库控制台
docker exec -it <容器名> gitlab-psql
-- 根据 relfilenode 查询表名
SELECT c.oid, n.nspname AS schema, c.relname,
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'i' THEN 'index' END AS type
FROM pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE c.relfilenode = 17102; -- 替换为实际数字
2. 尝试跳过损坏页面(需重启 PostgreSQL)
bash
# 方法一:修改 postgresql.conf(宿主机路径)
echo "ignore_invalid_pages = on" >> /宿主机数据目录/postgresql/data/postgresql.conf
docker restart <容器名>
# 方法二:通过 gitlab.rb 永久配置(推荐)
echo "postgresql['custom_config'] = { 'ignore_invalid_pages' => 'on' }" >> /etc/gitlab/gitlab.rb
docker exec -it <容器名> gitlab-ctl reconfigure
docker restart <容器名>
# 验证是否生效
docker exec -it <容器名> gitlab-psql -c "SHOW ignore_invalid_pages;"
3. 抢救损坏表的数据
sql
-- 创建备份表(会跳过损坏页面,若失败则用逐行插入)
CREATE TABLE namespaces_backup AS TABLE namespaces;
-- 若报错,改用逐行插入
CREATE TABLE namespaces_backup (LIKE namespaces INCLUDING ALL);
DO $$
DECLARE r RECORD;
BEGIN
FOR r IN SELECT * FROM namespaces LOOP
BEGIN
INSERT INTO namespaces_backup VALUES (r.*);
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Skipping row: %', SQLERRM;
END;
END LOOP;
END $$;
-- 替换原表
DROP TABLE namespaces;
ALTER TABLE namespaces_backup RENAME TO namespaces;
4. 单用户模式强制修复(绕过 Omnibus)
bash
# 停止 GitLab 进程,手动启动 PostgreSQL
docker exec -it <容器名> gitlab-ctl stop
docker exec -it <容器名> rm -f /var/opt/gitlab/postgresql/data/postmaster.pid
docker exec -it <容器名> su - gitlab-psql -c "/opt/gitlab/embedded/bin/postgres --single -c ignore_invalid_pages=on -D /var/opt/gitlab/postgresql/data template1"
二、数据库完全重置(不保留数据)
bash
# 进入容器
docker exec -it <容器名> /bin/bash
# 停止非数据库服务
gitlab-ctl stop sidekiq puma nginx
# 强制重置(跳过保护)
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 gitlab-rails db:drop db:create db:migrate
# 手动创建基础数据(若 db:seed 失败)
gitlab-rails runner "ApplicationSetting.create_from_defaults"
gitlab-rails runner "User.create(username: 'root', email: 'admin@example.com', name: 'Administrator', admin: true, password: 'your_password', password_confirmation: 'your_password')"
# 重新配置并启动
gitlab-ctl reconfigure
gitlab-ctl restart
三、用户管理(当登录失效)
1. 重置 root 密码
bash
# 方法一:使用 rake 任务
docker exec -it <容器名> gitlab-rake "gitlab:password:reset[root]"
# 方法二:通过 rails console
docker exec -it <容器名> gitlab-rails console
user = User.find_by_username('root')
user.password = 'new_password'
user.password_confirmation = 'new_password'
user.save!
exit
2. 创建新管理员用户
ruby
# rails console 中执行
user = User.new(
username: 'new_admin', email: 'admin@example.com', name: 'Admin',
password: 'password', password_confirmation: 'password',
admin: true, projects_limit: 10000
)
user.skip_confirmation!
user.save!
四、数据备份与恢复
1. 备份整个数据目录(宿主机)
bash
cp -r /volume1/dockerdata/gitlab /volume1/backup/gitlab_$(date +%Y%m%d)
2. 备份代码仓库(仅仓库,不含数据库)
bash
docker exec -it <容器名> tar -czf /tmp/repositories.tar.gz -C /var/opt/gitlab/git-data/repositories .
docker cp <容器名>:/tmp/repositories.tar.gz /volume1/backup/
3. 备份 GitLab 配置和密钥
bash
docker cp <容器名>:/etc/gitlab/gitlab.rb /volume1/backup/
docker cp <容器名>:/etc/gitlab/gitlab-secrets.json /volume1/backup/
docker cp <容器名>:/etc/gitlab/ssh_host_* /volume1/backup/
4. 完整备份(官方工具)
bash
docker exec -it <容器名> gitlab-backup create
# 备份文件位于 /var/opt/gitlab/backups/
5. 恢复备份
bash
# 停止服务
docker exec -it <容器名> gitlab-ctl stop puma sidekiq
# 恢复(BACKUP=时间戳)
docker exec -it <容器名> gitlab-backup restore BACKUP=1734567890_2025_04_25_18.4.0
# 重启
docker exec -it <容器名> gitlab-ctl restart
6. 仅恢复仓库文件(放弃数据库)
bash
# 清空现有仓库目录
docker exec -it <容器名> rm -rf /var/opt/gitlab/git-data/repositories/*
# 解压备份
docker cp /volume1/backup/repositories.tar.gz <容器名>:/tmp/
docker exec -it <容器名> tar -xzf /tmp/repositories.tar.gz -C /var/opt/gitlab/git-data/repositories/
docker exec -it <容器名> chown -R git:git /var/opt/gitlab/git-data/repositories
五、切换到外部 PostgreSQL 数据库
1. 在外部 PG 中创建数据库和用户
sql
CREATE USER gitlab WITH PASSWORD 'your_password';
ALTER ROLE gitlab WITH SUPERUSER CREATEDB CREATEROLE REPLICATION;
CREATE DATABASE gitlabhq_production OWNER gitlab;
2. 导出内部数据(使用 Unix socket)
bash
docker exec -it gitlab18.4.0 /opt/gitlab/embedded/bin/pg_dump \
-h /var/opt/gitlab/postgresql -U gitlab -c -C -f /tmp/gitlabhq_production.sql gitlabhq_production
docker cp gitlab18.4.0:/tmp/gitlabhq_production.sql .
3. 导入到外部 PG
bash
PGPASSWORD='your_password' psql -h 192.168.1.6 -p 15432 -U gitlab -f gitlabhq_production.sql postgres
4. 修改 GitLab 配置
ruby
# 编辑 /etc/gitlab/gitlab.rb,追加:
postgresql['enable'] = false
gitlab_rails['db_host'] = '192.168.1.6'
gitlab_rails['db_port'] = 15432
gitlab_rails['db_username'] = 'gitlab'
gitlab_rails['db_password'] = 'your_password'
gitlab_rails['db_database'] = 'gitlabhq_production'
5. 重新配置并重启
bash
docker exec -it <容器名> gitlab-ctl reconfigure
docker exec -it <容器名> gitlab-ctl restart
六、配置管理(避免修改被覆盖)
1. 正确的永久配置方法(通过 gitlab.rb)
bash
# 进入容器
docker exec -it <容器名> /bin/bash
# 编辑主配置文件
editor /etc/gitlab/gitlab.rb
# 追加配置,例如:
postgresql['custom_config'] = { 'ignore_invalid_pages' => 'on' }
gitlab_rails['db_password'] = 'my_password'
# 应用配置
gitlab-ctl reconfigure
2. 查看当前生效的配置
bash
docker exec -it <容器名> gitlab-rails runner "puts Gitlab::CurrentSettings.inspect"
七、日志维护
1. 安全清理日志(推荐)
bash
# 手动触发 logrotate
docker exec -it <容器名> logrotate -f /etc/logrotate.d/gitlab
# 或配置自动轮转(在 gitlab.rb 中)
logging['logrotate_frequency'] = "daily"
logging['logrotate_rotate'] = 30
logging['logrotate_compress'] = "compress"
gitlab-ctl reconfigure
2. 查看实时日志
bash
docker exec -it <容器名> gitlab-ctl tail # 所有服务
docker exec -it <容器名> gitlab-ctl tail postgresql
docker exec -it <容器名> gitlab-ctl tail gitlab-rails
3. 清理 Docker 容器日志(宿主机)
bash
truncate -s 0 /var/lib/docker/containers/*/*-json.log
八、容器与数据目录操作
1. 停止并删除容器(保留数据卷)
bash
docker stop <容器名>
docker rm <容器名>
2. 使用旧数据卷启动新容器
bash
docker run --detach \
--name gitlab-new \
--publish 3084:443 --publish 3022:80 --publish 3012:22 \
--volume /volume1/dockerdata/gitlab/config:/etc/gitlab \
--volume /volume1/dockerdata/gitlab/logs:/var/log/gitlab \
--volume /volume1/dockerdata/gitlab/data:/var/opt/gitlab \
docker.1ms.run/gitlab/gitlab-ce:18.4.0-ce.0
3. 进入容器执行命令
bash
docker exec -it <容器名> /bin/bash
docker exec -it <容器名> gitlab-psql
docker exec -it <容器名> gitlab-rails console
九、常见错误及快速解决
| 错误信息 | 快速解决 |
|---|---|
connection to server on socket ".../.s.PGSQL.5432" failed |
使用 gitlab-psql 或指定 -h /var/opt/gitlab/postgresql |
permission denied to set parameter "ignore_invalid_pages" |
通过 gitlab.rb 配置并执行 gitlab-ctl reconfigure |
Validation failed: Namespace can't be blank |
使用 Users::CreateService 创建用户,或先创建 root |
gitlab-ctl stop 导致容器退出 |
不要停全部服务,只停需要的:gitlab-ctl stop sidekiq puma |
pg_dump: connection refused |
改用 Unix socket:-h /var/opt/gitlab/postgresql |
FATAL: lock file "postmaster.pid" already exists |
rm -f /var/opt/gitlab/postgresql/data/postmaster.pid |
十、终极恢复:放弃数据库只保代码
当数据库损坏无法修复时,按以下顺序操作:
- 备份当前仓库:
tar -czf repos.tar.gz /var/opt/gitlab/git-data/repositories - 停止并删除旧容器,彻底删除数据卷中的
postgresql目录。 - 启动新容器,让 GitLab 自动初始化数据库。
- 导入仓库备份,修复权限。
- 登录 Web 界面,手动创建项目(路径必须与原项目一致),GitLab 会自动关联已有仓库。
此方案会丢失所有 issues、MR、用户权限等元数据,但代码仓库完整保留。
以上清单涵盖了本次排障过程中的主要命令和解决方案,可根据实际情况选用。