前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >GitHub Actions 自动构建镜像 并发布到 Docker Hub

GitHub Actions 自动构建镜像 并发布到 Docker Hub

作者头像
yiyun
发布2022-04-01 15:55:50
2.1K0
发布2022-04-01 15:55:50
举报
文章被收录于专栏:yiyun 的专栏yiyun 的专栏

引言

  • 通过GitHub的源代码自动构建镜像
  • 将镜像上传到 Docker Hub
  • 自动部署:远程服务器 pull Docker Hub

本文以 SimCaptcha 项目为例。

deploy-docker.yml

.github/workflows/deploy-docker.yml

代码语言:javascript
复制
name: Docker Image CI/CD
on:
  push:
    branches: [ master ]
jobs:
  # 构建并上传 Docker镜像
  build: 
    runs-on: ubuntu-latest # 依赖的环境      
    steps:
      - uses: actions/checkout@v2
      - name: Build Image
        run: |
          docker build -t yiyungent/simcaptcha -f examples/EasyAspNetCoreService/Dockerfile .
          docker build -t yiyungent/simcaptcha-client -f examples/AspNetCoreClient/Dockerfile .
      - name: Login to Registry
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}
      - name: Push Image
        run: |
          docker push yiyungent/simcaptcha
          docker push yiyungent/simcaptcha-client
        
  # Docker 自动部署
  deploy-docker: 
    needs: [build]
    name: Deploy Docker
    runs-on: ubuntu-latest
    steps:
      - name: Deploy
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }} # 服务器ip
          username: ${{ secrets.HOST_USERNAME }} # 服务器登录用户名
          password: ${{ secrets.HOST_PASSWORD }} # 服务器登录密码
          port: ${{ secrets.HOST_PORT }} # 服务器ssh端口
          script: |
            # 切换工作区
            cd simcaptcha
            # 下载 docker-compose.yml
            wget -O docker-compose.yml https://raw.githubusercontent.com/yiyungent/SimCaptcha/master/docker-compose.yml
            # 停止并删除旧 容器、网络、挂载点
            #docker-compose down                          # TODO: docker-compose: command not found. 不知道为什么找不到 docker-compose,但直接连接服务器执行就可以
            /usr/local/python3/bin/docker-compose down
            # 删除旧镜像
            docker rmi yiyungent/simcaptcha 
            docker rmi yiyungent/simcaptcha-client
            # 登录镜像服务器
            docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }} 
            # 创建并启动容器
            #docker-compose up -d --build
            /usr/local/python3/bin/docker-compose up -d --build

上面方法,每次 push 的均为 latest,没有版本号,不便于记录

区分版本

参考:

GitHub ghcr.io

Docker Hub

目标 我们想要让 拥有 tag 标记的成为一个 release 正式版或者 prerelease, 这样的版本会被 push 到 Docker Hub,而没有 tag 的为开发版,但为了让少部分人能及时获取最新开发版,也 push 到 Docker Hub,如何区分? 正式版: v1.0.0 在这个 v1.0.0 后又更新了些,但不足以发布新版本,但仍 push 到 Docker Hub, 于是由 GitHub Actions 自动 push 到 Docker Hub 标记为 上次版本号-beta,例如: v1.0.0-beta, 意味: v1.0.0后的最新开发版(介于 v1.0.0 到 下一个正式版本之前)

下面分为两种情况,有时我们的一个仓库可能需要发布不止一个包,于是如果直接使用 v1.0.0 这样的 tag 会导致混乱,不知道这是哪一个包的版本,于是这里用 包名-v1.0.0, 例如 PluginCore-v1.0.0,来标记 PluginCorev1.0.0, 这时 GitHub Actions 就需要去除 PluginCore-,再拿到 v1.0.0,用作 pushGitHub

Bug记录: 目前下方方案还有一个问题未解决: 那就是 获取上一次 releasetag,在一个仓库有多个包时,获取的 release tag,可能不是你所需要包的对应 tag,因此,为了防止混乱,-beta 是直接添加在获取到的上一次 release tag后,即release tag没有做去除包名,例如, 没有去除前面的 PluginCore-,而是直接用 PluginCore-v1.0.0

一个仓库发布一个包

docker-push-beta

UpyunAction-docker-push-beta.yml

代码语言:javascript
复制
name: Docker Image CI/CD - Beta - UpyunAction

on:
  push:
    branches: [ main ]

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

      - name: Get latest release
        id: last_release
        uses: InsonusK/get-latest-release@v1.0.1
        with:
          myToken: ${{ github.token }}
          exclude_types: "release, prerelease"
          view_top: 1  

      - name: Set outputs
        id: vars
        run: |
          # 修改为你要推送的 镜像名
          echo ::set-output name=IMAGE_NAME::upyun-action
      
      - name: Build Image
        run: |
          docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.last_release.outputs.tag_name }}-beta -f src/UpyunAction/Dockerfile .

      - name: Login to Registry - Docker Hub
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}

      - name: Push Image - Docker 
        # push: last_release-beta
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.last_release.outputs.tag_name }}-beta

      - name: Login to Registry - ghcr.io
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      
      - name: Push Image - ghcr.io
        # push: last_release-beta
        run: |
          IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ steps.vars.outputs.IMAGE_NAME }}
          VERSION=${{ steps.last_release.outputs.tag_name }}-beta
          echo IMAGE_ID=$IMAGE_ID
          echo VERSION=$VERSION
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.last_release.outputs.tag_name }}-beta $IMAGE_ID:$VERSION
          docker push $IMAGE_ID:$VERSION

docker-push-release

UpyunAction-docker-push-release.yml

代码语言:javascript
复制
name: Docker Image CI/CD - Release - UpyunAction

on:
#  release:
#    types: [published]
  push:
    tags:
      - 'v*'

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

      - name: Set outputs
        id: vars
        run: |
          #echo ::set-output name=RELEASE_VERSION::$(echo ${GITHUB_REF:10})
          # 去掉前面的 refs/tags/
          echo ::set-output name=RELEASE_VERSION::$(echo ${GITHUB_REF:10})
          # 修改为你要推送的 镜像名
          echo ::set-output name=IMAGE_NAME::upyun-action

      - name: Build Image
        run: |
          docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.RELEASE_VERSION }} -f src/UpyunAction/Dockerfile .

      - name: Login to Registry - Docker Hub
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}

      - name: Push Image - Docker Hub
        # push: RELEASE_VERSION, latest
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.RELEASE_VERSION }}
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.RELEASE_VERSION }} ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:latest
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:latest
      
      - name: Login to Registry - ghcr.io
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      
      - name: Push Image - ghcr.io
        # push: RELEASE_VERSION, latest
        run: |
          IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ steps.vars.outputs.IMAGE_NAME }}
          VERSION=${{ steps.vars.outputs.RELEASE_VERSION }}
          echo IMAGE_ID=$IMAGE_ID
          echo VERSION=$VERSION
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:latest $IMAGE_ID:$VERSION
          docker push $IMAGE_ID:$VERSION
          docker tag $IMAGE_ID:$VERSION $IMAGE_ID:latest
          docker push $IMAGE_ID:latest

一个仓库发布多个包

docker-push-beta

AspNetCore3_1-docker-push-beta.yml

代码语言:javascript
复制
name: Docker Image CI/CD - Beta - AspNetCore3_1

on:
  push:
    branches: [ main ]

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

      - name: Get latest release
        id: last_release
        uses: InsonusK/get-latest-release@v1.0.1
        with:
          myToken: ${{ github.token }}
          exclude_types: "release, prerelease"
          view_top: 1  

      - name: Set outputs
        id: vars
        run: |
          # 修改为你要推送的 镜像名
          echo ::set-output name=IMAGE_NAME::plugincore-aspnetcore3-1
      
      - name: Build Image
        run: |
          docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.last_release.outputs.tag_name }}-beta -f examples/AspNetCore3_1/Dockerfile .

      - name: Login to Registry - Docker Hub
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}

      - name: Push Image - Docker 
        # push: last_release-beta
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.last_release.outputs.tag_name }}-beta

      - name: Login to Registry - ghcr.io
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      
      - name: Push Image - ghcr.io
        # push: last_release-beta
        run: |
          IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ steps.vars.outputs.IMAGE_NAME }}
          VERSION=${{ steps.last_release.outputs.tag_name }}-beta
          echo IMAGE_ID=$IMAGE_ID
          echo VERSION=$VERSION
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.last_release.outputs.tag_name }}-beta $IMAGE_ID:$VERSION
          docker push $IMAGE_ID:$VERSION

docker-push-release

AspNetCore3_1-docker-push-release.yml

代码语言:javascript
复制
name: Docker Image CI/CD - Release - AspNetCore3_1

on:
#  release:
#    types: [published]
  push:
    tags:
      - 'AspNetCore3_1-v*'

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

      - name: Set outputs
        id: vars
        run: |
          #echo ::set-output name=RELEASE_VERSION::$(echo ${GITHUB_REF:10})
          # 去掉前面的 refs/tags/AspNetCore3_1-
          # 注意: 这里需要修改 24, 
          # 这个数字为 `refs/tags/AspNetCore3_1-` 这个字符串的长度, 即为 24=10+len(AspNetCore3_1-)
          echo ::set-output name=RELEASE_VERSION::$(echo ${GITHUB_REF:24})
          # 修改为你要推送的 镜像名
          echo ::set-output name=IMAGE_NAME::plugincore-aspnetcore3-1

      - name: Build Image
        run: |
          docker build -t ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.RELEASE_VERSION }} -f examples/AspNetCore3_1/Dockerfile .

      - name: Login to Registry - Docker Hub
        run: docker login --username=${{ secrets.DOCKER_USERNAME }} --password ${{ secrets.DOCKER_PASSWORD }}

      - name: Push Image - Docker Hub
        # push: RELEASE_VERSION, latest
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.RELEASE_VERSION }}
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:${{ steps.vars.outputs.RELEASE_VERSION }} ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:latest
          docker push ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:latest
      
      - name: Login to Registry - ghcr.io
        run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
      
      - name: Push Image - ghcr.io
        # push: RELEASE_VERSION, latest
        run: |
          IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ steps.vars.outputs.IMAGE_NAME }}
          VERSION=${{ steps.vars.outputs.RELEASE_VERSION }}
          echo IMAGE_ID=$IMAGE_ID
          echo VERSION=$VERSION
          docker tag ${{ secrets.DOCKER_USERNAME }}/${{ steps.vars.outputs.IMAGE_NAME }}:latest $IMAGE_ID:$VERSION
          docker push $IMAGE_ID:$VERSION
          docker tag $IMAGE_ID:$VERSION $IMAGE_ID:latest
          docker push $IMAGE_ID:latest

补充

docker-push-release.yml 触发运行时, docker-push-beta 并不会触发运行,(因此不用担心发布release时, 错误push两次)

因为 GitHub Actions 的触发条件互斥,

代码语言:javascript
复制
on:
  push:
    branches: [ main ]

上方并不意味着在所有 main 上的 push 都会触发,

因为有 同样的在有 tag: v* 时已经触发了,因此不会再触发 仅仅是 push 的条件

纠正,上诉说法有误 其实是因为 git pushgit push --tags 是两步,git push 触发一次, git push --tags 触发一次, git push --tags 仅仅是推送了 tag,而不是源代码,因此仅仅触发了 GitHub Action 的 tag 触发器, 而 git push,不会推送 tag,自然不会触发 tag触发器

GitHub 镜像仓库服务 ghcr.io

参考:

GitHub Container Registry 可免费用于公共镜像。 在 Beta 版期间,Container Registry 可免费用于私有镜像,并且作为 GitHub Packages 的一部分,在普遍可用时将遵循相同的定价模型。

PS: 以前是 GitHub Packages Docker Registry,现在新的替换品是 GitHub Container Registry, 它们都属于 GitHub Packages

域更改

Container registry 的域是 ghcr.io

注册表

示例 URL

GitHub Packages Docker Registry

docker.pkg.github.com/OWNER/REPOSITORY/IMAGE_NAME

Container registry

ghcr.io/OWNER/IMAGE_NAME

注意 对于 ghcr.io 而言,与 Docker Hub 不同,无需提交 latestlatest 标签将始终指向最新提交的镜像, 因此,在使用 GitHub Actions 自动构建时,无需 push xxx:latest, 而在 Docker Hub, latest只是在你没有指定 :tag 时默认即为 latest Docker Hub

ghcr.io

注意 测试了一下,发现好像又不一定 latest 始终指向最新,因此最好还是 release 情况下,latest 和指定版本号 的 docker imagepush 一次

补充

docker-compose CLI

docker-compose build

代码语言:javascript
复制
build              Build or rebuild services

docker-compose build --pull

代码语言:javascript
复制
--pull                  Always attempt to pull a newer version of the image.

docker-compose pull

代码语言:javascript
复制
pull               Pull service images

docker-compose up

代码语言:javascript
复制
up                 Create and start containers

其实直接一个up 就可以,如果没有build,则自动build,但是并不是每次都会build,如果已经存在镜像,则不build,如果要每次都build,则 up --build

docker-compose down

代码语言:javascript
复制
down               Stop and remove containers, networks, images, and volumes

注意:虽然文档说是会删除镜像,但实际测试,使用 docker images,依然会显示有镜像,不过,确实相关容器被停止并删除

docker-compose push

代码语言:javascript
复制
push               Push service images

示例:

代码语言:javascript
复制
docker-compose -f docker-compose.Debug.yml up -d

CentOS 用户,组

参考:

添加用户 deploy-docker

代码语言:javascript
复制
adduser deploy-docker

补充:

在新建用户的同时添加到 docker组

代码语言:javascript
复制
adduser -g docker deploy-docker

为此用户设置密码

代码语言:javascript
复制
passwd deploy-docker

给已有用户增加组

代码语言:javascript
复制
usermod -G docker deploy-docker

或者

代码语言:javascript
复制
gpasswd -a username groupname

注意: 添加用户到某一个组 可以使用usermod -G groupname username这个命令可以添加一个用户到指定的组,但是以前添加的组就会清空掉。 所以想要添加一个用户到一个组,同时保留以前添加的组时,请使用gpasswd这个命令来添加操作用户

查看当前用户所在组

代码语言:javascript
复制
groups

查看指定用户所在组

代码语言:javascript
复制
groups username

查看有哪些组

代码语言:javascript
复制
cat /etc/group

查看有哪些用户

代码语言:javascript
复制
cat /etc/passwd

ERROR: Failed to Setup IP tables

代码语言:javascript
复制
[deploy-docker@iZqnwheobg66nbZ simcaptcha]$ docker-compose up -d --build
Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
Creating network "simcaptcha_simcaptcha-net" with driver "bridge"
ERROR: Failed to Setup IP tables: Unable to enable SKIP DNAT rule:  (iptables failed: iptables --wait -t nat -I DOCKER -i br-f34f4bfebf69 -j RETURN: iptables: No chain/target/match by that name.
 (exit status 1))

重启 Docker

代码语言:javascript
复制
service docker restart

参考

感谢帮助!

本文作者: yiyun

本文链接: https://moeci.com/posts/分类-github/github-actions-docker/

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-01-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • deploy-docker.yml
  • 区分版本
    • 一个仓库发布一个包
      • docker-push-beta
      • docker-push-release
    • 一个仓库发布多个包
      • docker-push-beta
      • docker-push-release
    • 补充
    • GitHub 镜像仓库服务 ghcr.io
    • 补充
      • docker-compose CLI
        • CentOS 用户,组
          • ERROR: Failed to Setup IP tables
          • 参考
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档