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