Working with Container Services
1. Defining Service Containers
| Property | Description | Example |
|---|---|---|
| services | List of service containers to use in the workflow | |
| image | Container image to use for the service | "redis:alpine" |
| env | Environment variables to set in the service container | "REDIS_PASSWORD": "secret" |
| ports | Ports to expose from the service container | "6379/tcp" |
| options | Additional Docker run options for the service container | "--network custom-network" |
Example: Defining a Redis Service Container
jobs:
test:
runs-on: ubuntu-latest
services:
redis:
image: redis:alpine
env:
REDIS_PASSWORD: secret
options: --network custom-network
Note: Service containers are started before the job runs and stopped after the job completes.
2. Using PostgreSQL Service
| Property | Value | Description |
|---|---|---|
| services.postgres | postgres:15 |
PostgreSQL service image to use |
| services.postgres.options | --tmpfs /var/lib/postgresql/data |
Additional options for the service container |
Example: Using PostgreSQL in a Job
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: password
POSTGRES_DB: testdb
options: --tmpfs /var/lib/postgresql/data
steps:
- name: Test DB Connection
run: |
pg_isready -h localhost -p 5432 -U postgres
Note: The service container is automatically linked to the job container, so you can connect to it using
localhost.
Warning: Ensure that the PostgreSQL version matches your application's requirements to avoid compatibility issues.
3. Using MySQL Service
| Property | Values | Description |
|---|---|---|
| services.mysql | mysql:8.0 |
Specifies the MySQL image to use for the service |
| services.mysql.port | 3306 |
Port on which MySQL is exposed inside the container |
| services.mysql.env | MYSQL_ROOT_PASSWORD: password123 |
Environment variables to configure MySQL |
Example: Setting up MySQL Service
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: password123
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
Note: The
MYSQL_ROOT_PASSWORD is required for MySQL service setup.
Warning: For production use, avoid hardcoding passwords in workflows.
4. Using Redis Service
| Property | Values | Description |
|---|---|---|
| services.redis | redis:latest |
Specifies the Redis service to use. Can be a version tag or image reference. |
| services.redis.port | 6379 |
The port to expose the Redis service on. Default is 6379. |
| services.redis.options | --memory 256mb |
Additional options to pass to the Redis container. |
Example: Using Redis in a Workflow
name: Redis Example
on: [push]
jobs:
test:
runs-on: ubuntu-latest
services:
redis:
image: redis:latest
options: --memory 256mb
steps:
- name: Test Redis Connection
run: |
redis-cli -h localhost -p 6379 ping
Note: The Redis service is accessible from the job's steps at
localhost on port 6379.
5. Using MongoDB Service
GitHub Actions provides a managed MongoDB service that can be used in workflows to run tests, seed data, or perform integration checks against a real MongoDB instance.
| Property | Description | Default Value |
|---|---|---|
| image | Container image to use for MongoDB | mongo:latest |
| port | Port to expose MongoDB on | 27017 |
| username | Username for MongoDB authentication | admin |
| password | Password for MongoDB authentication | password |
Example: Using MongoDB in a Workflow
jobs:
test:
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:latest
options: >-
--health-cmd "mongo --eval 'db.adminCommand('ping')'"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: password
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Run tests
run: |
npm install
npm test
env:
MONGODB_URI: mongodb://admin:password@mongodb:27017/testdb
6. Configuring Service Ports
| Property | Description | Default | Notes |
|---|---|---|---|
| container.ports | Specifies the ports to expose from the container | None | Must be an array of port mappings |
| container.ports[].published | Host port to bind to | None | Optional, defaults to random available port if not specified |
| container.ports[].target | Container port to map to | None | Required, must match a port exposed by the container image |
| container.ports[].protocol | Protocol to use for the port (tcp or udp) | tcp |
Optional, defaults to tcp |
Example: Mapping Service Ports
jobs:
build:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- published: 5432
target: 5432
protocol: tcp
Note: When using
published, the host port must be unique across all jobs in a workflow.
Warning: If
published is not specified, the port will be randomly assigned and cannot be accessed from outside the job.
7. Setting Service Environment Variables
| Variable | Value | Description |
|---|---|---|
| container.env.VAR_NAME | value |
Environment variable to set inside the service container |
| container.env.OVERRIDE | true |
Override default environment variables if set to true |
Example: Setting Environment Variables in a Service Container
jobs:
build:
runs-on: ubuntu-latest
services:
redis:
image: redis:alpine
env:
REDIS_PASSWORD: secret123
DATABASE_URL: "redis://localhost:6379"
Note: Environment variables defined in the
env section of a service are available to all steps within that job.
8. Configuring Health Checks
| Property | Description | Values | Notes |
|---|---|---|---|
| healthcheck | Defines the health check configuration for a container | { interval: "30s", timeout: "10s", retries: 3, start_period: "40s" } |
Used in Dockerfile or compose file |
| interval | Time between health checks | "30s" |
Default is 30 seconds |
| timeout | Maximum time to wait for a health check response | "10s" |
Must be less than interval |
| retries | Number of consecutive failures before marking container as unhealthy | 3 |
Default is 3 retries |
| start_period | Time to wait before starting health checks after container starts | "40s" |
Useful for containers that take time to initialize |
Example: Health Check in Dockerfile
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
Example: Health Check in Compose File
services:
app:
image: myapp
healthcheck:
test: "curl -f http://localhost:8080/health || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Note: Health checks are only supported in Docker Compose v2+ and can be used to monitor application status or readiness.
9. Using Service Volumes
| Property | Description | Values | Notes |
|---|---|---|---|
| services.<service-name>.volumes | Mounts volumes into the service container | array |
Each item is a volume mount configuration |
Example: Mounting a volume to a service container
jobs:
build:
runs-on: ubuntu-latest
services:
redis:
image: redis:alpine
volumes:
- /host/path:/container/path
Note: Volume mounts are useful for sharing data between the service container and the host machine or other containers.
10. Accessing Service Containers
| Service | Access Method | Notes |
|---|---|---|
| database | localhost |
Access via localhost on default port |
| redis | localhost |
Access via localhost on default port |
| elasticsearch | localhost |
Access via localhost on default port |
Example: Accessing a Database Service
jobs:
test:
runs-on: ubuntu-latest
services:
database:
image: postgres:13
env:
POSTGRES_PASSWORD: password
steps:
- name: Test DB Connection
run: |
psql -h localhost -p 5432 -U postgres -c "SELECT version();"
Note: Service containers are accessible from the job's runner via
localhost. The default port is used unless overridden.
11. Using Multiple Services
When using multiple services in a GitHub Actions workflow, you can define them in the services section of your job configuration. Each service runs in its own container and can be accessed by other jobs or steps within the same workflow.
| Service | Image | Options | Description |
|---|---|---|---|
| redis | redis:6 |
ports: 6379:6379 |
Redis database service for caching and session storage. |
| mysql | mysql:8 |
env: MYSQL_ROOT_PASSWORD: password |
MySQL database service for testing and development. |
| postgres | postgres:13 |
env: POSTGRES_PASSWORD: password |
PostgreSQL database service for advanced SQL operations. |
Example: Using Multiple Services in a Workflow
jobs:
test:
runs-on: ubuntu-latest
services:
redis:
image: redis:6
options: "--health-cmd ping --health-interval 10s --health-timeout 5s"
mysql:
image: mysql:8
env:
MYSQL_ROOT_PASSWORD: password
steps:
- name: Test with Redis and MySQL
run: |
echo "Testing with Redis and MySQL"
Note: Services are started before the job steps begin and stopped after all steps complete. You can configure service startup and health checks using
options.
Warning: Ensure that your service containers are configured with appropriate environment variables and port mappings to avoid connection issues.
12. Waiting for Service Ready
When running workflows that depend on container services, it's crucial to ensure the service is fully ready before proceeding. GitHub Actions provides several mechanisms to wait for a service to be ready.
| Method | Description | Example |
|---|---|---|
| wait-for-service | Uses a script to poll the service endpoint until it returns a successful response. | |
| health-check | Uses a health check endpoint to verify service readiness. | curl -f http://localhost:8080/health |
| retry-logic | Implements retry logic with exponential backoff to handle transient issues. | |
Example: Using wait-for-service in a workflow
jobs:
test:
runs-on: ubuntu-latest
services:
database:
image: postgres:13
env:
POSTGRES_PASSWORD: password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Wait for database to be ready
run: |
until curl -f http://localhost:5432 > /dev/null; do
echo "Waiting for database..."
sleep 2
done
Note: The
--health-cmd option in the service configuration ensures that GitHub Actions waits for the container to be healthy before marking it as ready.
13. Debugging Service Containers
Example: Using debug logs in service containers
jobs:
debug-job:
runs-on: ubuntu-latest
services:
redis:
image: redis:alpine
options: >-
--log-driver json-file
--log-opt max-size=10m
--log-opt max-file=3
steps:
- name: Debug Redis logs
run: |
# Check Redis logs
docker logs redis
| Option | Values | Description |
|---|---|---|
| services.<name>.options | --log-driver json-file |
Configures logging driver for service container |
| services.<name>.options | --log-opt max-size=10m |
Maximum size of log file before rotation |
| services.<name>.options | --log-opt max-file=3 |
Number of rotated log files to keep |
Note: Use
docker logs to inspect logs from service containers in workflows.
Example: Inspecting container environment
jobs:
debug-job:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: password
steps:
- name: Inspect container environment
run: |
# Print environment variables from service container
docker exec postgres env