Минимально возможный Docker образ для GO

29.06.2020 docker компиляция upx ldflags


Минимально возможный Docker образ для GO

Docker поддерживает все семейства ОС — Linux, Unix, Windows, MacOS. Также он реализует контейнеризацию на уровне ОС, что означает незначительные накладные расходы на запуск контейнера.

Docker — один из самых популярных систем контейнеров. Поддерживается многими популярными хостингами, такими как Microsoft Azure, Amazon, Digital Ocean.

Сборка образа и Dockerfile

Создание docker-образа выполняется с помощью команды docker build при наличии файла Dockerfile.

FROM rhaps1071/golang-1.14-alpine-git AS build
WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags "-s -w -extldflags '-static'" -o ./app
RUN apk add upx
RUN upx ./app

FROM scratch
COPY --from=build /build/app /app

ENTRYPOINT ["/app"]

Благодаря использованию модулей GO, при компиляции проекта нам нет необходимости перемещать исходники в какую-либо специфическую папку, а также нет необходимости скачивать зависимости — GO делает это сам при выполнении go build.

Двухэтапная сборка

Образ будет передаваться по сети, его размер должен быть как можно меньше, иначе сборка и деплой будут занимать больше времени.
Поэтому, в данном Dockerfile мы проводим сборку бинарного файла в одном окружении — rhaps1071/golang-1.14-alpine-git, а итоговый образ выдаем в виде scratch с добавлением нашего файла.

Для сборки GO программы нам необходим достаточно весомый образ (c исходными кодами самого GO, множеством утилит). Однако все это не нужно нам в продакшне. Для продакшна нам необходим только бинарный файл программы.
scratch — встроенный docker-образ нулевого размера. Таким образом размер итогового образа будет равен размеру бинарного файла, что составляет несколько мегабайт.

Размер бинаного файла

Мы можем влиять на размер двумя путями:

  • флаги сборки (ldflags);
  • компрессия бинарного файла после сборки;

Флаги -s -w убирают отладочную информацию. В моем случае с ними файл уменьшился с 15MB до 11MB.

Использование upx уменьшило файл с 11MB до 4.1MB.

Флаги -extldflags '-static' использованы для статической линковки бинарного файла. Результатом стандартной динамической линковки является бинарный файл, требующий наличия в системе внешних библиотек (файлы .so в Linux).
Зависимость бинарного файла в Linux от внешних библиотек можно посмотреть командой ldd.
В scratch, alpine у нас не будут установлены внешние библиотеки, так как это очень минималистичные образы. В этом случае мы пользуемся статической линковкой — все внешние библиотеки будут скомпилированы внутрь нашего бинарного файла.

Исходные файлы доступны в репозитории Github.

Другие статьи