7 Docker and Docker Compose
Docker packages applications into isolated containers — self-contained environments with their own dependencies, libraries, and configuration. Docker Compose orchestrates multiple containers together.
7.1 Why Docker
Without Docker, installing R packages on a server often hits system dependency issues:
Configuration failed to find the Magick++ library. Try installing:
- deb: libmagick++-dev (Debian, Ubuntu)
A Dockerfile specifies exactly which system libraries, R packages, and configurations your application needs. Build it once, and it runs identically everywhere.
7.2 Containers vs. servers
Think of containers as mini-computers within your server. Each runs its own process in isolation:
- One container runs your Shiny app
- Another runs PostgreSQL
- Another runs Redis
- NGINX runs on the host and routes traffic to them
Docker Compose ties them all together in a single docker-compose.yaml file.
7.3 The ndexr Docker Compose configuration
version: '3.9'
services:
ndexrio:
restart: unless-stopped
build:
context: ./services/console
ports:
- 9001-9010:8000
network_mode: bridge
command: ["R", "-e", "shiny::runApp('/app/src')"]
profiles:
- ndexrio
postgres:
container_name: ndexr_postgres
restart: unless-stopped
env_file: .env
build:
context: ./services/postgres
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- '5432:5432'
network_mode: bridge
profiles:
- db
redis:
container_name: ndexr_redis
restart: unless-stopped
image: redis:6.2-alpine
command: redis-server
volumes:
- redis-data:/data
ports:
- '6379:6379'
network_mode: bridge
profiles:
- db
volumes:
redis-data:
postgres-data:Key points:
ports: 9001-9010:8000— maps container port 8000 to host ports 9001 through 9010. When you scale to 10 instances, each gets one of these ports.profiles— lets you selectively start groups of services (ndexriofor the app,dbfor databases)volumes— persist data across container restarts (database data survives a rebuild)restart: unless-stopped— containers come back after server reboots
7.4 Port mapping and NGINX
The port range in Docker Compose must match the NGINX upstream:
Docker Compose: ports: 9001-9010:8000
NGINX upstream: server 127.0.0.1:9001 through 127.0.0.1:9010
When you run make up profile=ndexrio scale=10, Docker starts 10 containers, each listening internally on port 8000 but mapped to ports 9001-9010 on the host. NGINX distributes incoming traffic across all active ports.
7.5 The integration
NGINX, Docker Compose, and Make form the deployment pipeline:
- Make runs the commands to build and start containers
- Docker Compose manages the containers, networking, and scaling
- NGINX routes external traffic to the right containers
Changing your application means rebuilding the container (make up). Scaling means adjusting the worker count (make up scale=20). Changing the server size means modifying the EC2 instance type through the ndexr console.