#docker #go #dockerfile #go-modules
#docker #Вперед #dockerfile #go-модули
Вопрос:
Я пытаюсь ускорить сборки Docker моего приложения Go. Прямо сейчас на создание зависимостей уходит около 60 секунд (это контроллер k8s, так что их много).
Одно очень важное ограничение: мой проект зависит от частных репозиториев GitHub. Я делаю это go mod vendor
снаружи docker build
, где у меня есть учетные записи для настроенных репозиториев.
Мой файл Dockerfile прямо сейчас примерно:
FROM golang:1.12
WORKDIR /src
COPY . .
RUN go build -mod=vendor
...
Даже без необходимости загружать deps, эта сборка занимает некоторое время, потому что она перестраивает несколько сотен пакетов каждый docker build
.
То, что я хотел бы сделать, это что-то вроде:
FROM golang:1.12
WORKDIR /src
# these shouldn't change very often
COPY go.mod go.sum vendor ./
RUN go build -mod=vendor <all dependency packages>
COPY . .
RUN go build -mod=vendor
...
Я пробовал синтаксический анализ go.mod
, но, конечно, в нем перечислены модули, а не пакеты. Я пытался go list
, но так и не смог получить рабочее заклинание.
Комментарии:
1. Взгляните на многоступенчатую сборку из Docker. Другой подход заключается в создании ваших зависимостей в другом контейнере, публикации его и использовании его в качестве базового контейнера для вашего контейнера для создания приложений.
2. @atayenel Я использую многоступенчатые сборки, просто не думаю, что они актуальны?
3. @atayenel И я не уверен, как помогают базовые изображения. Вы хотите сказать, что у меня мог бы быть базовый образ со старой сборкой и, возможно, обновленными зависимостями? Построение этого базового образа имеет ту же проблему
4. Да, но вы не обновляете свои dep слишком часто (ваши слова), вы просто создаете его один раз, и следующие итерации будут использовать его, пока вы снова не обновите свои dep
5. не спускайте глаз с процесса модулирования K8S. Как только это будет сделано, использование локального репозитория модулей (например, Athens или Artifactory) и центрального репозитория модулей (например, GoCenter) волшебно повлияет на время сборки.
Ответ №1:
У меня есть неприятный хак, который, кажется, работает:
FROM golang:1.12
WORKDIR /src
COPY go.mod go.sum ./
COPY vendor/ ./vendor
RUN go build -mod=vendor $(cat deps|grep -v mypackage | grep -v internal)
COPY . .
RUN go build -mod=vendor
...
go list -f '{{join .Deps "n"}}' > deps
docker build .
Комментарии:
1. Возможно, было бы немного проще переопределить
GOCACHE
перед созданием deps таким образом, чтобы они в конечном итоге стали частью вашего контекста сборки Docker, затем скопировать их, а затем соответствующим образом переопределить этот env. var в изображении. Пожалуйста, посмотрите это и перейдите по ссылкам. Обратите внимание, что-x
опция командной строки дляgo {build|install}
команд позволяет им болтать о том, что они делают (и где они ищут файлы и т.д.).2. @kostix это неплохая идея. Хотя я работаю на Mac. Я предполагаю,
GOCACHE
не зависит от платформы?3. Это зависит в том смысле, что местоположение домашнего каталога пользователя. Но обратите внимание, что
go
инструмент имеет встроенное значение по умолчанию для этой переменной (которое можно узнать, выполнивgo env
илиgo env GOCACHE
), и это значение по умолчанию может быть переопределено переменной среды с тем же именем. (На самом деле это работает для любой переменной, известнойgo env
).4. Я имею в виду зависящие от платформы, как в «пакеты, скомпилированные в кэше для darwin, не будут работать в Linux». Конечно, они не переносимы между операционными системами.
5. Я полагаю, что «это не так в любом случае» 😉 Причина в том, что скомпилированные пакеты не просто собраны в общем месте, а скорее разделены там
GOOS
иGOARCH
, под которыми они были созданы. Это означает две вещи: 1) пакеты, скомпилированные изначально в Mac OS, не будут «портить» кеш, установленный в Linux, поскольку компилятор, которому было приказано создавать собственный код там , просто не будет использовать эти кэшированные пакеты; 2) Пакеты, перекрестно скомпилированные в macOS X, могут быть использованы в изображении.
Ответ №2:
В документации Docker есть руководство, специфичное для образов Go docker (Создайте свой образ Go).
Это работает следующим образом:
# Layer for dependency installation
COPY go.mod go.sum ./
RUN go mod download
# Layer for app build
COPY . .
RUN go build -o main .