16
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

docker Advent Calendar 2021

Day 19

WindowsでDockerデーモンを自動起動させる方法をまとめてみる without Docker Desktop

Posted at

はじめに

アドベントカレンダーに初参加してみました。

さて、6日目のWindows PCでDocker Desktopを利用せずにLinuxコンテナーとWindowsコンテナー環境を構築する方法でも紹介されている通り、一定規模以上の法人でのDocker Desktopの利用が有償化されました(2022年1月31日まで猶予期間あり)。

早速ですが、Docker Desktopを使用する場合、PC起動時にDocker DesktopがDockerデーモンを起動してくれるため、デーモンの起動状況を意識せずとも任意のコンテナを実行することができます。
一方で、WSL2上のLinuxのinitはカスタムされているためにサービスの自動起動ができないようです。すなわち、Docker Desktop無しにWSL2上のLinuxへDockerエンジンをインストールすると、PC起動後にターミナルでわざわざsudo service docker startを実行する必要があります。

これだと、せかっくdocker run--restartオプションやdocker-compose.ymlのrestartalwaysを指定したコンテナも、PC起動時には再実行されません。
そこで、Docker Desktopを使わずにDockerエンジンをインストールした環境でも、デーモンを自動起動する方法をまとめてみたいと思います。

前提環境

  • Windows 10以降
  • WSL2上のUbuntuへDockerエンジンをインストール済み

方法

その1 .bashrcを使う

~/.bashrcservice docker startを書く方法です。
一般ユーザーがパスワードなしで実行できるようvisudoコマンドなどでsudoersファイルを変更しておく必要があります。

DockerDesktopからWSL2上のみで動くDockerに移行するが参考になります。

なお、この方法はPC起動後に初めてターミナルへログインしたときにデーモンが実行されるため、PC起動時にコンテナを再実行するという目的は果たせません。

その2 Systemdを使う

WSL2上のLinuxでSystemdを動かしてデーモンを起動する方法です。
genieを利用するのが定番みたいですが、他にはDistrodを使ってもSystemdを動かせるようになります。

WSL2(Ubuntu18.04 LTS)をセットアップしてDocker(on Ubuntu)とGUIアプリを使うが参考になります。

その3 タスクスケジューラを使う

Windowsのタスクスケジューラを使う方法です。
wslコマンドの-dオプションと-uオプションを使うと、Windows側から任意のディストリビューションの任意のユーザーで任意のコマンドを実行することができます。

  1. タスクスケジューラの「基本タスクの作成」を選びます
  2. タスクの名前を決めます
  3. トリガーとして「コンピュータの起動時(H)」を選びます
  4. 操作として「プログラムの開始(T)」を選びます
  5. プログラムにはPowerShellのパスであるC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exeを、引数の追加(オプション)には-Command "wsl -d Ubuntu -u root -- service docker startを指定します

これでほぼ完了です。
ただし、Windowsのプロセスの起動順によってはうまく効かない時があったので、作成したタスクのプロパティからトリガーを編集して、「遅延時間を指定する(K)」で「30秒間」を選択してタスクの実行を遅らせると安定します。

この方法は、Dockerエンジンのインストール以外に、Ubuntu側の設定ファイルを書き換えやツールのインストールが不要なので結構気に入っています。

wslコマンドでLinux側のコマンドを実行するオプションとして-eオプションと--オプションの二つがあります。
それぞれの違いについては深く調べられていませんが、-uオプションで指定したユーザーのデフォルトシェルが使われる--を使ってます。

その4 wsl.confのbootオプションを使う

Windows 11から使えるオプションのようなので試せていませんが、Linux側の/etc/wsl.confbootオプションを使うと、ディストリビューション起動時にroot権限で実行するコマンドを指定できるようです。
すなわち、以下のように書いておけば、タスクスケジューラを使わずともデーモンを立ち上げることができます。

/etc/wsl.conf
[boot]
command = service docker start

Microsoft DocsのWSL での詳細設定の構成でも、Dockerデーモンを起動する設定例が記載されているので、まさにDockerデーモンの自動起動を想定した機能なのでしょう。多分。

bootオプションはInsider Previewに参加しているWindows 10でもおそらく使えます。

2021/12/25時点で、Microsoft Docsの日本語が機械翻訳されたもののためにかなり読みづらいので、英語版を読むことをお勧めします。

課題

これまで4つの方法を紹介しましたが、いずれもほんの少しだけ課題がありました。
それは、コンテナのエントリポイントで指定したスクリプト内で、trapコマンドでシグナルを捕捉して終了処理を書いているときです。

ディストリビューションのシャットダウンに伴ってデーモンが正常に停止されれば、終了シグナルが発せらるので終了処理が呼び出されたうえでコンテナが停止します。
しかしながら、WSL2上で動くLinuxのプロセスたちは、PCシャットダウン時にマルっとKillされているような動きをしていました。(間違ってるかもしれません。)
そのため、シグナルが捕捉できないために終了処理が呼ばれないまま、コンテナが停止される状況に陥ります。

これに気づいたきっかけは、Docker でセルフホステッド エージェントを実行するを参考に、Azure PipelinesのセルフホステッドエージェントをDockerコンテナで構築しようと試した時でした。
終了処理が呼ばれないままコンテナが再実行されると、エージェントプログラムが実行できないようになっていました。

Docker Desktopが動いている環境では、Docker Desktopの常駐プロセスがPCシャットダウン時にデーモンを正常停止してくれてるっぽいので、この問題は起きません。

解決案

PCシャットダウン時にwsl -d Ubuntu -u root -- service docker stopを実行する。
調べてみると、グループポリシーを変更すればシャットダウン時に任意のプログラムを実行できるようになるみたいですが、できるだけWindowsの設定を変えずに何とかできないかと考えました。

そこで、タスクスケジューラでPC起動時に以下のようなスクリプトを実行すれば、シャットダウン時にfinallyに入ってくれると考えましたがダメでした。

ダメなパターン
wsl -d Ubuntu -u root -- service docker start
try
{
  while (1)
  {
    Start-Sleep 5
  }
}
finally
{
  wsl -d Ubuntu -u root -- service docker stop
}

その理由はPowershell finally block not executed in windows task schedulerにありました。
タスクスケジューラで実行しているプロセスは、PCシャットダウン時にWindowsによってKillされているためにfinallyで捕捉できないようです。
ただし、タスクスケジューラで実行したプロセスから派生したプロセスはKillされないそうです。
この仕様を使い、このスレッドの回答にある感じで、親プロセスの終了をWaitForExit()待ってからwsl -d Ubuntu -u root -- service docker stopを呼び出す派生プロセスを実行すればうまくいく気がしています。

以下が、タスクスケジューラで起動するスクリプトのイメージですが、私はまだこの方法を試せていないので、真偽は不明です…。
もし結果が分かったら追記します。

wsl -d Ubuntu -u root -- service docker start
# ここでWaitForExit()で親プロセスの終了を待ってwsl -d Ubuntu -u root -- service docker stopを実行するスクリプトを立ち上げる
while (1)
{
  Start-Sleep 5
}

最後に

有償化といっても1人当たり高々数百円ですし、有償化の対象になる法人もお金払って素直にDocker Desktop使ったほうがいい気がしますね。

16
20
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?