docker-composeで建てたjenkinsがお亡くなりになった時の蘇生術

# はじめに
この記事はdocker-composeで建てたjenkins(master)とslaveのうち、片方が突然の死を迎えた際に使った蘇生術の備忘録です。

docker-composeでjenkinsのビルド環境を構築する方法は下記を参考にしています。
参考：https://qiita.com/_ainosh_/items/04992adbab8502e2ed9e

環境情報
Windows 10
Docker Desktop

# Docker Desktopの起動エラー
ある日のこと、jenkinsのURLに接続しても返事がなく、
原因調査のためにjenkinsを立てているサーバーに接続してみたところ、こんなエラーをDocker for Desktopが吐き出していました。

```
stderr: 
   場所 Docker.ApiServices.WSL2.WslShortLivedCommandResult.LogAndThrowIfUnexpectedExitCode(String prefix, ILogger log, Int32 expectedExitCode) 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.ApiServices\WSL2\WslCommand.cs:行 146
   場所 Docker.Engines.WSL2.WSL2Provisioning.<DeployDistroAsync>d__17.MoveNext() 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.Desktop\Engines\WSL2\WSL2Provisioning.cs:行 169
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Docker.Engines.WSL2.WSL2Provisioning.<ProvisionAsync>d__8.MoveNext() 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.Desktop\Engines\WSL2\WSL2Provisioning.cs:行 85
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Docker.Engines.WSL2.LinuxWSL2Engine.<DoStartAsync>d__26.MoveNext() 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.Desktop\Engines\WSL2\LinuxWSL2Engine.cs:行 104
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Docker.ApiServices.StateMachines.TaskExtensions.<WrapAsyncInCancellationException>d__0.MoveNext() 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.ApiServices\StateMachines\TaskExtensions.cs:行 29
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   場所 Docker.ApiServices.StateMachines.StartTransition.<DoRunAsync>d__5.MoveNext() 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.ApiServices\StateMachines\StartTransition.cs:行 67
--- 直前に例外がスローされた場所からのスタック トレースの終わり ---
   場所 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   場所 Docker.ApiServices.StateMachines.StartTransition.<DoRunAsync>d__5.MoveNext() 場所 C:\workspaces\PR-15633\src\github.com\docker\pinata\win\src\Docker.ApiServices\StateMachines\StartTransition.cs:行 92
```

このエラーはDocker Desktopを起動する際に発生しているようで、
調べたところ下記の記事のようにDocker Desktopの設定が原因のようでした。
https://qiita.com/tsubasaogawa/items/7621c99eb3235e4fc908

実際にDocker Desktopの設定を変更した結果、Docker Desktopが起動するようになりました。



# jenkinsの起動不可
Docker Desktopの起動後もjenkinsへの接続ができず、さらに調査したところjenkins用のコンテナ(master)が起動していないことがわかりました。
再度サーバーに接続しmasterの起動を実施すると起動コマンド実行後にひっそりと停止していることがわかりました。
その後も起動時のエラーを調べてみましたが解決には至らず、以下のような理由もありmasterの再構築に取り掛かりました。

- エラーの原因特定が困難
- 長期間停止できない
- 以前から複製することを考えていたのでその検証もかねて


# 事前準備

以前から複製することを考えていた＋もしものときのために以下のバックアップを用意していました。

- イメージのバックアップ
- jenkinsの構成ファイル(configやpluginもろもろ）


# バックアップイメージをコンテナに

できるだけ元の環境と同じようにしたかったのでポートを指定するような下記のコマンドを実行。

```
docker run --name master2 -p 8081:8080 -p 50000:50000 jenkins-bk
起動　名前：master2　ポート：8081　イメージ名：jenkins-bk
```

# jenkinsの構成ファイルの配置

master2の起動を確認した後に、バックアップしていたjenkinsの構成ファイル(jenkins.tar.gz)を再構築したmaster2に配置します。

```
# コンテナへコピー
docker cp jenkins.tar.gz abcdef1234gh:/home/jenkins/jenkins.tar.gz
          対象ファイル　コンテナID:/パス
　(補足)コンテナIDの確認方法
　　docker ps (-a)  起動していないコンテナも含む場合は「-a」

# コンテナに入る
docker exec -it master2 /bin/bash

# コピーしたファイルの解凍
cd /home/jenkins
tar -zxvf jenkins.tar.gz

```

ここまでの実行が正常に完了すると以前までと同様にjenkinsにログインできるようになりました。

# slaveとの接続
jenkinsに接続できるようになりいざジョブを実行してみると、今度はジョブが始まりません。
理由は明確でslaveがオフラインだったからでした。
エラーを確認するとどうやらmasterがslaveを認識できない状態になっていることに起因しているらしく、
再度サーバーに接続し調査を始めました。


## docker network
docker composeで起動したため意識していませんでしたが、
今回masterとslaveが切り離されたことでnetworkが別のものに変わっていました。
masterの作成時に気づいていればそこで対応できたはずですが、すでに起動済みだったため別の方法をとりました。

```
# networkの確認
docker network ls
NETWORK ID     NAME                DRIVER    SCOPE
AAAAA          AAA
BBBBB          BBB
CCCCC          CCC

# それぞれのnetworkの確認
docker network inspect AAA
～～
                "Name": "slave",
                "EndpointID": "～～",
                "MacAddress": "～～",
                "IPv4Address": "～～",
                "IPv6Address": "
～～

docker network inspect BBB
～～
                "Name": "master2",
                "EndpointID": "～～",
                "MacAddress": "～～",
                "IPv4Address": "～～",
                "IPv6Address": "
～～

# master2をslaveのネットワークに接続
docker network connect AAA master2

```


## おわりに
かなり手探りではありましたが、docker-composeで建てた環境の復旧ができる方法を勉強できました。
まだまだ分からないことも多いので勉強したいと思います。