Drone CI’s pipeline steps, by default, are isolated environments. To connect a database service, you need to explicitly define and provision that service within your pipeline configuration.
Here’s how a database service comes to life in a Drone pipeline:
kind: pipeline
type: docker
name: database-example
services:
redis:
image: redis:7.0.0
ports:
- "6379"
steps:
- name: test-with-redis
image: alpine:latest
commands:
- apk add --no-cache redis-tools
- redis-cli ping
- redis-cli SET mykey "hello world"
- redis-cli GET mykey
environment:
REDIS_HOST: redis
REDIS_PORT: 6379
In this example, we define redis under the services section. Drone provisions a container running the redis:7.0.0 image. The ports: - "6379" line tells Drone to map a port from the service container to a port on the host (which the pipeline step can access). The REDIS_HOST environment variable is automatically set by Drone to redis, which is the service name we defined. This allows the test-with-redis step to connect to the Redis instance.
This pattern isn’t limited to Redis. You can provision any database or service that has a Docker image. Let’s look at a PostgreSQL example:
kind: pipeline
type: docker
name: postgres-example
services:
postgres:
image: postgres:14.5-alpine
environment:
POSTGRES_USER: drone
POSTGRES_DB: testdb
POSTGRES_PASSWORD: password
ports:
- "5432"
steps:
- name: migrate-with-postgres
image: postgres:14.5-alpine
commands:
- psql "postgresql://drone:password@postgres:5432/testdb" -c "CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name VARCHAR(50));"
- psql "postgresql://drone:password@postgres:5432/testdb" -c "INSERT INTO users (name) VALUES ('Alice');"
- psql "postgresql://drone:password@postgres:5432/testdb" -c "SELECT * FROM users;"
environment:
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_USER: drone
POSTGRES_DB: testdb
POSTGRES_PASSWORD: password
Here, Drone spins up a PostgreSQL container. We pass environment variables like POSTGRES_USER, POSTGRES_DB, and POSTGRES_PASSWORD directly to the service container, which the official PostgreSQL image uses for initialization. The ports: - "5432" ensures the PostgreSQL port is accessible. The pipeline step then uses these same credentials and the service name postgres (as the hostname) to connect to the database.
The key here is that Drone orchestrates these service containers alongside your build/test containers. It handles their startup and shutdown and makes them discoverable within the pipeline’s network. This means your application code or test scripts can treat the service name (e.g., postgres, redis) as the hostname, and Drone ensures it resolves to the correct service container.
You can define multiple services. For instance, if your application needs both a database and a caching layer:
kind: pipeline
type: docker
name: multi-service-example
services:
db:
image: postgres:14.5-alpine
environment:
POSTGRES_USER: appuser
POSTGRES_DB: appdb
POSTGRES_PASSWORD: dbpassword
ports:
- "5432"
cache:
image: redis:7.0.0
ports:
- "6379"
steps:
- name: run-app-tests
image: node:18-alpine
commands:
- npm install
- npm test
environment:
DATABASE_URL: postgresql://appuser:dbpassword@db:5432/appdb
CACHE_HOST: cache
CACHE_PORT: 6379
Drone guarantees that all services defined in the services block are running before any steps in the pipeline begin execution. This ensures your database and cache are ready when your application code attempts to connect.
When you use ports: - "PORT_NUMBER", Drone dynamically assigns an available port on the host and maps it to the specified port within the service container. However, for internal communication between pipeline steps and services, you generally don’t need to worry about the host-assigned port. You use the service name as the hostname and the port defined within the service container (e.g., 5432 for PostgreSQL, 6379 for Redis). Drone’s internal networking handles the rest.
The most surprising thing about Drone’s service provisioning is how seamlessly it integrates with Docker’s networking model, making service discovery feel almost magical. You define a service by name, and that name is the hostname your steps can use, without needing to manually configure DNS or IP addresses.
The next concept you’ll likely encounter is managing sensitive credentials for these database services, which is typically handled using Drone’s secrets management.