Working with Containers

nerdctl is a Docker-compatible CLI for containerd. The primary goal of nerdctl is to facilitate experimenting with cutting-edge features of containerd that are not present in Docker.

Moby is an open-source project that was created by Docker to enable and accelerate software containerization. Components include container build tools, a container registry, orchestration tools, and a runtime, and more. The Docker CLI uses the Moby runtime.

Running Containers

To run a container with the default bridge CNI network (10.4.0.0/24):

  • nerdctl
  • docker
  1. nerdctl run -it --rm alpine
  1. docker run -it --rm alpine

To build an image using BuildKit:

  • nerdctl
  • docker
  1. nerdctl build -t foo /some-dockerfile-directory
  2. nerdctl run -it --rm foo
  1. docker build -t foo /some-dockerfile-directory
  2. docker run -it --rm foo

To build and send output to a local directory using BuiltKit:

  • nerdctl
  • docker
  1. nerdctl build -o type=local,dest=. /some-dockerfile-directory
  1. docker build -o type=local,dest=. /some-dockerfile-directory

Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications.

  • nerdctl
  • docker

The nerdctl-compose CLI is designed to be compatible with docker-compose:

  1. nerdctl compose up -d
  2. nerdctl compose down

The compose command in the Docker CLI supports most of the docker-compose commands and flags. It is expected to be a drop-in replacement for docker-compose.

  1. docker compose up -d
  2. docker compose down

Exposing a Port

To expose port 8000 for a container:

  • nerdctl
  • docker
  1. nerdctl run -d -p 8000:80 nginx
  1. docker run -d -p 8000:80 nginx

You can then access the container via the browser here: http://localhost:8000/.

Note: By default the exposed ports are accessible on all network interfaces on macOS and Linux. However, on Windows, the exposed ports are currently only accessible through the localhost network interface (see issue #1180). As a workaround, you can configure a portproxy on the windows host to expose the port to additional network interfaces.

  1. netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=localhost

Exposing the port of a running container

If you forgot to expose the port as part of the run command, you can follow the steps below to start a proxy container that forwards traffic to the original container. This hack helps you avoid restarting the container and is especially useful when dealing with containerized services with longer startup times. With full disclosure, this hack is based on the suggestions in this stackoverflow discussion and this blog post.

  1. Let’s say you ran a container without publishing the port (by mistake).
  • nerdctl
  • docker
  1. nerdctl run -d --name rd-nginx nginx
  1. docker run -d --name rd-nginx nginx
  1. Set port variables to be used in the subsequent commands.
  1. # Powershell
  2. $HOST_PORT=8080
  3. $CONTAINER_PORT=80
  4. # Bash
  5. export HOST_PORT=8080
  6. export CONTAINER_PORT=80
  1. Get the container IP address. If you did not give a name to the container at the time of starting it, you can pass the container id in place of the container name rd-nginx in the commands below.
  • nerdctl
  • docker
  1. # Powershell
  2. $CONTAINER_IP=$(nerdctl inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' rd-nginx)
  3. # Bash
  4. export CONTAINER_IP=$(nerdctl inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' rd-nginx)
  1. # Powershell
  2. $CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' rd-nginx)
  3. # Bash
  4. export CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' rd-nginx)
  1. Start a proxy container to forward traffic to the original container.
  • nerdctl
  • docker
  1. nerdctl run --rm -p ${HOST_PORT}:${CONTAINER_PORT} alpine/socat TCP-LISTEN:${CONTAINER_PORT},fork TCP-CONNECT:${CONTAINER_IP}:${CONTAINER_PORT}
  1. docker run --rm -p ${HOST_PORT}:${CONTAINER_PORT} alpine/socat TCP-LISTEN:${CONTAINER_PORT},fork TCP-CONNECT:${CONTAINER_IP}:${CONTAINER_PORT}
  1. Once the proxy container is successfully run, you can access the NGINX server at localhost:8080 from your host machine.

Targeting a Kubernetes Namespace

You may also target a Kubernetes namespace with the --namespace parameter with containerd. Please note that docker doesn’t use namespaces.

  • nerdctl
  1. nerdctl --namespace k8s.io build -t demo:latest /code/demos/rd/anvil-app
  2. nerdctl --namespace k8s.io ps