Рубрики
Uncategorized

Простые статические приложения для проверки Gitlab с помощью Nginx

Краткое резюме о том, как я выловил простые статические приложения для обзора из GitLab CI, используя только минимальную конфигурацию Nginx и крошечную щепотку PHP для аутентификации. Теги с nginx, devops, gitlab, программированием.

Мотивация

При работе над передними проектами для клиентов я всегда хотел иметь возможность показать им текущее состояние без необходимости постоянно развертываться в тестовой среде все время. Я хотел бы иметь несколько версий, по одному на ветку, поэтому несколько человек могут работать на разных вещах, но развернутыми, всемирной доступной версией, чтобы показать и обсудить с коллегами или клиентами. Это также улучшит запросы слияния, поскольку можно не только просмотреть код, но и просматривать развернутый проект в браузере без необходимости проверки кода.

Это именно то, что звонит Gitlab «Обзор приложений» Отказ Это в основном использует их CI среда функция и показывая их в запросах слияния.

Реализация

Рекомендуемый способ сделать это, используя Docker & Kubernetes, но получение ресурсов для даже небольшого кластера не дешево и не устанавливает его только для лучших отзывов кода для небольшой части кода — это не то, что я хотел сделать. Поэтому я пошел с гораздо более простым подходом. Я получил маленькую виртуальную машину, настроил Nginx с подстановочным знаком Vhost $ name.review.example.com и настроил это, чтобы обслуживать файлы из /var/www/$ name/public . Он не может выполнить резервный код или прокси к другим бэкам, он только обслуживает статические файлы.

Конфигурация NGINX для этого довольно проста:

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name ~^(?.+?).review.exampe.com$;

  root /var/www/$name/public;

  # insert your TLS config here. https://mozilla.github.io/server-side-tls/ssl-config-generator/ is a great tool!

  location / {
    try_files $uri $uri/ /index.html;
  }

  access_log /var/log/nginx/pages-access.log;
  error_log /var/log/nginx/pages-error.log debug;
}

Конфигурация для GZIP, General TLS, SendFile и т. Д. Все глобально в nginx.conf Отказ

Развертывание работает через бегун GitLab Shell, работающий на одной и той же машине, который просто rsyncs код к этому целевому каталогу. Сценарии Gitlab CI выглядят так:

build_app:                                                                                                                                                                                                                                  
  stage: build                                                                                                                                                                                                                              
  image: node                                                                                                                                                                                                                               
  script:                                                                                                                                                                                                                                   
  - npm install                                                                                                                                                                                                                             
  - npm run build-release                                                                                                                                                                                                                   
  only:                                                                                                                                                                                                                                     
  - branches                                                                                                                                                                                                                                
  artifacts:                                                                                                                                                                                                                                
    paths:                                                                                                                                                                                                                                  
    - public/                                                                                                                                                                                                                               

deploy_review:                                                                                                                                                                                                                              
  stage: review                                                                                                                                                                                                                             
  script:                                                                                                                                                                                                                                   
  - mkdir -p "/var/www/$REVIEW_TAG/public"
  - rsync -drv --delete public/ "/var/www/$REVIEW_TAG/public/"
  environment:
    name: "review/$CI_BUILD_REF_NAME"
    url: https://$CI_PROJECT_ID-$CI_BUILD_REF_SLUG.review.example.com
    on_stop: stop_review
  dependencies:
  - build_app
  only:
  - branches
  tags:
  - review

stop_review:
  stage: review
  script:
  - rm -rf "/var/www/$REVIEW_TAG"
  variables:
    GIT_STRATEGY: none
  when: manual
  environment:
    name: "review/$CI_BUILD_REF_NAME"
    action: stop
  only:
  - branches
  tags:
  - review

Задача stop_review может быть запущена вручную или используется gitlab, когда г-н закрыт, а ветвь удалена. Это просто удаляет Docroot. Тег Обзор используется для выбора правильного бегуна для этих заданий.

Аутентиа — что?

Это отлично работает. Он создает код на нашем внутреннем Docker CI Runner, ставит результат в архиве, загружает архив на сервер отзыва и rsyncs содержимое в корневом документе. Задание Deploy_Review занимает около 3-4 секунд для большинства приложений. Оттуда на общедоступной папке подается публично через https:// - <имя филиала> .Review.example.com . Без аутентификации. Это легко, и не может быть проблемой для некоторых случаев, но это определенно не чувствует себя хорошо, когда вы развертываете разработанные для клиентов проектов, возможно, даже содержащие реальные тестовые данные.

Таким образом, какой-то аутентификация была обязана. Поскольку простота использования была одной из основных функций на этом, скрывая его за сложной системой SSO, не была опцией (также нет такой системы, в настоящее время не используемой здесь). HTTP Basic Auth будет идеальным подходящим, но поддерживая .htpasswd Файлы больно, если количество пользователей становится большим, и он позволяет только для аутентификации. Но когда у нас есть аутентификация, почему остановиться там? Мы могли бы добавить некоторую авторизацию в смесь, чтобы мы могли допустить только определенный набор пользователей для доступа к любому данному проекту.

Subrequests nginx к спасению

К счастью, есть приложение Модуль Nginx для этого. ngx_http_auth_request модуль Позволяет задать третью сторону аутентификации пользователя. На стороне сервера Nginx создает подстреку к этой третьей стороне и проверяет код состояния ответа. Если это 200, он продолжает обслуживать запрос клиентов, если это 401 или 403, он возвращает одну и ту же ошибку к клиенту, проходя через WWW-аутентифицирующий заголовок для 401 результатов. Каждый другой код состояния считается ошибкой (HTTP 500 для клиента).

Дополнения на конфигурацию Nginx выглядят так.

server {
  # ...
  location / {
    auth_request /_remote_auth_/;
    try_files $uri $uri/ /index.html;
  }

  location = /_remote_auth/ {
    proxy_pass https://auth.example.com/remote_auth;  
    proxy_pass_request_body off;  
    proxy_set_header Content-Length "";  
    internal;
  }
}

Мы добавили auth_request Директива к основным контексте расположения и добавлена другой, внутренний Контекст местоположения для прокси-сервера до нашей аутентификации. Использование прокси здесь позволяет нам иметь еще несколько контроля над запросами, например, удаление корпуса запроса (если есть какая-либо) и не требует длины содержимого.

Переживание — моя самая большая сила

Итак, с решающей стороной Nginx, нам нужна бэкэнда, чтобы ответить на нашу аутентификацию. Я решил бросить небольшое приложение Symfony, которое просто отвечает HTTP-запросы на одном маршруте и требует от HTTP Basic Auth на нем, используя пользователей из базы данных. Эта настройка позволяет для будущих расширений, подобных проверке запрошенного доменного имени в списке разрешенных продуктов или добавления разных хранилищных резекций, таких как LDAP.

Строительство Что-то вроде этого в PHP, используя Symfony в качестве рамки, на самом деле можно сделать довольно быстро, она включает в себя около 200LOC в PHP, большинство из чего можно сгенерировать (код Bootstrap, MIGRATION, MIGRATION, ORM) и несколько десятков конфигурации. Для удобства мы используем EasyAdminbundle Чтобы предоставить простой пользовательский интерфейс для администраторов для создания и модификации пользователей.

Я решил запустить бэкэнд аутентификации на одном сервере, что и приложение Review, поскольку в настоящее время единственное обслуживание, используя ее. Развертывание легко, так как у нас уже есть бегун GitLab.

deploy_to_prod:  
  stage: deploy  
  script:  
  - rsync -drv --exclude '.env' --exclude '.*' --exclude 'vendor' --exclude 'var/' --delete . "/var/www/authcenter/"  
  - cd /var/www/authcenter/  
  - curl -O "https://getcomposer.org/download/1.7.2/composer.phar"  
  - php composer.phar install --no-dev  
  - php bin/console doctrine:migrations:migrate --no-interaction  
  variables:  
    APP_ENV: prod
    DATABASE_URL: $PROD_DATABASE_URL  
  environment:  
    name: authcenter prod  
    url: https://auth.example.com
  only:  
  - master  
  tags:  
  - nginx 

Конфигурация Nginx для этого не является сложным вообще. Я только что использовал Шаблон, предоставленный Symfony и просто настраивал его, чтобы соответствовать моему PHP-FPM. конфигурация Я также использовал fastcgi_param Директива по установке App_env и База данных_URL Переменные среды, требуемые приложением Symfony.

Я могу войти в приложение, используя https://auth.example.com/admin и получите интерфейс EasyAdmin для изменения или создания пользователей или использовать https://auth.example.com/remote_auth И просто получите пустой ответ HTTP 200.

При просмотре одного из моих приложений обзора мне просят ввести свои базовые учетные данные AUTH по первому запросу, и каждый следующий запрос получает те же учетные данные, потому что это как браузеры делают этот материал.

Открытие медлительности

Это работает, но вскоре я узнал, что это медленно. На самом деле, ужасно медленно для чего-то, что «просто обслуживало статические файлы». Запросы взяли до 1 секунды, иногда еще больше, за файл. Это число должно быть значительно ниже 100 мс! Я пошел и пытался отладить/профиль приложения PHP. Мое первое подозрение было то, что OPCache будет отсутствовать. И действительно, этот модуль не был установлен. Но это не решило мою проблему. Это было быстрее, но не быстро. Я был готов попасть в грязную работу. Профилирование этой действительно небольшое приложение на уровне ОС, когда я узнал, что гигантское «предупреждение: Убийца производительности вперед», который я должен был увидеть, когда я начал этот проект. Текущая реализация работала следующим образом.

  • Браузер пользователя отправляет запрос на сервер, содержащий учетные данные в заголовке авторизации.
  • NGINX запускает subrequest, передавая учетные данные в моем приложении PHP.
  • PHP Запросы базы данных для имени пользователя
  • PHP проверяет пароль, используя BCRYPT Отказ
  • Если пароль совпадает, он отвечает HTTP 200, если не с 401.
  • Nginx либо продолжает служить файл или отвечать на 401.

Каждый шаг этого действительно дешево (запрос БД занимает около 1 мс), кроме Bcrypt . Это даже специально разработано, чтобы быть медленным. Это тяжелая работа, чтобы быть медленными. Это общее представление о хорошей функции обработки паролей/деривата ключа: вы не можете принять ярлыки, вы должны сделать жесткий математический материал. И во время запуска BCRYPT один раз во время входа в систему и установку файла cookie сеанса после того, как это не проблема вообще не проблема, работает BCRYPT для каждого файла на базовой сессии AUTHATEST AUTHATEST, на самом деле является ужасной идеей.

Плохое выступление? Есть кеш!

Хотя может быть способ сделать NGINX настроить файл cookie для аутентифицированных запросов, я выбрал решение, который требуется меньше конфигурации и фактически исправляет мою задачу производительности для большинства рабочих нагрузок. Nginx может кэшировать прокси-ответы. Все, что мне нужно было сделать, это позволить кэшированию для этого ответа в моем приложении PHP и добавить кэш прокси к блоке внутреннего местоположения. Код PHP выглядит так:

    public function index() {
        $response = new JsonResponse([]);
        $response->setCache(['max_age' => 300, 'public' => true]); // 5min
        return $response;
    }

Новый конфигурация Nginx, как это:

location = /_remote_auth/ {  
  proxy_pass https://auth.example.com/remote_auth;  
  proxy_pass_request_body off;  
  proxy_set_header Content-Length "";  
  proxy_cache auth_cache;  
  proxy_cache_key $name$remote_user;  
  proxy_cache_valid 5m;  
  internal;  
}

Это требует, чтобы прокси-зона была настроена в контексте HTTP в nginx.conf :

http {
  # ...
  proxy_cache_path /var/run/nginx keys_zone=auth_cache:10m;
}

proxy_cache_key Уверяет, что мы кэшируем один ответ на имя пользователя и приложение до пяти минут. Это позволяет нам служить всем ресурсам для этого приложения только с одним запросом к фактической версии AUTHEND, но мы все еще проверяем аутентификацию для каждого приложения, и каждый пользователь один раз.

Вывод

Я в настоящее время довольно доволен этой установкой. Производительность не имеет большого, но приемлема, мы получили базовую аутентификацию с пользовательским управлением, не являющимся ужасным и можем продлить эту систему довольно легко. В Nginx есть вариант автоматически повторной проверки прозрачных кэшей в фоновом режиме, который может быть полезен, хотя кэш может быть не лучшим решением для этой проблемы производительности.

Идеи о том, как улучшить эту установку или рекомендации для альтернатив всегда приветствуются!

После написания все, что я нашел (или refort Я думаю, что есть какая-то официальная документация для такого типа установки из GitLab: https://gitlab.com/gitlab-example/review-apps-nginx Отказ

Оригинал: «https://dev.to/themasch/simple-gitlab-static-review-apps-using-nginx—2d9»