MAATRIX / Блог / Woodpecker CI на Ubuntu 24.04: пошаговая установка

Woodpecker CI на Ubuntu 24.04: пошаговая установка

MAATRIX

Drone CI в 2019 году поменял лицензию, и часть его функций ушла за платный Enterprise-контур — сообщество разработчиков форкнуло последнюю открытую версию и с тех пор развивает её отдельно под именем Woodpecker CI. Если вам нужен self-hosted CI/CD без вендор-лока и без ограничений на количество репозиториев и пайплайнов, а Jenkins кажется тяжеловесным, Woodpecker — рабочий вариант на замену. Ниже — установка с нуля на чистом Ubuntu 24.04: сервер, агент, интеграция с Gitea и HTTPS через Caddy.

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

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

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

Что такое Woodpecker CI и чем он отличается от Drone

Woodpecker — полностью open-source (Apache 2.0), без «урезанной свободной версии» и без функций, которые появляются только в платной подписке. Архитектура простая и знакомая всем, кто работал с Drone:

  • Server — веб-интерфейс, API, хранит конфигурацию репозиториев и историю сборок в SQLite (по умолчанию) или Postgres/MySQL.
  • Agent — воркер, который реально выполняет шаги пайплайна в Docker-контейнерах. Агентов можно масштабировать горизонтально — хоть на других серверах, лишь бы был доступ до server по gRPC.
  • Forge — так в Woodpecker называют git-провайдера для OAuth-авторизации и вебхуков: Gitea, GitHub, GitLab, Bitbucket, Forgejo.

Пайплайны описываются в файле .woodpecker.yml в корне репозитория — синтаксис похож на Drone, но с ключом steps: вместо старого pipeline:. Каждый шаг — это отдельный Docker-образ с командами, что даёт изоляцию и воспроизводимость сборок без ручной настройки окружения на хосте.

Для установки понадобится сервер с Docker, публичный домен (или поддомен) с DNS-записью на него и уже работающий git-фордж — в примерах ниже используется Gitea, но с GitHub или GitLab шаги авторизации отличаются только названием переменных.

Подготовка сервера

Минимум для сервера + одного агента — 2 vCPU и 4 ГБ RAM: сам Woodpecker лёгкий, но каждый параллельный шаг пайплайна поднимает отдельный Docker-контейнер, и именно они съедают ресурсы. Под нагрузку CI с несколькими одновременными сборками закладывайте с запасом — конкретные цифры сильно зависят от того, что вы собираете (сборка Node.js-проекта и компиляция Rust требуют разного).

Обновите систему и поставьте Docker, если его ещё нет:

apt update && apt upgrade -y
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker compose version

Создайте рабочую директорию и сгенерируйте секрет для связи сервера с агентами — это не пароль пользователя, а общий ключ на gRPC-соединение:

mkdir -p /opt/woodpecker && cd /opt/woodpecker
openssl rand -hex 32

Сохраните полученную строку — она пойдёт в WOODPECKER_AGENT_SECRET в двух местах ниже.

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

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

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

OAuth-приложение в Gitea

Woodpecker авторизует пользователей и получает вебхуки через forge, поэтому сначала регистрируем OAuth2-приложение. В Gitea: Settings → Applications → Manage OAuth2 Applications → Create a new OAuth2 Application.

  • Application Name: Woodpecker CI
  • Redirect URI: https://ci.example.com/authorize (замените на ваш будущий домен CI)

После сохранения Gitea покажет Client ID и Client Secret — их нужно скопировать сразу, секрет повторно не показывается. Если используете GitHub или GitLab, аналогичная форма OAuth-приложения есть в настройках разработчика аккаунта/организации, callback URL тот же принцип: https://ваш-домен-ci/authorize.

docker-compose.yml для сервера и агента

Создайте файл /opt/woodpecker/docker-compose.yml:

services:
  woodpecker-server:
    image: woodpeckerci/woodpecker-server:latest
    container_name: woodpecker-server
    restart: unless-stopped
    ports:
      - "127.0.0.1:8000:8000"
    volumes:
      - woodpecker-server-data:/var/lib/woodpecker/
    environment:
      - WOODPECKER_OPEN=false
      - WOODPECKER_HOST=https://ci.example.com
      - WOODPECKER_ADMIN=your-gitea-username
      - WOODPECKER_GITEA=true
      - WOODPECKER_GITEA_URL=https://git.example.com
      - WOODPECKER_GITEA_CLIENT=вставьте_client_id
      - WOODPECKER_GITEA_SECRET=вставьте_client_secret
      - WOODPECKER_AGENT_SECRET=вставьте_сгенерированный_секрет

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:latest
    container_name: woodpecker-agent
    command: agent
    restart: unless-stopped
    depends_on:
      - woodpecker-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WOODPECKER_SERVER=woodpecker-server:9000
      - WOODPECKER_AGENT_SECRET=вставьте_сгенерированный_секрет
      - WOODPECKER_MAX_WORKFLOWS=2

volumes:
  woodpecker-server-data:

Пояснения по ключевым переменным:

  • WOODPECKER_OPEN=false — самостоятельная регистрация новых пользователей отключена, доступ дают вручную. Для одиночного сервера это правильная настройка по умолчанию.
  • WOODPECKER_ADMIN — username в вашем forge, который получит права администратора Woodpecker при первом входе.
  • Порт 8000 сервера пробрасывается только на 127.0.0.1 — наружу его отдаст Caddy по HTTPS, напрямую в интернет открывать не нужно.
  • Агент получает доступ к docker.sock хоста — это стандартный для Woodpecker (как и для Drone, Jenkins-агентов и GitLab Runner) способ запускать шаги пайплайна в контейнерах-соседях. Учитывайте это как компромисс безопасности: у процессов внутри пайплайна фактически есть доступ к Docker-демону хоста, поэтому не давайте запуск произвольных пайплайнов недоверенным пользователям.
  • WOODPECKER_MAX_WORKFLOWS ограничивает число параллельных сборок на одном агенте — подберите под RAM/CPU сервера, начните с 2 и смотрите на нагрузку.

Поднимите стек:

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

В логах сервера должно появиться сообщение о старте HTTP-сервера на :8000 и об успешном подключении агента.

Reverse proxy и HTTPS через Caddy

Woodpecker сам HTTPS не терминирует, поэтому нужен прокси перед ним. Если Caddy ещё не установлен — ставится одной командой, подробности разворачивания и автообновления сертификатов есть в отдельной статье про установку Caddy на Ubuntu 24.04.

apt install -y caddy

Конфиг /etc/caddy/Caddyfile:

ci.example.com {
    reverse_proxy 127.0.0.1:8000
    encode gzip
}

Перезапустите Caddy — сертификат Let's Encrypt выпустится автоматически при первом обращении, никаких дополнительных шагов не требуется:

systemctl reload caddy

Проверьте DNS: A-запись ci.example.com должна указывать на IP сервера ещё до запуска Caddy, иначе выпуск сертификата упадёт по HTTP-01 challenge. Откройте https://ci.example.com — должна открыться страница логина Woodpecker с кнопкой входа через Gitea.

Первый вход и подключение репозитория

Зайдите под своим forge-аккаунтом — Woodpecker перенаправит на OAuth-авторизацию в Gitea и вернётся обратно уже залогиненным. Если username совпадает со значением WOODPECKER_ADMIN, в интерфейсе появится раздел администрирования.

Дальше — Add Repository: Woodpecker покажет список ваших репозиториев в Gitea, включите нужный переключателем. При активации он сам создаёт вебхук в настройках репозитория (Settings → Webhooks в Gitea) — проверять руками не нужно, но полезно знать, что он там появляется, если потом будете разбираться, почему сборки не триггерятся.

Добавьте в корень репозитория файл .woodpecker.yml:

steps:
  build:
    image: node:20-alpine
    commands:
      - npm ci
      - npm run build

  test:
    image: node:20-alpine
    commands:
      - npm test
    when:
      - event: push
      - event: pull_request

  deploy:
    image: alpine:3.20
    commands:
      - echo "деплой запускается только из main"
    when:
      - branch: main
        event: push

Закоммитьте и запушьте — вебхук долетит до Woodpecker, агент подхватит пайплайн, поднимет для каждого шага отдельный контейнер из указанного образа и выполнит команды по порядку. Прогресс и логи каждого шага видны в реальном времени в веб-интерфейсе, на вкладке репозитория.

Хранение секретов и переменных окружения

Секреты (токены, пароли БД, ключи API) не кладут в .woodpecker.yml открытым текстом — для этого есть встроенное хранилище секретов. В веб-интерфейсе: Repository → Settings → Secrets → Add Secret, задаёте имя и значение, при желании ограничиваете, к каким событиям (push, tag, pull_request) и шагам секрет применяется.

В пайплайне секрет подключается так:

steps:
  deploy:
    image: alpine:3.20
    commands:
      - echo "$DEPLOY_TOKEN" | some-deploy-tool --token-stdin
    secrets: [deploy_token]

Значение секрета маскируется в логах автоматически — Woodpecker подменяет его на *** при выводе, если строка встречается в stdout/stderr шага. Это не железобетонная защита (секрет всё равно доступен процессу внутри контейнера), но от случайного попадания в публичные логи спасает.

Для секретов, общих на несколько репозиториев одной организации, есть уровень Organization Secrets — задаются в настройках организации в Woodpecker и видны всем репозиториям внутри неё без дублирования.

Масштабирование агентов и резервное копирование

Если одного агента не хватает — параллельных пайплайнов много и они выстраиваются в очередь — добавьте второй сервис woodpecker-agent в docker-compose (с тем же WOODPECKER_AGENT_SECRET) либо вынесите агент на отдельный сервер, указав в его переменных WOODPECKER_SERVER=ci.example.com:9000 (порт 9000 сервера тогда нужно открыть для gRPC — по возможности ограничьте его файрволом только IP-адресами доверенных агентов).

Данные сервера — конфигурация репозиториев, история сборок, пользователи — лежат в volume woodpecker-server-data, по умолчанию это SQLite-файл. Бэкап сводится к остановке контейнера и копированию volume:

docker compose stop woodpecker-server
docker run --rm -v woodpecker_woodpecker-server-data:/data \
  -v /opt/backups:/backup alpine \
  tar czf /backup/woodpecker-$(date +%F).tar.gz -C /data .
docker compose start woodpecker-server

Для продакшена с высокой нагрузкой на СУБД лучше сразу вынести базу на внешний Postgres через WOODPECKER_DATABASE_DRIVER=postgres и WOODPECKER_DATABASE_DATASOURCE — SQLite под конкурентную запись из нескольких процессов не рассчитан и на некоторых нагрузках становится узким местом.

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

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

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

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

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

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

Чем Woodpecker принципиально лучше Drone CI?

Он полностью open-source без искусственно урезанной бесплатной версии — все функции доступны без Enterprise-лицензии. Синтаксис пайплайнов почти идентичен, миграция с последней открытой версии Drone простая.

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

Да, поддерживаются GitHub, GitLab, Bitbucket и Forgejo — меняются только переменные окружения (WOODPECKER_GITHUB, WOODPECKER_GITHUB_CLIENT и т.д.) и адрес callback в OAuth-приложении провайдера.

Нужен ли docker.sock агенту обязательно?

Для docker-backend (стандартного и самого частого) — да. Есть альтернативные бэкенды (Kubernetes, exec на голом хосте без изоляции), но они требуют отдельной настройки и подходят не для всех сценариев.

Что делать, если пайплайн не запускается после пуша?

Проверьте, что вебхук в Gitea (Settings репозитория → Webhooks) активен и последние доставки помечены зелёным; частая причина — сервер Woodpecker недоступен извне по адресу из WOODPECKER_HOST в момент доставки вебхука.

Можно ли запускать сборки вручную, без пуша?

Да, через веб-интерфейс кнопкой Restart/Trigger на существующей сборке, либо через woodpecker-cli — официальный CLI, который общается с сервером по тому же API, что и веб-интерфейс.

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

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

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