专栏首页Serverless+基于 Alpine 的 Docker 镜像编译的程序无法在云函数环境运行
原创

基于 Alpine 的 Docker 镜像编译的程序无法在云函数环境运行

最近有一个用户反馈, 他使用 golang:1.13.1-alpine3.10 这个镜像来编译的可执行程序无法在云函数的环境运行, 报错信息如下:

fork/exec /var/user/main: no such file or directory

macOS 下编译则没有这个问题

问题定位

还未来得及定位问题, 用户便反馈说换了一个镜像就没问题了, 于是没能获得更多信息

过了几天, 有一个同事在群里贴出了 Go 程序链接出错的信息, 看起来也是在 Alpine Linux 下编译的, 有人回复道 Alpine Linux 使用的不是 glibc

啊哈, 终于有线索了, 写代码验证一下

package main

import "fmt"

func main() {
	fmt.Println("hello world")
}

CentOS 上编译后, 使用 ldd 查看一下程序依赖哪些 .so(也可以使用 readelf -d)

$ ldd main
        not a dynamic executable

程序太简单了, 没有依赖动态库

搜索了一下, 发现 Go 的仓库有一个 issue #33019, 和我们的问题很类似

package main

import (
	"net"
	"fmt"
	"os"
)

func main() {
	ips, err := net.LookupIP("localhost")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not get IPs: %v\n", err)
		os.Exit(1)
	}
	for _, ip := range ips {
		fmt.Printf("localhost. IN A %s\n", ip.String())
	}
}

编译这段代码, 再次使用 ldd 查看一下程序依赖哪些 .so

$ ldd main
        linux-vdso.so.1 =>  (0x00007ffca89c9000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f6c4b4bd000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f6c4b0f9000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f6c4aef5000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6c4b6d9000)

终于和 glibc 扯上关系了

使用 golang:1.13.1-alpine3.10 这个镜像重新编译一下这段代码, 看看结果有什么不同

$ docker run -v $PWD:/go/src/test -w /go/src/test golang:1.13.1-alpine3.10 go build -o main-alpine
$ ldd main-alpine
        linux-vdso.so.1 =>  (0x00007ffe0055e000)
        libc.musl-x86_64.so.1 => not found
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f2512754000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f2512390000)
        /lib/ld-musl-x86_64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x00007f2512958000)

可以看到, 缺失了 libc.musl-x86_64.so.1, 运行一下程序

$ ./main-alpine
-bash: ./main-alpine: /lib/ld-musl-x86_64.so.1: bad ELF interpreter: No such file or directory

No such file or directory 正是本文一开始提到的出错信息

(完整的出错信息可通过使用 Go 的 os/exec 包启动 main-alpine 获得)

解决方案

问题的原因在于云函数的运行环境(CentOS)提供的是 glibc, 而 Alpine Linux 却是 musl libc. 因而使用 golang:1.13.1-alpine3.10 这个镜像编译出来的程序如果依赖于 musl libc, 则会在程序加载的时候找不到所需的动态库

解决问题的方法很简单, 只需将镜像换成 golang:<version> 的版本(如golang:1.12)即可

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 从Docker镜像构建演化史来了解多阶段构建的影响

    现在很多开发者都会慢慢习惯在开发环境通过Docker来构建开发环境,有时候可能会有环境移植的问题,所以需要我们写好一套Dockerfile来构建相关的开发镜像,...

    云爬虫技术研究笔记
  • Docker学习笔记之使用 Docker Hub 中的镜像

    自己编写 Dockerfile 能够很好的实现我们想要的程序运行环境,不过如果装有我们想要环境的镜像已经由热心的开发者构建好并共享在 Docker Hub 上,...

    Jetpropelledsnake21
  • Docker 构建 Tengine 2.2.2 镜像

    Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型...

    緣來
  • 不要轻易使用 Alpine 镜像来构建 Docker 镜像,有坑!

    第一部分着重介绍多阶段构建(multi-stage builds),因为这是镜像精简之路至关重要的一环。在这部分内容中,我会解释静态链接和动态链接的区别,它们对...

    米开朗基杨
  • Dockerfile 之最小化 Java 镜像的常用技巧

    随着容器技术的普及,越来越多的应用被容器化。人们使用容器的频率越来越高,但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积。本文将介绍精简容器镜像的必要性...

    kubernetes中文社区
  • 三个技巧 大幅减少 Docker 镜像体积

    在构建 Docker 容器时,应该尽量想办法获得体积更小的镜像,因为传输和部署体积较小的镜像速度更快。但 RUN 语句总是会创建一个新层,而且在生成镜像之前还需...

    Debian中国
  • Docker 工作原理及容器化简易指南

    Docker 非常棒! 它使软件开发者无需担心配置和依赖性,在任何地方打包,发送和运行他们的应用程序。而在与 Kubernetes 相结合后,它使应用集群部署和...

    SDNLAB
  • Docker折腾记: (1)构建yapi容器,从构建发布到可用

    Docker/Linux/Node基础, 比如Linux和docker的常用命令,shell的编写等等

    CRPER
  • Docker镜像优化:从1.16GB到22.4MB!

    Docker 是一个供软件开发人员和系统管理员使用容器构建、运行和与分享应用程序的平台。容器是在独立环境中运行的进程,它运行在自己的文件系统上,该文件系统是使用...

    macrozheng
  • 创建自己的Docker基础镜像

    Docker 提供了两种方法来创建基础镜像,一种是通过引入tar包的形式,另外一种是通过一个空白的镜像来一步一步构建,本文使用的是第二种方法,既FROM scr...

    大江小浪
  • Docker最全教程之Go实战,墙裂推荐(十八)

    Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。在2016年,Go被软件评价公司TIOBE 选为“TI...

    雪雁-心莱科技
  • 如何缩小您的docker 镜像体积

    写好node代码后,打包进docker发现镜像非常大,下面方法有助于构建一个一个体积小很多的镜像;

    常见_youmen
  • 三个技巧,将Docker镜像体积减小90%

    在构建 Docker 容器时,应该尽量想办法获得体积更小的镜像,因为传输和部署体积较小的镜像速度更快。

    菲宇
  • 优化Docker镜像,加速应用部署,教你6个小窍门

    基于Kubernetes的新版小米应用引擎在小米生态云上线3个多月来,深受大家喜爱。为了让用户的云端应用管理更高效、更方便,今天从6个方面分享一些溜到飞起的小窍...

    DevOps云学堂
  • Docker镜像优化:从1.16GB到22.4MB

    Docker 是一个供软件开发人员和系统管理员使用容器构建、运行和与分享应用程序的平台。容器是在独立环境中运行的进程,它运行在自己的文件系统上,该文件系统是使用...

    码农架构
  • Docker 镜像优化:从 1.16GB 到 22.4MB

    Docker 是一个供软件开发人员和系统管理员使用容器构建、运行和与分享应用程序的平台。容器是在独立环境中运行的进程,它运行在自己的文件系统上,该文件系统是使用...

    肉眼品世界
  • 容器化Go应用--基础镜像的未知时区问题

    用Go开发的应用程序的一个优势在于,可以从"零"开始构建应用的Docker镜像,镜像中仅需要包含Go应用程序编译后的二进制文件,不需要额外安装其他执行环境。这样...

    KevinYan
  • docker 仓库里面python好多tag都代表什么意思?我们该如何选择

    今天让我同事帮忙构建一个基于python代码的docker包,然后他问我使用那个底层镜像,我说你直接去docker hub上找一个,他打开之后问我这么多我该使用...

    张琳兮
  • docker 仓库里面python好多tag都代表什么意思?我们该如何选择

    今天让我同事帮忙构建一个基于python代码的docker包,然后他问我使用那个底层镜像,我说你直接去docker hub上找一个,他打开之后问我这么多我该使用...

    张琳兮

扫码关注云+社区

领取腾讯云代金券