云原生之深入解析强大的镜像构建工具Earthly

一、Earthly 简介

  • Earthly 是一个更加高级的 Docker 镜像构建工具,Earthly 通过自己定义的 Earthfile 来代替传统的 Dockerfile 完成镜像构建;Earthfile 就如同 Earthly 官方所描述:
rust 复制代码
Makefile + Dockerfile = Earthfile
  • 在使用 Earthly 进行构建镜像时目前强依赖于 buildkit,Earthly 通过 buildkit 支持了一些 Dockerfile 的扩展语法,同时将 Dockerfile 与 Makefile 整合,使得多平台构建和代码化 Dockerfile 变得更加简单;使用 Earthly 可以更加方便的完成 Dockerfile 的代码复用以及更加友好的 CI 自动集成。

二、快速使用

① 安装依赖

  • Earthly 目前依赖于 Docker 和 Git,所以安装 Earthly 前请确保机器已经安装了 Docker 和 Git。

② 安装 Earthly

  • Earthly 采用 Go 编写,因此主要就一个二进制文件,Linux 下安装可以直接参考官方的安装脚本:
rust 复制代码
$ sudo /bin/sh -c 'wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-amd64 -O /usr/local/bin/earthly && chmod +x /usr/local/bin/earthly && /usr/local/bin/earthly bootstrap --with-autocomplete'
  • 安装完成后 Earthly 将会启动一个 buildkitd 容器:earthly-buildkitd。

③ 语法高亮

  • 目前 Earthly 官方支持 VS Code、VIM 以及 Sublime Text 三种编辑器的语法高亮,具体如何安装请参考 官方文档

④ 基本使用

  • 本示例源于官方 Basic 教程,以下示例以编译 Go 项目为样例。首先创建一个任意名称的目录,目录中存在项目源码文件以及一个 Earthfile 文件;
rust 复制代码
main.go
package main

import "fmt"

func main() {
    fmt.Println("hello world")
}
  • Earthfile:
rust 复制代码
FROM golang:1.17-alpine
WORKDIR /go-example

build:
    COPY main.go .
    RUN go build -o build/go-example main.go
    SAVE ARTIFACT build/go-example /go-example AS LOCAL build/go-example

docker:
    COPY +build/go-example .
    ENTRYPOINT ["/go-example/go-example"]
    SAVE IMAGE go-example:latest
  • 有了 Earthfile 以后,就可以使用 Earthly 将其打包为镜像;
rust 复制代码
# 目录结构
~/t/earthlytest ❯❯❯ tree
.
├── Earthfile
└── main.go

0 directories, 2 files

# 通过 earthly 进行构建
~/t/earthlytest ❯❯❯ earthly +docker
  • 构建完成后,就可以直接从 docker 的 images 列表中查看刚刚构建的镜像,并运行:

三、进阶使用

① 多阶段构建

  • Earthfile 中包含类似 Makefile 一样的 target,不同的 target 之间还可以通过特定语法进行引用,每个 target 都可以被单独执行,执行过程中 earthly 会自动解析这些依赖关系。这种多阶段构建时语法很弹性,可以在每个阶段运行独立的命令以及使用不同的基础镜像;从上文中可以看到,始终使用了一个基础镜像(golang:1.17-alpine),对于 Go 这种编译后自带运行时不依赖其语言 SDK 的应用,事实上可以将 "发布物" 仅放在简单的运行时系统镜像内,从而减少最终镜像体积:
  • 由于使用了多个 target,因此可以单独的运行 build 这个 target 来验证编译流程,这种多 target 的设计方便我们构建应用时对编译、打包步骤的细化拆分,同时也方便我们进行单独的验证。 例如单独执行 build 这个 target 来验证编译流程是否正确:
  • 在其他阶段验证完成后,可以直接运行最终的 target,earthly 会自动识别到这种依赖关系从而自动运行其依赖的 target:

② 扩展指令

  • SAVE
    • SAVE 指令是 Earthly 自己的一个扩展指令,实际上分为 SAVE ARTIFACT 和 SAVE IMAGE;其中 SAVE ARTIFACT 指令格式如下:
rust 复制代码
SAVE ARTIFACT [--keep-ts] [--keep-own] [--if-exists] [--force] <src> [<artifact-dest-path>] [AS LOCAL <local-path>]
    • SAVE ARTIFACT 指令用于将文件或目录从 build 运行时环境保存到 target 的 artifact 环境;当保存到 artifact 环境后,可以通过 COPY 等命令在其它位置进行引用,类似于 Dockerfile 的 COPY --from... 语法;不同的是 SAVE ARTIFACT 支持 AS LOCAL 附加参数,一但指定此参数后,earthly 会同时将文件或目录在宿主机复制一份,一般用于调试等目的。SAVE ARTIFACT 命令在上面的样例中已经展示了,在运行完 earthly +build 命令后实际上会在本地看到被 SAVE 出来的 ARTIFACT:
    • 而另一个 SAVE IMAGE 指令则主要用于将当前的 build 环境 SAVE 为一个 IMAGE,如果指定了 --push 选项,同时在执行 earthly +target 命令时也加入 --push 选项,该镜像将会自动被推送到目标 Registry 上。SAVE IMAGE 指令格式如下:
rust 复制代码
SAVE IMAGE [--cache-from=<cache-image>] [--push] <image-name>...
  • GIT CLONE
    • GIT CLONE 指令用于将指定 git 仓库 clone 到 build 环境中;与 RUN git clone... 命令不同的是,GIT CLONE 通过宿主机的 git 命令运行,它不依赖于容器内的 git 命令,同时还可以直接为 earthly 配置 git 认证,从而避免将这些安全信息泄漏到 build 环境中; 关于如何配置 earthly 的 git 认证请参考 官方文档
    • 如下是 GIT CLONE 指令的样例:
  • COPY
    • COPY 指令与标准的 Dockerfile COPY 指令类似,除了支持 Dockerfile 标准的 COPY 功能以外,earthly 中的 COPY 指令可以引用其他 target 环节产生的 artifact,在引用时会自动声明依赖关系;即当在 B target 中存在 COPY +A/xxxxx /path/to/copy 类似的指令时,如果只单纯的执行 earthly +B,那么 earthly 根据依赖分析会得出在 COPY 之前需要执行 target A。
    • COPY 指令的语法格式如下:
rust 复制代码
# 与 Dockerfile 相同的使用方式,从上下文复制
COPY [options...] <src>... <dest>

# 扩展支持的从 target 复制方式
COPY [options...] <src-artifact>... <dest>
  • RUN
    • RUN 指令在标准使用上与 Dockerfile 里保持一致,除此之外增加了更多的扩展选项,其指令格式如下:
rust 复制代码
# shell 方式运行(/bin/sh -c)
RUN [--push] [--entrypoint] [--privileged] [--secret <env-var>=<secret-ref>] [--ssh] [--mount <mount-spec>] [--] <command>

# exec 方式运行
RUN [[<flags>...], "<executable>", "<arg1>", "<arg2>", ...]
    • 其中 --privileged 选项允许运行的命令使用 privileged capabilities,但是需要 earthly 在运行 target 时增加 --allow-privileged 选项;--interactive / --interactive-keep 选项用于交互式执行一些命令,在完成交互后 build 继续进行,在交互过程中进行的操作都会被持久化到镜像中:

③ UDCS

  • UDCs 全称 "User-defined commands",即用户定义指令;通过 UDCs 我们可以将 Earthfile 中特定的命令剥离出来,从而实现更加通用和统一的代码复用。如下是一个定义 UDCs 指令的样例:
rust 复制代码
# 定义一个 Command
# ⚠️ 注意: 语法必须满足以下规则
# 1、名称全大写
# 2、名称下划线分割
# 3、首个命令必须为 COMMAND(后面没有冒号)
MY_COPY:
    COMMAND
    ARG src
    ARG dest=./
    ARG recursive=false
    RUN cp $(if $recursive =  "true"; then printf -- -r; fi) "$src" "$dest"

# target 中引用
build:
    FROM alpine:3.13
    WORKDIR /udc-example
    RUN echo "hello" >./foo
    # 通过 DO 关键字引用 UDCs
    DO +MY_COPY --src=./foo --dest=./bar
    RUN cat ./bar # prints "hello"
  • UDCs 不光可以定义在一个 Earthfile 中,UDCs 可以跨文件、跨目录引用:
  • 有了 UDCs 以后,我们可以通过这种方式将对基础镜像的版本统一控制、对特殊镜像的通用处理等操作全部抽象出来,然后每个 Earthfile 根据需要进行引用。

④ 多平台构建

  • 在以前使用 Dockerfile 的时候,需要自己配置然后开启 buildkit 来实现多平台构建;在配置过程中可能会很繁琐,现在使用 earthly 可以默认帮实现多平台的交叉编译,需要做的仅仅是在 Earthfile 中声明需要支持哪些平台而已:
  • 以上 Earthfile 在执行 earthly --push +all 构建时,将会自动构建四个平台的镜像,并保持单个 tag,同时由于使用了 --push 选项还会自动推送到 Docker Hub 上:

四、总结

  • Earthly 弥补了 Dockerfile 的很多不足,解决了很多痛点问题;但同样可能需要一些学习成本,但是如果已经熟悉了 Dockerfile 其实学习成本不高;所以目前还是比较推荐将 Dockerfile 切换为 Earthfile 进行统一和版本化管理的。
相关推荐
Yeats_Liao1 小时前
遗留系统微服务改造(二):数据迁移实战攻略与一致性保证
微服务·云原生·架构
野蛮人6号1 小时前
黑马微服务P3快速入门入门案例无法跑通解决方案,本文解决了数据库连接和java版本不匹配的问题
微服务·云原生·架构
没有口袋啦3 小时前
K8s集群多节点部署(Ubuntu22.04)
docker·云原生·容器·kubernetes
荣光波比3 小时前
K8S(三)—— 基于kubeadm 1.20版本部署Kubernetes集群与Harbor私有仓库实战
云原生·容器·kubernetes
荣光波比4 小时前
K8S(二)—— K8S 1.28 集群部署指南(kubeadm 方式)
云原生·容器·kubernetes
问道飞鱼5 小时前
【Kubernets进阶】Kubernetes VPA (Vertical Pod Autoscaler) 详解与配置指南
云原生·容器·kubernetes·vpa
Light606 小时前
领码方案|微服务与SOA的世纪对话(7):运营降本增效——智能架构时代的成本与服务管理
微服务·云原生·ai ops·成本边界·slo/sli·容量预测·成本治理
Vio7256 小时前
微服务基础:远程调用的基本使用详解
微服务·云原生·架构
分布式存储与RustFS13 小时前
告别手动配置:用 Terraform 定义你的 RustFS 存储帝国
云原生·wpf·文件系统·terraform·对象存储·minio·rustfs
悠闲蜗牛�17 小时前
人工智能时代下的全栈开发:整合AI、大数据与云原生的实践策略
大数据·人工智能·云原生