Gegeven een binair bestand, gecompileerd met Go met behulp van GOOS=linux
en 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 busybox
is (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 net
gebruikt, 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 -linkmode
vertelt Go om de externe linker te gebruiken, de optie -extldflags
stelt opties in om door te geven aan de linker en de -w
vlag schakelt DWARF-foutopsporingsinformatie uit om de binaire grootte te verbeteren.
Zie go tool link
en 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=1
nodig 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 goapp
toonde 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