跳转至

使用 Git 部署容器指南

预计阅读时长 : 8 分钟

虽然使用 Drone 配合 Github 做自动化部署非常方便,但是也有部分场景不方便使用 Github 作为远程存储库,例如在外网无法访问的内网服务器上部署。

对于这样的场景,可以直接在服务器上使用 Git 裸仓库作为远程存储库,然后通过 hooks 脚本进行自动化部署。

配置 Git 仓库

创建裸仓库

裸仓库是一个没有工作目录的 Git 仓库,特别适合用作远程存储库。

1
2
3
mkdir /path/to/repo.git
cd /path/to/repo.git
git init --bare

设置仓库权限

在多用户场景下,需要确保设置合适的权限以避免权限冲突。

chown -R user:group /path/to/repo.git
chmod -R 775 /path/to/repo.git

如果是个人项目的话,就不用考虑这么多了。

关联远程仓库

在开发者本地机器上,将本地仓库关联到服务器上的裸仓库:

提前配置好 SSH 秘钥

由于 Git 仓库在服务器上,所以需要提前配置好 SSH 秘钥,否则会添加和推送失败。

git remote add origin user@server:/path/to/repo.git
git push -u origin main

如果在 Cursor 的 UI 界面中添加远程仓库,那么需要使用 ssh:// 协议:

ssh://root@xxx.xxx.xx.xx/mnt/user/appdata/rsshub/git

创建 Hooks 脚本

Hooks 脚本本质上是放在指定路径下的 shell 脚本,因此可以在脚本中执行任何命令。

一般而言,建议在项目中使用 dockerfile 来创建镜像,然后使用 docker-compose 来部署容器。

创建 post-receive 钩子

由于我们的触发条件是 push 操作,所以需要在服务器裸仓库中创建 hooks/post-receive 文件:

nano /path/to/repo.git/hooks/post-receive

在这个脚本中添加以下内容:

#!/bin/bash

# 部署路径
DEPLOY_DIR="/mnt/user/appdata/rsshub/deploy"

# 仓库路径
REPO_DIR="/mnt/user/appdata/rsshub/git"

# 部署分支
BRANCH="update-from-upstream"

# 日志路径
LOG_FILE="/var/log/deployment.log"

# 启用日志记录
exec > >(tee -a "$LOG_FILE") 2>&1

echo "==============================================="
echo "---- Deployment started: $(date) ----"
echo "==============================================="

# 检查部署路径是否存在,不存在则创建
if [ ! -d "$DEPLOY_DIR" ]; then
    echo "Deployment directory $DEPLOY_DIR does not exist. Creating..."
    mkdir -p "$DEPLOY_DIR"
    if [ $? -ne 0 ]; then
        echo "Error: Failed to create deployment directory $DEPLOY_DIR."
        exit 1
    fi
fi

# 检查仓库是否为空
if [ -z "$(git --git-dir="$REPO_DIR" show-ref)" ]; then
    echo "Error: The bare repository is empty. Push some commits to the repository first."
    exit 1
fi

# 将代码从指定分支导出到部署路径
echo "Checking out branch $BRANCH to $DEPLOY_DIR..."

# 强制将分支内容检出到工作目录
GIT_WORK_TREE="$DEPLOY_DIR" GIT_DIR="$REPO_DIR" git checkout -f "$BRANCH"
if [ $? -ne 0 ]; then
    echo "Error: Git checkout failed for branch $BRANCH."
    exit 1
fi

# 确保工作目录与最新提交一致
echo "Resetting working tree in $DEPLOY_DIR to latest pushed content..."
GIT_WORK_TREE="$DEPLOY_DIR" GIT_DIR="$REPO_DIR" git reset --hard
if [ $? -ne 0 ]; then
    echo "Error: Git reset failed for branch $BRANCH."
    exit 1
fi

# 进入部署路径
cd "$DEPLOY_DIR" || { echo "Error: Failed to change directory to $DEPLOY_DIR"; exit 1; }

# 检查是否存在 docker-compose.york.yml 文件
if [ ! -f "docker-compose.fork.yml" ]; then
    echo "Error: docker-compose.york.yml not found in $DEPLOY_DIR"
    exit 1
fi

# 停止并移除现有服务
echo "Stopping and removing existing containers..."
docker compose -f docker-compose.fork.yml down

# 重建并启动服务
echo "Rebuilding and starting services..."
docker compose -f docker-compose.fork.yml up -d --force-recreate --build

# 部署完成
echo "Deployment finished successfully: $(date)"

设置执行权限

hooks 脚本本质上是 shell 脚本,所以需要设置执行权限:

chmod +x /path/to/repo.git/hooks/post-receive

准备部署环境

裸仓库中是没有工作目录的,我们在执行 hooks 的时候,必须在部署目录中创建本地工作目录,之后才能进行镜像构建和容器部署等操作。

mkdir -p /path/to/deploy
chown -R user:group /path/to/deploy

直接运行验证

为了验证 hooks 脚本是否正常工作,可以手动运行一次看看执行过程和结果是否符合预期:

cd /path/to/repo.git
./hooks/post-receive

测试部署流程

推送代码

确定 hooks 脚本正常工作后,就可以在本地推送代码到远程仓库,验证部署流程是否正常:

如果是第一次推送,那么需要指定推送的分支:

git push -u origin main

之后再推送代码时,就不需要指定分支了:

git push origin main

如果需要强制推送,那么可以使用 --force 选项:

git push origin main --force

验证部署

为了能够查看部署的进展,建议在终端中执行 push 操作,这样可以在终端中看到部署的实时日志。

如果是通过 UI 界面执行的 push 操作,那么也可以通过查看实时日志文件来跟进部署进度:

tail -f /var/log/deployment.log

也可以使用 lazydocker 来实时查看容器状态:

lazydocker

最佳实践

通过 Git 裸仓库和 hooks 机制,我们可以实现一个轻量级的自动化部署流程。这种方式特别适合:

  • 内网环境部署
  • 可用 docker 部署的小型项目

对于多人协作项目,还需要考虑相应的权限设置,可以参考 Git - 配置服务器 ⧉ 中的相关示例。