Введение
Pine & Path отправляет путеводитель по Alder Ridge в другой туристический центр. Текущий образ работает, но вместе с приложением содержит компилятор Go, исходные файлы и остатки сборки. Подготовьте компактный образ среды выполнения, сохранив все четыре маршрута, фильтры сложности, страницы подробностей, локальные иллюстрации и полные GPX-файлы для скачивания.
Вы уже должны уметь собирать и запускать простой образ Docker, понимать инструкции Dockerfile FROM, COPY и публикацию портов. Программировать на Go не требуется: готовое приложение и материалы предоставлены. Перед использованием в работе объясняются компиляция, этапы сборки, расположение файлов среды выполнения и синтаксис записи файлов в оболочке. Парк и данные маршрутов вымышлены и служат учебными материалами.
Docker, образ для сборки и эталонный сервис уже готовы. Вводите команды в Workstation, изучайте рабочий пример в Reference Guide, а свой результат — в Your Guide. Эта работа не зависит от испытания. Выделите около 60 минут с учётом чтения, сборок и обычных ошибок; это оценка автора.
Соберите рабочий исходный образ
На этом шаге вы выясните, что делает полноценный путеводитель, и соберёте предоставленный исходный образ. Начните во вкладке Reference Guide. В ней показаны четыре маршрута. Выберите Easy, откройте Cedar Loop, прочитайте расстояние и набор высоты и нажмите Download GPX. GPX — это XML с именованным треком и географическими точками; скачивается настоящий файл маршрута. Выберите Back to trails, затем Moderate и откройте Ridge Path. Вернитесь ко всем маршрутам. Обратите внимание не только на текст, но и на таблицу стилей и схематичную карту: это тоже ресурсы среды выполнения.

Переключитесь в Workstation, которая открывается в /home/labex/project/trail-guide. pwd выводит текущий каталог, а ls — его содержимое. Если вы вышли из проекта, следующая команда cd вернёт вас в него:
cd /home/labex/project/trail-guide
ls
Предоставлена следующая структура:
| Путь исходного файла | Назначение при выполнении |
|---|---|
app/main.go |
Программа Go для компиляции; исходный файл не нужен при выполнении |
content/trails.json |
Все четыре маршрута и связи между ними |
content/routes/ |
Четыре GPX-файла для скачивания |
public/ |
Таблица стилей и оригинальные схематичные иллюстрации |
author-notes/, build-cache/ |
Черновики и остатки сборки, не ресурсы среды выполнения |
Сохраните эти материалы и эталонный сервис без изменений. Вы будете редактировать Dockerfile, добавите .dockerignore и создадите учебные образы и контейнеры. Dockerfile.incomplete — предоставленный пример неудачной поставки для следующего шага.
cat показывает текстовый файл. Прочитайте существующий Dockerfile:
cat Dockerfile
Он начинается с dk02-go-builder:1 — подготовленного образа с компилятором Go. WORKDIR /guide задаёт рабочий каталог внутри образа. COPY . . копирует в него текущий контекст сборки, включая файлы, которые итоговому приложению не нужны. Последняя инструкция ENTRYPOINT — массив JSON, напрямую запускающий скомпилированную программу.
Команда сборки устанавливает CGO_ENABLED=0 только для этой команды, чтобы этому примеру Go со стандартной библиотекой не требовались библиотеки C. go build компилирует предоставленную программу; -trimpath удаляет из исполняемого файла сведения о локальном каталоге исходников, а -o /guide/guide задаёт его имя. Благодаря этому именно эта программа подходит для пустой базовой среды выполнения. Другим программам могут понадобиться разделяемые библиотеки, сертификаты или другие данные; пустая база подходит не всегда.
Сначала посмотрите версию компилятора. docker run --rm создаёт временный контейнер и удаляет его после завершения команды. Слова после имени образа задают запускаемую команду:
docker run --rm dk02-go-builder:1 go version
Вывод указывает Go 1.26 в Linux. Компилятор выполняется в контейнере, а не в Workstation.
Соберите исходный образ. docker build читает Dockerfile; -t присваивает результату тег, а завершающая . выбирает текущий каталог в качестве контекста сборки:
docker build -t trail-guide:sample .
Дождитесь сообщения об успешной сборке. Тег обозначает образ, а не работающий контейнер. Чтобы узнать размер в байтах, используйте docker image inspect для чтения метаданных; --format выбирает одно поле. Одинарные кавычки передают шаблон буквально:
docker image inspect trail-guide:sample --format '{{.Size}}'
Число зависит от подготовленного образа с компилятором. Исходный образ работает, но всё ещё содержит компилятор и исходники. Один лишь малый размер не доказывает полноту замены.
Отделите файлы сборки от файлов среды выполнения
На этом шаге вы соберёте программу на одном этапе, а на другом оставите только её исполняемый файл и ресурсы среды выполнения. Начните в Workstation, в том же каталоге проекта. Этап начинается с инструкции FROM. Имя AS build позволяет последующей инструкции COPY --from=build взять результат, не наследуя компилятор и предыдущие слои файловой системы.
Сначала изучите действительно неполную поставку. Предоставленный Dockerfile.incomplete компилирует программу и копирует общедоступные иллюстрации, но пропускает данные маршрутов:
cat Dockerfile.incomplete
Параметр -f выбирает этот альтернативный Dockerfile:
docker build -f Dockerfile.incomplete -t trail-guide:incomplete .
Сборка завершается успешно, поскольку компиляция не читает коллекцию маршрутов. Следующий запуск намеренно должен завершиться ошибкой с кодом 1:
docker run --rm trail-guide:incomplete
Прочитайте ошибку: open content/trails.json: no such file or directory. Исполняемый файл существует, но данные для выполнения отсутствуют. Успешная сборка и полноценное приложение — разные результаты. Временный контейнер с ошибкой уже удалён. Исправьте обычный Dockerfile вместо ремонта того контейнера или изменения приложения.
Here-document сохраняет целый блок текста. Ниже cat передаёт строки, > записывает Dockerfile, а <<'DOCKERFILE' обозначает буквальный блок, заканчивающийся строкой, содержащей только DOCKERFILE. Кавычки у открывающего маркера предотвращают подстановки оболочки при сохранении. Замените только редактируемый Dockerfile:
cat > Dockerfile <<'DOCKERFILE'
FROM dk02-go-builder:1 AS build
WORKDIR /src
COPY app/main.go ./main.go
RUN CGO_ENABLED=0 go build -trimpath -o /out/guide main.go
FROM scratch
WORKDIR /guide
COPY --from=build /out/guide ./guide
COPY content/ ./content/
COPY public/ ./public/
ENTRYPOINT ["/guide/guide"]
DOCKERFILE
Проследите за файлами: первый этап компилирует исходник в /out/guide. Второй FROM начинает с scratch, пустой базовой файловой системы Docker, не наследуя первый этап. Исполняемый файл становится /guide/guide; данные маршрутов и GPX сохраняют структуру content, а стили и иллюстрации — структуру public. Программа читает эти относительные пути из рабочего каталога. Поэтому одного исполняемого файла было недостаточно.
В итоговом образе нет оболочки и компилятора. Здесь это ожидаемо. Проверяйте приложение, а не пытайтесь запустить в нём оболочку.
Контекст сборки — отдельный вопрос. .dockerignore исключает совпадающие пути контекста до отправки сборщику. Начальная точка делает это имя файла скрытым. Эти правила исключают черновики и устаревший кеш, сохраняя приложение и ресурсы среды выполнения:
cat > .dockerignore <<'IGNORE'
author-notes/
build-cache/
IGNORE
Dockerfile с двумя этапами явно выбирает файлы среды выполнения; файл исключений также предотвращает отправку ненужных материалов. Исключение файла из контекста не может удалить байты, уже сохранённые в унаследованных слоях. Именно отдельный этап среды выполнения оставляет слои сборки позади.
Соберите образ для передачи:
docker build -t trail-guide:lean .
docker image inspect trail-guide:lean --format '{{.Size}}'
Сравните с размером исходного образа. Полезный результат — уменьшенная среда выполнения с полноценным путеводителем, а не минимально возможное число. Если COPY завершится ошибкой, прочитайте путь отсутствующего источника и сравните его с таблицей структуры и текущим каталогом. Исправьте Dockerfile или правило исключения и соберите заново. Не создавайте подменные данные и не монтируйте папку исходников, чтобы скрыть неполноту образа.
Запустите и заново создайте переданный путеводитель
На этом шаге вы запустите образ независимо от папки исходников и воспользуетесь всем путеводителем. Начните в Workstation. Программа слушает порт контейнера 8080. Публикация 8090:8080 делает её доступной на порту 8090 Workstation, который показывает Your Guide. -d оставляет сервер работать в фоне; --name задаёт имя этого учебного контейнера. Не добавляйте монтирования: образ должен содержать собственные ресурсы.
docker run -d --name trail-guide -p 8090:8080 trail-guide:lean
В выводе будет ID контейнера. Он продолжает работать, обслуживая путеводитель. docker logs читает вывод программы; --tail 5 ограничивает его последними пятью строками:
docker logs --tail 5 trail-guide
Ожидайте Guide listening on :8080: это порт контейнера, а не опубликованный порт хоста. Если имя контейнера уже занято после предыдущей попытки, воспользуйтесь приведённой ниже командой удаления учебного контейнера и повторите команду запуска. Ошибка отсутствующего ресурса требует сначала исправить Dockerfile и пересобрать образ.
Переключитесь в Your Guide и обновите страницу. Должны появиться все четыре маршрута. Выберите Easy: останутся только Cedar Loop и River Walk. Откройте Cedar Loop, изучите сведения и карту и скачайте его GPX. Нажмите Back to trails, выберите Moderate, откройте Ridge Path и скачайте также этот маршрут. Вернитесь ко всем маршрутам. Локальные иллюстрации и стили должны загружаться, а треки — соответствовать выбранным маршрутам. Reference Guide остаётся доступным независимо.

Теперь продемонстрируйте замену контейнера тем же образом. Переключитесь в Workstation. docker rm -f останавливает и удаляет только названный учебный контейнер; образ не удаляется. Оставьте dk02-reference работающим:
docker rm -f trail-guide
Создайте новый экземпляр без монтирований:
docker run -d --name trail-guide -p 8090:8080 trail-guide:lean
Переключитесь в Your Guide, обновите страницу и повторите посещения и скачивания Easy/Cedar Loop и Moderate/Ridge Path. Этот новый контейнер никогда не получал папку исходников рабочей станции. Его среда выполнения поступила из образа.
Оставьте контейнер работающим. После будущих изменений Dockerfile пересборка тега не обновляет существующий контейнер; удаляйте и заново создавайте только свой учебный контейнер для запуска нового образа. Остановленный сервис или ошибка подключения отличаются от собственной страницы Trail not found, которую путеводитель показывает для неизвестного маршрута.
Резюме
Вы отделили этап с компилятором от пустого этапа среды выполнения, скопировали действительно необходимые приложению ресурсы и исключили черновики из контекста сборки. Ваш компактный образ предоставляет полную коллекцию, фильтры, подробности, иллюстрации и GPX-файлы без монтирования каталогов рабочей станции. Повторное создание контейнера показало, что образ пригоден для многократной передачи приложения, а не просто запускает процесс, заимствующий папку исходников.



