Enterprise Workload Performance on Kubernetes with CPU Limits – VMware vSphere 7 with Tanzu Performance Study
VMwareThe results in this paper show that Kubernetes clusters deployed on VMware vSphere with Tanzu can match or exceed the performance of bare-metal clusters deployed on identical servers.
What’s New in Performance for VMware vSphere 7? Updated for vSphere 7.0 U1, U2, and U3
VMwareUnderlying each release of VMware vSphere are many performance and scalability improvements. The vSphere 7.x platform continues to provide industry-leading performance and features to ensure the successful virtualization and management
Patch Tuesday, October 2021 Edition
Cybersecurity apple, AskWoody.com, Bleeping Computer, CVE-2021-26427, CVE-2021-30883, CVE-2021-36970, CVE-2021-38672, CVE-2021-40449, CVE-2021-40461, Immersive Labs, Kevin Breen, Lawrence Abrams, Microsoft Patch Tuesday October 2021, Morphus Labs, sans internet storm center, Satnam Narang, Tenable, Time to PatchMicrosoft today issued updates to plug more than 70 security holes in its Windows operating systems and other software, including one vulnerability that is already being exploited in active attacks. This month’s Patch Tuesday also includes security fixes for the newly released Windows 11 operating system. …
Using the External AWS Cloud Provider for Kubernetes
CloudIn 2018, after finding a dearth of information on setting up Kubernetes with AWS integration/support, I set out to try to establish some level of documentation on this topic. That effort resulted in a few different blog posts, but ultimately culminated in this post on setting up an AWS-integrated Kubernetes cluster using kubeadm. Although originally written for Kubernetes 1.15, the process described in that post is still accurate for newer versions of Kubernetes. With the release of Kubernetes 1.22, though, the in-tree AWS cloud provider—which is what is used/described in the post linked above—has been deprecated in favor of the external cloud provider. In this post, I’ll show how to set up an AWS-integrated Kubernetes cluster using the external AWS cloud provider.
In addition to the post I linked above, there were a number of other articles I published on this topic:
- Setting up the AWS Cloud Provider
- Kubernetes, Kubeadm, and the AWS Cloud Provider
- Using Kubeadm to Add New Control Plane Nodes with AWS Integration
Most of the information in these posts, if not all of it, is found in the latest iteration, but I wanted to include these links here for some additional context. Also, all of these focus on the now-deprecated in-tree AWS cloud provider.
Although all of these prior posts focus on the in-tree provider, they are helpful because many of the same prerequisites/requirements for the in-tree provider are still—as far as I know—applicable for the external AWS cloud provider:
- The hostname of each node must match the EC2 Private DNS entry for the instance (by default, this is something like
ip-10-11-12-13.us-west-2.compute.internalor similar). Note that I haven’t explicitly tested/verified this requirement in a while, so it’s possible that this has changed. As soon as I am able, I’ll conduct some additional testing and update this post. - Each node needs to have an IAM instance profile that grants it access to an IAM role and policy with permissions to the AWS API.
- Specific resources used by the cluster must have certain AWS tags assigned to them. As with the hostname requirement, this is an area where I haven’t done extensive testing of the external cloud provider against the in-tree provider.
- Specific entries are needed in the
kubeadmconfiguration file used to bootstrap the cluster, join control plane nodes, and join worker nodes.
The following sections describe each of these four areas in a bit more detail.
Setting Node Hostnames
Based on my testing—see my disclaimer in #1 above—the hostname for the OS needs to match the EC2 Private DNS entry for that particular instance. By default, this is typically something like ip-10-11-12-13.us-west-2.compute.internal (change the numbers and the region to appropriately reflect the private IP address and region of the instance, and be aware that the us-east-1 AWS region uses the ec2.internal DNS suffix). The fastest/easiest way I’ve verified to make sure this is the case is with this command:
sudo hostnamectl set-hostname \
$(curl -s http://169.254.169.254/latest/meta-data/local-hostname)
Be sure to set the hostname before starting the bootstrapping process. I have some references of putting this command in the user data for the instance, so that it runs automatically. I have not, however, specifically tested this approach.
Creating and Assigning the IAM Instance Profile
The nodes in the cluster need permission to the AWS APIs in order for the AWS cloud provider to function properly. The “Prerequisites” page on the Kubernetes AWS Cloud Provider site has a sample policy for both control plane nodes and worker nodes. Consider these sample policies to be starting points; test and modify in order to make sure the policies work for your specific implementation. Once you create IAM instance profiles that reference the appropriate roles and policies, then be sure to specify the IAM instance profile when launching your instances. All the major IaC tools (including both Pulumi and Terraform) have support for specifying the IAM instance profile in code.
Tagging Cluster Resources
While the documentation for the cloud provider is improving, this is one area that could still use some additional work. The “Getting Started” page on the Kubernetes AWS Cloud Provider site only says this about tags:
Add the tag
kubernetes.io/cluster/<your_cluster_id>: owned(if resources are owned and managed by the cluster) orkubernetes.io/cluster/<your_cluster_id>: shared(if resources are shared between clusters, and should not be destroyed if the cluster is destroyed) to your instances.
Based on my knowledge of the in-tree provider and the testing I’ve done with the external provider, this is correct. However, additional tags are typically needed:
- Public (Internet-facing) subnets need a
kubernetes.io/elb: 1tag, while private subnets need akubernetes.io/internal-elb: 1tag. - All subnets need the
kubernetes.io/cluster/<your_cluster_id>: owned|sharedtag. - If the cloud controller manager isn’t started with
--configure-cloud-routes: "false", then the route tables also needed to be tagged like the subnets. - At least one security group—one which the nodes should be a member of—needs the
kubernetes.io/cluster/<your_cluster_id>: owned|sharedtag.
Failure to have things properly tagged results in odd failure modes, like ELBs being automatically created in response to the creation of a Service object of type LoadBalancer, but instances never being populated for the ELB (for example). Another failure I’ve seen is the Kubelet failing to start if the nodes aren’t properly tagged. Unfortunately, the failure modes of the external cloud provider aren’t any better documented than the in-tree provider, which can make troubleshooting a bit challenging.
Using Kubeadm Configuration Files
The final piece is adding the correct values to your kubeadm configuration files so that the cluster is bootstrapped properly. I tested the configurations shown below using Kubernetes 1.22.
Three different configuration files are needed:
- A configuration file to be used to bootstrap the first control plane node
- A configuration file used to join any additional control plane nodes
- A configuration file used to join worker nodes
I’ll begin with the natural starting point: the configuration file for bootstrapping the first/initial control plane node.
Bootstrapping the First Control Plane Node
A kubeadm configuration file you could use to bootstrap your first control plane node with the external AWS cloud provider might look something like this:
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
apiServer: extraArgs: cloud-provider: external
clusterName: foo
controllerManager: extraArgs: cloud-provider: external
kubernetesVersion: v1.22.2 # can use "stable"
networking: dnsDomain: cluster.local podSubnet: 192.168.0.0/16 serviceSubnet: 10.96.0.0/12
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration: name: ip-10-11-12-13.us-west-2.compute.internal kubeletExtraArgs: cloud-provider: external
Note that this does not take into account configuration settings related to setting up a highly-available control plane; refer to the kubeadm v1beta3 API docs for details on what additional settings are needed. (For sure the controlPlaneEndpoint field should be added, but there may be additional settings that are necessary for your specific environment.)
The big change from previous kubeadm configurations I’ve shared is that cloud-provider: aws is now cloud-provider: external. Otherwise, the configuration remains largely unchanged. Note the absence of the configure-cloud-routes; this is moved to the AWS cloud controller manager itself.
After you’ve bootstrapped the first control plane node (using kubeadm init --config <filename>.yaml) but before you add any other nodes—control plane or otherwise—you’ll need to install the AWS cloud controller manager. Manifests are available, but you’ll need to use kustomize to build them out:
kustomize build 'github.com/kubernetes/cloud-provider-aws/manifests/overlays/superset-role/?ref=master'
Review the output (to ensure the values supplied are correct for your environment), then send the results to your cluster by piping them into kubectl apply -f -.
You’ll also want to go ahead and install the CNI plugin of your choice.
Adding More Control Plane Nodes
If you are building a highly-available control plane, then a kubeadm configuration similar to the one shown below would work with the external AWS cloud provider:
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: JoinConfiguration
discovery: bootstrapToken: token: 123456.a4v4ii39rupz51j3 apiServerEndpoint: "cp-lb.us-west-2.elb.amazonaws.com:6443" caCertHashes: ["sha256:193feed98fb5fd2b497472fb7d9553414e27ff7eeb7b919c82ff3a08fdf5782f"]
nodeRegistration: name: ip-10-14-18-22.us-west-2.compute.internal kubeletExtraArgs: cloud-provider: external
controlPlane: localAPIEndpoint: advertiseAddress: 10.14.18.22 certificateKey: "f6fcb672782d6f0581a1060cf135920acde6736ef12562ddbdc4515d1315b518"
You’d want to adjust the values for token, apiServerEndpoint, caCertHashes, and certificateKey as appropriate based on the output of kubeadm init when bootstrapping the first control plane node. Also, refer to the “Adding More Control Plane Nodes” section of the previous post for a few notes regarding tokens, the SHA256 hash, and the certificate encryption key (there are ways to recover/recreate this information if you don’t have it).
Use your final configuration file with kubeadm join --config <filename>.yaml to join the cluster as an additional control plane node.
Adding Worker Nodes
The final step is to add worker nodes. You’d do this with kubeadm join --config <filename>.yaml, where the specified YAML file might look something like this:
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: JoinConfiguration
discovery: bootstrapToken: token: 123456.a4v4ii39rupz51j3 apiServerEndpoint: "cp-lb.us-west-2.elb.amazonaws.com:6443" caCertHashes: - "sha256:193feed98fb5fd2b497472fb7d9553414e27ff7eeb7b919c82ff3a08fdf5782f"
nodeRegistration: name: ip-10-12-14-16.us-west-2.compute.internal kubeletExtraArgs: cloud-provider: external
As noted earlier, be sure to specify a correct and valid bootstrap token and the SHA256 hash of the CA certificate.
Wrapping Up
At this point, you should have a (mostly) functional Kubernetes cluster. You’ll probably still want some sort of storage solution; see here for more details on the AWS EBS CSI driver.
If you run into problems or issues getting this to work, please feel free to reach out to me. You can find me on the Kubernetes Slack community, or you can contact me on Twitter (DMs are open). Also, if you’re well-versed in this area and have corrections, clarifications, or suggestions for how I can improve this article, I welcome all constructive feedback. Thanks!
…
Read MoreUsing the External AWS Cloud Provider for Kubernetes
Ada Lovelace Day: Tech’s most influential women share their views
Cloud Ada Lovelace, CIO, EditorialDuncan is an award-winning editor with more than 20 years experience in journalism. Having launched his tech journalism career as editor of Arabian Computer News in Dubai, he has since
Continue ReadingAda Lovelace Day: Tech’s most influential women share their views
Kustomize Transformer Configurations for Cluster API v1beta1
CloudThe topic of combining kustomize with Cluster API (CAPI) is a topic I’ve touched on several times over the last 18-24 months. I first touched on this topic in November 2019 with a post on using kustomize with CAPI manifests. A short while later, I discovered a way to change the configurations for the kustomize transformers to make it easier to use it with CAPI. That resulted in two posts on changing the kustomize transformers: one for v1alpha2 and one for v1alpha3 (since there were changes to the API between versions). In this post, I’ll revisit kustomize transformer configurations again, this time for CAPI v1beta1 (the API version corresponding to the CAPI 1.0 release).
In the v1alpha2 post (the first post on modifying kustomize transformer configurations), I mentioned that changes were needed to the NameReference and CommonLabel transformers. In the v1alpha3 post, I mentioned that the changes to the CommonLabel transformer became largely optional; if you are planning on adding additional labels to MachineDeployments, then the change to the CommonLabels transformer is required, but otherwise you could probably get by without it.
For v1beta1, the necessary changes are very similar to v1alpha3, and (for the most part) are focused on the NameReference transformer. The NameReference transformer tracks references between objects, so that if the name of an object changes—perhaps due to use of the namePrefix or nameSuffix directives in the kustomization.yaml file—references to that object are also appropriately renamed.
Here are the CAPI-related changes needed for the NameReference transformer:
- kind: Cluster group: cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/clusterName kind: MachineDeployment - path: spec/template/spec/clusterName kind: MachineDeployment - kind: AWSCluster group: infrastructure.cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/infrastructureRef/name kind: Cluster - kind: KubeadmControlPlane group: controlplane.cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/controlPlaneRef/name kind: Cluster - kind: AWSMachine group: infrastructure.cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/infrastructureRef/name kind: Machine - kind: KubeadmConfig group: bootstrap.cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/bootstrap/configRef/name kind: Machine - kind: AWSMachineTemplate group: infrastructure.cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/template/spec/infrastructureRef/name kind: MachineDeployment - path: spec/machineTemplate/infrastructureRef/name kind: KubeadmControlPlane - kind: KubeadmConfigTemplate group: bootstrap.cluster.x-k8s.io version: v1beta1 fieldSpecs: - path: spec/template/spec/bootstrap/configRef/name kind: MachineDeployment
Generally, you’d append this content to the default NameReference transformer configuration, which you’d obtain using kustomize config save. However, somewhere in the Kustomize 3.8.4 release timeframe, the kustomize config save command for extracting the default transformer configurations was removed, and I have yet to figure out another way of getting this information. In theory, when using kustomize with CAPI manifests, you wouldn’t need any of the default NameReference transformer configurations, but I haven’t conducted any thorough testing of that theory (yet).
Aside from replacing all instances of v1alpha3 with v1beta1, the only other difference in the YAML shown above compared to YAML in the the v1alpha3 post is a change to the fieldSpecs list for AWSMachineTemplate. Previously, the KubeadmControlPlane referenced an underlying AWSMachineTemplate at the path spec/infrastructureTemplate/name. In v1beta1, the KubeadmControlPlane object now references an AWSMachineTemplate at the path spec/machineTemplate/infrastructureRef/name.
As mentioned in both of the previous posts, you’ll need to put this content in a file (I use namereference.yaml) and then specify the path to this configuration in kustomization.yaml, like this:
configurations: - /path/to/customized/namereference.yaml
I hope this information is useful to readers. Feel free to find me on the Kubernetes Slack instance if you have questions, and I’ll do my best to help answer them. You’re also welcome to contact me on Twitter (DMs are open). Thanks!
…
Read MoreKustomize Transformer Configurations for Cluster API v1beta1


