WSL2でcontainerdとnerdctlを使えるようにする(initd/systemd両対応)

aptで配信されているcontainerdがいつまで経っても1.7のままなので、nerdctlのfull版tarballに含まれるものをインストールする場合の手順を追記する。

まず、インストールしたいバージョンのfull版tarballをダウンロードし、/usr/local以下に展開する

NERDCTL_FULL_VERSION="2.1.2"
wget "https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_FULL_VERSION}/nerdctl-full-${NERDCTL_FULL_VERSION}-linux-amd64.tar.gz"
sudo tar Cxzvf /usr/local "nerdctl-full-${NERDCTL_FULL_VERSION}-linux-amd64.tar.gz"

containerd用のCNIのパスを設定する。

> sudo vi /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir = "/opt/cni/bin"
conf_dir = "/etc/cni/net.d"

CNIの設定ファイルを生成する。

sudo mkdir -p /etc/cni/net.d
sudo nano /etc/cni/net.d/10-containerd-net.conf

デフォルトの内容は以下の通り。

{
  "cniVersion": "1.0.0",
  "name": "containerd-net",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "cni0",
      "isGateway": true,
      "ipMasq": true,
      "ipam": {
        "type": "host-local",
        "routes": [
          { "dst": "0.0.0.0/0" }
        ],
        "rangeSets": [
          { "rangeStart": "10.88.0.1", "rangeEnd": "10.88.0.254", "subnet": "10.88.0.0/16" }
        ]
      }
    },
    {
      "type": "portmap",
      "capabilities": {"portMappings": true}
    }
  ]
}

Daemonを起動する。

sudo systemctl enable buildkit
sudo systemctl start buildkit
sudo systemctl enable containerd
sudo systemctl start containerd

複数の端末に何度もinstallする機会があったので手順をshell scriptにまとめ。

方針としては、

  • nerdctlのtar ballには対応するバージョンのcontainerdも含まれるが、他にも依存関係があるようなのでまとめてupgradeできるようにaptから導入する。nerdctlもaptで配信して欲しい
  • systemdが有効なWSL2なら常駐させる。
  • init.d向けに別途init.d用scriptを生成する。

早速、諸々をinstallするshell scriptは以下の通り。

事前にsudo apt update && sudo apt upgradeをしておくことを忘れずに…

#!/bin/sh

#
# Download nerdctl
#

VERSION=1.3.1 # see https://github.com/containerd/nerdctl/releases
OS=linux
ARCH=$([ $(uname -m) = "x86_64" ] && echo "amd64" || echo "arm64")

TARNAME=nerdctl-full-$VERSION-$OS-$ARCH.tar.gz
TARPATH=/tmp/$TARNAME

if [ ! -e $TARPATH ]; then
    curl -L "https://github.com/containerd/nerdctl/releases/download/v$VERSION/$TARNAME" -o $TARPATH
fi

#
# Install nerdctl and related softwares
#

sudo apt install uidmap containerd -y
sudo tar xzf $TARPATH -C /usr/local/bin/ --strip-components 1 bin/nerdctl bin/buildctl bin/buildkitd
sudo tar xzf $TARPATH -C /usr/lib/systemd/system/ --strip-components 3 lib/systemd/system/buildkit.service
sudo tar xzf $TARPATH -C /usr/local/ libexec
sudo chmod +s "$(which nerdctl)"

# Set PATH so that CNI can be referenced
echo 'export CNI_PATH=/usr/local/libexec/cni' >> ~/.bashrc
. ~/.bashrc

#
# Start daemon
#

if [ $(ps -p 1 | awk 'NR==2{print $4}') = "systemd" ]; then
    sudo systemctl enable containerd
    sudo systemctl enable buildkit

    sudo service containerd start
    sudo service buildkit start

    echo "Resident daemons: systemd mode"
else
    sudo $(which containerd) &
    sudo $(which buildkitd) &

    echo "Onestart daemons: initd mode"
fi

これを適当な名前でファイルに保存して実行すればdaemonが常駐された状態になる…筈。

init.d用scriptを生成する

MSストア版が導入できないなどsystemdを使えずinit.dで頑張る環境用に、簡易的なinit.d用scriptを生成する汎用的なshell scriptも作ってみた。

なお上記のscriptで既に起動しているprocessがある場合は手動でkillする事。

> sudo kill $(ps -A | grep containerd | awk '{print $1}')  
> sudo kill $(ps -A | grep buildkitd | awk '{print $1}')
#!/bin/sh

if [ $# = 0 ]; then
  echo "daemon name required."
  exit 1
fi

DAEMON_PATH=`which $1`
RETVAL="$?"

if [ $RETVAL != 0 ]; then
  echo "unknown daemon name: $1"
  exit 1
fi

set -e

echo "daemon path: $DAEMON_PATH"

INIT_FILE=/etc/init.d/$1

cat <<-EOF > $INIT_FILE
	#!/bin/sh
	
	set -e

	. /lib/lsb/init-functions
	
	DAEMON=$DAEMON_PATH
	PID_FILE=/var/run/$1.pid
	
	case "\$1" in
	  start)
	    if [ -e \$PID_FILE ]; then
	      exit 1
	    fi
	    start-stop-daemon --start --background --pidfile \$PID_FILE --make-pidfile --exec \$DAEMON
	    ;;
	  stop)
	    start-stop-daemon --stop --oknodo --retry 30 --pidfile \$PID_FILE
	    RETVAL="\$?"
	    if [ \$RETVAL != 0 ]; then
	      exit 1
	    fi
	    rm -f \$PID_FILE
	    ;;
	  status)
	    status_of_proc -p \$PID_FILE "\$DAEMON" $1
	    exit \$?
	    ;;
	  *)
	    echo "service $1 [start|stop|status]"
	    ;;
	esac
EOF

chmod +x $INIT_FILE
echo "maked: $INIT_FILE"

上記のscriptをmakeinit.shなどとした場合、以下の様に使う。

$ sudo ./makeinit.sh containerd
$ sudo ./makeinit.sh buildkitd

/etc/init.dへの書き込みが発生するのでsudoが必要だ。chmod +x makeinit.shも忘れずに…

登録後はsystemdと同様に(?)serviceコマンドを利用して起動できるようになる。

$ sudo service containerd start
$ sudo service buildkit start