Access Strimzi Kafka using Ingress Part-I

Hi Guys, Writing a blog after a very long time, recently I am setting up the strimzi kafka operator on the EKS cluster and it is pretty straight forward, deploy the operator using the helm-chart and then just create the cluster yaml file to get the kafka up and running. But while Accessing it outside Kubernetes Environment is a task in itself and it supports so many ways and has some restriction and constraints. I managed to get this done after so many tries by using the Kong-Ingress Controller. So I am writing this so it will be helpful for others, as this way it is not mentioned anywhere in the documentation or in other mediums. And if you are completely new to Stimzi Kafka and looking for a guide, How to setup it on Kubernetes, Then you can check the below mentioned blog series:-
I have divided this complete blog in two parts
∙ Part- I (this one)
∙ Part-II
Let’s Start Guys:-
After you have setup the strimzi kafka and you are able to access it by the kafka cli or any other method inside the kubernetes cluster. But now you need to give this cluster access to the services which are not running inside your k8’s environment. In that case you need the Ingress or Service Exposed via load-balancer to get this served to the external client.
I am assuming your configuration before exposing the Kafka, looks like this or somewhat similar to this:-
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-cluster
spec:
entityOperator:
topicOperator: {}
userOperator: {}
kafka:
authorization:
type: simple
superUsers:
- CN=admin-user
version: 3.3.1
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9094
type: internal
tls: true
authentication:
type: tls
config:
offsets.topic.replication.factor: 1
transaction.state.log.replication.factor: 1
transaction.state.log.min.isr: 1
log.message.format.version: "2.4"
retries: 5
storage:
type: persistent-claim
size: 2Gi
deleteClaim: true
zookeeper:
replicas: 3
storage:
type: persistent-claim
size: 1Gi
deleteClaim: true
Method:1 [ Load-Balancer ]
If we Use the Load-balancer, then the config looks like this, but there is one issue in this config:-
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-cluster
spec:
entityOperator:
topicOperator: {}
userOperator: {}
kafka:
authorization:
type: simple
superUsers:
- CN=admin-user
version: 3.5.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9094
type: loadbalancer
tls: true
authentication:
type: tls
config:
offsets.topic.replication.factor: 1
transaction.state.log.replication.factor: 1
transaction.state.log.min.isr: 1
log.message.format.version: "2.4"
storage:
type: persistent-claim
size: 2Gi
deleteClaim: true
zookeeper:
replicas: 3
storage:
type: persistent-claim
size: 1Gi
deleteClaim: true
Note:- Issue in this config is that, as you can see from the above config is that I have mentioned 3 replicas, so it will create 4 services to support this config in my EKS cluster and each will have a load-balancer assigned, so in total we will always have (N+1) load-balancer, where N is the no. of brokers, now suppose if we have a big cluster and number of replicas is more then it will be issue, If Cost is not a concern for you then you can go ahead with this, but if it is then Method-2 is for you.

Method:2. [ Ingress ]
Case-I:- In this Method we will use the type: ingress and the configuration looks like this.
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-cluster
spec:
entityOperator:
topicOperator: {}
userOperator: {}
kafka:
authorization:
type: simple
superUsers:
- CN=admin-user
version: 3.5.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9094
type: ingress
tls: true
authentication:
type: tls
configuration:
bootstrap:
host: kafka.beta.zerodhafundhouse.com
brokers:
- broker: 0
host: kafka-0.beta.zerodhafundhouse.com
- broker: 1
host: kafka-1.beta.zerodhafundhouse.com
- broker: 2
host: kafka-2.beta.zerodhafundhouse.com
class: internal-tcp
config:
offsets.topic.replication.factor: 1
transaction.state.log.replication.factor: 1
transaction.state.log.min.isr: 1
log.message.format.version: "2.4"
retries: 5
storage:
type: persistent-claim
size: 2Gi
deleteClaim: true
zookeeper:
replicas: 3
storage:
type: persistent-claim
size: 1Gi
deleteClaim: true
Note:- I have used the class: internal-tcp ( as my kong ingress-class is this only). you can modify it according to our environment, you can check the ingress class using the kubectl get ingressclass.
Now After applying this, if you check your ingress resource in the namespace where you cluster is deployed, you will see the ingress resource being created.

The interesting thing over here is this, if you see the address column, all is using the same load-balancer on which your ingress-controller is listening, That is quite better then the older approach (load-balancer).
But there is one issue in this, this will work perfectly fine if you are using the nginx ingress controller and have enabled the tls-passthrough, as mentioned in the documentation blog:- https://strimzi.io/blog/2019/05/23/accessing-kafka-part-5/
But what if we are using it in any other Ingress-controller, then it will be a issue….., Now let’s see the Case-2, which solves this issue and you can even use this with any ingress controller that supports the tcp traffic, which most of does do..
Case-II:- In this Method we will use the general approach regard-less of the ingress-controller type: cluster-ip and we will create the ingress route by ourselves as we do in general, while exposing the micro-services via ingress and the configuration will looks like this.
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: kafka-cluster
spec:
entityOperator:
topicOperator: {}
userOperator: {}
kafka:
authorization:
type: simple
superUsers:
- CN=admin-user
version: 3.5.0
replicas: 3
listeners:
- name: plain
port: 9092
type: internal
tls: false
- name: tls
port: 9094
type: cluster-ip
tls: true
authentication:
type: tls
configuration:
brokers:
- broker: 0
advertisedHost: kafka-0.beta.example.com
advertisedPort: 9095
- broker: 1
advertisedHost: kafka-1.beta.example.com
advertisedPort: 9096
- broker: 2
advertisedHost: kafka-2.beta.example.com
advertisedPort: 9097
config:
offsets.topic.replication.factor: 1
transaction.state.log.replication.factor: 1
transaction.state.log.min.isr: 1
log.message.format.version: "2.4"
storage:
type: persistent-claim
size: 2Gi
deleteClaim: true
zookeeper:
replicas: 3
storage:
type: persistent-claim
size: 1Gi
deleteClaim: true
Now after you have applied this config, you can see that 4 services will be create and all is having a type: cluster-ip as mentioned in the above config.

Now Let’s see the config-map of the brokers, thing to see in the config-map is Common listener configuration

Broker-0-cm:- [ kafka-cluster-kafka-0 ]

Broker-1-cm:- [ kafka-cluster-kafka-1 ]

Broker-2-cm:- [ kafka-cluster-kafka-0 ]

Now this is quite Important, if you connect to Kafka using any method for example:- kafka cli, it will try to find the brokers on the same url
[ kafka-0.beta.example.com:9095, kafka-1.beta.example.com:9096, kafka-2.beta.example.com:9097 ]
In order to support this, we need to expose the ingress on different ports. To accomplish this, we will need to create 4 Ingress resources for each service listed below.

Now Let’s See how to create the ingress and connect to cluster using kafka-cli in the Next Part.