チラシの裏からうっすら見える外枠の外のメモ書き

新聞に挟まってる硬い紙のチラシの裏からうっすら見える外枠の外に走り書きされたようなものです。思いついたときにふらふらと。

WSL 2でRootless Dockerを使う

WSL 2がWindows 1909にバックポートされたおかげで、多くの人がWSL 2を体験できる状態になったと思います。

WSL 2のメリットにはDockerが使えるというものがありましたが、Rootless Dockerは使えないという問題がありました。 そこで、WSL 2に色々なものを加えてRootless Dockerをインストール、実行できるようにしました。

注意事項

  • systemdをinitの代わりに使うようにしてるのでMicrosoftの想定する使い方じゃないため後々動かなくなるかもしれません。
  • Rootless Dockerをインストールすることはできましたが、Rootless Dockerが100%動くかはわかりません。まだそこまで試せていません。 * 少なくともコンテナはインターネットに接続できないっぽいです(ホストマシンとの通信はできる)。
  • コンテナからインターネットへ接続するにはコンテナ起動時に--net=hostをつけることでインターネット接続できるようです。詳しくは後述します。
  • 自己責任です。

動作環境

やること

  1. systemdをPID 1で動くようにする
  2. Rootless Dockerをip_tablesカーネルモジュールを無視するようにしてインストールする

具体的な手順

  1. daemonize/dbus/policykit-1をインストールする
  2. dotnet-runtime-3.1をインストールする
  3. Genieをインストールする
  4. Genieを自動起動するようにする
  5. Rootless Dockerをインストールする
  6. .bashrcにRootless Dockerの設定を追記する

手順

systemdをPID 1で動作させるためにGenieをインストールしますが、それにはいくつかの前処理が必要です。 Genieのインストール方法までは以下のGenieのリポジトリにあるREADME.mdに記載されており、そこに従っています。 github.com

1. daemonize/dbus/policykit-1をインストールする

Genieの依存パッケージであるdaemonize/dbus/policykit-1をaptでインストールします。

sudo apt install daemonize dbus policykit-1

dbusとpilicykit-1はすでにインストールされていることがあります。

2. dotnet-runtime-3.1をインストールする

Genieは.NETを使っているようなので、動作に必要な.NET runtimeをインストールします。 インストール方法は以下にMicrosoft公式の日本語ドキュメントがあるので、それに途中まで従います。 docs.microsoft.com

wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt update
sudo apt install apt-transport-https
sudo apt update
sudo apt install dotnet-runtime-3.1

Microsoftのドキュメントではランタイムとしてaspnetcore-runtime-3.1をインストールしていますが、これで動作するかは未確認です。

3. Genieをインストールする

GenieのリポジトリにあるREADME.mdに記載されている方法でGenieをインストールします。 github.com

curl -s https://packagecloud.io/install/repositories/arkane-systems/wsl-translinux/script.deb.sh | sudo bash
sudo apt install systemd-genie

ここで、Genieが動作するか次のコマンドでGenieを起動し確認します。

genie -s

このとき、何も出力されなければ問題なく動作しています。 これでsystemdを使用することができます。

ここからはttsの代わりにptsを使うようになるので、getty@tty1サービスを無効しておきます。(なくても問題ないとは思います)

sudo systemctl stop getty@tty1

4. Genieを自動起動するようにする

このままではGenieはWSL 2が終了する度に一緒に終了して自動起動してくれないので、~/.bashrc自動起動するように設定を加えます。 以下の記事に記載されているスクリプトを引用します。 shikiyura.com

if [ "`ps -eo pid,lstart,cmd | grep systemd | grep -v -e grep -e systemd- | sort -n -k2 | awk 'NR==1 { print $1 }'`" != "1" ]; then
   genie -s
fi

5. Rootless Dockerをインストールする

Rootless Dockerをインストールしますが、そのままの手順ではip_tablesカーネルモジュールがないためインストールできないと言われてしまいます。 そこで、iptablesのチェックをスキップするようSKIP_IPTABLES=1にしておきます。

export SKIP_IPTABLES=1; curl -fsSL https://get.docker.com/rootless | sh

6. .bashrcにRootless Dockerの設定を追記する

Rootless Dockerをインストールすると画面に表示されていると思いますが、Dockerのホストを~/.bashrcに追記しておきます。

export DOCKER_HOST=unix:///run/user/1000/docker.sock

あとはターミナルを再起動すればRootless Dockerを利用することができます。

コンテナ起動時の引数に--net=hostをつける

WSL 2にはiptablesがないため、コンテナがインターネットに接続するにはコンテナ起動時のコマンドに--net=host引数をつける必要があります。

docker run --rm -it --net=host someimage /bin/bash

この情報は以下のツイートによりお知らせいただきました。ありがとうございます。

普通にインストールできない理由

ip_tablesカーネルモジュールがない問題

まず、WSL 2のカーネルLinuxカーネルとは言え純粋なLinuxカーネルではありません。当たり前ですが、Windowsがいるのでそこを考慮した構造にする必要があります。 そのため、WSL 2で使われるカーネルMicrosoftによってカスタマイズされたカーネルが使われています。

このカスタマイズされたカーネルにはカーネルモジュールが一切ありません。 よってip_tablesカーネルモジュールも同じように存在しないためRootless Dockerをインストールすることができません。

今回はSKIP_IPTABLES=1をつけることでip_tablesのチェックを無視してインストールしています。 普通のDockerはどうしているんでしょうか?まだよく見てないのでわかりません。

systemdが使えない問題

WSL 2のUbuntu 20.04ではinitにsystemdではなく独自のinitを使っているようです。しかもそれはおそらくSysVinitかUpstartをもとに作っているっぽい(systemctlは使えないのにserviceが使えるため)。

ただ、systemdが入ってないのではなく動いていないだけなので、動くようにしてやればsystemdを使うことができるようです。 このとき、systemdのPIDが1じゃないとほとんどのソフトウェアは動かないので、Genieを使ってsystemdがPID 1になるようにしています。

感想

Dockerはコンテナからインターネット接続できるのにRootless Dockerだとできないのはおかしいなぁと思うので、もしかしたらそのうちできるようになるのかもしれません。 Rootless Dockerは素敵な仕組みなのに今の所冷遇されててもったいないと思っています。

コンテナ内からインターネット接続が必要な人はおとなしくDockerを使ったほうが良さげです。 一応、これらを全部消して元に戻す方法は別の記事にまとめる予定です。書きました。 k-hyoda.hatenablog.com もちろんWSL 2を入れ直すのが手っ取り早いのですが、データも全部消えてしまいます。