如题,在docker-compose 编排Go应用的时候alphine容器出现可执行文件不存在的问题。

猜测:

一:难道文件在容器中没有执行权限?

针对这个操作,我在command命令中加入了chmod 700
运行结果:not found …

二:由于可执行文件是通过volume映射过去的,莫非哪里出了问题导致容器中不存在该文件?

为了验证上面的想法于是在command命令中加上了ls -l,运行结果显示是存在该文件的。

三:莫非是alphine的问题??

于是我直接将整个alphine镜像换成的golang,运行发现没有再报not fount异常。
这样基本就可以断定是alphine镜像的问题了,但是为什么会这样呢,经过一番搜索引擎操作,发现这样的原因:

Alpine 使用的标准库与大多数发行版不同,它使用的是 musl libc,这个库相比于 glibc 更小、更简单、更安全,但是与大家常用的标准库 glibc 并不兼容。

我们知道正常的golang应用的编译一般上会将大部分的依赖打包进二进制文件,但是某些包是需要依赖系统标准库的,只要代码中有使用到这样类似的包,应用就会去调用系统中对应的库,Golang使用cgo(允许go调用c)机制去实现这样的调取过程。

解决办法

所以在知道原因后我们也就有些解决办法了。

一:不要直接使用alpine:latest镜像,而是使用官方给我们提供的golang:alpine版本(没有解决,照样会报not found异常-2021.6.14更新)
二:使用静态编译,静态编译将不使用动态链接库,所以可以在alpine:latest中使用。
三:增加软连接

mkdir /lib64
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

其实在第三点的时候我们知道musl跟glic是兼容的所以采取增加软连接后就可以使用。那么如何增加软连接呢,难道是在容器创建了之后像第三点一样进入容器手动创建?如果有多个那不是得麻烦死。所以最好的办法是我们使用Dockerfile创建一个符合要求的镜像,然后我们再使用这个二次创建的镜像来开发。如:

//Dockerfile文件
FROM alpine:3.14
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

创建好Dockerfile文件后编译成镜像:

sudo docker build -t my-alpine:v1.0 .

然后在docker-compose中使用

//docker-compose.yml文件
version: "3"

services:
  app:
    image: my-alpine:v1.0
    volumes:
    - /work/testmysql/:/app
    working_dir: /app
    command: ./app
    ports:
    - 5885:5885

这样就以后就可以直接使用这个编译好的镜像了。
当然也可以直接使用我打包好的镜像:

docker pull nelsonjs/glibc-alpine:v1.0
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐