[JAWS-UG CLI]Amazon AppStream 2.0 入門 (3) Fleetの作成・起動

# この記事について

[JAWS-UG CLI専門支部 #76 AppStream 2.0入門](https://jawsug-cli.doorkeeper.jp/events/52024)で実施するハンズオン用の手順書です。


# 前提条件

## 必要な権限

作業にあたっては、以下の権限を有したIAMユーザもしくはIAMロールを利用してください。

- AppStream(2.0)のフルコントロール権限
- EC2のフルコントロール権限
- CloudFormationの関するフルコントロール権限
- IAMの関するフルコントロール権限


# 0. 準備

## 0.1. リージョンを指定

```bash:コマンド
export AWS_DEFAULT_REGION="ap-northeast-1"
```

## 0.2. 資格情報を確認

```bash:コマンド
aws configure list
```

インスタンスプロファイルを設定したEC2インスタンスでアクセスキーを設定せずに実行した場合、以下のようになります。

```text:結果
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************QSAA         iam-role
secret_key     ****************c1xY         iam-role
    region                us-west-2              env    AWS_DEFAULT_REGION
```

## 0.3. バージョン確認

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

```text:結果
aws-cli/1.11.35 Python/2.7.12 Linux/4.4.35-33.55.amzn1.x86_64 botocore/1.4.92
```

## 0.4. バージョンアップ（必要に応じて）

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


# 1. Fleetの作成

## 1.1. Imageの確認

### imageとは

Applications that will be streamed to users accessing a stack. The image is used to launch streaming instances that are part of a fleet.

ユーザが独自にImageを作成し利用できる機能（Image Builder）がリリースされました。

[Amazon AppStream 2.0 Image Builder is now available](https://aws.amazon.com/about-aws/whats-new/2017/01/amazon-appstream-2-0-image-builder-is-now-available/)

### Imageの詳細の確認

```bash:コマンド
aws appstream describe-images
```

```json:結果
{
    "Images": [
        {
            "Description": "Image containing sample applications for Amazon AppStream2",
            "Applications": [
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/firefox.png",
                    "DisplayName": "Mozilla Firefox",
                    "Name": "firefox",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/eclipse.png",
                    "DisplayName": "Eclipse",
                    "Name": "eclipse",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/gimp.png",
                    "DisplayName": "Gimp",
                    "Name": "gimp",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/notepadplusplus_icon.png",
                    "DisplayName": "Notepad++",
                    "Name": "notepadplusplus",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/swriter_icon.png",
                    "DisplayName": "OpenOffice Writer",
                    "Name": "writer",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/scalc_icon.png",
                    "DisplayName": "OpenOffice Calc",
                    "Name": "calc",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/simpress_icon.png",
                    "DisplayName": "OpenOffice Impress",
                    "Name": "impress",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/sdraw_icon.png",
                    "DisplayName": "OpenOffice Draw",
                    "Name": "draw",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/smath_icon.png",
                    "DisplayName": "OpenOffice Math",
                    "Name": "math",
                    "Metadata": {}
                }
            ],
            "Visibility": "PUBLIC",
            "Platform": "WINDOWS",
            "State": "AVAILABLE",
            "CreatedTime": 1480540914.203,
            "Arn": "arn:aws:appstream:ap-northeast-1::image/Amazon-AppStream2-Sample-Image-12-1-16",
            "Name": "Amazon-AppStream2-Sample-Image-12-1-16"
        },
        {
            "DisplayName": "Amazon-AppStream2-Sample-Image-12-15-2016",
            "Name": "Amazon-AppStream2-Sample-Image-12-15-2016",
            "Applications": [
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/firefox.png",
                    "DisplayName": "Mozilla Firefox",
                    "Name": "firefox",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/eclipse.png",
                    "DisplayName": "Eclipse",
                    "Name": "eclipse",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/notepadplusplus_icon.png",
                    "DisplayName": "Notepad++",
                    "Name": "notepadplusplus",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/swriter_icon.png",
                    "DisplayName": "OpenOffice Writer",
                    "Name": "writer",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/scalc_icon.png",
                    "DisplayName": "OpenOffice Calc",
                    "Name": "calc",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/simpress_icon.png",
                    "DisplayName": "OpenOffice Impress",
                    "Name": "impress",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/sdraw_icon.png",
                    "DisplayName": "OpenOffice Draw",
                    "Name": "draw",
                    "Metadata": {}
                },
                {
                    "Enabled": true,
                    "IconURL": "https://s3.amazonaws.com/photon-application-icons-iad/smath_icon.png",
                    "DisplayName": "OpenOffice Math",
                    "Name": "math",
                    "Metadata": {}
                }
            ],
            "Visibility": "PUBLIC",
            "Platform": "WINDOWS",
            "State": "AVAILABLE",
            "CreatedTime": 1481832538.799,
            "Arn": "arn:aws:appstream:ap-northeast-1::image/Amazon-AppStream2-Sample-Image-12-15-2016",
            "Description": "Image containing sample applications for Amazon AppStream2."
        }
    ]
}
```

### Image名の確認

```bash:コマンド
aws appstream describe-images \
    --query "Images[].Name"
```

```json:結果
[
    "Amazon-AppStream2-Sample-Image-12-1-16",
    "Amazon-AppStream2-Sample-Image-12-15-2016",
    "AppStream2-Image-Builder-1-19-2017"
]
```

## 1.2. Fleetの作成

### Service Roleの作成

以下の手順に従い、Service Roleを定義します。（Fleetの作成時に必要です。）

[[JAWS-UG CLI] IAM #66 IAMロールの作成 (AmazonAppStreamServiceAccess)](http://qiita.com/tcsh/items/03b90dc7f0c08e8cc5d2)

[[JAWS-UG CLI] IAM #67 IAMロールのポリシー追加 (AmazonAppStreamServiceAccess)](http://qiita.com/tcsh/items/371f7d4aee390193c7e8)

Management ConsoleのAppStream 2.0のページで「Get Started」をクリックしている場合、上記のService Role(IAM Role)が自動で作成されています。

適宜、現状を確認の上で以降の手順を実施してください。


### fleetとは

A group of streaming instances on which users' applications are executed and from which the applications are streamed.

### Image名の指定

前の手順で出力されたImage名を指定します。
（アップデートなどで以下の例で設定したImageが存在しない可能性があります。）

```bash:コマンド（例）
IMAGE_NAME="Amazon-AppStream2-Sample-Image-12-15-2016"
```


### Fleet名の指定

```bash:コマンド
FLEET_NAME="FLEET_JAWSUG_CLI"
FLEET_DESCRIPTION="A fleet for test at jaws-ug"
FLEET_DISPLAY_NAME="FLEET_JAWSUG_CLI"
```


### 同名のFleetがないことを確認

```bash:コマンド
aws appstream describe-fleets \
    --query Fleets[?Name==\`${FLEET_NAME}\`]
```

```json:結果
[]
```


### その他パラメータの指定

MAX_USER_DURATION_IN_SECONDSでは、Streaming URL（後述）のセッションの有効期限を設定しています。
60～57600（秒？）の間の値を設定できます。

```text:ErrorMessage
An error occurred (InvalidParameterValueException) when calling the CreateFleet operation: The value for disconnectTimeout () must be between 60 and 57600
```

DISCONNECT_TIMEOUT_IN_SECONDSでは、切断からセッションの終了までの間隔を設定しています。（このパラメータで設定した時間以内に再接続すると、同一のセッションを再利用します。）
600～57600（秒）の間の値を設定できます。

```text:ErrorMessage
An error occurred (InvalidParameterValueException) when calling the CreateFleet operation: The value for maxLeaseDuration () must be between 600 and 57600
```


```bash:コマンド
INSTANCE_TYPE="stream.standard.medium"
MAX_USER_DURATION_IN_SECONDS="600"
DISCONNECT_TIMEOUT_IN_SECONDS="120"
```


### Compute Capacityの指定

COMPUTE_CAPACITYは、

```bash:コマンド
COMPUTE_CAPACITY="1"
COMPUTE_CAPACITY_FILE_NAME="compute_capacity.json"
```

```bash:コマンド
cat << EOF > ${COMPUTE_CAPACITY_FILE_NAME}
{
    "DesiredInstances": ${COMPUTE_CAPACITY}
}
EOF

cat ${COMPUTE_CAPACITY_FILE_NAME}
```

```json:結果
{
    "DesiredInstances": 1
}
```

```bash:コマンド
jsonlint -q ${COMPUTE_CAPACITY_FILE_NAME}
```


### Subnetの指定（変数の確認）

Fleetを稼働させるSubnetを指定します。
異なるAvailability ZoneのSubnetを1つずつ指定します。


```bash:コマンド
cat << ETX

    SUBNETID1: ${SUBNETID1}
    SUBNETID2: ${SUBNETID2}

ETX
```

```text:結果

    SUBNETID1: subnet-********
    SUBNETID2: subnet-********

```

```bash:コマンド
VPC_CONFIG_FILE_NAME="vpc_config.json"
```

```bash:コマンド
cat << EOF > ${VPC_CONFIG_FILE_NAME}
{
    "SubnetIds": ["${SUBNETID1}", "${SUBNETID2}"]
}
EOF

cat ${VPC_CONFIG_FILE_NAME}
```

```json:結果
{
    "SubnetIds": ["subnet-********", "subnet-********"]
}
```

```bash:コマンド
jsonlint -q ${VPC_CONFIG_FILE_NAME}
```


### 変数の確認

```bash:コマンド
cat << ETX

    FLEET_NAME: ${FLEET_NAME}
    IMAGE_NAME: ${IMAGE_NAME}
    INSTANCE_TYPE: ${INSTANCE_TYPE}
    COMPUTE_CAPACITY: ${COMPUTE_CAPACITY}
    COMPUTE_CAPACITY_FILE_NAME: ${COMPUTE_CAPACITY_FILE_NAME}
    SUBNETID1: ${SUBNETID1}
    SUBNETID2: ${SUBNETID2}
    VPC_CONFIG_FILE_NAME: ${VPC_CONFIG_FILE_NAME}
    MAX_USER_DURATION_IN_SECONDS: ${MAX_USER_DURATION_IN_SECONDS}
    DISCONNECT_TIMEOUT_IN_SECONDS: ${DISCONNECT_TIMEOUT_IN_SECONDS}
    FLEET_DESCRIPTION: ${FLEET_DESCRIPTION}

ETX
```

```text:結果

    FLEET_NAME: JAWSUG_CLI
    IMAGE_NAME: Amazon-AppStream2-Sample-Image-12-15-2016
    INSTANCE_TYPE: stream.standard.medium
    COMPUTE_CAPACITY: 1
    COMPUTE_CAPACITY_FILE_NAME: compute_capacity.json
    SUBNET_ID_a: subnet-********
    SUBNET_ID_c: subnet-********
    VPC_CONFIG_FILE_NAME: vpc_config.json
    MAX_USER_DURATION_IN_SECONDS: 600
    DISCONNECT_TIMEOUT_IN_SECONDS: 120
    FLEET_DESCRIPTION: A fleet for test at jaws-ug

```


### Fleetの作成

```bash:コマンド
aws appstream create-fleet \
    --name ${FLEET_NAME} \
    --image-name ${IMAGE_NAME} \
    --instance-type ${INSTANCE_TYPE} \
    --compute-capacity file://${COMPUTE_CAPACITY_FILE_NAME} \
    --vpc-config file://${VPC_CONFIG_FILE_NAME} \
    --max-user-duration-in-seconds ${MAX_USER_DURATION_IN_SECONDS} \
    --disconnect-timeout-in-seconds ${DISCONNECT_TIMEOUT_IN_SECONDS} \
    --description "${FLEET_DESCRIPTION}" \
    --display-name ${FLEET_DISPLAY_NAME}
```

```json:結果
{
    "Fleet": {
        "ComputeCapacityStatus": {
            "Available": 0,
            "Desired": 1,
            "Running": 0,
            "InUse": 0
        },
        "DisplayName": "JAWSUG_CLI",
        "Name": "JAWSUG_CLI",
        "VpcConfig": {
            "SubnetIds": [
                "subnet-********",
                "subnet-********"
            ]
        },
        "FleetErrors": [],
        "DisconnectTimeoutInSeconds": 900,
        "State": "STOPPED",
        "ImageName": "Amazon-AppStream2-Sample-Image-12-15-2016",
        "CreatedTime": 1483117639.89,
        "MaxUserDurationInSeconds": 3600,
        "InstanceType": "stream.standard.medium",
        "Arn": "arn:aws:appstream:ap-northeast-1:************:fleet/JAWSUG_CLI",
        "Description": "A fleet for test at jaws-ug"
    }
}
```


## 1.3. 作成したFleetの確認

```bash:コマンド
aws appstream describe-fleets \
    --names ${FLEET_NAME}
```

```json:結果
{
    "Fleets": [
        {
            "ComputeCapacityStatus": {
                "Available": 0,
                "Desired": 1,
                "Running": 0,
                "InUse": 0
            },
            "DisplayName": "JAWSUG_CLI",
            "Name": "JAWSUG_CLI",
            "VpcConfig": {
                "SubnetIds": [
                    "subnet-********",
                    "subnet-********"
                ]
            },
            "FleetErrors": [],
            "DisconnectTimeoutInSeconds": 900,
            "State": "STOPPED",
            "ImageName": "Amazon-AppStream2-Sample-Image-12-15-2016",
            "CreatedTime": 1483117639.89,
            "MaxUserDurationInSeconds": 3600,
            "InstanceType": "stream.standard.medium",
            "Arn": "arn:aws:appstream:ap-northeast-1:************:fleet/JAWSUG_CLI",
            "Description": "A fleet for test at jaws-ug"
        }
    ]
}
```


## 1.4. Stackへの関連づけ

作成したFleetは、Stackに関連づけることで利用できるようになります。
（この時点では、Management ConsoleではStackが確認できるだけでFleetの存在を確認することはできません。）

### 変数の確認

```bash:コマンド
cat << ETX

    FLEET_NAME: ${FLEET_NAME}
    STACK_NAME: ${STACK_NAME}

ETX
```

```text:結果

    FLEET_NAME: FLEET_JAWSUG_CLI
    STACK_NAME: STACK_JAWSUG_CLI

```


### Fleetに関連づけられたStackの確認

FleetがどのStackにも関連づけられていないことを確認します。

```bash:コマンド
aws appstream list-associated-stacks \
    --fleet-name ${FLEET_NAME}
```

```json:結果
{
    "Names": []
}
```


### Stackに関連づけられたFleetの確認

StackがどのFleetにも関連づけられていないことを確認します。

```bash:コマンド
aws appstream list-associated-fleets \
    --stack-name ${STACK_NAME}
```

```json:結果
{
    "Names": []
}
```


### FleetをStackに関連づける

```bash:コマンド
aws appstream associate-fleet \
    --fleet-name ${FLEET_NAME}\
    --stack-name ${STACK_NAME}
```

```text:結果
（返値無し）
```


### Fleetに関連づけられたStackの確認

```bash:コマンド
aws appstream list-associated-stacks \
    --fleet-name ${FLEET_NAME}
```

```json:結果
{
    "Names": [
        "STACK_JAWSUG_CLI"
    ]
}
```


### Stackに関連づけられたFleetの確認

```bash:コマンド
aws appstream list-associated-fleets \
    --stack-name ${STACK_NAME}
```

```json:結果
{
    "Names": [
        "FLEET_JAWSUG_CLI"
    ]
}
```


## 1.5. Fleetの起動

### 変数の確認

```bash:コマンド
cat << ETX

    FLEET_NAME: ${FLEET_NAME}

ETX
```

```text:結果

    FLEET_NAME: FLEET_JAWSUG_CLI

```


### Fleetの起動

```bash:コマンド
aws appstream start-fleet \
    --name ${FLEET_NAME}
```

```text:結果
（返値無し）
```


### 起動したFleetの確認

```bash:コマンド
aws appstream describe-fleets \
    --names ${FLEET_NAME}
```

```json:結果（実行直後）
{
    "Fleets": [
        {
            "ComputeCapacityStatus": {
                "Available": 0,
                "Desired": 1,
                "Running": 0,
                "InUse": 0
            },
            "DisplayName": "JAWSUG_CLI",
            "Name": "JAWSUG_CLI",
            "VpcConfig": {
                "SubnetIds": [
                    "subnet-********",
                    "subnet-********"
                ]
            },
            "FleetErrors": [],
            "DisconnectTimeoutInSeconds": 900,
            "State": "STARTING",
            "ImageName": "Amazon-AppStream2-Sample-Image-12-15-2016",
            "CreatedTime": 1483117639.89,
            "MaxUserDurationInSeconds": 3600,
            "InstanceType": "stream.standard.medium",
            "Arn": "arn:aws:appstream:ap-northeast-1:************:fleet/JAWSUG_CLI",
            "Description": "A fleet for test at jaws-ug"
        }
    ]
}
```

起動が完了するまで、20分ほど待ちます。


### 起動したFleetの確認（待機後）

```bash:コマンド
aws appstream describe-fleets \
    --names ${FLEET_NAME}
```

```json:結果
{
    "Fleets": [
        {
            "ComputeCapacityStatus": {
                "Available": 1,
                "Desired": 1,
                "Running": 1,
                "InUse": 0
            },
            "DisplayName": "JAWSUG_CLI",
            "Name": "JAWSUG_CLI",
            "VpcConfig": {
                "SubnetIds": [
                    "subnet-********",
                    "subnet-********"
                ]
            },
            "FleetErrors": [],
            "DisconnectTimeoutInSeconds": 900,
            "State": "RUNNING",
            "ImageName": "Amazon-AppStream2-Sample-Image-12-15-2016",
            "CreatedTime": 1483117639.89,
            "MaxUserDurationInSeconds": 3600,
            "InstanceType": "stream.standard.medium",
            "Arn": "arn:aws:appstream:ap-northeast-1:************:fleet/JAWSUG_CLI",
            "Description": "A fleet for test at jaws-ug"
        }
    ]
}
```

以上