Skip to main content

Basic Usage

Learn how to use gVisor with containers through practical examples and common use cases.

Running Your First gVisor Container

With Docker

The simplest way to run a container with gVisor:

# Run a basic container
docker run --rm --runtime=runsc hello-world

# Run an interactive container
docker run --rm -it --runtime=runsc ubuntu:20.04 /bin/bash

With containerd and ctr

Using containerd's ctr command:

# Pull an image
sudo ctr image pull docker.io/library/alpine:latest

# Run with gVisor runtime
sudo ctr run --runtime=runsc --rm -t docker.io/library/alpine:latest test-container sh

Container Lifecycle Management

Starting and Stopping Containers

# Start a long-running container
docker run -d --name=gvisor-test --runtime=runsc nginx

# Check container status
docker ps

# Stop the container
docker stop gvisor-test

# Remove the container
docker rm gvisor-test

Executing Commands in Running Containers

# Start a container
docker run -d --name=my-app --runtime=runsc nginx

# Execute commands inside
docker exec -it my-app /bin/bash
docker exec my-app ps aux
docker exec my-app cat /proc/version

Working with Volumes and Networking

Volume Mounting

gVisor supports various types of volume mounts:

# Bind mount from host
docker run --rm -it --runtime=runsc \
-v /host/path:/container/path \
alpine:latest sh

# Named volume
docker volume create my-volume
docker run --rm -it --runtime=runsc \
-v my-volume:/data \
alpine:latest sh

# tmpfs mount
docker run --rm -it --runtime=runsc \
--tmpfs /tmp:noexec,nosuid,size=100m \
alpine:latest sh

Networking

gVisor containers support standard Docker networking:

# Default bridge network
docker run --rm --runtime=runsc nginx

# Custom network
docker network create my-network
docker run --rm --runtime=runsc \
--network=my-network \
nginx

# Port mapping
docker run -d --runtime=runsc \
-p 8080:80 \
nginx

Environment Variables and Configuration

Setting Environment Variables

# Single environment variable
docker run --rm --runtime=runsc \
-e MY_VAR=value \
alpine:latest env

# Multiple variables
docker run --rm --runtime=runsc \
-e VAR1=value1 \
-e VAR2=value2 \
alpine:latest env

# From file
echo "DB_HOST=localhost" > .env
echo "DB_PORT=5432" >> .env
docker run --rm --runtime=runsc \
--env-file .env \
alpine:latest env

Working Directory and User

# Set working directory
docker run --rm -it --runtime=runsc \
-w /app \
alpine:latest pwd

# Run as specific user
docker run --rm -it --runtime=runsc \
-u 1000:1000 \
alpine:latest id

# Run as non-root user
docker run --rm -it --runtime=runsc \
--user nobody \
alpine:latest whoami

Resource Limits and Constraints

Memory Limits

# Set memory limit
docker run --rm --runtime=runsc \
-m 512m \
alpine:latest sh -c 'cat /proc/meminfo | head -5'

# Memory and swap limit
docker run --rm --runtime=runsc \
-m 512m --memory-swap 1g \
alpine:latest free -h

CPU Limits

# CPU shares (relative weight)
docker run --rm --runtime=runsc \
--cpu-shares 512 \
alpine:latest cat /sys/fs/cgroup/cpu/cpu.shares

# CPU cores
docker run --rm --runtime=runsc \
--cpus="1.5" \
alpine:latest nproc

Multi-Container Applications

Docker Compose with gVisor

Create a docker-compose.yml file:

version: '3.8'

services:
web:
image: nginx
ports:
- "8080:80"
runtime: runsc
volumes:
- ./html:/usr/share/nginx/html:ro

app:
image: node:16-alpine
runtime: runsc
working_dir: /app
volumes:
- .:/app
command: npm start

db:
image: postgres:13
runtime: runsc
environment:
POSTGRES_PASSWORD: secret
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:

Run with:

docker-compose up -d

Service Communication

# Create a custom network
docker network create app-network

# Start database
docker run -d --name=db \
--runtime=runsc \
--network=app-network \
-e POSTGRES_PASSWORD=secret \
postgres:13

# Start application (can communicate with db via hostname 'db')
docker run -d --name=app \
--runtime=runsc \
--network=app-network \
-e DATABASE_URL=postgresql://postgres:secret@db:5432/app \
my-app:latest

Debugging and Monitoring

Container Inspection

# Inspect container details
docker inspect container-name

# View container logs
docker logs container-name

# Monitor resource usage
docker stats container-name

Process Monitoring

# View processes in container
docker exec container-name ps aux

# Monitor system calls (with debug enabled)
docker run --rm --runtime=runsc \
--runtime-opt debug=true \
alpine:latest strace ls /

Health Checks

# Run container with health check
docker run -d --runtime=runsc \
--health-cmd="curl -f http://localhost/ || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
nginx

# Check health status
docker inspect --format='{{.State.Health.Status}}' container-name

Common Patterns and Best Practices

Stateless Applications

# Run stateless web service
docker run -d --runtime=runsc \
-p 3000:3000 \
--restart=unless-stopped \
node:16-alpine node server.js

Batch Processing

# Process data with resource limits
docker run --rm --runtime=runsc \
-v /data:/input:ro \
-v /results:/output \
-m 2g --cpus="2" \
data-processor:latest process /input /output

Development Environment

# Interactive development container
docker run -it --rm --runtime=runsc \
-v $(pwd):/workspace \
-w /workspace \
-p 3000:3000 \
node:16 bash

# Inside container
npm install
npm run dev

Performance Considerations

Platform Selection

# Use KVM for better performance (if available)
docker run --rm --runtime=runsc \
--runtime-opt platform=kvm \
alpine:latest echo "Using KVM"

# Check platform being used
docker run --rm --runtime=runsc \
--runtime-opt debug=true \
alpine:latest echo "Check logs for platform info"

Memory and CPU Tuning

# Optimize for memory-intensive applications
docker run --runtime=runsc \
-m 4g \
--memory-swappiness=1 \
memory-intensive-app

# Optimize for CPU-intensive applications
docker run --runtime=runsc \
--cpus="4" \
--cpu-shares 1024 \
cpu-intensive-app

Security Features in Practice

Running Untrusted Code

# Safely run untrusted workload
docker run --rm --runtime=runsc \
--read-only \
--tmpfs /tmp \
--user nobody \
--cap-drop ALL \
untrusted-image:latest

Isolation Verification

# Check that gVisor is handling system calls
docker run --rm --runtime=runsc \
--runtime-opt debug=true \
alpine:latest cat /proc/version

# Should show gVisor version, not host kernel version

Troubleshooting Common Issues

Container Won't Start

# Check gVisor logs
sudo journalctl -u docker | grep runsc

# Run with detailed logging
docker run --rm --runtime=runsc \
--runtime-opt debug=true \
--runtime-opt debug-log=/tmp/runsc.log \
alpine:latest echo "test"

Performance Issues

# Try different platform
docker run --rm --runtime=runsc \
--runtime-opt platform=ptrace \
alpine:latest echo "test"

# Check resource constraints
docker run --rm --runtime=runsc \
alpine:latest sh -c 'cat /proc/meminfo; cat /proc/cpuinfo'

Next Steps

Now that you understand basic usage, explore: