In this post, we will be testing Istio’s ServiceEntry by accessing a PostgreDB database hosted externally from the Kubernetes cluster.

Setup⌗

“External” PostgresDB service⌗

Since we are running the Kubernetes cluster locally in Docker containers using k3d, we can create an “external” service by running a PostgresDB Docker container on the same host and expose its ports to localhost.

Create a local PostgresDB container database using Docker

docker run --name postgres --restart always -e POSTGRES_PASSWORD=password -d -p 5432:5432 postgres

Create a test database app_db

docker exec -u postgres -it postgres createdb app_db

This service should be accessible within the cluster at host.k3d.internal:5432 (See k3d FAQ for more information on host.k3d.internal)

Postgres client⌗

To test the externally hosted service, we will use pgcli to open a connection towards the database. I have published an image leonseng/pgcli-docker on Dockerhub, which contains the pgcli binary for the purpose of this test.

Create a deployment with the image

kubectl create deployment pgcli --image leonseng/pgcli-docker:3.1.0 -- sleep 36000

Assuming the namespace has been labelled with istio-injection=enabled, the pod should come up with 2 containers - one for pgcli-docker, another for istio-proxy

$ kubectl get pods pgcli-6d678b54fb-v8fpp
NAME                     READY   STATUS    RESTARTS   AGE
pgcli-6d678b54fb-v8fpp   2/2     Running   0          30m

Try initial connection to the PostgresDB external to the Kubernetes cluster

$ kubectl exec <pgcli_pod> -it -- pgcli postgres://postgres:password@host.k3d.internal:5432/app_db
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.

command terminated with exit code 1
$

Connection fails as expected due to missing entry in the registry for the external service. Looking at logs of istio-proxy confirms that traffic is being sent to the BlackHoleCluster

$ kubectl logs <pgcli_pod> -c istio-proxy --tail 50 -f
[2021-08-16T00:47:49.898Z] "- - -" 0 UH - - "-" 0 0 0 - "-" "-" "-" "-" "-" BlackHoleCluster - 172.17.0.1:5432 10.42.0.10:35742 - -

Service Entry⌗

Create a ServiceEntry which registers the PostgresDB service at host.k3d.internal:5432

kubectl create -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: postgresdb
spec:
  hosts:
  - host.k3d.internal
  location: MESH_EXTERNAL
  ports:
  - number: 5432
    name: postgres
    protocol: TCP
  resolution: DNS
EOF

Once the ServiceEntry has been created, the pgcli client is now able to connect to the PostgresDB

$ kubectl exec <pgcli_pod> -it -- pgcli postgres://postgres:password@host.k3d.internal:5432/app_db
Server: PostgreSQL 13.3 (Debian 13.3-1.pgdg100+1)
Version: 3.1.0
Chat: https://gitter.im/dbcli/pgcli
Home: http://pgcli.com
postgres@host:app_db> quit
Goodbye!
$

This successful connection is also logged on the istio-proxy

[2021-08-16T00:57:32.037Z] "- - -" 0 - - - "-" 452 880 30823 - "-" "-" "-" "-" "172.17.0.1:5432" outbound|5432||host.k3d.internal 10.42.0.10:40108 172.17.0.1:5432 10.42.0.10:40106 - -

Digging deeper into the istio-proxy configuration will show the relevant Envoy objects created by this ServiceEntry

$ istioctl proxy-config listeners pgcli-6d678b54fb-v8fpp | grep host.k3d.internal
0.0.0.0       5432  ALL                                                                      Cluster: outbound|5432||host.k3d.internal

$ istioctl proxy-config clusters pgcli-6d678b54fb-v8fpp | grep host.k3d.internal
host.k3d.internal                                       5432      -          outbound      STRICT_DNS

$ istioctl proxy-config endpoints pgcli-6d678b54fb-v8fpp | grep host.k3d.internal
172.17.0.1:5432                  HEALTHY     OK                outbound|5432||host.k3d.internal