Introducing Acorn

by | Aug 3, 2022

Today I’d like to announce Acorn, an application packaging and deployment framework for Kubernetes. Acorn aims to complete the original vision of containers enabled by Docker and Kubernetes. When I jumped on the Docker bandwagon nine years ago my favorite thing was the idea that I could build a container and then seamlessly push it to production. Turns out, it’s way harder than that. To get a container from dev to production requires an elaborate process where multiple teams collaborate on an artisanally crafted rube goldberg machine utilizing scripting, YAML, templating, auditing, scanning, and git. One might say managing Kubernetes deployments is as much art as it is science.

Acorn is here to bring some of the fun and simplicity of Docker back to application deployments. First Acorn introduces a proper application oriented package. Something simple enough for developers to understand and powerful enough to package the most complex stateless and stateful applications. Second, Acorn includes a runtime to ensure that you can run applications with confidence, security, sanity, and a reasonable set of operational best practices. And finally, we make this possible without requiring deep Kubernetes knowledge because the best way to use Kubernetes is to never worry about Kubernetes.

The Origin of Acorn

As we all know, one of the most important use cases, if not the most important use case of containers is to run Minecraft servers. During the Covid-lockdown my son asked me to host a server for him and his friends. As the creator of k3s, I spun up a k3s cluster in a couple seconds. Easy. I wanted to run Minecraft at home with a reverse tunnel through a ngrok TCP endpoint so that his friends could join. Also I would need to persist the Minecraft state. I went to craft my Kubernetes deployment and immediately started hating my life. I gave up, switched to docker-compose, and started writing Acorn.

The Problem

Much of the problem of application deployments on Kubernetes spawns from two things. First, Kubernetes can do absolutely anything (trust me, I know all the tricks). And second, the core concepts in Kubernetes are raw and essentially infrastructure oriented.

The raw power of a Kubernetes is great. The same system that runs your application is also powerful enough to deploy and manage complicated low level things like storage systems, SDN, service mesh, GPU device drives, and even kernel modules (yikes!). In order to do all of these things Kubernetes has a series of raw flexible primitives. But these raw flexible primitives are very verbose and very technical.  If you are one of the majority of Kubernetes users only interested in deploying applications on Kubernetes, you should not have to worry about these raw primitives. For example, if your use case is to run a container exposing a port with a configured password you should not need to understand Deployments, Replicaset, Pods, selectors, volume mounts, secrets, services, service types like ClusterIP, NodePort, LoadBalancer, and more. You should not have to write infrastructure assembly language.

If we narrow our domain to application deployment we can make Kubernetes much easier to use. There have been many attempts to abstract away the complexity of Kubernetes. Acorn is our attempt at Kubernetes abstraction while offering everything needed to run applications in production.

The Solution

Acorn solves these problems by first introducing a proper application package. This package in its binary form is an OCI image that can be pushed to any OCI (Docker) registry. The OCI image includes all the referenced Docker images plus the application definition metadata needed to run the application. This single artifact is signable and nicely compatible with tools like cosign.

An Acorn image is different from a Docker image as it contains multiple Docker images plus application metadata.  An Acorn image is different from a Helm chart in that an Acorn image can only define resources needed for an application and does not have the ability to do insecure or dangerous things like create privileged containers or gain access to the cluster. Also the Acorn image is fundamentally abstracted away from Kubernetes.  While not currently in scope, an Acorn image could eventually run on something like ECS or Nomad because the image is abstracted to just the application concepts. And finally it’s different because it’s simple and fun to build.

In order to build an Acorn image we introduce a new build file called the Acornfile.  We took a lot of inspiration from Docker and Docker Compose in designing the user experience of Acorn. The Acornfile has a new language that should be simple enough for people to learn if you have experience with JSON, YAML, or HCL.  Technically the Acornfile syntax is a derivative of CUE, but CUE knowledge is not required as the portions of the language we use are very easy to learn.

The Acornfile describes the application but not the infrastructure. At deploy time specific infrastructure needs like storage, networking, other resources, and environment specific information can be configured without needing to change the original acorn image.

Below is a simple “Hello World!” style Acornfile but to see all it can do check out Getting Started and my introduction video.

containers: {
 web: {
  image: "nginx"
  ports: publish: "80/http"
  files: {
   // Simple index.html file
   "/usr/share/nginx/html/index.html": "<h1>My First Acorn!</h1>"
  }
 }
}

Conclusion

Today is just the start of a journey towards a future where we can stop focusing on infrastructure and spend more time working  on applications. With Acorn application deployments should be faster,easier, and hopefully more enjoyable; and it should be possible to significantly simplify Kubernetes cluster operations by standardizing workloads.  We have many things in store for Acorn like automatic service mesh integration and enforcement, application autoscaling, simple automatic Acorn continuous delivery and more.

Join us August 10th for our very first online meetup.

And finally, after about six months of hacking on Acorn this is the Acornfile running my son’s Minecraft server.

// You must populate the ngrok token with your actual ngrok auth token
// acorn secret create --type=token --data token="$TOKEN" my-token
// acorn run -s my-token:ngrok-token . --ngrok-address 1.tcp.ngrok.io:11111

args: {
    // The TCP address you pre allocated
    ngrokAddress: ""
}

containers: minecraft: {
    env: {
        EULA: "TRUE"
        MODE: "creative"
        DIFFICULTY: "peaceful"
        OPS: "FireArtist53095"
        ALLOW_NETHER: "true"
        ENABLE_COMMAND_BLOCK: "true"
        GENERATE_STRUCTURES: "true"
        SPAWN_ANIMALS: "true"
        SPAWN_MONSTERS: "true"
        SPAWN_NPCS: "true"
        ALLOW_FLIGHT: "TRUE"
        VERSION: "1.19"
    }
    image: "itzg/minecraft-server"
    ports: 25565
    dirs: {
        "/data": "data"
    }
    probe: "mc-health"
}

containers: ngrok: {
    image: "ngrok/ngrok:alpine"
    env: {
        NGROK_AUTHTOKEN: "secret://ngrok-token/token"
    }
    command: "tcp --remote-addr=(args.ngrokAddress) minecraft:25565"
}

secrets: {
    "ngrok-token": {
        type: "token"
    }
}