Containers are a great way to package code and dependencies in a portable package. This is fantastic in a world where dependencies keep getting bigger and more complex. But we are not here to discuss their benefits. If Google brought you here, more than likely you know already what a container is and you are trying to troubleshoot one. If that’s the case, I hope you find useful the tip I am about to tell you.
To understand the solution we must first remember that containers are designed to run a task as soon as they start. You define such task with either CMD or ENTRYPOINT. The problem is that if the task dies the container dies too and you can’t log in into it to find out what happened. Sometimes “docker logs” will give you a hint of what’s happening but other times you wish you could simply log in to the container and check things out, but of course you can’t because the container is dead
A solution I have become fond of is to override the ENTRYPOINT with a process that keeps the container alive and then open a terminal session into it. Let me give you an example.
IMPORTANT: I am using Podman but all of this will work perfectly fine with Docker as well. This is the “Dockerfile“. Notice how the main task for this container is “python app.py“
FROM python:3.10.5
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 7860
CMD ["python", "app.py"]
This is the code contained in “app.py“. It is a simple Gradio chatbot. It gets the users prompt and sends an API call to to get a response.
import gradio as gr
import os, requests, import urllib3
urllib3.disable_warnings()
appurl = os.environ["APP_URL"]
def give_response(query, history):
payload = {"query": query}
response = requests.post(appurl, json=payload)
return response.json()["response"]
demo = gr.ChatInterface(
give_response,
type = "messages",
title="My first Chatbot",
description="Ask me a question, don't be shy")
demo.launch(server_name="0.0.0.0")
As you can see the code requires us to define an environment variable “APP_URL” with the URL to send the request to. Let’s say that we don’t define the variable and attempt to run the container.
pi@piper1:~$ podman run -d -p 7860:7860 localhost/blog:v1
19dc02db0b2e06c51756c7f55a3eb861c11f831a21574efdcd2e00081c9191a1
pi@piper1:~$ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
19dc02db0b2e localhost/blog:v1 python app.py 3 seconds ago Exited (1) dry_rice
As expected the container fails but here is the trick … we run it again but we use the “–entrypoint” argument to run “tail -f /dev/null“. The container is not changing we are simply overriding “python app.py” with this “tail” command which stays running and in doing so keeps the container alive. Notice the “single quote” around the square brackets.
pi@piper1:~$ podman run -d --entrypoint='["tail", "-f", "/dev/null"]' -p 7860:7860 localhost/blog:v1
e1031d4c2ecbf3d4ec244aef262e71fb2f4e227154b6e22eabf634e4e053f4a0
pi@piper1:~$ podman ps
CONTAINER ID IMAGE STATUS PORTS NAMES
e1031d4c2ecb localhost/blog:v1 Up 6 seconds 0.0.0.0:7860->7860/tcp sour_soup
Now we can login into the container and do whatever checks we need to do. We can even run “python app.py” and see what’s going on live.
pi@piper1:~$ podman exec -it e1031d4c2ecb /bin/bash
root@e1031d4c2ecb:/app# ls -l
total 12
-rw-r--r-- 1 root root 518 Mar 24 04:35 Dockerfile
-rw-r--r-- 1 root root 566 Mar 24 04:35 app.py
-rw-r--r-- 1 root root 897 Mar 24 04:35 requirements.txt
root@e1031d4c2ecb:/app# python3 app.py
Traceback (most recent call last):
File "/app/app.py", line 7, in <module>
appurl = os.environ["APP_URL"]
File "/usr/local/lib/python3.10/os.py", line 679, in __getitem__
raise KeyError(key) from None
KeyError: 'APP_URL'
This was a simplistic example but you get point. There could be a file or a path missing, a typo, a permissions issue … by using this trick you can troubleshoot interactively inside the container. Once you know what the issue is you can fix your files and rebuild the container image.
The next question is, can you do this in Kubernetes as well? Yes, you can add the “command” to the “Deployment”, not to the “Pod”. This is a list of strings as you see in the last line in the simplified manifest below.
As soon as I save the changes to the deployment manifest, Openshift creates a new pod and kills the old one. Then I can terminal into the new pod and browse around. Notice I can even launch the application from the terminal session.
$ pwd
/app
$ ls -l
total 12
-rw-r--r--. 1 root root 518 Mar 24 04:35 Dockerfile
-rw-r--r--. 1 root root 566 Mar 24 04:35 app.py
-rw-r--r--. 1 root root 897 Mar 24 04:35 requirements.txt
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
1000770+ 1 0 0 00:00 ? 00:00:00 tail -f /dev/null
1000770+ 7 0 0 00:00 pts/0 00:00:00 sh -i -c TERM=xterm sh
1000770+ 13 7 0 00:00 pts/0 00:00:00 sh
1000770+ 90 13 0 00:02 pts/0 00:00:00 ps -ef
$ python3 app.py
* Running on local URL: http://0.0.0.0:7860
To create a public link, set `share=True` in `launch()`.
Of course, this is only intended for troubleshooting. Once you find out what’s wrong you can fix the image and manifest and deploy them again.
In the world of software development, Murphy’s law holds an unassailable truth: Anything that can go wrong, will go wrong. As a proud member of this masochistic club, you might be looking for innovative ways to stall your Kubernetes enterprise rollout. Maybe you want to add a little chaos to your routine CI/CD workflow, or perhaps you’re just a thrill-seeker who loves the high stakes game of orchestration roulette. Either way, you’ve come to the right place. Sit back, relax, and let us guide you through the delightful maze of missteps and detours that will ensure your Kubernetes enterprise rollout is anything but a walk in the park.
Ah, Kubernetes! The open-source platform that’s become the equivalent of a Hollywood blockbuster in the tech world. It’s like the Iron Man of container orchestration, bringing together an array of superpowers including automation, scaling, and management of container deployment. Enterprises are lining up to get their tickets, excited by the promises of streamlined application deployment. But before you go head over heels for Kubernetes, remember, even Iron Man had his quirks. Navigating the CI/CD waterfall can sometimes feel more like a rollercoaster ride without a seatbelt. So before you charge headfirst into your enterprise rollout, take a moment to consider Murphy’s Law – anything that can go wrong, will go wrong. So buckle up, my friends, it’s going to be a wild ride.
Indeed, Kubernetes is a boon for developers, cloud-native architects, and business owners alike. Its versatility and flexibility can make you feel like a superhero orchestrating seamless deployments. But when it comes to deploying and scaling in Enterprise data centers, Kubernetes might just swap its Iron Man suit for a Godzilla costume, spawning fresh challenges born out of its cloud-native architecture. This transition can lead to excessive mental gymnastics as you grapple with these new beasts of burden. So, if you’re feeling like a deer caught in the headlights, staring down the Kubernetes-python poised to gobble up your Enterprise applications, fear not! This blog is your sanctuary, your guide, your ‘how-to-tame-your-dragon’ manual. Stay with us, as we venture into the labyrinth of Kubernetes deployment and come out the other side grinning. 🙂
Let’s dive into the 10 ways you might unintentionally stall your enterprise Kubernetes rollout, and inadvertently send your organization spiraling back to the ‘golden age’ of monolithic architecture:
1.Do Not Plan Your Deployment: Some may argue that the beauty of Kubernetes lies in its simplicity, and indeed, the internet is abundant with blogs and videos promoting the notion that the deployment process is a walk in the park. Following such advice without investing time in understanding your unique use case could be a significant pitfall. Kubernetes deployments require thoughtful planning, taking into account the intricacies of workload requirements, resource allocation, and network architecture. The idea of “Kubernetes is the easy button for everything” is a perilous assumption that can easily derail your enterprise rollout. Always remember, while Kubernetes does a spectacular job in many aspects, it’s not a one-size-fits-all solution for every enterprise problem.
2. Avoid Using Certified Kubernetes Distributions: Now this one’s a head-scratcher, isn’t it? Here’s the thing, though: Kubernetes is powerful, flexible, and can be customized to a dizzying degree. However, this does not mean you should do everything from scratch. Consider this – why would you build your car when you can buy a perfectly good one off the lot? Certified Kubernetes distributions, like Red Hat OpenShift or VMware Tanzu, come with the assurance of being properly configured, tested, and meeting industry standards. They’re like your ready-to-drive cars, offering robust features and world-class support. By choosing to bypass these options, you’re essentially signing up for unnecessary headaches that could easily stall your enterprise rollout. Remember, Kubernetes is a tool, not an ideology. There’s no virtue in unnecessary complexities.
3. Do NOT Implement Security Best Practices: This one’s a classic misstep in the tech world. Yes, Kubernetes is inherently secure, but that doesn’t mean it’s invincible. If you’re looking to stall your enterprise rollout, then by all means, ignore security best practices. However, if you’re keen on a smoothly functioning system, pay close attention to security measures like access control, network segmentation, and encryption. It’s akin to leaving your car unlocked in a crowded parking lot — sure, it might have an immobilizer and alarm system, but why invite trouble? Access control ensures only authorized personnel can interact with your Kubernetes clusters, network segmentation limits the blast radius of potential breaches, and encryption keeps your sensitive data safe in transit and at rest. Failing to implement these measures is like leaving the keys in your car with the engine running – a surefire way to invite mischief. Remember, in the world of Kubernetes deployments, security is not an afterthought, it’s a primary driver of successful CI/CD pipelines and enterprise rollouts.
4. Forget about Using CI/CD Pipelines: There’s a certain masochistic charm in choosing not to use CI/CD pipelines in your enterprise rollout. After all, who needs automation when you can manually deploy your applications, right? CI/CD pipelines, or Continuous Integration/Continuous Deployment pipelines, are like that studious classmate who always double-checks their work before submitting it – they automate the deployment process and ensure that all changes are thoroughly examined and validated before entering the production environment. If you’re a fan of chaos and unpredictability (and potentially stalling your Kubernetes enterprise rollout), then by all means, go ahead and give CI/CD pipelines a pass. However, if you value efficiency, reliability, and sanity, incorporating CI/CD pipelines into your operations could be a game-changer. They ensure a streamlined, error-free process that keeps your applications updated and secure, allowing your team to focus on what truly matters – building and improving your products. But hey, if you’re in the market for a bit of pandemonium, feel free to ignore this advice!
5.Visibility/Observability, what’s that?: There’s something rather intriguing about stumbling in the dark, isn’t there? For those of you who enjoy a good surprise, why not apply this approach to your Kubernetes deployment? Think about it, with no comprehensive monitoring solution in place, every day is like a thrilling game of hide-and-seek with your application’s performance, capacity, and availability. However, if you (like most sane people) prefer to know what’s happening under the hood, it’s time to incorporate a robust monitoring solution into your Kubernetes enterprise rollout. Think of it as a reliable co-pilot that keeps an eye on the road while you’re busy steering the ship. It helps you identify potential roadblocks or speed bumps, ensuring your journey toward a successful enterprise rollout is as smooth as possible. So go ahead, embrace the unknown, or better yet, ensure your unknowns are known with a comprehensive monitoring solution. But remember, no pressure; after all, it’s only your Kubernetes deployment we’re talking about here!
6.Don’t care about Config Management Tools: If you’re fond of unpredictability and enjoy the thrill of variance, throwing caution to the wind when it comes to config management could be your next adrenaline spike! Who needs tools like Ansible or Puppet that automate the configuration of your Kubernetes deployment and ensure consistent settings across your environment? Why make life easier and your enterprise rollout smoother when you can indulge in the chaotic symphony of inconsistency? Sure, these tools can simplify the management of your Kubernetes configuration, reduce errors, and ensure uniformity across your deployment, but where’s the fun in that? So sit back, relax, and let the inconsistencies rollick through your deployment, because who wouldn’t love a good configuration surprise?
7.Forget about Disaster Recovery: If you’re the type who loves to live on the edge, why not take a leap of faith with your Kubernetes rollout too? After all, implementing disaster recovery measures like backup and recovery procedures is like carrying an umbrella all the time just because it might rain. Sure, these measures could prevent your enterprise from figuratively getting drenched in the event of an unexpected outage or data loss, but what’s a little water, right? Having a disaster recovery plan could mean the difference between a minor hiccup and a full-fledged organizational crisis during a catastrophe, but let’s face it, who doesn’t love a little game of Russian Roulette with their Kubernetes deployment? So, go ahead and roll the dice. After all, disaster recovery is just for those who aren’t fans of suspense, right?
8.Train Your Staff (or Don’t): Now, here’s a real knee-slapper: education. Nothing quite like seeing your team scramble around like a bunch of cats on a hot tin roof because they don’t know their Pods from their Nodes. Who needs well-trained staff, conversant with Kubernetes best practices, when you can bask in the glorious pandemonium of mismanaged deployments instead? Sure, giving your employees the necessary skills to effectively manage and operate your Kubernetes deployment might lead to fewer issues, greater efficiency, and a more successful enterprise rollout. But let’s be real, why stifle the potential theatre of the absurd that could result from untrained staff wrestling a mammoth like Kubernetes? Life is a stage, after all, and in your Kubernetes drama, training is just too mainstream a script. So, sit back, grab some popcorn, and enjoy the show!
9.Live in the Past: Here’s a revolutionary idea – rolling with the times. You could, if you’re feeling particularly adventurous, actually stay up-to-date with the latest Kubernetes releases and security patches. That, of course, would imply that you’re interested in ensuring your deployment operates with the latest features and security updates. But hey, who doesn’t love a little nostalgia? Sure, you could prioritize keeping your enterprise rollout in line with the newest, slickest versions of Kubernetes, ensuring that your CI/CD pipelines are as cutting-edge as they come, but isn’t there a certain charm in running your enterprise on an antiquated version that’s as outdated as a floppy disk in an AI lab? After all, cybersecurity threats, outdated functionalities, and inefficiencies are just minor speed bumps on the road of enterprise rollouts. So, why not kick back, ignore those pesky update notifications, and let your Kubernetes deployment bask in the warm glow of obsolescence? Just remember – living in the past is only fun until the ghosts of security vulnerabilities and outdated features come knocking on your door.
10.Embrace Impermanence (non-persistence): In the grand scheme of things, isn’t Kubernetes is supposed to be ephemeral? Why should your data be any different? Go ahead, live dangerously. Don’t bother with planning for data persistence in your Kubernetes rollout. Imagine the thrill of living on the edge, knowing that you could lose all your data the moment a pod goes down or the system crashes. Sure, you could use the Kubernetes Persistent Volume (PV) and Persistent Volume Claim (PVC) architecture to ensure your data survives even when your pods don’t, but where’s the fun in that? Data persistence is so pedestrian. Remember, the goal here is to stall your Kubernetes enterprise rollout, not to make it robust, resilient, and reliable. So, go ahead, and throw caution (and your data) to the wind. It’s only important business information after all, right?
But hey, here’s a novel idea – what if you actually wanted to succeed in your cloud-native strategy? I know, I know, it sounds a bit radical given our prior conversation. But bear with me. For those of you who enjoy sailing smoothly on the seas of enterprise IT, without the thrill of hitting every possible iceberg, Dell has created a glorious solution. A tool, that’s as much a life preserver as it is a nautical chart, guiding you safely through the treacherous waters of Kubernetes enterprise rollouts. This magic wand is called the Container Storage Modules (CSM).
This isn’t just any tool – it’s your co-pilot on the journey to a seamless Kubernetes implementation. It’s like having a Swiss army knife for enterprise data management. The CSM ensures that your data persistence strategies are as solid as a rock, ensuring that no pod crash or system failure can sweep your data into the abyss. With CSM, you can laugh in the face of data loss, secure in the knowledge that your enterprise information is safe and sound. So, for the daredevils who actually like to succeed in their endeavors, the Dell Technologies CSM is the perfect tool to ensure your Kubernetes enterprise rollout is as smooth and trouble-free as a hot knife through butter.
I hope this post proves helpful, regardless of which direction you choose for your enterprise cloud journey. If you’re inclined to thrill and enjoy the odd game of Russian roulette with your data, you now have some innovative strategies to stall your Kubernetes rollout. However, if your preference is smooth as a jazz tune and your data as secure as Dell’s Project Fort Zero, then Dell’s Container Storage Modules (CSM) is the tool you need. The CSM is your beacon in the foggy world of Kubernetes enterprise rollout, ensuring that no data loss or system failure can derail your cloud-native strategy. It’s your data’s best friend, your enterprise’s lifeline, and your ticket to a successful Kubernetes implementation.
Enjoy the journey, and remember – with the right tools and strategies, Murphy’s Law doesn’t stand a chance!
Kubernetes keeps increasing in popularity and not just in public cloud. It keeps making inroads into the on-premises market. This is creating the need for automation. In many Kubernetes environments you tend to find developers using CI/CD pipelines not just for their applications code for the Kubernetes objects that deploy the code in the cluster (ex: deployment, service …). This means that most of the automation needs are covered. However there are several instances where you might want to use automation tools (ex: Ansible) either to replace or to supplement CI/CD tools. By the way, I am not talking about the deployment of the Kubernetes cluster itself, which is a valid use case. I am talking about the things that you would normally do with the “kubectl” tool
While creating a new video for the IaC Avengers channel in Youtube I came across one such use case and this prompt me to investigate how to manage Kubernetes with Ansible. This article contains my lessons learned.
My use case is as follows. I wanted to expose the creation of namespaces in any cloud to end-users from ServiceNow. The idea is that rather than giving developers and other personas the right to create their own namespaces an organization would like to keep a central control plane where they can implement the much needed governance and cost transparency. This use case is very important in RedHat OpenShift environments because the general guidance is to share a few clusters as opposed to creating a cluster per tenant as other vendors recommend. Namespaces is the native mechanism to keep tenants separate with this approach
This “Multi-Cloud Kubernetes as a Service” is the latest in a growing set of demos that we have been creating for a while.
In this article we are going to cover:
Architecture
Installation in command line Ansible
Installation in AWX/Tower
A practical example
Architecture
We will use a single Ansible module for this solution: “kubernetes.core.k8s”, which might surprise many of you. At first when I was thinking about this solution I thought there would be multiple modules to manage all the different objects in the Kubernetes API: pods, deployments, secrets … but no, there is a single one. To put this into perspective let’s bear in mind that there are more than 150 different modules to manage all aspects of vSphere environments.
So why is there a single module for Kubernetes? At the end of the day Kubernetes and Ansible have much in common. Both frameworks use a declarative syntax where you express your desired state and then the system does whatever is necessary to implement your specified end state. Furthermore, they both use YAML files. So rather than creating multiple modules, you embed your each individual Kubernetes task manifest inside its own Ansible task. You need to watch out for the right indentations but that in essence how it works. We will see some examples in a later section
Another clever shortcut the creators of the module took is that the module doesn’t include its own Kubernetes client. Instead what the Ansible engine will do is to SSH into a machine that has “kubectl” and the “kubeconfig” installed. You could install “kubectl” in your Ansible system if you wanted (and use “localhost” as the target) but you don’t have to. In my case I have created a separate VM with “kubectl” and all the “kubeconfig” files for all clusters I am managing and the Ansible playbook is targeting that VM which is defined in the inventory. In OpenShift environments your Kubernetes client machine will need to run also the “oc” tool
In our video we assumed there will be multiple clusters available for different combinations of:
Cloud (vSphere based private cloud, AWS, Azure and GCP)
Production or development (You might want to have more like UAT …)
Different Kubernetes versions (v1.22, v1.23, v1.24)
The actual selections made by the user determine the target cluster in which to create the “namespace” (a.k.a “project” in RedHat parlance). The playbook takes the 3 parameters selected by the user and builds the name of the “kubeconfig” file to use. The Ansible module allows you to specify a “kubeconfig” file. From that point any tasks are run in the relevant cluster
The Ansible playbook allows you to specify also a “context”. At the beginning I started using a single “kubeconfig” with multiple contexts but as I kept adding clusters it was getting hard to manage. I think the “kubeconfig” method is easier. Every time you create a new cluster, grab the file, rename it to match the type/location of the cluster (ex: “aws-prod-22.config”) and place it in the directory where the client machine expects to find them and you are done
Installation in command line Ansible
The installation requires you to install things in both the Ansible and Kubernetes client system. With other modules you typically install some Python libraries as a prerequisite and then install the Ansible collection. A very important difference with the Kubernetes collection is the libraries are required in the Kubernetes client system, not in the Ansible system. Of course if you have decided to run the Kubernetes client in your Ansible system you will install everything in the same machine.
Before you start please make sure you are running Python 3.6 or higher in the client. In my case I started installing this in a system with CentOS7 which comes with Python 2.7 by default and I was getting errors until I did
ln -s /usr/bin/python3 /usr/bin/python
In terms of libraries you need the following in the Kubernetes client machine:
kubernetes >= 12.0.0
PyYAML >= 3.11
jsonpatch
In my case I just did “pip install kubernetes” and it installed everything else. OpenShift environments are better managed with the “oc” tool. For that reason you also need an additional library called “openshift”.
The ‘kubernetes’ library expects the kubeconfig file to be present in .kube/config. However, as we discussed earlier you can specify a different location and kubeconfig file name as part of the task inside the playbook
Now in the the Ansible machine you need to install the Ansible collection
ansible-galaxy collection install kubernetes.core
Finally, you will need to add your Kubernetes client to the inventory in the Ansible machine, This is mine:
The above syntax assumes that the kubeconfig is in the default location, i.e. ~/.kube/config in the home directory of the user running the playbook as in the kubernetes client system. Keep reading to see how to store the config in a different location
Installation in AWX/Tower
If we need to run the playbook in AWX or Ansible Tower, nothing of we discussed previously for the Kubernetes clients changes. So you still need the following in the client:
the Python libraries
a supported version of Python in the client
the “kubectl” tool (and “oc” if you are managing OpenShift clusters
However, on the Ansible system you need to:
create the inventory entry that points to the Kubernetes client system
install the “kubernetes.core” collection in the “task” container
create a job template as usual
This is how I installed the “kubernetes.core” collection in my AWX system. Notice how I install it in the “awx_task” container
However, when I went to trigger the job template I got this error
TASK [Create namespace in target Kubernetes cluster] ***************************
fatal: [172.24.167.53]: FAILED! => {"msg": "Could not find imported module support code for ansiblemodule. Looked for either AnsibleTurboModule.py or module.py"}
I fixed it by installing the “cloud.common” collection also inside the “task” container:
[root@awx17 ~]# docker exec -it awx_task /bin/bash
bash-4.4# ansible-galaxy collection install cloud.common
Process install dependency map
Starting collection install process
Installing 'cloud.common:2.1.2' to '/var/lib/awx/.ansible/collections/ansible_collections/cloud/common'
A practical example
The example we are going to use will do 2 things:
create a namespace
assign permissions to the namespace to the user that requested the namespace
In this Kubernetes as a Service design the assumption is that developers and other personas they cannot create or join namespaces by themselves. This is achieved by creating a new namespace or joining an existing one. Hence the need to assign the relevant permissions in the playbook. A future blog post show the “join namespace” scenario which includes including the creator of the namespace in a ServiceNow workflow approval.
The first thing the playbook does is to figure out what kubeconfig file needs to be use. It does so by combining 3 pieces of information. In the video you can see how these details are provided by the user that is requesting the namespace in ServiceNow. They allow us to uniquely identify the Kubernetes cluster we have to use to apply the changes
- name: Build the kubeconfig file name out of input parameters
set_fact:
configname: "{{ cloud }}-{{ envtype }}-{{ version }}"
So for example if the user selects “aws”, “production” and “1.22” the playbook will look for a file named “aws-prod-22.config” and run the remaining tasks on the cluster that is defined in that kubeconfig file. Note how we decided to drop the “1.” from the Kubernetes version to make the file names more streamlined. With this approach, onboarding a new cluster couldn’t be easier. Let’s say in the future we want to create a new development cluster in GCP that is running v1.25. All we need to do is grab the kubeconfig file and place it in the same directory as the other files in the client and rename it to “gcp-dev-25.config”. No further changes are required
Let’s take a look at the playbook
---
- name: Create a namespace in a kubernetes cluster
hosts: kubectl01
gather_facts: false
vars:
#nsname: ansible # needs to be provided by end-user
#version: 22 # corresponds to k8s version 1.22, 1.23 ...
#envtype: dev # type of environment: prod, dev ...
#cloud: vsphere # vpshere, gcp, aws ...
#snow_username: finance1 # this comes also in the API call
#backup_type: gold # user needs to choose between gold/silver policies
tasks:
- name: Build the kubeconfig file name out of input parameters
set_fact:
configname: "{{ cloud }}-{{ envtype }}-{{ version }}"
- debug:
msg: "Let's create namespace {{ nsname }} with kubeconfig {{ configname }}.config"
- name: Create namespace in target Kubernetes cluster
kubernetes.core.k8s:
state: present
kubeconfig: "~/.kube/{{ configname }}.config"
kind: Namespace
name: "{{ nsname }}"
definition:
metadata:
labels:
backuptype: "{{ backup_type }}"
snowowner: "{{ snow_username }}"
- name: Create role binding for user {{ snow_username }}
kubernetes.core.k8s:
state: present
kubeconfig: "~/.kube/{{ configname }}.config"
definition:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: "{{ nsname }}-owner"
namespace: "{{ nsname }}"
subjects:
- kind: User
name: "{{ snow_username }}"
roleRef:
kind: ClusterRole
name: admin
I have commented out all the variables required as they are being passed as parameters but you can remove the comments when you are testing the playbook
Pay close attention to the “definition” section in the “role binding” task. If you took everything that follows, insert it into a YAML file and use “kubectl apply” it accomplish the same thing. This is what I was referring to about the beauty of how the creators have designed the Ansible module
Notice how we are adding 2 labels to the namespace. These will be used for the “join namespace” workflow and for automatically adding the namespace to a backup policy in PPDM (PowerProtect Data Manager). We will cover these two features in future posts
The “snow_username” is the username of the user that places the request in ServiceNow. In our demo we used KeyCloak to create in seamless authentication infrastructure across ServiceNow and the rest of our infrastructure including OpenShift
Finally, notice how we are binding the default “admin” role to the user, but restricted to the namespace, which is what you would expect from an owner. However, by the rules of least privilege, if you wanted to you could restrict to whatever you need by defining a specific role. You could potentially create this role at the only once at the cluster level. In that case it wouldn’t need to be part of this playbook. We will use this technique for offering various roles in the “join namespace” workflow. The following code is an example for a “deployment manager” role in a specific namespace
- name: Create a new role for deployment managers
kubernetes.core.k8s:
state: present
kubeconfig: "~/.kube/{{ configname }}.config"
definition:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1 #rbac.authorization.k8s.io/v1
metadata:
namespace: office
name: deployment-manager
rules:
- apiGroups: ["", "extensions", "apps"]
resources: ["deployments", "replicasets", "pods"]
verbs: ["*"]
I hope you found this helpful. Keep an eye on the follow up video and the two follow up blog articles
I created below tasks in my Ansible role playbook.
# Set net.bridge.bridge-nf-call-ip6tables value to 1 all K8S cluster nodes
- name: ensure net.bridge.bridge-nf-call-ip6tables is set to 1
sysctl:
name: net.bridge.bridge-nf-call-ip6tables
value: 1
state: present
# Set net.bridge.bridge-nf-call-iptables value to 1 all K8S cluster nodes
- name: ensure net.bridge.bridge-nf-call-iptables is set to 1
sysctl:
name: net.bridge.bridge-nf-call-iptables
value: 1
state: present
But when I executed this playbook I got below error
fatal: [prod-k8s-master01]: FAILED! => {"changed": false, "msg": "Failed to reload sysctl: sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or dire ctory\nsysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory\n"}
fatal: [prod-k8s-worker01]: FAILED! => {"changed": false, "msg": "Failed to reload sysctl: sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-ip6tables: No such file or dire ctory\nsysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory\n"}
After lots of reading and researching I found that I did not escalate the privileges on in my main YML file. After adding Become: yes in the main YML resolved my issue. Below is the syntax of my main playbook.
- hosts: all
gather_facts: false
become: yes
vars_files:
- answerfile.yml
Sometimes common mistakes are the most time consuming because we take it for granted.
In this post, we will discuss automating Kubernetes deployment using Ansible.
In my example, I have used CentOS VMs (on VMware) for deploying Kubernetes. But technically Kubernetes deployment steps don’t differ irrespective of the platform you use.
Before getting started to make sure you have
Ansible server up and running on the network. Also, make sure Ansible can reach the VMware environment.
Make sure you’ve added Ansible server SSH authentication keys into VMware virtual machine before converting the same into the template. Follow this blog post for steps.
Once you have the pre-requisites in place follow the below steps.
Step 1 – Clone my GitHub repository which consists of required playbooks and instructions.
Step 2 – Edit k8s-deployment.yml file and edit below lines from VARS
common environment details
#ntp_server: - Replace with your NTP server IP/hostname
domain: "" - Replace with your DOMAIN NAME
dns_server: - Replace with your DNS server IP/hostname
vmware environment details
vcenter_ip: - Replace with your vCenter server IP/hostname
vcenter_username: - Replace with vCenter admin account username
vcenter_password: - Replace with vCenter admin account password
vmware_datacenter: - Replace with VMware datacenter you want to use
vmware_cluster: - Replace with VMware cluster you want to use
vm_network: "" - Replace with VM network you want kubernetes VMs to connect
k8s_vm_folder: - Replace with VM folder in which you want to place kubernetes VMs
k8s_template_name: - Replace with VMware CentOS template name
K8S environment details
k8s_master_ip: 192.168.172.100 - Replace IP address with kubernetes master server IP address you want to use
k8s_network_netmask: 255.255.255.0 - Replace subnet mask with netmask of kubernetes network
k8s_network_gateway: 192.168.172.1 - Replace gateway with kubernetes network gateway
k8s_node1_ip: 192.168.172.101 - Repalce IP address with kubernetes node IP address
#k8s_node2_ip: 192.168.1.102
#k8s_node3_ip: 192.168.1.103
#k8s_node4_ip: 192.168.1.104
#k8s_node5_ip: 192.168.1.105
#k8s_node6_ip: 192.168.1.106
#k8s_node7_ip: 192.168.1.107
#k8s_node8_ip: 192.168.1.108
Step 3 – Edit the /etc/ansible hosts file and insert the Kubernetes environment details. Make sure IP address details are inline with your Kubernetes environment
Containers are everywhere and they are here to stay. They are great level-playing ground to break the infrastructure dependency and allow developers to release their code to any environment.
Containers also help customers to operate at greater scales with ability to quickly scaling up and down, patching with disruptions, withstand infrastructure component failures, moving easily from on-premises to public clouds, etc.
As per the survey from sysdig lifespan of containers and container images is also very short.
At this stage of the popularity of containers there are two thought processes in the container fan club – Persistent or Non-Persistent Containers
If you explore docker hub top downloads you’ll notice that 7/10 top downloads require data persistence (snippet below)
Let’s understand persistent containers in more details.
Prior to Container Storage Integration CSI, Kubernetes provided in-tree (ie as part of the core code) plugins to support volumes but that posed a problem in that storage vendors had to align to the Kubernetes release process to fix a bug or to release new features among other problems. This also means every storage vendor had their own process to present volumes to Kubernetes.
This heterogeneous non-standard integrations were one of the biggest reasons why CSI was created. CSI was developed as a standard for exposing block and file storage storage systems to containerized workloads on Container Orchestration Systems (COs) like Kubernetes. With the adoption of the Container Storage Interface (CSI), the Kubernetes volume layer becomes truly extensible. Using CSI, third-party storage providers like DellEMC can write and deploy plugins exposing new storage systems in Kubernetes without ever having to touch the core Kubernetes code. This gives Kubernetes users more options for storage and makes the system more secure and reliable. Also this approach makes sure that every vendor has standard way of interacting with Kubernetes.
With CSI Kubernetes supports Persistent Volumes (PV). PVs life-cycle independent of any Kubernetes POD. Kubernetes supports 2 ways to provision PVs
Static – Admin Pre-provisions / creates a number of PVs
Static PV provisioning
Dynamic – Cluster “automatically” provisions a volume
Dynamic PV provisioning
No matter which is the method of PV provisioning it can support varying properties such as performance, QOS, backup policies, etc. These properties are defined by StorageClass
There are 3 access modes which are supported on PV. Storage volume cannot be mounted simultaneously in more than one access mode.
ReadWriteOnce (RWO) – Volume can be mounted as ready-write by a single node
ReadOnlyMany (ROX) – Volume can be mounted read-only by many nodes
ReadWriteMany (RWX) – Volume can be mounted as read-write by many nodes
Below is the summary of persistence
DellEMC CSI Support
DellEMC understands that that Enterprise applications require persistent storage. As of now (Nov 2019) DellEMC supports CSI plugins for below storage arrays
Part of my job is to talk about the latest geeky technologies and many times I also have to demonstrate the same – Kind of “Show me” discussions.
When I started working on getting my hands dirty on Kubernetes (aka K8S) I faced many issues to get started. Now I am at the level where deploying K8S isn’t a big deal at all. The reason I am writing this blog is that often more than not I always get into discussions where someone is just starting with the K8S journey and has the same queries and questions which I also had. Hopefully, this summary will help people to get started with K8S.
Before I get started it’s important to understand the K8S lingo 🙂 This will help understand the implementation steps. Also, note that the purpose of this page is not to re-iterate the K8S components and architecture. It’s purely intended to list the steps o have hassle-free K8S deployment
Make sure that the VMware template which will be used has Ansible master server SSH keys added before you convert the VM image to the template. I have already documented this process of enabling SSH-based authentication in this blog
Part 1 – Dependencies
Below are the list of dependencies which needs to be installed on all the K8S nodes (master and worker)
Disable SELinux
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
Turnoff swap (also remove swap entry from /etc/fstab)
At this moment your K8S master is installed and configured. Next step is to configure worker nodes and add them into the K8S cluster
Part 3 – Kubernetes Worker
Final part is to have worker nodes configured and add them in K8S cluster. This steps involves running commands on Master and Worker nodes.
Master node – For adding worker nodes into the K8S cluster we first need to get the join command from the master server. Run the below command on Master server
kubeadm token create --print-join-command
Note/copy the join command output. We need to run this join command on all worker nodes.
Finally run below command on the K8S Master. If everything was successful then you should see list of all the nodes (Master and Worker) of your K8S cluster.
kubectl get nodes
This concludes K8S installation and configuration 🙂