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?

Script Design:

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:

  1. Checks/installs Homebrew
  2. Installs kubectl and helm
  3. Downloads talosctl
  4. Downloads Talos ISO
  5. 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:

Script 02: Install Talos

Purpose: Install Talos Linux on R430 disk

What it does:

  1. Collects network configuration
  2. Generates Talos config files
  3. Applies config to R430
  4. Waits for reboot
  5. 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:

  1. Bootstraps etcd
  2. Retrieves kubeconfig
  3. Waits for API server
  4. 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:

  1. Applies Local Path manifest
  2. Sets as default StorageClass
  3. Tests with sample PVC
  4. 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:

  1. Installs MetalLB
  2. Configures IP pool (interactive)
  3. Installs Traefik
  4. 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:

  1. Checks hardware virtualization
  2. Installs KubeVirt operator
  3. Installs KubeVirt CR
  4. 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:

  1. Creates namespace
  2. Creates PVCs
  3. Deploys NPM
  4. 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:

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

  1. Idempotency - Scripts can be run multiple times safely
  2. Validation - Check prerequisites before proceeding
  3. Progress - Show what’s happening
  4. Error Messages - Clear, actionable errors
  5. Documentation - Comments explain why, not what
  6. 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:

Customization

Environment Variables:

# Allow override
SERVER_IP="${SERVER_IP:-192.168.1.100}"
NAMESPACE="${NAMESPACE:-default}"

Configuration Files:

Maintenance

Updating Scripts:

  1. Test on non-production first
  2. Update version numbers
  3. Test each script individually
  4. Update documentation
  5. Commit to Git

Adding New Scripts:

  1. Follow naming convention: NN-description.sh
  2. Add to master script
  3. Document in README
  4. Test thoroughly

Conclusion

Automation scripts make the installation:

All scripts are in scripts/ directory and can be run individually or via master script.


Next: Complete Project Summary