Automation Scripts: Infrastructure as Code
All installation steps are automated with bash scripts. This article explains the automation strategy and how each script works.
Philosophy
Why Automate?
- Reproducible installations
- Documented process
- Less human error
- Version controlled
- Easy to rerun
Script Design:
- Idempotent where possible
- Clear error messages
- Progress indicators
- Validation steps
- Rollback instructions
Script Overview
scripts/
├── 00-install-all.sh # Master script (runs all)
├── 01-prepare-talos.sh # Download tools & ISO
├── 02-install-talos.sh # Install Talos on R430
├── 03-bootstrap-k8s.sh # Initialize Kubernetes
├── 04-install-storage.sh # Local Path Provisioner
├── 05-install-network.sh # MetalLB + Traefik
├── 07-install-kubevirt.sh # KubeVirt operator
└── 08-install-npm.sh # Nginx Proxy Manager
Script 01: Prepare Talos
Purpose: Download all required tools and ISO
What it does:
- Checks/installs Homebrew
- Installs
kubectlandhelm - Downloads
talosctl - Downloads Talos ISO
- Downloads
virtctl
Key Features:
# Version management
TALOS_VERSION="v1.6.4"
# Download with progress
curl -LO --progress-bar "https://github.com/..."
# Verify downloads
if [ ! -f "metal-amd64-${TALOS_VERSION}.iso" ]; then
echo "❌ ISO download failed"
exit 1
fi
Output:
~/r430-migration/directory- Tools in
/usr/local/bin/ - ISO ready for iDRAC mounting
Script 02: Install Talos
Purpose: Install Talos Linux on R430 disk
What it does:
- Collects network configuration
- Generates Talos config files
- Applies config to R430
- Waits for reboot
- Verifies installation
Interactive Parts:
# Network configuration
read -p "IP du serveur: " SERVER_IP
read -p "Passerelle: " GATEWAY
read -p "DNS primaire: " DNS1
# Generate config
talosctl gen config tom-lab-cluster https://${SERVER_IP}:6443
# Apply config
talosctl apply-config --insecure --nodes ${SERVER_IP} --file controlplane.yaml
Validation:
# Wait for Talos to be ready
for i in {1..30}; do
if talosctl --nodes ${SERVER_IP} version &>/dev/null; then
echo "✅ Talos ready"
break
fi
sleep 10
done
Script 03: Bootstrap Kubernetes
Purpose: Initialize Kubernetes cluster
What it does:
- Bootstraps etcd
- Retrieves kubeconfig
- Waits for API server
- Verifies cluster
Key Steps:
# Bootstrap
talosctl bootstrap --nodes ${SERVER_IP}
# Get kubeconfig
export TALOSCONFIG=~/r430-migration/talos-config/talosconfig
talosctl -e ${SERVER_IP} --nodes ${SERVER_IP} kubeconfig --force
# Wait for API
kubectl wait --for=condition=ready node --all --timeout=300s
Error Handling:
# Retry logic
for i in {1..10}; do
if kubectl get nodes &>/dev/null; then
break
fi
echo "⏳ Waiting for Kubernetes API... ($i/10)"
sleep 10
done
Script 04: Install Storage
Purpose: Deploy Local Path Provisioner
What it does:
- Applies Local Path manifest
- Sets as default StorageClass
- Tests with sample PVC
- Cleans up test PVC
Implementation:
# Install
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.26/deploy/local-path-storage.yaml
# Set default
kubectl patch storageclass local-path \
-p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# Test
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
storageClassName: local-path
resources:
requests:
storage: 1Gi
EOF
# Verify
kubectl get pvc test-pvc
kubectl delete pvc test-pvc
Script 05: Install Network
Purpose: Deploy MetalLB and Traefik
What it does:
- Installs MetalLB
- Configures IP pool (interactive)
- Installs Traefik
- Verifies LoadBalancer IPs
Interactive Configuration:
# Get IP range from user
read -p "IP de début (ex: 192.168.1.200): " IP_START
read -p "IP de fin (ex: 192.168.1.220): " IP_END
# Create IP pool
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- ${IP_START}-${IP_END}
EOF
Verification:
# Wait for MetalLB
kubectl wait --for=condition=ready pod -n metallb-system -l app=metallb --timeout=120s
# Test LoadBalancer
kubectl apply -f test-lb.yaml
sleep 10
EXTERNAL_IP=$(kubectl get svc test-lb -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "✅ LoadBalancer IP: ${EXTERNAL_IP}"
Script 07: Install KubeVirt
Purpose: Deploy KubeVirt operator
What it does:
- Checks hardware virtualization
- Installs KubeVirt operator
- Installs KubeVirt CR
- Waits for components
Hardware Check:
# Check VT-x/AMD-V
if talosctl -e ${SERVER_IP} --nodes ${SERVER_IP} read /proc/cpuinfo | grep -qE "vmx|svm"; then
echo "✅ Virtualisation matérielle détectée"
else
echo "⚠️ Virtualisation matérielle NON détectée !"
read -p "Continuer quand même ? (y/n) " -n 1 -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
Installation:
# Set version
KUBEVIRT_VERSION="v1.1.2"
# Install operator
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml
# Wait for operator
kubectl wait --for=condition=ready pod -n kubevirt-system -l kubevirt.io=virt-operator --timeout=120s
# Install KubeVirt
kubectl apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml
# Wait for components
kubectl wait --for=condition=ready pod -n kubevirt-system -l kubevirt.io=virt-handler --timeout=300s
Script 08: Install NPM
Purpose: Deploy Nginx Proxy Manager
What it does:
- Creates namespace
- Creates PVCs
- Deploys NPM
- Exposes LoadBalancer service
Implementation:
# Apply manifest
kubectl apply -f kubernetes/networking/npm/npm-deploy.yaml
# Wait for pod
kubectl wait --for=condition=ready pod -l app=nginx-proxy-manager -n npm --timeout=120s
# Get LoadBalancer IP
NPM_IP=$(kubectl get svc -n npm nginx-proxy-manager -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "✅ NPM installé"
echo "🌐 Interface admin: http://${NPM_IP}:81"
echo " Email: admin@example.com"
echo " Password: changeme"
Master Script: 00-install-all.sh
Purpose: Run all scripts in sequence
Features:
- Progress tracking
- Error handling
- Pause between steps
- Summary at end
Structure:
#!/bin/bash
set -e # Exit on error
echo "========================================"
echo "Installation Complète - Tom Lab"
echo "========================================"
# Step 1: Prepare
./scripts/01-prepare-talos.sh
read -p "Appuyez sur Entrée pour continuer..."
# Step 2: Install Talos
./scripts/02-install-talos.sh
read -p "Appuyez sur Entrée pour continuer..."
# ... continue with all steps
# Final summary
echo "========================================"
echo "✅ Installation terminée !"
echo "========================================"
Error Handling Patterns
Retry Logic
# Retry with backoff
for i in {1..10}; do
if command; then
break
fi
echo "⏳ Tentative $i/10..."
sleep $i
done
Validation
# Verify before proceeding
if ! kubectl get nodes &>/dev/null; then
echo "❌ Kubernetes non accessible"
exit 1
fi
Cleanup on Error
# Trap errors
trap cleanup EXIT
cleanup() {
echo "🧹 Nettoyage..."
kubectl delete pvc test-pvc 2>/dev/null || true
}
Best Practices
- Idempotency - Scripts can be run multiple times safely
- Validation - Check prerequisites before proceeding
- Progress - Show what’s happening
- Error Messages - Clear, actionable errors
- Documentation - Comments explain why, not what
- Version Pinning - Specific versions, not “latest”
Testing Scripts
Dry Run Mode
# Check what would happen
kubectl apply --dry-run=client -f manifest.yaml
Validation Mode
# Verify without making changes
if kubectl get nodes &>/dev/null; then
echo "✅ Cluster accessible"
else
echo "❌ Cluster not ready"
exit 1
fi
Version Management
Pinned Versions:
TALOS_VERSION="v1.6.4"
KUBEVIRT_VERSION="v1.1.2"
METALLB_VERSION="v0.14.3"
Benefits:
- Reproducible installations
- Known working versions
- Easy to update later
Customization
Environment Variables:
# Allow override
SERVER_IP="${SERVER_IP:-192.168.1.100}"
NAMESPACE="${NAMESPACE:-default}"
Configuration Files:
- Network config:
talos/directory - Kubernetes manifests:
kubernetes/directory - All version controlled in Git
Maintenance
Updating Scripts:
- Test on non-production first
- Update version numbers
- Test each script individually
- Update documentation
- Commit to Git
Adding New Scripts:
- Follow naming convention:
NN-description.sh - Add to master script
- Document in README
- Test thoroughly
Conclusion
Automation scripts make the installation:
- ✅ Reproducible
- ✅ Documented
- ✅ Less error-prone
- ✅ Version controlled
All scripts are in scripts/ directory and can be run individually or via master script.
Next: Complete Project Summary