master 3b73ff8ee2b1 cached
141 files
572.4 KB
213.3k tokens
15 symbols
1 requests
Download .txt
Showing preview only (615K chars total). Download the full file or copy to clipboard to get everything.
Repository: GoogleCloudPlatform/istio-samples
Branch: master
Commit: 3b73ff8ee2b1
Files: 141
Total size: 572.4 KB

Directory structure:
gitextract_ft7f4bst/

├── .github/
│   └── snippet-bot.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── common/
│   ├── default.yaml
│   └── install_istio.sh
├── internal-load-balancer/
│   ├── README.md
│   └── manifests/
│       ├── install.yaml
│       └── server-ilb.yaml
├── istio-canary-gke/
│   ├── README.md
│   └── canary/
│       ├── destinationrule.yaml
│       ├── productcatalog-v2.yaml
│       ├── rollback.yaml
│       └── vs-split-traffic.yaml
├── istio-stackdriver/
│   └── README.md
├── mesh-expansion-gce/
│   ├── README.md
│   └── scripts/
│       ├── 1-create-cluster.sh
│       ├── 2-create-vm.sh
│       ├── 3-install-istio.sh
│       ├── 4-deploy-hipstershop.sh
│       ├── 5-prep-cluster.sh
│       ├── 6-prep-vm.sh
│       ├── 7-add-to-mesh.sh
│       ├── 8-start-vm-istio.sh
│       ├── install.yaml
│       ├── vm-install-istio.sh
│       └── vm-run-products.sh
├── multicluster-gke/
│   ├── dual-control-plane/
│   │   ├── README.md
│   │   ├── cluster1/
│   │   │   ├── deployments.yaml
│   │   │   ├── istio-defaults.yaml
│   │   │   ├── service-entries.yaml
│   │   │   └── services-local.yaml
│   │   ├── cluster2/
│   │   │   ├── deployments.yaml
│   │   │   ├── istio-defaults.yaml
│   │   │   ├── service-entries.yaml
│   │   │   └── services-local.yaml
│   │   └── scripts/
│   │       ├── 1-create-gke-clusters.sh
│   │       ├── 2-install-istio.sh
│   │       ├── 3-configure-dns.sh
│   │       ├── 4-deploy-online-boutique.sh
│   │       ├── cleanup-delete-clusters.sh
│   │       ├── env.sh
│   │       └── install.yaml
│   ├── single-control-plane/
│   │   ├── README.md
│   │   └── scripts/
│   │       ├── 1-cluster-create.sh
│   │       ├── 2-get-credentials.sh
│   │       ├── 3-firewall.sh
│   │       ├── 4-cluster1-install.sh
│   │       ├── 5-cluster2-install.sh
│   │       ├── 6-connect-clusters.sh
│   │       ├── 7-deploy-hipstershop.sh
│   │       ├── cleanup-delete-clusters.sh
│   │       ├── cluster1.yaml
│   │       ├── cluster2.yaml
│   │       └── env.sh
│   └── vm-migration/
│       ├── README.md
│       ├── cluster1/
│       │   ├── deployments.yaml
│       │   ├── istio-defaults.yaml
│       │   ├── service-entries.yaml
│       │   └── services-local.yaml
│       ├── cluster2/
│       │   ├── deployments.yaml
│       │   ├── istio-defaults.yaml
│       │   ├── service-entries.yaml
│       │   └── services-local.yaml
│       ├── productcatalog-gke/
│       │   ├── deployment.yaml
│       │   ├── service-cluster2.yaml
│       │   ├── serviceentry-cluster1.yaml
│       │   ├── vs-0-cluster1.yaml
│       │   ├── vs-0-cluster2.yaml
│       │   ├── vs-100-cluster1.yaml
│       │   ├── vs-100-cluster2.yaml
│       │   ├── vs-20-cluster1.yaml
│       │   └── vs-20-cluster2.yaml
│       └── scripts/
│           ├── 1-create-infra.sh
│           ├── 10-split-traffic.sh
│           ├── 11-complete-migration.sh
│           ├── 12-cleanup.sh
│           ├── 2-firewall.sh
│           ├── 3-install-istio-gke.sh
│           ├── 4-deploy-onlineboutique-gke.sh
│           ├── 5-prep-cluster1.sh
│           ├── 6-prep-vm.sh
│           ├── 7-add-vm-to-mesh.sh
│           ├── 8-verify-deploy.sh
│           ├── 9-deploy-productcatalog-gke.sh
│           ├── env.sh
│           ├── install.yaml
│           ├── vm-install-istio.sh
│           └── vm-run-products.sh
├── multicluster-ingress/
│   ├── 1-create-clusters.sh
│   ├── 2-install-istio.sh
│   ├── 3-deploy-app.sh
│   ├── 4-verify-app.sh
│   ├── 5-prep-mci.sh
│   ├── 6-mci.sh
│   ├── 7-cleanup.sh
│   ├── README.md
│   ├── common.sh
│   ├── manifests/
│   │   ├── healthcheck.yaml
│   │   ├── ingress.yaml
│   │   └── istio-ingressgateway-patch.json
│   └── zone_printer/
│       ├── deployment.yaml
│       ├── gateway.yaml
│       ├── service.yaml
│       └── virtualservice.yaml
├── sample-apps/
│   ├── grpc-greeter-go/
│   │   ├── README.md
│   │   ├── client/
│   │   │   ├── .dockerignore
│   │   │   ├── .gcloudignore
│   │   │   ├── Dockerfile
│   │   │   ├── client.go
│   │   │   ├── go.mod
│   │   │   └── go.sum
│   │   ├── manifests/
│   │   │   ├── greeter-istio-destinationrule.yaml
│   │   │   ├── greeter-istio-gateway.yaml
│   │   │   ├── greeter-istio-virtualservice.yaml
│   │   │   ├── greeter-k8s.template.yaml
│   │   │   └── istio-operator.yaml
│   │   └── server/
│   │       ├── .dockerignore
│   │       ├── .gcloudignore
│   │       ├── Dockerfile
│   │       ├── go.mod
│   │       ├── go.sum
│   │       └── server.go
│   └── helloserver/
│       ├── README.md
│       ├── loadgen/
│       │   ├── Dockerfile
│       │   ├── Dockerfile-base
│       │   ├── loadgen.py
│       │   ├── loadgen.yaml
│       │   └── requirements.txt
│       └── server/
│           ├── Dockerfile
│           ├── server.py
│           └── server.yaml
├── security-intro/
│   ├── README.md
│   └── manifests/
│       ├── authz-frontend.yaml
│       ├── jwt-frontend-authz.yaml
│       ├── jwt-frontend-request.yaml
│       ├── mtls-default-ns.yaml
│       └── mtls-frontend.yaml
└── stackdriver-metrics/
    ├── README.md
    └── istio-stackdriver-metrics.yaml

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/snippet-bot.yml
================================================



================================================
FILE: .gitignore
================================================
.DS_Store
*.env
*.pem
*.tar.gz
cluster-2
istio_master.yaml
istio-1*
istio-2*
istio-master.yaml
istio-remote.yaml
istio.yaml
kubeconfig
kubectx
kubemci*
region-tag-adder

================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

## Development Principles (for Googlers)

There are a few principles for developing or refactoring the service
implementations. Read the [Development Principles
Guide](./docs/development-principles.md).

## Contributor License Agreement

Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution;
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.

You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.

## Code reviews

All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.

## Community Guidelines

This project follows [Google's Open Source Community
Guidelines](https://opensource.google.com/conduct/).


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# ⛵️ istio-samples

This repository contains Google Cloud Platform demos and sample code for [Istio](https://istio.io/).

**⚠️ Note**: These samples are last updated to the [Istio 1.5 release](https://github.com/istio/istio/releases/), and are no longer under active development. See the [Istio documentation](https://istio.io/) for the most up-to-date examples. For Anthos Service Mesh (ASM) samples, see https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples

## Contents

### [Canary Deployments with Istio on GKE](/istio-canary-gke)

Uses the [Hipstershop](https://github.com/GoogleCloudPlatform/microservices-demo) sample app to demonstrate traffic splitting with Istio on GKE, and how to view Istio-generated metrics in Stackdriver.

### [Introduction to Istio Security](/security-intro)

Provides an introduction to Istio service-to-service encryption (mutual TLS), end-user authentication (JSON Web Tokens), and service authorization (role-based access control).

### [Istio and Stackdriver](/istio-stackdriver)

A deep-dive on how to use Stackdriver to monitor Istio services' health, analyze traces, and view logs.

### [Using a GCP Internal Load Balancer with Istio](/internal-load-balancer)

Demonstrates how to connect GCE (VM-based) workloads to Istio services running in GKE, through a private internal load balancer on GCP.

### [Geo-Aware Istio Multicluster Ingress](/multicluster-ingress)

Shows how to attach a global Anycast IP address to multiple Istio IngressGateways running in clusters across regions.

### [Integrating a Google Compute Engine VM with Istio](/mesh-expansion-gce)

Demonstrates how to do Istio Mesh Expansion: the process of incorporating a GCE-based workload into an Istio mesh running in GKE.

### [Multicluster Istio- Single Control Plane](/multicluster-gke/single-control-plane)

Introduces Multicluster Istio by uniting GKE workloads in two different clusters into a single Istio mesh.

### [Multicluster Istio- Dual Control Plane](/multicluster-gke/dual-control-plane)

Shows how to connect two separate GKE clusters, each with their own Istio control planes, into a single Gateway-connected mesh.

### [Virtual Machine Migration with Multicluster Istio](/multicluster-gke/vm-migration/)

Demonstrates how to integrate an Istio-enabled VM into a multicluster mesh, then migrate traffic from the VM to GKE.


================================================
FILE: common/default.yaml
================================================
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  addonComponents:
    grafana:
      enabled: true
      k8s:
        replicaCount: 1
    istiocoredns:
      enabled: false
    kiali:
      enabled: true
      k8s:
        replicaCount: 1
    prometheus:
      enabled: true
      k8s:
        replicaCount: 1
    tracing:
      enabled: true
  components:
    base:
      enabled: true
    citadel:
      enabled: false
      k8s:
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    cni:
      enabled: false
    egressGateways:
    - enabled: false
      k8s:
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ingressgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
      name: istio-egressgateway
    galley:
      enabled: false
      k8s:
        replicaCount: 1
        resources:
          requests:
            cpu: 100m
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    ingressGateways:
    - enabled: true
      k8s:
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ingressgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
      name: istio-ingressgateway
    nodeAgent:
      enabled: false
    pilot:
      enabled: true
      k8s:
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 5
        resources:
          requests:
            cpu: 500m
            memory: 2048Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    policy:
      enabled: false
      k8s:
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-policy
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    sidecarInjector:
      enabled: false
      k8s:
        replicaCount: 1
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    telemetry:
      enabled: false
      k8s:
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: GOMAXPROCS
          value: "6"
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-telemetry
        replicaCount: 1
        resources:
          limits:
            cpu: 4800m
            memory: 4G
          requests:
            cpu: 1000m
            memory: 1G
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
  hub: docker.io/istio
  tag: 1.5.1
  values:
    clusterResources: true
    galley:
      enableAnalysis: false
      image: galley
    gateways:
      istio-egressgateway:
        autoscaleEnabled: true
        env:
          ISTIO_META_ROUTER_MODE: sni-dnat
        ports:
        - name: http2
          port: 80
        - name: https
          port: 443
        - name: tls
          port: 15443
          targetPort: 15443
        secretVolumes:
        - mountPath: /etc/istio/egressgateway-certs
          name: egressgateway-certs
          secretName: istio-egressgateway-certs
        - mountPath: /etc/istio/egressgateway-ca-certs
          name: egressgateway-ca-certs
          secretName: istio-egressgateway-ca-certs
        type: ClusterIP
      istio-ingressgateway:
        applicationPorts: ""
        autoscaleEnabled: true
        debug: info
        domain: ""
        env:
          ISTIO_META_ROUTER_MODE: sni-dnat
        meshExpansionPorts:
        - name: tcp-pilot-grpc-tls
          port: 15011
          targetPort: 15011
        - name: tcp-citadel-grpc-tls
          port: 8060
          targetPort: 8060
        - name: tcp-dns-tls
          port: 853
          targetPort: 853
        ports:
        - name: status-port
          port: 15020
          targetPort: 15020
        - name: http2
          port: 80
          targetPort: 80
        - name: https
          port: 443
        - name: kiali
          port: 15029
          targetPort: 15029
        - name: prometheus
          port: 15030
          targetPort: 15030
        - name: grafana
          port: 15031
          targetPort: 15031
        - name: tracing
          port: 15032
          targetPort: 15032
        - name: tls
          port: 15443
          targetPort: 15443
        sds:
          enabled: false
          image: node-agent-k8s
          resources:
            limits:
              cpu: 2000m
              memory: 1024Mi
            requests:
              cpu: 100m
              memory: 128Mi
        secretVolumes:
        - mountPath: /etc/istio/ingressgateway-certs
          name: ingressgateway-certs
          secretName: istio-ingressgateway-certs
        - mountPath: /etc/istio/ingressgateway-ca-certs
          name: ingressgateway-ca-certs
          secretName: istio-ingressgateway-ca-certs
        type: LoadBalancer
        zvpn:
          enabled: false
          suffix: global
    global:
      arch:
        amd64: 2
        ppc64le: 2
        s390x: 2
      certificates: []
      configValidation: true
      controlPlaneSecurityEnabled: true
      defaultNodeSelector: {}
      defaultPodDisruptionBudget:
        enabled: true
      defaultResources:
        requests:
          cpu: 10m
      disablePolicyChecks: true
      enableHelmTest: false
      enableTracing: true
      imagePullPolicy: IfNotPresent
      imagePullSecrets: []
      istioNamespace: istio-system
      istiod:
        enabled: true
      jwtPolicy: third-party-jwt
      k8sIngress:
        enableHttps: false
        enabled: false
        gatewayName: ingressgateway
      localityLbSetting:
        enabled: true
      logAsJson: false
      logging:
        level: default:info
      meshExpansion:
        enabled: false
        useILB: false
      meshNetworks: {}
      mountMtlsCerts: false
      mtls:
        auto: true
        enabled: false
      multiCluster:
        clusterName: ""
        enabled: false
      network: ""
      omitSidecarInjectorConfigMap: false
      oneNamespace: false
      operatorManageWebhooks: false
      outboundTrafficPolicy:
        mode: ALLOW_ANY
      pilotCertProvider: istiod
      policyCheckFailOpen: false
      priorityClassName: ""
      proxy:
        accessLogEncoding: TEXT
        accessLogFile: "/dev/stdout"
        accessLogFormat: ""
        autoInject: enabled
        clusterDomain: cluster.local
        componentLogLevel: misc:error
        concurrency: 2
        dnsRefreshRate: 300s
        enableCoreDump: false
        envoyAccessLogService:
          enabled: false
        envoyMetricsService:
          enabled: false
          tcpKeepalive:
            interval: 10s
            probes: 3
            time: 10s
          tlsSettings:
            mode: DISABLE
            subjectAltNames: []
        envoyStatsd:
          enabled: false
        excludeIPRanges: ""
        excludeInboundPorts: ""
        excludeOutboundPorts: ""
        image: proxyv2
        includeIPRanges: '*'
        includeInboundPorts: '*'
        kubevirtInterfaces: ""
        logLevel: warning
        privileged: false
        protocolDetectionTimeout: 100ms
        readinessFailureThreshold: 30
        readinessInitialDelaySeconds: 1
        readinessPeriodSeconds: 2
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        statusPort: 15020
        tracer: zipkin
      proxy_init:
        image: proxyv2
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
          requests:
            cpu: 10m
            memory: 10Mi
      sds:
        enabled: false
        token:
          aud: istio-ca
        udsPath: ""
      sts:
        servicePort: 0
      tracer:
        datadog:
          address: $(HOST_IP):8126
        lightstep:
          accessToken: ""
          address: ""
          cacertPath: ""
          secure: true
        stackdriver:
          debug: false
          maxNumberOfAnnotations: 200
          maxNumberOfAttributes: 200
          maxNumberOfMessageEvents: 200
        zipkin:
          address: ""
      trustDomain: cluster.local
      useMCP: false
    grafana:
      accessMode: ReadWriteMany
      contextPath: /grafana
      dashboardProviders:
        dashboardproviders.yaml:
          apiVersion: 1
          providers:
          - disableDeletion: false
            folder: istio
            name: istio
            options:
              path: /var/lib/grafana/dashboards/istio
            orgId: 1
            type: file
      datasources:
        datasources.yaml:
          apiVersion: 1
      env: {}
      envSecrets: {}
      image:
        repository: grafana/grafana
        tag: 6.5.2
      ingress:
        enabled: false
        hosts:
        - grafana.local
      nodeSelector: {}
      persist: false
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        enabled: false
        passphraseKey: passphrase
        secretName: grafana
        usernameKey: username
      service:
        annotations: {}
        externalPort: 3000
        name: http
        type: ClusterIP
      storageClassName: ""
      tolerations: []
    istiocoredns:
      coreDNSImage: coredns/coredns
      coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1
      coreDNSTag: 1.6.2
    kiali:
      contextPath: /kiali
      createDemoSecret: true
      dashboard:
        grafanaInClusterURL: http://grafana:3000
        jaegerInClusterURL: http://tracing/jaeger
        passphraseKey: passphrase
        secretName: kiali
        usernameKey: username
        viewOnlyMode: false
      hub: quay.io/kiali
      ingress:
        enabled: false
        hosts:
        - kiali.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        cert_file: /kiali-cert/cert-chain.pem
        enabled: false
        private_key_file: /kiali-cert/key.pem
      tag: v1.14
    mixer:
      adapters:
        kubernetesenv:
          enabled: true
        prometheus:
          enabled: true
          metricsExpiryDuration: 10m
        stackdriver:
          auth:
            apiKey: ""
            appCredentials: false
            serviceAccountPath: ""
          enabled: false
          tracer:
            enabled: false
            sampleProbability: 1
        stdio:
          enabled: false
          outputAsJson: false
        useAdapterCRDs: false
      policy:
        adapters:
          kubernetesenv:
            enabled: true
          useAdapterCRDs: false
        autoscaleEnabled: true
        image: mixer
        sessionAffinityEnabled: false
      telemetry:
        autoscaleEnabled: true
        env:
          GOMAXPROCS: "6"
        image: mixer
        loadshedding:
          latencyThreshold: 100ms
          mode: enforce
        nodeSelector: {}
        podAntiAffinityLabelSelector: []
        podAntiAffinityTermLabelSelector: []
        replicaCount: 1
        reportBatchMaxEntries: 100
        reportBatchMaxTime: 1s
        sessionAffinityEnabled: false
        tolerations: []
    nodeagent:
      image: node-agent-k8s
    pilot:
      appNamespaces: []
      autoscaleEnabled: true
      autoscaleMax: 5
      autoscaleMin: 1
      configMap: true
      configNamespace: istio-config
      cpu:
        targetAverageUtilization: 80
      enableProtocolSniffingForInbound: false
      enableProtocolSniffingForOutbound: true
      env: {}
      image: pilot
      ingress:
        ingressClass: istio
        ingressControllerMode: STRICT
        ingressService: istio-ingressgateway
      keepaliveMaxServerConnectionAge: 30m
      meshNetworks:
        networks: {}
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      policy:
        enabled: false
      replicaCount: 1
      tolerations: []
      traceSampling: 1
    prometheus:
      contextPath: /prometheus
      hub: docker.io/prom
      ingress:
        enabled: false
        hosts:
        - prometheus.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      provisionPrometheusCert: true
      retention: 6h
      scrapeInterval: 15s
      security:
        enabled: true
      tag: v2.15.1
      tolerations: []
    security:
      dnsCerts:
        istio-pilot-service-account.istio-control: istio-pilot.istio-control
      enableNamespacesByDefault: true
      image: citadel
      selfSigned: true
    sidecarInjectorWebhook:
      enableNamespacesByDefault: false
      image: sidecar_injector
      injectLabel: istio-injection
      objectSelector:
        autoInject: true
        enabled: false
      rewriteAppHTTPProbe: false
      selfSigned: false
    telemetry:
      enabled: true
      v1:
        enabled: false
      v2:
        enabled: true
        prometheus:
          enabled: true
        stackdriver:
          configOverride: {}
          enabled: true
          logging: true
          monitoring: true
          topology: true
    tracing:
      ingress:
        enabled: false
      jaeger:
        accessMode: ReadWriteMany
        hub: docker.io/jaegertracing
        memory:
          max_traces: 50000
        persist: false
        spanStorageType: badger
        storageClassName: ""
        tag: "1.16"
      nodeSelector: {}
      opencensus:
        exporters:
          stackdriver:
            enable_tracing: true
        hub: docker.io/omnition
        resources:
          limits:
            cpu: "1"
            memory: 2Gi
          requests:
            cpu: 200m
            memory: 400Mi
        tag: 0.1.9
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      provider: jaeger
      service:
        annotations: {}
        externalPort: 9411
        name: http-query
        type: ClusterIP
      zipkin:
        hub: docker.io/openzipkin
        javaOptsHeap: 700
        maxSpans: 500000
        node:
          cpus: 2
        probeStartupDelay: 200
        queryPort: 9411
        resources:
          limits:
            cpu: 300m
            memory: 900Mi
          requests:
            cpu: 150m
            memory: 900Mi
        tag: 2.14.2
    version: ""



================================================
FILE: common/install_istio.sh
================================================
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#!/bin/bash

# installs standard single-cluster Istio on GKE + the Istio Stackdriver adapter

# Download Istio
WORKDIR="`pwd`"
ISTIO_VERSION="${ISTIO_VERSION:-1.5.2}"
echo "Downloading Istio ${ISTIO_VERSION}..."
curl -L https://git.io/getLatestIstio | ISTIO_VERSION=$ISTIO_VERSION sh -

# Prepare for install
kubectl create namespace istio-system

cd ./istio-${ISTIO_VERSION}/
kubectl create secret generic cacerts -n istio-system \
    --from-file=samples/certs/ca-cert.pem \
    --from-file=samples/certs/ca-key.pem \
    --from-file=samples/certs/root-cert.pem \
    --from-file=samples/certs/cert-chain.pem
cd ../

kubectl label namespace default istio-injection=enabled
kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole=cluster-admin \
    --user=$(gcloud config get-value core/account)


# install using operator config - https://istio.io/docs/setup/install/istioctl/#customizing-the-configuration
INSTALL_PROFILE=${INSTALL_YAML:-default.yaml}
./istio-${ISTIO_VERSION}/bin/istioctl manifest apply -f ${INSTALL_PROFILE}

================================================
FILE: internal-load-balancer/README.md
================================================
# Demo: Using a GCP Internal Load Balancer with Istio

This demo shows how to use an Internal Load Balancer (ILB) to connect Istio workloads running in Google Kubernetes Engine (GKE) with VM-based workloads in Google Compute Engine (GCE).

**Note**: [ILB for GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balancing) is currently in beta.

## How It Works

An [Internal Load Balancer (ILB)](https://cloud.google.com/load-balancing/docs/internal/) is a Google Cloud Platform (GCP) resource that exposes workloads (in GCE or GKE) to other workloads within the same region, and the same [Virtual Private Cloud](https://cloud.google.com/vpc/) (VPC) network. Using an ILB replaces the need to use a GKE external load balancer with a set of firewall rules.

You can [annotate Kubernetes Services](https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balancing#overview) directly to provision a GCP ILB, instead of an external network load balancer. However, Istio has its own [ILB Gateway](https://istio.io/docs/reference/config/installation-options/#gateways-options) for exposing Services inside the mesh.

The value of using the Istio ILB Gateway is that it's highly configurable -- you can, for instance, [define granular traffic rules](https://istio.io/docs/tasks/traffic-management/ingress/) to be applied for a specific service exposed via that ILB Gateway. Using an ILB Gateway replaces the need to use an external `Service type=LoadBalancer` with a set of firewall rules.

If Istio's ILB Gateway is enabled on install, it is annotated to provision its own ILB inside your GCP project. Note that a GCP Internal Load Balancer [is not a proxy](https://cloud.google.com/load-balancing/docs/internal/#how_ilb_works), but rather a resource that configures GCE instances directly to talk to "backends" within the same VPC network. In this case, the "backend" of the Istio ILB load balancer will be a GKE Instance Group — or, the set of VMs that comprise the GKE cluster.

In this demo, we will build the following architecture:

![arch-diagram](screenshots/architecture.png)

## Prerequisites

- A GCP project with billing enabled
- [Helm](https://helm.sh/docs/using_helm/#installing-helm) (CLI) installed on your local machine

## Create a GKE Cluster

1. **Export project ID:**

```
PROJECT_ID=<your-project-id>
```

2. **Create the cluster:**

```
gcloud container clusters create istio-ilb --project $PROJECT_ID --zone us-central1-c \
--machine-type "n1-standard-2" --disk-size "100" \
--num-nodes "4" --network "default" --async
```

3. Wait for the cluster to be `RUNNING`, by executing:

```
gcloud container clusters list --project $PROJECT_ID
```

4. Get credentials:

```
gcloud container clusters get-credentials istio-ilb --zone us-central1-c --project $PROJECT_ID
```

## Install Istio with ILB Gateway Enabled

1. Open the install profile in `manifests/install.yaml`. This is a default install profile with the ILB ingress gateway enabled in addition to the default, publicly-accessible `istio-ingressgateway`. Notice line 104:

```
      k8s:
        serviceAnnotations:
          cloud.google.com/load-balancer-type: "Internal"
```

Here, instead of provisioning this second Istio gateway with a public load balancer, we are telling GKE to instead provision an internal [GCP internal load balancer](https://cloud.google.com/load-balancing/docs/internal). This means that this gateway will only be accessible from inside the GCP virtual private cloud (VPC) - for instance, from a Google Compute Engine instance in the same GCP project.

2. Install Istio on the cluster. Clone this repository and navigate to the root `istio-samples` directory. Then, apply the install profile:

```
cd common/
INSTALL_YAML="../internal-load-balancer/manifests/install.yaml" ./install_istio.sh
```

3. Run `kubectl get pods -n istio-system`. You should see two gateway pods running: `istio-ilbgateway` and `istio-ingressgateway`.

```
NAME                                    READY   STATUS    RESTARTS
 AGE
grafana-556b649566-s2bj2                1/1     Running   0
 39s
istio-ilbgateway-7fb4b47dcc-x7zbc       1/1     Running   0
 43s
istio-ingressgateway-598796f4d9-gszfx   1/1     Running   0
 43s
istio-tracing-7cf5f46848-g47zt          1/1     Running   0
 39s
istiod-55fb557b7-ltfxj                  1/1     Running   0
 58s
kiali-6d54b8ccbc-v26ds                  1/1     Running   0
 39s
prometheus-5bd4c4679b-dbvsn             2/2     Running   0
 38s
```

4. Get the Kubernetes services corresponding to the two Istio Gateways. You should see two gateway services, both with an `EXTERNAL_IP` field. The `istio-ilbgateway` external IP is only "external" to its own VPC. **Note** - it may take several minutes to for the external IP to appear - in the meantime, you will see `<pending>` while the load balancers are provisioned.

```
$ kubectl get service -n istio-system | grep gateway

istio-ilbgateway            LoadBalancer   10.0.5.3      10.128.0.9      15011:30940/TCP,15010:32052/TCP,8060:32219/TCP,5353:30527/TCP,80:30694/TCP                                                   19m
istio-ingressgateway        LoadBalancer   10.0.2.236    34.70.166.247   15020:30267/TCP,80:32184/TCP,443:30578/TCP,15029:32296/TCP,15030:31735/TCP,15031:32750/TCP,15032:32506/TCP,15443:30743/TCP   19m
```


## Deploy the HelloServer application

HelloServer is a Python HTTP server that serves the `GET / ` endpoint, and prints `HelloWorld`. We'll also deploy a load generator (also Python) that will repeatedly send 10 Requests per Second (RPS) to `helloserver`.

```
cd ../internal-load-balancer/
kubectl apply -f ../sample-apps/helloserver/server/server.yaml
kubectl apply -f ../sample-apps/helloserver/loadgen/loadgen.yaml
```

## Explore the Kiali Dashboard

[Kiali](https://www.kiali.io/) is a web-based Istio dashboard for observing your Istio mesh topology. We installed Kiali already, with the rest of the Istio control plane.

1. Open the Kiali dashboard in a browser.

```
alias istioctl="../common/istio-1.5.2/bin/istioctl"
istioctl dashboard kiali &
```


2. Log in with the demo credentials: `admin/admin`.

3. navigate in the left sidebar to `Graph`, and view the Service Graph for the `default` Kubernetes namespace. This is the namespace into which we've deployed the `helloserver` application.

![service-graph](screenshots/default-svc-graph.png)

## Access HelloServer via ILB

Now that we can confirm that in-cluster workloads (like `loadgenerator`) can access `helloserver`, let's access `helloserver` from outside the GKE cluster, via the ILB gateway.

To do this, we'll create a GCE Instance in the same project / VPC. **Note**: we will create this VM in the same region as the GKE cluster. This is a prerequisite for GCP resource communication via ILB. Also notice that `--network=default` means we're creating the GCE VM in the same VPC network as the GKE cluster, which is also using the `default` network.

1. **Create a GCE instance.**

```
gcloud compute --project=$PROJECT_ID instances create gce-ilb --zone=us-central1-c --machine-type=n1-standard-2 --network=default
```


2. **Create a VirtualService and Gateway.**

If we want to send traffic from GCE to GKE, via the Istio ILB Gateway, we will have to expose HelloServer within GCP. This will be the same process as if we were exposing HelloServer to the public internet ([with the IngressGateway](https://istio.io/docs/tasks/traffic-management/ingress/#configuring-ingress-using-an-istio-gateway)). For this, we'll use an Istio `Gateway` resource, along with a `VirtualService`.

```
kubectl apply -f manifests/server-ilb.yaml
```

Because the Istio ILBGateway service is `type=LoadBalancer`, it gets an `EXTERNAL_IP`, but only "external" within our regional VPC network:

3. **Get the EXTERNAL_IP for istio-ilbgateway:**
```
kubectl get svc -n istio-system istio-ilbgateway
```

You should see something like:

```
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                                      AGE
istio-ilbgateway   LoadBalancer   10.67.240.220   10.150.0.7    15011:32390/TCP,15010:32626/TCP,8060:32429/TCP,5353:32066/TCP,80:32624/TCP   39m
```

Copy the `EXTERNAL_IP` to the clipboard.

4. **ssh into the GCE instance:**

```
gcloud compute ssh --project $PROJECT_ID  --zone "us-central1-c" gce-ilb
```

5. **Reach helloserver via the ILB gateway IP, at port 80:**

```
export EXTERNAL_IP="<your-external-ip"

curl http://${EXTERNAL_IP}:80
```

You should see:

```
Hello World! /
```

This request just went from your GCE instance, to the Istio ILB Gateway, then to the `hellosvc` Service inside the Istio mesh.

Notice that if you try to execute the same `curl` request on your local machine, you will time out -- this because the ILB Gateway is only exposed from within your GCP project's private VPC network.

Finally, re-open the Kiali service graph in the browser -- now notice how the ilb-gateway is also now serving traffic for `hellosvc`.

![service-graph](screenshots/ilb-graph.png)


🌟 **Well done** - you just exposed a GKE service via Istio's ILB Gateway!


## Cleanup

1. **Delete the GCE VM**:

```
gcloud compute --project=$PROJECT_ID instances delete gce-ilb --zone=us-central1-c --async
```

2. **Delete the GKE Cluster**:

```
gcloud container clusters delete istio-ilb --project $PROJECT_ID --zone us-central1-c --async
```


================================================
FILE: internal-load-balancer/manifests/install.yaml
================================================
# ILB config source - https://github.com/istio/istio/issues/20033
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  addonComponents:
    grafana:
      enabled: true
      k8s:
        replicaCount: 1
    istiocoredns:
      enabled: false
    kiali:
      enabled: true
      k8s:
        replicaCount: 1
    prometheus:
      enabled: true
      k8s:
        replicaCount: 1
    tracing:
      enabled: true
  components:
    base:
      enabled: true
    citadel:
      enabled: false
      k8s:
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    cni:
      enabled: false
    egressGateways:
    - enabled: false
      k8s:
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ingressgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
      name: istio-egressgateway
    galley:
      enabled: false
      k8s:
        replicaCount: 1
        resources:
          requests:
            cpu: 100m
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
      k8s:
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ingressgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    - name: istio-ilbgateway
      enabled: true
      k8s:
        serviceAnnotations:
          cloud.google.com/load-balancer-type: "Internal"
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ilbgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        service:
          ports:
          - name: grpc-pilot-mtls
            port: 15011
          - name: grpc-pilot
            port: 15010
          - name: tcp-citadel-grpc-tls
            port: 8060
            targetPort: 8060
          - name: tcp-dns
            port: 5353
          - name: http
            port: 80
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
        overlays:
          - kind: HorizontalPodAutoscaler
            name: istio-ilbgateway
            patches:
              - path: metadata.labels.app
                value: istio-ilbgateway
              - path: metadata.labels.istio
                value: ilbgateway
              - path: spec.scaleTargetRef.name
                value: istio-ilbgateway
          - kind: Deployment
            name: istio-ilbgateway
            patches:
              - path: metadata.labels.app
                value: istio-ilbgateway
              - path: metadata.labels.istio
                value: ilbgateway
              - path: spec.selector.matchLabels.app
                value: istio-ilbgateway
              - path: spec.selector.matchLabels.istio
                value: ilbgateway
              - path: spec.template.metadata.labels.app
                value: istio-ilbgateway
              - path: spec.template.metadata.labels.istio
                value: ilbgateway
          - kind: Service
            name: istio-ilbgateway
            patches:
              - path: metadata.labels.app
                value: istio-ilbgateway
              - path: metadata.labels.istio
                value: ilbgateway
              - path: spec.selector.app
                value: istio-ilbgateway
              - path: spec.selector.istio
                value: ilbgateway
    nodeAgent:
      enabled: false
    pilot:
      enabled: true
      k8s:
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 5
        resources:
          requests:
            cpu: 500m
            memory: 2048Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    policy:
      enabled: false
      k8s:
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-policy
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    sidecarInjector:
      enabled: false
      k8s:
        replicaCount: 1
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    telemetry:
      enabled: false
      k8s:
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: GOMAXPROCS
          value: "6"
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-telemetry
        replicaCount: 1
        resources:
          limits:
            cpu: 4800m
            memory: 4G
          requests:
            cpu: 1000m
            memory: 1G
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
  hub: docker.io/istio
  tag: 1.5.1
  values:
    clusterResources: true
    galley:
      enableAnalysis: false
      image: galley
    gateways:
      istio-egressgateway:
        autoscaleEnabled: true
        env:
          ISTIO_META_ROUTER_MODE: sni-dnat
        ports:
        - name: http2
          port: 80
        - name: https
          port: 443
        - name: tls
          port: 15443
          targetPort: 15443
        secretVolumes:
        - mountPath: /etc/istio/egressgateway-certs
          name: egressgateway-certs
          secretName: istio-egressgateway-certs
        - mountPath: /etc/istio/egressgateway-ca-certs
          name: egressgateway-ca-certs
          secretName: istio-egressgateway-ca-certs
        type: ClusterIP
      istio-ingressgateway:
        applicationPorts: ""
        autoscaleEnabled: true
        debug: info
        domain: ""
        env:
          ISTIO_META_ROUTER_MODE: sni-dnat
        meshExpansionPorts:
        - name: tcp-pilot-grpc-tls
          port: 15011
          targetPort: 15011
        - name: tcp-citadel-grpc-tls
          port: 8060
          targetPort: 8060
        - name: tcp-dns-tls
          port: 853
          targetPort: 853
        ports:
        - name: status-port
          port: 15020
          targetPort: 15020
        - name: http2
          port: 80
          targetPort: 80
        - name: https
          port: 443
        - name: kiali
          port: 15029
          targetPort: 15029
        - name: prometheus
          port: 15030
          targetPort: 15030
        - name: grafana
          port: 15031
          targetPort: 15031
        - name: tracing
          port: 15032
          targetPort: 15032
        - name: tls
          port: 15443
          targetPort: 15443
        sds:
          enabled: false
          image: node-agent-k8s
          resources:
            limits:
              cpu: 2000m
              memory: 1024Mi
            requests:
              cpu: 100m
              memory: 128Mi
        secretVolumes:
        - mountPath: /etc/istio/ingressgateway-certs
          name: ingressgateway-certs
          secretName: istio-ingressgateway-certs
        - mountPath: /etc/istio/ingressgateway-ca-certs
          name: ingressgateway-ca-certs
          secretName: istio-ingressgateway-ca-certs
        type: LoadBalancer
        zvpn:
          enabled: false
          suffix: global
    global:
      arch:
        amd64: 2
        ppc64le: 2
        s390x: 2
      certificates: []
      configValidation: true
      controlPlaneSecurityEnabled: true
      defaultNodeSelector: {}
      defaultPodDisruptionBudget:
        enabled: true
      defaultResources:
        requests:
          cpu: 10m
      disablePolicyChecks: true
      enableHelmTest: false
      enableTracing: true
      imagePullPolicy: IfNotPresent
      imagePullSecrets: []
      istioNamespace: istio-system
      istiod:
        enabled: true
      jwtPolicy: third-party-jwt
      k8sIngress:
        enableHttps: false
        enabled: false
        gatewayName: ingressgateway
      localityLbSetting:
        enabled: true
      logAsJson: false
      logging:
        level: default:info
      meshExpansion:
        enabled: false
        useILB: false
      meshNetworks: {}
      mountMtlsCerts: false
      mtls:
        auto: true
        enabled: false
      multiCluster:
        clusterName: ""
        enabled: false
      network: ""
      omitSidecarInjectorConfigMap: false
      oneNamespace: false
      operatorManageWebhooks: false
      outboundTrafficPolicy:
        mode: ALLOW_ANY
      pilotCertProvider: istiod
      policyCheckFailOpen: false
      priorityClassName: ""
      proxy:
        accessLogEncoding: TEXT
        accessLogFile: "/dev/stdout"
        accessLogFormat: ""
        autoInject: enabled
        clusterDomain: cluster.local
        componentLogLevel: misc:error
        concurrency: 2
        dnsRefreshRate: 300s
        enableCoreDump: false
        envoyAccessLogService:
          enabled: false
        envoyMetricsService:
          enabled: false
          tcpKeepalive:
            interval: 10s
            probes: 3
            time: 10s
          tlsSettings:
            mode: DISABLE
            subjectAltNames: []
        envoyStatsd:
          enabled: false
        excludeIPRanges: ""
        excludeInboundPorts: ""
        excludeOutboundPorts: ""
        image: proxyv2
        includeIPRanges: '*'
        includeInboundPorts: '*'
        kubevirtInterfaces: ""
        logLevel: warning
        privileged: false
        protocolDetectionTimeout: 100ms
        readinessFailureThreshold: 30
        readinessInitialDelaySeconds: 1
        readinessPeriodSeconds: 2
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        statusPort: 15020
        tracer: zipkin
      proxy_init:
        image: proxyv2
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
          requests:
            cpu: 10m
            memory: 10Mi
      sds:
        enabled: false
        token:
          aud: istio-ca
        udsPath: ""
      sts:
        servicePort: 0
      tracer:
        datadog:
          address: $(HOST_IP):8126
        lightstep:
          accessToken: ""
          address: ""
          cacertPath: ""
          secure: true
        stackdriver:
          debug: false
          maxNumberOfAnnotations: 200
          maxNumberOfAttributes: 200
          maxNumberOfMessageEvents: 200
        zipkin:
          address: ""
      trustDomain: cluster.local
      useMCP: false
    grafana:
      accessMode: ReadWriteMany
      contextPath: /grafana
      dashboardProviders:
        dashboardproviders.yaml:
          apiVersion: 1
          providers:
          - disableDeletion: false
            folder: istio
            name: istio
            options:
              path: /var/lib/grafana/dashboards/istio
            orgId: 1
            type: file
      datasources:
        datasources.yaml:
          apiVersion: 1
      env: {}
      envSecrets: {}
      image:
        repository: grafana/grafana
        tag: 6.5.2
      ingress:
        enabled: false
        hosts:
        - grafana.local
      nodeSelector: {}
      persist: false
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        enabled: false
        passphraseKey: passphrase
        secretName: grafana
        usernameKey: username
      service:
        annotations: {}
        externalPort: 3000
        name: http
        type: ClusterIP
      storageClassName: ""
      tolerations: []
    istiocoredns:
      coreDNSImage: coredns/coredns
      coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1
      coreDNSTag: 1.6.2
    kiali:
      contextPath: /kiali
      createDemoSecret: true
      dashboard:
        grafanaInClusterURL: http://grafana:3000
        jaegerInClusterURL: http://tracing/jaeger
        passphraseKey: passphrase
        secretName: kiali
        usernameKey: username
        viewOnlyMode: false
      hub: quay.io/kiali
      ingress:
        enabled: false
        hosts:
        - kiali.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        cert_file: /kiali-cert/cert-chain.pem
        enabled: false
        private_key_file: /kiali-cert/key.pem
      tag: v1.14
    mixer:
      adapters:
        kubernetesenv:
          enabled: true
        prometheus:
          enabled: true
          metricsExpiryDuration: 10m
        stackdriver:
          auth:
            apiKey: ""
            appCredentials: false
            serviceAccountPath: ""
          enabled: false
          tracer:
            enabled: false
            sampleProbability: 1
        stdio:
          enabled: false
          outputAsJson: false
        useAdapterCRDs: false
      policy:
        adapters:
          kubernetesenv:
            enabled: true
          useAdapterCRDs: false
        autoscaleEnabled: true
        image: mixer
        sessionAffinityEnabled: false
      telemetry:
        autoscaleEnabled: true
        env:
          GOMAXPROCS: "6"
        image: mixer
        loadshedding:
          latencyThreshold: 100ms
          mode: enforce
        nodeSelector: {}
        podAntiAffinityLabelSelector: []
        podAntiAffinityTermLabelSelector: []
        replicaCount: 1
        reportBatchMaxEntries: 100
        reportBatchMaxTime: 1s
        sessionAffinityEnabled: false
        tolerations: []
    nodeagent:
      image: node-agent-k8s
    pilot:
      appNamespaces: []
      autoscaleEnabled: true
      autoscaleMax: 5
      autoscaleMin: 1
      configMap: true
      configNamespace: istio-config
      cpu:
        targetAverageUtilization: 80
      enableProtocolSniffingForInbound: false
      enableProtocolSniffingForOutbound: true
      env: {}
      image: pilot
      ingress:
        ingressClass: istio
        ingressControllerMode: STRICT
        ingressService: istio-ingressgateway
      keepaliveMaxServerConnectionAge: 30m
      meshNetworks:
        networks: {}
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      policy:
        enabled: false
      replicaCount: 1
      tolerations: []
      traceSampling: 1
    prometheus:
      contextPath: /prometheus
      hub: docker.io/prom
      ingress:
        enabled: false
        hosts:
        - prometheus.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      provisionPrometheusCert: true
      retention: 6h
      scrapeInterval: 15s
      security:
        enabled: true
      tag: v2.15.1
      tolerations: []
    security:
      dnsCerts:
        istio-pilot-service-account.istio-control: istio-pilot.istio-control
      enableNamespacesByDefault: true
      image: citadel
      selfSigned: true
    sidecarInjectorWebhook:
      enableNamespacesByDefault: false
      image: sidecar_injector
      injectLabel: istio-injection
      objectSelector:
        autoInject: true
        enabled: false
      rewriteAppHTTPProbe: false
      selfSigned: false
    telemetry:
      enabled: true
      v1:
        enabled: false
      v2:
        enabled: true
        prometheus:
          enabled: true
        stackdriver:
          configOverride: {}
          enabled: true
          logging: true
          monitoring: true
          topology: true
    tracing:
      ingress:
        enabled: false
      jaeger:
        accessMode: ReadWriteMany
        hub: docker.io/jaegertracing
        memory:
          max_traces: 50000
        persist: false
        spanStorageType: badger
        storageClassName: ""
        tag: "1.16"
      nodeSelector: {}
      opencensus:
        exporters:
          stackdriver:
            enable_tracing: true
        hub: docker.io/omnition
        resources:
          limits:
            cpu: "1"
            memory: 2Gi
          requests:
            cpu: 200m
            memory: 400Mi
        tag: 0.1.9
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      provider: jaeger
      service:
        annotations: {}
        externalPort: 9411
        name: http-query
        type: ClusterIP
      zipkin:
        hub: docker.io/openzipkin
        javaOptsHeap: 700
        maxSpans: 500000
        node:
          cpus: 2
        probeStartupDelay: 200
        queryPort: 9411
        resources:
          limits:
            cpu: 300m
            memory: 900Mi
          requests:
            cpu: 150m
            memory: 900Mi
        tag: 2.14.2
    version: ""



================================================
FILE: internal-load-balancer/manifests/server-ilb.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_internal_load_balancer_manifests_gateway_hello_ilb_gateway]
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: hello-ilb-gateway
spec:
  selector:
    istio: ilbgateway
  servers:
  - hosts:
    - '*'
    port:
      name: http
      number: 80
      protocol: HTTP
# [END istio_internal_load_balancer_manifests_gateway_hello_ilb_gateway]
---
# [START istio_internal_load_balancer_manifests_virtualservice_hellosvc_vs]
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: hellosvc-vs
spec:
  gateways:
  - hello-ilb-gateway
  hosts:
  - '*'
  http:
  - route:
    - destination:
        host: hellosvc
        port:
          number: 80
# [END istio_internal_load_balancer_manifests_virtualservice_hellosvc_vs]
---


================================================
FILE: istio-canary-gke/README.md
================================================
# ProductCatalog Canary Deployment (GKE / Istio)

This demo accompanies [a GCP Blog Post](https://cloud.google.com/blog/products/networking/advanced-application-deployments-and-traffic-management-with-istio-on-gke) on managing application deployments with Istio and
Stackdriver.

## Introduction

In this example, we will learn how to use [Istio’s](https://istio.io/) [Traffic Splitting](https://istio.io/docs/concepts/traffic-management/#splitting-traffic-between-versions) feature to perform a Canary deployment on [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/).

In this sample, `productcatalogservice-v2` introduces a 3-second
[latency](https://github.com/GoogleCloudPlatform/microservices-demo/tree/master/src/productcatalogservice#latency-injection) into all server requests. We’ll show how to use Stackdriver and Istio together to
view the latency difference between the existing `productcatalog` deployment and the
slower v2 deployment.

  - [Setup](#setup)
  - [Deploy the Sample App](#deploy-the-sample-app)
  - [Deploy ProductCatalog v2](#deploy-productcatalog-v2)
  - [Observe Latency with Stackdriver](#observe-latency-with-stackdriver)
  - [Rollback](#rollback)
  - [Cleanup](#cleanup)
  - [Learn More](#learn-more)

## Setup

[Google Cloud Shell](https://cloud.google.com/shell/docs/) is a browser-based terminal that Google provides to interact with your GCP resources. It is backed by a free Compute Engine instance that comes with many useful tools already installed, including everything required to run this demo.

Click the button below to open the demo instructions in your Cloud Shell:

[![Open in Cloud Shell](http://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/open?git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2Fistio-samples&page=editor&tutorial=istio-canary-gke/README.md)


## Create a GKE Cluster

1. From Cloud Shell, enable the Kubernetes Engine API.

```
gcloud services enable container.googleapis.com
```

2. Create a GKE cluster:

```
gcloud beta container clusters create istio-canary \
    --zone=us-central1-f \
    --machine-type=n1-standard-2 \
    --num-nodes=4
```

3. Change into the Istio install directory from the root of this repository.
```
cd common/
```

4. Install Istio on the cluster:

```
./install_istio.sh
```

5. Once the cluster is ready, ensure that Istio is running:

```
$ kubectl get pods -n istio-system

NAME                                   READY   STATUS    RESTARTS   AGE
grafana-556b649566-fw67z               1/1     Running   0          5m24s
istio-ingressgateway-fc6c9d9df-nmndg   1/1     Running   0          5m30s
istio-tracing-7cf5f46848-qksxq         1/1     Running   0          5m24s
istiod-7b5d6db6b6-b457p                1/1     Running   0          5m48s
kiali-b4b5b4fb8-hwm42                  1/1     Running   0          5m23s
prometheus-558b665bb7-5v647            2/2     Running   0          5m23s
```

## Deploy the Sample App

1. Deploy the [microservices-demo](https://github.com/GoogleCloudPlatform/microservices-demo) application, and add a `version=v1` label to the `productcatalog` deployment

```
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/istio-manifests.yaml
kubectl delete serviceentry allow-egress-google-metadata
kubectl delete serviceentry allow-egress-googleapis
kubectl patch deployments/productcatalogservice -p '{"spec":{"template":{"metadata":{"labels":{"version":"v1"}}}}}'
```

2. Using `kubectl get pods`, verify that all pods are `Running` and `Ready`.

At this point, ProductCatalog v1 is deployed to the cluster, along with the rest of the
demo microservices. You can reach the Hipstershop frontend at the `EXTERNAL_IP` address
output for this command:

```
kubectl get svc -n istio-system istio-ingressgateway
```

## Deploy ProductCatalog v2

1. `cd` into the example directory.

```
cd istio-canary-gke/
```

2. Create an Istio [DestinationRule](https://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationRule) for `productcatalogservice`.

```
kubectl apply -f canary/destinationrule.yaml
```

3. Deploy `productcatalog` v2.
```
kubectl apply -f canary/productcatalog-v2.yaml
```

4. Using `kubectl get pods`, verify that the `v2` pod is Running.
```
productcatalogservice-v2-79459dfdff-6qdh4   2/2       Running   0          1m
```

5. Create an Istio [VirtualService](https://istio.io/docs/reference/config/istio.networking.v1alpha3/#VirtualService) to split incoming `productcatalog` traffic between v1 (75%) and v2 (25%).
```
kubectl apply -f canary/vs-split-traffic.yaml
```

6. In a web browser, navigate again to the hipstershop frontend.
7. Refresh the homepage a few times. You should notice that periodically, the frontend is
   slower to load. Let's explore ProductCatalog's latency with Stackdriver.


## View traffic splitting in Kiali

1. Open the Kiali dashboard.

```
istioctl dashboard kiali &
```

2. Navigate to Service Graph > namespace: `default`

3. Select "Versioned App Graph."
4. In the service graph, zoom in on `productcatalogservice`. You should see that approximately 25% of productcatalog requests are going to `v2`.

![kiali](screenshots/kiali.png)

## Observe Latency with Stackdriver

1. Navigate to [Stackdriver Monitoring](https://app.google.stackdriver.com).
2. Create a Stackdriver Workspace for your GCP project
   ([instructions](https://cloud.google.com/monitoring/workspaces/guide#single-project-ws)).
3. From your new Stackdriver Workspace, navigate to **Resources > Metrics Explorer.** in the
   left sidebar.

![stackdriver sidebar](screenshots/stackdriver-sidebar.png)


4. From Metrics Explorer, enter the following parameters on the left side of the window:
	- **Resource type**: Kubernetes Container
	- **Metric**: Server Response Latencies (`istio.io/service/server/response_latencies`)
	- **Group by**: `destination_workload_name`
	- **Aggregator**: 50th percentile

5. In the menubar of the chart on the right, choose the **Line** type.
6. Once the latency chart renders, you should see `productcatalog-v2` as an outlier, with
    mean latencies hovering at 3 seconds. This is the value of `EXTRA_LATENCY` we injected into v2.

![metrics explorer](screenshots/metrics-explorer.png)

You’ll also notice that other services (such as `frontend`) have an irregular latency spike. This is because the [frontend relies on](https://github.com/GoogleCloudPlatform/microservices-demo#service-architecture) ProductCatalog, for which 25% of requests are routing through the slower `v2` deployment.

![v2 latency](screenshots/v2-latency.png)

## Rollback

1. Return 100% of `productcatalog` traffic to `v1`:
```
kubectl apply -f canary/rollback.yaml
```
2. Finally, remove `v2`:
```
kubectl delete -f canary/productcatalog-v2.yaml
```

## Cleanup

To avoid incurring additional billing costs, delete the GKE cluster.

```
gcloud container clusters delete istio-canary --zone us-central1-f
```

## Learn More

- [Incremental Istio Part 1, Traffic
  Management](https://istio.io/blog/2018/incremental-traffic-management/) (Istio blog)
- [Canary Deployments using Istio](https://istio.io/blog/2017/0.1-canary/)  (Istio blog)
- [Drilling down into Stackdriver Service
  Monitoring](https://cloud.google.com/blog/products/gcp/drilling-down-into-stackdriver-service-monitoring)
  (GCP blog)


================================================
FILE: istio-canary-gke/canary/destinationrule.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_istio_canary_gke_canary_destinationrule_productcatalogservice]
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: productcatalogservice
spec:
  host: productcatalogservice
  subsets:
  - labels:
      version: v1
    name: v1
  - labels:
      version: v2
    name: v2
# [END istio_istio_canary_gke_canary_destinationrule_productcatalogservice]
---


================================================
FILE: istio-canary-gke/canary/productcatalog-v2.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_istio_canary_gke_canary_deployment_productcatalogservice_v2]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productcatalogservice-v2
spec:
  selector:
    matchLabels:
      app: productcatalogservice
  template:
    metadata:
      labels:
        app: productcatalogservice
        version: v2
    spec:
      containers:
      - env:
        - name: PORT
          value: '3550'
        - name: EXTRA_LATENCY
          value: 3s
        image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:3550
        name: server
        ports:
        - containerPort: 3550
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:3550
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
      terminationGracePeriodSeconds: 5
# [END istio_istio_canary_gke_canary_deployment_productcatalogservice_v2]
---


================================================
FILE: istio-canary-gke/canary/rollback.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_istio_canary_gke_canary_virtualservice_productcatalogservice]
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productcatalogservice
spec:
  hosts:
  - productcatalogservice
  http:
  - route:
    - destination:
        host: productcatalogservice
        subset: v1
# [END istio_istio_canary_gke_canary_virtualservice_productcatalogservice]
---


================================================
FILE: istio-canary-gke/canary/vs-split-traffic.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_istio_canary_gke_canary_virtualservice_productcatalogservice2]
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productcatalogservice
spec:
  hosts:
  - productcatalogservice
  http:
  - route:
    - destination:
        host: productcatalogservice
        subset: v1
      weight: 75
    - destination:
        host: productcatalogservice
        subset: v2
      weight: 25
# [END istio_istio_canary_gke_canary_virtualservice_productcatalogservice2]
---


================================================
FILE: istio-stackdriver/README.md
================================================
# Istio and Stackdriver

This example demonstrates the ways you can use [Stackdriver](https://cloud.google.com/stackdriver/) to gain insights into and debug microservices deployments running on GKE with [Istio's telemetry support](https://istio.io/docs/concepts/policies-and-telemetry/).

We'll deploy the Hipstershop sample application along with an updated service that introduces a 3-second latency into all requests. Then we'll create Stackdriver Monitoring dashboards to dig into key metrics like cluster and service health. Next, we'll use Stackdriver Trace to identify high latency requests. Finally, we'll dig into service output using Stackdriver Logging.

### Contents
- [Istio and Stackdriver](#istio-and-stackdriver)
    - [Contents](#contents)
  - [Setup](#setup)
    - [Create a GKE cluster](#create-a-gke-cluster)
    - [Deploy the sample application](#deploy-the-sample-application)
    - [Deploy a high latency service](#deploy-a-high-latency-service)
  - [Monitoring](#monitoring)
    - [Create a monitoring dashboard](#create-a-monitoring-dashboard)
    - [Examine service and cluster health](#examine-service-and-cluster-health)
  - [Tracing](#tracing)
    - [Review trace output](#review-trace-output)
    - [Identify high latency requests](#identify-high-latency-requests)
  - [Logging](#logging)
    - [Examine service logs](#examine-service-logs)
  - [Cleanup](#cleanup)
  - [Learn more](#learn-more)

## Setup
1. Clone the repo and change into the demo directory.

```
git clone https://github.com/GoogleCloudPlatform/istio-samples
cd istio-samples/common
```

### Create a GKE cluster

1. From Cloud Shell, **enable the Kubernetes Engine API**.

```
gcloud services enable container.googleapis.com
```

2. **Create a GKE cluster** using [Istio on GKE](https://cloud.google.com/istio/docs/istio-on-gke/overview). This add-on will provision your GKE cluster with Istio.

```
gcloud beta container clusters create istio-stackdriver-demo \
    --zone=us-central1-f \
    --machine-type=n1-standard-2 \
    --num-nodes=4
```

3. **Install Istio** on the cluster.

```
./install_istio.sh
```

4. Wait for all Istio pods to be `Running` or `Completed`.
```
kubectl get pods -n istio-system
```

*Note*: This Istio installation uses the default `PERMISSIVE` [mesh-wide security
option](https://istio.io/docs/reference/config/installation-options/#global-options).
This means that all services in the cluster will send unencrypted traffic by default.

### Deploy the sample application

1. Apply the sample app manifests to the cluster:

```
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/istio-manifests.yaml
kubectl patch deployments/productcatalogservice -p '{"spec":{"template":{"metadata":{"labels":{"version":"v1"}}}}}'
```

2. Run `kubectl get pods -n default` to ensure that all pods are `Running` and `Ready`.

```
NAME                                     READY     STATUS    RESTARTS   AGE
adservice-76b5c7bd6b-zsqb8               2/2       Running   0          1m
checkoutservice-86f5c7679c-8ghs8         2/2       Running   0          1m
currencyservice-5749fd7c6d-lv6hj         2/2       Running   0          1m
emailservice-6674bf75c5-qtnd8            2/2       Running   0          1m
frontend-56fdfb866c-tvdm6                2/2       Running   0          1m
loadgenerator-b64fcb8bc-m6nd2            2/2       Running   0          1m
paymentservice-67c6696c54-tgnc5          2/2       Running   0          1m
productcatalogservice-76c6454c57-9zj2v   2/2       Running   0          1m
recommendationservice-78c7676bfb-xqtp6   2/2       Running   0          1m
shippingservice-7bc4bc75bb-kzfrb         2/2       Running   0          1m
```

*Note*: Each pod has 2 containers, because each pod now has the injected Istio sidecar proxy.

### Deploy a high latency service

1. Create an Istio [DestinationRule](https://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationRule) for `productcatalogservice`.

```
cd ../istio-canary-gke/
kubectl apply -f canary/destinationrule.yaml
```

2. Deploy `productcatalogservice` v2 which introduces a 3-second latency into all server requests.
```
kubectl apply -f canary/productcatalog-v2.yaml
```

3. Using `kubectl get pods`, verify that the `v2` pod is Running.
```
productcatalogservice-v2-79459dfdff-6qdh4   2/2       Running   0          1m
```

4. Create an Istio VirtualService to split incoming `productcatalogservice` traffic between v1 (75%) and v2 (25%).
```
kubectl apply -f canary/vs-split-traffic.yaml
```

## Monitoring

Now that we've deployed Hipstershop, along with an updated service that introduces higher latency to server requests, let's dig into how we can surface that latency via monitoring. Hipstershop includes a built-in load generator that issues requests across a number of services so after a few minutes you should start to see traffic hitting the deplyoment. The following steps will show you how to create a basic dashboard that let's you monitor some metrics for service and cluster health.

### Create a monitoring dashboard

1. Head over to [Stackdriver Monitoring](https://app.google.stackdriver.com/) and [create a Stackdriver Workspace](https://cloud.google.com/monitoring/workspaces/guide#single-project-ws).

2. Navigate to **Dashboards > Create Dashboard** in the left sidebar.

3. In the new Dashboard, click **Add Chart** and the following metric:

* **Metric**: Server Response Latencies (`istio.io/service/server/response_latencies`)
* **Group By**: `destination_workload_name`
* **Aligner**: 50th percentile
* **Reducer**: mean
* **Alignment Period**: 1 minute
* **Type**: Line

4. Click **Save Chart** in the upper right corner and repeat the process by adding new charts for each of the following metrics:

**Client Roundtrip Latencies**
* **Metric**: Client Roundtrip Latencies (`istio.io/service/client/roundtrip_latencies`)
* **Group By**: `destination_workload_name`
* **Aligner**: 50th percentile
* **Reducer**: mean
* **Alignment Period**: 1 minute
* **Type**: Line

**CPU Utilization**
* **Metric**: CPU Utilization (`compute.googleapis.com/instance/cpu/utilization`)
* **Resource Type**: GCE VM Instance
* **Filter**: `goog-gke-node` = ""
* **Aligner**: mean
* **Reducer**: none
* **Alignment Period**: 1 minute
* **Type**: Line

**Memory Usage**
* **Metric**: Memory Usage (`kubernetes.io/node/memory/used_bytes`)
* **Group By**: `node_name`
* **Aligner**: mean
* **Reducer**: mean
* **Alignment Period**: 1 minute
* **Type**: Line

5. After the metrics have been added, you will have a Dashboard that looks similar to the following:

![stackdriver-dashboard](screenshots/stackdriver-dashboard.png)

### Examine service and cluster health

1. Now that you have a functioning Dashboard and some load has been generated, take a look at **Server Response Latencies** and **Client Roundtrip Latencies** charts. You will see there are some clear outliers, specifically the `productcatalog` service. You will also see other related services (such as `frontend`) also have latency spikes. This is because the [frontend relies on](https://github.com/GoogleCloudPlatform/microservices-demo#service-architecture) ProductCatalog, for which 25% of requests are routing through the slower `v2` deployment.

![v2 latency](screenshots/v2-latency.png)

Also take a look at the **CPU Utilization** and **Memory Usage** charts and you'll notice that there are no significant outliers there. As expected, the issue isn't with the GKE cluster itself, it's due to the fact that we specifically deployed a service that introduced a 3-second per request latency.

## Tracing

Now that the high latency service (`productcatalogservice`) has been identified, we can use [Stackdriver Trace](https://cloud.google.com/trace/) to dig in and examine the latency impact it's having across the entire deployment.

### Review trace output

1. Open [Stackdriver Trace](https://console.cloud.google.com/traces) and you will see the tracing overview.

The left side of the **Overview** contains
* **Recent traces** captured
* **Most frequent URIs** requested
* **Most frequent RPCs** called

And on the right you'll see automated analysis reports. These reports are generated by the system and correspond to some of the recent and/or high frequency requests/calls.

![trace overview](screenshots/trace-overview.png)

2. From the left navigation, head over to the **Trace List** and you'll see a chart of all requests plotted against latency along with a table of the most recent 1000 traces.

![trace list](screenshots/trace-list.png)

### Identify high latency requests

1. From the **Trace List** chat, select a high latency outlier and you'll see a **Timeline** and **Summary** appear below.

![trace selected](screenshots/trace-selected.png)

2. The timeline shows an initial request and the subsequent requests it generated. In the example below, you can see that requesting the URL `/product/L9ECAV7KIM` took about 12.1s, primarily due to the subsequent requests to the `productcatalogservice` (which has an extra 3s of latency added to each request).

![trace timeline](screenshots/trace-timeline.png)

3. The **Summary** table to the right aggregates all of the outbound RPC requests and their total duration, along with additional metadata about the initial request itself.

![trace summary](screenshots/trace-summary.png)

## Logging

At this point, we've been able to
- Identify a high latency service `productcatalogservice` using Stackdriver Monitoring
- Examine the impact that service is having by digging through request traces using Stackdriver Trace

The final step is to look at the logs generated by our services to see if there's any additional debug information we can capture. Using [Stackdriver Logging](https://cloud.google.com/logging/) we can examine individual service logs from our deployment.

### Examine service logs

1. Open [Stackdriver Logging](https://console.cloud.google.com/logs/viewer) and you'll see the logs viewer.

![logs viewer](screenshots/logs-viewer.png)

2. Using the **Filter** field and controls, you can select which logs you want to view. In the example below we used the following filter:
- **Resource**: Kubernetes Container
- **Cluster Name**: istio-stackdriver-demo
- **Namespace**: default
- **Container Name**: server

![logs filter](screenshots/logs-filter.png)

*Note*: In our example, we manually injected the latency into `productcatalogservice-v2` so these example logs won't be of much help.

## Cleanup

Once you're all done, delete the GKE cluster:
```
gcloud container clusters delete istio-stackdriver-demo
```

## Learn more

- [Istio Policies and Telemetry](https://istio.io/docs/concepts/policies-and-telemetry/)
- [Istio In-Depth Telemetry](https://istio.io/docs/examples/telemetry/)
- [Drilling down into Stackdriver Service Monitoring](https://cloud.google.com/blog/products/gcp/drilling-down-into-stackdriver-service-monitoring) (GCP blog)

================================================
FILE: mesh-expansion-gce/README.md
================================================
# Demo: Integrating a Google Compute Engine VM with Istio

This demo shows how to connect a Google Compute Engine virtual machine to an Istio service
mesh running in Google Kubernetes Engine.

This example is relevant if you're running an application outside
of Kubernetes, but still want to enjoy the full benefits of Istio for that service.

We will use the [Hipstershop](https://github.com/GoogleCloudPlatform/microservices-demo) sample app for this demo, with the following topology:

![screenshot](screenshots/topology.png)

Here, the `productcatalog` service will be our "monolith" running in a VM outside of
Kubernetes. For demonstration purposes, we'll run productcatalog in a raw Docker container
inside the VM, then integrate it with the rest of the in-mesh services running in GKE.

## Prerequisites

- A GCP project with billing enabled
- gcloud
- kubectl


## GCP Setup

For this demo, the GCE VM and the GKE cluster will live in the same GCP project. Set an
environment variable for your project ID.


```
export PROJECT_ID=<your-project-id>
```

## Create a GKE Cluster

Create a 4-node GKE cluster named `mesh-exp-gke`:

```
./scripts/1-create-cluster.sh
```

Wait for the GKE cluster to be `RUNNING` -

```
gcloud container clusters list
```

Connect to the cluster:

```
gcloud container clusters get-credentials mesh-exp-gke --zone us-central1-b --project $PROJECT_ID
```


## Create a GCE Instance

This script will create a Ubuntu GCE instance in your GCP Project. The VM is named `istio-gce`.

```
./scripts/2-create-vm.sh
```

## Install Istio on the cluster

```
./scripts/3-install-istio.sh
```


## Deploy the rest of the sample application to GKE

This step deploys all the services expect `productcatalog` to the GKE cluster, in the Istio-injected `default` namespace.

```
./scripts/4-deploy-hipstershop.sh
```

## Prepare the cluster for the VM.

```
./scripts/5-prep-cluster.sh
```

This step generates a cluster.env file containing the Istio service CIDR (pod IP ranges for your cluster) and the inbound ports - since productcatalog will listen on grpc port `3550` on the VM, we specify port `3550` for the VM proxy to intercept.

This step also creates client certificate files that we'll send to the VM. In the end, your `cluster.env` file should look like this:

```
ISTIO_SERVICE_CIDR=10.87.0.0/20

ISTIO_INBOUND_PORTS=3550,8080
```

## Set up the VM for Istio.

```
./scripts/6-prep-vm.sh
```

This script does the following:
- Sends the certs and `cluster.env` file we just created to the VM, via `scp`
- Logs into the VM via `ssh`
- From the VM, installs the Istio sidecar proxy and updates `/etc/hosts` so that the VM can reach istiod running on the GKE cluster
- Installs Docker
- Runs the `productcatalogservice` on the VM, as a plain Docker container

## Add productcatalog to the mesh

```
./scripts/7-add-to-mesh.sh
```

This step uses the `istioctl add-to-mesh` command to generate a ServiceEntry and headless Service corresponding to the VM `productcatalogservice`. This allows the frontend running as a GKE pod to resolve the `productcatalogservice` DNS to the GCE VM, via Istio.

## Start the Istio proxy on the VM

```
./scripts/8-start-vm-istio.sh
```

## View the service topology

```
alias istioctl="../common/istio-1.5.2/bin/istioctl"
istioctl dashboard kiali &
```

Open Service Graph > click the "default" namespace. You should see traffic moving to the `meshexpansion-productcatalogservice` ServiceEntry, corresponding to the VM.

![screenshots/kiali.png](screenshots/kiali.png)

## Open the frontend in a browser

Get the external IP address of the Istio ingressgateway. Navigate to that IP address in a web browser.

```
kubectl get svc -n istio-system istio-ingressgateway | awk '{print $4}'
```

You should see the sample app frontend with a list of products, fetched from `productcatalog` running on the VM.

![screenshots/onlineboutique.png](screenshots/onlineboutique.png)

## Clean up

To delete the resources used in this sample:

```
gcloud compute firewall-rules delete k8s-to-istio-gce
gcloud compute instances --project $PROJECT_ID delete --zone "us-central1-b" "istio-gce"
gcloud container clusters delete mesh-exp-gke --zone us-central1-b --async
```

## Learn more

Learn about each step of the VM install in the [Istio documentation](https://istio.io/docs/examples/virtual-machines/single-network/#preparing-the-kubernetes-cluster-for-vms).

Learn [how to set up a proxy-injected VM in another network](https://istio.io/docs/examples/virtual-machines/multi-network/).

================================================
FILE: mesh-expansion-gce/scripts/1-create-cluster.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

# set vars
PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
ZONE="us-central1-b"
CLUSTER_NAME="mesh-exp-gke"
CTX="gke_${PROJECT_ID}_${ZONE}_${CLUSTER_NAME}"

# Create GKE Cluster
gcloud config set project $PROJECT_ID

 gcloud container clusters create $CLUSTER_NAME --zone $ZONE --username "admin" \
   --machine-type "n1-standard-2" \
   --num-nodes "4" --network "default" --enable-stackdriver-kubernetes --enable-ip-alias --async


================================================
FILE: mesh-expansion-gce/scripts/2-create-vm.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

# set vars
PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
gcloud config set project $PROJECT_ID
ZONE="us-central1-b"
CLUSTER_NAME="mesh-exp-gke"
CTX="gke_${PROJECT_ID}_${ZONE}_${CLUSTER_NAME}"

GCE_INSTANCE_NAME="istio-gce"

# allow traffic from K8s cluster to VM service
export K8S_POD_CIDR=$(gcloud container clusters describe ${CLUSTER_NAME?} --zone ${ZONE?} --format=json | jq -r '.clusterIpv4Cidr')

gcloud compute firewall-rules create k8s-to-istio-gce \
--description="Allow k8s pods CIDR to istio-gce instance" \
--source-ranges=$K8S_POD_CIDR \
--target-tags=${GCE_INSTANCE_NAME} \
--action=ALLOW \
--rules=tcp:3550

# Create GCE VM
gcloud config set project $PROJECT_ID

gcloud compute --project=$PROJECT_ID instances create $GCE_INSTANCE_NAME --zone=$ZONE \
--machine-type=n1-standard-2 --subnet=default --network-tier=PREMIUM --maintenance-policy=MIGRATE \
--image=ubuntu-1604-xenial-v20190628 --image-project=ubuntu-os-cloud --boot-disk-size=10GB \
--boot-disk-type=pd-standard --boot-disk-device-name=$GCE_INSTANCE_NAME --tags=${GCE_INSTANCE_NAME}



================================================
FILE: mesh-expansion-gce/scripts/3-install-istio.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
ZONE="us-central1-b"
CLUSTER_NAME="mesh-exp-gke"
CTX="gke_${PROJECT_ID}_${ZONE}_${CLUSTER_NAME}"

# configure cluster context
gcloud config set project $PROJECT_ID
gcloud container clusters get-credentials $CLUSTER_NAME --zone $ZONE
kubectl config use-context $CTX


cd ../common/
INSTALL_YAML="../mesh-expansion-gce/scripts/install.yaml" ./install_istio.sh
cd ../mesh-expansion-gce

================================================
FILE: mesh-expansion-gce/scripts/4-deploy-hipstershop.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
ZONE="us-central1-b"
CLUSTER_NAME="mesh-exp-gke"
CTX="gke_${PROJECT_ID}_${ZONE}_${CLUSTER_NAME}"

# configure cluster context
gcloud config set project $PROJECT_ID
gcloud container clusters get-credentials $CLUSTER_NAME --zone $ZONE
kubectl config use-context $CTX

# deploy sample app to GKE
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/istio-manifests.yaml

# remove the cluster-based productcatalog - we'll deploy this on the VM
kubectl delete svc productcatalogservice; kubectl delete deployment productcatalogservice
kubectl delete serviceentry allow-egress-google-metadata
kubectl delete serviceentry allow-egress-googleapis

================================================
FILE: mesh-expansion-gce/scripts/5-prep-cluster.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

# set vars
PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
ZONE="us-central1-b"
CLUSTER_NAME="mesh-exp-gke"
CTX="gke_${PROJECT_ID}_${ZONE}_${CLUSTER_NAME}"
GCE_INSTANCE_NAME="istio-gce"
SERVICE_NAMESPACE="default"

# Generate cluster.env
export ISTIOD_IP=$(kubectl get -n istio-system service istiod -o jsonpath='{.spec.clusterIP}')
log "⛵️ istiod IP is $ISTIOD_IP"

ISTIO_SERVICE_CIDR=$(gcloud container clusters describe $CLUSTER_NAME --zone $ZONE --project $PROJECT_ID --format "value(servicesIpv4Cidr)")
echo -e "ISTIO_SERVICE_CIDR=$ISTIO_SERVICE_CIDR\n" > cluster.env
echo "ISTIO_INBOUND_PORTS=3550,8080" >> cluster.env

# client certs
log "Getting client certs..."
go run istio.io/istio/security/tools/generate_cert -client -host spiffee://cluster.local/vm/vmname \
 --out-priv key.pem --out-cert cert-chain.pem  -mode self-signed

# root cert
log "Getting root cert..."
kubectl -n istio-system get cm istio-ca-root-cert -o jsonpath='{.data.root-cert\.pem}' > root-cert.pem


================================================
FILE: mesh-expansion-gce/scripts/6-prep-vm.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

# set vars
PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
ZONE="us-central1-b"
CLUSTER_NAME="mesh-exp-gke"
CTX="gke_${PROJECT_ID}_${ZONE}_${CLUSTER_NAME}"
GCE_NAME="istio-gce"
SERVICE_NAMESPACE="default"

# send certs and cluster.env to VM
gcloud compute scp --project=${PROJECT_ID} --zone=${ZONE} \
 {key.pem,cert-chain.pem,cluster.env,root-cert.pem,scripts/vm-install-istio.sh,scripts/vm-run-products.sh} ${GCE_NAME}:

# from the VM, install the Istio sidecar proxy and update /etc/hosts to reach istiod
export ISTIOD_IP=$(kubectl get -n istio-system service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
log "⛵️ GWIP is is $ISTIOD_IP"

gcloud compute --project $PROJECT_ID ssh --zone ${ZONE} ${GCE_NAME} --command="ISTIOD_IP=${ISTIOD_IP} ./vm-install-istio.sh"

# from the VM, install Docker and run productcatalog as a docker container
gcloud compute --project $PROJECT_ID ssh --zone ${ZONE} ${GCE_NAME} --command="./vm-run-products.sh"


================================================
FILE: mesh-expansion-gce/scripts/7-add-to-mesh.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }
ZONE="us-central1-b"
GCE_NAME="istio-gce"

export GCE_IP=$(gcloud --format="value(networkInterfaces[0].networkIP)" compute instances describe ${GCE_NAME} --zone ${ZONE})
log "GCE IP is ${GCE_IP}"
../common/istio-1.5.2/bin/istioctl experimental add-to-mesh external-service productcatalogservice ${GCE_IP} grpc:3550 -n default
log "✅ added productcatalog to the mesh."

================================================
FILE: mesh-expansion-gce/scripts/8-start-vm-istio.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
log() { echo "$1" >&2; }

PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
ZONE="us-central1-b"
GCE_NAME="istio-gce"

# re-kick Istio on the VM
log "Restarting istio on the VM..."
gcloud compute --project $PROJECT_ID ssh --zone ${ZONE} ${GCE_NAME} --command="sudo systemctl stop istio; sudo systemctl start istio;"
log "Done."

================================================
FILE: mesh-expansion-gce/scripts/install.yaml
================================================
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  addonComponents:
    grafana:
      enabled: true
      k8s:
        replicaCount: 1
    istiocoredns:
      enabled: false
    kiali:
      enabled: true
      k8s:
        replicaCount: 1
    prometheus:
      enabled: true
      k8s:
        replicaCount: 1
    tracing:
      enabled: true
  components:
    base:
      enabled: true
    citadel:
      enabled: false
      k8s:
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    cni:
      enabled: false
    egressGateways:
    - enabled: false
      k8s:
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ingressgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
      name: istio-egressgateway
    galley:
      enabled: false
      k8s:
        replicaCount: 1
        resources:
          requests:
            cpu: 100m
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    ingressGateways:
    - enabled: true
      k8s:
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-ingressgateway
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
      name: istio-ingressgateway
    nodeAgent:
      enabled: false
    pilot:
      enabled: true
      k8s:
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 5
        resources:
          requests:
            cpu: 500m
            memory: 2048Mi
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    policy:
      enabled: false
      k8s:
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-policy
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    sidecarInjector:
      enabled: false
      k8s:
        replicaCount: 1
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
    telemetry:
      enabled: false
      k8s:
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        - name: GOMAXPROCS
          value: "6"
        hpaSpec:
          maxReplicas: 5
          metrics:
          - resource:
              name: cpu
              targetAverageUtilization: 80
            type: Resource
          minReplicas: 1
          scaleTargetRef:
            apiVersion: apps/v1
            kind: Deployment
            name: istio-telemetry
        replicaCount: 1
        resources:
          limits:
            cpu: 4800m
            memory: 4G
          requests:
            cpu: 1000m
            memory: 1G
        strategy:
          rollingUpdate:
            maxSurge: 100%
            maxUnavailable: 25%
  hub: docker.io/istio
  tag: 1.5.1
  values:
    clusterResources: true
    galley:
      enableAnalysis: false
      image: galley
    gateways:
      istio-egressgateway:
        autoscaleEnabled: true
        env:
          ISTIO_META_ROUTER_MODE: sni-dnat
        ports:
        - name: http2
          port: 80
        - name: https
          port: 443
        - name: tls
          port: 15443
          targetPort: 15443
        secretVolumes:
        - mountPath: /etc/istio/egressgateway-certs
          name: egressgateway-certs
          secretName: istio-egressgateway-certs
        - mountPath: /etc/istio/egressgateway-ca-certs
          name: egressgateway-ca-certs
          secretName: istio-egressgateway-ca-certs
        type: ClusterIP
      istio-ingressgateway:
        applicationPorts: ""
        autoscaleEnabled: true
        debug: info
        domain: ""
        env:
          ISTIO_META_ROUTER_MODE: sni-dnat
        meshExpansionPorts:
        - name: tcp-pilot-grpc-tls
          port: 15011
          targetPort: 15011
        - name: tcp-citadel-grpc-tls
          port: 8060
          targetPort: 8060
        - name: tcp-dns-tls
          port: 853
          targetPort: 853
        ports:
        - name: status-port
          port: 15020
          targetPort: 15020
        - name: http2
          port: 80
          targetPort: 80
        - name: https
          port: 443
        - name: kiali
          port: 15029
          targetPort: 15029
        - name: prometheus
          port: 15030
          targetPort: 15030
        - name: grafana
          port: 15031
          targetPort: 15031
        - name: tracing
          port: 15032
          targetPort: 15032
        - name: tls
          port: 15443
          targetPort: 15443
        sds:
          enabled: false
          image: node-agent-k8s
          resources:
            limits:
              cpu: 2000m
              memory: 1024Mi
            requests:
              cpu: 100m
              memory: 128Mi
        secretVolumes:
        - mountPath: /etc/istio/ingressgateway-certs
          name: ingressgateway-certs
          secretName: istio-ingressgateway-certs
        - mountPath: /etc/istio/ingressgateway-ca-certs
          name: ingressgateway-ca-certs
          secretName: istio-ingressgateway-ca-certs
        type: LoadBalancer
        zvpn:
          enabled: false
          suffix: global
    global:
      arch:
        amd64: 2
        ppc64le: 2
        s390x: 2
      certificates: []
      configValidation: true
      controlPlaneSecurityEnabled: true
      defaultNodeSelector: {}
      defaultPodDisruptionBudget:
        enabled: true
      defaultResources:
        requests:
          cpu: 10m
      disablePolicyChecks: true
      enableHelmTest: false
      enableTracing: true
      imagePullPolicy: IfNotPresent
      imagePullSecrets: []
      istioNamespace: istio-system
      istiod:
        enabled: true
      jwtPolicy: third-party-jwt
      k8sIngress:
        enableHttps: false
        enabled: false
        gatewayName: ingressgateway
      localityLbSetting:
        enabled: true
      logAsJson: false
      logging:
        level: default:info
      meshExpansion:
        enabled: true
        useILB: false
      meshNetworks: {}
      mountMtlsCerts: false
      mtls:
        auto: true
        enabled: false
      multiCluster:
        clusterName: ""
        enabled: false
      network: ""
      omitSidecarInjectorConfigMap: false
      oneNamespace: false
      operatorManageWebhooks: false
      outboundTrafficPolicy:
        mode: ALLOW_ANY
      pilotCertProvider: istiod
      policyCheckFailOpen: false
      priorityClassName: ""
      proxy:
        accessLogEncoding: TEXT
        accessLogFile: "/dev/stdout"
        accessLogFormat: ""
        autoInject: enabled
        clusterDomain: cluster.local
        componentLogLevel: misc:error
        concurrency: 2
        dnsRefreshRate: 300s
        enableCoreDump: false
        envoyAccessLogService:
          enabled: false
        envoyMetricsService:
          enabled: false
          tcpKeepalive:
            interval: 10s
            probes: 3
            time: 10s
          tlsSettings:
            mode: DISABLE
            subjectAltNames: []
        envoyStatsd:
          enabled: false
        excludeIPRanges: ""
        excludeInboundPorts: ""
        excludeOutboundPorts: ""
        image: proxyv2
        includeIPRanges: '*'
        includeInboundPorts: '*'
        kubevirtInterfaces: ""
        logLevel: warning
        privileged: false
        protocolDetectionTimeout: 100ms
        readinessFailureThreshold: 30
        readinessInitialDelaySeconds: 1
        readinessPeriodSeconds: 2
        resources:
          limits:
            cpu: 2000m
            memory: 1024Mi
          requests:
            cpu: 100m
            memory: 128Mi
        statusPort: 15020
        tracer: zipkin
      proxy_init:
        image: proxyv2
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
          requests:
            cpu: 10m
            memory: 10Mi
      sds:
        enabled: false
        token:
          aud: istio-ca
        udsPath: ""
      sts:
        servicePort: 0
      tracer:
        datadog:
          address: $(HOST_IP):8126
        lightstep:
          accessToken: ""
          address: ""
          cacertPath: ""
          secure: true
        stackdriver:
          debug: false
          maxNumberOfAnnotations: 200
          maxNumberOfAttributes: 200
          maxNumberOfMessageEvents: 200
        zipkin:
          address: ""
      trustDomain: cluster.local
      useMCP: false
    grafana:
      accessMode: ReadWriteMany
      contextPath: /grafana
      dashboardProviders:
        dashboardproviders.yaml:
          apiVersion: 1
          providers:
          - disableDeletion: false
            folder: istio
            name: istio
            options:
              path: /var/lib/grafana/dashboards/istio
            orgId: 1
            type: file
      datasources:
        datasources.yaml:
          apiVersion: 1
      env: {}
      envSecrets: {}
      image:
        repository: grafana/grafana
        tag: 6.5.2
      ingress:
        enabled: false
        hosts:
        - grafana.local
      nodeSelector: {}
      persist: false
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        enabled: false
        passphraseKey: passphrase
        secretName: grafana
        usernameKey: username
      service:
        annotations: {}
        externalPort: 3000
        name: http
        type: ClusterIP
      storageClassName: ""
      tolerations: []
    istiocoredns:
      coreDNSImage: coredns/coredns
      coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1
      coreDNSTag: 1.6.2
    kiali:
      contextPath: /kiali
      createDemoSecret: true
      dashboard:
        grafanaInClusterURL: http://grafana:3000
        jaegerInClusterURL: http://tracing/jaeger
        passphraseKey: passphrase
        secretName: kiali
        usernameKey: username
        viewOnlyMode: false
      hub: quay.io/kiali
      ingress:
        enabled: false
        hosts:
        - kiali.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        cert_file: /kiali-cert/cert-chain.pem
        enabled: false
        private_key_file: /kiali-cert/key.pem
      tag: v1.14
    mixer:
      adapters:
        kubernetesenv:
          enabled: true
        prometheus:
          enabled: true
          metricsExpiryDuration: 10m
        stackdriver:
          auth:
            apiKey: ""
            appCredentials: false
            serviceAccountPath: ""
          enabled: false
          tracer:
            enabled: false
            sampleProbability: 1
        stdio:
          enabled: false
          outputAsJson: false
        useAdapterCRDs: false
      policy:
        adapters:
          kubernetesenv:
            enabled: true
          useAdapterCRDs: false
        autoscaleEnabled: true
        image: mixer
        sessionAffinityEnabled: false
      telemetry:
        autoscaleEnabled: true
        env:
          GOMAXPROCS: "6"
        image: mixer
        loadshedding:
          latencyThreshold: 100ms
          mode: enforce
        nodeSelector: {}
        podAntiAffinityLabelSelector: []
        podAntiAffinityTermLabelSelector: []
        replicaCount: 1
        reportBatchMaxEntries: 100
        reportBatchMaxTime: 1s
        sessionAffinityEnabled: false
        tolerations: []
    nodeagent:
      image: node-agent-k8s
    pilot:
      appNamespaces: []
      autoscaleEnabled: true
      autoscaleMax: 5
      autoscaleMin: 1
      configMap: true
      configNamespace: istio-config
      cpu:
        targetAverageUtilization: 80
      enableProtocolSniffingForInbound: false
      enableProtocolSniffingForOutbound: true
      env: {}
      image: pilot
      ingress:
        ingressClass: istio
        ingressControllerMode: STRICT
        ingressService: istio-ingressgateway
      keepaliveMaxServerConnectionAge: 30m
      meshNetworks:
        networks: {}
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      policy:
        enabled: false
      replicaCount: 1
      tolerations: []
      traceSampling: 1
    prometheus:
      contextPath: /prometheus
      hub: docker.io/prom
      ingress:
        enabled: false
        hosts:
        - prometheus.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      provisionPrometheusCert: true
      retention: 6h
      scrapeInterval: 15s
      security:
        enabled: true
      tag: v2.15.1
      tolerations: []
    security:
      dnsCerts:
        istio-pilot-service-account.istio-control: istio-pilot.istio-control
      enableNamespacesByDefault: true
      image: citadel
      selfSigned: true
    sidecarInjectorWebhook:
      enableNamespacesByDefault: false
      image: sidecar_injector
      injectLabel: istio-injection
      objectSelector:
        autoInject: true
        enabled: false
      rewriteAppHTTPProbe: false
      selfSigned: false
    telemetry:
      enabled: true
      v1:
        enabled: false
      v2:
        enabled: true
        prometheus:
          enabled: true
        stackdriver:
          configOverride: {}
          enabled: true
          logging: true
          monitoring: true
          topology: true
    tracing:
      ingress:
        enabled: false
      jaeger:
        accessMode: ReadWriteMany
        hub: docker.io/jaegertracing
        memory:
          max_traces: 50000
        persist: false
        spanStorageType: badger
        storageClassName: ""
        tag: "1.16"
      nodeSelector: {}
      opencensus:
        exporters:
          stackdriver:
            enable_tracing: true
        hub: docker.io/omnition
        resources:
          limits:
            cpu: "1"
            memory: 2Gi
          requests:
            cpu: 200m
            memory: 400Mi
        tag: 0.1.9
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      provider: jaeger
      service:
        annotations: {}
        externalPort: 9411
        name: http-query
        type: ClusterIP
      zipkin:
        hub: docker.io/openzipkin
        javaOptsHeap: 700
        maxSpans: 500000
        node:
          cpus: 2
        probeStartupDelay: 200
        queryPort: 9411
        resources:
          limits:
            cpu: 300m
            memory: 900Mi
          requests:
            cpu: 150m
            memory: 900Mi
        tag: 2.14.2
    version: ""



================================================
FILE: mesh-expansion-gce/scripts/vm-install-istio.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


# install the sidecar proxy
curl -L https://storage.googleapis.com/istio-release/releases/1.5.1/deb/istio-sidecar.deb > istio-sidecar.deb
sudo dpkg -i istio-sidecar.deb

# update /etc/hosts
echo "${ISTIOD_IP} istiod.istio-system.svc" | sudo tee -a /etc/hosts

# install certs
sudo mkdir -p /etc/certs
sudo cp {root-cert.pem,cert-chain.pem,key.pem} /etc/certs
sudo mkdir -p /var/run/secrets/istio/
sudo cp root-cert.pem /var/run/secrets/istio/

# install cluster.env
sudo cp cluster.env /var/lib/istio/envoy

# transfer file ownership to istio proxy
sudo chown -R istio-proxy /etc/certs /var/lib/istio/envoy /var/run/secrets/istio/

# start Istio
sudo systemctl start istio

================================================
FILE: mesh-expansion-gce/scripts/vm-run-products.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# install docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable";
sudo apt-get update;
sudo apt-get install -y docker-ce;

# run productcatalog
sudo docker run -d -p 3550:3550 gcr.io/google-samples/microservices-demo/productcatalogservice:v0.3.4



================================================
FILE: multicluster-gke/dual-control-plane/README.md
================================================
# Demo: Multicluster Istio - Gateway-Connected Clusters

This example shows how to orchestrate an application with [Istio](https://istio.io/) across two different
Google Kubernetes Engine clusters. To do this, we will unite two different Istio service meshes into
one logical, hybrid mesh.

![dual-screenshot](screenshots/topology.png)

This example is relevant if you run microservices on two different cloud platforms, or are
using a combination of on-prem and cloud Kubernetes. For demonstration purposes here, we'll use two GKE clusters in two different projects, and thus two
different [virtual networks](https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview#inside-cluster).

## How it works

This demo uses Istio 1.4's [Gateway-Connected Clusters](https://preliminary.istio.io/docs/concepts/multicluster-deployments/#multiple-control-plane-topology) feature. This is a specific mode of
multicluster Istio where two separate Kubernetes clusters run their own Istio control
plane, and orchestrate their own mesh. But each Istio control plane also runs a CoreDNS
server, which allows services in both clusters to refer to services in the other cluster,
as if they were part of their own mesh. A service in cluster 1 can call a
cluster 2 service with a DNS name of the format `svc-name.cluster-2-namespace.global`.
The Kubernetes DNS server and Istio's CoreDNS know how to work together to resolve that
`global` DNS suffix.


## Prerequisites

- Two GCP projects with billing and the Kubernetes API enabled
- `gcloud` CLI
- `kubectl`
- `helm` CLI


## Set Project Variables

```
export PROJECT_1=<your-project1>

export PROJECT_2=<your-second-project>
```

## Create Two GKE Clusters

```
./scripts/1-create-gke-clusters.sh
```

Then, run:

```
watch -n 1 gcloud container clusters list
```

And wait for both clusters to be `RUNNING`.

## Install Istio on Both Clusters

```
./scripts/2-install-istio.sh
```

Wait for all Istio pods to be `RUNNING` -

```
NAME                                    READY   STATUS    RESTARTS
 AGE
grafana-556b649566-4fwb9                1/1     Running   0
 2m28s
istio-egressgateway-79ffd95b56-zf2vg    1/1     Running   0
 8m18s
istio-ingressgateway-6df84b84d4-dp9rw   1/1     Running   0
 8m17s
istio-tracing-7cf5f46848-pzmf7          1/1     Running   0
 2m28s
istiocoredns-5f7546c6f4-gjl2x           2/2     Running   0
 8m17s
istiod-8465c8f9d9-pxb6v                 1/1     Running   0
 8m38s
kiali-6d54b8ccbc-9qhc9                  1/1     Running   0
 2m28s
prometheus-75f89f4df8-gd5mn             2/2     Running   0
 8m16s
```

## Configure KubeDNS to talk to Istio's CoreDNS

You'll notice `istiocoredns` in the list of pods. This DNS server which will handle DNS resolution across
cluster boundaries.

The next step configures the Kubernetes server (kubedns) to with a
DNS
[stub domain](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/#configure-stub-domain-and-upstream-dns-servers)
to talk to this auxiliary Istio CoreDNS server.
A StubDomain is a forwarding rule for DNS addresses with a certain prefix.

Run the script to configure the stub domain on both GKE clusters:

```
./scripts/3-configure-dns.sh
```


## Deploy the Sample App

We will now deploy [Online Boutique, a sample application](https://github.com/GoogleCloudPlatform/microservices-demo), across our two GKE clusters.

For demonstration purposes, we've split the microservices into two halves. One group
will run on Cluster 1 (namespace `hipster1`):

- emailservice
- checkoutservice
- paymentservice
- currencyservice
- shippingservice
- adservice

And another group will run on Cluster 2 (namespace
`hipster2`):

- frontend
- productcatalogservice
- recommendationservice
- cartservice (configured to use a local store, not Redis)


Visually, we will deploy this topology:

![dual-screenshot](screenshots/topology.png)

The following script creates the following resources on both GKE clusters:
- Kubernetes Deployments for the services assigned to this cluster
- Kubernetes Services for the services that *are* running local to this cluster
- ServiceEntries (type `MESH_INTERNAL`) for all the services *not* running on this cluster. **Note**: for each
  of these external ServiceEntries, the script injects the Istio `IngressGateway` IP for the
  opposite cluster. This is how CoreDNS will be able to resolve `global` to an actual
  external Istio IP.
- ServiceEntries (type `MESH_EXTERNAL`) to access external Google APIs (necessary for
  Online Boutique to run)
- Istio VirtualServices / Gateway (for cluster 2 / the frontend only)

Run the script to deploy these resources across both clusters:

```
./scripts/4-deploy-online-boutique.sh
```


## Verify successful deployment

1. Get pods in cluster 1 (namespace `hipster1`) to make sure all are `RUNNING` -

```
NAME                               READY   STATUS    RESTARTS   AGE
adservice-84449b8756-4nhpm         2/2     Running   0          3m29s
checkoutservice-8dfb487c6-rwh9n    2/2     Running   0          3m30s
currencyservice-b9fcb4c98-98q7x    2/2     Running   0          3m29s
emailservice-57f9ddf9b9-hmpv7      2/2     Running   0          3m30s
paymentservice-84d7bf956-8f9br     2/2     Running   0          3m29s
shippingservice-78dc8784d4-7h4zx   2/2     Running   0          3m29s
```

2. Get pods in cluster 2 (namespace `hipster2`) to make sure all are `RUNNING` -

```
NAME                                     READY   STATUS    RESTARTS
  AGE
cartservice-5b88d44bd-t6s6c              2/2     Running   0
2m31s
frontend-7958cf4f9-r2b9m                 2/2     Running   0
  2m32s
productcatalogservice-c796f4c6d-qgfp8    2/2     Running   0
  2m32s
recommendationservice-6788b77796-z4xq8   2/2     Running   0
  2m31s
```

3. Get the Ingress Gateway `EXTERNAL_IP` in `cluster2`, where the web `frontend` is deployed:

```
kubectl config use-context gke_${PROJECT_2}_us-central1-b_dual-cluster2
kubectl get svc -n istio-system istio-ingressgateway
```

Navigate to that address in a browser.

![](screenshots/frontend.png)

4. View the service graph.

From `cluster2`, open the Kiali service graph dashboard.

```
../../common/istio-1.5.2/bin/istioctl dashboard kiali &
```

Log in as `admin/admin`. Navigate to Graph > Service Graph > namespace: `default`. You should see traffic moving from the `frontend` on cluster2, to services running in both cluster2 (eg. `productcatalogservice`) and in cluster1 (eg. `adservice`). Note that in-cluster traffic within cluster1 is not visible in cluster2's Kiali dashboard.

![](screenshots/kiali-cluster2.png)

Congrats! you just deployed Multicluster Istio across
two separate networks, then ran an application that spanned two Kubernetes
environments! All part of a single, two-headed Service Mesh. 🎉


## Clean up

Delete the 2 GKE clusters:

```
./scripts/cleanup-delete-clusters.sh
```

## Further reading

- To learn about Multicluster Istio and its different modes, [see the Istio docs](https://istio.io/docs/concepts/multicluster-deployments/)
- To learn how to configure and install the different modes, see the [Setup](https://istio.io/docs/setup/install/multicluster/) section in the Istio docs.


================================================
FILE: multicluster-gke/dual-control-plane/cluster1/deployments.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# [START istio_dual_control_plane_cluster1_deployment_emailservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: emailservice
spec:
  selector:
    matchLabels:
      app: emailservice
  template:
    metadata:
      labels:
        app: emailservice
    spec:
      containers:
      - image: gcr.io/google-samples/microservices-demo/emailservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:8080
          periodSeconds: 5
        name: server
        ports:
        - containerPort: 8080
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:8080
          periodSeconds: 5
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster1_deployment_emailservice]
---
# [START istio_dual_control_plane_cluster1_deployment_checkoutservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: checkoutservice
spec:
  selector:
    matchLabels:
      app: checkoutservice
  template:
    metadata:
      labels:
        app: checkoutservice
    spec:
      containers:
      - env:
        - name: PRODUCT_CATALOG_SERVICE_ADDR
          value: productcatalogservice.default.global:3550
        - name: SHIPPING_SERVICE_ADDR
          value: shippingservice.default.svc.cluster.local:50051
        - name: PAYMENT_SERVICE_ADDR
          value: paymentservice.default.svc.cluster.local:50051
        - name: EMAIL_SERVICE_ADDR
          value: emailservice.default.svc.cluster.local:5000
        - name: CURRENCY_SERVICE_ADDR
          value: currencyservice.default.svc.cluster.local:7000
        - name: CART_SERVICE_ADDR
          value: cartservice.default.global:7070
        image: gcr.io/google-samples/microservices-demo/checkoutservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:5050
        name: server
        ports:
        - containerPort: 5050
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:5050
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
# [END istio_dual_control_plane_cluster1_deployment_checkoutservice]
---
# [START istio_dual_control_plane_cluster1_deployment_paymentservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: paymentservice
spec:
  selector:
    matchLabels:
      app: paymentservice
  template:
    metadata:
      labels:
        app: paymentservice
    spec:
      containers:
      - env:
        - name: PORT
          value: '50051'
        image: gcr.io/google-samples/microservices-demo/paymentservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:50051
        name: server
        ports:
        - containerPort: 50051
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:50051
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster1_deployment_paymentservice]
---
# [START istio_dual_control_plane_cluster1_deployment_currencyservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: currencyservice
spec:
  selector:
    matchLabels:
      app: currencyservice
  template:
    metadata:
      labels:
        app: currencyservice
    spec:
      containers:
      - env:
        - name: PORT
          value: '7000'
        image: gcr.io/google-samples/microservices-demo/currencyservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:7000
        name: server
        ports:
        - containerPort: 7000
          name: grpc
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:7000
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster1_deployment_currencyservice]
---
# [START istio_dual_control_plane_cluster1_deployment_shippingservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shippingservice
spec:
  selector:
    matchLabels:
      app: shippingservice
  template:
    metadata:
      labels:
        app: shippingservice
    spec:
      containers:
      - image: gcr.io/google-samples/microservices-demo/shippingservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:50051
        name: server
        ports:
        - containerPort: 50051
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:50051
          periodSeconds: 5
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
# [END istio_dual_control_plane_cluster1_deployment_shippingservice]
---
# [START istio_dual_control_plane_cluster1_deployment_adservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: adservice
spec:
  selector:
    matchLabels:
      app: adservice
  template:
    metadata:
      labels:
        app: adservice
    spec:
      containers:
      - env:
        - name: PORT
          value: '9555'
        image: gcr.io/google-samples/microservices-demo/adservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:9555
          initialDelaySeconds: 20
          periodSeconds: 15
        name: server
        ports:
        - containerPort: 9555
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:9555
          initialDelaySeconds: 20
          periodSeconds: 15
        resources:
          limits:
            cpu: 300m
            memory: 300Mi
          requests:
            cpu: 200m
            memory: 180Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster1_deployment_adservice]
---


================================================
FILE: multicluster-gke/dual-control-plane/cluster1/istio-defaults.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_dual_control_plane_cluster1_serviceentry_currency_provider_external]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: currency-provider-external
spec:
  hosts:
  - www.ecb.europa.eu
  ports:
  - name: http
    number: 80
    protocol: HTTP
  - name: https
    number: 443
    protocol: HTTPS
# [END istio_dual_control_plane_cluster1_serviceentry_currency_provider_external]

================================================
FILE: multicluster-gke/dual-control-plane/cluster1/service-entries.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_dual_control_plane_cluster1_serviceentry_frontendservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: frontendservice-entry
spec:
  addresses:
  - 240.0.0.5
  endpoints:
  - address: 35.193.92.27
    ports:
      http1: 15443
  hosts:
  - frontend.default.global
  location: MESH_INTERNAL
  ports:
  - name: http1
    number: 80
    protocol: http
  resolution: DNS
# [END istio_dual_control_plane_cluster1_serviceentry_frontendservice_entry]
---
# [START istio_dual_control_plane_cluster1_serviceentry_productcatalogservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: productcatalogservice-entry
spec:
  addresses:
  - 240.0.0.6
  endpoints:
  - address: 35.193.92.27
    ports:
      grpc: 15443
  hosts:
  - productcatalogservice.default.global
  location: MESH_INTERNAL
  ports:
  - name: grpc
    number: 3550
    protocol: GRPC
  resolution: DNS
# [END istio_dual_control_plane_cluster1_serviceentry_productcatalogservice_entry]
---
# [START istio_dual_control_plane_cluster1_serviceentry_cartservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: cartservice-entry
spec:
  addresses:
  - 240.0.0.7
  endpoints:
  - address: 35.193.92.27
    ports:
      grpc: 15443
  hosts:
  - cartservice.default.global
  location: MESH_INTERNAL
  ports:
  - name: grpc
    number: 7070
    protocol: GRPC
  resolution: DNS
# [END istio_dual_control_plane_cluster1_serviceentry_cartservice_entry]
---


================================================
FILE: multicluster-gke/dual-control-plane/cluster1/services-local.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_dual_control_plane_cluster1_service_emailservice]
apiVersion: v1
kind: Service
metadata:
  name: emailservice
spec:
  ports:
  - name: grpc
    port: 5000
    targetPort: 8080
  selector:
    app: emailservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster1_service_emailservice]
---
# [START istio_dual_control_plane_cluster1_service_checkoutservice]
apiVersion: v1
kind: Service
metadata:
  name: checkoutservice
spec:
  ports:
  - name: grpc
    port: 5050
    targetPort: 5050
  selector:
    app: checkoutservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster1_service_checkoutservice]
---
# [START istio_dual_control_plane_cluster1_service_paymentservice]
apiVersion: v1
kind: Service
metadata:
  name: paymentservice
spec:
  ports:
  - name: grpc
    port: 50051
    targetPort: 50051
  selector:
    app: paymentservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster1_service_paymentservice]
---
# [START istio_dual_control_plane_cluster1_service_currencyservice]
apiVersion: v1
kind: Service
metadata:
  name: currencyservice
spec:
  ports:
  - name: grpc
    port: 7000
    targetPort: 7000
  selector:
    app: currencyservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster1_service_currencyservice]
---
# [START istio_dual_control_plane_cluster1_service_shippingservice]
apiVersion: v1
kind: Service
metadata:
  name: shippingservice
spec:
  ports:
  - name: grpc
    port: 50051
    targetPort: 50051
  selector:
    app: shippingservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster1_service_shippingservice]
---
# [START istio_dual_control_plane_cluster1_service_adservice]
apiVersion: v1
kind: Service
metadata:
  name: adservice
spec:
  ports:
  - name: grpc
    port: 9555
    targetPort: 9555
  selector:
    app: adservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster1_service_adservice]
---


================================================
FILE: multicluster-gke/dual-control-plane/cluster2/deployments.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: loadgenerator
spec:
  selector:
    matchLabels:
      app: loadgenerator
  replicas: 1
  template:
    metadata:
      labels:
        app: loadgenerator
      annotations:
        sidecar.istio.io/rewriteAppHTTPProbers: "true"
    spec:
      terminationGracePeriodSeconds: 5
      restartPolicy: Always
      containers:
      - name: main
        image: gcr.io/google-samples/microservices-demo/loadgenerator:v0.3.4
        env:
        - name: FRONTEND_ADDR
          value: "frontend:80"
        - name: USERS
          value: "10"
        resources:
          requests:
            cpu: 300m
            memory: 256Mi
          limits:
            cpu: 500m
            memory: 512Mi
---
# [START istio_dual_control_plane_cluster2_deployment_frontend]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - env:
        - name: PRODUCT_CATALOG_SERVICE_ADDR
          value: productcatalogservice.default.svc.cluster.local:3550
        - name: CURRENCY_SERVICE_ADDR
          value: currencyservice.default.global:7000
        - name: CART_SERVICE_ADDR
          value: cartservice.default.svc.cluster.local:7070
        - name: RECOMMENDATION_SERVICE_ADDR
          value: recommendationservice.default.svc.cluster.local:8080
        - name: SHIPPING_SERVICE_ADDR
          value: shippingservice.default.global:50051
        - name: CHECKOUT_SERVICE_ADDR
          value: checkoutservice.default.global:5050
        - name: AD_SERVICE_ADDR
          value: adservice.default.global:9555
        image: gcr.io/google-samples/microservices-demo/frontend:v0.3.4
        livenessProbe:
          httpGet:
            httpHeaders:
            - name: Cookie
              value: shop_session-id=x-liveness-probe
            path: /_healthz
            port: 8080
          initialDelaySeconds: 10
        name: server
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            httpHeaders:
            - name: Cookie
              value: shop_session-id=x-readiness-probe
            path: /_healthz
            port: 8080
          initialDelaySeconds: 10
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
# [END istio_dual_control_plane_cluster2_deployment_frontend]
---
# [START istio_dual_control_plane_cluster2_deployment_productcatalogservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productcatalogservice
spec:
  selector:
    matchLabels:
      app: productcatalogservice
  template:
    metadata:
      labels:
        app: productcatalogservice
    spec:
      containers:
      - image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:3550
        name: server
        ports:
        - containerPort: 3550
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:3550
        resources:
          limits:
            cpu: 200m
            memory: 128Mi
          requests:
            cpu: 100m
            memory: 64Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster2_deployment_productcatalogservice]
---
# [START istio_dual_control_plane_cluster2_deployment_cartservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cartservice
spec:
  selector:
    matchLabels:
      app: cartservice
  template:
    metadata:
      labels:
        app: cartservice
    spec:
      containers:
      - env:
        - name: REDIS_ADDR
          value: ''
        - name: PORT
          value: '7070'
        - name: LISTEN_ADDR
          value: 0.0.0.0
        image: gcr.io/google-samples/microservices-demo/cartservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:7070
          initialDelaySeconds: 15
          periodSeconds: 10
        name: server
        ports:
        - containerPort: 7070
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:7070
          initialDelaySeconds: 15
        resources:
          limits:
            cpu: 300m
            memory: 128Mi
          requests:
            cpu: 200m
            memory: 64Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster2_deployment_cartservice]
---
# [START istio_dual_control_plane_cluster2_deployment_recommendationservice]
apiVersion: apps/v1
kind: Deployment
metadata:
  name: recommendationservice
spec:
  selector:
    matchLabels:
      app: recommendationservice
  template:
    metadata:
      labels:
        app: recommendationservice
    spec:
      containers:
      - env:
        - name: PRODUCT_CATALOG_SERVICE_ADDR
          value: productcatalogservice.default.svc.cluster.local:3550
        image: gcr.io/google-samples/microservices-demo/recommendationservice:v0.3.4
        livenessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:8080
          periodSeconds: 5
        name: server
        ports:
        - containerPort: 8080
        readinessProbe:
          exec:
            command:
            - /bin/grpc_health_probe
            - -addr=:8080
          periodSeconds: 5
        resources:
          limits:
            cpu: 200m
            memory: 450Mi
          requests:
            cpu: 100m
            memory: 220Mi
      terminationGracePeriodSeconds: 5
# [END istio_dual_control_plane_cluster2_deployment_recommendationservice]
---


================================================
FILE: multicluster-gke/dual-control-plane/cluster2/istio-defaults.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_dual_control_plane_cluster2_gateway_frontend_gateway]
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: frontend-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - '*'
    port:
      name: http
      number: 80
      protocol: HTTP
# [END istio_dual_control_plane_cluster2_gateway_frontend_gateway]
---
# [START istio_dual_control_plane_cluster2_virtualservice_frontend_ingress]
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: frontend-ingress
spec:
  gateways:
  - frontend-gateway
  hosts:
  - '*'
  http:
  - route:
    - destination:
        host: frontend
        port:
          number: 80
# [END istio_dual_control_plane_cluster2_virtualservice_frontend_ingress]
---
# [START istio_dual_control_plane_cluster2_virtualservice_frontend]
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: frontend
spec:
  hosts:
  - frontend.default.svc.cluster.local
  http:
  - route:
    - destination:
        host: frontend
        port:
          number: 80
# [END istio_dual_control_plane_cluster2_virtualservice_frontend]

================================================
FILE: multicluster-gke/dual-control-plane/cluster2/service-entries.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_dual_control_plane_cluster2_serviceentry_adservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: adservice-entry
spec:
  addresses:
  - 240.0.0.2
  endpoints:
  - address: 34.70.9.157
    ports:
      grpc: 15443
  hosts:
  - adservice.default.global
  location: MESH_INTERNAL
  ports:
  - name: grpc
    number: 9555
    protocol: GRPC
  resolution: DNS
# [END istio_dual_control_plane_cluster2_serviceentry_adservice_entry]
---
# [START istio_dual_control_plane_cluster2_serviceentry_checkoutservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: checkoutservice-entry
spec:
  addresses:
  - 240.0.0.3
  endpoints:
  - address: 34.70.9.157
    ports:
      grpc: 15443
  hosts:
  - checkoutservice.default.global
  location: MESH_INTERNAL
  ports:
  - name: grpc
    number: 5050
    protocol: GRPC
  resolution: DNS
# [END istio_dual_control_plane_cluster2_serviceentry_checkoutservice_entry]
---
# [START istio_dual_control_plane_cluster2_serviceentry_currencyservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: currencyservice-entry
spec:
  addresses:
  - 240.0.0.4
  endpoints:
  - address: 34.70.9.157
    ports:
      grpc: 15443
  hosts:
  - currencyservice.default.global
  location: MESH_INTERNAL
  ports:
  - name: grpc
    number: 7000
    protocol: GRPC
  resolution: DNS
# [END istio_dual_control_plane_cluster2_serviceentry_currencyservice_entry]
---
# [START istio_dual_control_plane_cluster2_serviceentry_shippingservice_entry]
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: shippingservice-entry
spec:
  addresses:
  - 240.0.0.8
  endpoints:
  - address: 34.70.9.157
    ports:
      grpc: 15443
  hosts:
  - shippingservice.default.global
  location: MESH_INTERNAL
  ports:
  - name: grpc
    number: 50051
    protocol: GRPC
  resolution: DNS
# [END istio_dual_control_plane_cluster2_serviceentry_shippingservice_entry]
---


================================================
FILE: multicluster-gke/dual-control-plane/cluster2/services-local.yaml
================================================

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# [START istio_dual_control_plane_cluster2_service_recommendationservice]
apiVersion: v1
kind: Service
metadata:
  name: recommendationservice
spec:
  ports:
  - name: grpc
    port: 8080
    targetPort: 8080
  selector:
    app: recommendationservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster2_service_recommendationservice]
---
# [START istio_dual_control_plane_cluster2_service_frontend]
apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: frontend
  type: ClusterIP
# [END istio_dual_control_plane_cluster2_service_frontend]
---
# [START istio_dual_control_plane_cluster2_service_productcatalogservice]
apiVersion: v1
kind: Service
metadata:
  name: productcatalogservice
spec:
  ports:
  - name: grpc
    port: 3550
    targetPort: 3550
  selector:
    app: productcatalogservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster2_service_productcatalogservice]
---
# [START istio_dual_control_plane_cluster2_service_cartservice]
apiVersion: v1
kind: Service
metadata:
  name: cartservice
spec:
  ports:
  - name: grpc
    port: 7070
    targetPort: 7070
  selector:
    app: cartservice
  type: ClusterIP
# [END istio_dual_control_plane_cluster2_service_cartservice]
---


================================================
FILE: multicluster-gke/dual-control-plane/scripts/1-create-gke-clusters.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

# Project 1 - Create GKE Cluster 1
gcloud config set project $PROJECT_1

gcloud container clusters create $CLUSTER_1 --zone $ZONE --username "admin" \
--machine-type "n1-standard-2" \
--scopes "https://www.googleapis.com/auth/compute","https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "4" --network "default" --enable-stackdriver-kubernetes  --async


# Project 2 - Create GKE Cluster 2
gcloud config set project $PROJECT_2

gcloud container clusters create $CLUSTER_2 --zone $ZONE --username "admin" \
--machine-type "n1-standard-2" \
--num-nodes "4" --network "default" --enable-stackdriver-kubernetes --async


================================================
FILE: multicluster-gke/dual-control-plane/scripts/2-install-istio.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

DUAL_PROFILE="../multicluster-gke/dual-control-plane/scripts/install.yaml"
cd ../../common

# Cluster 1
log "Installing Istio on Cluster 1..."
gcloud config set project $PROJECT_1
gcloud container clusters get-credentials $CLUSTER_1 --zone $ZONE
kubectl config use-context $CTX_1
INSTALL_YAML=${DUAL_PROFILE} ./install_istio.sh


# Cluster 2
log "Installing Istio on Cluster 2..."
gcloud config set project $PROJECT_2
gcloud container clusters get-credentials $CLUSTER_2 --zone $ZONE
kubectl config use-context $CTX_2
INSTALL_YAML=${DUAL_PROFILE} ./install_istio.sh



================================================
FILE: multicluster-gke/dual-control-plane/scripts/3-configure-dns.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

configure_kubedns () {
     kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {"global": ["$(kubectl get svc -n istio-system istiocoredns -o jsonpath={.spec.clusterIP})"]}
EOF
}

# Cluster 1
log "Configuring DNS on Cluster 1..."
gcloud config set project $PROJECT_1
kubectl config use-context $CTX_1
configure_kubedns
log "...done with cluster 1."


# Cluster 2
log "Configuring DNS on Cluster 2..."
gcloud config set project $PROJECT_2
kubectl config use-context $CTX_2
configure_kubedns
log "...done with cluster 2."


================================================
FILE: multicluster-gke/dual-control-plane/scripts/4-deploy-online-boutique.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

# Get the Istio IngressGateway IP for both clusters
kubectl config use-context $CTX_1
GWIP1=$(kubectl get -n istio-system service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

kubectl config use-context $CTX_2
GWIP2=$(kubectl get -n istio-system service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')


# Populate YAML / Deploy to Cluster 1
log "Deploying OnlineBoutique on Cluster 1..."
gcloud config set project $PROJECT_1
gcloud container clusters get-credentials $CLUSTER_1 --zone $ZONE
kubectl config use-context $CTX_1
pattern='.*- address:.*'
replace="  - address: "$GWIP2""
gsed -r -i "s|$pattern|$replace|g" cluster1/service-entries.yaml
kubectl apply -f ./cluster1
log "...done with cluster 1."


# Populate YAML /  Deploy to Cluster 2
log "Deploying OnlineBoutique on Cluster 2..."
gcloud config set project $PROJECT_2
gcloud container clusters get-credentials $CLUSTER_2 --zone $ZONE
kubectl config use-context $CTX_2
pattern='.*- address:.*'
replace="  - address: "$GWIP1""
gsed -r -i "s|$pattern|$replace|g" cluster2/service-entries.yaml
kubectl apply -f ./cluster2
log "...done with cluster 2."




================================================
FILE: multicluster-gke/dual-control-plane/scripts/cleanup-delete-clusters.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

log "Deleting cluster 1..."
gcloud container clusters delete $CLUSTER_1 --project $PROJECT_1 --zone $ZONE --async

# Project 2 - Create GKE Cluster 2
log "Deleting cluster 2..."
gcloud config set project $PROJECT_2
gcloud container clusters delete $CLUSTER_2 --project $PROJECT_2 --zone $ZONE --async


================================================
FILE: multicluster-gke/dual-control-plane/scripts/env.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

log() { echo "$1" >&2; }

ZONE="us-central1-b"

ISTIO_VERSION=${ISTIO_VERSION:=1.4.2}

PROJECT_1="${PROJECT_1:?PROJECT_1 env variable must be specified}"
CLUSTER_1="dual-cluster1"
CTX_1="gke_${PROJECT_1}_${ZONE}_${CLUSTER_1}"

PROJECT_2="${PROJECT_2:?PROJECT_2 env variable must be specified}"
CLUSTER_2="dual-cluster2"
CTX_2="gke_${PROJECT_2}_${ZONE}_${CLUSTER_2}"

================================================
FILE: multicluster-gke/dual-control-plane/scripts/install.yaml
================================================
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  addonComponents:
    grafana:
      enabled: true
      k8s:
        replicaCount: 1
    istiocoredns:
      enabled: true
    kiali:
      enabled: true
      k8s:
        replicaCount: 1
    prometheus:
      enabled: true
      k8s:
        replicaCount: 1
    tracing:
      enabled: true
  components:
    egressGateways:
      - name: istio-egressgateway
        enabled: true

  values:
    kiali:
      contextPath: /kiali
      createDemoSecret: true
      dashboard:
        grafanaInClusterURL: http://grafana:3000
        jaegerInClusterURL: http://tracing/jaeger
        passphraseKey: passphrase
        secretName: kiali
        usernameKey: username
        viewOnlyMode: false
      hub: quay.io/kiali
      ingress:
        enabled: false
        hosts:
        - kiali.local
      nodeSelector: {}
      podAntiAffinityLabelSelector: []
      podAntiAffinityTermLabelSelector: []
      security:
        cert_file: /kiali-cert/cert-chain.pem
        enabled: false
        private_key_file: /kiali-cert/key.pem
      tag: v1.14
    global:
      # Provides dns resolution for global services
      podDNSSearchNamespaces:
        - global
        - "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global"

      multiCluster:
        enabled: true

      controlPlaneSecurityEnabled: true

    # Multicluster with gateways requires a root CA
    # Cluster local CAs are bootstrapped with the root CA.
    security:
      selfSigned: false

    gateways:
      istio-egressgateway:
        env:
          # Needed to route traffic via egress gateway if desired.
          ISTIO_META_REQUESTED_NETWORK_VIEW: "external"


================================================
FILE: multicluster-gke/single-control-plane/README.md
================================================
# Demo: Multicluster Istio- Single Control Plane

This demo shows how to use Istio to orchestrate [an application](https://github.com/GoogleCloudPlatform/microservices-demo) running across two Google
Kubernetes Engine clusters in the same project, but across two different [zones](https://cloud.google.com/compute/docs/regions-zones/#identifying_a_region_or_zone).

![topology](screenshots/topology.png)

### Prerequisites

1. a GCP project with Billing enabled.
2. gcloud
3. kubectl
4. [helm CLI](https://github.com/helm/helm/releases), installed wherever you're running
   these commands (Google Cloud shell, laptop,
   etc.) Note that we are only using the `helm template` command in this demo (ie. [Tiller](https://helm.sh/docs/glossary/#tiller)
   not required on any of the Kubernetes clusters).

## Create two GKE clusters

Set the project ID to your GCP Project:

```
export PROJECT_ID=<your-GCP-project-ID>
```

Then run the script to create two GKE clusters in your project:

```
./scripts/1-cluster-create.sh
```

Then, run:

```
watch -n 1 gcloud container clusters list
```

Wait for both clusters to be `RUNNING`.

## Connect to clusters

This script creates kubeconfigs for both clusters, to allow future `kubectl` commands to
switch back and forth between them.

```
./scripts/2-get-credentials.sh
```

## Create a GKE Firewall Rule

This step allows pods on both clusters to communicate directly.

```
./scripts/3-firewall.sh
```


## Install the Istio Control Plane on Cluster 1

This step installs the Istio control plane on one of the GKE clusters.

```
./scripts/4-cluster1-install.sh
```


## Install the Istio Remote on Cluster 2

Now we'll install the remote Istio components (Citadel's node-agent, and an Envoy sidecar injector) on Cluster 2.

```
./scripts/5-cluster2-install.sh
```


## Connect Cluster 2 to Cluster 1

This step generates a [Kubeconfig](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#define-clusters-users-and-contexts) file for the remote cluster 2, then adds it as a [Secret](https://kubernetes.io/docs/concepts/configuration/secret/)
to Cluster 1. This step allows the Istio control plane on cluster 1 to configure Istio proxies on cluster 2.

```
./scripts/6-connect-clusters.sh
```


## Deploy [Hipstershop](https://github.com/GoogleCloudPlatform/microservices-demo)

This script deploys the sample application across both cluster 1 and cluster 2. We have
split the microservices in the application so that some run centrally to the Istio control
plane (cluster 1), and the rest run on the remote Istio cluster (cluster 2):

![topology](screenshots/topology.png)


Run the script to deploy:

```
./scripts/7-deploy-hipstershop.sh
```

*Note*:  This script uses the default Hipstershop installation, which deploys all services to the cluster, then deletes the deployments that belong on the other cluster. Both clusters need Kubernetes Services for all the Hipstershop workloads, in order for cross-cluster DNS to work.

You can verify that the multicluster deployment was successful using 3 methods:

1. Run `kubectl get pods` on both clusters to ensure all pods are `RUNNING` and `READY`.

2. From cluster-1, run `istioctl proxy-status`. You should see cluster-2 services (eg.
   `cartservice`) appear in the list. This means that the Istio control plane can
   successfully configure Envoy proxies running on the remote GKE cluster-2.

```
NAME                                                   CDS        LDS        EDS        RDS        PILOT                       VERSION
adservice-86674bf94d-gq52w.default                     SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
checkoutservice-74df4f44c8-b6xlq.default               SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
currencyservice-6444b89474-ln4zp.default               SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
emailservice-c98d5d48d-5pg65.default                   SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
frontend-67dcdc8cf8-z64jh.default                      SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
istio-ingressgateway-5b477bdb4f-l9fw2.istio-system     SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
paymentservice-579d78fc44-r65wp.default                SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
productcatalogservice-65794cb878-bb6zf.default         SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
prometheus-7bc49f57-mjhqx.istio-system                 SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
shippingservice-794b4d66bb-prc9j.default               SYNCED     SYNCED     SYNCED     SYNCED     istiod-6c6c489d84-8rgnr     1.5.2
```

3. open Hipstershop in the browser by getting the Istio `IngressGateway`'s `EXTERNAL_IP`:

```
kubectl get svc istio-ingressgateway -n istio-system
```

From the frontend, click on a product. You should see product recommendations, and be able to navigate to your Cart without any errors:

![browser-screenshot](screenshots/browser-screenshot.png)

This means that the Hipstershop Frontend service (running in cluster 1) was able to use
its Istio sidecar proxy to resolve DNS to Kubernetes Services running in cluster 2.

🎉 Well done! You just orchestrated an application with Istio across multiple Google
Kubernetes Engine
clusters.

## Cleanup

To delete all the GCP resources used in this demo:

```
./scripts/cleanup-delete-clusters.sh
```

## What's next?

Now that you have Istio installed on two clusters, you can create [traffic rules](https://github.com/GoogleCloudPlatform/istio-samples/tree/master/istio-canary-gke) and [security policies](https://github.com/GoogleCloudPlatform/istio-samples/tree/master/security-intro) that
span both clusters.

Or to deploy the BookInfo app with multicluster Istio, [see the Istio documentation](https://preliminary.istio.io/docs/examples/multicluster/gke/).


================================================
FILE: multicluster-gke/single-control-plane/scripts/1-cluster-create.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Creates two GKE clusters in different regions.

set -euo pipefail
source ./scripts/env.sh

log "Creating cluster1..."
 gcloud container clusters create cluster-1 --zone $cluster1zone --username "admin" \
  --machine-type "n1-standard-4" \
  --scopes "https://www.googleapis.com/auth/compute","https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "2" --network "default" --enable-stackdriver-kubernetes --enable-ip-alias --async

sleep 20

log "Creating cluster2..."
  gcloud container clusters create cluster-2 --zone $cluster2zone --username "admin" \
  --machine-type "n1-standard-4" \
  --scopes "https://www.googleapis.com/auth/compute","https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "2" --network "default" --enable-stackdriver-kubernetes --enable-ip-alias --async


================================================
FILE: multicluster-gke/single-control-plane/scripts/2-get-credentials.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

gcloud container clusters get-credentials cluster-1 --zone $cluster1zone
gcloud container clusters get-credentials cluster-2 --zone $cluster2zone

================================================
FILE: multicluster-gke/single-control-plane/scripts/3-firewall.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

function join_by { local IFS="$1"; shift; echo "$*"; }

ALL_CLUSTER_CIDRS=$(gcloud container clusters list --format='value(clusterIpv4Cidr)' | sort | uniq)
ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
ALL_CLUSTER_NETTAGS=$(gcloud compute instances list --format='value(tags.items.[0])' | sort | uniq)
ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))

gcloud compute firewall-rules create istio-multicluster-test-pods \
  --allow=tcp,udp,icmp,esp,ah,sctp \
  --direction=INGRESS \
  --priority=900 \
  --source-ranges="${ALL_CLUSTER_CIDRS}" \
  --target-tags="${ALL_CLUSTER_NETTAGS}" --quiet


================================================
FILE: multicluster-gke/single-control-plane/scripts/4-cluster1-install.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# cluster 1 is the "main" cluster running the Istio control plane
# src https://istio.io/docs/setup/install/multicluster/shared/

set -euo pipefail
source ./scripts/env.sh

kubectl config use-context $ctx1
log "Installing the Istio ${ISTIO_VERSION} control plane on ${ctx1} ..."

cd ../../common
INSTALL_YAML="../multicluster-gke/single-control-plane/scripts/cluster1.yaml" ./install_istio.sh


================================================
FILE: multicluster-gke/single-control-plane/scripts/5-cluster2-install.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

export ISTIOD_REMOTE_EP=$(kubectl --context=${ctx1} -n istio-system get svc istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
log "ISTIOD_REMOTE_EP is ${ISTIOD_REMOTE_EP}"

kubectl config use-context $ctx2

# configure cluster2 with "remote pilot" to get its config (istiod running in cluster1)
pattern='ISTIOD_REMOTE_EP'
replace="${ISTIOD_REMOTE_EP}"
gsed -r -i "s|$pattern|$replace|g" scripts/cluster2.yaml

# install the istio sidecar injector (istiod), prometheus in cluster2
cd ../../common
INSTALL_YAML="../multicluster-gke/single-control-plane/scripts/cluster2.yaml" ./install_istio.sh



================================================
FILE: multicluster-gke/single-control-plane/scripts/6-connect-clusters.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


set -euo pipefail
source ./scripts/env.sh

# Configure cross cluster service registries
# (let cluster 1 discover services in cluster 2)
cd ../../common/istio-1.5.2/bin
./istioctl x create-remote-secret --context=${ctx2} --name "cluster2" | \
    kubectl apply -f - --context=${ctx1}
cd ../../../multicluster-gke/single-control-plane/

================================================
FILE: multicluster-gke/single-control-plane/scripts/7-deploy-hipstershop.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
source ./scripts/env.sh

# Deploy "most of" Hipstershop to cluster 1
kubectl config use-context $ctx1
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/istio-manifests.yaml
kubectl delete svc frontend-external
# delete cluster2 svcs from cluster1
for i in "${services2[@]}"
do
   echo "Deleting ${i} from ${ctx1}"
   kubectl delete deployment $i
done


# Deploy the rest of Hipstershop (cartservice, rediscart, recommendations, loadgenerator) to cluster2
kubectl config use-context $ctx2
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/istio-manifests.yaml
kubectl delete svc frontend-external
# delete cluster1 svcs from cluster2
for i in "${services1[@]}"
do
   echo "Deleting ${i} from ${ctx2}"
   kubectl delete deployment $i
done


================================================
FILE: multicluster-gke/single-control-plane/scripts/cleanup-delete-clusters.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Creates two GKE clusters in different regions.

set -euo pipefail
source ./scripts/env.sh

log "Deleting cluster1..."
gcloud container clusters delete cluster-1 --zone $cluster1zone --async

log "Deleting cluster2..."
gcloud container clusters delete cluster-2 --zone $cluster2zone --async


================================================
FILE: multicluster-gke/single-control-plane/scripts/cluster1.yaml
================================================
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    security:
      selfSigned: false
    global:
      multiCluster:
        clusterName: cluster1
      network: ""
      meshExpansion:
        enabled: true

================================================
FILE: multicluster-gke/single-control-plane/scripts/cluster2.yaml
================================================
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      multiCluster:
        clusterName: cluster2
      network: ""
      remotePilotAddress: ISTIO_REMOTE_EP

================================================
FILE: multicluster-gke/single-control-plane/scripts/env.sh
================================================
#!/usr/bin/env bash

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

log() { echo "$1" >&2; }

PROJECT_ID="${PROJECT_ID:?PROJECT_ID env variable must be specified}"
gcloud config set project $PROJECT_ID

cluster1="cluster1"
cluster2="cluster2"
network1="network1"
cluster1zone="us-east1-b"
cluster2zone="us-central1-b"

ctx1="gke_${PROJECT_ID}_${cluster1zone}_cluster-1"
ctx2="gke_${PROJECT_ID}_${cluster2zone}_cluster-2"

ISTIO_VERSION=${ISTIO_VERSION:=1.5.2}

services1=("emailservice" "paymentservice" "shippingservice" "adservice" "checkoutservice" "currencyservice" "frontend" "productcatalogservice")
services2=("loadgenerator" "cartservice" "recommendationservice" "redis-cart")

================================================
FILE: multicluster-gke/vm-migration/README.md
================================================
# Virtual Machine Migration with Multicluster Istio

  - [Introduction](#introduction)
  - [Setup](#setup)
  - [Deploy the sample application to GKE](#deploy-the-sample-application-to-gke)
  - [Install Istio on the VM](#install-istio-on-the-vm)
  - [Prepare for VM to GKE Migration](#prepare-for-vm-to-gke-migration)
  - [Migrate productcatalog to GKE](#migrate-productcatalog-to-gke)
  - [Complete the GKE Migration](#complete-the-gke-migration)
  - [Cleanup](#cleanup)

## Introduction

Istio works with services running in Kubernetes containers, but it also works with virtual machines. Because of this, Istio can help you integrate legacy VM workloads into a modern, Kubernetes-based service mesh - and help you migrate the VM services to Kubernetes, when you're ready.

For instance, let's say we want to deploy a multi-service application. This application consists mostly of Kubernetes-ready microservices (running across two cloud datacenters in `us-west` and `us-east`), but one of the older services (`productcatalog`) runs in a virtual machine in `us-central`. We can still get all the benefits of Istio (telemetry, security, traffic policies) for that virtual machine service. Then, when we're ready to migrate `productcatalog` from a VM to a container running in one of our Kubernetes clusters, Istio can progressively - and safely - migrate traffic from the VM to the container version with zero downtime.

In this sample, we will set up multicluster Istio on two GKE clusters, then configure a GCE instance to join the mesh. Then we'll deploy a sample app across the two clusters and the VM. Finally, we'll deploy the VM service a Kubernetes pod alongside the VM instance, and use Istio traffic splitting to migrate from GCE to all GKE. We will work towards this final state, where the VM service is no longer needed -

![](screenshots/migrate-complete-traffic.png)


## Setup

1. Set your project ID.
```
export PROJECT_ID="<your-project-id>"
```

2. Run the first script to create two GKE clusters and one GCE instance in your project.

```
./scripts/1-create-infra.sh
```

3. Wait for the clusters to be `RUNNING`.

```
watch gcloud container clusters list

NAME      LOCATION    MASTER_VERSION  MASTER_IP      MACHINE_TYPE
NODE_VERSION    NUM_NODES  STATUS
cluster2  us-east1-b  1.14.10-gke.27  35.196.192.71  n1-standard-2
1.14.10-gke.27  4          RUNNING
cluster1  us-west1-b  1.14.10-gke.27  34.83.227.203  n1-standard-2
1.14.10-gke.27  4          RUNNING
```


4. Create firewall rules to allow traffic from the GKE pods in both clusters to your GCE instance. This will allow traffic to move freely between the two GKE clusters and the service running on the VM.

```
./scripts/2-firewall.sh
```


5. Install the Istio control plane on both GKE clusters. This script also connects the two Istio control planes into one logical mesh by updating the KubeDNS stubdomain - this is what will allow cross-cluster GKE mesh traffic to resolve to local Kubernetes services on the opposite cluster. [See the Istio docs](https://istio.io/docs/setup/install/multicluster/gateways/#setup-dns) for more information.

```
./scripts/3-install-istio-gke.sh
```


## Deploy the sample application to GKE

1. Deploy the OnlineBoutique sample application -- minus one backend service, `productcatalog` -- across the two GKE clusters. Note that until we deploy `productcatalog` onto the VM, the app will be in an error state and the loadgenerator pod will not start. This is expected because productcatalog is unreachable for now.

```
./scripts/4-deploy-onlineboutique-gke.sh
```

Note that this script creates Istio `ServiceEntry` resources so that services across clusters can access each other via the `IngressGateway` running in the opposite cluster. For example, in cluster 2, we create a `ServiceEntry` for `adservice` (running in cluster1) to that the frontend (in cluster2) can reach adservice in the opposite cluster via the Kubernetes DNS name `adservice.default.global`:


```YAML
# this service entry lives in cluster 2
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: adservice-entry
spec:
  addresses:
# this is a placeholder virtual IP, it's not used for routing
  - 240.0.0.2
  endpoints:
  # this is the istio ingressgateway IP for cluster 1 (the actual routing IP)
  - address: 35.230.67.174
    ports:
      grpc: 15443
  hosts:
# this is the address the frontend uses to reach adservice
  - adservice.default.global
# mesh internal means we own this service and it has a sidecar proxy
  location: MESH_INTERNAL
  ports:
  - name: grpc
# adservice serves grpc traffic on this port #
    number: 9555
    protocol: GRPC
  resolution: DNS
```

[See the Istio docs](https://istio.io/docs/setup/install/multicluster/gateways/#configure-the-example-services) for more details on how cross-cluster service discovery works.


## Install Istio on the VM

Now we're ready to install the Istio agent (sidecar proxy) on the GCE instance we provisioned earlier. This is the architecture we will set up:

![](screenshots/migrate-before-traffic.png)

1. Gather information about the Istio mesh running on GKE. This information is needed so that the Istio proxy on the VM can "call home" to a control plane, to receive proxy config, certs for mutual TLS, and know where to send metrics. Because we're running two Istio control planes, **we will configure the VM to "call home" to the Istio control plane running on cluster1.**

```
./scripts/5-prep-cluster1.sh
```

2. Install the Istio proxy on the VM, along with Docker. Then deploy `productcatalog` onto the VM as a raw Docker container. Note that you could use systemd or another deployment method to deploy your Istio-enabled service to the VM.

```
./scripts/6-prep-vm.sh
```


3. Add productcatalog to the logical mesh, via the `istioctl` tool. This command will create a `Service` and `ServiceEntry` for productcatalog running on the VM, to allow pods inside both clusters to reach `productcatalog` with a Kubernetes DNS name (`productcatalog.default.svc.cluster.local`), even though `productcatalog` isn't running in Kubernetes.

```
./scripts/7-add-vm-to-mesh.sh
```

The configuration across clusters now looks like this:


![](screenshots/migrate-before-config.png)

Note that we do this step for both clusters, because services on **both** cluster1 (recommendations, checkout) and cluster2 (frontend) must reach productcatalog on the VM.


4. Verify deployment. This script shows the pods running across both clusters, opens the Kiali service graph (for cluster1) in a browser tab, and outputs the Online frontend


```
./scripts/8-verify-deploy.sh
```

5. In a browser, navigate the IP shown at the end of the script output. You should see the OnlineBoutique frontend with a list of products - this shows that the frontend running on `cluster2` can reach both the services running on `cluster1` (eg. `currencyservice`) **and** the `productcatalog` service running on the VM, using the Kubernetes DNS names made possible by the Istio `ServiceEntry` resources we just created.

![](screenshots/../../dual-control-plane/screenshots/frontend.png)

6. Open the Kiali service graph for cluster1. Log in with the demo credentials - `admin`/`admin`. You should see traffic going from two backend services -- `checkout` and `recommendations` to the ServiceEntry for `productcatalogservice`:

![](screenshots/cluster1-kiali-vm.png)

7. Open the Kiali service graph for cluster2. You should see traffic going from the frontend to `productcatalogservice` on the VM:

![](screenshots/cluster2-kiali-vm.png)

## Prepare for VM to GKE Migration

Now let's say we are ready to migrate `productcatalog` from GCE to one of our Istio-enabled GKE clusters. The first step to do this is to deploy `productcatalog` as a GKE pod, alongside the VM. To start, we will continue sending all traffic to the VM.

1. Deploy `productcatalog-gke` to cluster2, but don't send any traffic there yet. This script creates the Kubernetes and Istio resources to set up the VM-to-GKE migration - `Deployment` (cluster2), `Service` (cluster2), `ServiceEntry` (cluster1), and `VirtualService` (both clusters).

```
./scripts/9-deploy-productcatalog-gke.sh
```

Note the way we're "wrapping" a single VirtualService around two Kubernetes hostnames. This is what will let us split traffic across the GKE and VM versions of `productcatalog` in the next step. Here, `productcatalogservice` is the VM `ServiceEntry` already created on both clusters. `productcatalogservice-gke` is a separate Kubernetes service. For cluster2, `productcatalogservice-gke` is a **local** `Service`:

```YAML
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productcatalog-migration
spec:
  hosts:
    - productcatalogservice
  http:
  - route:
    - destination:
        host: productcatalogservice
      weight: 0
    - destination:
        host: productcatalogservice-gke
      weight: 100
```

For cluster1, productcatalog's hostname corresponds to an Istio ServiceEntry.

```YAML
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productcatalog-migration
spec:
  hosts:
    - productcatalogservice
  http:
  - route:
    - destination:
        host: productcatalogservice
      weight: 0
    - destination:
        host: productcatalogservice-gke.default.global
      weight: 100
```

## Migrate productcatalog to GKE

1. Update the two VirtualServices to send 20% of productcatalog traffic to the GKE pod running in `cluster2`, and send the remaining 80% of traffic to the VM.

```
./scripts/10-split-traffic.sh
```

Our Istio configuration now looks like this:

![](screenshots/migrate-progress-config.png)


And the traffic split looks like this:

![](screenshots/migrate-progress-traffic.png)

2. Return to the Kiali service graph to view the traffic splitting in action:

![](screenshots/traffic-split-cluster1.png)

## Complete the GKE Migration

In a real production migration, you would continue updating the traffic percentages to slowly send more traffic to the GKE version of `productcatalog.`. Let's say we've done that and we're ready to send 100% of traffic to the GKE pod.

1. Complete the migration by updating both VirtualServices to send 100% of productcatalog traffic to the GKE pod, and 0% of traffic to the VM.

```
./scripts/11-complete-migration.sh
```

Our Istio config is now:

![](screenshots/migrate-complete-config.png)

To create the final traffic state where all traffic is now within GKE:

![](screenshots/migrate-complete-traffic.png)

You should also see in Kiali (cluster1 shown here) that 100% of productcatalog traffic is going to the GKE version:

![](screenshots/migrate-complete-kiali.png)

The VM migration is complete! Now it would be safe to retire the VM, since all the app services are now running across our two GKE clusters.


## Cleanup

To clean up the resources (GKE clusters, VM) used in this tutorial:

```
./scripts/12-cleanup.sh
```

================================================
FILE: multicluster-gke/vm-migra
Download .txt
gitextract_ft7f4bst/

├── .github/
│   └── snippet-bot.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── common/
│   ├── default.yaml
│   └── install_istio.sh
├── internal-load-balancer/
│   ├── README.md
│   └── manifests/
│       ├── install.yaml
│       └── server-ilb.yaml
├── istio-canary-gke/
│   ├── README.md
│   └── canary/
│       ├── destinationrule.yaml
│       ├── productcatalog-v2.yaml
│       ├── rollback.yaml
│       └── vs-split-traffic.yaml
├── istio-stackdriver/
│   └── README.md
├── mesh-expansion-gce/
│   ├── README.md
│   └── scripts/
│       ├── 1-create-cluster.sh
│       ├── 2-create-vm.sh
│       ├── 3-install-istio.sh
│       ├── 4-deploy-hipstershop.sh
│       ├── 5-prep-cluster.sh
│       ├── 6-prep-vm.sh
│       ├── 7-add-to-mesh.sh
│       ├── 8-start-vm-istio.sh
│       ├── install.yaml
│       ├── vm-install-istio.sh
│       └── vm-run-products.sh
├── multicluster-gke/
│   ├── dual-control-plane/
│   │   ├── README.md
│   │   ├── cluster1/
│   │   │   ├── deployments.yaml
│   │   │   ├── istio-defaults.yaml
│   │   │   ├── service-entries.yaml
│   │   │   └── services-local.yaml
│   │   ├── cluster2/
│   │   │   ├── deployments.yaml
│   │   │   ├── istio-defaults.yaml
│   │   │   ├── service-entries.yaml
│   │   │   └── services-local.yaml
│   │   └── scripts/
│   │       ├── 1-create-gke-clusters.sh
│   │       ├── 2-install-istio.sh
│   │       ├── 3-configure-dns.sh
│   │       ├── 4-deploy-online-boutique.sh
│   │       ├── cleanup-delete-clusters.sh
│   │       ├── env.sh
│   │       └── install.yaml
│   ├── single-control-plane/
│   │   ├── README.md
│   │   └── scripts/
│   │       ├── 1-cluster-create.sh
│   │       ├── 2-get-credentials.sh
│   │       ├── 3-firewall.sh
│   │       ├── 4-cluster1-install.sh
│   │       ├── 5-cluster2-install.sh
│   │       ├── 6-connect-clusters.sh
│   │       ├── 7-deploy-hipstershop.sh
│   │       ├── cleanup-delete-clusters.sh
│   │       ├── cluster1.yaml
│   │       ├── cluster2.yaml
│   │       └── env.sh
│   └── vm-migration/
│       ├── README.md
│       ├── cluster1/
│       │   ├── deployments.yaml
│       │   ├── istio-defaults.yaml
│       │   ├── service-entries.yaml
│       │   └── services-local.yaml
│       ├── cluster2/
│       │   ├── deployments.yaml
│       │   ├── istio-defaults.yaml
│       │   ├── service-entries.yaml
│       │   └── services-local.yaml
│       ├── productcatalog-gke/
│       │   ├── deployment.yaml
│       │   ├── service-cluster2.yaml
│       │   ├── serviceentry-cluster1.yaml
│       │   ├── vs-0-cluster1.yaml
│       │   ├── vs-0-cluster2.yaml
│       │   ├── vs-100-cluster1.yaml
│       │   ├── vs-100-cluster2.yaml
│       │   ├── vs-20-cluster1.yaml
│       │   └── vs-20-cluster2.yaml
│       └── scripts/
│           ├── 1-create-infra.sh
│           ├── 10-split-traffic.sh
│           ├── 11-complete-migration.sh
│           ├── 12-cleanup.sh
│           ├── 2-firewall.sh
│           ├── 3-install-istio-gke.sh
│           ├── 4-deploy-onlineboutique-gke.sh
│           ├── 5-prep-cluster1.sh
│           ├── 6-prep-vm.sh
│           ├── 7-add-vm-to-mesh.sh
│           ├── 8-verify-deploy.sh
│           ├── 9-deploy-productcatalog-gke.sh
│           ├── env.sh
│           ├── install.yaml
│           ├── vm-install-istio.sh
│           └── vm-run-products.sh
├── multicluster-ingress/
│   ├── 1-create-clusters.sh
│   ├── 2-install-istio.sh
│   ├── 3-deploy-app.sh
│   ├── 4-verify-app.sh
│   ├── 5-prep-mci.sh
│   ├── 6-mci.sh
│   ├── 7-cleanup.sh
│   ├── README.md
│   ├── common.sh
│   ├── manifests/
│   │   ├── healthcheck.yaml
│   │   ├── ingress.yaml
│   │   └── istio-ingressgateway-patch.json
│   └── zone_printer/
│       ├── deployment.yaml
│       ├── gateway.yaml
│       ├── service.yaml
│       └── virtualservice.yaml
├── sample-apps/
│   ├── grpc-greeter-go/
│   │   ├── README.md
│   │   ├── client/
│   │   │   ├── .dockerignore
│   │   │   ├── .gcloudignore
│   │   │   ├── Dockerfile
│   │   │   ├── client.go
│   │   │   ├── go.mod
│   │   │   └── go.sum
│   │   ├── manifests/
│   │   │   ├── greeter-istio-destinationrule.yaml
│   │   │   ├── greeter-istio-gateway.yaml
│   │   │   ├── greeter-istio-virtualservice.yaml
│   │   │   ├── greeter-k8s.template.yaml
│   │   │   └── istio-operator.yaml
│   │   └── server/
│   │       ├── .dockerignore
│   │       ├── .gcloudignore
│   │       ├── Dockerfile
│   │       ├── go.mod
│   │       ├── go.sum
│   │       └── server.go
│   └── helloserver/
│       ├── README.md
│       ├── loadgen/
│       │   ├── Dockerfile
│       │   ├── Dockerfile-base
│       │   ├── loadgen.py
│       │   ├── loadgen.yaml
│       │   └── requirements.txt
│       └── server/
│           ├── Dockerfile
│           ├── server.py
│           └── server.yaml
├── security-intro/
│   ├── README.md
│   └── manifests/
│       ├── authz-frontend.yaml
│       ├── jwt-frontend-authz.yaml
│       ├── jwt-frontend-request.yaml
│       ├── mtls-default-ns.yaml
│       └── mtls-frontend.yaml
└── stackdriver-metrics/
    ├── README.md
    └── istio-stackdriver-metrics.yaml
Download .txt
SYMBOL INDEX (15 symbols across 4 files)

FILE: sample-apps/grpc-greeter-go/client/client.go
  constant defaultName (line 43) | defaultName = "world"
  constant timeout (line 44) | timeout     = 5 * time.Second
  function main (line 47) | func main() {

FILE: sample-apps/grpc-greeter-go/server/server.go
  type greeterServer (line 46) | type greeterServer struct
    method SayHello (line 51) | func (s *greeterServer) SayHello(ctx context.Context, in *pb.HelloRequ...
  type healthServer (line 65) | type healthServer struct
    method Check (line 68) | func (s *healthServer) Check(ctx context.Context, in *healthpb.HealthC...
    method Watch (line 74) | func (s *healthServer) Watch(in *healthpb.HealthCheckRequest, srv heal...
  function main (line 78) | func main() {

FILE: sample-apps/helloserver/loadgen/loadgen.py
  function exception_handler (line 22) | def exception_handler(request, exception):
  function callserver (line 26) | def callserver():

FILE: sample-apps/helloserver/server/server.py
  class S (line 20) | class S(BaseHTTPRequestHandler):
    method _set_response (line 21) | def _set_response(self):
    method do_GET (line 26) | def do_GET(self):
  function run (line 32) | def run(server_class=HTTPServer, handler_class=S, port=8080):
Condensed preview — 141 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (614K chars).
[
  {
    "path": ".github/snippet-bot.yml",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": ".gitignore",
    "chars": 168,
    "preview": ".DS_Store\n*.env\n*.pem\n*.tar.gz\ncluster-2\nistio_master.yaml\nistio-1*\nistio-2*\nistio-master.yaml\nistio-remote.yaml\nistio.y"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1173,
    "preview": "# Contributing\n\n## Development Principles (for Googlers)\n\nThere are a few principles for developing or refactoring the s"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 2364,
    "preview": "# ⛵️ istio-samples\n\nThis repository contains Google Cloud Platform demos and sample code for [Istio](https://istio.io/)."
  },
  {
    "path": "common/default.yaml",
    "chars": 16967,
    "preview": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "common/install_istio.sh",
    "chars": 1625,
    "preview": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "internal-load-balancer/README.md",
    "chars": 9432,
    "preview": "# Demo: Using a GCP Internal Load Balancer with Istio\n\nThis demo shows how to use an Internal Load Balancer (ILB) to con"
  },
  {
    "path": "internal-load-balancer/manifests/install.yaml",
    "chars": 18888,
    "preview": "# ILB config source - https://github.com/istio/istio/issues/20033\napiVersion: install.istio.io/v1alpha1\nkind: IstioOpera"
  },
  {
    "path": "internal-load-balancer/manifests/server-ilb.yaml",
    "chars": 1356,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "istio-canary-gke/README.md",
    "chars": 7529,
    "preview": "# ProductCatalog Canary Deployment (GKE / Istio)\n\nThis demo accompanies [a GCP Blog Post](https://cloud.google.com/blog/"
  },
  {
    "path": "istio-canary-gke/canary/destinationrule.yaml",
    "chars": 971,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "istio-canary-gke/canary/productcatalog-v2.yaml",
    "chars": 1699,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "istio-canary-gke/canary/rollback.yaml",
    "chars": 969,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "istio-canary-gke/canary/vs-split-traffic.yaml",
    "chars": 1079,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "istio-stackdriver/README.md",
    "chars": 11114,
    "preview": "# Istio and Stackdriver\n\nThis example demonstrates the ways you can use [Stackdriver](https://cloud.google.com/stackdriv"
  },
  {
    "path": "mesh-expansion-gce/README.md",
    "chars": 4542,
    "preview": "# Demo: Integrating a Google Compute Engine VM with Istio\n\nThis demo shows how to connect a Google Compute Engine virtua"
  },
  {
    "path": "mesh-expansion-gce/scripts/1-create-cluster.sh",
    "chars": 1095,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/2-create-vm.sh",
    "chars": 1726,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/3-install-istio.sh",
    "chars": 1093,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/4-deploy-hipstershop.sh",
    "chars": 1532,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/5-prep-cluster.sh",
    "chars": 1643,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/6-prep-vm.sh",
    "chars": 1632,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/7-add-to-mesh.sh",
    "chars": 1007,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/8-start-vm-istio.sh",
    "chars": 962,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/install.yaml",
    "chars": 16391,
    "preview": "apiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nspec:\n  addonComponents:\n    grafana:\n      enabled: true\n    "
  },
  {
    "path": "mesh-expansion-gce/scripts/vm-install-istio.sh",
    "chars": 1270,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "mesh-expansion-gce/scripts/vm-run-products.sh",
    "chars": 983,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/README.md",
    "chars": 7189,
    "preview": "# Demo: Multicluster Istio - Gateway-Connected Clusters\n\nThis example shows how to orchestrate an application with [Isti"
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster1/deployments.yaml",
    "chars": 7190,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster1/istio-defaults.yaml",
    "chars": 994,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster1/service-entries.yaml",
    "chars": 2105,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster1/services-local.yaml",
    "chars": 2473,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster2/deployments.yaml",
    "chars": 6468,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster2/istio-defaults.yaml",
    "chars": 1723,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster2/service-entries.yaml",
    "chars": 2586,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/cluster2/services-local.yaml",
    "chars": 1867,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/1-create-gke-clusters.sh",
    "chars": 1528,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/2-install-istio.sh",
    "chars": 1207,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/3-configure-dns.sh",
    "chars": 1244,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/4-deploy-online-boutique.sh",
    "chars": 1806,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/cleanup-delete-clusters.sh",
    "chars": 941,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/env.sh",
    "chars": 962,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/dual-control-plane/scripts/install.yaml",
    "chars": 1714,
    "preview": "apiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nspec:\n  addonComponents:\n    grafana:\n      enabled: true\n    "
  },
  {
    "path": "multicluster-gke/single-control-plane/README.md",
    "chars": 6116,
    "preview": "# Demo: Multicluster Istio- Single Control Plane\n\nThis demo shows how to use Istio to orchestrate [an application](https"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/1-cluster-create.sh",
    "chars": 1920,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/2-get-credentials.sh",
    "chars": 785,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/3-firewall.sh",
    "chars": 1265,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/4-cluster1-install.sh",
    "chars": 990,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/5-cluster2-install.sh",
    "chars": 1257,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/6-connect-clusters.sh",
    "chars": 932,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/7-deploy-hipstershop.sh",
    "chars": 1724,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/cleanup-delete-clusters.sh",
    "chars": 889,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/cluster1.yaml",
    "chars": 234,
    "preview": "apiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nspec:\n  values:\n    security:\n      selfSigned: false\n    glob"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/cluster2.yaml",
    "chars": 195,
    "preview": "apiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nspec:\n  values:\n    global:\n      multiCluster:\n        cluste"
  },
  {
    "path": "multicluster-gke/single-control-plane/scripts/env.sh",
    "chars": 1213,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/README.md",
    "chars": 10987,
    "preview": "# Virtual Machine Migration with Multicluster Istio\n\n  - [Introduction](#introduction)\n  - [Setup](#setup)\n  - [Deploy t"
  },
  {
    "path": "multicluster-gke/vm-migration/cluster1/deployments.yaml",
    "chars": 8325,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster1/istio-defaults.yaml",
    "chars": 994,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster1/service-entries.yaml",
    "chars": 1574,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster1/services-local.yaml",
    "chars": 2818,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster2/deployments.yaml",
    "chars": 5089,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster2/istio-defaults.yaml",
    "chars": 1723,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster2/service-entries.yaml",
    "chars": 2960,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/cluster2/services-local.yaml",
    "chars": 1348,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/deployment.yaml",
    "chars": 849,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: productcatalogservice-gke\nspec:\n  selector:\n    matchLabels:\n    "
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/service-cluster2.yaml",
    "chars": 203,
    "preview": "apiVersion: v1\nkind: Service\nmetadata:\n  name: productcatalogservice-gke\nspec:\n  ports:\n  - name: grpc\n    port: 3550\n  "
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/serviceentry-cluster1.yaml",
    "chars": 363,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: ServiceEntry\nmetadata:\n  name: productcatalogservice-gke\nspec:\n  addresse"
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/vs-0-cluster1.yaml",
    "chars": 329,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productcatalog-migration\nspec:\n  hosts:\n"
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/vs-0-cluster2.yaml",
    "chars": 314,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productcatalog-migration\nspec:\n  hosts:\n"
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/vs-100-cluster1.yaml",
    "chars": 329,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productcatalog-migration\nspec:\n  hosts:\n"
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/vs-100-cluster2.yaml",
    "chars": 314,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productcatalog-migration\nspec:\n  hosts:\n"
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/vs-20-cluster1.yaml",
    "chars": 329,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productcatalog-migration\nspec:\n  hosts:\n"
  },
  {
    "path": "multicluster-gke/vm-migration/productcatalog-gke/vs-20-cluster2.yaml",
    "chars": 314,
    "preview": "apiVersion: networking.istio.io/v1alpha3\nkind: VirtualService\nmetadata:\n  name: productcatalog-migration\nspec:\n  hosts:\n"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/1-create-infra.sh",
    "chars": 2264,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/10-split-traffic.sh",
    "chars": 901,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/11-complete-migration.sh",
    "chars": 920,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/12-cleanup.sh",
    "chars": 960,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/2-firewall.sh",
    "chars": 1550,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/3-install-istio-gke.sh",
    "chars": 1792,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/4-deploy-onlineboutique-gke.sh",
    "chars": 1803,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/5-prep-cluster1.sh",
    "chars": 1646,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/6-prep-vm.sh",
    "chars": 1564,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/7-add-vm-to-mesh.sh",
    "chars": 1204,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/8-verify-deploy.sh",
    "chars": 1075,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/9-deploy-productcatalog-gke.sh",
    "chars": 1598,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/env.sh",
    "chars": 1140,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/install.yaml",
    "chars": 16490,
    "preview": "apiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nspec:\n  addonComponents:\n    grafana:\n      enabled: true\n    "
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/vm-install-istio.sh",
    "chars": 1270,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-gke/vm-migration/scripts/vm-run-products.sh",
    "chars": 983,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/1-create-clusters.sh",
    "chars": 1668,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/2-install-istio.sh",
    "chars": 1037,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/3-deploy-app.sh",
    "chars": 866,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/4-verify-app.sh",
    "chars": 875,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/5-prep-mci.sh",
    "chars": 1084,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/6-mci.sh",
    "chars": 1017,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/7-cleanup.sh",
    "chars": 1122,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/README.md",
    "chars": 11175,
    "preview": "# Geo-Aware Istio Multicluster Ingress\n- [Geo-Aware Istio Multicluster Ingress](#geo-aware-istio-multicluster-ingress)\n "
  },
  {
    "path": "multicluster-ingress/common.sh",
    "chars": 1011,
    "preview": "#!/usr/bin/env bash\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# y"
  },
  {
    "path": "multicluster-ingress/manifests/healthcheck.yaml",
    "chars": 1279,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-ingress/manifests/ingress.yaml",
    "chars": 1043,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-ingress/manifests/istio-ingressgateway-patch.json",
    "chars": 153,
    "preview": "[\n    {\n      \"op\": \"replace\",\n      \"path\": \"/spec/type\",\n      \"value\": \"NodePort\"\n    },\n    {\n      \"op\": \"remove\",\n"
  },
  {
    "path": "multicluster-ingress/zone_printer/deployment.yaml",
    "chars": 1099,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-ingress/zone_printer/gateway.yaml",
    "chars": 969,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-ingress/zone_printer/service.yaml",
    "chars": 922,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "multicluster-ingress/zone_printer/virtualservice.yaml",
    "chars": 992,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "sample-apps/grpc-greeter-go/README.md",
    "chars": 1134,
    "preview": "# grpc-greeter-go\n\nThis sample application consists of a gRPC server and client.\n\nIt is a adapted from\n[the gRPC-Go hell"
  },
  {
    "path": "sample-apps/grpc-greeter-go/client/.dockerignore",
    "chars": 662,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/client/.gcloudignore",
    "chars": 679,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/client/Dockerfile",
    "chars": 1088,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/client/client.go",
    "chars": 2802,
    "preview": "/*\n *\n * Original work Copyright 2015 gRPC authors.\n * Modified work Copyright 2020 Google LLC\n *\n * Licensed under the "
  },
  {
    "path": "sample-apps/grpc-greeter-go/client/go.mod",
    "chars": 843,
    "preview": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use th"
  },
  {
    "path": "sample-apps/grpc-greeter-go/client/go.sum",
    "chars": 109912,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
  },
  {
    "path": "sample-apps/grpc-greeter-go/manifests/greeter-istio-destinationrule.yaml",
    "chars": 916,
    "preview": "\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "sample-apps/grpc-greeter-go/manifests/greeter-istio-gateway.yaml",
    "chars": 996,
    "preview": "\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "sample-apps/grpc-greeter-go/manifests/greeter-istio-virtualservice.yaml",
    "chars": 980,
    "preview": "\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "sample-apps/grpc-greeter-go/manifests/greeter-k8s.template.yaml",
    "chars": 1576,
    "preview": "\n# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "sample-apps/grpc-greeter-go/manifests/istio-operator.yaml",
    "chars": 1270,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/server/.dockerignore",
    "chars": 662,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/server/.gcloudignore",
    "chars": 679,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/server/Dockerfile",
    "chars": 1336,
    "preview": "# Copyright 2021 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/grpc-greeter-go/server/go.mod",
    "chars": 843,
    "preview": "// Copyright 2021 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use th"
  },
  {
    "path": "sample-apps/grpc-greeter-go/server/go.sum",
    "chars": 109912,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
  },
  {
    "path": "sample-apps/grpc-greeter-go/server/server.go",
    "chars": 2899,
    "preview": "/*\n *\n * Original work Copyright 2015 gRPC authors\n * Modified work Copyright 2021 Google LLC\n *\n * Licensed under the A"
  },
  {
    "path": "sample-apps/helloserver/README.md",
    "chars": 595,
    "preview": "## Sample App: helloserver \n\nThe `helloserver` application is a small sample application designed to be used for \"hello "
  },
  {
    "path": "sample-apps/helloserver/loadgen/Dockerfile",
    "chars": 318,
    "preview": "FROM gcr.io/google-samples/istio-samples/helloserver/loadgen-base as final\n\n# Enable unbuffered logging\nENV PYTHONUNBUFF"
  },
  {
    "path": "sample-apps/helloserver/loadgen/Dockerfile-base",
    "chars": 232,
    "preview": "FROM python:3-slim as builder\n\nRUN apt-get -qq update \\\n    && apt-get install -y --no-install-recommends \\\n        g++ "
  },
  {
    "path": "sample-apps/helloserver/loadgen/loadgen.py",
    "chars": 1427,
    "preview": "# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this f"
  },
  {
    "path": "sample-apps/helloserver/loadgen/loadgen.yaml",
    "chars": 1691,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "sample-apps/helloserver/loadgen/requirements.txt",
    "chars": 50,
    "preview": "grequests==0.3.0\nrequests==2.31.0\nschedule==0.6.0\n"
  },
  {
    "path": "sample-apps/helloserver/server/Dockerfile",
    "chars": 544,
    "preview": "FROM python:3.9-slim as base\nFROM base as builder\nRUN apt-get -qq update \\\n    && apt-get install -y --no-install-recomm"
  },
  {
    "path": "sample-apps/helloserver/server/server.py",
    "chars": 1641,
    "preview": "#!/usr/bin/env python3\n\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n"
  },
  {
    "path": "sample-apps/helloserver/server/server.yaml",
    "chars": 1387,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "security-intro/README.md",
    "chars": 15915,
    "preview": "# Demo: Introduction to Istio Security\n\nThis example demonstrates how to leverage [Istio's](https://istio.io/docs/concep"
  },
  {
    "path": "security-intro/manifests/authz-frontend.yaml",
    "chars": 966,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "security-intro/manifests/jwt-frontend-authz.yaml",
    "chars": 1015,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "security-intro/manifests/jwt-frontend-request.yaml",
    "chars": 1050,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "security-intro/manifests/mtls-default-ns.yaml",
    "chars": 1204,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "security-intro/manifests/mtls-frontend.yaml",
    "chars": 1250,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  },
  {
    "path": "stackdriver-metrics/README.md",
    "chars": 4892,
    "preview": "# Configuring Stackdriver Monitoring for Open Source Istio\n\n- [Background](#background)\n- [Stackdriver Adapter](#stackdr"
  },
  {
    "path": "stackdriver-metrics/istio-stackdriver-metrics.yaml",
    "chars": 30004,
    "preview": "\n# Copyright 2020 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this "
  }
]

About this extraction

This page contains the full source code of the GoogleCloudPlatform/istio-samples GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 141 files (572.4 KB), approximately 213.3k tokens, and a symbol index with 15 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!