Я работаю над проектом Go, который докеризован. Он находится внутри каталога src
на моей GOPATH. Проект имеет следующую структуру:
project/
Dockerfile
go.mod
cmd/
cmd_pkg1/
main.go
go.mod
cmd_pkg2/
main.go
go.mod
internal/
int_pkg1/
source.go
int_pkg2/
source.go
pkg/
pkg1/
source.go
pkg2/
source.go
project
- это не настоящее имя, а имена файлов упрощены (существует несколько файлов, вложенных каталогов, ...). main.go
указывает, что эти пакеты называются main
(исполняемые файлы), а файлы source.go
указывают, что они имеют имя, равное его каталогу (библиотекам). Файл project/go.mod
содержит зависимости проекта, в то время как project/cmd/cmd_pkgX/go.mod
содержит определенные зависимости пакета плюс директивы require project v0.0.0
и replace project => ../../
.
Упрощенная версия файла Docker выглядит следующим образом:
ARG goversion=1.12.3
ARG goos
ARG goarch
ARG goarm=6
ARG cmd
FROM golang:${goversion}-stretch AS build-env
ENV CGO_ENABLED=0
ENV GO111MODULE=on
ENV GOOS=${goos}
ENV GOARCH=${goarch}
ENV GOARM=${goarm}
ENV COMMAND=${cmd}
ADD . /src/project
WORKDIR /src/project/cmd/cmd_pkg1
RUN go build -i -o /bin/app .
FROM scratch
COPY --from=build-env /bin/app /
ENTRYPOINT ["/app"]
Как видите, я объявляю некоторые аргументы, которые позволяют мне настраивать разные версии Go и выполнять кросс-компиляцию для любой поддерживаемой цели. Это многошаговый процесс. Первый шаг начинается с образа Go для конкретной версии, отключает cgo
, включает модули для go 1.11 и 1.12 и передает аргументы как переменные среды. Затем он добавляет всю структуру проекта к /src/
, устанавливает рабочий каталог и компилирует код. На втором этапе просто перетаскиваем исполняемый двоичный файл в чистое изображение и определяем его как точку входа.
Теперь я пытаюсь поделиться этим Dockerfile среди всех исполняемых пакетов (cmd/cmd_pkg1
, cmd/cmd_pkg2
, .. .) и для этого я пытался установить новый ARG cmd
с именем исполняемого пакета (cmd_pkg1
, cmd_pkg2
, ...) и как-то передать его команде WORKDIR
.
Я пробовал несколько вариантов для WORKDIR
, и ни один из них не работает:
/src/package/cmd/${cmd}
/src/package/cmd/$COMMAND
"/src/package/cmd/$COMMAND"
Все они выдают следующую ошибку:
can't load package: package package/cmd: unknown import path "package/cmd": cannot find module providing package package/cmd
Кажется, он не распознает cmd_pkg1
dir ни в одной из предоставленных опций.
Я хочу сохранить Dockerfile там, где он есть, чтобы избежать дублирования Dockerfile и наличия единой точки входа для CI и так далее. Я также предпочел бы избегать автоматической генерации Dockerfile для каждого проекта из шаблона.
Есть идеи? Я совсем новичок в модулях go и не так много играл с go build, поскольку до сих пор он работал из коробки для всех моих проектов.