[GitOps] 白嫖神器Github Actions,构建、推送Docker镜像一路畅通无阻

引言

  当你没找到合适的基础的Docker镜像时,是否会一时冲动,想去自己构建。然而因为网络问题,各种软件官方源、镜像源(包括但不限于apt、pip、maven,npm),不但编译奇慢无比,还时常出错白白浪费几十个G的网络流量;硬件问题,爱用Windows但装WSL开了Hyper-V玩不了模拟器,用虚拟机又觉得麻烦占磁盘空间,还没钱续期云服务器……

  我的朋友,如果你还在为以上种种问题而苦恼,那么我很荣幸为你推荐Nuget GitOps,Github Actions!

  GitOps,作为一种现代化的运维理念,强调通过版本控制系统来管理基础设施和应用配置,提高可维护性和可靠性。在这个背景下,Github Actions作为一项强大的CI/CD工具,为我们提供了优雅的解决方案。本文将深入探讨如何充分利用Github Actions服务,白嫖其强大的构建能力,实现Docker镜像的自动构建与推送,确保网络畅通无阻。

【不得不说同样是官方源,Nuget就极少像前面几个源出问题,.net yyds!】

Github Actions简介

  Github Actions是Github提供的一项持续集成和持续交付服务,与仓库无缝集成,可通过简单的YAML配置文件定义工作流程。这使得我们能够轻松地在代码仓库中管理和执行CI/CD任务,提高开发和部署的效率。借助Github Actions,我们可以构建、测试和部署项目,将整个开发周期变得更加流畅。

  GitHub可以提供 Linux、Windows 和 macOS 虚拟机来运行你的工作流程,在使用Github Actions之前,你需要了解以下前置知识:

  • Yaml基础语法
  • Linux(或Windows或macOS)脚本相关知识
  • Git及Github的相关知识

什么是Yaml

  当创建Github Actions时,会在代码库.github/workflows目录下,创建一个.yml 文件,每个yml对应一个工作流。

  YAML(YAML Ain't Markup Language或YAML是一个人类可读的数据序列化格式)是一种简洁且易读的数据标记语言。它常被用于配置文件和数据交换格式,以人类可读的方式表示数据结构,有以下几个特点:

  • 大小写敏感。
  • 使用缩进表示层级关系。
  • 缩进只能使用空格,不能用 TAB 字符。
  • 缩进的空格数量不重要,只要层级相同的元素左对齐即可。
  • 表示注释。

Github Actions的Yaml结构

  • name:workflow名称
  • on:触发器
  • env:自定义的环境变量
  • job:一个workflow可以有多个job,每个job包含多个step
  • runs-on:任务容器,如ubuntu-latest,windows-latest,macos-latest
  • step:任务步骤
  • action:每个步骤可以执行多个命令

Github Actions的使用限制

  Github Actions可以免费使用,也可以付费使用,其中免费用户有以下限制:

  • 使用时长

    可以每月使用2000分钟,存储500MB(应该是指仓库大小),其中不同容器时间系数是不同的,Linux是1,Windows是2(1000分钟),MacOS是10(200分钟);
  • 并发作业数20
  • 作业执行时间最长6小时
  • 工作流运行时间每次工作流运行时间限制为 35 天

    (笔者没看懂这项目)

  更详细内容可以在官网中找到usage-limits-billing-and-administration

Docker镜像的构建

  在Github Actions中配置Docker镜像构建的过程非常简单。通过定义workflow,我们可以指定触发条件、构建步骤和依赖关系。配置一个构建步骤,执行Docker镜像的构建,确保在每次代码推送时触发自动构建流程。这种自动化的构建流程不仅提高了效率,还减少了人为出错的可能性。

新建workflow

  首先打开你的Github 代码库,点击Actions



  点击New workflow按钮

  搜索Docker,会有很多workflow模板,其中Docker Image是非常简洁的模板,适合笔者我这种简约主义者,以下将使用它作为教程示例。

顺带一提,隔壁那个模板很复杂……英文好的人可以研究研究

  点击Configure,进入编写yml,编写任务

  官方默认模板内容如下,功能是当push或者pull master分支时,触发构建流程

name: Docker Image CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)

  而run标签,就是linux下的shell脚本,既然是shell,那么就可以做很多事情了。

  比如说你原本已有一套构建脚本(build.sh),那么可能稍作修改,就能用着Github Actions中,run改为sh build.sh即可。

  yml可以在线编辑,也可以保存后pull到本地代码库。

示例代码库

  回到前言所说的内容,笔者痛点是希望找一个人工智能的运行环境镜像,但没有整合的,人工智能的镜像一般又很大,各环境单独一个镜像下载慢又占空间,在whl包不冲突的情况下,装在一起能省很多控件,于是乎就诞生了本项目:Wlkr.DockerBuild

注意,本项目目的是编译基础环境的镜像,没有什么代码,可能常见的项目开发有所出入,请自行甄选。

  观察Wlkr.AiRuntime项目,会见到有多个 Dockfile,此举是为了避免编译失败,导致漫长的构建过程又要重新编译。

  比如Ubuntu镜像默认没有python,除了python还有其他一些深度学习所需的基础组件也没有,当你编译通过python后,安装pytorch报错缺失组件,规划不好又要从python那个步骤开发编译,非常浪费时间。

  在分而治之的思想指导下, 最终镜像构建分为了7个Dockerfile。

触发器

  修改工作流的yml,改为监听这7个Dockerfile和一个python文件

name: Docker Image CI
on:
push:
# 监听的分支
branches:
- master
# 监听的文件
paths:
- 'Wlkr.AiRuntime/Dockerfile*'
- 'Wlkr.AiRuntime/model_init.py'

  如果你在自己的linux服务器下编译过docker镜像,Dockerfile中编译成功的步骤会有一个缓存layer,减少编译的所需时间。

  但是在Github Actions中,每次执行工作流,均没有缓存。

同时笔者所编译的镜像是环环相扣的,上一层镜像有改动时,下层的所有镜像也应该重新编译。

优化构建流程

  有没有优化的可能?答案是有的!

  先定义7个flag变量

env:
flag_python: 0
flag_pytorch: 0
flag_modelscope: 0
flag_modelscope_cv: 0
flag_mscv_pd: 0
flag_mscv_pdocr: 0
flag_mscv_pdocr_mdl: 0
flag_done: 0

  修改拉取代码的action,默认会带上参数--dept=1,无法满足后续的操作

jobs:
build:
runs-on: ubuntu-latest steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 2 #加上这个参数

  在上面监听文件中,我们监听了所有Dockerfile,显然没有变动的Dockerfile,是不需要重新编译重新构建的。

  那么怎么知道哪些文件有变动,哪个镜像需要重新编译?答案就是commit后产生的sha id。



  利用git diff命令,检查上一次commit与本次commit的文件是否不同,如果不容,则修改flag,标记为需要编译。

    - name: Check Modify
run: |
echo "previous_sha=${{ github.event.before }}" cd Wlkr.AiRuntime
# python
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.python)" ]; then
echo "flag_python=1" >> $GITHUB_ENV
fi
# 其他flag省略

  在构建的action中,加上添加if: env.flag_python == 1,来确定是否要执行编译,如果要则将下一步骤的flag也改为1。

    - name: Build python
if: env.flag_python == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.python -t dimwalker/wlkr.python .
echo "flag_pytorch=1" >> $GITHUB_ENV

  至此,编译的优化已完成。

  需要注意,每个action都是独立的,也就是说工作目录cd Wlkr.AiRuntime要在每个step中先运行一次。

Docker镜像的推送

  Docker Hub作为一个广泛使用的Docker镜像仓库,为开发者提供了便捷的镜像存储和分享平台。通过Github Actions,我们可以配置自动将构建好的Docker镜像推送到Docker Hub。这一步骤使得我们的应用在构建完成后,能够迅速被部署和共享,为团队协作和持续集成提供了更多可能性。

  在构建和推送Docker镜像的过程中,网络通信可能会成为一个潜在的问题。为了确保畅通无阻,我们可以采取一系列措施,如配置合适的网络代理、优化镜像构建步骤、以及合理选择构建和推送的时机。这些措施将有助于提高构建成功率,确保整个流程的顺畅进行。

  但在大局域网中,依然寸步难行。而你只需将构建步骤移到Github Actions中,一切问题都能迎刃而解,真香!

有一点需要注入,虽然Github和Docker Hub很香,但是Docker Hub的镜像时开源的!有商用、涉密等使用要求的人,请谨慎使用。

登录Docker Hub

  现在先回到Github Actions的workflow编辑页面,它的右边也是有很多action模板的!



  把Docker login的代码复制进你的workflow yml中,放在steps靠前的位置



  保留示例中的三个参数即可

  其中在env节点加上变脸REGISTRY,留空是将镜像推送到docker hub中,如果是其他库则填相应的地址

    - name: Docker Login
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERACC }}
password: ${{ secrets.DOCKERPWD }}

DOCKERACCDOCKERPWD则需要在代码库中的settings里设置。

  按照docker官网说法,这的PWD也可以是你设置的一个token,多人协作就不怕密码泄露的风险

推送Docker镜像

  很简单,稍微修改构建的步骤,增加依据push命令即可

    - name: Build & Push python
if: env.flag_python == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.python -t dimwalker/wlkr.python .
docker push dimwalker/wlkr.python:latest
echo "flag_pytorch=1" >> $GITHUB_ENV

完整的yml

  你没猜错,这段就是用来水字数的。

name: Docker Image CI

on:
push:
# 监听的分支
branches:
- master
# 监听的文件
paths:
- 'Wlkr.AiRuntime/Dockerfile*'
- 'Wlkr.AiRuntime/model_init.py'
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ''
flag_python: 0
flag_pytorch: 0
flag_modelscope: 0
flag_modelscope_cv: 0
flag_mscv_pd: 0
flag_mscv_pdocr: 0
flag_mscv_pdocr_mdl: 0
flag_done: 0 jobs:
build:
runs-on: ubuntu-latest steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 2 - name: Docker Login
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERACC }}
password: ${{ secrets.DOCKERPWD }} - name: Check Modify
run: |
echo "previous_sha=${{ github.event.before }}" cd Wlkr.AiRuntime
# python
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.python)" ]; then
echo "flag_python=1" >> $GITHUB_ENV
fi
# pytorch
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.pytorch)" ]; then
echo "flag_pytorch=1" >> $GITHUB_ENV
fi
# modelscope
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.modelscope)" ]; then
echo "flag_modelscope=1" >> $GITHUB_ENV
fi
#
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.modelscope_cv)" ]; then
echo "flag_modelscope_cv=1" >> $GITHUB_ENV
fi
# mscv_pd
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.mscv_pd)" ]; then
echo "flag_mscv_pd=1" >> $GITHUB_ENV
fi
# mscv_pdocr
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.mscv_pdocr)" ]; then
echo "flag_mscv_pdocr=1" >> $GITHUB_ENV
fi
# mscv_pdocr_mdl
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- Dockerfile.mscv_pdocr_mdl)" ]; then
echo "flag_mscv_pdocr_mdl=1" >> $GITHUB_ENV
fi
if [ -n "$(git diff --name-only ${{ github.event.before }} HEAD -- model_init.py)" ]; then
echo "flag_mscv_pdocr_mdl=1" >> $GITHUB_ENV
fi - name: Print Env
run: |
echo "flag_python: ${{ env.flag_python }}"
echo "flag_pytorch: ${{ env.flag_pytorch }}"
echo "flag_modelscope: ${{ env.flag_modelscope }}"
echo "flag_modelscope_cv: ${{ env.flag_modelscope_cv }}"
echo "flag_mscv_pd: ${{ env.flag_mscv_pd }}"
echo "flag_mscv_pdocr: ${{ env.flag_mscv_pdocr }}"
echo "flag_mscv_pdocr_mdl: ${{ env.flag_mscv_pdocr_mdl }}" - name: Build & Push python
if: env.flag_python == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.python -t dimwalker/wlkr.python .
docker push dimwalker/wlkr.python:latest
echo "flag_pytorch=1" >> $GITHUB_ENV - name: Build & Push pytorch
if: env.flag_pytorch == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.pytorch -t dimwalker/wlkr.pytorch .
docker push dimwalker/wlkr.pytorch:latest
echo "flag_modelscope=1" >> $GITHUB_ENV - name: Build & Push modelscope
if: env.flag_modelscope == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.modelscope -t dimwalker/wlkr.modelscope .
docker push dimwalker/wlkr.modelscope:latest
echo "flag_modelscope_cv=1" >> $GITHUB_ENV - name: Build & Push modelscope_cv
if: env.flag_modelscope_cv == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.modelscope_cv -t dimwalker/wlkr.modelscope_cv .
docker push dimwalker/wlkr.modelscope_cv:latest
echo "flag_mscv_pd=1" >> $GITHUB_ENV - name: Build & Push mscv_pd
if: env.flag_mscv_pd == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.mscv_pd -t dimwalker/wlkr.mscv_pd .
docker push dimwalker/wlkr.mscv_pd:latest
echo "flag_mscv_pdocr=1" >> $GITHUB_ENV - name: Build & Push mscv_pdocr
if: env.flag_mscv_pdocr == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.mscv_pdocr -t dimwalker/wlkr.mscv_pdocr .
docker push dimwalker/wlkr.mscv_pdocr:latest
echo "flag_mscv_pdocr_mdl=1" >> $GITHUB_ENV - name: Build & Push mscv_pdocr_mdl
if: env.flag_mscv_pdocr_mdl == 1
run: |
cd Wlkr.AiRuntime
# 基础
docker build -f Dockerfile.mscv_pdocr_mdl -t dimwalker/wlkr.mscv_pdocr_mdl .
docker push dimwalker/wlkr.mscv_pdocr_mdl:latest
echo "flag_done=1" >> $GITHUB_ENV - name: Print Env End
run: |
echo "flag_python: ${{ env.flag_python }}"
echo "flag_pytorch: ${{ env.flag_pytorch }}"
echo "flag_modelscope: ${{ env.flag_modelscope }}"
echo "flag_modelscope_cv: ${{ env.flag_modelscope_cv }}"
echo "flag_mscv_pd: ${{ env.flag_mscv_pd }}"
echo "flag_mscv_pdocr: ${{ env.flag_mscv_pdocr }}"
echo "flag_mscv_pdocr_mdl: ${{ env.flag_mscv_pdocr_mdl }}"
echo "flag_done: ${{ env.flag_done }}"

  Well Done!

总结

  在本文中,我们深入探讨了如何充分发挥 GitHub Actions 在 GitOps 中的作用,特别是在构建和推送 Docker 镜像方面。通过 GitHub Actions,开发者能够充分利用云端资源,轻松实现 CI/CD 流程。

  通过配置 GitHub Actions 的工作流程,我们可以确保构建和推送 Docker 镜像的流程畅通无阻。这不仅提高了开发团队的效率,还降低了出错的可能性,使整个开发过程更加可靠和可预测。

  总的来说,GitHub Actions作为一个集成于GitHub平台的CI/CD工具,为开发者提供了强大而灵活的工具,支持他们构建出高质量的软件。尤其是对于 Docker 镜像的构建和推送,GitHub Actions 提供了简单易用的方式,使开发者能够专注于代码本身而不必过多关心底层的部署细节。

  除了Github Actions,笔者以往还使用过Webhooks+Jenkins的方式,在自己的云端服务器编译镜像。未来,我们可以期待 GitOps 在持续集成、持续部署领域的进一步演进。随着云原生技术的不断发展,这些工具将更加贴近开发者的需求,提供更多创新的功能,帮助开发团队更好地应对快速变化的软件交付需求。

[GitOps] 白嫖神器Github Actions,构建、推送Docker镜像一路畅通无阻的更多相关文章

  1. 使用Gitlab的CI/CD功能自动化推送docker镜像到Nexus仓库出现的问题

    在服务器中可以直接使用命令行登录,推送docker镜像等 但是在使用Gitlab的CI/CD功能中,gitlab-ci.yml文件执行过程中出现如下错误: 原因分析: 服务器上之前使用命令行登陆过Ne ...

  2. 企业运维实践-丢弃手中的 docker build , 使用Kaniko直接在Kubernetes集群或Containerd环境中快速进行构建推送容器镜像

    关注「WeiyiGeek」公众号 设为「特别关注」每天带你玩转网络安全运维.应用开发.物联网IOT学习! 希望各位看友[关注.点赞.评论.收藏.投币],助力每一个梦想. 本章目录 目录 首发地址: h ...

  3. jenkins推送docker镜像到远程仓库

    参考链接:https://blog.csdn.net/qq_34252622/article/details/92791262

  4. IDEA推送docker镜像到私服/利用dockerfile-maven-plugin插件在springboot中上传镜像到远程的docker服务器、远程仓库

    利用dockerfile-maven-plugin插件在springboot中上传镜像到远程仓库      这篇文章讲解在开发工具中把打包好的jar编译成docker镜像,上传到远程的docker服务 ...

  5. 多阶段构建Golang程序Docker镜像

    Docker简介 Docker是基于Linux容器技术(LXC),使用Go语言实现的开源项目,诞生于2013年,遵循Apache2.0协议.Docker自开源后,受到广泛的关注和讨论. Docker在 ...

  6. 四:(之四)基于已有镜像构建自己的Docker镜像

    4构建自己的Docker镜像 4.1常用命令: 等同于docker commit 将一个被改变的容器创建成一个新的image 等同于docker build 通过Dockerfile创建一个image ...

  7. 使用 buildx 构建多平台 Docker 镜像

    原文链接:使用 buildx 构建多平台 Docker 镜像 在工作和生活中,我们可能经常需要将某个程序跑在不同的 CPU 架构上,比如让某些不可描述的软件运行在树莓派或嵌入式路由器设备上.特别是 D ...

  8. 为Github仓库添加Github Actions实现持续集成: Android apk自动编译发布以及github pages同步推送coding.net

    内容转载自我的博客 目录 说明 1. 编写Android项目的CI配置文件 2. 编写Jekyll项目的CI配置文件 2.1 配置coding.net 2.2 配置github 2.3 自动部署到co ...

  9. vuepress-theme-reco + Github Actions 构建静态博客,部署到第三方服务器

    最新博客链接 Github链接 查看此文档前应先了解,vuepress基本操作 参考官方文档进行配置: vuepress-theme-reco VuePress SamKirkland / FTP-D ...

  10. git命令合集及github的克隆推送

    安装git 初始化仓库 提交相关 撤销相关 远程推送 分支相关 其他 遇到的错误 github的克隆上传 此文章只是对命令的一个统计,起备忘和复习git只是的作用,不建议从没接触过git的同学通过它来 ...

随机推荐

  1. 王道oj/problem11(函数调用中实现指针的传递)

    网址:http://oj.lgwenda.com/prblem/11 思路:函数中的j=&i,为i的地址 *j可以从地址访问,从而改变i的值 代码: #define _CRT_SECURE_N ...

  2. 看,这些 plugins 常用又简单

    前面文章中 体验了webpack的打包 .解析css资源 .处理图片字体等文件 接下来看看 plugins 有什么作用吧~ 项目路径如下,和上一篇 处理图片字体等文件 项目保持一致 demo ├─ s ...

  3. nlp入门(二) :商品信息可视化与文本分析实战

    源码请到:自然语言处理练习: 学习自然语言处理时候写的一些代码 (gitee.com) 数据来源:麦卡里价格建议挑战Mercari Price Suggestion Challenge | Kaggl ...

  4. U268603 I Hate This Tree 题解

    传送门 一道纯粹的码力 + 卡常题. 前置 矩阵乘法,线段树. 分析 线段树存矩阵. 构造迭代矩阵: \[\begin{pmatrix}f_i&f_{i-1}\end{pmatrix}\tim ...

  5. ubuntu/linux 好用的截图工具 搜狗输入法自带的截图快捷键,自己觉得不方便的话,修改为自己习惯的快捷键即可

    公司要求使用ubuntu开发,在安装完必要得开发工具之后,按照我在windows平台的习惯,就准备安装一个好用的截图工具了,我比较推荐的是snipaste([https://zh.snipaste.c ...

  6. 程序员 不得不知道的 API 接口常识

    说实话,我非常希望自己能早点看到本篇文章,大学那个时候懵懵懂懂,跟着网上的免费教程做了一个购物商城就屁颠屁颠往简历上写. 至今我仍清晰地记得,那个电商教程是怎么定义接口的: 管它是增加.修改.删除.带 ...

  7. 多层前馈神经网络及BP算法

    一.多层前馈神经网络 首先说下多层前馈神经网络,BP算法,BP神经网络之间的关系.多层前馈[multilayer feed-forward]神经网络由一个输入层.一个或多个隐藏层和一个输出层组成,后向 ...

  8. Python基础语法--课程笔记

    Smiling & Weeping ----我的心是旷野的鸟,在你的眼睛里找到了它的天空 定义和使用类: 1.声明类: class类名: 成员变量,成员函数 2.定义类的对象: 对象名 = 类 ...

  9. 聊聊 QianKun JS 沙箱的那些事

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:空山 什么是沙箱 沙箱即 SandBox,它是一种安全机制 ...

  10. Sentinel系列之SlotChain、NodeSelectorSlot、ClusterBuilderSlot分析

    本文基于Sentinel 1.8.6版本分析 1. SlotChain 我们从入口com.alibaba.csp.sentinel.SphU#entry(java.lang.String) 开始分析. ...