Как собрать Docker-образ?

«Как собрать Docker-образ?» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основная команда для сборки образа — docker build. Она читает инструкции из Dockerfile в текущем контексте (директории) и создаёт образ.

Базовый пример:

docker build -t my-service:1.0.0 .
  • -t my-service:1.0.0 — задаёт имя и тег образа.
  • . — путь к контексту сборки (где находится Dockerfile).

Ключевые практики, которым я следую:

  1. Оптимизация Dockerfile:

    # Использую официальный легковесный базовый образ
    FROM alpine:3.19
    # Объединяю команды RUN для уменьшения количества слоёв и очистки кэша apt/apk в одной строке
    RUN apk add --no-cache nginx && 
        mkdir -p /var/log/nginx
    # Копирую файлы приложения отдельно, после установки зависимостей
    COPY ./app /usr/share/nginx/html
    # Определяю порт и команду запуска
    EXPOSE 80
    CMD ["nginx", "-g", "daemon off;"]
  2. Использую .dockerignore: Файл, аналогичный .gitignore, чтобы не копировать в контекст сборки ненужные файлы (.git, node_modules, лог-файлы), что ускоряет сборку и уменьшает размер образа.

  3. Многоэтапная сборка (Multi-stage build): Для компилируемых языков (Go, Rust) это обязательно.

    # Этап сборки
    FROM golang:1.21-alpine AS builder
    WORKDIR /app
    COPY go.mod go.sum ./ 
    RUN go mod download
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -o /app/main .
    
    # Финальный этап
    FROM alpine:latest
    COPY --from=builder /app/main /usr/local/bin/main
    CMD ["/usr/local/bin/main"]

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