Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion apps/unicorn-store-spring/scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ docker build \
--secret id=db-password,env=DB_PASS \
"${EXTRA_ARGS[@]}" \
-t "${REPO}:${TAG}" -f "$DOCKERFILE" .
docker push "${REPO}:${TAG}"
# A push can stall without output (seen once: 20 min for two layers that usually take
# seconds). Bound each attempt and retry; layers already uploaded are not sent again.
for attempt in 1 2 3; do
if timeout 180 docker push "${REPO}:${TAG}"; then break; fi
[ "${attempt}" = 3 ] && { echo "[build] push failed 3 times" >&2; exit 1; }
echo "[build] push did not finish in 180 s, retrying (${attempt}/3)..." >&2
done
echo "[build] pushed ${REPO}:${TAG}" >&2
echo "${REPO}:${TAG}"
69 changes: 59 additions & 10 deletions infra/scripts/deploy/java-performance/platform-placement.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,77 @@
# workloads have no selector, so Karpenter places them wherever there is room, usually on
# the app's 4-vCPU node. There the app shares physical cores (SMT) with Prometheus,
# Pyroscope and Kyverno, and the session's measurements move with that load (startup and
# steady CPU 10–60 % higher in a test run). This script pins every platform Deployment and
# StatefulSet to the Auto Mode built-in `general-purpose` NodePool, so the `workshop` node
# carries only the app and the DaemonSets. The app manifest is unchanged.
# steady CPU 10–60 % higher in a test run). This script creates a `platform` NodePool and
# pins every platform Deployment and StatefulSet to it, so the `workshop` node carries only
# the app and the DaemonSets. The app manifest is unchanged.
#
# The pool admits only instances with at least 4 vCPU and 8 GiB (c6a.xlarge is the cheapest
# match): the platform requests about 1.5 vCPU and 4.4 GiB, so one node holds all of it. On
# the built-in general-purpose pool Karpenter started a c6a.large per batch of pending pods
# and kept two (do-not-disrupt blocks the merge), at more cost than one c6a.xlarge.
#
# Namespaces: monitoring (Prometheus, Grafana, Pyroscope, Alloy, sensor), kyverno,
# kube-startup-cpu-boost-system, and metrics-server in kube-system. Pods move once, at
# bootstrap; Prometheus, Grafana and Pyroscope keep their data on their PVCs. The pods are
# marked do-not-disrupt, so consolidation does not move them later.
# Idempotent. Run after the platform installs (template stage E). A later `helm upgrade`
# marked do-not-disrupt and the pool consolidates only when empty, so nothing moves them later.
# Idempotent. `platform-placement.sh pool` creates only the NodePool (template stage B, so
# monitoring.sh installs onto it via MONITORING_NODEPOOL); without an argument it also pins
# the workloads (after stage E). A later `helm upgrade`
# of one of these releases drops the selector: run this script again afterwards.
# =============================================================================
set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../../lib/common.sh"

POOL="${PLATFORM_NODEPOOL:-general-purpose}"
kubectl get nodepool "${POOL}" >/dev/null 2>&1 || { log_error "NodePool ${POOL} not found (EKS Auto Mode built-in pools disabled?)"; exit 1; }
POOL="${PLATFORM_NODEPOOL:-platform}"

kubectl apply -f - <<EOF >/dev/null || { log_error "NodePool ${POOL} could not be created"; exit 1; }
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: ${POOL}
spec:
template:
spec:
nodeClassRef:
group: eks.amazonaws.com
kind: NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand"]
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: kubernetes.io/os
operator: In
values: ["linux"]
- key: eks.amazonaws.com/instance-category
operator: In
values: ["c", "m"]
- key: eks.amazonaws.com/instance-generation
operator: Gt
values: ["5"]
- key: eks.amazonaws.com/instance-cpu
operator: Gt
values: ["3"]
- key: eks.amazonaws.com/instance-memory
operator: Gt
values: ["8000"]
limits:
cpu: "16"
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 5m
EOF
log_info "NodePool ${POOL}: at least 4 vCPU and 8 GiB, consolidation WhenEmpty"
# `pool`: only the NodePool (template stage B, before monitoring.sh installs onto it).
[ "${1:-}" = pool ] && exit 0

# do-not-disrupt: the general-purpose pool consolidates underutilized nodes after 30 s. A
# consolidation during the session would move the sensor or Kyverno in the middle of a
# checklist or an admission; the annotation keeps their nodes until the pods go.
# do-not-disrupt: a consolidation during the session would move the sensor or Kyverno in
# the middle of a checklist or an admission; the annotation keeps their node until the pods go.
PATCH="{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"karpenter.sh/do-not-disrupt\":\"true\"}},\"spec\":{\"nodeSelector\":{\"karpenter.sh/nodepool\":\"${POOL}\"}}}}}"
RC=0
pin() { # pin NAMESPACE KIND/NAME...
Expand Down
17 changes: 14 additions & 3 deletions infra/scripts/setup/monitoring.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ DATASOURCE_FILE="grafana-datasource.yaml"
GRAFANA_VALUES_FILE="grafana-values.yaml"

WORK=""

# Optional NodePool for the stack: MONITORING_NODEPOOL, set by a workshop template that keeps
# the platform off its app's node (java-performance). Applied at install, so the PVCs of
# Prometheus, Pyroscope and Grafana bind in that pool's zone from the start. Unset: no
# selector, the charts install as before.
PROM_POOL=(); PYRO_POOL=(); GRAFANA_POOL=()
if [ -n "${MONITORING_NODEPOOL:-}" ]; then
PROM_POOL=(--set-string "server.nodeSelector.karpenter\\.sh/nodepool=${MONITORING_NODEPOOL}")
PYRO_POOL=(--set-string "pyroscope.nodeSelector.karpenter\\.sh/nodepool=${MONITORING_NODEPOOL}")
GRAFANA_POOL=(--set-string "nodeSelector.karpenter\\.sh/nodepool=${MONITORING_NODEPOOL}")
fi
cleanup() {
rm -f "$VALUES_FILE" "$DATASOURCE_FILE" "$GRAFANA_VALUES_FILE"
[[ -n "$WORK" ]] && rm -rf "$WORK"
Expand Down Expand Up @@ -79,7 +90,7 @@ EOF

log_info "Deploying Prometheus..."
helm upgrade --install prometheus prometheus-community/prometheus \
--namespace "$NAMESPACE" \
--namespace "$NAMESPACE" ${PROM_POOL[@]+"${PROM_POOL[@]}"} \
--values "$VALUES_FILE" >>"$LOG" 2>&1 \
|| { log_error "Prometheus helm install failed — last 40 lines of $LOG:"; tail -n 40 "$LOG"; exit 1; }

Expand Down Expand Up @@ -203,7 +214,7 @@ pyroscope:
EOF

helm upgrade --install pyroscope grafana/pyroscope \
--namespace "${NAMESPACE}" \
--namespace "${NAMESPACE}" ${PYRO_POOL[@]+"${PYRO_POOL[@]}"} \
--values "${WORK}/pyroscope-values.yaml" >>"$LOG" 2>&1 \
|| { log_error "Pyroscope helm install failed — last 40 lines of $LOG:"; tail -n 40 "$LOG"; exit 1; }
log_info "Pyroscope install submitted (readiness checked after Grafana)"
Expand Down Expand Up @@ -291,7 +302,7 @@ EOF

log_info "Deploying Grafana..."
helm upgrade --install grafana grafana-community/grafana \
--namespace "$NAMESPACE" \
--namespace "$NAMESPACE" ${GRAFANA_POOL[@]+"${GRAFANA_POOL[@]}"} \
--values "$GRAFANA_VALUES_FILE" >>"$LOG" 2>&1 \
|| { log_error "Grafana helm install failed — last 40 lines of $LOG:"; tail -n 40 "$LOG"; exit 1; }

Expand Down
6 changes: 4 additions & 2 deletions infra/scripts/templates/java-performance.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# --- wait for A ---
# D app app-deploy (namespace, Pod Identity, manifests) } in
# E platform perf-profiler install, startup-cpu-boost, perf-sensor } parallel
# placement platform Deployments/StatefulSets → general-purpose NodePool
# placement platform Deployments/StatefulSets → own platform NodePool
# F verify ALB answers, sensor measures, Claude wiring present
#
# Each stage script is idempotent and runnable on its own from the IDE.
Expand Down Expand Up @@ -65,10 +65,12 @@ A_PID=$!
stage "B: EKS cluster"
run "EKS cluster configured" "$SETUP/eks.sh"
try "NodePool pinned to m6a" "$DEPLOY/nodepool-pin.sh"
run "Platform NodePool created" "$DEPLOY/platform-placement.sh" pool
try "metrics-server installed" "$DEPLOY/metrics-server.sh"

# --- C: monitoring ---------------------------------------------------------------------
stage "C: monitoring (Prometheus, Pyroscope, Grafana)"
export MONITORING_NODEPOOL=platform # monitoring.sh installs the stack onto the platform pool
run "Monitoring stack deployed" "$SETUP/monitoring.sh"

# --- wait for A -------------------------------------------------------------------------
Expand Down Expand Up @@ -101,7 +103,7 @@ cat "$D_LOG"; cat "$E_LOG"
[ "$E_RC" -eq 0 ] && log_success "$(stamp)Stage E done (profiler, boost, sensor)" || { log_error "$(stamp)Stage E FAILED"; exit 1; }

# --- platform placement: platform pods off the app's node ------------------------------
run "Platform on the general-purpose NodePool" "$DEPLOY/platform-placement.sh"
run "Platform on its own NodePool" "$DEPLOY/platform-placement.sh"

# --- F: verify --------------------------------------------------------------------------
stage "F: verify"
Expand Down
Loading
Loading