Skip to content

Reimplementing the AWS EKS API with Clojure using BigConfig, Rama, and Pedestal

K8s

The world of cloud infrastructure often involves interacting with complex APIs. While services like AWS EKS provide robust management for Kubernetes clusters, there might be scenarios where you need a more tailored or localized control plane. This article will guide you through reimplementing the AWS EKS API using a powerful Clojure stack: Pedestal for the API, BigConfig to wrap Terraform and Ansible in a workflow, and Rama for state and jobs.

Before we dive into the how, let’s consider the why. K8s, Spark, ClickHouse, Postgres, and so on are all good candidates for an in-house software as a service solution. Reimplementing a cloud API might seem counterintuitive, but it can be beneficial for:

  • Avoiding vendor lock-in: This can be relevant for some companies.
  • Multi-cloud strategy: You need an EKS-like solution in multiple cloud providers and you need a generic API.
  • Saas: You have an open source software and the Saas is your source of revenue.
  • Metal: You cannot use the cloud but you want to provide the same developer experience in your company.
  • Integration costs: Buying EKS and integrating it with the rest of your infrastructure is not feasible or very expensive. Building an EKS-like solution is cheaper.

Disclaimer: This is a simplified blueprint for educational and experimental purposes. It will not cover the full breadth and complexity of the actual AWS EKS API.

Here’s a quick overview of the tools we’ll be using:

  • BigConfig: A workflow and a template engine that enables us to have a zero-cost build step before running any devops tool like Terraform or Ansible.
  • Rama: A distributed stream processing and analytics engine that can also function as a durable, highly concurrent data store. We’ll use Rama to manage our cluster definitions and state.
  • Pedestal: A comprehensive web framework for Clojure that emphasizes data-driven development and offers excellent support for both synchronous and asynchronous request handling. It will serve as our API gateway.

Let’s imagine the core entities we want to manage: EKS Clusters. For simplicity, we’ll focus on creating and describing clusters.

  • Reuse GitOps: Building a single K8s cluster with GitOps should be reuseable. Replacing GitOps with an API should not require to reimplement everything from scratch. The solution should contain a more generalized version of the GitOps one for one cluster.
  • Declerative when possible: Terraform should be used to create resources instead of the AWS APIs whenever it is possible.
Diagram
  • Pedestal API: to create and describe clusters.
  • Rama Module: to store the desired state, and invoke the BigConfig module with the desired state.
  • BigConfig Module: this is where the heavy lifting is happening:
    • Workflow: achieving the desired state will require multiple steps.
    • Lock: to be sure that changes are ACID.
    • Build: to generate the configuration files for Terraform based on the desired state.
    • Apply: to run terraform apply programmatically.
  • Modularity: Every deliverable can be developed in parallel by adopting contracts.
  • Uniformity: BigConfig, Rama, and Pedestal deliverables are all written in Clojure.
  • Declerative: Creating an EC2 instance programmatically can be done faster with Terraform and we don’t need to worry about the life cycle management.
  • Reusability: The GitOps code can be reused. The code to provision one K8s cluster with GitOps or multiple K8s clusters with an API, doesn’t require to change from Terraform to the AWS SDK. The API is just a virtual admin. The GitOps version developed interactivly by an admin can be package as a Clojure dependency and reused inside Rama. This is a killer feature of BigConfig.

I’m working on the code right now. Stay tuned, I will update the blog post as soon as I have the first version.

This is a basic example, but you can extend it significantly:

  • More EKS Features: Implement more aspects of the EKS API, such as node groups, Fargate profiles, or update operations.
  • Authentication and Authorization: Integrate with a robust authentication system to secure your API.
  • Error Handling: Implement more sophisticated error handling and meaningful error messages by adopting OpenTelemetry.

By combining BigConfig, Rama, and Pedestal, we’ve built a foundation for a in-house EKS-like API in Clojure. This approach provides a high degree of control, flexibility, and the ability to tailor your infrastructure management precisely to your needs. This project serves as an excellent starting point for exploring the potential of building custom cloud-native services with Clojure.

Would you like to have a follow-up on this topic? What are your thoughts? I’d love to hear your experiences.