Skip to main content

Working with Container Services

1. Defining Service Containers

Property Description Example
services List of service containers to use in the workflow
{
  "services": {
    "redis": {
      "image": "redis:alpine"
    }
  }
}
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.
#!/bin/bash
set -e
until curl -f http://localhost:8080/health > /dev/null; do
  echo "Waiting for service to be ready..."
  sleep 2
done
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.
for i in {1..5}; do
  if curl -f http://localhost:8080/health > /dev/null; then
    echo "Service ready"
    exit 0
  fi
  sleep $((2**i))
done

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

Debugging Workflow

  1. Run job with service containers
  2. Use docker logs <container> to view logs
  3. Use docker exec <container> env to inspect environment
  4. Use docker exec <container> ps aux to check running processes

Debugging Methods

  • Logs: Use --log-driver and docker logs
  • Environment: Use docker exec <container> env
  • Processes: Use docker exec <container> ps aux

Was this article helpful?