Docker Targets
Docker targets enable command execution within containerized environments. Xec provides comprehensive Docker integration with support for container lifecycle management, volume mounting, networking, and Docker Compose.
Basic Configuration​
Define Docker containers in the targets.containers section:
targets:
containers:
app:
image: node:18
workdir: /app
volumes:
- ./src:/app
Container Properties​
Essential Properties​
targets:
containers:
basic:
# Container identification (one required)
image: ubuntu:22.04 # Docker image to use
container: existing-container # OR existing container name/ID
# Common settings
workdir: /workspace # Working directory
user: "1000:1000" # User ID or name
Advanced Properties​
targets:
containers:
advanced:
image: node:18-alpine
# Volumes
volumes:
- ./src:/app:rw # Read-write mount
- ./config:/config:ro # Read-only mount
- data:/data # Named volume
- /tmp:/host-tmp # Absolute path
# Networking
ports:
- "3000:3000" # Host:Container
- "8080:80"
network: my-network # Network name
# Container settings
restart: unless-stopped # Restart policy
privileged: false # Privileged mode
tty: true # Allocate TTY
autoRemove: true # Remove after exit
# Resource limits
memory: 512m # Memory limit
cpus: "0.5" # CPU limit
# Health check
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
startPeriod: 40s
Execution Modes​
Run Mode (Default)​
Creates new container for each command:
targets:
containers:
ephemeral:
image: alpine:latest
runMode: run # Default
autoRemove: true
# Each command creates new container
# xec in containers.ephemeral "echo test"
Exec Mode​
Executes in existing container:
targets:
containers:
persistent:
container: my-app-container # Existing container
runMode: exec
# Commands run in existing container
# xec in containers.persistent "ps aux"
Hybrid Mode​
targets:
containers:
smart:
image: postgres:15
container: db-container
# Automatically uses exec if container exists,
# otherwise creates with run
Volume Management​
Volume Types​
targets:
containers:
volumes-demo:
image: ubuntu:22.04
volumes:
# Bind mount (relative path)
- ./app:/app
# Bind mount (absolute path)
- /var/log:/logs:ro
# Named volume
- mydata:/data
# Anonymous volume
- /tmp
# With options
- type: bind
source: ./config
target: /config
readonly: true
Volume Permissions​
targets:
containers:
permissions:
image: node:18
volumes:
- ./src:/app:rw # Read-write (default)
- ./config:/config:ro # Read-only
- ./cache:/cache:rw,z # With SELinux label
# Run as specific user
user: "1000:1000"
Networking​
Port Mapping​
targets:
containers:
web:
image: nginx:alpine
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "127.0.0.1:8080:8080" # Bind to localhost only
- "3000-3005:3000-3005" # Port range
Network Modes​
targets:
containers:
# Default bridge network
bridge:
image: alpine
network: bridge
# Custom network
custom:
image: alpine
network: my-app-network
# Host network
host:
image: alpine
network: host
# No network
isolated:
image: alpine
network: none
Container Linking​
targets:
containers:
database:
image: postgres:15
network: app-network
app:
image: node:18
network: app-network
env:
DB_HOST: database # Can reference by name
Environment Variables​
targets:
containers:
configured:
image: node:18
env:
# Simple values
NODE_ENV: production
PORT: "3000"
# From secrets
API_KEY: ${secrets.api_key}
DB_PASSWORD: ${secrets.db_password}
# Complex values
DATABASE_URL: "postgres://user:pass@db:5432/mydb"
# From host environment
HOME: ${env.HOME}
USER: ${env.USER}
Environment Files​
targets:
containers:
from-file:
image: node:18
envFile:
- .env
- .env.production
Container Lifecycle​
Restart Policies​
targets:
containers:
# Always restart
critical:
image: redis:alpine
restart: always
# Restart on failure
resilient:
image: app:latest
restart: on-failure
restartMaxRetries: 5
# Don't restart
oneshot:
image: alpine
restart: "no"
Auto-removal​
targets:
containers:
# Remove after execution
temporary:
image: alpine
autoRemove: true
# Keep container
persistent:
image: postgres:15
autoRemove: false
Health Checks​
targets:
containers:
healthy:
image: nginx:alpine
healthcheck:
# Command-based check
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]
# Or shell command
# test: "curl -f http://localhost/ || exit 1"
# Timing configuration
interval: 30s # Check interval
timeout: 10s # Check timeout
retries: 3 # Failure retries
startPeriod: 40s # Grace period
Labels and Metadata​
targets:
containers:
labeled:
image: app:latest
labels:
app: myapp
environment: production
version: "1.2.3"
"com.example.team": backend
"com.example.git-commit": ${env.GIT_COMMIT}
Docker Compose Integration​
targets:
# Global compose configuration
$compose:
file: docker-compose.yml
project: myproject
containers:
# Reference compose service
web:
$service: web
# Override compose settings
db:
$service: database
env:
POSTGRES_PASSWORD: ${secrets.db_password}
Resource Limits​
targets:
containers:
limited:
image: node:18
# Memory limits
memory: 512m # Memory limit
memorySwap: 1g # Memory + swap limit
memoryReservation: 256m # Soft limit
# CPU limits
cpus: "0.5" # Number of CPUs
cpuShares: 512 # CPU shares (relative)
cpusetCpus: "0,1" # CPU cores to use
# Other limits
pidsLimit: 100 # Process limit
ulimits:
nofile:
soft: 65535
hard: 65535
Security Configuration​
User and Groups​
targets:
containers:
secure:
image: node:18
# Run as specific user
user: "1000:1000" # UID:GID
# OR
user: appuser # Username
# Additional groups
groupAdd:
- docker
- video
Capabilities​
targets:
containers:
capabilities:
image: alpine
# Add capabilities
capAdd:
- SYS_ADMIN
- NET_ADMIN
# Drop capabilities
capDrop:
- ALL
# Privileged mode (all capabilities)
privileged: false
Security Options​
targets:
containers:
hardened:
image: alpine
securityOpt:
- no-new-privileges
- seccomp=unconfined
- apparmor=docker-default
readonlyRootfs: true
Docker Socket Access​
targets:
containers:
docker-in-docker:
image: docker:dind
privileged: true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Custom Docker Configuration​
Docker Host​
targets:
containers:
remote:
image: alpine
dockerHost: tcp://remote-docker:2376
dockerCertPath: ~/.docker/certs
Registry Authentication​
targets:
containers:
private:
image: registry.example.com/app:latest
registryAuth:
username: ${secrets.registry_user}
password: ${secrets.registry_password}
Real-World Examples​
Development Environment​
targets:
containers:
dev:
image: node:18
workdir: /app
volumes:
- .:/app
- node_modules:/app/node_modules
ports:
- "3000:3000"
- "9229:9229" # Debugger
env:
NODE_ENV: development
DEBUG: "*"
tty: true
stdin: true
Production Database​
targets:
containers:
postgres:
image: postgres:15-alpine
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backup:/backup
env:
POSTGRES_DB: production
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${secrets.db_password}
ports:
- "127.0.0.1:5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser"]
interval: 10s
timeout: 5s
retries: 5
Build Environment​
targets:
containers:
builder:
image: node:18
workdir: /build
volumes:
- .:/build:ro
- build_cache:/build/.cache
- dist:/build/dist
env:
CI: true
NPM_TOKEN: ${secrets.npm_token}
user: "1000:1000"
autoRemove: true
Troubleshooting​
Container Debugging​
# Check container status
docker ps -a
# View container logs
xec logs containers.app
# Execute debug commands
xec in containers.app "ps aux"
xec in containers.app "env | sort"
Common Issues​
Image Not Found​
# Ensure image exists
targets:
containers:
app:
image: node:18 # Use official images
# OR pull explicitly
imagePullPolicy: always
Permission Denied​
# Fix volume permissions
targets:
containers:
fixed:
image: node:18
user: "$(id -u):$(id -g)" # Match host user
volumes:
- .:/app:rw,z # SELinux label if needed
Port Already in Use​
# Use different ports
targets:
containers:
app:
ports:
- "3001:3000" # Map to different host port
Best Practices​
1. Use Specific Tags​
# Good - specific version
image: node:18.17.1-alpine
# Bad - latest tag
image: node:latest
2. Minimize Layers​
# Combine related operations
targets:
containers:
efficient:
image: alpine
command: sh -c "apk add --no-cache git && git clone repo"
3. Use .dockerignore​
# .dockerignore
node_modules
.git
*.log
.env
4. Security First​
targets:
containers:
secure:
image: alpine
user: nobody # Non-root user
readonlyRootfs: true # Read-only filesystem
capDrop: [ALL] # Drop all capabilities
5. Resource Limits​
targets:
containers:
limited:
image: node:18
memory: 512m # Always set limits
cpus: "0.5"
Next Steps​
- Kubernetes Targets - Kubernetes pod configuration
See Also​
- Docker Commands - Docker-specific commands
- Container Logs - Viewing container logs