【AWS】ロードバランサー+ApacheでHTTPSリダイレクトをしてみる

AWSのEC2インスタンス上に立てたApacheサーバーを、HTTPSリダイレクトできるように設定してみます。

環境:
Apache2.4

前提:サーバー証明書

今回はHTTPSリダイレクトを実現するので、もちろんサーバー証明書が必要となります。AWSではCertification Manager(通称ACM)という無料でサーバー証明書が発行できるサービスがあるので、それを利用します。

ですがこのサーバー証明書、EC2インスタンス上に置くことはできず、CloudFrontもしくはLoadBalancerに置いてEC2インスタンスに接続するという形を取らなければなりません。

今回はこの二つのうち、より一般的そうなLoadBalancerを用いた場合の設定方法を書いていきます。

このサーバー証明書の発行に関して、またCloudFrontでの利用についてはここでは割愛します。(また今度書きます)

本題:環境構築

EC2インスタンスの作成

今回はAmazon Linuxで作成します。セキュリティグループのインバウンド設定は以下のようにします。

タイプ ポート範囲 ソース
HTTP 80 0.0.0.0/0
SSH 22 [マイIP]

ロードバランサーはHTTPSのリクエストも内部的にはHTTPとして扱っているので、EC2の設定としては80番ポートのみ開けておけばリクエストは通ります。SSHを開けてあとでApacheのセットアップをします。

これで起動します。

ロードバランサーの作成

Application Load Balancerを用います。

ロードバランサーの設定

リスナーにHTTPS(443)を追加します。

Screen Shot 2017-09-20 at 16.32.20.png

セキュリティ設定の構成

「ACMから証明書を選択する(推奨)」を選択し、証明書を選択します。

セキュリティグループの設定

今回は

  • HTTPのリクエストをHTTPSにリダイレクト
  • HTTPSのリクエストはそのまま通す

という設計なので、HTTP/HTTPS共に受け付けるように下のように設定します。

タイプ ポート範囲 ソース
HTTP 80 0.0.0.0/0
HTTPS 443 0.0.0.0/0

ルーティングの設定

ヘルスチェックの詳細設定において、成功コードをリダイレクトの301にしないといけないそうです。

Screen Shot 2017-09-20 at 16.41.55.png

ターゲットの登録

先ほど作成したEC2インスタンスをポート80でターゲットグループに追加します。

以上で作成完了です。

Apacheの設定

それでは実際にリダイレクトの設定をApacheの方で行なってみます。

Apacheのインストール

バージョンは2.4です。

$ sudo yum install -y httpd24
$ sudo apache start

デフォルトでドキュメントルートは/var/www/htmlなのでそこをドキュメントルートとしてやっていきます。

.htaccessの設定

リライトの設定はこのファイルに書いていきます。以下のように書いて、ドキュメントルート(ここでは/var/www/html)におきます。

RewriteEngine On

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)?$ https://%{HTTP:Host}%{REQUEST_URI} [L,R=301]

.htaccessにおけるリダイレクトでは基本的に

RewriteCond
RewriteRule
...

という繰り返しで書くことが多く、ある条件(RewriteCond)に合致するものに対し、あるルール(RewriteRule)に基づき、アドレスのリライトを行うと考えればわかりやすいかと思います。

ここで注意していただきたいのが、HTTP環境変数です。「.htaccess 書き方」などのキーワードでググった結果をそのままコピペしても、この場合うまくいかない可能性が高いです。なぜならApacheサーバーとクライアントの間にロードバランサーがいるからです。

クライアントからどのようなHTTPリクエストが来たかを判別するため、AWSではX-Forwardedというプレフィックスのついたリクエストヘッダーを用いることができます。

そのため、httpsか否かの判定には%{HTTPS}や%{SERVER_PORT}ではなく%{HTTP:X-Forwarded-Proto}、ホスト名の判定には%{HTTP_HOST}や%{SERVER_NAME}ではなく%{HTTP:Host}を用います。

%{HTTPS}や%{SERVER_PORT}ではEC2インスタンスが通信に用いているHTTPが表示され、%{HTTP_HOST}や%{SERVER_NAME}ではEC2インスタンスのIPアドレスが表示されると思います。

httpd.confの設定

先ほど.htaccessを書いてドキュメントルートに置きましたが、このままではその設定は有効になりません。

  • httpd.confで.htaccessの有効化
  • httpdの再起動

をして初めて有効になります。

httpd.conf(初期設定では/etc/httpd/conf/にある)の次のAllowOverrideをNoneからAllに変えてやります。「htaccess」とかでファイル検索をかければすぐ見つかると思います。

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None

これで変更を保存し、apacheを再起動してください。

$ sudo apache restart

httpd.confの設定(追加)

mod_rewriteのログがみたかったのでついでにその設定もしてみました。検索するとRewriteLogLevelを.htaccessに書いている記事が多くあったのですが、上手くいかなかったので詳しく調べるとApache2.4系ではログは全部まとめてerror_logに吐かれるようでした。加えて、.htaccessへの記述はサポートされていないとのことだったので以下のようにhttpd.confに追記します。

LogLevel info rewrite:trace8

以上で完了です。これでロードバランサーを介してHTTPSリダイレクトが実現できました。

どうしてHTTPS?

自社でAWS上にWEBサイトを運営しているのですが、HTTPSがSEOに関わってるらしい、ということで対策せざるを得ない…
そもそも「not secure」とか出てたら、そんなサイト見る気しませんよね…

参考

https://www.crosshead.co.jp/blog/apache-alb-http-to-https
https://murashun.jp/blog/20141229-01.html
http://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/x-forwarded-headers.html
https://blog.cles.jp/item/8180
https://stackoverflow.com/questions/23054592/htaccess-loglevel-not-allowed-here

続きを読む

AWS WAF導入 ブラックリストによるアクセス拒否

AWS WAFとは

  • 2017.9月時点で、CloudFrontとALBにのみ適用可能
  • 悪意あるウェブリクエストのアクセスを拒否する

IP address(IP一致制限条件)でできること

  • 設定したIPアドレスのアクセスを拒否or許可
  • 指定したしきい値(最小2000)以上のリクエストを、5分以内に行ったIPアドレスのみ自動で拒否(Rate-based ruleのみ)

やること

  • Web ACLsの作成(Application Load Balancerへの適用)
  • Conditionsの作成(IP addresses)
  • Rulesの作成
  • AWS WAFを作成済みのALBに適用させる

前提

  • Application Load Balancerを作成済み。

WAF作成手順

1.AWSコンソールにログインする。

2.WAFの画面へ移動

[サービス]⇒[WAF & Shield]

3.ACLの作成

[Create web ACL]⇒[Next]
– Web ACL name: 任意のACL名
– CloudWatch metric name: 任意の名前(Web ACL nameを入力すると自動ではいる。)
– Reigion: 任意のリージョン
– AWS resource to associate: WAFの適用先
02.png

4.Conditionsの作成(今回はIP制限、ブラックリストによる制限)

IP match conditionsの[Create condition]⇒設定項目を入力⇒[Next]
– Name: 任意のCondition名
– IP Version: WAFの対象となるIPアドレスバージョン
 ※ここで設定しないと、デフォルトアクションが適用される。
  ⇒デフォルトアクションがAllowの場合、全許可(0.0.0.0/0)。
   デフォルトアクションがBlockの場合、全拒否になる。
04.png
03.png

5.Rulesの作成

[Create rule]⇒[Create]
●Ruleの作成
– Name: 任意のRule名
– CloudWatch metric name: 任意の名前(Nameを入力すると自動ではいる。)
– Rule type: [Rate-based rule]を選択。
– Rate limit: 任意のしきい値(5分間のリクエスト数の上限)最低2000
●Add match conditionsの設定
– does: リクエストが条件に一致するときに選択
– does not: リクエストが条件に一致しないときに選択
– original from an IP address in: IP制限のときに選択
– 4.で作成したConditionを選択(多分Black listとかになる?)
06.png

6.作成したRuleの動作を設定

作成したRuleの動作(BlockかCount)とデフォルトアクション(AllowかBlock)⇒[Review and create]
07.png

7.最終確認をして作成する

[Confirm and create]
08.png

続きを読む

ECS運用のノウハウ

概要

ECSで本番運用を始めて早半年。ノウハウが溜まってきたので公開していきます。

設計

基本方針

基盤を設計する上で次のキーワードを意識した。

Immutable infrastructure

  • 一度構築したサーバは設定の変更を行わない
  • デプロイの度に新しいインフラを構築し、既存のインフラは都度破棄する

Infrastructure as Code (IaC)

  • インフラの構成をコードで管理
  • オーケストレーションツールの利用

Serverless architecture

  • 非常中型プロセスはイベントごとにコンテナを作成
  • 冗長化の設計が不要

アプリケーションレイヤに関して言えば、Twelve Factor Appも参考になる。コンテナ技術とも親和性が高い。

ECSとBeanstalk Multi-container Dockerの違い

以前に記事を書いたので、詳しくは下記参照。

Beanstalk Multi-container Dockerは、ECSを抽象化してRDSやログ管理の機能を合わせて提供してくれる。ボタンを何度か押すだけでRubyやNode.jsのアプリケーションが起動してしまう。
一見楽に見えるが、ブラックボックスな部分もありトラブルシュートでハマりやすいので、素直にECSを使った方が良いと思う。

ALBを使う

ECSでロードバランサを利用する場合、CLB(Classic Load Balancer)かALB(Application Load Balancer)を選択できるが、特別な理由がない限りALBを利用するべきである。
ALBはURLベースのルーティングやHTTP/2のサポート、パフォーマンスの向上など様々なメリットが挙げられるが、ECSを使う上での最大のメリットは動的ポートマッピングがサポートされたことである。
動的ポートマッピングを使うことで、1ホストに対し複数のタスク(例えば複数のNginx)を稼働させることが可能となり、ECSクラスタのリソースを有効活用することが可能となる。

※1: ALBの監視方式はHTTP/HTTPSのため、TCPポートが必要となるミドルウェアは現状ALBを利用できない。

アプリケーションの設定は環境変数で管理

Twelve Factor Appでも述べられてるが、アプリケーションの設定は環境変数で管理している。
ECSのタスク定義パラメータとして環境変数を定義し、パスワードやシークレットキーなど、秘匿化が必要な値に関してはKMSで暗号化。CIによってECSにデプロイが走るタイミングで復号化を行っている。

ログドライバ

ECSにおいてコンテナはデプロイの度に破棄・生成されるため、アプリケーションを始めとする各種ログはコンテナの内部に置くことはできない。ログはイベントストリームとして扱い、コンテナとは別のストレージで保管する必要がある。

今回はログの永続化・可視化を考慮した上で、AWSが提供するElasticsearch Service(Kibana)を採用することにした。
ECSは標準でCloudWatch Logsをサポートしているため、当初は素直にawslogsドライバを利用していた。CloudWatchに転送してしまえば、Elasticsearch Serviceへのストリーミングも容易だったからである。

Network (3).png

しかし、Railsで開発したアプリケーションは例外をスタックトレースで出力し、改行単位でストリームに流されるためログの閲覧やエラー検知が非常に不便なものだった。
Multiline codec plugin等のプラグインを使えば複数行で構成されるメッセージを1行に集約できるが、AWS(Elasticsearch Service)ではプラグインのインストールがサポートされていない。
EC2にElasticsearchを構築することも一瞬考えたが、Elasticsearchへの依存度が高く、将来的にログドライバを変更する際の弊害になると考えて止めた。
その後考案したのがFluentd経由でログをElasticsearch Serviceに流す方法。この手法であればFluentdでメッセージの集約や通知もできるし、将来的にログドライバを変更することも比較的容易となる。

Network (4).png

ジョブスケジューリング

アプリケーションをコンテナで運用する際、スケジュールで定期実行したい処理はどのように実現するべきか。
いくつか方法はあるが、1つの手段としてLambdaのスケジュールイベントからタスクを叩く方法がある(Run task)。この方法でも問題はないが、最近(2017年6月)になってECSにScheduled Taskという機能が追加されており、Lambdaに置き換えて利用可能となった。Cron形式もサポートしているので非常に使いやすい。

運用

ECSで設定可能なパラメータ

ECSコンテナインスタンスにはコンテナエージェントが常駐しており、パラメータを変更することでECSの動作を調整できる。設定ファイルの場所は /etc/ecs/ecs.config
変更する可能性が高いパラメータは下表の通り。他にも様々なパラメータが存在する。

パラメータ名 説明 デフォルト値
ECS_LOGLEVEL ECSが出力するログのレベル info
ECS_AVAILABLE_LOGGING_DRIVERS 有効なログドライバの一覧 [“json-file”,”awslogs”]
ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION タスクが停止してからコンテナが削除されるまでの待機時間 3h
ECS_IMAGE_CLEANUP_INTERVAL イメージ自動クリーンアップの間隔 30m
ECS_IMAGE_MINIMUM_CLEANUP_AGE イメージ取得から自動クリーンアップが始まるまでの間隔 1h

パラメータ変更後はエージェントの再起動が必要。

$ sudo stop ecs
$ sudo start ecs

クラスタのスケールアウトを考慮し、ecs.configはUserDataに定義しておくと良い。
以下はfluentdを有効にしたUserDataの記述例。

#!/bin/bash
echo ECS_CLUSTER=sandbox >> /etc/ecs/ecs.config
echo ECS_AVAILABLE_LOGGING_DRIVERS=["fluentd"] >> /etc/ecs/ecs.config

CPUリソースの制限

現状ECSにおいてCPUリソースの制限を設定することはできない(docker runの--cpu-quotaオプションがサポートされていない)。
タスク定義パラメータcpuは、docker runの--cpu-sharesにマッピングされるもので、CPUの優先度を決定するオプションである。従って、あるコンテナがCPUを食いつぶしてしまうと、他のコンテナにも影響が出てしまう。
尚、Docker 1.13からは直感的にCPUリソースを制限ができる--cpusオプションが追加されている。是非ECSにも取り入れて欲しい。

ユーティリティ

実際に利用しているツールを紹介。

graph.png

ルートボリューム・Dockerボリュームのディスク拡張

ECSコンテナインスタンスは自動で2つのボリュームを作成する。1つはOS領域(/dev/xvda 8GB)、もう1つがDocker領域(/dev/xvdcz 22GB)である。
クラスタ作成時にDocker領域のサイズを変更することはできるが、OS領域は項目が見当たらず変更が出来ないように見える。

Screen_Shot_2017-08-31_at_11_00_03.png

どこから設定するかというと、一度空のクラスタを作成し、EC2マネージメントコンソールからインスタンスを作成する必要がある。

また、既存ECSコンテナインスタンスのOS領域を拡張したい場合は、EC2マネージメントコンソールのEBS項目から変更可能。スケールアウトを考慮し、Auto scallingのLaunch Configurationも忘れずに更新しておく必要がある。

補足となるが、Docker領域はOS上にマウントされていないため、ECSコンテナインスタンス上からdf等のコマンドで領域を確認することはできない。

デプロイ

ECSのデプロイツールは色々ある(ecs_deployerは自分が公開している)。

社内で運用する際はECSでCIを回せるよう、ecs_deployerをコアライブラリとしたCIサーバを構築した。

デプロイ方式

  • コマンド実行形式のデプロイ
  • GitHubのPushを検知した自動デプロイ
  • Slackを利用したインタラクティブデプロイ

Screen_Shot_2017-08-31_at_11_31_15.png

デプロイフロー

ECSへのデプロイフローは次の通り。

  1. リポジトリ・タスクの取得
  2. イメージのビルド
    • タグにGitHubのコミットID、デプロイ日時を追加
  3. ECRへのプッシュ
  4. タスクの更新
  5. 不要なイメージの削除
    • ECRは1リポジトリ辺り最大1,000のイメージを保管できる
  6. サービスの更新
  7. タスクの入れ替えを監視
    • コンテナの異常終了も検知
  8. Slackにデプロイ完了通知を送信

現在のところローリングデプロイを採用しているが、デプロイの実行から完了までにおよそ5〜10分程度の時間を要している。デプロイのパフォーマンスに関してはまだあまり調査していない。

ログの分類

ECSのログを分類してみた。

ログの種別 ログの場所 備考
サービス AWS ECSコンソール サービス一覧ページのEventタブ APIで取得可能
タスク AWS ECSコンソール クラスタページのTasksタブから”Desired task status”が”Stopped”のタスクを選択。タスク名のリンクから停止した理由を確認できる APIで取得可能
Docker daemon ECSコンテナインスタンス /var/log/docker ※1
ecs-init upstart ジョブ ECSコンテナインスタンス /var/log/ecs/ecs-init.log ※1
ECSコンテナエージェント ECSコンテナインスタンス /var/log/ecs/ecs-agent.log ※1
IAMロール ECSコンテナインスタンス /var/log/ecs/audit.log タスクに認証情報のIAM使用時のみ
アプリケーション コンテナ /var/lib/docker/containers ログドライバで変更可能

※1: ECSコンテナインスタンス上の各種ログは、CloudWatch Logs Agentを使うことでCloudWatch Logsに転送することが可能(現状の運用ではログをFluentdサーバに集約させているので、ECSコンテナインスタンスにはFluentdクライアントを構築している)。

サーバレス化

ECSから少し話が逸れるが、インフラの運用・保守コストを下げるため、Lambda(Node.js)による監視の自動化を進めている。各種バックアップからシステムの異常検知・通知までをすべてコード化することで、サービスのスケールアウトに耐えうる構成が容易に構築できるようになる。
ECS+Lambdaを使ったコンテナ運用に切り替えてから、EC2の構築が必要となるのは踏み台くらいだった。

トラブルシュート

ログドライバにfluentdを使うとログの欠損が起きる

ログドライバの項に書いた通り、アプリケーションログはFluentd経由でElasticsearchに流していたが、一部のログが転送されないことに気付いた。
構成的にはアプリケーションクラスタからログクラスタ(CLB)を経由してログを流していたが、どうもCLBのアイドルタイムアウト経過後の最初のログ数件でロストが生じている。試しにCLBを外してみるとロストは起きない。

Network (1).png

ログクラスタ(ECSコンテナインスタンスの/var/log/docker)には次のようなログが残っていた。

time="2017-08-24T11:23:55.152541218Z" level=error msg="Failed to log msg "..." for logger fluentd: write tcp *.*.*.*:36756->*.*.*.*:24224: write: broken pipe"
3) time="2017-08-24T11:23:57.172518425Z" level=error msg="Failed to log msg "..." for logger fluentd: fluent#send: can't send logs, client is reconnecting"

同様の問題をIssueで見つけたが、どうも現状のECSログドライバはKeepAliveの仕組みが無いため、アイドルタイムアウトの期間中にログの送信が無いとELBが切断してしまうらしい(AWSサポートにも問い合わせた)。

という訳でログクラスタにはCLBを使わず、Route53のWeighted Routingでリクエストを分散することにした。

Network (2).png

尚、この方式ではログクラスタのスケールイン・アウトに合わせてRoute 53のレコードを更新する必要がある。
ここではオートスケールの更新をSNS経由でLambdaに検知させ、適宜レコードを更新する仕組みを取った。

コンテナの起動が失敗し続け、ディスクフルが発生する

ECSはタスクの起動が失敗すると数十秒間隔でリトライを実施する。この時コンテナがDockerボリュームを使用していると、ECSコンテナエージェントによるクリーンアップが間に合わず、ディスクフルが発生することがあった(ECSコンテナインスタンスの/var/lib/docker/volumesにボリュームが残り続けてしまう)。
この問題を回避するには、ECSコンテナインスタンスのOS領域(※1)を拡張するか、コンテナクリーンアップの間隔を調整する必要がある。
コンテナを削除する間隔はECS_ENGINE_TASK_CLEANUP_WAIT_DURATIONパラメータを使うと良い。

※1: DockerボリュームはDocker領域ではなく、OS領域に保存される。OS領域の容量はデフォルトで8GBなので注意が必要。

また、どういう訳か稀に古いボリュームが削除されず残り続けてしまうことがあった。そんな時は次のコマンドでボリュームを削除しておく。

# コンテナから参照されていないボリュームの確認
docker volume ls -f dangling=true

# 未参照ボリュームの削除
docker volume rm $(docker volume ls -q -f dangling=true)

ECSがELBに紐付くタイミング

DockerfileのCMDでスクリプトを実行するケースは多々あると思うが、コンテナはCMDが実行された直後にELBに紐付いてしまうので注意が必要となる。

bundle exec rake assets:precompile

このようなコマンドをスクリプトで実行する場合、アセットがコンパイル中であろうがお構いなしにELBに紐付いてしまう。
時間のかかる処理は素直にDockerfile内で実行した方が良い。

続きを読む

実務経験がなくても2ヶ月でAWSソリューションアーキテクトに合格するためにやったこと

ゴールデンウィークくらいからAWSを趣味で触り始めてちょっと面白そうだったので、ソリューションアーキテクトの試験を受けてみようかと思い立ちました。
2017年7月12日になんとかギリギリ69%で合格できていたのでどういう風に勉強していったのかを残してみます。
なお、Qiitaには初投稿になります。

まずAWSに触り始める前事の自分自身の知識としては

  • 普段はエンプラ系の製品開発に従事
  • IPAのネットワークスペシャリストとデータベーススペシャリストを保持
  • AWSの主要サービスがなんなのかくらいはうっすらとわかる
  • たまにAWS関連のニュースを見てる
  • 実務でのAWSの経験は今まで全くない(そしてこれからもなさそう…

という感じでした。

自分としてはネットワークやデータベース周りの基本的な知識はある方だと思っています。
しかし、実際のお仕事ではクラウドのクの字にもかすりもしない、全く縁がない分野の人間です。

また、平日はあまり勉強することはなく(Evernoteに記録したノートを読み返す程度)、主に土日のみ勉強していました。実際には休みの日に4~5時間程度だったと思います。

アカウントを作成する

なにはともあれまずは無料枠を全力で駆使するためにアカウントを作成しました。とはいえ最初は何からやって良いのかわからないので、ざっとチュートリアルを触ってみました。

AWS 10分間チュートリアル

ほんとに10分だけでいろいろと体験できるのでありがたいです。
チュートリアルでは途中でつまづくことものほぼありませんでした。
チュートリアルとしてはとても役に立ったと思います。

試験ガイドを見てみる

AWSソリューションアーキテクトの右側にある試験ガイドのダウンロードからダウンロードして試験の範囲などを確認しました。特に製品名が明示的に書かれているものは重点的勉強する必要があると感じました。

セキュリティの基本的な考え方を知る

セキュリティプロセスの概要を読んで共有責任モデルを始めとする考え方を知っておきます。ページ数が結構あります。

サンプル問題をやってみる

AWS 認定ソリューションアーキテクト – アソシエイトの右側にある[サンプル問題のダウンロード]からダウンロードして解いて見ました。最初には全然わかりませんでした…

AWSのドキュメントを見てみる

基本的には勉強といってもAWS ドキュメントをひたすら読むということが大半でした。あとはAWS用語集も割と目を通しました。
さらに、AWSクラウド活用資料集も必要そうな製品のものについては一通り目を通しました(その内リンク切れしそう…)。
また、よくある質問は確実に目を通しておいたほうが良いと思います(特にページの上の方にある質問。下の方はより細かい質問に対する解答になっている気がしてあまり読みませんでした)。
以下のドキュメントはだいたい目を通しましたが、応用っぽい使い方などについてはあまり深追いはしませんでした。

重要そうな項目や説明はEvernoteの方に残してマーカなどで印をつけていきました(上記だけでも結構な分量になりました)。
上記の製品をいかに組み合わせて問題を解決するのかといった視点が重要になるようです。

AWS Summit 2017に参加してみる

1日だけでしたが、入門系のセッションだけ参加してきた。過去の分も含めて後からPDFでも動画でも確認できるのは非常にありがたいです。モチベーションも上がりました。

AWS Summit Tokyo 2017 セッション資料・動画一覧

また参加していて思ったこととしては、最新情報はある程度キャッチアップしておく必要があると思いました。例えば、「既存のAmazon EC2インスタンスにIAM Roleがアタッチできるようになりました」のように、今までできていなかったものができるようになったのはよくチェックした方が良いと思います。

書籍関連

書籍としては以下のものを読んで、その内のいくつかは実際に書籍の従って動かしてみたりもしました。
たまたまKindle版が半額になっていたものやポイントが多かったりすることもあって購入もしています(運が良かった…)。
購入していないものは図書館で借りて2週間(図書館の期限が2週間なので)で隅から隅まで熟読してました。
実務経験がない以上、とにかく手を動かしていくことが重要だと考えました。

いろいろなリンクを回ってみる

クラスメソッドさんのブログは情報も早くてよく見てました。他にもAWS公式ブログやqiitaの記事なども目を通していました。特にQiitaのソリューションアーキテクトに合格した系の記事は大変参考に、かつモチベーションの維持に効果がありました!

Amazon Web Services ブログ
Developers.IO
Qiita -ソリューションアーキテクト-

また、以下のサイトでは実際に試験のような問題を解くことができます。有料なところもあるので、やるかどうかは自己判断になります。

AWS Web問題集で学習しよう

あまり深く勉強しないものを知っておく

「この製品はなんですか?」「この製品で何ができますか?」くらいの知識でも大丈夫そうなものについては、あまり深く勉強しないようにしました。例えばRedShiftやKinesis、OpsWorkなどがそれに当たるかと思います。
また、SDKやコマンドラインツールなどについては範囲外だと思うので一切見ていません。

模擬試験を受けてみる

1週間前くらいに模擬試験を受けてみた結果、70%でした。
模擬試験は本試験の半分くらいのボリュームでしたが、それでも結構難しく感じました。
マークをつけることで後から見直すことができるので、ちょっとでも不安な問題にはマークをつけて復習できるようにメモっておきました(試験が終わると問題文などに確認はできなくなります)。
この時点ではちょっとまだ本番に自信がなかったので、ここから本試験まではあまり手を動かさずに、ここまで勉強したことの復習をメインに、Evenoteを読み返したりドキュメントの再確認をやり始めました(この時点で書籍はほぼ読了済みの状態)。

実際の試験のときの心構え

試験は午前中にして朝早めにおきて、現地には早めにいき近くの喫茶店で最終確認をしておきました。
本試験では、とにかく問題文をしっかりと読むこと大切だと感じました。
また、ちょっと引っ掛けのようなものも混じっていたりして、うろ覚えではなくキチンと理解することが重要だと感じました。

最後までやってみたところで時間は結構余ったので、読み返しに結構時間が使えました。
採点結果としては実務経験がないこともあって、トラブルシューティングの得点はやはりよくありませんでした(なんと33%…)。
ここはやはり経験が生きるところなのだと思いますが、ドキュメントのトラブルシューティングをもっと読み込んでおけば良かったと後悔しています。

今後

趣味で終わらせるには勿体無い分野だと思うので、クラウド絡みのお仕事したいけど今のところじゃまずそんな仕事はないという…
でもプロフェッショナルもいずれはとってみたいので、やはり実務経験が欲しいところです。

続きを読む

AWSクラウド環境の構築からSpring Bootアプリのデプロイまで(初心者向け)

アプリケーションエンジニアとして、普段の仕事でインフラ設計をなかなか経験したことがないですが、AWSを通じてインフラ知識がほぼZeroの私でもインフラ基盤を気軽に構築できて感動しました。今回は、私と同じの初心者に向け、AWSクラウド環境の構築からSpring Bootアプリのデプロイまでの手順を共有します。

環境構成図

AWS構成について、東京リージョン内で2つのアベイラビリティゾーン(AZ)を使用した冗長構成を採用します。EC2インスタンスはその2つのAZに分散配置し、ALB(ロードバランサ)経由でアクセスを分散する構成とします。また、RDSインスタンスはEC2と同様に2つのAZに分散配置するようMulti-AZの構成とします。
この構成はAWSの無料利用枠を超えているため、料金がかかります!ご注意ください。
全体構成図.jpg

まず、VPCを構築します!

外部ネットワークからAWS内のインスタンスに到達できるように、AWS内の各インスタンスにIPアドレスが割り振られ、適切にルーティングされる必要があります。このような仮想ネットワークを提供しているサービスをAmazon Virtual Private Cloud(VPC)と言います。

VPCの構成について

練習とは言え、実戦に近いVPC環境を目指しています。今回のVPCは、インターネット通信用のパブリックサブネットとインターネットから遮断されるプライベートサブネットの2種類で構成されます。その2種類のサブネットへのアクセスを制御するために、それぞれに異なるセキュリティグループを適用します。APサーバーはパブリックサブネット上に構築し、DBサーバーはプライベートサブネット上に構築します。
VPC構成詳細.jpg

VPC作成

AWSアカウントを新規登録した後に、デフォルトのVPC環境が既に作られていましたが、今回はそれを利用せずに、一から以下のVPCを新規構築します。
vpc構成図.jpg

1.AWSマネジメントコンソールVPCをクリック⇒左のメニューからVPCを選択⇒VPCの作成ボタンを押下します。
2.VPCの作成画面に適当な名前を入力し、CIDRブロック欄にIPアドレス範囲に入力します。(今回は「10.0.0.0/16」を入力します。)
3.はい、作成するボタンを押下します。
VPC作成.jpg

サブネット作成

上記のVPCの中にサブネットを作成します。サブネットは複数のAZに跨って作成することはできないので、必ず1つのAZを指定して作成します。負荷分散と冗長化のために、APサーバー用サブネットとDBサーバー用サブネットをそれぞれ2つずつ構築します。
subnet構成.jpg

1.左のメニューからサブネットを選択⇒サブネットの作成ボタンを押下します。
2.サブネットの作成画面に、適当な名前入力し、上記作成されたVPCを選んでCIDRブロックを入力します。(Subnet1は「10.0.0.0/24」とします。)
subnet1作成.jpg
3.上記と同じの手順で、Subnet2、Subnet3、Subnet4を構築します。

Subnet AZ IPv4 CIDRブロック
public-subnet1 ap-northeast-1a 10.0.0.0/24
public-subnet2 ap-northeast-1c 10.0.1.0/24
private-subnet1 ap-northeast-1a 10.0.2.0/24
private-subnet2 ap-northeast-1c 10.0.3.0/24

完成後サブネット一覧画面
subnetList.jpg

インターネットゲートウェイ(IGW)とルートテーブルの作成

インターネットゲートウェイ(IGW)は、名前の通りにインターネットとの出入口であり、VPCと外部ネットワークの間で通信を行うために設置します。
また、上記作成されたサブネットがパブリックサブネットなのか、あるいはプライベートサブネットなのかは、そのサブネットに適用されているルートテーブルによって決まります。
送信先:0.0.0.0/0のターゲットとしてIGWが設定されているルートテーブルが適用されているサブネットはパブリックサブネットです。一方、送信先:0.0.0.0/0のターゲットとしてIGWが設定されていないルートテーブル(デフォルトのまま)が適用されているサブネットはプライベートサブネットです。
igw&rtb.jpg

1.左のメニューからインターネットゲートウェイを選択⇒インターネットゲートウェイの作成ボタンを押下します。
2.適当な名前を入力し、はい、作成するのボタンを押下します。
igw.jpg
3.VPCにアタッチのボタンを押下し、VPCとの紐付けを行います。
igw attache.jpg
4.左のメニューからルートテーブルを選択⇒ルートテーブルの作成ボタンを押下します。
5.パブリックサブネットであるSubnet1のルートテーブルを作成するために、適当な名前を入力し、VPCとの紐付けを行い、はい、作成するのボタンを押下します。
rtb1.jpg
6.上記と同様の手順で、public-rtb2を構築します。今回はプライベートサブネット用ルートテーブルを作成せずに、デフォルトのルートテーブルを使用します。
7.パブリックサブネット用のルートテーブルに、デフォルトゲートウェイ(送信先0.0.0.0/0)のターゲットにIGWを登録します。
route.jpg
ルートテーブル内の「10.0.0.0/16 local」というルート情報は、デフォルトの設定で変更・削除することができません。このデフォルト設定は、VPC内の通信はルートテーブルでは制御できないということで、同じVPC内のサブネットであればサブネット間の通信が可能なっていることを意味しています。

セキュリティグループの作成

セキュリティグループは、AWS内各インスタンスごとのファイアウォールで、受信(インバウンド)と送信(アウトバウンド)のアクセス制御ができます。各インスタンスには少なくとも1つのセキュリティグループを適用する必要があります。
VPC構成詳細.jpg
1.左のメニューからセキュリティグループを選択⇒セキュリティグループの作成ボタンを押下する。
2.APサーバー用セキュリティグループを作成するために、適当な名前を入力し、VPCへの紐付けを行い、はい、作成するのボタンを押下します。
sg作成.jpg
3.上記と同じの手順でDBサーバー用のセキュリティグループを作成します。
private sg.jpg
4.それぞれのセキュリティグループに受信(インバウンド)と送信(アウトバウンド)のルールを作成します。デフォルトでインバウンドは許可されているルールがないため、どこからのアクセスも受け付けません。一方、アウトバウンドは、デフォルトで全ての宛先/ポート番号に対するアクセスを許可するルールが設定されています。
外部からアクセスできように、APサーバー用セキュリティグループでSSHの22ポートとウェブアプリの8085ポートを開けておきます。
public inbound.jpg
一方、DBサーバー用セキュリティグループは、APサーバーからDBアクセスのみを許可するために、Auroraの3306ポートを開けておきます。
private sg rule.jpg

以上でVPCの構築が完了しました。

RDSインスタンスの構築

RDSは、リレーショナルデータベースのマネージャーサービスのことです。RDSで選択できるデータベースエンジンは、以下の6種類です。
・Amazon Aurora
・MySQL
・MariaDB
・PostgreSQL
・Oracle
・MS SQL Server
今回はAurora DBを構築します。Auroraは、MySQLと互換性のあるAWS独自のリレーショナルDBエンジンで、最大で MySQL の5倍のスループットおよび3倍の PostgreSQL スループットのパフォーマンスを持つと言われます。
RDS.jpg

サブネットグループの作成

DBインスタンス作成の前提条件として、VPC内でDBサブネットグループを指定する必要があります。
DB サブネットグループには、特定のリージョン内の少なくとも 2 つのアベイラビリティーゾーンにサブネットが必要です。 VPC に DB インスタンスを作成するときに、DB サブネットグループを選択する必要があります。Amazon RDS は、その DB サブネットグループと優先アベイラビリティーゾーンを使用し、サブネットとそのサブネット内の IP アドレスを選択して DB インスタンスに関連付けます。
1.AWSマネジメントコンソールRDSをクリック⇒左のメニューからサブネットグループを選択⇒サブネットグループの作成ボタンを押下します。
2.名前等を適当に入力し、2つのDB用サブネット(private subnet1、private subnet2)を追加し、作成ボタンを押下します。
db subnet group1.jpg

DBインスタンスの作成

1.左のメニューからインスタンスを選択⇒DBインスタンスの起動ボタンを押下します。
2.エンジンの選択画面にAmazon Auroraを選択します。
db1.jpg
3.DB詳細画面にて、DBインスタンスクラスなどを指定し、次のステップボタンを押下します。
※マルチAZ配置を選んだ場合、料金2倍かかります!
db2.jpg
4.VPC、DBサブネットグループ、優先AZ、およびセキュリティグループを指定します。
db3.jpg
5.設定完了後にDBインスタンスが作成中の状態であることを確認できます。
db4.jpg

EC2インスタンスの構築

やっと、EC2まで辿り着きました。Amazon Elastic Compute Cloud(EC2)は、AWSにおける仮想サーバのことです。今回負荷分散のために、2つのインスタンスを構築します。
EC2.jpg

EC2インスタンスの作成

1.AWSマネジメントコンソールEC2をクリック⇒左のメニューからインスタンスを選択⇒インスタンスの作成ボタンを押下します。
2.インスタンスの種類にAmazon Linuxを選択します。
ec21.jpg
3.インスタンスタイプ選択画面に、無料利用枠対象のタイプを選択します。
ec22.jpg
4.詳細設定画面に、VPCとサブネットを指定します。
ec23.jpg
5.ストレージを追加します。
ec24.jpg
6.APサーバー用セキュリティグループを指定します。
ec25.jpg
7.最後に、EC2にログインするためのキーペアをダウンロードし、インスタンスの作成ボタンを押下し、インスタンス作成が完了です。
ec26.jpg

ELASTIC IPの関連付け

上記のEC2インスタンスに対して、静的なパブリックIPアドレスを付与するために、ELASTIC IPの割り当てが必要です。
1.左のメニューからELASTIC IPを選択⇒新しいアドレスの割り当てボタンを押下します。
eip1.jpg
2.EC2インスタンスに関連付けを行います。
eip2.jpg

EC2環境の初期設定

Tera TermなどのSSHクライアントを使って上記のELASTIC IPを入力し、EC2インスタンスにアクセスします。
ec27.jpg
「ec2-user」ユーザーを使って、先ほどダウンロードしたキーでログインします。
ec28.jpg

tera term.jpg

無事にログインできたら、EC2の初期設定を行います。

# 最新のソフトウェアにアップデート
$ sudo yum update -y
# ホスト名変更
$ sudo hostname ec2-1-cinpo1
$ sudo vim /etc/sysconfig/network
HOSTNAME=ec2-cinpo1;
# ホストファイルを編集し、AWSから払い出された<Private IP>を書く。
$ echo "17X.XX.X.X30 ec2-cinpo1" |sudo tee -a /etc/hosts
# ホスト名確認
$ hostname -f
# タイムゾーン変更
# /etc/sysconfig/clockの編集
$ echo -e 'ZONE="Asia/Tokyo"nUTC=false' | sudo tee /etc/sysconfig/clock
# タイムゾーンファイルの変更
$ sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# 結果確認
$ date
# Java 8のインストール
$ sudo yum install java-1.8.0-openjdk.x86_64
# Java 8の選択
$ sudo alternatives --config java
# 結果確認
$ java -version

2台目のEC2を構築します。

上記と同じの手順で、2台目のEC2インスタンスを構築します。

Aurora環境へのデータ移植

# Auroraサーバーに接続するために、MySQLクライアントをインストールします。
$ sudo yum install mysql
# Auroraサーバーに接続し、データベースの新規作成やデータの移植を行います。
$ mysql -h <RDSインスタンスのエンドポイント> -u username -p
$ create database sampleDB

...下記省略...

mysql.jpg

Spring Bootアプリのデプロイ

1.Tera TermのSSH SCP転送を利用し、Spring Bootアプリをローカルから上記2つのEC2インスタンスにアップロードします。
2.完了後に、従来通りにSpring Bootアプリを起動します。

$ java -jar XXXXXXXX.jar

boot.jpg

3.この時点で、ELASTIC IP:8085 にアクセスしてみれば、アプリ画面が表示されるはずです。

ロードバランサーの作成

最後に、ロードバランサー(Application Load Balancer [ALB])を適用し、APサーバーの負荷分散を実現します。
ALB.jpg

ターゲットグループの構築

ALB適用の前提条件として、EC2インスタンスをターゲットとしてターゲットグループに登録する必要があります。ALBは、クライアントにとって単一の通信先として機能し、登録済みターゲットに受信トラフィックを分散します。
1.AWSマネジメントコンソールEC2をクリック⇒左のメニューからターゲットグループを選択⇒ターゲットグループの作成ボタンを押下します。
ALB1.jpg
2.ターゲットグループ一覧画面にて選択済みのターゲットグループにターゲットの登録を行います。
ALB2.jpg
3.EC2インスタンスをターゲットとしてターゲットグループに登録します。
ALB3.jpg

ALBの構築

1.左のメニューからロードバランサーを選択⇒ロードバランサーの作成ボタンを押下し、Application Load Balancerを選択します。
ALB4.jpg
2.名前を適当に指定し、リスナーとサブネット等を指定します。
ALB5.jpg
3.セキュリティグループを指定します。
ALB6.jpg
4.先ほど作成されたターゲットグループを指定します。
ALB7.jpg
5.作成中のステータスとなり、1~2分後に利用可能となります。
ALB8.jpg

動作確認

以上、AWS環境の構築からアプリのデプロイまで完成しました。
http://:ポート/にアクセスすれば、アプリ画面が表示されたら完成です。
final1.jpg

続きを読む