先週のAWS関連ブログ

先週のAWS関連ブログ 〜1/21(日) – yoshidashingo. セクションナイン の 吉田真吾(@yoshidashingo)です。 AWS公式Amazon RDS for MySQLとMariaDBのログ… 続きを表示 セクションナイン の 吉田真吾(@yoshidashingo)です。 AWS公式Amazon RDS for MySQLとMariaDBのログをAmazon CloudWatchで監視 … 続きを読む

「Microservices Meetup vol.6」に行ってきた

2017/1/19のデイリーストックランキングにランクインしました。

【毎日自動更新】Qiitaのデイリーストックランキング!ウィークリーもあるよ_-_Qiita.png


いままでの。
「Microservices Meetup vol.2」行ってきたメモ。
「Microservices Meetup vol.4」に行ってきた

図らずして1回おきに参加してますね。

Connpassのイベントページ

少し間が空いてしまったがまた定期的に開催していきたいです。
登壇したいよーって人は直接リプ投げてください
by @qsona さん

Microservices on AWS by @Keisuke69 さん

Keisuke Nishitani @ AWS

Specialist Solutions Architect

サーバーレスアプリケーション開発ガイド 2月発売

マイクロサービスのポイント

  • 管理運用まで含めて分散型
  • 各コンポーネントが独立している
    • 単独で実行できないのは適切に設計されていない

独立して分散していると負荷の高い機能の単位でスケールさせられる=コスト効率が良い

  • 一つのことをうまくやる

    • 複雑化したら分割する
  • 多言語

    • チーム(機能)にはそれぞれの問題に対して適切なツールを選択する自由がある
    • OS、言語、各種ツールに至るまで最適なアプローチを目指せる
  • 検索:Elasticsearch / Solr

  • ソーシャル:グラフDB

  • ログデータ:Cassandra

  • セッション:Redis

†AWSでは:AWSには100ちょいのサービスがあって、その中で更にチームが分かれている。
各チームに社内標準の開発プロセスは存在しない。

  • ブラックボックス

    • 詳細は外部のコンポーネントに公開されない
  • DevOps
    • マイクロサービスにおける組織原理

†AWSでは:運用のみのチームはない。オンコールも開発チームが請け負う

  • 俊敏性

    • 狭い範囲のコンテキストで活動=サイクルタイムが短い
    • システムもシンプル
    • パラレルな開発とデプロイが可能
  • イノベーション

    • 選択に対する権限と責任を持つのでイノベーションを起こしやすい
    • DevとOpsの対立がないため、効率化やイノベーションが起こしやすい
  • 拡張性

    • 適切に非干渉化されてていることで水平方向に単独にスケールできる
  • 可用性

    • ヘルスチェック、キャッシング、隔壁、サーキットブレーカーと言った仕組みは全体の可用性を向上させる

課題

  • 分散型であることは難しい

    • システム数が増える
    • 協調動作の難しさ
    • コンポーネント間のコミュニケーションメッセージ増によるレイテンシ低下
    • ネットワークの信頼性は無限ではない、帯域も無限ではない
  • 移行が大変
    • モノリシックなシステムの分割は難しい
  • 組織
    • 組織体制の変更が必要になるが、それは大変なこと
  • アーキテクチャの難易度
    • 非同期通信
    • データ整合性
    • やっぱりココが一番の課題
    • サービスディスカバリ
    • 認証
  • 運用の複雑さ

アーキテクチャ

一番シンプルなパターン

CloudFront – ALB – ECS – datastore(ElastiCache, Dynamo, )
|
S3

  • バックエンドをRESTfulなAPIにしたSPA
  • 静的なコンテンツはS3とCloudFront
    • CDN通すことでレイテンシが上がることもある
    • キャッシュとの併用を検討
  • ECSとAutoScalingをALBとともに使うことが多い
    • ALB(L7LB)でアプリレベルの情報をルーティング
    • コンテナインスタンスにリクエストを分散
    • ECSのコンテナを負荷に応じてスケールアウト/インする

コンテナのメリット

  • Portable
  • Flexible
  • Fast
    • 軽量で早い
    • ポータビリティと関連して開発サイクルも早く
  • Efficient

  • 一貫性のある環境

  • バージョン管理出来る

Dockerの特徴

  • Package
  • Ship
  • Run

ECS

  • 複数のコンテナをEC2のクラスタ上で一元管理

    • まだTokyoにきてないけど、FargateでEC2の管理もいらなくなるよ
    • EKS(Kubernetes)も発表されています

データストア

  • インメモリ

    • Memcached, Redis
    • ElastiCache
    • DB負荷の軽減
  • RDBMS
    • 無限のスケーリングには向いていない
    • Amazon RDS
  • NoSQL
    • 水平スケーリングをサポートするものが多い
    • テーブル結合ができないのでロジックの実装が必要になる場合も
    • Amazon DynamoDb, KynamoDB Accelarator(DAX)

APIの実装

  • APIの設計、改善、デプロイ、モニタリング、保守派手間がかかる
  • 異なるバージョンが混在すると大変

Amazon API Gateway

  • 複数バージョンとステージ
  • Cognite User Poolsと連携して認証を追加
  • スロットリング、モニタリング
  • バックエンドとしてLamdbaが使える

サーバーレス

  • サーバーはないに越したことはない
  • スケーリングと高可用性の担保が大変
CloudFront - API Gateway - Lamdba - datastore
   |                            (ElastiCache, Dynamo)
   |
  S3

課題をAWSでどうするか

サービスディスカバリ

  • お互いの死活確認や発見
  • ハードコードするとスケールできない

    • メタデータをどこに置くか
  • ALBを利用したサービスディスカバリ

  • DNS(Route53)のサービスディスカバリ

    • VPC単位の振り分け
  • ECSイベントストリームを使用したサービスディスカバリ

    • CloudWatchイベントで拾ってキック
    • LamdbaでRoute53に登録
    • これが一番多いかも
  • DynamoDBを使用したサービスディスカバリ

    • DNSキャッシュの問題がない
    • 自由度が高い
    • 実装が大変
    • DynamoDBストリームを活用して他のサービスへステータス変更を反映
  • イベントベースのアーキテクチャ

    • イベントで処理する
    • いわゆる結果整合性とも関連
    • Dual Write Problem
    • Event Sourcing
      • 状態の記録ではなく状態の変更「イベント」を記録
      • Amazon Kinesis
      • kinesisにpublishして他サービスはsubscribe
      • S3にログを残す
      • トランザクションログの仕組み

モニタリング

  • CloudWatch

    • ログファイルの一元化
    • CloudWatch LogsかS3に保存可能
    • ECSはCloudWatch Logsに一元化できる

分散トレース

  • AWS X-Ray
  • 複数サービスに分散したリクエスト処理を透過的に追える

LogWatchの先に Kinesis FireHorse – ほにゃほにゃ

スロットリング

  • 大事だよ

リトライ

  • 多くのエラーはリトライでカバーできるものが多い
  • リトライ多発で過負荷になることがある
    • Exponential back offもしくはフィボナッチ数列を利用したリトライ感覚の調整
    • 更に乱数でゆらぎを付けて重ならないように

LT:クラウド型医療系業務システムと Microservices への歩み by @hashedhyphen さん

https://speakerdeck.com/hashedhyphen/kuraudoxing-dian-zi-karutesisutemuto-microservices-hefalsebu-mi

クラウド型電子カルテシステムの話

  • メインロジックをRails
  • 常時接続をNode.js
  • バックエンドをScala
  • 基盤はAWS

ここに至る道のり

ファーストリリース前

  • レコメンドは大量のデータが必要

  • メインロジックで実現させようとすると厳しかった

    • Threadとか試したけど……
    • 別アプリケーションとして分離
    • JVM上でScala + Skinnyでスレッドアプリケーションンを実装
    • Microservicesちっくな構成へ
  • 障害検知時

    • メインロジック内のプロトタイプ版が動く!

会計機能リリース前

  • お金を扱う機能は安定性が欲しい
  • Scala + Cats による実装を別エンドポイントとして実装
  • マイクロサービスっぽい作りになっていたから自由度のある技術選択が出来た

まとめ

  • ちょっとマイクロサービス化したことで自由度が上がった
  • 原理主義的にならなくても恩恵がある
  • エンジニアの伸びしろ!

FrontEndからみるmicroserviceとBackendからみるmicroservice by @taka_ft さん

Takahiro Fujii @ Rakuten Travel

楽天内でも採用アーキテクチャはサービスによって異なる。

サービスとしては

  • コンシューマ向け
  • Extranet
  • In-house
  • other
    • ここまではWEBとモバイルがあって、100以上のAPIを利用する
  • API(内部APIを直接利用)

Phase 1

  • 大きなモノリシックなアプリだった
  • 機能がどんどん増えていく
    • 機能別で複数のモノリシックなアプリに分割
    • その後フロントエンドとバックエンドに分割

Phase 2

  • ドメインモデルを整理
  • なるべくRESTfulで作るようになっていった
  • 大きなAPIから小さなAPIに分離
  • I/Fの決定に時間がかかるようになった
  • API呼び出しが大変になった
  • Microservicesっぽくなってきた 2014年くらい

  • 国内予約、海外予約で多言語化だけではない商習慣に根ざしたドメインの差異による重複ロジックの増殖が起きた

  • Microservicesっぽくなってきたが、どんどん品質が下がっていった

Phase 3

(ちょうど前日にプレスリリース)サイト前面刷新に向けての取り組み

  • FrontendsはJavaScriptに刷新
  • API GatewayにKong

組織

  • フロントエンドチームが2人から始まって半年でReactエンジニアを集めて20人以上に

    • 日本人は2, 3人

UI Component

  • SpringからJavaScriptでSPAに変更
  • zeplinのデザインモックからUI Componentを実装するようになった
  • Storyboardを使ってUI Coponentを管理
  • ドメインを含むUI Componentはドメインと結び付きが強いことが多い=専用のオーケストレーションAPIを用意してUI Componentないで処理を閉じることが出来る
  • レスポンシビリティを明示的に定義

    • どこまでフロントエンドでやるか、どこからAPIからもらうか
  • フロントエンドの「使いやすいレスポンス」の要求

  • バックエンドの「汎用的でシンプルなレスポンス」の希望

    • これらのバランスを取る
  • API Gatewayはフロントエンド(UI)チームの管轄

    • ただし状況によってはバックエンド側に持っていくことも検討するつもり

LT: “マイクロサービスはもう十分”か? by @qsona さん

https://speakerdeck.com/qsona/enough-with-the-microservices

POSTDに投稿していた翻訳記事。

スタートアップ企業のほとんどはマイクロサービスをさいようすべきではない

銀の弾丸はない。

「チーム間の依存性」の解決にマイクロサービスというアプローチは違う。疎結合と分散は別。

組織が大きくなると、複数チームが1つのコードベースを触るようになる。そしてマイクロサービス化したくなる。

しかし、モノリスの分割で十分。

チームとは何か

  • 自律的に動けるべき

    • チームが増えるとコミュニケーションコストや、しがらみ
  • チームの分割は目的にそった分割を行う

  • 悪い分割の例: Dev / Ops

  • 依存度が低いほど自律的に動ける

  • High Output という本

  • 使命型組織/技術型組織

    • Micorservicesは使命型組織
    • 組織間が密ならサービス間も密になる

話戻して

  • スタートアップは組織をキレイに分割することが難しい
  • 分割しても密になってしまう

  • 大きなモノリスになるとやはり分割は難しい

    • ドメインの意識は必要
  • マイクロサービス設計しなくても「マイクロサービス精神」で開発すると効果的なのではないか

FiNCが初期からマイクロサービスでやってた理由

  • 単独の事業にできるような一つ一つのサービスを組み合わせて提供してきたから

あとで読み返して修正します。
資料パスの追加とかも。

続きを読む

AWS CloudWatchについての記事まとめ

個人メモ用記事

概要

【AWS】CloudWatch
CloudWatch 標準メトリクス(監視項目) 一覧
Black Belt Online Seminar Amazon CloudWatch
AWS Black Belt Techシリーズ Amazon CloudWatch & Auto Scaling
AWS Black Belt Techシリーズ AWS CloudTrail & CloudWatch Logs
AWS Blackbelt 2015シリーズ Amazon CloudWatch & Amazon CloudWatch Logs

ELB

CloudWatchのELB監視項目
あらたにELBを作成する時の、CloudWatch設定メモ
ELBの挙動とCloudWatchメトリクスの読み方を徹底的に理解する
CloudWatchのあるはずのメトリックスが存在しない理由
ELBのHealthyHostCountは全AvailabilityZoneの合計値をモニタリングできない?

EC2

死活監視

AWS CloudWatchでEC2の死活監視

メトリクス監視

新しいCloudWatch AgentでEC2インスタンスのメモリ使用率を監視する
[AWS] CloudWatch でロードアベレージとかメモリ使用量とか監視
ECSクラスタのCPUとメモリをCloudWatchメトリックスで取得してみた
EC2のメモリ使用量とdisk使用量をcollectdでサクッとCloudWatchに登録
AWS CloudWatch で、Amazon Linux のパフォーマンスとログの監視をしてみる
はじめてのCloudWatch(AWS) 〜カスタムメトリクスを作って無料枠でいろいろ監視する〜
AWS CloudWatch シェルだけでPutMetricDataを実行する
AWS CloudWatchでEC2を監視する (プロセス死活監視、ディスク使用率、iノード使用率を監視してアラートメールを送信する)

ログ取得

CloudWatch Logsを使ってログを集める!
CloudWatch Logsのインストール・設定
EC2インスタンスのログをCloudWatchで見る
AWS EC2でメモリ利用率をCloud Watchで監視する
nginxのエラーログをcloudwatch logsに送信する

RDS

Amazon RDS のモニタリング
CloudWatchのRDS監視項目

S3

Amazon CloudWatch を使用したメトリクスのモニタリング
S3のアクセス状況を可視化してみる

Auto Scaling

[翻訳]チュートリアル:CloudWatchアラームによるコンテナインスタンスのスケーリング

アラート設定

CloudWatchでエラーログの内容を通知させたい
CloudWatchアラームでSlackへ通知を行う。
AWS SNS(Amazon Simple Notification Service)の通知設定をしてみる

続きを読む

AWS再入門 Amazon EC2(Linux)編 | Developers.IO

はじめに AWSチームのすずきです。 Amazon RDS (MySQL, MariaDB)のリードレプリカ、Multi-AZ で利用可能となるアップデートがありました。 その設定を試す機会がありましたので、紹介させて頂きます。 Amazon RDSのリードレプリカがMulti-AZ配置をサポートしました 手順 AWSコンソール リードレプリカのMulti-AZ設定に … 続きを読む

【AWS】年末年始休暇などでRDSを停止しても7日後には自動的に開始してしまう

はじめに

今年の年末年始は11連休でした。

発生した事象

  • 12/28に停止した開発環境のRDSが、1/9に出社すると起動していた

!?

原因

なんと公式の仕様だった。

インスタンスは 1 回で最大 7 日まで停止できます。7 日後に、自動的に開始されます。

Amazon RDS でデータベースインスタンスの停止と開始をサポート

根本的な対策

クラスメソッドさんのブログのように、Lambdaで自動起動・自動停止する。

[Amazon RDS]起動停止をスケジュール実行してみた

おわりに

新年早々、頭がぼけたのかと焦りました。

続きを読む

AWSとAzureとGCPを比較してみる – DB編

DBについて、AWSとAzureとGCPを比較してみました。

1. 新世代DB

AWS Azure GCP
新世代DB Aurora Cosmos DB Cloud Spanner
DBの種類 MySQL,
Postgresql
SQL (document DB),
MongoDB (document DB),
Gremlin (graph DB),
Azure Table(KVS),
Cassandra
オリジナルのリレーショナルDB
サーバレスか否か サーバあり サーバレス サーバレス
高可用性構成 / 負荷分散 Auroraレプリカ,
クロスリージョンレプリカ(MySQLのみ)
リージョン間フェイルオーバー,
予約済みスループット
リージョン内レプリケーション,
マルチリージョンレプリケーション
地理的範囲 リージョン(MySQLは別リージョンにレプリケーション可) グローバル グローバル
マルチマスター シングルマスター,
マルチマスター*
マスターになるリージョンは1個 マルチマスター

*プレビュー

DBの種類ですが、Auroraは手堅くMySQLとPostgresql、Cosmos DBはバラエティーにとんでいてドキュメントDB・KVS・グラフDBとCassandra、Cloud SpannerはオリジナルのリレーショナルDBとなっています。
Cloud Spannerはクライアントライブラリが各言語(C#,GO,Java**, node.js**,PHP**, Python**, Ruby)に対し用意されていますが、ORMの対応が気になるところです。
**ベータ

Cosmos DBとCloud Spannerはサーバレスですが、Auroraはインスタンスタイプを指定してインスタンスを構築します。また、拡張機能というよりは別物として、サーバレスタイプのAurora serverless*がプレビュー中です。

高可用性構成と負荷分散ですが、Auroraはリージョン内ではリードレプリカが障害時にマスターに昇格することで対応しています。MySQL版はクロスリージョンレプリケーション構成を取ることができますが、リージョン間で自動フェイルオーバーする仕組みはありません。
また、Auroraはマルチマスター機能であるAurora Multi-Master*が現在プレビュー中ですが、リージョン間でも利用可能になる予定があるとアナウンスされています。リリースされればグローバルで高可用性と負荷分散が簡単に実現できそうです。
Cosmos DBは、1個の書き込みリージョンを持つリージョン間フェイルオーバー***の仕組みで高可用性を実現しています。
Cloud Spannerはリージョン内レプリケーションとマルチリージョンレプリケーションの仕組みで高可用性を実現しています。1つのリージョンで構築する場合は、3個のread-writeレプリカを保持します。複数リージョンで構築する場合は、2個のread-writeレプリカを保持する2個のread-writeリージョン(と場合によってread-onlyリージョン)で構成されます。

***Microsoftのドキュメントではregional failoverをリージョン内フェイルオーバーと訳していますが、意味合いはリージョン間フェイルオーバーなので、ここではそのように表記しています。

2. リレーショナルDB

AWS Azure GCP
MYSQL互換 MySQL
/ MariaDB
Azure Database for MySQL* Google Cloud SQL for MySQL
高可用性構成 Multi-AZ,
クロスリージョンリードレプリカ
フェイルオーバーレプリカ
負荷分散 リードレプリカ,
クロスリージョンリードレプリカ
リードレプリカ
Postgresql Postgresql Azure Database for PostgreSQL* Google Cloud SQL for PostgreSQL**
高可用性構成 Multi-AZ,
クロスリージョンリードレプリカ
リージョナルインスタンス**
負荷分散 リードレプリカ,
クロスリージョンリードレプリカ
リードレプリカ**
SQL Server SQL Server Azure SQL Database
高可用性構成 Multi-AZ アクティブgeoレプリケーション
負荷分散 アクティブgeoレプリケーション
Oracle Oracle
高可用性構成 Multi-AZ
負荷分散

*プレビュー
**ベータ

・各クラウド間での違い-その1

AWSのMulti-AZとGCPのリージョナルインスタンス(PostgreSQL)は、スタンバイ側はリードの機能がないので負荷分散には利用できませんが、GCPのフェイルオーバーレプリカ(MySQL)はリードの機能があるので負荷分散にも利用できます。

3. NOSQL

AWS Azure GCP
KVS・ドキュメント ElastiCache(Memcached, Redis),
DynamoDB
Redis Cache,
Cosmos DB(Azure Table, SQL, MongoDB)
Cloud Datastore,
Cloud Bigtable
グラフ Neptune* Cosmos DB(Gremlin)
Cosmos DB(Cassandra)

*プレビュー

Neptuneの現時点のプレビューのAWSマネジメントコンソール画面はAmazon RDSとよく似ています。また裏でAuroraと同じ仕組みを利用しているそうなので、ひょっとしたらCosmos DBみたいに、Auroraの一機能としてリリースされるかも知れません。

4. まとめ

現在は、MySQL・Postgresqlを利用したければAWSのAuroraかRDS、SQL Serverを利用したければAzureでしょうか。
ただ各クラウドのプレビュー・ベータ提供状況を見ていると、そのうち機能差は無くなるように思えます。

続きを読む

MetabaseからAmazon Auroraにアクセスしてみた

Metabaseのアクセス先にMySQLとか書いてあったので、Aurora接続もできるだろうと思って勉強がてら試してみました。

Metabaseとは

ベタですが、公式ページが一番わかりやすいっす。

Auroraの準備

デフォルトの設定でとりあえず作成します。

  1. Publicアクセスさせたかったので(色々考えるの面倒)、Publicアクセスの設定
  2. お金ないのでMulti AZはなしん設定

というあたりはデフォルトと変えた感じ。それでサクッと用意しました。

スクリーンショット 2018-01-06 21.41.00.png

Auroraにデータを投入

こちらのページを参考に、DBとテーブルの作成など諸々行いました。

Amazon RDS for Aurora を試してみた

ここで紹介されている郵便データに関してですが、時間が経ったためか実際のカラムの並び順などが変わっていたので、そういう点だけ変更してあとは上記のページのまま進めます。(ありがたや)

mysql> CREATE TABLE zipcode_list (
    -> zipcode varchar(10),
    -> prefecture varchar(255),
    -> city varchar(255),
    -> street varchar(255),
    -> prefecture_kana varchar(255),
    -> city_kana varchar(255),
    -> street_kana varchar(255)
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.38 sec)

データ投入もすんなり行きました。

$ mysqlimport --local --compress --user=root --password --host=xxxxxxxx.xxxxxxxxx.us-east-1.rds.amazonaws.com --fields-terminated-by=',' --fields-enclosed-by='"' --lines-terminated-by='rn' -d metabase ./zipcode_list.csv
Enter password: 
metabase.zipcode_list: Records: 124117  Deleted: 0  Skipped: 0  Warnings: 0 

Metabaseを起動する

今回はJavaで起動しました。

$ java jar metabase.jar 

起動したら、localhost:3000でアクセスできます。で、諸々画面に従って設定をしますが、MySQLベースの設定をします。

Name Value
Database MySQL
URL Auroraのエンドポイント
Port 3306

スクリーンショット 2018-01-06 21.27.43.png

すると無事繋がって、普通に作成したデータベースが表示されました。(予想通りでした)

データも何か欠損しているわけではなく、投入分がしっかり反映されています。

スクリーンショット 2018-01-06 21.29.02.png

まとめ

予想通り、Auroraは問題なくつなぐことができました。一応GithubのIssueではDynamoDBやAthenaへの対応の要望も出ているので、少し待てばどんどん対応されるんじゃないでしょうか。個人的にはMetabaseの操作性が抜群にいいので、Athenaのクライアントとして使ってみたいと思っています。

おまけ

操作性が抜群にいいですねこれ。

例えば一覧でデータを表示した後に

スクリーンショット 2018-01-06 21.29.29.png

絞り込みたい対象のカラムをクリックすると、その値で絞り込めるようになってる。

スクリーンショット 2018-01-06 21.31.50.png

まだ試してませんが、Pulseとかも使ってみたいですね。

続きを読む

2017年のAzure国内トピックを振り返る

MySQL、PostgreSQL、Maria DBのPaaSは、AWSのAmazon RDSから遅れての登場になりました。マイクロソフトは、サービスの可用性(SLA99.99%)の高さ、バックアップ/リストア機能の標準内蔵といった競合優位性をアピールし、PostgreSQLの利用が多い日本市場や、国策でクラウドDBの利用がOSSのみに制限される … 続きを読む

ある程度の規模で運用するAWS CloudFormationの勘所

概要

インフラエンジニアとしてAWS基盤の構築・運用に携わって早1年が経ちました。
今回は自分がCloudFormationを運用する中で培ってきたノウハウや勘所をご紹介したいと思います。

なお、これがCloudFormationのベストプラクティスだとかそんなことを言うつもりはなく、
あくまで自分がこう考えてきたぞというものなので、ご参考程度にお願いします。
いろんな考え方があると思いますので、ぜひマサカリコメントお待ちしてます。

どの程度の規模で運用してきたか?

サービスとしてはビッグデータ分析プラットフォームのようなものを構築しておりますが、
AWSの規模感としては大体こんな感じです。

  • AWSアカウント:2

    • 1つは開発環境・内部結合環境用
    • 1つはステージング環境、本番環境用
  • 環境数:5
    • 開発環境
    • 内部結合環境
    • ステージング環境1
    • ステージング環境2
    • 本番環境
  • 利用しているAWSサービス:約15サービス
    • Amazon VPC
    • Amazon EC2
    • Amazon RDS
    • Amazon ElastiCache
    • Amazon S3
    • Amazon DynamoDB
    • Amazon CloudWatch
    • Amazon SNS
    • Amazon Cognito
    • Amazon Route53
    • AWS Lambda
    • AWS IAM
    • Amazon Kinesis
    • AWS WAF
    • AWS CloudTrail
  • 基盤担当者:2~3名
  • CloudFormation テンプレートステップ数:約80KStep

CloudFormationの適用範囲

さてCloudFormationを利用するにあたって、どのAWSリソースをCloudFormationで管理すべきでしょうか?
個人的には「可能な限り全て」を推奨しています。
「可能な限り全て」というのは、「EC2のキーペア登録などCloudFormationでは管理できないもの、新規サービス等でCloudFormationが対応していないものを除き、CloudFormationで構築可能なAWSリソースの全て」という意味です。

AWSの利用サービスが多いほど全てに対応するのは大変に思えるかもしれません。
しかし管理方法(AWS CLI, CloudFormation, 管理コンソールなど)がバラバラになるよりかは遥かに混乱せずミスも防げます。
特にCloudFormationで作成したリソースをCloudFormation以外で更新・削除してしまうと整合性が取れなくなり、最悪CloudFormationの運用ができなくなってしまうので、そのような事故を避けるという意味でも原則CloudFormationに統一することをお勧めします。

1つの技術要素に統一しておけばキャッチアップコストも低くなるでしょう。

テンプレートフォーマット

テンプレートのフォーマットはJSONとYAMLが選択できますが、これは可読性の観点から「YAML一択」です。
もともとJSONのみのサポートでコメントが書けない等の問題がありましたが、2016年9月のアップデート1でYAMLがサポートされるようになりました。

既にJSONフォーマットのテンプレートを利用している場合でも、CloudFormationデザイナーを利用してコンバート可能なので積極的にYAMLフォーマットを利用しましょう。

ディレクトリ/ファイル構成

ある程度の規模のAWSリソースを管理することが想定される場合、事前にディレクトリ構成やファイル構成をしっかり考えておかないと管理が非常につらくなってきます。

特にファイル構成(1テンプレートファイルに何のAWSリソースを含めるか)は、1度スタックを作成してしまうと後から容易に変更ができないため重要です。

ディレクトリ構成

適切なファイルの構成を考えるためには、適切なディレクトリ構成を考える必要があります。
開発者や運用者がテンプレートファイルを管理しやすい構成が望ましいでしょう。

筆者のチームでは「AWS契約単位」、「環境単位」、「システム or サブシステム単位」にディレクトリを分割することを推奨 2しています。

ディレクトリ構成例
cloudformation
├─ aws-000000000000              # AWSアカウントID[000000000000]のリソースのテンプレートを格納
│  ├─ common                     # 環境共通的なリソースのテンプレートを格納(IAM設定, CloudTrail設定など)
│  │  ├─ iam.template
│  │  ├─ cloudtrail.template
│  │  ├─ …
│  │
│  ├─ production                 # 本番環境のリソースのテンプレートを格納
│  │  ├─ common                  # 本番環境のシステム/サブシステム共通的なリソースのテンプレートを格納  
│  │  │  ├─ network.template
│  │  │  ├─ s3.template
│  │  │  ├─ dns.template
│  │  │  ├─ …
│  │  │
│  │  ├─ systemA                 # 本番環境のAシステム/サブシステムのリソースの/テンプレートを格納
│  │  │  ├─ composite.template
│  │  │  ├─ …
│  │  │
│  │  ├─ systemB                 # 本番環境のBシステム/サブシステムのリソースの/テンプレートを格納
│  │  │  ├─ …
│  │  │
│  │  ├─ …
│  │
│  ├─ staging1                   # ステージング1環境のテンプレートを格納
│  │  ├─ …
│  │
│  └─ staging2                   # ステージング2環境のテンプレートを格納
│     ├─ …
│
└─ aws-111111111111              # AWSアカウントID[111111111111]のリソースのテンプレートを格納
   ├─ …

ファイル構成

ディレクトリ構成が決まるとファイルの構成が概ね見えてきます。
上記のディレクトリ構成に基づくと、1つのテンプレートファイルに複数環境のAWSリソースが存在したり、複数システムのAWSリソースが存在したりするということはあり得ません。

仮に1テンプレートファイルに本番とステージング環境のAWSリソースが混在する場合を考えてみましょう。
ステージング環境のAWSリソースを更新する際は、必然的に本番環境のAWSリソースを含むスタックを更新することになります。仮に本番環境のAWSリソースに変更を加えていないとしても、精神衛生上よろしいものではありませんね。
事故を未然に防ぐという意味でも、最低限「環境単位」、「システム or サブシステム単位」にディレクトリを分割することは有効です。

ではディレクトリ内のファイル単位についてはどう考えるべきでしょうか。
ここで考慮すべきはAWSリソース間の依存度AWS管理者の単位です。

AWSリソース間の依存度

  • 互いに依存度の高いAWSリソースは同一テンプレートで管理すべきです。
    別テンプレートで管理してしまうと、AWSリソース間の依存関係を人が意識してスタックの作成・更新・削除を行わなければなりません。これはAWSに熟練した人ならまだしも、通常は容易なことではありません。
     
  • 互いに依存度の低いAWSリソースはテンプレートで管理すべきです。
    そうすることでスタックの作成・更新・削除時の影響を極小化することができます。(他のリソースをうっかり更新して事故を起こす可能性がなくなります。)

AWS管理者の単位

  • 例えばアカウント(IAM)管理者、データベース(RDS)管理者といったようにAWSのリソースに対して管理者が分かれている場合は、権限制御の観点から1テンプレートファイルに含めるリソースを判断したほうがよいでしょう。

筆者の経験上、上記のディレクトリ構成に基づくのであれば、ディレクトリ配下のAWSリソースは1テンプレートファイルにまとめてしまったほうが運用しやすいです。
実際system系のディレクトリ配下は各種AWSリソース(ALB, EC2, RDS, SecurityGroup, IAMRole, InstanceProfile etc..)をcomposite.templateにひとまとめにしており、分割しているのはcommonディレクトリに含まれるIAM(ユーザ・グループ)、CloudTrailなど明確に他のAWSリソースとの結合度が低いもののみとなっております。

テンプレートの共通化

ここまで読んでいただいた方は「テンプレートの共通化をしないのか?」と思われるかもしれません。

公式ドキュメントのAWS CloudFormationのベストプラクティスでも紹介されていますが、テンプレートファイルはパラメータを利用することによって共通化することが可能です。
同じコンポーネントを宣言する共通パターンを共通テンプレートとして再利用することで、ダブルメンテを防ぐことができます。

しかしながら、筆者はテンプレートの共通化は極力しないほうがむしろメンテナンス性は高いと考えています。

1. 可読性が低い

共通化をしようとすればするほど、各種リソースの設定値をパラメータ化して、外部から値を受け取るようになります。極端な例ですがEC2インスタンスを作成するテンプレートを共通化すると下記のようになります。
パラメータを利用しているため、具体的に何の値が設定されているかは管理コンソールや呼び出し元の親テンプレートを参照しないとわかりません。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  ImageId:
    Description: EC2 ImageId
    Type: String
    Default: ""
  InstanceType:
    Description: EC2 InstanceType
    Type: String
    Default: ""
  AvailabilityZone:
    Description: EC2 AvailabilityZone
    Type: String
    Default: ""
  InstanceInitiatedShutdownBehavior:
    Description: EC2 InstanceInitiatedShutdownBehavior
    Type: String
    Default: ""
  DeviceName:
    Description: EC2 DeviceName
    Type: String
    Default: ""
  VolumeType:
    Description: EC2 VolumeType
    Type: String
    Default: ""
  VolumeSize:
    Description: EC2 VolumeSize
    Type: String
    Default: ""

Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      AvailabilityZone: !Ref AvailabilityZone
      InstanceInitiatedShutdownBehavior: !Ref InstanceInitiatedShutdownBehavior
      BlockDeviceMappings:
        - DeviceName: !Ref DeviceName
          Ebs:
            VolumeType: !Ref VolumeType
            VolumeSize: !Ref VolumeSize
      # 省略

共通化をしない場合、下記のようにパラメータを利用せず設定値をベタ書きする形になります。
似たような記述を繰り返し書くことになりますが、実際のリソースとテンプレートの定義が1対1で定義されており、設定値が一目でわかります。

AWSTemplateFormatVersion: 2010-09-09
Resources:
  EC2Instance001:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-da9e2cbc
      InstanceType: t2.micro
      AvailabilityZone: ap-northeast-1a
      InstanceInitiatedShutdownBehavior: stop
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: 100
            VolumeSize: gp2
      # 省略

  EC2Instance002:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-da9e2cbc
      InstanceType: t2.large
      AvailabilityZone: ap-northeast-1c
      InstanceInitiatedShutdownBehavior: stop
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeType: 200
            VolumeSize: gp2
      # 省略

2. 修正に伴う影響範囲が大きくなる

共通化できると考えていたとしても後から「この環境だけ、もしくはこのリソースだけ個別に変更を加えたい」というようなことは往々にして発生します。
共通テンプレートを修正する場合は影響を受けるリソースを常に意識しなければなりません。
最悪、共通化したテンプレートの中でConditionによる条件分岐を行うなど、負の遺産を生み出しかねません。

3. 変更プレビューにてネストされたスタックの変更分が参照できない

これは親テンプレートを用意してその中で共通テンプレートを利用する場合に発生する問題となります。
管理コンソールからCloudFormationを実行する場合、実行前に「変更のプレビュー」として、差分を確認できますが、親スタック(テンプレート)の更新を行う場合、子スタック(テンプレート)の詳細な変更分は見ることができません。

Changes.png

仮にテンプレートファイルの差分を事前に別の方法で確認していたとしても、これは精神衛生上非常によくありませんし、思わぬ事故を引き起こすかもしれません。
 
 
以上の理由から、テンプレートファイルはプログラマブルに共通化することによって返って複雑度が増してしまうと考えています。
筆者のチームでは、原則共通化禁止ネストスタック禁止という形で可能な限りテンプレートをわかりやすくシンプルにしてきました。
単純、故に冗長な部分もありますが、裏を返せば簡単であり、知識の少ない運用者でもキャッチアップが容易でミスも最小化できます。

コーディング規約

コーディング規約というほど大それたものではありませんが、テンプレートを作成するにあたっていくつか決めておいたほうがいいことがあります。

  • AWSリソースのキー名
    下記でいうEC2InstanceProductionSystemA0001に相当する部分となります。
    筆者のチームでは「AWSリソース名」+「環境名」+「システム名」+「連番」としています。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  EC2InstanceProductionSystemA0001:
    Type: AWS::EC2::Instance
    # 以下省略
  • AWSリソースに付与するタグ
    筆者のチームでは「環境」、「システム名」、「一意の名称」は最低限必須としています。
     
  • 使用しないプロパティの記載要否
    使用しないプロパティの記載方法については次の3パターンが考えられます。
    筆者のチームでは明示的に使用しない意図が分かるよう「3. 記載した上でAWS::NoValueを参照する」方針としています。

    1. 使用しないプロパティは記載しない
    2. 記載した上でコメントアウトする
    3. 記載した上でAWS::NoValueを参照する

開発フロー/CI

テンプレートファイルはGitなどのバージョン管理システムを利用して管理することが望ましいでしょう。
筆者のチームではGitlabを利用して下記のフローで開発を進めています。

プレゼンテーション1.png

aws-cliのaws cloudformation validate-templateコマンドを実行することでフォーマットの検証を行うことで、実際にスタックを作成する前に、タイポ等の単純なミスを発見することができます。
より細かいチェックを行ってくれるcfn-lintというツールがあるみたいですが、筆者は未検証です。

ある程度の規模までは、このフローで問題なく運用できるはずです。
しかし規模が大きくなればなるほど次のような課題がでてきます。

  • テンプレートファイルが複数に分かれているため、環境横断的に各種リソースの設定値を見たり、横串で修正をしたりするのがつらい。
  • YAMLを書くのがそもそもつらい。
  • コーディング規約違反のチェックなどレビューもつらい。

そこで筆者のチームではCloudFormationの設定値をExcel, RDBで管理し、YAML自動生成するような仕組みを導入しています。
プレゼンテーション2.png

これにより、開発者はExcelだけをメンテナンスすればよくなりました。
同じAWSリソースは1シートに全て定義しているため、環境横断的にリソースの設定値を参照・修正することも容易です。

ただしこのような仕組みを作るのはそれなりに時間がかかりますし、汎用的に作ろうとするとある程度高度な設計も必要になってきます。ご紹介した方法は決して推奨するようなものではなくただの一例になりますが、何かしらのメンテナンスコストを下げるような仕組みがあると幸せになれると思います。

リリース

ここでのCloudFormationのリリースとはスタックを作成・更新・削除することを指します。
AWS CLIを利用してJOB等で実行させるなど色々な方法が考えられますが、スタックの操作については「管理コンソールからの実行」が一番良いと筆者は考えています。
理由としては「変更のプレビュー」により、AWSリソースの変更点が「視覚的」に確認できるためです。

console-changeset-details.png

スタックの更新を行う場合には必ず変更セットの作成から更新を行うようにしましょう。

CloudFormationを腐らせてはいけない

公式ドキュメントにも書かれていますが、AWS CloudFormationで作成したリソースをCloudFormation以外の方法で変更しては絶対にいけません。

スタックを起動した後、AWS CloudFormation コンソール、API、または AWS CLI を使用して、スタック内のリソースを更新します。スタックのリソースを AWS CloudFormation 以外の方法で変更しないでください。 変更するとスタックのテンプレートとスタックリソースの現在の状態の間で不一致が起こり、スタックの更新または削除でエラーが発生する場合があります。詳細については、「ウォークスルー: スタックの更新」を参照してください。

CloudFormationはあくまでCloudFormationの世界でAWSリソースを管理しており、管理コンソールから行った変更をいい感じに取り込んではくれません。最悪の場合、二度とCloudFormationが実行できなくなる可能性があります。

特にこの問題は、CloudFormationに詳しくない運用者に引継ぎを行う場合などに発生します。
本当の緊急事態を除き、原則AWSの管理コンソールはRead Onlyにしておくなど、権限制御を行いましょう。
(人を信じてはいけません。)

おわりに

まとまりなくつらつらと書いてしまいましたが、いかがでしたでしょうか。
CloudFormationを実際の現場でどう運用するのか考える際に、この記事が少しでも参考になれば幸いです。


  1. https://aws.amazon.com/jp/blogs/aws/aws-cloudformation-update-yaml-cross-stack-references-simplified-substitution/ 

  2. マルチリージョンでサービスを提供する場合はAWS契約単位、リージョン単位、環境単位、システム or サブシステム単位に分割したほうがいいでしょう。 

続きを読む