Go-gecompileerd binair bestand werkt niet in een alpine docker-container op de Ubuntu-host

Gegeven een binair bestand, gecompileerd met Go met behulp van GOOS=linuxen GOARCH=amd64, geïmplementeerd in een docker-container op basis van alpine:3.3, het binaire bestand wordt niet uitgevoerd als de host van de docker-engine Ubuntu (15.10) is:

sh: /bin/artisan: not found

Ditzelfde binaire bestand (gecompileerd voor hetzelfde besturingssysteem en dezelfde boog) zal prima werkenals de host van de docker-engine busyboxis (wat de basis is voor alpine) geïmplementeerd binnen een VirtualBox VM op Mac OS X.

Ditzelfde binaire bestand werkt ook prima als de container is gebaseerd op een van de Ubuntu-afbeeldingen.

Enig idee wat dit binaire bestand mist?

Dit is wat ik heb gedaan om te reproduceren (succesvolle uitvoering in VirtualBox/busybox op OS X niet weergegeven):

Bouw (expliciet bouwen met vlaggen, ook al komt de boog overeen):

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

Controleer of het op de host kan draaien:

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

Kopieer naar docker-map, bouw, voer uit:

➜  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

Verander nu de afbeeldingsbasis in 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 

Antwoord 1, autoriteit 100%

Als u het pakket netgebruikt, zal een build standaard een binair bestand produceren met enige dynamische koppeling, b.v. naar libc. U kunt een dynamische vs. statische link inspecteren door het resultaat van ldd output.bin

te bekijken

Er zijn twee oplossingen die ik ben tegengekomen:

  • CGO uitschakelen, via CGO_ENABLED=0
  • Dwing het gebruik van de Go-implementatie van netafhankelijkheden af, netgo via go build -tags netgo -a -v, dit is geïmplementeerd voor bepaalde platforms

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

Het net-pakket vereist standaard cgo omdat het hostbesturingssysteem in het algemeen moet bemiddelen bij het instellen van netwerkoproepen. Op sommige systemen is het echter mogelijk om het netwerk zonder cgo te gebruiken, en handig om bijvoorbeeld dynamisch linken te vermijden. De nieuwe build-tag netgo (standaard uitgeschakeld) maakt de constructie van een netpakket in pure Go mogelijk op die systemen waar dit mogelijk is.

Bij het bovenstaande wordt ervan uitgegaan dat de enige afhankelijkheid van de CGO het net-pakket van de standaardbibliotheek is.


Antwoord 2, autoriteit 84%

Ik had hetzelfde probleem met een go binary, en ik kreeg het werkend nadat ik dit aan mijn docker-bestand had toegevoegd:

RUN apk add --no-cache libc6-compat 

Antwoord 3, autoriteit 8%

Go-compiler vanaf uw bouwmachine koppelt waarschijnlijk uw binaire bestand met bibliotheken op een andere locatie dan in Alpine. In mijn geval was het gecompileerd met afhankelijkheden onder /lib64 maar Alpine gebruikt die map niet.

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

Ik werk aan een artikel over dit probleem. U kunt een concept met deze oplossing hier vinden http://kefblog.com/2017-07 -04/Golang-ang-docker.


Antwoord 4, autoriteit 6%

Wat de truc voor mij was, was het inschakelen van statische koppeling in de linkeropties:

$ go build -ldflags '-linkmode external -w -extldflags "-static"'

De optie -linkmodevertelt Go om de externe linker te gebruiken, de optie -extldflagsstelt opties in om door te geven aan de linker en de -wvlag schakelt DWARF-foutopsporingsinformatie uit om de binaire grootte te verbeteren.

Zie go tool linken Statisch gecompileerde Go-programma’s, altijd, zelfs met cgo, met musl
voor meer details


Antwoord 5, autoriteit 3%

Ik had een app waarvoor CGO_ENABLED=1nodig was.

De oplossing voor mij om de gecompileerde go binary uit te voeren in een debian-slim container was om de binary te bouwen met behulp van RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o goapp

En voer de volgende commando’s uit in debian slim

RUN apt-get update && apt-get install -y musl-dev
RUN ln -s /usr/lib/x86_64-linux-musl/libc.so /lib/libc.musl-x86_64.so.1

Heeft me in staat gesteld om de goapp achteraf uit te voeren

TIP: ldd goapptoonde aan dat libc.musl-x86_64 ontbrak in de container.


Antwoord 6

Tijdens het uitvoeren van een go binary in een debian docker-container, kreeg ik dit probleem:
/bin/bash: line 10: /my/go/binary: No such file or directory

Het binaire bestand is gebouwd met behulp van docker-in-docker (dind) vanuit een alpine container met het commando:
GOOS=linux GOARCH=amd64 go build

Opgelost door de volgende env te gebruiken tijdens het bouwen van het binaire bestand:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build

Other episodes