はじめに
VSCode Remote Containers を使って開発する場合、Dockerfile を書いて「Reopen in Container」とすると Docker コンテナが起動しますが、この時 VSCode が docker run
を実行します。
このため、何も気にせず公式の手順などを参考に起動すれば、--privileged
オプションを付加できず、ENTRYPOINT に /sbin/init
も渡せないため、コンテナで systemctl
を実行できません。
※実行すると「Failed to get D-Bus connection: Operation not permitted」と表示されエラーとなります。
※このあたりの仕組みについては、既に「CentOS 7のDockerコンテナ内でsystemdを使ってサービスを起動する」などの記事で語られているため、本記事では割愛します。
本記事では、題記の通り、VSCode Remote Containers で使うコンテナで、docker run
に --privileged
と /sbin/init
を渡すための調査経緯と、実現した方法を紹介します。
0. 序章: 調査編
まずは正攻法で行けないかと調査してみると、設定ファイルの devcontainer.json には「runArgs」というパラメータがあり、ここで docker run
する時のパラメータを追加できることが分かりました。
参考: devcontainer.json reference
しかし、この方法では --privileged
を追加できても、--entrypoint
を上書きできませんでした。
VSCode Remote Containers で 「Reopen in Container」 して docker コンテナを起動すると、docker run
の引数に --entrypoint /bin/sh <各自のDocker Image> -c echo Container started ; trap "exit 0" 15; while sleep 1 & wait $!; do :; done
が付加されてしまい、devcontainer.json に書いたパラメータではこれを上書きできない仕様となっているようです。
起動時にどんなコマンドが流れているかは、起動中に表示される以下ポップアップのリンクを押すことで見えるログから把握できます。
また、次のリンク先で解説されているように、Dockerfile に書いた ENTRYPOINT と CMD よりも、引数で指定された --entrypoint
が優先されるため、Dockerfile に書いても上書きできません。
VSCode が必ず docker run
に引数で --entrypoint
を付加するためこれが最優先されてしまいます。
参考: Dockerfileによるビルド
1. 実現手順
そこで、以下の手順を辿ることにしました。
(1) まずは手順通り 「Reopen in Container」 を実行
この手順により Docker イメージがビルドされ、コンテナが起動します。
この時、先ほどのポップアップのリンクからログを開き、ログの中から以下のコマンドを探してコピーします。
docker run -a STDOUT -a STDERR --mount type=bind,source=<各自の環境のパス>,target=<各自の環境のパス>,consistency=cached -l vsch.quality=stable -l vsch.remote.devPort=0 -l vsch.local.folder=<各自の環境のパス> --entrypoint /bin/sh <各自のDocker Image> -c echo Container started ; trap "exit 0" 15; while sleep 1 & wait $!; do :; done
(2) VSCode でコンテナとの接続を解除
(1) で起動したコンテナは --privileged
されていませんので、VSCode で一旦接続を解除します。
(3) コピーしたコマンドを一部変更
コピーしたコマンドに --privileged
を追記し、--entrypoint
を書き換えます。
docker run -a STDOUT -a STDERR --mount type=bind,source=<各自の環境のパス>,target=<各自の環境のパス>,consistency=cached -l vsch.quality=stable -l vsch.remote.devPort=0 -l vsch.local.folder=<各自の環境のパス> --privileged --entrypoint /sbin/init <各自のDocker Image>
(4) 上記コマンドをローカルのターミナルで実行
実行すると (3) のオプション通りに docker コンテナが起動します。
docker ps
で起動状態を確認できます。
(5) VSCodeで「Attach to Running Container」を実行
次に、(4) で起動したコンテナを VSCode にアタッチします。
まず、以下画像のように「Attach to Running Container」を選びます。
ここまでで、VSCode からコンテナに接続して、開発環境を開けます。
2. 動作確認
VSCode でコンテナのターミナルを開いて systemctl
を打ってみます。
bash-4.2# systemctl
UNIT LOAD ACTIVE SUB DESCRIPTION
dev-vda1.device loaded activating tentative /dev/vda1
-.mount loaded active mounted /
dev-hugepages.mount loaded active mounted Huge Pages File System
dev-mqueue.mount loaded active mounted POSIX Message Queue File Syste
etc-hostname.mount loaded active mounted /etc/hostname
etc-hosts.mount loaded active mounted /etc/hosts
(以下長いので略)
このようにエラーが解消され、打てるようになっています。
最後に
このように、起動したコンテナに VSCode から接続する手順を踏むことで、VSCode Remote Containers でも systemctl
が実行できるようになります。
今回、少々面倒ですが docker build
までは VSCode で実行して、各種オプションが含まれる docker run
コマンドを VSCode のログから発掘する方が早いと判断しました。
(もっと良い方法があるのかもしれませんが、もし見つかったら追記します)
なお --privileged
はその名の通り特権という意味なので、ご利用は計画的に、とすべきです。