AWS EC2 インスタンスと同じ環境をローカルに作る

# AWS EC2 インスタンスと同じ環境をDockerでローカルに作る
AWS EC2 上にあるインスタンスと同じ環境をローカルに作成します。
インスタンスの中身を丸ごとtarにしてローカルにダウンロードして、Dockerインポートしようというお話です。

## 前提
+ 対象のインスタンスには Docker は導入されていない。
+ 作業の過程でスナップショット、インスタンス、ボリュームを追加する。
+ 作業マシンからEC2 インスタンスにSSHできる。
+ 操作は主に AWS CLI で操作するため、それ相応の権限のあるユーザーがある。

（一部 [jq](https://stedolan.github.io/jq/) コマンドを使って説明している箇所があります。）

## 手順
### AWS編
1. 下準備
2. 現状確認
3. スナップショットを取る
4. ボリュームを作る
4. 作業用インスタンスを作成する
5. ボリュームを作業用インスタンスにアタッチする
6. 作業用インスタンスにSSH
7. アタッチしたボリュームをマウント
8. マウントしたボリュームを tar
9. tar を ダウンロード
10. 作業用インスタンスを止める

### Docker編
1. Docker Toolboxインストール
2. Docker イメージとして tar をインポート
3. Docker コンテナ起動
4. コンテナ内のセットアップ

## AWS編
### 下準備
SSH
ローカル作業環境を作りたいインスタンスにSSHします。

```sh
ssh -i ~/.ssh/YOUR_KEY ec2-user@YOUR_IP
```

jq コマンドインストール
JSONのデータフィルタリングと出力結果を整形するのに使用します。
インスタンス内での作業を助けます。
不要であれば飛ばしてください。

```sh
sudo yum intall -y jq
```

AWS CLI の設定
下記コマンドから設定を開始します。

```sh
aws configure
```

下記質問に順に答え、値を設定します。
※適当な[IAM](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/introduction.html)ユーザーがいない場合は、[AWS マネジメントコンソール](https://aws.amazon.com/jp/console/)で作成の上、
権限を付与（ポリシーのアタッチ）しておいてください。

```sh
AWS Access Key ID []:
AWS Secret Access Key []:
Default region name []:
Default output format [json]
```

未設定の場合、下記ようなメッセージが表示されます。

```sh
You must specify a region. You can also configure your region by running "aws configure".
```

### 現状確認
下記3つの現状を確認します。
※出力結果はどこかに控えておいてください。後ほど使用します。
インスタンスの確認

```sh
aws ec2 describe-instances | jq '.Reservations[].Instances[] | if .State.Code != 48 then . else "no results" end | {InstanceId, KeyName, PublicIpAddress, ImageId, SecurityGroups, Tags, State, InstanceType, RootDeviceName, SecurityGroups, Placement}'
```
[describe-instances — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html)

ボリュームの確認

```sh
aws ec2 describe-volumes | jq '.Volumes[] | {InstanceId, VolumeId, State, Device, VolumeType, Size}'
```
[describe-volumes — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-volumes.html)

スナップショットの確認

```sh
aws ec2 describe-snapshots
```
[describe-snapshots — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/describe-snapshots.html)


※以降の作業はEC2上に作成・変更を行います。
実際のコマンドを実行する前に --dry-run オプションを付けて実行結果を事前に確認することをおすすめします。

### スナップショットを取る
スナップショットの作成
※スナップショットを取る際、対象のインスタンスは停止しておいた方が良いそうです。

```sh
aws ec2 create-snapshot --volume-id YOUR_VOLUME_ID --description "This is my root volume snapshot."
```

[create-snapshot — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/create-snapshot.html)

作成できたか確認します。
※出力結果はどこかに控えておいてください。後ほど使用します。

```sh
aws ec2 describe-snapshots
```

### ボリュームを作る
スナップショットからボリュームを作ります。

```sh
aws ec2 create-volume --size YOUR_VOLUME_SIZE --region YOUR_REGION --availability-zone YOUR_AVAILABILITY_ZONE --volume-type gp2 --snapshot-id YOUR_SNAPSHOT_ID
```

[create-volume — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/create-volume.html)

作成できたか確認します。
※出力結果はどこかに控えておいてください。後ほど使用します。

```sh
aws ec2 describe-volumes | jq '.Volumes[] | {InstanceId, VolumeId, State, Device, VolumeType, Size}'
```

### 作業用インスタンスを作成する
作業用のインスタンスを1つ作成します。
※対象のインスタンスと同じイメージIDを指定してください。
※--key-name と --security-groups には、対象のインスタンスと同じものを指定すると同じ情報でSSHできて楽です。

```sh
aws ec2 run-instances --image-id YOUR_IMAGE_ID --count 1 --instance-type YOUR_INSTANCE_TYPE --key-name YOUR_KEY_NAME --security-groups YOUR_SECURITY_GROUPS
```

[run-instances — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/run-instances.html)

作成できたか確認します。
※出力結果はどこかに控えておいてください。後ほど使用します。

```sh
aws ec2 describe-instances | jq '.Reservations[].Instances[] | if .State.Code != 48 then . else "no results" end | {InstanceId, KeyName, PublicIpAddress, ImageId, SecurityGroups, Tags, State, InstanceType, RootDeviceName, SecurityGroups, Placement}'
```

### ボリュームを作業用インスタンスにアタッチする
ボリュームをアタッチします。

```sh
aws ec2 attach-volume --volume-id YOUR_VOLUME_ID --instance-id YOUR_INSTANCE_ID --device /dev/sdf
```

[attach-volume — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/attach-volume.html)

### 作業用インスタンスにSSH
SSH

```sh
ssh -i ~/.ssh/YOUR_KEY ec2-user@YOUR_IP
```

必要であれば jq コマンドをインストールします。

```sh
sudo yum intall -y jq
```

AWS CLIの設定をします。

```sh
aws configure
```

ボリュームがアタッチできているか確認しておきます。
ルートボリューム以外のボリュームが増えていたら問題ないです。
※出力結果はどこかに控えておいてください。デバイス名を後ほど使用します。

```sh
lsblk
```

### アタッチしたボリュームをマウント
マウントする用のディレクトリを作成します。(ディレクトリ名は任意)

```sh
sudo mkdir /work
```

指定するデバイス名は環境によって適宜変更してください。

```sh
sudo mount /dev/YOUR_DEVICE_NAME /work
```

マウントしたディレクトリに移動します。

```sh
cd /work
```

### マウントしたボリュームを tar
マウントしたボリュームの内容を tar圧縮します。（ファイル名は任意）

```sh
sudo tar --numeric-owner -cJpf image.tar.xz .
```

### tar を ダウンロード
scp コマンドなどでダウンロードします。（保存先は任意）

```sh
scp -i ~/.ssh/YOUR_KEY ec2-user@YOUR_IP:/work/image.tar.xz ~/desktop/.
```

### 作業用インスタンスを止める
インスタンスを停止します。
※--dry-run オプションで実行結果を先に確認してください。

```sh
aws ec2 stop-instances --instance-ids YOUR_INSTANCE_ID
```

停止できたか確認します。

```sh
aws ec2 describe-instances | jq '.Reservations[].Instances[] | if .State.Code != 48 then . else "no results" end | {InstanceId, KeyName, PublicIpAddress, ImageId, SecurityGroups, Tags, State, InstanceType, RootDeviceName, SecurityGroups, Placement}'
```

[stop-instances — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/stop-instances.html)

※以降、本作業で使用した作業用のインスタンスなどは不要なので削除しても構いません。

## Docker編
### Docker Toolboxインストール
[Docker Toolbox | Docker](https://www.docker.com/products/docker-toolbox)

### Docker イメージとして tar をインポート
インポートします。

```sh
docker import /YOUR_WORK_DIR/image.tar.xz YOUR_IMAGE_NAME:YOUR_TAG
```

[import](https://docs.docker.com/engine/reference/commandline/import/)

### Docker コンテナ起動
コンテナを起動します。
下記指定では、コンテナ起動後にサーバにSSHしたような状態になります。

```sh
docker run -it --name YOUR_CONTAINER_NAME YOUR_IMAGE_NAME:YOUR_TAG /bin/bash
```

[run](https://docs.docker.com/engine/reference/commandline/run/)

### コンテナ内のセットアップ
#### AWS CLI
設定すれば使用できます。AWS上で設定した時と同じ情報で設定できます。

```sh
aws configure
```

#### yum
yumリポジトリがaws内のURLになっているため、アクセスできず失敗します。
適宜任意のリポジトリを指定して有効にしてください。
下記に Amazon側のリポジトリ指定があります。enable=0にしておきましょう。

```sh
/etc/yum.repo.d/amzn-main.repo
```

下記に epelは元々ありました。

```sh
/etc/yum.repo.d/epel.repo
```

# 参考
+ [jq](https://stedolan.github.io/jq/)
+ [ec2 — AWS CLI 1.10.12 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/ec2/index.html#cli-aws-ec2)