71 lines
5.3 KiB
Docker
71 lines
5.3 KiB
Docker
# ==============================================================================
|
||
# ЭТАП СБОРКИ (BUILDER)
|
||
# ==============================================================================
|
||
# Используем официальный образ Go на базе легковесного дистрибутива Alpine Linux.
|
||
# Именуем этот этап как "builder", чтобы позже забрать из него скомпилированный файл.
|
||
FROM golang:1.27-alpine AS builder
|
||
|
||
# Устанавливаем Git без сохранения кэша пакетов (уменьшает размер слоя).
|
||
# Он необходим Go для скачивания внешних зависимостей (например, golang.org/x/sys).
|
||
RUN apk add --no-cache git
|
||
|
||
# Объявляем переменные окружения для создания изолированного системного пользователя.
|
||
ENV USER=stunuser
|
||
ENV UID=10001
|
||
|
||
# Создаем безопасного пользователя внутри сборочного контейнера:
|
||
# --disabled-password: без пароля (вход по паролю заблокирован)
|
||
# --gecos "": отключает заполнение анкетных данных (имя, телефон и т.д.)
|
||
# --home "/nonexistent": без домашней папки
|
||
# --shell "/sbin/nologin": запрещает пользователю выполнять bash/sh команды в системе
|
||
# --no-create-home: принудительно запрещает создавать домашний каталог
|
||
RUN adduser --disabled-password --gecos "" --home "/nonexistent" --shell "/sbin/nologin" --no-create-home --uid "${UID}" "${USER}"
|
||
|
||
# Устанавливаем рабочую директорию, где будет происходить сборка кода
|
||
WORKDIR /app
|
||
|
||
# Шаг оптимизации кэша Docker: сначала копируем только файлы зависимостей go.mod и go.sum.
|
||
# Звездочка * защищает от ошибки сборки, если файла go.sum еще физически не существует.
|
||
COPY go.mod* go.sum* ./
|
||
|
||
# Если файл go.mod существует, скачиваем все внешние библиотеки и проверяем их хэш-суммы.
|
||
# Благодаря этому шагу зависимости будут кэшироваться и не будут скачиваться заново при изменении кода.
|
||
RUN if [ -f go.mod ]; then go mod download && go mod verify; fi
|
||
|
||
# Копируем весь оставшийся исходный код проекта (main.go и другие файлы) в рабочую директорию
|
||
COPY . .
|
||
|
||
# Компилируем высокопроизводительный бинарник:
|
||
# CGO_ENABLED=0: отключаем зависимости от C-библиотек (делает бинарник полностью автономным)
|
||
# GOOS=linux: жестко указываем целевую операционную систему Linux
|
||
# -ldflags="-s -w": отключает генерацию отладочной информации (символов) и таблиц DWARF.
|
||
# Это уменьшает размер итогового файла почти в 2 раза без потери скорости.
|
||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/stun_server .
|
||
|
||
|
||
# ==============================================================================
|
||
# ФИНАЛЬНЫЙ ЭТАП (PRODUCTION)
|
||
# ==============================================================================
|
||
# FROM scratch — это пустой слой. В нем нет Linux, нет bash, нет пакетных менеджеров.
|
||
# Это гарантирует минимальный размер контейнера и максимальную безопасность (его невозможно взломать).
|
||
FROM scratch
|
||
|
||
# Переносим файлы пользователей и групп, созданные на этапе сборки.
|
||
# Без этого контейнер scratch не узнает, кто такой "stunuser".
|
||
COPY --from=builder /etc/passwd /etc/passwd
|
||
COPY --from=builder /etc/group /etc/group
|
||
|
||
# Копируем единственный скомпилированный исполняемый файл STUN-сервера из этапа builder
|
||
COPY --from=builder /app/stun_server /stun_server
|
||
|
||
# Переключаем контекст выполнения. Сервер будет работать от имени stunuser, а не root.
|
||
# Если в коде сервера найдут уязвимость, злоумышленник все равно не получит права root на хосте.
|
||
USER stunuser:stunuser
|
||
|
||
# Документируем, что контейнер слушает порт 3478 по протоколу UDP
|
||
EXPOSE 3478/udp
|
||
|
||
# Точка входа: при старте контейнера автоматически запускается наш STUN-сервер.
|
||
# Использование квадратных скобок [строгий JSON] запускает процесс напрямую (PID 1) без лишней оболочки sh.
|
||
ENTRYPOINT ["/stun_server"]
|