What’s new with Microsoft in open-source and Kubernetes at KubeCon North America 2024
At Microsoft, we are committed to innovation in the cloud-native ecosystem through…
The team that brought you Helm and Draft is announcing its newest open source Kubernetes-native tool, designed to help dev and ops get their work done quickly. It’s called Brigade and with it you can build any ordered workflow of containers in Kubernetes and trigger the workflow by listening for arbitrary events.
Kubernetes is a great platform for not only managing long-running services, but also running short-term tasks commonly used for things like event-driven programming, big data, code quality testing, and batch processing. Often, tools for these areas are either too complex for a simple situation or some combination of xml, yaml, or json seems like a barrier.
This is where Brigade comes in. Brigade is a framework for scripting together multiple tasks and executing them inside of containers. Following patterns popular in other forms of “serverless” computing, a Brigade pipeline is triggered by an event. When an event occurs, the appropriate event handler is given the opportunity to respond. Brigade responses, however, are not limited to functions, simple or complex. Instead, Brigade provides a structured pipeline that you can use to define a sequence of jobs, and Brigade will run them to completion as you specified.
At a glance, Brigade:
Brigade is a tool that you can use to easily automate almost anything you can think of, quickly, easily, in JavaScript using your local minikube or any Kubernetes cluster to which your kube/context points. It’s a form of “structured serverless” that you own, completely.
A whole bunch of things, is the answer. So what do you need in your world? Brigade will likely fit the bill in many cases; it is designed to be flexible and open ended. Our team has used Brigade to interact with Slack, listen for events on Trello, save data in Azure CosmosDB, execute unit and functional tests, and even run machine learning on images using Azure Container Instances (oooooh, per-second billed containers!). Since core logic is encapsulated in containers, we’ve experienced a high degree of flexibility as we create a new generation of serverless apps.
Brigade is built as a service in Kubernetes. When Brigade receives a JavaScript file, it interprets the script and creates the appropriate underlying Kubernetes resources. Jobs become pods, and the relevant containers are fetched from their sources (DockerHub, an Azure Container Registry, or other container registries).
Brigade manages the execution of these pods, controlling the flow of data between them, and monitoring for errors. All of this can be done without requiring the original script author to even have access to the Kubernetes cluster. Let’s look at this more closely.
Brigade scripts follow a simple formula: it listens for a trigger (like a webhook or a message on queue) and emits an event. Scripts that are registered to handle that event will then be executed – conforming to any ordering specifications – inside of a Kubernetes cluster.
Brigade uses JavaScript. JavaScript is the most popular scripting language for a reason: It’s well-documented, flexible, ubiquitous, and easy to learn. Here’s a simple Brigade script that is triggered by an “exec” event, which is raised when you use the Brigage CLI client (from either in or outside the cluster):
const { events } = require("brigadier") events.on("exec", () => { console.log("Hello world") })
The single-function script above says, “When something calls using the Brigade CLI, log ‘Hello world’”. Brigade will watch its event queue for any “exec” events, and execute the function whenever such an event occurs. Brigade ships with several other predefined events, including events for handling GitHub and DockerHub webhooks, and it’s easy to add custom events with just a little bit of coding.
Most of the time, we want to write scripts that do something more powerful than logging a string. Rather than baking in lots of libraries, though, Brigade takes a different approach. Inspired by shell scripts, Brigade chains containers into scripts for Kubernetes.
A friend of mine, Beau, once pointed out to me that shell scripting is what transformed the operating system from a specialized foundation layer into a general purpose computing platform. Instead of having to write a special piece of software for each and every task you want to perform, shell scripting enables you to chain together existing tools to create custom programs large and small.
For example, I have a plain text file with some fruits and prices like “Pear $1.99” and so on. Now say I want to generate an alphabetical list of fruits, with no prices. I could write a script with this line to strip out prices and print and ordered list of fruit names:
cat fruits.txt | awk '{ print $1 }' | sort
Power and flexibility: three programs in just one line. Had we done this in a pure programming language like C# or Java, we would have had to write dozens, possibly even hundreds, of lines of code. Instead, the script simply re-uses other programs.
Brigade brings a similar notion of scripting and pipelining to Kubernetes. Instead of running individual programs, though, Brigade treats containers as the fundamental constituent parts.
Inside of a Brigade event handler, we create one or more Jobs. In Brigade, a Job is a step in the process. A script can run any number of jobs and jobs can run in parallel (the default), or execute in a defined sequence. The output of one job can be captured, modified, and passed into another job. And since JavaScript is a full-fledged scripting language, you can build flow control rules that meet your own needs.
Let’s look at a simple Brigade script that loads a basic Linux container and executes a command in that container:
const { events, Job } = require("brigadier") events.on("exec", () => { var job = new Job("echo", "alpine:3.5", ["echo 'hello'"]) job.run() })
In the example above, we create a new job. Our job starts with the off-the-shelf Alpine Linux 3.5 Docker container (https://hub.docker.com/_/alpine/) and runs a simple echo command inside of the container.
Here’s an example that still uses simple containers, but adds some workflow.
const { events, Job, Group } = require("brigadier") events.on("exec", () => { var hello = new Job("hello", "alpine:3.4", ["echo hello"]) var goodbye = new Job("goodbye", "alpine:3.4", ["echo goodbye"]) var helloAgain = new Job("hello-again", "alpine:3.4", ["echo hello again"]) Group.runAll([hello, goodbye]).then( ()=> { helloAgain.run() }) })
This new script declares three jobs instead of just one: hello, goodbye, and helloAgain. When it comes to running these jobs, the script above creates a pipeline that executes like this: Run hello and goodbye in parallel, wait until both are done, and then run helloAgain. Brigade is designed to make it easy to build such pipelines.
Kubernetes is already a great platform for running persistent services. Brigade brings new power to the Kubernetes platform, making it easy to build applications by chaining together containers. In this post, we’ve seen a few simple examples of Brigade. To learn more, head over to http://brigade.sh and install Brigade into your Kubernetes cluster and see what you can do with it.
Feedback or questions? Let us know in the comments.