Skip to content
Open
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
45 changes: 28 additions & 17 deletions Labs/10-Istio/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
---

# Istio Service Mesh & Kiali

- `Istio` is an open-source service mesh that provides a uniform way to manage microservices communication.
Expand All @@ -11,7 +9,7 @@
## What will we learn?

- Install and configure Istio service mesh using Helm
- Deploy Kiali, Prometheus, Grafana, and Jaeger as observability addons
- Deploy Kiali, Prometheus, Grafana, Jaeger, and Loki as observability addons
- Deploy a microservices demo application with sidecar injection
- Generate live traffic and observe it in Kiali's topology graph
- Configure traffic management: routing, canary deployments, fault injection
Expand Down Expand Up @@ -39,17 +37,18 @@
| **Prometheus** | Metrics collection and storage for Istio telemetry | `9090` |
| **Grafana** | Dashboards for mesh, service, and workload metrics | `3000` |
| **Jaeger** | Distributed tracing backend and UI | `16686` |
| **Loki** | Log aggregation (used with Grafana for logs) | `3100` |

### Istio Key CRDs

| CRD | Purpose |
| --------------------- | --------------------------------------------------------------------------------- |
| `VirtualService` | Define routing rules: traffic shifting, fault injection, timeouts |
| `DestinationRule` | Define policies after routing: load balancing, circuit breaker, mTLS |
| `DestinationRule` | Define policies after routing: load balancing, circuit breaker, mTLS |
| `Gateway` | Configure load balancer at mesh edge for HTTP/TCP traffic |
| `PeerAuthentication` | Configure mTLS mode: `STRICT`, `PERMISSIVE`, `DISABLE` |
| `PeerAuthentication` | Configure mTLS mode: `STRICT`, `PERMISSIVE`, `DISABLE` |
| `AuthorizationPolicy` | Access control policies for workloads |
| `ServiceEntry` | Add external services (outside the mesh) to Istio's service registry |
| `ServiceEntry` | Add external services (outside the mesh) to Istio's service registry |

---

Expand All @@ -67,6 +66,7 @@ graph TB
grafana["Grafana"]
jaeger["Jaeger"]
kiali["Kiali"]
loki["Loki"]
end

subgraph bookinfo["bookinfo namespace (istio-injection=enabled)"]
Expand Down Expand Up @@ -104,14 +104,15 @@ graph TB
jaeger --> kiali
istiod --> kiali
prometheus --> grafana
loki -. logs .-> grafana
end
```

---

## Directory Structure

```
```bash
10-Istio/
├── README.md # This file
├── demo.sh # Main deployment script (deploy/cleanup)
Expand All @@ -120,7 +121,7 @@ graph TB
├── scripts/
│ ├── common.sh # Shared functions & colors
│ ├── 01-install-istio.sh # Install Istio via Helm
│ ├── 02-install-addons.sh # Install Kiali, Prometheus, Grafana, Jaeger
│ ├── 02-install-addons.sh # Install observability addons + gateway routes
│ ├── 03-deploy-bookinfo.sh # Deploy Bookinfo sample application
│ ├── 04-traffic-generator.sh # Deploy live traffic generator
│ └── 05-verify.sh # Verify all components
Expand All @@ -130,12 +131,14 @@ graph TB
│ ├── bookinfo.yaml # Bookinfo application manifests
│ ├── bookinfo-gateway.yaml # Istio Gateway + VirtualService for ingress
│ ├── destination-rules.yaml # DestinationRules for all service versions
│ ├── observability-routes.yaml # VirtualServices (addons + Bookinfo via gateway)
│ ├── traffic-generator.yaml # CronJob for continuous traffic generation
│ └── addons/ # Observability addon manifests
│ ├── prometheus.yaml
│ ├── grafana.yaml
│ ├── jaeger.yaml
│ └── kiali.yaml
│ ├── kiali.yaml
│ └── loki.yaml
└── istio-features/
├── 01-traffic-shifting.yaml # Canary: route % of traffic to v2/v3
Expand All @@ -155,9 +158,11 @@ graph TB
- Kubernetes cluster (v1.24+) with at least 8 GB RAM available
- `kubectl` configured to access your cluster
- `Helm 3.x` installed
- Nginx Ingress Controller (required for Ingress-based access to dashboards and Bookinfo)
- (Optional) `istioctl` for debugging

Access to dashboards and Bookinfo is via the Istio Ingress Gateway
(port-forward or hosts file); no Nginx Ingress Controller is required.

```bash
# Install kubectl (macOS)
brew install kubectl
Expand All @@ -175,7 +180,7 @@ helm version

---

# Lab
## Lab

## Part 01 - Deploy Istio Service Mesh

Expand All @@ -193,7 +198,8 @@ The script will:

- Check prerequisites: `kubectl`, `helm`, cluster connectivity
- Install Istio CRDs and control plane via Helm
- Install Kiali, Prometheus, Grafana, and Jaeger
- Install observability addons (Kiali, Prometheus, Grafana, Jaeger, Loki) and
Istio Gateway routes for them
- Create the `bookinfo` namespace with sidecar injection enabled
- Deploy the Bookinfo sample application (4 microservices, multiple versions)
- Configure the Istio Ingress Gateway and DestinationRules
Expand Down Expand Up @@ -543,11 +549,14 @@ kubectl logs -n istio-system -l app=kiali --tail=50
This will remove:

- `traffic-gen` namespace and all traffic generator resources
- `bookinfo` namespace and all application resources
- Kiali, Prometheus, Grafana, and Jaeger Helm releases
- Istio control plane Helm release
- All Istio CRDs
- All remaining namespaces created by this lab
- `bookinfo` namespace and all application resources (including Istio gateway
routes)
- Observability addons (Kiali, Prometheus, Grafana, Jaeger, Loki) and their
Istio VirtualService routes; Loki PVCs (e.g. `storage-loki-0`) are deleted
so persistent volumes are not left behind
- Istio Ingress Gateway, Istiod, and base Helm releases
- `istio-system` namespace
- All Istio CRDs and cluster-wide addon RBAC (e.g. Prometheus, Kiali, Loki)

### Partial Cleanup

Expand All @@ -561,6 +570,8 @@ kubectl delete namespace traffic-gen

# Remove only observability addons (keep Istio + app running)
kubectl delete -f manifests/addons/ -n istio-system
# If you removed addons manually, delete Loki PVCs to free storage (e.g. storage-loki-0):
kubectl delete pvc -n istio-system storage-loki-0 --ignore-not-found
```

---
Expand Down
93 changes: 56 additions & 37 deletions Labs/10-Istio/demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,75 +8,86 @@ set -euo pipefail
# =============================================================================

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

# Deploy all components
# Run full lab deployment: Istio, addons, Bookinfo, traffic generator, and verify.
# Prints access info at the end.
deploy() {
print_header "Istio + Kiali Lab Deployment"

check_prerequisites
echo ""

# Step 1: Install Istio
source "${SCRIPT_DIR}/scripts/01-install-istio.sh"
# Step 1: Install Istio (sourced script may overwrite SCRIPT_DIR, so use LAB_DIR)
source "${LAB_DIR}/scripts/01-install-istio.sh"
install_istio
echo ""

# Step 2: Install observability addons
source "${SCRIPT_DIR}/scripts/02-install-addons.sh"
source "${LAB_DIR}/scripts/02-install-addons.sh"
install_addons
echo ""

# Step 3: Deploy Bookinfo application
source "${SCRIPT_DIR}/scripts/03-deploy-bookinfo.sh"
source "${LAB_DIR}/scripts/03-deploy-bookinfo.sh"
deploy_bookinfo
echo ""

# Step 4: Deploy traffic generator
source "${SCRIPT_DIR}/scripts/04-traffic-generator.sh"
source "${LAB_DIR}/scripts/04-traffic-generator.sh"
deploy_traffic_generator
echo ""

# Step 5: Verify
source "${SCRIPT_DIR}/scripts/05-verify.sh"
source "${LAB_DIR}/scripts/05-verify.sh"
verify_deployment
echo ""

# Display access information
display_access_info
}

# Display access information
# Print gateway URLs, /etc/hosts hints, port-forward commands, and demo usage.
display_access_info() {
echo ""
echo "=========================================="
print_success "Istio + Kiali Lab Deployment Complete!"
echo "=========================================="
echo ""

# Get ingress IP
INGRESS_IP=$(kubectl get ingress -n istio-system kiali -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null)
# Get Istio Ingress Gateway external IP (or hostname for LoadBalancer)
GATEWAY_IP=$(kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null) || true
if [ -z "$GATEWAY_IP" ]; then
GATEWAY_IP=$(kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null) || true
fi

print_info "Access via Ingress (recommended):"
print_info "Access via Istio Ingress Gateway:"
echo ""
echo -e " Kiali: ${GREEN}http://kiali.local${NC}"
echo -e " Grafana: ${GREEN}http://grafana.local${NC}"
echo -e " Jaeger: ${GREEN}http://jaeger.local${NC}"
echo -e " Prometheus: ${GREEN}http://prometheus.local${NC}"
echo -e " Loki: ${GREEN}http://loki.local${NC}"
echo -e " Bookinfo: ${GREEN}http://bookinfo.local/productpage${NC}"
echo ""

# Check /etc/hosts
HOSTS_NEEDED=""
for host in kiali.local grafana.local jaeger.local prometheus.local bookinfo.local; do
for host in kiali.local grafana.local jaeger.local prometheus.local loki.local bookinfo.local; do
if ! grep -q "$host" /etc/hosts 2>/dev/null; then
HOSTS_NEEDED="$HOSTS_NEEDED $host"
fi
Comment on lines +77 to 80

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n Labs/10-Istio/demo.sh | sed -n '75,85p'

Repository: nirgeier/KubernetesLabs

Length of output: 511


Use fixed-string matching for /etc/hosts host checks to avoid regex interpretation and commented entries.

The current grep -q "$host" has two issues:

  1. The . in .local is treated as a regex wildcard matching any character, potentially causing false positives
  2. More importantly, commented entries like # 127.0.0.1 kiali.local would incorrectly match, causing the script to skip adding the host even though it's not actually configured
🔧 Proposed fix
   for host in kiali.local grafana.local jaeger.local prometheus.local loki.local bookinfo.local; do
-    if ! grep -q "$host" /etc/hosts 2>/dev/null; then
+    if ! grep -vE '^[[:space:]]*#' /etc/hosts 2>/dev/null | grep -qwF "$host"; then
       HOSTS_NEEDED="$HOSTS_NEEDED $host"
     fi
   done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for host in kiali.local grafana.local jaeger.local prometheus.local loki.local bookinfo.local; do
if ! grep -q "$host" /etc/hosts 2>/dev/null; then
HOSTS_NEEDED="$HOSTS_NEEDED $host"
fi
for host in kiali.local grafana.local jaeger.local prometheus.local loki.local bookinfo.local; do
if ! grep -vE '^[[:space:]]*#' /etc/hosts 2>/dev/null | grep -qwF "$host"; then
HOSTS_NEEDED="$HOSTS_NEEDED $host"
fi
done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Labs/10-Istio/demo.sh` around lines 77 - 80, In the for-loop that builds
HOSTS_NEEDED, replace the plain grep check that can match regexes and commented
lines with a fixed-string, non-commented-line check; for example, change the
condition that uses grep -q "$host" /etc/hosts to an awk invocation that ignores
lines starting with # and searches for the literal host (e.g., use awk -v
h="$host" '!/^[[:space:]]*#/ && index($0,h){exit 0} END{exit 1}' /etc/hosts) so
HOSTS_NEEDED is only left unchanged when an actual, non-commented hosts entry
for the literal host exists.

done

if [ -n "$HOSTS_NEEDED" ]; then
print_warning "Add these hosts to /etc/hosts:"
echo " echo \"${INGRESS_IP:-192.168.139.2}${HOSTS_NEEDED}\" | sudo tee -a /etc/hosts"
if [ -n "$GATEWAY_IP" ]; then
echo " echo \"${GATEWAY_IP}${HOSTS_NEEDED}\" | sudo tee -a /etc/hosts"
else
echo " # Get gateway IP: kubectl get svc istio-ingressgateway -n istio-system"
echo " echo \"<GATEWAY_IP>${HOSTS_NEEDED}\" | sudo tee -a /etc/hosts"
fi
echo ""
else
print_success "/etc/hosts already configured"
Expand All @@ -87,6 +98,7 @@ display_access_info() {
echo ""
echo " kubectl port-forward svc/kiali -n istio-system 20001:20001 &"
echo " kubectl port-forward svc/grafana -n istio-system 3000:3000 &"
echo " kubectl port-forward svc/loki -n istio-system 3100:3100 &"
echo " kubectl port-forward svc/tracing -n istio-system 16686:80 &"
echo " kubectl port-forward svc/prometheus -n istio-system 9090:9090 &"
echo " kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80 &"
Expand Down Expand Up @@ -116,59 +128,66 @@ display_access_info() {
echo ""
}

# Cleanup all components
# Remove all lab resources: traffic-gen, Bookinfo, addons, Istio Helm releases,
# istio-system namespace, CRDs, and related cluster roles/bindings.
cleanup() {
print_header "Cleaning Up Istio + Kiali Lab"

# Remove traffic generator
print_step "Removing traffic generator..."
kubectl delete namespace traffic-gen 2>/dev/null
kubectl delete namespace traffic-gen 2>/dev/null || true
print_success "Traffic generator removed"

# Remove Bookinfo
print_step "Removing Bookinfo application..."
kubectl delete -f "${SCRIPT_DIR}/manifests/bookinfo-gateway.yaml" -n bookinfo 2>/dev/null
kubectl delete -f "${SCRIPT_DIR}/manifests/destination-rules.yaml" -n bookinfo 2>/dev/null
kubectl delete -f "${SCRIPT_DIR}/manifests/bookinfo.yaml" -n bookinfo 2>/dev/null
kubectl delete namespace bookinfo 2>/dev/null
kubectl delete -f "${LAB_DIR}/manifests/bookinfo-gateway.yaml" -n bookinfo 2>/dev/null || true
kubectl delete -f "${LAB_DIR}/manifests/destination-rules.yaml" -n bookinfo 2>/dev/null || true
kubectl delete -f "${LAB_DIR}/manifests/bookinfo.yaml" -n bookinfo 2>/dev/null || true
kubectl delete namespace bookinfo 2>/dev/null || true
print_success "Bookinfo removed"

# Remove Istio feature demos (if any applied)
print_step "Cleaning up Istio feature demos..."
kubectl delete peerauthentication --all -n bookinfo 2>/dev/null
kubectl delete peerauthentication --all -n istio-system 2>/dev/null

# Remove addons and ingress
print_step "Removing observability addons and ingress..."
kubectl delete -f "${SCRIPT_DIR}/manifests/ingress.yaml" 2>/dev/null
kubectl delete -f "${SCRIPT_DIR}/manifests/addons/" -n istio-system 2>/dev/null
print_success "Addons and ingress removed"
kubectl delete peerauthentication --all -n bookinfo 2>/dev/null || true
kubectl delete peerauthentication --all -n istio-system 2>/dev/null || true

# Remove addons and Istio gateway routes
print_step "Removing observability addons and gateway routes..."
kubectl delete -f "${LAB_DIR}/manifests/observability-routes.yaml" 2>/dev/null || true
kubectl delete -f "${LAB_DIR}/manifests/addons/" 2>/dev/null || true
# Delete Loki PVCs from StatefulSet volumeClaimTemplates (e.g. storage-loki-0)
for pvc in $(kubectl get pvc -n istio-system -o name 2>/dev/null | sed 's|persistentvolumeclaim/||' | grep -E '^storage-loki-' || true); do
kubectl delete pvc -n istio-system "$pvc" --ignore-not-found 2>/dev/null || true
done
print_success "Addons and gateway routes removed"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Remove Istio
print_step "Removing Istio..."
helm uninstall istio-ingressgateway -n istio-system 2>/dev/null
helm uninstall istiod -n istio-system 2>/dev/null
helm uninstall istio-base -n istio-system 2>/dev/null
helm uninstall istio-ingressgateway -n istio-system 2>/dev/null || true
helm uninstall istiod -n istio-system 2>/dev/null || true
helm uninstall istio-base -n istio-system 2>/dev/null || true
print_success "Istio Helm releases removed"

# Clean up namespace
print_step "Removing istio-system namespace..."
kubectl delete namespace istio-system 2>/dev/null
kubectl delete namespace istio-system 2>/dev/null || true

# Clean up Istio CRDs
print_step "Removing Istio CRDs..."
kubectl get crd -o name | grep 'istio.io' | xargs -r kubectl delete 2>/dev/null
for crd in $(kubectl get crd -o name 2>/dev/null | grep 'istio.io' || true); do
kubectl delete "$crd" --ignore-not-found 2>/dev/null || true
done

# Clean up cluster-wide resources
kubectl delete clusterrole istio-prometheus kiali 2>/dev/null
kubectl delete clusterrolebinding istio-prometheus kiali 2>/dev/null
# Clean up cluster-wide resources (addon ClusterRoles/ClusterRoleBindings)
kubectl delete clusterrole istio-prometheus kiali loki-clusterrole 2>/dev/null || true
kubectl delete clusterrolebinding istio-prometheus kiali loki-clusterrolebinding 2>/dev/null || true

echo ""
print_success "Cleanup complete! All Istio + Kiali resources removed."
}

# Parse command line arguments
case "${1}" in
case "${1:-}" in
deploy)
deploy
;;
Expand Down
Loading