Docker Container Lifecycle
Implementation Reference​
Source Files:
packages/core/src/adapters/docker-adapter.ts- Docker adapter implementationpackages/core/src/docker/docker-client.ts- Docker API clientpackages/core/src/docker/container.ts- Container managementpackages/core/src/docker/types.ts- Docker type definitionsapps/xec/src/commands/in.ts- Container execution command
Key Functions:
DockerAdapter.execute()- Main execution entry pointDockerClient.exec()- Execute commands in containersDockerClient.run()- Run new containersDockerClient.start()- Start stopped containersDockerClient.stop()- Stop running containersDockerClient.inspect()- Get container detailsContainerManager.waitForHealthy()- Wait for container readiness
Overview​
Xec provides comprehensive Docker container lifecycle management through the @xec-sh/core execution engine. This enables seamless command execution in containers, container management, and integration with Docker Compose.
Container States​
State Transitions​
Docker containers managed by Xec follow standard Docker state transitions:
Created → Running → Paused → Stopped → Removed
↓ ↑
Restarting
State Detection (via DockerClient.inspect()):
- running - Container is actively executing
- paused - Container execution is paused
- restarting - Container is restarting
- exited - Container has stopped
- dead - Container is dead (unrecoverable)
- created - Container created but not started
Container Execution​
Direct Execution​
Execute commands in existing containers using the Docker adapter:
import { $ } from '@xec-sh/core';
// Execute in running container
const result = await $.docker('my-container')`ls -la /app`;
console.log(result.stdout);
// Execute with working directory
const result = await $.docker('my-container', {
cwd: '/app'
})`npm test`;
// Execute as specific user
const result = await $.docker('my-container', {
user: 'node'
})`whoami`;
CLI Execution​
Use the in command for container execution:
# Execute command in container
xec in my-container ls -la
# Execute in specific container of a pod
xec in my-container:app "npm start"
# Interactive shell
xec in my-container /bin/bash
Container Management​
Starting Containers​
Start stopped containers or create new ones:
// Start existing container
await $.docker.start('my-container');
// Run new container from image
const container = await $.docker.run('node:18', {
name: 'my-app',
detach: true,
ports: ['3000:3000'],
volumes: ['./app:/app'],
env: {
NODE_ENV: 'production'
}
});
// Run with command
await $.docker.run('alpine', {
command: ['echo', 'Hello World'],
rm: true // Remove after exit
});
Stopping Containers​
Stop running containers gracefully:
// Stop with default timeout (10s)
await $.docker.stop('my-container');
// Stop with custom timeout
await $.docker.stop('my-container', {
timeout: 30 // 30 seconds
});
// Force stop (SIGKILL)
await $.docker.kill('my-container');
Restarting Containers​
Restart containers with optional timeout:
// Restart container
await $.docker.restart('my-container');
// Restart with timeout
await $.docker.restart('my-container', {
timeout: 5 // Wait 5s before killing
});
Removing Containers​
Remove stopped containers:
// Remove stopped container
await $.docker.remove('my-container');
// Force remove running container
await $.docker.remove('my-container', {
force: true
});
// Remove with volumes
await $.docker.remove('my-container', {
volumes: true
});
Container Creation​
Configuration Options​
Create containers with detailed configuration:
const container = await $.docker.create('nginx:latest', {
name: 'web-server',
hostname: 'web',
domainname: 'example.com',
// Port mapping
ports: [
'80:80',
'443:443',
'127.0.0.1:8080:8080'
],
// Volume mounts
volumes: [
'./html:/usr/share/nginx/html:ro',
'nginx-cache:/var/cache/nginx',
'/etc/ssl/certs:/etc/ssl/certs:ro'
],
// Environment variables
env: {
NGINX_HOST: 'example.com',
NGINX_PORT: '80'
},
// Resource limits
memory: '512m',
cpus: '0.5',
// Networking
network: 'bridge',
networkAlias: ['web', 'nginx'],
// Health check
healthcheck: {
test: ['CMD', 'curl', '-f', 'http://localhost/'],
interval: '30s',
timeout: '3s',
retries: 3
},
// Restart policy
restart: 'unless-stopped',
// Labels
labels: {
'com.example.app': 'web',
'com.example.version': '1.0'
}
});
// Start the created container
await $.docker.start(container.id);
Container Inspection​
Getting Container Information​
Inspect container details and state:
// Get container details
const info = await $.docker.inspect('my-container');
console.log({
id: info.Id,
name: info.Name,
state: info.State.Status,
running: info.State.Running,
exitCode: info.State.ExitCode,
startedAt: info.State.StartedAt,
image: info.Config.Image,
ports: info.NetworkSettings.Ports,
volumes: info.Mounts,
env: info.Config.Env
});
// Check if container exists
const exists = await $.docker.exists('my-container');
// Get container logs
const logs = await $.docker.logs('my-container', {
follow: false,
tail: 100,
timestamps: true
});
Health Checks​
Container Health Monitoring​
Monitor and wait for container health:
// Wait for container to be healthy
await $.docker.waitHealthy('my-container', {
timeout: 60000, // 60 seconds
interval: 1000 // Check every second
});
// Check health status
const health = await $.docker.health('my-container');
if (health.Status === 'healthy') {
console.log('Container is healthy');
}
// Custom health check
const isHealthy = await $.docker.exec('my-container')`curl -f http://localhost/health`
.then(() => true)
.catch(() => false);
Container Events​
Monitoring Container Events​
Listen to container lifecycle events:
// Monitor container events
const events = $.docker.events({
filters: {
container: ['my-container'],
event: ['start', 'stop', 'die', 'restart']
}
});
events.on('data', (event) => {
console.log(`Container ${event.Actor.ID}: ${event.Action}`);
});
// Stop monitoring
events.stop();
Auto-Cleanup​
Temporary Containers​
Create containers that clean up automatically:
// Run with auto-remove
await $.docker.run('alpine', {
rm: true,
command: ['echo', 'Temporary execution']
});
// Using try/finally for cleanup
const container = await $.docker.create('node:18', {
name: `temp-${Date.now()}`
});
try {
await $.docker.start(container.id);
await $.docker.exec(container.id)`npm test`;
} finally {
await $.docker.stop(container.id);
await $.docker.remove(container.id, { force: true });
}
Container Groups​
Managing Multiple Containers​
Work with groups of related containers:
// Start multiple containers
const containers = ['web', 'api', 'db'];
await Promise.all(
containers.map(name => $.docker.start(name))
);
// Stop all with prefix
const allContainers = await $.docker.list({
filters: { name: ['^myapp-'] }
});
for (const container of allContainers) {
await $.docker.stop(container.Names[0]);
}
// Restart all running containers
const running = await $.docker.list({
filters: { status: ['running'] }
});
await Promise.all(
running.map(c => $.docker.restart(c.Names[0]))
);
Configuration in Xec​
Target Configuration​
Define Docker targets in .xec/config.yaml:
targets:
containers:
web:
type: docker
container: web-server
app:
type: docker
container: app-server
user: node
workdir: /app
db:
type: docker
container: postgres
env:
PGUSER: postgres
# Auto-start container if not running
worker:
type: docker
container: worker
autoStart: true
image: myapp:worker # Image to use if container doesn't exist
# Compose service reference
api:
type: docker
compose:
file: docker-compose.yml
service: api
Lifecycle Hooks​
Configure lifecycle hooks:
targets:
containers:
app:
type: docker
container: my-app
hooks:
beforeStart: |
echo "Starting container..."
docker network create app-net 2>/dev/null || true
afterStart: |
echo "Waiting for app to be ready..."
sleep 5
beforeStop: |
echo "Gracefully shutting down..."
docker exec my-app npm run shutdown
afterStop: |
echo "Container stopped"
Performance Characteristics​
Based on Implementation Analysis:
Operation Timings​
- Container Start: 100-500ms (image cached)
- Container Stop: 100ms-10s (depends on grace period)
- Container Exec: 50-100ms overhead
- Container Create: 200ms-2s (depends on image)
- Container Remove: 50-200ms
- Health Check: 100ms per check
Resource Usage​
- Memory per Exec: ~1MB
- Connection Overhead: Minimal (Unix socket)
- Event Stream: ~100KB/hour
Error Handling​
Common Errors and Solutions​
| Error | Exit Code | Solution |
|---|---|---|
| Container not found | 3 | Verify container name/ID |
| Container not running | 5 | Start container first |
| Permission denied | 11 | Check Docker permissions |
| Image not found | 8 | Pull image first |
| Port already in use | 8 | Use different port mapping |
| Volume mount failed | 8 | Check path permissions |
Error Recovery​
// Automatic retry on failure
async function executeWithRetry(container: string, command: string) {
for (let i = 0; i < 3; i++) {
try {
return await $.docker(container)`${command}`;
} catch (error) {
if (error.code === 'CONTAINER_NOT_RUNNING') {
await $.docker.start(container);
continue;
}
throw error;
}
}
}
// Health-based execution
async function executeWhenHealthy(container: string, command: string) {
await $.docker.waitHealthy(container);
return await $.docker(container)`${command}`;
}
Best Practices​
Container Management​
- Always use names - Use meaningful container names instead of IDs
- Set resource limits - Prevent containers from consuming all resources
- Use health checks - Define health checks for reliable container state
- Clean up - Remove stopped containers and unused images regularly
- Use restart policies - Configure appropriate restart behavior
Execution Patterns​
// Good: Named container with cleanup
const containerName = `test-${Date.now()}`;
try {
await $.docker.run('node:18', {
name: containerName,
rm: false // Don't auto-remove for debugging
});
await $.docker(containerName)`npm test`;
} finally {
await $.docker.remove(containerName, { force: true });
}
// Good: Wait for readiness
await $.docker.start('database');
await $.docker.waitHealthy('database');
await $.docker('app')`npm run migrate`;
Related Topics​
- Docker Overview - Docker target basics
- Compose Integration - Docker Compose support
- Volume Management - Managing volumes
- Networking - Container networking
- in Command - CLI container execution