Lancker头像
关注

宝塔 Docker Compose + GitHub Actions CI/CD 完整教程

宝塔 Docker Compose + GitHub Actions CI/CD 完整教程

适用场景:宝塔面板 + Docker Compose 编排部署 + Docker Hub 镜像仓库 + GitHub Actions 自动部署
本文以实际项目为例:镜像 zhongdaiqi/xiezitai,服务器 Oracle Cloud,编排文件由宝塔管理。


一、整体架构

开发者 push 代码到 GitHub
        │
        ▼
GitHub Actions
   ├─ 构建 Docker 镜像
   ├─ 推送到 Docker Hub
   └─ SSH 登录服务器
              │
              ▼
        服务器 authorized_keys 限制
        command="/data/xiezitai_deploy/deploy.sh"
              │
              ▼
        deploy.sh 执行
        docker compose pull && up -d
              │
              ▼
        容器更新完成

二、前置条件

项要求
服务器已装 Docker + Docker Compose(插件版 docker compose)
宝塔面板已用「Docker 编排」跑起项目
镜像仓库Docker Hub 账号,镜像已能 push
GitHub仓库已关联代码,Actions 可用
本地有 SSH 客户端(Windows PowerShell / macOS / Linux 均可)

三、服务器端配置

3.1 确认 Docker 环境

docker -v
docker compose version

应输出类似:

Docker version 29.8.2
Docker Compose version v5.6.0

3.2 确认宝塔编排文件位置

宝塔编排文件通常在:

/www/server/panel/data/compose/<项目名>/docker-compose.yaml

本例中项目名为 xiezitai,所以:

/www/server/panel/data/compose/xiezitai/docker-compose.yaml

确认内容里 image: 是你的 Docker Hub 镜像:

cat /www/server/panel/data/compose/xiezitai/docker-compose.yaml

3.3 创建部署脚本

本例脚本路径为 /data/xiezitai_deploy/deploy.sh。

mkdir -p /data/xiezitai_deploy
cat > /data/xiezitai_deploy/deploy.sh << 'EOF'
#!/bin/bash
set -e

COMPOSE_DIR="/www/server/panel/data/compose/xiezitai"

cd "$COMPOSE_DIR"

echo "===== $(date) 开始部署 ====="

docker compose pull
docker compose up -d --remove-orphans
docker image prune -f

echo "===== 部署完成 ====="
EOF

chmod +x /data/xiezitai_deploy/deploy.sh

说明:

  • set -e:任何一步失败立即退出,CI 能感知。
  • docker compose pull:拉取最新镜像。
  • up -d --remove-orphans:重建容器并清理孤立容器。
  • image prune -f:清理悬空镜像。

3.4 手动验证脚本

bash /data/xiezitai_deploy/deploy.sh

预期输出:

===== ... 开始部署 =====
[+] pull 2/2
 ✔ Image zhongdaiqi/xiezitai:latest Pulled
 ✔ Image mariadb:11.4 Pulled
[+] up 2/2
 ✔ Container xiezitai    Running
 ✔ Container xiezitai-db Healthy
===== 部署完成 =====

确认容器状态:

docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"

这一步必须手动跑通,再继续。


四、SSH 密钥配置

4.1 生成专用密钥(服务器上执行)

ssh-keygen -t ed25519 -f ~/.ssh/github_deploy -N ""

生成:

  • ~/.ssh/github_deploy(私钥,给 GitHub)
  • ~/.ssh/github_deploy.pub(公钥,留服务器)

4.2 把公钥加入授权列表并加限制

cat ~/.ssh/github_deploy.pub >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

编辑 ~/.ssh/authorized_keys:

vi ~/.ssh/authorized_keys

找到刚加的那行(ssh-ed25519 AAAA...),在行首加上限制:

restrict,command="/data/xiezitai_deploy/deploy.sh" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... root@instance-xxx

说明:

  • restrict:禁用端口转发、X11、PTY 等所有危险功能。
  • command=...:无论客户端发什么命令,只执行指定脚本。
  • 这样即使私钥泄露,攻击者也只能触发部署,无法执行任意命令。

4.3 查看私钥内容(复制到 GitHub)

cat ~/.ssh/github_deploy

完整复制 -----BEGIN OPENSSH PRIVATE KEY----- 到 -----END OPENSSH PRIVATE KEY----- 的全部内容。

⚠️ 私钥只能填到 GitHub Secrets,绝不要提交到仓库或贴到聊天里。

4.4 本地验证登录

在你本机(把私钥下载到本机后):

chmod 600 ~/.ssh/github_deploy
ssh -i ~/.ssh/github_deploy -p 22 root@ip地址

预期:直接执行 deploy.sh,打印部署日志,然后自动断开,不给你 shell。

看到 PTY allocation request failed 是正常的(因为加了 no-pty)。

如果看到 Please login as the user "opc",说明 root 被 Oracle 禁了,需要改用 opc 用户(见附录)。


五、GitHub 配置

5.1 添加 Secrets

仓库 → Settings → Secrets and variables → Actions → New repository secret:

Secret 名称值
SSH_HOSTip地址
SSH_USERroot
SSH_PORT22
SSH_KEYgithub_deploy 私钥全文

如果镜像构建也在 GitHub Actions 里做,再加:

  • DOCKERHUB_USERNAME
  • DOCKERHUB_TOKEN(Docker Hub → Account Settings → Security → New Access Token)

5.2 创建 workflow

在项目仓库创建 .github/workflows/deploy.yml。

情况 A:镜像已由其他 workflow 构建推送,只需要部署
name: Deploy

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          port: ${{ secrets.SSH_PORT }}
          key: ${{ secrets.SSH_KEY }}
          script_stop: true
          script: |
            echo "trigger deploy"

因为服务器 authorized_keys 里加了 command=,这里的 script 内容会被服务器忽略,真正执行的是 deploy.sh。

情况 B:构建推送 + 部署 一条龙
name: Build and Deploy

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: |
            zhongdaiqi/xiezitai:latest
            zhongdaiqi/xiezitai:${{ github.sha }}

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          port: ${{ secrets.SSH_PORT }}
          key: ${{ secrets.SSH_KEY }}
          script_stop: true
          script: |
            echo "trigger deploy"

六、触发验证

  1. 提交并 push 到 main。
  2. 打开 GitHub 仓库 → Actions 标签页。
  3. 点进 workflow,能看到部署日志,与手动 SSH 时一致:
===== ... 开始部署 =====
...
===== 部署完成 =====
  1. 服务器确认:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"

七、安全加固(强烈建议)

7.1 锁 appleboy 版本到 commit SHA

@v1 是浮动 tag,作者发新版会自动用上。想更稳,锁到具体 SHA:

uses: appleboy/ssh-action@0ff4204d59e8e51228ff73bce53f80d53301dee2  # v1.2.0

到 https://github.com/appleboy/ssh-action/releases 查最新版本对应 SHA。

7.2 用专用用户替代 root(可选,更安全)

useradd -m -s /bin/bash deploy
usermod -aG docker deploy

mkdir -p /home/deploy/.ssh
cat ~/.ssh/github_deploy.pub > /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

GitHub Secrets 里 SSH_USER 改成 deploy。

7.3 禁用 root 密码登录

/etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin prohibit-password

重启 SSH:

systemctl restart sshd

7.4 修改默认 SSH 端口

/etc/ssh/sshd_config 改 Port 2222,云安全组和宝塔防火墙同步放行,GitHub Secrets 里 SSH_PORT 改成 2222。


八、回滚机制

构建时同时打 latest 和 commit sha 两个 tag(见情况 B)。回滚时:

cd /www/server/panel/data/compose/xiezitai
# 临时把 image 改成某个 sha
sed -i 's|zhongdaiqi/xiezitai:latest|zhongdaiqi/xiezitai:<sha>|' docker-compose.yaml
docker compose up -d

或更规范的方式,用 .env 控制版本:

# docker-compose.yaml
image: zhongdaiqi/xiezitai:${IMAGE_TAG:-latest}

部署时:

IMAGE_TAG=<sha> docker compose up -d

九、常见问题排查

现象原因解决
Permission denied (publickey)私钥不对/不全重新 cat ~/.ssh/github_deploy,完整粘贴到 SSH_KEY
Load key ... error in libcrypto用了 .pub 公钥登录改用私钥(无 .pub 后缀)
PTY allocation request failed正常(no-pty)忽略
Please login as the user "opc"Oracle 禁用 root改用 opc 用户,见附录
dial tcp ... i/o timeout网络/防火墙检查 Oracle 安全组、宝塔防火墙放行 SSH 端口
Host key verification failedknown_hostsappleboy 默认跳过,一般不会遇到
Action 成功但容器没更新脚本未执行检查 authorized_keys 的 command= 路径
Conflict. container name already in use同名容器残留docker rm -f 容器名 后重试

十、附录:Oracle Cloud 用 opc 用户

如果 root 被禁,改用 opc:

# 1. 公钥放到 opc
sudo mkdir -p /home/opc/.ssh
sudo chmod 700 /home/opc/.ssh
sudo vi /home/opc/.ssh/authorized_keys
# 加入:
# restrict,command="/data/xiezitai_deploy/deploy.sh" ssh-ed25519 AAAA...
sudo chown -R opc:opc /home/opc/.ssh
sudo chmod 600 /home/opc/.ssh/authorized_keys

# 2. opc 加入 docker 组
sudo usermod -aG docker opc

# 3. deploy.sh 里 docker 命令加 sudo,并配置免密
echo "opc ALL=(ALL) NOPASSWD: /usr/bin/docker" | sudo tee /etc/sudoers.d/opc-docker

GitHub Secrets 里 SSH_USER 改成 opc。


十一、完整检查清单

服务器端

  • Docker / Docker Compose 已装
  • 宝塔编排文件就位,服务正常运行
  • deploy.sh 已创建并 chmod +x
  • 手动 bash deploy.sh 成功

SSH

  • github_deploy 密钥已生成
  • 公钥加入 authorized_keys 并加 restrict,command=...
  • 权限 700 / 600 正确
  • 本地用私钥 SSH 登录成功(自动触发部署)

GitHub

  • SSH_HOST / SSH_USER / SSH_PORT / SSH_KEY 已加 Secrets
  • .github/workflows/deploy.yml 已创建
  • push 后 Actions 运行成功
  • 服务器容器确认已更新

安全

  • 私钥只存 GitHub Secrets
  • authorized_keys 已加 restrict,command=
  • (可选)锁 appleboy commit SHA
  • (可选)专用用户替代 root
  • (可选)禁用密码登录

十二、流程总结

① 服务器:deploy.sh 手动跑通
② 服务器:生成 SSH 密钥,公钥加 restrict,command= 限制
③ 本地:用私钥 SSH 验证能自动触发部署
④ GitHub:配置 4 个 Secrets
⑤ GitHub:创建 deploy.yml
⑥ push 触发,Actions 自动 SSH 执行 deploy.sh
⑦ 服务器:容器自动更新,数据卷复用,不丢数据

至此,代码 push → 镜像构建推送 → 服务器自动更新 的完整 CI/CD 链路就跑通了。


有任何一步卡住,把报错原文和当前执行的命令贴出来,我帮你定位。记住:私钥永远不要贴出来。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/zhongdaiqi/article/details/167221221

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--