Приватний пакет, який на вашій машині розв’язується без проблем, може не пройти всередині збірки з помилкою 404 або через тайм-аут, і Dockerfile рідко буває причиною. Крок збірки виконується в іншому мережевому просторі імен, з іншим поданням DNS і іншим сховищем облікових даних, ніж оболонка, у якій ви тестували. Пройдіть ці перевірки по порядку і зупиніться на першій невдалій, бо кожна наступна припускає, що попередня пройшла. Кожен крок називає команду, яка вирішує питання.

Почніть з імені builder, а не з Dockerfile

BuildKit може бути локальним, працювати в контейнері або на іншій машині, і кожен має свою мережу за замовчуванням. Виконайте docker buildx ls і прочитайте вузол, позначений зірочкою, перш ніж щось змінювати. Один docker-container драйвер або хмарний builder не поділяє приватний маршрут на вашому ноутбуці лише тому, що ви набрали команду там. Якщо активний builder віддалений, кожна подальша перевірка має виконуватися на тому хості, а не на вашій робочій станції.

Builder також несе свою конфігурацію resolver і змінні proxy. Обидві читаються під час збірки і не успадковуються від термінала, який її запустив.

Доведіть мережевий шлях зсередини кроку збірки

Напишіть одноразовий етап, який розв’язує хост залежності й відкриває до нього з’єднання. Це єдиний тест, який відповідає на питання для builder, а не для вашої оболонки.

FROM alpine:3.20
RUN apk add --no-cache curl bind-tools  && getent hosts registry.example.internal  && curl -sS -o /dev/null -w "%{http_code}
" https://registry.example.internal/simple/

Зберіть цей файл тим самим builder, мережевим режимом і тими самими монтуваннями секретів, що й ваша справжня збірка: docker buildx build --builder remote0 -f Dockerfile.probe --progress=plain .. Якщо getent нічого не виводить, несправність у розв’язанні імен і жодні облікові дані її не виправлять. Якщо ім’я розв’язується, але curl повідомляє про тайм-аут, перешкода — маршрут або політика виходу перед реєстром.

Видаліть зонд, щойно він відповість. Це діагностичний етап, і його ніколи не слід позначати тегом чи відправляти.

Монтуйте облікові дані, а не копіюйте їх

Коли шлях запрацює, наступна невдача в черзі — автентифікація. Монтування секрету BuildKit відкриває файл одному RUN кроку, не записуючи його в шар; саме це потрібно інструментові залежностей і саме цього образ не повинен зберігати.

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc     npm ci --omit=dev

Секрет має подаватися ззовні Dockerfile: docker buildx build --secret id=npmrc,src=/home/me/.npmrc .. Файл залишається в клієнта й ніколи не потрапляє в історію образу. Ні ARG ні ENV з тим самим токеном не виконують цю роботу, бо обидва записуються в конфігурацію образу.

Образу без root потрібен власний цільовий шлях, наприклад /home/app/.npmrc або еквівалентний файл для pip, Maven чи Cargo. Ціль монтування має збігатися з користувачем, який виконує команду, інакше інструмент повідомить про відсутній файл конфігурації, який насправді є.

Перевірте, що інструмент залежностей залишає в образі

Тимчасове монтування тримає облікові дані поза шаром, але не заважає інструментові записати щось інше. Менеджери пакетів залишають lock-файли, каталоги кешу й іноді розв’язану адресу реєстру.

Читайте готову файлову систему, а не довіряйте Dockerfile. docker history --no-trunc image:tag перелічує кожну команду шару, а docker run --rm image:tag sh -c "ls -a /root" показує, що вціліло в робочому контейнері. Навіть якщо файл було лише змонтовано, токен, записаний у рядок журналу під час npm ci усе одно залишається витоком.

Прочитайте також журнал збірки, бо --progress=plain друкує вивід команд дослівно. Якщо токен з’явиться там, змініть його раніше за все інше й передавайте через файл, який інструмент читає тихо.

Переконайтеся, що робочому образові більше не потрібен приватний шлях

Збірка й робочий застосунок — два різні споживачі однієї залежності, і приватний маршрут потрібен лише першому. Готовий образ має запускатися, розв’язувати свої робочі залежності й обслуговувати трафік без облікових даних збірки.

Перевірте це там, де приватний реєстр недоступний, або просто запустіть контейнер із --network none і переконайтеся, що він піднімається без змонтованого секрету. Контейнер, який запускається лише за наявності секрету збірки, усе ще пов’язаний із середовищем збірки.

Якщо контейнерові справді потрібен реєстр під час роботи, це окреме рішення про доступ, і його місце — у сховищі секретів оркестратора, а не в збірці. Опишіть два шляхи окремо, щоб ніхто не намагався виправити завантаження під час роботи прапорцем збірки. Коли всі п’ять перевірок пройдено, початковий симптом має названу причину на кожному рівні замість здогаду про мережу Docker.

Схожі статті