GitLab CE в Docker Compose с Traefik

Обновлено и опубликовано Опубликовано:

Используемые термины: GitLabDockerTraefik.

В этой инструкции развернем GitLab CE в Docker Compose с Traefik в роли reverse proxy: Traefik возьмет на себя TLS через Let's Encrypt, а GitLab будет работать за ним по HTTPS. Команды приведены для Ubuntu, Debian и RPM-дистрибутивов отдельно, где это нужно.

Требования

  • Linux-сервер с публичным IP и установленными Docker Engine и Docker Compose plugin. Подробнее об этом ниже.
  • Не менее 4 ГБ оперативной памяти — Omnibus GitLab требователен к RAM даже с уменьшенным числом воркеров.
  • DNS A-запись домена GitLab на IP сервера.
  • Открытые порты 80, 443 (HTTP/HTTPS) и 22 (Git по SSH).

Убедимся, что Docker и Compose plugin уже установлены на сервере:

docker --version

docker-compose version

Если docker compose установлен как плагин, то команда будет:

docker compose version

* если команд нет — потребуется установка Docker Compose и Docker Engine. Подробнее об этом в конце инструкции.

Смена SSH-порта хоста на 2222

В compose GitLab публикует 22:22. Для удобства работы с Gitlab лучше так и оставить, но чтобы порт 22 на хосте не занял sshd, перенесем системный SSH на 2222 до запуска контейнеров. Сессию не закрываем, пока не проверим вход по новому порту.

Создадим конфиг с новым портом:

mkdir -p /etc/ssh/sshd_config.d

vi /etc/ssh/sshd_config.d/port.conf

Port 2222

* Port 2222 — порт SSH самой хостовой системы; GitLab будет слушать 22.
** на старых системах (Debian 10, CentOS 7) в основном sshd_config может не быть директивы Include для sshd_config.d — проверьте это, иначе конфиг не подхватится. В таком случае, настройки нужно делать в файле /etc/ssh/sshd_config.

Откроем порт 2222 в firewall — выберем вариант под свою систему.

а) firewall — Iptables (Deb):

iptables -I INPUT -p tcp --dport 2222 -j ACCEPT

netfilter-persistent save

б) firewall — UFW (Deb):

ufw allow 2222/tcp && ufw reload

в) firewall — firewalld (RPM):

firewall-cmd --permanent --add-port=2222/tcp

firewall-cmd --reload

Проверим, какие порты слушает сервер:

ss -tlnp | grep -E ':22|:2222'

* на 2222 должен слушать sshd хоста; порт 22 пока свободен — его займет контейнер GitLab.

Во втором терминале проверьте вход: ssh -p 2222 root@IP. Только после успешного входа продолжайте.

Применим новый порт и перезапустим SSH — выберем вариант под свой дистрибутив.

а) для Deb (Debian / Ubuntu):

sshd -t && systemctl restart ssh

б) для RPM (Rocky Linux / AlmaLinux / Fedora):

semanage port -a -t ssh_port_t -p tcp 2222 || semanage port -m -t ssh_port_t -p tcp 2222

sshd -t && systemctl restart sshd

* где:

  • sshd -t — проверка синтаксиса конфига до перезапуска.
  • semanage port — разрешение нестандартного SSH-порта в SELinux (RPM).

Порт SSH хоста сменен, можно переходить к развертыванию GitLab.

Каталог и переменные окружения

Создадим рабочий каталог проекта и перейдем в него:

mkdir -p /opt/gitlab && cd /opt/gitlab

Опишем переменные окружения в файле .env:

vi .env

TZ=Europe/Moscow
TRAEFIK_TAG=v3.6
GITLAB_TAG=19.2.2-ce.0
ACME_EMAIL=admin@example.com
GITLAB_HOST=gitlab.dmosk.ru
GITLAB_ROOT_PASSWORD=ChangeMe_StrongPass1

* где:

  • TZ — часовой пояс контейнеров и GitLab; замените на свой, если сервер не в московском часовом поясе (например, Etc/UTC).
  • TRAEFIK_TAG / GITLAB_TAG — теги образов; при необходимости зафиксируйте более актуальные версии, сверив их с Docker Hub.
  • ACME_EMAIL — email для Let's Encrypt.
  • GITLAB_HOST — FQDN GitLab; A-запись должна указывать на этот сервер.
  • GITLAB_ROOT_PASSWORD — начальный пароль пользователя root (не короче 8 символов); применяется только при первой инициализации.

Файл docker-compose.yml

Опишем сервисы Traefik и GitLab в docker-compose.yml:

vi docker-compose.yml

services:

  traefik:
    image: traefik:${TRAEFIK_TAG}
    container_name: gitlab-traefik
    hostname: traefik
    restart: unless-stopped
    environment:
      TZ: ${TZ}
      DOCKER_API_VERSION: 1.44
    command:
      - "--log.level=INFO"
      - "--ping=true"
      - "--api.dashboard=false"
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.docker.network=gitlab"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/letsencrypt:/letsencrypt
    networks:
      - gitlab
    healthcheck:
      test: ["CMD-SHELL", "traefik healthcheck --ping"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 5s

  gitlab:
    image: gitlab/gitlab-ce:${GITLAB_TAG}
    container_name: gitlab
    hostname: ${GITLAB_HOST}
    restart: unless-stopped
    shm_size: "512m"
    environment:
      TZ: ${TZ}
      GITLAB_ROOT_PASSWORD: ${GITLAB_ROOT_PASSWORD}
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://${GITLAB_HOST}'
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        gitlab_rails['gitlab_shell_ssh_port'] = 22
        gitlab_rails['time_zone'] = '${TZ}'
        nginx['real_ip_trusted_addresses'] = ['172.16.0.0/12', '10.0.0.0/8', '192.168.0.0/16']
        nginx['real_ip_header'] = 'X-Forwarded-For'
        nginx['real_ip_recursive'] = 'on'
        puma['worker_processes'] = 2
        sidekiq['concurrency'] = 5
        prometheus_monitoring['enable'] = false
        alertmanager['enable'] = false
        node_exporter['enable'] = false
        redis_exporter['enable'] = false
        postgres_exporter['enable'] = false
        gitlab_exporter['enable'] = false
    expose:
      - "80"
    ports:
      - "22:22"
    volumes:
      - ./gitlab/config:/etc/gitlab
      - ./gitlab/logs:/var/log/gitlab
      - ./gitlab/data:/var/opt/gitlab
    networks:
      - gitlab
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=gitlab"
      - "traefik.http.routers.gitlab.rule=Host(`${GITLAB_HOST}`)"
      - "traefik.http.routers.gitlab.entrypoints=websecure"
      - "traefik.http.routers.gitlab.tls.certresolver=letsencrypt"
      - "traefik.http.routers.gitlab.service=gitlab"
      - "traefik.http.routers.gitlab-http.rule=Host(`${GITLAB_HOST}`)"
      - "traefik.http.routers.gitlab-http.entrypoints=web"
      - "traefik.http.routers.gitlab-http.middlewares=gitlab-redirect-https"
      - "traefik.http.routers.gitlab-http.service=gitlab"
      - "traefik.http.middlewares.gitlab-redirect-https.redirectscheme.scheme=https"
      - "traefik.http.middlewares.gitlab-redirect-https.redirectscheme.permanent=true"
      - "traefik.http.services.gitlab.loadbalancer.server.port=80"
      - "traefik.http.services.gitlab.loadbalancer.passhostheader=true"
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:80/-/health || exit 1"]
      interval: 60s
      timeout: 10s
      retries: 10
      start_period: 600s

networks:
  gitlab:
    name: gitlab
    driver: bridge

* где:

  • traefik — reverse proxy на 80/443, HTTP→HTTPS и выпуск сертификата Let's Encrypt.
  • DOCKER_API_VERSION — версия Docker API для провайдера Traefik; задана прямо в этом файле, отдельной переменной в .env для нее нет. На старых версиях Docker Engine значение может не совпасть с поддерживаемым API — тогда версию нужно снизить.
  • prometheus_monitoring / node_exporter / redis_exporter / postgres_exporter / gitlab_exporter — отключены для экономии ресурсов. Если нужны графики производительности во встроенной админке GitLab — уберите эти строки или замените false на true.
  • gitlab — GitLab CE; nginx внутри слушает 80 без TLS, TLS терминирует Traefik.
  • ports 22:22 — Git по SSH на стандартном порту 22 хоста.
  • ./gitlab/config, ./gitlab/logs, ./gitlab/data — постоянные данные Omnibus GitLab относительно /opt/gitlab.
  • start_period: 600s — первый старт GitLab может занимать несколько минут.

На RPM-системах с SELinux (Rocky Linux, AlmaLinux, RHEL) примонтированные локальные каталоги могут упасть с ошибкой Permission denied. Если это произошло, добавьте суффикс :Z к путям в volumes, например ./gitlab/config:/etc/gitlab:Z.

Запуск и первый вход

Запустим стек:

docker-compose up -d

Проверим статус контейнеров:

docker-compose ps

Посмотрим лог инициализации GitLab:

docker-compose logs -f --tail=100 gitlab

* ждем строки вроде gitlab Reconfigured! / готовности healthcheck; выход из follow — Ctrl+C.

Открываем в браузере https://gitlab.dmosk.ru (в вашем случае будет другой домен). Вводим данные для входа:

  • Логин: root
  • Пароль: значение GITLAB_ROOT_PASSWORD из /opt/gitlab/.env

Убедимся, что порты распределены верно:

ss -tlnp | grep -E ':22|:2222'

* 2222 — sshd хоста; 22 — SSH GitLab (git clone/push по SSH без указания нестандартного порта).

Стоит сразу сменим пароль root в интерфейсе GitLab и убрать GITLAB_ROOT_PASSWORD из .env — переменная нужна только для первой инициализации.

Резервное копирование

Рассмотрим небольшой пример, как сделать резервную копию и восстановиться из нее.

Остановка и бэкап

Сделаем бэкап данных перед остановкой:

cd /opt/gitlab && docker-compose exec -T gitlab gitlab-backup create STRATEGY=copy

* архив появится в /opt/gitlab/data/backups внутри volume data.

Остановим стек:

docker-compose down

* контейнеры остановлены; каталоги config, logs, data, traefik на диске сохраняются.

Заберем бэкап и конфигурацию с сервера одним архивом:

tar -czf /root/gitlab-backup-$(date +%F).tar.gz -C /opt gitlab/config gitlab/data gitlab/traefik gitlab/.env gitlab/docker-compose.yml

* где:

  • config / data — конфигурация Omnibus GitLab и данные приложения (репозитории, БД, uploads).
  • traefik — в том числе acme.json с сертификатами.
  • .env и docker-compose.yml — чтобы поднять тот же стенд на другом сервере.

В архиве оказываются секреты в открытом виде: gitlab-secrets.json из config (без него не расшифровать данные БД) и пароль root из .env. Храните архив в безопасном месте и ограничьте к нему доступ.

Вернем стек в работу:

docker-compose up -d

* возврат сервисов после бэкапа файлов.

Восстановление из бэкапа

Перед восстановлением остановим внутренние сервисы GitLab, которые пишут в базу:

docker-compose exec -T gitlab gitlab-ctl stop puma

docker-compose exec -T gitlab gitlab-ctl stop sidekiq

Запустим восстановление из архива:

docker-compose exec -T gitlab gitlab-backup restore BACKUP=1717000000_2024_06_01_16.11.0-ce

* BACKUP — имя архива из /opt/gitlab/data/backups без суффикса _gitlab_backup.tar.

Вернем сервисы в работу:

docker-compose exec -T gitlab gitlab-ctl start

GitLab восстановлен из бэкапа и снова доступен по HTTPS.

Обновление GitLab

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

Поднимем значение GITLAB_TAG (и при необходимости TRAEFIK_TAG) в .env:

vi .env

...
TRAEFIK_TAG=vXXX
GITLAB_TAG=XXX
...

Затем обновим образы и перезапустим стек:

docker-compose pull

docker-compose up -d

* GitLab выполнит reconfigure и миграции автоматически при старте; прогресс смотрим через docker-compose logs -f --tail=100 gitlab.

GitLab CE развернут в Docker Compose за Traefik и готов к работе.

Возможные проблемы

Рассмотрим несколько наиболее популярных проблем.

1. Traefik отдаёт 502 при старте

После запуска контейнера веб-интерфейс не грузится и отдает ошибку 502.

Причина: GitLab проходит внутренний reconfigure — инициализация БД, миграции, запуск puma/sidekiq. Контейнер уже поднялся, но приложение ещё не готово принимать запросы.

Решение: дождаться перехода healthcheck в healthy. Для этого в конфиге задаётся start_period: 600s — GitLab может стартовать до 10 минут. Проверить состояние можно командой:

docker ps --filter name=gitlab

Пока статус (health: starting) — 502 это норма, просто ждём.

2. Let's Encrypt перестаёт выдавать сертификаты

Причина: лимит — 5 сертификатов на один домен в неделю. При частом пересоздании контейнера Traefik каждый раз запрашивает новый сертификат и упирается в ограничение.

Решение: хранить сертификаты в томе и не удалять его между перезапусками. Настройка для этого находится в директиве volumes:

traefik:
  ...
  volumes:
    - ./traefik/letsencrypt:/letsencrypt  # не удалять эту папку

Если лимит уже исчерпан — ждать неделю или использовать staging-сервер Let's Encrypt для тестов.

3. GitLab падает из-за нехватки памяти

Gitlab перестает работать, а в статусе контейнеров можно наблюдать периодические перезапуски.

Причина: puma (веб-сервер) и sidekiq (фоновые задачи) по умолчанию потребляют много RAM. На сервере с 2–4 ГБ GitLab просто не стартует или убивается OOM-killer'ом.

Решение: уменьшить количество воркеров в docker-compose.yml:

gitlab:
  environment:
    GITLAB_OMNIBUS_CONFIG: |
      puma['worker_processes'] = 2
      sidekiq['concurrency'] = 10

Либо увеличить RAM сервера — минимально комфортно 4 ГБ, лучше 8 ГБ.

Читайте также

Полезные инструкции, связанные с данной темой:

1. Установка Docker Compose на Linux.

2. Установка веб-инструмента GitLab на Rocky.

3. Установка веб-инструмента GitLab на Linux Ubuntu Server.

# DevOps # Gitlab # Контейнеризация # Серверы
Дмитрий Моск — частный мастер
Был ли вам полезен этот скрипт?

Да            Нет

Дмитрий Моск
— IT-специалист.
Настройка серверов, услуги DevOps.

Заказать настройку контейнеризации

Нужна бесплатная консультация?

Скрипты

GitLab CE в Docker Compose за Traefik с HTTPS

Пример манифеста для запуска Swagger в Kubernetes

Пример скрипта для миграции запущенной виртуальной машины Proxmox с ZFS репликацией

Пример манифеста для развертывания Hermes AI в Kubernetes

Пример файла docker-compose для развертывания брокера Kafka

Пример сценария docker-compose для запуска сервера Dependency-Track

Запуск SonarQube Server в контейнере с помощью docker-compose

Другие скрипты

Все статьи

Нужен скрипт? Опишите его назначение:





Реклама