diff --git a/docs/migrate-from-sidecar-to-ambient/migration.adoc b/docs/migrate-from-sidecar-to-ambient/migration.adoc index 12e635f62..50238c994 100644 --- a/docs/migrate-from-sidecar-to-ambient/migration.adoc +++ b/docs/migrate-from-sidecar-to-ambient/migration.adoc @@ -114,6 +114,15 @@ This migration guide uses example commands that can be adapted to any applicatio You can use any application that is currently running with sidecar injection enabled. +ifdef::istio-migrate-from-sidecar-to-ambient[] +create_default_istio +install_bookinfo "{istio_release_name}" +create_bookinfo_gateway_api "{istio_release_name}" +with_retries wait_pods_ready_by_ns "bookinfo" +echo "Checking if pods have their application container and the Istio sidecar container (READY 2/2):" +kubectl get pods -n "bookinfo" -l app +endif::[] + [[technical-requirements]] === 2.1 Technical Requirements @@ -202,20 +211,31 @@ For additional compatibility considerations refer to: link:../common/coexistence === 2.3 Pre-Migration Checklist **Environment Validation:** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Verify Sail Operator is deployed kubectl get pods -n sail-operator ---- -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check Istio control plane version kubectl get istio -n istio-system +---- + +Output should be similar to: +[source,console] +---- NAME NAMESPACE PROFILE REVISIONS READY IN USE ACTIVE REVISION STATUS VERSION AGE default istio-system 1 1 1 default Healthy v{istio_latest_version} 20m ---- +ifdef::istio-migrate-from-sidecar-to-ambient[] +wait_istio_ready "istio-system" +with_retries istiod_pods_count "1" +print_istio_info +endif::[] + [NOTE] ==== * If you have any of the unsupported features like VirtualServices or DestinationRules, during Step 5 you will need to migrate those to be compatible with ambient mode. @@ -225,18 +245,28 @@ default istio-system 1 1 1 default **Application Namespace Validation:** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check your application namespaces for sidecar injection kubectl get namespaces -l istio.io/rev=default #or any other istio revision name. Also, check if you are using instead istio-injection=enabled label. +---- + +Output should be similar to: +[source,console] +---- NAME STATUS AGE bookinfo Active 6m56 ---- -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check current workloads with sidecar injection kubectl get pods -n bookinfo +---- + +Output should be similar to: +[source,console] +---- NAME READY STATUS RESTARTS AGE bookinfo-gateway-istio-75d96b45d9-m65mq 1/1 Running 0 4m31s details-v1-646f945867-2gg99 2/2 Running 0 6m6s @@ -247,10 +277,19 @@ reviews-v2-54ff7fcf79-22k8r 2/2 Running 0 6m5s reviews-v3-6445668877-gdr22 2/2 Running 0 6m5s ---- -[source,console] +ifdef::istio-migrate-from-sidecar-to-ambient[] +with_retries wait_pods_ready_by_ns "bookinfo" +endif::[] + +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check current gateway API being used kubectl get gateway -n bookinfo +---- + +Output should be similar to: +[source,console] +---- NAME CLASS ADDRESS PROGRAMMED AGE bookinfo-gateway istio 10.0.147.96 True 5m41s ---- @@ -261,7 +300,7 @@ image:./images/kiali-bookinfo-traffic.png[Kiali Bookinfo Traffic] For testing purposes during migration, you can generate traffic to your application's main service using commands similar to: -[source,console] +[source,bash] ---- # Generate traffic to productpage service export INGRESS_HOST=$(kubectl get gtw bookinfo-gateway -n bookinfo -o jsonpath='{.status.addresses[0].value}') @@ -283,7 +322,7 @@ done === 2.4 Backup Existing Configuration Before starting migration, back up all existing Istio resources and namespace labels: -[source,console] +[source,bash] ---- # Backup all Istio resources kubectl get istio,istiocni,virtualservice,destinationrule,authorizationpolicy,requestauthentication,httproute,gateway,peerauthentication -A -o yaml > istio-backup.yaml @@ -311,30 +350,30 @@ This migration follows a structured step-by-step approach, with each step includ Before starting migration, validate your cluster meets all requirements and check the current configuration for compatibility. **Enhanced Policy Compatibility Check:** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check for Layer 7-only authorization policies that will require waypoints -kubectl get authorizationpolicy -A -o yaml | grep -E "(methods|paths|headers)" | grep -v "name:" +kubectl get authorizationpolicy -A -o yaml | grep -E "(methods|paths|headers)" | grep -v "name:" || echo "No authorization policies found" # Identify VirtualServices with subset-based routing requiring service migration -kubectl get virtualservice -A -o yaml | grep -B5 -A10 "subset:" | grep -E "(name:|subset:)" +kubectl get virtualservice -A -o yaml | grep -B5 -A10 "subset:" | grep -E "(name:|subset:)" || echo "No virtualservices with subset-based routing found" # Check for unsupported features that need manual conversion -kubectl get virtualservice -A -o yaml | grep -E "(fault|delay|mirror)" | grep -v "name:" +kubectl get virtualservice -A -o yaml | grep -E "(fault|delay|mirror)" | grep -v "name:" || echo "No unsupported features found" ---- **Migration Readiness Assessment:** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # List all resources that need conversion echo "=== VirtualServices requiring HTTPRoute conversion ===" kubectl get virtualservice -A --no-headers | wc -l echo "=== DestinationRules with subsets requiring service creation ===" -kubectl get destinationrule -A -o yaml | grep -c "subset:" +kubectl get destinationrule -A -o yaml | grep -c "subset:" || true echo "=== Authorization policies requiring waypoint deployment ===" -kubectl get authorizationpolicy -A -o yaml | grep -c -E "(methods|paths|headers)" +kubectl get authorizationpolicy -A -o yaml | grep -c -E "(methods|paths|headers)" || true ---- Note: In the step 5 of this guide you will need to migrate unsupported features. This includes: @@ -358,8 +397,9 @@ Note: In the step 5 of this guide you will need to migrate unsupported features. Update your existing Istio resource: -[source,yaml] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- +cat </dev/null 2>&1 || kubectl create namespace istio-cni + +# Apply Istio CNI configuration +cat </dev/null 2>&1 || kubectl create namespace ztunnel + # If you are using discoverySelectors, label the namespace accordingly -kubectl label namespace ztunnel istio-discovery=enabled ----- +kubectl label namespace ztunnel istio-discovery=enabled --overwrite -[source,yaml] ----- +# Wait for istiod to propagate the CA certificate ConfigMap to the ztunnel namespace +kubectl wait --for=condition=Complete --timeout=120s job/wait-for-configmap -n ztunnel 2>/dev/null || \ + for i in {1..30}; do \ + kubectl get configmap istio-ca-root-cert -n ztunnel >/dev/null 2>&1 && break || sleep 2; \ + done + +# Apply ZTunnel configuration +cat <> for Step 2 cluster setup rollback instructions (Low Risk). [[step-3-update-sidecars-for-hbone-support]] @@ -466,7 +514,7 @@ default ztunnel True Healthy v{istio_latest_version} 12m Existing sidecars need to support the HBONE protocol. Restart deployments in all sidecar-injected namespaces: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Restart workloads in each application namespace kubectl rollout restart deployment -n bookinfo @@ -476,15 +524,25 @@ kubectl get pods -n bookinfo ---- Note: during the restart, sidecars will be updated to support HBONE while still functioning as traditional sidecars. Having HBONE support enabled is a prerequisite for ambient mode. +ifdef::istio-migrate-from-sidecar-to-ambient[] +with_retries wait_pods_ready_by_ns "bookinfo" +kubectl get pods -n bookinfo +endif::[] + [[step-32-validate-hbone-capability]] ==== Step 3.2 Validate HBONE Capability Check that sidecars now support HBONE protocol: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check for HBONE is enabled in sidecar -$ kubectl get pod $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -n bookinfo -o yaml | yq '.spec.containers[] | select(.name=="istio-proxy") | .env[] | select(.name=="PROXY_CONFIG")' +kubectl get pod $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -n bookinfo -o yaml | grep -A 2 'name: PROXY_CONFIG' +---- + +The output should be similar to: +[source,yaml] +---- name: PROXY_CONFIG value: | {"proxyMetadata":{"ISTIO_META_ENABLE_HBONE":"true"},"image":{"imageType":"distroless"}} @@ -495,10 +553,15 @@ As shown above, the `ISTIO_META_ENABLE_HBONE` environment variable is set to `tr [[step-33-connectivity-validation]] ==== Step 3.3 Connectivity Validation Send requests to ensure connectivity remains intact: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Test service connectivity through sidecars -$ kubectl exec $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -n bookinfo -- curl http://reviews.bookinfo:9080/reviews/1 +kubectl exec $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -n bookinfo -- curl http://reviews.bookinfo:9080/reviews/1 +---- + +The output result should be similar to: +[source,json] +---- { "id": "1", "podname": "reviews-v1-75797bd984-7b5g6", @@ -521,10 +584,15 @@ Note: At this point, sidecars are fully functional with HBONE support, but traff **Critical**: Do NOT remove sidecars yet. They must remain until waypoints are fully deployed and active in Step 7. Test connectivity from outside the mesh: -[source,console] +[source,bash] ---- # Test ingress connectivity -$ curl -s http://$GATEWAY_URL/productpage | grep title +curl -s http://$GATEWAY_URL/productpage | grep title +---- + +The output should be similar to: +[source,html] +---- Simple Bookstore App ---- @@ -540,11 +608,11 @@ Traffic should continue flowing as before. This confirms that sidecars are still Analyze your current configuration to identify services that need waypoint proxies: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check for existing L7 policies that will need waypoints kubectl get virtualservice,httproute -A -kubectl get authorizationpolicy -A -o yaml | grep -A 10 -B 5 "rules.*methods\|operation" +kubectl get authorizationpolicy -A -o yaml | grep -A 10 -B 5 "rules.*methods\|operation" || true ---- [[step-42-create-waypoint-configurations]] @@ -552,9 +620,10 @@ kubectl get authorizationpolicy -A -o yaml | grep -A 10 -B 5 "rules.*methods\|op Create waypoints for namespaces requiring L7 processing: -**Example Waypoint for bookinfo namespace:** -[source,yaml] +Apply the Waypoint for bookinfo namespace configurations: +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- +cat < NAME ACTION AGE productpage-waypoint ALLOW 18s productpage-ztunnel-protection DENY 7s @@ -913,7 +995,7 @@ reviews-ztunnel-protection DENY 6s **Critical**: Keep existing sidecar policies active until Policy Simplification step. Test that services are still accessible (policies not yet enforced): -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- NAMESPACE="bookinfo" # Replace with your namespace TEST_POD=$(kubectl get pods -n $NAMESPACE -l app=reviews -o jsonpath='{.items[0].metadata.name}') @@ -922,7 +1004,7 @@ if [[ "$HTTP_STATUS" == "200" ]]; then echo "PASS: Service connectivity still working" else echo "FAIL: Service connectivity failed: HTTP $HTTP_STATUS" - exit 1 + sleep 1 fi ---- @@ -936,15 +1018,21 @@ fi We recommend enabling ambient mode for one namespace at a time, starting with the least critical. Replace `bookinfo` with your actual namespace name: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- kubectl label namespace bookinfo istio.io/dataplane-mode=ambient ---- -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Verify ztunnel configuration for each namespace -$ istioctl ztunnel-config workloads --namespace ztunnel | grep bookinfo +istioctl ztunnel-config workloads --namespace ztunnel | grep bookinfo +---- + +The output should be similar to: + +[source,console] +---- bookinfo bookinfo-gateway-istio-6b9cf4b8c8-xxsq2 10.128.2.58 user-rhos-d-4-9b684-worker-0-4fhm6 None TCP bookinfo details-v1-bb955f94b-4sppn 10.128.2.59 user-rhos-d-4-9b684-worker-0-4fhm6 None HBONE bookinfo productpage-v1-c4cb9cb4b-ghzwc 10.128.2.60 user-rhos-d-4-9b684-worker-0-4fhm6 None HBONE @@ -956,7 +1044,7 @@ bookinfo waypoint-58cdc7f494-98h79 ---- **Validation after each namespace:** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Test connectivity after enabling each namespace, e.g., bookinfo kubectl exec -n bookinfo $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -- curl http://reviews.bookinfo:9080/ @@ -979,7 +1067,7 @@ kubectl exec -n bookinfo $(kubectl get pods -n bookinfo -l app=ratings -o jsonpa Up to this point, waypoint proxies have been deployed but are not processing any traffic. They remain dormant until you explicitly configure workloads to use them. This activation happens through labeling: **Namespace-level Activation (recommended):** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Enable waypoint for all services in the namespace kubectl label namespace bookinfo istio.io/use-waypoint=waypoint @@ -1003,6 +1091,10 @@ kubectl get namespace --show-labels kubectl get service -n --show-labels ---- +ifdef::istio-migrate-from-sidecar-to-ambient[] +with_retries wait_pods_by_label "bookinfo" "gateway.networking.k8s.io/gateway-name=waypoint" +endif::[] + **Critical Identity Security Consideration**: Waypoints do not spoof client identity. When ztunnel processes traffic from waypoints, it sees the waypoint's identity, not the original client's identity. This has important implications: @@ -1025,7 +1117,7 @@ Ensure your authorization policies account for this identity behavior when valid Once traffic flows through waypoints, remove duplicate sidecar-specific policies: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # List all authorization policies to identify duplicates kubectl get authorizationpolicy -A @@ -1053,7 +1145,7 @@ kubectl delete virtualservice -n **Final step**: Remove sidecar injection now that ambient mode is fully operational: -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Remove sidecar injection while preserving ambient mode labels kubectl label namespace bookinfo istio.io/rev- istio.io/dataplane-mode=ambient @@ -1067,7 +1159,11 @@ kubectl rollout restart deployment -n bookinfo Verify sidecars are removed and ambient mode is working: -[source,console] +ifdef::istio-migrate-from-sidecar-to-ambient[] +with_retries wait_pods_ready_by_ns "bookinfo" +endif::[] + +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Verify pods no longer have sidecars containers in the application pods kubectl get pods -n bookinfo @@ -1080,17 +1176,29 @@ Checking on Kiali should show traffic flowing through ambient mode. You should s Test that L7 policies are now enforced through waypoints (L7 policies should work as before after waypoint activation): -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Test authorization policies work through waypoint -kubectl exec -n bookinfo $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -- curl -v http://reviews.bookinfo:9080/reviews/1 +kubectl exec -n bookinfo $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -- curl -s http://reviews.bookinfo:9080/reviews/1 + +---- + +Output should be similar to: +[source,json] +---- {"id": "1","podname": "reviews-v3-dd9d6fc89-6glvk","clustername": "null","reviews": [{ "reviewer": "Reviewer1", "text": "An extremely entertaining play by Shakespeare. The slapstick humor is refreshing!", "rating": {"stars": 5, "color": "red"}},{ "reviewer": "Reviewer2", "text": "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.", "rating": {"stars": 4, "color": "red"}}]} ---- -[source,console] +Test the traffic routing through waypoint with header (if HTTPRoute configured): + +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] +---- +kubectl exec -n bookinfo $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -- curl -s -H "end-user: jason" http://reviews.bookinfo:9080/reviews/1 +---- + +Output should be similar to: +[source,json] ---- -# Test traffic routing through waypoint with header (if HTTPRoute configured) -$ kubectl exec -n bookinfo $(kubectl get pods -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -- curl -H "end-user: jason" http://reviews.bookinfo:9080/reviews/1 {"id": "1","podname": "reviews-v2-67ff7bcdc5-kklgl","clustername":"null","reviews": [{ "reviewer": "Reviewer1", "text": "An extremely entertaining play by Shakespeare. The slapstick humor is refreshing!","rating": {"stars": 5, "color": "black"}},{ "reviewer": "Reviewer2", "text": "Absolutely fun and entertaining. The play lacks thematic depthwhen compared to other plays by Shakespeare.","rating": {"stars": 4, "color": "black"}}]} ---- @@ -1098,7 +1206,7 @@ Note: L7 policies should function as before, now enforced through waypoints inst Test external connectivity (if gateway configured): -[source,console] +[source,bash] ---- # Test external connectivity through gateway export INGRESS_HOST=$(kubectl get gtw bookinfo-gateway -n bookinfo -o jsonpath='{.status.addresses[0].value}') @@ -1135,10 +1243,15 @@ fi **mTLS Verification:** -[source,console] +[source,bash,subs="attributes+",name="istio-migrate-from-sidecar-to-ambient"] ---- # Check ztunnel protocols for the bookinfo namespace istioctl ztunnel-config workloads -n ztunnel |grep bookinfo +---- + +Output should be similar to: +[source,console] +---- bookinfo bookinfo-gateway-istio-86496d9445-fgczp 10.128.2.66 user-rhos-d-4-9b684-worker-0-4fhm6 None TCP bookinfo details-v1-584b5c5f6c-dhkjx 10.128.2.67 user-rhos-d-4-9b684-worker-0-4fhm6 None HBONE bookinfo productpage-v1-7b5749b8bf-96mmg 10.128.2.68 user-rhos-d-4-9b684-worker-0-4fhm6 None HBONE @@ -1283,7 +1396,7 @@ kubectl exec $TEST_POD -n -- curl -v -H "authorization: invalid" htt [source,console] ---- # Check waypoint proxy performance -$ istioctl proxy-config listeners $(kubectl get pod -n -l gateway.networking.k8s.io/gateway-name= -o jsonpath='{.items[0].metadata.name}') -n +istioctl proxy-config listeners $(kubectl get pod -n -l gateway.networking.k8s.io/gateway-name= -o jsonpath='{.items[0].metadata.name}') -n ADDRESSES PORT MATCH DESTINATION 0 ALL Cluster: inbound-vip|9080|http|..svc.cluster.local 0 ALL Cluster: inbound-vip|9080|http|-v3..svc.cluster.local @@ -1608,4 +1721,4 @@ spec: These resources provide further information on ambient mode and related configurations: -- https://istio.io/latest/docs/ambient/[Upstream Istio Ambient Documentation] - Official Istio ambient mode docs +- https://istio.io/latest/docs/ambient/[Upstream Istio Ambient Documentation] - Official Istio ambient mode docs \ No newline at end of file diff --git a/tests/documentation_tests/scripts/prebuilt-func.sh b/tests/documentation_tests/scripts/prebuilt-func.sh index 14bd7cb3c..88d42a92b 100644 --- a/tests/documentation_tests/scripts/prebuilt-func.sh +++ b/tests/documentation_tests/scripts/prebuilt-func.sh @@ -124,6 +124,7 @@ wait_pods_ready_by_ns() { for pod_name in $pod_names; do wait_for_pod_ready "$namespace" "$pod_name" done + sleep 5 } # Wait for all pods that match labels in a namespace to be ready @@ -204,7 +205,6 @@ wait_istio_ready() { print_istio_info() { kubectl get istio kubectl get pods -n istio-system - kubectl get istio kubectl get istiorevision kubectl get istiorevisiontag } @@ -323,4 +323,40 @@ wait_for_rollout_success() { for deploy in $deploy_names; do kubectl rollout status "$deploy" -n "$namespace" --timeout=60s done +} + +# Create default Istio resource +create_default_istio() { + namespace="${1:-istio-system}" + + kubectl get namespace "$namespace" >/dev/null 2>&1 || kubectl create namespace "$namespace" + cat </dev/null 2>&1 || kubectl create namespace "$namespace" + kubectl label namespace "$namespace" istio.io/rev=default + kubectl apply -n "$namespace" -f https://raw.githubusercontent.com/istio/istio/"${istio_release_name}"/samples/bookinfo/platform/kube/bookinfo.yaml +} + +# Create Bookinfo gateway API +create_bookinfo_gateway_api() { + istio_release_name="$1" + namespace="${2:-bookinfo}" + + kubectl get crd gateways.gateway.networking.k8s.io >/dev/null 2>&1 || \ + kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml + kubectl apply -f https://raw.githubusercontent.com/istio/istio/"${istio_release_name}"/samples/bookinfo/gateway-api/bookinfo-gateway.yaml -n "$namespace" } \ No newline at end of file