Kubernetes Endpoint and externalName Service
It’s been a while since I did not write some Kubernetes things because a few months back I just played with another workload/container orchestration tools, the Hashicorp Nomad and Consul stacks (Will write it someday hahaha ✌️).
From the Hashicorp Nomad and Consul stacks, i just got some miracle about how basic things the workload works, especially when you deal with container stuff, horizontal/vertical scaling or something most people call distributed system and yeah its about DNS (Domain Name System) implementation for your workload mapping and how they call or communicate each others (for this one i learn much from main features of Consul).
I remembered that Kubernetes already owns the internal DNS, and got an idea how if I have an external service like DB’s and external API but i just want to consume or mapping with current Kubernetes internal DNS ? 🤔
First of all I just usually whitelist some ip’s or domain to my cluster then open a few firewalls and done or add legit things with Envoy Proxy
(Istio with Egress Gateway). But I was so curious how to do that with native Kubernetes and perhaps the possible way to apply with externalName
and Endpoint
Service.
Preparing
The first, launch Kubernetes in Docker (Kind) with a small cluster and tweak to enable the ingress.
# kind-config.yaml
---
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
- role: worker
# just want to specify the version at v1.22.xx 🤪
kind create cluster --name abc \
--config kind-config.yaml \
--image kindest/node:v1.22.9
Secondly, launch a virtual machine or container that can run a database and I just did it with this.
# Remember to used --network=kind as a default network from kind
# The reason is: Currently so lazy dealing with internal network route
# So keep it same network with default kind cluster
docker run --rm -p 127.0.0.1:3306:3306 --name mysql \
--network=kind --env MARIADB_USER=user \
--env MARIADB_PASSWORD=111 \
--env MARIADB_ROOT_PASSWORD=123 \
mariadb:10.7.4-focal
For the additional to make sure what my database ip’s, check it with docker network inspect kind
, and the output its like this one.
"Containers": {
"23d326e8787473cd1ee0e479fd38cf362ee4aa62c91d3d74e9e7c64fcb50105b": {
"Name": "dev-cluster-worker",
"EndpointID": "37d9b239d7d67aa835227bafaaada74006324ed762dcf538d6e72323fe3fec1b",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": "fc00:f853:ccd:e793::2/64"
},
"295d932fc495565f625ccabd6a093991aa88ffe062a98807201102986c25f314": {
"Name": "mysql",
"EndpointID": "8996ce8fd25192318e41a9be571c2b184d89b8c85819e8679cafd622269c5e33",
"MacAddress": "02:42:ac:12:00:04",
"IPv4Address": "172.18.0.4/16",
"IPv6Address": "fc00:f853:ccd:e793::4/64"
},
"7b02453376b8aadd1a904f350b913f5fc524fd955951e07b2ece2abe0d11f7ca": {
"Name": "dev-cluster-control-plane",
"EndpointID": "f54966c97f28533c9d5f6b6a9862aaa7a459dd5f22619ba3e4335956e3a6bda7",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": "fc00:f853:ccd:e793::3/64"
}
},
The database has a 172.18.0.4
ip address with the same network with KinD cluster (/16)
prefixes.
Kubernetes Endpoints
Create Kubernetes Service manifest that defines database ip address and port.
---
apiVersion: v1
kind: Endpoints
metadata:
name: ext-svc
subsets:
- addresses:
- ip: 172.18.0.4 # DB ip
ports:
- port: 3306 # DB port
---
apiVersion: v1
kind: Service
metadata:
name: ext-svc
spec:
ports:
- protocol: TCP # It's TCP communication
port: 3306
targetPort: 3306
Kubernetes Endpoints usually created automatically when you define Deployment and some Pod’s, its act for upstream the ip address Pod’s. So for the example: having 4 Pods so the list subsets.addresses
will having 4 different ip address.
But for this case, we define it manually and Kubernetes Endpoint upstream is the ip address of DB’s.
Spawn new container inside KinD eg: kubectl run --rm -i --tty ubuntu-focal --image=ubuntu:focal -- bash
then test it with nc and mysql-client command.
# nc
root@ubuntu-focal:/# nc -zv ext-svc 3306
Connection to ext-svc 3306 port [tcp/*] succeeded!
root@ubuntu-focal:/#
# mysql-client
root@ubuntu-focal:/# mysql -u user -h ext-svc -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.5.5-10.7.4-MariaDB-1:10.7.4+maria~focal mariadb.org binary distribution
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
Kubernetes externalName Service
Next case is how if my external workload or API is domain based ? 🤔
For this case, we will using spec.externalName and about full docs, read carefully here .
Let’s go back to KinD cluster before, I will show the fun way how to use it with Kubernetes Ingress. First install the Ingress with the following steps from official docs .
After that create manifest Service and the Ingress one.
---
apiVersion: v1
kind: Service
metadata:
name: ext-landing
spec:
type: ExternalName
# can be your Db's DNS too
externalName: httpbin.org
# ingress
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ext-ingress
spec:
rules:
- http:
paths:
- backend:
service:
name: ext-landing
port:
number: 80
path: /
pathType: ImplementationSpecific
status:
loadBalancer: {}
Type the magical command aka kubectl apply
then test it with calling curl
command to localhost
.
curl -I http://localhost
HTTP/1.1 200 OK
Date: Wed, 13 Jul 2022 17:31:26 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9593
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Bump a fun way how to reverse proxy 😃😃
Closing Notes
- We learn about how to communicate workloads or APIs from external to internal cluster Kubernetes natively, based on ip’s or domain.
- For better security or ACL things, you may considering Kubernetes NetworkPolicy, read full docs here .
…
Thank You!!