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