<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          GitHub Actions 自托管 Runner 優(yōu)化——和運營商斗智斗勇

          共 6480字,需瀏覽 13分鐘

           ·

          2022-01-10 17:59


          在之前的文章 在 Kubernetes 上運行 GitHub Actions Self-hosted Runner[1]關(guān)于從 GitHub Actions Self-Hosted Runner 中偷 Secrets/Credentials 的一些安全研究[2] 中,我們知道已經(jīng)可以通過各種手段讓 Self Hosted Runner 在我們內(nèi)部設(shè)施上跑起來,加上一個設(shè)計合理的專線+路由表,基本已經(jīng)可以流暢地接受+處理 GitHub 上使用了 self-hosted 的 CI 任務(wù)了,由于語法和 GitHub Actions 官方語法一致,基本使用者都會有類似「太順滑了,幾乎沒有任何的體感差異」,「有效減少了高峰用官方 Runner 排隊的問題」,「成功獲得了 ARM64 環(huán)境」,「性能和 RAM 直接翻倍」等等好評。

          但是使用一個非海外的基礎(chǔ)設(shè)施我們很快就會看到一些地理位置上的缺陷,比如…

          為什么 actions/setup-go@v2 可以跑這么久?

          那..這..用的國內(nèi)三大運營商,這不是很正常么?(雖然這個包本身并不大,才 120M 左右)

          GOPROXY 優(yōu)化

          為了優(yōu)化 Golang 做 go mod tidy 等操作,在 Runner 的鏡像中已經(jīng)顯式地指定好了 GOPROXY ,Dockerfile 類似:

          ENV?GOPROXY?"http://goproxy.nova.moe,https://proxy.golang.org,direct"

          這樣在用戶使用 Golang 程序的時候就可以直接走內(nèi)部 GOPROXY 來加速了,但是這樣依然不夠,因為要給 Runner 安裝 Go ,還需要使用 actions/setup-go@v2 來安裝。

          這個時候,有些小機靈鬼就會說了:「那你把 Go 打在 Image 里面不就好了么?」

          確實可以,但是這樣對于多版本管理是很不利的,難道你像下圖一樣維護一堆類似 n0vad3v/github-runner:go1130n0vad3v/github-runner:go1160 的鏡像,然后手動控制這些鏡像的 Container 數(shù)量和 Tag,然后讓用戶去用類 Jenkins 的語法,去手動指定 runs-on: [self-hosted,X64,go1130]

          所以為了解決這個問題,我們還是得讓用戶自己去用一個 Step 來安裝 Go,畢竟環(huán)境的模塊化組裝(以及 Matrix 的使用)是 GitHub Actions 的一大優(yōu)勢,不然一堆 if-else 和 Jenkins 有啥區(qū)別,更何況現(xiàn)在 Runner 安裝了一次 Go 之后就會緩存下來(除非你啟動的時候指定了 --ephemeral),在下一次遇到同版本的時候會直接使用緩存。

          actions/setup-go 優(yōu)化

          在 Runner 上安裝 Golang,大家一般會使用 actions/setup-go@v2,用法也很簡單,如下:

          -?uses:?actions/setup-go@v2
          ??with:
          ????go-version:?'1.16'

          為了了解這個 Action 是如何工作的,在不看代碼,只看代碼結(jié)構(gòu)的角度,我們從 https://github.com/actions/setup-go/blob/main/__tests__/data/versions-manifest.json 文件中可以發(fā)現(xiàn)它 ”背后的數(shù)據(jù)地址“ 類似:

          https://github.com/actions/go-versions/releases/download/1.12.17-20200616.21/go-1.12.17-darwin-x64.tar.gz

          反推得到實際的數(shù)據(jù)倉庫為:https://github.com/actions/go-versions/ 的 https://github.com/actions/go-versions/blob/main/versions-manifest.json , 數(shù)據(jù)格式類似如下:

          [
          ??{
          ????"version":?"1.17.5",
          ????"stable":?true,
          ????"release_url":?"https://github.com/actions/go-versions/releases/tag/1.17.5-1559554870",
          ????"files":?[
          ??????{
          ????????"filename":?"go-1.17.5-darwin-x64.tar.gz",
          ????????"arch":?"x64",
          ????????"platform":?"darwin",
          ????????"download_url":?"https://github.com/actions/go-versions/releases/download/1.17.5-1559554870/go-1.17.5-darwin-x64.tar.gz"
          ??????},
          ??????{
          ????????"filename":?"go-1.17.5-linux-x64.tar.gz",
          ????????"arch":?"x64",
          ????????"platform":?"linux",
          ????????"download_url":?"https://github.com/actions/go-versions/releases/download/1.17.5-1559554870/go-1.17.5-linux-x64.tar.gz"
          ??????},
          ??????{
          ????????"filename":?"go-1.17.5-win32-x64.zip",
          ????????"arch":?"x64",
          ????????"platform":?"win32",
          ????????"download_url":?"https://github.com/actions/go-versions/releases/download/1.17.5-1559554870/go-1.17.5-win32-x64.zip"
          ??????}
          ????]
          ??},
          ]

          后來發(fā)現(xiàn)其實 README 中有寫:It will first check the local cache for a version match. If version is not found locally, It will pull it from main branch of go-versions[3]

          在確認(rèn)了實際下載的包的地址之后我們就可以反推 setup-go 中是如何使用這個地址的了,通過一波 rg,我們在 src/installer.ts 的 143 行發(fā)現(xiàn):

          ??const?releases?=?await?tc.getManifestFromRepo(
          ????'actions',
          ????'go-versions',
          ????auth,
          ????'main'
          ??);

          所以現(xiàn)在緩存的思路就很清晰了:

          1. 下載 https://github.com/actions/go-versions/blob/main/versions-manifest.json 中的包到內(nèi)網(wǎng)
          2. Fork + 修改一份 https://github.com/actions/go-versions 倉庫,把 download_url 中的內(nèi)容換為內(nèi)網(wǎng)地址
          3. Fork + 修改一份 setup-go,把它獲取 Manifest 的地址指向 Fork 后的 go-versions 倉庫
          4. 在 Runner 中調(diào)用 Fork 后的 setup-go

          下載包到內(nèi)網(wǎng)

          非常容易,Python 可以這么寫,只要指定一下 HOST_URL 為內(nèi)網(wǎng)下載地址,STORE_PATH 為實際存儲地址,GOLANG_VERSION_LIST 中填上想要緩存的 Golang 版本即可,保存為一個 download.py ,運行后等著就好:

          import?requests
          from?urllib.parse?import?urlparse
          import?os
          import?json

          ##?ENV
          HOST_URL?=?"http://download.nova.moe/download/github-actions/golang/"
          STORE_PATH?=?"/path/to/download/github-actions/golang/"
          GOLANG_VERSION_LIST?=?['go-1.16','go-1.17','go-1.13']
          ##?END?ENV

          def?process_each_package(package_filename,?package_url):
          ????package_path?=?STORE_PATH?+?package_filename
          ????if?not?os.path.isfile(package_path):
          ????????print("Downloading:?"?+?package_url)
          ????????r?=?requests.get(package_url)
          ????????with?open(package_path,?'wb')?as?f:
          ????????????f.write(r.content)
          ????return?package_path

          if?__name__?==?'__main__':
          ????go_versions_url?=?'https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json'
          ????r?=?requests.get(go_versions_url).json()

          ????return_list?=?[]
          ????golang_package_list?=?[]
          ????for?item?in?r:
          ????????package_url?=?item['files'][1]['download_url']

          ????????for?version?in?GOLANG_VERSION_LIST:
          ????????????if?version?in?package_url:
          ????????????????golang_package_list.append(package_url)
          ????????????????a?=?urlparse(package_url)
          ????????????????package_filename?=?os.path.basename(a.path)

          ????????????????process_each_package(package_filename,?package_url)

          ????????????????item['files'][1]['download_url']?=?HOST_URL?+?package_filename
          ????????????????return_list.append(item)

          ????with?open('versions-manifest.json',?'w')?as?f:
          ????????f.write(json.dumps(return_list,?indent=2))

          運行結(jié)束后所有的 tar.gz 包都會保存到 STORE_PATH 中,同時運行目錄下會生成一個下載地址已經(jīng)替換為內(nèi)網(wǎng)地址的 versions-manifest.json

          修改 go-versions 和 setup-go

          Fork 這兩個倉庫后,將 Fork 后的 go-versions 倉庫下的 versions-manifest.json 替換為剛剛已經(jīng)生成好的版本(這個操作過于簡單建議直接用網(wǎng)頁修改,避免浪費拉倉庫使用的本地帶寬)。

          由于 setup-go 需要編譯,為了省事考慮(反正我們只修改兩個變量),直接將 Fork 的 setup-go 中 dist/index.js 的 5037 行

          const?releases?=?yield?tc.getManifestFromRepo('actions',?'go-versions',?auth,?"main");

          改為 fork 后的地址,比如:

          const?releases?=?yield?tc.getManifestFromRepo('n0vad3v',?'go-versions-forked',?auth,?"master");

          修改 Runner

          在上面的操作完成之后,我們只需要使用 fork 后的 setup-go ,即可使用到內(nèi)網(wǎng)的下載速度了,用法類似:

          -?uses:?n0vad3v/setup-go-forked@master
          ??with:
          ????go-version:?'1.16'

          看看效果?

          快到模糊!

          小結(jié)

          由于緩存 Golang 的包的操作看上去是一個 One shot 的操作,基本沒有短時間內(nèi)持續(xù)更新的需求,暫時也就沒有考慮自動化之類的事情,在有了內(nèi)網(wǎng)緩存之后,整體的 Runner 運行效率一下子就提升了起來,使用體驗又愉快了不少。

          這是關(guān)于 GitHub Actions Self-hosted Runner 優(yōu)化的第一篇文章,后續(xù)可能還會有一些相關(guān)的有趣的分享,同時我也在考慮把相關(guān)的組件(比如 關(guān)于從 GitHub Actions Self-Hosted Runner 中偷 Secrets/Credentials 的一些安全研究[4] 中提到的那個假 KMS,以及可用的 Runner 的 Dockerfile)開源出來,不過這些都還沒想好,有興趣的同學(xué)可以期待一下~

          引用鏈接

          [1]

          在 Kubernetes 上運行 GitHub Actions Self-hosted Runner: https://nova.moe/run-self-hosted-github-action-runners-on-kubernetes/

          [2]

          關(guān)于從 GitHub Actions Self-Hosted Runner 中偷 Secrets/Credentials 的一些安全研究: https://nova.moe/steal-credentials-from-ci-agents/

          [3]

          go-versions: https://github.com/actions/go-versions/blob/main/versions-manifest.json

          [4]

          關(guān)于從 GitHub Actions Self-Hosted Runner 中偷 Secrets/Credentials 的一些安全研究: https://nova.moe/steal-credentials-from-ci-agents/

          原文鏈接:https://nova.moe/self-hosted-runner-golang-cache/


          你可能還喜歡

          點擊下方圖片即可閱讀

          再見 Dockerfile,擁抱新型鏡像構(gòu)建技術(shù) Buildpacks

          云原生是一種信仰???

          關(guān)注公眾號

          后臺回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!



          點擊?"閱讀原文"?獲取更好的閱讀體驗!


          發(fā)現(xiàn)朋友圈變“安靜”了嗎?

          瀏覽 82
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色视频在线观看www | 操美女视频网站 | 精品91秘 一区二区三区 | 亚洲天堂网在线播放 | 天天干在线观看视频 |