Learning Istio | Accessing external TCP services using ServiceEntry
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:[email protected]: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:[email protected]: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