Jupyter+Ansible で実行可能な Notebook 形式のメンテナンス手順書をテンプレートから生成して実行してみた

morikawa

インフラグループの morikawa です。

タイトルが長くてすいません。

今回の話は、以下の記事で Jupyter と Ansible の組み合わせで面白いものが作れるらしい、ということを知ったのとルーチン業務の見直しが必要だったことが重なったのがキッカケでした。

他にもこの件に関連してアツい記事 (参考資料 参照) はいろいろ出ていて面白かったのですが、具体的なコードまで晒して、というのはあまり見当たらなかったので、今回は以下のような事を、実際に動くコード含めて記事にしてみた次第です。

  • Jupyter Notebook (ipynb) 形式の、「実行できる」、「結果を記録に残せる」手順書でメンテナンスを実施

なお、少しややこしいですが、Ansible は今回以下の2つの役割を果たします。混乱が無いようご留意下さいませ。

  • Jupyter Notebook 形式のテンプレート (Jinja2形式) から実際の手順書 (ipynb 形式) を生成
  • メンテナンスにおけるサーバの制御
    • 手順書上はサーバに直接ログインせず、Ansible を介して本番サーバを制御します

この記事を書くにあたりいろいろ考えることもあったのですが、記事がまた長くなるので別の機会にまとめられればと思います。

今回題材にするメンテナンス

  • Apache の ServerLimit (+関連の設定項目) の値を変更します。
    • Apacheの仕様上、reload や restart では設定が反映されず、stop と start が必要になります。
  • ロードバランサで冗長化している前提で、クライアントへの影響を及ぼさずに変更します。

前提とする環境

  • ロードバランサで冗長化された以下2台のウェブサーバがメンテナンス対象 (以降は FQDN ではなく web1, web2 と表記します)。なお、もちろんこのようなサーバは実際にはなく、以下試した環境では /etc/hosts にこのサーバの IP アドレスとして社内開発マシンのものをあてがっています。
    • web1.example.com
    • web2.example.com
  • ウェブサーバに対して、Ansible によりシステム構成が変更可能となっている
  • Ansible が実行できる JupyterLab 環境が利用できる
  • Apache の MPM Prefork はメンテナンス以前は以下の設定となっている
Plain Text
/etc/httpd/conf/httpd.conf

なお、今回記事を作るにあたっては以下の環境で試しました。

  • Ansible 2.9
  • JupyterLab 1.0.2

各種ソースコード

さて、前置きが長くなりましたが、早速関連のコードをざざっと紹介していきます。「実際にどう動かすのか」について先に興味がある方は 使い方 から先にご覧下さい。

Jinja2 + Jupyter Notebook 形式の手順書テンプレート

以下が Jupyter Notebook 形式の手順書を作成するための Jinja2 形式テンプレートになります。

ポイントの一つは、Jinja2 の for 文で、サーバ毎に同様な作業を行う部分をテンプレートでは一箇所で済ませている点です。

実際の手順書では、サーバごとに個々に手順が並ぶことになります。

また、サーバの数や種別は後述の設定ファイル内で記述する形をとっているので、サーバの名称や数が変更になる場合にはテンプレートそのものの編集は不要です。もちろんメンテナンスの内容自体を変更する場合はテンプレートも変更をすることになります。

また作業日も同様に変数化しています。この例ではシンプルにしてますが、作業者や作業時間なども変数化しておくのが良いかもしれませんね。

JSON
maintenance-manual-template.ipynb.j2

テンプレートから本番の手順書を作成するための YAML形式の設定ファイル

上記のテンプレート内の変数を埋める設定になります。Ansible を使って Jinja2 から生成するので、YAML で記載しています。

Plain Text
maintenance-manual-variables.yml

テンプレートから本番の手順書を作成するための Ansible プレイブック

上記のテンプレートと設定 YAML を読み込み、手順書を生成するための YAML プレイブックになります。これら 3 つのファイルと ansible-playbook コマンドを使用して手順書が生成されます。具体的なやり方は後述します。

Plain Text
manual-generator.yml

手順書に記載された ansible-playbook コマンドから参照されるインベントリファイル

メンテナンス作業でも ansible-playbook を利用しますが、その際に使用されるインベントリファイルとなります。

最近、インベントリファイルは YAML で書けることを知り、YAML で書いてみてます。(個人的には階層構造がわかりやすいのでこちらのが好きですね)

vars の中で接続用の変数を定義してます。今回は一通り動くこと、記事にする関係上ファイルの数は少ないほうが良かろうとここに押し込んでます。実際に Ansible でサーバの構成管理をしている状況であれば host_vars 以下など、ホストの情報を管理するファイルは独立して存在してると思いますので、その中に書くことになるのかと思います。

Plain Text
inventory.yml

手順書に記載された ansible-playbook コマンドから参照されるプレイブック

メンテナンス作業の実体がこちらの Ansible プレイブックになります。

Ansible は冪等性を担保するデザインのソフトウェアになっていますので、「このような状態となっていること」といった書き方をする必要があります。「この作業でこのような変更を加える」といった書き方をするメンテナンス手順書とは少々考え方が異なるかもしれません。

作業の単位ごとに、block と tags で括るような書き方にしており、個々に手順を実施できるようにしています。

Plain Text
apache-serverlimit-change-maintenance.yml

使い方

手順書テンプレートから本番テンプレート生成

手順書テンプレートからの実際の手順書の生成には、ansible-playbook コマンドを用います。インベントリファイルは作らず、 “-i localhost" で済ませています。

Shell

これにより、ipynb ファイル (今回は maintenance-manual-template.ipynb という名称のもの) が生成されます。

JupyterLab 上で実行

準備は整ったので、JupyterLab 上で実際にコマンドを実行していくことになります。以下では実行の様子をキャプチャしたものを貼っていきます。

手順書冒頭はこのような感じです。

まず、web1 のサービスアウトから開始します。

次に接続中コネクションについて確認します。接続中コネクションがある場合は以下のようにエラーが表示されます。

コネクションがなくなると以下のようになります。

次に設定の変更と httpd の停止と起動を行います。上記のプレイブックを見てもらうとわかりますが、このタイミングでバックアップファイルがとられ、また設定ファイルの文法チェックも行われます。 (個人的には変更差分を Ansible に表示してほしいんですが、blockinfile モジュールは未対応のようで残念)

今回の作業では ServerLimit を 16 → 32 に引き上げ、併せて
MaxClients 他のパラメータを 10 → 20 に引き上げているため、起動プロセス数が実際に増えていることも確認します。

以上で web1 の作業を完了したのでサービスインします。

これ以降に web2 の手順が続きます。あとの流れは同じなので割愛します。

メンテナンス中にイレギュラーが発生した場合はこの限りではありませんが、基本的な流れはこのような感じかと思います。

今回の手法のメリット

メンテナンスそのものはやはり緊張感を持って実施する必要があり、格段楽になるとかではないですが、以下のメリットはあるかもしれません。

  • コピペ作業が減る
  • コピペミスが起きうる場面も減る
  • 変更対象のファイルのバックアップとかシンタックスチェックとかの定形作業はお任せできる
  • 確認作業の内容も機械的な部分はプログラムに判定させられる

ただし、サービスインしているシステムでは想定外の事象が生じる可能性も少なくありません。そのような場合には Ansible を介さずに実際にサーバにログインして確認せざるを得ない状況もあるでしょう。

ここで良いのは Jupyter を使ってるので記録を残しやすいところでしょうか。ターミナルからのコピペは必要ですが、Jupyter Notebook 形式の手順書は追記が可能で、また Markdown で書けますので、コマンド自体はバッククォート3つで挟んで貼り付ければそのまま等幅フォントで表示されます。説明が必要なら見出しやリストなどを使うとより見やすくできるでしょう。

メンテナンス終了後に ipynb 形式の手順書を保存し、メンテナンス実施の際のAnsibleプレイブック及びインベントリファイルと併せてアーカイブしておけば、そのままメンテナンスの証跡になります。所詮テキストファイルですから GitHub や GitLab を利用している組織であればソースコードと近い形でアーカイブしてしまっても良いかもしれませんね。

やってみて大変そうだなと感じたところ

後半メリットっぽいことを多く書いたので、デメリットも挙げておきます。

  • 事前準備が多い
    • 今回の記事のパターンだと以下これだけのファイルの用意が必要です。通常 (?) のやり方であれば手順書一つあれば良いところ、複雑であることは否めないかと思います。
      • Jinja2 + Jupyter Notebook 形式の手順書テンプレート
      • テンプレートから本番の手順書を作成するための YAML 形式の設定ファイル
      • テンプレートから本番の手順書を作成するための Ansible プレイブック
      • 手順書に記載された ansible-playbook コマンドから参照されるインベントリファイル
      • 手順書に記載された ansible-playbook コマンドから参照されるプレイブック
    • 実際にプレイブックの動作確認をするのに、開発環境などでの動作確認も必要になってくるでしょう。
    • JupyterLab 環境の準備も必要です。メンテナンスのたびに構築、というのはあまり現実的ではないでしょうから、環境の維持のコストもかかりますね。
    • 今回の記事では触れなかったところですが、Ansible プレイブックでリモートサーバの作業を行う場合の認証まわりの準備も必要です。Jupyter Notebook 上でプログラムを実行する際にはパスワード入力のようなインタラクティブな入力ができないため、ssh-agent を用いるなりなんなりして、パスワードやパスフレーズ入力不要にしておくことも必要になります。
  • 学習コストもそれなりに
    • JupyterLab については環境さえあればそれほど学習は要りませんが、 Ansible でメンテナンスを実施するには一定の習熟が必要になるかと思います。

まとめ

ここまでお付き合い頂きありがとうございます。いかがでしたでしょうか。どんな環境でもすぐ導入、という感じではなさそうですが、以下のような条件・環境が整っている運用現場であれば試してみる価値はあるかもしれません。

  • Ansible によるサーバの構成管理がある程度行われている
  • メンテナンスは日々真面目にやっているものの、関連するフローやドキュメントの管理で悶々としている。

今回の記事であまり良くなかったと思っているのは「手順書に記載された ansible-playbook コマンドから参照されるプレイブック」をあたかもメンテナンスのたびに作成する、みたいに見える書き方をしてしまった点です。

Ansible を「サーバ構築自動化ツール」としてサーバ構築初期のみに使っている場面も多いかとは思うのですが、本来は冪等性 (何度実行しても結果が同じ) を担保するツールなので、ツールの思想に則った使い方をするとサーバの構成変更に先行して変更するものであるはずで、サーバの設定を変更するようなメンテナンスの作業エンジンは、実は既存のプレイブックが正にそれにあたるんですよね。要するに上記で「事前準備」として挙げたファイルの最後の 2 つは自ずと事前に揃ってるとも言えます。

今回記事を書くのと合わせて私自身こういったトライアルをしてみましたが、構成管理を Ansible で進めつつ、メンテナンスもこういった形に整理し直すことで、相互作用しあって良いことは色々ありそうだなと感じた次第です。

気がつけばもう年末ですね。みなさまも良い年末年始をお過ごしください。来年が良い年でありますように!

参考資料

morikawa

Posted by morikawa