0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Docker提供的构建功能有哪些

马哥Linux运维 来源:马哥Linux运维 作者:马哥Linux运维 2022-08-25 09:08 次阅读

Docker 提供了一些出色的构建时功能和基本映像,我们可以用它们来实现轻量、安全和高效的应用程序构建。

本文会介绍为什么 Golang 可以很好地展示这些特性,因为 Golang 可以编译为单个二进制文件(或一组二进制文件)。

这篇文章的示例所关注的焦点是极简主义。尽管这些示例很基础,但它们非常重要,你可以在这些概念基础上为大型 Golang 项目引入更多最佳实践,以提高安全性和效率。

我们将使用这个简单的 main.go 来演示本文的概念:


package main import "fmt" func main() {  fmt.Println("Hello Cloudreach!") }

最少的层带来效率最大化:最佳实践

Docker 在 Dockerfile 文档中一上来就强调:尽量减少层数是一个最佳实践!这是一个重要的概念,必须从一开始就做好。

你很容易就能写一个包含很多层的 Dockerfile——它的语法就有这个倾向——结果你不知不觉中就会写出很多效率低下的内容。

最佳实践是将构建的相关阶段分组和链接在一起,例如下载依赖项、供应商文件夹集成或使用 RUN 命令设置构建环境等阶段。

你还需要考虑分组的哪些部分是可以经常更改的,然后将它们分组到 Dockerfile 中尽可能低的层,同时把静态构建依赖项、构建环境配置或应用程序资产放到 Dockerfile 中尽可能上层的位置上。

每一层,更具体地说是 Dockerfile 中以指令开头的每一行,都经过哈希处理并建立在另一层之上,最后一个映像由“堆叠(stacked)”层构成。

由于 Dockerfile 的每一层都是从下一层继承的,因此构建缓存提供了一种很好的机制,可以帮助你跳过已构建或静态的内容,然后转到你需要构建和重新哈希的部分!

尽量缩短构建时间是很重要的,因为高效的 CI/CD 系统每天都会运行这些构建很多次。当团队规模逐渐扩大后,这可能意味着大量的构建工作,可能会需要很多 Jenkins worker,有时甚至需要很长时间才能集成开发人员的代码!

Docker 有一些构建缓存功能,它们可以显著节省构建时间。等待构建的时间越短,意味着集成和自动化测试的速度也就越快,也能提升 CI/CD 流程的速度,让你的流程足以和团队规模相匹配。

尽可能为应用程序安排单独的非 root 用户也是很重要的。你只需要在 linux adduser 命令中使用 RUN 指令,然后在 Dockerfile 中使用 USER 指令就可以使用这个用户来运行二进制文件了。

下面是使用这些最佳实践构造的一个最精简的 Dockerfile main.go 示例,它只有一个基本的 main 函数,没有外部依赖项:

FROM golang:alpine RUN mkdir /app  ADD . /app/ WORKDIR /app  RUN go build -o main . RUN adduser -S -D -H -h /app appuser USER appuser CMD ["./main"]

构建后,生成的映像大小为 378MB:


$  docker build -t hellocloudreachmain:1.0 . -f Dockerfile.single... (build output omitted)$  docker images | grep hellocloudreachmainhellocloudreachmain1.0d1c5090585bcLessthanasecondago378MB

尽可能使用基于 Alpine 的官方映像!它是基于 busybox 和 musl 构建的,最轻量级的 Linux 发行版之一。与较重的发行版相比,它的容器映像体积很小,这是一个轻松提升效率的好方法。

但我们还可以进一步简化!这些官方映像构建(比如golang:alpine)都包含很多层,里面含一些安全组件,用来构建应用程序资产时很方便;但是如果我们的应用程序不需要这些层,那就不要把它们放进去!我们需要使用其他一些 Docker 构建功能,进一步缩小文件体积。

下一步:多阶段

当需要在生产环境中运行应用程序时,我们需要让容器的设计可以确保性能和安全性。我们还需要尽可能多的可移植性,以便轻松地移动容器,并使用 DockerSwarm 和 Kubernetes 之类的编排器对其进行大规模调度。

将映像推入和拉出注册表所需的时间应尽量缩短。编写用于生产的 Dockerfile 时,要记住的一个要点就是在最终运行时映像中实践极简主义。

如果运行的时候并不需要某样东西,请不要把它放进去!

在开发环境中,有时需要一个“较重”的容器映像,也许是一个开发人员专属的 Dockerfile,方便开发人员随时扔进来一些工具,和容器一起进行调试等开发活动。也可能会附加或保留一两个卷和活动容器交互。这些当然都是很常见的情况!

但是,随着容器映像沿开发管线向上移动,一定要记得把这些东西都取出来。一条正规的安全软件供应链会要求在管道中尽早构建最终映像,对映像签名,并将经过正式签名的映像推到生产环境的各个阶段。

因此,你需要尽早在供应链中构建、验证、集成和签名这个最小化的映像;这是 Dockerfile 开发人员、QA 团队和安全工程师必须熟悉的操作!换句话说,只构建一次,然后让你的流程将生成的映像投入生产环境。

多阶段构建是实现这一目标的一个好方法!多阶段涉及的基本原理包括:调用一个临时容器以简化应用程序的构建,然后将构建的资产从这个空间复制到只有运行应用所需必要组件的容器映像中。拿之前的 Dockerfile 示例来说:

FROM golang:alpine as builder RUN mkdir /build  ADD . /build/ WORKDIR /build  RUN go build -o main . FROM alpine RUN adduser -S -D -H -h /app appuser USER appuser COPY --from=builder /build/main /app/ WORKDIR /app CMD ["./main"]

注意这个 Dockerfile 中的两个 FROM 指令。我们将第一个标记为“builder”,使用它来构建应用程序。

然后,我们使用第二个 FROM,这一次是从基本的“alpine”(非常轻巧!)中提取的,并将我们构建的可执行文件从该环境复制到该新环境。

这就让映像的体积比以前小了很多!另外,“builder”容器被缓存在 docker builder 上下文中,因此可以像前面的示例一样利用构建缓存来提升速度!

$  docker build -t hellocloudreachmain:1.1 . -f Dockerfile.multi... (build output omitted)$  docker images | grep hellocloudreachmainhellocloudreachmain                1.0 d1c5090585bc  8 minutes ago 378MBhellocloudreachmain                1.1 ea737df5cc64 Less than a second ago    6.16MB

这个映像的大小是 6.16MB。相比 378MB 来说,体积减少的效果很明显!

最小化整个运行环境……从头开始构建!

实际上,我们在精简之路上还可以走得更远。Golang 有很多有趣的特性,其中之一是你可以编译为单个二进制文件,并且在大多数情况下,你可以使用某些特殊的构建时参数将所有相关的库静态编译进这个二进制文件。

这样我们就能构建一个最小化的 Docker 容器,并减少额外的运行时开销,以实现我们所追求的出色性能、可移植性和安全性!

如果我们可以将 Golang 应用程序编译为单个二进制文件,并将它静态链接到依赖项上,就可以使用一个 0KB 容器来运行这个应用程序。这是 Docker 提供的一个特殊的基础映像,称为“scratch”。

在我们的 Docker 培训课程中总会遇到一个问题:所有容器内部都装有操作系统吗?答案是否定的,就是因为有这种特殊类型!

这个映像内部没有关联受支持的操作系统环境。它有一些特殊要求,最重要的是,主机的架构必须支持编译好的二进制文件的架构(x86、x64 等),然后,你实际得到的容器除了隔离功能和 Docker 容器的那些优秀特性外,不向应用程序提供任何功能或支持!尽量使用 scratch 作为基础映像,将为你的应用程序容器提供极高的简约性和安全性水平。

FROM golang:alpine as builder RUN mkdir /build  ADD . /build/ WORKDIR /build  RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main . FROM scratch COPY --from=builder /build/main /app/ WORKDIR /app CMD ["./main"]

在第 6 行,FROM scratch 告诉 Docker 从头开始,就像我们在上一个多阶段示例中看到的那样,但这次使用的是 0KB 临时映像。第一个阶段与之前类似,但这次我们在构建阶段使用一些编译时参数来指示 go 编译器将运行时库静态链接到二进制文件本身:


RUNCGO_ENABLED=0GOOS=linuxgobuild-a-installsuffixcgo-ldflags'-extldflags"-static"'-omain.

在此示例中,最终的 Docker 映像只会包含这一个可执行文件,而无需使用容器操作系统。

$ docker build -t hellocloudreachmain:1.2 . -f Dockerfile.scratch ... (build output omitted) $ docker images | grep hellocloudreachmain hellocloudreachmain 1.0 d1c5090585bc 8 minutes ago 378MB hellocloudreachmain 1.1 ea737df5cc64 4 minutes ago 6.16MB hellocloudreachmain 1.2 bda5c99404ae 33 seconds ago 2.01MB

太棒了,生成的容器大小只有 2.01MB!与最初的 378MB 映像相比,这是一个巨大的进步!

那么这些真的有用吗?

$  docker run -it hellocloudreachmain:1.0 Hello Cloudreach! $  docker run -it hellocloudreachmain:1.1 Hello Cloudreach! $  docker run -it hellocloudreachmain:1.2 Hello Cloudreach!

小结

我们用一个基本的 Dockerfile 举例,然后一步步缩减最终映像的体积。通过这个简单的练习,我们很容易看到在构建 Golang 应用程序时,有很多选择可以在 Docker 构建中实践极简主义。

我们有很多办法可以利用这种语言的特性,及其在编译期间提供给开发人员的特性来减小容器的体积。由于 Golang 可以编译为静态链接的可执行文件,因此我们能利用这类特性为运行时剥离所有不必要的组件。

更复杂的应用程序和构建可能无法遵循和上面完全相同的设计模式,但是这些原理可以应用在大多数 Golang Dockerfile 上!只需花一些时间来确保自己使用行业最佳实践正确构建 Dockerfile,就能成功地在容器中构建快速、安全和可扩展的应用程序!

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 应用程序
    +关注

    关注

    37

    文章

    3092

    浏览量

    56165
  • 编译
    +关注

    关注

    0

    文章

    607

    浏览量

    32307
  • Docker
    +关注

    关注

    0

    文章

    430

    浏览量

    11573

原文标题:如何构建 Golang Dockerfiles?

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    docker核心概念

    密度。企业利用 Docker 可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为 Linux 和 Windows Server 应用发布新功能
    发表于 07-15 07:29

    怎么构建docker镜像仓库软件

    Docker Registry】用docker registry 镜像搭建私有测试仓库
    发表于 08-13 11:03

    采用CentOS7的JDK Docker镜像构建

    基于CentOS7构建JDK Docker镜像
    发表于 04-02 11:25

    构建ARM64版本nacos docker镜像

    在适配过程中有大量合作伙伴用到nacos且采用容器化部署,dockerhub未提供官方镜像,因此需要在鲲鹏服务器自定义构建构建前提:Docker已部署
    发表于 06-16 14:29

    如何使用AirGradient构建功能强大的PM2.5细尘传感器

    描述空气梯度作为 AirGradient for Education 系列的一部分,本说明教授如何使用 AirGradient 构建功能强大的 PM2.5 细尘传感器。传感器将在显示屏上显示
    发表于 06-22 06:25

    介绍一款非常方便的java领域docker镜像构建工具

    前言本文主要介绍的是google开源的一个java领域的docker构建工具jib.目前在github上的start有8.5k,fork有784,是一款非常方便的java领域docker构建
    发表于 07-19 17:41

    在Ubuntu 18.04 for Arm上运行的TensorFlow和PyTorch的Docker映像

    入门要构建和运行 Docker 映像,请确保使用的机器是 Arm AArch64。$ uname -maarch64任何由Graviton提供支持的 AWS EC2 实例 均可
    发表于 10-14 14:25

    库是否有另一种选项来构建功能更全面的控件UI?

    一些我想要的功能,例如选项卡、下拉菜单等。库是否有另一种选项来构建功能更全面的控件 UI?我还想让 UI 比现在更漂亮,但我不确定是否可行。虽然我有其他几种类型的 ESP8266,但我很欣赏这不是一款
    发表于 02-23 06:55

    docker容器中构建yocto imx-image时出错怎么解决?

    我正在尝试根据规范 <>(修订版 LF5.15.5_1.0.0 — 2022 年 3 月 31 日)中的第 3.1 章 Dockerdocker 容器中构建
    发表于 06-08 09:30

    一种具有输出限压功能的电荷泵的设计_范建功

    一种具有输出限压功能的电荷泵的设计_范建功
    发表于 01-07 22:14 2次下载

    Docker:微容器的优势与构建教程

    非必要的东西也打包进去,所以最后构建出来的镜像就很庞大,直接导致我们的容器也变得很大。对于刚入门的Docker新手来说,大家一开始基本都是用的Docker官方镜像仓库里提供的基础镜像,
    发表于 10-10 11:32 0次下载

    passenger-docker Docker基础镜像提供工具

    ./oschina_soft/passenger-docker.zip
    发表于 05-13 10:35 1次下载
    passenger-<b class='flag-5'>docker</b> <b class='flag-5'>Docker</b>基础镜像<b class='flag-5'>提供</b>工具

    如何使用AirGradient构建功能强大的PM2.5细尘传感器

    电子发烧友网站提供《如何使用AirGradient构建功能强大的PM2.5细尘传感器.zip》资料免费下载
    发表于 07-01 15:42 0次下载
    如何使用AirGradient<b class='flag-5'>构建功能</b>强大的PM2.5细尘传感器

    docker微服务架构实战

    的容器化技术,为微服务架构的实施提供了强大的支持。本文将介绍Docker微服务架构的实战经验,包括Docker的概述、微服务架构的设计原则以及实际应用中的具体实践。 一、Docker
    的头像 发表于 11-23 09:26 274次阅读

    docker exec命令的使用方法

    Docker是一种开源的容器化平台,可以让开发人员在容器中打包和运行应用程序。它提供了一种快速、可靠和一致的方式来构建、部署和运行应用程序。Docker exec命令是
    的头像 发表于 11-23 09:33 608次阅读