0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

DockerDesktopアプリケーションをシェルスクリプトからいい感じに起動させる

Last updated at Posted at 2024-07-06

Introduction

Docker Desktopが起動してなかったら起動させたいし、リソースセーバーが動いてたら再起動をシェルスクリプトでやりたい!をやったというお話です。

さて、大学の講義で演習に使用しているプログラムがあります。
Docker Desktopが起動している前提で動くものなのですが、学生から「なんか実行できないんですが…」と言われて確認すると…
「Docker、起動してないやんけ…!!!」
となることが多いTA(教育補助の学生)さんです。こんにちは。
そんなのにいちいち対応するのはとっても面倒大変なので、コンテナ起動を仲介してる.command(中身はbashスクリプト)からよしなにDockerくんを起動させてしまおう!というのが今回の趣旨です。

想定する環境

  • Mac系のPC
  • Docker Desktop導入済み
  • AppleScriptが使える(正確にはosascript)

結論

Docker_autorun.command
# 現在実行されているアプリケーション名を取得
RUN=`osascript -e 'tell application "System Events" to get name of (processes where background only is false)' | grep -c 'Docker Desktop'`

# Docker Desktopがアプリケーションとして起動してないと認識されている場合
if [ ${RUN} = 0 ]; then
    echo "Docker Desktop is not Started."

    # Dockerがリソースセーバーモードで起動している場合
    DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
    if [ ${DOCER_PROCESS_COUNT} -gt 0 ]; then
        echo "Docker kernel is run Resource Saver Mode... "
        pkill -KILL -f Docker
        pkill -KILL -f docker
        echo "Docker application killed."
    fi

    open -g -a /Applications/Docker.app

    # 全てのプロセスの起動を待つ
    DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
    until [ ${DOCER_PROCESS_COUNT} -gt 6 ]
    do
        sleep 1
        echo "Preparing to launch Docker Desktop ..."
        DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
    done
    # UI起動後の読み込み待ち
    sleep 5
    
    echo "Docker Desktop is running..."

# Docker Desktopがアプリケーションとして起動していると認識されている場合
else
    echo "Docker Desktop is running..."
    
fi

全体の挙動

  • Docker Desktopがアクティブに起動していれば、「Docker Desktop is running...」と出力して終了
  • Resource Saver Modeで起動していれば、一旦全部のプロセスをkillして再起動
  • 起動していなければ、起動
  • 全部のプロセスが起動して、UIのコンテナ情報読み込みが終了するまで待機した後、「Docker Desktop is running...」と出力して終了

全体はこんな感じです。

詳細と解説

実行されているアプリケーション名の取得

RUN=`osascript -e 'tell application "System Events" to get name of (processes where background only is false)' | grep -c 'Docker Desktop'`

起動していたら1、していなかったら0がRUNに格納されます。

どうにかして取れないかな〜〜〜と思っていた時にこちらのstackoverflowを見つけて実行したら取れました。

osascriptとは?
AppleScriptをターミナルで実行できるコマンドです。
今回はその後ろの方にあるシングルクオート内がAppleScriptです。

後ろの方のgrep -c 'Docker Desktop'は得られた結果をパイプで渡して、一致した個数とってくるようにしているものです。

Resource Saver Modeで起動している時はプロセスをkill

DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
if [ ${DOCER_PROCESS_COUNT} -gt 0 ]; then
    echo "Docker kernel is run Resource Saver Mode... "
    pkill -KILL -f Docker
    pkill -KILL -f docker
    echo "Docker application killed."
fi

Resource Saver Modeとは

メニューバーのDockerアイコン
↑これに見覚えがある人、この状態がResource Saver Modeです。

It significantly reduces Docker Desktop's CPU and memory utilization on the host by 2 GBs or more, by automatically stopping the Docker Desktop Linux VM when no containers are running for a period of time.

つまり、一定時間アクティブなコンテナがなければ自動的にCPUとメモリの使用を制限してくれるというモード。

このモードの最中は、コンテナの起動、終了とかの操作、特にdocker composeは何があったの?と思うくらい遅くなります。

killする必要あるの?

実はリソース管理面ではかなりありがたい機能なんですが、講義で使うようなパターンだといくつか落とし穴があります。

  • 下手すると1週間起動しっぱなしの学生がいる
    →次週の講義までに他のアプリケーションによって設定変更とかあるとDockerくんが修繕要求出してくる
  • 何かしらのエラーが出ても正常だと思い込んで使おうとする
    →明らかに止まってて実行できてないのに「ここのコードがうまく動かなくて」と言われて発覚が遅れる
  • たまに/Application/DockerDesktop 2.appなる複製体がいる
    →うまく動かないと入れ直ししようとするんだが、その時に前のものを消さずに.dmgからコピーする信じられない挙動をする
  • 実行に時間がかかるとそれだけでターミナル自体を落としてしまうことがある
    →そのまま待ってればできるはずなのに待ってあげないので「なんか起動しなくて…」と言われる(時間の無駄)

知らないって、怖いですよね…。
これらの事象を起こさないようにするためには、そもそもResource Saver Modeを切ればいいわけです。

環境構築もままならない子がいるのに???意味わからんとこ弄られたら困るが???
ということで、こっちでプロセスをkillします。恐ろしいことにそっちの方が安全だからです。

そんなことない人はこっちの手順の方がいいです。
Docker for Mac/Windowsが妙に遅い時はResource Saverをオフに

DOCER_PROCESS_COUNT

ps aux | grep docker | grep -v grep | wc -l

これは「CPUとか割り当てられて現在実行中のプロセスから(ps aux)、dockerとプロセスに入ってるものを抽出して(grep docker)、その中から抽出に使用してるgrepプロセスを抜いて(grep -v grep)、改行の数を数える(wc -l)」という処理です。
つまりコマンドとしては「Dockerの現在実行中のプロセスの数を数える」というものになります。

プロセスと前述のアプリケーション起動確認のコマンドの状況だけを見れば、Resource Saver Modeは「アプリケーションとしてDockerは起動してないと認識されてるけど、プロセスはある」状況です。
なのでプロセスの個数が0以上であれば、Resource Saver Modeとなります。

後述のcom.docker.virtualizationプロセスを検知するという手段も考えたんですが、「kernelのプロセスがない」を判定するよりも、プロセスの個数のみを見た方が簡単でミスりにくいです。
プロセスが本当に何も起動していない時はもちろんcom.docker.virtualizationプロセスがなく、「Dockerのプロセスはあるがkernelがない」は直接的で分かりやすいですが、条件式としては複雑になります。
プロセスを強制的にkillするので、無意味に叩くのはちょっと…

bashでのif文については【シェルスクリプトBash】 if 文(test文)のオプションまとめを参考にしました。

プロセスのkill

pkill -KILL -f Docker
pkill -KILL -f docker

pkillは名前を指定してプロセスをkillするコマンドです。
こちらを参考にしました。

Docker Desktopのもつ基本プロセスは以下のもの。

  • com.docker.build
  • com.docker.dev-envs -watchdog
  • /Applications/Docker.app/Contents/MacOS/com.docker.backend
  • /Applications/Docker.app/Contents/MacOS/com.docker.backend run
  • /Applications/Docker.app/Contents/MacOS/Docker
    • UIの表示に使われてるものっぽい
    • メニューバーとウィンドウとか起動してるUIの分ある
  • /Applications/Docker.app/Contents/MacOS/com.docker.virtualization
    • Docker Desktop Linux VMのカーネルと思われるもの

ps aux | grep docker | grep -v grepで確認できます。

これらのうち、/Applications/Docker.app/Contents/MacOS/com.docker.virtualization以外がResource Saver Modeの時に存在する可能性のあるプロセスです。
わざわざDockerとdockerでやっているのはプロセス名が異なるから。
先にUIをkillしてから本体のプロセスをkillしています。

アプリケーションの起動

open -g -a /Applications/Docker.app

こちらの記事を参考にしました。

全プロセスの起動を待機する

DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
until [ ${DOCER_PROCESS_COUNT} -gt 6 ]
do
    sleep 1
    echo "Preparing to launch Docker Desktop ..."
    DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
done

プロセス数の再計算

DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`

「Resource Saver Modeで起動している時はプロセスをkill」の項目で書いた通り。

プロセス数が6より多くなるまで待機する

再掲になるがDocker Desktopのもつ基本プロセスは以下。

  • com.docker.build
  • com.docker.dev-envs -watchdog
  • /Applications/Docker.app/Contents/MacOS/com.docker.backend
  • /Applications/Docker.app/Contents/MacOS/com.docker.backend run
  • /Applications/Docker.app/Contents/MacOS/Docker
    • UIの表示に使われてるものっぽい
    • メニューバーとウィンドウとか起動してるUIの分ある
  • /Applications/Docker.app/Contents/MacOS/com.docker.virtualization
    • Docker Desktop Linux VMのカーネルと思われるもの

ちゃんと全部が起動できれば上4つとメニューバー、メインとなるウィンドウ、カーネルで7つのプロセスが起動するはずです。
それらが全部起動するまで1秒待機して、プロセス数を更新し続けます。

bashの繰り返しについてはとほほのBash入門を参考にしました

UI起動後の読み込み待ち

sleep 5

Docker Desktopはメインとなるウィンドウが起動した後、ローディングがあってからコンテナ一覧とかが表示されると思います。
読み込み中とか処理中に、こっちから割り込みすると予期せぬ挙動をすることがあるので5秒(適当に指定した)待機するようにしています。

PC本体の処理状況やスペックによっては5秒では短いかもしれない。

全体像(再掲)

ということで、以上のことをやっているのがDockerDesktop.appをいい感じで自動起動させる処理です。

Docker_autorun.command
# 現在実行されているアプリケーション名を取得
RUN=`osascript -e 'tell application "System Events" to get name of (processes where background only is false)' | grep -c 'Docker Desktop'`

# Docker Desktopがアプリケーションとして起動してないと認識されている場合
if [ ${RUN} = 0 ]; then
    echo "Docker Desktop is not Started."

    # Dockerがリソースセーバーモードで起動している場合
    DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
    if [ ${DOCER_PROCESS_COUNT} -gt 0 ]; then
        echo "Docker kernel is run Resource Saver Mode... "
        pkill -KILL -f Docker
        pkill -KILL -f docker
        echo "Docker application killed."
    fi

    open -g -a /Applications/Docker.app

    # 全てのプロセスの起動を待つ
    DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
    until [ ${DOCER_PROCESS_COUNT} -gt 6 ]
    do
        sleep 1
        echo "Preparing to launch Docker Desktop ..."
        DOCER_PROCESS_COUNT=`ps aux | grep docker | grep -v grep | wc -l`
    done
    # UI起動後の読み込み待ち
    sleep 5
    
    echo "Docker Desktop is running..."

# Docker Desktopがアプリケーションとして起動していると認識されている場合
else
    echo "Docker Desktop is running..."
    
fi

無駄処理あるかも〜と思いつつ、一旦できていそうなのでこれで。
issueにこれ入れたの誰だ(私だな…)と思いつつの開発でしたができてよかった〜!

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?