[JAWS-UG CLI] Application Load Balancer 入門 #1

目的
========
AWS CLIを用いてApplication Load Balancer を構築します。
まずは通常のロードバランシングを行い、次にURLパスによる振り分けを行います。
アクセスログ、スティッキネス設定、振り分け先の登録解除、ロードバランサ削除防止機能など、
ロードバランサの設定情報を変更して各種コマンドの動作を学ぶことを目的とします。



前提条件
========

デフォルトVPCとサブネットが存在すること
-----------
東京リージョンにデフォルトVPCと、デフォルトVPCの各AZにサブネットが1つずつ存在すること。
（クラシックEC2が利用可能な古いアカウントは対象外です。無料で新規アカウントを作成してください）
アカウントを作成後、VPCに変更削除をしていなければ問題ありません。
何らかの変更を加えている方はVPCの知識があると思われますので適宜設定してください。

必要な権限
-----------

トラブル防止の為、全ての操作が可能なクレデンシャル（アカウント）を原則として使用してください。
（IAMの設定を理解されている方は、AmazonEC2FullAccess, AmazonS3FullAccess, AmazonVPCReadOnlyAccess, IAMReadOnlyAccess を付与してください。）

(参考) HTTPS終端について
-----------

SSL証明書を登録してロードバランサでHTTPS終端することができます。
独自ドメインが必要であるため、ハンズオン対象外ですが手順は記載しています。
HTTPS対応したい場合は事前にSSL証明書のARNを取得し、環境変数 CERT_ARN へ格納しておいてください。SSL証明書はACMで新規に作成しても、手持ちの証明書をIAMへアップロードしても構いません。
<A HREF="http://qiita.com/zakky/items/1b11c57388062ea542b4#1-ssl%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E4%BD%9C%E6%88%90" TARGET="_blank">ACMによる無料のSSL証明書取得手順はこちらから</A>。項番「1. SSL証明書の作成」のみ実行します（前後はELBへの接続手順なので不要）。

AWS CLI
-------

以下のバージョンで動作確認済

* AWS CLI 1.10.63

```bash:コマンド:
aws --version
```

```text:結果(例):
      aws-cli/1.10.63 Python/2.7.11 Darwin/15.6.0 botocore/1.4.53
```

注意：elbv2は2016年8月実装の新機能です。バージョン 1.10.57 より古い場合は動作しません。
次のコマンドを実行して最新版に更新しましょう。

```bash:コマンド:
sudo -H pip install -U awscli
```


0. 準備
=======


0.1. リージョンの決定
---------------------

今回は必ず東京リージョン(ap-northeast-1)で作業してください。
ハンズオンで使用するEC2 AMIが東京リージョンに置かれているからです。

```bash:変数の設定:
export AWS_DEFAULT_REGION='ap-northeast-1'
```

0.2. 変数の確認
---------------

プロファイルが想定のものになっていることを確認します。

```bash:変数の確認:
aws configure list
```
```text:結果(例):
            Name                    Value             Type    Location
            ----                    -----             ----    --------
         profile                <not set>             None    None
      access_key     ****************2LMA shared-credentials-file
      secret_key     ****************VXyK shared-credentials-file
          region           ap-northeast-1      config-file    ~/.aws/config
```

0.3. VPC IDの取得
---------------

```bash:コマンド:
VPC_ID=` aws ec2 describe-vpcs \
          --filters Name=isDefault,Values=true \
          --query 'Vpcs[].VpcId' \
          --output text ` && echo ${VPC_ID}
```

```text:結果(例):
      vpc-xxxxxxxx
```
ここで出力結果がこのように出ない方は、デフォルトVPCが存在しないか値を正しく取得できていません。
そのままでは以後の作業ができませんから、すぐにチューターまたは講師に声を掛けてください。

0.4. Subnet IDの取得
---------------

```bash:コマンド:
aws ec2 describe-subnets \
 --query "Subnets[?VpcId==\`${VPC_ID}\`].[SubnetId,CidrBlock]" --output text
```

```text:結果(例):
      subnet-11111111 172.31.0.0/20
      subnet-33333333 172.31.16.0/20
```

出力結果は左がsubnet id、右がそのサブネットのCIDRブロックです。
172.31.0.0/20のSubnet IDを変数 SUBNET_ID1 へ、172.31.16.0/20のものをSUBNET_ID2 へ、コピーペーストして変数へ格納します。

```bash:コマンド:
SUBNET_ID1="subnet-11111111"
SUBNET_ID2="subnet-33333333"
```





1. Webサーバ(EC2インスタンス)の作成
===========

1.1. 鍵ペアの作成
---------------

鍵ペア elbv2-handson を作成します。
秘密鍵ファイルは ~/.ssh/elbv2-handson.pem に保存されます。
まずは既にファイルが存在しないか確認します。

```bash:コマンド
EC2_KEY_NAME="elbv2-handson"
FILE_SSH_KEY="${HOME}/.ssh/${EC2_KEY_NAME}.pem"
ls ${FILE_SSH_KEY}
```
```text:結果(例):
      ls: cannot access /home/hoge/.ssh/elbv2-handson.pem: No such file or directory
```

もしもファイルが既に存在した場合は、 EC2_KEY_NAME を別な物に変更してやり直してください。
問題無ければ鍵ペアの作成を行います。

```bash:コマンド
aws ec2 create-key-pair --key-name ${EC2_KEY_NAME} --query 'KeyMaterial' \
 --output text > ${FILE_SSH_KEY} && cat ${FILE_SSH_KEY} && chmod 600 ${FILE_SSH_KEY}
```
```text:結果(例):
      -----BEGIN RSA PRIVATE KEY-----
      MIIEowIBAAKCAQEAg4AFnT934UdMmuSADElYSWzOQ/XpXUc0570zKwtDB3RXS9Fi8YP8J5jv6QRl
      adC9842sHMld7gxF2oqg2zDa82t0usKo27dutwziH+XK/HTOerza7FAGGwZM1vBz1WE5sEar1oWr
      DhWxXgJ1IXznORRPNzE697ljJjFYD/xlmh50pyn0e86ZuydXttlV8SinXEG0W67Ks/H/mfZLoAa6
      .....（本当はもっと長い）
      Kfx3RPKQlvaDpXOO60pIdn31RV16wxrxqTBxZ161XM6GMR1ltAp0FmQ9FQC76vBwgsDtxBidkz5e
      AqUB9GoLQ8npFPJBF+sRcDGD6EeHdI4fn2JhQXB+WOU5AoGBAKvXu+Xm1Kx6TSAsRchCyUdZmF2y
      MfRletfQDp2Hbth3SnNu2MaFQs8C+ODyx7XTx/13LW247AGVsSfq63jovntOL7PRuFA=
      -----END RSA PRIVATE KEY-----
```

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

セキュリティグループ elbv2-handson-sg を作成します。

```bash:コマンド:
SG_NAME="elbv2-handson-sg"
aws ec2 create-security-group --group-name ${SG_NAME} --description ${SG_NAME}
SG_ID=`aws ec2 describe-security-groups --filter Name=group-name,Values=${SG_NAME} \
 --query 'SecurityGroups[].GroupId' --output text` && echo ${SG_ID}
```
```text:結果(例):
      {
          "GroupId": "sg-59c3e63d"
      }

      sg-59c3e63d
```

外部からのHTTP接続をセキュリティグループに追加。

```bash:コマンド:
aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol 'tcp' --port 80 --cidr 0.0.0.0/0
```
```text:結果:
      返り値なし
```

(参考) HTTPS対応する場合のみ、外部からのHTTPS接続をセキュリティグループに追加。

```bash:コマンド:
aws ec2 authorize-security-group-ingress --group-id ${SG_ID} --protocol 'tcp' --port 443 --cidr 0.0.0.0/0
```
```text:結果:
      返り値なし
```



1.3. Webサーバ用EC2インスタンスの起動
-----------------------

今回はWebサーバをプレインストール済みのAMIを使用してWebサーバ用EC2インスタンスを起動します。
通常バランシング用のapache（緑）とnginx（青）サーバ、そしてURLパスルーティング用のWebサーバ（赤）の３台を起動します。


```bash:コマンド:
EC2_INSTANCE_TYPE="t2.micro"
EC2_IMAGE_ID="ami-fac2149b"
EC2_INSTANCE_IP1="172.31.0.201"
EC2_INSTANCE_PORT1=80
aws ec2 run-instances --private-ip-address ${EC2_INSTANCE_IP1} \
 --image-id ${EC2_IMAGE_ID} --instance-type ${EC2_INSTANCE_TYPE} \
 --key-name ${EC2_KEY_NAME} --security-group-ids ${SG_ID} --subnet-id ${SUBNET_ID1}
EC2_INSTANCE_ID1=$( aws ec2 describe-instances \
 --filters Name=private-ip-address,Values=${EC2_INSTANCE_IP1} \
 --query 'Reservations[].Instances[].InstanceId' \
 --output text ) && echo ${EC2_INSTANCE_ID1}

EC2_IMAGE_ID="ami-81c016e0"
EC2_INSTANCE_IP2="172.31.16.201"
EC2_INSTANCE_PORT2=80
aws ec2 run-instances --private-ip-address ${EC2_INSTANCE_IP2} \
 --image-id ${EC2_IMAGE_ID} --instance-type ${EC2_INSTANCE_TYPE} \
 --key-name ${EC2_KEY_NAME} --security-group-ids ${SG_ID} --subnet-id ${SUBNET_ID2}
EC2_INSTANCE_ID2=$( aws ec2 describe-instances \
 --filters Name=private-ip-address,Values=${EC2_INSTANCE_IP2} \
 --query 'Reservations[].Instances[].InstanceId' \
 --output text ) && echo ${EC2_INSTANCE_ID2}

EC2_IMAGE_ID="ami-58c51339"
EC2_INSTANCE_IP3="172.31.0.202"
EC2_INSTANCE_PORT3=80
aws ec2 run-instances --private-ip-address ${EC2_INSTANCE_IP3} \
 --image-id ${EC2_IMAGE_ID} --instance-type ${EC2_INSTANCE_TYPE} \
 --key-name ${EC2_KEY_NAME} --security-group-ids ${SG_ID} --subnet-id ${SUBNET_ID1}
EC2_INSTANCE_ID3=$( aws ec2 describe-instances \
 --filters Name=private-ip-address,Values=${EC2_INSTANCE_IP3} \
 --query 'Reservations[].Instances[].InstanceId' \
 --output text ) && echo ${EC2_INSTANCE_ID3}
```
```text:結果(例):
      {
          "OwnerId": "571972591141",
          "ReservationId": "r-5b18cfd4",
          "Groups": [],
          "Instances": [
              {
                  "Monitoring": {
                      "State": "disabled"
                  },
                  "PublicDnsName": "",
                  "RootDeviceType": "ebs",
                  "State": {
                      "Code": 0,
                      "Name": "pending"
                  },
                  "EbsOptimized": false,
                  "LaunchTime": "2016-09-15T04:45:19.000Z",
                  "PrivateIpAddress": "172.31.0.201",
                  "ProductCodes": [],
                  "VpcId": "vpc-15b0ec70",
                  "StateTransitionReason": "",
                  "InstanceId": "i-078f6d89",
                  "ImageId": "ami-fac2149b",
                  "PrivateDnsName": "ip-172-31-0-201.ap-northeast-1.compute.internal",
                  "KeyName": "elbv2-handson",
                  "SecurityGroups": [
                      {
                          "GroupName": "default",
                          "GroupId": "sg-377fcc53"
                      }
                  ],
                  "ClientToken": "",
                  "SubnetId": "subnet-692a7730",
                  "InstanceType": "t2.micro",
                  "NetworkInterfaces": [
                      {
                          "Status": "in-use",
                          "MacAddress": "0a:9f:07:54:45:af",
                          "SourceDestCheck": true,
                          "VpcId": "vpc-15b0ec70",
                          "Description": "",
                          "NetworkInterfaceId": "eni-d8dad885",
                          "PrivateIpAddresses": [
                              {
                                  "PrivateDnsName": "ip-172-31-0-201.ap-northeast-1.compute.internal",
                                  "Primary": true,
                                  "PrivateIpAddress": "172.31.0.201"
                              }
                          ],
                          "PrivateDnsName": "ip-172-31-0-201.ap-northeast-1.compute.internal",
                          "Attachment": {
                              "Status": "attaching",
                              "DeviceIndex": 0,
                              "DeleteOnTermination": true,
                              "AttachmentId": "eni-attach-666159cb",
                              "AttachTime": "2016-09-15T04:45:19.000Z"
                          },
                          "Groups": [
                              {
                                  "GroupName": "default",
                                  "GroupId": "sg-377fcc53"
                              }
                          ],
                          "SubnetId": "subnet-692a7730",
                          "OwnerId": "571972591141",
                          "PrivateIpAddress": "172.31.0.201"
                      }
                  ],
                  "SourceDestCheck": true,
                  "Placement": {
                      "Tenancy": "default",
                      "GroupName": "",
                      "AvailabilityZone": "ap-northeast-1c"
                  },
                  "Hypervisor": "xen",
                  "BlockDeviceMappings": [],
                  "Architecture": "x86_64",
                  "StateReason": {
                      "Message": "pending",
                      "Code": "pending"
                  },
                  "RootDeviceName": "/dev/xvda",
                  "VirtualizationType": "hvm",
                  "AmiLaunchIndex": 0
              }
          ]
      }
      i-078f6d89

      {
          "OwnerId": "571972591141",
          "ReservationId": "r-7f0dd6da",
          "Groups": [],
          "Instances": [
              {
                  "Monitoring": {
                      "State": "disabled"
                  },
                  "PublicDnsName": "",
                  "RootDeviceType": "ebs",
                  "State": {
                      "Code": 0,
                      "Name": "pending"
                  },
                  "EbsOptimized": false,
                  "LaunchTime": "2016-09-15T04:47:29.000Z",
                  "PrivateIpAddress": "172.31.16.201",
                  "ProductCodes": [],
                  "VpcId": "vpc-15b0ec70",
                  "StateTransitionReason": "",
                  "InstanceId": "i-5d3f2bc2",
                  "ImageId": "ami-81c016e0",
                  "PrivateDnsName": "ip-172-31-16-201.ap-northeast-1.compute.internal",
                  "KeyName": "elbv2-handson",
                  "SecurityGroups": [
                      {
                          "GroupName": "default",
                          "GroupId": "sg-377fcc53"
                      }
                  ],
                  "ClientToken": "",
                  "SubnetId": "subnet-67919410",
                  "InstanceType": "t2.micro",
                  "NetworkInterfaces": [
                      {
                          "Status": "in-use",
                          "MacAddress": "06:76:ae:af:bc:81",
                          "SourceDestCheck": true,
                          "VpcId": "vpc-15b0ec70",
                          "Description": "",
                          "NetworkInterfaceId": "eni-129dd458",
                          "PrivateIpAddresses": [
                              {
                                  "PrivateDnsName": "ip-172-31-16-201.ap-northeast-1.compute.internal",
                                  "Primary": true,
                                  "PrivateIpAddress": "172.31.16.201"
                              }
                          ],
                          "PrivateDnsName": "ip-172-31-16-201.ap-northeast-1.compute.internal",
                          "Attachment": {
                              "Status": "attaching",
                              "DeviceIndex": 0,
                              "DeleteOnTermination": true,
                              "AttachmentId": "eni-attach-e6dc114b",
                              "AttachTime": "2016-09-15T04:47:29.000Z"
                          },
                          "Groups": [
                              {
                                  "GroupName": "default",
                                  "GroupId": "sg-377fcc53"
                              }
                          ],
                          "SubnetId": "subnet-67919410",
                          "OwnerId": "571972591141",
                          "PrivateIpAddress": "172.31.16.201"
                      }
                  ],
                  "SourceDestCheck": true,
                  "Placement": {
                      "Tenancy": "default",
                      "GroupName": "",
                      "AvailabilityZone": "ap-northeast-1a"
                  },
                  "Hypervisor": "xen",
                  "BlockDeviceMappings": [],
                  "Architecture": "x86_64",
                  "StateReason": {
                      "Message": "pending",
                      "Code": "pending"
                  },
                  "RootDeviceName": "/dev/xvda",
                  "VirtualizationType": "hvm",
                  "AmiLaunchIndex": 0
              }
          ]
      }
      i-5d3f2bc2

      {
          "OwnerId": "571972591141",
          "ReservationId": "r-4019cecf",
          "Groups": [],
          "Instances": [
              {
                  "Monitoring": {
                      "State": "disabled"
                  },
                  "PublicDnsName": "",
                  "RootDeviceType": "ebs",
                  "State": {
                      "Code": 0,
                      "Name": "pending"
                  },
                  "EbsOptimized": false,
                  "LaunchTime": "2016-09-15T04:50:31.000Z",
                  "PrivateIpAddress": "172.31.0.202",
                  "ProductCodes": [],
                  "VpcId": "vpc-15b0ec70",
                  "StateTransitionReason": "",
                  "InstanceId": "i-f88f6d76",
                  "ImageId": "ami-58c51339",
                  "PrivateDnsName": "ip-172-31-0-202.ap-northeast-1.compute.internal",
                  "KeyName": "elbv2-handson",
                  "SecurityGroups": [
                      {
                          "GroupName": "default",
                          "GroupId": "sg-377fcc53"
                      }
                  ],
                  "ClientToken": "",
                  "SubnetId": "subnet-692a7730",
                  "InstanceType": "t2.micro",
                  "NetworkInterfaces": [
                      {
                          "Status": "in-use",
                          "MacAddress": "0a:c9:4d:f9:ea:83",
                          "SourceDestCheck": true,
                          "VpcId": "vpc-15b0ec70",
                          "Description": "",
                          "NetworkInterfaceId": "eni-2cdedc71",
                          "PrivateIpAddresses": [
                              {
                                  "PrivateDnsName": "ip-172-31-0-202.ap-northeast-1.compute.internal",
                                  "Primary": true,
                                  "PrivateIpAddress": "172.31.0.202"
                              }
                          ],
                          "PrivateDnsName": "ip-172-31-0-202.ap-northeast-1.compute.internal",
                          "Attachment": {
                              "Status": "attaching",
                              "DeviceIndex": 0,
                              "DeleteOnTermination": true,
                              "AttachmentId": "eni-attach-07625aaa",
                              "AttachTime": "2016-09-15T04:50:31.000Z"
                          },
                          "Groups": [
                              {
                                  "GroupName": "default",
                                  "GroupId": "sg-377fcc53"
                              }
                          ],
                          "SubnetId": "subnet-692a7730",
                          "OwnerId": "571972591141",
                          "PrivateIpAddress": "172.31.0.202"
                      }
                  ],
                  "SourceDestCheck": true,
                  "Placement": {
                      "Tenancy": "default",
                      "GroupName": "",
                      "AvailabilityZone": "ap-northeast-1c"
                  },
                  "Hypervisor": "xen",
                  "BlockDeviceMappings": [],
                  "Architecture": "x86_64",
                  "StateReason": {
                      "Message": "pending",
                      "Code": "pending"
                  },
                  "RootDeviceName": "/dev/xvda",
                  "VirtualizationType": "hvm",
                  "AmiLaunchIndex": 0
              }
          ]
      }
      i-f88f6d76
```




2. アプリケーションロードバランサの作成
=================

2.1. ロードバランサの作成
-----------------------

```bash:コマンド
ELB_NAME="elbv2-handson-lb"
ELB_ARN=`aws elbv2 create-load-balancer --name ${ELB_NAME} \
 --subnets ${SUBNET_ID1} ${SUBNET_ID2} --security-groups ${SG_ID} \
 --query LoadBalancers[].LoadBalancerArn --output text `
aws elbv2 describe-load-balancers --load-balancer-arns ${ELB_ARN}
```
```text:結果(例):
      {
          "LoadBalancers": [
              {
                  "VpcId": "vpc-15b0ec70",
                  "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:loadbalancer/app/elbv2-handson-lb/666a7169294ec5bc",
                  "State": {
                      "Code": "provisioning"
                  },
                  "DNSName": "elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com",
                  "SecurityGroups": [
                      "sg-c2a4b2a6"
                  ],
                  "LoadBalancerName": "elbv2-handson-lb",
                  "CreatedTime": "2016-09-13T13:05:11.480Z",
                  "Scheme": "internet-facing",
                  "Type": "application",
                  "CanonicalHostedZoneId": "Z14GRHDCWA56QT",
                  "AvailabilityZones": [
                      {
                          "SubnetId": "subnet-67919410",
                          "ZoneName": "ap-northeast-1a"
                      },
                      {
                          "SubnetId": "subnet-692a7730",
                          "ZoneName": "ap-northeast-1c"
                      }
                  ]
              }
          ]
      }
```


2.2. ターゲットグループの作成 (デフォルトアクション用)
-----------------

デフォルトアクション(リスナへ届いた通常のアクセスの転送先)用のターゲットグループを作成します。

```bash:コマンド:
ELB_TG_NAME="elbv2-handson-tg"
ELB_TG_ARN=`aws elbv2 create-target-group --name ${ELB_TG_NAME} \
 --protocol HTTP --port 80 --vpc-id ${VPC_ID} \
 --query TargetGroups[].TargetGroupArn --output text `
aws elbv2 describe-target-groups --target-group-arns ${ELB_TG_ARN}
```
```text:結果(例):
      {
          "TargetGroups": [
              {
                  "HealthCheckPath": "/",
                  "HealthCheckIntervalSeconds": 30,
                  "VpcId": "vpc-15b0ec70",
                  "Protocol": "HTTP",
                  "HealthCheckTimeoutSeconds": 5,
                  "HealthCheckProtocol": "HTTP",
                  "LoadBalancerArns": [],
                  "UnhealthyThresholdCount": 2,
                  "HealthyThresholdCount": 5,
                  "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg/0dc3bae28b0c8b99",
                  "Matcher": {
                      "HttpCode": "200"
                  },
                  "HealthCheckPort": "traffic-port",
                  "Port": 80,
                  "TargetGroupName": "elbv2-handson-tg"
              }
          ]
      }
```


2.3. ターゲットグループへターゲットを登録
-----------------

ターゲット(Webサービスのインスタンス)をターゲットグループへ登録します。
インスタンスIDとポート番号の組み合わせで登録するので、コンテナインスタンスで複数のWebサービスコンテナが稼働していてもそれらを登録することができます。
ポート番号はターゲットグループのデフォルト値である場合、省略可能です。

```bash:コマンド:
aws elbv2 register-targets --target-group-arn ${ELB_TG_ARN} \
 --targets Id=${EC2_INSTANCE_ID1},Port=${EC2_INSTANCE_PORT1} Id=${EC2_INSTANCE_ID2}
```
```text:結果:
      返り値なし
```

ポート番号をここでは全て指定していますが、ターゲットグループで設定したポート番号をインスタンス側でも使用する場合は省略可能です。(この例ではtcp/80)
何か表示されたらエラーなので確認しましょう。


2.4. リスナの作成
-----------------

最後に外部からHTTP(tcp/80)でアクセスを受けるリスナを作成して、先に作成したターゲットグループを接続してアクセスできるようにします。

```bash:コマンド:
ELB_LISTENER_ARN=`aws elbv2 create-listener --load-balancer-arn ${ELB_ARN} \
 --protocol HTTP --port 80 \
 --default-actions Type=forward,TargetGroupArn=${ELB_TG_ARN} \
 --query Listeners[].ListenerArn --output text `
aws elbv2 describe-listeners --listener-arns ${ELB_LISTENER_ARN}
```
```text:結果(例):
      {
          "Listeners": [
              {
                  "Protocol": "HTTP",
                  "DefaultActions": [
                      {
                          "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg/0dc3bae28b0c8b99",
                          "Type": "forward"
                      }
                  ],
                  "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:loadbalancer/app/elbv2-handson-lb/666a7169294ec5bc",
                  "Port": 80,
                  "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener/app/elbv2-handson-lb/666a7169294ec5bc/5a9991ad284ddc19"
              }
          ]
      }
```


2.4.1. (参考) SSL証明書を使用したHTTPS終端リスナの作成
-----------------

※ 本項はSSL証明書を取得している場合のみ実行します。
SSL証明書のARNが環境変数 CERT_ARN へ格納されているものとします。

```bash:コマンド:
ELB_LISTENER_ARN2=`aws elbv2 create-listener --load-balancer-arn ${ELB_ARN} \
 --protocol HTTPS --port 443 --certificates CertificateArn=${CERT_ARN} \
 --default-actions Type=forward,TargetGroupArn=${ELB_TG_ARN} \
 --query Listeners[].ListenerArn --output text `
aws elbv2 describe-listeners --listener-arns ${ELB_LISTENER_ARN2}
```
```text:結果(例):
      {
          "Listeners": [
              {
                  "Protocol": "HTTPS",
                  "DefaultActions": [
                      {
                          "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/hoge/e155d347d35f05f0",
                          "Type": "forward"
                      }
                  ],
                  "SslPolicy": "ELBSecurityPolicy-2015-05",
                  "Certificates": [
                      {
                          "CertificateArn": "arn:aws:acm:ap-northeast-1:571972591141:certificate/07150260-d46a-4a5f-8f20-900a9573d0a6"
                      }
                  ],
                  "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:loadbalancer/app/hoge/b6183b688ccfbdce",
                  "Port": 443,
                  "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener/app/hoge/b6183b688ccfbdce/c9dc5e52bde4de8e"
              }
          ]
      }
```



2.5. ターゲットのヘルスチェック状況確認
-----------------

```bash:コマンド:
aws elbv2 describe-target-health --target-group-arn ${ELB_TG_ARN}
```
```text:結果(例):
      {
          "TargetHealthDescriptions": [
              {
                  "HealthCheckPort": "80",
                  "Target": {
                      "Id": "i-5d3f2bc2",
                      "Port": 80
                  },
                  "TargetHealth": {
                      "State": "healthy"
                  }
              },
              {
                  "HealthCheckPort": "80",
                  "Target": {
                      "Id": "i-078f6d89",
                      "Port": 80
                  },
                  "TargetHealth": {
                      "State": "healthy"
                  }
              }
          ]
      }
```

State が healthy に２台ともなっていることを確認します。
initial である場合はヘルスチェックが規定回数まで達していないので少し待って再実行します。
unhealthy など他の内容が表示された場合は、チューターか講師へ声を掛けてください。


2.6. ブラウザでアクセスして確認
-----------------

アクセス用のURLを取得します。

```bash:コマンド:
DNSName=`aws elbv2 describe-load-balancers --load-balancer-arns ${ELB_ARN} \
 --query LoadBalancers[].DNSName --output text `
echo http://${DNSName}/
```
```text:結果(例):
      http://elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com/
```

HTTPS対応した方はhttpとhttpsの両方で確認しましょう。

出力されたURLへブラウザでアクセスしてみます。緑(apache)または青(nginx)が表示されるはずです。
ブラウザをリロードしてみてください。何度も繰り返すと緑と青が交互に切り替わり、ロードバランサにより振り分けられていることが確認できると思います。
DNS参照エラーで何も表示されない場合はDNSが浸透していませんのでしばらく待って試してください。
それ以外のエラーが出たら、チューターか講師に声を掛けて下さい。


3. ロードバランサの属性変更
=================

modify-load-balancer-attributes コマンドで以下の内容を変更できます。

- アクセスログをS3へ出力するか
- ロードバランサの誤削除防止機能を有効にするか
- アイドリング時のタイムアウト秒数の設定

|Key|Value|説明|
|:--|:--|:--|
|deletion_protection.enabled|true/false|削除保護機能が有効か|
|idle_timeout.timeout_seconds|秒|アイドリング時のタイムアウト時間|
|access_logs.s3.enabled|true/false|アクセスログをS3に保存するか|
|access_logs.s3.bucket|バケット名|アクセスログ保存先のS3バケット名|
|access_logs.s3.prefix|文字列|保存先S3バケットのプレフィックス(サブディレクトリ)|

変更したい設定項目のみ指定可能です。指定がない値は従前の値が継承されます。


3.1. アクセスログをS3バケットへ保存する
-----------------
アクセスログの保存先は

```
S3バケット/プレフィックス/AWSLogs/アカウントID/elasticloadbalancing/リージョン/年/月/日/
```
で、定期的に出力されます。
このように非常に階層が深いため今回は専用のバケットを作成し、プレフィックス無しで作成します。

ELBでは出力間隔時間をEmitIntervalで5分または60分で指定できましたが、ELBv2では時間指定はできません。

3.2. アクセスログ用S3バケットの作成
-----------------

ロードバランサがS3へログを出力するためのS3バケットを作成します。

```bash:コマンド:
LOGS_S3_BUCKET="elbv2-log-${VPC_ID}"
aws s3 mb s3://${LOGS_S3_BUCKET}
```
```text:結果(例):
      make_bucket: s3://elbv2-log-vpc-15b0ec70/
```

フォルダを作成する必要はありません。保存先はロードバランサによってプレフィックスを含め自動的に作成されます。


3.3. バケットポリシの作成
-----------------

ロードバランサがログを出力できるよう、バケットポリシーを設定する必要があります。

```bash:追加内容:
cat << EOF > ${LOGS_S3_BUCKET}.policy
{
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": {
            "AWS": "582318560864"
         },
         "Action": [
            "s3:PutObject"
         ],
         "Resource": "arn:aws:s3:::${LOGS_S3_BUCKET}/*"
      }
   ]
}
EOF
```

文中にあるプリンシパルの AWS: 582318560864 はリージョン毎に定められたELBのID(固定値)です。
他のリージョンを使用する場合、[こちらの公式ドキュメント](http://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/enable-access-logs.html#attach-bucket-policy) を参考に適宜変更してください。


3.4. バケットポリシの適用
-----------------

作成したバケットポリシを適用します。

```bash:コマンド:
aws s3api put-bucket-policy --bucket ${LOGS_S3_BUCKET} \
 --policy file://${LOGS_S3_BUCKET}.policy
```
```text:結果(例):
      返り値無し
```

適用されたポリシを確認します。

```bash:コマンド:
aws s3api get-bucket-policy --bucket ${LOGS_S3_BUCKET}
```
```text:結果(例):
      {
          "Policy": "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::582318560864:root\"},\"Action\":\"s3:PutObject\",\"Resource\":\"arn:aws:s3:::elbv2-log-vpc-15b0ec70/*\"}]}"
      }
```


3.5. アクセスログ出力設定を有効にする
-----------------

```bash:コマンド:
LOGS_S3_ENABLE="true"
LOGS_S3_PREFIX=""
aws elbv2 modify-load-balancer-attributes \
 --load-balancer-arn  ${ELB_ARN} \
 --attributes Key=access_logs.s3.enabled,Value=${LOGS_S3_ENABLE} \
   Key=access_logs.s3.bucket,Value=${LOGS_S3_BUCKET} \
   Key=access_logs.s3.prefix,Value=${LOGS_S3_PREFIX}
```
```text:結果(例):
      {
          "Attributes": [
              {
                  "Value": "true",
                  "Key": "access_logs.s3.enabled"
              },
              {
                  "Value": "elbv2-log-vpc-15b0ec70",
                  "Key": "access_logs.s3.bucket"
              },
              {
                  "Value": "elbv2-handson-lb-",
                  "Key": "access_logs.s3.prefix"
              },
              {
                  "Value": "60",
                  "Key": "idle_timeout.timeout_seconds"
              },
              {
                  "Value": "false",
                  "Key": "deletion_protection.enabled"
              }
          ]
      }
```

アクセスログはリアルタイムに出力されるわけではないので、後で確認することにしましょう。




4. パスベースドルーティングの実装
=================

特定のURLパスのみ別のサーバ群へ振り分ける機能を実装します。
これは別のターゲットグループを作成し、リスナへルールを追加することで実現されます。
今回は /hoge/* へのアクセスをルーティングし、別途用意した赤いページを表示させます。


4.1. まずはブラウザで現在の表示を確認
-----------------

先ほどアクセスしたブラウザのURL末尾に /hoge/ を付けてアクセスします。

```text:URL例:
      http://elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com/hoge/
```
特に変わりなく、青または緑のページが表示されると思います。
この後、ブラウザは再度アクセスしますので閉じないでください。


4.2. ターゲットグループの作成 (ルールのアクション用)
-----------------

ルールにより振り分けられたトラヒックを処理するターゲットグループを追加します。
このサーバは /hoge/ へアクセスされる想定なので、ヘルスチェックパスも /hoge/ に設定しています。

```bash:コマンド:
ELB_TG_NAME2="elbv2-handson-tg2"
HEALTHCHECK_PATH="/hoge/"
ELB_TG_ARN2=`aws elbv2 create-target-group --name ${ELB_TG_NAME2} \
 --protocol HTTP --port 80 --vpc-id ${VPC_ID} \
 --health-check-path=${HEALTHCHECK_PATH} \
 --query TargetGroups[].TargetGroupArn --output text `
aws elbv2 describe-target-groups --target-group-arns ${ELB_TG_ARN2}
```
```text:結果(例):
      {
          "TargetGroups": [
              {
                  "HealthCheckPath": "/hoge/",
                  "HealthCheckIntervalSeconds": 30,
                  "VpcId": "vpc-15b0ec70",
                  "Protocol": "HTTP",
                  "HealthCheckTimeoutSeconds": 5,
                  "HealthCheckProtocol": "HTTP",
                  "LoadBalancerArns": [],
                  "UnhealthyThresholdCount": 2,
                  "HealthyThresholdCount": 5,
                  "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg2/55c8683a3419f424",
                  "Matcher": {
                      "HttpCode": "200"
                  },
                  "HealthCheckPort": "traffic-port",
                  "Port": 80,
                  "TargetGroupName": "elbv2-handson-tg2"
              }
          ]
      }
```

4.3. ターゲットグループへターゲットを登録
-----------------

ターゲットのインスタンス(赤)をターゲットグループへ登録します。

```bash:コマンド:
aws elbv2 register-targets --target-group-arn ${ELB_TG_ARN2} \
 --targets Id=${EC2_INSTANCE_ID3}
```
```text:結果:
      返り値なし
```

4.4. リスナへルールを追加
-----------------

リスナへPass-Based Routingのルールを追加します。
URLパス一致条件を /hoge/* とし、アクセスを振り分けるターゲットグループを指定しています。
優先度は10としています。優先度はルールを複数設定した場合に、値の小さい順に評価され最初に合致した物が適用されます。

```bash:コマンド:
RULE_PATH="/hoge/*"
RULE_PRIORITY=10
aws elbv2 create-rule --listener-arn ${ELB_LISTENER_ARN} --priority ${RULE_PRIORITY} \
--conditions Field=path-pattern,Values=${RULE_PATH} \
--actions Type=forward,TargetGroupArn=${ELB_TG_ARN2}
```
```text:結果(例):
      {
          "Rules": [
              {
                  "Priority": "10",
                  "Conditions": [
                      {
                          "Field": "path-pattern",
                          "Values": [
                              "/hoge/*"
                          ]
                      }
                  ],
                  "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener-rule/app/elbv2-handson-lb/666a7169294ec5bc/5a9991ad284ddc19/20c2114505842535",
                  "IsDefault": false,
                  "Actions": [
                      {
                          "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg2/0da8cc3fe635736c",
                          "Type": "forward"
                      }
                  ]
              }
          ]
      }
```

4.4.1. (参考) HTTPSリスナへルールを追加
-----------------

HTTPSリスナを2.4.1.で設定している場合には、こちらも実行します。

```bash:コマンド:
aws elbv2 create-rule --listener-arn ${ELB_LISTENER_ARN2} --priority ${RULE_PRIORITY} \
--conditions Field=path-pattern,Values=${RULE_PATH} \
--actions Type=forward,TargetGroupArn=${ELB_TG_ARN2}
```
```text:結果(例):
      {
          "Rules": [
              {
                  "Priority": "10",
                  "Conditions": [
                      {
                          "Field": "path-pattern",
                          "Values": [
                              "/hoge/*"
                          ]
                      }
                  ],
                  "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener-rule/app/elbv2-handson-lb/666a7169294ec5bc/5a9991ad284ddc19/20c2114505842577",
                  "IsDefault": false,
                  "Actions": [
                      {
                          "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg2/0da8cc3fe635736c",
                          "Type": "forward"
                      }
                  ]
              }
          ]
      }
```



4.5. ルールの状況確認
-----------------

```bash:コマンド:
aws elbv2 describe-rules --listener-arn ${ELB_LISTENER_ARN}
```
```text:結果(例):
      {
          "Rules": [
              {
                  "Priority": "10",
                  "Conditions": [
                      {
                          "Field": "path-pattern",
                          "Values": [
                              "/hoge/*"
                          ]
                      }
                  ],
                  "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener-rule/app/elbv2-handson-lb/666a7169294ec5bc/5a9991ad284ddc19/20c2114505842535",
                  "IsDefault": false,
                  "Actions": [
                      {
                          "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg2/0da8cc3fe635736c",
                          "Type": "forward"
                      }
                  ]
              },
              {
                  "Priority": "default",
                  "Conditions": [],
                  "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:listener-rule/app/elbv2-handson-lb/666a7169294ec5bc/5a9991ad284ddc19/1a041d17234a0aea",
                  "IsDefault": true,
                  "Actions": [
                      {
                          "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg/0dc3bae28b0c8b99",
                          "Type": "forward"
                      }
                  ]
              }
          ]
      }
```

ルールは優先度順に表示されます。
優先度10で設定した /hoge/ へのルールが確認できますね。
一番最後にあるデフォルトの動作は、リスナ作成時に設定したものです。

(参考) HTTPSリスナを設定している場合は、同様に確認をします。

```bash:コマンド:
aws elbv2 describe-rules --listener-arn ${ELB_LISTENER_ARN2}
```
```text:結果:
      (省略)
```


4.6. ターゲットのヘルスチェック状況確認
-----------------

```bash:コマンド:
aws elbv2 describe-target-health --target-group-arn ${ELB_TG_ARN2}
```
```text:結果(例):
      {
          "TargetHealthDescriptions": [
              {
                  "HealthCheckPort": "80",
                  "Target": {
                      "Id": "i-f88f6d76",
                      "Port": 80
                  },
                  "TargetHealth": {
                      "State": "healthy"
                  }
              }
          ]
      }
```

State が healthy になっていることを確認します。
initial である場合はヘルスチェックが規定回数まで達していないので少し待って再実行します。
unhealthy など他の内容が表示された場合は、チューターか講師へ声を掛けてください。


4.7. ブラウザをリロードして確認
-----------------

ブラウザをリロードすると、赤いページに変わっているはずです。
続いてURL末尾の /hoge を取り除き / へアクセスしてみます。緑か青のページが表示されるはずです。
これでロードバランサによって /hoge/ 以下が赤へ振り分けられていることが確認できました。
ブラウザはこの後も使いますので / へアクセスした状態で閉じないでおいてください。




5. ターゲットグループの属性変更
=================

modify-target-group-attributes コマンドで以下の内容を変更できます。

- スティッキネスセッション管理を有効にするか
- セッション管理の方式
- ロードバランサが発行するcookieの有効期限
- 接続不能ターゲットを削除するまでの猶予時間

|Key|Value|説明|
|:--|:--|:--|
|deregistration_delay.timeout_seconds|秒|接続不能となったターゲットをdrainingからunusedに変更するまでの時間を0から3600秒の間で指定します。デフォルトは300秒。|
|stickiness.enabled|true/false|stickinessセッション管理が有効かどうか|
|stickiness.type|lb_cookie|sticky sessionの種類。現在は lb_cookie のみ|
|stickiness.lb_cookie.duration_seconds|秒|stickinessセッション管理で同じターゲットへ振り分けるためのcookieタイムアウト時間を1秒から604800秒(1週間)の間で指定します。デフォルトは1日(86400秒)|

変更したい設定項目のみ指定可能です。指定がない値は従前の値が継承されます。

### stickinessセッション管理とは
ロードバランサがクライアントへcookieを発行し、複数回アクセスがあってもcookieの有効期限内は最初に接続したターゲット（サーバ）へ接続されるよう振り分け時に制御を行うことです。
これにより毎回異なるサーバに振り分けられず、サーバでセッション管理を行うことができます。
注：従来のELBのようにサーバ生成のcookieによるセッション維持を行うことはできません。また、無期限のcookieを発行することはできません(最大7日)。

今回は stickiness を有効にして、ブラウザで何度リロードしても同一のサーバへ接続されるようになることを確認します。


5.1. スティッキネス設定の有効化
-----------------

デフォルトのターゲットグループ（現在赤と緑へ振り分けられる）へ有効期限3600秒(1時間)のスティッキネス設定を有効に設定します。

```bash:コマンド:
aws elbv2 modify-target-group-attributes \
 --target-group-arn  ${ELB_TG_ARN} \
 --attributes Key=stickiness.enabled,Value=true Key=stickiness.lb_cookie.duration_seconds,Value=3600
```
```text:結果(例):
      {
          "Attributes": [
              {
                  "Value": "true",
                  "Key": "stickiness.enabled"
              },
              {
                  "Value": "300",
                  "Key": "deregistration_delay.timeout_seconds"
              },
              {
                  "Value": "lb_cookie",
                  "Key": "stickiness.type"
              },
              {
                  "Value": "3600",
                  "Key": "stickiness.lb_cookie.duration_seconds"
              }
          ]
      }
```

設定が反映されるまで30秒程度かかります。一寸待ってから次に進んでください。


5.2. ブラウザでアクセスして確認
-----------------

ブラウザでアクセスしてみます。

```text:URL例:
      http://elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com/
```

リロードすると以前は緑と青が交互に表示されましたが、現在は何度リロードしても変化しなくなっていることが確認できると思います。
ブラウザはこの後も使いますので / へアクセスした状態で閉じないでおいてください。


5.3. スティッキネス設定を無効に戻す
-----------------

確認が済んだらスティッキネス設定を無効に戻します。

```bash:コマンド:
aws elbv2 modify-target-group-attributes \
 --target-group-arn  ${ELB_TG_ARN} \
 --attributes Key=stickiness.enabled,Value=false
```
```text:結果(例):
      {
          "Attributes": [
              {
                  "Value": "false",
                  "Key": "stickiness.enabled"
              },
              {
                  "Value": "300",
                  "Key": "deregistration_delay.timeout_seconds"
              },
              {
                  "Value": "lb_cookie",
                  "Key": "stickiness.type"
              },
              {
                  "Value": "3600",
                  "Key": "stickiness.lb_cookie.duration_seconds"
              }
          ]
      }
```

設定が反映されるまで30秒程度かかります。一寸待ってから次に進んでください。


5.4. ブラウザでアクセスして確認
-----------------

ブラウザでアクセスしてみます。
何度かリロードをすると、再び緑と青が交互に表示されるようになっているはずです。
これでスティッキネスの動作を確認できました。




6. ターゲットグループからターゲットを登録解除する
=================

緑と青が登録されているデフォルトルールのターゲットグループからターゲット緑を登録解除します。
その後、残りのターゲット（青）でアクセスが処理されることを確認します。


6.1. ターゲットの登録解除
-----------------

ターゲットを指定して登録解除します。

```bash:コマンド:
aws elbv2 deregister-targets \
 --target-group-arn  ${ELB_TG_ARN} \
 --targets Id=${EC2_INSTANCE_ID1},Port=${EC2_INSTANCE_PORT1}
```
```text:結果:
      返り値なし
```

学習のためPortを指定していますが、今回のような場合は省略しても動作します。
コンテナインスタンスなどでターゲットグループのデフォルトトラヒックポートと異なるポート番号を使用している場合、このようにターゲット指定でインスタンスIDと共にポート番号も明示しなければなりません。


6.2. ターゲットのヘルスチェック状況確認
-----------------

```bash:コマンド:
aws elbv2 describe-target-health --target-group-arn ${ELB_TG_ARN}
```
```text:結果(例):
      {
          "TargetHealthDescriptions": [
              {
                  "HealthCheckPort": "80",
                  "Target": {
                      "Id": "i-5d3f2bc2",
                      "Port": 80
                  },
                  "TargetHealth": {
                      "State": "healthy"
                  }
              },
              {
                  "Target": {
                      "Id": "i-078f6d89",
                      "Port": 80
                  },
                  "TargetHealth": {
                      "State": "draining",
                      "Reason": "Target.DeregistrationInProgress",
                      "Description": "Target deregistration is in progress"
                  }
              }
          ]
      }
```

登録解除したターゲットの State が draining になっていることが確認できます。


6.3. ブラウザでアクセスして確認
-----------------

ブラウザでアクセスしてみます。

```text:URL例:
      http://elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com/
```

何度リロードしても、青しか表示されないはずです。


7. ロードバランサ削除防止機能
=================

ELBv2の新機能として削除防止機能があります。EC2インスタンスのTermination Protectionと同等の機能です。
これはロードバランサの属性 deletion_protection.enabled により制御されます。


7.1. 削除防止機能を有効にする
-----------------

deletion_protection.enabled を true にセットすると有効になります。

```bash:コマンド:
aws elbv2 modify-load-balancer-attributes \
 --load-balancer-arn  ${ELB_ARN} \
 --attributes Key=deletion_protection.enabled,Value=true
```
```text:結果:
      {
          "Attributes": [
              {
                  "Value": "true",
                  "Key": "deletion_protection.enabled"
              },
              {
                  "Value": "true",
                  "Key": "access_logs.s3.enabled"
              },
              {
                  "Value": "60",
                  "Key": "idle_timeout.timeout_seconds"
              },
              {
                  "Value": "",
                  "Key": "access_logs.s3.prefix"
              },
              {
                  "Value": "elbv2-log-vpc-15b0ec70",
                  "Key": "access_logs.s3.bucket"
              }
          ]
      }
```

必ず出力内容をよく見て deletion_protection.enabled の Value が true であることを確認します。
なっていない場合はチューターか講師へ声を掛けてください。そのまま進むと悲しいことになります。


7.2. ロードバランサの削除を試みる
-----------------

実際にロードバランサの削除コマンドを実行して削除を試みます。

```bash:コマンド:
aws elbv2 delete-load-balancer \
 --load-balancer-arn  ${ELB_ARN}
```
```text:結果(例):
      An error occurred (OperationNotPermitted) when calling the DeleteLoadBalancer operation: Load balancer 'arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:loadbalancer/app/elbv2-handson-lb/666a7169294ec5bc' cannot be deleted because deletion protection is enabled
```

削除防止機能が有効のため、ロードバランサを削除できないことが確認できたと思います。
何も表示されなかった場合はロードバランサが削除されてしまったので、チューターか講師へ声を掛けてください。


7.3. 削除防止機能を無効に戻す
-----------------

deletion_protection.enabled を false にセットすると無効になります。

```bash:コマンド:
aws elbv2 modify-load-balancer-attributes \
 --load-balancer-arn  ${ELB_ARN} \
 --attributes Key=deletion_protection.enabled,Value=false
```
```text:結果:
      {
          "Attributes": [
              {
                  "Value": "false",
                  "Key": "deletion_protection.enabled"
              },
              {
                  "Value": "true",
                  "Key": "access_logs.s3.enabled"
              },
              {
                  "Value": "60",
                  "Key": "idle_timeout.timeout_seconds"
              },
              {
                  "Value": "",
                  "Key": "access_logs.s3.prefix"
              },
              {
                  "Value": "elbv2-log-vpc-15b0ec70",
                  "Key": "access_logs.s3.bucket"
              }
          ]
      }
```



8. アクセスログの確認
=================

8.1. アクセスログの一覧を取得
-----------------

アクセスログが保存されているS3バケットを確認します。

```bash:コマンド:
AWS_ID=`aws sts get-caller-identity --query Account --output text`
aws s3 ls ${LOGS_S3_BUCKET}/AWSLogs/${AWS_ID}/elasticloadbalancing/${AWS_DEFAULT_REGION}/2016/09/26/
```
```text:結果(例):
      2016-09-26 20:00:12       1155 571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0100Z_52.196.228.251_4czisvx0.log.gz
      2016-09-26 20:05:12        693 571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0105Z_52.196.228.251_rieunm58.log.gz
```

このように非常に長いファイル名が付けられています。


8.2. アクセスログの取得
-----------------

どれか適当にファイルを選び取得してみます。
出力結果からファイル名(12桁の数字で始まる長い文字列)をコピーペーストして s3 cp コマンドで自端末へコピーします。

```bash:コマンド(例):
aws s3 cp \
 s3://${LOGS_S3_BUCKET}/AWSLogs/${AWS_ID}/elasticloadbalancing/${AWS_DEFAULT_REGION}/2016/09/14/571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0905Z_52.196.228.251_2v18zssh.log.gz \
 ./
```
```text:結果(例):
      download: s3://elbv2-log-vpc-15b0ec70/AWSLogs/571972591141/elasticloadbalancing/ap-northeast-1/2016/09/26/571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0905Z_52.196.228.251_2v18zssh.log.gz to ./571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0905Z_52.196.228.251_2v18zssh.log.gz
```


8.3. ログファイルの内容確認
-----------------

ログファイルはgzip圧縮されたテキストファイルです。お好みの方法で内容を確認してください。

```text:ログファイルの内容(例):
http 2016-09-26T09:00:26.495817Z app/elbv2-handson-lb/666a7169294ec5bc 110.158.110.157:59014 172.31.18.28:80 -1 -1 -1 460 - 548 0 "GET http://elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com:80/ HTTP/1.1" "Mozilla/5.0 (Windows NT 5.2; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0" - - arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg/0dc3bae28b0c8b99
http 2016-09-26T09:00:26.941392Z app/elbv2-handson-lb/666a7169294ec5bc 110.158.110.157:59018 172.31.18.28:80 0.003 0.003 0.000 200 200 548 330 "GET http://elbv2-handson-lb-1654351783.ap-northeast-1.elb.amazonaws.com:80/ HTTP/1.1" "Mozilla/5.0 (Windows NT 5.2; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0" - - arn:aws:elasticloadbalancing:ap-northeast-1:571972591141:targetgroup/elbv2-handson-tg/0dc3bae28b0c8b99
```

独自書式ですが、およそアクセス解析に必要な情報は全て含まれていると思います。




9. 片付け
=================

9.1. ロードバランサの削除
-----------------

ロードバランサを削除します。
関連づけられたリスナやルールも自動的に削除されます。

```bash:コマンド:
aws elbv2 delete-load-balancer --load-balancer-arn ${ELB_ARN}
```
```text:結果:
      返り値なし
```

ロードバランサが削除されたことを確認します。

```bash:コマンド:
aws elbv2 describe-load-balancers
```
```text:結果:
      {
          "LoadBalancers": []
      }
```


9.2. ターゲットグループの削除
-----------------

ターゲットグループを削除します。
１つずつしか削除できないため、今回は２つ定義していますから２回実行します。

```bash:コマンド:
aws elbv2 delete-target-group --target-group-arn ${ELB_TG_ARN}

aws elbv2 delete-target-group --target-group-arn ${ELB_TG_ARN2}
```
```text:結果:
      返り値なし
```

ターゲットグループが削除されたことを確認します。

```bash:コマンド:
aws elbv2 describe-target-groups
```
```text:結果:
      {
          "TargetGroups": []
      }
```


9.3. S3バケットの削除
-----------------

中にログファイルが残っているけど強制的にS3バケットごと削除します。

```bash:コマンド:
aws s3 rb --force s3://${LOGS_S3_BUCKET}
```
```text:結果(例):
      delete: s3://elbv2-log-vpc-15b0ec70/AWSLogs/571972591141/elasticloadbalancing/ap-northeast-1/2016/09/14/571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0315Z_52.196.228.251_3xhum0x3.log.gz
      delete: s3://elbv2-log-vpc-15b0ec70/AWSLogs/571972591141/elasticloadbalancing/ap-northeast-1/2016/09/14/571972591141_elasticloadbalancing_ap-northeast-1_app.elbv2-handson-lb.666a7169294ec5bc_20160914T0100Z_52.196.228.251_4czisvx0.log.gz
      remove_bucket: s3://elbv2-log-vpc-15b0ec70/
```


9.4. EC2インスタンスの削除
-----------------

```bash:コマンド:
aws ec2 terminate-instances --instance-ids ${EC2_INSTANCE_ID1} ${EC2_INSTANCE_ID2} ${EC2_INSTANCE_ID3}
```
```text:結果(例):
      {
          "TerminatingInstances": [
              {
                  "InstanceId": "i-578a69d9",
                  "CurrentState": {
                      "Code": 32,
                      "Name": "shutting-down"
                  },
                  "PreviousState": {
                      "Code": 16,
                      "Name": "running"
                  }
              },
              {
                  "InstanceId": "i-ae848e31",
                  "CurrentState": {
                      "Code": 32,
                      "Name": "shutting-down"
                  },
                  "PreviousState": {
                      "Code": 16,
                      "Name": "running"
                  }
              },
              {
                  "InstanceId": "i-3d9399a2",
                  "CurrentState": {
                      "Code": 32,
                      "Name": "shutting-down"
                  },
                  "PreviousState": {
                      "Code": 16,
                      "Name": "running"
                  }
              }
          ]
      }
```

9.5. セキュリティグループの削除
-----------------

前項のEC2インスタンスの削除は数分程度の時間がかかります。
ちょっとコーヒーでも飲んでから次のコマンド実行へ進んでください。

```bash:コマンド:
aws ec2 delete-security-group --group-id ${SG_ID}
```
```text:結果:
      返り値なし
```

何らかのエラーが表示された場合、EC2インスタンスの削除が完了していないと思われます。
その場合、しばらく待ってから再度実行してみてください。

9.6. 鍵ペアの削除
-----------------

```bash:コマンド:
rm -f ${FILE_SSH_KEY}
aws ec2 delete-key-pair --key-name ${EC2_KEY_NAME}
```
```text:結果:
      返り値なし
```



10. 懇親会へ行きましょう！
=================

以上でハンズオン終了です。お疲れ様でした。
懇親会へ行きましょう。

今回のハンズオンで使用しなかったコマンドも多数有ります。
<A HREF="http://qiita.com/zakky/items/34be198d1816e99d7a1a" TARGET="_blank">CLIコマンドリファレンス</A>に全てのコマンドを収録してありますので、適宜参考にしてください。