专栏首页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 条评论
登录 后参与评论

相关文章

  • 在 SCF 中运行 Puppeteer

    Puppeteer 是一个 Node.js 库, 提供了一组封装良好的接口, 使你可以通过 DevTools 协议控制 Chrome. 本文介绍如何在 SCF ...

    ritchiechen
  • 云函数安装依赖

    使用 Python, Node.js 等开发云函数时, 可能遇到的一个问题就是依赖安装. 由于操作系统版本, 系统库版本及语言版本不一致, 有时在本地环境可以运...

    ritchiechen
  • 爱加密so保护简单脱壳测试

    1.   最近研究so文件的保护,在网上搜索发现爱加密支持对so文件的保护,然后联系客户,本来是想让客户保护一个自己的so文件来做测试的,结果客户各种不愿意,说...

    我是小三
  • Android 动态库压缩壳的实现

    计算机软件领域所说的壳实际上是一种软件加密技术。壳主要分为两大类:加密壳和压缩壳,加密壳侧重于防止软件被篡改,而压缩壳则侧重于减小软件体积。其实,在Window...

    小时光
  • SDK热更系列之如何获取应用在当前设备上的so对应的指令集

    子勰
  • Linux下so动态库一些不为人知的秘密

    Linux 下有动态库和静态库,动态库以.so为扩展名,静态库以.a为扩展名。二者都使用广泛。本文主要讲动态库方面知识。

    刘盼
  • 文件丢失?损坏?兼容性问题?到底是什么导致了错误

    在日常的维护中,免不了和文件打交道,文件涉及的问题有很多类,这里讨论: 文件丢失,损坏,兼容性问题。 而对于文件丢失导致的问题一般比较容易定位,而文件损坏,特...

    干点啥吧
  • ldd命令排查文件crash的问题

    ldd用来输出二进制可执行文件或者库文件的依赖;它本是一个script, 并不是binary 文件,其本质上只是设置了环境变量: D_TRACE_LOADED...

    干点啥吧
  • Linker加载so失败问题分析

    原文链接:https://wetest.qq.com/lab/view/421.html

    WeTest质量开放平台团队
  • Activity 基础知识

    类加载方案需要重启App后让ClassLoader重新加载新的类,为什么需要重启,因为类是无法卸载的,要想重新加载类就需要重启App,因此采用类加载方案的热修复...

    Yif

扫码关注云+社区

领取腾讯云代金券