Compare commits
1 commit
main
...
docs/sched
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
482255a7f1 |
14 changed files with 951 additions and 0 deletions
121
packages/system/cozystack-scheduler/examples/demo/00-helpers.sh
Executable file
121
packages/system/cozystack-scheduler/examples/demo/00-helpers.sh
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
#!/bin/bash
|
||||
# Helper functions for the scheduling classes demo
|
||||
# Source this file in other scripts: source "$(dirname "$0")/00-helpers.sh"
|
||||
|
||||
# ANSI color codes
|
||||
export RED='\033[0;31m'
|
||||
export GREEN='\033[0;32m'
|
||||
export YELLOW='\033[1;33m'
|
||||
export BLUE='\033[0;34m'
|
||||
export MAGENTA='\033[0;35m'
|
||||
export CYAN='\033[0;36m'
|
||||
export WHITE='\033[1;37m'
|
||||
export NC='\033[0m' # No Color
|
||||
export BOLD='\033[1m'
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}ℹ${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}✔${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}⚠${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}✖${NC} $*" >&2
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "\n${MAGENTA}${BOLD}▶ $*${NC}" >&2
|
||||
}
|
||||
|
||||
log_command() {
|
||||
echo -e "${WHITE} \$ $*${NC}" >&2
|
||||
}
|
||||
|
||||
separator() {
|
||||
echo -e "\n${CYAN}────────────────────────────────────────────────────────────${NC}\n" >&2
|
||||
}
|
||||
|
||||
print_header() {
|
||||
local title="$1"
|
||||
echo -e "\n${MAGENTA}${BOLD}╔════════════════════════════════════════════════════════════╗${NC}" >&2
|
||||
echo -e "${MAGENTA}${BOLD}║${NC} ${WHITE}${BOLD}$title${NC}" >&2
|
||||
echo -e "${MAGENTA}${BOLD}╚════════════════════════════════════════════════════════════╝${NC}\n" >&2
|
||||
}
|
||||
|
||||
# Display a YAML manifest with syntax highlighting (just colored output)
|
||||
show_manifest() {
|
||||
echo -e "${YELLOW}$1${NC}" >&2
|
||||
}
|
||||
|
||||
# Wait for user to press any key
|
||||
pause() {
|
||||
echo -e "\n${CYAN}Press any key to continue...${NC}" >&2
|
||||
read -rsn1
|
||||
}
|
||||
|
||||
# Wait for pods to appear and stabilize
|
||||
wait_for_pods() {
|
||||
local namespace="$1"
|
||||
local label="${2:-}"
|
||||
local timeout="${3:-120}"
|
||||
local elapsed=0
|
||||
|
||||
log_info "Waiting for pods in $namespace..."
|
||||
while true; do
|
||||
local count
|
||||
if [[ -n "$label" ]]; then
|
||||
count=$(kubectl get pods -n "$namespace" -l "$label" --no-headers 2>/dev/null | wc -l)
|
||||
else
|
||||
count=$(kubectl get pods -n "$namespace" --no-headers 2>/dev/null | wc -l)
|
||||
fi
|
||||
if [[ "$count" -gt 0 ]]; then
|
||||
break
|
||||
fi
|
||||
if [[ $elapsed -ge $timeout ]]; then
|
||||
log_warning "Timed out waiting for pods"
|
||||
return 1
|
||||
fi
|
||||
sleep 2
|
||||
elapsed=$((elapsed + 2))
|
||||
done
|
||||
# Give pods a moment to get node assignments
|
||||
sleep 3
|
||||
}
|
||||
|
||||
# Show pods with node placement
|
||||
show_pods() {
|
||||
local namespace="$1"
|
||||
echo "" >&2
|
||||
kubectl get pods -n "$namespace" -o wide 2>&1 >&2
|
||||
echo "" >&2
|
||||
}
|
||||
|
||||
# Wait for a Redis resource to be ready (HelmRelease applied)
|
||||
wait_for_redis_ready() {
|
||||
local namespace="$1"
|
||||
local name="$2"
|
||||
local timeout="${3:-180}"
|
||||
local elapsed=0
|
||||
|
||||
log_info "Waiting for Redis $name in $namespace to become ready..."
|
||||
while true; do
|
||||
local phase
|
||||
phase=$(kubectl get redis "$name" -n "$namespace" -o jsonpath='{.status.conditions[0].status}' 2>/dev/null || echo "")
|
||||
if [[ "$phase" == "True" ]]; then
|
||||
log_success "Redis $name is ready"
|
||||
break
|
||||
fi
|
||||
if [[ $elapsed -ge $timeout ]]; then
|
||||
log_warning "Timed out waiting for Redis to be ready, continuing anyway..."
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
elapsed=$((elapsed + 5))
|
||||
done
|
||||
}
|
||||
133
packages/system/cozystack-scheduler/examples/demo/01-scheduling-classes.sh
Executable file
133
packages/system/cozystack-scheduler/examples/demo/01-scheduling-classes.sh
Executable file
|
|
@ -0,0 +1,133 @@
|
|||
#!/bin/bash
|
||||
# Script 01: Create SchedulingClasses
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
print_header "Step 1: Create SchedulingClasses"
|
||||
|
||||
# --- pin-to-node2 ---
|
||||
log_step "SchedulingClass: pin-to-node2"
|
||||
log_info "All pods will always be scheduled to node2."
|
||||
|
||||
show_manifest "apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: pin-to-node2
|
||||
spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: node2"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: pin-to-node2
|
||||
spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: node2
|
||||
EOF
|
||||
|
||||
log_success "Created SchedulingClass pin-to-node2"
|
||||
|
||||
separator
|
||||
|
||||
# --- one-per-node ---
|
||||
log_step "SchedulingClass: one-per-node"
|
||||
log_info "Pods of the same application will never share a node."
|
||||
|
||||
show_manifest "apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: one-per-node
|
||||
spec:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- topologyKey: kubernetes.io/hostname"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: one-per-node
|
||||
spec:
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- topologyKey: kubernetes.io/hostname
|
||||
EOF
|
||||
|
||||
log_success "Created SchedulingClass one-per-node"
|
||||
|
||||
separator
|
||||
|
||||
# --- spread-evenly ---
|
||||
log_step "SchedulingClass: spread-evenly"
|
||||
log_info "Pods will be spread evenly across nodes (maxSkew=1)."
|
||||
|
||||
show_manifest "apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: spread-evenly
|
||||
spec:
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: DoNotSchedule"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: spread-evenly
|
||||
spec:
|
||||
topologySpreadConstraints:
|
||||
- maxSkew: 1
|
||||
topologyKey: kubernetes.io/hostname
|
||||
whenUnsatisfiable: DoNotSchedule
|
||||
EOF
|
||||
|
||||
log_success "Created SchedulingClass spread-evenly"
|
||||
|
||||
separator
|
||||
|
||||
# --- colocate ---
|
||||
log_step "SchedulingClass: colocate"
|
||||
log_info "All pods of the same application will land on the same node."
|
||||
|
||||
show_manifest "apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: colocate
|
||||
spec:
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- topologyKey: kubernetes.io/hostname"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: cozystack.io/v1alpha1
|
||||
kind: SchedulingClass
|
||||
metadata:
|
||||
name: colocate
|
||||
spec:
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- topologyKey: kubernetes.io/hostname
|
||||
EOF
|
||||
|
||||
log_success "Created SchedulingClass colocate"
|
||||
|
||||
separator
|
||||
log_success "All SchedulingClasses created."
|
||||
log_command "kubectl get schedulingclasses"
|
||||
kubectl get schedulingclasses >&2
|
||||
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./02-create-tenants.sh"
|
||||
121
packages/system/cozystack-scheduler/examples/demo/02-create-tenants.sh
Executable file
121
packages/system/cozystack-scheduler/examples/demo/02-create-tenants.sh
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
#!/bin/bash
|
||||
# Script 02: Create tenants, one per scheduling class
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
print_header "Step 2: Create Tenants"
|
||||
|
||||
# --- tenant colocate ---
|
||||
log_step "Tenant: colocate (schedulingClass: colocate)"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: colocate
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: colocate"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: colocate
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: colocate
|
||||
EOF
|
||||
|
||||
log_success "Created tenant colocate"
|
||||
|
||||
separator
|
||||
|
||||
# --- tenant onepernode ---
|
||||
log_step "Tenant: onepernode (schedulingClass: one-per-node)"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: onepernode
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: one-per-node"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: onepernode
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: one-per-node
|
||||
EOF
|
||||
|
||||
log_success "Created tenant onepernode"
|
||||
|
||||
separator
|
||||
|
||||
# --- tenant spread ---
|
||||
log_step "Tenant: spread (schedulingClass: spread-evenly)"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: spread
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: spread-evenly"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: spread
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: spread-evenly
|
||||
EOF
|
||||
|
||||
log_success "Created tenant spread"
|
||||
|
||||
separator
|
||||
|
||||
# --- tenant node2 ---
|
||||
log_step "Tenant: node2 (schedulingClass: pin-to-node2)"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: node2
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: pin-to-node2"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<'EOF'
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Tenant
|
||||
metadata:
|
||||
name: node2
|
||||
namespace: tenant-root
|
||||
spec:
|
||||
schedulingClass: pin-to-node2
|
||||
EOF
|
||||
|
||||
log_success "Created tenant node2"
|
||||
|
||||
separator
|
||||
log_success "All tenants created."
|
||||
log_command "kubectl get tenants -n tenant-root"
|
||||
kubectl get tenants -n tenant-root >&2
|
||||
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./03-colocate-demo.sh"
|
||||
69
packages/system/cozystack-scheduler/examples/demo/03-colocate-demo.sh
Executable file
69
packages/system/cozystack-scheduler/examples/demo/03-colocate-demo.sh
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
#!/bin/bash
|
||||
# Script 03: Colocate demo - all pods of a Redis land on the same node
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-colocate"
|
||||
REDIS_NAME="redis-demo"
|
||||
|
||||
print_header "Step 3: Colocate Demo"
|
||||
|
||||
log_step "Creating Redis in $NAMESPACE (1 replica + 3 sentinels)"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS_NAME created"
|
||||
|
||||
separator
|
||||
|
||||
log_step "Waiting for pods to be scheduled..."
|
||||
wait_for_redis_ready "$NAMESPACE" "$REDIS_NAME"
|
||||
wait_for_pods "$NAMESPACE"
|
||||
|
||||
log_step "All pods should be on the SAME node:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
pause
|
||||
|
||||
separator
|
||||
|
||||
log_step "Scaling up replicas to 9..."
|
||||
log_command "kubectl patch redis $REDIS_NAME -n $NAMESPACE --type=merge -p '{\"spec\":{\"replicas\":9}}'"
|
||||
|
||||
kubectl patch redis "$REDIS_NAME" -n "$NAMESPACE" --type=merge -p '{"spec":{"replicas":9}}'
|
||||
|
||||
log_info "Waiting for new pods..."
|
||||
sleep 15
|
||||
|
||||
log_step "All pods (storage + sentinels) are still on the same node:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Colocate demo complete. All pods landed on one node."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./04-colocate-second-redis.sh"
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/bash
|
||||
# Script 04: Second Redis in colocate tenant - shows cross-app independence
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-colocate"
|
||||
REDIS_NAME="redis-demo2"
|
||||
|
||||
print_header "Step 4: Colocate - Second Redis (cross-app independence)"
|
||||
|
||||
log_step "Cleaning up $REDIS_NAME if it already exists..."
|
||||
kubectl delete redis "$REDIS_NAME" -n "$NAMESPACE" --ignore-not-found >&2
|
||||
sleep 3
|
||||
|
||||
separator
|
||||
|
||||
log_step "Creating a second Redis in $NAMESPACE"
|
||||
log_info "This Redis will colocate its own pods together,"
|
||||
log_info "but may land on a DIFFERENT node than the first Redis."
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS_NAME created"
|
||||
|
||||
log_step "Waiting for pods to be scheduled..."
|
||||
wait_for_redis_ready "$NAMESPACE" "$REDIS_NAME"
|
||||
wait_for_pods "$NAMESPACE"
|
||||
|
||||
log_step "Pod placement for both Redis instances:"
|
||||
log_info "Each Redis colocates its own pods, but the two Redises are independent."
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Second Redis demo complete."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./05-colocate-cleanup.sh"
|
||||
24
packages/system/cozystack-scheduler/examples/demo/05-colocate-cleanup.sh
Executable file
24
packages/system/cozystack-scheduler/examples/demo/05-colocate-cleanup.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# Script 05: Clean up Redis instances in tenant-colocate
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-colocate"
|
||||
|
||||
print_header "Step 5: Clean up tenant-colocate"
|
||||
|
||||
log_step "Deleting all Redis instances in $NAMESPACE..."
|
||||
|
||||
kubectl delete redis --all -n "$NAMESPACE" --ignore-not-found >&2
|
||||
|
||||
log_info "Waiting for pods to terminate..."
|
||||
sleep 10
|
||||
|
||||
log_step "Remaining pods:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Cleanup complete."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./06-onepernode-demo.sh"
|
||||
92
packages/system/cozystack-scheduler/examples/demo/06-onepernode-demo.sh
Executable file
92
packages/system/cozystack-scheduler/examples/demo/06-onepernode-demo.sh
Executable file
|
|
@ -0,0 +1,92 @@
|
|||
#!/bin/bash
|
||||
# Script 06: One-per-node demo - anti-affinity prevents pods on the same node
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-onepernode"
|
||||
REDIS_NAME="redis-demo"
|
||||
|
||||
print_header "Step 6: One-per-node Demo"
|
||||
|
||||
log_step "Creating Redis in $NAMESPACE (1 replica)"
|
||||
log_info "We'll also reduce sentinels to 2 (1 storage + 2 sentinels = 3 pods for 3 nodes)."
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS_NAME created"
|
||||
|
||||
log_info "Waiting for RedisFailover to appear..."
|
||||
sleep 10
|
||||
|
||||
log_step "Patching RedisFailover to use 2 sentinels instead of 3"
|
||||
log_info "With 3 nodes and anti-affinity, 1 storage + 3 sentinels = 4 pods won't fit."
|
||||
log_command "kubectl patch rf $REDIS_NAME -n $NAMESPACE --type=merge -p '{\"spec\":{\"sentinel\":{\"replicas\":2}}}'"
|
||||
|
||||
kubectl patch rf redis-"$REDIS_NAME" -n "$NAMESPACE" --type=merge -p '{"spec":{"sentinel":{"replicas":2}}}'
|
||||
|
||||
log_info "Waiting for pods to be scheduled..."
|
||||
wait_for_pods "$NAMESPACE"
|
||||
sleep 5
|
||||
|
||||
log_step "Each pod is on a different node (1 storage + 2 sentinels on 3 nodes):"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
pause
|
||||
|
||||
separator
|
||||
|
||||
log_step "Scaling up to 3 replicas..."
|
||||
log_command "kubectl patch redis $REDIS_NAME -n $NAMESPACE --type=merge -p '{\"spec\":{\"replicas\":3}}'"
|
||||
|
||||
kubectl patch redis "$REDIS_NAME" -n "$NAMESPACE" --type=merge -p '{"spec":{"replicas":3}}'
|
||||
|
||||
log_info "Waiting for new pods..."
|
||||
sleep 15
|
||||
|
||||
log_step "Some pods should now be Pending (anti-affinity prevents scheduling):"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
pause
|
||||
|
||||
separator
|
||||
|
||||
log_step "Describing a Pending pod to see why it can't be scheduled..."
|
||||
PENDING_POD=$(kubectl get pods -n "$NAMESPACE" --field-selector=status.phase=Pending -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "$PENDING_POD" ]]; then
|
||||
log_command "kubectl describe pod $PENDING_POD -n $NAMESPACE | tail -10"
|
||||
kubectl describe pod "$PENDING_POD" -n "$NAMESPACE" 2>&1 | tail -10 >&2
|
||||
else
|
||||
log_warning "No Pending pods found (pods may still be initializing)."
|
||||
log_command "kubectl get pods -n $NAMESPACE -o wide"
|
||||
fi
|
||||
|
||||
separator
|
||||
log_success "One-per-node demo complete. Anti-affinity prevents co-scheduling."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./07-onepernode-second-redis.sh"
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#!/bin/bash
|
||||
# Script 07: Second Redis in one-per-node tenant - shows cross-app independence
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-onepernode"
|
||||
REDIS_NAME="redis-demo2"
|
||||
|
||||
print_header "Step 7: One-per-node - Second Redis (cross-app independence)"
|
||||
|
||||
log_step "Cleaning up $REDIS_NAME if it already exists..."
|
||||
kubectl delete redis "$REDIS_NAME" -n "$NAMESPACE" --ignore-not-found >&2
|
||||
sleep 3
|
||||
|
||||
separator
|
||||
|
||||
log_step "Creating a second Redis in $NAMESPACE"
|
||||
log_info "Anti-affinity only applies WITHIN the same application."
|
||||
log_info "This second Redis has no anti-affinity against the first one."
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS_NAME created"
|
||||
|
||||
log_info "Waiting for RedisFailover to appear..."
|
||||
sleep 10
|
||||
|
||||
log_step "Patching sentinels to 2 for the second Redis as well"
|
||||
kubectl patch rf redis-"$REDIS_NAME" -n "$NAMESPACE" --type=merge -p '{"spec":{"sentinel":{"replicas":2}}}'
|
||||
|
||||
log_info "Waiting for pods to be scheduled..."
|
||||
wait_for_pods "$NAMESPACE"
|
||||
sleep 5
|
||||
|
||||
log_step "Pod placement for both Redis instances:"
|
||||
log_info "Each Redis spreads its own pods one-per-node independently."
|
||||
log_info "The two Redises CAN share nodes — anti-affinity is per-application."
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Second Redis demo complete."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./08-onepernode-cleanup.sh"
|
||||
24
packages/system/cozystack-scheduler/examples/demo/08-onepernode-cleanup.sh
Executable file
24
packages/system/cozystack-scheduler/examples/demo/08-onepernode-cleanup.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# Script 08: Clean up Redis instances in tenant-onepernode
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-onepernode"
|
||||
|
||||
print_header "Step 8: Clean up tenant-onepernode"
|
||||
|
||||
log_step "Deleting all Redis instances in $NAMESPACE..."
|
||||
|
||||
kubectl delete redis --all -n "$NAMESPACE" --ignore-not-found >&2
|
||||
|
||||
log_info "Waiting for pods to terminate..."
|
||||
sleep 10
|
||||
|
||||
log_step "Remaining pods:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Cleanup complete."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./09-spread-demo.sh"
|
||||
73
packages/system/cozystack-scheduler/examples/demo/09-spread-demo.sh
Executable file
73
packages/system/cozystack-scheduler/examples/demo/09-spread-demo.sh
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
#!/bin/bash
|
||||
# Script 09: Spread-evenly demo - topology spread constraints
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-spread"
|
||||
REDIS_NAME="redis-demo"
|
||||
|
||||
print_header "Step 9: Spread-evenly Demo"
|
||||
|
||||
log_step "Creating Redis in $NAMESPACE (1 replica)"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS_NAME
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS_NAME created"
|
||||
|
||||
log_info "Waiting for pods to be scheduled..."
|
||||
wait_for_redis_ready "$NAMESPACE" "$REDIS_NAME"
|
||||
wait_for_pods "$NAMESPACE"
|
||||
|
||||
log_step "Initial pod distribution (1 storage + 3 sentinels):"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
pause
|
||||
|
||||
separator
|
||||
|
||||
log_step "Scaling up to 9 replicas..."
|
||||
log_command "kubectl patch redis $REDIS_NAME -n $NAMESPACE --type=merge -p '{\"spec\":{\"replicas\":9}}'"
|
||||
|
||||
kubectl patch redis "$REDIS_NAME" -n "$NAMESPACE" --type=merge -p '{"spec":{"replicas":9}}'
|
||||
|
||||
log_info "Waiting for new pods..."
|
||||
sleep 20
|
||||
|
||||
log_step "Pods should be evenly distributed across all nodes (maxSkew=1):"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
|
||||
log_step "Pod count per node:"
|
||||
kubectl get pods -n "$NAMESPACE" -o wide --no-headers 2>/dev/null \
|
||||
| awk '{print $7}' | sort | uniq -c | sort -rn >&2
|
||||
|
||||
separator
|
||||
log_success "Spread-evenly demo complete. Pods are balanced across nodes."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./10-spread-cleanup.sh"
|
||||
24
packages/system/cozystack-scheduler/examples/demo/10-spread-cleanup.sh
Executable file
24
packages/system/cozystack-scheduler/examples/demo/10-spread-cleanup.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# Script 10: Clean up Redis instances in tenant-spread
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-spread"
|
||||
|
||||
print_header "Step 10: Clean up tenant-spread"
|
||||
|
||||
log_step "Deleting all Redis instances in $NAMESPACE..."
|
||||
|
||||
kubectl delete redis --all -n "$NAMESPACE" --ignore-not-found >&2
|
||||
|
||||
log_info "Waiting for pods to terminate..."
|
||||
sleep 10
|
||||
|
||||
log_step "Remaining pods:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Cleanup complete."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./11-node2-demo.sh"
|
||||
94
packages/system/cozystack-scheduler/examples/demo/11-node2-demo.sh
Executable file
94
packages/system/cozystack-scheduler/examples/demo/11-node2-demo.sh
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
#!/bin/bash
|
||||
# Script 11: Pin-to-node2 demo - all pods on a specific node
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-node2"
|
||||
REDIS1="redis-demo"
|
||||
REDIS2="redis-demo2"
|
||||
|
||||
print_header "Step 11: Pin-to-node2 Demo"
|
||||
|
||||
log_step "Creating first Redis in $NAMESPACE"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS1
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS1
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS1 created"
|
||||
|
||||
log_info "Waiting for pods to be scheduled..."
|
||||
wait_for_redis_ready "$NAMESPACE" "$REDIS1"
|
||||
wait_for_pods "$NAMESPACE"
|
||||
|
||||
log_step "All pods should be on node2:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
pause
|
||||
|
||||
separator
|
||||
|
||||
log_step "Creating a second Redis in $NAMESPACE"
|
||||
|
||||
show_manifest "apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS2
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false"
|
||||
|
||||
pause
|
||||
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: Redis
|
||||
metadata:
|
||||
name: $REDIS2
|
||||
namespace: $NAMESPACE
|
||||
spec:
|
||||
replicas: 1
|
||||
storageClass: local
|
||||
resourcesPreset: nano
|
||||
authEnabled: false
|
||||
EOF
|
||||
|
||||
log_success "Redis $REDIS2 created"
|
||||
|
||||
log_info "Waiting for pods to be scheduled..."
|
||||
wait_for_redis_ready "$NAMESPACE" "$REDIS2"
|
||||
wait_for_pods "$NAMESPACE"
|
||||
|
||||
log_step "Both Redis instances — all pods pinned to node2:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Pin-to-node2 demo complete."
|
||||
echo -e "\n${GREEN}${BOLD}Next step:${NC} ./12-node2-cleanup.sh"
|
||||
23
packages/system/cozystack-scheduler/examples/demo/12-node2-cleanup.sh
Executable file
23
packages/system/cozystack-scheduler/examples/demo/12-node2-cleanup.sh
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
# Script 12: Clean up Redis instances in tenant-node2
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
NAMESPACE="tenant-node2"
|
||||
|
||||
print_header "Step 12: Clean up tenant-node2"
|
||||
|
||||
log_step "Deleting all Redis instances in $NAMESPACE..."
|
||||
|
||||
kubectl delete redis --all -n "$NAMESPACE" --ignore-not-found >&2
|
||||
|
||||
log_info "Waiting for pods to terminate..."
|
||||
sleep 10
|
||||
|
||||
log_step "Remaining pods:"
|
||||
show_pods "$NAMESPACE"
|
||||
|
||||
separator
|
||||
log_success "Cleanup complete. Demo finished!"
|
||||
24
packages/system/cozystack-scheduler/examples/demo/13-teardown.sh
Executable file
24
packages/system/cozystack-scheduler/examples/demo/13-teardown.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# Script 13: Tear down all tenants and scheduling classes
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/00-helpers.sh"
|
||||
|
||||
print_header "Teardown: Remove tenants and scheduling classes"
|
||||
|
||||
log_step "Deleting tenants..."
|
||||
for t in colocate onepernode spread node2; do
|
||||
kubectl delete tenant "$t" -n tenant-root --ignore-not-found >&2
|
||||
done
|
||||
|
||||
log_info "Waiting for tenant namespaces to be cleaned up..."
|
||||
sleep 15
|
||||
|
||||
log_step "Deleting scheduling classes..."
|
||||
for sc in colocate one-per-node spread-evenly pin-to-node2; do
|
||||
kubectl delete schedulingclass "$sc" --ignore-not-found >&2
|
||||
done
|
||||
|
||||
separator
|
||||
log_success "Teardown complete."
|
||||
Loading…
Add table
Add a link
Reference in a new issue