A flow diagram of the inner and outer loops in a Kubernetes development process.

Kubernetes conversations rarely center the developer's perspective. As a result, doing our job in a k8s cluster often requires building complicated YAML resource files, writing custom shell scripts, and understanding the countless options that are available in kubectl and docker commands. On top of all of that, we have the learning curve of understanding Kubernetes terminology and using it the way that operations teams do.

To address these challenges, the Red Hat Developer Tools team created odo (OpenShift Do), a command-line interface (CLI) tool built for developers and designed to prioritize the things that developers care about. In this article, I will use a hands-on example to introduce you to the benefits of using odo in conjunction with Kubernetes.

Improving the developer workflow

First, let's consider a typical workflow for a developer whose team has adopted Kubernetes. The workflow starts with local development activities and finishes with containers deployed and code running in one or more Kubernetes clusters. To help visualize this flow, you can think of it in terms of an inner loop and an outer loop. The inner loop consists of local coding, building, running, and testing the application—all activities that you, as a developer, can control. The outer loop consists of the larger team processes that your code flows through on its way to the cluster: code reviews, integration tests, security and compliance, and so on. The inner loop could happen mostly on your laptop. The outer loop happens on shared servers and runs in containers, and is often automated with continuous integration/continuous delivery (CI/CD) pipelines. Usually, a code commit to source control is the transition point between the inner and outer loops. Figure 1 illustrates the interplay of these loops in a Kubernetes development process.

A flow diagram of the inner and outer loops in a Kubernetes development process.
Figure 1. A flow diagram of the inner and outer loops in a Kubernetes development process.

Notice that, while you code, you are constantly iterating through various development activities: You code, build, deploy locally, and debug—and you keep going until you achieve a degree of feature completeness. At some point, you will be ready to transition from inner to outer, right? Not so quick.

Deploying from the inner loop

You might think that your job stops at local testing and a Git pull request (or a git push)—but that's not usually the case. You will still need to ensure that your code functions correctly in containers, runs in the cluster, and plays nicely with other containerized components. Therefore, you will want some iterations of your inner loop to deploy and debug directly into the Kubernetes cluster.

Here's a list of steps you might typically follow to deploy from the inner loop:

  1. Describe how to configure the OS for your container:
    • Write a Dockerfile to set up Linux.
  2. Describe how to package your app into a container image:
    • Update the Dockerfile.
  3. Create a container image:
    • Issue the commands docker build and docker tag.
  4. Upload the container image to a registry:
    • Issue a docker push.
  5. Write one or more Kubernetes or OpenShift resource files:
    • Write lots of YAML.
  6. Deploy your app to the cluster:
    • Issue the command: kubectl apply -f my_app.yaml.
  7. Deploy other services to the cluster:
    • Issue the command: kubectl apply -f svc*.yaml.
  8. Write the config (or set ENV) to allow apps to work together:
    • Issue a kubectl create configmap.
  9. Configure apps to work together correctly:
    • Issue a kubectl apply -f my_configmap.yaml.

That's a lot of steps!

Enter, odo

Red Hat OpenShift's oc CLI tool can help make many of those steps easier; however, oc is operations focused. Using it requires a deep understanding of Kubernetes and OpenShift concepts. Odo, on the other hand, was designed to be simple and concise:

  • Its syntax and design center concepts familiar to developers, such as projects, applications, and components.
  • It automates the creation of deployment configurations, build configurations, service routes, and other OpenShift elements.
  • It is designed for quick iterations—as an example, it detects changes to local code and deploys to the cluster automatically, giving developers instant feedback to validate changes in realtime.
  • It is completely client-based, so no server-side-component setup is required.

Odo also offers:

  • Red Hat support for Node.js and Java components.
  • Compatibility with other languages such as Ruby, Perl, PHP, and Python.
  • Status updates for components and services on the cluster.

Odo works from any terminal on the Windows, macOS, and Linux operating systems, and it supports autocompletion for bash and zsh command-line shells.

That's enough overview. Let's see odo in action.

Hands-on development with Odo

If you want to follow along with this example, start by downloading odo for your platform of choice.

For macOS, the command is:

> curl -L https://mirror.openshift.com/pub/openshift-v4/clients/odo/latest/odo-darwin-amd64 -o /usr/local/bin/odo && chmod +x /usr/local/bin/odo

For Linux, it's:

> curl -L https://mirror.openshift.com/pub/openshift-v4/clients/odo/latest/odo-linux-amd64 -o /usr/local/bin/odo && chmod +x /usr/local/bin/odo

Next, clone the example source code:

> git clone https://github.com/RedHatGov/openshift-workshops.git > cd openshift-workshops/dc-metro-map

If you aren't already logged in to your cluster with oc, run this and enter your login info:

> odo login https://api.yourcluster.com:6443

Alternatively, you could use the following link to get a token-based login (note that you must update the URL with your cluster's domain name): https://oauth-openshift.apps.yourcluster.com/oauth/token/display.

We now have a setup for a sample Node.js application. In the next sections, I'll show you how to use odo to deploy the app to a Kubernetes cluster; configure and connect the app to other services; and update an environment variable and verify the changes in a web browser. I'll conclude by showing you how to do a simple code change and quickly iterate through the development process before propagating your local code back into the Kubernetes cluster.

Part 1: Deploy the app

The first thing you'll do is set up a new project and deploy it on a Kubernetes cluster.

  1. Create a project that only you can work in by entering a command similar to the one below:
    > odo project create jasons-odo
    

    You should see output similar to mine below:

    ✓ Project 'jasons-odo' is ready for use
    ✓ New project created and now using project: jasons-odo
    
  2. Create a Node.js component for the new project:
    > odo create nodejs
    

    The output should look something like this:

    ✓ Validating component [61ms]
    Please use `odo push` command to create the component with source deployed
    
  3. Push the changes—in this case, a new component and the example application code—to the cluster:
    > odo push
    

    You should see something like this:

    Validation
     ✓  Checking component [116ms]
    
    Configuration changes
     ✓  Initializing component
     ✓  Creating component [336ms]
    
    Pushing to component nodejs-dc-metro-map-zvff of type local
     ✓  Checking files for pushing [2ms]
     ✓  Waiting for component to start [1m]
     ✓  Syncing files to the component [7s]
     ✓  Building component [32s]
     ✓  Changes successfully pushed to component
    

The code is now running in a container on the cluster. But we also want to create a URL route into the code so that we can view the running application in a web browser. Next steps:

  1. Expose an HTTP route into your Node.js app:
    > odo url create --port 8080

    Check the output:

    ✓  URL nodejs-dc-metro-map-zvff-8080 created for component: nodejs-dc-metro-map-zvff
    To create URL on the OpenShift Cluster, please use `odo push`
    
  2. Push the new URL change to the cluster:
    > odo push
    

    Check the output:

    Validation
     ✓  Checking component [88ms]
    
    Configuration changes
     ✓  Retrieving component data [107ms]
     ✓  Applying configuration [107ms]
    
    Applying URL changes
     ✓  URL nodejs-dc-metro-map-zvff-8080: http://nodejs-dc-metro-map-zvff-8080-app-jasons-odo.apps.yourcluster.com created
    
    Pushing to component nodejs-dc-metro-map-zvff of type local
     ✓  Checking file changes for pushing [7ms]
     ✓  No file changes detected, skipping build. Use the '-f' flag to force the build.
    

To verify that the deployment has worked, locate the URL in the command output just shown (or run odo url list) and try opening it in your web browser. You should see something like the map in Figure 2.

A map of transit stops in Washington DC's Federal Triangle.
Figure 2. A map of transit stops in Washington D.C.'s Federal Triangle.

Part 2: Configure and connect the app to other services

Next, you'll use odo to add a database dependency to your Node.js app. For this to work, your cluster will need to have both OpenShift Service Catalog and Template Service Broker installed.

  1. Create the database and pass-in the defaults for config variables:
    > odo service create mongodb-persistent --plan default --wait \
    -p DATABASE_SERVICE_NAME=mongodb -p MEMORY_LIMIT=512Mi \
    -p MONGODB_DATABASE=sampledb -p VOLUME_CAPACITY=1Gi
    

    Here's the output:

    Deploying service mongodb-persistent of type: mongodb-persistent
    
     ✓  Deploying service [55ms]
     ✓  Waiting for service to come up [3m]
     ✓  Service 'mongodb-persistent' is ready for use
    

    Optionally, link mongodb-persistent to your component by running: odo link.

  2. Provide your Node.js app with the database credentials and other secrets needed to configure and connect to the database:
    > odo link mongodb-persistent
    

    You should see something like the following output:

    ✓  Service mongodb-persistent has been successfully linked to the component nodejs-dc-metro-map-zvff
    
    The below secret environment variables were added to the 'nodejs-dc-metro-map-zvff' component:
    
    admin_password
    database_name
    password
    uri
    username
    
    You can now access the environment variables from within the component pod, for example:
    $uri is now available as a variable within component nodejs-dc-metro-map-zvff
    

Part 3: Update the environment variables

Let's say you need to update some env vars for your containerized Node.js app. Doing that with odo is really straightforward.

  1. Tell odo what env var to add or update:
    > odo config set --env BEERME=true
    

    You should see something like the following output:

     ✓  Environment variables were successfully updated
    Run `odo push --config` command to apply changes to the cluster.
    
  2. Push the changes with the new env var to the cluster:
    > odo push --config
    

    You should see something like this:

    Validation
     ✓  Checking component [84ms]
    
    Configuration changes
     ✓  Retrieving component data [96ms]
     ✓  Applying configuration [40s]
    
    Applying URL changes
     ✓  URL nodejs-dc-metro-map-zvff-8080 already exists
    

Now refresh the page in your web browser. You'll see that the new env has taken effect. Your map icons should now look like pint glasses, as shown in Figure 3.

The updated map shows the effect of changing the environment variable.
Figure 3. The updated map icons verify that changing the environment variable worked.

Part 4: Iterate the inner loop

In this last part, I'll show you how to do a simple code change with odo. I'll also demonstrate how iterating on your inner loop easily propagates local code into the cluster deployment.

  1. Edit the local file public/assets/stations.geojson to add a new bus stop. Append it to the bottom of the file, right after Ronald Reagan Washington National Airport:
    > vim public/assets/stations.geojson
       {
          "type": "Feature",
          "properties": {
            "name": "Presidential Metro Stop",
            "marker-color": "#ffd700",
            "marker-symbol": "rail-metro",
            "line": "blue"
          },
          "geometry": {
            "type": "Point",
            "coordinates": [
              -77.0365,
              38.8977
            ]
          }
        }
    
  2. Push changes to the cluster:
    > odo push

    You should see the following output:

    Validation
     ✓  Checking component [86ms]
    
    Configuration changes
     ✓  Retrieving component data [96ms]
     ✓  Applying configuration [114ms]
    
    Applying URL changes
     ✓  URL nodejs-dc-metro-map-zvff-8080 already exists
    
    Pushing to component nodejs-dc-metro-map-zvff of type local
     ✓  Checking file changes for pushing [3ms]
     ✓  Waiting for component to start [23ms]
     ✓  Syncing files to the component [1s]
     ✓  Building component [3s]
     ✓  Changes successfully pushed to component
    

Now, refresh the web page. You should see that there's a new transit stop for the White House, as shown in Figure 4.

An updated map with a new bus icon located at the White House.
Figure 4. The updated map shows that code changes have been successfully pushed to the deployed cluster.

Conclusion

In this article, I showed you how to use odo for a variety of day-to-day development activities (what I call the inner loop of a Kubernetes-based development process). I also showed you how to deploy and debug iterations of your inner loop directly into the Kubernetes cluster.

We completed all of the tasks required to develop and deploy the example application without writing any YAML, without bash scripts, and without needing to understand the deep concepts of Kubernetes operations. Instead, we used the CLI and just a handful of commands—odo, project, create, push, service, url, link, config.

Odo can do a few things I didn't cover in this article. See the official odo documentation to learn more about its full capabilities.

Also, if you liked the concepts in this article but really don't like using a CLI, Red Hat has you covered. We've embedded odo into a VS Code plugin and a JetBrains plugin, so that you can get the same capability directly in an IDE.

Odo is just one of the awesome tools that Red Hat has been working on to make it easier for developers to build modern applications with open source software. Stay tuned for more articles introducing these tools that are tailored just for developers.

Last updated: March 30, 2023