My Adventure getting started with rkt
Tags: containers, rkt
Published: 2019-03-20 17:20:07

---
title: My Adventure getting started with rkt
published: true
description: building and running containers without docker
tags: containers, rkt
---

I built an application that I'd like to containerize. Docker seems to be the most popular option for containerization, so I learned how to build docker images from [their website](https://docs.docker.com/get-started/). The only problem is that Docker's community edition won't run on RHEL, and I don't think I can convince our IT department to throw money at Docker enterprise for my one-off project that works just fine without it. (I should also point out that we're not a software or IT consulting company. There aren't many people here who would find the value in Docker enterprise, outside of this one project.) Maybe I can find a free-as-in-beer, open-source alternative.

In my search for a [Docker alternative](https://alternativeto.net/software/docker/), I found [RKT](https://github.com/rkt/rkt/) (pronounced "rocket"), which led me to the [App Container (appc) specification](https://github.com/appc/spec/) which defines the [Application Container Image (ACI) format](https://github.com/appc/spec/blob/master/spec/aci.md#app-container-image). Evidently, the appc spec is no longer being developed as a standalone protocol, as it has been rolled into the [Open Container Initiative (OCI)](https://www.opencontainers.org/). Here's the disclaimer in appc's github page:

> With the formation of the [Open Container Initiative (OCI)](https://www.opencontainers.org/), the industry has come together in a single location to define specifications around applications containers.
OCI is intended to incorporate the best elements of existing container efforts like appc, and several of the appc maintainers are participating in OCI projects as maintainers and on the Technical Oversight Board (TOB).
Accordingly, as of late 2016, appc is no longer being actively developed, other than minor tweaks to support existing implementations.
> 
> It is highly encouraged that parties interested in container specifications join the OCI community.
>
> * The App Container Image format (ACI) maps more or less directly to the [OCI Image Format Specification](https://github.com/opencontainers/image-spec), with the exception of signing and dependencies.
> * The App Container Executor (ACE) specification is related conceptually to the [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec), with the notable distinctions that the latter does not support pods and generally operates at a lower level of specification.
> * App Container Image Discovery does not yet have an equivalent specification in the OCI project (although it has been [discussed](https://groups.google.com/a/opencontainers.org/forum/#!msg/dev/OqnUp4jOacs/ziEwxasyFQAJ) and [proposed](https://groups.google.com/a/opencontainers.org/forum/#!msg/tob/oaEza4cu25M/gBLeHm5NFAAJ))
>
> For more information, see the [OCI FAQ](https://www.opencontainers.org/) and a more recent [CoreOS blog post announcing the OCI Image Format](https://coreos.com/blog/oci-image-specification.html).

In other words, the tools I use below are **obsolete**. I'm chronicling my adventure here, but don't you shouldn't read this as a recommendation or a best practice. After I had completed the "get started" exercise below, I realized that the OCI maintains several official tools like [`runc`](https://github.com/opencontainers/runc) and [`oci-image-tool`](https://github.com/opencontainers/image-tools) that are probably better for this task. I'll study those tools on another day.

Let's jump in.

# Getting Started with rkt

Lets's start with [rkt's getting started guide](https://github.com/rkt/rkt/blob/master/Documentation/getting-started-guide.md). At first glance the guide looks pretty straightforward: create a go application and build an ACI for it. However, I can't do this directly on my development machine (I'm running MacOS, and the guide claims that this can only be done on Linux). Instead, I first need to start up a linux VM using Vagrant.

The guide glosses over some prerequisite knowledge, like go and Vagrant. When I was going through it myself for the first time, I hit a few stumbling blocks because I've never used either of these tools before. I'll go through the guide step-by-step, with added context and commentary where appropriate.

## Setup a virtual linux host with Vagrant

After installing [Vagrant](https://www.vagrantup.com), we can follow the instructions for starting up the rkt VM, from [here](https://github.com/rkt/rkt/blob/master/Documentation/trying-out-rkt.md). Here are the instructions in a nutshell:

```sh
git clone https://github.com/rkt/rkt
cd rkt
vagrant up # this step takes a while
vagrant ssh
```

That last call to `vagrant ssh` is what logs you into the VM. 

The rkt `Vagrantfile` sets up an Ubuntu VM with rkt preinstalled, but it doesn't come with the go compiler, or `acbuild`. Since installing Go and acbuild isn't within the scope of this post, I'll save you the headache of doing it yourself. If you paste the following commands into the shell of your Vagrant VM, you'll be up and running.

```sh
# Install the golang compiler
GO_VERSION=1.12.1
GO_OS=linux
GO_ARCH=amd64
GO_TARBALL=go$GO_VERSION.$GO_OS-$GO_ARCH.tar.gz
wget https://dl.google.com/go/$GO_TARBALL
sudo tar -C /usr/local -xzf $GO_TARBALL
rm $GO_TARBALL
export PATH=$PATH:/usr/local/go/bin

# Install acbuild
ACBUILD_VERSION=0.4.0
ACBUILD_TARBALL=acbuild-v$ACBUILD_VERSION.tar.gz
wget https://github.com/containers/build/releases/download/v$ACBUILD_VERSION/$ACBUILD_TARBALL
sudo tar -C /usr/local -xzf $ACBUILD_TARBALL
rm $ACBUILD_TARBALL
export PATH=$PATH:/usr/local/acbuild-v$ACBUILD_VERSION
```

Now that the prerequisites are handled, we should be able to move on with the Getting Started tutorial.

## Compiling the sample Go application

You should still be inside your Vagrant VM. Create an empty folder name `hello` (the name of the folder is important because it will become the name of the compiled executable), and create a file named `hello.go` inside it with the following contents.

```go
package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		log.Printf("request from %v\n", r.RemoteAddr)
		w.Write([]byte("hello\n"))
	})
	log.Fatal(http.ListenAndServe(":5000", nil))
}
```

From here, you should be able to compile a statically linked binary using this command:

> **Note**: It's not clear to me why it's important for the binary to be statically linked instead of dynamically linked, but the guide seems to stress that the binary be statically linked.

```sh
CGO_ENABLED=0 go build -ldflags '-extldflags "-static"'
```

If you want to test out the go application, you can run it with `./hello`. It will listen for incoming HTTP requests on port `5000` and respond with `hello`. Run `ip address` on the VM to see what IP address it's bound to.

## Create the image with actool

The next step is to create the image using `acbuild`. According to the docs, `acbuild` is no longer maintained, and 

> **Note**: The first time I got to this point, `acbuild` kept telling me that it wanted to be run as root, but when I started over to write this post, it happily worked without it. I'm not sure what I did wrong the first time around, but you *should* be able to run these commands as the default `vagrant` user in your VM

```sh
acbuild begin
acbuild set-name example.com/hello
acbuild copy hello /bin/hello
acbuild set-exec /bin/hello
acbuild port add www tcp 5000
acbuild label add version 0.0.1
acbuild label add arch amd64
acbuild label add os linux
acbuild annotation add authors "Carly Container <carly@example.com>"
acbuild write hello-0.0.1-linux-amd64.aci
acbuild end
```

## Run the image with rkt

```sh
rkt --insecure-options=image run hello-0.0.1-linux-amd64.aci
```

Once the container is running, you have to type `^]` thee times in order to kill the container.

This command will create a new container from your new image, but you won't be able to access it easily from your host environment because it's running in a *contained* network. If you want the ports inside the container to be exposed to the machine running it (in this case, our VM), we have to specify the `--net=host` option.

```sh
rkt --insecure-options=image run --net=host hello-0.0.1-linux-amd64.aci
```

# Running!

![web browser showing the output of a rkt container inside a VM](https://thepracticaldev.s3.amazonaws.com/i/xn41qrp43d4l704ftj8p.png)

And with that, I have a container running custom code! This was a fun, educational experience for me. I hope you learned something too!