This post is going to describe how to build applications using the BusyBox docker image, along with a sample web server that we will run using BusyBox as the base.

banner

You can see the sample code for this post on Github

What Is BusyBox?

From it’s own webpage:

BusyBox combines tiny versions of many common UNIX utilities into a single small executable.

The BusyBox Docker container gives us an image many times smaller than, for example, the Ubuntu image:

➜  ~ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
busybox      latest    34378e11e069   7 days ago    1.4MB
ubuntu       latest    58810d071ecb   4 weeks ago   65.6MB

This lets us create our own images with a much smaller footprint if we use BusyBox as the base.

This is especially useful when you want to optimize overall resources on your system, or if you’re using a system with limited disk space.

Creating a BusyBox Container

To run an interactive shell on a BusyBox container, we can execute this command:

docker run -it --rm busybox

We can then run common commands on the shell. For example, let’s list all the commands that are available to us:

/ #
/ # ls /bin
[                  ifdown             rm
[[                 ifenslave          rmdir
acpid              ifplugd            rmmod
add-shell          ifup               route
 ...
 ...

Running Custom Executable Files

Since BusyBox gives us a basic Linux environment, we can compile programs to run on Linux and create custom executables using BusyBox as the base.

For example, let’s create a simple “hello world” program using Go (Golang).

First, we can create a directory on our machine. Within the directory, we’ll create a Dockerfile and main.go file:

.
├── Dockerfile
└── main.go

Our main.go file contains a simple program to print “hello world” to the console:

package main

import "fmt"

func main() {
	fmt.Println("hello world")
}

If you’ve installed Go, you can compile the above program:

GOOS=linux GOARCH=amd64 go build main.go

This should output a file called main.

GOOS and GOARCH specify the target system that we want to compile for. In this case, BusyBox runs Linux OS with the “amd64” architecture.

Because we’re compiling for BusyBox, the compiled file may not work on your own machine. To run this on your own machine, you can execute go build main.go without the GOOS and GOARCH variables

Creating Our Docker Image

We can add commands to our Dockerfile to run the compiled program:

# Use busybox as the base image
FROM busybox
# Copy over the executable file
COPY ./main /home/
# Run the executable file
CMD /home/main

We can create the image by running:

docker build -t hello-world .

This will create the new hello-world image, which we can now run by executing:

docker run --rm  hello-world

Once the container has been run, you can see the output on your terminal:

hello world

What’s more, the total size of the hello-world image is only around 3.3MB:

REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
hello-world   latest    3b0d3ab8c11f   3 minutes ago    3.34MB

Running an HTTP Web Server

Let’s add a new file called server.go in the same directory. Here, we’ll create a simple HTTP server that runs on port 8080 responds to every request with the text "Hello World!":

package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello World!")
}

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("Server running...")
	http.ListenAndServe(":8080", nil)
}

Compile the program:

GOOS=linux GOARCH=amd64 go build server.go

Now, the executable file name will be server. We can modify the Dockerfile to use this instead:

FROM busybox
COPY ./server /home/
CMD /home/server

Build the Dockerfile with a new image tag:

docker build -t go-server .

Create and run new container from your image by running :

docker run -p 8080:8080 --rm -it go-server

The -p 8080:8080 forwards the 8080 port from the container to your local machine

You can send a curl request to http://localhost:8080/, or even visit it on your browser:

curl -v http://localhost:8080/
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sat, 28 Aug 2021 09:31:38 GMT
< Content-Length: 12
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
Hello World!

The total size of the Docker image is around 7MB:

REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
go-server     latest    e5b1fb0caa64   52 seconds ago   7.53MB

We have now successfully created and run an HTTP web application in Docker using BusyBox.

You can see the sample code for this post on Github

Have you ever used BusyBox to run your application? How was your experience? Let me know in the comments!