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