创建最小的Go docker 镜像

简介:

虽然曾有一些文章介绍了如何创建一个最小的Go Docker镜像,我也曾写过一篇文章,但是随着Go的新的版本的发布, 以及docker本身的进化,有些技巧已经发生了变化, 本文介绍了最新的创建超小的Go镜像的方法。

一个简单Go程序的镜像

首先让我们创建一个很简单的Go程序:


1package main
2import "fmt"
3func main() {
4 fmt.Println("hello world")
5}

运行下面的命令会创建一个超小的镜像, 这是我们的第一种方式:

1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest
下一节介绍其中的编译参数

查看镜像, 生成的镜像只有 1.21MB


1# docker images app
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app latest b716e13758cd 11 seconds ago 1.21MB

这命令将编译、打包、输入镜像集成到一条命令了。

第二种方式是使用一个Dockerfile文件:


1FROM scratch
2ADD app /
3CMD ["/app"]

运行下面的命令创建一个镜像:

1docker build -t app2 .

查看生成的镜像, 也是 1.21MB:


1# docker images app2
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app2 latest 4e2af2ffb695 4 seconds ago 1.21MB

第三种方式是利用Docker的 multistage 功能,在镜像中编译,Dockerfile文件:


1Dockerfile.multistage
2docker build -t app3 -f Dockerfile.multistage .

查看生成的镜像, 也是``:


1# docker images app3
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app3 latest 9177859dad64 16 seconds ago 1.21MB

你可以结合你的情况选择一种生成镜像的方式。

编译Go程序

上面的例子中我们使用下面的命令编译Go程序:

1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go

你可能在其它一些文章中还看到installsuffix参数:

1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o app app.go

自Go 1.10以后,你不必再使用installsuffix参数(或许更早的版本),Go的核心开发人员Ian Lance Taylor已经确认了这一点。

你可能有人还使用-a参数,它强制重新编译相关的包,一般你不会使用它。

-s 忽略符号表和调试信息,-w忽略DWARF符号表,通过这两个参数,可以进一步减少编译的程序的尺寸,更多的参数可以参考go link, 或者 go tool link -help(另一个有用的命令是go tool compile -help)。

你也可以使用strip工具对编译的Go程序进行裁剪。

本身Go是静态编译的, 对于CGO, 如果设置CGO_ENABLED=0,则完全静态编译,不会再依赖动态库。

如果设置CGO_ENABLED=0,并且你的代码中使用了标准库的net包的话,有可能编译好的镜像无法运行,报sh: /app: not found的错误,尽管/app这个文件实际存在,并且如果讲基础镜像换为centos或者ubuntu的话就能执行。这是一个奇怪的错误,原因在于:

默认情况下net包会使用静态链接库, 比如libc

知道了原因,解决办法也很简单,就是完全静态链接或者在基础镜像中加入libc库。

下面是几种解决办法:

设置 CGO_ENABLED=0 编译是使用纯go的net: go build -tags netgo -a -v 使用基础镜像加glibc(或等价库musl、uclibc), 比如 busybox:glibc、alpine + RUN apk add --no-cache libc6-compat、frolvlad/alpine-glibc

有的同学说了,我代码中确实必须使用CGO,因为需要依赖一些C/C++的库。目前没有对应的Go库可替代, 那么可以使用-extldflags "-static",go tool link help介绍了extldflags的功能:

-extldflags flags

Set space-separated flags to pass to the external linker.

-static means do not link against shared libraries

基础镜像

其实前面已经列出了一些常用的基础镜像:

scratch: 空的基础镜像,最小的基础镜像

busybox: 带一些常用的工具,方便调试, 以及它的一些扩展busybox:glibc

alpine: 另一个常用的基础镜像,带包管理功能,方便下载其它依赖的包

显然。 你应该只在编译阶段使用Go的镜像,这样才能将你的镜像减小到最小。


原文发布时间为:2018-10-31

本文作者:smallnest 

本文来自云栖社区合作伙伴“Golang语言社区”,了解相关信息可以关注“Golang语言社区”。

相关文章
|
16天前
|
缓存 Linux 网络安全
docker的镜像无法下载如何解决?
【10月更文挑战第31天】docker的镜像无法下载如何解决?
524 29
|
29天前
|
缓存 监控 持续交付
|
12天前
|
存储 关系型数据库 Linux
【赵渝强老师】什么是Docker的镜像
Docker镜像是一个只读模板,包含应用程序及其运行所需的依赖环境。镜像采用分层文件系统,每次修改都会以读写层形式添加到原只读模板上。内核bootfs用于加载Linux内核,根镜像相当于操作系统,上方为应用层。镜像在物理存储上是一系列文件的集合,默认存储路径为“/var/lib/docker”。
|
18天前
|
存储 监控 Linux
docker构建镜像详解!!!
本文回顾了Docker的基本命令和管理技巧,包括容器和镜像的增删改查操作,容器的生命周期管理,以及如何通过端口映射和数据卷实现容器与宿主机之间的网络通信和数据持久化。文章还详细介绍了如何使用Docker部署一个简单的Web应用,并通过数据卷映射实现配置文件和日志的管理。最后,文章总结了如何制作自定义镜像,包括Nginx、Python3和CentOS镜像,以及如何制作私有云盘镜像。
90 2
|
19天前
|
关系型数据库 MySQL Docker
docker环境下mysql镜像启动后权限更改问题的解决
在Docker环境下运行MySQL容器时,权限问题是一个常见的困扰。通过正确设置目录和文件的权限,可以确保MySQL容器顺利启动并正常运行。本文提供了多种解决方案,包括在主机上设置正确的权限、使用Dockerfile和Docker Compose进行配置、在容器启动后手动更改权限以及使用 `init`脚本自动更改权限。根据实际情况选择合适的方法,可以有效解决MySQL容器启动后的权限问题。希望本文对您在Docker环境下运行MySQL容器有所帮助。
33 1
|
21天前
|
存储 Java 开发者
成功优化!Java 基础 Docker 镜像从 674MB 缩减到 58MB 的经验分享
本文分享了如何通过 jlink 和 jdeps 工具将 Java 基础 Docker 镜像从 674MB 优化至 58MB 的经验。首先介绍了选择合适的基础镜像的重要性,然后详细讲解了使用 jlink 构建自定义 JRE 镜像的方法,并通过 jdeps 自动化模块依赖分析,最终实现了镜像的大幅缩减。此外,文章还提供了实用的 .dockerignore 文件技巧和选择安全、兼容的基础镜像的建议,帮助开发者提升镜像优化的效果。
|
25天前
|
存储 缓存 Java
Java应用瘦身记:Docker镜像从674MB优化至58MB的实践指南
【10月更文挑战第22天】 在容器化时代,Docker镜像的大小直接影响到应用的部署速度和运行效率。一个轻量级的Docker镜像可以减少存储成本、加快启动时间,并提高资源利用率。本文将分享如何将一个Java基础Docker镜像从674MB缩减到58MB的实践经验。
39 1
|
1月前
|
Docker 容器
docker:记录如何在x86架构上构造和使用arm架构的镜像
为了实现国产化适配,需将原x86平台上的Docker镜像转换为适用于ARM平台的镜像。本文介绍了如何配置Docker buildx环境,包括检查Docker版本、安装buildx插件、启用实验性功能及构建多平台镜像的具体步骤。通过这些操作,可以在x86平台上成功构建并运行ARM64镜像,实现跨平台的应用部署。
674 2
|
1月前
|
网络协议 Docker 容器
docker pull命令拉取镜像失败的解决方案
docker pull命令拉取镜像失败的解决方案
887 1
|
12天前
|
缓存 JavaScript 安全
深入理解Docker镜像构建过程
深入理解Docker镜像构建过程
43 0
下一篇
无影云桌面