運用中のサービスに与える影響を最小限に抑えつつ、EC2-Classic上のRDSをVPC上に移行する

たまチームで開発しているWebサービスの大半は AWS EC2-Classic 上で動いているのだが、去年から標準でサポートされるようになった VPC (Virtual Private Cloud) に移行しないといろいろと不便なことが多くなってきた。というわけで、移行にあたって一番厄介だと思われる RDS の移行手順を以下にまとめた。

ちなみにこの手順は、EC2-Classic から VPC への移行だけでなく、VPC から VPC の移行にも適用出来るはず。

rds-migration1

大まかな流れとしては、

  1. リードレプリカ経由でClassic側のdumpを取り
  2. それをVPC側で復元
  3. 復元したデータベースをClassic側のslaveとして動かしてデータを同期
  4. 読み込み専用のアプリはここでVPC側に移行して動作確認
  5. VPC側をmasterに昇格した後(ここで一瞬だけ Read Only になる)
  6. 書き込みのあるアプリケーションもVPC側に切り替えて
  7. Classic側を潰せば

めでたく移行は完了する。

1. リードレプリカ経由でClassic側のdumpを取る

rds-migration2

まずはClassic側で移行用のdumpを取得する。リードレプリカを作ってすぐにリプリケーションを停止し、そのときのdumpとバイナリログの位置を取得しておく。リードレプリカ経由なので、この間、サービスの運用には一切影響を与えない。

バイナリログの保持期間を変更する

デフォルトのバイナリログの保持期間が短いので、VPC-slaveを作る間にログが消失してしまわないよう、Classic-masterで以下のように変更しておく。

CALL mysql.rds_set_configuration('binlog retention hours', 24);

現在の設定を確認する:

CALL mysql.rds_show_configuration;

レプリケーション用のユーザーを作る

Classic-masterでレプリケーション用のユーザーを作っておく。

GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'repl_user' IDENTIFIED BY 'some-password';

Classic-masterのリードレプリカを作る

AWS管理コンソールで Classic-master となるRDSインスタンスを選び、”Instance Actions” から “Create Read Replica” を選択する。

レプリケーションをストップする

Classic-slave(今作ったレプリカ)のレプリケーションをストップする。

CALL mysql.rds_stop_replication;

バイナリログの位置を記録する

Classic-slaveで、レプリケーションの状態をメモる(どの位置からレプリケーションを再開すれば良いか)。

show slave statusG
...
    Master_Log_File: mysql-bin-changelog.050354
Read_Master_Log_Pos: 422
...
   Slave_IO_Running: No
  Slave_SQL_Running: No
...

Slave_IO_RunningSlave_SQL_RunningNoになっているので、ちゃんとレプリケーションが止まっていることが分かる。

Classic-slaveのdumpを取る

  • Classic-slaveのエンドポイントを classic-slave.rds.amazonaws.com、管理ユーザーを dbuser とする。
mysqldump -u dbuser -h classic-slave.rds.amazonaws.com --single-transaction --compress --order-by-primary --max_allowed_packet=1G -p --databases database1 databases2  > classic-slave.dump

2. VPCにClassic-masterのレプリカを作る

rds-migration3

VPC内に立てたRDSインスタンスに、Classic-slaveのdumpをインポートしてClassic-masterへのレプリケーションを再開させる(VPC-slave)。

VPC-slaveとなるRDSインスタンスを立ち上げる

AWS管理コンソールでサクッと立ち上げる。

VPC-slaveにClassic-slaveのdumpをインポート

  • VPC-slaveのエンドポイントを vpc.rds.amazonaws.com、管理ユーザーを dbuser とする。
mysql -u dbuser -h vpc.rds.amazonaws.com -p --default-character-set=utf8 < classic-slave.dump

Classic-masterのセキュリティグループ設定を変更する

レプリケーションを可能にするために、VPC-slave から Classic-master にアクセス出来るようにセキュリティグループ(DB Security Groups)を設定する。

以下のような感じで VPC-slave のIPを調べて、そのIPからのアクセスを許可する:

$ ping vpc.rds.amazonaws.com

以下を Classic-master のセキュリティグループに追加。

CIDR/IP to Authorize:  xxx.xxx.xxx.xxx/32

レプリケーションをスタートさせる

VPC-slave にログインして、レプリケーションをスタートさせる(さっき作った専用ユーザーがここで活躍)。
パラメータは先ほどメモしたレプリケーションの状態を参考に。

CALL mysql.rds_set_external_master('classic-master.rds.amazonaws.com',3306,'repl_user','some-password','mysql-bin-changelog.050354',422,0);
CALL mysql.rds_start_replication;

レプリケーションの状態を確認:

show slave statusG

以下のような項目があれば、正しくレプリケーションが動作している。

...
 Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

レプリケーションがうまく行ったら、Classic-slaveは用無しなので削除する。
この段階で読み込み専用のアプリはVPC内に移行出来る。

3. VPC-slaveをmasterに昇格する

rds-migration4

Classic-masterをReadOnlyにする

FLUSH TABLES WITH READ LOCK;

Closes all open tables and locks all tables for all databases with a global read lock. This is a very convenient way to get backups if you have a file system such as Veritas or ZFS that can take snapshots in time. Use UNLOCK TABLES to release the lock.

として、全てのテーブルをロックしてから切り替えたいところなのだが、RDSではこの命令を実行するための権限がないことが判明。

簡単な代替策もないようなので、とりあえず編集を行う可能性があるサービスを全て「メンテナンス中」として操作出来ないようにした。

VPC-slaveのレプリケーションを停止する

CALL mysql.rds_stop_replication;
CALL mysql.rds_reset_external_master;

以後、こちらを master として扱う。

アプリケーションをVPC内に移動する

VPC内にアプリケーションサーバーを立てて、そちらを指すようにDNSの設定を書き換える。

後は古いClassic環境を潰して移行は完了。

ドキュメンテーションを成功させるには

ドキュメンテーションをうまく機能させるのは本当に難しい。

たまチームの開発は、同じフロアにいるマーケティングチームからの要求に従って行われている。ミーティングなどで要件のヒアリングを行い、それを簡単なタスクの箇条書きに落とし込む。PDCAサイクルを一週間(場合によっては二週間)ごとに行うイテレーション開発を採用しているので、全ての要件を一度に明らかにせず、次のイテレーションのタスクが埋まる程度にヒアリングを行う。ミーティングではイテレーションの成果を踏まえて次の要件やタスクを考えるので、想定外の事象が発生しても早い段階で軌道修正を行える(ここに落とし穴があったのだが、これはまた後日)。

いわゆるアジャイル的な開発である。進捗は可視化されていて、軌道修正もしやすく、見当違いなものを作ってしまうリスクも抑えられるので、なかなか効果的な開発方法に思えるが一つ大きな問題があった。それは、きちんとしたドキュメントを残すタイミングがなく、ほとんど全てが現物主義になってしまうことだ。

そもそもアジャイルという手法に現物主義の傾向があるとも言える。動くソフトウェアとクリーンなコードが何よりも現状を雄弁に語るという考え方だ。

しかし、それはある程度小規模な開発であれば当てはまるかもしれないが、一年以上に渡って開発し続ける複雑なシステムではなかなか難しい状況になる。たとえ動くソフトウェアがあったとしても全貌を把握することは難しくなるし、全てのコードをクリーンに保つことも現実的には難しい。

ある日、こういうことがあった。開発がスタートしてから一年半が経過し、システムの機能も大分増えてきた頃だ。

マーケティング担当者「そう言えば、この機能って XXX のような仕様だったと思うんですけど。」

開発者「え、そうでしたっけ。私は YYY と聞いたように記憶してるんですが。」

マーケティング担当者「うーん、それは困るな。お客さんになんと説明すればよいのか。。。」

もの凄くありがちな光景である。イテレーションごとに現物を確認していても、同じ機能を何度も修正している間に、マーケティング担当者の想定と現物がズレてきてしまったのだ。

その後もシステムはどんどん複雑化することが予想されたので、たまチームとしても何か対策を打たざるを得なくなった。仕様書を書こうということになったのだが、常に変化し続けるシステムの仕様書を維持管理することの難しさは重々承知している。そこで、どのようにドキュメントを管理したよいかを入念に検討して以下の指針を作った。

  • 分かりやすさ: XXXを知らない人でもシステムの目的・機能要件が理解できること
  • 網羅性: 要件が一通りカバーできていること
  • 探しやすさ: 必要な情報をすぐに見つけられること
  • ステータス管理: 要件ごとに「実装待ち」「実装済み」「検証済み」のようなステータスを管理すること
  • 変更容易性: 文書の内容が常にup-to-dateになるように、変更のコストを最小化すること
  • テスト仕様書: この文書を見ながらシステムを操作して要件をテストできること

今回のお題である「Lean Documentation」に書かれている指針と大体同じである。Lean Documentationで紹介されている「良いドキュメンテーションのためのルール」は以下の通り:

  • 素早く書けて更新出来るようにする。現状を反映してない情報は、まったく情報が存在しないことより有害である。
  • 簡単に正しい回答を得られること。必要な情報が見つけづらければ誰もそれを利用しなくなる。
  • ドキュメンテーションが対話を置き換えるわけではない。「プロセスやツールよりも、個人や対話に重きを置くべきである(Manifesto for Agile Software Development より)」。

変更容易性はかなり重要な要件で、これを考えるとWordやExcelなどで仕様書を管理することの問題がよく分かると思う。プロジェクトメンバー全員で情報を共有しつつ、かつ変更も容易に行えるとなると、データベース的な仕組みがどうしても必要になる。

昨今の開発プロジェクトだとWikiで仕様を管理することも多いのではないかと思う。しかしWikiでも、まだ変更容易性に若干の不満があり、ステータス管理やフィードバックなどの扱いに難がある。そこで、たまチームではチケットシステム(具体的には GitHub の Issues)を試してみることにした。

仕様を独立した小さな単位に分割してチケットとして管理すれば、その単位でステータスを管理したり、フィードバックをチケットのコメントとして行えるようになる。変更についても、そのチケット自体を修正したり、破棄したり、また新しく作ったりと、より柔軟に行える。どのような機能が修正されたかも把握しやすい。

全体の構成について、Lean Documentation では「Structure it like Google Earth(グーグルアースのように構造化せよ)」というプラクティスが紹介されている。全体像から詳細に向かって徐々にズームインしていく仕組みがあれば、情報が格段に見つけやすくなるというわけだ。たまチームでは、細かい単位であるチケットだけだと全体像が見えないので、Wikiページに概要とチケットへのインデックスを作った。

「さて、これで完璧なドキュメントが出来上がったぞ(ドヤァ)」

数ヶ月後、苦労して作ったドキュメントは誰にも読まれなくなっていた。読まれないので更新もされない。ドキュメントは徐々に現実からズレていく。

つまり、大失敗である。

原因は一体何だったのだろうか? Lean Documentation にあるように、ドキュメントがマーケティング担当者のニーズに沿った構成や内容になっていなかったのだろうか(「Practice 1 – ドキュメントの利用者とその目的を特定せよ」)?

マーケティング担当者曰く「GitHubを見ることが習慣化していないというのと、同じフロアにいるので、つい直接尋ねてしまう。」

ドキュメンテーションを成功させるために、最も重要でかつ最低限必要なことは「(継続的に)読まれること」である。

このことは文書そのものをどう書くかということよりも遥かに重要である。文書が適切に書かれるから読まれるのではなくて、読まれるから適切な形に変わっていく。読まれなければその文書は死んだも同然である。

ドキュメンテーションというのは固定化されたものではない。コミュニケーションの記録である。口頭の対話は記録されないが、ドキュメンテーションという対話は記録され、かつ構造化される。かなり効率は落ちるが、その記録が残ることの価値はかなり大きい。

ここで重要なのは、「読まれること」は「読ませること」ではないということだ。「GitHubを見ることが習慣化していない」という人に対して「じゃあ、習慣化して下さい」と言うのは間違っている。ドキュメンテーションを行うものは、その文書を読んでもらうためのあらゆる努力をしなければならない。それには、Web上にブログを開設して読者を集めることと同様の難しさがある。

仕様を表現するための一手法である「Specification by Example」も、手法としては素晴らしいと思う。Living document のコンセプトも良いし、Given-When-Then 形式の Acceptance Test Scenario(あるいは、Acceptance Criteria)も分かりやすく書きやすい。実際に、たまチームの一つのプロジェクトでは英語話者と日本語話者が効率的にコミュニケーションするためにこのフォーマットを採用している。しかしこれでも「読まれること」とは、全く別次元の話なのだ。

ビジネスパーソンとエンジニアは、そもそも異なる言語で会話をしている。アジャイルコミュニティではドキュメントの限界を理解しつつも、テストプログラムに通じる形式的な文書を、いかにビジネスパーソンに読ませる(書かせる)かということに苦心してきた。しかしこの試みも Fit の失敗 に代表されるように、うまく行っているとは言えないように見える。ビジネスパーソンとエンジニア、両者の想定があまりに違うのである。

書いたものを読んでもらうというのは、人を動かすということである。Stackoverflow の共同創業者で、Joel on Software で有名な Joel Spolsky 氏は、編著「The Best Software Writing I」の中で「ストーリー」の重要性を説いている(「”Show, don’t tell” rule」)。いくら内容が正しくとも、ストーリーなき文章を長々と読めるわけがないというわけだ。

ストーリーなんて仕様書のような形式的な文書とは関係がないと思うだろうか? アジャイル開発で要件の単位となる「ユーザーストーリー」は、形式的表現に慣れているエンジニアからビジネスパーソンに歩み寄った結果として生み出されたものだ。ドキュメンテーションとはコミュニケーションであり、その質にはコミュニケーション能力がそのまま反映される。だからこそプログラミングそのものよりも難しいと言っても過言ではないように思える。

Microservicesアーキテクチャの思想性

Microservices and the Goal of Software Development:
http://www.infoq.com/news/2015/03/microservices-software

  • ソフトウェア開発の目的は business impact を生み出すこと
    • Business impactとは、組織内で観測可能な効果のこと(新規顧客やオペレーションコストの削減など)
    • Lead time(機会の発見からその解答を生み出すまでの時間)を最小限にすること
    • これを持続的に行うのが難しい
  • 三種類のコード
    1. 最近書いて理解しているコード
    2. よくテストされ、文書化されているコード
    3. 誰も知らないコード(不明瞭な依存関係、変更の影響範囲が局所化されない)
  • ソフトウェア開発最大の問題は、大部分のコードが 3 に分類されるということ
  • コードはきちんと運用出来るものだけを維持するようにするべき(3のコードを排除すべき)
  • North氏の提案する二つのパターン
    1. コードの目的(意図)を明確にすること
      • ソフトウェアの半減期は短い(「半減期」とは放射性崩壊の速さを示す物理学用語)
      • なので、それぞれのコードの目的を明確にして安定化に努めるべし
    2. 理解しやすいようにコードを分割統治すること
  • 上の二つのパターンを実現するために有効なのが「置換可能なコンポーネントによるアーキテクチャ (replaceable component architecture) 」
    • APIによって意図が明確にされたコンポーネント
    • コンポーネントは Alan Kay の発明したオブジェクト指向のオブジェクトのごとく、メッセージのやり取りをする小さなコンピュータのようなもの
  • Microservicesは、置換可能なコンポーネントによるアーキテクチャになり得る
    • 置換可能性と一貫性を追求すること
    • コンポーネントの「小ささ」よりも「置換可能性」の方が重要

現場のエンジニアがMicroservicesアーキテクチャを評価するときは、どうしてもその実用性や現実性、例えばプロセス間通信の多用によるオーバーヘッドなどが問題にされがちである。しかし、そのコンセプトをつぶさに見ていくと、これは単にアーキテクチャだけの問題ではなく、ソフトウェア開発はどうあるべきかという、ある種の思想を提示していることに気がつく。

開発の現場には「エンジニアとは外から持ち込まれた問題に解を与える者だ」という強い思い込みがあることが多い。しかし、これはプログラミングに対する誤解を含んでいるだけでなく、一つのシステムを長く育てるというケースにおいては、持続可能なモデルではない。

Martin Fowler氏が「The New Methodology」の中で「ソフトウエア開発は、全てが「デザイン」である」と指摘したのはもう大分昔のことだが、この考え方が開発の現場においてどれだけ浸透しているだろうか。

ソフトウエア開発は、本質的に、問題に対する解法の実装だけでなく、問題自体の検証と再設定を含むサイクルを繰り返す作業で、プログラミングというのはそのための強力な武器である。既に設定された問題を解決するためだけにプログラミングが存在し、そしてその問題設定を開発から切り離せると考えるのは、ソフトウエア開発に対する大きな誤解である。

Microservicesで提案されているのは、一つのサービスだけでなく、それを開発する開発者(あるいはチーム)も、できるだけ完結した存在になることが望ましいということである。中央集権的な開発体制ではなく、いくつものサービスとその開発を担当する cross-functional なチームが自律的に連携して、全体として大きなシステムを実現するという、オブジェクト指向が理想としていたようなモデルである。

あまり理想主義的になり過ぎるのも良くないが、このような考え方のルーツの一つにオブジェクト指向があり、それが考え方としてはデザインパターンやアジャイル開発などにつながり、プロダクトとしてはインターネットやiPhoneなどにつながっていることを考えると、実用性や現実性はともかく、その思想の重要性に注目しておく必要はあるだろう。

Microservices時代のプロジェクト管理を考える (1) – 水平型から垂直型へ

たまチームで管理しているGitHubリポジトリの数もどんどん増えてきて、今ではデプロイ可能なサービスだけでも20個ぐらい、リポジトリの総数は30を超えた。既に書いた通り、これらのサービスに共通するサーバーの構築 (Provisioning) と管理は、これまで一人のインフラ担当者が頑張って面倒を見てきた。しかしこのままサービスの数が増えていくと、インフラ部分がボトルネックになって効率が大きく損なわれることが目に見えている。そこで Deployment や Provisioning の管理方法を変えよう、というのが前回の話であった。

この方針変更をたまチームでは「水平型から垂直型への移行」と呼んでいる。

従来の管理方法だと、アプリケーション開発者はアプリケーションのビルドにだけに注力すればよい一方、インフラ担当者は、すべてのアプリの Deployment、サーバーの Provisioning や Monitoring まで面倒を見なければならなかった。

horizontal

これを垂直型に移行すると以下のようになる。

vertical

アプリケーション開発者はサービス開発者となり、アプリケーションのビルドに加えて、そのアプリケーションが動作する環境の Provisioning も担当し、最終的には Server Image をアウトプットするようにビルドプロセスを変更する。インフラの共通部分は最小限に抑えて、チームメンバー全員で共同管理出来るようにする。

水平型も垂直型も、それぞれ一長一短でありトレードオフがある。インフラの共通部分を厚くすれば、同じような構成のサーバーを一括で変更したり、多くのProvisioningコードを再利用出来る一方、共通部分と各アプリケーション開発者間で生じるコミュニケーションコストは馬鹿にならない。

あるいは、高度に訓練されたチームであれば、メンバーの誰もが共通部分(インフラ)とアプリケーションを行ったり来たりしながら自在に開発出来るのかもしれない。しかし、残念ながら我々たまチームはそこまでのレベルには達していないので、共通管理する部分を出来るだけ薄くして、後はアプリケーション開発者の裁量に任せてみることにした。

この考え方はソフトウェアのモジュール(あるいはオブジェクト)の考え方に似ている。モジュールは外部との責任を明確にする一方、内部構造については隠蔽しておくのが望ましいとされる(責任を果たす限り内部の詳細を問題にしない)。これはモジュール間のコミュニケーションコストを最小限にして、大量のモジュールが柔軟に連携出来るようにするための考え方であり、これをそのままサービス開発に応用するとすれば、アプリケーション開発者は、そのアプリケーションが外部に果たす役割を明確にする限り、他の開発者はその内部のことを(とりあえずは)気にしなくて済む。

サービスの数が増えていくのと同時に、技術の進歩に伴って、サービスの粒度が小さくなってきている。サービスが Microservice化すると、一つのリポジトリを複数の人間が管理するよりも、一人の人間が複数のリポジトリを管理するケースの方が増えてくる。その意味でも、コミュニケーションコストを抑える方法を考えておかなければならない。

個々のサービス開発者に課せられる責任は、オープンソースプロジェクトの開発に要求されることに似ている。そのプロジェクトを誰かに使って欲しければ、それが外部に提供する価値について、そしてその利用方法について、第三者が分かる形で説明する必要がある。ここで何を説明するべきかという最小限のラインを考えることが垂直型の勘所ではないかと思う。

ソフトウェアアーキテクチャと組織の構造

Martin Fowler氏が記事 Microservices の中で言及しているように、コンウェイの法則によれば、ある組織が開発するソフトウェアのアーキテクチャはその組織の構造をそっくりそのまま反映した形になる。今回の話で言えば、水平型のアーキテクチャを生み出す組織は職能で分けられた水平分業組織であり、垂直型の場合は cross-functional な垂直統合チーム型組織になる。

既に述べたように、いずれも一長一短があるため、どちらが良いとは一概には言えない。たまチームではたまチーム独自の事情があって、今回は垂直型への移行を試みることになった。この移行によって開発のやり方やアウトプットがどう変わったかはこのブログで逐一レポートする予定である。

最後に一つだけ垂直型への期待を述べるとすれば、現代は専門領域の境界がめまぐるしく変化する時代である。一つの専門領域に留まっていたら、あっという間に時代遅れになることも珍しく無い。このような時代においては、多様な領域に横断的に関わり、それらの融合をもって競争社会のアドバンテージとするべきであり、そういう意味ではチームだけでなく、個人にも cross-functional な能力が求められるのではないだろうか。

Immutable Infrastructureを導入する

現在たまチームでは、以下のような自動化を実現している。

gyron-infra-old

自動化の柱は大きく分けて二つあって、まずは Deployment Pipeline。アプリケーションコードを変更して git push すると、Jenkins上でビルドされて、Amazon S3上へのパッケージのリリースから、アプリケーションサーバー上へのデプロイまで自動で行われる。

もう一つはサーバー群の構成管理 (Provisioning)で、Chef による Codification(コード化) が実現されている。

この環境でかれこれ二年ぐらい運用してきたが、自動デプロイは便利だと思いつつ、いくつかの問題点が明らかになってきた。

  • デプロイの際に更新されるのはアプリケーションだけなので、サーバー上のミドルウェアの更新をいつやるか、どうやって安全にやるかを考えるのはなかなか悩ましかった。
  • Chefを経由するより、まずはサーバーを直接直してしまおうという誘惑が常にある(突然のセキュリティアップデートが必要になった場合など)。
  • EC2のインスタンスがリタイアするときにあたふたしてしまう。
  • Chefのコードを書く人がインフラ担当者に限られてしまい、アプリケーション開発者側から手出し出来なくなる。
  • 簡単とは言えないChefにも問題があると思われ。
  • ProvisioningコードがCI上に乗っかってない。

というわけで、たまチームへの新たな要求や DevOps の新たなトレンドなどを鑑みて、インフラの大幅刷新を行うことにした。

以下が、目下移行中、新インフラの概要図である。

gyron-infra-new

大きく変わるのはアプリケーション開発者が担当するビルドの部分。以下、重要なポイントごとに検討してみる。

DeploymentとProvisioningの統合

今までは別々に管理されていた Deployment と Provisioning のプロセスを統合して、アプリケーション側で Server Image の生成まで面倒を見るようにする。

現状のビルドプロセス:

deploy-and-provision-old

新ビルドプロセス:

deploy-and-provision

この統合によって、Provisioningの大部分がアプリケーション側に移動することになる。今まではインフラ担当者の責任だった Provisioning を各アプリケーションの開発者が担当することによって、誰もがアプリケーションコードを扱う感覚でProvisioningコードを扱えるようになることを狙いたい。

また、今回は Chef から Ansible への移行も行う。プロジェクト全体で Provisioning を共有する場合、あるいはインフラが大規模になるようなケースであれば Chef のメリットもあると思われるが、アプリケーションに Provisioning を含めてしまうという今回のケースでは、より習得が容易でコンパクトに書ける Ansible が向いているのではないかという判断である。

アプリだけでなくサーバー全体を含めたContinuous Integration

今までCI上で実施されていたのはアプリのビルドまでだった。新しい仕組みでは、サーバーのビルド(AMIの作成)までをCI上で回す。これによって、以下のようなメリットが得られる。

  • Provisioningも自動テストの対象にできる(serverspec
  • アプリケーションの変更を行う感覚でミドルウェアの変更を行える
  • サーバーのPortabilityが改善し、テスト用の環境などが構築しやすくなる

Immutable Infrastructure

新インフラのアプリケーションサーバーは、原則として、一度起動した後にsshなどでログインしてその状態を変更しないようにする。アプリケーションやミドルウェアを更新する場合は、コードを変更してServer Imageを作り直し、古いサーバーを破棄して新しいサーバーに入れ替える。

このような方針で管理されたインフラを「Immutable Infrastructure」と呼ぶ。インフラがコードに表現された以外の状態を取り得ないということは、コードさえあれば環境を容易に再現できるということであり、テストが簡単になる、理解しやすくなる、不測の事態が起こりづらくなる、Blue-Green Deployment がやりやすくなるなど、数多くのメリットがある。

DevOps Split – BuildとOrchestration

新しいインフラでは、Server Image (AMI) という Artifact を生成するプロセスと、そのArtifactを利用してOrchestration(サーバーの構成管理)を行うプロセスを分離する。前者は個々のアプリケーション開発者が担当し、後者はチーム全体で共同管理することになる。

以下は HashiCorp で紹介されているワークフロー:

Atlas-DevOps-Split

このワークフローを採用した場合、Artifactの作成で流れが一旦切れるため、git pushしたらアプリケーションの更新まで行われるという、現状実現できている自動化を再現するのが難しくなる。新インフラで得られるメリットに比べたら些細なことだと言えるかもしれないが、今後の課題ということでここに記録しておく。

CIのCodification – JenkinsからCircleCIへ

現状のインフラで自動化の要を担っているJenkinsであるが、ジョブの数が多くなってくると管理が大変になってくる上に、設定が Codification されていないという問題があるため、CircleCIに移行することにした。

Blue-Green Deployment

現状のインフラで Blue-Green Deployment を実現しているのは、状態(セッション)を持たないアプリケーションに限られ、かつデプロイ作業の多くは手動で行っている(ELBの操作など)。新インフラでは、以下のような手法を採用して、全てのアプリでより安全な Blue-Green Deployment の導入を目指す。

  • JEEアプリについては、 tomcat-redis-session-manager を利用してセッションをRedis (Elasticache) に保存するようにし、アプリケーションサーバーをステートレスにする。
  • Terraform を利用して新しい Server Image を立ち上げた後、Smoke Testで動作確認し、ELB配下で新旧の切り替えを行う。
  • Terraformによって、サーバーの設定・構成がコード化されると共に、管理コンソールで操作する必要がなくなるため、ヒューマンエラーの予防になる。