Migrating from Istio on GKE to Anthos Service Mesh

This guide shows how to upgrade a Google Kubernetes Engine (GKE) cluster with Istio on Google Kubernetes Engine (Istio on GKE) version 1.4 (Beta) to Anthos Service Mesh version 1.10 with the Anthos Service Mesh Google-managed control plane and Anthos Service Mesh certificate authority (Mesh CA).

Prerequisites

The following prerequisites are required to complete this guide:

  • A GKE cluster with Istio on GKE enabled. If you have multiple GKE clusters, follow the same steps for all clusters. If you do not have a GKE cluster, or you would like to test this guide on a new (test) cluster first, you can follow the steps in Appendix A to create a new GKE cluster with Istio on GKE enabled and deploy a test application.

  • Istio on GKE must be version 1.4.

  • Ensure that you are running GKE version 1.17.17-gke.3100+, 1.18.16-gke.1600+, 1.19.8-gke.1600+, or later.

  • The GKE cluster must be running in one of these locations.

  • The user or Service Account running this script requires the IAM permissions documented in Setting up your project.

  • This guide is tested on Cloud Shell, so we recommend that you use Cloud Shell to perform the steps in this guide.

Objectives

  • Deploy Anthos Service Mesh Google-managed control plane version 1.10.
  • Migrate Istio configurations to Anthos Service Mesh.
  • Configure Mesh CA.
  • Migrate applications to Anthos Service Mesh.
  • Upgrade istio-ingressgateway from Istio on GKE to Anthos Service Mesh.
  • Finalize Anthos Service Mesh migration or roll back to Istio on GKE.

Set up your environment

To set up your environment, follow these steps:

  1. In the Google Cloud Console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Cloud Console page, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Cloud SDK and the gcloud command-line tool already installed, and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. Create the environment variables used in this guide:

    # Enter your project ID
    export PROJECT_ID=PROJECT_ID
    
    # Copy and paste the following
    gcloud config set project ${PROJECT_ID}
    export PROJECT_NUM=$(gcloud projects describe ${PROJECT_ID} --format='value(projectNumber)')
    export CLUSTER_1=GKE_CLUSTER_NAME
    export CLUSTER_1_LOCATION=GKE_CLUSTER_REGION_OR_ZONE
    export SHELL_IP=$(curl ifconfig.me) # This is required for private clusters with `master-authorized-networks` enabled.
    
  3. Create a WORKDIR folder. All files associated with this guide end up in WORKDIR so that you can delete WORKDIR when you are finished.

    mkdir -p addon-to-asm && cd addon-to-asm && export WORKDIR=`pwd`
    
  4. Create a KUBECONFIG file for this guide. You can also use your existing KUBECONFIG file that contains the cluster context for the GKE cluster to be migrated to Anthos Service Mesh.

    touch asm-kubeconfig && export KUBECONFIG=`pwd`/asm-kubeconfig
    
  5. Get credentials for the GKE cluster and store the context in a variable:

    Zonal clusters

    gcloud container clusters get-credentials ${CLUSTER_1} \
      --zone=${CLUSTER_1_LOCATION}
    
    export CLUSTER_1_CTX=gke_${PROJECT_ID}_${CLUSTER_1_LOCATION}_${CLUSTER_1}
    

    Regional clusters

    gcloud container clusters get-credentials ${CLUSTER_1} \
      --region=${CLUSTER_1_LOCATION}
    
    export CLUSTER_1_CTX=gke_${PROJECT_ID}_${CLUSTER_1_LOCATION}_${CLUSTER_1}
    

Optional step

If the cluster is a private cluster (with master-authorized-networks enabled), add your $SHELL_IP to the master-authorized-networks allowlist. If you already have access to your cluster, this step might not be required.

Zonal clusters

export SHELL_IP=$(curl ifconfig.me)

gcloud container clusters update ${CLUSTER_1} \
    --zone=${CLUSTER_1_LOCATION} \
    --enable-master-authorized-networks \
    --master-authorized-networks ${SHELL_IP}/32

Regional clusters

export SHELL_IP=$(curl ifconfig.me)

gcloud container clusters update ${CLUSTER_1} \
    --region=${CLUSTER_1_LOCATION} \
    --enable-master-authorized-networks \
    --master-authorized-networks ${SHELL_IP}/32

Install Anthos Service Mesh

In this section, you deploy Anthos Service Mesh version 1.10 with the Google-managed control plane on the GKE cluster. This control plane is deployed alongside Istio on GKE as a second (or canary) control plane.

  1. Download the latest version of the script that installs Anthos Service Mesh v1.10 to the current working directory, and make the script executable:

    curl https://storage.googleapis.com/csm-artifacts/asm/install_asm_1.10 > install_asm_1_10
    chmod +x install_asm_1_10
    
  2. To configure the GKE cluster, run the installation script to install Anthos Service Mesh with the Google-managed control plane:

    ./install_asm_1_10 --mode install --managed \
    -p ${PROJECT_ID} \
    -l ${CLUSTER_1_LOCATION} \
    -n ${CLUSTER_1} \
    --verbose \
    --output_dir ${CLUSTER_1} \
    --enable-all \
    --enable-registration \
    --option cni-managed
    

    This step can take a few minutes to complete.

  3. Copy istioctl version 1.10 to the WORKDIR folder:

    cp ./${CLUSTER_1}/istioctl ${WORKDIR}/.
    

In the next section, you download and run the migrate_addon script to assist in migrating to Anthos Service Mesh. The istioctl command-line utility needs to be in the same folder as the migrate_addon script. You use the WORKDIR folder for both the istioctl command-line utility and the migrate_addon script.

Migrate configurations to Anthos Service Mesh

In this section, you migrate Istio on GKE configurations to Anthos Service Mesh. The guided script identifies which configurations can and cannot be migrated.

  1. Download the migration tool and make it executable:

    curl https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-packages/master/scripts/migration/migrate-addon > ${WORKDIR}/migrate_addon
    chmod +x ${WORKDIR}/migrate_addon
    
  2. Disable the Galley validation webhook. This step is required to migrate some of the 1.4 configurations to Anthos Service Mesh. Answer Y to both questions:

    ${WORKDIR}/migrate_addon -d tmpdir --command disable-galley-webhook
    

    The output is similar to the following:

    tmpdir directory not present. Create directory? Continue? [Y/n] Y
    
    Disabling the Istio validation webhook... Continue? [Y/n] Y
    Running: kubectl get clusterrole istio-galley-istio-system -n istio-system -o yaml
    Running: kubectl patch clusterrole -n istio-system istio-galley-istio-system --type=json -p=[{"op": "replace", "path": "/rules/2/verbs/0", "value": "get"}]
    clusterrole.rbac.authorization.k8s.io/istio-galley-istio-system patched
    Running: kubectl get ValidatingWebhookConfiguration istio-galley --ignore-not-found
    Running: kubectl delete ValidatingWebhookConfiguration istio-galley --ignore-not-found
    validatingwebhookconfiguration.admissionregistration.k8s.io "istio-galley" deleted
    
    
  3. Verify and manually migrate the configuration. This step helps identify some of the configurations that need to be manually migrated before migrating workloads to the Google-managed control plane.

    ${WORKDIR}/migrate_addon -d tmpdir --command config-check
    

    The output is similar to the following:

    Installing the authentication CR migration tool...
    OK
    
    Checking for configurations that will need to be explicitly migrated...
    No resources found
    

Migrate custom configurations

You might need to manually migrate custom configurations before you migrate to Anthos Service Mesh. The preceding script identifies custom configurations and prints information about what is required. These customizations are as follows:

  • Detected custom envoy filters are not supported by Anthos Service Mesh. Remove these if possible. Envoy filters are currently not supported in the Google-managed control plane.

  • Detected custom plugin certificate. The plugin certificates will not be migrated to Anthos Service Mesh. If plugin certificates are used with Istio on GKE, these certificates are not used after the workloads migrate to the Google-managed control plane. All workloads use certificates signed by Google Mesh CA. Plugin certificates are not supported by Mesh CA. This message is informational and no action is required.

  • Detected security policies that could not be migrated. <Error reason>. This usually fails because of alpha AuthZ policies that need to be manually migrated. For more context and information about how to migrate policies, see Migrate pre-Istio 1.4 Alpha security policy to the current APIs. For more information regarding the error message, see security-policy-migrate.

  • Detected possibly incompatible VirtualService config. <Specific deprecated config>. You need to update the following VirtualService configurations:

    • Use of appendHeaders is not supported. Use spec.http.headers instead.
    • Use of websocketUpgrade is not needed. It is turned on by default.
    • Replace the field abort.percent with abort.percentage.
  • Detected custom installation of mixer resources that could not be migrated. Requires manual migration to telemetryv2. If custom mixer policies are configured in addition to the default Istio on GKE installation, you need to manually migrate these policies to telemetry v2. For more information about how to do this, see Customizing Istio Metrics.

  • Deployment <deploymentName> could be a custom gateway. Migrate this manually. You need to manually migrate all gateway Deployments other than the istio-ingressgateway (which is installed by default). For information about how to upgrade gateways for the Google-managed control plane, see Configuring the Google-managed control plane.

To migrate configurations, follow these steps:

  1. Manually migrate all custom configurations (except for the last configuration listed) before proceeding to step 2.

  2. Use the migration tool to migrate the configurations that can be automatically migrated (or ignored).

    ${WORKDIR}/migrate_addon -d tmpdir --command migrate-configs
    

    The output is similar to the following:

    Converting authentication CRs...
    2021/06/25 20:44:58 found root namespace: istio-system
    2021/06/25 20:44:59 SUCCESS converting policy /default
    Running: kubectl apply --dry-run=client -f beta-policy.yaml
    peerauthentication.security.istio.io/default created (dry run)
    
    Applying converted security policies in tmpdir/beta-policy.yaml... Continue? [Y/n] Y
    Running: kubectl apply -f beta-policy.yaml
    peerauthentication.security.istio.io/default created
    OK
    
    
  3. Apply the Mesh CA root trust. This lets you migrate from the current Citadel CA to Mesh CA without incurring any downtime to your applications.

    ${WORKDIR}/migrate_addon -d tmpdir --command configure-mesh-ca
    

    The output is similar to the following:

    Configuring Istio on GKE to trust Anthos Service Mesh... Continue? [Y/n] Y
    Running: kubectl get cm -n istio-system istio-asm-managed -oyaml
    Running: kubectl -n istio-system apply -f -
    secret/meshca-root created
    Running: kubectl get cm istio -n istio-system -o yaml
    Running: kubectl get cm istio -n istio-system -o yaml
    Running: kubectl replace -f -
    configmap/istio replaced
    Running: kubectl get deploy istio-pilot -n istio-system -o yaml
    Running: kubectl patch deploy istio-pilot -n istio-system -p={"spec":{"template":{"spec":{"containers":[{
        "name":"discovery",
        "image":"gcr.io/gke-release/istio/pilot:1.4.10-gke.12",
        "env":[{"name":"PILOT_SKIP_VALIDATE_TRUST_DOMAIN","value":"true"}]
      }]}}}}
    deployment.apps/istio-pilot patched
    Running: kubectl get deploy istio-citadel -n istio-system -o yaml
    Running: kubectl patch deploy istio-citadel -n istio-system -p={"spec":{"template":{"spec":{
        "containers":[{
          "name":"citadel",
          "args": ["--append-dns-names=true", "--grpc-port=8060", "--citadel-storage-namespace=istio-system", "--custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system", "--monitoring-port=15014", "--self-signed-ca=true", "--workload-cert-ttl=2160h", "--root-cert=/var/run/root-certs/meshca-root.pem"],
          "volumeMounts": [{"mountPath": "/var/run/root-certs", "name": "meshca-root", "readOnly": true}]
        }],
        "volumes": [{"name": "meshca-root", "secret":{"secretName": "meshca-root"}}]
      }}}}
    deployment.apps/istio-citadel patched
    OK
    
    Waiting for root certificate to distribute to all pods. This will take a few minutes...
    ASM root certificate not distributed to asm-system, trying again later
    ASM root certificate not distributed to asm-system, trying again later
    ASM root certificate distributed to namespace asm-system
    ASM root certificate distributed to namespace default
    ASM root certificate distributed to namespace istio-operator
    ASM root certificate not distributed to istio-system, trying again later
    ASM root certificate not distributed to istio-system, trying again later
    ASM root certificate distributed to namespace istio-system
    ASM root certificate distributed to namespace kube-node-lease
    ASM root certificate distributed to namespace kube-public
    ASM root certificate distributed to namespace kube-system
    ASM root certificate distributed to namespace online-boutique
    Waiting for proxies to pick up the new root certificate...
    OK
    
    

    This step takes a few minutes for the Anthos Service Mesh root certificate to be distributed to all namespaces. Wait until the script finishes with an OK message.

The previous step does the following:

  • Installs the Mesh CA root of trust for all v1.4 workloads in the cluster.
  • Changes the configurations of the v1.4 control plane Deployments istio-pilot and istio-citadel. The changes include the following:

    • Upgrading the istio-pilot v1.4 image to the latest build.
    • Disabling trust-domain verification by setting PILOT_SKIP_VALIDATE_TRUST_DOMAIN=true.
    • Adding the Mesh CA root of trust to istio-citadel to distribute the ConfigMap to all namespaces.
  • Stores the older configuration manifests in the tmpdir.

  • Provides steps for the rollback function (documented later).

Migrate workloads to Anthos Service Mesh

In this section, you migrate workloads running on Istio on GKE to Anthos Service Mesh. After migration, you verify that the correct sidecar proxies (Anthos Service Mesh) are injected in every Pod and that the application is working as expected.

If you created a test cluster by following the steps in Appendix A, you use the online-boutique namespace as an example. If you are performing this procedure on an existing cluster, select a namespace to be migrated.

  1. Define the namespace as a variable; this namespace is migrated to Anthos Service Mesh:

    export NAMESPACE=NAMESPACE_NAME # or online-boutique if using the test cluster in Appendix A
    
  2. To migrate workloads to Anthos Service Mesh, you must relabel the namespace for Anthos Service Mesh. Labeling the namespace allows Anthos Service Mesh to automatically inject sidecars to all workloads. To label the namespace, run the following command, setting the label to asm-managed-rapid:

    kubectl --context=${CLUSTER_1_CTX} label namespace ${NAMESPACE} istio.io/rev=asm-managed-rapid istio-injection- --overwrite
    
  3. Perform a rolling restart of all Deployments in the namespace:

    kubectl --context=${CLUSTER_1_CTX} rollout restart deployment -n ${NAMESPACE}
    

    The output is similar to the following:

    deployment.apps/deploymentName1 restarted
    deployment.apps/deploymentName2 restarted
    ...
    
  4. Ensure that all Pods are restarted and are running with two containers per Pod:

    kubectl --context=${CLUSTER_1_CTX} -n ${NAMESPACE} get pods
    

    The output is similar to the following:

    NAME                        READY   STATUS    RESTARTS   AGE
    deploymentName1-PodName     2/2     Running   0          101s
    deploymentName2-PodName     2/2     Running   2          100s
    ...
    

    A good way to verify this step is by looking at the AGE of the Pods. Ensure that the value is short—for example, a few minutes.

  5. Check the sidecar Envoy proxy version from any one of the Pods from any Deployment in the namespace to confirm that you now have Anthos Service Mesh v1.10 Envoy proxies deployed:

    export POD_NAME=NAME_OF_ANY_POD_IN_NAMESPACE
    kubectl --context=${CLUSTER_1_CTX} get pods ${POD_NAME} -n ${NAMESPACE} -o json | jq '.status.containerStatuses[].image'
    

    The output is similar to the following:

    "gcr.io/gke-release/asm/proxyv2:1.10.2-asm.2"
    "appContainerImage"
    
  6. Verify and test your applications after restarting.

Access Anthos Service Mesh dashboards

In this section, you go to the Anthos Service Mesh dashboards and make sure that you are receiving the golden signals for all Services. You should also be able to see your application topology.

  1. In the Cloud Console, go to the Anthos Service Mesh page.

    Go to Anthos Service Mesh

  2. You should be able to view the metrics and topology for your Services.

To learn more about Anthos Service Mesh dashboards, see Exploring Anthos Service Mesh in the Cloud Console.

Complete a successful migration

In this section, you finalize your Istio on GKE to Anthos Service Mesh migration. Before proceeding with this section, make sure that you want to proceed with Anthos Service Mesh. This section also helps you clean up your Istio on GKE artifacts. If you want to roll back to Istio on GKE, proceed to the next section.

  1. Replace the istio-ingressgateway (part of standard Istio on GKE) with the Google-managed control plane versioned gateway:

    ${WORKDIR}/migrate_addon -d tmpdir --command replace-gateway
    

    The output is similar to the following:

    Replacing the ingress gateway with an Anthos Service Mesh gateway... Continue? [Y/n] Y
    Running: kubectl label namespace istio-system istio-injection- istio.io/rev- --overwrite
    label "istio.io/rev" not found.
    namespace/istio-system labeled
    Running: kubectl apply -f -
    serviceaccount/asm-ingressgateway created
    deployment.apps/asm-ingressgateway created
    role.rbac.authorization.k8s.io/asm-ingressgateway created
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway created
    Running: kubectl wait --for=condition=available --timeout=600s deployment/asm-ingressgateway -n istio-system
    deployment.apps/asm-ingressgateway condition met
    
    Scaling the Istio ingress gateway to zero replicas... Continue? [Y/n] Y
    Running: kubectl -n istio-system patch hpa istio-ingressgateway --patch {"spec":{"minReplicas":1}}
    horizontalpodautoscaler.autoscaling/istio-ingressgateway patched (no change)
    Running: kubectl -n istio-system scale deployment istio-ingressgateway --replicas=0
    deployment.apps/istio-ingressgateway scaled
    OK
    
  2. Reconfigure the webhook to use the Google-managed control plane; all workloads start by using the Google-managed control plane:

    ${WORKDIR}/migrate_addon -d tmpdir --command replace-webhook
    

    The output is similar to the following:

    Configuring sidecar injection to use Anthos Service Mesh by default... Continue? [Y/n] Y
    Running: kubectl patch mutatingwebhookconfigurations istio-sidecar-injector --type=json -p=[{"op": "replace", "path": "/webhooks"}]
    mutatingwebhookconfiguration.admissionregistration.k8s.io/istio-sidecar-injector patched
    Revision tag "default" created, referencing control plane revision "asm-managed". To enable injection using this
    revision tag, use 'kubectl label namespace <NAMESPACE> istio.io/rev=default'
    OK
    
  3. Relabel all the namespaces with the Anthos Service Mesh label, and perform a rolling restart of all workloads to get them on the Google-managed control plane:

    export NAMESPACE=NAMESPACE_NAME \
        kubectl --context=${CLUSTER_1_CTX} label namespace ${NAMESPACE}
        istio.io/rev=asm-managed-rapid istio-injection- --overwrite`
    
        kubectl --context=${CLUSTER_1_CTX} rollout restart deployment -n
    ${NAMESPACE}
    
  4. Finalize the migration by running the following command:

    ${WORKDIR}/migrate_addon -d tmpdir --command write-marker
    

    The output is similar to the following:

    Current migration state: COMPLETE
    Running: kubectl apply -f -
    configmap/asm-addon-migration-state created
    OK
    
    
  5. Disable Istio on GKE by running the following command:

    Zonal clusters

    gcloud beta container clusters update ${CLUSTER_1} \
        --project=$PROJECT_ID \
        --zone=${CLUSTER_1_LOCATION} \
        --update-addons=Istio=DISABLED
    

    Regional clusters

    gcloud beta container clusters update ${CLUSTER_1} \
        --project=$PROJECT_ID \
        --region=${CLUSTER_1_LOCATION} \
        --update-addons=Istio=DISABLED
    
  6. Clean up configurations by running the following command:

    ${WORKDIR}/migrate_addon -d tmpdir --command cleanup
    

    The output is similar to the following:

    Cleaning up old resources...
    Running: kubectl get cm -n istio-system asm-addon-migration-state -ojsonpath={.data.migrationStatus}
    Will delete IstioOperator/istio-1-6-11-gke-0.istio-system
    Will delete ServiceAccount/istio-citadel-service-account.istio-system
    ...
    Will delete DestinationRule/istio-policy.istio-system
    Will delete DestinationRule/istio-telemetry.istio-system
    Will delete Secret/istio-ca-secret.istio-system
    
    Deleting resources previously listed... Continue? [Y/n] Y
    Running: kubectl delete IstioOperator istio-1-6-11-gke-0 -n istio-system --ignore-not-found
    istiooperator.install.istio.io "istio-1-6-11-gke-0" deleted
    Running: kubectl delete ServiceAccount istio-citadel-service-account -n istio-system --ignore-not-found
    serviceaccount "istio-citadel-service-account" deleted-ingressgateway -n istio-system --ignore-not-found
    ...
    Running: kubectl delete Secret istio-ca-secret -n istio-system --ignore-not-found
    secret "istio-ca-secret" deleted
    Running: kubectl delete -n istio-system jobs -lk8s-app=istio,app=security
    job.batch "istio-security-post-install-1.4.10-gke.8" deleted
    
  7. Ensure that Istio on GKE Deployments and Services have been successfully removed from the cluster:

    kubectl --context=${CLUSTER_1_CTX} -n istio-system get deployments,services
    

    The output is similar to the following:

    NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/asm-ingressgateway   1/1     1            1           10m
    
    NAME                           TYPE           CLUSTER-IP    EXTERNAL-IP      AGE   PORT(S)
    service/istio-ingressgateway   LoadBalancer   10.64.5.208   34.139.100.237   95m   15020:31959/TCP,80:30971/TCP,443:31688/TCP,31400:31664/TCP,15029:32493/TCP,15030:31722/TCP,15031:30198/TCP,15032:31910/TCP,15443:31222/TCP
    
    

    You only see the Anthos Service Mesh ingress gateway Service and Deployment.

Congratulations. You have successfully migrated from Istio on GKE v1.4 to Anthos Service Mesh v1.10 with the Google-managed control plane and Mesh CA without any downtime to your applications.

Roll back changes

In this section, if you do not want to proceed with Anthos Service Mesh, you can roll back your Anthos Service Mesh changes. After completing this section, your workloads move back to Istio on GKE.

  1. Relabel the namespaces to use Istio on GKE sidecar injection instead of Anthos Service Mesh by running the following command:

    export NAMESPACE=NAMESPACE_NAME
    kubectl --context=${CLUSTER_1_CTX} label namespace ${NAMESPACE} istio.io/rev- istio-injection=enabled --overwrite
    
  2. Perform a rolling restart of all Deployments in the namespace:

    kubectl --context=${CLUSTER_1_CTX} rollout restart deployment -n ${NAMESPACE}
    
  3. Wait a few minutes and ensure that all Pods are running:

    kubectl --context=${CLUSTER_1_CTX} -n ${NAMESPACE} get pods
    

    The output is similar to the following:

    NAME                       READY   STATUS    RESTARTS   AGE
    deploymentName1-PodName    2/2     Running   0          101s
    deploymentName2-PodName    2/2     Running   2          100s
    ...
    
    
  4. Verify the sidecar Envoy proxy version from any one of the Pods to confirm that you have Istio on GKE v1.4 Envoy proxies deployed:

    export POD_NAME=NAME_OF_ANY_POD_IN_NAMESPACE
    kubectl --context=${CLUSTER_1_CTX} get pods ${POD_NAME} -n ${NAMESPACE} -o json | jq '.status.containerStatuses[].image'
    

    The output is similar to the following:

    "gke.gcr.io/istio/proxyv2:1.4.10-gke.8"
    "appContainerImage"
    
  5. Verify and test your applications after restarting.

  6. Roll back the Mesh CA changes:

    ${WORKDIR}/migrate_addon -d tmpdir --command rollback-mesh-ca
    
  7. Re-enable the Istio Galley webhook:

    ${WORKDIR}/migrate_addon -d tmpdir enable-galley-webook
    

You have successfully rolled back your changes to Istio on GKE.

Appendix A

Create a GKE cluster with Istio on GKE

In this section, you deploy a GKE cluster with Istio on GKE enabled. You can use a private or a non-private GKE cluster. Private GKE clusters must have a public GKE endpoint. You also verify the Istio on GKE installation.

If you already have an existing GKE cluster, you can skip the creation step and make sure that you have access to the cluster that uses the KUBECONFIG file. The context that this guide uses is defined in the variable ${CLUSTER_1_CTX}. You can set the context of your cluster to this variable.

  1. Create the environment variables used in this guide:

    # Enter your project ID
    export PROJECT_ID=PROJECT_ID
    
    # Copy and paste the following
    gcloud config set project ${PROJECT_ID}
    export PROJECT_NUM=$(gcloud projects describe ${PROJECT_ID} --format='value(projectNumber)')
    export CLUSTER_1=GKE_CLUSTER_NAME
    export CLUSTER_1_LOCATION=GKE_CLUSTER_REGION_OR_ZONE
    export SHELL_IP=$(curl ifconfig.me) # This is required for private clusters with `master-authorized-networks` enabled.
    
  2. Create a GKE cluster with Istio on GKE enabled (this is a private cluster). You can also perform these steps with a non-private GKE cluster.

    Zonal clusters

    gcloud beta container clusters create ${CLUSTER_1} \
      --project ${PROJECT_ID} \
      --zone=${CLUSTER_1_LOCATION} \
      --machine-type "e2-standard-4" \
      --num-nodes "4" --min-nodes "2" --max-nodes "5" \
      --addons=Istio --istio-config=auth=MTLS_STRICT \
      --enable-master-authorized-networks \
      --master-authorized-networks ${SHELL_IP}/32 \
      --enable-private-nodes \
      --master-ipv4-cidr 172.16.0.32/28 \
      --enable-ip-alias \
      --enable-autoscaling
    

    Regional clusters

    gcloud beta container clusters create ${CLUSTER_1} \
      --project ${PROJECT_ID} \
      --region=${CLUSTER_1_LOCATION} \
      --machine-type "e2-standard-4" \
      --num-nodes "4" --min-nodes "2" --max-nodes "5" \
      --addons=Istio --istio-config=auth=MTLS_STRICT \
      --enable-master-authorized-networks \
      --master-authorized-networks ${SHELL_IP}/32 \
      --enable-private-nodes \
      --master-ipv4-cidr 172.16.0.32/28 \
      --enable-ip-alias \
      --enable-autoscaling
    
  3. Confirm that the cluster is RUNNING:

    gcloud container clusters list
    

    The output is similar to the following:

    NAME      LOCATION    MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    gke-east  us-east1-b  1.19.10-gke.1600  34.73.171.206  e2-standard-4  1.19.10-gke.1600  4          RUNNING
    
  4. Connect to the cluster:

    Zonal clusters

    gcloud container clusters get-credentials ${CLUSTER_1} \
      --zone=${CLUSTER_1_LOCATION}
    
    export CLUSTER_1_CTX=gke_${PROJECT_ID}_${CLUSTER_1_LOCATION}_${CLUSTER_1}
    

    Regional clusters

    gcloud container clusters get-credentials ${CLUSTER_1} \
      --region=${CLUSTER_1_LOCATION}
    
    export CLUSTER_1_CTX=gke_${PROJECT_ID}_${CLUSTER_1_LOCATION}_${CLUSTER_1}
    

    Optional step

    If you're using Cloud Shell for these steps, your SHELL_IP could change. If that happens, you can run the following command to update the master-authorized-networks value with your new Cloud Shell IP address.

    To update the master-authorized-networks value for your cluster, run the following commands. You only need to run the following commands when your Cloud Shell IP address changes.

    Zonal clusters

    export SHELL_IP=$(curl ifconfig.me)
    gcloud container clusters update ${CLUSTER_1} \
      --zone=${CLUSTER_1_LOCATION} \
      --enable-master-authorized-networks \
      --master-authorized-networks ${SHELL_IP}/32
    

    Regional clusters

    export SHELL_IP=$(curl ifconfig.me)
    gcloud container clusters update ${CLUSTER_1} \
      --region=${CLUSTER_1_LOCATION} \
      --enable-master-authorized-networks \
      --master-authorized-networks ${SHELL_IP}/32
    
  5. Ensure that Istio is deployed to the cluster. Check to ensure that all Services are deployed:

    kubectl --context=${CLUSTER_1_CTX} get service -n istio-system
    

    The output is similar to the following:

    NAME                     TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                                                                                      AGE
    istio-citadel            ClusterIP      10.64.7.167    <none>        8060/TCP,15014/TCP                                                                                                                           90s
    istio-galley             ClusterIP      10.64.15.216   <none>        443/TCP,15014/TCP,9901/TCP                                                                                                                   90s
    istio-ingressgateway     LoadBalancer   10.64.9.36     <pending>     15020:31962/TCP,80:31663/TCP,443:31658/TCP,31400:32022/TCP,15029:31829/TCP,15030:30063/TCP,15031:32466/TCP,15032:30649/TCP,15443:30807/TCP   90s
    istio-pilot              ClusterIP      10.64.10.175   <none>        15010/TCP,15011/TCP,8080/TCP,15014/TCP                                                                                                       90s
    istio-policy             ClusterIP      10.64.1.82     <none>        9091/TCP,15004/TCP,15014/TCP                                                                                                                 90s
    istio-sidecar-injector   ClusterIP      10.64.13.43    <none>        443/TCP,15014/TCP                                                                                                                            90s
    istio-telemetry          ClusterIP      10.64.7.76     <none>        9091/TCP,15004/TCP,15014/TCP,42422/TCP                                                                                                       90s
    promsd                   ClusterIP      10.64.5.236    <none>        9090/TCP
    
  6. Ensure that all Pods are running and that jobs are completed:

    kubectl --context=${CLUSTER_1_CTX} get pods -n istio-system
    

    The output is similar to the following:

    NAME                                             READY   STATUS      RESTARTS   AGE
    istio-citadel-f5586dffb-8c9sm                    1/1     Running     0          10m
    istio-galley-7975f77bbf-zxccq                    1/1     Running     0          10m
    istio-ingressgateway-b9477dcdb-gr7wb             1/1     Running     0          10m
    istio-pilot-59d4884d67-v6zh6                     2/2     Running     0          10m
    istio-policy-6885cb4644-h5pnv                    2/2     Running     1          10m
    istio-security-post-install-1.4.10-gke.8-q9w5s   0/1     Completed   0          10m
    istio-sidecar-injector-649d664b99-555dx          1/1     Running     0          10m
    istio-telemetry-59b6bf55c7-r2q57                 2/2     Running     1          10m
    istiod-istio-1611-6895859f65-zvlzq               1/1     Running     0          9m21s
    prometheus-6655946b9f-hdsrd                      2/2     Running     0          9m21s
    promsd-574ccb9745-w65pl                          2/2     Running     1          10m
    

Deploy Online Boutique

In this section, you deploy a sample microservices-based application called Online Boutique to the GKE cluster. Online Boutique is deployed in an Istio-enabled namespace. You verify that the application is working and that Istio on GKE is injecting the sidecar proxies to every Pod.

If you already have existing clusters with applications, you can skip creating a new namespace and deploying Online Boutique. You can follow the same process for all namespaces in the Migrate workloads to Anthos Service Mesh section.

  1. Deploy Online Boutique to the GKE cluster:

    kpt pkg get \
    https://github.com/GoogleCloudPlatform/microservices-demo.git/release \
    online-boutique
    
    kubectl --context=${CLUSTER_1_CTX} create namespace online-boutique
    kubectl --context=${CLUSTER_1_CTX} label namespace online-boutique istio-injection=enabled
    
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique apply -f online-boutique
    
  2. Wait until all Deployments are ready:

    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment adservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment checkoutservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment currencyservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment emailservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment frontend
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment paymentservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment productcatalogservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment shippingservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment cartservice
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment loadgenerator
    kubectl --context=${CLUSTER_1_CTX} -n online-boutique wait --for=condition=available --timeout=5m deployment recommendationservice
    
  3. Ensure that there are two containers per Pod—the application container and the Istio sidecar proxy that Istio on GKE automatically injects into the Pod:

    kubectl --context=${CLUSTER_1_CTX} -n online-boutique get pods
    

    The output is similar to the following:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-7cbc9bd9-t92k4                 2/2     Running   0          3m21s
    cartservice-d7db78c66-5qfmt              2/2     Running   1          3m23s
    checkoutservice-784bfc794f-j8rl5         2/2     Running   0          3m26s
    currencyservice-5898885559-lkwg4         2/2     Running   0          3m23s
    emailservice-6bd8b47657-llvgv            2/2     Running   0          3m27s
    frontend-764c5c755f-9wf97                2/2     Running   0          3m25s
    loadgenerator-84cbcd768c-5pdbr           2/2     Running   3          3m23s
    paymentservice-6c676df669-s779c          2/2     Running   0          3m25s
    productcatalogservice-7fcf4f8cc-hvf5x    2/2     Running   0          3m24s
    recommendationservice-79f5f4bbf5-6st24   2/2     Running   0          3m26s
    redis-cart-74594bd569-pfhkz              2/2     Running   0          3m22s
    shippingservice-b5879cdbf-5z7m5          2/2     Running   0          3m22s
    
  4. You can also check the sidecar Envoy proxy version from any one of the Pods to confirm that you have Istio on GKE v1.4 Envoy proxies deployed:

    export FRONTEND_POD=$(kubectl get pod -n online-boutique -l app=frontend --context=${CLUSTER_1_CTX} -o jsonpath='{.items[0].metadata.name}')
    kubectl --context=${CLUSTER_1_CTX} get pods ${FRONTEND_POD} -n online-boutique -o json | jq '.status.containerStatuses[].image'
    

    The output is similar to the following:

    "gke.gcr.io/istio/proxyv2:1.4.10-gke.8"
    "gcr.io/google-samples/microservices-demo/frontend:v0.2.3"
    
  5. Access the application by navigating to the IP address of the istio-ingressgateway Service IP address:

    kubectl --context=${CLUSTER_1_CTX} -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
    

What's next