Skip to content

Connect VM Workloads to Istio mesh

This document is a recipe illustrating Istio mesh expansion using a single network and a single cluster.

We install Istio and deploy all BookInfo services to the mesh, with the exception of the ratings service, which will run separately on a VM.

The idea is to make this work, and thereby to demonstrate that Istio supports a mesh where some services run in-cluster and some outside it.

The artifacts referenced in these instructions can be obtained from the GitHub repository for this site.


  • A GCP or other cloud account

Create K8s Cluster


Wait until cluster is ready.

Create the VM

gcloud compute instances create my-mesh-vm --tags=mesh-vm \
  --machine-type=n1-standard-2 \
  --network=default --subnet=default \
  --image-project=ubuntu-os-cloud \

Install ratings app on the VM

Wait for the machine to be ready.

  1. Copy over the ratings app

    gcloud compute scp --recurse bookinfo/ratings ubuntu@my-mesh-vm:ratings
  2. ssh onto the VM

    gcloud compute ssh ubuntu@my-mesh-vm
  3. Install nodejs, the ratings app and start it, test it.

    sudo apt-get update
    sudo apt-get install nodejs npm
  4. Install dependencies

    cd ratings/
    npm install
  5. Run the app:

    node ratings.js 9080 &
  6. Test the app.

    Retrieve a rating.

    curl http://localhost:9080/ratings/123

Allow POD-to-VM traffic on port 9080

CLUSTER_POD_CIDR=$(gcloud container clusters describe my-istio-cluster --format=json | jq -r '.clusterIpv4Cidr')
gcloud compute firewall-rules create "cluster-pods-to-vm" \
  --source-ranges=$CLUSTER_POD_CIDR \
  --target-tags=mesh-vm \
  --action=allow \

Install Istio

istioctl install \

Deploy BookInfo (sans ratings)

  1. Turn on sidecar-injection.

    k label ns default istio-injection=enabled
  2. Deploy the reviews service.

    k apply -f bookinfo/bookinfo-reviews.yaml

    Important: the reviews service uses an environment variable named SERVICES_DOMAIN that we use to adjust the ratings app target url to reflect the fact that it resides in a different namespace.

  3. Deploy the remaining services.

    k apply -f bookinfo/bookinfo-rest.yaml

Install east-west gateway and expose Istiod

Control plane traffic between the VM and istiod goes through this gateway (see the Istio documentation).

  1. Install the gateway

    ./scripts/ --single-cluster | istioctl install -y -f -
  2. Expose istiod

    k apply -n istio-system -f ./artifacts/expose-istiod.yaml

Create the ratings namespace and service account

The ratings service running on the VM will map to the ratings namespace in kubernetes.

k create namespace ratings
k create serviceaccount bookinfo-ratings -n ratings

Create the WorkloadGroup

A WorkloadGroup is a template for WorkloadEntry objects, see the Istio reference.

istioctl x workload group create \
  --name "ratings" \
  --namespace "ratings" \
  --labels app="ratings" \
  --serviceAccount "bookinfo-ratings" > workloadgroup.yaml

Apply the workloadgroup:

k apply -f workloadgroup.yaml -n ratings

Generate VM artifacts

istioctl x workload entry configure \
  --file workloadgroup.yaml \
  --output vm_files \

Note: check that vm_files/hosts is not blank. If it is, it means you ran the command too soon. Re-run it.

VM configuration recipe

Copy the generated artifacts to the VM.

gcloud compute scp vm_files/* ubuntu@my-mesh-vm:

Ssh onto the VM

gcloud compute ssh ubuntu@my-mesh-vm

And, on the VM, run the following commands (taken from here).

sudo mkdir -p /etc/certs
sudo cp ~/root-cert.pem /etc/certs/root-cert.pem
sudo  mkdir -p /var/run/secrets/tokens
sudo cp ~/istio-token /var/run/secrets/tokens/istio-token
curl -LO
sudo dpkg -i istio-sidecar.deb
sudo cp ~/cluster.env /var/lib/istio/envoy/cluster.env
sudo cp ~/mesh.yaml /etc/istio/config/mesh
sudo sh -c 'cat $(eval echo ~$SUDO_USER)/hosts >> /etc/hosts'
sudo mkdir -p /etc/istio/proxy
sudo chown -R istio-proxy /etc/certs /var/run/secrets /var/lib/istio /etc/istio/config /etc/istio/proxy

Exercise 1

Watch the WorkloadEntry get created as a consequence of the VM registering with the mesh.

k get workloadentry -n ratings -w

On the VM:

sudo systemctl start istio

Notice the workload entry show up in the listing. This can take up to a minute.

Exercise 2

Although the ratings service does not need to call back into the mesh, we can manually test communication from the VM into the mesh.

From the VM, run:

curl details.default.svc:9080/details/123

Exercise 3

Test communication from a pod to the ratings service running on the VM.

Create a ClusterIP service to front the application:

k apply -n ratings -f bookinfo/bookinfo-ratings-service.yaml

Create a temporary client pod in the default namespace

k run curlpod --image=radial/busyboxplus:curl -it --rm

From within the container, run the curl command:

curl ratings.ratings:9080/ratings/123

Finally, exit the container.

Put it all together

Expose BookInfo:

k apply -f bookinfo/bookinfo-gateway.yaml

Grab your load balancer public IP address:

GATEWAY_IP=$(kubectl get svc -n istio-system istio-ingressgateway -ojsonpath='{.status.loadBalancer.ingress[0].ip}')

Open a browser and visit the BookInfo product page (at /productpage). Verify that you can see ratings on the page.

curl $GATEWAY_IP/productpage