---
# System prepended metadata

title: GitLab Geo

---

# GitLab Geo 

>**官方原文：**
>
> - [Geo](https://docs.gitlab.com/ee/administration/geo/#geo)
> - [Geo Setting up](https://docs.gitlab.com/ee/administration/geo/setup/)
> - [Geo database replication](https://docs.gitlab.com/ee/administration/geo/setup/database.html)
> - [Geo configuration](https://docs.gitlab.com/ee/administration/geo/replication/configuration.html)
> - [Using a Geo Site](https://docs.gitlab.com/ee/administration/geo/replication/usage.html)
> - [Introduction to GitLab Geo - GitLab Features](https://www.youtube.com/watch?v=-HDLxSjEh6w)
> - [Geo for multiple servers](https://docs.gitlab.com/ee/administration/geo/replication/multiple_servers.html)
> 
>**修订记录：**
>
> - 2021/05/12 [Alex Ju](mailto:alexju@gitlab.cn) 创建文档
>
>**Note:** _本操作笔记仅供参考，请务必阅读官方文档链接_

---

## 1. GitLab Geo概述

有时候从一个距离很远的GitLab实例，拉取一个非常大的仓库，会比较费时费力。
GitLab Geo 提供了一个`近距离的、只读`的GitLab实例克隆，可以大大减少用户拉取代码的时间，帮助加快开发进度。

Geo视频介绍：
[Introduction to GitLab Geo - GitLab Features](https://www.youtube.com/watch?v=-HDLxSjEh6w)

**Geo使用场景：**

Geo能够提供：
- 一个只读的`从节点`(Secondary node)
- 完全继承`主节点`(Primary node)的用户权限
- 与主节点相同的UI，不过在用户访问的时候会提示用户正在使用从节点

Geo带来哪些好处：
- 拉取大的仓库，耗时从`分钟级`降到`秒级`
- 让开发者之间更便捷的同步工作，分享想法
- 在两个节点之间分摊只读流量
- [灾难恢复](https://docs.gitlab.com/ee/administration/geo/disaster_recovery/index.html)时，可以快速的切换到从节点
- 能够[有计划的](https://docs.gitlab.com/ee/administration/geo/disaster_recovery/planned_failover.html)切换到从节点

与Gitaly集群的区别：
- 两者不能混淆，具体比较：[Gitaly集群和Geo比较](https://docs.gitlab.com/ee/administration/gitaly/index.html#gitaly-cluster-compared-to-geo)


**Geo工作原理：**

场景示意图：
![Geo](https://docs.gitlab.com/ee/administration/geo/replication/img/geo_overview.png)

- 原始节点，也称主节点(Primary node)
- 镜像的只读节点，也称从节点(Secondary node)，从节点可以有多个
- 从节点通过API获取主节点的用户数据，通过HTTPS+JWT同步仓库，LFS对象和附件
- GitLab Premium 10.0之后，主节点不再主动将变化通知从节点
- GitLab Premium 11.3之后，可以直接推送代码到从节点
- 使用Geo有部分限制，详细参考：[Geo限制](https://docs.gitlab.com/ee/administration/geo/#limitations)



架构图：
![Geo架构图](https://docs.gitlab.com/ee/administration/geo/replication/img/geo_architecture.png)

- 对数据库的写入，只发生在主节点。从节点通过Postgresql流复制,收到数据库的更新
- 从节点会有两个PostgreSQL数据库：一个只读数据库，用来同步主节点。另外一个数据库，用来记录哪些数据被同步
- 建议LDAP也配置主备模式，来应对灾难恢复的场景
- 从节点虽然是只读的，但可以接收Push请求，然后转发到主节点，这使得从节点看上去可以接收Push请求


**运行要求：**
- OpenSSH 6.9+ (CentOS 7.4+, Ubuntu 16.04+ 默认支持)
- PostgreSQL 11+ 
- Git 2.9+
- Git-lfs 2.4.2+(用户端）
- 所有节点必须使用相同版本的GitLab, 要求GitLab EE 10.0+


## 2. Geo安装配置

**测试环境：**
- 主节点：192.168.123.116 
- 从节点：192.168.123.118

### 2.1 安装Geo从节点
在从节点上，[安装极狐GitLab EE版](https://about.gitlab.com/install/)，建议使用极狐官方最新版。
安装完成后，`不要`在从节点上`创建用户`或者`登录`。

### 2.2 主节点添加许可证
在主节点上，[安装license](https://docs.gitlab.com/ee/user/admin_area/license.html)，要求Premium版本以上，解锁Geo功能。

### 2.3 配置数据库复制
如果你的Omnibus实例用的是默认的内置PostgreSQL数据库，请继续下面操作。
如果你的Omnibus使用的是外部PostgreSQL数据库，请参照[Geo with external PostgreSQL instances](https://docs.gitlab.com/ee/administration/geo/setup/external_database.html)进行配置。

#### 2.3.1 配置主节点
- 修改`/etc/gitlab/gitlab.rb`，为主节点定义一个独特的名称：
  ```bash
  gitlab_rails['geo_node_name'] = 'cn'
  ```
- 运行`gitlab-ctl reconfigure`，使上述配置生效。
- 指定当前节点为主节点:
  ```bash
  gitlab-ctl set-geo-primary-node
  ```
  输出：
  ```bash
  Saving primary Geo node with name cn.alexju.cn and URL https://cn.alexju.cn/ ...
  https://cn.alexju.cn/ is now the primary Geo node
  ```
- 设置PostgreSQL数据库用户的密码:
  ```bash
  gitlab-ctl pg-password-md5 gitlab
  # Enter password: 
  # Confirm password: 
  # a21bac212b079462ce5a27472e46e2e2
  ```
  编辑`/etc/gitlab/gitlab.rb`:
  ```bash
  postgresql['sql_user_password'] = 'a21bac212b079462ce5a27472e46e2e2'
  gitlab_rails['db_password'] = 'Gitlab,123'
  ```
  Omnibus GitLab默认内置的复制用户gitlab_replicator,需要设置密码:
  ```bash
  gitlab-ctl set-replication-password
  ```
  如果你使用的`外置PostgreSQL数据库`，你需要创建复制用户并设置密码：
  ```bash
  --- 创建用户 'replicator'
  CREATE USER gitlab_replicator;

  --- 配置密码和权限
  ALTER USER gitlab_replicator WITH REPLICATION ENCRYPTED PASSWORD '<replication_password>';
  ```

- 配置PostgreSQL监听地址
  编辑`/etc/gitlab/gitlab.rb`：
  ```bash
  #启用Geo标志
  roles ['geo_primary_role']
  #配置PG监听的公网地址或者VPC内部地址
  postgresql['listen_address'] = '192.168.123.116'  
  postgresql['md5_auth_cidr_addresses'] = ['192.168.123.116/32', '192.168.123.118/32']
  #配置从节点的数量
  postgresql['max_replication_slots'] = 1
  #临时禁止数据库自动迁移，直到PG完成重启并监听内部地址
  gitlab_rails['auto_migrate'] = false
  ```
- 运行`gitlab-ctl reconfigure`,使GitLab配置生效
- 运行`gitlab-ctl restart postgresql`，使PostgreSQL配置生效

- 编辑`/etc/gitlab/gitlab.rb`,将false改为true：
  ```bash
  gitlab_rails['auto_migrate'] = true
  ```
- 运行`gitlab-ctl reconfigure`,使GitLab配置生效


#### 2.3.2 配置从节点
- 停止 `puma`和`sidekiq`
  目的是在从节点配置完成之前，防止执行任何东西
  ```bash
  gitlab-ctl stop puma
  gitlab-ctl stop sidekiq
  ```

- 检查与主节点PostgreSQL数据库连通性
  ```bash
  gitlab-rake gitlab:tcp_check[192.168.123.116,5432]
  ```
  输出：
  ```bash
  TCP connection from 192.168.123.118:45696 to 192.168.123.116:5432 succeeded
  ```
  如果这步失败，请检查IP地址（注意区分内、外网地址）以及防火墙规则。

- 安装`server.crt`
  将主节点的证书 `~gitlab-psql/data/server.crt`拷贝到从节点，在从节点执行安装
  ```bash
  scp root@192.168.123.116:~gitlab-psql/data/server.crt /etc/gitlab/ssl

  install \
    -D \
    -o gitlab-psql \
    -g gitlab-psql \
    -m 0400 \
    -T /etc/gitlab/ssl/server.crt ~gitlab-psql/.postgresql/root.crt
  ```
- 测试数据库TLS加密通信
  使用`gitlab-psql`用户测试与主节点的数据库连通性，主节点的默认数据库为gitlabhq_production
  ```bash
  sudo \
    -u gitlab-psql /opt/gitlab/embedded/bin/psql \
    --list \
    -U gitlab_replicator \
    -d "dbname=gitlabhq_production sslmode=verify-ca" \
    -W \
    -h 192.168.123.116
  ``` 
  输出：
  ```bash
                                        List of databases
          Name         |    Owner    | Encoding | Collate | Ctype |        Access privileges        
  ---------------------+-------------+----------+---------+-------+---------------------------------
  gitlabhq_production | gitlab      | UTF8     | C       | C     | 
  postgres            | gitlab-psql | UTF8     | C       | C     | 
  template0           | gitlab-psql | UTF8     | C       | C     | =c/"gitlab-psql"               +
                      |             |          |         |       | "gitlab-psql"=CTc/"gitlab-psql"
  template1           | gitlab-psql | UTF8     | C       | C     | "gitlab-psql"=CTc/"gitlab-psql"+
                      |             |          |         |       | =c/"gitlab-psql"
  (4 rows)
  ```

- 配置gitlab.rb文件
  ```bash
  roles ['geo_secondary_role']
  postgresql['listen_address'] = '192.168.123.118'
  postgresql['md5_auth_cidr_addresses'] = ['192.168.123.118/32']
  #sql_user_password是之前主节点的hash密码
  postgresql['sql_user_password'] = 'a21bac212b079462ce5a27472e46e2e2'
  gitlab_rails['db_password'] = 'Gitlab,123'
  ```
- 运行`gitlab-ctl reconfigure`,使GitLab配置生效
- 运行`gitlab-ctl restart postgresql`，使PostgreSQL配置生效

#### 2.3.3 数据库复制

&emsp;&emsp;**请确保下列操作在`从节点`上执行，该操作将删除所有`从节点`的数据。**

- 复制数据库
  给从节点指定一个独特的名称slot-name, 该名称只允许包含`小写字母、数字和下划线`。
  ```bash
  gitlab-ctl replicate-geo-database --slot-name=us --host=192.168.123.116
  ```
  输出：
  ```bash
  No user created projects. Database not active

  ---------------------------------------------------------------
  WARNING: Make sure this script is run from the secondary server
  ---------------------------------------------------------------

  *** You are about to delete your local PostgreSQL database, and replicate the primary database. ***
  *** The primary geo node is `192.168.123.116` ***

  *** Are you sure you want to continue (replicate/no)? ***
  Confirmation: replicate
  Enter the password for gitlab_replicator@192.168.123.116: 
  * Executing GitLab backup task to prevent accidental data loss
  * Stopping PostgreSQL and all GitLab services
  * Checking for replication slot us
  * Creating replication slot us
  * Backing up postgresql.conf
  * Moving old data directory to '/var/opt/gitlab/postgresql/data.1620826017'
  * Starting base backup as the replicator user (gitlab_replicator)
  pg_basebackup: initiating base backup, waiting for checkpoint to complete
  pg_basebackup: checkpoint completed
  pg_basebackup: write-ahead log start point: 0/C000028 on timeline 1
  pg_basebackup: starting background WAL receiver
      0/79784 kB (0%), 0/1 tablespace (...lab/postgresql/data/backup_label)
  65879/79784 kB (82%), 0/1 tablespace (...postgresql/data/base/16401/28114)
  79794/79794 kB (100%), 0/1 tablespace (...ostgresql/data/global/pg_control)
  79794/79794 kB (100%), 1/1 tablespace                                         
  pg_basebackup: write-ahead log end point: 0/C000138
  pg_basebackup: waiting for background process to finish streaming ...
  pg_basebackup: syncing data to disk ...
  pg_basebackup: base backup completed
  * Restoring postgresql.conf
  * PostgreSQL 12 or newer. Writing settings to postgresql.conf and creating standby.signal
  * Setting ownership permissions in PostgreSQL data directory
  * Starting PostgreSQL and all GitLab services
  ```
  至此，数据库复制完成。


### 2.4 配置SSH密钥快速查找
- 默认情况下，GitLab通过查找遍历`~git/.ssh/authorized_keys`文件来判断用户是否可以访问GitLab, 该文件包含了用户访问Gitlab的公钥。如果用户需要频繁的更改自己的公钥，导致`authorized_keys`文件越来越大，GitLab来不及缓存，那么GitLab将不得不频繁的访问硬盘，导致整个SSH鉴权比较缓慢。
因此，更快速的方法是，**配置GitLab通过数据库查找SSH公钥指纹。**

- 配置sshd_config
  在主节点和从节点上，都配置`/etc/ssh/sshd_config`文件：
  ```bash
  cat << EOF >> /etc/ssh/sshd_config
  Match User git    # 开始匹配，让AuthorizedKeysCommand仅适用于git用户
    AuthorizedKeysCommand /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell-authorized-keys-check git %u %k
    AuthorizedKeysCommandUser git
  Match all    # 结束匹配, 配置再次适用于所有用户
  EOF
  ```
- 重新加载OpenSSH
  ```bash
  # Debian 或 Ubuntu
  service ssh reload
  # CentOS
  service sshd reload
  ```
- 注销公钥并拉取代码
  在`~git/.ssh/authorized_keys`（注意不是`/root/.ssh/authorized_keys`）中找到并注销你自己用户的公钥，然后测试pull拉取代码是否依然成功。
  如果成功，表明GitLab已经可以顺利从数据库找到公钥指纹，因为`authorized_keys`文件里已经没有这个公钥了。
  如果失败，请检查上述步骤。
  

- 新添加的SSH公钥依然会写入`authorized_keys`, 想要禁止写入`authorized_keys`，请在UI界面上打开`Admin Area > Settings > Network > Performance optimization`，取消勾选`Write to "authorized_keys" file`。
- 在UI界面上删除你的个人SSH Key，添加一个新SSH Key，测试是否能用新SSH Key对应的客户端成功拉取代码，新的SSH Key并不会出现在`~git/.ssh/authorized_keys`中。

- 如果以上均顺利通过，你可以备份并删除你的`~git/.ssh/authorized_keys`了。


### 2.5 Geo配置
以下步骤将完成：
- 在主节点和从节点之间，复制配置
- 在从节点上，配置一个额外的跟踪数据库
- 在从节点上，启用GitLab
  
#### 2.5.1 拷贝secrets
主节点和从节点的`/etc/gitlab/gitlab-secrets.json`文件必须保持一致。
- 备份从节点secrets文件
  ```bash
  mv /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.`date +%F`
  ```
- 复制主节点secrets文件到从节点
  ```bash
  scp root@192.168.123.116:/etc/gitlab/gitlab-secrets.json /etc/gitlab
  ```
- 修改权限
  ```bash
  chown root:root /etc/gitlab/gitlab-secrets.json
  chmod 0600 /etc/gitlab/gitlab-secrets.json
  ```
- 重启从节点
  ```bash
  gitlab-ctl reconfigure
  gitlab-ctl restart
  ```
#### 2.5.2 拷贝SSH主机密钥
在灾难恢复的场景下，管理员通常会指定从节点成为新的主节点，同时会变更DNS指向从节点，这样客户端就不需要更改仓库地址也能拉取代码。
但由于从节点(新主节点)的SSH主机密钥与旧的主节点不一样，所以会导致客户端SSH请求失败。
下列操作可以确保从节点和主节点的SSH主机密钥一致。
- 备份从节点主机密钥
  ```bash
  find /etc/ssh -iname ssh_host_* -exec cp {} {}.backup.`date +%F` \;
  ```

- 拷贝主节点主机密钥
  ```bash
  scp root@192.168.123.116:/etc/ssh/ssh_host_*_key* /etc/ssh
  ```
- 修改主机密钥权限
  ```bash
  chown root:root /etc/ssh/ssh_host_*_key*
  chmod 0600 /etc/ssh/ssh_host_*_key*
  ```
- 检查两边主机密钥一致性
  在两边都运行，比对输出结果是否一致：
  ```bash
  for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
  ```
  输出：
  ```bash
  256 SHA256:+zS8Eu3XaV/MS3LDNGXtnj4u8xBdIqdhmQjPkO2xg60 /etc/ssh/ssh_host_ecdsa_key.pub (ECDSA)
  256 SHA256:r8hi50aXfS7yl8CuExLYr4DuW7JX20swoDlqPWKwKdo /etc/ssh/ssh_host_ed25519_key.pub (ED25519)
  2048 SHA256:T+QzA8AJqD5UHoVsRIljDTdVy2ooimNWHJjJoue+O+U /etc/ssh/ssh_host_rsa_key.pub (RSA)
  ```
- 检查公钥和私钥的匹配性
  在从节点上，拷贝过来的公钥和私钥的指纹应该是一致的。
  ```bash
  #打印私钥的指纹
  for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done

  #打印公钥的指纹
  for file in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
  ```

- 重新加载OpenSSH
  ```bash
  # Debian 或 Ubuntu
  service ssh reload
  # CentOS
  service sshd reload
  ```

- 重新登陆从节点
  打开一个新的Terminal, 尝试是否可以成功登陆从节点。如果不能，请检查上述步骤。


#### 2.5.3 添加从节点
- 配置gitlab.rb
  编辑`/etc/gitlab/gitlab.rb`文件，加入一行：
  ```bash
  gitlab_rails['geo_node_name'] = 'us'
  ```
  运行`gitlab-ctl reconfigure`,使上述配置生效.

- 在界面上添加从节点
  打开主节点GitLab界面：Admin Area > Geo (/admin/geo/nodes)
  点击`New node`按钮：
  ![New node](https://docs.gitlab.com/ee/administration/geo/replication/img/adding_a_secondary_node_v13_3.png)

  填写Name和URL，Name是/etc/gitlab/gitlab.rb文件中的`gitlab_rails['geo_node_name']`,URL是`external_url`，必须和配置文件保持一致。

- 在从节点上运行`gitlab-ctl restart`
- 在从节点上检查geo配置
  ```bash
  gitlab-rake gitlab:geo:check
  ```
  输出：
  ```bash
  Checking Geo ...

  GitLab Geo secondary database is correctly configured ... yes
  Database replication enabled? ... yes
  Database replication working? ... yes
  GitLab Geo HTTP(S) connectivity ... 
  * Can connect to the primary node ... yes
  GitLab Geo is available ... 
  GitLab Geo is enabled ... yes
  This machine's Geo node name matches a database record ... yes, found a secondary node named "us"
  HTTP/HTTPS repository cloning is enabled ... yes
  Machine clock is synchronized ... yes
  Git user has default SSH configuration? ... yes
  OpenSSH configured to use AuthorizedKeysCommand ... skipped
    Reason:
    Cannot access OpenSSH configuration file
    Try fixing it:
    This is expected if you are using SELinux. You may want to check configuration manually
    For more information see:
    doc/administration/operations/fast_ssh_key_lookup.md
  GitLab configured to disable writing to authorized_keys file ... yes
  GitLab configured to store new projects in hashed storage? ... yes
  All projects are in hashed storage? ... yes

  Checking Geo ... Finished
  ```

  在主节点上检查geo配置，确认与从节点的geo连接：
  ```bash
  gitlab-rake gitlab:geo:check
  ```
  输出：
  ```bash
  Checking Geo ...

  GitLab Geo is available ... 
  GitLab Geo is enabled ... yes
  This machine's Geo node name matches a database record ... yes, found a primary node named "cn"
  HTTP/HTTPS repository cloning is enabled ... yes
  Machine clock is synchronized ... yes
  Git user has default SSH configuration? ... yes
  OpenSSH configured to use AuthorizedKeysCommand ... skipped
    Reason:
    Cannot access OpenSSH configuration file
    Try fixing it:
    This is expected if you are using SELinux. You may want to check configuration manually
    For more information see:
    doc/administration/operations/fast_ssh_key_lookup.md
  GitLab configured to disable writing to authorized_keys file ... yes
  GitLab configured to store new projects in hashed storage? ... yes
  All projects are in hashed storage? ... yes

  Checking Geo ... Finished
  ```
- 主节点界面
  你的主节点Geo界面样例如下：
  ![](https://i.imgur.com/6bo63GY.png)


#### 2.5.4 (可选)从节点信任主节点
如果你的主节点SSL证书由`权威CA`颁发，那么你可以跳过这项配置。
如果你的主节点证书是自签的，那么你需要将主节点证书加入到从节点证书的`信任仓库`中，具体步骤参考[SSL Configuration](https://docs.gitlab.com/omnibus/settings/ssl.html).


#### 2.5.4 为Geo启用HTTP/HTTPS
Geo默认通过`HTTP/HTTPS`同步仓库，所以需要确保可以通过`HTTP/HTTPS`进行克隆。
- 在主节点界面打开`Admin Area > Settings (/admin/application_settings/general)`
- 展开`Visibility and access controls`
- 确认`Enabled Git access protocols`被设置为`Both SSH and HTTP(S)`或者`Only HTTP(S)”`

#### 2.5.6 检查从节点
你的从节点配置至此已经完成.
现在你可以使用主节点的用户，登陆从节点，访问`/admin/geo/nodes`,界面如下：
![](https://i.imgur.com/SzYm57N.png)

#### 2.5.7 故障检查
如果你的配置有故障，请参考[Troubleshooting Geo](https://docs.gitlab.com/ee/administration/geo/replication/troubleshooting.html)

通过UI界面能观察到的最明显的2个故障：
- 节点与节点之间的数据库复制不正常
- 节点与节点之间的通知不正常，原因通常是：1.非权威CA颁发的证书；2.防火墙拦截。
  

## 3. 用户指南
用户现在可以：
- 从`从节点`上`pull`代码
- 直接`push`代码到`从节点`, `从节点`会将`push`请求转发到`主节点`：
  ```bash
  remote: 
  remote: This request to a Geo secondary node will be forwarded to the
  remote: Geo primary node:
  remote: 
  remote:   git@cn.alexju.cn:root/p1.git
  remote: 
  Counting objects: 4, done.
  Delta compression using up to 4 threads.
  Compressing objects: 100% (2/2), done.
  Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done.
  Total 3 (delta 1), reused 0 (delta 0)
  To git@us.alexju.cn:root/p1.git
    eaa4833..a678624  master -> master
  ```

## 4. 其他工作
### 4.1 暂停和恢复Geo
在GitLab Premium 13.2版本之后，Geo支持暂停和恢复。
- 暂停Geo(在从节点上)
  ```bash
  gitlab-ctl geo-replication-pause
  ```
- 恢复Geo(在从节点上)
  ```bash
  gitlab-ctl geo-replication-resume
  ```

### 4.2 多节点配置
Geo的从节点可以是多个，详细步骤：[Geo for multiple servers](https://docs.gitlab.com/ee/administration/geo/replication/multiple_servers.html)

### 4.3 Geo配合对象存储
Geo配合对象存储使用，详细步骤:[Geo with Object storage](https://docs.gitlab.com/ee/administration/geo/replication/object_storage.html)

### 4.4 Geo灾难恢复
在灾难恢复场景下，可以对Geo主节点和从节点进行切换，详细步骤：[Disaster Recovery (Geo)](https://docs.gitlab.com/ee/administration/geo/disaster_recovery/index.html)
