<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Elias Vakkuri</title>
    <description>The latest articles on DEV Community by Elias Vakkuri (@eliasvakkuri).</description>
    <link>https://dev.to/eliasvakkuri</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F979064%2Fba495f13-557d-49d6-bf30-a68a3de0c7bd.png</url>
      <title>DEV Community: Elias Vakkuri</title>
      <link>https://dev.to/eliasvakkuri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eliasvakkuri"/>
    <language>en</language>
    <item>
      <title>Clusterception Part 3: Getting started with Kafka</title>
      <dc:creator>Elias Vakkuri</dc:creator>
      <pubDate>Mon, 19 Dec 2022 10:20:31 +0000</pubDate>
      <link>https://dev.to/eliasvakkuri/clusterception-part-3-getting-started-with-kafka-4ngh</link>
      <guid>https://dev.to/eliasvakkuri/clusterception-part-3-getting-started-with-kafka-4ngh</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of a series on running Kafka on Kubernetes on Azure. You can find links to other posts in the series &lt;a href="https://dev.to/eliasvakkuri/clusterception-running-kafka-on-kubernetes-on-azure-49ce"&gt;here&lt;/a&gt;. All code is available in &lt;a href="https://github.com/evakkuri/blog/tree/main/clusterception"&gt;my Github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this part, we'll install Kafka to our Kubernetes cluster using &lt;a href="https://strimzi.io/"&gt;Strimzi&lt;/a&gt; and try it out.&lt;/p&gt;




&lt;p&gt;As discussed in part 1 of this series, running Kafka on Kubernetes widens the choice of deployment platform. Managed Kubernetes is provided by almost every cloud provider, whereas managed Kafka is rarer.&lt;/p&gt;

&lt;p&gt;Strimzi makes it quite simple to start up your Kafka cluster. Note that Strimzi is not the only option for running Kafka in Kubernetes; another prominent alternative is &lt;a href="https://docs.confluent.io/operator/current/co-quickstart.html#co-long-quickstart"&gt;Confluent for Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Strimzi
&lt;/h2&gt;

&lt;p&gt;I'll install Strimzi on the Azure Kubernetes Cluster that we set up in the previous part of this series. We'll follow &lt;a href="https://strimzi.io/quickstarts/"&gt;Strimzi's quickstart&lt;/a&gt; for installing Strimzi. Select the "Minikube" option; it should work precisely similarly against AKS.&lt;/p&gt;

&lt;p&gt;I'll first create a new namespace for our Kafka resources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace kafka
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With version 0.32.0, Strimzi has introduced a one-line command for installation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s1"&gt;'https://strimzi.io/install/latest?namespace=kafka'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; kafka
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The script deploys the Strimzi Cluster Operator, which will run and administer the Kafka resources, and the required Kubernetes users and rights for it to function. In addition, the process installs several &lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/"&gt;Custom Resource Definitions&lt;/a&gt; or CRDs. These enable declarative deployment of Kafka resources supported by Strimzi.&lt;/p&gt;

&lt;p&gt;For convenience, I'll set &lt;code&gt;kafka&lt;/code&gt; as the default namespace to avoid having to write it out each time:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl config set-context &lt;span class="nt"&gt;--current&lt;/span&gt; &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;kafka
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You can also check out the CRDs that were installed:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get crd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The console shows several resources with the word &lt;code&gt;kafka&lt;/code&gt; in them. If interested, you can get further details with &lt;code&gt;kubectl describe&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe crd kafkas.kafka.strimzi.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now that is a long one! Lucky that you don't need to implement all that yourself. 😄&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a Kafka cluster
&lt;/h2&gt;

&lt;p&gt;With the CRDs created, I can deploy a Kafka cluster using a single resource definition in a YAML. I'll start with the sample YAML provided by Strimzi in their quickstart, linked previously. All scripts used in this post are also available in the series' &lt;a href="https://github.com/evakkuri/blog/tree/main/clusterception"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The YAML is as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;There are a lot of possible configurations when setting up the cluster. I'll not go into those in this post; that's a possible topic for the future. 🙂&lt;/p&gt;

&lt;p&gt;I'll create the cluster with &lt;code&gt;kubernetes apply&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; kafka-cluster.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can have a look at the Kubernetes Services that this created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many services with the name of your cluster prefixed; if you used the sample YAML, the prefix is &lt;code&gt;my-cluster&lt;/code&gt;. These services include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ZooKeeper&lt;/strong&gt;: ZooKeeper is Apache's general-purpose orchestrator for distributed services, used in Kafka and several other services like Hadoop. Note that you shouldn't need to interact with this directly; it just works in the background. Also, &lt;a href="https://www.youtube.com/watch?v=mT7dbLNCGtQ"&gt;Strimzi is working on removing this dependency&lt;/a&gt; to simplify the setup even further.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kafka Brokers&lt;/strong&gt;: As discussed in part 1, brokers are the actual worker servers containing all the topics and messages in Kafka. You can think of them as comparable to "nodes" in most other distributed services. We only have one broker in our setup, but we could scale up our cluster by simply increasing the value in &lt;code&gt;spec.kafka.replicas&lt;/code&gt; in the YAML.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bootstrap&lt;/strong&gt;: Strimzi simplifies connecting to Kafka by providing a bootstrap service. You only need to provide this service for any client process, and the Kafka protocol will connect to the broker containing your target topic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, you don't see an External IP on any of these services, and you'll need one for connecting to Kafka from outside Kubernetes. For this, you need to add an external listener. This is luckily easy to do - I'll add the following entry to &lt;code&gt;spec.kafka.listeners&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;- name: external
  port: 9094
  &lt;span class="nb"&gt;type&lt;/span&gt;: loadbalancer
  tls: &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you now apply the YAML and list your services, you'll see a service with an external IP for your broker and an external bootstrap service. The external bootstrap works the same as the internal bootstrap already added - you can use this as the single entry point for clients.&lt;/p&gt;

&lt;p&gt;I now created an external listener of type "LoadBalancer", but there are other types. You can find more information in &lt;a href="https://strimzi.io/blog/2019/04/17/accessing-kafka-part-1/"&gt;this series of posts by Strimzi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING:&lt;/strong&gt; You'll also see that &lt;code&gt;tls&lt;/code&gt; is set to false. This means that communication to Kafka &lt;em&gt;is not encrypted&lt;/em&gt;, so it's highly insecure. I'll return to this topic in the next part of this series, where I configure security for the Kafka cluster. &lt;/p&gt;

&lt;p&gt;For now, let's continue with these settings; however, don't send anything sensitive to your Kafka. After testing, you can remove the external listener or stop your AKS cluster to limit exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing connectivity
&lt;/h2&gt;

&lt;p&gt;Following the Strimzi quickstart, you'll find instructions for testing the Kafka cluster from inside Kubernetes. For this post, you can try it out also from outside Kubernetes with the external listener. You can do this do this with the same Docker image used in the quickstart, but with local Docker instead of Kubernetes - so you'll need Docker running.&lt;/p&gt;

&lt;p&gt;First, get the external IP of your external bootstrap service, for example, &lt;code&gt;my-cluster-kafka-external-bootstrap&lt;/code&gt;. With this in hand, start the console producer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; kafka-producer quay.io/strimzi/kafka:0.32.0-kafka-3.3.1 bin/kafka-console-producer.sh &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; EXTERNAL_BOOTSTRAP_IP:9094 &lt;span class="nt"&gt;--topic&lt;/span&gt; my-topic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The setting &lt;code&gt;-it&lt;/code&gt; connects an interactive terminal to the running container, and &lt;code&gt;--rm&lt;/code&gt; automatically removes the container when you exit the console.&lt;/p&gt;

&lt;p&gt;In another terminal, start the consumer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; kafka-consumer quay.io/strimzi/kafka:0.32.0-kafka-3.3.1 bin/kafka-console-consumer.sh &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; EXTERNAL_BOOTSTRAP_IP:9094 &lt;span class="nt"&gt;--topic&lt;/span&gt; my-topic &lt;span class="nt"&gt;--from-beginning&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write a message in the producer console, and you should see it appear in the consumer console. If so, you now have a functioning Kafka cluster in AKS! 🎉&lt;/p&gt;




&lt;p&gt;That's it for this post. Next time we'll look into setting up security for Kafka - see you then!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>apachekafka</category>
      <category>strimzi</category>
    </item>
    <item>
      <title>Clusterception Part 2: Initial Azure setup</title>
      <dc:creator>Elias Vakkuri</dc:creator>
      <pubDate>Sun, 04 Dec 2022 16:46:06 +0000</pubDate>
      <link>https://dev.to/eliasvakkuri/clusterception-part-2-initial-azure-setup-1bn6</link>
      <guid>https://dev.to/eliasvakkuri/clusterception-part-2-initial-azure-setup-1bn6</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of a series on running Kafka on Kubernetes on Azure. You can find links to other posts in the series &lt;a href="https://dev.to/eliasvakkuri/clusterception-running-kafka-on-kubernetes-on-azure-49ce"&gt;here&lt;/a&gt;. All code is available in &lt;a href="https://github.com/evakkuri/blog/tree/main/clusterception" rel="noopener noreferrer"&gt;my Github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In part 2 of the series, I will set up a VNET, Azure Container Registry, and Azure Kubernetes Service (AKS). The end goal is to set up the infrastructure so that we're ready to start deploying Kafka in the next part.&lt;/p&gt;




&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;For AKS, there are a LOT of different settings that you can tweak when provisioning your cluster - look at the length of the &lt;a href="https://learn.microsoft.com/en-us/azure/templates/microsoft.containerservice/managedclusters?pivots=deployment-language-bicep#resource-format" rel="noopener noreferrer"&gt;resource format definition&lt;/a&gt;. Especially in networking there are many options.&lt;/p&gt;

&lt;p&gt;To keep this post to a reasonable length, I will focus on AKS, and the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Securing access to AKS's control plane APIs (if there's one thing you secure, make it this one)&lt;/li&gt;
&lt;li&gt;Integration between AKS and Container Registry&lt;/li&gt;
&lt;li&gt;Expandability for future services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As I am creating a development cluster, we do not require production-grade settings for sensitive data. I'll look at configurations that are simple to implement and use and simultaneously increase your cluster's security.&lt;/p&gt;

&lt;p&gt;By the end, my architecture will look like this (diagram created with draw.io and Azure stencil):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqcqqoo852unx0jjwf5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqcqqoo852unx0jjwf5t.png" alt="Architecture diagram, created with Draw.io and Azure stencil"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have drawn AKS control plane outside of the VNET, as the control plane's nodes usually live in a separate VNET (and subscription) managed by Microsoft. There is in preview an option to deploy &lt;a href="https://learn.microsoft.com/en-us/azure/aks/api-server-vnet-integration" rel="noopener noreferrer"&gt;also the control plane to your VNET&lt;/a&gt;, but I don't see a reason for that here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Bicep
&lt;/h2&gt;

&lt;p&gt;I will set up the infrastructure in &lt;a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener noreferrer"&gt;Bicep language&lt;/a&gt;. I mainly use Terraform in projects, but Bicep looks like a good alternative for Azure-only setups. Over the older ARM templates, Bicep has a number of benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Easier to read and write:&lt;/em&gt; First and foremost, Bicep is much easier to read and write than ARM templates. I foresee much less wasted time figuring out where a curly brace is missing when validation won't pass. Also, the autocomplete and suggestions in VS Code work great.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Decorators:&lt;/em&gt; You can use parameter decorators as one easy way to document your solution and add validations. In the full templates, I use decorators to add a description and to set a list of allowed values.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Named subresources:&lt;/em&gt; We create the subnets as part of the VNET declaration, but then we immediately retrieve the subnet resources using the &lt;code&gt;existing&lt;/code&gt; keyword. This way, we can refer to the subnet directly, as we'll see when creating the AKS cluster.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Simpler modules:&lt;/em&gt; When using ARM templates, you need to deploy the linked templates somewhere Azure can reach them. With Bicep, Azure CLI combines all the modules into 1 ARM template, so it's enough to have all the templates locally available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One big drawback of Bicep against Terraform is that you can only manage Azure resources with Bicep. You need to manage Azure AD objects like users, groups, or service principals in another way, like directly with Azure CLI. Separating Azure and Azure AD feels like a weird division between services, but I guess Microsoft has its reasons. 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;I will not post the full templates in this post, as you can find them in &lt;a href="https://github.com/evakkuri/blog/tree/main/clusterception" rel="noopener noreferrer"&gt;my Github&lt;/a&gt;. Instead, I'll post smaller snippets below relevant to my topics.&lt;/p&gt;

&lt;p&gt;I'll deploy AKS and closely related resources via a separate template. I then call the AKS template from my main template as a module. I also output AKSs identities from the module and use those to assign relevant accesses to our Container Registry. I'll explain this more closely further down.&lt;/p&gt;

&lt;p&gt;Let's look at the most relevant pieces of the AKS template.&lt;/p&gt;

&lt;h3&gt;
  
  
  Linking the Container Registry
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The container images I will run in AKS need to come from somewhere. Public images might come from Docker Hub, for example, but private images are usually stored in Azure Container Registry. This connection will need to be set up for AKS to work.&lt;/p&gt;

&lt;p&gt;AKS pods and deployments use a &lt;code&gt;kubelet&lt;/code&gt; identity to authenticate to container registries. When creating an AKS cluster via Azure CLI, there is the option &lt;code&gt;--attach-acr&lt;/code&gt; - this deploys a user-assigned managed identity, assigns it as the kubelet identity in AKS, and gives it the AcrPull role in the Container Registry. The managed identity is created in the cluster's resource group, so users might not have access to the actual resource.&lt;/p&gt;

&lt;p&gt;With Bicep, I'll need to manually create and assign the kubelet identity. In addition, the cluster's control plane identity needs specific RBAC rights to manage the kubelet identity. Therefore, I'll use user-assigned managed identities for both. I set the cluster identity in &lt;code&gt;identity&lt;/code&gt; and kubelet identity in &lt;code&gt;properties.identityProfile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, I'll output the identities so I can use them for role assignments in the main template.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking for services
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;AKS has two main networking modes: Kubenet and Azure CNI. On a very high level, with Kubenet, only nodes get IPs from your subnet, and for pods, some address translation magic happens. With Azure CNI, both nodes and pods get assigned IPs. There are benefits to pods having IPs, like more transparent networking, but it also means that you will burn through your IP ranges much faster and require more planning with the networks you use.&lt;/p&gt;

&lt;p&gt;Previously only Azure CNI supported using a custom VNET, and Kubenet was only suggested for development and testing environments. Nowadays, also Kubenet supports custom VNETs and based on the documentation, both are fine for production deployments.&lt;/p&gt;

&lt;p&gt;Which to choose? It depends on your specific circumstances. I'm not an expert in the area, so I'll not go into too much detail now. I don't have to worry too much about IP ranges for this blog, so I'll go with Azure CNI. &lt;/p&gt;

&lt;p&gt;The only thing we need to configure is that the AKS internal IP ranges don't overlap with the IP ranges in our VNET. The actual values don't matter in our case; I just picked some I saw in the &lt;a href="https://learn.microsoft.com/en-us/azure/aks/configure-azure-cni#configure-networking---cli" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We'll use &lt;a href="https://learn.microsoft.com/en-us/azure/aks/configure-azure-cni#dynamic-allocation-of-ips-and-enhanced-subnet-support" rel="noopener noreferrer"&gt;dynamic allocation of IPs for pods&lt;/a&gt;. With this option, Azure deploys nodes and pods to separate subnets, and pod IPs are assigned dynamically from their subnet. This has several benefits, as outlined in the documentation. In Bicep, I only need to create a separate subnet and assign it to pods in the &lt;code&gt;agentPoolProfiles&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;Finally, I'll set &lt;code&gt;publicNetworkAccess&lt;/code&gt; as &lt;code&gt;Enabled&lt;/code&gt;, as I want to reach the cluster and its services from my laptop. As a side note, there are also separate settings to create a private cluster. I'm not entirely sure how these settings relate to one another - I might investigate this more in a future post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication: &lt;code&gt;aadProfile&lt;/code&gt; and &lt;code&gt;disableLocalAccounts&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As mentioned earlier, we want to limit access to AKS's control plane. AKS has a pretty nice-looking integration with Azure AD nowadays, so I'll use that for both authentication and authorization for admin operations.&lt;/p&gt;

&lt;p&gt;I enable Azure AD for control plane operations in &lt;code&gt;aadProfile.enableAzureRBAC&lt;/code&gt; and disable local Kubernetes admin accounts with &lt;code&gt;disableLocalAccounts&lt;/code&gt;. This way, control plane operations are authorized via Azure AD, simplifying maintenance. &lt;/p&gt;

&lt;p&gt;Setting &lt;code&gt;aadProfile.managed&lt;/code&gt; is related to how AKS links with Azure AD internally. In terms of using the cluster, it shouldn't matter. However, &lt;code&gt;managed&lt;/code&gt; is the newer setting, so I'll set it on.  &lt;/p&gt;

&lt;p&gt;Finally, in &lt;code&gt;aadProfile.adminGroupObjectIDs&lt;/code&gt;, we assign an admin group for the cluster. We provide the object ID of the group as a parameter. You can achieve the same result by assigning the "Azure Kubernetes Service RBAC Cluster Admin" role to any Azure AD identity you wish.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;apiServerAccessProfile&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I'll set some IP range restrictions for API server access so that &lt;code&gt;kubectl&lt;/code&gt; commands can only be run from these IP ranges. I provide them as parameters to the main profile and then pass them to the AKS module.&lt;/p&gt;

&lt;p&gt;I could also disable access to the control plane from public networks altogether, which would be preferable for production deployments. However, for this series, we're not dealing with anything sensitive, plus I don't want the hassle of creating jump machines or VPN connections. As such, I consider Azure AD authentication plus IP range restriction a good combination.  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;autoUpgradeProfile&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here, I set automatic upgrades for the Kubernetes version. AKS supports specifying the desired level of automatic version upgrades - I'll go with the suggested "patch" level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying AKS as a module
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Finally, as mentioned previously, I deploy AKS and related resources as a submodule and assign access rights to the Container Registry for the kubelet identity.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I didn't do
&lt;/h3&gt;

&lt;p&gt;There's a lot more that you could do by tweaking the properties. One thing that might be a good addition would be to enable SSH access to the cluster nodes for maintenance scenarios. However, this also requires securing network access properly, which goes off this post's focus. We'll revisit the topic later on if needed.&lt;/p&gt;

&lt;p&gt;Also, additional security options are available, like Microsoft Defender for Cloud. This sounds like a good idea for production deployments, but I don't see it as necessary for this post.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Let's deploy a service to our cluster to verify that everything is running as expected. We'll follow the &lt;a href="https://learn.microsoft.com/en-us/azure/aks/tutorial-kubernetes-prepare-app" rel="noopener noreferrer"&gt;Microsoft tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let's login to the cluster API server with &lt;code&gt;kubelogin&lt;/code&gt; and check connectivity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks get-credentials \
  --resource-group clusterception \
  --name clusterceptionaks

KUBECONFIG=&amp;lt;path to kubeconfig&amp;gt; kubelogin convert-kubeconfig

kubectl get services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that working correctly, let's log in to our Container Registry and push the tutorial frontend image there. This way, we can test connectivity between the cluster and the registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az acr login --name clusterceptionacr

docker pull mcr.microsoft.com/azuredocs/azure-vote-front:v1

docker tag \
  mcr.microsoft.com/azuredocs/azure-vote-front:v1 \
  clusterceptionacr.azurecr.io/azure-vote-front:v1

docker push clusterceptionacr.azurecr.io/azure-vote-front:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's apply the &lt;a href="https://github.com/Azure-Samples/azure-voting-app-redis/blob/master/azure-vote-all-in-one-redis.yaml" rel="noopener noreferrer"&gt;YAML&lt;/a&gt; with the Deployment and Service definitions and using the image in our Container Registry as explained in &lt;a href="https://learn.microsoft.com/en-us/azure/aks/tutorial-kubernetes-deploy-application?tabs=azure-cli#update-the-manifest-file" rel="noopener noreferrer"&gt;the tutorial instructions&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f sample-app/azure-vote.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can get the external IP of the frontend service by running the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get service azure-vote-front
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this command does not return an IP, wait for a few minutes, then try again. Once you have the IP, navigate there, and the voting app front should greet you. Great stuff!&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;What a long article! This really goes to show the depth of configuration options in AKS. Microsoft has done much work to simplify the setup, but for long-term operation and production deployments, you often need a dedicated team that understands all the knobs and levers. This gap in the required level of knowledge is one of the reasons why I usually prefer PaaS services.&lt;/p&gt;

&lt;p&gt;In any case, I hope you got something out of this post! Please join me for the next part when we deploy Kafka to our AKS cluster.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>azure</category>
      <category>bicep</category>
    </item>
    <item>
      <title>Clusterception Part 1: Introduction</title>
      <dc:creator>Elias Vakkuri</dc:creator>
      <pubDate>Thu, 01 Dec 2022 19:46:17 +0000</pubDate>
      <link>https://dev.to/eliasvakkuri/clusterception-part-1-introduction-38g6</link>
      <guid>https://dev.to/eliasvakkuri/clusterception-part-1-introduction-38g6</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of a series on running Kafka on Kubernetes on Azure. You can find links to other posts in the series &lt;a href="https://dev.to/eliasvakkuri/clusterception-running-kafka-on-kubernetes-on-azure-49ce"&gt;here&lt;/a&gt;. All code is available in &lt;a href="https://github.com/evakkuri/blog/tree/main/clusterception"&gt;my Github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this first part, I'll introduce the central technologies used in the rest of the series.&lt;/p&gt;




&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;I usually work with Platform-as-a-Service (PaaS) by choice. In Azure this means running application in, for example, Azure Web Apps or Azure Functions instead of Kubernetes.&lt;/p&gt;

&lt;p&gt;I like having the cloud provider take care of hairy details like certificates and intra-cluster communications. I like using Azure AD for all authentication and authorization, both for users and services, instead of setting up certificate authorities and worrying about rotating keys. I like sensible defaults instead of a laundry list of possible configurations.&lt;/p&gt;

&lt;p&gt;I will need to look at many of these hairy details during this series. As such, I will not be exactly in my comfort zone.&lt;/p&gt;

&lt;p&gt;So why learn about all of this stuff? Well, firstly, both Kafka and Kubernetes are wildly popular technologies used in many organizations, big and small. So from a pure market value point of view, there are worse things you could spend your time on learning.&lt;/p&gt;

&lt;p&gt;Secondly, even though many PaaS services hide the details from us, getting to know what happens behind the curtain is useful. It will enable better decision-making with a better idea of the tradeoffs, help debug weird errors, and give an understanding of what it would take to run these technologies outside of a cloud environment.&lt;/p&gt;

&lt;p&gt;In summary, I am excited about what's to come!&lt;/p&gt;




&lt;h2&gt;
  
  
  The main characters
&lt;/h2&gt;

&lt;p&gt;Let's introduce the two main cluster types that I will be discussing. Now, I'm taking a very simplified, user-centric view of both of these. So don't get me wrong, I greatly appreciate both of these as feats of engineering, but I'll avoid details in this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kafka
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kafka.apache.org"&gt;Apache Kafka&lt;/a&gt; is, in its own words, a "distributed event streaming platform". On a very high level, you have a bunch of &lt;em&gt;topics&lt;/em&gt; hosted on &lt;em&gt;brokers&lt;/em&gt;, to which &lt;em&gt;producers&lt;/em&gt; send messages and from which &lt;em&gt;consumers&lt;/em&gt; read messages. From Kafka's point of view, messages are just bytes, so they can be almost anything - it's up to the producers and consumers to assign meaning to the byte stream. These core services allow you to build elaborate systems that pass and process messages between applications.&lt;/p&gt;

&lt;p&gt;Kafka is, by design, relatively simple in terms of its services. However, there is a Kafka ecosystem of other services that integrate with Kafka and offer crucial extensions to functionality. Examples include Schema Registry for defining message structure between producers and consumers and Kafka Connect for configuration-based integrations between Kafka and other systems. I will be looking at these in later parts of this blog series. &lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;, on the other hand, is "an open-source system for automating deployment, scaling, and management of containerized applications". What Kubernetes tries to solve is how to distribute available compute capacity to applications, how to make sure the applications keep running during software and hardware breakages, and how to expose the applications inside and outside of the cluster in a structured way. &lt;/p&gt;

&lt;p&gt;In a high-level workflow, you put one or more containers that need to work together into a &lt;em&gt;pod&lt;/em&gt;, organize one or more pods into a &lt;em&gt;deployment&lt;/em&gt; that defines, for example, the resource allocation, and then expose the deployment as a &lt;em&gt;service&lt;/em&gt;. Again, very simplified - there are loads more core concepts in Kubernetes and an infinite amount of extensions and abstractions you can install to your cluster. I will discuss examples later on in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why run Kafka on Kubernetes?
&lt;/h2&gt;

&lt;p&gt;Every cloud provider has a managed Kubernetes offering available. However, managed Kafka is rare; out of the big players, only AWS has a managed Kafka offering. Therefore, Kafka on Kubernetes allows a broader selection of cloud service providers.&lt;/p&gt;

&lt;p&gt;There are also good implementations available to get started quickly. I will be using &lt;a href="https://strimzi.io/"&gt;Strimzi&lt;/a&gt; during this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not go with Azure Event Hubs for Kafka?
&lt;/h2&gt;

&lt;p&gt;Based on the documentation, Azure Event Hub offers transparent support for Kafka workloads, plus a schema registry to boot. So in principle, I could use Event Hubs and forget about running Kafka on Kubernetes altogether.&lt;/p&gt;

&lt;p&gt;However, there are two reasons why I'm going with Kubernetes at this stage. Firstly, if you have a hybrid scenario where your solution needs to run on actual Kafka, you'll need to know eventually about many things that you can forget about when using Event Hubs. So better to eat the frog early and develop against something as close to the runtime environment as possible.&lt;/p&gt;

&lt;p&gt;Secondly, through this series, I will look at several Kafka ecosystem components that need to run somewhere. So I'll need a platform for the other components, and Kubernetes is a sensible choice, especially for hybrid scenarios.&lt;/p&gt;

&lt;p&gt;If, however, you are migrating an on-premise Kafka cluster completely to Azure, then Event Hubs and, for example, Container Apps can make an architecture that's easier to manage. That's something I might revisit in a later post. :)&lt;/p&gt;




&lt;p&gt;Hopefully, you found this short introduction interesting! Do join me for part 2 in this series, where I'll set up the initial Azure infrastructure (coming soon)&lt;/p&gt;

</description>
      <category>apachekafka</category>
      <category>kubernetes</category>
      <category>azure</category>
      <category>strimzi</category>
    </item>
    <item>
      <title>Clusterception: Running Kafka on Kubernetes (on Azure)</title>
      <dc:creator>Elias Vakkuri</dc:creator>
      <pubDate>Thu, 01 Dec 2022 18:26:54 +0000</pubDate>
      <link>https://dev.to/eliasvakkuri/clusterception-running-kafka-on-kubernetes-on-azure-49ce</link>
      <guid>https://dev.to/eliasvakkuri/clusterception-running-kafka-on-kubernetes-on-azure-49ce</guid>
      <description>&lt;p&gt;This is a collection of posts on running Kafka on Kubernetes, based on my journey into the topic. In the end, we will be running a cluster (or actually several different clusters) on a cluster - hence, "Clusterception".&lt;/p&gt;

&lt;p&gt;Please find the links to the individual posts below. I wish you safe travels and hopefully also some learnings!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/eliasvakkuri/clusterception-part-1-introduction-38g6"&gt;Part 1: Introduction&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/eliasvakkuri/clusterception-part-2-initial-azure-setup-1bn6"&gt;Part 2: Initial Azure setup&lt;/a&gt;&lt;br&gt;
Part 3: Setting up Kafka on Kubernetes with Strimzi (coming soon)&lt;/p&gt;

&lt;p&gt;Further parts to be added!&lt;/p&gt;

</description>
      <category>apachekafka</category>
      <category>kubernetes</category>
      <category>azure</category>
    </item>
  </channel>
</rss>
