Kubernetes with OpenTofu: A Guide to Being Fully Open Source

Jubril Oyetunji
Jubril Oyetunji

Table of Contents

On the 10th of August 2023, Hashicorp announced they where adopting the BSL license, which would affect all future releases of Hashicorp products , API’s and SDK’s. This was huge because Hashicorp has largely released its products under the Mozilla Public License v2.0 (MPL 2.0) since it’s founding in 2012.  This set the Terraform community ablaze and within weeks a manifesto and fork named OpenTF was launched made. OpenTF would eventually be donated to the Linux Foundation and be renamed to OpenTofu.

In this article, we will explore OpenTofu, why you should care, and discuss how you can orchestrate your Kubernetes deployments with it.

OpenTofu vs Terraform

The decision by HashiCorp to switch Terraform to the Business Source License (BSL) in 2023 sent shockwaves through the infrastructure automation community. The BSL, a more restrictive license than the Mozilla Public License (MPL) 2.0 under which Terraform had previously been released, raised concerns about the future of Terraform's openness and community-driven development.

While OpenTofu is a fork of Terraform and shares much of its codebase, there are some key differences between the two tools.

Licensing: OpenTofu is released under the MPL 2.0 license, while Terraform is released under the BSL. This means that OpenTofu is more openly developed, and anyone can contribute to the project without fear of their contributions being locked down by a company.

Community: OpenTofu has a strong and growing community of developers and users. This community is actively developing the tool and contributing to its documentation and support. You can check out its public roadmap.

Future Development: OpenTofu is committed to maintaining compatibility with Terraform and ensuring that it remains a powerful and versatile tool for infrastructure automation. However, OpenTofu is also free to explore new features and innovations that may not be possible under the BSL.

Viable Alternative: OpenTofu is a viable alternative to Terraform. It is a drop-in replacement for Terraform versions prior to 1.5.x, meaning that existing Terraform configurations can be used with OpenTofu without any modifications.

Why should you orchestrate Kubernetes with OpenTofu?

OpenTofu's ability to leverage Kubernetes' API-driven nature and its declarative OpenTofu language provides a compelling solution for orchestrating Kubernetes deployments. It simplifies infrastructure management, enhances consistency while improving collaboration, and enabling automation.

OpenTofu's declarative language, provides a consistent and expressive way to define infrastructure configurations, regardless of the underlying provider.

This declarative approach offers several advantages for Kubernetes orchestration:

Reduced Complexity: Declarative configurations simplify infrastructure management by explicitly stating the desired state of the infrastructure. OpenTofu automatically handles the underlying complexities, ensuring that the infrastructure converges to the desired state.

Increased Consistency: OpenTofu's consistent HCL syntax eliminates the need to learn multiple configuration languages for different providers. This consistency reduces the risk of errors and simplifies infrastructure management across diverse environments.

Improved Collaboration: Declarative configurations enhance collaboration by providing a clear and concise representation of the desired infrastructure state. This transparency facilitates collaboration among developers, DevOps engineers, and infrastructure teams.

Enhanced Automation: OpenTofu's declarative nature enables powerful automation capabilities. By defining the desired state of the infrastructure, OpenTofu can automatically apply changes, ensuring that the infrastructure remains in the desired state even as requirements evolve.

Demo: Orchestrating Kubernetes with OpenTofu

Armed with an understanding of OpenTofu,  why it exists, and why you should care lets’ dive into a demo.

Prerequisites
To follow along in this article, you would need the following:

  1. A working Kubernetes cluster: This cluster will serve as the foundation for deploying and managing containerized applications using OpenTofu. Minikube, and Kind are great for local development.
  2. Basic familiarity with Kubernetes and Terraform: A rudimentary understanding of Kubernetes concepts and Terraform syntax will be beneficial for comprehending the demo's steps.

Installing OpenTofu
You can install OpenTofu on a wide range of operating systems.  For installation instructions on your choice operating systems, refer to this section of the installation documentation.

To verify your installation, execute the following tofu command:

tofu —version 

Creating OpenTofu Files
According to the docs

The main purpose of the OpenTofu language is declaring resources, which represent infrastructure objects. All other language features exist only to make the definition of resources more flexible and convenient.

OpenTofu language is almost indistinguishable from HCL, this essentially guarantees that your existing Terraform files would work.

Within a directory of your choice,  create a file called main.tf,  open it up in an editor of your choice, and follow along with the code below

terraform {
  required_providers {
    kubernetes = {
      source = "hashicorp/kubernetes"
      version = "2.23.0"
    }
  }
}

provider "kubernetes" {
 config_path = "~/.kube/config"
}

In the code above we declare two blocks one for the required providers and another to configure the Kubernetes provider, within the Kubernetes provider block we point OpenTofu to the default location of your kubeconfig using the config_path field.

As of the time of writing this code would pull in the providers from the Terraform registry,  however there are efforts on going to make a dedicated registry for OpenTofu providers.

Initializing your OpenTofu  Directory
With an OpenTofu file created,  the next step is to initialize the directory.  Initializing effectively instructs OpenTofu to download the required providers and create a dependency and state file.

To do this run the following command:

tofu init 

Once this completes you should see something like this:

Creating a Namespace

Namespaces provide a mechanism for organizing Kubernetes resources within a cluster. They allow you to logically group resources, such as pods, deployments, and services, into separate units, making it easier to manage and isolate resources from each other.

To create a namespace, open up main.tf in your editor of choice and follow along with the code below:

...
resource "kubernetes_namespace" "tofu-tests" {
  metadata {
    name = "tofu-experiements"
  }
}

With the kubernetes_namespace resource added, we can get a preview of the resource OpenTofu would create with the plan sub-command.  To do this,  run the following command:

tofu plan 

in a couple of seconds you should see the following:

If this looks good you can apply the configuration using:

tofu apply 

OpenTofu would prompt you one more time to confirm the action, enter yes and in couple of minutes you should see the following output:

Creating a Deployment
With a namespace created, we can begin deploying resources using Kubernetes deployments.   Deployments are t responsible for creating and managing pods, the basic units of computation in Kubernetes.

To create a deployment using OpenTofu, you'll need to define a resource declaration within main.tf  the following code snippet deploys a simple Nginx web server to the tofu-experiments namespace:

resource "kubernetes_deployment" "nginx" {
  metadata {
    name = "nginx"
    namespace = kubernetes_namespace.tofu-tests.metadata.0.name
  }
  spec {
    replicas = 3
    selector {
      match_labels = {
        app = "nginx"
      }
    }
    template {
      metadata {
        labels = {
          app = "nginx"
        }
      }
      spec {
        container {
          name  = "nginx"
          image = "nginx:latest"
          port {
            container_port = 80
          }
        }
      }
    }
  }
}

The code snippet defines a Kubernetes deployment resource named nginxthat creates and manages three Nginx pods in the tofu-experimentsnamespace. The deployment ensures that the desired number of replicas (pods) are running at all times.

The metadata block specifies the name of the deployment (nginx) and the namespace where it should be created (tofu-experiments). The spec block defines the desired state of the deployment, including the number of replicas (replicas = 3) and the container configuration.

The selectorblock identifies the pods that belong to the deployment using a label selector (app = "nginx"). The templateblock defines the container configuration, including the container image (nginx:latest) and the container port (container_port = 80).

Once you have defined the deployment configuration. apply it to your Kubernetes cluster using the tofu apply command:

tofu apply

This command will create the deployment resource in your Kubernetes cluster and spin up three Nginx pods. To verify that the deployment was successful and the pods are running, use the kubectl get pods command:

kubectl get pods -n tofu-experiments

The output should include three pods named nginx-deployment-xxxxxx, indicating that the deployment was successful and the pods are running in the tofu-experiments namespace.

Exposing the Deployment with a Port Forward

Instead of using a Kubernetes service, you can also expose the deployment to the outside world using a port forward. This method provides direct access to the Nginx pods without a load balancer.

Note: Port forwarding exposes the deployment directly to the outside world, which may not be suitable for production environments. It's recommended to use a Kubernetes service for production deployments.
To expose the deployment using a port forward, follow these steps:

  1. Identify the port where the Nginx pods are listening. This information can be obtained using the following command:
kubectl get pods -n tofu-experiments -o jsonpath='{.items[*].metadata.labels.app}

The output will list the pods associated with the deployment. For each pod, identify its port using the containerPort property in the pod's spec:

kubectl get pod nginx-deployment-xxxxxx -n tofu-experiments -o jsonpath='{.spec.containers[0].ports[*].containerPort}'

Once you've identified the port, open a terminal window and execute the following command:
Bash

kubectl port-forward pod/nginx-deployment-xxxxxx -n experiments 8080:80

This command will forward traffic from port 8080 on your local machine to port 80 on the nginx-deployment-xxxxxx pod.

You can now access the Nginx web server using the following URL in your web browser:

http://localhost:8080

To stop port forwarding, press Ctrl+C in the terminal window where the port forward command is running.

Conclusion

In this article, we delved into the world of OpenTofu, a promising alternative to Terraform for infrastructure automation. We explored OpenTofu's advantages, including its declarative language, consistent HCL syntax, and strong community support. We also demonstrated how to orchestrate Kubernetes deployments using OpenTofu, guiding readers through the process of creating a namespace, deploying an Nginx application, and exposing the deployment for external access.

OpenTofu emerges as a compelling choice for infrastructure automation, particularly for those familiar with Terraform. Its intuitive syntax compatibility with Terraform and growing community make it a viable alternative for managing Kubernetes infrastructure. As OpenTofu continues to evolve, it holds the potential to revolutionize the way we manage and orchestrate infrastructure in the cloud.

KubernetesOpenTofu

Jubril Oyetunji Twitter

Jubril is a software engineer, primarily focused on building infrastructure using cloud native technologies. When he’s not coding or ranting, he’s sharing his learnings through technical writing.