Tag: delltechnologies

  • Ansible Dynamic Inventory Tutorial

    This is the first of a 3 part series on Ansible dynamic inventories. I was looking for some information about dynamic inventories as part of a project and I realized that even though there are a few articles out there, there is little detailed content specially around building your own dynamic inventory script and how to use it in Tower/AWX. So I am planning to share all the lessons I learned to help you in your own journey. This series is structured as follows:

    • Introduction to dynamic inventory
    • Develop your own dynamic inventory
    • Dynamic inventory in AWX/AAP

    The code for the examples shown in this series is written in Python and is available in this GitHub repo: https://github.com/cermegno/ansible-dynamic-inventory. And now, without further ado let’s start with the introduction.

    Static Inventory 1 min recap

    If you are reading this article more than likely you are not new to Ansible and you know what a static inventory is, but we need to spend a minute laying out the example we will use in this tutorial. Inventories can be formatted in several ways but INI is perhaps the most common. In an inventory you can define groups and children groups. The following is an example that shows 2 groups: “webprod” and “webdev”, each one with 2 target systems on it.

    [webprod]
    web1 http_port=123
    web2 http_port=456
    
    [webdev]
    dev1
    dev2
    
    [webdev:vars]
    user=admin
    pass=password
    

    You also have the ability to define variables for a group and for individual hosts. In this example we have defined a host variable for each host in the “webprod” group. However, the 2 variables we need for the “webdev” group are the same for all systems in that group so it makes sense to use group variables as shown.

    Another way you can format inventory files is JSON, and as we will see next, the JSON format is specially useful when creating dynamic inventories

    Understanding Dynamic Inventories

    Static files like these are the most common type of Ansible inventories and as long as the information contained in them doesn’t change often this is the way to go. However there are many environments that are very dynamic in nature and a static inventory file like this becomes obsolete very quickly and it is hard to maintain. So the solution is to use a dynamic inventory.

    Another consideration is that sometimes the targets themselves don’t change much but the variables (for hosts or groups) do. The use case we will play with in the second part of this tutorial is a great example of this.

    So, what is a dynamic inventory? It is a script that returns the inventory information in a specific format that Ansible expects. What format is that? JSON. The following is the JSON equivalent of the static inventory we used earlier

    {
        "webprod": {
            "hosts": [
                "web1",
                "web2"
            ]
        },
        "webdev": {
            "hosts": [
                "dev1",
                "dev2"
            ],
            "vars": {
                "user": "admin",
                "pass": "password"
            }
        },
        "_meta": {
            "hostvars": {
                "web1": {
                    "http_port": "123"
                },
                "web2": {
                    "http_port": "456"
                }
            }
        }
    }

    Notice how there is a top level key for each group. Each of these “group” keys can have the following keys:

    • hosts. This key contains a list of targets
    • vars. This is a dictionary that contains the variables for the group. The “webprod” didn’t have any group variables, so the “vars” key can be omitted
    • children. This key contains a list of children groups of this group. If it is not present Ansible will assume the group doesn’t have any children groups

    Also notice how there is another top level key called “_meta” which includes the host variables under a key called “hostvars”.

    Ansible expects the “dynamic inventory” script to implement 2 flags. Only one of these will be invoked at once:

    • “–list”. When the script is run with this flag it has to return the entire JSON structure as shown above
    • “–host”. This flag is followed by the name of a specific host in the inventory and when used your script has to return the variables for that host.

    IMPORTANT: In the past the “–host” flag was the only way of getting host variables but it is very inefficient to do things when Ansible needs to get the “hostvars” from many hosts, one at a time. So in modern versions of Ansible, the preferred way of implementing this functionality with the “–list” flag is by using the “_meta” key shown above. Also, to ensure Ansible pays attention only to the “_meta” section, the “–host” flag needs to be functional but needs to return only an empty dictionary.

    NOTE: If your preference is to use the “–host” flag instead your “_meta” still needs to include an empty “hostvars” dictionary as described in the documentation.

    Using the ansible-inventory tool

    Ansible provides a very handy tool to display and troubleshoot the inventory. The tool is called “ansible-inventory”. We can use this tool to observe how Ansible sees the inventory. You can see the full help page of the command by typing “ansible-inventory -h” but let’s play with some of the options here. Firstly we have “–list” that shows the full inventory as Ansible sees it.

    
    [root@alb-ansible3]# ansible-inventory -i staticinv.ini --list
    {
        "_meta": {
            "hostvars": {
                "dev1": {
                    "pass": "password",
                    "user": "admin"
                },
                "dev2": {
                    "pass": "password",
                    "user": "admin"
                },
                "web1": {
                    "http_port": 123
                },
                "web2": {
                    "http_port": 456
                }
            }
        },
        "all": {
            "children": [
                "ungrouped",
                "webdev",
                "webprod"
            ]
        },
        "webdev": {
            "hosts": [
                "dev1",
                "dev2"
            ]
        },
        "webprod": {
            "hosts": [
                "web1",
                "web2"
            ]
        }
    }
    

    There are a few things to note from the output above:

    • You need to specify the inventory file with the “-i” option. It doesn’t matter whether it is a script or a static file, you need to use the “-i” option. In this case I am using the INI inventory file we showed first. I have called it “staticinv.ini”
    • Notice how Ansible has taken the group variables of the “webdev” group and has turned them into host variables under the “_meta” section. So for us it is more efficient to use group variables but internally Ansible unfolds those into individual hosts variables. Consequently, the group keys show only the list of hosts in the group
    • Ansible has created the “all” group and has add the other groups as “children” of “all”. It has also added the “ungrouped” group. Now we understand how Ansible handles your plays when you specify “hosts: all”

    So the “–list” option helps us understand many things. But it would be good if it could provide the optimal JSON version of a static INI inventory file that we can use as a template to write the code of our dynamic inventory script. Luckily for us, that option is also available. It is just a matter of adding the “–export” flag to the previous command. Please note how this is in addition to “–list” not as a replacement.

    [root@alb-ansible3]# ansible-inventory -i staticinv.ini --list --export
    {
        "_meta": {
            "hostvars": {
                "web1": {
                    "http_port": 123
                },
                "web2": {
                    "http_port": 456
                }
            }
        },
        "all": {
            "children": [
                "ungrouped",
                "webdev",
                "webprod"
            ]
        },
        "webdev": {
            "hosts": [
                "dev1",
                "dev2"
            ],
            "vars": {
                "pass": "password",
                "user": "admin"
            }
        },
        "webprod": {
            "hosts": [
                "web1",
                "web2"
            ]
        }
    }
    

    Now the variables “user” and “pass” have been turned into group variables of the “webdev”. So that’s it, if we want to create a dynamic inventory script we can start by creating a sample INI version of the inventory and use the “–export” flag to create a JSON equivalent. We then write our code to produce that on demand

    Another handy option available in the “ansible-inventory” tool is “–graph”. When invoked it provides a graph representation of the inventory. Group names are prepended with “@”. Hosts in the group are shown indented under the group name

    [root@alb-ansible3]# ansible-inventory -i staticinv.ini --graph
    @all:
      |--@ungrouped:
      |--@webdev:
      |  |--dev1
      |  |--dev2
      |--@webprod:
      |  |--web1
      |  |--web2
    

    Built-in inventory plugins

    Ansible comes with some built-in inventory plugins to help you with some of the most common use cases. You can see what inventory plugins were installed by using the “ansible-doc” command as follows. My version of Ansible is 2.9.21 and this is what it came by default

    [root@alb-ansible3]# ansible-doc -t inventory -l
    advanced_host_list  Parses a 'host list' with ranges
    auto                Loads and executes an inventory plugin specified in a YAML config
    aws_ec2             EC2 inventory source
    aws_rds             rds instance source
    azure_rm            Azure Resource Manager inventory plugin
    cloudscale          cloudscale.ch inventory source
    constructed         Uses Jinja2 to construct vars and groups based on existing inventory
    docker_machine      Docker Machine inventory source
    docker_swarm        Ansible dynamic inventory plugin for Docker swarm nodes
    foreman             foreman inventory source
    gcp_compute         Google Cloud Compute Engine inventory source
    generator           Uses Jinja2 to construct hosts and groups from patterns
    gitlab_runners      Ansible dynamic inventory plugin for GitLab runners
    hcloud              Ansible dynamic inventory plugin for the Hetzner Cloud
    host_list           Parses a 'host list' string
    ini                 Uses an Ansible INI file as inventory source
    k8s                 Kubernetes (K8s) inventory source
    kubevirt            KubeVirt inventory source
    linode              Ansible dynamic inventory plugin for Linode
    netbox              NetBox inventory source
    nmap                Uses nmap to find hosts to target
    online              Online inventory source
    openshift           OpenShift inventory source
    openstack           OpenStack inventory source
    scaleway            Scaleway inventory source
    script              Executes an inventory script that returns JSON
    toml                Uses a specific TOML file as an inventory source
    tower               Ansible dynamic inventory plugin for Ansible Tower
    virtualbox          virtualbox inventory source
    vmware_vm_inventory VMware Guest inventory source
    vultr               Vultr inventory source
    yaml                Uses a specific YAML file as an inventory source
    

    Create your first dynamic inventory

    So far we know that a dynamic inventory script needs to return a well-known JSON structure. So how do you obtain the information to populate the JSON? It depends on your use case. Ultimately, you will have a source of truth for your inventory information and you will have to interact with that source programmatically. For example, if the inventory information is on a database you will have to write a script that queries the database to find out what to put in the JSON output. Other examples could be Excel or even a text file. Nowadays it is very common to deal with systems that expose a REST API interface and all programming languages have web client libraries that allow you to talk to such API’s. In the next post we will show you an example of how to create a dynamic inventory for your Dell infrastructure by using CloudIQ’s REST API

    To wrap up this post let’s show how to create the most basic dynamic inventory script how to use it . For simplicity we are going to drop the “webdev” group and create a script that returns the details of the “webprod” group only, including the “_meta” with their host variables. In my system I have created a python script called “basicinv.py” that looks as follows:

    [root@alb-ansible3]# cat basicinv.py
    #!/usr/bin/env python3
    import json
    output = {
        "_meta": {
            "hostvars": {
                "web1": {
                    "http_port": 123
                },
                "web2": {
                    "http_port": 456
                }
            }
        },
        "webprod": {
            "hosts": [
                "web1",
                "web2"
            ]
        }
    }
    print(json.dumps(output))
    

    It is creating a dictionary with the static information and using the “json.dumps” function to dump it on the terminal. Notice how for simplicity I am not checking for “–list” or “–host” flag. So the script dumps everything every time which is the default behavior of “–list”. Hence running tasks for “all” hosts will fine but not for specific hosts. The objective was to create the script as simple as possible so we will leave the “–host” flag out in this post. In the next post of this series we will use the “argparse” library to implement both flags properly.

    [root@alb-ansible3]# ansible all -i basic.py -m debug -a "var=http_port"
    web2 | SUCCESS => {
        "http_port": 456
    }
    web1 | SUCCESS => {
        "http_port": 123
    }
    [root@alb-ansible3]# ansible web1 -i basic.py -m debug -a "var=http_port"
    [WARNING]: Unable to parse /root/basic.py as an inventory source
    [WARNING]: No inventory was parsed, only implicit localhost is available
    [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

    The previous screenshot shows the ad-hoc “debug” running successfully against “all” hosts but not against host “web1” as expected as this would require a functional “–host” flag as explained earlier. Notice how we use the “-i” option to specify the script.

    Now let’s see if it works with a playbook too. I have created the following “ping.yml” playbook

    - name: Check that our targets are reachable
      hosts: webprod
      gather_facts: false
    
      tasks:
      - ping:

    Now we run it like this. Notice above how we are targeting the “webprod” group. Using “all” works as well. If we try with an individual host like “web1” it also works, but this is only because our simple “ping.yml” doesn’t require Ansible to look for the “hostvars”. In that case we would need to make our simple dynamic inventory script award of the “–host” flag and return an empty dictionary as we discussed earlier

    [root@alb-ansible3]# ansible-playbook -i basicinv.py ping.yml
    
    PLAY [Check that our targets are reachable] *********************************************************************
    
    TASK [ping] *******************************************************************************
    ok: [web2]
    ok: [web1]
    
    PLAY RECAP *******************************************************************************
    web1 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0
    web2 : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0 
    

    Things to watch out for – Possible errors

    There are 2 important things to watch out for when you create your own script:

    • Make sure your script has execute permission, otherwise you will get the error “Unable to parse /root/basic.py as an inventory source”
    • Make sure you add the shebang that matches your Pyhon version, which in my case is “!/usr/bin/env python3“. Otherwise you get the error “Failed to parse with script plugin” below. Notice how it tries to parse it as a script first and then it tries to parse it as an INI before it gives up
    [root@alb-ansible3]# ansible-playbook -i basic.py ping.yml
    [WARNING]:  * Failed to parse /root/basic.py with script plugin: problem running
    /root/basic.py --list ([Errno 8] Exec format error: '/root/basic.py')
    [WARNING]:  * Failed to parse /root/basic.py with ini plugin:
    /root/basic.py:1: Expected key=value host variable assignment, got: json
    [WARNING]: Unable to parse /root/basic.py as an inventory source
    [WARNING]: No inventory was parsed, only implicit localhost is available
    [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
    match 'all'
    

    I hope you found this introduction valuable. On the second part we will create the full-blown solution for a dynamic inventory script where we extract the data from a REST API at runtime. See you soon!

  • Murphy’s Law – How to stall your Kubernetes enterprise rollout.

    Murphy’s Law – How to stall your Kubernetes enterprise rollout.

    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.

    This Photo by Unknown Author is licensed under CC BY-NC

    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.

    This Photo by Unknown Author is licensed under CC BY-SA

    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.

    Image from CNCF landscape

    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.

    Image courtesy - https://www.google.com/url?sa=i&url=https%3A%2F%2Fsnyk.io%2Flearn%2Fcloud-application-security%2F&psig=AOvVaw0cLWWp0MtGNoPo1idw-iL7&ust=1691737538095000&source=images&cd=vfe&opi=89978449&ved=0CBIQjhxqFwoTCPCrh8vD0YADFQAAAAAdAAAAABAE

    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!

    image courtesy - https://devrant.com/rants/1535091/ci-cd-in-a-nutshell

    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!

    image courtesy - https://linkedin.github.io/school-of-sre/level101/metrics_and_monitoring/observability/

    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?

    image courtesy - https://www.atlassian.com/microservices/microservices-architecture/configuration-management

    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?

    image courtesy - https://www.sungardas.com/en-us/blog/how-to-create-a-dr-plan-you-can-be-confident-in/

    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!

    image courtesy - https://www.makemebetter.net/learning-to-go-with-the-flow/

    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?

    image courtesy - https://cloudtweaks.com/2016/11/4-cloud-tools-help-business-save-money/

    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). 

    https://dell.github.io/csm-docs/docs/

    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!

  • Red Hat OpenShift – Add SSH Keys to Cluster (After Deployment)

    Red Hat OpenShift – Add SSH Keys to Cluster (After Deployment)

    Part of my job is to demonstrate the Red Hat OpenShift integration with Dell Technologies’ portfolio. Most of the time I repurpose my OCP infrastructure and re-install the cluster. This means using the same Bastion host to manage the new OCP cluster. There have been a couple of instances where I forgot to include bastion host SSH keys in the OCP installation and because of that, I couldn’t log in to the OCP cluster nodes.

    By default, RH CoreOS gets installed with a single user (core) with the option to add SSH keys at the install time. Most of the tasks in the RH OCP environment are done from the bastion/service node without the need to log in directly on the OCP nodes. But in some cases, you might find it useful to have SSH access to OCP nodes. In my case, it was for configuring the iSCSI and multipath on OCP nodes (for CSI configuration)

    Installing SSH keys post OCP installation is a bit tricky and hence the purpose of this blog. I hope this helps fellow OCP architects (and as a reference for me as well).

    To start with below is the high-level Red Hat OCP setup I have created. My test OCP cluster (version 4.8.x) is having 3 nodes, which are acting as both master and worker.

    Logging into the RH OCP cluster from bastion/service node

    Before you get started make sure you’re able to execute OC commands from the bastion/service node. If you’re getting an error (like below) then make sure you’re logged into the newly created cluster.

    RH OCP – Login Error

    For connecting the service node to the RH OCP cluster you will need an API token. For generating the API token, log into the RH OCP UI –> Click on User Name (top right corner) –> Click on Copy Login Command.

    This will open a new window. Click on the Display Token link. Copy the oc login command and run it on the service node.

    RH OCP – Copy Login Command
    RH OCP – Log into the OCP Cluster

    Update RH OCP SSH Keys

    In RH OCP there are 2 MachineConfigs (99-master-ssh and 99-worker-ssh) that handle the SSH key management. You can list those using the below command. If you had given the SSH keys while installing RH OCP then it will get registered in these MachineConfigs

    [root@ocp-svc ~]# oc get machineconfig | grep "ssh"
    99-assisted-installer-master-ssh 3.1.0 54d
    99-master-ssh 3.2.0 54d
    99-worker-ssh 3.2.0 54d

    First, we will start with master nodes.

    The next step is to download the MachineConfig as YAML to update the SSH keys. You can run the below command to download the machine config object. In this case, I am getting the configuration from the master server.

    [root@ocp-svc ~]# oc get mc 99-master-ssh -o yaml > 99-master-ssh.yaml

    Copy the SSH keys from the service/bastion node. You can generate the new keys (if needed using the ssh-keygen command). By default, SSH keys are stored on the /root/.ssh/id_rsa.pub location.

    Edit the downloaded 99-master-ssh.yaml file and append the copied SSH key in the passwd section of the yaml file (as shown below) and save the file. Make sure you follow the YAML syntax while editing the file.

        passwd:
          users:
          - name: core
            sshAuthorizedKeys:
            - <existing SSH key>
            - <your new SSH key>
      fips: false
      kernelType: ""
      osImageURL: ""
    

    Then run the following command to apply the new MachineConfig file with the updated SSH key. This step might restart your nodes (one by one).

    [root@ocp-svc ~]# oc apply -f 99-master-ssh.yaml

    At this stage, you will be able to log into the master nodes. You’ll need to run the same procedure again for the worker nodes by updating the 99-worker-ssh MachineConfig.

    Additionally, if you’re reusing the bastion/service node then make sure you remove the old entries from the /root/.ssh/known_hosts file.

    I hope this article helps everyone.