ecs-cli バージョン指定してインストール

完全な備忘録です。

経緯

6月に入って数日、
ecs-cli の latest をインストールすると latest が 1.6.0 となり
ecs-cli compose ... を実行すると以下のようなエラーが出るようになりました。

1
level=error msg="Unable to open ECS Compose Project" error="Volume driver is not supported"

1.4.0 では問題なかったタスク定義でしたが
1.6.0 では Volume driver is not supported となったそうで処理がこけるようになりました。

その対応として 1.4.0 にバージョン固定した設定です。

続きを読む
AWS ECS prefix 指定してまとめてタスク登録解除
AWS Vault で複数アカウントにMFA認証通過

AWS Vault で複数アカウントにMFA認証通過

AWS Vault とは?

AWS Vault は IAM の認証情報 (Access Key Id, Secret Access Key) を安全に OS のキーストアに保存しアクセスできる仕組みを提供するツールです。

Vault = 金庫 というだけあって
PC 落としても秘匿情報が漏れにくい仕組みにしてくれます。

今回の目的

AWS Vault で複数アカウントのコンソールログインを簡単にしたいと思います。

続きを読む

続 ECR にログイン(aws ecr get-login)無しでプッシュする

概要

前回 ECR への Docker イメージをプッシュする際の認証コマンドを実行せずにプッシュできる様にしました。

ECR にログイン(aws ecr get-login)無しでプッシュする

ですが、
設定が手間というのがあり、CircleCI, AWS CodeBuild 等でワンライナーでささっと書きたいときには不便です。

解決

awscli profile で設定した profile を利用し ecs-cli を利用することで認証をよろしくやってくれます。

1
ecs-cli push <image> --aws-profile <profile> --region <region>

設定 Step

1
2
3
aws configure set --profile hogehoge aws_access_key_id $ACCESS_KEY_ID
aws configure set --profile hogehoge aws_secret_access_key $SECRET_ACCESS_KEY
aws configure set --profile hogehoge region ap-northeast-1
1
2
3
ecs-cli push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/stg-mogemoge-rails:latest \
--aws-profile hogehoge \
--region ap-northeast-1

以上で aws ecr get-login を使用せず、ECR へプッシュができる様になりました♪

ECR にログイン(aws ecr get-login)無しでプッシュする

ECR にログイン(aws ecr get-login)無しでプッシュする

概要

Docker version 1.11 で実装された credential-helper を利用し
ECR へのプッシュを安全に簡易的に行う仕組みを実装します。

Docker ver 1.11 以上にアップグレード

1
2
3
4
5
6
7
$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
$ sudo sh -c "echo deb https://apt.dockerproject.org/repo ubuntu-trusty main\
> /etc/apt/sources.list.d/docker.list"
$ sudo apt-get purge lxc-docker docker
$ sudo apt-get update
$ sudo apt-get install docker-engine
$ sudo service docker restart

pull Dockerized ECR credential helper

1
$ docker pull pottava/amazon-ecr-credential-helper

認証設定

以下 3 つの中から 1 つ利用ください。
EC2 であれば、1. インスタンスロールで認証 が一番すっきりしていてコードの見通しが良いです。

  1. インスタンスロールで認証
  2. credential で認証
  3. 環境変数で認証

1. インスタンスロールで認証

1
2
3
docker run --rm \
-e REGISTRY=123457689012.dkr.ecr.us-east-1.amazonaws.com \
pottava/amazon-ecr-credential-helper
1
2
3
4
5
6
7
8
9
10
sudo sh -c 'cat << EOF > /usr/bin/docker-credential-ecr-login
#!/bin/sh
SECRET=\$(docker run --rm \\
-e METHOD=\$1 \\
-e REGISTRY=\$(cat -) \\
pottava/amazon-ecr-credential-helper)
echo \$SECRET | grep Secret
EOF'

sudo chmod +x /usr/bin/docker-credential-ecr-login

2. credential で認証

1
2
3
4
docker run --rm \
-e REGISTRY=123457689012.dkr.ecr.us-east-1.amazonaws.com \
-v $HOME/.aws/credentials:/root/.aws/credentials \
pottava/amazon-ecr-credential-helper
1
2
3
4
5
6
7
8
9
10
11
sudo sh -c 'cat << EOF > /usr/bin/docker-credential-ecr-login
#!/bin/sh
SECRET=\$(docker run --rm \\
-e METHOD=\$1 \\
-e REGISTRY=\$(cat -) \\
-v $HOME/.aws/credentials:/root/.aws/credentials \\
pottava/amazon-ecr-credential-helper)
echo \$SECRET | grep Secret
EOF'

sudo chmod +x /usr/bin/docker-credential-ecr-login

3. 環境変数で認証

  • 環境変数セット
1
2
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
1
2
3
4
5
docker run --rm \
-e REGISTRY=123457689012.dkr.ecr.us-east-1.amazonaws.com \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
pottava/amazon-ecr-credential-helper
1
2
3
4
5
6
7
8
9
10
11
sudo sh -c 'cat << EOF > /usr/bin/docker-credential-ecr-login
#!/bin/sh
SECRET=\$(docker run --rm \\
-e METHOD=\$1 \\
-e REGISTRY=\$(cat -) \\
-e AWS_ACCESS_KEY_ID \\
-e AWS_SECRET_ACCESS_KEY \\
pottava/amazon-ecr-credential-helper)
echo \$SECRET | grep Secret
EOF'
sudo chmod +x /usr/bin/docker-credential-ecr-login

credential 保存設定

1
2
3
4
5
6
7
mv $HOME/.docker/config.json $HOME/.docker/config.json.org

cat << EOF > $HOME/.docker/config.json
{
"credsStore": "ecr-login"
}
EOF

これで aws ecr get-login から解放されます ♪

AWS ECS トラブルシューティング

ECS を利用していて幾つかはまったポイントがあったのでまとめました。

started 1 task が複数回実行されるが、コンテナが起動しない

1
2
3
4
5
$ ecs-cli compose service up ...

level=info msg="(service hogehoge) has started 1 tasks ..."
level=info msg="(service hogehoge) has started 1 tasks ..."
level=info msg="(service hogehoge) has started 1 tasks ..."

ecs-cli compose service up でデプロイ時にタスク起動を実行するものの、起動が正しくできていない状態です。
こちらはコンテナ起動時の処理に問題がある場合があります。

  • コンテナログを確認して、コンテナ起動失敗時刻付近のログを確認してください。
  • 例えば、Nginx の設定ファイル, Rails のコードに typo, syntax error がある等です。

already using a port required by your task

1
2
service hogehoge was unable to place a task because no container instance met all of its requirements.
The closest matching container-instance a1b2c3d4-e5f6-g7h8-j9k0-l1m2n3o4p5q6 is already using a port required by your task

port mapping を以下の様に設定していた。

1
2
3
4
5
6
7
"portMappings": [
{
"hostPort": 0,
"protocol": "tcp",
"containerPort": 80
}
],

新しいタスクでも 0:80 のポートを利用しようとする為、エラーとなります。
以下の様に設定することで回避できました。

1
2
3
4
5
"portMappings": [
{
"containerPort": 80
}
],

insufficient memory available

1
INFO[0031] (service hogehoge) was unable to place a task because no container instance met all of its requirements. The closest matching (container-instance a1b2c3d4-e5f6-g7h8-j9k0-l1m2n3o4p5q6) has insufficient memory available. For more information, see the Troubleshooting section of the Amazon ECS Developer Guide.  timestamp=2018-03-09 15:45:24 +0000 UTC

タスク更新(ecs-cli compose service up)実行時、
上記の様なメモリ不足が出る場合はインスタンスタイプを上げる、また、他タスクを削除する等、メモリーリソースを増やす対応が必要です。

no space on device

no space on device で イメージを pull できない。

df -hT コマンドで 容量の使用状況確認

未使用のコンテナ・ボリュームを強制削除しお掃除

1
docker system prune -af --volumes

msg=”Couldn’t run containers” reason=”RESOURCE:CPU”

1
msg="Couldn't run containers" reason="RESOURCE:CPU"

タスクで指定している cpu (vCPU) が不足しています。
インスタンスタイプを上げる、もしくは、他タスクを削除する等、 CPU リソースを増やす対応が必要です。

Fargate - Port Mapping Error

1
level=error msg="Create task definition failed" error="ClientException: When networkMode=awsvpc, the host ports and container ports in port mappings must match.\n\tstatus code: 400, request id: a1b2c3d4-e5f6-g7h8-j9k0-l1m2n3o4p5q6"

起動タイプ Fargate で以下の様な設定だと、NG

1
2
ports:
- "80"

こちらだと OK。

1
2
ports:
- "80:80"

ホストポートとコンテナポートのマッピングが必要です。

Fargate volume_from は利用できない

volume_from は Fargate では使用できません。

1
level=error msg="Create task definition failed" error="ClientException: host.sourcePath should not be set for volumes in Fargate.\n\tstatus code: 400, request id: a1b2c3d4-e5f6-g7h8-j9k0-l1m2n3o4p5q6"

指定された IAM Role が適切なパーミッションを与えられていない

IAM Role に権限を適宜付与します。

1
2
level=info msg="(service hogehoge) failed to launch a task with (error ECS was unable to assume the role 'arn:aws:iam::123456789012:role/ecsTask
ExecutionRole' that was provided for this task. Please verify that the role being passed has the proper trust relationship and permissions and that your IAM user has permissions to pass this role.)." timestamp=2018-06-21 08:15:43 +0000 UTC

イメージ pull できないというエラーも権限を付与していないことに起因することが主です。

1
CannotPullContainerError: API error (500): Get https://123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/v2/: net/http: request canceled while waiting for connection"

現在稼働している ECS の IAM Role の権限を参考してください。変更される可能性があるのであくまで参考にし、適宜最新の情報を以ってご対応ください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"logs:PutLogEvents",
"logs:CreateLogStream",
"logs:CreateLogGroup",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:Describe*",
"elasticloadbalancing:DeregisterTargets",
"ecs:UpdateService",
"ecs:Submit*",
"ecs:StartTelemetrySession",
"ecs:StartTask",
"ecs:RunTask",
"ecs:RegisterTaskDefinition",
"ecs:RegisterContainerInstance",
"ecs:Poll",
"ecs:ListTasks",
"ecs:DiscoverPollEndpoint",
"ecs:DescribeTasks",
"ecs:DescribeServices",
"ecs:DescribeContainerInstances",
"ecs:DeregisterContainerInstance",
"ecs:CreateService",
"ecr:UploadLayerPart",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:GetDownloadUrlForLayer",
"ecr:GetAuthorizationToken",
"ecr:CompleteLayerUpload",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ec2:Describe*"
],
"Resource": "*"
}
]
}

以上です。

また何か発生したら追記していきたいと思います。

Reference

WAF+CloudFront でリファラチェック (直リンク禁止)

WAF+CloudFront でリファラチェック (直リンク禁止)

概要

AWS WAF (Web Application Firewall) を利用し Cloudfront でのリファラ制御を実装しましたのでそのまとめです。

直リンク禁止対策として導入しました。

以下手順になります。

Go to AWS WAF ボタンクリック

サービス > WAF & Shield と辿り Go to AWS WAF クリック

Configure Web ACL ボタンクリック

ACL (Access Control List) を設定していきます。

概要確認

特にチェックせず Next ボタンクリック

web ACL 設定

以下、設定項目を設定し、Next ボタンクリック

Item Value
Web ACL name (任意) 例では Cloudfront の CNAME を設定しています。
CloudWatch metric name Web ACL name を入力すると自動で入力される。変更したい場合のみ変更
Region Global(CloudFront) 選択
AWS resource to associate 対象となる Cloudfront を選択する箇所。運用中の Cloudfront を対象とすると場合は後々設定。

条件作成

今回は文字列一致を条件とする為、 String match conditions にて Create condition ボタンクリック

string match condition 作成

以下設定し Add filter ボタンクリック。
複数 filter がある場合、Add filter を繰り返します。

Item Value
Name (任意)
Part of the request to filter on Header
Header Referer
Match type Contains
Transformation Convert to lowercase
Value to match 対象となるドメイン設定

Add filter 後、 Create ボタンクリック。

Next ボタンクリック

追加したもののすぐに反映されていない。
そのまま Next ボタンクリック

ルール作成

Create rule ボタンクリック。

ルールに条件を紐付け

Name, Cloudwatch metric name を設定し
Add conditions で条件を追加します。

その後、Create ボタンクリック。

ルール以外のリクエストのアクセス禁止

やはり Rule は反映されていない。ですが、続けて
Block all requests that don't match any rules をチェックし Review and create ボタンクリック。

※対象の Cloudfront に反映させたくない場合は、Cloudfront を選択したリソースを解除する必要があります。
※最後に関連付けができるのでここではするべきではないと思います。

確認ページで入力内容確認後作成

Confirm and create ボタンクリック。

対象の web ACL を編集

WEB ACLs より選択し Edit web ACL ボタンクリック

web ACL 編集

  1. 作成したルールを選択
  2. Add rule to web ACL ボタンクリック
  3. Allow 選択
  4. Update ボタンクリック

[f:id:kenzo0107:20171005183720p:plain]

Cloudfront 関連付け

Add association ボタンクリック

Web ACL に Cloudfront を関連付け

Resource で 対象の Cloudfront を選択し Add ボタンクリック

以上で数分後 WAF+CloudFront によるリファラチェックが確認できる状態になります。

アクセス確認

自環境では
ローカルの /etc/hosts 修正し対象ドメインから Cloudfront CNAME へのリンクを貼って確認しました。

Cloudfront CNAME ドメインでのリソースを直接アクセスすると
以下の様な エラーページが表示されることが確認できました。

もう少しユーザフレンドリーに

上記のエラーページは Cloudfront > Error Pages で Create Custom Error Response で S3 上のパスを指定することでカスタマイズが可能です。

是非サイトコンセプトに合ったエラーページをご用意されるとよりユーザフレンドリーな配信になるかと思います。

以上
ご参考になれば幸いです。

AWS Elasticsearch Service バージョンアップ 2.2 → 5.5

AWS Elasticsearch Service バージョンアップ 2.2 → 5.5

概要

AWS Elasticsearch Service (ES) 2.3 → 5.5 へバージョンアップを実施に際して
以下記事をまとめました。

大まかな流れ

  1. ES バージョン 2.3 のドメインから Snapshot 取得
  2. ES バージョン 5.5 のドメイン作成
  3. アプリの fluentd の向け先を ES バージョン 5.5 へ変更
  4. ES バージョン 5.5 のドメインにデータリストア
  5. ES バージョン 2.3 のドメイン削除

現状バージョン確認

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ curl https://<Elasticsearch 2.3 Endpoint Domain>

{
"name" : "Jackdaw",
"cluster_name" : "<Account ID>:xxxxxxxxxx",
"version" : {
"number" : "2.3.2",
"build_hash" : "72aa8010df1a4fc849da359c9c58acba6c4d9518",
"build_timestamp" : "2016-11-14T15:59:50Z",
"build_snapshot" : false,
"lucene_version" : "5.5.0"
},
"tagline" : "You Know, for Search"
}

その他、AWS console のクラスターの設定確認

その他クラスターへ設定している情報をメモ

  • インスタンスタイプ
  • アクセスポリシーの確認

AWS Elasticsearch Service スナップショットを S3 で管理する

IAM role 作成

  • ec2 タイプで作成
  • アクセス権限は特に設定せず 「次のステップ」ボタンクリック
  • ロール名を es-index-backups とし作成

ロール ARN arn:aws:iam:::role/es-index-backups で作成されていることが確認できる

  • 信頼関係の編集

Service を es.amazonaws.com に編集

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "es.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

IAM User 作成

  • ユーザ > ユーザ追加 選択


  • ユーザ名 es-index-backup-user とし プログラムによるアクセスにチェックを入れて 次のステップ クリック


  • 特にポリシーをアタッチせず 次のステップ クリック
  • es-index-backup-user を作成し独自ポリシーで先ほど作成した role へのアクセス許可設定をアタッチします。
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": "arn:aws:iam::<Account ID>:role/es-index-backups"
}
]
}

  • 発行されたアクセスキー、シークレットアクセスキーをメモしておきます。

S3 バケット作成

S3 > バケットを作成する でバケット作成してください。

Elasticsearch にてスナップショットリポジトリ作成

スナップショットを管理するリポジトリを Elasticsearch に作成する必要があります。

Elasticsearch へのアクセス可能なサーバにて以下スクリプト実行します。

  • register_es_repository.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from boto.connection import AWSAuthConnection

class ESConnection(AWSAuthConnection):

def __init__(self, region, **kwargs):
super(ESConnection, self).__init__(**kwargs)
self._set_auth_region_name(region)
self._set_auth_service_name("es")

def _required_auth_capability(self):
return ['hmac-v4']

if __name__ == "__main__":

client = ESConnection(
region='ap-northeast-1',
host='<Elasticsearch 2.3 Endpoint Domain>',
aws_access_key_id='<ACCESS KEY ID>',
aws_secret_access_key='<SECRET ACCESS KEY>', is_secure=False)

resp = client.make_request(
method='POST',
path='/_snapshot/index-backups',
data='{"type": "s3","settings": { "bucket": "<bucket name>","region": "ap-northeast-1","role_arn": "arn:aws:iam::<Account ID>:role/es-index-backups"}}'
)
body = resp.read()
print body
1
2
3
4
5
6
$ chmod +x register_es_repository.py

$ python register_es_repository.py

// 成功
{"acknowledged":true}

リポジトリ登録完了しました。

Snapshot 取得

snapshot 名を 20170926 とします。

1
2
3
4
$ curl -XPUT "https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/20170926"

// 成功
{"accepted":true}

Snapshot 一覧

20170926 という snapshot 名で取得したことが確認できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ curl -s -XGET "https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/_all" | jq .
{
"snapshots": [
{
"snapshot": "20170926",
"version_id": 2030299,
"version": "2.3.2",
"indices": [
"nginx-access-2017.09.09",
"nginx-access-2017.09.07",
"nginx-access-2017.09.08",
"nginx-error-2017.08.24",
"nginx-error-2017.08.23",
".kibana-4",
...
],
"state": "IN_PROGRESS",
"start_time": "2017-09-26T03:58:51.040Z",
"start_time_in_millis": 1506398331040,
"failures": [],
"shards": {
"total": 0,
"failed": 0,
"successful": 0
}
}
]
}

Snapshot 削除

スナップショット 20170926 を削除する場合、DELETE メソッドを実行します。

1
2
3
4
$ curl -XDELETE https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/20170926

// 成功
{"acknowledged":true}

S3 確認

以下が作成されているのがわかります。

  • indices/*
  • meta-*
  • snap-*

はじめ meta-_ が作成できたら完了なのかなと思いきや
snap-_ も作られるまで待つ必要がありました。

  • CLI 上でスナップショット完了確認した方が確実です。
1
2
3
4
5
6
$ curl -s -GET https://<Elasticsearch 2.3 Endpoint Domain>/_snapshot/index-backups/20170926

...
"state": "SUCCESS",
...
...

Elasticsearch 5.5 Service 新規ドメイン作成

Elasticsearch 2.3 の設定に倣って作成します。

リポジトリ作成

  • register_es55_repository.py

register_es_repository.py の host 部分を新規ドメインに修正します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from boto.connection import AWSAuthConnection

class ESConnection(AWSAuthConnection):

def __init__(self, region, **kwargs):
super(ESConnection, self).__init__(**kwargs)
self._set_auth_region_name(region)
self._set_auth_service_name("es")

def _required_auth_capability(self):
return ['hmac-v4']

if __name__ == "__main__":

client = ESConnection(
region='ap-northeast-1',
host='<Elasticsearch 5.5 Endpoint Domain>',
aws_access_key_id='<ACCESS KEY ID>',
aws_secret_access_key='<SECRET ACCESS KEY>', is_secure=False)

print 'Registering Snapshot Repository'
resp = client.make_request(
method='POST',
path='/_snapshot/index-backups',
data='{"type": "s3","settings": { "bucket": "<bucket name>","region": "ap-northeast-1","role_arn": "arn:aws:iam::<Account ID>:role/es-index-backups"}}'
)
body = resp.read()
print body
1
2
3
4
5
6
$ chmod +x register_es55_repository.py

$ python register_es55_repository.py

// 成功
{"acknowledged":true}

スナップショットからリストア

20170926 のスナップショットをリストアします。

1
2
3
4
$ curl -XPOST "https://<Elasticsearch 5.5 Endpoint Domain>/_snapshot/index-backups/20170926/_restore"

// 成功
{"accepted": true}

リストア確認

1
$ curl -XGET "https://<Elasticsearch 5.5 Endpoint Domain>/_cat/indices"

スナップショットに失敗するケース

  • .kibana index が既に存在しており、リストアできない。
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"error":{
"root_cause":[
{
"type":"snapshot_restore_exception",
"reason":"[index-backups:20170926/Hc4rLIoARCWqpyJXeP7edw] cannot restore index [.kibana] because it's open"
}
],
"type":"snapshot_restore_exception",
"reason":"[index-backups:20170926/Hc4rLIoARCWqpyJXeP7edw] cannot restore index [.kibana] because it's open"
},
"status":500
}

対応策

1
2
3
curl -XPOST https://<Elasticsearch 5.5 Endpoint Domain>/_snapshot/index-backups/20170926/_restore -d '{
"indices": "nginx-*"
}' | jq .

indices を用い、スナップショット内のインデックスの中からマッチする正規表現のみをリストアできます。

自身ではこの様な解決法を実施し回避できました。
その他良い方法があれば御指南いただけますと幸いです。

ちなみに

Terraform で ES 2.2 → 5.5 バージョンアップを実施した所
1 時間以上経過してようやくアップデートが完了しました。

1
2
3
4
aws_elasticsearch_domain.elasticsearch: Still destroying... (ID: arn:aws:es:ap-northeast-1:xxxxxxxxxxxx:domain/***, 59m11s elapsed)
aws_elasticsearch_domain.elasticsearch: Still destroying... (ID: arn:aws:es:ap-northeast-1:xxxxxxxxxxxx:domain/***, 59m21s elapsed)
aws_elasticsearch_domain.elasticsearch: Still destroying... (ID: arn:aws:es:ap-northeast-1:xxxxxxxxxxxx:domain/***, 59m31s elapsed)
aws_elasticsearch_domain.elasticsearch: Destruction complete after 59m41s

これは辛い (>_<)

Terraform で管理している場合、
スナップショットを取得したら aws console 上でドメイン削除した方が早い。

ブルーグリーン的に ES 5.5 作成して ES 2.2 から乗り換えて
しばらく運用して問題なければ ES 2.2 を削除する方法が一番確実だなと思いました。

AWS [Retirement Notification] 対応

AWS [Retirement Notification] 対応

概要

とある日、AWS よりこんなメール通知が来ました。

要約すると
ホストしている基盤のハードウェアで回復不可能な障害が検知されたので
指定期限までに対応しないとインスタンスが停止する、とのこと。

今回こちらの対応をまとめました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Dear Amazon EC2 Customer,

We have important news about your account (AWS Account ID: xxxxxxxxxxxx). EC2 has detected degradation of the underlying hardware hosting your Amazon EC2 instance (instance-ID: i-xxxxxxxx) in the ap-northeast-1 region. Due to this degradation, your instance could already be unreachable. After 2017-04-25 04:00 UTC your instance, which has an EBS volume as the root device, will be stopped.

You can see more information on your instances that are scheduled for retirement in the AWS Management Console (https://console.aws.amazon.com/ec2/v2/home?region=ap-northeast-1#Events)

* How does this affect you?
Your instance's root device is an EBS volume and the instance will be stopped after the specified retirement date. You can start it again at any time. Note that if you have EC2 instance store volumes attached to the instance, any data on these volumes will be lost when the instance is stopped or terminated as these volumes are physically attached to the host computer

* What do you need to do?
You may still be able to access the instance. We recommend that you replace the instance by creating an AMI of your instance and launch a new instance from the AMI. For more information please see Amazon Machine Images (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) in the EC2 User Guide. In case of difficulties stopping your EBS-backed instance, please see the Instance FAQ (http://aws.amazon.com/instance-help/#ebs-stuck-stopping).

* Why retirement?
AWS may schedule instances for retirement in cases where there is an unrecoverable issue with the underlying hardware. For more information about scheduled retirement events please see the EC2 user guide (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-retirement.html). To avoid single points of failure within critical applications, please refer to our architecture center for more information on implementing fault-tolerant architectures: http://aws.amazon.com/architecture

If you have any questions or concerns, you can contact the AWS Support Team on the community forums and via AWS Premium Support at: http://aws.amazon.com/support

Sincerely,
Amazon Web Services
  • AWS Console イベントを見ると一覧で表示されている。
  • AWS Console 詳細を見ると Notice が出ている。

ToDO

ボリュームタイプによって異なります。

  • EBS ボリューム

    • インスタンスの停止後、起動 (Reboot は ×)
  • インスタンスストアボリューム

    • AMI からインスタンス再作成、データ移行

今回は EBS ボリューム対応について記載してます。

対応

対象インスタンスが多かったのでローカル PC (macOS) から awscli でインスタンス停止 → 起動するシェル作成しました。
本番環境で利用されるインスタンスも含まれていた為、1 件ずつ実行することとしました。

事前準備

  • awscli, jq インストール
1
$ brew install awscli jq
  • 各アカウント毎のアクセスキー、シークレットキー等設定
1
2
$ aws configure --profile <profile>
$ grep 'profile' ~/.aws/config

インスタンスの停止・再起動シェル

以下のように実行すると
インスタンスが起動(running)していれば
停止後、再び起動し、ステータスチェックをするようにしました。

1
$ sh stop_and_start_ec2_instance.sh "<profile>" "<instance id>"

イベント情報取得シェル

.aws/config で設定されている profile を全てチェックし
未対応インスタンスのみ表示する様修正しました。

結果確認

大体 1 インスタンス 5 分程度で完了。
問題なく停止起動でき、対象イベントが一覧から消えたことを確認しました ♪

所感

メンテ対象インスタンスの Region が northeast に集中していたのが気になる点でした。
このインスタンス何に使ってるんだっけ?とならない様に、インスタンスや private key の命名ルール必須と感じました。

以上です。

Terraform でキーペア登録し起動した EC2 に SSH接続

Terraform でキーペア登録し起動した EC2 に SSH接続

今回やること

  • Mac ローカルで公開鍵、秘密鍵を生成
  • Terraform で EC2 起動、セキュリティグループで SSH (ポート 22)許可、key-pair 登録

Terraform の Hello World 的なチュートリアルと思っていただけたら幸いです。

環境

  • Mac OS 10.12.3 (Sierra)
  • Terraform 0.9.1

公開鍵、秘密鍵生成

RSA フォーマットで鍵を生成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ssh-keygen -t rsa

Enter file in which to save the key (/Users/kenzo_tanaka/.ssh/id_rsa): /Users/kenzo_tanaka/.ssh/terraform-test
Enter passphrase (empty for no passphrase): (空のままEnter)
Enter same passphrase again: (空のままEnter)
...
...

// 生成されたか確認
$ ls ~/.ssh/terraform-test*

/Users/kenzo_tanaka/.ssh/terraform-test # 秘密鍵
/Users/kenzo_tanaka/.ssh/terraform-test.pub # 公開鍵

公開鍵を起動した EC2 インスタンスに登録し
秘密鍵でアクセスします。

以下のように利用する予定です。

1
$ ssh -i ~/.ssh/terraform-test <ec2 user>@<ec2 public ip>

Terraform 設定ファイル

  • Point !

    • resource "aws_key_pair" で使用する公開鍵設定をしています。
    • resource "aws_security_group" で SSH(ポート 22)を開いてます。
    • resource "aws_instance" で使用しているセキュリティグループの指定は vpc_security_group_ids を利用
      • セキュリティグループの条件追加・削除する場合にインスタンスを一度削除し作り直すことをしたくない場合に vpc_security_group_ids を利用すると良いです。
  • main.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}

resource "aws_instance" "example" {
ami = "${lookup(var.amis, var.region)}"
instance_type = "t2.nano"
key_name = "${aws_key_pair.auth.id}"
vpc_security_group_ids = ["${aws_security_group.default.id}"]
}

resource "aws_key_pair" "auth" {
key_name = "${var.key_name}"
public_key = "${file(var.public_key_path)}"
}

resource "aws_security_group" "default" {
name = "terraform_security_group"
description = "Used in the terraform"

# SSH access from anywhere
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
  • variables.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
variable "access_key" {}
variable "secret_key" {}
variable "region" {
default = "ap-northeast-1"
}

variable "amis" {
type = "map"
default = {
us-east-1 = "ami-13be557e"
us-west-2 = "ami-21f78e11"
ap-northeast-1 = "ami-1bfdb67c"
}
}

variable "key_name" {
description = "Desired name of AWS key pair"
}

variable "public_key_path" {
description = <<DESCRIPTION
Path to the SSH public key to be used for authentication.
Ensure this keypair is added to your local SSH agent so provisioners can
connect.

Example: ~/.ssh/terraform.pub
DESCRIPTION
}
  • terraform.tfvars
1
2
3
4
5
access_key = "A******************Q"
secret_key = "q**************************************Z"

key_name = "terraform-test"
public_key_path = "~/.ssh/terraform-test.pub"

いざ実行

  • 実行計画確認
1
$ terraform plan
  • 実行
1
$ terraform apply

確認

  • AWS コンソール上で起動確認

    • キーペアに terraform-test が指定されています。
    • vpc, subnet も自動的にアタッチされてます。
  • キーペア
    一応キーペアを見てみると登録されているのがわかります。
  • セキュリティグループ確認
  • SSH ログイン確認
1
$ ssh -i ~/.ssh/terraform-test ubuntu@ec2-54-65-244-25.ap-northeast-1.compute.amazonaws.com

無事 SSH ログインできました!

所感

terraform を見ながら各パラメータの利用意図を確認しながら
設定してみましたが
パラメータの説明自体はざっくりで利用方法まではわからないです。

Teffaform のチュートリアルに始まり
その他 Stack Overflow
適宜パターンを蓄積していく学習が程よいと思います。

参考