什么时候使用Dockerfiles(什么时候不使用……) 您所在的位置:网站首页 docker一般部署什么 什么时候使用Dockerfiles(什么时候不使用……)

什么时候使用Dockerfiles(什么时候不使用……)

2024-06-02 20:32| 来源: 网络整理| 查看: 265

在这篇文章中,我们将讨论一些使用 Dockerfile 的最佳实践,探索一些注意事项,并使用 Dockerfile 和云原生 Buildpacks 构建应用。你将了解每种工具最擅长的工作是什么,以及如何决定何时使用它们。

Dockerfiles 是什么?

Dockerfile 是一个包含命令的文本文件,Docker 将执行这些命令来构建一个容器镜像。Dockerfiles 总是以一个 FROM 指令开始,指定从基本镜像开始。后续命令构建并修改该基本镜像。

让我们通过使用 Dockerfile 构建一个小的“hello world”,一个文件的 Go 应用程序来更好地了解 Dockerfile。你不需要安装 Go 以跟随教程,Docker 会照顾依赖。

代码语言:javascript复制package main import ( "fmt" "net/http" ) func main() { http.HandleFunc("/", sayHello) http.ListenAndServe(":8080", nil) } func sayHello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World!") }

现在,让我们创建一个简单的 Dockerfile。

代码语言:javascript复制FROM golang:1.16.5 WORKDIR /app COPY main.go . RUN go build main.go CMD ./main

为了让我们的容器运行起来,我们需要通过从 docker.com 安装 Docker CLI 来设置 Docker。然后,运行以下命令来构建应用程序。

代码语言:javascript复制docker build -t hello .

我们新构建的镜像的大小是 868.3 MB

代码语言:javascript复制REPOSITORY TAG IMAGE ID CREATED SIZE hello latest 005c27e8cd40 7 minutes ago 868.3MB

现在我们可以使用以下命令运行镜像:

代码语言:javascript复制docker run -it hello

这是一个很好的开始,但是镜像没有得到优化。

编写更好的 Dockerfile

我们开始使用 golang:1.16.5 作为我们的 Go 应用程序的基本镜像。但我们实际上可以从以下两个镜像中选择:

代码语言:javascript复制1.16.5 862MB 1.16.5-alpine 302MB

golang:1.16.5-alpine 指定 Go 基准镜像的 Alpine 版本。Alpine 是一个专门为容器设计的微型 Linux 发行版。所以 Docker、Go 和 Alpine 是天生一对!

我们也可以在 Dockerfile 中添加一个 FROM scratch 行,它告诉 Docker 以一个全新的、完全空的容器镜像(这被称为 scratch 容器)重新开始,并将编译后的程序复制到其中。这是我们稍后将继续运行的容器镜像。

使用 scratch 镜像也节省了大量空间,因为我们实际上不需要 Go 工具或其他工具来运行编译后的程序。使用一个容器用于构建,另一个容器用于最终镜像,这称为多阶段构建。

我们更好的 Dockerfile 看起来像这样

代码语言:javascript复制FROM golang:1.14-alpine AS build COPY main.go . RUN CGO_ENABLED=0 go build -o /bin/demo FROM scratch COPY --from=build /bin/demo /bin/demo ENTRYPOINT ["/bin/demo"]

当我们再次运行 docker 构建后,我们的镜像将会变小,新构建的镜像的大小大约为 8MB。

利用构建缓存

因为镜像是在构建过程的最后阶段构建的,所以你可以通过利用构建缓存[1]来最小化镜像层。

如果构建包含多个层,则可以将其从更改频率较低的层排序为更改频率较高的层,这确保了构建缓存是可重用的。

遵循以下步骤:

安装构建应用程序所需的工具安装和更新依赖项。生成的应用程序。

多阶段构建[2]允许你大幅减少最终镜像的大小,而不必费劲地减少中间层和文件的数量。下面是 Dockerfile 的示例。

代码语言:javascript复制FROM golang:1.16-alpine AS build # Install tools required for project # Run `docker build --no-cache .` to update dependencies RUN apk add --no-cache git RUN go get github.com/golang/dep/cmd/dep # List project dependencies with Gopkg.toml and Gopkg.lock # These layers are only re-built when Gopkg files are updated COPY Gopkg.lock Gopkg.toml /go/src/demo/ WORKDIR /go/src/demo/ # Install library dependencies RUN dep ensure -vendor-only # Copy the entire project and build it # This layer is rebuilt when a file changes in the project directory COPY . /go/src/demo/ RUN go build -o /bin/demo # This results in a single layer image FROM scratch COPY --from=build /bin/demo /bin/demo ENTRYPOINT ["/bin/demo"] CMD ["--help"]

然而,Dockerfile 缓存是脆弱的,你必须小心如何编写 Dockerfile。如果,你不需要写呢?

让我们用 Buildpacks

构建包(buildpack)是将源代码转换为可运行的容器镜像的程序。通常,构建包封装了单一语言生态系统工具链。有针对 Ruby、Go、Node.js、Java、Python 等的构建包。

用构建包构建我们的 Go 应用

要设置构建包,请遵循Pack CLI 安装说明[3]。让我们使用下面的命令来构建应用程序

代码语言:javascript复制pack build hello --builder=paketobuildpacks/builder:tiny

该镜像的大小大约为 30 MB。

pack 使用构建包来帮助你轻松创建可以在任何地方运行的 OCI 镜像。

代码语言:javascript复制===> DETECTING 4 of 6 buildpacks participating google.go.runtime 0.9.1 google.go.gopath 0.9.0 google.go.build 0.9.0 google.utils.label 0.0.1 ===> ANALYZING Previous image with name "go-app" not found ===> RESTORING ===> BUILDING === Go - Runtime ([email protected]) ===

构建包运行以下一组进程来构建应用程序的镜像。

CLI 检测项目的主要语言。例如,如果你的源代码目录有一个 Gemfile,构建包就会把它识别为 Ruby 项目;pom.xml 文件将其标识为 Java 项目,等等。然后执行环境分析之前的构建,以确定是否有任何步骤可以在后续构建中重用。构建包运行构建,下载所有依赖项并准备应用程序在生产环境中运行。最后,它将构建的结果导出为 Docker 镜像

除了构建镜像,pack 还让你为容器镜像生成一个材料清单。软件物料清单(Software Bill-of-Materials,BOM)提供了必要的信息,以了解容器中是什么以及它是如何构造的。

让我们为使用构建包构建的镜像运行下面的程序。

代码语言:javascript复制pack inspect-image your-image-name --bom

对我们的示例 Go 应用程序镜像运行它会得到以下结果。

代码语言:javascript复制{ "remote": null, "local": [ { "name": "go", "metadata": { "version": "1.17.1" }, "buildpacks": { "id": "google.go.runtime", "version": "0.9.1" } } ] }

云原生 Buildpacks 提供了两种形式的材料清单。

构建包可以填充关于它们所提供的依赖项的材料清单信息。用于构建应用程序的构建包列表。可复制的构建

构建包为容器镜像创建“可复制的构建(reproducible builds)”。以可复制的方式创建镜像。可复制构建意味着无论何时运行:

代码语言:javascript复制pack build hello --builder=paketobuildpacks/builder:tiny

它将产生完全相同的镜像 ID(也称为 sha / digest),假设你有:

同样的源代码相同的构建器镜像底层的构建包/语言支持可复制的构建(例如,go 二进制文件在默认情况下是可复制的)

让我们为最近构建的容器演示一下

同一个 Go 应用的两个镜像使用相同的构建器镜像和构建包有相同的哈希值。

我们为什么需要它?

镜像 sha 考虑镜像层的内容,包括元数据,例如镜像生成的日期。可复制构建可以作为信任链的一部分;源代码可以被签名,确定性编译可以证明二进制文件是从可信的源代码编译的。

现在,尝试将新镜像部署到你最喜欢的云上,这里有一些文档[4]可以帮助你!

适合每项工作的工具

到目前为止,我们已经讨论了云原生 Buildpacks、Dockerfiles 以及使用它们构建的应用程序。对于 Dockerfiles 来说,它们的灵活性使它们熠熠发光。你构建的镜像只受限于你编写 Dockerfile 脚本的能力;你可以安装系统包,允许或限制根访问,从头开始,增加一个现有的镜像,使用任何一个 Docker 的认证镜像,天空是唯一限制!然而,真正的挑战在于同样的灵活性。你的 Dockerfile 将成为你必须维护的另一段代码。随着时间的推移,操作系统或运行时配置可能需要补丁或更新。标准化、维护和构建镜像的自动化完全取决于你。

云原生 Buildpacks 解决了 Dockerfiles 操作上的复杂性,并提供了大规模创建和维护镜像所需的结构,提供了简单的用户体验。从选择和维护基本镜像到为其余层提供内容,提供与镜像大小和分层、缓存和安全性相关的优化,以及特定于给定编程语言的标准和优化,Buildpacks 可以完成所有这些工作。生成的应用程序镜像通过元数据进行了丰富,使其易于检查,你还可以获得详细的软件材料清单(Software Bill of Materials,SBOM),包括运行时版本、应用程序依赖关系和其他细节。

虽然 buildpack 为大多数用例提供了解决方案,但在某些情况下,你可能需要更大的灵活性,例如,如果你正在使用当前的 Buildpacks 生态系统不支持的语言构建应用程序,那么在这种情况下,你可能必须编写自定义的 Buildpacks。在 Buildpacks 不能处理某些需求的情况下,你可能必须创建一个一次性的 Dockerfile。

现在,轮到你探索这些工具并找出最适合你需要的工具了!

鸣谢

Javier Romero 和 Joe Kutner。

参考资料

[1]

利用构建缓存: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#leverage-build-cache

[2]

多阶段构建: https://docs.docker.com/develop/develop-images/multistage-build/

[3]

Pack CLI 安装说明: https://github.com/buildpacks/pack#getting-started

[4]

文档: https://docs.docker.com/language/golang/deploy/



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有