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