Bei einer Binärdatei, die mit Go unter Verwendung von kompiliert GOOS=linux
und GOARCH=amd64
in einem docker
Container bereitgestellt wurde alpine:3.3
, wird die Binärdatei nicht ausgeführt, wenn der Docker-Engine-Host Ubuntu (15.10) ist:
sh: /bin/artisan: not found
Dieselbe Binärdatei (kompiliert für dasselbe Betriebssystem und denselben Arch) läuft einwandfrei, wenn der Docker-Engine-Host busybox
(der die Basis dafür ist alpine
) in einer VirtualBox-VM unter Mac OS X bereitgestellt wird.
Dieselbe Binärdatei läuft auch einwandfrei, wenn der Container auf einem der Ubuntu-Images basiert.
Irgendeine Idee, was diese Binärdatei fehlt?
Folgendes habe ich getan, um zu reproduzieren (erfolgreiche Ausführung in VirtualBox / Busybox unter OS X nicht gezeigt):
Erstellen (explizit mit Flaggen erstellen, obwohl der Bogen übereinstimmt):
➜ artisan git:(master) ✗ GOOS=linux GOARCH=amd64 go build
Überprüfen Sie, ob es auf dem Host ausgeführt werden kann:
➜ artisan git:(master) ✗ ./artisan
10:14:04.925 [ERROR] artisan: need a command, one of server, provision or build
In Docker-Verzeichnis kopieren, erstellen, ausführen:
➜ 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
Ändern Sie nun die Bildbasis 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
go build -tags netgo -a -v std
mit CGO_ENABLED = 1 versuchen ? Ich denke, es könnten Probleme mit dem Netzpaket sein, die eine dynamische Verknüpfung verursachen.CGO_ENABLED=1 go build -tags netgo -a -v
. Wenn ich im Gegensatz zu CGO_ENABLED = 0 richtig verstehe, bleibt auch die TLS-Funktionalität im Netzpaket erhalten, die sonst verloren gehen würde, stimmt das? Kann ich irgendwie sehen, was statisch mit der Binärdatei verknüpft ist und was für die dynamische Verknüpfung übrig bleibt?ldd output.bin
Wenn Sie das obige Tag verwenden oder CGO_ENABLED = 0 erzwingt, dass die Go-Standard-Implementierung für Suchvorgänge verwendet wird, können Sie Folgendes tun: Bei jeder Build-Variante, um festzustellen, ob sie wirklich statisch kompiliert sind oder wenn es eine dynamische Verknüpfung gibt.Antworten:
Standardmäßig erzeugt
net
ein Build bei Verwendung des Pakets wahrscheinlich eine Binärdatei mit einer dynamischen Verknüpfung, z. B. zu libc. Sie können die Verknüpfung dynamisch oder statisch überprüfen, indem Sie das Ergebnis von anzeigenldd output.bin
Ich bin auf zwei Lösungen gestoßen:
CGO_ENABLED=0
go build -tags netgo -a -v
, dies ist für eine bestimmte Plattform implementiertVon https://golang.org/doc/go1.2 :
Das Obige setzt voraus, dass die einzige CGO-Abhängigkeit das
net
Paket der Standardbibliothek ist .quelle
CGO_ENABLED=0
Außerdem wurde mein Problem behoben: Der Versuch, ein von Alpen erstelltes Go-Programm auf einem nicht-alpinen Docker auszuführen. Der Fehler in meinem Fall sagte geradedocker: Error response from daemon: Container command not found or does not exist..
--features=static --features=pure
Flags erreicht werden.Ich hatte das gleiche Problem mit einer Go-Binärdatei und habe sie zum Laufen gebracht, nachdem ich sie meiner Docker-Datei hinzugefügt habe:
RUN apk add --no-cache \ libc6-compat
quelle
error relocating ...: fprintf chk: symbol not found
Der Go-Compiler von Ihrem Build-Computer aus verknüpft Ihre Binärdatei wahrscheinlich mit Bibliotheken an einem anderen Speicherort als in Alpine. In meinem Fall wurde es mit Abhängigkeiten unter / lib64 kompiliert, aber Alpine verwendet diesen Ordner nicht.
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"]
Ich arbeite an einem Artikel zu diesem Thema. Den Entwurf mit dieser Lösung finden Sie hier http://kefblog.com/2017-07-04/Golang-ang-docker .
quelle
Was für mich der Trick war, war die Aktivierung der statischen Verknüpfung in den Linkeroptionen:
$ go build -ldflags '-linkmode external -w -extldflags "-static"'
Die
-linkmode
Option weist Go an, den externen Linker zu verwenden, die-extldflags
Option legt Optionen fest, die an den Linker übergeben werden sollen, und das-w
Flag deaktiviert DWARF-Debug-Informationen, um die Binärgröße zu verbessern.Siehe
go tool link
und Statisch Go Programme zusammengestellt, immer, auch mit CGO, mit MUSL für weitere Detailsquelle
Beim Ausführen einer Go-Binärdatei in einem Debian-Docker-Container trat dieses Problem auf:
/bin/bash: line 10: /my/go/binary: No such file or directory
Die Binärdatei wurde mithilfe von Docker-in-Docker (dind) aus einem alpinen Container mit dem folgenden Befehl erstellt:
GOOS=linux GOARCH=amd64 go build
Es wurde behoben, indem beim Erstellen der Binärdatei die folgende env verwendet wurde:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
quelle