動いた手順しか書かないと何をどう格闘したのか分からない訳だが、色々遠回りをしただけな気もするので「これで動いた」というのをまとめておく。おっと、苦労して何をやったのかというのを書かないとアカンかった。
VSCodeが動かない
VSCode、便利ですね?
息子ちゃんがPythonに興味を持ったのは良いけれど、学校で買わされたChromebookだとVSCodeは動かない、と。ChromebookはLXCでターミナルが動くのでVimでPythonのコードを書き始める健気な息子ちゃん…。いや、VimとPythonを同時に学習するのはちょっとコストが高すぎるでしょ。
じゃあ、先日リリースされたvscode.devにするかとブラウザで開いてコードを書いてみたのは良いけれど、vscode.devではターミナルがまだ無いからコードが実行出来ないんですわ。んで、Jupyter Notebookにするかな、いやvscode.devがあるんだからvscodeのレポジトリにWUI化するコードが入ってるんじゃないかと調べてみたりしてたら、code-serverを見つけたと(ここから格闘が始まった)。
何で格闘するハメになったか
code-serverのRPMパッケージはある。自宅鯖のRHEL8にもインストール出来る(出来た)。しかしRPMパッケージで入れてサービスとして立ち上げると、vscodeのターミナルでサーバの/ディレクトリも見えちゃう。つまり
$ sudo systemctl start code-server@user
してても、/home/user/
以外も見えちゃうし、/tmp
にファイルが作れちゃったり、あるいは/home/user/Maildir/
を消せたりする。あかん、完全にセキュリティホール作成サービスやんけw
じゃあ、chrootすりゃ良いんじゃね?と思ってsystemdのunitファイルに、
RootDirectory=/usr/lib/code-server/
RootDirectoryStartOnly=yes
とかやってみたけど、まあ色々アクセス出来なくなっちゃうから動かない、と。code-serverそのものがchrootされる環境を想定して設計・実装されてないから無理も無い。RHEL8だとsystemd-nspawnは無いしねぇ…。
Dockerで動くって書いてある
RPMがあるんだけども、Install手順にはDockerも当然書いてあって、
mkdir -p ~/.config
docker run -it --name code-server -p 127.0.0.1:8080:8080 \
-v "$HOME/.config:/home/coder/.config" \
-v "$PWD:/home/coder/project" \
-u "$(id -u):$(id -g)" \
-e "DOCKER_USER=$USER" \
codercom/code-server:latest
で動くことになってる(動くとは言ってない)。実際、動かない。
一見、動くんだけど、マウントしてる~/.config
と~/project
が両方ともroot:rootになっちゃうから、code-serverが書き込めない。code-serverのDockerイメージはDockerfileで
USER 1000
しちゃってるのでEACCESが出ちゃう(そりゃそうだ)。書いたコードをそのままgithubに上げちゃうなら問題ないけれど、Dockerホストのディレクトリに保存出来ないわけ。おまけにenv DOCKER_USERするとsudoers.d/にファイルを放り込んで、とかentrypointでやってるけどこれも上手く動いて無い。たぶんちゃんと検証してないんじゃないかなぁ…。このディレクトリの問題は、
docker volume create config
とかやって、それをマウントすりゃ良いだけなんだけども。
Podmanで動かす
さて、そんなわけでどうやったらPodmanで動くかなんだけど、以下のようにやっていく。なお環境はRHEL8.5だけど、たぶん8.1以降なら同じ手順で動く(はず)。
コンテナーツールをインストールする
まずモジュールのインストール。これはコマンド一発で終わる。
$ sudo dnf module install -y container-tools
ついdockerというコマンドを叩いてしまって毎回怒られが発生するのを避けるために以下を追加で。
$ sudo dnf install -y podman-docker
あと、ルートレスコンテナーを使えるようにしたいので、以下も。
$ sudo dnf install -y slirp4netns
既存のユーザについてもsubuid/subgid
を設定してくれるようだ。
$ grep rio /etc/subuid
rio:100000:65536
$ grep rio /etc/subgid
rio:100000:65536
で、おそらくなんだけど、ここで一度サーバを再起動した方が良い。container-toolsをインストールした際に何かやってて、それが反映されるのは再起動後、というのがあるっぽい(ちゃんと調べてないけど)。
ルートレス固有の事柄
- rootユーザなら
/var/lib/containers/
だけど、root以外は~/.local/share/containers/
に色々入る。 - その他詳細はRed Hatのマニュアルを読もう
コンテナレジストリの設定
以下の内容で~/.config/containers/registries.confを作る、とマニュアルには書いてあるんだけど、実は作らなくてもpullできる。
[registries.search]
registries = ['registry.access.redhat.com', 'registry.redhat.io', 'docker.io']
[registries.insecure]
registries = []
[registries.block]
registries = []
registry.access.redhat.comはサブスクリプション登録が必要なので、ここに書いただけではpull出来ないので注意。
code-serverのイメージをpull
普通にpullするだけ。
$ podman pull codercom/code-server:latest
✔ docker.io/codercom/code-server:latest
Trying to pull docker.io/codercom/code-server:latest...
Getting image source signatures
Copying blob f2992a38f428 done
Copying blob 955615a668ce done
Copying blob 1b7eaec48458 done
Copying blob f78b6250e9f8 done
Copying blob 4d402e4b2b85 done
Copying blob e0f780da324e done
Copying blob be75cc27e711 done
Copying blob 225329f6c59c done
Copying config 08823d7380 done
Writing manifest to image destination
Storing signatures
08823d73807e2a522c69bb67acc20d68052bb794b0a6f7776593fa756d5b6ac7
マウントするボリュームを作成する
code-serverの設定と書いたコードのファイルを格納するボリュームを作成する。
$ podman volume create config
$ podman volume create projects
作成したボリュームはどこにあるかというと、
$ ls ~/.local/share/containers/storage/volumes/
config projects
podman runする
あい、これでrunできます。
$ podman run -it --name code-server \
-p 192.168.1.2:8080:8080 \
-v "config:/home/coder/.config:Z" \
-v "projects:/home/coder/projects:Z" \
-e "PASSWORD=your_password" \
codercom/code-server:latest
[2021-11-11T14:06:50.394Z] info code-server 3.12.0 2661a690ac228872e8d1dc28ab6d33e8afc30add
[2021-11-11T14:06:50.395Z] info Using user-data-dir ~/.local/share/code-server
[2021-11-11T14:06:50.404Z] info Using config file ~/.config/code-server/config.yaml
[2021-11-11T14:06:50.404Z] info HTTP server listening on http://0.0.0.0:8080
[2021-11-11T14:06:50.404Z] info - Authentication is enabled
[2021-11-11T14:06:50.404Z] info - Using password from $PASSWORD
[2021-11-11T14:06:50.404Z] info - Not serving HTTPS
[2021-11-11T14:06:50.415Z] error Unauthorized HttpError: Unauthorized
at ensureAuthenticated (/usr/lib/code-server/out/node/http.js:38:15)
[2021-11-11T14:06:50.415Z] error Unauthorized HttpError: Unauthorized
at ensureAuthenticated (/usr/lib/code-server/out/node/http.js:38:15)
[2021-11-11T14:06:50.424Z] error Unauthorized HttpError: Unauthorized
at ensureAuthenticated (/usr/lib/code-server/out/node/http.js:38:15)
-p
のIPアドレス:ポートは適宜読み替えること。
-vでpodman volume createで作成したconfig
とprojects
を、それぞれコンテナ内の/home/coder/.config
と/home/coder/projects
にマウントする。
その後に続いてる":Z"はSELinuxのラベルを修正するおまじない。複数のコンテナで共有するなら":z"(スモールゼット)で。
-eでcode-serverにブラウザでログインする時のパスワードを設定すると。
動作が確認できたら一旦ctrl-cして止めてpodman rm code-serverしても良いけど、そのまま次の手順にいった方が楽です。
systemdのUNITファイルを作る
コマンド一発でsystemdのUNITファイルが作成出来る。このコマンド、–nameで分かる通り、その名前で動いてるコンテナかポッドが無いとダメ。だから「そのまま次の手順」と書いた。
$ podman generate systemd --new --files --name code-server
コマンドの結果はcontainer-code-server.serviceというファイルになる。中身は以下。podman generateコマンドに上記の通りの引数を渡さないと、こうならないので注意。
# container-code-server.service
# autogenerated by Podman 3.3.1
# Thu Nov 11 21:26:31 JST 2021
[Unit]
Description=Podman container-code-server.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --sdnotify=conmon --cgroups=no-conmon --rm -d --replace -it --name code-server -p 192.168.1.2:8080:8080 -v config:/home/coder/.config:Z -v projects:/home/coder/projects:Z -e PASSWORD=your_password codercom/code-server:latest
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all
[Install]
WantedBy=multi-user.target default.target
さて、ここでRed Hatのマニュアルに不備があってちょっとハマった。このあと、この"container-code-server"
をsystemctlでenableするんだけども、マニュアルにコマンドが抜けていて、
$ sudo cp -Z ~/container-code-server.service /usr/lib/systemd/system/
するみたいに見えるけど、それ、違う。次に以下のコマンドを実行すると、そんなサービスは無い、って怒られが発生する。
$ sudo systemctl --user enable container-code-server.service
正しくは、以下を実行してから
$ sudo cp -Z ~/container-code-server.service /etc/systemd/user/
$ sudo chcon -u system_u /etc/systemd/user/container-code-server.service
systemctlでenableする。サーバを再起動してもコンテナが起動するようになる。
$ sudo systemctl --user enable container-code-server.service
Created symlink /root/.config/systemd/user/multi-user.target.wants/container-code-server.service → /etc/systemd/user/container-code-server.service.
Unit /etc/systemd/user/container-code-server.service is added as a dependency to a non-existent unit multi-user.target.
Created symlink /root/.config/systemd/user/default.target.wants/container-code-server.service → /etc/systemd/user/container-code-server.service.
と思うじゃん?以下も必要。
$ sudo loginctl enable-linger root
コンテナを止める
ここまで出来たら、code-serverのコンテナを止める。ctrl-cして止めてpodman rm code-server
サービスを起動する
これはもういつも通り。
$ sudo systemctl --user start container-code-server
Firewalldの設定を忘れずに
この説明では8080/tcpなので、以下のように。
$ sudo firewall-cmd --permanent --add-port=8080/tcp
おわり
こうやって書くと簡単そうだけど、半日格闘したよ…。
では皆さん、良い「自宅vscode.devライフ」を。
で、終わりだと思うじゃん?
macOSのSafariだと、ターミナルの文字が表示されないんだこれがwww
ほら、真っ白。
GPU Accelerationが悪さをしているので、Settingsから
“GPU Acce..までタイプすれば出てくるのでoffにする。
これで完成。