CI/CD in Docker with Gitea and Woodpecker CI

I’ve been using Gitea and Woodpecker CI for a while now, and they’ve become invaluable tools when working on larger projects or collaborating with multiple people. The ability to catch integration issues earlier, enforce clean workflows, and keeping pushes honest helps maintain a high standard of code quality. With some major updates released recently, I decided it was time for a fresh install of latest versions.

Setup Docker Volumes

For the Gitea /data directory, I prefer host (bind) volumes simply to make backups easier. The downside is now you have to handle file permissions. If security isn’t a concern, having it in your home directory isn’t a bad choice.

sudo mkdir -p /<path_do_data_dir>/docker/volumes/gitea
sudo chown -R 1000:1000 /<path_do_data_dir>/docker/volumes/gitea

Docker Compose

Use docker compose (or create a stack in portainer). Note, at this point, we are only interested in the Gitea container.

Here is the docker_compose.yml I used for my setup.

version: "3.8"

networks:
  gitea:
    external: false

services:
  gitea:
    image: docker.gitea.com/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - gitea
    volumes:
      - /<path_do_data_dir>/docker/volumes/gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3333:3000"
      - "2222:22"

  woodpecker-server:
    image: woodpeckerci/woodpecker-server:v3
    container_name: woodpecker-server
    restart: always
    ports:
      - "8888:8000"

    networks:
      - gitea
    volumes:
      - woodpecker-server-data:/var/lib/woodpecker/
    environment:
      - WOODPECKER_OPEN=true
      - WOODPECKER_HOST=http://<ip_address>:8888
      - WOODPECKER_GITEA=true
      - WOODPECKER_GITEA_URL=http://<ip_address>:3333
      - WOODPECKER_GITEA_CLIENT=<secret_client_id_from_gitea>
      - WOODPECKER_GITEA_SECRET=<secret_code_from_gitea>
      - WOODPECKER_AGENT_SECRET=<shared_secret_code>
      - WOODPECKER_DATABASE_DRIVER=sqlite3
      - WOODPECKER_DATABASE_DATASOURCE=/var/lib/woodpecker/woodpecker.sqlite
      - WOODPECKER_LOG_LEVEL=debug
    depends_on:
      - gitea

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:v3
    container_name: woodpecker-agent
    restart: always
    depends_on:
      - woodpecker-server
    networks:
      - gitea
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - woodpecker-agent-config:/etc/woodpecker
    environment:
      - WOODPECKER_SERVER=woodpecker-server:9000
      - WOODPECKER_AGENT_SECRET=<shared_secret_code>
      - WOODPECKER_LOG_LEVEL=debug
      - WOODPECKER_BACKEND_DOCKER_NETWORK=gitea-woodpecker_gitea
      - WOODPECKER_MAX_WORKFLOWS=1

volumes:
  woodpecker-server-data:
  woodpecker-agent-config:

Note: Once final operation is confirmed, you can remove WOODPECKER_LOG_LEVEL.

Some Gitea homework first

To allow Woodpecker to access Gitea repositories, we need to setup an OAuth key. Log into your fresh new Gitea instantiation and go to your profile (your avatar symbol in the upper right corner) and go to Setting/Applications At the bottom, Create a new OAuth2 Application.

Name:  Woodpecker CI
Redirect URI:  http://<ip_address>:8888/authorize

You should have successfully created a new OAuth ID and Key. Update your docker_compose file with the Client ID and Client Secret.

Next, we need to enable Webhooks in Gitea. Webhooks allow Gitea to inform Woodpecker that an event occurred (push, merge request, etc).

In /<path_to_data_dir>/docker/volumes/gitea/gitea/conf, there is a file app.ini. Edit this file and place this snippet at the end of the file.

[webhook]
ALLOWED_HOST_LIST = external,loopback

Finally, the Woodpecker CI

First, we need to update our docker compose file with all the new info.

WOODPECKER_GITEA_CLIENT= Gitea OAuth client ID
WOODPECKER_GITEA_SECRET= Gitea OAuth secret
WOODPECKER_AGENT_SECRET= a random text string shared between server and agent

Stop then restart the containers using the updated docker_compose file.

Once up, you can now log into Woodpecker for the first time. The first time running, you will have to authorize the connection and log into your Gitea account through the Woodpecker interface.

First Woodpecker pipeline

Create a new repo in Gitea and clone it locally. Add file ‘.woodpecker/firstpipeline.yml’ to the root of your repo:

when:
  - event: push
    branch: main
steps:
  - name: build
    image: alpine
    commands:
      - echo "This is the build step"
      - echo "Hello from Woodpecker CI"

Commit and push.

You should now see Woodpecker running your pipeline and output the echo data.

Final Notes and Thoughts

I use Portainer for docker administration. A warning that Portainer creates networks as <stack_name>_<network_name>, which is why the network is called “gitea” but DOCKER_NETWORK is “gitea-woodpecker_getea”

Woodpecker does NOT use a “latest” keyword. Use v3 to select the latest v3.x.x

If you use the “Run Pipeline” button inside Woodpecker, make sure the pipeline has something for event “Manual” to do. Otherwise, nothing seems to happen and things might look broken.

Gitea and Woodpecker CI are a powerful combination of tools that can be more than just used for integration testing.

At the time of writing, Gitea was at V1.24.2 and Woodpecker was v3.7.0

Leave a Reply