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
をつけることでインターネット接続できるようです。詳しくは後述します。 - 自己責任です。
動作環境
やること
- systemdをPID 1で動くようにする
- Rootless Dockerをip_tablesカーネルモジュールを無視するようにしてインストールする
具体的な手順
- daemonize/dbus/policykit-1をインストールする
- dotnet-runtime-3.1をインストールする
- Genieをインストールする
- Genieを自動起動するようにする
- Rootless Dockerをインストールする
- .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
この情報は以下のツイートによりお知らせいただきました。ありがとうございます。
SKIP_IPTABLES=1 の時は、`docker run --net=host` を使うとコンテナ内からインターネットに接続できます
— Akihiro Suda (@_AkihiroSuda_) 2020年9月21日
普通にインストールできない理由
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を入れ直すのが手っ取り早いのですが、データも全部消えてしまいます。