33 Docker образ scratch Статическая и динамическая
33 Docker образ scratch Статическая и динамическая компиляция¶
Идея образа scratch в том, что можно скопировать в него любые зависимости с машины-хоста и либо использовать их внутри Dockerfile (это как скопировать их в apt
и установить с нуля), либо позднее, когда образ Docker материализован. Это позволяет полностью контролировать содержимое контейнера Docker, и, таким образом, полностью же контролировать размер образа.
Благодаря минимальному набору зависимостей, безопасность докер образа увеличивается, а размер уменьшается.
FROM scratch
ADD alpine-minirootfs-3.13.5-x86_64.tar.gz /
CMD ["/bin/sh"]
Здесь alpine-minirootfs-3.13.5-x86_64.tar.gz
Внутри докер файлов можно можно взаимодействовать с несколькими образоми, часто это применяется для 2-step build методики, когда образ компилирует код, а файлы запуска копирует в финальный образ.
# Этап сборки
FROM golang:1.18 AS build
# Устанавливаем рабочий каталог внутри контейнера
WORKDIR /app
# Копируем модульные файлы Go и загружаем зависимости
COPY go.mod .
COPY go.sum .
RUN go mod download
# Копируем исходный код
COPY . .
# Компилируем статически связанный исполняемый файл
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# Финальный минимальный образ
FROM scratch
COPY --from=build /app/main /main
# Устанавливаем команду запуска по умолчанию
CMD ["/main"]
Статическая и динамическая компиляция¶
Статическая компиляция¶
При статической компиляции все необходимые библиотеки включаются непосредственно в исполняемый файл. Программа становится независимой от библиотек, установленных в системе, что делает её легко переносимой.
Преимущества:¶
Отсутствие зависимостей Переносимость Меньший размер образа Docker - поскольку все библиотеки включены в исполняемый файл, контейнер может базироваться на более легковесных образах (например, alpine
или scratch
).
Недостатки:¶
Больший размер исполняемого файла: Поскольку все библиотеки включены, размер исполняемого файла может быть значительно больше. Отсутствие обновлений безопасности: В случае обнаружения уязвимостей в зависимости, необходимо перекомпилировать всю программу, чтобы применить исправления.
Код сверху можно привести в качестве примера статической компиляции
Динамическая компиляция¶
При динамической компиляции исполняемый файл ссылается на внешние библиотеки, которые должны быть установлены в системе выполнения.
Преимущества:¶
Меньший размер исполняемого файла Использование общих библиотек
Недостатки:¶
Зависимости: Необходимы все библиотеки, с которыми связана программа, иначе программа не будет работать Большее количество слоёв в Docker образе: Поскольку требуемые библиотеки должны быть включены в образ Docker.
В качестве примера можно привести программу на С
# Используем базовый образ с GCC для компиляции приложения
FROM gcc:latest as build-stage
# Установка библиотеки OpenSSL для сборки
RUN apt-get update && apt-get install -y libssl-dev
# Копирование исходного кода приложения
COPY app.c /src/app.c
WORKDIR /src
# Компиляция приложения и связывание с libssl
RUN gcc app.c -o app -lssl -lcrypto
# Используем новый чистый образ для запуска приложения
FROM debian:latest
# Установка библиотек libssl и libcrypto для динамической компиляции во время выполнения
RUN apt-get update && apt-get install -y libssl1.1 libcrypto++6
# Копирование исполняемого файла из стадии сборки
COPY --from=build-stage /src/app /app
# Запуск приложения
CMD ["/app"]
Когда мы говорим о "динамической компиляции" в контексте библиотек, мы имеем в виду, что программа будет использовать динамически подключаемые библиотеки (dynamic libraries или shared libraries), которые должны быть доступны в среде, где программа выполняется, но не включены в сам исполняемый файл.