【CI奮闘記】第7章:Amazon EC2のWindows ServerをJenkinsのエージェントとして利用する!


はじめに

前回のブログでは、エージェントの作成方法について説明しました。
前回のブログはこちら
今回は、Amazon EC2 のWindows ServerをJenkinsのエージェントとして利用する方法を説明します。

登場人物

吉田:転職したてのエンジニア。前職では積極的にCIやCDという事に取り組みながら開発をしていた。

服部:配属1年後の新人。CIやJenkinsについては言葉は聞いたことがある程度。もともと開発で今回初めて環境周りを扱う事になった。

WindowsOSのエージェントにクラウド環境(Amazon EC2)を用いるには

前回設定したエージェントについてだけど、Amazon EC2のインスタンスをエージェントとして利用することも可能なの。

単純にノードをAmazon EC2インスタンスにするという事ではなくてですか?

もちろんそれでもできるんだけど、もうちょっとクラウドっぽく利用したいよね。
ちょっと工夫すると
・利用していない時間は自動でインスタンスを停止
・利用するときだけインスタンスを起動
といったこともできる様になるわ。

コスト削減によさそうですね!ぜひ聞きたいです。

Amazon EC2 Pluginを利用する

JenkinsのAmazon EC2 Pluginを利用することで、インスタンスの自動停止といったことが可能になるの。
プラグインの概要としては
・AMIにラベルを指定する。
・ジョブを実行した際に、対応するラベルが設定されているノードが存在しない場合、プラグインの設定に従ってインスタンスを作成しノードとして利用する。
・一定時間そのノードが利用されない場合、インスタンスを停止(stop)または終了(Terminate)する。
という事ができるわ。

聞く限りとても便利そうですね。

ただ、利用するにあたっての設定に少し癖があるので説明していくわね。

今回利用した環境の情報です。

  • Amazon EC2 Plugin:1.56
  • ベース環境として用いたAMI:Microsoft Windows Server 2019 Base – ami-02642c139a9dfb378

まずAmazon EC2 Pluginをインストールね。
プラグインをインストールすると、「Jenkinsの管理」 > 「ノードの管理」の左側メニューに「Configure Clouds」という項目が出てくるの。
ここから設定ページへ遷移することができるわ。

備考になりますが、以前はAmazon EC2 Pluginページの説明に記載されているように「Jenkinsの管理」 > 「システムの設定」の下に設定メニューがありました。現在は以下のようにリンクに変わっており、遷移先が上記の「Configure Clouds」のページとなります。

今回はAmazon EC2を利用するので「追加」 から「Amazon EC2」を選択ですね。

そう。
設定項目が表示されるわ。入力が必要な項目について説明していくわね。

以下は私が実施した際の設定となります。
それ以外の追加設定が必要な場合は適宜入力をお願いします。

Amazon EC2の設定

Nameノードの名称に利用。「Agent EC2 (【この項目の入力値】) – 【AmiのDescription項目の入力値】(インスタンスID)」というノード名称になる。
Amazon EC2 Credentials種類には「AWS Credentials」を利用する。
入力値としてAccess Key ID及び、Seacret Access Keyが必要。
RegionAmazon EC2 Credentialsを入力すると選択できるようになる。
EC2 Key Pair’s Private Key種類には「SSHユーザー名と秘密鍵」を利用する。
キーペアが必要。

ここまで入力してから「Test Connection」をクリックすると接続確認ができるの。
接続関連の入力が完了したら利用するAMIの設定値を入力していくわ。

設定が正常にできているとSuccessと表示されます。

AMIの設定

Descriptionノードの名称に利用。「Agent EC2 (【上記Nameの入力値】) – 【この項目の入力値】(インスタンスID)」というノード名称になる。
AMI ID利用するAMIのID。
入力後、「CheckAMIをクリックすることで存在確認が可能」
表示されない場合、Regionが異なる場合があるので注意。
AMI OwnersAMIのオーナーを入力する。
Instance Type作成時に希望するインスタンスタイプを選択する。
Availability ZoneJenkinsコントローラーが存在するAvailability Zoneを入力する。
Security group namesセキュリティグループ名を入力。複数入力したい場合は,で区切る。
Remote FS root通常のノードと同じ。ここで指定したフォルダがagent.jarを配置するフォルダとなる。
Remote user「Administrator」等接続できるユーザー名を入力する。
AMI Typewindowsを選択する。
Specify Password上記「Remote user」に対応するパスワードを入力する。
Use HTTPSチェックを外す。
Labelsノードに設定するラベルを入力する。通常のノードのラベルと同じ扱いであり、複数指定したい場合は,で区切る。ジョブからここに入力したラベルが呼び出された場合、実行するノードやインスタンスが起動していなければ新規でインスタンスを起動しそのノードでジョブを実行する。
Idle termination timeエージェントが停止または終了する前にアイドル状態を維持できる時間を決定する。単位は分。

高度な設定を開く

Tagsインスタンス作成時に利用するタグを入力しておくと、インスタンス作成時に設定してくれる。
Instance Capここに値を設定しておくと意図せずインスタンスが大量に作成されるという事が無くなるので、制限したい場合は数値の入力を推奨。
Minimum number of instances例えばこれを1に指定すると、Idle termination timeに入力した時間を過ぎた場合でも、同一のラベルを持つインスタンスは1個以上常時起動するようになる。
Stop/Disconnect on Idle Timeoutこの項目にチェックを入れると利用されていなタイミングで停止(Stop)になる。そうでない場合は終了(Terminate)する。

それ以外は変更無しで利用が可能になります。以下のようにConnection Strategyの項目でエラーが表示されていますが利用可能です。

設定項目多いですね。
確かにクセがありそうです。

設定はこれだけじゃないの。
ここまで設定が完了したら「Labels」に入力したエージェントがJenkinsのジョブで指定されるとノードとしてインスタンスが自動で作成されるんだけど、うまい事接続ができないのね。

ノードのログ。インスタンスが起動しても接続ができない。

こんな風に
Waiting for WinRM to come up. Sleeping 10s.
というのが無限ループで表示されるわ。

インスタンスは起動するけど接続ができないんですね。

この問題を解決するためにエージェント側のインスタンス側に次の設定をしてあげる必要があるわ。

インスタンスのセキュリティグループ設定

以下2つのポートについて、Jenkinsコントローラーのインスタンスからの接続を許可する必要があります。

WinRM-HTTP5985
SMB445

WinRMの起動確認

Windows Server 2012 以降ならデフォルトで有効になっていますが、起動していないと接続ができないので確認をしてください。デフォルトではポート 5985を利用しています。

Windowsのサービスから確認が可能です。

外部から接続できるように許可

以下の設定をpowershellを用いて実施してください。

PS C:\> winrm set winrm/config/client/auth '@{Basic="true"}'
PS C:\> winrm set winrm/config/service/auth '@{Basic="true"}'
PS C:\> winrm set winrm/config/service '@{AllowUnencrypted="true"}'
PS C:\> powershell Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine
PS C:\> restart-service winrm
PS C:\> netsh advfirewall Firewall add rule name = "WinRM-HTTP" dir = in localport = 5985 protocol = TCP action = allow
PS C:\> netsh advfirewall firewall add rule name="SMB-HTTP" dir=in localport=445 protocol=TCP action=allow

備考
接続自体はWinRMを用いて接続していると思われるのですが、コードの以下のあたりから判断するに、WinRMの5985ポートだけでなく、445からも接続ができる必要がある模様です。

public boolean ping() {

socket.connect(new InetSocketAddress(host, 445), TIMEOUT);

https://github.com/jenkinsci/ec2-plugin/blob/0278dd242a554ff200144b813122505f6d8dcd0e/src/main/java/hudson/plugins/ec2/win/WinConnection.java

私が環境構築した際は、445も許可をしないとJenkinsコントローラーインスタンス→エージェントインスタンス間のWinRMでの疎通ができても、エージェントとしての利用ができませんでした。

このようにPowerShellを利用して接続はできたとしても、Jenkinsからノードとして接続した場合「Waiting for WinRM to come up. Sleeping 10s.」の無限ループは解消されません。

これでエージェントとして利用ができる様になるわ。
あと、Amazon EC2 PluginのAMIの設定をすると、「ノードの管理」に「Provision via connectiontest」のボタンが表示されて、ここでノードして設定したインスタンスとの疎通テストもできるわ。

なるほど。いきなりAmazon EC2 Pluginを利用するのではなく、事前準備をしっかりする必要があるんですね。

そうね。今回説明した流れで利用するとスムーズね。

1. エージェント用のインスタンスを起動する
2. ビルドツールといったエージェントマシンとして必要なツールの設定をする
3. 上記「WinRMの起動確認」
4. 上記「外部から接続できるように許可」
5. AMI IDを取得する
6. Amazon EC2 Pluginを利用する

まとめ

一度設定してしまえばインスタンスが必要に応じて起動するようになります。Amzon EC2を利用してエージェントを構築する場合、Amazon EC2 Pluginは有益なプラグインです。

その一方で、設定が大変であったり、接続がうまくいかなかったりする場面が多々あります。「外部から接続できるように許可する」以外にも、プラグインのバージョンによって「Linuxマシンは接続できるが、Windowsマシンは接続できない」といった場合もある様です。
バージョン1.49.1で発生しており、2020-09-25と比較的最近に解決されています。
https://issues.jenkins.io/browse/JENKINS-61006

接続テストはある程度の時間的余裕があるタイミングで実施されると良いと思います。

補足1

設定の際の注意です。
エージェント側のインスタンスマシンについてWinRMの接続設定等を行わず、正常にノードと接続ができない状態で下記の設定をした場合は注意が必要です。

  • Minimum number of instancesに数値を入力する。
  • Instance Capの設定をしない。
  • Launch Timeout in secondsに数値を入力する。

このような設定にしジョブを実行した場合、
インスタンスを作成→接続できない→タイムアウト→入力値以上インスタンスが存在しない→インスタンスを作成→・・・
とジョブを停止しない限り無限にインスタンスを作成し続けます。

その場合は慌てずジョブを停止し、不要に作成されてしまったインスタンスを削除して下さい。

補足2

今回紹介したAmazon EC2プラグインの特徴として、現在起動中のインスタンスを利用するという事はできず、プラグインを介して起動したインスタンスのみをノードとして利用することができます。
そのため、エージェントとして利用するツールのライセンスに制約がある場合、相性は良くないです。
ライセンスの制約上特定のインスタンスでしか利用したくないという場合は、

  • 「Stop/Disconnect on Idle Timeout」の項目にチェックを入れAmazon EC2プラグイン経由でインスタンスを起動する。これでTerminateがされなくなります。
  • 「Instance Cap」を1にし、複数起動しないように設定する。
  • 起動したインスタンスにツールをインストールし、ライセンスの認証を行う。

といった手順を踏めば、利用していないときは停止し、利用するときのみ起動するという事は可能かと思います。
ただ、慣れないプラグインの場合何かあったときのリカバリーが難しい事もあるかと思いますので、まずはライセンスに問題ないツールを利用するときのみこのプラグインの利用を検討したほうが良いかと思います。

CI奮闘記一覧