Достаточно долгое время у меня не получалось корректно настроить одновременную работу Gitlab и встроенный Container Registry. Сложность состояла в том, что все это хозяйство работало за внешним nginx reverse proxy с настроенным https. С прокси же запросы на сам gitlab шли по http и на сервере сертификатов не было вовсе. Это важно, так как не хотелось одновременно настраивать и обновлять сертификаты на nginx proxy и gitlab.
На углубленном курсе "Архитектура современных компьютерных сетей" вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.
Введение
Просто настроить gitlab за nginx в режиме proxy_pass не представляет никакой сложности. Трудности возникают именно тогда, когда вы хотите использовать встроенный Container Registry. Я несколько раз подходил к этой задаче и каждый раз отступал, либо отказываясь от registry, либо от nginx proxy.
Без прокси неудобно, так как чаще всего, если у вас есть какая-та инфраструктура, а не одиночный сервер, смотреть напрямую в интернет у вас будет какой-то шлюз, а не сам сервис. Так удобно разграничивать доступ, контролировать и перенаправлять подключения, следить за сертификатами, балансировать нагрузку и т.д. В общем, я использую его всегда, когда это возможно и оправдано (почти всегда).
С registry не получалось корректно настроить работу за прокси. Я перепробовал все советы, что только нашел в интернете. Перечитал всю документацию, но так ничего не получилось. Команда docker login успешно отрабатывала на сервере, а вот запушить образ в реджистри gitlab никак не получалось. Получал ошибку.
Error: Status 404 trying to push repository zeroxzed/website
Проблему я в итоге решил, когда залез во внутренности gitlab и разобрался, как там все устроено. Когда все понял, придумал рабочее решение, которым с вами делюсь.
Gitlab и proxy nginx
Если у вас используется только сам gitlab, без встроенного registry, то никаких особых настроек делать не надо. Достаточно выполнить обычную установку gitlab. В качестве EXTERNAL_URL во время установки можно указать адрес с http. Затем, после установки, настраивайте proxy nginx примерно вот так.
server { listen 443 http2 ssl; server_name gl.serveradmin.ru; access_log /var/log/nginx/gl.serveradmin.ru-access.log full; error_log /var/log/nginx/gl.serveradmin.ru-error.log; ssl_certificate /etc/letsencrypt/live/gl.serveradmin.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/gl.serveradmin.ru/privkey.pem; limit_conn perip 50; location /.well-known { root /tmp; } location / { proxy_pass http://10.20.50.8:80; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_set_header X-Forwarded-Proto https; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Ssl on; } } server { listen 80; server_name gl.serveradmin.ru; return 301 https://gl.serveradmin.ru$request_uri; }
На самом сервере с gitlab в /etc/gitlab/gitlab.rb измените параметры.
external_url 'https://gl.serveradmin.ru' nginx['listen_port'] = 80 nginx['listen_https'] = false
И после этого дайте команду на переконфигурацию системы.
gitlab-ctl reconfigure
После этого gitlab будет нормально работать за nginx proxy. Дальше рассказываю, что надо сделать, чтобы включить и нормально запустить в работу Container Registry за reverse proxy.
Настройка Gitlab registry за reverse nginx proxy
На первый взгляд никаких особенных сложностей быть не должно. Делаем по аналогии настройки, только для registry_nginx и пробуем работать с registry. Но ничего не получится. Будет приведенная выше ошибка. Я покопался в настройках gitlab и понял, в чем проблема.
Если у вас используется одинаковый url для web интерфейса gitlab и registry, то корректная работа за nginx proxу невозможна. Я посмотрел конфигурацию nginx, входящего в состав gitlab. Она живет тут - /var/opt/gitlab/nginx/conf. Там отдельный конфиг для web интерфейса и для registry. Если используются одинаковые доменные имена, то все запросы попадают на конфигурацию веб интерфейса и проксируются на gitlab-workhorse.
Это происходит, потому что директива server_name в обоих конфигах одинаковая. Обрабатывается первым то, что стоит раньше в конфигурации. Я заподозрил это еще раньше, когда 404 ошибки обращений к registry обнаруживал в лог файлах /var/log/gitlab/nginx/gitlab_access.log, тогда как gitlab_registry_access.log были пустые.
Сбивало с толку то, что авторизация docker login при этом отрабатывала корректно, а ошибка возникала только во время push. Судя по всему, процесс авторизации один и тот же, что для registry, что для http доступа. В общем, чтобы все корректно работало, вам нужно разделить на разные домены gitlab и registry.
Я сделал для registry отдельный домен. Настроил для него проксирование, примерно так.
server { listen 443 http2 ssl; server_name rg.serveradmin.ru; access_log /var/log/nginx/rg.serveradmin.ru-access.log full; error_log /var/log/nginx/rg.serveradmin.ru-error.log; ssl_certificate /etc/letsencrypt/live/rg.serveradmin.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/rg.serveradmin.ru/privkey.pem; limit_conn perip 50; location /.well-known { root /tmp; } location / { proxy_pass http://10.20.50.8:80; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_set_header X-Forwarded-Proto https; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Frame-Options SAMEORIGIN; proxy_cache off; proxy_buffering off; proxy_request_buffering off; proxy_http_version 1.1; } } server { listen 80; server_name rg.serveradmin.ru; return 301 https://rg.serveradmin.ru$request_uri; }
Дальше в gitalb.rb добавил параметры, отвечающие за работу registry.
registry_external_url 'https://rg.serveradmin.ru' gitlab_rails['registry_enabled'] = true registry['enable'] = true registry_nginx['enable'] = true registry_nginx['proxy_set_headers'] = { "Host" => "$http_host", "X-Real-IP" => "$remote_addr", "X-Forwarded-For" => "$proxy_add_x_forwarded_for", "X-Forwarded-Proto" => "https", "X-Forwarded-Ssl" => "on" } registry_nginx['listen_port'] = 80 registry_nginx['listen_https'] = false
Я не уверен, что нужны все эти параметры. Привожу пример с реально работающего сервера и чтобы случайно чего-то не забыть, привожу сразу все, что на нем сейчас активно из настроек. Думаю, заголовки указывать не обязательно. Без них тоже заработает.
После этого перечитывайте конфигурацию gitlab и nginx и проверяйте работу.
Проверка работы gitlab registry
Теперь проверим работу Gitlab Container Registry. Для этого создаем любой проект через web интерфейс. Идем в раздел Packages -> Container Registry. Там увидите краткую инструкцию по работе с реджистри.
Идем на сервер, где будем собирать образы docker. Настраиваем подключение к registry, указав логин с паролем.
docker login rg.serveradmin.ru Username: zeroxzed Password: Login Succeeded
Создадим тестовый докер образ из Dockerfile.
FROM busybox RUN echo "Test OK"
Собираем образ и загружаем его в registry.
# docker image build -t rg.serveradmin.ru/zeroxzed/myapp:latest . # docker push rg.serveradmin.ru/zeroxzed/myapp:latest
Указанный образ будет загружен в Registry данного проекта.
Часто задаваемые вопросы по теме статьи (FAQ)
В моем примере запросы с прокси на рабочий сервер идут в рамках закрытой непубличной инфраструктуры, где вероятность перехвата трафика минимальна. Нет смысла тратить ресурсы и время на настройку и обновления сертификатов не только на nginx proxy, но и рабочем сервере.
Да, это возможно. Принципиальной разницы нет. Единственное отличие - нужно использовать протокол https при перенаправлении запросов с прокси на сервер gitlab.
Да, настраивается это примерно так же. Необходимо создать поддомен для каждого сервиса и по аналогии с приведенным примером настроить перенаправление запросов с nginx на gitlab.
Да, у меня есть отдельная статья - установка, настройка и работа с gitlab.
Заключение
На этом все по работе gitlab за nginx proxy. Настройка очень простая, продуктом пользоваться удобно. Настроить типовой ci/cd на базе докера очень просто. В будущем опишу такой пример. Так что рекомендую Gitlab для совместной работы команды. Минус у него только один - очень требователен к ресурсам.
Научиться настраивать MikroTik с нуля или систематизировать уже имеющиеся знания можно на углубленном онлайн-курcе по администрированию MikroTik. Автор курcа – сертифицированный тренер MikroTik Дмитрий Скоромнов. Более 40 лабораторных работ по которым дается обратная связь. В три раза больше информации, чем в MTCNA.
Еще бы раскрыть тайну gitlab-pages для Wildcard доменов вида
https://GROUP-or-USERNAME.youdomain.ru/project
Володя, спасибо тебе! Я 2 дня парился с идиотскими советами от гугла, пока не попал на твою статью! Всё работает как часы теперь! Жму руку!
Добавлю еще свои 5 копеек вот пример docker-compose.yml где сразу все заводится и gitlab и registry:
version: '3.6'
services:
gitlab:
image: 'gitlab/gitlab-latest'
container_name: gitlab
restart: always
hostname: 'gitlab.${DOMAIN}'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.${DOMAIN}'
letsencrypt['enable'] = false
nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['redirect_http_to_https'] = false
gitlab_rails['time_zone'] = 'Europe/Moscow'
registry_external_url 'https://cr.${DOMAIN}'
gitlab_rails['registry_enabled'] = true
registry_nginx['enable'] = true
registry_nginx['listen_port'] = 5005
registry_nginx['listen_https'] = false
ports:
- '40080:80'
- '22:22'
- '5005:5005'
nginx конфиг для gitlab:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name gitlab.${DOMAIN}
location / {
proxy_pass http://127.0.0.1:40080;
}
nginx конфиг для registry:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cr.${DOMAIN}
location / {
proxy_pass http://127.0.0.1:5005;
}
Спасибо за информацию. К сожалению, движок сайта в комментариях убирает все отступы.
Помогите, пожалуйста. Делал по вашей инструкции, но при docker login вылетает ошибка: "Error response from daemon: Get "https://registry.git.*.ru/v2/": denied: access forbidden". Не встречалось ли вам такое, в чем может быть дело?
Если кто-то столкнется с этим, то проблем решилась так:
external_url http://gitlab.example.com -> external_url https://gitlab.example.com
У меня почему-то изначально была установлена схема http в external_url.
Не взлетело, пока в генерируем автоматически файле config.yml в /var/opt/gitlab/registry не изменил http в realm на https, после чего перезапустил гитлаб. Версия 14.6.3
https://gitlab.com/gitlab-org/gitlab-foss/-/issues/48349
Альтернатива - в gitlab.rb установить все же https, отключить letsencrypt и в прокси указать адрес с https
https://docs.gitlab.com/omnibus/settings/nginx.html#manually-configuring-https
Тогда не будет шанса забыть про эту правку в генерируемом файле при обновлении и т.п.
Клааааасс! Всё получилось!
Ровно на те же самые грабли наступил с запуском gitlab'а и registry в докере. И так же реджистри не хотел ни в какую запускаться. На stackoverflow и прочих ресурсах ответа не нашёл, все советы - мимо. Только у вас нормальный анализ ситуации и объяснение причин происходящего. Запустил реджистри на отдельном домене и всё заработало.
Спасибо огромное!
Да, я тоже долго возился, ничего не нашел в интернете. Пришлось самому разбираться в вопросе.
Странно но не работает.
2020-10-01_09:54:12.60341 time="2020-10-01T12:54:12.603377149+03:00" level=error msg="response completed with error" auth.user.name= err.code="name unknown" err.detail="map[data:map[name:registry/registry]]" err.message="repository name not known to registry" go.version=go1.14.7 http.request.host="localhost:5000" http.request.id=d040e0bb-59c9-49b9-8ac7-5fa624cd248d http.request.method=GET http.request.remoteaddr="127.0.0.1:45794" http.request.uri=/v2/registry/registry/tags/list http.request.useragent=GitLab/13.4.1 http.response.contenttype="application/json; charset=utf-8" http.response.duration=1.891008ms http.response.status=404 http.response.written=125 vars.name=registry/registry
2020-10-01_09:54:12.60343 127.0.0.1 - - [01/Oct/2020:12:54:12 +0300] "GET /v2/registry/registry/tags/list HTTP/1.1" 404 125 "" "GitLab/13.4.1"
Ой какая тема классная! как раз на прошлой неделе занимался gitlab.
Вобщем такая проблема имеется:
есть сервер nginx, он в моей локальной сети с адресом 192.168.10.40 (к нему микротик пробрасывает 80 и 443 порты)
есть сервер gitlab, он тоже в моей сети с адресом 192.168.10.50
настраиваю сертификат на nginx, проксирую на gitlab
Если из внешки заходить - gitlab виден, с https, все красиво.
Чтоб из локалки заходить - прописываю на микротике static dns и направляю его на nginx. Все, теперь из локалки gitlab виден по https.
А теперь пробую клонировать репозиторий, и тут затык.
Запрос идет на 22 порт nginx.
Гуглил, спрашивал в телеграм чатах.
Мне подсказали делать через hairpin nat.
Тоесть чтоб запросы шли как-то через внешку.
Вот и статья есть вроде понятная - https://lantorg.com/article/kak-zajti-po-vneshnemu-ip-adresu-iz-lokalnoj-seti-dlya-mikrotik
Но мне кажется я что-то упустил, и делаю неправильно.
Как быть? Подскажите направление.
Да, с ssh есть нюансы, как и со всем остальным. Держать gitlab за NAT немного геморройно, если доступ идет с двух сторон. Как самое простое решение, работать с репозиториями по https, а не ssh.
Может еще сработает вариант подключения git по ip адресу, а не домену. Для ssh подключений валидный сертификат не нужен, так что должно сработать, но я не проверял. Обычно у меня gitlab где-то в виртуалке на дедике за шлюзом. Работать из локальной сети с ним не надо. Все запросы из вне идут.
Совет работать с репозиториями по https, а не ssh, хорош, но есть нюансы.
Я столкнулся с тем, что если подключить к Jenkins виндовый агент, и на нём попытаться склонировать репозиторий, то процесс падает с ошибкой stderr: fatal: Unable to persist credentials with the 'wincredman' credential store.
А вот по SSH всё нормально.
У меня сделано так:
/ip firewall nat print
0 chain=dstnat action=dst-nat to-addresses= to-ports= protocol=tcp dst-address= dst-port= log=no log-prefix=""
1 chain=srcnat action=masquerade protocol=tcp src-address= dst-address= out-interface=bridge-local dst-port=
2 chain=srcnat action=masquerade out-interface=WAN log=no log-prefix=""
Дело в том, что если домен Gitlab-а привязан к nginx-reverse-proxy,
то вполне логично, что и 22 порт Gitlab пытается проксировать через него же.
Самым простым решением является перевесить SSH порт nginx-proxy на нестандартный,
а потом поднять с него до Gitlab тунель SSH или пробросить 22 порт на уровне iptables.
Что-то типа
/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -o "ExitOnForwardFailure=yes" -NL 0.0.0.0:22:localhost:22 root@IP_Gitlab -p 22
ну и обвернуть это дело в systemd или supervisor
Можно и так сделать.
Добрый день, Владимир. Можете подсказать в следующей ситуации. У нас есть корпоративный registry gitlab, к которому можно подключиться только по VPN. Есть такая задача, я тестирую новое облако, в котором поднят кластер kuberntetes, чтобы выкачивать образы с нашего registry я добавлял IP ноды в новом кластере в белый список IP-ков для registry. Но выяснилась проблема так как в облаке нет нет VPC (как у большой тройки), Pod-ы поднимаются на разных нодах которые имеют каждый раз разные IP-адреса и постоянно расширять свой список адресов, которым разрешен доступ я не могу. Как вы посоветуете решить эту проблему? Я пытался поднять в кубернетес openvpn, и запустить его с коропоротвным VPN сертификатом, но это у меня не вышло, да и не совсем правильное наверно это решение пробовал вот это https://github.com/helm/charts/tree/master/stable/openvpn
Буду благодарен за любой совет, спасибо!
Openvpn в Kubernetes тут точно не поможет. Нужно разбираться, как организована маршрутизация для нод кластера Kubernetes. Самое простое и верное решение, на мой взгляд - настроить отдельный шлюз, через который все ноды кластера будут выходить во внешний мир. Возможность такой настройки зависит от конкретного облачного провайдера Kubernetes. Я думаю, проще всего задать этот вопрос поддержке облака. Я думаю, они предложат решение. Ситуация не экзотическая, а скорее типовая. А дальше уже ip адрес этого шлюза добавите в белый лист на доступ к registry.
Спасибо за быстрый ответ, Владимир. Ситуация в том, что маршрутизацию в Kubernetes можно было бы организовать если бы у меня был бы доступ к самому кластеру, а такак у меня доступ через Kubectl только то вредил удасться настроить маршруты через какой нибудь соседний инстанс у этого провайдера.
Если у вас доступ только как пользователя кластера, судя по всему в отдельном неймспейсе, решить этот вопрос вы можете только через тех. поддержку.