厌烦了每次手动的创建 docker images,然后还需要发布到 GitHub Container Registry。研究了下 GitHub Actions 在这方面的应用,写了个 demo,记录下操作步骤。
创建一个项目,这里是 dockerdemo,只有一个文件 app.js
const Koa = require("koa");
const port = "9000";
const app = new Koa();
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(port);
如果正常执行,即 node app.js
,访问 http://localhost:9000
可以得到 Hello World
。
创建 Dockerfile 文件
FROM tourcoder/nodebasic:latest
RUN mkdir -p /tcdocker/dockerdemo
COPY . /tcdocker/dockerdemo
WORKDIR /tcdocker/dockerdemo
RUN npm install
EXPOSE 9000
CMD node app.js
没有什么特别的地方。
创建 Action,即在项目的根目录下的 .github/workflows/
文件夹下创建一个 .yml
文件,名字随意,我写了 github.yml
name: GitHub Actions Demo
on:
push:
branches: [ master ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/[email protected]
- name: Set up Docker Buildx
uses: docker/[email protected]
- name: Login to Github Packages
uses: docker/[email protected]
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Build image and GitHub Container Registry
uses: docker/[email protected]
with:
context: ./
tags: |
ghcr.io/tourcoder/dockerdemo/dockerdemo:latest
push: ${{ github.ref == 'refs/heads/master' }}
本来我是想自己写一个这个 Action 的,但 GitHub Marketplace 里面有 Docker 公司写好的,索性用了它的。每一步的作用可以看 name
的说明。这里需要说明的内容是
github.actor
: 会自动获取
password
: 在 https://github.com/settings/tokens
创建一个 token,权限是 repo
以及 package
的权限,得到一个 token,然后进入项目的 settings->secrets->actions
,创建一个 secret
,在 name
部分写入内容,我这里是 GHCR_TOKEN
,而在 Value
里写入刚才获取到的 token。
最后一个 push 表示只是对 master 分支起作用,即向 master 分支 push 或 merge 才会激发该 action。致此,一个通过 Github Actions 创建并发布 Docker images 的功能就实现了。
上面是常规的内容,很多是固定写好的,在实际操作中也会将一些内容做环境变量等。比如 ghrc 的内容 ghcr.io/tourcoder/dockerdemo/dockerdemo:latest
其中 tourcoder/dockerdemo
就可以通过 ${{ github.repository_owner }}
来获取,而 dockerdemo:latest
中的镜像名字可以在文件中设置 env,也可以在 actions 创建的地方设置一个变量,然后通过 ${{ vars.IMAGE_NAME }}
这样的方式来读取。特别需要注意的是在实际生成镜像的过程中是需要 repo 的名字都是小写的,很多时候,需要先将 repo 的名字改成小写,所以上面的 github.yaml 文件内容会变成
name: GitHub Actions Demo
//...
- name: Convert repository_owner to lowercase
run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
- name: Build image and GitHub Container Registry
uses: docker/[email protected]
with:
context: ./
tags: |
ghcr.io/${{ env.REPO_OWNER }}/${{ vars.IMAGE_NAME }}:latest
push: ${{ github.ref == 'refs/heads/master' }}
部分内容省略。
GitHub 并不建议这么做,应该的做法是在服务器上进行部署的操作,这里我只是做了一个实验。大概的步骤是通过 ssh 登录到服务器,然后执行 docker pull 命令即可,用 GitHub Actions 就是下面的内容
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USERNAME }}
key: ${{ secrets.DEPLOY_KEY }}
port: ${{ secrets.DEPLOY_PORT }}
script: |
sudo docker pull ghcr.io/tourcoder/dockerdemo/dockerdemo:latest
几个参数的解释
参数名 | 说明 |
---|---|
host | 服务器地址 |
username | 登录名 |
key | 登录的密钥,需要用私钥,而非 .pub 公钥 |
port | ssh的端口,默认为 22 |
将这些内容都写入到该项目的 settings->secrets->actions
中,和上面创建 token 时候一样。
备注
在执行最下面一行的 sudo docker
时会遇到问题 sudo: no tty present and no askpass program specified
,解决办法是将用户名的 sudo 设置成无需密码,即编辑 /etc/sudoers
,增加一行 用户名 ALL = NOPASSWD: /etc/docker, /usr/bin/docker, /usr/libexec/docker
,需要重启。
本地创建密钥 ssh-keygen -t rsa -C "密钥名"
,公钥需要上传到服务器 ssh-copy-id -i id_rsa.pub 登录名@服务器地址
,而在 GitHub 的项目设置里用的是私钥 id_rsa
。
在拉取 ghcr 的内容时提示未认证,有两种处理办法,一种是在上面的发布脚本里写 cat ~/ghtoken | sudo docker login ghcr.io -u tourcoder --password-stdin
,但真不建议这样做,建议在服务器上执行一次这个命令比较好。
最后
项目地址:这里
> 可在 Twitter/X 上评论该篇文章或在下面留言(需要有 GitHub 账号)