當你沒找到合適的基礎的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提供的一項持續整合和持續交付服務,與倉庫無縫整合,可通過簡單的YAML組態檔定義工作流程。這使得我們能夠輕鬆地在程式碼倉庫中管理和執行CI/CD任務,提高開發和部署的效率。藉助Github Actions,我們可以構建、測試和部署專案,將整個開發週期變得更加流暢。
GitHub可以提供 Linux、Windows 和 macOS 虛擬機器器來執行你的工作流程,在使用Github Actions之前,你需要了解以下前置知識:
當建立Github Actions時,會在程式碼庫.github/workflows目錄下,建立一個.yml 檔案,每個yml對應一個工作流。
YAML(YAML Ain't Markup Language或YAML是一個人類可讀的資料序列化格式)是一種簡潔且易讀的資料標示語言。它常被用於組態檔和資料交換格式,以人類可讀的方式表示資料結構,有以下幾個特點:
Github Actions可以免費使用,也可以付費使用,其中免費使用者有以下限制:
更詳細內容可以在官網中找到usage-limits-billing-and-administration
在Github Actions中設定Docker映象構建的過程非常簡單。通過定義workflow,我們可以指定觸發條件、構建步驟和依賴關係。設定一個構建步驟,執行Docker映象的構建,確保在每次程式碼推播時觸發自動構建流程。這種自動化的構建流程不僅提高了效率,還減少了人為出錯的可能性。
首先開啟你的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 Hub作為一個廣泛使用的Docker映象倉庫,為開發者提供了便捷的映象儲存和分享平臺。通過Github Actions,我們可以設定自動將構建好的Docker映象推播到Docker Hub。這一步驟使得我們的應用在構建完成後,能夠迅速被部署和共用,為團隊共同作業和持續整合提供了更多可能性。
在構建和推播Docker映象的過程中,網路通訊可能會成為一個潛在的問題。為了確保暢通無阻,我們可以採取一系列措施,如設定合適的網路代理、優化映象構建步驟、以及合理選擇構建和推播的時機。這些措施將有助於提高構建成功率,確保整個流程的順暢進行。
但在大區域網中,依然寸步難行。而你只需將構建步驟移到Github Actions中,一切問題都能迎刃而解,真香!
有一點需要注入,雖然Github和Docker Hub很香,但是Docker Hub的映象時開源的!有商用、涉密等使用要求的人,請謹慎使用。
現在先回到Github Actions的workflow編輯頁面,它的右邊也是有很多action模板的!
把Docker login的程式碼複製進你的workflow yml中,放在steps靠前的位置
保留範例中的三個引數即可
其中在env
節點加上變臉REGISTRY
,留空是將映象推播到docker hub中,如果是其他庫則填相應的地址
- name: Docker Login
uses: docker/[email protected]
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERACC }}
password: ${{ secrets.DOCKERPWD }}
DOCKERACC
和DOCKERPWD
則需要在程式碼庫中的settings裡設定。
按照docker官網說法,這的PWD也可以是你設定的一個token,多人共同作業就不怕密碼洩露的風險
很簡單,稍微修改構建的步驟,增加依據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
你沒猜錯,這段就是用來水字數的。
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/[email protected]
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 在持續整合、持續部署領域的進一步演進。隨著雲原生技術的不斷髮展,這些工具將更加貼近開發者的需求,提供更多創新的功能,幫助開發團隊更好地應對快速變化的軟體交付需求。