MAATRIX / Блог / Как установить и настроить Drone CI на VPS

Как установить и настроить Drone CI на VPS

MAATRIX

Jenkins тянет за собой Java-процесс на гигабайт памяти и плагины, которые ломаются при каждом обновлении. GitLab CI удобен, только если у вас уже есть GitLab. Drone CI устроен иначе: это два маленьких Go-бинарника в контейнерах — сервер и раннер, — а каждый шаг пайплайна выполняется в отдельном одноразовом Docker-контейнере, который скачал образ, отработал и исчез. Ниже — путь от чистого VPS до первого зелёного пайплайна.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Drone CI и почему он контейнерный

Drone построен на связке из двух компонентов. Drone Server — это веб-интерфейс, хранилище конфигурации пайплайнов и координатор: он получает вебхуки от Git-провайдера и раздаёт задания. Drone Runner — исполнитель: подключается к серверу по RPC, забирает задание и поднимает под него контейнеры. Раннеров может быть несколько, и они не обязаны жить на том же сервере, что и Drone Server — можно масштабировать исполнение отдельно от координации.

Ключевая идея Drone — каждый step пайплайна это отдельный Docker-контейнер, а не шаг в общей виртуалке, как у Jenkins с агентом. Шаг test может стартовать из образа golang:1.23, шаг build — из node:20, а шаг deploy — из вашего кастомного образа с kubectl и ssh, и все они изолированы друг от друга, кроме расшаренной рабочей директории. Это убирает целый класс проблем «а у меня на агенте другая версия node» и не требует ничего устанавливать на сервер, кроме Docker.

Минусы тоже стоит назвать честно: у Drone нет встроенного визуального конструктора пайплайнов (только YAML), сообщество меньше, чем у GitLab CI или GitHub Actions, а часть функций (matrix-сборки, сложные promotion-политики) закрыта в платной версии Drone Enterprise. Для типового проекта — сборка образа, тесты, деплой по SSH или в реестр — бесплатной версии хватает с запасом.

Требования к серверу и подготовка VPS

Drone Server лёгкий: 1 vCPU и 1–2 ГБ RAM вытянут координацию без проблем, база у него встроенная — SQLite по умолчанию, для нагрузки повыше можно переключить на PostgreSQL или MySQL через DRONE_DATABASE_DRIVER. Основные ресурсы съедает не сервер, а раннер — на время сборки контейнеры шага тянут CPU, RAM и диск под слои образов, так что под раннер закладывайте отдельно 2 vCPU / 4 ГБ RAM как стартовую точку, а для сборок с тестами баз данных или фронтенд-бандлов — больше.

Понадобится:

  • VPS с Ubuntu 22.04/24.04 или Debian 12, установленный Docker и Docker Compose plugin;
  • домен (или поддомен) с A-записью на сервер — Drone формирует OAuth callback-URL по этому адресу, работать по голому IP не получится;
  • доступ на редактирование настроек OAuth-приложений в вашем Git-провайдере — GitHub, GitLab, Bitbucket или self-hosted Gitea/Gitlab.

Если Docker ещё не установлен — сначала пройдите базовую установку, это отдельная тема с нюансами systemd и cgroup, которую я не буду дублировать здесь. Домен и DNS настраиваются так же, как для любого сервиса за реверс-прокси.

apt update && apt upgrade -y
mkdir -p /opt/drone && cd /opt/drone
docker --version && docker compose version

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

OAuth-приложение в Git-провайдере

Drone не хранит собственных пользователей — авторизация идёт через OAuth провайдера, у которого лежит ваш код. Дальше пример для self-hosted Gitea (логичная пара, если вы уже подняли Gitea на VPS), но для GitHub и GitLab процесс аналогичный — меняются только переменные окружения.

В Gitea: Настройки профиля → Приложения → Управление OAuth2-приложениями → Создать приложение OAuth2. Укажите:

  • Имя приложения: Drone CI;
  • Redirect URI: https://drone.example.com/login.

После сохранения Gitea покажет Client ID и Client Secret — секрет показывается один раз, скопируйте сразу. Если используете GitHub, аналогичная форма лежит в Settings → Developer settings → OAuth Apps, а callback URL там тот же формат: https://ваш-домен/login.

Здесь же сгенерируйте RPC-секрет — общий пароль, которым сервер и раннер аутентифицируют друг друга:

openssl rand -hex 16

Сохраните значение, оно понадобится в обоих docker-compose.yml ниже.

Развёртывание Drone Server

Создайте docker-compose.yml для сервера:

version: "3.8"
services:
  drone-server:
    image: drone/drone:2
    container_name: drone-server
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:80"
    volumes:
      - drone-data:/data
    environment:
      - DRONE_GITEA_SERVER=https://git.example.com
      - DRONE_GITEA_CLIENT_ID=ваш_client_id
      - DRONE_GITEA_CLIENT_SECRET=ваш_client_secret
      - DRONE_RPC_SECRET=секрет_из_openssl
      - DRONE_SERVER_HOST=drone.example.com
      - DRONE_SERVER_PROTO=https
      - DRONE_USER_CREATE=username:ваш_логин,admin:true
      - DRONE_LOGS_DEBUG=false
volumes:
  drone-data:

Для GitHub переменные другие: DRONE_GITHUB_CLIENT_ID, DRONE_GITHUB_CLIENT_SECRET. Для GitLab — DRONE_GITLAB_SERVER, DRONE_GITLAB_CLIENT_ID, DRONE_GITLAB_CLIENT_SECRET. Порт сервера намеренно смотрит только в 127.0.0.1 — наружу его отдаёт реверс-прокси с TLS, потому что OAuth callback обязан идти по HTTPS. Настройте Nginx или Caddy как реверс-прокси с SSL на drone.example.com, проксируя на 127.0.0.1:8080 и получив сертификат Let's Encrypt.

Запускаете:

docker compose up -d
docker compose logs -f drone-server

В логе должна появиться строка about starting the server без ошибок аутентификации. Откройте https://drone.example.com — Drone перенаправит на страницу авторизации вашего Git-провайдера, после согласия вернёт вас уже залогиненным.

Развёртывание раннера

Раннер — отдельный контейнер, который дёргает Docker-сокет хоста, чтобы поднимать контейнеры под шаги пайплайна. Отдельный docker-compose.yml (можно в том же каталоге, другим файлом или той же композицией):

services:
  drone-runner:
    image: drone/drone-runner-docker:1
    container_name: drone-runner
    restart: unless-stopped
    depends_on:
      - drone-server
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_RPC_PROTO=http
      - DRONE_RPC_HOST=drone-server
      - DRONE_RPC_SECRET=секрет_из_openssl
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NAME=runner-1

DRONE_RPC_SECRET должен быть побайтово тем же значением, что и в конфиге сервера — это единственный ключ доверия между ними, при опечатке раннер будет молча висеть без заданий и без внятной ошибки в UI. DRONE_RUNNER_CAPACITY — сколько пайплайнов раннер выполняет параллельно; ставьте по факту доступных CPU, а не «побольше», иначе сборки начнут конкурировать за ресурсы и падать по таймауту.

Обратите внимание: раннер получает доступ к Docker-сокету хоста напрямую (docker-out-of-docker), а не к изолированному docker-in-docker. Это стандартная и рекомендованная схема для Drone, но она означает, что любой пайплайн технически может достучаться до хостовых контейнеров через сокет. Для публичных репозиториев с внешними контрибьюторами это риск, который стоит держать в уме — ограничивайте, кто может пушить .drone.yml, отдельным раннером или политикой доступа в репозитории.

docker compose -f docker-compose.runner.yml up -d
docker compose -f docker-compose.runner.yml logs -f

В логах раннера должна появиться строка о успешном подключении к RPC-серверу и polling запуска.

Первый пайплайн и секреты

Зайдите в Drone UI, найдите нужный репозиторий во вкладке синхронизации и активируйте его — Drone сам зарегистрирует вебхук в Git-провайдере. С этого момента каждый push будет триггерить пайплайн, если в корне репозитория лежит файл .drone.yml:

kind: pipeline
type: docker
name: default

steps:
  - name: test
    image: node:20
    commands:
      - npm ci
      - npm test

  - name: build
    image: docker
    volumes:
      - name: dockersock
        path: /var/run/docker.sock
    commands:
      - docker build -t myapp:${DRONE_COMMIT_SHA:0:8} .
    when:
      branch:
        - main

  - name: deploy
    image: appleboy/drone-ssh
    settings:
      host: prod.example.com
      username: deploy
      key:
        from_secret: ssh_deploy_key
      script:
        - cd /opt/myapp && docker compose pull && docker compose up -d
    when:
      branch:
        - main

volumes:
  - name: dockersock
    host:
      path: /var/run/docker.sock

Секреты (SSH-ключи, токены реестра, пароли) не кладите в .drone.yml открытым текстом — добавьте их через UI: Repository → Settings → Secrets, дав каждому имя вроде ssh_deploy_key, и ссылайтесь на них через from_secret. Drone шифрует секреты при хранении и не показывает их значение в логах сборки, даже если шаг случайно выведет переменную через echo — там будет заглушка ***.

Если пайплайн собирает Docker-образ и вы хотите публиковать его в собственный реестр, а не Docker Hub, поднимите его рядом — вот как настроить приватный Docker registry на VPS, и добавьте логин в секреты шага build.

Обслуживание: обновление, бэкап и масштабирование

Обновление сводится к смене тега образа и пересозданию контейнера — состояние (пользователи, история сборок, секреты) живёт в volume drone-data, контейнер сам по себе одноразовый:

docker compose pull
docker compose up -d

Перед мажорным обновлением (например, между минорными релизами Drone 2.x) стоит снять бэкап volume — это тот же принцип, что для бэкапа Docker volume на VPS, только применительно к drone-data:

docker run --rm -v drone-data:/data -v $(pwd):/backup alpine \
  tar czf /backup/drone-data-$(date +%F).tar.gz -C /data .

Если сборок становится много и один раннер не справляется, поднимите второй drone-runner-docker контейнер на этом же или отдельном сервере — достаточно указать тот же DRONE_RPC_HOST и DRONE_RPC_SECRET, но другой DRONE_RUNNER_NAME. Drone Server сам распределит задания между доступными раннерами по свободной ёмкости, отдельно настраивать балансировку не нужно.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем Drone CI отличается от Jenkins и GitLab CI?

Drone легче по памяти (два небольших контейнера против гигабайтного Java-процесса Jenkins) и не требует своего Git-сервера, в отличие от GitLab CI, который завязан на сам GitLab. Расплата — меньше готовых плагинов и более скромный визуальный интерфейс, всё описывается YAML-файлом.

Можно ли использовать Drone с GitHub вместо Gitea?

Да, достаточно завести OAuth-приложение в GitHub и заменить переменные DRONE_GITEA_* на DRONE_GITHUB_* в конфиге сервера. Логика раннера и .drone.yml не меняется.

Обязательно ли ставить раннер на тот же сервер, что и Drone Server?

Нет. Раннер общается с сервером по RPC через сеть, так что его можно вынести на отдельный, более мощный VPS — например, если сборки требовательны к CPU, а сервер держат на минимальном тарифе.

Безопасно ли пробрасывать Docker-сокет в контейнер раннера?

Это стандартная для Drone схема, но она даёт пайплайну доступ уровня хоста к Docker. Для репозиториев с недоверенными контрибьюторами ограничивайте, кто может менять .drone.yml, или используйте отдельный изолированный раннер под такие проекты.

Как понять, что раннер не подключился к серверу?

В логах раннера не появится строка о polling, а новые сборки будут висеть в статусе Pending в UI бесконечно. В 9 случаях из 10 причина — несовпадение DRONE_RPC_SECRET между сервером и раннером или недоступность DRONE_RPC_HOST по сети.

Нужна ли отдельная база данных вместо SQLite?

Для одного проекта или небольшой команды SQLite, который идёт в комплекте, справляется без проблем. Переходить на PostgreSQL стоит, когда счёт активных репозиториев и параллельных сборок идёт на десятки, а не единицы.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →