Author: Michelle Kiyan


Although Kubernetes developed the container runtime interface (CRI) standard, the only container runtime that could be used in the early stage was Docker, and Docker was not suitable for this standard, so it opened a back door for Docker. It took a lot of effort to adapt it. Later, with more container runtimes available, Kubernetes had to reconsider whether to continue to adapt Docker, because every update to Kubelet has to consider the adaptation of Docker.

The standard is like this, I set the standard, you compatible to play together, incompatible goodbye, it is like the bottom line of two people together, you can be heavy, you can be ugly, you can not perfect, but you are not compatible with the standard really can not play together, so Kubernetes kicked Docker out of the group chat.

Kubernetes chose Containerd, and today Containerd is an industrial-grade container runtime that is simple, robust, and portable.

Shortcomings of the existing CLI

While Containerd can do all the things Docker can do today, it has one significant drawback: it’s not CLI friendly. It can’t launch a container with a single command like Docker and Podman, and neither of its two CLI tools, CTR and Crictl, can fulfill a very simple requirement that most people need, I can’t just deploy a Kubernetes cluster to test the container locally, can I?

CTR is not designed to be very human friendly, for example, it lacks the following docker-like features:

  • docker run -p <PORT>
  • docker run --restart=always
  • By credential file~/.docker/config.jsonLet’s pull the mirror image
  • docker logs

There is also a CLI tool called Crictl, which is as unfriendly as CTR.

To address this pain point, Containerd has officially launched a new CLI called Nerdctl. Nerdctl is as smooth as Docker, for example:

🐳  → nerdctl run -d -p 8080:80 --name=nginx --restart=always nginx
Copy the code

Nerdctl just a copy of Docker?

The goal of nerdctl is not just to replicate the functionality of Docker. It also implements many features that Docker does not have, such as lazy-pulling and imgcrypt.

For the delayed image fetching feature, see this article: Containerd uses Stargz Snapshotter to delay image fetching.

While these features are expected to be implemented in Docker eventually, it could take months or even years, as Docker’s current design uses only a small number of Containerd subsystems. Docker could potentially refactor the code to use a full Containerd in the future, but we haven’t seen much progress yet. So the Containerd community decided to create a new CLI to be more Containerd friendly.

Nerdctl trial

You can download the latest executable from nerdctl’s release, and each version is available in two distributions:

  • nerdctl-<VERSION>-linux-amd64.tar.gz: Contains only nerdctl.
  • nerdctl-full-<VERSION>-linux-amd64.tar.gz: contains nerdCTL and its dependencies (containerd, runc, CNI…). .

If you already have Containerd installed, select only the previous release, otherwise select the full version.

With nerdCTL installed, you can use nerdctl to run containers:

🐳 - nerdctl run - d - p 80:80 - name = nginx, restart = always nginx: alpine docker. IO/library/nginx: alpine: resolved |++++++++++++++++++++++++++++++++++++++| index-sha256:d33e9e24389d7d8b90fe2bcc2dd1bc09b4d235e916ba9d5d9a71cf52e340edb6:done           |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:c1f4e1974241c3f9ddb2866b2bf8e7afbceaa42dae82aabda5e946d03f054ed2: done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:bfad9487e175364fd6315426feeee34bf5e6f516d2fe6a4e9b592315e330828e:   done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:29d3f97df6fd99736a0676f9e57e53dfa412cf60b26d95008df9da8197f1f366:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:9aae54b2144e5b2b00c610f8805128f4f86822e1e52d3714c463744a431f0f4a:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:a5f0adaddd5456b7c5a3753ab541b5fad750f0a6499a15f63571b964eb3e2616:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:5df810e1c460527fe400cdd2cab62228f5fb3da0f2dce86a6a6c354972f19b6e:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:345aee38d3533398e0eb7118e4323a8970f7615136f2170dfb2b0278bbd9099d:    done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:e6a4c36d7c0e358e5fc02ccdac645b18b85dcfec09d4fb5f8cbdc187ce9467a0:    done| + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | elapsed: 5.7 s total: 9.4 Mi 27 b55e0b18b10c4c8f34e3ba709614e7b1760a75db061d2ce5183e8b1101ce09 MiB/s (1.6)Copy the code

View the created container:

🐳 - nerdctl ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3 b5faa266a43 docker. IO/library/nginx: alpine"/ docker - entrypoint...."3 minutes ago Up 0.0.0.0:80->80/ TCP nginxCopy the code

Like Docker, Containerd has a subcommand, network:

🐳  → nerdctl network ls
NETWORK ID    NAME               FILE
0             bridge
              k8s-pod-network    /etc/cni/net.d/10-calico.conflist
              host
              none
Copy the code

Take a look at the default Bridge configuration:

🐳 → nerdctl network inspect bridge [{"CNI": {
            "cniVersion": "0.4.0"."name": "bridge"."nerdctlID": 0."plugins": [{"type": "bridge"."bridge": "nerdctl0"."isGateway": true."ipMasq": true."hairpinMode": true."ipam": {
                        "type": "host-local"."routes": [{"dst": "0.0.0.0/0"}]."ranges": [[{"subnet": "10.4.0.0/24"."gateway": "10.4.0.1"}]]}}, {"type": "portmap"."capabilities": {
                        "portMappings": true}}, {"type": "firewall"
                },
                {
                    "type": "tuning"}},"NerdctlID": 0}]Copy the code

It can be seen that CNI is still operating behind the network subcommand, which is different from the principle of docker network subcommand.

Build the mirror

Nerdctl can also be used in conjunction with BuildKit to build container images by downloading the BuildKit executable:

🐳  → wget https://github.com/moby/buildkit/releases/download/v0.8.2/buildkit-v0.8.2.darwin-amd64.tar.gz
Copy the code

Unzip it into $PATH:

🐳  → tar -C /usr/local/ - ZXVF buildkit - v0.8.2. Linux - amd64. Tar. GzCopy the code

Write systemd Unit file:

# /etc/systemd/system/buildkit.service
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit

[Service]
ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true

[Install]
WantedBy=multi-user.target
Copy the code

Enable buildKit. service and set startup to run automatically:

🐳  → systemctl enable --now buildkit.service
Copy the code

Using the KubeSphere project as an example, the following shows how to use nerdCTL to build the image.

First clone KubeSphere official warehouse:

🐳 to gitclone --depth=1 https://github.com.cnpmjs.org/kubesphere/kubesphere.git
Copy the code

Go to the repository directory and compile the binaries:

🐳 -cdKubesphere 🐳 → make ks-apiserverCopy the code

Copy binary files to Dockerfile directory:

🐳 → cp bin/ CMD /ks-apiserver build/ks-apiserverCopy the code

Dockerfile directory:

# Copyright 2020 The KubeSphere Authors. All rights reserved.
# Use of this source code is governed by an Apache license
# that can be found in the LICENSE file.
FROM alpine:3.11

ARG HELM_VERSION=v3.5.2

RUN apk add --no-cache ca-certificates
# install helm
RUN wget https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz && \
    tar xvf helm-${HELM_VERSION}-linux-amd64.tar.gz && \
    rm helm-${HELM_VERSION}-linux-amd64.tar.gz && \
    mv linux-amd64/helm /usr/bin/ && \
    rm -rf linux-amd64
# To speed up building process, we copy binary directly from make
# result instead of building it again, so make sure you run the
# following command first before building docker image
# make ks-apiserver
#
COPY  ks-apiserver /usr/local/bin/

EXPOSE 9090
CMD ["sh"]
Copy the code

Build an image:

🐳 -cdBuild /ks-apiserver 🐳 → nerdctl build -t ks-apiserver. [+] Building 22.6s (9/9) FINISHED => [internal] Load build Definition from Dockerfile 0.9s => => Dockerignore 0.0s => [internal] load. Dokerignore 0.0s => [internal] load. Dokerignore 0.0s => [internal] loadforDocker. IO/library/alpine: 3.11 1.0 s = > [1/4] the FROM Docker. IO/library/alpine: 3.11 @ sha256:7.9 s = > = > bf5fa774f08a9ed2cb301e522b769d43d48124315a4ec50eae3228d03b9dc558 resolve Docker. IO/library/alpine: 3.11 @ sha256: bf5fa774f08a9ed2cb301e522b769d43d48124315a4ec50eae3228d03b9dc558 0.0 s = > = > Sha256:9 b794450f7b6db7c944ba1f4161edb68cb535052fe7db8ac06e613516c4a658d 2.10 2.82 MB 21.4 MB/s = > = > extracting Sha256:9 b794450f7b6db7c944ba1f4161edb68cb535052fe7db8ac06e613516c4a658d 0.1 s = > (internal) load build context 1.0 s = > = >  transferring context: 115.87MB 1.0s => [3/4] RUN apk add --no-cache ca-certificates 2.7s => [3/4] RUN wget https://get.helm.sh/helm-v3.5.2-linux-amd64.tar.gz && tar XVF helm-V3.5.2-linux-AMd64.tar.gz && rm Helm-v3.5.2-linux-amd64.tar. gz && mv Linux-amd64 4.7s => [4/4] COPY ks-apiserver /usr/local/bin/ 0.2s => exporting to OCI image format 5.9s => => exporting layers 4.6s => => exporting manifest Sha256: d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e 0.0 s = > = > exporting config Sha256:8 eb6a5187ce958e76c8d37e18221d88f25b48dd7e6672021d0fce21bb071f284 0.0 s = > = > sending tarball 1.3 s unpacking docker.io/library/ks-apiserver:latest (sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e)...done
unpacking overlayfs@sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e (sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e)...done
Copy the code

View the built image:

🐳  → nerdctl images
REPOSITORY                                                   TAG       IMAGE ID        CREATED          SIZE
alpine                                                       3.11      bf5fa774f08a    3 seconds ago    2.7 MiB
ks-apiserver                                                 latest    d7eb2a904966    6 minutes ago    57.7 MiB
Copy the code

For more information on nerdctl usage, see the official repository’s README.

conclusion

In terms of industry trends, Docker has become increasingly alienated from the Kubernetes community, with Containerd being the most popular container runtime to implement the CRI interface. The nerdCTL CLI tool fills in the gaps in Containerd’s ease of use, allowing you to use Containerd happily on a single machine.