AWS Cloud9はシンガポールリージョンでも使う価値はあるか？ その検証と報告

# はじめに

2017年の年末に「[Macに別れを告げて、クラウド中心の開発生活を始めるまで](https://qiita.com/cognitom/items/c489991a05f9abac748f)」という投稿を読んで、強く刺激を受けました。私も「Chrome縛り」をしてみたい（されてみたい？）と思うようになりました。

今回、AWSの東京リージョンに新しくWebサーバーをたてるという仕事をいただき、なにはともあれ（クライアントの）新アカウントを使って、シンガーポールリージョンに[AWS Cloud9](https://aws.amazon.com/jp/cloud9/)を構築してみました。果たして、そこから東京リージョンのWebサーバーをコントロールすることができるのか？ 以下はその報告です。

![AWS Networking (1).png](https://qiita-image-store.s3.amazonaws.com/0/48056/5ec2b82e-f397-6a96-7bc9-735dd4ce8074.png)

## まずは、シンガポールリージョンにCloud9開発環境を構築する

作業そのものは簡単でした。「[AWS Cloud9を動かしてみた](https://qiita.com/icck/items/7705ef6871e261d6535e)」という投稿に書いてある通りです。

![aws-cloud9-b.png](https://qiita-image-store.s3.amazonaws.com/0/48056/447040a4-d087-a40f-7e06-e0d350e60390.png)

右下のBashコンソールを操作してみます。

```bash
sudo yum update -y

cat /etc/system-release
#=> Amazon Linux AMI release 2017.09
git --version
#=> git version 2.13.6
node -v
#=> v6.13.1
npm -v
#=> 3.10.10
python --version
#=> Python 2.7.13
pip --version
#=> pip 9.0.3 from /usr/local/lib/python2.7/dist-packages (python 2.7)
aws --version
#=> aws-cli/1.14.9 Python/2.7.13 Linux/4.9.91-40.57.amzn1.x86_64 botocore/1.8.13
```

予想していたとおり、普通のAmazon Linuxです。
今までもWebサーバーにSSH接続したときは、Bashコンソールでコマンドを叩いてきましたけど、Cloud9にはGUIのファイルマネージャとテキストエディタがついています。「そうか、これはGNOME,KDEに続く、新しいLinuxのデスクトップ環境なんだ！」と思ったら、自分の中で腑に落ちました。

## 普通のAmazon Linuxなら、フツーにElastic IPをアサインできるんじゃね？

私が調べた時のシンガポールリージョンでのt2.microインスタンスの料金は、`$0.0146/h`でした。月720時間とすると`$10.51`です。
Elastic IPの料金は`$0.005/h`で月`$3.6`です。
Cloud9には、コストを節約するための設定がついていて、私も構築するときに、「30分経ったらEC2インスタンスを停止する」を選んでいます。Elastic IPをアサインしてしまったら、停止しているときもコストがかかるようになります。動作中のコストはかかりません。
つまり、`$0.00~$10.51`のコスト予想が、`$3.6~$10.51`のコスト予想になるということです。一瞬考えた末に、固定IPアドレスを取得してみることにしました。

```text
AWSマネジメントコンソール ＞ EC2 ＞ リージョンをシンガポールに変更
左枠 ＞ ネットワーク＆セキュリティ ＞ Elastic IP
右枠 ＞ 新しいアドレスの割り当てボタン ＞ 割り当てボタン
xxx.xxx.xxx.xxxを入手

右枠 ＞ そのIPを選んでから ＞ アクションドロップダウンリスト ＞ アドレスの関連付け
リソースタイプ： インスタンス
インスタンス： {Cloud9がインストールされているインスタンスのID}
プライベートIP： {Cloud9がインストールされているインスタンスのIP}
関連付けボタン
````
Cloud9に戻って、右上のShareボタンをクリックしたら、Application欄のIPアドレスがxxx.xxx.xxx.xxxになっていました。成功です。

![share_button.png](https://qiita-image-store.s3.amazonaws.com/0/48056/e428427f-a35a-7a02-128d-3d48fe4db046.png)

![ip_address.png](https://qiita-image-store.s3.amazonaws.com/0/48056/6801aedd-8d65-9b86-3ff4-6b86e3c92b7f.png)

## ならば、今後設置するWebサーバーはCloud9からだけSSH接続できるようにすればいいんじゃね？

東京リージョンのセキュリティグループには、このElastic IPからのSSH接続だけを許可するように設定します。

![security group.png](https://qiita-image-store.s3.amazonaws.com/0/48056/337cfee0-e06d-aac9-f7e9-e7a2f626a448.png)

そして、EC2インスタンスに接続するために必要なSSH鍵を、Cloud9に設置します。Cloud9はローカルのファイルをアップロードできます。

![file upload.png](https://qiita-image-store.s3.amazonaws.com/0/48056/42f2ecca-94a7-9e82-3084-3a39591238a0.png)

例えば、以下のようなコマンドを叩くと、Cloud9からWebサーバーにログインできるようになります。

```bash
ssh ec2-user@{webサーバーのIPアドレス} -i ~/.ssh/{アップしたSSH鍵}.pem
```
私は、もう場所にもPCにも縛られることなく、Cloud9にアクセスすることができれば（すなわち、AWSマネジメントコンソールにログインすることができれば）、Webサーバーを管理することができるようになりました。

## Cloud9は開発環境なんでしょ？ ソースコードの管理はどうするの？

Cloud9には、認証情報ヘルパーという機能があって、AWSのリソースを使うためのクレデンシャルが自動的に付与されます。[AWS CodeCommit](https://aws.amazon.com/jp/codecommit/)ならば、以下の作業だけでGitリポジトリとして使えるようになります。

```bash
# コミットをするためのいつもの準備
git config --global user.name "{自分の名前}"
git config --global.user.email {自分のメルアド}

# 認証情報ヘルパーを設定する
git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true

# リポジトリからクローンする
git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/{リポジトリ名}
```

CodeCommitは、シンガポールリージョンにも、東京リージョンにも用意されています。近い将来、Cloud9が東京リージョンに来たときのことを考えて、リポジトリは東京リージョンに作りました。

### 【上級問題】 アカウントをまたいだCodeCommitは使えるの？

プロファイルを切り替えれば、`~/.aws/credentials`ファイルに複数のクレデンシャルを設定できることをご存知の方は、このような疑問をお持ちになるでしょう。CodeCommitに限らず、アカウントをまたいだAWSリソースの操作、私もやってみたくなりました。しかし、それをやるとCloud9からめっちゃ怒られます。
「credentialsファイルを勝手にいじったら、認証情報ヘルパー効かなくなるで。どうなっても知らんからな。」 正直、私はブルッときましたね。
Cloud9開発環境はアカウントごとに作成するべきというのが今の結論です。

## 認証情報ヘルパーというアドバンテージを`aws-cli`で味わう

アカウントをまたいだリソースの操作はすべきではありませんが、リージョンをまたいだリソースの操作はなんの問題もありません。以下のようなBashスクリプトを書くと、東京リージョンでEC2インスタンスが一発で立ち上がります。（`--region`オプションで東京リージョンを指定するところがミソです。）

```bash:launch.sh
#!/bin/bash

echo "? input name ?"
read name

echo "First, searching ${name}..."
id=`aws ec2 describe-instances --region ap-northeast-1 \
    --filters "Name=tag:Name,Values=${name}" "Name=instance-state-name,Values=running" \
    --query "Reservations[0].Instances[0].InstanceId" \
    --output text`

if [ "${id}" != "None"  ]; then
    echo "Error, ${id} is running."
    exit 2
else
    echo "OK! launching ${name}..."
fi

subnet={あらかじめ用意したサブネットのID}
sg={あらかじめ用意したセキュリティグループのID}
image={あらかじめ選んだAMIのID}
type={t2.nano, t2.small, t2.medium...}
key={あらかじめ用意したSSH鍵の名称}

aws ec2 run-instances --region ap-northeast-1 \
    --subnet-id ${subnet} \
    --security-group-ids ${sg} \
    --image-id ${image} \
    --instance-type ${type} \
    --key-name ${key} --count 1 \
    --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=${name}}]" \
    --output table \
    --no-dry-run
```

立ち上がったインスタンスに、Elastic IPを与えるスクリプトはこんな感じです。

```bash:assign-ip.sh
#!/bin/bash

echo "? input name ?"
read name
case "${name}" in
    "web1" ) ip=xxx.xxx.xxx.xxx;;
    ...
    * ) exit 2;;
esac

echo "First, searching ${name}..."
id=`aws ec2 describe-instances --region ap-northeast-1 \
    --filters "Name=tag:Name,Values=${name}" "Name=instance-state-name,Values=running" \
    --query "Reservations[0].Instances[0].InstanceId" \
    --output text`

if [ "${id}" = "None"  ]; then
    echo "Error, ${name} is not running."
    exit 2
else
    echo "OK, assigning ip to ${name}..."
    aws ec2 associate-address --region ap-northeast-1 \
        --instance-id ${id} --public-ip ${ip} \
        --output table
fi
```

「クレデンシャルの設定抜きで、これができちゃうのってラクだわーっ」て思うのは私だけでしょうか？

## そして、AnsibleでWebサーバーの内部構成の設定を行う

Cloud9にAnsibleをインストールできました `sudo pip install ansible`

詳しい説明は省きますが、以下のようなファイル構成でAnsibleを動かします。

```text
|--- templates\
  `---　nginx.conf
|-- ansible.cfg
|-- hosts
|-- setup.yml
|-- ssh_config
```

nginx.confを除いたファイルの中身を披露します。

```text:ansible.cfg
[defaults]
inventory = ./hosts
retry_files_enabled = False
host_key_checking = False
command_warnings = False

[ssh_connection]
ssh_args = -F ssh_config
```

```text:hosts
[all]
web1
```

```yaml:setup.yml
---
- hosts: all
- become: yes
  tasks:
    - name: set timezone to Asia/Tokyo
      timezone:
        name: Asia/Tokyo

    - name: update installed packages
      yum: name=* state=latest

    - name: install new apps
      yum: name=nginx state=installed

    - name: backup original files
      shell: mv /etc/nginx/nginx.conf /etc/nginx/nginx.original

    - name: copy new files
      template:
        src: ./templates/nginx.conf
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: "644"

    - name: start apps
      service: name=nginx state=started enabled=yes
```

```text:ss_config
Host web1
  User ec2-user
  HostName xxx.xxx.xxx.xxx
  IdentityFile ~/.ssh/{アップしたSSH鍵}.pem
```

`ansible-playbook setup.yml`と叩くと、webサーバーへのnginxのインストールが終わります。

## ソースコードのデプロイにはGitを使う

話が長くなって疲れてしまいました。興味がある方は、この記事を参照してください => 「[SSH接続があればGitでデプロイできる](https://qiita.com/isamusuzuki/items/794f4d44648c2f7a8239)」

# 今回のまとめ

私は、Chromeブラウザと、AWSマネジメントコンソールにログインするためのパスワードだけを持っていれば、東京リージョンにあるWebサーバーを管理できるようになりました。インスタンスの起動から、サーバー内部の設定まで、すべてスクリプト化して、リポジトリに放り込むことができました。もちろんアプリケーションのソースコードも同様です。

正直に言うと、SSH鍵のコピーはさすがにローカルに保存しています。でも、これだっていつでも刷新できます。ついにクラウド中心の開発生活を達成できました。イエーイ。

![AWS Networking (1).png](https://qiita-image-store.s3.amazonaws.com/0/48056/5ec2b82e-f397-6a96-7bc9-735dd4ce8074.png)

## Cloud9が東京リージョンに来たらどうなる？

Elastic IPのアサインが不要になるので、~~セキュリティがさらに強固になり、そして設定がラクになると思います。~~私は、来た初日にCloud9を東京リージョンに移して~~、セキュリティグループに取り付けたSSH接続の許可を塞いで~~しまうと思います。

~~ただ、それほど移管作業は簡単なことでもあります。「まだ東京リージョンに来てないから、Cloud9への移行は待ちだわ」にはならないと思います。現時点では、SSH接続の許可がひとつもないサーバーは管理できないはずですからね。Cloud9を採用すれば、SSH接続の許可はひとつに集約できます。~~

**2018/04/14追記** Cloud9が動いているEC2インスタンスのセキュリティグループは、SSH接続の許可が全開になっています。これはログインに成功したブラウザがSSH接続しているからではないかと考えています。なので、Cloud9が東京リージョンに来ても、SSH接続が全閉になるわけではないです。「セキュリティがさらに強固になり、そして設定がラクになる」という発言は取り消します。

Cloud9が東京リージョンに来た初日の作業としては、Cloud9とWebサーバーを別のセキュリティグループにして、WebサーバーへのSSH接続は、Cloud9のセキュリティグループからのみ許可するように設定することになると思います。

![ssh.png](https://qiita-image-store.s3.amazonaws.com/0/48056/d3b023c9-c931-c1ad-385f-959a6a48493b.png)

## Cloud9採用の副産物

Gitコマンドに強くなりました。まさか私が`git reset`コマンドを使うようになるなんて夢にも思っていませんでした。 ちょっとコードを書いたら、`git status` `git diff`を叩いている自分。だいぶプログラマーっぽくなりました。

## 最後にお願いです

* 面白いと思っていただけたら「いいね」をクリックしてください。励みになります。
* Cloud9で実現するクラウド開発環境についてご意見あったら、お気軽にコメントしてください。