# Setup Docker Compose

> Configure Docker Compose for multi-container R development environments. Covers service definitions, volume mounts, networking, environment variables, and development vs production configurations. Use when running R alongside other services (databases, APIs), setting up a reproducible R development environment, orchestrating an R-based MCP server container, or managing environment variables and volume mounts for R projects.

- Skill: `pjt222/setup-docker-compose` (Agent Skill)
- Install (CLI): `npx skillmds@latest add pjt222/setup-docker-compose`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pjt222/setup-docker-compose/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: MIT
- Author: pjt222 (https://skillmd.com/u/pjt222)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/pjt222/setup-docker-compose

---


# Set Up Docker Compose

Configure Docker Compose for R development and deployment environments.

## When to Use

- Running R alongside other services (databases, APIs)
- Setting up a reproducible development environment
- Orchestrating an R-based MCP server container
- Managing environment variables and volume mounts

## Inputs

- **Required**: Dockerfile for the R service
- **Required**: Project directory to mount
- **Optional**: Additional services (database, cache, web server)
- **Optional**: Environment variable configuration

## Procedure

### Step 1: Create docker-compose.yml

```yaml
version: '3.8'

services:
  r-dev:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: r-dev
    image: r-dev:latest

    volumes:
      - .:/workspace
      - renv-cache:/workspace/renv/cache

    stdin_open: true
    tty: true

    environment:
      - TERM=xterm-256color
      - R_LIBS_USER=/workspace/renv/library
      - RENV_PATHS_CACHE=/workspace/renv/cache

    command: R

    restart: unless-stopped

volumes:
  renv-cache:
    driver: local
```

**Expected:** A `docker-compose.yml` file exists with the R service defined, including volume mounts for the project directory and renv cache, and environment variables for R library paths.

**On failure:** If YAML syntax is invalid, validate with `docker compose config`. Ensure indentation uses spaces (not tabs) and all string values with special characters are quoted.

### Step 2: Add Additional Services (If Needed)

```yaml
services:
  r-dev:
    # ... as above
    depends_on:
      - postgres
    environment:
      - DB_HOST=postgres
      - DB_PORT=5432

  postgres:
    image: postgres:16
    container_name: r-postgres
    environment:
      POSTGRES_DB: analysis
      POSTGRES_USER: ruser
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  renv-cache:
  pgdata:
```

**Expected:** The additional service (e.g., PostgreSQL) is defined with its own volume, environment variables, and port mapping. The R service has `depends_on` referencing the new service.

**On failure:** If the database service fails to start, check `docker compose logs postgres` for initialization errors. Verify that environment variables like `POSTGRES_PASSWORD_FILE` point to valid secrets or switch to `POSTGRES_PASSWORD` for development.

### Step 3: Configure Networking

For services that need localhost access (e.g., MCP servers):

```yaml
services:
  r-dev:
    network_mode: "host"
```

For isolated networking:

```yaml
services:
  r-dev:
    networks:
      - app-network
    ports:
      - "3000:3000"

networks:
  app-network:
    driver: bridge
```

**Expected:** Networking is configured appropriately: `host` mode for services needing localhost access (MCP servers), or bridge networking with explicit port mappings for isolated services.

**On failure:** If services cannot communicate, verify they are on the same network. With bridge networking, use service names as hostnames (e.g., `postgres` not `localhost`). With host mode, use `localhost` and ensure ports do not conflict.

### Step 4: Manage Environment Variables

Create `.env` file (git-ignored):

```text
R_VERSION=4.5.0
GITHUB_PAT=your_token_here
```

Reference in compose:

```yaml
services:
  r-dev:
    build:
      args:
        R_VERSION: ${R_VERSION}
    env_file:
      - .env
```

**Expected:** A `.env` file exists (git-ignored) with project-specific variables, and `docker-compose.yml` references it via `env_file` or variable interpolation (`${VAR}`).

**On failure:** If variables are not resolving, ensure the `.env` file is in the same directory as `docker-compose.yml`. Run `docker compose config` to see the resolved configuration with all variables expanded.

### Step 5: Build and Run

```bash
# Build images
docker compose build

# Start services
docker compose up -d

# Attach to R session
docker compose exec r-dev R

# View logs
docker compose logs -f r-dev

# Stop services
docker compose down
```

**Expected:** All services start. R session accessible.

**On failure:** Check `docker compose logs` for startup errors. Common: port conflicts, missing environment variables.

### Step 6: Create Override for Development

Create `docker-compose.override.yml` for local development settings:

```yaml
services:
  r-dev:
    volumes:
      - /path/to/local/packages:/extra-packages
    environment:
      - DEBUG=true
```

This is automatically merged with `docker-compose.yml`.

**Expected:** A `docker-compose.override.yml` file exists with development-specific settings (extra volumes, debug flags) that are automatically applied when running `docker compose up`.

**On failure:** If overrides are not taking effect, verify the filename is exactly `docker-compose.override.yml`. Run `docker compose config` to confirm the merge. For explicit override files, use `docker compose -f docker-compose.yml -f custom-override.yml up`.

## Validation

- [ ] `docker compose build` completes without errors
- [ ] `docker compose up` starts all services
- [ ] Volume mounts correctly share files between host and container
- [ ] Environment variables are available inside containers
- [ ] Services can communicate with each other
- [ ] `docker compose down` cleanly stops everything

## Common Pitfalls

- **Volume mount permissions**: Linux containers may create files as root. Use `user:` directive or fix permissions.
- **Port conflicts**: Check for services already using the same ports on the host
- **Docker Desktop vs CLI**: `docker compose` (v2) vs `docker-compose` (v1). Use v2.
- **WSL path mounts**: Use `/mnt/c/...` paths when mounting Windows directories from WSL
- **Named volumes vs bind mounts**: Named volumes persist across rebuilds; bind mounts reflect host changes immediately

## Related Skills

- `create-r-dockerfile` - create the Dockerfile that compose references
- `containerize-mcp-server` - compose configuration for MCP servers
- `optimize-docker-build-cache` - speed up compose builds

