GitLab: настройка Pages

Буквально вчера запустил Pages для GitLab. Поскольку документация не шибко понятная и информации мало, то решил расписать здесь как все было.

Кто не знает, что такое Pages рекомендую к просмотру следующий материал:

Публикация сайтов в GitLab Pages

Обновление GitLab

Постольку поскольку пропустил кучу обновлений, а на данный момент актуальной является версия 12.х, то надо было обновится, но при обновлении выскакивала ошибка о том, что сперва необходимо обновиться до версии 11.11. Идем в репозиторий Community Edition, копируем название пакета и выполняем обновление «yum upgrade gitlab-ce-11.11.5-ce.0.el7.x86_64». После обновления видим сообщение, что необходимо обновить PostgreSQL до версии 10, что и выполняем «gitlab-ctl pg-upgrade». Следом отправляем еще одну команду на обновление «yum upgrade gitlab-ce» и тогда уже произойдет обновление до версии 12.

Настройка GitLab

Теперь открываем конфиг /etc/gitlab/gitlab.rb, идем в секцию GitLab Pages и приводим к следующем виду:

################
# GitLab Pages #
################

## Define to enable GitLab Pages
pages_external_url "http://git.mydomain.com/"

gitlab_pages['enable'] = true
#gitlab_pages['external_http'] = nil # Configure to expose GitLab Pages on external IP address, serving the HTTP
#gitlab_pages['external_https'] = nil # Configure to expose GitLab Pages on external IP address, serving the HTTPS
gitlab_pages['listen_proxy'] = "localhost:8090"
#gitlab_pages['redirect_http'] = true
#gitlab_pages['use_http2'] = true
gitlab_pages['dir'] = "/var/opt/gitlab/gitlab-pages"
gitlab_pages['log_directory'] = "/var/log/gitlab/gitlab-pages"

######################
# GitLab Pages NGINX #
######################

pages_nginx['enable'] = true
pages_nginx['redirect_http_to_https'] = false
#pages_nginx['redirect_http_to_https_port'] = 80
#pages_nginx['ssl_certificate'] = "/etc/letsencrypt/live/git.mydomain.com/fullchain.pem"
#pages_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/git.mydomain.com/privkey.pem"
#pages_nginx['ssl_ciphers'] = "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"
#pages_nginx['ssl_prefer_server_ciphers'] = "on"
#pages_nginx['ssl_protocols'] = "TLSv1 TLSv1.1 TLSv1.2" # recommended by https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
#pages_nginx['ssl_session_cache'] = "builtin:1000  shared:SSL:10m" # recommended in http://nginx.org/en/docs/http/ngx_http_ssl_module.html
#pages_nginx['ssl_session_timeout'] = "5m" # default according to http://nginx.org/en/docs/http/ngx_http_ssl_module.html
#pages_nginx['ssl_dhparam'] = nil # Path to ci_dhparams.pem, eg. /etc/gitlab/ssl/ci_dhparams.pem
#pages_nginx['listen_addresses'] = ['*']
#pages_nginx['listen_port'] = nil # override only if you use a reverse proxy: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md#setting-the-nginx-listen-port
#pages_nginx['listen_https'] = nil # override only if your reverse proxy internally communicates over HTTP: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/nginx.md#supporting-proxied-ssl
#pages_nginx['custom_gitlab_server_config'] = "location ^~ /foo-namespace/bar-project/raw/ {\n deny all;\n}\n"

## Advanced settings
pages_nginx['dir'] = "/var/opt/gitlab/nginx"
pages_nginx['log_directory'] = "/var/log/gitlab/nginx"

Здесь настройки SSL закоментированы поскольку у меня пока, что нет возможности выписать Wildcard SSL сертификат для конторы (в процессе переезд DNS парковок), но если у вас есть, то раскоментируйте.

Настройка DNS

В DNS надо будет зарегистрировать Wildcard A-запись. В Bind это выглядит следующим образом:

$TTL 14400
@       IN      SOA     mydomain.com root.mydomain.com (
                        1430170619      ; serial
                        10800           ; refresh
                        3600            ; retry
                        604800          ; expire
                        38400 )         ; minimum
@                       IN      NS      mydomain.com.
mydomain.com.           IN      A       192.168.0.4
www                     IN      CNAME   mydomain.com.
git			IN	A	192.168.0.11
*.git			IN	A	192.168.0.11

Это нужно, чтобы GitLab сам определял поддомены.

Настройка Reverse Proxy

Если у вас нету реверсивного прокси, то пропускайте данный шаг, а у меня он есть в виде Nginx. Поскольку у меня нет Wildcard сертификата, то прописал все директивы в блок для HTTP отключив редирект на HTTPS. Если у вас есть сертификат, то пропишите в блоке для HTTPS.

server {
        listen 80;
        #rewrite ^(.*) https://$host$1;
        server_name ~^(?<subdomain>.*)\.git.mydomain.com$;
        server_tokens off;
        disable_symlinks on;
        location / {
                proxy_pass http://192.168.0.11/;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $http_host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Nginx-Proxy true;
                proxy_cache off;
                proxy_redirect off;
        }
}

Установка Gitlab Runner

Да, да. Он нужен для сборки страниц. Если у вас уже есть какой-либо Runner, то опять таки пропускаем данный шаг. Вообщем установил его на одном из свободных виртуальных машин:

$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash
$ yum install gitlab-runner
$ systemctl enable gitlab-runner
$ systemctl start gitlab-runner

Теперь, чтобы зарегистрировать Runner надо в GitLab создать проект (скажем пусть будет pages-test) и зайти в настройки «Settings -> CI/CD -> Runners». В секции «Set up a specific Runner manually» увидим url и token, которыми и воспользуемся:

$ gitlab-runner register
https://git.mydomain.com/
# токен не покажу, но тут надо его вводить
# далее надо задать имя раннеру
# тег (зададим например pages)
# выбрать метод сборки. Пусть будет shell.

Тег после регистрации раннера не меняется, но используется для запуска раннера, так что если захотите удалить раннер, то надо делать следующим образом:

$ gitlab-runner unregister --name <runner_name>
$ gitlab-runner verify --delete
$ gitlab-runner list

Таким образом раннеры надо подключать во все проекты, которые хотят использовать Pages.

Сборка

Теперь идем обратно в репозиторий и создаем новый файл. Сверху в меню Template выбираем .gitlab-ci.yml. В «Apply a GitLab CI Yaml template» выбираем например HTML. Шаблон должен получится примерно таким (обратите внимание на tags):

pages:
  stage: deploy
  script:
    - mkdir .public
    - cp -r * .public
    - mv .public public
  artifacts:
    paths:
      - public
  only:
    - master
  tags:
    - pages

Теперь создадим еще один файл index.html:

<html>
<title>pages test</title>
<h1>pages test</h1>
</html>

Как только сделаете коммит сразу же начнется сборка, в чем можно убедится пройдя в меню «CI/CD -> Pipelines». После сборки идем в «Settings -> Pages» и в «Access pages» видим ссылку на нашу страницу.

Настройка Shared Runner

Shared Runner позволяет использовать раннер в любом проекте. Если уже регистрировали раннер, то удалите ну или добавьте как новый. Необходимо залогиниться под администратором и в меню «Admin Area -> Runners» скопировать url и token с секции «Shared Runners». Дальше регистрируем как обычный runner:

$ gitlab-runner register
https://git.mydomain.com/
# токен не покажу, но тут надо его вводить
# далее надо задать имя раннеру
# тег (зададим например pages)
# выбрать метод сборки. Пусть будет shell.

Траблы

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

npm ERR! Linux 3.10.0-693.11.6.el7.x86_64
npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install" "gitbook-cli" "-g"
npm ERR! node v6.16.0
npm ERR! npm  v3.10.10
npm ERR! path /usr/lib/node_modules
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall accessnpm ERR! Error: EACCES: permission denied, access '/usr/lib/node_modules'
npm ERR!     at Error (native)
npm ERR!  { Error: EACCES: permission denied, access '/usr/lib/node_modules'
npm ERR!     at Error (native)
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/lib/node_modules' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.npm ERR! Please include the following file with any support request:
npm ERR!     /home/gitlab-runner/builds/z34uLw31/0/al/ms-tech-docs/npm-debug.log

Вот пример .gitlab-ci.yml:

# requiring the environment of NodeJS 10
image: node:10

# add 'node_modules' to cache for speeding up builds
cache:
  paths:
    - node_modules/ # Node modules and dependencies

before_script:
  - npm install gitbook-cli -g # install gitbook
  - gitbook fetch 3.2.3 # fetch final stable version
  - gitbook install # add any requested plugins in book.json

test:
  stage: test
  script:
    - gitbook build . public # build to public path
  only:
    - branches # this job will affect every branch except 'master'
  except:
    - master

# the 'pages' job will deploy and build your site to the 'public' path
pages:
  stage: deploy
  script:
    - gitbook build . public # build to public path
  artifacts:
    paths:
      - public
    expire_in: 1 week
  only:
    - master # this job will affect only the 'master' branch
  tags:
    - pages

Вообщем раннер никак не может установить пакеты npm. Перебрали кучу разных вариантов вроде использования su и unsafe-perm, но помог только запуск раннера из-под рута. Открываем /etc/systemd/system/gitlab-runner.service и в строке ExecStart меняем значение параметра —user на root. Перезапускаем сервис и все работает. Конечно не секьюрно, но что делать.

Что с правами доступа к Pages?

Добавляем в /etc/gitlab/gitlab.rb строку:

gitlab_pages['access_control'] = true

Выполняем gitlab-ctl reconfigure и в настройках проекта «Settings -> General -> Visibility, project features, permissions -> Pages access control» выбираем необходимый вариант доступа к странице. При первом посещении страницы будет предложено разрешить GitLab Pages доступ к вашему аккаунту.

Заключение

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

UPDATE

Время от времени стал падать Pages с ошибкой 503. В логах видно «connection: no route to host». Оказывается Pages хранит бинды в директории /tmp, а в RHEL подобных дистрибутивах используется служба systemd-tmpfiles-clean для очистки временных файлов. Это и провоцирует падение Pages.
Решений на сколько понял ровно два. Первое это перенастройка службы systemd-tmpfiles и второе это использовать опцию gitlab_pages[‘inplace_chroot’] = true, тогда временные файлы должны ложится в Pages Root Directory. Естественно пошел первым путем.

SYSTEMD-TMPFILES

Настройки лежат в /lib/tmpfiles.d/, а интересует нас конфигурация tmp.conf. Здесь опция «x» означает, что надо исключить директорию и все что в ней лежит, а «X» означает, что надо исключить директорию, но все содержимое директории удалить. Соответственно пишем «x /tmp/gitlab-pages-*», сохраняем и перезапускаем GitLab. Сама же служба видимо запускается по крону поскольку всегда находится в состоянии «inactive (dead)».

UPDATE: This job is stuck, because the project doesn’t have any runners online assigned to it

Обратился один из программистов и говорит, что раннер завис. И действительно не принимал job на обработку повисая в статусе pending. Оказалось, что job был без тега, а раннер по-умолчанию не принимает такие. Идем в Admin Area -> Runners -> Edit и устанавливаем галочку «Run untagged jobs».