小小树莓派干大事-自部署Git库(一)

小小树莓派干大事-自部署Git库(一)

动机

现在免费的git托管库非常流行, 使用起来也非常方便。仿佛没有必要再自建(self-hosted)Git库了。但是最近国际形势突变,许多原本自由的代码也不再自由。这让我们重新考虑,代码作为一个开发者,一个企业最重要的无形资产之一,是否应该考虑一种方式,保证能完全掌握在自己手中。当然了, 也有其他一些动机,我一并列出来。

  1. 远程库访问限制,如速度较慢,如某github。或者因为其他zz原因考虑。
  2. 信息安全考虑,不希望公开源代码,不信任第三方git托管。
  3. 代码同步,镜像等用途。
  4. 单纯为了本地版本控制,不需要远程存储服务。
  5. 多个设备之间切换同步。

总之,如果有哪一条打动你,可以继续我们的自部署历程。

自部署Git库

市面上开源Git库很多,我们需要进一步选型。因为本文希望使用树莓派部署,选型要满足我自己的几个要求:

  1. 支持树莓派的arm架构,最好已提供Docker镜像。
  2. 数据安全备份功能,因此库文件不能过于分散。
  3. 需支持API调用。
  4. 性能需要好,开源并且相对成熟。

我通过网络查询比较,发现Gitea比较符合要求。它基于中国人开发的Gogs项目fork出来,两者使用Go语言开发,足够轻量。Gitea演进的更多,社区更活跃。这里选择Gitea。 这里有官方快速Demo预览

使用Docker镜像安装Gitea

我使用ubuntu64,因此需要支持arm64/v8的镜像。想知道一个镜像是否支持arm64,到DockerHub网站寻找Gitea镜像的Tag那一页是否包含即可。可以看到Gitea官方镜像默认latest和多个Tag都已经支持了arm64v8。

本文使用树莓派4b安装Ubuntu64,因此需要arm64v8。如果使用了Raspbian等32位操作系统,或者其他早期树莓派可能时armv7架构的话,就不适用了。这也是为什么我们在使用树莓派做服务器最佳实践选择Ubuntu的原因,详情可以点击了解。

安装过程非常容易。Gitea文档相对齐全,官方提供基于Docker镜像的安装文档。如想最简安装请看文档,我这里提供我认为的最佳实践,Gitea + MariaDB的方式。

  1. 我们需要先创建宿主操作系统上的一个新用户git来运行Gitea的整个Docker镜像程序。执行sudo adduser git如下:
sudo adduser git
Adding user `git' ...
Adding new group `git' (1003) ...
Adding new user `git' (1002) with group `git' ...
Creating home directory `/home/git' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for git
Enter the new value, or press ENTER for the default
        Full Name []: Git User
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] Y

记住上面自动创建的user和group的id,10021003
如宿主机已经有同名用户,你又需要使用不同用户,起个gitt类似的就行了。

  1. 利用docker-compose文件创建Docker实例。
version: "3"

networks:
  gitea:
    external: false

services:
  server:
    image: gitea/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1002
      - USER_GID=1003
      - GITEA__database__DB_TYPE=mysql
      - GITEA__database__HOST=db:3306
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
    restart: always
    volumes:
      - /home/git/.ssh/:/data/git/.ssh
      - ./gitea-data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"
    networks:
      - gitea
    depends_on:
      - db

  db:
    image: mariadb:10.5
    container_name: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=xxx  # Requested, set the root's password of MySQL service.
      - MYSQL_LOG_CONSOLE=true
    volumes:
      - /opt/mysql/db:/var/lib/mysql  # Requested, specifies the path to MySQL data persistent store.
    networks:
      - gitea

注意配置中USER_UIDUSER_GID分别填入步骤1记录中的ID, 然后docker-compose up -d启动。 打开 http://:3000,正常打开页面出现以下初始配置页面。

-----2022-03-27-155043

此时选择MSSQL,主机填写db:3306,填写相应账号密码即可。

这里填写的数据库名称是要求存在的, 所以要事前连接数据库进行创建名为gitea的空database,和与其对应的gitea用户。建议使用Adminer可视化操作。这里不赘诉,参考以前关于Adminer文章

初始页面的其他配置也可以在这个时候修改。
将服务器url中的域名ssh域名都改成树莓派服务器域名。这里都设置成pi
22的端口都不要动,因为这里指Docker容器内的服务端口。
建议关闭注册,设定唯一管理员账号。

完成后选择立即安装,完成。不用太担心有写配置没有改好就安装了,这些配置其实会生成一个在/data的volumes下的gitea-data/gitea/conf/app.ini文件。修改此文件后再重启服务即可生效。

设置ssh转发

经过上一步骤安装, Gitea绝大多数功能都能正常使用了, 除了ssh。 但是我们也做了一些工作。

  • 设置了git系统账户,并且其对应的ssh公钥位置映射。/home/git/.ssh/:/data/git/.ssh 这样保证容器内外的用户的公钥可以共享。
  • 设置了ssh端口映射。2222:22,我们将容器内部的22端口映射到了2222,这样保证和宿主机的22不会冲突。
    此时只差最后一步, 即如何让git@pi:jmu/test.git这样的SSH请求如何从 Host:22转发到Docker:2222上面。

方法1:改变客户机上(即git clone代码的机器上)的配置,让ssh默认连接2222端口。在客户机上创建~/.ssh/config文件,内容如下:

Host pi
    HostName pi
    Port 2222

这种方法的好处是不需要修改宿主机任何配置,ssh请求直达容器2222端口,理论速度最快。坏处当然是所有使用这个git服务的机器,都要配置一遍。

方法2:使用Gitea官网的SSHing Shim方式。在宿主机上依次执行

sudo -u git ssh-keygen -t rsa -b 4096 -C "Gitea Host Key"
sudo -u git cat /home/git/.ssh/id_rsa.pub | sudo -u git tee -a /home/git/.ssh/authorized_keys
sudo -u git chmod 600 /home/git/.ssh/authorized_keys
cat <<"EOF" | sudo tee /usr/local/bin/gitea
#!/bin/sh
ssh -p 2222 -o StrictHostKeyChecking=no [email protected] "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
EOF
sudo chmod +x /usr/local/bin/gitea

配置完成后, 重新启动Docker容器: docker-compose up --force-recreate --build -d即完成。

这种方法是Gitea官方提供的方式,相对复杂。使用场景稍微有些要求,因为要进行宿主机配置。但是可以兼顾宿主机的22端口可用,也保证了Gitea容器的22端口对外服务的一致性。git@pi:jmu/test.git的连接看起来简洁优雅。 缺点除了复杂外,因为ssh转发可能有性能损失。

方法3:修改Gitea的对外显示端口配置成2222。即修改gitea-data/gitea/conf/app.ini文件中的SSH_PORT修改成2222,注意SSH_LISTEN_PORT维持22不要动。
配置完成后, 重新启动Docker容器: docker-compose up --force-recreate --build -d即完成。 重新打开页面,会发现代码clone的SSH一栏已经变成类似ssh://git@pi:2222/jmu/test.git形式。

这种方法是最快捷简单的方式,缺点是每个链接都会包含2222,不够优雅。

使用.env灵活覆盖app.ini配置(选读章节)

以上内容就结束了。 我们发现包括初始配置页面和app.ini配置都需要手动修改。 如果想在docker启动后就一下子都配置好,Gitea提供了环境变量。 形如GITEA__SECTION_NAME__KEY_NAME, 我们直接配置到docker-compse.yml文件中即可。里面变量使用同目录.env保存。 下面是两者环境变量+.env结合的例子:

  server:
    image: gitea/gitea:1.16.5
    container_name: gitea
    environment:
      - USER_UID=1002
      - USER_GID=1003
      - GITEA__database__DB_TYPE=mysql
      - GITEA__database__HOST=db:3306
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=${GITEA__database__PASSWD:?GITEA__database__PASSWD not set}
      - GITEA__mailer__ENABLED=true
      - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set}
      - GITEA__mailer__MAILER_TYPE=smtp
      - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set}
      - GITEA__mailer__IS_TLS_ENABLED=true
      - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey}
      - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}"""

.env文件内容:

GITEA__database__PASSWD=xxxx
[email protected]
GITEA__mailer__HOST=smtp.xxx.com:465
[email protected]
GITEA__mailer__PASSWD=xxxx

安装部分全部结束。