web-dev-qa-db-fra.com

Le binaire compilé par Go ne fonctionnera pas dans un conteneur Docker Alpine sur l'hôte Ubuntu

Étant donné un binaire, compilé avec Go en utilisant GOOS=linux et GOARCH=AMD64, déployé dans un conteneur docker basé sur Alpine:3.3, le binaire ne fonctionnera pas si l'hôte du moteur docker est Ubuntu (15.10):

sh: /bin/artisan: not found

Ce même binaire (compilé pour le même OS et Arch) fonctionnera très bien si l'hôte du moteur docker est busybox (qui est le base pour Alpine) déployée dans une VirtualBox VM sur Mac OS X.

Ce même binaire fonctionnera également parfaitement si le conteneur est basé sur l'une des images Ubuntu.

Une idée de ce qui manque à ce binaire?

Voici ce que j'ai fait pour reproduire (exécution réussie dans VirtualBox/busybox sur OS X non illustré):

Build (construction explicite avec des drapeaux même si l'Arch correspond):

➜  artisan git:(master) ✗ GOOS=linux GOARCH=AMD64 go build

Vérifiez qu'il peut fonctionner sur l'hôte:

➜  artisan git:(master) ✗ ./artisan 
10:14:04.925 [ERROR] artisan: need a command, one of server, provision or build 

Copier dans le répertoire docker, construire, exécuter:

➜  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

Modification de la base de l'image en 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 
49
Oleg Sklyar

Par défaut, si vous utilisez le package net, une génération produira probablement un binaire avec une liaison dynamique, par exemple à libc. Vous pouvez inspecter dynamiquement ou statiquement le lien en affichant le résultat de ldd output.bin

Il y a deux solutions que j'ai rencontrées:

  • Désactivez CGO, via CGO_ENABLED=0
  • Forcer l'utilisation de l'implémentation Go des dépendances réseau, netgo via go build -tags netgo -a -v, ceci est implémenté pour certaines plateformes

De https://golang.org/doc/go1.2 :

Le package net nécessite cgo par défaut car le système d'exploitation hôte doit en général arbitrer la configuration des appels réseau. Sur certains systèmes, cependant, il est possible d'utiliser le réseau sans cgo, et utile de le faire, par exemple pour éviter la liaison dynamique. La nouvelle balise de construction netgo (désactivée par défaut) permet la construction d'un package net en pure Go sur les systèmes où cela est possible.

Ce qui précède suppose que la seule dépendance CGO est le package net de la bibliothèque standard.

57
Martin Gallagher

J'ai eu le même problème avec un binaire go, et je l'ai fait fonctionner après avoir ajouté cela à mon fichier docker:

RUN apk add --no-cache \ libc6-compat

40
zakaria amine

Le compilateur Go de votre machine de génération relie probablement votre binaire à des bibliothèques situées à des emplacements différents de ceux d'Alpine. Dans mon cas, il a été compilé avec des dépendances sous/lib64 mais Alpine n'utilise pas ce dossier.

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"]

Je travaille sur un article sur ce problème. Vous pouvez trouver un brouillon avec cette solution ici http://kefblog.com/2017-07-04/Golang-ang-docker .

8
Norbert Szydlik