ALB（Application Load Balancer）でWebサービスを冗長化する

## 概要
[ALB](https://aws.amazon.com/jp/elasticloadbalancing/applicationloadbalancer/)を使ってアプリケーションを冗長化する手順です。

HTTPS接続でアプリケーションにアクセス出来るところまでをこの記事で紹介します。

## 前提条件
以下の事前条件が必要です。

- VPCの作成を行っておく
- 最低でも2台のWebサーバインスタンスを起動させておく事
- ロードバランサー用サブネットの作成が行われている事（後で説明します。）

## 事前準備その1（ロードバランサー用サブネットの作成）

以下は公式サイトに書かれている内容です。

>>ロードバランサーのアベイラビリティーゾーンを指定します。ロードバランサーは、これらのアベイラビリティーゾーンにのみトラフィックをルーティングします。アベイラビリティーゾーンごとに 1 つだけサブネットを指定できます。ロードバランサーの可用性を高めるには、2 つ以上のアベイラビリティーゾーンからサブネットを指定する必要があります。

今回検証で利用している東京リージョンには ```ap-northeast-1a``` と ```ap-northeast-1c``` の2つのアベイラビリティーゾーンが存在するので、それぞれでサブネットの作成を行います。

サービス → VPC → サブネット → 「サブネットの作成」より作成を行います。

```ap-northeast-1a``` で サブネットを作成します。
以下のように入力を行います。

- ネームタグ
    - account_api_alb_1a
    - 開発環境アカウント用APIのALB用と分かる名前を付けています。分かりやすい名前であれば何でも構いません。

- VPC
    - 利用対象となるVPCを選択します。

- IPv4 CIRD block
    - 192.0.30.0/24
    - ネットワークの設計方針にもよりますが今回は 192.0.30.0/24 を割り当てます。

![alb_subnet_step1.png](https://qiita-image-store.s3.amazonaws.com/0/71899/be93e985-8fd0-0959-91f8-6fab10daf2cb.png)

続いて ```ap-northeast-1c``` でも同じ要領でサブネットを作成します。
※先程とほとんど同じなので、入力内容に関しての詳細は省略します。

![alb_subnet_step2.png](https://qiita-image-store.s3.amazonaws.com/0/71899/387d9b42-92c1-5ccc-e726-64b419431c32.png)

## 事前準備その2（SSLの証明書の用意）

SSLで接続を可能にするのでSSL証明書の用意が必要です。

今回は検証なので自己証明書を利用する事にします。

以前、[LAMP 環境構築 PHP 7 MySQL 5.7（前編）](http://qiita.com/keita-nishimoto/items/5441244604fbc6db7907#ssl%E9%80%9A%E4%BF%A1%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E9%8D%B5%E3%81%AE%E7%94%9F%E6%88%90) という記事を書きました。

こちらに載っている手順を参考に自己証明書を用意します。

## ALB（Application Load Balancer）の新規作成

ここからが本題になります。
サービス → EC2 → ロードバランサー → ロードバランサーの作成 を選択します。

![alb_step1.png](https://qiita-image-store.s3.amazonaws.com/0/71899/04d5c951-f34d-68ce-4bf8-4c24e9eef207.png)


### Step1 ロードバランサーの設定

基本的な設定を行っていきます。
名前を入力します。（今回はaccount-api-alb）という名前を付けました。

インターネットに公開するサービスを想定しているので、スキーマは「インターネット向け」を選択します。

ロードバランサーのプロトコルにHTTPSを追加します。

![alb_step2-1.png](https://qiita-image-store.s3.amazonaws.com/0/71899/84f14f66-67a8-10c8-6ecf-d572ccf37d6f.png)

アベイラビリティーゾーンに先程作成したサブネットを割り当てます。

![alb_step2-2.png](https://qiita-image-store.s3.amazonaws.com/0/71899/d8b4324b-b7a9-a108-0d88-79ca6c903a8f.png)

### Step2 セキュリティ設定の構成

SSL証明書の設定を行います。

![alb_step2-3.png](https://qiita-image-store.s3.amazonaws.com/0/71899/6a3eafb9-3aeb-c180-092c-fd93a6450648.png)

証明書の名前は分かりやすい名前でOKです。

プライベートキーには事前準備で作成した、プライベートキーを入れます。
※ ```-----BEGIN RSA PRIVATE KEY-----``` から ```-----END RSA PRIVATE KEY-----``` までを全てコピーして下さい。

パブリックキー証明書には ```-----BEGIN CERTIFICATE-----``` から ```-----END CERTIFICATE-----``` までの内容を全てコピーして下さい。

セキュリティポリシーは ```ELBSecurityPolicy-2016-08``` を選択します。

※2017-05-22 現在、この手順で問題なく証明書の追加が出来るハズなのですが ```Certificate not found``` というエラーが発生しロードバランサーの作成に失敗してしまいます。

証明書のアップロードを [aws-cli](https://aws.amazon.com/jp/cli/) を使って事前に実施するようにしたら上手く行きました。

```bash:証明書のアップロード
aws iam upload-server-certificate --server-certificate-name self-certificate --certificate-body file://crt.crt --private-key file://private.key
```

```file://``` を付けるのがポイントです。これがないと上手くアップロード出来ませんでした。

```--server-certificate-name``` には任意の名前を入力して下さい。

上手く行くと下記のようなレスポンスが返ってきます。

```json:証明書アップロードのレスポンス
{
    "ServerCertificateMetadata": {
        "ServerCertificateId": "XXXXXXXXXXXXXXXXXXXXX",
        "ServerCertificateName": "self-certificate",
        "Expiration": "2018-05-22T04:14:02Z",
        "Path": "/",
        "Arn": "arn:aws:iam::999999999999:server-certificate/self-certificate",
        "UploadDate": "2017-05-22T05:58:44.754Z"
    }
}
```

アップロード完了後に「AWS Identity and Access Management(IAM)から、既存の証明書を選択する」を選んで先程アップロードした証明書を選択して下さい。

![alb_step2-3.1.png](https://qiita-image-store.s3.amazonaws.com/0/71899/98c253b0-aa60-d9f1-0987-091a03af507c.png)

この問題については [既存の ELB に SSL 証明書を追加しようとすると Server Certificate not found for the key というエラーになる件の解決方法](http://qiita.com/ynii/items/694d60614b98f73f780f) を参考にさせて頂きました。

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

セキュリティグループの設定を行います。

![alb_step2-4.png](https://qiita-image-store.s3.amazonaws.com/0/71899/93bb63a8-de96-3e70-6f90-51ec83e46aa6.png)

### Step4 ルーティングの設定

ターゲットグループの新規作成を行います。

![alb_step2-5.png](https://qiita-image-store.s3.amazonaws.com/0/71899/ef40c02d-0a9b-e071-7ea8-191de28da2ac.png)

名前、プロトコル、ヘルスチェック用のURLの設定等を行います。

### Step5 ターゲットの登録

ロードバランサーの配下で起動するインスタンスを選択します。

![alb_step2-6.png](https://qiita-image-store.s3.amazonaws.com/0/71899/a0c52f76-ca13-4757-f73a-87f6b4cae5ac.png)

作成に必要な情報入力は以上となります。

確認画面に進み作成を行いしばらくすると、ロードバランサーが作成され利用可能な状態となります。

※サービス → EC2 → ロードバランサー より確認が出来ます。

![alb_step3.png](https://qiita-image-store.s3.amazonaws.com/0/71899/9d980254-69d4-6dce-c8f1-04e150cdf3df.png)

## 動作確認

サービス → EC2 → ロードバランサー よりDNSが確認出来るので、動作確認を行います。

```
curl -kv https://account-api-alb-000000000.ap-northeast-1.elb.amazonaws.com/
```

```
*   Trying 0.0.0.0...
* TCP_NODELAY set
* Connected to account-api-alb-000000000.ap-northeast-1.elb.amazonaws.com (0.0.0.0) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: system
> GET / HTTP/1.1
> Host: account-api-alb-000000000.ap-northeast-1.elb.amazonaws.com
> User-Agent: curl/7.51.0
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Mon, 22 May 2017 07:26:02 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Server: nginx/1.12.0
< X-Request-Id: 76c7e41f-1a4e-4328-972c-b98055e84395
< Cache-Control: no-cache, private
<
* Curl_http_done: called premature == 0
* Connection #0 to host account-api-alb-000000000.ap-northeast-1.elb.amazonaws.com left intact
{"code":404,"message":"Not Found"}
```

各Webサーバのログを確認すると、処理が振り分けられているのが、確認出来ます。

## 本番環境での運用に向けて

ここまで簡単に作成が出来ましたが実環境で運用を行うにはまだまだ考慮が必要な点が多いです。

- SSL証明書を正式な物にする（自己証明書で運用とかはさすがに厳しいと思います）
- 独自ドメインでのアクセスを可能にする
- 各EC2のログに記載されているIPがロードバランサーの物になっている

※これらの手順は順次行っていく予定ですので、準備が出来次第記事を書く予定です。

最後まで読んで頂きありがとうございました。