docker 踩坑
docker copy命令
COPY 遵循的规则
<src> 路径必须在构建的上下文中
不能添加 ../something 、 /something ,因为 docker 构建的第一步是将上下文目录(和子目录)发送到 docker 守护进程
# test.txt 是相对路径,相对于构建上下文 COPY test.txt /mkdir/ # 错误写法,文件均不在上下文目录中,并不会被找到 # 这个找的就是构建上下文的上级目录的 test.txt COPY ../test.txt /mkdir/ # 这个找的是本机根目录下的 test.txt, 所以找不到文件。 COPY /test.txt /mkdir/ <src> 是目录 则复制目录的全部内容,包括文件系统元数据 不会复制目录本身,只会复制其内容 COPY dir /mydir/ <src> 是任何其他类型的文件 则将其与其元数据一起单独复制 <dest> 以斜杠 / 结尾,它将被视为一个目录,并且 <src> 的内容将写入 <dest>/base(<src>)
基础镜像
scratch: 空的基础镜像,最小的基础镜像 busybox: 带一些常用的工具,方便调试, 以及它的一些扩展busybox:glibc alpine: 另一个常用的基础镜像,带包管理功能,方便下载其它依赖的包
CGO静态编译的问题
本身Go是静态编译的, 对于CGO, 如果设置CGO_ENABLED=0
,则完全静态编译,不会再依赖动态库。
如果设置CGO_ENABLED=0
,并且你的代码中使用了标准库的net
包的话,有可能编译好的镜像无法运行,报sh: /app: not found
的错误,尽管/app
这个文件实际存在,并且如果讲基础镜像换为centos
或者ubuntu
的话就能执行。这是一个奇怪的错误,原因在于:
知道了原因,解决办法也很简单,就是完全静态链接或者在基础镜像中加入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
的功能:
参照链接: https://colobu.com/2018/08/13/create-minimal-docker-image-for-go-applications/
docker交叉编译
存在交叉编译的情况时,cgo
工具是不可用的。在标准 go 命令的上下文环境中,交叉编译意味着程序构建环境的目标计算架构的标识与程序运行环境的目标计算架构的标识不同,或者程序构建环境的目标操作系统的标识与程序运行环境的目标操作系统的标识不同
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go ##或者 GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o app app.go
自Go 1.10以后,你不必再使用installsuffix
参数(或许更早的版本),Go的核心开发人员Ian Lance Taylor已经确认了这一点。
你可能有人还使用-a
参数,它强制重新编译相关的包,一般你不会使用它。
关闭 cgo
后,在构建过程中会忽略 cgo
并静态链接所有的依赖库,而开启 cgo
后,方式将转为动态链接。
其他参数:
CGO_ENABLED : CGO 表示 golang 中的工具,CGO_ENABLED=0 表示 CGO 禁用,交叉编译中不能使用 CGO;
GOOS : 环境变量用于指定目标操作系统,mac 对应 darwin,linux 对应 linux,windows 对应 windows ,还有其它的 freebsd、android 等;
GOARCH:环境变量用于指定处理器的类型,386 也称 x86 对应 32位操作系统、amd64 也称 x64 对应 64 位操作系统,arm 这种架构一般用于嵌入式开发。比如 Android , iOS , Win mobile 等;