如何解决Golang程序在Alpine镜像中的”not found”问题
- December 14, 2023
问题描述
在容器环境中,使用 Alpine 作为基础镜像进行服务构建是一种常见的选择。由于 Alpine 镜像非常轻量,可以显著减小程序镜像的体积,从而降低程序运行时对服务器资源的占用。
然而,某些情况下可能会导致使用 Alpine 构建的最终镜像无法正确运行主程序,尽管主程序本身是存在的。
~ # ls
client
~ # ./client
sh: ./client: not found
解决方案
为解决这个问题,需要执行以下两个关键步骤:
- 编译时加上
CGO_ENABLED=1
参数:
go build -o main main.go
->
CGO_ENABLED=1 go build -o main main.go
-
在 Alpine 基础镜像中安装必要的依赖:
在 Dockerfile 中加入以下指令,以确保在原有的基础镜像上安装
libc6-compat
:
FROM alpine:3.18.4
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.18/main" > /etc/apk/repositories
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.18/community" >> /etc/apk/repositories
RUN apk add --no-cache libc6-compat
或者,可以选择使用带有 glibc 环境的其他基础镜像。
原理
Go参数
CGO_ENABLED
控制编译期间是否支持调用 cgo
命令。其值为 1 或 0,默认值为 1。具体作用如下:
- 当
CGO_ENABLED
为 1 时,Go 编译器会调用 C 编译器来构建 C 语言的部分代码,从而允许在 Go 代码中调用 C 函数。 - 当
CGO_ENABLED
为 0 时,Go 编译器将完全忽略 C 语言的部分,只使用 Go 的构建工具链。
如果程序内未调用 cgo
,则 CGO_ENABLED
的值对编译结果不产生影响。换言之,程序未调用 cgo
时,无论 CGO_ENABLED
为 0 还是 1,最终都能够成功编译,并且生成的二进制文件是一致的。
go-sqlite3
官方 🔗介绍:go-sqlite3本身就是一个cgo的包,如果需要使用go-sqlite3,那么需要gcc编译器,并且需要指定参数CGO_ENABLED=1
。
所以在程序引用了go-sqlite3之后,需要将参数CGO_ENABLED
设置为 1 ,并且需要在最终运行的镜像内存在c环境。
参考: