Введение
Контейнеры упаковывают и запускают приложения, но сама упаковка не выбирает безопасную учётную запись процесса. Этот подготовленный обработчик DeskLite создаёт небольшой отчёт по заявкам и сейчас работает как root.
Вы изучите минимальный порядок работы с Docker, затем пересоберёте и запустите обработчик под непривилегированной учётной записью и только с тем доступом к файлам, который нужен его задаче. Docker и фиксированный базовый образ подготовлены; учётная запись реестра или предварительный опыт Docker не нужны.
Познакомьтесь с подготовленным проектом контейнера
На этом шаге вы определите файлы, из которых состоит задача формирования отчёта.
Образ — упакованная файловая система и конфигурация запуска. Контейнер — работающий экземпляр образа со своими процессами и доступным для записи слоем файловой системы. Dockerfile описывает, как собрать образ. Тег, например ticket-report:practice, — удобное имя образа; после пересборки его можно переназначить новому образу.
cd /home/labex/project/ticket-worker
ls
Ожидаются Dockerfile, worker.sh, input и output. Подготовленный обработчик читает строки CSV, записывает их количество в отчёт, затем продолжает работать, чтобы мы могли его проверить.
cat input/tickets.csv
После заголовка идут три строки заявок. Ожидаемый отчёт — tickets=3.
cat Dockerfile
FROM выбирает кэшированный базовый образ, WORKDIR выбирает рабочий каталог образа, а COPY добавляет обработчик. USER root выбирает учётную запись процесса. CMD — команда запуска по умолчанию, представленная списком. Вы измените только USER.
Базовый тег desklite-base:1.37.0 уже кэширован из фиксированного образа BusyBox. Все последующие сборки и запуски используют локальные файлы. Команды Docker используют sudo для доступа к демону этой лабораторной работы. Такой доступ на уровне хоста обладает широкими полномочиями; он отделён от учётной записи приложения, чьи права мы сокращаем внутри контейнера.
Соберите и запустите существующий обработчик
На этом шаге вы установите рабочее, но избыточно привилегированное исходное состояние.
docker build читает Dockerfile и контекст сборки — каталог файлов, доступных для COPY. Здесь . означает текущий каталог. -t назначает локальный тег образа:
sudo docker build -t ticket-report:practice .
Ожидается успешная сборка. Образ существует, но обработчик ещё не работает.
docker run создаёт контейнер. -d запускает его в фоновом режиме, а --name даёт ему повторно используемое имя. --network none отключает сеть, поскольку этому отчёту нужны только файлы.
Bind mount, или привязка каталога, делает путь хоста доступным по пути контейнера. Каждый --mount описывает тип, источник (src) и назначение (dst). Это исходное состояние открывает оба каталога для записи, поскольку параметр readonly отсутствует. Позже мы ограничим входной каталог.
sudo docker run -d --name ticket-worker --network none --mount type=bind,src=/home/labex/project/ticket-worker/input,dst=/data/input --mount type=bind,src=/home/labex/project/ticket-worker/output,dst=/data/output ticket-report:practice
Docker выводит идентификатор контейнера. Это не идентификатор пользователя обработчика. Исходный обработчик должен создать свой отчёт, который мы проверим далее.
Проверьте реальную учётную запись при выполнении
На этом шаге вы отличите успешный отчёт от выполнения с минимальными привилегиями.
docker ps перечисляет работающие контейнеры:
sudo docker ps
Найдите ticket-worker. docker logs читает стандартный вывод приложения:
sudo docker logs ticket-worker
Ожидаются worker uid=0 и tickets=3. UID 0 — root. Бизнес-задача работает, но использует больше привилегий, чем нужно.
docker exec запускает команду проверки в этом работающем контейнере. id -u выводит её эффективный числовой идентификатор пользователя:
sudo docker exec ticket-worker id -u
Снова ожидается 0. docker inspect читает конфигурацию. --format выбирает одно поле; скопируйте шаблон в кавычках точно. .Config.User — настроенный пользователь:
sudo docker inspect --format '{{.Config.User}}' ticket-worker
Ожидается root. Настройка образа и проверка реального процесса совпадают. Файл с надписью «non-root» не предоставил бы такого подтверждения.
Пересоберите с подготовленным непривилегированным пользователем
На этом шаге вы зададите учётную запись приложения по умолчанию в образе.
Кэшированная база уже включает nobody с UID 65534. Создавать пользователя или пароль не нужно. Откройте Dockerfile:
nano Dockerfile
Измените только инструкцию USER. Полный файл должен быть таким:
FROM desklite-base:1.37.0
WORKDIR /app
COPY worker.sh /app/worker.sh
USER nobody
CMD ["sh", "/app/worker.sh"]
Сохраните с помощью Ctrl+O, Enter и выйдите с помощью Ctrl+X.
sudo docker build -t ticket-report:practice .
Теперь тег обозначает пересобранный образ. Существующие контейнеры не переключаются на пересобранный образ автоматически; старый root-контейнер остаётся старым экземпляром. На следующем шаге вы замените его и дадите новой учётной записи требуемый доступ к выходному каталогу.
Замените контейнер с ограниченными монтированиями
На этом шаге вы объедините непривилегированную учётную запись с рабочими правами доступа к файлам.
docker rm удаляет контейнер. -f сначала останавливает его, если он работает. Удалите только именованный контейнер этого упражнения:
sudo docker rm -f ticket-worker
Каталог отчётов изначально принадлежал root. Как в лабораторной работе по правам файлов, процессу не от root нужны владение и разрешение для записи результата. chown -R рекурсивно меняет владельца каталога и существующего отчёта на UID и GID 65534. Режим 750 даёт владельцу полный доступ без общедоступной записи:
sudo chown -R 65534:65534 output
sudo chmod 750 output
Теперь создайте замену. Монтирование входного каталога добавляет readonly; монтирование выходного остаётся доступным для записи. Это предотвращает изменение входных данных, позволяя формировать отчёт:
sudo docker run -d --name ticket-worker --network none --mount type=bind,src=/home/labex/project/ticket-worker/input,dst=/data/input,readonly --mount type=bind,src=/home/labex/project/ticket-worker/output,dst=/data/output ticket-report:practice
Ожидается новый идентификатор контейнера. Теперь образ задаёт непривилегированного пользователя; переопределять его на root при запуске не нужно.
Проверьте учётную запись, доступ и бизнес-результат
На этом шаге вы проверите все три части результата в заменяющем контейнере.
sudo docker exec ticket-worker id -u
Ожидается 65534. Проверьте реальный вывод обработчика:
sudo docker logs ticket-worker
Ожидаются worker uid=65534 и tickets=3. Прочитайте реальный выходной файл через контейнер:
sudo docker exec ticket-worker cat /data/output/report.txt
Ожидается tickets=3. Это доказывает, что сокращение привилегий не нарушило задачу.
Проверьте монтирования. Шаблон в кавычках выбирает .Mounts и форматирует его как JSON:
sudo docker inspect --format '{{json .Mounts}}' ticket-worker
Найдите /data/input с "RW":false и /data/output с "RW":true. RW означает чтение/запись. Те же байты входных данных доступны для чтения, но монтирование запрещает запись.
Попробуйте безвредное создание файла, чтобы проверить ограничение. touch создал бы пустой файл, если бы это было разрешено:
sudo docker exec ticket-worker touch /data/input/probe.txt
Ожидаются ошибка Read-only file system и ненулевой код завершения. Этот отказ намеренный. Не делайте входной каталог доступным для записи, чтобы убрать его; отчёт уже успешно создан с входными данными только для чтения.
Убедитесь, что итоговый обработчик продолжает работать
На этом шаге вы оставите нужный обработчик готовым к проверке.
sudo docker ps
Именованный контейнер ticket-worker должен работать. Ещё раз подтвердите настроенного пользователя и отчёт:
sudo docker inspect --format '{{.Config.User}}' ticket-worker
sudo docker exec ticket-worker cat /data/output/report.txt
Ожидаются nobody и tickets=3. Проверка курса также сравнивает работающий образ с вашим тегом для передачи, проверяет реальный PID обработчика и тестирует исходные входные и выходные данные. Пересборки Dockerfile без замены контейнера недостаточно.
Это упражнение сокращает привилегии учётной записи приложения и доступ к файлам. Оно не делает доступ к демону Docker непривилегированным и не устанавливает полную политику защиты контейнеров рабочей среды.
Резюме
Вы собрали реальный образ с непривилегированной учётной записью приложения, запустили его с ограниченным входом и рабочим доступом к выходу и проверили реальный процесс и отчёт. Конфигурация образа, учётная запись при выполнении, режимы монтирования и функциональное поведение вместе формируют итоговое состояние.



