Docker版Gitlab与Host共享22端口

date
Sep 21, 2021
slug
tyshudaa
status
Published
tags
Docker
summary
type
Post
 
本文的 Docker 版 Gitlab 是基于docker-compose方式进行安装,其基本配置如下:
version: "3.9"
services:
  gitlab:
    container_name: gitlab
    image: "gitlab/gitlab-ce:14.2.3-ce.0"
    restart: always
    hostname: "gitlab.fe.sw"
    environment:
      TZ: "Asia/Shanghai"
      GITLAB_OMNIBUS_CONFIG: |
        external_url = "gitlab.fe.sw"
    ports:
      - "9000:80"
      - "9022:22"
    volumes:
      - "/backups/gitlab:/backups"
      - "/opt/dockers/gitlab/config:/etc/gitlab"
      - "/opt/dockers/gitlab/logs:/var/log/gitlab"
      - "/opt/dockers/gitlab/data:/var/opt/gitlab"
如下图,根本不能通过显示的 ssh/http 地址进行正常 git clone,必须调整 git 地址。
notion image
E89mLr

HTTP 协议

根据上面的配置信息,正确的 http url 是:http://gitlab.fe.sw:9000/root/test.git,效果如下
notion image
UJ8UPy
强迫症表示受不了,带个端口干啥?马上用 Nginx 做一个反向代理,配置如下:
  server {
    listen 80;
    server_name gitlab.fe.sw;

    location / {
      proxy_pass http://localhost:9000/;
    }
  }
然后就可以 http 方式就可以改为:http://gitlab.fe.sw/root/test.git,完美!

git 协议

同样的,目前阶段要通过 git 协议是不行的,只能借助ssh的,所以正确的 git url 是:ssh://git@gitlab.fe.sw:9022/root/test.git,效果如下
notion image
y7Hx3O
这里为啥说要借助ssh,可以参考聊聊 Git 的三种传输协议及实现
刚才 http 中多了一个端口都不行,更别说现在还改了协议!!马上研究。先贴参考资料,大家可以先自己研究:
下面开始介绍具体步骤:
1、Docker 和 Host 上用户 git 的 gid 和 uid 的值一致,模拟成同一个用户。可参见后面的坑 1。
进入到 Docker 内查看/etc/group/etc/passwd中用户 git 的 gid 和 uid,这里假设是1002
$ docker exec -it gitlab id git

uid=1002(git) gid=1002(git) groups=1002(git)
在 Host 上创建用户 git 即可:
groupadd -g 1002 git
useradd -m -u 1002 -g git -s /bin/sh -d /home/git git
2、配置正确的文件路径映射。可参见后面的坑 2。
git 是关键角色,要让其能访问 volumes 两侧的文件数据,如/opt/dockers/gitlab之类的,即完成文件数据的共享。
3、配置 SSH 链接转发。可参见后面的坑 3。
在 Host 中创建文件/opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell,这个路径不能变!!!
mkdir -p /opt/gitlab/embedded/service/gitlab-shell/bin
touch gitlab-shell
chmod +x gitlab-shell
chown git:git gitlab-shell
gitlab-shell 的内容如下,其中 9022 是前面配置的端口:
#!/bin/sh
ssh -i /home/git/.ssh/id_rsa -p 9022 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
4、Host 中用户 git 到 Docker 中的免密访问。可参见后面的坑 4。
在 Host 中切换到用户 git,进行.ssh 关联,目的是执行 SSH 转发。
su git
mkdir -p /opt/dockers/gitlab/data/.ssh
ln -sf /opt/dockers/gitlab/data/.ssh /home/git/.ssh

ssh-keygen
cat /home/git/.ssh/id_rsa.pub >> /home/git/.ssh/authorized_keys
这时可以验证免密是否成功没ssh git@127.0.0.1 -p 9022
notion image
82xege
到此,git 协议的 clone 应该改造完成了,不改协议、不加端口。
大家应该看得出,这是利用用户 git 的协议转发来实现(!!!重点!!!):
  • Docker 和 Host 两侧的用户 git 公用一套.ssh,即 Gitlab 用户通过 Web 方式添加 public key 后,也备用在 Gitlab 用户访问 Host。
  • Host 侧用户 git 利用免密访问实现协议转发。

踩坑记录

虽说中秋节放假 3 天,但大概有两天时间都在想这事,看了上面资料后是『原理我大概懂』,但就是没效果,下面来挨个记录。
其实问题主要集中在 Linux 权限上。
前面 4 篇文章都提到了,要求 Docker 与 Host 中的 git 用户的 gid 和 uid 要一致。

1.git 的 gid 和 uid 要一致

Host 已有用户 git 且不能删除

Host 上的到用户 git 的 gid 和 uid,这里假设均为2222
$ id git

uid=2222(git) gid=2222(git)=2222(git)
先创建一个 Gitlab 的 Docker 实例,拿到/opt/dockers/gitlab/config/gitlab.rb配置文件,添加以下内容
manage_accounts['enable'] = true
user['group'] = 'git'
user['username'] = 'git'
user['uid'] = 2222
user['gid'] = 2222
manage_accounts['enable']是限制 Gitlab 能不能自动创建账户,默认为false。所以这里改为true,并指定 Docker 中用户 git 的 git 和 gid 的值和 Host 中保持一致。
接着停止和删除 Gitlab 的 Docker 服务,且删除 Host 中/opt/dockers/gitlab/中的datalogs文件夹,只保留config。然后又新创建 Gitlab 的 Docker 服务,就保证了 Docker 和 Host 中用户 git 的 gid 和 uid 保持一致。
你也可以修改gitlab.rb后,在 Docker 中对执行gitlab-ctl reconfigure和gitlab-ctl restart,就不需要删除和新建 Docker 实例了。

在 Host 新建用户 git

如果 Host 中没有用户 git,或可以删除用户 git 后新建,那么就稍简单些。那么先删除 Host 中用户 git:
groupdel git // 删除组
userdel -r git  // 删除用户,且移除用户所有的文件和目录。(请删除前请备份数据)

2.用户的目录权限

docker-compose 里 volumes 中 Host 上的地址不能在用户目录下,因为 Linux 中当前用户(root 除外)不能访问其他用户目录下的数据。
比如最开始版本的docker-compose.yml是这样子,且是以 root 身份创建的 Docker 实例:
volumes:
    - "/backups/gitlab:/backups"
    - "~/dockers/gitlab/config:/etc/gitlab"
    - "~/dockers/gitlab/logs:/var/log/gitlab"
    - "~/dockers/gitlab/data:/var/opt/gitlab"
那么实际情况是,两侧的用户 git 是都访问不到 Host 中目录/root/dockers/gitlab里的任何文件,所以必须切换到其他目录下。

3.SSH 转发脚本

第一次创建该文件的时候,觉得很奇怪。明明都已经是 Docker 方式创建,为啥还要写死这个目录,通过映射进去不香吗?
但事实是这样子的
当 Gitlab 用户 git 使用命令时, 每次都会默认执行/opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell脚本(会在容器里执行),因为.ssh是软连接过来的,所以 Host 用户 git 下面的.ssh也会这样,刚好也凭借这个自动触发来做自动跳转。
当你通过 Web 方式添加一个 ssh public key 之后就会在 Docker 中/home/git/.ssh/authorized_keys看到内容大致如下(完整的请见图,方便理解):
command="/opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3...
notion image
gDZoGC

4. Host 中用户 git 到 Docker 中的免密访问

前面提到的 SSH 转发就是,Host 的用户 git 收到 Gitlab 用户侧的请求,需要 Host 侧用户 git 能免密访问 Docker,才能无缝的执行脚本进行数据转发。
我是直接用 Host 侧用户 git 创建的/home/git/.ssh/id_rsa.pub拷贝到authorized_keys中。
另外也可以将这个文件映射为容器内/gitlab-data/ssh/authorized_keys,在这次提交中表明
添加了除了/.ssh/authorized_keys以外的/gitlab-data/authorized_keys文件用于 SSH 认证
所以docker-compose.yml(volumes 部分)更新如下:
volumes:
    - "/backups/gitlab:/backups"
    - "/opt/dockers/gitlab/config:/etc/gitlab"
    - "/opt/dockers/gitlab/logs:/var/log/gitlab"
    - "/opt/dockers/gitlab/data:/var/opt/gitlab"
    - "/home/git/.ssh/id_rsa.pub:/gitlab-data/ssh/authorized_keys"

参考资料:
 
 
123

© 刘德华 2020 - 2023