0% прочитано

Composer + приватний GitLab пакет у Docker: чому ssh -T працює, а composer install не може клонувати

Під час deployment ICanUp Composer не зміг клонувати приватний GitLab пакет і показав згенеровану помилку Failed to clone. При цьому ssh -T git@gitlab.com усередині Docker успішно впізнавав мій GitLab account. Розбираю, чому цього тесту недостатньо, як окремо перевірити SSH агента, доступ саме до репозиторію, контекст виконання Composer і URL репозиторію.

13 вересня 2026 р. 9 хв читанняLaradock

Під час deployment ICanUp на новий VPS composer install зупинився на приватному GitLab package.

Composer повідомляв, що не зміг clone repository, і радив спробувати interactive mode.

Найцікавіше було далі: SSH-з'єднання з GitLab усередині Docker уже працювало.

Помилка Composer
Failed to clone the git@... repository,try running in interactive mode
BASH - Перевірка GitLab SSH усередині Docker
docker compose exec workspace \  ssh -T git@gitlab.com
GitLab успішно впізнає SSH key
Welcome to GitLab, @username!
Успішний ssh -T доводить, що GitLab може автентифікувати SSH key у цьому середовищі. Але він ще не доводить, що Composer може клонувати конкретний приватний репозиторій.
Composer private GitLab package troubleshooting in Docker where SSH authentication succeeds but repository clone still fails
SSH authentication, repository authorization і Composer execution context - це окремі перевірки. Успішний ssh -T підтверджує тільки першу.

Спочатку я розділила одну помилку на три різні перевірки

Повідомлення Composer виглядає як одна проблема з GitLab, але насправді між composer install і private package є кілька окремих меж.

Кожну з них потрібно перевіряти окремо.

Рівень

Що він доводить

ssh -T git@gitlab.com

GitLab приймає SSH identity

git ls-remote

Ця identity має доступ до конкретного repository

composer install

Composer запускає Git у правильному environment і використовує правильний repository URL

ssh -T перевіряє account, а не конкретний package

Це була головна логічна пастка.

Якщо GitLab відповідає привітанням, легко зробити висновок, що SSH повністю справний.

Але ssh -T лише підтверджує, що key пов'язаний із GitLab account.

Доступ до окремого приватногорепозиторію є ще одною перевіркою авторизації.

Наступним тестом має бути саме repository

Тому після ssh -T я переходжу не до повторного Composer install, а до Git-команди для того самого репозиторію, який не зміг отримати Composer.

BASH - Перевірити доступ до конкретного GitLab repository
git ls-remote \  git@gitlab.com:group/private-package.git

git ls-remote зручний тим, що перевіряє реальний repository URL і permissions, але не потребує повного clone.

Якщо ця команда падає, Composer ще не є головним підозрюваним.

Для діагностики використовую той самий SSH URL, який Composer фактично намагається клонувати. Тест іншого repository не доводить доступ до потрібного пакета.

Потім я перевіряю SSH agent, а не тільки SSH command

У Docker приватний ключ не обов'язково лежить усередині контейнера.

Кращий варіант - передати доступ до host SSH agent через socket.

Тоді container може використовувати identity, але private key не потрібно копіювати в image або project.

BASH - Перевірити SSH agent на host
echo "$SSH_AUTH_SOCK" ssh-add -l
BASH - Перевірити agent усередині Docker
docker compose exec workspace \  sh -lc '    echo "$SSH_AUTH_SOCK"    ssh-add -l    ssh -T git@gitlab.com  '

Мені важливі всі три результати: socket існує, агент бачить identity, GitLab її приймає.

Composer повинен запускатися в тому самому контексті

Ще одна пастка - перевірити SSH одним користувачем, а Composer запустити іншим.

У Docker або під час deployment це легко зробити непомітно.

Інший user може мати інший HOME, інший SSH_AUTH_SOCK, інший known_hosts і взагалі не бачити агента.

BASH - Зафіксувати execution context
docker compose exec workspace \  sh -lc '    whoami    id    printf "HOME=%s\n" "$HOME"    printf "SSH_AUTH_SOCK=%s\n" "$SSH_AUTH_SOCK"    ssh-add -l  '

SSH check і Composer потрібно порівнювати в одному container, під одним user і з тим самим environment.

sudo може прибрати SSH_AUTH_SOCK

Запуск Composer через sudo може змінити environment.

Тоді команда ssh -T від звичайного користувача працює, а Composer від root уже не має доступу до того самого agent socket.

BASH - Не змінювати користувача заради Composer
# Avoid using this as a normal fix:sudo composer install
Якщо Composer працює тільки через sudo, це не доказ правильного налаштування. Спочатку перевіряю user, HOME, SSH_AUTH_SOCK і filesystem permissions.

Repository URL теж є частиною перевірки

SSH може працювати і permissions можуть бути правильними, але Composer все одно не отримає пакет, якщо URL репозиторію застарів або вказує не туди.

Це особливо важливо після перенесення GitLab проектів між групами або зміни ієрархії репозиторіїв.

BASH - Перевірити Composer configuration
composer config --list --source \  | grep -i gitlab

Також перевіряю composer.json і lock data, залежно від того, як приватний пакет підключений до проєкту.

BASH - Знайти GitLab repository URLs
grep -R "git@gitlab.com" \  composer.json \  composer.lock

Composer -vvv показує, що він запускає насправді

Generic Failed to clone недостатньо для діагностики.

Verbose output дозволяє побачити URL репозиторію Git командою, на якому зупинився процес.

BASH - Запустити Composer з verbose output
composer install \  --no-interaction \  -vvv

Я використовую цей output як доказ того, який URL і який transport Composer використовує, а не намагаюся вгадати це з composer.json.

Interactive mode не був справжнім поясненням

Фраза try running in interactive mode звучить так, ніби Composer просто хоче поставити запитання користувачу.

Але для приватного Git репозиторію це лише загальне повідомлення після невдалого клонування.

Я не сприймаю interactive mode як root cause. Спочатку потрібно знайти, чому саме Git не отримав repository.

known_hosts - окрема перевірка

SSH key і host verification вирішують різні задачі.

Агент може мати правильний key, але нове середовище ще не мати GitLab host key у known_hosts.

BASH - Перевірити GitLab host і verbose SSH
ssh-keygen -F gitlab.com ssh -vT git@gitlab.com
Не вимикаю StrictHostKeyChecking як постійне виправлення. Для нового сервера або container environment host key потрібно додати контрольовано і перевірити.

Я не копіюю private SSH key у Docker image

Найпростіше технічно рішення могло б виглядати як копіювання ~/.ssh/id_* у container.

Для мене це неправильна межа безпеки.

Private key не повинен ставати частиною image layer, repository або Docker build context.

Agent forwarding замість копіювання key
Preferred: Host private key      |      vSSH agent      |      vforwarded socket      |      vDocker container      |      vGitLab  Avoid: private key      |      vCOPY into Docker image

Чому я не починаю з composer clear-cache

Проблема клонування через SSH часто провокує очистити Composer cache.

Але якщо git ls-remote не має доступу до репозиторію, cache нічого не виправить.

Спочатку я перевіряю транспорт, ідентичність, дозволи сховища та контекст виконання.

Мій troubleshooting flow

Перевірка

Що означає результат

ssh -T git@gitlab.com

SSH identity працює

ssh-add -l

Агент бачить key

git ls-remote repository

Є доступ саме до репозиторію пакета

whoami + SSH_AUTH_SOCK

Composer запускається в очікуваному environment

composer install -vvv

Видно реальний URL і Git command

composer.json / composer.lock

URL репозиторію не застарів

Порядок, який економить найбільше часу

  • Не запускати Composer повторно десять разів з тією самою помилкою.
  • Перевірити SSH_AUTH_SOCK.
  • Перевірити identities через ssh-add -l.
  • Перевірити ssh -T git@gitlab.com.
  • Перевірити точний repository через git ls-remote.
  • Звірити user, HOME і environment, у якому працює Composer.
  • Перевірити repository URL.
  • Тільки після цього аналізувати composer install -vvv.

Раніше я вже описувала базове налаштування Composer, private GitLab repository і Docker SSH agent.

Цей кейс починається на наступному рівні: агент уже переданий, GitLab уже впізнає key, але одного цього факту недостатньо для успішного composer install.

Laradock wrapper не скасовує потребу перевіряти environment

У локальному середовищі я використовую Laradock wrappers, щоб команди виконувалися в потрібному runtime.

Це зручно, але wrapper не повинен приховувати від мене, під яким user запускається процес і який SSH socket він бачить.

Сам multi-PHP підхід я окремо описувала у Post про Laradock з кількома PHP runtime і командами dphp, dartisan та dcomposer.

Що я б не робила

  • Не вважала б успішний ssh -T доказом доступу до конкретного приватного пакета

  • Не копіювала б приватний ключ у Docker image.

  • Не запускала б Composer через sudo тільки для обходу SSH проблеми.

  • Не вимикала б host verification назавжди.

  • Не починала б з очищення Composer cache без repository-level перевірки.

  • Не перевіряла б SSH одним користувачем, а Composer іншим.

  • Не ігнорувала б старий URL репозиторію після GitLab переміщення проекту.

  • Не оновлювала б залежності навмання, якщо composer install падає через transport.

Під час такого усунення несправностей важливо не вставляти приватний ключ, access token або повний вміст SSH конфігурації у logs, опис завдання чи Post.

Що я залишила собі на майбутнє

  • ssh -T перевіряє account authentication, але не весь Composer flow.

  • git ls-remote є швидкою перевіркою доступу до конкретного репозиторію.

  • SSH агента потрібно перевіряти через SSH_AUTH_SOCK і ssh-add -l.

  • Composer і SSH діагностики мають виконуватися під одним user.

  • URL репозиторію потрібно перевіряти після переміщення або перейменування GitLab проекту.

  • composer install -vvv використовую для фактичного Git command і URL.

  • Приватний ключ не копіюю в контейнер.

  • Generic Composer error розкладаю на authentication, authorization і execution context.

Успішний ssh -T означає: GitLab знає мій key. Він не означає: Composer точно може клонувати будь-який приватний репозиторій у цьому контейнер.

Висновок

У цьому кейсі найкориснішим результатом стало не знайти ще одну команду для Composer, а правильно розділити рівні проблеми.

GitLab уже впізнавав SSH identity всередині Docker, тому повторювати тільки ssh -T не мало сенсу.

Далі потрібно перевірити доступ до конкретного репозиторію, agent socket, user і environment Composer, актуальність URL репозиторію та реальний Git command у verbose output.

У ICanUp я після цього використовую просте правило: authentication success ще не дорівнює repository clone success.