Skip to content

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), которые должны быть доступны в среде, где программа выполняется, но не включены в сам исполняемый файл.