Moby is the open-source project behind Docker containers. Here's what Go developers should know about it.

Did you know Docker is actually built on Moby?


Most developers use Docker daily. Few know that Docker itself is built on an open-source Go project called Moby. Moby is a toolkit for building container systems that Docker uses as its foundation.

Let me explain what Moby is and why it matters for Go developers.

What is Moby?

Moby is a collaborative project that provides the components needed to build container-based systems. Docker Inc. created it in 2017 to separate the open-source container technology from the Docker product.

Docker is to Moby what Chrome is to Chromium. Moby provides the building blocks. Docker assembles them into a product.

The project is written almost entirely in Go. This makes it an excellent case study for building complex systems in Go.

Why Go for Containers?

Containers require low-level system interactions. Go handles this well. Here’s a simple example of how Moby uses Go’s syscall package to create namespaces:

package main

import (
	"os"
	"os/exec"
	"syscall"
)

func main() {
	cmd := exec.Command("/bin/sh")
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
	}

	if err := cmd.Run(); err != nil {
		panic(err)
	}
}

This creates a new process with isolated namespaces. It’s the foundation of container isolation. Go’s ability to work with Linux system calls directly makes this straightforward.

The Client-Server Architecture

Moby uses a client-server model. The Docker CLI talks to the Docker daemon via a REST API. Here’s how you interact with the Docker daemon using Go:

package main

import (
	"context"
	"fmt"

	"github.com/docker/docker/client"
)

func main() {
	ctx := context.Background()
	
	cli, err := client.NewClientWithOpts(client.FromEnv)
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	containers, err := cli.ContainerList(ctx, container.ListOptions{})
	if err != nil {
		panic(err)
	}

	for _, c := range containers {
		fmt.Printf("Container: %s - %s\n", c.ID[:12], c.Image)
	}
}

Notice how context is used to manage the request lifecycle. This pattern is everywhere in Moby’s codebase. It allows proper cancellation and timeout handling.

Building Images Programmatically

You can build Docker images directly from Go. This is useful for CI/CD pipelines or custom tooling:

package main

import (
	"archive/tar"
	"bytes"
	"context"
	"io"
	"os"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
)

func main() {
	ctx := context.Background()
	
	cli, err := client.NewClientWithOpts(client.FromEnv)
	if err != nil {
		panic(err)
	}
	defer cli.Close()

	// Create a tar archive with Dockerfile
	buf := new(bytes.Buffer)
	tw := tar.NewWriter(buf)

	dockerfile := `FROM alpine:latest
RUN echo "Hello from Go-built image"
`
	
	header := &tar.Header{
		Name: "Dockerfile",
		Size: int64(len(dockerfile)),
	}
	tw.WriteHeader(header)
	tw.Write([]byte(dockerfile))
	tw.Close()

	// Build the image
	resp, err := cli.ImageBuild(ctx, buf, types.ImageBuildOptions{
		Tags:       []string{"my-go-image:latest"},
		Dockerfile: "Dockerfile",
	})
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	io.Copy(os.Stdout, resp.Body)
}

Lessons from Moby’s Codebase

Moby’s codebase teaches several Go best practices:

1. Interface-based design. Components communicate through interfaces. This allows different implementations for different platforms.

2. Graceful shutdown. The daemon handles signals properly. When you stop Docker, it cleans up running containers. This pattern is something you can learn from error handling.

3. Plugin architecture. Moby supports plugins for storage, networking, and logging. Go’s interface system makes this natural.

Getting Started with Moby Development

Want to contribute to Moby or understand containers better? Start here:

  1. Clone the Moby repository
  2. Read the contributing guide
  3. Run make to build the project

The codebase is large but well-organized. Start with the client package to understand the API. Then explore daemon to see how containers actually work.

Wrapping Up

Moby is one of the most influential Go projects. It proves Go can handle complex system programming. The patterns used - context propagation, interface-based design, graceful shutdown - are worth studying.

Understanding Moby helps you understand how containers actually work under the hood.