Understanding Startup Commands
TOC
Overview
Startup commands in Kubernetes define the primary executable that runs when a container starts. They correspond to the command
field in Kubernetes Pod specifications and override the default ENTRYPOINT instruction defined in container images. Startup commands provide complete control over what process runs inside your containers.
Core Concepts
What are Startup Commands?
Startup commands are:
- The primary executable that runs when a container starts
- Override the ENTRYPOINT instruction in Docker images
- Define the main process (PID 1) inside the container
- Work in conjunction with parameters (args) to form the complete command line
Relationship with Docker and Parameters
Understanding the relationship between Docker instructions and Kubernetes fields:
Docker | Kubernetes | Purpose |
---|
ENTRYPOINT | command | Defines the executable |
CMD | args | Provides default arguments |
# Dockerfile example
FROM ubuntu:20.04
ENTRYPOINT ["/usr/bin/myapp"]
CMD ["--config=/etc/default.conf"]
# Kubernetes override
apiVersion: v1
kind: Pod
spec:
containers:
- name: myapp
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["--config=/etc/custom.conf", "--debug"]
Command vs Args Interaction
Scenario | Docker Image | Kubernetes Spec | Resulting Command |
---|
Default | ENTRYPOINT + CMD | (none) | ENTRYPOINT + CMD |
Override args only | ENTRYPOINT + CMD | args: ["new-args"] | ENTRYPOINT + new-args |
Override command only | ENTRYPOINT + CMD | command: ["new-cmd"] | new-cmd |
Override both | ENTRYPOINT + CMD | command: ["new-cmd"]
args: ["new-args"] | new-cmd + new-args |
Use Cases and Scenarios
1. Custom Application Startup
Run different applications using the same base image:
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
containers:
- name: nginx
image: ubuntu:20.04
command: ["/usr/sbin/nginx"]
args: ["-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
2. Debugging and Troubleshooting
Override the default command to start a shell for debugging:
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
spec:
containers:
- name: debug
image: myapp:latest
command: ["/bin/bash"]
args: ["-c", "sleep 3600"]
3. Initialization Scripts
Run custom initialization before starting the main application:
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
command: ["/bin/sh"]
args:
- "-c"
- |
echo "Initializing application..."
/scripts/init.sh
echo "Starting main application..."
exec /usr/bin/myapp --config=/etc/app.conf
4. Multi-Purpose Images
Use the same image for different purposes:
# Web server
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
template:
spec:
containers:
- name: web
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["server", "--port=8080"]
---
# Background worker
apiVersion: apps/v1
kind: Deployment
metadata:
name: worker
spec:
template:
spec:
containers:
- name: worker
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["worker", "--queue=tasks"]
---
# Database migration
apiVersion: batch/v1
kind: Job
metadata:
name: migrate
spec:
template:
spec:
containers:
- name: migrate
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["migrate", "--up"]
restartPolicy: Never
CLI Examples and Practical Usage
Using kubectl run
# Override command completely
kubectl run debug --image=nginx:alpine --command -- /bin/sh -c "sleep 3600"
# Run interactive shell
kubectl run -it debug --image=ubuntu:20.04 --restart=Never --command -- /bin/bash
# Custom application startup
kubectl run myapp --image=myapp:latest --command -- /usr/local/bin/start.sh --config=/etc/app.conf
# One-time task
kubectl run task --image=busybox --restart=Never --command -- /bin/sh -c "echo 'Task completed'"
Using kubectl create job
# Create a job with custom command
kubectl create job backup --image=postgres:13 --dry-run=client -o yaml -- pg_dump -h db.example.com mydb > backup.yaml
# Apply the job
kubectl apply -f backup.yaml
Complex Startup Command Examples
Multi-Step Initialization
apiVersion: v1
kind: Pod
metadata:
name: complex-init
spec:
containers:
- name: app
image: myapp:latest
command: ["/bin/bash"]
args:
- "-c"
- |
set -e
echo "Step 1: Checking dependencies..."
/scripts/check-deps.sh
echo "Step 2: Setting up configuration..."
/scripts/setup-config.sh
echo "Step 3: Running database migrations..."
/scripts/migrate.sh
echo "Step 4: Starting application..."
exec /usr/bin/myapp --config=/etc/app/config.yaml
volumeMounts:
- name: scripts
mountPath: /scripts
- name: config
mountPath: /etc/app
volumes:
- name: scripts
configMap:
name: init-scripts
defaultMode: 0755
- name: config
configMap:
name: app-config
Conditional Startup Logic
apiVersion: apps/v1
kind: Deployment
metadata:
name: conditional-app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
command: ["/bin/sh"]
args:
- "-c"
- |
if [ "$APP_MODE" = "worker" ]; then
exec /usr/bin/myapp worker --queue=$QUEUE_NAME
elif [ "$APP_MODE" = "scheduler" ]; then
exec /usr/bin/myapp scheduler --interval=60
else
exec /usr/bin/myapp server --port=8080
fi
env:
- name: APP_MODE
value: "server"
- name: QUEUE_NAME
value: "default"
Best Practices
1. Signal Handling and Graceful Shutdown
# ✅ Proper signal handling
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
command: ["/bin/bash"]
args:
- "-c"
- |
# Trap SIGTERM for graceful shutdown
trap 'echo "Received SIGTERM, shutting down gracefully..."; kill -TERM $PID; wait $PID' TERM
# Start the main application in background
/usr/bin/myapp --config=/etc/app.conf &
PID=$!
# Wait for the process
wait $PID
2. Error Handling and Logging
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
command: ["/bin/bash"]
args:
- "-c"
- |
set -euo pipefail # Exit on error, undefined vars, pipe failures
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
}
log "Starting application initialization..."
if ! /scripts/health-check.sh; then
log "ERROR: Health check failed"
exit 1
fi
log "Starting main application..."
exec /usr/bin/myapp --config=/etc/app.conf
3. Security Considerations
# ✅ Run as non-root user
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
containers:
- name: app
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["--config=/etc/app.conf"]
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
4. Resource Management
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["--config=/etc/app.conf"]
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Advanced Usage Patterns
1. Init Containers with Custom Commands
apiVersion: v1
kind: Pod
spec:
initContainers:
- name: setup
image: busybox
command: ["/bin/sh"]
args:
- "-c"
- |
echo "Setting up shared data..."
mkdir -p /shared/data
echo "Setup complete" > /shared/data/status
volumeMounts:
- name: shared-data
mountPath: /shared
containers:
- name: app
image: myapp:latest
command: ["/bin/sh"]
args:
- "-c"
- |
while [ ! -f /shared/data/status ]; do
echo "Waiting for setup to complete..."
sleep 1
done
echo "Starting application..."
exec /usr/bin/myapp
volumeMounts:
- name: shared-data
mountPath: /shared
volumes:
- name: shared-data
emptyDir: {}
2. Sidecar Containers with Different Commands
apiVersion: v1
kind: Pod
spec:
containers:
# Main application
- name: app
image: myapp:latest
command: ["/usr/bin/myapp"]
args: ["--config=/etc/app.conf"]
# Log shipper sidecar
- name: log-shipper
image: fluent/fluent-bit:latest
command: ["/fluent-bit/bin/fluent-bit"]
args: ["--config=/fluent-bit/etc/fluent-bit.conf"]
# Metrics exporter sidecar
- name: metrics
image: prom/node-exporter:latest
command: ["/bin/node_exporter"]
args: ["--path.rootfs=/host"]
3. Job Patterns with Custom Commands
# Backup job
apiVersion: batch/v1
kind: Job
metadata:
name: database-backup
spec:
template:
spec:
containers:
- name: backup
image: postgres:13
command: ["/bin/bash"]
args:
- "-c"
- |
set -e
echo "Starting backup at $(date)"
pg_dump -h $DB_HOST -U $DB_USER $DB_NAME > /backup/dump-$(date +%Y%m%d-%H%M%S).sql
echo "Backup completed at $(date)"
env:
- name: DB_HOST
value: "postgres.example.com"
- name: DB_USER
value: "backup_user"
- name: DB_NAME
value: "myapp"
volumeMounts:
- name: backup-storage
mountPath: /backup
restartPolicy: Never
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
Startup commands provide complete control over container execution in Kubernetes. By understanding how to properly configure and use startup commands, you can create flexible, maintainable, and robust containerized applications that meet your specific requirements.