Подтвердить что ты не робот

Скомпилированный двоичный код не будет запускаться в контейнере с альпийским докером на хосте Ubuntu

Учитывая двоичный код, скомпилированный с помощью Go с использованием GOOS=linux и GOARCH=amd64, развернутый в контейнер docker на основе alpine:3.3, двоичный файл не будет запущен, если хост-сервер докеры - Ubuntu (15.10):

sh: /bin/artisan: not found

Этот же двоичный файл (скомпилированный для той же ОС и арки) будет работать просто отлично, если хост хоста docker busybox (который является базой для alpine), развернутый в виртуальной виртуальной машине VM на Mac OS X.

Этот же двоичный файл также будет работать отлично, если контейнер основан на одном из изображений Ubuntu.

Любая идея, что этот бинарный файл отсутствует?

Это то, что я сделал для воспроизведения (успешный запуск в VirtualBox/busybox в OS X не показан):

Сборка (создание явно с флагами, даже если совпадение арки):

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

Проверьте, может ли он выполняться на хосте:

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

Скопировать в docker dock, выполнить, запустить:

➜  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

Теперь изменим базу изображений на 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 
4b9b3361

Ответ 1

По умолчанию при использовании пакета net сборка, скорее всего, создаст двоичный файл с некоторым динамическим связыванием, например. к libc. Вы можете проверить динамически и статически ссылку, просмотрев результат ldd output.bin

Есть два решения, с которыми я столкнулся:

  • Отключить CGO через CGO_ENABLED=0
  • Принудительно использовать реализацию Go для сетевых зависимостей, netgo через go build -tags netgo -a -v, это реализовано для определенных платформ.

Из https://golang.org/doc/go1.2:

В сетевом пакете по умолчанию требуется cgo, поскольку операционная система хоста должна в общем случае оповестить о настройке сетевого вызова. Однако в некоторых системах можно использовать сеть без cgo и полезно для этого, например, чтобы избежать динамической компоновки. Новый тег сборки netgo (по умолчанию отключен) позволяет построить чистый пакет в чистом виде Go на тех системах, где это возможно.

Вышеизложенное предполагает, что единственная зависимость CGO - это стандартный пакет библиотеки net.

Ответ 2

У меня возникла та же проблема с бинарным файлом go, и я добавил его в работу после добавления этого в файл Docker:

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

Ответ 3

Go компилятор с вашего компьютера сборки, вероятно, связывает ваш бинарный файл с библиотеками в другом месте, чем в Alpine. В моем случае он был скомпилирован с зависимостями в /lib64, но Alpine не использует эту папку.

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

Я работаю над статьей об этой проблеме. Вы можете найти черновик с этим решением здесь http://kefblog.com/2017-07-04/Golang-ang-docker.

Ответ 4

Для меня главное - включить статические ссылки в настройках компоновщика:

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

Параметр -linkmode указывает Go использовать внешний компоновщик, параметр -extldflags устанавливает параметры для передачи компоновщику, а флаг -w отключает информацию отладки DWARF для улучшения двоичного размера.

Смотрите go tool link и статически скомпилированные программы Go, всегда, даже с cgo, используя musl для более подробной информации