Инструкции сборки образа из Dockerfile

Dockerfile — это текстовый документ без расширения с фиксированным названием. В нем записана последовательность инструкций, которые Docker использует для сборки образа.

Образ (Image) — это неизменяемый (read-only) шаблон, содержащий исходный код приложения, библиотеки, зависимости, инструменты и другие файлы, необходимые для запуска приложения в изолированной среде (контейнере).

Сборка образа начинается с базового (родительского) образа, который указывается с помощью инструкции FROM. Этот образ обычно загружается из публичного реестра (например, Docker Hub) или из локального хранилища, если он уже был скачан или собран ранее. Docker считывает инструкции сверху вниз, и каждая успешная команда создает новый слой, который кэшируется для ускорения последующих сборок.

Инструкции сборки образа

Инструкции представляют собой человекочитаемые команды с определенными параметрами выполнения. Их можно условно разделить на несколько категорий:

Ниже представлены инструкции Dockerfile с разбором их синтаксиса, подробным описанием параметров исполнения и примерами.

FROM — выбор родительского образа для сборки

Инструкция FROM задает базовый (родительский) образ для последующих инструкций. В Dockerfile инструкция FROM должна быть первой. Исключение — использование предшествующей инструкции ARG, которая может использоваться для передачи аргументов в FROM.

Базовый или родительский образ — это образ любой Linux ОС, содержащий rootfs (структуру файловой системы Linux), на базе которой будет собираться новый образ. При этом все утилиты и библиотеки базового образа будут доступны в новом образе, а ядро будет использовано с хоста (ОС, на которой запускаются контейнеры).

Синтаксис инструкции FROM:

FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

Параметры инструкции FROM:

Примеры использования инструкции FROM:

  1. FROM node:18-alpine AS builder — использовать образ Node.js 18 на базе Alpine Linux и присвоить этой стадии имя builder
  2. ARG VERSION=latest перед FROM alpine:$VERSION — объявить переменную VERSION (по умолчанию latest) и использовать её для задания тега базового образа
  3. FROM --platform=linux/amd64 python:3.9 — использовать образ Python 3.9, принудительно указав архитектуру linux/amd64 (например, при сборке на Mac M1 для сервера Linux)

ARG — установка переменной сборки образа

Инструкция ARG задаёт переменные, которые используются при сборке образа. Можно задать пустую переменную и присвоить ей значение при сборке командой docker build --build-arg VAR_NAME=value, либо указать значение по умолчанию прямо в Dockerfile. Переменные, заданные с помощью ARG, доступны только во время сборки образа и не сохраняются в финальном контейнере.

Синтаксис инструкции ARG: ARG [=].

Переменные, объявленные через ARG, подставляются в другие инструкции с помощью конструкции ${VAR_NAME} или $VAR_NAME. Разберем три примера использования инструкции ARG.

1. Использование в FROM (версионирование образа):

ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine
# Чтобы использовать переменную дальше, объявляем её снова
ARG NODE_VERSION
RUN echo "Building with Node version $NODE_VERSION"

2. Передача параметров сборки:

FROM ubuntu:22.04
ARG APP_DIR
WORKDIR $APP_DIR
COPY . .

Сборка: docker build --build-arg APP_DIR=/var/www.

3. Условная логика (в сочетании с shell):

FROM alpine
ARG ENVIRONMENT=production
RUN if [ "$ENVIRONMENT" = "development" ]; then \
   apk add --no-cache vim; \
 fi

ENV — установка переменной окружения внутри образа

Инструкция ENV задаёт переменные окружения внутри образа. Значения, объявленные через ENV, доступны во всех последующих инструкциях текущей стадии сборки и автоматически сохраняются в финальном образе и контейнере.

Синтаксис инструкции ENV: ENV = [= ...].

Заданные через ENV переменные можно использовать в других инструкциях Dockerfile через $VAR или ${VAR}:

FROM busybox
ENV APP_DIR=/app
WORKDIR ${APP_DIR}
ADD . $APP_DIR

WORKDIR — установить рабочую директорию

Инструкция WORKDIR задаёт рабочую директорию внутри собираемого образа для последующих инструкций COPY, ADD, RUN, CMD и ENTRYPOINT. Если указанная директория не существует — она будет создана. В одном Dockerfile можно использовать несколько инструкций WORKDIR: если путь относительный, он задаётся относительно предыдущей рабочей директории, а если путь абсолютный (начинается с /), рабочая директория просто меняется на указанный путь.

Синтаксис инструкции WORKDIR: WORKDIR /path/to/workdir. WORKDIR можно сочетать с ENV и использовать переменные окружения в пути.

Пример использования инструкции WORKDIR с переменными окружения:

ENV DIRPATH=/path
ENV DIRNAME=subdir
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

RUN — выполнение команды при сборке

Инструкция RUN выполняет команду внутри временного контейнера и сохраняет результат в новый слой образа. Чаще всего RUN используют для установки пакетов, настройки системы и подготовки окружения приложения. Чтобы уменьшить количество слоёв и эффективнее использовать кэш, связанные команды часто объединяют в одну инструкцию RUN с помощью && или here-doc. Поэтому в официальных образах иногда встречаются очень длинные и «многострочные» RUN.

Есть распространённый приём для сложной логики: команду выносят в отдельный shell-скрипт, копируют его в образ, запускают через RUN, а затем удаляют сам скрипт. Например:

COPY install.sh /install.sh
RUN /install.sh && rm /install.sh

У инструкции RUN есть две основные формы синтаксиса:

Shell-форма удобнее для сложных команд, пайпов и &&, а exec-форма даёт более предсказуемое поведение без дополнительных преобразований со стороны оболочки.

Вот несколько примеров использования RUN.

1. Установка системных пакетов в shell-форме:

FROM ubuntu:22.04
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curlㅤca-certificates && \
    rm -rf /var/lib/apt/lists/*

2. Exec-форма для простой команды:

FROM alpine:3.19
RUN [⠀"sh",⠀"-c",⠀"echo⠀Hello⠀from⠀build⠀stage"⠀]

3. Использование ENV и ARG внутри RUN:

FROM node:20-alpine
ARG APP_DIR=/usr/src/app
ENV NODE_ENV=production

WORKDIR $APP_DIR
COPY package*.json ./

RUN npm ci --only=production && \
⠀⠀echo "Environment: $NODE_ENV" && \
⠀⠀ls -la

CMD — выполнение команды при запуске контейнера

Инструкция CMD задаёт команду или аргументы по умолчанию, которые будут выполнены при запуске контейнера из образа. В Dockerfile может быть только одна эффективная инструкция CMD — если их несколько, используется только последняя. CMD не выполняется на этапе сборки образа и не создаёт слой. CMD определяет, что должно происходить при запуске контейнера, если пользователь не передаст свою команду.

Инструкция CMD поддерживает две основные формы записи, аналогичные RUN и ENTRYPOINT:

Кроме того, есть специальная exec-форма без указания исполняемого файла:CMD ["param1", "param2"]. В этом случае CMD задаёт аргументы по умолчанию для инструкции ENTRYPOINT и используется только вместе с ней.

Примеры использования CMD:

1. Простая команда по умолчанию (shell-форма):

FROM python:3.12-slim
WORKDIR /app
COPY app.py .

CMD python app.py

При запуске контейнера выполнится python app.py, но пользователь может переопределить команду: docker run image python other.py.

2. Рекомендуемая exec-форма:

FROM node:20-alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

CMD ["node", "server.js"]

Exec-форма надёжнее: аргументы не проходят через оболочку и обрабатываются без дополнительных преобразований.

3. ENTRYPOINT + CMD как аргументы по умолчанию:

FROM alpine:3.19
RUN apk add --no-cache curl

ENTRYPOINT ["curl"]
CMD ["https://example.com"]

Здесь ENTRYPOINT фиксирует основной исполняемый файл (curl), а CMD задаёт URL по умолчанию. Запуск docker run image выполнит curl https://example.com, а docker run image https://oblako.kz переопределит только аргументы и выполнит curl https://oblako.kz.

Важно! В одном Dockerfile может быть только одна «рабочая» инструкция CMD (последняя по порядку). Формально другие инструкции могут идти после CMD, но по смыслу CMD обычно располагают в конце, чтобы было очевидно, что именно запускается по умолчанию.

ENTRYPOINT — запуск исполняемого файла образа

Инструкция ENTRYPOINT задаёт «главный» исполняемый файл контейнера — то, что всегда будет запускаться при docker run image, даже если пользователь передаст свои аргументы. Чаще всего через ENTRYPOINT описывают сервис или утилиту, которую этот образ представляет, например: nginx, postgres, python ваш_скрипт.

У ENTRYPOINT две формы, как и у CMD и RUN:

В большинстве случаев для приложений и сервисов используют exec-форму, чтобы исполняемый файл был PID 1 и корректно получал сигналы (SIGTERM при docker stop).

Тут может возникнуть путаница в области применения RUN, CMD и ENTRYPOINT, поэтому кратко опишем инструкции и их назначение:

Примеры использования ENTRYPOINT:

1. Сервис как основной процесс (exec-форма):

FROM nginx:1.27-alpine
# В базовом образе уже есть правильный ENTRYPOINT,
# но если бы мы писали свой образ nginx:
ENTRYPOINT ["nginx", "-g", "daemon off;"]

Такой образ всегда запускает nginx на переднем плане. В docker run можно добавлять флаги nginx, которые просто дополнят команду.

2. Команда + аргументы по умолчанию (ENTRYPOINT + CMD):

FROM⠀alpine:3.19
RUN⠀apk⠀add⠀--no-cache⠀curl
ENTRYPOINT⠀["curl"]
CMD⠀["https://example.com"]
  • docker⠀run⠀image⠀→⠀curl⠀https://example.com
  • docker⠀run⠀image⠀https://1cloud.ru⠀-I⠀→⠀curl⠀https://1cloud.ru -I

3. Образ-утилита (контейнер как «команда»):

FROM python:3.12-slim
WORKDIR /app
COPY cli.py .

ENTRYPOINT ["python", "cli.py"]
CMD ["--help"]

Важно! ENTRYPOINT задаётся до инструкции CMD, если они используются вместе: сначала фиксируем основной исполняемый файл, затем задаём для него аргументы по умолчанию через CMD.

COPY — копирование файлов и директорий в образ из локального хранилища

Инструкция COPY копирует файлы и директории из контекста сборки (обычно это директория, откуда запускается docker build) внутрь образа. Обычно через COPY добавляют исходный код приложения, конфигурации, скрипты и другие необходимые файлы.

Синтаксис инструкции COPY:

Параметры инструкции COPY:

Примеры использования инструкции COPY:

1. Копировать всё приложение в /app:

FROM⠀python:3.12-slim
WORKDIR⠀/app

COPY⠀.⠀/app

2. Копировать только необходимые файлы:

FROM⠀node:20-alpine
WORKDIR /usr/src/app

COPY⠀package*.json⠀./
RUN npm ci --only=production

COPY⠀src/⠀./src/

Здесь сначала копируются только package*.json для установки зависимостей, а уже потом — исходный код. Так кэш слоёв будет использоваться эффективнее.

3. Копирование нескольких файлов в директорию (JSON-форма):

FROM⠀alpine:3.19
WORKDIR /app

COPY⠀["script.sh",⠀"config.yml",⠀"/app/"]

По умолчанию COPY не меняет права доступа на файлы — они сохраняются такими, как в контексте сборки. При необходимости можно задать пользователя или группу и изменить права доступа с помощью флагов:

Флаги⠀можно⠀комбинировать:

COPY⠀--chown=myuser:mygroup⠀--chmod=644files*⠀/somedir/

ADD — расширенная версия COPY

Инструкция ADD работает подобно COPY, но имеет дополнительные возможности. Она умеет автоматически распаковывать локальные архивы tar (ADD archive.tar.gz /usr/src/things/) и копировать файлы и директории из контекста сборки, как и COPY (ADD . /app).

Синтаксис инструкции ADD такой же, как COPY

Важно! В современных Dockerfile обычно рекомендуют по возможности использовать COPY, а ADD — только когда нужна автоматическая распаковка tar‑архива. Загрузка файлов по URL или клонирование Git‑репозиториев через ADD считается устаревшей практикой: такие операции лучше выполнять заранее (скриптом или на этапе CI) и копировать готовые файлы через COPY.

EXPOSE — документирование портов

Инструкция EXPOSE сообщает Docker, какие сетевые порты контейнер слушает во время работы. Она не публикует порты наружу сама по себе, а лишь служит подсказкой. EXPOSE не прокидывает никаких портов за пределы контейнера — это только документация.

Синтаксис инструкции EXPOSE: EXPOSE <port>  [<port>/<protocol>...].

По умолчанию используется протокол TCP. Если нужно явно указать протокол, используется форма <port>/<protocol>, например EXPOSE 80/udp - порт 80/UDP.

Чтобы связать внешний порт на хосте с задекларированным внутренним портом контейнера, их нужно явно смаппить командой docker run -p host_port:container_port. Также можно воспользоваться автоматическим назначением случайных внешних портов и автомаппингом: docker run -P. Если запустить контейнер без ключей -p или -P, то порт не будет доступен снаружи контейнера.

Например, Dockerfile веб-сервера может выглядеть так:

FROM nginx:alpine
EXPOSE 80

Тогда при запуске контейнера командой docker run nginx-image контейнер будет слушать 80‑й порт внутри себя, но он не будет доступен снаружи хоста. Чтобы порт контейнера был доступен снаружи, его нужно явно смаппить с внешним портом командой docker run -p 8080:80 nginx-image — порт 80 в контейнере будет доступен на хосте по адресу http://localhost:8080.

LABEL — добавление метаданных к образу

Инструкция LABEL добавляет к образу произвольные метаданные в формате «ключ–значение». Это современный и рекомендуемый способ указания автора и других сведений об образе вместо устаревшей инструкции MAINTAINER.

Лейблы можно использовать для описания версии, автора, контактной информации, ссылки на репозиторий, окружения деплоя, принадлежности к команде и т.п. Лейблы не влияют на запуск контейнера напрямую, но широко применяются для автоматизации: фильтрации образов и контейнеров, политики деплоя, мониторинга, биллинга.

Синтаксис инструкции LABEL: LABEL <key>=<value> [<key>=<value> ...].

Примеры:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

Образ может содержать несколько лейблов, которые можно задавать как в одной, так и в нескольких инструкциях LABEL. Лейблы, определённые в базовом образе (FROM ...), наследуются. Если тот же ключ объявлен повторно, используется последнее значение.

Значения лейблов указываются в двойных кавычках, так можно задействовать пробелы, специальные символы и переменные окружения: LABEL example="build-$BUILD_NUMBER".

Пример типичного набора лейблов (по мотивам Open Containers Image Spec):

LABEL org.opencontainers.image.title="my-service" \
  org.opencontainers.image.version="1.2.3" \
  org.opencontainers.image.source="https://github.com/example/my-service" \
  org.opencontainers.image.authors="devops@example.com"

Посмотреть лейблы у образа можно командой: docker image inspect --format='{{json .Config.Labels}}' myimage.

HEALTHCHECK — проверка здоровья контейнера

Инструкция HEALTHCHECK позволяет Docker периодически проверять «здоровье» запущенного контейнера с помощью указанной команды. Результат проверки влияет на статус контейнера: healthy, unhealthy или starting. Этот статус можно использовать в оркестраторах (Swarm, Kubernetes) и системах мониторинга.

HEALTHCHECK наследуется от родительского образа, и если HEALTHCHECK в контейнере вам не нужен – отключить его можно командой HEALTHCHECK NONE.

Синтаксис инструкции HEALTHCHECK: HEALTHCHECK [OPTIONS] CMD <команда_проверки>.

Примеры:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

Образ может содержать несколько лейблов, которые можно задавать как в одной, так и в нескольких инструкциях LABEL. Лейблы, определённые в базовом образе (FROM ...), наследуются. Если тот же ключ объявлен повторно, используется последнее значение.

Значения лейблов указываются в двойных кавычках, так можно задействовать пробелы, специальные символы и переменные окружения: LABEL example="build-$BUILD_NUMBER".

Пример типичного набора лейблов (по мотивам Open Containers Image Spec):

LABEL org.opencontainers.image.title="my-service" \
  org.opencontainers.image.version="1.2.3" \
  org.opencontainers.image.source="https://github.com/example/my-service" \
  org.opencontainers.image.authors="devops@example.com"

Посмотреть лейблы у образа можно командой: docker image inspect --format='{{json .Config.Labels}}' myimage.

HEALTHCHECK — проверка здоровья контейнера

Инструкция HEALTHCHECK позволяет Docker периодически проверять «здоровье» запущенного контейнера с помощью указанной команды. Результат проверки влияет на статус контейнера: healthy, unhealthy или starting. Этот статус можно использовать в оркестраторах (Swarm, Kubernetes) и системах мониторинга.

HEALTHCHECK наследуется от родительского образа, и если HEALTHCHECK в контейнере вам не нужен – отключить его можно командой HEALTHCHECK NONE.

Синтаксис инструкции HEALTHCHECK: HEALTHCHECK [OPTIONS] CMD <команда_проверки>.

Опции инструкции HEALTHCHECK:.

Пример проверки HTTP‑сервиса с помощью curl:

FROM nginx:alpine

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1

В этом примере каждые 30 секунд Docker вызывает curl -f http://localhost/. Если команда завершится с ненулевым кодом (например, сервис не отвечает или возвращает 500), то после трёх неудачных попыток подряд статус контейнера станет unhealthy.

USER — пользователь и группа по умолчанию для последующих инструкций

Инструкция USER задаёт пользователя (и опционально группу), от имени которого будут выполняться последующие инструкции Dockerfile (RUN, CMD, ENTRYPOINT, HEALTHCHECK) и процессы в запущенном контейнере по умолчанию.

По умолчанию большинство базовых образов запускаются от root. Это удобно для настройки системы на этапе сборки, но небезопасно для продакшена. USER позволяет переключиться на менее привилегированного пользователя, что повышает безопасность контейнеров.

Синтаксис инструкции USER имеет три вида:

Пользователь и группа должны существовать в образе к моменту выполнения USER (создать их можно, например, через RUN adduser / useradd).

Примеры:

FROM node:20-alpine

# Создаём непривилегированного пользователя и директорию приложения
RUN addgroup -S appgroup && adduser -S appuser -G appgroup \
  && mkdir -p /app && chown -R appuser:appgroup /app

WORKDIR /app
COPY . .

# Все последующие инструкции и процессы будут выполняться от appuser
USER appuser:appgroup

CMD ["node", "server.js"]

VOLUME — точка монтирования для внешнего тома

Инструкция VOLUME объявляет одну или несколько директорий внутри образа как точки монтирования для томов. Такие директории предназначены для хранения данных, которые не должны пропадать при пересоздании контейнера, и/или должны быть вынесены на внешний том или хост.

Том — это отдельная область хранения данных Docker (на диске хоста или в управляемом драйвером хранилище), которая монтируется в контейнер и живёт независимо от жизненного цикла конкретного контейнера. Физически Docker держит тома в директории /var/lib/docker/volumes/tom_name/. Если в образе в эту директорию были записаны какие‑то файлы, при первом монтировании тома эти файлы будут скопированы в том (инициализация содержимого).

Когда контейнер создаётся из образа с объявленной инструкцией VOLUME, Docker автоматически создаёт анонимный том (если не был указан явный том или bind‑mount) и монтирует его в указанную директорию.

Синтаксис инструкции VOLUME:

VOLUME ["/path/to/dir"]
VOLUME ["/path/one", "/path/two"]
VOLUME /path/to/dir

Примеры использования инструкции VOLUME:

FROM mysql:8

# Каталог с данными MySQL будет вынесен в том
VOLUME /var/lib/mysql

ENV MYSQL_DATABASE=mydb

В этом примере при создании контейнера Docker создаст том и смонтирует его в /var/lib/mysql, если при запуске явно не указать другой том или bind‑mount.

Пример запуска контейнера с использованием объявленного в Dockerfile каталога как точки монтирования именованного тома:

docker run -d \
  -v mydata:/var/lib/mysql \
  --name my-mysql \
  mysql-image

Здесь mydata — это именованный том Docker, который будет смонтирован в /var/lib/mysql вместо автоматически созданного анонимного тома.

Примонтировать можно не только том как изолированную среду хранения данных, но и директорию с хоста (bind mount) – это частый прием при разработке и тестировании контейнеров. Например, при разработке FastAPI-сервиса можно собрать образ на базе нужной версии Python, установить зависимости через RUN pip install, объявить рабочую директорию через VOLUME, а затем при запуске контейнера примонтировать локальную директорию проекта:

FROM python:3.12-slim
WORKDIR /app

# Установка зависимостей
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Объявляем точку монтирования
VOLUME /app

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

Запуск контейнера с монтированием локальной директории:

docker run -d \
  -v "$(pwd)":/app \
  -p 8000:8000 \
  --name fastapi-dev \
  fastapi-image

Теперь можно редактировать код локально, и благодаря флагу --reload в uvicorn изменения будут автоматически подхватываться внутри контейнера без пересборки образа.

ONBUILD — триггер-инструкция для дочерних образов

Инструкция ONBUILD добавляет в образ триггерную инструкцию, которая будет выполнена позже — когда этот образ используется как базовый для сборки другого образа. Триггер выполняется в контексте дочерней сборки, как если бы он был вставлен сразу после инструкции FROM в дочернем Dockerfile.

Это полезно при создании базовых образов, которые будут использоваться для сборки других образов. Например, можно создать образ с окружением для сборки приложений, который требует добавления исходного кода в определенную директорию.

Синтаксис инструкции ONBUILD: ONBUILD <ИНСТРУКЦИЯ>.

Принцип работы ONBUILD: при сборке образа триггер добавляется в метаданные (ключ OnBuild в docker inspect), но не выполняется, а когда образ используется как базовый (FROM) — все триггеры выполняются по порядку после FROM. Если при сборке триггер завершается с ошибкой — сборка прерывается. После выполнения триггеры удаляются и не передаются «внукам».

У ONBUILD есть ограничения:

Примеры использования инструкции ONBUILD.

1. Базовый образ для Python-приложений:

FROM python:3.12-slim

WORKDIR /app

# Триггеры выполнятся в дочерней сборке
ONBUILD COPY requirements.txt .
ONBUILD RUN pip install --no-cache-dir -r requirements.txt
ONBUILD COPY . .

CMD ["python", "app.py"]

Дочерний Dockerfile становится максимально простым:

dockerfile FROM mycompany/python-base:latest
# Все ONBUILD триггеры выполнятся здесь автоматически

2. Использование с многостадийной сборкой (начиная с Dockerfile 1.11):

# syntax=docker/dockerfile:1.11
FROM alpine AS build
RUN apk add --no-cache gcc musl-dev
COPY app.c .
RUN gcc -o /app app.c

FROM alpine AS base
ONBUILD COPY --from=build /app /usr/local/bin/app
ONBUILD RUN chmod +x /usr/local/bin/app

STOPSIGNAL — сигнал контейнеру при остановке

Инструкция STOPSIGNAL задает системный сигнал, который будет отправлен контейнеру при его остановке. Этот сигнал может быть указан в формате имени SIG, например SIGKILL, или в виде беззнакового числа, соответствующего позиции в таблице системных вызовов ядра, например 9. Если сигнал не задан явно, по умолчанию используется SIGTERM.

Синтаксис инструкции STOPSIGNAL: STOPSIGNAL signal.

Параметр signal — это системный сигнал, который будет отправлен контейнеру. Может быть задан как именем (SIGTERM, SIGKILL, SIGINT и т.д.), так и числом (15, 9, 2 и т.д.). Сигнал по умолчанию, заданный в образе, можно переопределить для конкретного контейнера с помощью флага --stop-signal при выполнении команд docker run или docker create.

Основные сигналы:

Примеры использования инструкции STOPSIGNAL.

1. Использование именованного сигнала:

FROM nginx:alpine
STOPSIGNAL SIGTERM

В этом примере nginx будет получать сигнал SIGTERM при остановке контейнера (это значение по умолчанию).

2. Использование числового значения сигнала:

FROM alpine
STOPSIGNAL 9

Здесь при остановке контейнер получит сигнал SIGKILL (номер 9), который принудительно завершает процессы без возможности корректного завершения.

3. Использование с приложением, требующим специфичного сигнала:

FROM node:20-alpine
WORKDIR /app
COPY . .

# Node.js корректно обрабатывает SIGINT для graceful shutdown
STOPSIGNAL SIGINT

CMD ["node", "server.js"]

STOPSIGNAL также может использовать переменные окружения, определенные через ENV:

FROM alpine
ENV STOP_SIG=SIGTERM
STOPSIGNAL $STOP_SIG

SHELL — смена используемой оболочки

Инструкция SHELL позволяет изменить оболочку по умолчанию, которая используется для shell-формы команд. По умолчанию в Linux используется оболочка ["/bin/sh", "-c"], а в Windows — ["cmd", "/S", "/C"]. Инструкция SHELL особенно полезна в Windows, где существуют две распространенные и совершенно разные встроенные оболочки: cmd и powershell, а также доступны альтернативные оболочки, включая sh.

Инструкция SHELL может использоваться несколько раз, каждая инструкция SHELL переопределяет все предыдущие инструкции и влияет на все последующие инструкции, в том числе: RUN, CMD и ENTRYPOINT. Инструкция SHELL должна быть записана в JSON-формате.

Примеры использования инструкции SHELL.

1. Смена оболочки на Bash в Linux:

FROM ubuntu:22.04

# Используем bash вместо sh
SHELL ["/bin/bash", "-c"]

RUN echo "Executing in Bash: $BASH_VERSION"

2. Использование PowerShell в Windows:

# escape=`
FROM microsoft/nanoserver

SHELL ["powershell", "-command"]
RUN New-Item -ItemType Directory C:\Example
RUN Write-Host "Hello from PowerShell"

3. Оптимизация для Windows с escape-директивой:

# escape=`
FROM microsoft/nanoserver

SHELL ["powershell", "-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'

Директива escape позволяет использовать обратный апостроф для переноса строк вместо обратного слеша, что естественнее для Windows и PowerShell.

4. Использование с задержкой раскрытия переменных в Windows:

FROM microsoft/windowsservercore

# Включаем отложенное раскрытие переменных окружения
SHELL ["cmd", "/S", "/C", "/V:ON"]

RUN set VAR=Hello && echo !VAR! World

5. Смена на альтернативную оболочку в Linux:

FROM alpine

RUN apk add --no-cache zsh
SHELL ["/bin/zsh", "-c"]

RUN echo "Now using Zsh: $ZSH_VERSION"

Последнее обновление: 11.03.2026