Istio enables comprehensive monitoring and visualization of microservice communication within your Kubernetes cluster. By using Istio, you can gain valuable insights into how your microservices interact, allowing for improved management and optimization of your system. Istio employs a proxy to capture all network traffic, enabling a wide range of application-aware functionalities that are determined by the configurations you establish.

In this tutorial, we will explore simple steps on how to run an nginx pod in Kubernetes with Istio. The example provided involves deploying an Nginx server to evaluate the functionality of the gateways and virtual services. We will utilize Istio ingress to manage traffic within the service mesh.

Istio provides two configurations for its data plane: Sidecar mode and Ambient mode.

Install Istio

We are in the process of installing the most recent version, 1.23.3, which is available as of the time this tutorial was composed. The installation process is quite simple. Provided that you already have a Kubernetes cluster operational, the next steps are as follows: I am executing these commands from my Mac (output truncated)

Download the Istio package and configure istioctl command line. The simplest way to install Istio is using the default profile. You can take a look at this document to check other available configuration profiles.

$ curl -L https://istio.io/downloadIstio | sh -
//adding the istioctl path as part of my shell
$ export PATH="$PATH:/istio-1.23.3/bin"
//default profile installation - output truncated
$ istioctl install
Installation complete
$

If you observe an output resembling the one mentioned above, it indicates that the installation has been successful. The subsequent step is to confirm that the Istio-related pods are operational. Please be aware that the relevant namespace will be istio-system.

$  kubectl get pods -n=istio-system
NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-794797dbb8-fpxxw   1/1     Running   0          2m18s
istiod-6c854cfc5d-7vtml                 1/1     Running   0          2m26s

$  kubectl get deployment -n istio-system
NAME                   READY   UP-TO-DATE   AVAILABLE   AGE
istio-ingressgateway   1/1     1            1           3m12s
istiod                 1/1     1            1           3m14s

Istio Gateway

Gateway specification outlines the configuration for a load balancer operating at the edge of the mesh. This includes details on the ports to expose, the protocols to use (e.g. HTTP, TCP), hosts etc., for the load balancer to handle incoming and outgoing connections. Save the yaml as gateway.yaml

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: istio-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - app.myserver.com

As you can see the selector is used to select the istio-ingressgateway pod that runs the envoy proxy at the edge of the mesh. We also have servers in which we define the listening protocol and the port number. HTTP request will match the hosts value and forward the request to the virtual service defined.

Create the gateway

$  kubectl apply -f gateway.yaml

Configure Telemetry

Before we proceed with installing the virtual service for Istio, we need to take one last step: enabling access logging. In Istio, the concept of Telemetry outlines how data is collected for workloads within a mesh. For our specific needs, enabling access logging is essential to monitor how the application performs and responds. Save the manifest below as a yaml file and apply it.

apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system
spec:
  accessLogging:
    - providers:
      - name: envoy

Istio Virtual Service

Virtual Service defines route for the request arriving at istio-gateway with the host name app.myserver.com, then forwarded to destination service with the name mywebapp in the default namespace. Save this file virtualservice.yaml

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: my-route
spec:
  hosts:
  - app.myserver.com
  gateways:
  - istio-gateway
  http:
  - name: "mywebapp"
    route:
    - destination:
        host: mywebapp

Get the ingress service IP address, I am running a private cluster so there is no way for me to access it from outside or else have to use port-forward. If you can access the istio-ingressgateway hostname from outside the cluster then use that to test.

$ INGRESS_IP=$(kubectl -n istio-system get service istio-ingressgateway -ojsonpath='{.spec.clusterIP}')
$  echo $INGRESS_IP
10.100.37.230
$  kubectl apply -f virtualservice.yaml
virtualservice.networking.istio.io/my-route created

Lets test whether things are working, I have an ubuntu pod running and gonna use that to access mywebapp

$   kubectl exec pod/ubuntu-- curl -IH "Host: app.myservernew.com" $INGRESS_IP -s
HTTP/1.1 503 Service Unavailable
date: Tue, 05 Nov 2024 17:16:28 GMT
server: istio-envoy
transfer-encoding: chunked

As you can see from the output we got a 503 service unavailable, this simply means that there is no service with the name mywebapp ready to serve the traffic.

Deploy nginx service

The last step is to deploy NGINX service for our host app.myserver.com , save the file as nginx_deploy.yaml

apiVersion: v1
kind: Pod
metadata:
  name: mywebapp
  labels:
    app: mywebapp
spec:
  containers:
  - name: mywebapp
    image: nginx
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
    ports:
      - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: mywebapp
spec:
  selector:
    app: mywebapp
  ports:
  - port: 80
    targetPort: 80

Apply the manifest file

$  kubectl apply -f nginx_deploy.yaml
pod/mywebapp created
service/mywebapp created
$  kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
mywebapp        2/2     Running   0          3s
ubuntu         1/1     Running   0          10d
php-app-new   1/1     Running   0          10d
$

Lets now test the loadbalancer IP with the host as app.myservernew.com

$ kubectl exec pod/ubuntu-- curl -IH "Host: app.myservernew.com" $INGRESS_IP -s
HTTP/1.1 200 OK
server: istio-envoy
date: Tue, 05 Nov 2024 17:14:08 GMT
content-type: text/html
content-length: 615
last-modified: Wed, 02 Oct 2024 15:13:19 GMT
etag: "66fd630f-267"
accept-ranges: bytes
x-envoy-upstream-service-time: 9

Verify Logs

During our testing of the virtual service, we encountered a 504 service unavailable error. The corresponding entry in the access logs of the istio-ingressgateway is as follows.

//logs are truncated
$ kubectl logs deploy/istio-ingressgateway -n istio-system
[2024-11-05T17:16:28.255Z] "HEAD / HTTP/1.1" 503 NC cluster_not_found - "-" 0 0 0 - "172.31.27.122" "curl/7.88.1" "d421e78b-556f-441d-8edb-68df894b1369" "app.myservernew.com" "-" - - 172.31.18.76:8080 172.31.27.122:38780 - mynewapp

For a successful 200 OK request we will see

//logs are truncated
$ kubectl logs deploy/istio-ingressgateway -n istio-system
[2024-11-05T17:14:08.135Z] "HEAD / HTTP/1.1" 200 - via_upstream - "-" 0 0 9 9 "172.31.27.122" "curl/7.88.1" "ea7e98c5-d347-42a8-a4bd-9bd6599ecd69" "app.myservernew.com" "172.31.31.87:80" outbound|80||mynewapp.default.svc.cluster.local 172.31.18.76:59854 172.31.18.76:8080 172.31.27.122:37658 - mynewapp

It seems we haven’t set up Kiali for visualizing the mesh yet, nor have we enabled Istio in any of my namespaces. Don’t worry, we’ll cover that in the next tutorial. Stay tuned!