instalar - El binario compilado de Go no se ejecutará en un contenedor de ventana acoplable alpino en el host de Ubuntu
gcc linux (3)
De forma predeterminada, si utiliza el paquete de net
, es probable que una compilación produzca un binario con algún enlace dinámico, por ejemplo, a libc. Puede inspeccionar el enlace dinámico vs. estático viendo el resultado de ldd output.bin
Hay dos soluciones que he encontrado:
- Deshabilitar CGO, a través de
CGO_ENABLED=0
- Forzar el uso de la implementación de Go de las dependencias de red, netgo a través de
go build -tags netgo -a -v
, esto se implementa para ciertas plataformas
De https://golang.org/doc/go1.2 :
El paquete net requiere cgo de forma predeterminada porque el sistema operativo del host debe mediar en general en la configuración de llamadas de red. En algunos sistemas, sin embargo, es posible usar la red sin cgo, y es útil hacerlo, por ejemplo, para evitar la vinculación dinámica. La nueva etiqueta de compilación netgo (desactivada de forma predeterminada) permite la construcción de un paquete de red en Go puro en aquellos sistemas donde sea posible.
Lo anterior supone que la única dependencia de CGO es el paquete net
la biblioteca estándar.
Dado un binario, compilado con Go usando GOOS=linux
y GOARCH=amd64
, implementado en un contenedor docker
basado en alpine:3.3
, el binario no se ejecutará si el host del motor del docker es Ubuntu (15.10):
sh: /bin/artisan: not found
Este mismo binario (compilado para el mismo sistema operativo y arco) se ejecutará bien si el host del motor de docker es busybox
(que es la base para alpine
) implementado dentro de una VM VirtualBox en Mac OS X.
Este mismo binario también funcionará perfectamente si el contenedor está basado en una de las imágenes de Ubuntu.
¿Alguna idea de lo que falta este binario?
Esto es lo que he hecho para reproducir (ejecución exitosa en VirtualBox / busybox en OS X no se muestra):
Construir (construir explícitamente con banderas aunque el arco coincida):
➜ artisan git:(master) ✗ GOOS=linux GOARCH=amd64 go build
Compruebe que se puede ejecutar en el host:
➜ artisan git:(master) ✗ ./artisan
10:14:04.925 [ERROR] artisan: need a command, one of server, provision or build
Copiar a la ventana acoplable dir, construir, ejecutar:
➜ artisan git:(master) ✗ cp artisan docker/build/bin/
➜ artisan git:(master) ✗ cd docker
➜ docker git:(master) ✗ cat Dockerfile
FROM docker:1.10
COPY build/ /
➜ docker git:(master) ✗ docker build -t artisan .
Sending build context to Docker daemon 10.15 MB
Step 1 : FROM docker:1.10
...
➜ docker git:(master) ✗ docker run -it artisan sh
/ # /bin/artisan
sh: /bin/artisan: not found
Ahora cambiando la base de la imagen a phusion/baseimage
:
➜ docker git:(master) ✗ cat Dockerfile
#FROM docker:1.10
FROM phusion/baseimage
COPY build/ /
➜ docker git:(master) ✗ docker build -t artisan .
Sending build context to Docker daemon 10.15 MB
Step 1 : FROM phusion/baseimage
...
➜ docker git:(master) ✗ docker run -it artisan sh
# /bin/artisan
08:16:39.424 [ERROR] artisan: need a command, one of server, provision or build
El compilador Go de su máquina de compilación probablemente vincula su binario con bibliotecas en una ubicación diferente a la de Alpine. En mi caso, fue compilado con dependencias bajo / lib64 pero Alpine no usa esa carpeta.
FROM alpine:edge AS build
RUN apk update
RUN apk upgrade
RUN apk add --update go=1.8.3-r0 gcc=6.3.0-r4 g++=6.3.0-r4
WORKDIR /app
ENV GOPATH /app
ADD src /app/src
RUN go get server # server is name of our application
RUN CGO_ENABLED=1 GOOS=linux go install -a server
FROM alpine:edge
WORKDIR /app
RUN cd /app
COPY --from=build /app/bin/server /app/bin/server
CMD ["bin/server"]
Estoy trabajando en un artículo sobre este tema. Puede encontrar el borrador con esta solución aquí http://kefblog.com/2017-07-04/Golang-ang-docker .
Tuve el mismo problema con un binario go, y lo hice funcionar después de agregar esto a mi archivo docker:
RUN apk add --no-cache / libc6-compat