惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
L
LINUX DO - 最新话题
博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
C
Cisco Blogs
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
G
GRAHAM CLULEY
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
D
DataBreaches.Net
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
I
InfoQ
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
Project Zero
Project Zero

二丫讲梵

学习周刊-总第258期-2026年第15周 学习周刊-总第257期-2026年第14周 学习周刊-总第256期-2026年第13周 学习周刊-总第255期-2026年第12周 学习周刊-总第254期-2026年第11周 学习周刊-总第253期-2026年第10周 临时插播一条羊毛,免费领取450元大模型API代金券 学习周刊-总第252期-2026年第09周 学习周刊-总第251期-2026年第08周 学习周刊-总第250期-2026年第07周 学习周刊-总第249期-2026年第06周 诚邀评论,聊聊你所知欲知的我 学习周刊-总第248期-2026年第05周 我的QQ动态之2015年 我的QQ动态之2014年 我的QQ动态之2013年 我的QQ动态之2012年 我的QQ动态-2010-2011年 我的QQ动态-创栏小叙 学习周刊-总第247期-2026年第04周 Nexus社区版权益阉割--一文告诉你有哪些版本可以选择 学习周刊-总第246期-2026年第03周 学习周刊-总第245期-2026年第02周 学习周刊-总第244期-2026年第01周 学习周刊-总第243期-2025年第52周 学习周刊-总第242期-2025年第51周 开源项目ZenOps:带你领略禅意运维 学习周刊-总第241期-2025年第50周 用京东金融,享负债人生 学习周刊-总第240期-2025年第49周 学习周刊-总第239期-2025年第48周 整理我在静态服务透明代理上的极致求索之路,最后一个你绝想不到 学习周刊-总第238期-2025年第47周 我们输了,但收获颇多 太多了,太多了 学习周刊-总第237期-2025年第46周 学习周刊-总第236期-2025年第45周 学习周刊-总第235期-2025年第44周 二五年国庆二三事 学习周刊-总第234期-2025年第43周 学习周刊-总第233期-2025年第42周 学习周刊-总第232期-2025年第41周 学习周刊-总第231期-2025年第40周 学习周刊-总第230期-2025年第39周 西湖毅行 2025年开源世界逸闻三则 学习周刊-总第229期-2025年第38周 手抄《与妻书》 CNB开发与构建基于docker-cache缓存复用的配置实践心得 学习周刊-总第228期-2025年第37周 父亲善行录 学习周刊-总第227期-2025年第36周 带你认识我之看看我的高中同学录(其二) 学习周刊-总第226期-2025年第35周 带你认识我之看看我的高中同学录(其一) 认识神级MCP工具系列--用anyquery和数据库交互 学习周刊-总第225期-2025年第34周 学习周刊-总第224期-2025年第33周 学习周刊-总第223期-2025年第32周 学习周刊-总第222期-2025年第31周 学习周刊-总第221期-2025年第30周 CNB云原生开发环境届的瑞士军刀,详解qifei项目 vuepress-vdoing主题配置自建不蒜子统计 学习周刊-总第220期-2025年第29周 写在博客发表文章1000篇的节点 从claude cli的体验聊聊最大的敌人是我们自己的成见 学习周刊-总第219期-2025年第28周 学习周刊-总第218期-2025年第27周 学习周刊-总第217期-2025年第26周 理论正确,事实错误 学习周刊-总第216期-2025年第25周 学习周刊-总第215期-2025年第24周 学习周刊-总第214期-2025年第23周 学习周刊-总第213期-2025年第22周 学习周刊-总第212期-2025年第21周 从赵心童世锦赛夺冠聊聊我的斯诺克情缘 学习周刊-总第211期-2025年第20周 记录二五年五一之短暂回归家庭 学习周刊-总第210期-2025年第19周 学习周刊-总第209期-2025年第18周 学习周刊-总第208期-2025年第17周 Go开发实践之Gin框架将前端的dist目录embed到二进制 学习周刊-总第207期-2025年第16周 近期关于cobra库的一些实践心得总结 学习周刊-总第206期-2025年第15周 我的嗜好--嗑瓜子 记大宝参加幼儿园组织的清明烈士陵园扫墓活动 学习周刊-总第205期-2025年第14周 学习周刊-总第204期-2025年第13周 前端开发小笔记--在数组中给字段添加值与删除字段的操作 学习周刊-总第203期-2025年第12周 人生实苦,何以自渡 学习周刊-总第202期-2025年第11周 近期发现的一些优秀的工具提名(一) 学习周刊-总第201期-2025年第10周 学习周刊-总第200期-2025年第09周 记一次女友喝醉使我忍术破功 爱情风波--一次分手又复合的经历 学习周刊-总第199期-2025年第08周 整理我的信息源
记录最近在Github Action配置实践中的几个新的收获
二丫讲梵 · 2025-04-13 · via 二丫讲梵

上周给 k8m (opens new window) 配置了 Github Actions 流水线,对自己而言,虽然以往配置过 go 项目的打 release 和 docker 镜像,但这次配置时又引入了一些新的思路方案,对自己的知识也是一个更新,这里做一下记录。

# 缓存的应用

以往的构建中,因为 GitHub 的构建环境没有网络的受限问题,于是并没有使用过缓存,这次是给别人项目贡献代码,所以格外注重构建时间上的体验,因此也研究学习了一下构建缓存的应用。

# Node 项目

完整示例:点我查看 (opens new window)

因为该项目使用的是 pnpm 构建工具,在 pnpm 官方文档 (opens new window)中对如何构建及使用缓存已经做了介绍,这里把当前实践的配置直接放在下边:

jobs:
  build-release:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [ 18 ]
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: latest
      - name: 使用 Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "pnpm"
          cache-dependency-path: "ui/pnpm-lock.yaml"
      - name: 编译前端
        run: |
          cd ui
          pnpm install
          pnpm build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

其中参数也比较简单,不一一介绍,当流水线完成一次成功的构建之后,就可以在该流水线看到 node_modules 的缓存了:

My_Photor_1744453425010.webp

再次构建时,可以从构建日志中看到已经使用了该缓存:

My_Photor_1744453662598.webp

# Go 项目

完整示例:点我查看 (opens new window)

同理,go 语言项目在编译的时候,也可以配置 pkg 的缓存,以加快构建速度:

- name: 设置go环境
  uses: actions/setup-go@v5
  with:
    go-version-file: "go.mod"
    cache-dependency-path: "go.sum"

1
2
3
4
5

在定义 go 环境时,版本可以基于 mod 文件声明,缓存则可以通过 sum 声明。

同样,在有成功构建之后,下次再次构建,就可以看到缓存会启用了:

My_Photor_1744456534968.webp

# docker 构建缓存

完整示例:点我查看 (opens new window)

在构建 docker 镜像时,我们也可以应用一些缓存,从而加快构建速度。

一般在 GitHub Action 中,镜像构建使用的是 docker 官方提供的 action:build-push-action (opens new window),我之前也介绍过用法:利用GitHub Actions自动构建项目的docker镜像并发布到DockerHub (opens new window),之前的文章没有介绍缓存的用法,此处算做一个补充。

关于缓存的用法,官方也有文档:Cache management with GitHub Actions (opens new window)

docker 构建的缓存的存放方式,有多种,这里介绍两种,一种是基于镜像的缓存,一种是基于 GitHub Action 提供的缓存机制。

镜像缓存配置如下:

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v6
  with:
    push: true
    tags: user/app:latest
    cache-from: type=registry,ref=user/app:buildcache
    cache-to: type=registry,ref=user/app:buildcache,mode=max

1
2
3
4
5
6
7
8
9
10

构建之后,会在镜像仓库中生成一个标签为 buildcache 的镜像,后续构建则会先下载这个缓存,如有更新,也会自动再更新该缓存的内容。

Github 缓存配置如下:

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v6
  with:
    push: true
    tags: user/app:latest
    cache-from: type=gha
    cache-to: type=gha,mode=max

1
2
3
4
5
6
7
8
9
10

两种方式都可以,按照个人喜好选择即可。

# 一些组件

# 添加 UPX

完整示例:点我查看 (opens new window)

upx 是一个通用的可以将二进制文件大小缩小约 50%-70%的工具,在开源项目中,在最佳实践中,尽可能优化二进制大小,也是一个应该考量的点,因此我所有的 Go 项目,都会默认使用该工具压缩。

通过在 Action 中添加如下内容,可以直接在构建环境中安装 upx 命令:

- name: 安装 UPX
  uses: crazy-max/ghaction-upx@v3
  with:
    install-only: true

1
2
3
4

进入到 action 的详情页面,可以看到更多介绍,不过这些参数就够用了,默认会安装最新版本。

# 添加 gox 命令

完整示例:点我查看 (opens new window)

gox 是一个可以并发交叉编译 Go 语言项目的工具,原项目目前归档不再更新,我这里使用的是 fork 中的一个还在维护的版本。

  uses: actions/setup-go@v5
  with:
    go-version-file: "go.mod"
    cache-dependency-path: "go.sum"
- run: go install github.com/authelia/gox@latest # setup gox

1
2
3
4
5

在设置好 go 环境之后,就可以直接安装 gox 了。安装好 gox 之后,就可以使用此工具并发编译了,这里也放一个个人目前使用的 Makefile (opens new window)

# 制品共享

完整示例:点我查看 (opens new window)

在一些构建环境中,我们可能会把构建拆分成不同阶段。比如 k8m 是一个前后端在同一个仓库的项目,并且也设计成了前端 dist 制品 embed 到后端二进制架构。这个时候,前后端的构建会做一些分段设计,在不同阶段,就会出现制品共享的需求。

# 制品上传

- name: 上传到共享
  uses: actions/upload-artifact@v4
  with:
    name: workspace
    path: ui/dist

1
2
3
4
5

这是 GitHub 官方提供的 action,可以指定路径,把第一阶段的 dist 暂存。更多参数,可到 readme (opens new window) 详看。

# 制品下载

第一构建阶段上传的制品,可在第二阶段,用如下方式下载:

- name: 从共享下载
  uses: actions/download-artifact@v4
  with:
    name: workspace
    path: ui/dist

1
2
3
4
5

注意,需要 name 与上边上传的保持一致。同理,如果想要应用更多参数,可到 readme (opens new window) 查看。

# docker 镜像构建的思路

前提:这里提到的镜像构建,是指常规的构建出 linux/amd64,linux/arm64 两个平台的镜像。

# 思路一

之前,我都是用 build-push-action (opens new window) 提供的能力做的构建,比如以往的项目:go-ldap-admin (opens new window), 对应的 Dockerfile (opens new window),对应的流水线如下:

- name: Build and push
  uses: docker/build-push-action@v4
  with:
    context: .
    file: ./Dockerfile
    # 所需要的体系结构,可以在 Available platforms 步骤中获取所有的可用架构
    platforms: linux/arm64,linux/amd64
    # 镜像推送时间
    push: ${{ github.event_name != 'pull_request' }}
    # 给清单打上多个标签
    tags: |
      eryajf/go-ldap-admin:latest
      eryajf/go-ldap-admin:${{ steps.date.outputs.today }}

1
2
3
4
5
6
7
8
9
10
11
12
13

通过 action 中声明的不同 platform,然后用 go build -o go-ldap-admin 命令自动识别系统来构建对应系统的二进制。

这种构建思路,存在两个问题:

  1. 构建 arm 的镜像时,会格外慢,项目越大越明显。此问题我也提了 issue (opens new window)
  2. 因为 Dockerfile 设计成了分阶段构建,go 的 mod 缓存做起来也不是很方便,如果再加上前端的缓存,配置方案会更加复杂。

# 思路二

最近,我学习到一种新的知识点,可阅读跨平台 (opens new window)这篇文档。

简单来说,就是在构建多平台镜像时,我们会用到 --platform=linux/amd64 类似这样的参数。而在 Dockerfile 中,默认内置了三个变量,分别如下:

  • TARGETPLATFORM:解析值为 linux/amd64
  • TARGETOS:解析值为 linux
  • TARGETARCH :解析值为 amd64

这里做一个简单的 demo 进行验证,有 Dockerfile 如下:

FROM docker.cnb.cool/znb/images/alpine:3.21

ARG TARGETOS
ARG TARGETARCH
ARG TARGETPLATFORM

RUN echo "Target OS: ${TARGETOS}"
RUN echo "Target Arch: ${TARGETARCH}"
RUN echo "Target Platform: ${TARGETPLATFORM}"

1
2
3
4
5
6
7
8
9

然后分别运行不同平台的参数:

# amd
$ docker build -t eryajf --platform=linux/amd64  .

# arm
$ docker build -t eryajf --platform=linux/arm64  .

1
2
3
4
5

可以看到不同的结果:

My_Photor_1744463152452.webp

获取到这个知识点之后,我把整个构建的思路做了一下调整:

  • 原来的思路是在 dockerfile 中做分阶段构建,务求在里边独立完整地构建,不依赖其他操作。
  • 现在的思路是把二进制的构建放在 dockerfile 之外,dockerfile 只需把对应架构的二进制放到对应容器环境即可。

新的思路可以较好地规避以及解决掉思路一中提到的两个问题点:

  • 构建慢
    • 利用交叉编译,再加上 gox 的加持,构建速度提升非常大。
  • 缓存问题
    • 在外边构建,比在 Dockerfile 中配置缓存要容易得多。

因此,现在我个人针对 go 语言项目的镜像构建实践,可参考:eryajfctl (opens new window) 项目的 Makefile (opens new window)Dockerfile (opens new window) 以及 Action (opens new window)

这个项目本身就是一个模板项目,以后我也会把个人理解的 cobra 框架,以及 Github Action 构建 Go 项目的最佳实践,在该项目中体现,欢迎持续关注该项目。