Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Hi there, I’m Yura Zatsepin. This is a tutorial for Woodpecker—a CI/CD system.

This tutorial exists because I’m trying to find a good CI for “non K8S world”, fully locally and which can give me a fresh perspective. This is all about Woodpecker CI, which was formerly a fork of Drone CI. Drone CI I used long time ago on couple projects. It was a real lightweight solution after Jenkins and TeamCity where I had my experience before.

I know Woodpecker CI doesn’t yet offer many battle-tested features from modern commercial CI, but it’s an open source and very niche product. It’s based on ideas already applied in Gitlab CI and GitHub Actions. But the core advantage from Drone is still here: you can start working with CI locally. You don’t need external solutions for this like Gitlab local runner or GitHub Actions - act CLI. Here you can install Woodpecker-cli and write some YAML files and you’re ready. Our workflows can be run locally. If we see a broken pipeline on Woodpecker server, we can download metadata from a failed build and re-run it locally. In general, you can start writing CI workflows when starting a new project from day 0 without any server at all. Yes, GitHub Actions is available. And it’s actually great. But when you need a self-hosted, fully open CI solution for modern world dev experience this is what you probably need Woodpecker CI.

I am writing tutorials here after some personal research about this tool. Actually, I already have production pipelines on this CI and I’ve encountered some problems with hosting it and deploying certain things. The docs are great, but they don’t address all the challenges I faced. I find this book a good place to save my thoughts for the future and anyone who wants to try Woodpecker.

In the current version, this book is written in Russian language.

How to read this tutorial

Пока каждый раздел — это отдельная статья о Woodpecker CI. Можно читать любую в зависимости, что интереснее, пример с rust web app или с мобильным приложением.

Для удобной работы, советую использовать mise. В корне примеров есть файл mise.toml. В нем описано, что нам потребуется woodpecker-cli

По умолчанию нам потребуется woodpecker-cli.

Чтобы установить глобально:

mise use --global aqua:woodpecker-ci/woodpecker/woodpecker-cli

Либо в файле mise.toml должна быть строчка с установкой утилиты. В таком случае при переходе в папку с таким toml у вас будет доступна утилита woodpecker-cli.

[tools]
"aqua:woodpecker-ci/woodpecker/woodpecker-cli" = "latest"

Hello World Woodpecker

Создадим папку нашего проекта, папку для всех сценариев CI/CD и первый сценарий.

mkdir -p woodpecker-test/.woodpecker && touch woodpecker-test/.woodpecker/hello-world-flow.yml

Заполним файл сценария.

when:
  - event: manual

steps:
  - name: build
    image: bash
    commands:
      - echo "This is the build step"
      - sleep 5

И мы уже готовы запустить наш сценарий для будущего CI/CD с помощью CLI woodpecker-cli.

woodpecker-cli exec
# hello-world-flow.yml
[build:L0:0s] + echo "This is the build step"
[build:L1:0s] This is the build step
[build:L2:0s] + sleep 5

Да, да! Таким образом существует в мире возможность начать проект не с инициализации через cargo new или npm create. А с того чтобы описать что вы решили собрать и протестировать и запустить.

Поговорим о yaml нашего workflow для woodpecker. Мы видим язык для определения шагов выполнения. Каждый шаг требует условия для запуска. И обычно условием будет что-то вроде

when:
  - event: push
    branch: master-of-the-zoo

when:
  - event: [push, pull_request]

Мы не можем не указать никакого условия, шаг не будет исполнен. А если мы укажем pull-request или push, woodpecker-cli локально тоже не станет запускать шаги. Есть несколько способов для запуска сразу, это использование условия

- evaluate: "true"

Либо CI_PIPELINE_EVENT=manual, что дает больше информации о том что происходит. Можно передать любую другую env при вызове и сделать проверку. Еще вариант указать event как manual. Собственно то, что и надо использовать.

when:
  - event: [push, pull_request]
    branch: master
  - event: manual

Если сборка завалилась уже на сервере woodpecker, то можно через UI или CLI скачать metadata файл, который, переданный через аргумент при запуске сценария, будет содержать информацию о том, что произошло событие пуша нового коммита, и сценарий также будет выполнен.

Debug pipeline Screenshot

 woodpecker-cli exec --metadata-file Partysun-napatam-pipeline-2-metadata.json

Вернемся к нашему yaml для сценария, там есть еще одна магия, которую надо понять. Local Backend

Агент Woodpecker может запустить код в контейнерах Docker, k8s и запускать сценарии в среде bash/fish локально на системе, где установлен агент Woodpecker. Локальный запуск опасен, и стоит понимать возможные риски для системы.

Когда мы используем локальный backend для запуска сценария, параметр image используется для выбора того, какой shell (Bash или Fish) будет использован для запуска команд.

Full Example 1: Rust web app

Итак разберемся как сделать сценарии woodpecker CI для простого веб приложения на Rust. Само веб приложение можно скачать с github. Это фактически hello world на axum, с двумя endpoints / и /health.

Написание веб приложения на Rust не является предметом нашего разговора.

Для удобной работы, советую использовать mise. В корне проекта есть файл mise.toml. В нем описано, что нам потребуется woodpecker-cli и hurl. Hurl это утилита для запуска http запросов по файлу сценария. Мы будем его использовать для имитации интеграционных тестов. С помощью mise нужные утилиты будут установлены автоматически и будут доступны только когда вы находитесь в папке проекта.

curl https://mise.run | sh
mise trust mise.toml
mise install

Мы будем работать с docker и docker должен быть установлен в системе. И это проект на Rust, так что установить Rust тоже необходимо.

Проверим, что проект запускается и тесты в main модуле на Rust работают.

cargo check && cargo test

Также проверим, можем ли мы поднять docker с помощью compose и запустим hurl тесты:

docker compose up -d && mise test-hurl

Если в обоих случаях все работает и веб сервер поднимается, то перейдем к пониманию сценариев или workflow для Woodpecker CI. Для того чтобы запустить сценарии Woodpecker, вам не надо даже настраивать сервер CI, можно начать без всего, но woodpecker-cli потребуется.

Структура наших сценариев на Woodpecker CI:

❯ tree .woodpecker
/.woodpecker
├── deploy.yaml
├── docker.yaml
└── test.yaml

Source of example project

test.yaml

matrix:
  RUST: [stable, nightly]

when:
  - event: [push, pull_request]
    branch: master
  - event: manual

labels:
  backend: docker
  platform: linux/amd64

steps:
  - name: build
    image: rust
    environment:
      CARGO_TERM_COLOR: always
    commands:
      - rustup default $RUST
      - echo "Building Cargo Demo Project"
      - cargo build

  - name: test
    image: rust
    environment:
      CARGO_TERM_COLOR: always
    commands:
      - rustup default $RUST
      - cargo test

Запустить этот сценарий можно абсолютно без проблем локально.

woodpecker-cli exec .woodpecker/test.yaml --repo-path .

Нужно обязательно указать “–repo-path .” если вы запускаете команду в корне проекта. Иначе CLI попробует запустить сценарий из папки .woodpecker Или воспользоваться тасками прописанными в mise.toml.

mise test

Чтобы посмотреть все возможные таски:

mise tasks

Name       Description
build      Build Docker image, run integration tests, and push to registry using Woodpecker CI
lint       Format and lint Rust code
test       Run tests using Woodpecker CI
test-hurl  Run integration tests using Hurl against local server (http://localhost:4000)

Интересным в этом простом pipeline отмечу matrix

Matrix позволяет запустить билды для разных версий images, зависимостей, компиляторов.

Условия When

Для того чтобы сценарий можно было запустить локально, мы должны указать event: manual. Мы можем гибко организовать условия запуска для определенных веток репозитория и событиях на этих ветках, можно также проверять переменные окружения на определенные значения.

Теперь о Labels

Это тоже условия для запуска билда, но они выполняются не при локальном запуске, а на сервере woodpecker CI. Их цель определить на какой ноде агента будет выполнена сборка. Можно к примеру указать:

labels:
  node: production

И если в конфигурации ноды агента есть

WOODPECKER_AGENT_LABELS: "node=production"

То сценарий запустится только на этой одной ноде.