Drone CI Testing: Lightweight Docker-Based Test Pipelines

Drone CI Testing: Lightweight Docker-Based Test Pipelines

Drone CI is a container-native CI/CD platform that uses Docker for every step of the pipeline. Unlike CI tools that add Docker support as an afterthought, Drone was designed from the ground up around containers — each pipeline step runs in its own Docker image with complete isolation.

This makes Drone predictable and portable. The same .drone.yml that runs locally in Drone runs identically in CI. No environment drift, no "works on my machine" issues.

How Drone Works

Drone pipelines are defined in .drone.yml at the repository root. Each pipeline consists of steps, and each step runs in a specified Docker image.

The key difference from other CI tools: steps don't share a filesystem by default. Drone uses a Docker volume to mount the repository into each step's container at the same path (/drone/src). Steps share this workspace, so files written in one step are visible in the next.

kind: pipeline
type: docker
name: default

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

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

Both steps use node:20 and can see node_modules/ because they share the workspace volume.

Basic Pipeline Structure

kind: pipeline
type: docker
name: tests

# Clone settings (optional)
clone:
  depth: 1

steps:
  - name: install-dependencies
    image: node:20-alpine
    commands:
      - npm ci

  - name: lint
    image: node:20-alpine
    commands:
      - npm run lint

  - name: unit-tests
    image: node:20-alpine
    commands:
      - npm run test:unit

  - name: build
    image: node:20-alpine
    commands:
      - npm run build

Steps execute in order. If any step fails, subsequent steps are skipped (unless you configure otherwise).

Running Different Test Types

JavaScript with Jest

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

  - name: unit-tests
    image: node:20
    environment:
      CI: "true"
      NODE_ENV: test
    commands:
      - npm test -- --coverage --ci

Python with pytest

kind: pipeline
type: docker
name: python-tests

steps:
  - name: install
    image: python:3.12-slim
    commands:
      - pip install --upgrade pip
      - pip install -r requirements.txt

  - name: pytest
    image: python:3.12-slim
    commands:
      - pytest -v --junitxml=test-results/junit.xml

Go tests

steps:
  - name: test
    image: golang:1.22
    commands:
      - go test ./... -v -race -coverprofile=coverage.out
      - go tool cover -func=coverage.out

.NET tests

steps:
  - name: restore
    image: mcr.microsoft.com/dotnet/sdk:8.0
    commands:
      - dotnet restore

  - name: test
    image: mcr.microsoft.com/dotnet/sdk:8.0
    commands:
      - dotnet test --no-restore --logger "console;verbosity=detailed"

Service Containers

Drone supports service containers — containers that run alongside your pipeline steps, accessible by hostname.

PostgreSQL

kind: pipeline
type: docker
name: integration-tests

services:
  - name: postgres
    image: postgres:15
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: testpassword
      POSTGRES_DB: testdb

steps:
  - name: wait-for-postgres
    image: postgres:15
    commands:
      - until pg_isready -h postgres -U test; do sleep 1; done

  - name: run-migrations
    image: node:20
    environment:
      DATABASE_URL: postgresql://test:testpassword@postgres/testdb
    commands:
      - npm ci
      - npm run migrate

  - name: integration-tests
    image: node:20
    environment:
      DATABASE_URL: postgresql://test:testpassword@postgres/testdb
      NODE_ENV: test
    commands:
      - npm run test:integration

The service postgres is accessible as hostname postgres from all steps.

Redis

services:
  - name: redis
    image: redis:7-alpine
    commands:
      - redis-server --requirepass testpassword

steps:
  - name: tests
    image: node:20
    environment:
      REDIS_URL: redis://:testpassword@redis:6379
    commands:
      - npm ci
      - npm test

Multiple services

services:
  - name: postgres
    image: postgres:15
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
      POSTGRES_DB: app

  - name: redis
    image: redis:7

  - name: rabbitmq
    image: rabbitmq:3-management
    environment:
      RABBITMQ_DEFAULT_USER: test
      RABBITMQ_DEFAULT_PASS: test

steps:
  - name: integration-tests
    image: node:20
    environment:
      DATABASE_URL: postgresql://test:test@postgres/app
      REDIS_URL: redis://redis:6379
      AMQP_URL: amqp://test:test@rabbitmq:5672
    commands:
      - npm ci
      - npm run test:integration

Parallel Pipelines

Drone pipelines run sequentially within a single .drone.yml pipeline definition. For parallelism, define multiple pipelines:

---
kind: pipeline
type: docker
name: unit-tests

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

---
kind: pipeline
type: docker
name: integration-tests

steps:
  - name: test
    image: node:20
    environment:
      DATABASE_URL: postgresql://test:test@postgres/app
    commands:
      - npm ci
      - npm run test:integration
    services:
      - name: postgres
        image: postgres:15

---
kind: pipeline
type: docker
name: e2e-tests

steps:
  - name: test
    image: mcr.microsoft.com/playwright:v1.44.0-jammy
    commands:
      - npm ci
      - npx playwright test

Multiple pipelines in the same .drone.yml file run in parallel on separate agents.

Pipeline dependencies

If one pipeline should run after another:

---
kind: pipeline
type: docker
name: build

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

---
kind: pipeline
type: docker
name: e2e-tests

depends_on:
  - build  # wait for build pipeline to succeed

steps:
  - name: e2e
    image: mcr.microsoft.com/playwright:v1.44.0-jammy
    commands:
      - npm ci
      - npx playwright test

Environment Variables and Secrets

Environment variables

steps:
  - name: test
    image: node:20
    environment:
      NODE_ENV: test
      LOG_LEVEL: debug
      API_BASE_URL: https://api.staging.example.com
    commands:
      - npm test

Secrets from Drone secret store

Store secrets in Drone's secret management (configured via drone secret add):

steps:
  - name: integration-tests
    image: node:20
    environment:
      DATABASE_URL:
        from_secret: database_url
      API_KEY:
        from_secret: api_key
    commands:
      - npm ci
      - npm run test:integration

Add secrets via CLI:

drone secret add \
  --repository your-org/your-repo \
  --name database_url \
  --value "postgresql://user:pass@prod.db/app"

Or manage via the Drone web UI.

Caching

Drone doesn't have a native caching layer like some CI tools, but you can achieve caching with volume mounts or plugins.

Volume caching (self-hosted Drone)

steps:
  - name: install
    image: node:20
    volumes:
      - name: npm-cache
        path: /root/.npm
    commands:
      - npm ci --cache /root/.npm

volumes:
  - name: npm-cache
    host:
      path: /tmp/drone-npm-cache

This maps a host directory to the step container, persisting across builds.

Cache plugin

steps:
  - name: restore-cache
    image: drillster/drone-volume-cache
    volumes:
      - name: cache
        path: /cache
    settings:
      restore: true
      mount:
        - node_modules

  - name: install
    image: node:20
    commands:
      - npm ci

  - name: rebuild-cache
    image: drillster/drone-volume-cache
    volumes:
      - name: cache
        path: /cache
    settings:
      rebuild: true
      mount:
        - node_modules

volumes:
  - name: cache
    host:
      path: /tmp/cache

Branch Filtering

Run pipelines only on specific branches or events:

kind: pipeline
type: docker
name: pr-tests

trigger:
  event:
    - pull_request

steps:
  - name: test
    image: node:20
    commands:
      - npm ci
      - npm test
kind: pipeline
type: docker
name: main-tests

trigger:
  branch:
    - main
  event:
    - push

steps:
  - name: full-test-suite
    image: node:20
    commands:
      - npm ci
      - npm run test:all

Excluding branches

trigger:
  branch:
    exclude:
      - dependabot/*
      - renovate/*

Step Conditions

Skip individual steps based on conditions:

steps:
  - name: unit-tests
    image: node:20
    commands:
      - npm test

  - name: deploy
    image: node:20
    when:
      branch:
        - main
      event:
        - push
    commands:
      - npm run deploy

Failure handling

Continue the pipeline even if a step fails:

steps:
  - name: lint
    image: node:20
    failure: ignore  # don't fail the pipeline if lint fails
    commands:
      - npm run lint

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

Drone with Kubernetes

For Kubernetes-native Drone, use type: kubernetes instead of type: docker:

kind: pipeline
type: kubernetes
name: tests

steps:
  - name: test
    image: node:20
    commands:
      - npm ci
      - npm test
    resources:
      requests:
        cpu: 500m
        memory: 512Mi
      limits:
        cpu: 2000m
        memory: 2Gi

Each step runs as a Kubernetes pod, enabling fine-grained resource control.

Limitations and When to Use Drone

Strengths:

  • Pure Docker — every step is a container, complete isolation
  • Simple configuration — fewer abstractions than Jenkins or GitLab CI
  • Self-hosted and cloud-hosted options
  • Lightweight resource requirements
  • Good multi-pipeline parallelism

Limitations:

  • No built-in test result visualization (no dashboard like TeamCity or Azure DevOps)
  • Caching requires workarounds or plugins
  • Less marketplace of pre-built actions compared to GitHub Actions
  • Secret management is more manual

Drone is a good fit for teams that want container-native CI with simple configuration and don't need a heavy platform with built-in test analytics. It's particularly popular in environments where you want to self-host CI without the complexity of Jenkins.

Conclusion

Drone CI's container-first design means your pipeline runs exactly the same locally and in CI. No environment drift, no agent configuration surprises — just Docker images and commands.

For testing, define your pipeline steps with the right images, add service containers for databases and caches, and use parallel pipelines for faster feedback. The .drone.yml file is readable and easy to maintain, making Drone a low-overhead CI option for teams that value simplicity and container portability.

Read more