<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>API Server on Digi Hunch</title><link>https://static.digihunch.com/tag/api-server/</link><description>Recent content in API Server on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 08 Apr 2025 14:43:30 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/api-server/index.xml" rel="self" type="application/rss+xml"/><item><title>Build and Manage Kubernetes Clusters</title><link>https://static.digihunch.com/2022/09/build-a-kubernetes-cluster/</link><pubDate>Fri, 23 Sep 2022 11:50:00 -0400</pubDate><guid>https://static.digihunch.com/2022/09/build-a-kubernetes-cluster/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-cluster.webp" alt="Featured image of post Build and Manage Kubernetes Clusters" /&gt;&lt;p class="wp-block-paragraph"&gt;There are numerous options to build a Kubernetes cluster. If your company has a multi-cloud strategy, most likely you will have to deal with cluster creation on multiple cloud platform or on virtual machines on premise. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Most likely, the chosen cloud platform already make it simple for us. However, it is still important to understand what it really takes to build a Kubernetes cluster. In general, we need to figure out these tasks:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Decide where to host the computing infrastructure (i.e. Node) : on premise or public cloud;&lt;/li&gt;&#10;&lt;li&gt;Choose a Kubernetes release: either the vanilla release or one of the third-party distributions;&lt;/li&gt;&#10;&lt;li&gt;Install Kubernetes to the computing environment, and integrate it with the cloud platform;&lt;/li&gt;&#10;&lt;li&gt;Determine required add-ons (e.g. Istio or Linkerd for Service Mesh, dashboard utility, etc);&lt;/li&gt;&#10;&lt;li&gt;Deploy application workload to Kubernetes platform;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A public cloud platform provider usually can assist you with task 1 through 3, and partially 4, depending on the provider. If your Kubernetes resides on private cloud or on-prem environment, you can use a Platform solution such as VMware Tanzu or Openshift, which usually covers task 1, 3 and 4. There is no standard about what task these platform solution must address. Therefore it is important to have this list of tasks in mind in order to make a good comparison. I will discuss each of the tasks in this post.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-hosting-environment"&gt;Hosting environment&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Nodes are the building blocks of a Kubernetes cluster. We need master nodes as well as worker nodes. In addition, a working cluster also requires storage, and networking infrastructure. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Public cloud platforms typically provides control plane as a service, obviating administrator&amp;#8217;s effort to provision master nodes. For example, the control plane of Azure AKS has two levels of uptime commitment: a free tier of 99.5% SLO and a paid tier with an SLA of 99.95% (using AZs) and 99.9% (without using AZs). This uptime commitment applies to control plane only and do not apply to worker nodes. The management of etcd store is also a responsibility of the cloud provider, which frees up the cluster administrator from managing etcd store. However, they cannot access etcd store either. This is not very convenient because as the size of the cluster grows it is a common requirement to connect to etcd store for troubleshooting purpose.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The deployment APIs for public cloud allow the cluster administrator to define the instance size, count and availability zone for the worker nodes. They also automatically register the worker nodes to control plane so that the cluster administrators do not have to do so by themselves. As to &lt;a href="https://static.digihunch.com/2022/07/kubernetes-storage-on-azure-1-of-3-built-in-storage-and-nfs/"&gt;storage&lt;/a&gt;, the public cloud usually provide some default storage classes based on their storage as service. For networking device, the cluster provision process automatically configures the cloud API so the cluster can manage cloud resources such as network load balancer. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With private cloud or data centre, we usually use virtual machines, or bare-metal servers. Cluster administrators will need to make their own control plane with master nodes. and install worker nodes and register them to the master nodes. The Kubernetes Installation section below will discuss this.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Kubernetes release&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you have to install Kubernetes, you have to think about the Kubernetes release being used. You can use the binary from official Github &lt;a href="https://github.com/kubernetes/kubernetes"&gt;repository&lt;/a&gt;. For example, the &lt;a href="https://github.com/kubernetes/kubernetes/releases/tag/v1.24.3"&gt;release note&lt;/a&gt; of version 1.24.3 points to the &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md"&gt;change log&lt;/a&gt; file for &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#downloads-for-v1243"&gt;download&lt;/a&gt; links to &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#server-binaries"&gt;server binaries&lt;/a&gt;, &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#node-binaries"&gt;node binaries&lt;/a&gt;. This is the vanilla Kubernetes release.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from the vanilla release, many developers build their own distributions, based off forks of the Kubernetes project. CNCF has a page to keep track of certified Kubernetes distributions. Some of the distributions are open source and can be used for on-prem infrastructure. Here is a list of top players:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-black-color has-cyan-bluish-gray-background-color has-text-color has-background"&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Distribution Name&lt;/th&gt;&lt;th&gt;Repo&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://distro.eks.amazonaws.com/"&gt;EKS Distro&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/aws/eks-distro"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Used in EKS managed service or EKS Anywhere for on-prem infrastructure&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://docs.microsoft.com/en-us/azure-stack/user/azure-stack-kubernetes-aks-engine-overview?view=azs-2108#overview-of-the-aks-engine"&gt;AKS Engine&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/Azure/aks-engine"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Used in Azure Stack for on-prem infrastructure. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://cloud.google.com/kubernetes-engine/"&gt;Google Kubernetes Engine&lt;/a&gt;&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;td&gt;Used in GKE managed service only. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://docs.openshift.com/container-platform/4.8/welcome/oke_about.html"&gt;OpenShift Kubernetes Engine&lt;/a&gt;&lt;br&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/openshift/kubernetes"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Community distribution (OKD, or &lt;a href="https://www.okd.io/"&gt;OpenShift Kubernetes Distribution&lt;/a&gt;) is the open-source upstream.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://rancher.com/docs/rke/latest/en/"&gt;Rancher Kubernetes Engine&lt;/a&gt; (RKE)&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/rancher/rke"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;still using Docker as container runtime. Supported CNI include: Canal, Flannel, Calico and Weave&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://k3s.io/"&gt;K3s&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/k3s-io/k3s"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Lightweight distro without small resource requirement. Great for Edge, IoT, ARM etc&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://docs.rke2.io/"&gt;RKE2&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/rancher/rke2"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Originally named RKE government. Supports deployment via Cluster API. Supports containerd as container runtime. Supported CNI include: Cillium, Calico, Canal and Multus. Lightweight&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;VMware Tanzu&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/vmware-tanzu/community-edition"&gt;Link&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://tanzu.vmware.com/kubernetes-grid"&gt;VMWare Tanzu Grid&lt;/a&gt; and &lt;a href="https://tanzucommunityedition.io/"&gt;VMWare Tanzu Community&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Above is just a very incomplete list of Kubernetes distributions. There are many more distributions that are not on this list, such as CoreOS Tectonic, Docker Kubernetes, Heptio, Mesosphere, Mirantis, Platform9, Stackube, Telekube. For full details of how each distribution is different, you will need to go over their documents. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With the selected distribution, we still need to deploy the binaries to the nodes. We can do this with a cluster management platform, or standalone installers. Cluster management platform can also help us with baseline configuration (e.g. IAM integration, CNI plugin), in addition to the binary installation. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Cluster Management Platform&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These platforms are also sometimes referred to as container management platform.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For example, OpenShift container platform is a self-managed platform based on OpenShift Kubernetes Engine and can run on a variety of hosting environment, public cloud, or private cloud. The &lt;a href="https://docs.openshift.com/container-platform/4.7/installing/index.html"&gt;installation steps &lt;/a&gt;varies depending on the hosting environment. When running on public cloud such as &lt;a href="https://aws.amazon.com/rosa/"&gt;AWS&lt;/a&gt; (aka &lt;a href="https://docs.openshift.com/rosa/welcome/index.html"&gt;ROSA&lt;/a&gt;), the public cloud only provides computing nodes and associated infrastructure. Many corporate with multi-cluster strategy use this option on public cloud to keep their Kubernetes cluster fleet consistent across cloud vendors. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Openshift container platform also packages some useful open-source add-ons with corporate support, for example:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/what-is-openshift-service-mesh"&gt;OpenShift Service Mesh&lt;/a&gt;: Istio&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.redhat.com/en/technologies/storage/ceph"&gt;Ceph Storage&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.redhat.com/en/technologies/storage/gluster"&gt;Gluster Storage&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://docs.openshift.com/container-platform/4.10/cicd/gitops/understanding-openshift-gitops.html"&gt;OpenShift GitOps&lt;/a&gt; (ArgoCD)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://docs.openshift.com/container-platform/4.10/cicd/pipelines/op-release-notes.html"&gt;OpenShift Pipelines&lt;/a&gt;&amp;nbsp;(Tekton)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.redhat.com/en/technologies/cloud-computing/quay"&gt;Quay&lt;/a&gt; (Quay Image Registry)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/openshift-streams-for-apache-kafka"&gt;OpenShift Streams for Apache Kafka&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless"&gt;OpenShift Serverless&lt;/a&gt; (Knative Serving)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Red Hat&amp;#8217;s strategy is to pick the most renowned open-source project in each domain and add enterprise support to it. However, for management portal, Red Hat developed its own &lt;a href="https://www.redhat.com/en/technologies/management/advanced-cluster-management"&gt;Advanced Cluster Management&lt;/a&gt; tool for Kubernetes, and &lt;a href="https://www.redhat.com/en/blog/open-sourcing-red-hat-advanced-cluster-management-kubernetes"&gt;open-sourced&lt;/a&gt; it in 2020 in the upstream &lt;a href="https://open-cluster-management.io/"&gt;project&lt;/a&gt; &lt;a href="https://github.com/open-cluster-management-io/OCM"&gt;Open Cluster Management&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Similar to OpenShift, VMware Tanzu also attempts to cover the domains, with a smaller product portfolio:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://tanzu.vmware.com/service-mesh"&gt;Service Mesh&lt;/a&gt;: compatible with &lt;a href="https://tanzu.vmware.com/content/blog/istio-mode-tanzu-service-mesh"&gt;Istio&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://tanzu.vmware.com/mission-control"&gt;Mission Control&lt;/a&gt;: management portal&lt;/li&gt;&#10;&lt;li&gt;Observability&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Google &lt;a href="https://cloud.google.com/anthos/docs/concepts/overview"&gt;Anthos&lt;/a&gt; is also a container platform. Their product line include, but not limited to:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://cloud.google.com/anthos/config-management"&gt;Anthos Config Management&lt;/a&gt; (ACM)&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://cloud.google.com/anthos/service-mesh"&gt;Anthos Service Mesh&lt;/a&gt; (ASM, an Istio distribution)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;SUSE, the developer of RKE, RKE2, and K3s) offers Rancher as multi-cluster management platform. Apart from the engines, SUSE also offers Lonhorn as a storage solution. However, they do not have offerings for service mesh or GitOps. So there is no doubt that Red Hat OpenShift has the most complete portfolio for Kubernetes.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are also companies that only offers management platforms without their own Kubernetes distribution. For example:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://platform9.com/docs/kubernetes/about-pmk"&gt;Platform9&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rafay.co/"&gt;Rafay&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Product capabilities in this category vary a lot and you should refer to their specific documentation to understand. You will probably see a stack chart from each of the platform provider (e.g. SUSE Enterprise Container, &lt;a href="https://cloud.redhat.com/blog/introducing-red-hat-openshift-container-platform"&gt;OpenShift&lt;/a&gt;, &lt;a href="https://docs.vmware.com/en/VMware-Tanzu/services/tanzu-adv-deploy-config/GUID-components.html"&gt;Tanzu&lt;/a&gt;, &lt;a href="https://cloud.google.com/blog/topics/developers-practitioners/what-are-my-hybrid-and-multicloud-deployment-options-anthos"&gt;Anthos&lt;/a&gt;, &lt;a href="https://rafay.co/why-rafay/#what-rafay-does"&gt;Rafay&lt;/a&gt;) with all technology integrations.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Cluster Installation Tools&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As we saw in the installation steps for OpenShift, they are highly dependent on platform. With public cloud, the provisioning process also applies only to a specific platform. Since Kubernetes Installation process is tedious, some tools emerged to help, for example: &lt;a href="https://github.com/kubernetes-sigs/kubespray"&gt;kubespray&lt;/a&gt;, &lt;a href="https://github.com/kubernetes/kubeadm"&gt;kubeadm&lt;/a&gt;, &lt;a href="https://github.com/kubernetes/kops"&gt;kops&lt;/a&gt; and Cluster API. These are governed by &lt;a href="https://github.com/kubernetes/community/tree/master/sig-cluster-lifecycle"&gt;SIG cluster lifecycle&lt;/a&gt; special interest group. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here are some traditional options to install a Kubernetes clusters:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;kube-up&lt;/strong&gt;: the first tool to build cluster from 2015. It has been deprecated.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Kubeadm&lt;/strong&gt;: a tool built to provide best-practice &amp;#8220;fast paths&amp;#8221; for creating Kubernetes clusters that are minimum viable, and secure. Kubeadm&amp;#8217;s scope is limited to the local node filesystem and the Kubernetes API, and it is intended to be a composable building block of higher level tools. It is first released in Sep 2016. The high level configuration steps goes through initialization (kubeadm init), control plane (kubeadm join control plane), and node (kubeadm join node). Kubeadm does not integrate with cloud providers and it does not install addons (auth, monitoring, CNI, storage class)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Kubespray&lt;/strong&gt;: runs on bare metal or VMs using Ansible for provisioning and orchestration. The first release was in Oct 2015. Since v2.3 (Oct 2017) kubespray started to use kubeadm internally. In addition to kubeadm, kubespray configures CNI, storage class, other CRI. It supports cloud providers and air-gap environment. However it does not support infrastructure management.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The options above are official options. You may use kubeadm and kubespray to quickly (i.e. in an hour) spin up clusters for education purposes. However, with their limitations, it typically requires a lot of efforts to build a production-grade cluster with the needed addons and integrations. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from the official options, there are also unofficial tools such as &lt;a href="http://kubicorn.io/"&gt;kubicorn&lt;/a&gt;, which was first introduced in 2018 as a cluster management framework with modular support for cloud providers. However it appears to be short-lived.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the next two sections, we introduce kops and cluster API, two most recent projects to install cluster.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Kops&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The kops utility directly perform the provisioning and orchestration via API to the cloud deployment engine. Kops, with first release in Oct 2016, is tightly integrated with the unique features of the cloud providers (e.g. AWS: ASG, ELB, EBS, KMS, S3, IAM). However, kops is only CLI without controller-style reconciliation. It does not support baremetal or vsphere. It also bundles addons with fixed version.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When picking a tool to install cluster, we need to strike a balance between how much simplification the tool brings, and how many different platform the installer can work with. &lt;a href="https://kops.sigs.k8s.io/"&gt;Kops&lt;/a&gt; appears to be such a good compromise. It works with a number of cloud platforms using different set of APIs, although most are in alpha and beta stages today. &lt;a href="https://kops.sigs.k8s.io/getting_started/aws/"&gt;Here&lt;/a&gt; is how to install cluster on AWS. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both kops and Cluster API have &lt;a href="https://thenewstack.io/cluster-api-kops-or-both-for-kubernetes-multicluster-deployments/"&gt;good momentum&lt;/a&gt; but they work differently. &lt;a href="https://cluster-api.sigs.k8s.io/"&gt;Cluster API&lt;/a&gt; was first released in Mar 2019, and is currently less mature than kops. However, it is declarative and may reflect the direction of where cluster lifecycle management is heading.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Cluster API&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://cluster-api.sigs.k8s.io/"&gt;Cluster API&lt;/a&gt; focuses on following areas:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Manage cluster &lt;span style="text-decoration: underline" class="underline"&gt;lifecycle &lt;/span&gt;declaratively&lt;/li&gt;&#10;&lt;li&gt;Infrastructure abstraction (e.g. computing, storage, networking, security, etc)&lt;/li&gt;&#10;&lt;li&gt;Utilizing existing tools (e.g. kubeadm, cloud-init)&lt;/li&gt;&#10;&lt;li&gt;Modular and pluggable: to be adaptable to different infrastructure providers.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It involves a number of CRs as illustrated in its &lt;a href="https://cluster-api.sigs.k8s.io/user/concepts.html#concepts"&gt;diagram&lt;/a&gt;. We should be clear on the providers for Bootstrap, Infrastructure and Control Plane.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The biggest benefit is the controller pattern to manage the entire lifecycle of a cluster. This allows managing clusters with GitOps, and rolling upgrade of the cluster. It also allows for declarative node scaling, self healing and multi-cluster management.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The client utility for is &lt;a href="https://cluster-api.sigs.k8s.io/clusterctl/overview.html"&gt;clusterctl&lt;/a&gt;, and with that along with the manifest, we can create a cluster in a few commands. A lot of workflows are still in development but we can take a look at its &lt;a href="https://cluster-api.sigs.k8s.io/user/quick-start.html#quick-start"&gt;quick start&lt;/a&gt; guide to get a taste of how it works. The installation steps vary a lot based on the environment and the cluster. Also it introduces the separation of management cluster and workload cluster.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Workload cluster is the target cluster being created, as per the manifests.&lt;/li&gt;&#10;&lt;li&gt;Management cluster is where you keep track of the workload cluster being managed. You can manage multiple workload clusters from a single management cluster. Note that this management cluster will store credentials about workload clusters, and may become a single point of failure.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although Cluster API reflects a great initiative to standardize the provisioning of Kubernetes cluster, whether it will succeed has to do with the level of complexity. In the next section, we will get a taste of how it looks to deploy a Kubernetes cluster in a lab.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="516" height="181" src="https://static.digihunch.com/wp-content/uploads/2022/08/diagram.png" alt="" class="wp-image-6757"/&gt;&lt;figcaption class="wp-element-caption"&gt;Management cluster vs workload cluster&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the lab, I use my MacBook to create a management cluster with &lt;a href="https://kind.sigs.k8s.io/"&gt;KinD&lt;/a&gt;. Then we configure a workload cluster in AWS from the management cluster. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Cluster API Lab&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that the steps here are based on the &lt;a href="https://cluster-api.sigs.k8s.io/user/quick-start.html#quick-start"&gt;quick start guide&lt;/a&gt; on Cluster API document. Also, there is a bug with the AWS provider so the end of the lab will report a warning. The main purpose of this lab is to demonstrate how Cluster API is supposed to work, even though it still has yet to mature.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To start, I install clusterctl (the cluster API client utility), clusterawsadm (the utility specific for AWS) on MacBook, then start a simple KinD cluster.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.2.0/clusterctl-darwin-amd64 -o clusterctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x ./clusterctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo mv ./clusterctl /usr/local/bin/clusterctl&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusterctl version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -L https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/download/v1.4.1/clusterawsadm-darwin-amd64 -o clusterawsadm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod +x clusterawsadm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo mv clusterawsadm /usr/local/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusterawsadm version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kind create cluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;So far, I installed the required utility and a KinD cluster on MacBook. Then I use clusterawsadm to create InstanceProfile, ManagedPolicy and IAM Roles required for cluster creation. The AWS region and access are configured as environment variables:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_REGION&lt;span style="color:#f92672"&gt;=&lt;/span&gt;us-east-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_ACCESS_KEY_ID&lt;span style="color:#f92672"&gt;=&lt;/span&gt;AKIAXXXXXXXXXXX&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_SECRET_ACCESS_KEY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;J8ByduiofpwuisDjDoijOISDs&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusterawsadm bootstrap iam create-cloudformation-stack&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This runs a CloudFormation stack to create the permission related resources:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1556" height="464" src="https://static.digihunch.com/wp-content/uploads/2022/08/image-1.png" alt="" class="wp-image-6795"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Then I initialize the management cluster with the clusterctl utility, specifying AWS as a provider. I also need to assign the environment variable AWS_B64ENCODED_CREDENTIALS with proper value: &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_B64ENCODED_CREDENTIALS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;clusterawsadm bootstrap credentials encode-as-profile&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusterctl init --infrastructure aws&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now I use clusterctl to generate the manifest for the workload cluster. In environment variables, I specify cluster and node sizes, SSH key name, control plane machine type and node machine type:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_SSH_KEY_NAME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;cskey&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_CONTROL_PLANE_MACHINE_TYPE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t3.large&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export AWS_NODE_MACHINE_TYPE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;t3.large&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusterctl generate cluster myekscluster --kubernetes-version 1.24.3 --control-plane-machine-count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; --worker-machine-count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &amp;gt; capi-quickstart.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -f capi-quickstart.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;At the end I tell the management cluster to create a workload cluster as per the manifest, by simply declaring the CRs. It will take some time for the cluster to create, and there are a number of ways to monitor the progress. You can monitor the log on the controller pods in their respect namespaces. You can also check the cluster status with:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get kubeadmcontrolplane&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;clusterctl describe cluster myekscluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Currently there is a &lt;a href="https://github.com/kubernetes-sigs/cluster-api/issues/6417"&gt;bug&lt;/a&gt; and the commands at the end will report as below:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="2423" height="206" src="https://static.digihunch.com/wp-content/uploads/2022/08/image.png" alt="" class="wp-image-6785"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hopefully the bug will be fixed shortly. To delete the cluster, simply delete the resources in the manifest with kubectl delete -f capi-quickstart.yaml&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are numerous ways to build a Kubernetes cluster. Before deciding on the approach, I recommend having a full understanding of the hosting environment. This is because installation approach and hosting environment are still tightly coupled. This is the status quo and is not going to change in the near future. Both kops and cluster API reflects initiative to decouple the two but both are still in early stage and already facing growing complexity. Cluster API manages complexity with CRDs to abstract system resources and infrastructure, as illustrated here:&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="501" height="669" src="https://static.digihunch.com/wp-content/uploads/2022/08/image-7.png" alt="" class="wp-image-7086"/&gt;&lt;figcaption class="wp-element-caption"&gt;CRDs and providers to abstract system resources and infrastructure&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The diagram is from the &amp;#8220;&lt;a href="https://www.oreilly.com/library/view/cluster-api-and/9781098126865/"&gt;Cluster API and declarative Kubernetes Management&lt;/a&gt;&amp;#8221; white paper. &lt;a href="https://www.cncf.io/online-programs/cluster-api-yesterday-today-tomorrow/"&gt;Here &lt;/a&gt;is a stream with more about the same topic.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/09/minio-object-storage/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;MinIO for S3-compatible Object Storage&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/10/graphql-and-grpc/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;GraphQL and gRPC&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Etcd – the key-value store for Kubernetes</title><link>https://static.digihunch.com/2022/06/etcd-the-key-value-store-for-kubernetes/</link><pubDate>Tue, 14 Jun 2022 00:10:00 -0400</pubDate><guid>https://static.digihunch.com/2022/06/etcd-the-key-value-store-for-kubernetes/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-etcd.webp" alt="Featured image of post Etcd – the key-value store for Kubernetes" /&gt;&lt;h2 class="wp-block-heading"&gt;Etcd in Kubernetes&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In Kubernetes &lt;a href="https://static.digihunch.com/2021/04/preparing-certified-kubernetes-administrator-exam/"&gt;architecture&lt;/a&gt;, &lt;a href="https://etcd.io/"&gt;etcd&lt;/a&gt; is the data store. It stores the desired state of Kubernetes object. API server is the only client that connects to etcd (via &lt;a href="https://grpc.io/"&gt;gRPC&lt;/a&gt; protocol). Cluster builder specifies the endpoint of etcd as a parameter to the kube-api-server process. Other Kubernetes components, whether in the control plane or from the nodes, connect to API server. API server translates their request into etcd query, and then translates etcd query result into what its clients ask for. For this reason, communication with etcd accounts for a lot of network traffic in a Kubernetes cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The etcd store is a CNCF project for &amp;#8220;a distributed, reliable key-value store for critical data in a distributed system&amp;#8221;, developed by CoreOS team. So it is essentially a distributed key-value store for any distributed application. If an application runs on Kubernetes, it can leverage etcd store, by keeping their configurations in ConfigMap and Secret objects. One key feature is to watch for specific keys or directories for changes, and react to the changes. Voila! This is the underlying mechanism for &lt;a href="https://kubernetes.io/docs/concepts/architecture/controller/"&gt;controller&lt;/a&gt;!&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A Kubernetes cluster may have stacked etcd deployment or connect to an external etcd store.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="848" height="560" src="https://static.digihunch.com/wp-content/uploads/2022/05/stacked.png" alt="" class="wp-image-5250"/&gt;&lt;figcaption class="wp-element-caption"&gt;stacked etcd architecture&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="856" height="601" src="https://static.digihunch.com/wp-content/uploads/2022/05/external.png" alt="" class="wp-image-5251"/&gt;&lt;figcaption class="wp-element-caption"&gt;external etcd architecture&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In managed Kubernetes services such as EKS in AWS and AKS in Azure, users usually do not directly access etcd store. However, it is still a very important component to understand. Its use case includes:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Configuration sharing&lt;/li&gt;&#10;&lt;li&gt;Service discovery&lt;/li&gt;&#10;&lt;li&gt;Consistency&lt;/li&gt;&#10;&lt;li&gt;Watching mechanism&lt;/li&gt;&#10;&lt;li&gt;Expiry and extension of key &lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The consistency use case is based on Raft protocol for distributed consensus.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Raft protocol&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I am not an expert in distributed consensus protocols and nor do I intent to cover it in depth. At a high level, I have heard of three of them so far:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Etcd uses Raft protocol&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2020/08/zookeeper/"&gt;Zookeeper&lt;/a&gt; uses ZAB protocol&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2018/03/cassandra-architecture-summary/"&gt;Cassandra&lt;/a&gt; uses paxos protocol&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.alibabacloud.com/blog/a-brief-analysis-of-consensus-protocol-from-logical-clock-to-raft_594675"&gt;Here&lt;/a&gt; is a good intro to the three protocols. Instead of getting into the fine details, I would like to discuss why we need such a consensus protocol (or consensus mechanism) in distributed systems, which are also decentralized systems.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="686" src="https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-1024x686.webp" alt="" class="wp-image-13111" srcset="https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-1024x686.webp 1024w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-300x201.webp 300w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-768x514.webp 768w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology-410x275.webp 410w, https://static.digihunch.com/wp-content/uploads/2025/04/etcd-topology.webp 1138w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Centralized, Decentralized, Distributed systems&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The reason a distributed system needs consensus protocol, is that a distributed system lacks a single source of truth as centralized systems do. Different parts of the distributed system may receive different signals but they must come to agreement of a single plan to act. Lamport studies this with an analogy of &lt;a href="https://en.wikipedia.org/wiki/Byzantine_fault"&gt;Byzantine Generals&lt;/a&gt; problem, and first proposed Paxos protocol. &lt;a href="https://en.wikipedia.org/wiki/Paxos_(computer_science)"&gt;Paxos&lt;/a&gt; has been an important foundation to modern distributed systems. In Paxos, consensus is achieved in &lt;a href="https://martinfowler.com/articles/patterns-of-distributed-systems/paxos.html"&gt;two phases&lt;/a&gt;, which creates the problem of livelocks. Raft is an alternative to Paxos, and is widely adopted today. &lt;a href="http://thesecretlivesofdata.com/raft/"&gt;Here&lt;/a&gt; is a link to an animated illustration for Raft protocol. The Raft protocol is also used in Redis. It has three roles: Leader, Candidate, and follower. ZAB protocol is similar to Raft, where it needs to select a leader.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Etcd Lab&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In troubleshooting, if we suspect that the response from API server is inconsistent with etcd store, we want to directly connect to it.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Managed Kubernetes services do not expose their etcd store. We can use KinD or Minikube. There are two types of jump box to access etcd store: using etcd Pod, or SSH to a Node. To connect to etcd, we also need the X509 key, certificate and CA&amp;#8217;s certificate, in addition to the endpoint, usually an IP with port 2389. When I connect to Pod shell, I find the command shell not easy to use. They might miss basic command such as ls, or do not support auto completion.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Take KinD for example, we first create a secret, then we can connect to the node with docker CLI command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl create ns myns&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n myns create secret generic mysecret --from-literal key1&lt;span style="color:#f92672"&gt;=&lt;/span&gt;value1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n myns get secret mysecret -o jsonpath&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;{.data.key1}&amp;#39;&lt;/span&gt; | base64 -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker exec -it control /bin/bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From the node, &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt update &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt install etcd-client&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nc -vz localhost &lt;span style="color:#ae81ff"&gt;2379&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_API&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_CERT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/etc/kubernetes/pki/apiserver-etcd-client.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_KEY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/etc/kubernetes/pki/apiserver-etcd-client.key&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_CACERT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/etc/kubernetes/pki/etcd/ca.crt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export ETCDCTL_ENDPOINTS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;https://127.0.0.1:2379&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl member list write out&lt;span style="color:#f92672"&gt;=&lt;/span&gt;table&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can see the secret object directly with etcd store:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get /registry/secrets/myns/mysecret&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;With get query, when using &amp;#8211;prefix, we can use &amp;#8211;keys-only switch to list keys without values:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get --prefix /registry/api --keys-only&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get --prefix /registry/namespace -wjson&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can write key-value with put command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl put myloc &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get myloc -wjson&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In Kubernetes, all the key names start with / which makes the key looks like a POSIX path. Every Kubernetes object is stored in etcd with a unique key following a self-explanatory naming pattern. To display the path, we can also use debug log that records the call to API server:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get ns myns -v9&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Look for curl command such as:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;I0523 22:51:43.517728 32347 round_trippers.go:466] curl -v -XGET -H &amp;#34;Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json&amp;#34; -H &amp;#34;User-Agent: kubectl/v1.23.6 (darwin/amd64) kubernetes/ad33385&amp;#34; &amp;#39;https://127.0.0.1:64081/api/v1/namespaces/myns&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From there we can see the etcd query as the URI is namespaces/myns, which we use in etcdctl query path:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl get /registry/namespaces/myns&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Every type of Kubernetes object has a storage.go file in their implementation that defines how api server should write object. &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/pkg/registry/core/pod/storage/storage.go"&gt;Here&lt;/a&gt; is an example for Pod object.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Etcd also supports watch command to watch for changes. For example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl watch --prefix /registry/namespace &lt;span style="color:#75715e"&gt;# watch output k create ns newns&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we create a namespace with kubectl:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl create ns myns&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The output from etcdctl will reflect the change. The communication between etcdctl and etcd is gRPC protocol. The output is based on stream, as we can see from the watch result.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-etcd-maintenance"&gt;Etcd Maintenance&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Like any distributed store, etcd needs &lt;a href="https://etcd.io/docs/v3.5/op-guide/maintenance/"&gt;maintenance&lt;/a&gt; and operation work. For example, we can check endpoint status with endpoint command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl endpoint status&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can also backup and restore etcd store with etcdctl command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;etcdctl snapshot save /tmp/backup.db&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This was an question in &lt;a href="https://static.digihunch.com/2021/04/preparing-certified-kubernetes-administrator-exam/"&gt;CKA exam&lt;/a&gt;. In real life, when the workload scales up, the etcd store may come across many pitfalls, such as degraded performance, unresponsiveness, some etcd member going down, network partition on etcd store causing split brain. It is important to ensure efficient communication between API server and etcd store. The etcdctl provides defrag and compact commands for common maintenance activities.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/05/hosting-database-on-kubernetes/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Hosting database on Kubernetes&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/06/chaos-mesh-cloud-native-chaos-engineering/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Chaos Mesh – Cloud Native Chaos Engineering&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Kubernetes Admission Control</title><link>https://static.digihunch.com/2022/01/kubernetes-admission-control/</link><pubDate>Fri, 07 Jan 2022 22:21:00 -0400</pubDate><guid>https://static.digihunch.com/2022/01/kubernetes-admission-control/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-admin-control.webp" alt="Featured image of post Kubernetes Admission Control" /&gt;&lt;p class="wp-block-paragraph"&gt;This post discusses admission control, and its implementation &amp;#8211; the OPA Gatekeeper. I also discuss Azure Policy as a different Gatekeeper implementation.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="admission-webhooks"&gt;Admission Webhooks&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Admission controller intercepts requests to the Kubernetes API server after the request has been authenticated and authorized, and prior to persistence of the object into etcd store. There are many compiled-in &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#what-does-each-admission-controller-do"&gt;controllers&lt;/a&gt;, which can be turned on and off on the node with the arguments of &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/"&gt;kube-apiserver&lt;/a&gt; process. For example, the &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook"&gt;ImagePolicyWebhook&lt;/a&gt; can be enabled with value ImagePolicyWebhook added to the &amp;#8211;enable-admission-plugins switch. Its configuration can be provided via the &amp;#8211;admission-control-config-file &lt;a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/#options"&gt;switch&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to the compiled-in admission plugins (which must be configured for kube-apiserver process on the node), admission plugins can be developed as extensions and run as webhooks configured at runtime. This allows users to configure webhooks via API access, dynamically without having to restart kube-apiserver process on the Node, which is usually hard to do with managed Kubernetes platforms. They are therefore called Dynamic Admission Control.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can define two types of admission webhooks in dynamic admission control: validating admission webhook, and mutating admission webhook. Their interaction with API server can be illustrated in the diagram below:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="307" src="https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-1024x307.jpeg" alt="" class="wp-image-7733" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-1024x307.jpeg 1024w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-300x90.jpeg 300w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-768x231.jpeg 768w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-1536x461.jpeg 1536w, https://static.digihunch.com/wp-content/uploads/2023/01/Kubernetes-Admission-controllers-01-flow-diagram-2048x615.jpeg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The mutating admission hook takes action to change the API request, whereas the validating admission hook accepts or denies the request. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A good example of mutating webhook is Istio&amp;#8217;s sidecar injector. We can view the configuration with this command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get MutatingWebhookConfiguration istio-sidecar-injector -o yaml | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From the manifest returned, we can see that in this configuration the request is forwarded to istiod service on port 443, at path /inject for processing. We can also see some matching rules to find the target Pod creation API request.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Validating webhook can be display with the following call:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl get ValidatingWebhookConfiguration&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The output of validating webhook is a yes or no decision. We usually use validating webhook in conjunction with a policy engine to decide whether the request should be accepted or denied.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="open-policy-agent"&gt;Open Policy Agent&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Open Policy Agent (OPA) is an open-source general-purpose policy engine that applies policies written in &lt;a href="https://www.openpolicyagent.org/docs/latest/policy-language/"&gt;Rego language&lt;/a&gt; to ingested JSON document and returns a result. It is usually integrated with system which requires a policy engine. For example, &lt;a href="https://kyverno.io/"&gt;Kyverno&lt;/a&gt; is a policy engine designed for Kubernetes. &lt;a href="https://blog.styra.com/blog/authorize-better-istio-traffic-policies-with-opa-styra-das"&gt;Styra&lt;/a&gt; (one of the OPA contributors) develops policy engines to integrate with Istio&amp;#8217;s authorization policy. They have &lt;a href="https://academy.styra.com/"&gt;online courses&lt;/a&gt; on &lt;a href="https://academy.styra.com/courses/opa-rego"&gt;OPA policy authoring&lt;/a&gt; and &lt;a href="https://academy.styra.com/courses/microservice"&gt;microservice authorization&lt;/a&gt; with their product.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;OPA is build to be a general-purpose, unified way of solving policy and authorization problem. With microservice authorization, the activities includes decision making (determine action based on input, aka Policy Decision Point, PDP), and decision enforcement (issue 400 code or 200 code depending on decision, aka Policy Enforcement Point, PEP). OPA is introduced to decouple these two activities. OPA&amp;#8217;s input is a JSON payload and it uses Policy in Rego language to come to decision.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The team that developers Open Policy Agent also created their controller (with OPA as the core component) to run validating web hook and mutating web hook. The original version is OPA-Kubernetes that uses kube-mgmt. This original version is also dubbed Gatekeeper v1.0. When OPA starts, the kube-mgmt sidecar container will load Kubernetes Namespace and Ingress objects into OPA. You can configure the sidecar to load any kind of Kubernetes object into OPA. The sidecar establishes watches on the Kubernetes API server so that OPA has access to an eventually consistent cache of Kubernetes objects. It has gone through a couple of major version changes as summarized in &lt;a href="https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes/#evolution"&gt;this&lt;/a&gt; section. As of today, when we deploy Gatekeeper we should use version 3.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="gatekeeper-v3"&gt;Gatekeeper v3&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Currently, Gatekeeper v3 is the most popular choice for Kubernetes Policy Controller. The diagram bellow illustrate how Gatekeeper integrates with Kubernetes API server.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="943" height="478" src="https://static.digihunch.com/wp-content/uploads/2022/02/apiserver.png" alt="" class="wp-image-3481"/&gt;&lt;figcaption class="wp-element-caption"&gt;Gatekeeper and Kubernetes&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can follow &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/install/"&gt;this&lt;/a&gt; guide to install Gatekeeper but the key step is as simple as to apply the correct version of manifest. Alternatively it can be installed &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/install#deploying-via-helm"&gt;using Helm&lt;/a&gt;. After the installation, we should see a Service named &lt;em&gt;gatekeeper-webhook-service&lt;/em&gt; in the &lt;em&gt;gatekeeper-system&lt;/em&gt; namespace. We can also inspect the newly created validationg web hook configuration&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;k get validatingwebhookconfiguration gatekeeper-validating-webhook-configuration -o yaml | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The result indicates that the configuration forwards incoming manifests to the &lt;em&gt;gatekeeper-webhook-service&lt;/em&gt; web service at the path /v1/admin for validation, and then at /v1/admitlabel for labelling. The configuration also stores rules as matching criteria.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can smoke test Gatekeeper v3, with the basic example in its &lt;a href="https://github.com/open-policy-agent/gatekeeper/tree/master/example"&gt;directory&lt;/a&gt;. Apply the template, constraint and then the manifests in resources. The pod creation will fail with an error like:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Error from server &lt;span style="color:#f92672"&gt;([&lt;/span&gt;pod-must-have-gk&lt;span style="color:#f92672"&gt;]&lt;/span&gt; you must provide labels: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;gatekeeper&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;})&lt;/span&gt;: error when creating &lt;span style="color:#e6db74"&gt;&amp;#34;resources/bad_pod_namespaceselector.yaml&amp;#34;&lt;/span&gt;: admission webhook &lt;span style="color:#e6db74"&gt;&amp;#34;validation.gatekeeper.sh&amp;#34;&lt;/span&gt; denied the request: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;pod-must-have-gk&lt;span style="color:#f92672"&gt;]&lt;/span&gt; you must provide labels: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;gatekeeper&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The gatekeeper &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/howto"&gt;document&lt;/a&gt; also covers the details of using ConstraintTemplate and Constraints. However, Writing your own a policy in Rego still takes time and we want to piggyback on the community for commonly used policies. &lt;a href="https://github.com/open-policy-agent"&gt;OPA&lt;/a&gt;&amp;#8216;s &lt;a href="https://github.com/open-policy-agent/gatekeeper-library"&gt;gatekeeper-library&lt;/a&gt; projects keeps a handful of those in its &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library"&gt;library&lt;/a&gt; directory. We can test the &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/pod-security-policy/privileged-containers"&gt;privileged container&lt;/a&gt; example:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ cd gatekeeper-library/library/pod-security-policy/privileged-containers&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kustomize build . | kubectl apply -f -&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;constrainttemplate.templates.gatekeeper.sh/k8spspprivilegedcontainer created&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f samples/psp-privileged-container/example_disallowed.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod/nginx-privileged-disallowed created&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl delete -f samples/psp-privileged-container/example_disallowed.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pod &lt;span style="color:#e6db74"&gt;&amp;#34;nginx-privileged-disallowed&amp;#34;&lt;/span&gt; deleted&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f samples/psp-privileged-container/constraint.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container created&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl apply -f samples/psp-privileged-container/example_disallowed.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Error from server &lt;span style="color:#f92672"&gt;([&lt;/span&gt;psp-privileged-container&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Privileged container is not allowed: nginx, securityContext: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;privileged&amp;#34;&lt;/span&gt;: true&lt;span style="color:#f92672"&gt;})&lt;/span&gt;: error when creating &lt;span style="color:#e6db74"&gt;&amp;#34;samples/psp-privileged-container/example_disallowed.yaml&amp;#34;&lt;/span&gt;: admission webhook &lt;span style="color:#e6db74"&gt;&amp;#34;validation.gatekeeper.sh&amp;#34;&lt;/span&gt; denied the request: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;psp-privileged-container&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Privileged container is not allowed: nginx, securityContext: &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;privileged&amp;#34;&lt;/span&gt;: true&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Currently the library &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library"&gt;directory&lt;/a&gt; contains two sub-directories, general and pod-scurity-policy. The latter is to regulate Pod creation, while the former includes more common usecases such as disable node port, enforce https, and enforce probes. This is the place I start with when building a policy.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The policy constraints take effect cluster wide. When we have multiple clusters, we would like a unified place to manage policies. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="azure-policy-with-aks"&gt;Azure Policy with AKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We take Azure Policy with AKS as an example to illustrate how public cloud platform can simplify policy management. When building AKS cluster, an &lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/concepts/policy-for-kubernetes#install-azure-policy-add-on-for-aks"&gt;addon&lt;/a&gt; profile for Azure Policy can be installed. This allows Azure Policy to connect to the AKS cluster. Azure Policy contains many built-in policies definitions (as well as initiative definitions which are groups of related policies). We can simply search by Kubernetes keyword and look for the built-in policies. For example, there is a built-in policy definition &amp;#8220;Kubernetes clusters should not allow container privilege escalation. The definitions (policy or initiative) can be assigned to a resource group with enforcement action set to denied, and with excluded namespaces, as shown in the screenshot below&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1566" height="1056" src="https://static.digihunch.com/wp-content/uploads/2022/02/image-2.png" alt="" class="wp-image-3497"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The assignment can take as long as 10 minutes to push down to the cluster. Then we should be able to confirm by checking the constraint CRDs. We can see this This setup brings a centralized policy management system that can be easily hooked up to multiple clusters.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://ahmedkhamessi.com/img/azurepolicy/azurepolicy.png" alt="Azure Policy and OPA Gatekeeper underlay for AKS"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Other benefits of this architecture includes the ability to report compliance. As per CIS report for Azure AKS recommendation 4.3:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Azure Policy extends Gatekeeper v3, an admission controller webhook for Open Policy Agent (OPA), to apply at-scale enforcements and safeguards on your clusters in a centralized, consistent manner. It covers many &lt;a href="https://static.digihunch.com/2021/01/basic-kubernetes-resource-object-1-of-2/"&gt;basic resource&lt;/a&gt; &lt;a href="https://static.digihunch.com/2021/02/basic-resource-object-in-kubernetes-2-of-2/"&gt;types&lt;/a&gt; but does not cover any well-known CRDs. Azure Policy makes it possible to manage and report on the compliance state of your Kubernetes clusters from one place.&amp;nbsp;&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Checks with Azure Policy service for policy assignments to the cluster.&lt;/li&gt;&#10;&lt;li&gt;Deploys policy definitions into the cluster as constraint template and constraint custom resources.&lt;/li&gt;&#10;&lt;li&gt;Reports auditing and compliance details back to Azure Policy service.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As of February 2022, AWS EKS doesn&amp;#8217;t seem to have the equivalent of this capability to integrate with a policy management. The only option would be to install Gatekeeper v3 &lt;a href="https://aws.amazon.com/blogs/opensource/using-open-policy-agent-on-amazon-eks/"&gt;yourself&lt;/a&gt; on the cluster, or host it separately. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="bottom-line"&gt;Bottom line&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Admission control should be a standard setup in Kubernetes deployment. When building gatekeeper system on your own, it can be set up separately on a different cluster. When Kubernetes is provided as a platform, it is very helpful for platform operator to manage their tenants. If the tenant is application development team, it also makes sense for them to develop their own policies for the developers in their team.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/12/from-ingress-to-gateway-why-you-need-istio-gateways-on-kubernetes-platforms/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;From Ingress to CRD: why my solution needs Istio Gateways on Kubernetes platforms&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/01/fluxcd-continuous-deployment-with-gitops/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;FluxCD: Continuous Deployment with GitOps&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>