IoTデバイスへの直接アクセスが可能になる「SORACOM Gate」のGatePeerをECS EC2タイプでスケールアウト出来るようにする

# SORACOM Gateとは
SORACOMで提供されているSIMカード（SORACOM Air）をIoTデバイスに挿すことでIoTデバイス - AWS VPC間をプライベートIPアドレスでリモートアクセスできるようにするサービスです。
https://soracom.jp/services/gate/

このサービスを利用すると、とても簡単に自分のAWS VPC内のインスタンスからIoTデバイスにアクセスできるようになります！
イメージはこんな感じ↓

<img width="80%" alt="スクリーンショット 2019-10-27 17.49.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106116/9c375eda-e6bb-4afc-7e3b-6039cbd8f7d7.png">

# やり方
ECS EC2タイプの場合、公式に案内されている[手順](https://dev.soracom.io/jp/start/gate/)とは若干異なるのでざっくり手順まとめました。

### SORACOM Canalを構築
https://dev.soracom.io/jp/start/canal/

### AWSでECSクラスターを作成
EC2タイプで作成します。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/create_cluster.html

### AUTO SCALINGグループを作成し、起動設定のユーザーデータを設定
こちらが今回の肝です。
下記をユーザーデータに設定してください。コンテナインスタンスはAmazon ECS-optimized Amazon Linux 2 AMIを利用します。

```sh:ユーザーデータ

#!/bin/bash -xe
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1 
# ↑ ユーザーデータの実行ログを/var/log/user-data.logで確認できるように

export FILE_VXLAN="/opt/gate_init_vxlan.sh"
export FILE_JQ="/usr/local/bin/jq"
export FILE_SORACOM="/usr/local/bin/soracom"
export PATH="/usr/local/bin":"$PATH"
# NOTE: 下記パラメーターはssmのパラメータストアやgit-cryptなど使ってください
export VPG_ID="soracom VPGのIDを設定する"
export AUTH_KEY_ID="soracom auth-key-idを設定する"
export AUTH_KEY="soracom auth-keyを設定する"

# ecsクラスター設定
echo ECS_CLUSTER=gate-peer >> /etc/ecs/ecs.config;echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config;

main() {
    # soracom cliの返却値がjsonなのでjqコマンドをつかう。
    if [ ! -e $FILE_JQ ];then
        curl -o $FILE_JQ -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
        chmod +x $FILE_JQ
    fi

    # soracom cliインストール
    if [ ! -e $FILE_SORACOM ];then
        curl -o /root/soracom_0.5.0_linux_amd64.tar.gz -L https://github.com/soracom/soracom-cli/releases/download/v0.5.0/soracom_0.5.0_linux_amd64.tar.gz
        tar xvf /root/soracom_0.5.0_linux_amd64.tar.gz -C /root
        cp /root/soracom_0.5.0_linux_amd64/soracom /usr/local/bin/.
        mkdir /root/.soracom
        # soracom cliの認証情報を生成
        echo "{\"sandbox\":false,\"coverageType\":\"jp\",\"authKeyId\":\"${AUTH_KEY_ID}\",\"authKey\":\"${AUTH_KEY}\",\"registerPaymentMethod\":false}" > /root/.soracom/default.json
        chmod 700 /root/.soracom/default.json
    fi

    LOCAL_IP=`ifconfig eth0 | awk '/inet / {gsub("addr:", "", $2); print $2}'`
    # ECSインスタンスをgatepeerとしてsoracomに登録し、登録したgatepeerと紐づくsoracom側VPC内のip取得
    echo "get GatePeer InnerIP"
    GATE_PEER_INNER_IP=`soracom vpg register-gate-peer --outer-ip-address "$LOCAL_IP" --vpg-id "$VPG_ID" | jq -r '.innerIpAddress'`
    # soracom側VPC内のGatePeer ip一覧取得
    echo "get soracom GatePeer IPs"
    SORACOM_GATE_PEER_IPS=`soracom vpg list-gate-peers --vpg-id $VPG_ID | jq -r '.[] | select(.ownedByCustomer==false) | .outerIpAddress' | tr '\n' ' '`

    # vxlanで論理L2ネットワークを構築する
    if [ ! -e $FILE_VXLAN ];then
        curl -o $FILE_VXLAN -l https://soracom-files.s3-ap-northeast-1.amazonaws.com/gate-peer-tools/gate_init_vxlan.sh
        chmod +x $FILE_VXLAN
    fi
    echo "${FILE_VXLAN} eth0 $LOCAL_IP vxlan0 $GATE_PEER_INNER_IP 9 $SORACOM_GATE_PEER_IPS"
    ${FILE_VXLAN} eth0 $LOCAL_IP vxlan0 $GATE_PEER_INNER_IP 9 $SORACOM_GATE_PEER_IPS
}

main

```

※ 注意点としてユーザーデータはスケールアウト時の１回しか実行されないため、再起動の時など、vxlanの再設定が必要になります。上記ユーザーデータは再起動までは考慮してません。


### ECSタスク定義のネットワークモードはHostに設定
ECSインスタンスのホスト側でGatePeerの設定を行うので、ECSタスク定義のネットワークモードはHostにして、ホスト側のネットワークインターフェースを利用できるようにしてください。

<img width="80%" alt="スクリーンショット 2019-10-27 17.30.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106116/cb92fcd0-e25a-c1d2-a19a-d4a215a63d1c.png">

### Gate Peer となる ECSインスタンスをSORACOMに登録する
https://dev.soracom.io/jp/start/gate/#step2

### Gateを有効にする
https://dev.soracom.io/jp/start/gate/#step4

### Gate Peer からデバイスに接続できることを確認する
https://dev.soracom.io/jp/start/gate/#step5


以上で完了です！
ちょっと面倒ですがNatゲートウェイ方式だとスケールアウトできないのでこの方法が現時点で一番良さそうな気がします。