「AWS認定DevOpsエンジニア–プロフェッショナル」資格取得に向けた勉強

## この投稿について
* いつ受験するかも決めることなくダラダラと勉強してましたが、 埒があかないのでここに1週間以内に受験することを宣言し、気合いを入れます。(__無事合格できました！(2018/10/18)__)
* 一番身につく勉強法はアウトプットであるという信念のもと、今まで溜まっていたメモをまとめて公開
* 自分なりの理解で作成しています。ツッコミ大歓迎です！

## 整理の枠組み
* ...と言えばシリーズ: 状況と要件を見た瞬間に即答したい！
* (単体では)できないことシリーズ: 知って入れば除外できる選択肢を増やしたい！
* アンチパターンシリーズ: 知って入れば除外できる選択肢を増やしたい！
* 苦しい解釈シリーズ: 選択肢が全て疑わしいときのヒント
* 用語: 自分が知らなかった用語、目的を誤解していた機能を書き出す。
* 覚えておいた方が良い(と思った)こと

## ...と言えばシリーズ
* Dockerの展開パターン: CloudFormationでAWSリソースをプロビジョニングし、Elastic Beanstalk、Opsworksまたは、ECSでDockerを展開する。
* 運用中のシステムに影響を与えることなく更新: Blue/Greenかimmutableデプロイ(新ELB作成 → 新起動設定作成(新AMI関連の設定) → 新ASG作成(ELBと起動設定等を関連付け) → Route53でCNAMEを更新)
* ダウンタイムなし、1日に何度もアプリ更新をリリース、ほぼ即座にロールバック: Blue/Greenデプロイ(2つ環境を構築してDNSでCNAME切り替え)の一択、ローリングアップデートでは即座にロールバックできない。
* 大規模なトラフィック増を検知&通知: リクエスト数(ELBの標準メトリクス)と紐付けたアラーム + SNS

参考: [Amazon CloudWatch を使用した Auto Scaling グループとインスタンスのモニタリング](https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-instance-monitoring.html)

* AWSリソースのアクセス権限管理: IAMロール(漏洩やキーの危殆化リスクがなくなる。リスク対策としてのキー更新が不要)
* CloudFormationで構成されたAuto Scalingの更新: スタックの更新時にインスタンスを入れ替えるには、UpdatePolicy属性(AutoScalingRollingUpdateポリシまたはAutoScalingReplacingUpdateポリシ)を指定する必要がある。
  * AutoScalingRollingUpdate: 既存のAutoScalingGroup配下のインスタンスを数台ずつ入れ替えていく方法
  * AutoScalingReplacingUpdate: 新しいAutoScalingGroupを作成して、新旧のグループを入れ替える方法
* CloudFormationで構成されたAuto Scalingの感度を調節: PauseTimeとCoolDownパラメータの調整が基本
  * PauseTime: UpdatePolicy属性のPauseTimeプロパティのこと。インスタンス上のアプリを起動する間、スケーリングアクションを一時停止する時間の長さ。CloudFormationでAuto Scaling Groupを構成する場合の設定項目であり、Auto Scaling Groupにはない。
  * CoolDown: スケールアウト/インアラーム後に次のスケールアクションを実行しない時間の長さ
* トラブルシューティング(原因調査): アプリログを調べて問題の理由を調査することが基本(小手先の対策は暫定対策フェーズ)
* APIサービスに対するユーザ負荷のスパイクに起因したレスポンス悪化: ELBの事前ウォーミングアップ
  * ELBの事前ウォーミングアップが必要な場合はAWSに申請(サポートチケット)
  * 自前でELBを事前ウォーミングアップする場合は、外部から定期的にAPIをコールし続ける。
* 1秒あたりのリクエスト数を取得: ELBの標準メトリクスと紐付けたアラームを作成
* Chef v11.10を実行するOpsWorksスタックで複数のクックブック(外部クックブック利用時など)を利用: OpsWorksで「Berkshelf」を使用することで依存関係を管理する。
  * クックブックのルートディレクトリに「Berkfile」を配置する。
  * OpsWorksのスタック設定でBerkshelfを有効にした上で、使用するクックブック群が指定されたBerkfileを使用する新しいクックブックを作成し、同クックブックを使用する様、OpsWorksのスタックを設定することがベストプラクティス
* I/Oとネットワークがボトルネック: 拡張ネットワーキングに対応したEBS最適化インスタンスを起動設定としたAuto Scaling Groupを活用する。EBSはストライピングでI/Oでも高速化できるがインスタンスの停止が必要となる。ストライピングはEBSの種類によらず構成可能(インスタンスストア、PIOPS、汎用SSD、マグテネティック、...)
* 一貫したI/Oパフォーマンスが求められる: EBSの事前ウォームアップ(全てのブロックに対して読み取りを実行する。)
* 通信の暗号化: インターネット〜ELB間およびELB〜EC2間の通信路とEBS内のデータ、S3内のデータが暗号化されていること。
* DynamoDBを活用した構成で一部のユーザだけレスポンスが悪い: データ全般に渡って均等に分散されるプライマリーキーを持つ新たなテーブルを作成し、Data Pipelineで移行する。
  * レンジキーを追加して複合キーテーブルとすることで、パフォーマンス向上が期待できる。
  * Data Pipeline: データの移動と変換を自動化できる。
* 参照系のクエリが中心のデータ、システム全体的な高速化が必要: ElastiCacheを活用することでEC2からデータ層(RDSなど)への通信をキャッシュする。
* DynamoDBでスロットリングが発生(パフォーマンスダウンではなく、API失敗): RCUまたはWCU増加
* 並行処理・非同期処理が可能で冪等性が保証されたシステム、データストアがボトルネックではない、一つ一つの処理負荷が大きい: SQSでレスポンスタイム向上可能
* アプリケーションのレスポンス鈍化原因の特定
  * ELBのログから原因となったAPIを特定
  * データベースの負荷を確認
  * 原因がCPUなのかメモリなのかI/OなのかネットワークなのかDBMSのチューニングなのか分析
  * 【意味ないこと】EC2の停止/終了されたか確認(Cloud Trail) → 障害調査ではない。
  * 【意味ないこと】スケーリングイベントの有無を確認 → スケーリングイベントとレスポンス劣化の相関は低い
  * 【意味ないこと】正確な時間を知る。 → 原因特定とは関係がない。
* ELBの__アクセスログ__からレイテンシレートを取得する方法: 「backend_processing_time」にELBがインスタンスへリクエスト送信開始〜ELBがインスタンスからレスポンスを受信開始するまでの時間(秒単位)が記録されている。
* Opsworksでのロールバック: アプリケーションバージョニング(Gitなど)を利用して整合性が保ちつつ実行(Opsworksスタックを使用してデプロイされたアプリは、DeploymentCommandのロールバックオプションを使用してロールバックできるが、整合性担保の観点からアプリケーションバージョニング活用がベストプラクティス)
* 通知にはSNSを使用するのが王道、Kinesisはストリーミングによるリアルタイムなデータ分析が目的
* 高可用性(単一障害点回避)、高耐久性、分散データストア、短時間(1時間以内とか)のRTO: S3(またはスナップショット)
  * EBSは分散データストアではない。(単一AZ内のレプリケーションはAWSでは分散データストアと言わない。)
  * Glacierは取り出しに3〜5h要するのでRTOが充足可能か確認が必要
* 仕様が安定しない(俊敏性が必要)、複雑な構成のAWSリソースをCloud Formationで管理: 論理パート毎に別個のテンプレートを作成し、ネストされたスタックを構成する。それぞれのテンプレートをバージョン管理する。(複雑なテンプレートにしない。可能な限りCloud Formationだけで完結させる。)
* いつでもアクセスできる堅牢なデータストア: DynamoDB or RDS
  * Kinesis: 24時間しかデータを保存できないため永続性がない。(リアルタイム分析が目的)
  * Glacier: アーカイブストレージのため、いつでもアクセスできるストレージではない。
* 大規模分散処理: Apache Hive + Elastic MapReduce
* S3へのオブジェクト追加をトリガとした処理: S3は新しいオブジェクトの追加時やオブジェクト削除時にSNS、SQS、Lambdaに対してイベントを通知できる。この仕組みを活用すれば、GET Bucket API(List Objects API)でポーリングするよりもコストを抑えることが可能
* 大量ログデータをリアルタイム処理、リクエスト増に対応、費用対効果を考慮: Kinesisに公開、ログ処理用アプリをサブスクライブ(kinesisは、データ受信のスケール性がある、また費用も安くできる。EMRは、常に起動しておく必要があり、しかもマルチAZのなので費用が高くなる。(そもそもEMRはリアルタム処理が目的ではなく、大量データを処理するためのもの))
* アプリケーション障害監視: カスタムCloud Watchメトリクスを作成し、当該アプリに一定間隔でInstanceIdディメンジョンを送信するハートビートアプリ機能を追加する。同メトリクスが一定時間Insufficient状態が続いた場合に必要なアクションを実行するように設定されたCloud Watchアラームを実行するに設定する。(インスタンス停止アクションとAuto Scalingと組み合わせてインスタンスを入替など)
* DRシナリオ: AWSの世界ではリージョン全体障害級の惨事をいう。故にMulti-AZはDR対策にならない。

## (単体では)できないことシリーズ
### Cloud Formation
* ValidateTemplateはテンプレートに定義されているAWSリソースのプロパティ検証(構文チェック(含: JSONとしての妥当性も確認)まで)
* テンプレート記述によるELBの事前ウォーミングアップ(要申請(サポートチケット))

### Opsworks
* AWSリソースのプロビジョニング(Chef + AWSコマンドを駆使すればできないことはないが...)
* デプロイ失敗を検知 + 自動ロールバック
* Elastic Beanstalkのような凝ったデプロイ(ローリングデプロイ、immutableデプロイ、...)

### Elastic Beanstalk
* デプロイ失敗を検知 + 自動ロールバック(デプロイをキャンセルする際に手動でロールバック)

### Docker
* ローカル環境から本番環境へ移行する際の環境差異を全て吸収(NWやセキュリティグループ、または拡張性が必要な場合は、Elastic BeanstalkまたはECSなどを考慮する必要)

### Auto Scaling
* 起動設定の更新
* 一つのAuto Scaling Groupに複数の起動設定を関連付ける

### ELB
* EIPを割り当てる。
* 設定で事前ウォーミングアップ
* 明示的なAutoScaling設定(自動的にスケールアウトしかない。)
* リクエストを配下のAuto Scaling Groupへ送信する割合を制御(Route53のWRRで実現)

### Cloudtrail
* 直接的なトラフィック量を監視
* ELBのレイテンシレートの取得

### Kinesis
* CloudWatchへデータストリーミングできない。

### Elastic MapReduce
* RDSを直接利用できない。

## アンチパターンシリーズ
* 環境(開発環境、ステージング環境、本番環境)を用意するために別々テンプレートやのRecipe、スクリプトを作成する。(1コードが基本)
* OpsworksとElastic Beanstalkを併用(資格試験では)
* 新らたな起動設定作成(新AMI関連の設定) → 既存Auto Scaling Group更新(旧起動設定で起動したサーバを停止させないとデプロイできない。)
* 突然の大規模トラフィック増加を素早く検知する要件なのに、定期実行JOB(例: 30分毎)で検知
* わざわざAWSリソースをプロビジョニングするためのEC2インスタンスを作成
* Cloud Formationで変更セットを使用せず、テンプレートを使用してスタックを更新(期待どおりの構成になっているか確認した方がリスクが低い)
* 即時性が求められているのにポーリングでトリガ検出
* 人間からのリクエストをトリガとしたワークフロー
* 独自クックブックに外部クックブックの詳細を追記(外部クックブックの更新に追従できない。)
* DynamoDBやRDSがボトルネックなのにAP層(EC2)をスケールアップ
* 性能向上を目的としたDynamoDBからRDSへ移行(パフォーマンス向上は期待できない。)
* SQSのメッセージにイメージやファイルを含める: 容量に制限あり(256KB)
* ElastiCacheにイメージやファイルをキャッシュ: 大きなメモリサイズが必要となりコストアップ
* 費用対効果を求められているのにインスタンスを追加する構成: ウォッチドッグインスタンス追加など

## ありえないシリーズ
* Cloud Formationのスタックを複数作成してELBで負荷分散
* ELBやAuto Scaling Groupの設定でローリングデプロイ
* SQSの後段にELB(メッセージをサブスクライブするEC2かLambdaしかありえない。)
* オープンソースのコミッタに自分の都合がいいように改修してもらう。(プルリクするのは超推奨なんだけど...)
* ELBにNetworkInメトリクスなんてない。(※当該インスタンスの全NICで受信したバイト数、EC2とAuto Scaling Groupのメトリクス)
* InstanBootTimeメトリクス(インスタンス起動に要した時間？)はなんて存在しない。
* Elastic BeanstalkにFailedDeployment APIはなんて存在しない。
* AWS::EC2::Containerはリソースなんて存在しない。コンテナ関連ではESCのリソースしかない。(「AWS::ECR::Repository」、「AWS::ECS::Cluster」、「AWS::ECS::Service」、「AWS::ECS::TaskDefinition」など)
* TomcatはGo言語に対応していない。(Javaのサーブレットコンテナ)
* s3 symlink object(S3はシンボリックリンクをサポートしていない。S3はファイルシステムではなく、オブジェクトストア)
* ec2-create-volume APIでEBSを作成してec2-copy-snapshot APIをコール(ec2-copy-snapshot APIはスナップショットをコピーするAPIなのでEBSを作成する必要がない。)

## 苦しい解釈シリーズ
* Elastic Beanstalkは、AWSリソースのプロビジョニングが可能: ソースバンドルのルートに隠しディレクトリ「.ebextensions」を作成し、その中に設定ファイル(ファイル拡張子: .config、形式: YAMLまたはJSON)を配置する。
  * __対象はElastic Beanstalkでプロビジョニングされた　AWSリソースのみ__(ELB、SQS、EBS、...)
  * この機能により定番構成であれば、Elastic Beanstalkのみ(OpsworksやCloud Formationを使用せずに)プロビジョニング+デプロイを完結できる。

参考: [ElasticBeanstalk .ebextensions 逆引き辞典](https://qiita.com/inouet/items/e8b39962c0de0f866531)

## 用語の定義(AWS)
### 全般
* プロビジョニング: インフラストラクチャ構築のこと
* デプロイ: コードやバイナリ、 アセットなどの配布のこと

出典: [初心者向けWebiner](https://www.slideshare.net/AmazonWebServicesJapan/awswebinaraws-54198407)

* 認証情報ファイル: aws configureコマンドで指定された認証情報をホームディレクトリに保存したファイル(~/.aws/credentials)
* ScalingAdjustment: Auto Scalingにおけるインスタンスの増分(または減分)
* アーティファクト: ビルドされたバイナリ(本来は自然界に存在しない人造物の意)
* ソースバンドルとはzipに固めたソースコード一式
* テストハーネス: ソフトウェアテストで用いられるテスト実行用のソフトウェア、テスト対象モジュールを呼び出し、テストケースを適用して実行を制御・監視し、テスト結果のレポートを行う。テストドライバやテストスタブなどで構成される。
* バックアップ(=DUMPの取得)とスナップショットは別の用語として使い分けている場合がある。

### Cloud Formation
* テンプレート: 定義ファイル
* スタック: テンプレートから作成された実体

### Opsworks
* Cookbook: Recipeの管理単位、Recipe実行に必要なパラメータなどをまとめたもの
* Recipe: 「○○がインストールされている」、「このパスに△△が配置されている」など対象Nodeがプロビジョニングされた状態を示す情報を記述する。

### Elastic Beanstalk
* 環境枠(tier): Web Server Tier(ELB+EC2(Auto Scaling)+RDS)とWorker Tier(SQS+EC2)の2種類が用意されている。
* 環境: 本試験で環境といったら、「開発環境」と「ステージング環境」と「本番環境」のこと
* プラットフォーム(ソリューションスタック)
  * ソフトウェアコンポーネント1つ(特定バージョンのオペレーティングシステム(OS)を実行するAMIとツール、Elastic Beanstalk固有のスクリプト)と設定コンポーネント1つ(プラットフォームで作成され環境に適用されたデフォルト設定)で構成される。
  * プログラミング言語(Java、PHP、Python、Ruby、Go)、ウェブコンテナ(Tomcat、Passenger、Puma)、Dockerコンテナがそれぞれ複数の設定で用意されている。

参考[AWSが提供する「プラットフォーム」](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/concepts.platforms.html)

* Dockerrun.aws.jsonファイル: DockerコンテナのセットをElastic Beanstalkアプリケーションとしてデプロイする方法を記述するElastic Beanstalk固有のJSONファイル

### DynamoDB
* スロットリング: 使えるリソースの上限を超えた場合のサービス制限、リクエストがスロットリングされる。スロットリングされると、ProvisionedThroughputExceededException例外が発生し、HTTP Statusコード: 400(Bad Request)が返却される。

### S3
* ライフサイクルポリシ: オブジェクトの有効期限を設定する。(Glacierへ移動、削除など)
* GET Bucket API: List Objects APIと同じ

### イメージ
* Createimage APIは、自インスタンスに紐付けされたEBSボリュームのイメージを作成

## 覚えておいた方が良い(と思った)こと
### Elastic Beanstalkのデプロイの種類
* All at Once: 同一インスタンス上で、サービスを止めて入れ替える。
* Roling: 新旧バージョンが混在しながら入れ替わる。サービス停止はなし。
* Roling with additional batch: 旧バージョンもしくは新バージョンのインスタンス数が必ず指定した数以下にならないようにコントロールしつつ、新旧バージョンが混在しながら入れ替わる。サービス停止なし。
* immutable: 新バージョン用に別の環境を作成し、デプロイが終わったらDNSのCNAMEを切り替えて旧バージョン用の環境を破棄する。Blue/Greenとの違いはデプロイに成功したら旧環境を破棄するところ。
* シンボリック(参考): シンボリックリンクの切り替えでデプロイ(ChefやPappetで採用されている。)
* カナリアリリース(参考): 新旧バージョンを混在させ、設定されて割合に基づき、トラフィックを流す。(GCPではできる。AWSではRoute53でWRRを設定)

### ebコマンドによるプロビジョニング+デプロイ(Elastic Beanstalk)
※ローカルリポジトリを作成したディレクトリで実行すること。

* eb init: Access Key/Secret Access Key、リージョン、アプリ名、環境名、環境枠、ソリューションスタック(プラットフォーム)、タイプ(LB or シングルインスタンス)、RDS(スナップショットから作成 or 新規、ID/Password)
* eb create: 環境の作成(v2ではeb start)
* eb deploy: アプリケーションコードを更新(v2ではeb push/git aws.push ← 本質的には同じ動作)
* eb open: デフォルトブラウザに表示
* eb status: アプリの状態確認
* eb stop: アプリ停止
* eb delete: アプリ破棄

### イメージの種類
* 全部入りAMI: 柔軟性:　低/プロビジョニング&デプロイ時間: 最速
* Golden image: アプリコードのみ最新を取得すれば良い。
* 最小構成AMI: 柔軟性:　高/プロビジョニング&デプロイ時間: 最遅、場合によっては外部ライブラリが取得できないこともあり得る。

### 開発環境、ステージング環境、本番環境を1コードで作成する方法
#### cloud Formation
* リソースプロパティの条件式で各環境固有に必要なAWSリソースをプロビジョニング

#### Opsworks
* Chefの「Environment」に対象Nodeに適用する各環境毎のパラメータを記述する。

#### Elastic Beanstalk
* 環境名を設定する。(eb create)

### 変更セットを使用したスタックの更新
* テンプレートを更新すれば、スタックが更新される訳ではない。
* テンプレートの更新→ローカルまたはS3へ保存→変更セットの作成(更新するスタック、修正済みテンプレートの場所(ローカルコンピュータのパスやS3のURLなど)、テンプレートにパラメーターが含まれる場合は値を指定する。)→アップデートを実行する前にどのような変更が加えられるかを確認→実際に変更

### Cloud Formationのスタック作成通知
テンプレートのリソース属性にて、スタック作成後にSNSトピックへサブスクライブすることができる。

```
"MySNSTopic":{
  "Type":"AWS::SNS::Topic",
  "Properties":{
    "Subscription":[
      {
        …
```