Pod Execution
Implementation Referenceβ
Source Files:
packages/core/src/adapters/kubernetes-adapter.ts
- Main Kubernetes adapterpackages/core/src/utils/kubernetes-api.ts
- K8s API utilities and pod instancespackages/core/src/core/command.ts
- KubernetesAdapterOptions interface
Key Functions:
KubernetesAdapter.execute()
- Main command execution in podsKubernetesAdapter.buildKubectlExecArgs()
- Build kubectl exec argumentscreateK8sPod()
- Create pod instance with execution methodsK8sPod.exec()
- Execute commands in specific podK8sPod.raw()
- Raw command execution without shell
Overviewβ
Xec provides powerful capabilities for executing commands inside Kubernetes pods through the kubectl exec
interface. The execution engine handles pod selection, container targeting, and command execution with proper error handling and stream management.
Basic Pod Executionβ
Direct Pod Executionβ
Execute commands in pods using the Kubernetes adapter:
import { $ } from '@xec-sh/core';
// Execute in specific pod
const result = await $.k8s({
pod: 'web-server-abc123',
namespace: 'production'
})`ps aux`;
console.log(result.stdout);
Using Pod Instanceβ
Get a pod instance for multiple operations:
const k8s = $.k8s({ namespace: 'default' });
const pod = k8s.pod('my-app-pod');
// Execute multiple commands
const hostname = await pod.exec`hostname`;
const processes = await pod.exec`ps aux | grep node`;
const diskUsage = await pod.exec`df -h`;
console.log(`Pod: ${hostname.stdout.trim()}`);
console.log(`Node processes: ${processes.stdout}`);
Container Selectionβ
Multi-Container Podsβ
Target specific containers in multi-container pods:
// Execute in specific container
const appResult = await $.k8s({
pod: 'multi-container-pod',
container: 'app',
namespace: 'production'
})`cat /app/version.txt`;
// Execute in sidecar container
const sidecarResult = await $.k8s({
pod: 'multi-container-pod',
container: 'nginx',
namespace: 'production'
})`nginx -t`;
Container Methodsβ
Use pod instance methods for container-specific operations:
const pod = k8s.pod('multi-container-pod');
// Different containers in same pod
const appStatus = await pod.exec`curl localhost:3000/health`;
const nginxConfig = await pod.exec`nginx -T`; // Uses default container
// Override container per command
const specificContainer = await $.k8s({
pod: 'multi-container-pod',
container: 'sidecar'
})`tail -f /var/log/sidecar.log`;
Execution Optionsβ
TTY and Interactive Modeβ
Control TTY and interactive options:
// Enable TTY for interactive commands
const interactive = await $.k8s({
pod: 'debug-pod',
tty: true,
stdin: true
})`top -b -n 1`;
// Non-interactive mode (default)
const batch = await $.k8s({
pod: 'worker-pod',
tty: false
})`batch-process --config /app/config.json`;
Custom kubectl Flagsβ
Pass additional flags to kubectl exec:
const result = await $.k8s({
pod: 'my-pod',
execFlags: ['--quiet', '--request-timeout=30s']
})`long-running-command`;
Shell vs Raw Executionβ
Shell Execution (Default)β
Commands are executed through shell by default:
// Shell command with pipes and redirects
const result = await pod.exec`ps aux | grep node | wc -l`;
// Environment variable expansion
const path = await pod.exec`echo $PATH`;
// Complex shell operations
const cleanup = await pod.exec`find /tmp -name "*.log" -mtime +7 -delete`;
Raw Executionβ
Execute commands directly without shell interpretation:
// Raw command execution
const direct = await pod.raw`ls -la /app`;
// Safer for commands with special characters
const literal = await pod.raw`echo "Hello | World"`;
Pod Selection Patternsβ
Exact Pod Namesβ
Target pods by exact name:
// Full pod name
await $.k8s({
pod: 'web-deployment-abc123-xyz',
namespace: 'production'
})`uptime`;
Label Selectorsβ
Select pods using Kubernetes label selectors:
// Using label selector syntax
await $.k8s({
pod: '-l app=web,env=production',
namespace: 'production'
})`systemctl status nginx`;
// The adapter automatically resolves to first matching pod
Pattern Matchingβ
Use patterns for pod selection:
// Regex pattern (handled by kubectl)
const webPods = await $.k8s({
pod: 'web-.*',
namespace: 'production'
})`curl localhost:8080/health`;
Environment and Working Directoryβ
Environment Variablesβ
Set environment variables for pod execution:
const configured = $.k8s({
pod: 'my-pod'
}).env({
DATABASE_URL: 'postgres://localhost:5432/mydb',
LOG_LEVEL: 'debug'
});
await configured`echo "DB: $DATABASE_URL"`;
Working Directoryβ
Execute commands in specific directories:
const app = $.k8s({
pod: 'app-pod'
}).cd('/app');
// All commands run in /app directory
await app`npm test`;
await app`ls -la package.json`;
Error Handlingβ
Command Failuresβ
Handle pod execution failures:
try {
await $.k8s({
pod: 'worker-pod'
})`failing-command`;
} catch (error) {
if (error.code === 'KUBERNETES_ERROR') {
console.log('Kubectl failed:', error.message);
console.log('Stderr:', error.stderr);
}
}
Non-throwing Executionβ
Use .nothrow()
to handle failures gracefully:
const result = await $.k8s({
pod: 'test-pod'
})`risky-operation`.nothrow();
if (result.ok) {
console.log('Success:', result.stdout);
} else {
console.log('Failed with code:', result.exitCode);
console.log('Error:', result.stderr);
}
Pod Availabilityβ
Check pod readiness before execution:
const adapter = $.getAdapter('kubernetes');
// Check if pod is ready
const isReady = await adapter.isPodReady('my-pod', 'default');
if (!isReady) {
console.log('Pod not ready, waiting...');
// Implementation would wait or retry
}
Advanced Executionβ
Timeout Configurationβ
Set execution timeouts:
const longRunning = $.k8s({
pod: 'batch-processor'
}).timeout(300000); // 5 minutes
await longRunning`large-batch-job --input /data/large-file.csv`;
Retry Logicβ
Implement retry for transient failures:
const resilient = $.k8s({
pod: 'api-pod'
}).retry({
attempts: 3,
delay: 1000
});
await resilient`curl -f http://external-api/data`;
Streaming Outputβ
Stream command output in real-time:
const stream = $.k8s({
pod: 'log-processor'
})`tail -f /var/log/app.log`;
// Process streaming output
stream.stdout.on('data', (chunk) => {
process.stdout.write(`[${pod}] ${chunk}`);
});
await stream;
Common Patternsβ
Health Checksβ
Implement pod health checking:
async function checkPodHealth(podName: string) {
const pod = $.k8s({ pod: podName, namespace: 'production' });
const health = await pod.exec`curl -f http://localhost:8080/health`.nothrow();
if (health.ok) {
const status = JSON.parse(health.stdout);
return { healthy: status.status === 'ok', details: status };
}
return { healthy: false, error: health.stderr };
}
Log Collectionβ
Collect logs from application files:
async function collectApplicationLogs(pods: string[]) {
const results = await Promise.all(
pods.map(async (podName) => {
const pod = $.k8s({ pod: podName, namespace: 'production' });
const logs = await pod.exec`tail -n 100 /var/log/app.log`.nothrow();
return {
pod: podName,
logs: logs.ok ? logs.stdout : `Error: ${logs.stderr}`
};
})
);
return results;
}
Configuration Validationβ
Validate configuration in pods:
async function validateConfig(podName: string) {
const pod = $.k8s({ pod: podName, namespace: 'staging' });
// Check config file exists
const configCheck = await pod.exec`test -f /app/config.json`.nothrow();
if (!configCheck.ok) {
throw new Error('Configuration file missing');
}
// Validate JSON syntax
const jsonCheck = await pod.exec`python -m json.tool /app/config.json`.nothrow();
if (!jsonCheck.ok) {
throw new Error('Invalid JSON configuration');
}
// Application-specific validation
const appCheck = await pod.exec`/app/bin/validate-config`.nothrow();
if (!appCheck.ok) {
throw new Error(`Config validation failed: ${appCheck.stderr}`);
}
return true;
}
Performance Considerationsβ
Command Efficiencyβ
- Batch Commands: Combine multiple operations into single commands
- Shell Pipelines: Use shell features to reduce round trips
- Local Processing: Process data locally when possible
Resource Usageβ
- Memory: Each kubectl exec creates a new process
- Network: Commands go through Kubernetes API server
- Timing: Allow 200-500ms overhead per command
Best Practicesβ
// Good: Single command with pipeline
await pod.exec`ps aux | grep node | awk '{print $2}' | head -5`;
// Less efficient: Multiple separate commands
const ps = await pod.exec`ps aux`;
const filtered = await pod.exec`echo "${ps.stdout}" | grep node`;
const pids = await pod.exec`echo "${filtered.stdout}" | awk '{print $2}'`;