Gitea 自建 Git 服务部署
Gitea 是一个 Go 实现了非常轻量级的 Git 服务。功能上与成熟的 Gitlab 相比,相差较大,但是胜在简单快捷。如果没有奇怪的问题,大概 10 分钟就可以成功使用 Docker 部署
我们假定在把数据文件存储在/opt/gitea
目录中,将该文件挂载到 Docker 的/data
目录。
由于在 Docker 中启动,而 Git 功能依赖于 SSH 服务,因此需要做一个端口转发,具体实现见后文,需要首先在宿主机建立相应的 Git 账户
上述任务完成后,执行下面的 Docker 即可启动 Gitea 服务。
docker run -d --rm --name=gitea -p 10022:22 -p 10080:3000 -v /opt/gitea:/data -v /home/git/.ssh/:/data/git/.ssh gitea/gitea:latest
这样,访问 10080 端口,即可进入 Gitea 页面。首次进入需要进行初始化配置,不过既然是图形化配置,识字就能配置好。
上面的文件可以存成一个 Bash 脚本,如果后面有修改文件,或其他操作需要重启 Gitea,只需要docker stop gitea
,然后再执行上面的脚本即可(不需要清理 Docker,已经配置了结束自动清理)
Nginx 反向代理
如果可以,建议使用 Nginx 反向代理下 10080 端口,并且启用 HTTPS 服务。
server { listen 80; server_name git.oyohyee.com; rewrite ^(.*)$ https://$host$1 permanent; } server { listen 443 ssl http2; server_name git.oyohyee.com; client_max_body_size 20m; ssl_certificate "/etc/nginx/ssl/1_git.oyohyee.com_bundle.crt"; ssl_certificate_key "/etc/nginx/ssl/2_git.oyohyee.com.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; proxy_max_temp_file_size 0; location ^~ / { proxy_pass http://127.0.0.1:10080; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $server_name; } }
SSH 映射
该部分逻辑有点绕,如果不想知道原理可以直接跳到最后看操作
我们常用的git pull
、git push
实际上使用的是 SSH 服务,由于其默认为 22 端口,因此通常省略了相关操作,但是由于这里我们运行在 Docker 中,因此需要把原本的 22 端口映射到宿主机的其他端口(除非宿主机本身不需要在 22 端口运行 SSH)
大致思路就是,宿主机也启用一个 git 用户,当需要传输代码时,实际上连接的是宿主机的 git 用户,而后将该请求转发至 10022 端口(Docker 中的 Gitea 服务)
authorized_keys
文件中,可以使用command
在连接后自动执行命令,而 Gitea 的authorized_keys
会通过该操作执行/app/gitea/gitea
文件,由于所有用户都使用 git 账户连接,需要借助公钥来判断其对应的是系统中的哪一个用户,以及其是否拥有仓库权限。该操作就在/app/gitea/gitea
中实现
如果我们希望 Gitea 内配置的用户也可以在宿主机拥有连接权限,那么需要将 Gitea 与宿主机共享同一份 authorized_keys
文件。而刚好 Gitea 的该文件需要执行前面提到的/app/gitea/gitea
鉴权文件,那么我们刚好可以使用这个文件来实现一个 SSH 转发。
另外,还需要建立一份公私钥对,用于宿主机连接到 Docker 内的鉴权。虽然逻辑上属于两个主机,但是由于共享了同一个文件夹,因此id_rsa
和authorized_keys
。将对应的id_rsa.pub
添加到authorized_keys
即可。
(这个公钥 不需要 添加command
,鉴权使用的参数已经通过宿主机的鉴权文件传输了)
那么我们的整体思路如下:
- 用户 A 通过 22 端口连接到宿主机 git 用户
- 触发宿主机的鉴权文件
- 鉴权文件将连接转发至 10022 端口,连接到 Gitea 中的 git 用户
- 触发 Gitea 的鉴权文件
- 鉴权文件进行用户鉴权
首先确保宿主机和 Docker 内的 git 用户 id 相同。如果不同需要调整为相同才可以进行后面的步骤
> id git uid=1000(git) gid=1000(git) groups=1000(git)
然后,生成一份宿主机和 Docker 通信的 SSH 公私钥对
这个公私钥对需要放置在/home/git/.ssh
文件夹中,如果有必要需要修改文件权限(文件夹 755,文件 600,用户和用户组都是 git)
ssh-keygen -t rsa -b 4096 -C "Gitea Host Key"
将上面生成的公钥添加到/home/git/.ssh/authorized_keys
中
cat /home/git/.ssh/id_rsa.pub >> /home/git/.ssh/authorized_keys
在宿主机内配置/app/gitea/gitea
文件,并添加可执行权限chmod a+x /app/gitea/gitea
#!/bin/bash ssh -p 10022 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
映射宿主机的/home/git/.ssh
到/data/git/.ssh
(如果前面按照说明启动,那么已经配置好了)
Git Hooks 启用
配置文件修改
Git Hooks 是在 Git 某些特定条件下触发的钩子,可以用来实现代码同步、自动部署。
要启用 Git Hooks 需要在配置文件/opt/gitea/gitea/conf/app.ini
(docker 中的 /data/gitea/conf/app.ini
)中配置如下内容。默认可能没有这一项,需要手动添加。
[security] DISABLE_GIT_HOOKS = false
添加后,管理员就可以在用户管理允许部分用户编辑 Git Hooks 了。
Git Hooks 允许在服务器上执行脚本,请不要把权限授予不可信的人
自动同步 Github 的例子
post-receive
指接收到提交的代码后触发的钩子,在这里将代码传一份到 Github,即可实现自动同步功能
具体内容如下
#!/bin/bash repos=("git@github.com:OhYee/code-questions.git") export GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no -i /data/git/.ssh/id_rsa" for repo in $repos; do nohup git push --mirror $repo done
repos
存储了所有需要同步的仓库,使用空格分割,双引号包裹即可。
如果有必要,也可以同步一份到 Gitee。
配置之前,需要把相应的公钥配置到 Github 和 Gitee。
(这里直接使用前面宿主机和 Docker 通信的 SSH 公私钥对即可)
自动备份
由于 Docker 的存在,已经屏蔽了大部分复杂的操作,只有三部分数据被映射在了宿主机上:
/app/gitea/gitea
/opt/gitea/
/home/git/.ssh/
其中,第一个文件内容是固定的,实际上没有备份的必要性,只需要备份后两者即可
可以添加一个 cron 每日任务,定时打包几个文件夹(可以借助onedrivecmd
和 ServerChan 实现自动传输到 OneDrive,并在失败时微信通知)
使用 git 用户建立/home/git/gitea_backup/
文件夹,内部包含两个文件:
/home/git/gitea_backup/backup.crontab.bash
/home/git/gitea_backup/backup.conf
需要提前安装onedrivecmd
和curl
,并使用onedrivecmd init
python3 -m pip install https://github.com/OneDrive/onedrive-sdk-python/archive/master.zip onedrivecmd
文件内容如下
#!/bin/bash # For user git `crontab -e` # # 0 5 * * * /bin/bash /home/git/gitea_backup/backup.crontab.bash # SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) NAME=`date '+%Y_%m_%d'` FILENAME="${SHELL_FOLDER}/backup/${NAME}.zip" ONEDRIVE=$(cat ${SHELL_FOLDER}/backup.conf | grep -E '^OneDrive\s+.+$' | tr -s " " | cut -d " " -f 2) SERVERCHAN=$(cat ${SHELL_FOLDER}/backup.conf | grep -E '^ServerChan\s+.+$' | tr -s " " | cut -d " " -f 2) function notify() { if [[ -n ${SERVERCHAN} ]]; then curl -X POST "http://sc.ftqq.com/${SERVERCHAN}.send" \ -G \ --data-urlencode "text=${1}" \ --data-urlencode "desp=${2}" fi } zip -r ${FILENAME} /opt/gitea /home/git/.ssh /app/gitea/gitea if [[ $? -ne 0 ]]; then notify "Gitea Backup error" "" else if [[ -n ${ONEDRIVE} ]]; then onedrivecmd put "${FILENAME}" "od:${ONEDRIVE}" fi if [[ $? -ne 0 ]]; then notify "Gitea Backup upload error" "" fi fi
# OneDrive 备份文件夹 # 需要安装 `onedrivecmd` 并运行 `onedrivecmd init` # 详情见 https://github.com/cnbeining/onedrivecmd OneDrive /backup/gitea/ # Server酱微信通知 # 详情见 https://sc.ftqq.com/ # 需要安装 curl # Example: ServerChan abcdefg ServerChan xxxxxxxx