如何解决Golang程序在Alpine镜像中的”not found”问题

如何解决Golang程序在Alpine镜像中的”not found”问题

问题描述

在容器环境中,使用 Alpine 作为基础镜像进行服务构建是一种常见的选择。由于 Alpine 镜像非常轻量,可以显著减小程序镜像的体积,从而降低程序运行时对服务器资源的占用。

然而,某些情况下可能会导致使用 Alpine 构建的最终镜像无法正确运行主程序,尽管主程序本身是存在的。

~ # ls
client
~ # ./client 
sh: ./client: not found

解决方案

为解决这个问题,需要执行以下两个关键步骤:

  1. 编译时加上 CGO_ENABLED=1 参数:
go build -o main main.go

-> 

CGO_ENABLED=1 go build -o main main.go
  1. 在 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环境。

参考:

  1. https://naiv.fun/Ops/binary-not-found-in-Alpine.html 🔗
  2. https://www.4wei.cn/archives/1003060 🔗
  3. https://github.com/mattn/go-sqlite3/issues/384 🔗
lomtom

标题:如何解决Golang程序在Alpine镜像中的”not found”问题

作者:lomtom

链接:https://lomtom.cn/bczawum4lcaw0