Amazon Elasticsearch Serviceでcluster_block_exceptionがでたら

症状

こんなエラー。
読み込みは出来るが、書き込みやインデックス作成は全て失敗するようになる。

"error": {
  "type": "cluster_block_exception",
  "reason": "blocked by: [FORBIDDEN/8/index write (api)];"
}
"error": {
  "type": "index_create_block_exception",
  "reason": "blocked by: [FORBIDDEN/10/cluster create-index blocked (api)];"
}

原因と対策

原因は主に2つある模様。

ディスク容量不足

AmazonESのメトリックスでFreeStorageSpaceを見ると0になっているはず。
インスタンスタイプかEBSの容量を上げればいいはず。

Amazon ES ドメインの設定 – AmazonES 開発者ガイド
EBS ベースのストレージの設定 – AmazonES 開発者ガイド

メモリ容量不足

AmazonESのメトリックスでJVMMemoryPressureが92%を超えているはず。
超えているというか92%をキープしている。

スクリーンショット 2017-06-20 14.35.10.png

t2特有の現象というわけでなく他のインスタンスタイプでも同じことが起きたので、単純にスケールアップしてメモリ増やせということだと思う。
この状態でもClusterHealthは青いままなので要注意。
JVMMemoryPressureは監視対象にしたほうがよさそう。

参考

AWS サービスエラー処理 – AmazonES 開発者ガイド
elasticsearchを利用するときは容量を管理しようという話 – Qiita

続きを読む

tectonic で kubernetes クラスタを構築・管理する(AWS)

概要

tectonic で AWS に kubernetes クラスタを構築する。

対応プラットフォーム(2017.06.09 時点)
  • AWS
  • Bare Metal
  • Microsoft Azure (alpha)
  • OpenStack (pre-alpha)
料金
  • 10ノードまで無料

環境

インストーラを実行した環境
– Amazon Linux AMI 2017.03
– tectonic 1.6.4

事前準備

セットアップ前に必要な作業

  • CoreOS

    • CoreOS アカウントサインアップ
    • CoreOS License 取得 (tectonic-license.txt)
    • Secret 取得 (config.json)
  • AWS

    • IAM Role 設定 (Policy)
    • Route 53 でパブリックホストゾーンの作成

tectonic のインストーラー取得

ダウンロード・解凍

$ wget https://releases.tectonic.com/tectonic-1.6.4-tectonic.1.tar.gz
$ tar xzvf tectonic-1.6.4-tectonic.1.tar.gz
$ cd tectonic

tectonic セットアップ (GUI)

インストーラー起動

$ ./tectonic-installer/linux/installer -address=0.0.0.0:4444 -open-browser=false
Starting Tectonic Installer on 0.0.0.0:4444

ブラウザで インストーラーを起動したホストIPアドレス:4444 にアクセスして、画面に従いセットアップする

01.png

tectonic セットアップ (terraform)

インストーラーの環境設定

$ export INSTALLER_PATH=$(pwd)/tectonic-installer/linux/installer
$ export PATH=$PATH:$(pwd)/tectonic-installer/linux

terraform 環境設定

$ sed "s|<PATH_TO_INSTALLER>|$INSTALLER_PATH|g" terraformrc.example > .terraformrc
$ export TERRAFORM_CONFIG=$(pwd)/.terraformrc

cluster resources 取得

$ terraform get platforms/aws

credential を環境変数に設定

$ export AWS_ACCESS_KEY_ID=AK***************
$ export AWS_SECRET_ACCESS_KEY=**************************************
$ export AWS_REGION=ap-northeast-1

クラスタ設定

クラスタ名を設定

$ export CLUSTER=cluster-1

クラスタ環境設定

$ mkdir -p build/${CLUSTER}
$ cp examples/terraform.tfvars.aws build/${CLUSTER}/terraform.tfvars

terraform 環境設定

$ vi build/cluster-1/terraform.tfvars

設定内容

tectonic_admin_email = "********************"   #tectonic console ログインID
tectonic_admin_password_hash = "*************"  #ログインパスワード※

tectonic_aws_az_count = "1"
tectonic_aws_region = "ap-northeast-1"
tectonic_aws_ssh_key = "************"           #AWS に登録した Key pair

tectonic_base_domain = "*************"          #Route 53 に登録したドメイン
tectonic_cluster_name = "cluster-1"             #クラスタ名

tectonic_license_path = "/path/to/tectonic-license.txt" #事前に取得した CoreOS Lisence
tectonic_pull_secret_path = "/path/to/config.json"      #事前に取得した CoreOS Secret

tectonic_worker_count = "2"                     #worker ノード数

tectonic_admin_password_hash は bcrypt で hash 化する (bcrypt-hash tool)

$ wget https://github.com/coreos/bcrypt-tool/releases/download/v1.0.0/bcrypt-tool-v1.0.0-linux-amd64.tar.gz
$ tar zxvf bcrypt-tool-v1.0.0-linux-amd64.tar.gz
$ ./bcrypt-tool/bcrypt-tool 
Enter password: 
Re-enter password: 
$2a$10$*****************************************************

plan 実行

$ terraform plan -var-file=build/${CLUSTER}/terraform.tfvars platforms/aws
Plan: 116 to add, 0 to change, 0 to destroy.

クラスタをデプロイ

apply 実行

$ terraform apply -var-file=build/${CLUSTER}/terraform.tfvars platforms/aws

クラスタへのアクセス

作成された kubeconfig を読み込み

$ export KUBECONFIG=generated/auth/kubeconfig

クラスタ確認

$ kubectl cluster-info
Kubernetes master is running at https://cluster-1-api.***.****.jp:443
KubeDNS is running at https://cluster-1-api.***.****.jp:443/api/v1/proxy/namespaces/kube-system/services/kube-dns

ノード確認

$ kubectl get node
NAME                                             STATUS    AGE       VERSION
ip-10-0-22-59.ap-northeast-1.compute.internal    Ready     4m        v1.6.4+coreos.0
ip-10-0-37-60.ap-northeast-1.compute.internal    Ready     2m        v1.6.4+coreos.0
ip-10-0-52-127.ap-northeast-1.compute.internal   Ready     1m        v1.6.4+coreos.0

tectonic console にアクセス

ブラウザで https://{{ tectoniccluster_name }}.{{ tectonic_base_domain }}/ にアクセス

12.png

設定したログインID、パスワードでログインする

13.png

続きを読む

A Zero Administration AWS Lambda Based Amazon Redshift Database Loader を HTTP Proxy 経由で利用する

はじめに

S3上のログファイルを、逐次Redhisftに取り込んでいきたいと思って調べてみると、AWS謹製の A Zero Administration AWS Lambda Based Amazon Redshift Database Loadera Based Amazon Redshift Database Loader (名前長い。以降、Redshift Loaderとする。) が良さそうです。

仕組みを調べてみると、RedshiftやS3、LambdaはVPC Endpointによってプライベートネットワークで接続し、設定情報や対象ファイルの管理に使うDynamoDBはNATゲートウェイ経由でパブリックネットワーク経由の接続が前提になっていました。

使おうとしていた環境のVPCでは、NATゲートウェイを使用せず、HTTP ProxyによってパブリックIPの無いインスタンスでのインターネット向け通信を実現していたため、HTTP Proxy対応を行ったソースを使っての導入手順をまとめます。

HTTP Proxy対応については、PR を出しています。この記事を書いている段階ではまだ取り込まれていません。

Redshift Loaderで出来ること

  • S3にログが書き込まれたイベントをきっかけに、Redshiftへロードするファイルリストを管理
  • 指定したバッファサイズ、件数又は時間ベースの閾値をトリガーにしてRedshiftへのロードを実行
  • ロード実行は、1ファイル1回を保証
  • 成功・失敗時のSNS通知
  • コマンドラインからの、ロード処理のバッチ進行状況の確認、再実行等
  • S3でのイベントトリガーは複数設定でき、1つのLambdaファンクションがイベントに応じてスケールして処理する

手順概要

  • S3バケットの作成とログのアップロード、VPCエンドポイントの設定
  • Redshiftインスタンス・テーブル、DBユーザーの作成
  • 設定・運用ツール実行のためのNode.js環境の構築
  • Lambdaファンクションのデプロイ
  • Redshift Loaderの設定
  • ログが取り込まれていることの確認

S3バケットの作成とログのアップロード、VPCエンドポイントの設定

本記事を書いている際には、ApacheのエラーログのアップロードをFluentdで実施して試しています。特に注意点も無いので、説明は省略します。

  • Redshiftインスタンス、Lambdaファンクションと同じリージョンで作成
  • アップロードは fluentd(td-agent) 辺りで実施
  • ログの保管用 と Redshift LoaderがCOPYコマンド(Redshift)で指定するためのマニフェスト保管用の計2バケットが最低限必要

Redshiftインスタンス・テーブル、DBユーザーの作成

インスタンスの作成

以下の設定項目に注意する。

  • S3バケット、Lambdaファンクションと同じリージョンで作成
  • パブリックアクセス可能(Publicly accessible) : No
  • 拡張された VPC のルーティング(Enhanced VPC Routing) : Yes
  • IAMロール(Available roles): 連携するS3バケットに対して、s3:GetObject 及び s3:ListBucket を許可しておく

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "s3:GetObject",
                    "s3:ListBucket"
                ],
                "Resource": [
                    "arn:aws:s3:::your-s3-bucket",
                    "arn:aws:s3:::your-s3-bucket/*"
                ]
            }
    }
    
    • この時点で COPY コマンドで、S3からデータがロードできることを確認しておく

参照ドキュメント

テーブルの作成

Apacheエラーログを、fluentdのin_tailオプションによって、JSONにパースした場合の一例。

create table if not exists apache_errors(
  time TIMESTAMPTZ,
  hostname VARCHAR(256),
  domain VARCHAR(256),
  message VARCHAR(8192),
  client VARCHAR(21),
  pid VARCHAR(5),
  level VARCHAR(32)
) 
DISTKEY(hostname)
SORTKEY(time);

DBユーザーの作成

前述のテーブル専用のユーザーを作る場合の一例。

create user load_apache_errors password 'パスワードに置き換え';
grant all on table apache_errors to load_apache_errors;

設定・運用ツール実行のためのNode.js環境の構築

設定・運用ツールは、Node.jsの0.10又は0.12でのみ確認されているとあるため、ndenv等で環境を用意します。

ndenv を導入した前提で、次のように利用するバージョンを指定します。

ndenv install v0.12.18

git clone https://github.com/tkimura/aws-lambda-redshift-loader
cd aws-lambda-redshift-loader

ndenv local v0.12.18

npm install
  • ndenv でインストールしているバージョンは、本記事記載時点の0.12系最新
  • PR が 取り込まれていないので、リポジトリは fork して修正したバージョンです

Lambdaファンクションのデプロイ

アップロード用のzipを作成

cd aws-lambda-redshift-loader
git checkout add-proxy-support
./build.sh
  • 前述手順でcloneして、ndenv local で設定済みであることを想定
  • ./dist/ 以下に zip ファイルが作成される

出来上がったzipファイルをアップロード

IAMロールの設定

  • 前述ドキュメントに記載の設定例を指定
  • 作成したロールに、AWSLambdaVPCAccessExecutionRole ポリシーを追加する (VPC利用のため)

Proxyの設定

  • Lambdaファンクションの環境変数に設定を追加

Redshift Loaderの設定

cd aws-lambda-redshift-loader
git checkout add-proxy-support
vi config.json # このファイルに設定を書いておく
node setup-file.js ./config.hoge.json

設定及び運用コマンドの実行環境向けのIAMポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:CreateTable",
                "dynamodb:DeleteItem",
                "dynamodb:DeleteTable",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:UpdateItem"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:CreateAlias",
                "kms:CreateKey",
                "kms:Decrypt",
                "kms:DescribeKey",
                "kms:Encrypt"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

ログが取り込まれていることの確認

  • CloudWatch Logs で Lambdaファンクションが実行されていることを確認

    • Proxy設定が正しくないと、タイムアウト時間いっぱいまで動いて失敗する
  • Redshiftインスタンスに直接繋いで確認する

    • PGTZ変数でタイムゾーンを指定しておくと時間がわかりやすい
    • タイムゾーン付き(TIMESTAMPTZ)でテーブルを作っておくと、PGTZで指定したタイムゾーンに合わせて表示される
    PGTZ="Asia/Tokyo" psql -U ユーザー名 -h Redshiftインスタンスのエンドポイント logs
    

参考ドキュメント

続きを読む

Route 53でローカルDNSを構築する

概要

Route 53を使ってローカルDNSを構築します。
この記事では最終的に作成されたRDSのエンドポイントに任意の名前で接続出来るようにします。

前提条件

この記事の内容を実践する為に必要な前提条件です。

  • 利用可能なVPCが存在する事
  • RDSのインスタンスが作成されている事

Privet Hosted Zoneを作成する

マネジメントコンソール → Route 53 → Hosted zones → Create Hosted Zone より作成を行います。

ドメイン名は認可で構いません。
この記事では test.local という名前で作成します。

Type: “Private Hosted Zone for Amazon VPC” を選択
Domain Name: test.local
Comment: 任意のコメント
VPC ID: 予め準備してあるVPCを指定します

private-domain-1.png

Privet Hosted ZoneにCNAMEレコードを追加する

CNAMEレコードとは既存のドメインに対して別名を付ける為のものです。

こちらの記事 に詳しく解説してくれている方がいますので、参考にすると良いかもしれません。
※この記事の中ではAレコードの解説も載っています。

AWSに割り振られたFQDNに対して、以下のように別名を付けます。

元のFQDN 与える別名 役割
dev-account-db.cluster-aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com account-db-master.test.local 書き込み用DB
dev-account-db-ap-northeast-1c.aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com account-db-master.test.local 読み取り用DB

「Create Record Set」よりレコードを作成します。

Name: “account-db-master” を入力
Type: “CNAME – Canonical name” を選択
Alias: “No”を選択
TTL: デフォルトのまま(300)
Value: 対象のRDSのエンドポイント dev-account-db.cluster-aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com を入力

private-domain-2-1.png

同じ要領で account-db-master.test.local のほうも作成します。

DHCPオプションセットを作成する

接続元のサーバ(EC2)からDNSサーバを参照するように設定が必要です。
ローカルDNSのIPは 公式ドキュメント にあるように、

VPC ネットワークの範囲に 2 をプラスした値です。例えば、10.0.0.0/16 ネットワークの DNS サーバーの位置は 10.0.0.2 となります。

となっています。
本件で扱うVPCは 192.0.0.0/16 なので 192.0.0.2 がローカルDNSのIPアドレスになります。

/etc/resolv.conf に情報を書き込む事で名前解決が可能になりますが、DHCPオプションを設定する方法が便利なのでこちらを利用します。

マネジメントコンソール → VPC → DHCPオプションセット → DHCPオプションセットの作成 より開始します。

情報は以下の通りに入力して下さい。

ネームタグ: dev
ドメイン名: “ap-northeast-1.compute.internal test.local”
ドメイン・ネームサーバ: “AmazonProvidedDNS”

入力した情報について説明します。

  • ネームタグ
    任意の分かりやすい名前をつけて下さい。
    私は環境を表す”dev”を付けました。

  • ドメイン名
    2つのドメイン名を半角スペース繋ぎで記載します。
    1つ目のドメインはリージョン固有のドメイン(今回は東京リージョンなので ap-northeast-1.compute.internal
    2つ目のドメインは今回作成したローカルドメイン test.local です。

  • ドメインネームサーバ
    “AmazonProvidedDNS”を指定することでresolv.confのnameserverにRoute 53での名前解決用IPが記載されます。

private-domain-3.png

このあたりの詳しい説明は 公式ドキュメント にも記載があります。

VPCにDHCPオプションセットを設定する

マネジメントコンソール → VPC → アクション より DHCPオプションセットを設定します。
それぞれの項目を下記のように設定します。

private-domain-4.png

private-domain-5.png

private-domain-6.png

動作確認

接続元のEC2インスタンスにログインを行い以下のコマンドを実行します。

DHCP設定を再取得(rootで実行)
dhclient eth0

※インスタンスの再起動を行う事でもDHCP設定の再取得は出来ます。

DNS設定前のnslookupの結果
nslookup account-db-master.test.local
Server:     192.0.0.2
Address:    192.0.0.2#53

** server can't find account-db-master.test.local: NXDOMAIN
DNS設定後のnslookupの結果
nslookup account-db-master.test.local

Server:     192.0.0.2
Address:    192.0.0.2#53

Non-authoritative answer:
account-db-master.test.local    canonical name = dev-account-db.cluster-aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com.
dev-account-db.cluster-aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com    canonical name = dev-account-db.aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com.
Name:   dev-account-db.aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com
Address: 192.0.20.68

設定した名前で名前解決が出来ている事が確認出来ます。

念のため設定したホスト名でmysql接続が出来る事を確認します。

設定したドメイン名で接続
mysql -u test_user -h account-db-master.test.local -p

接続の確認が出来ました。

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 5885
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql>

別名をつけただけなので、もちろん元々のFQDNでも接続が可能です。

元々のFQDNでも接続出来る事を確認
mysql -u test_user -h dev-account-db.cluster-aaaaabbbbcc1.ap-northeast-1.rds.amazonaws.com -p

同じように接続が出来ました。

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 5884
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql>

別名を付ける事によるメリット

この設定を行う事で下記のようなメリットが考えられます。

  1. 任意の名前を付けられる事でAWSから提供される長いFQDNを覚えなくても良くなります
  2. 例えばDBサーバを丸ごと入れ替えたとしても変更するのはRoute 53のCNAMEレコードのみなので移行が簡単になる

特に2のメリットは大きいと考えます。
Route 53なら簡単に設定が可能なので設定しておく事をオススメします。

この記事の内容は以上になります。
最後まで読んで頂きありがとうございました。

続きを読む

AWSコストカット大作戦

AWS


サーバ代、決して安くないですよね


学習コストも安くはない


下手すると


破産します


:banana:


現状を見直してコストカットできるかもな方法をご紹介します💰


🌏お品書き

  • コストエクスプローラー
  • Trusted Advisor
  • 一括請求(ボリューム割引)
  • S3
  • EC2

コストエクスプローラー

サービス毎に月または日毎のサービス使用量をグラフ化。もちろんサービス(EC2やRDS)毎に見れる。


Cost Reports 2017-06-02 09-09-14.png


1->2->3の順でクリックすれば見れます(3は見たいやつをクリック)

Billing Management Console 2017-06-02 09-12-47.png


コストエクスプローラーでまずは現状を把握することから始めましょう🐑


Trusted Advisor

「コスト最適化」、「パフォーマンス」、「セキュリティ」、「フォールトトレーランス」の観点からAWSが自動で精査し、推奨設定を通知してくれるサービス


Trusted Advisor Management Console 2017-06-02 09-24-22.png


  • 「コスト最適化」はダッシュボードで下記確認可能に

    • EC2 リザーブドインスタンスの最適化
    • 使用率の低いAmazon EC2 Instances
    • アイドル状態の Load Balancer
    • 関連付けられていない Elastic IP Address
    • アイドル状態の RDS
    • 期限が近づいているリザーブドインスタンス
    • Amazon Route 53 レイテンシーリソースレコードセット
    • 利用頻度の低いAmazon EBSボリューム
    • 利用頻度の低いAmazon Redshift Cluster

注意点

  • 無料で利用できるのはほんの一部の機能のみで、無料枠では残念ながらコスト最適化の項目が使いものになりません…
  • $100のアップグレードを行えば、項目が利用可能に(パフォーマンスチェックやセキュリティチェックも高機能に)

一括請求(ボリューム割引)

一括請求を使用した複数アカウントの料金の支払いでボリューム割引が適用可能


BasicDiagram.gif


VolumeDiscount.gif


データ転送量の合計やRI購入額などいろんな部分にボリューム割引がある。
個別のアカウント毎にはボリューム割引を受けられる量を使っていなくても、
一括請求を設定することで全アカウントで合算をもとにボリューム割引が受けられるようになる


S3

言わずと知れたストレージサービス


  • S3(標準)
  • S3(低頻度アクセス)
  • Glacier

違い(ざっくり)

S3(標準)->S3(低頻度アクセス)->Glacier
と右に行くほど
ストレージ価格が安くなり、リクエストや取り出し料金は逆に高くなります。


料金 - Amazon S3 | AWS 2017-06-02 13-37-59.png


  • 基本的にはS3(標準)
  • 巨大なアーカイブデータ(ログなど)はS3(低頻度アクセス)、Glacier

という運用が良さそうです。
リクエストと取り出しの料金帯が複雑なので省きます。ドキュメントを確認してください


余談

Amazon Glacierでクラウド破産しないために という記事があるので詳細は省きますが、
Glacierで100GBのファイルを復元しようとすると2万円、何かの間違いで120TBを一気に復元しようとすると2,521万円請求される計算になるらしい(旧価格ですが)


EC2

言わずと知れた仮想サーバー


リザーブドインスタンス


リザーブドインスタンスとは

  • 簡単に言うとインスタンス費用の先払いで割引が発生するサービス
  • 先払い期間は1年(平均40%割引)と3年(平均60%)の2種類
  • 最大75%OFF

  • 厳密に言うとリザーブドインスタンスの権利
  • インスタンスタイプのことではない
  • 購入したリザーブドインスタンスと同じインスタンスタイプがあれば、そのインスタンスタイプは自動でリザーブドインスタンスになる

他EC2のチェックポイント


  • 旧世代のインスタンスタイプのグレードアップ

    • 新しいほど安くて高性能(m3、m4などは数字が大きい方が新世代)
  • 開発環境/stagingの稼働時間見直し(夜間休日は止めるとか)
  • オーバースペックなインスタンスのグレードダウン検討
  • アプリケーションレベルでの転送量削減(画像・html・js・cssの圧縮、無駄なリクエストの削減など)

など


ありがとうございました

続きを読む

ElastiCacheでRedisClusterを作成する

目的

ElastiCacheでRedisClusterを作成し接続確認を行います。

前提条件

今回はClusterモードを有効な状態で作成します。
※Clusterモードの説明に関してはこの記事では割愛させて頂きます。
こちら に記載されています。

事前準備

必要な事前準備は下記の通りになります。
※Clusterを作りながらでも、進められるのですが、今回は事前に必要な物の作成を行っておきます。

  • Clusterに割り当てるサブネット、サブネットグループ
  • Clusterに適応するセキュリティグループ

サブネットの作成

ElastiCacheが利用するサブネットの作成を行います。

対障害性を向上させる為に、東京リージョンの ap-northeast-1aap-northeast-1c の2つのアベイラビリティーゾーンにサブネットを構築します。

  • ネームタグ: dev-session-redis-1a
  • IPv4 CIDRs: 192.0.50.0/24

create-subnet-a1.png

  • ネームタグ: dev-session-redis-1c
  • IPv4 CIDRs: 192.0.51.0/24

create-subnet-c1.png

サブネットグループの作成を行います。
マネジメントコンソールのElastiCache → Subnet Groups → 「Create Subnet Group」より作成を行います。

Name、Description は分かりやすいものであれば何でも構いません。
Availability Zoneにそれぞれ先程作成したサブネットを追加して「Create」をクリックします。

create-subnet-group.png

以上でサブネットの準備は完了です。

セキュリティグループの作成

ElastiCache用にセキュリティグループの作成を行います。

インバウンドルールで接続元からの6379ポートを空けておきます。

security-group1.png

security-group2.png

Clusterの作成(本題)

ここからようやく本題です。

マネジメントコンソールのElastiCache → Redis → 「Create」より作成を行います。

Cluster engine: Redis
Cluster Mode enabled (Scale Out): チェックを入れる

redis-cluster1.png

Name、Description は分かりやすいものであれば何でも構いません。
Subnet Groupには先程作成したサブネットグループを指定します。
その他は下記画像の通りに入力して下さい。(ほぼデフォルト設定のハズ)

redis-cluster2.png

Multi-AZ with Auto-Failover: チェックを入れます。(というかCluster Mode enabled (Scale Out)にチェックを入れた時点でチェック済になっているハズ)

Slots and keyspaces: [Equal distribution]
Availability zone(s): [No preference]
Security groups: 先程作成したセキュリティグループを指定

redis-cluster3.png

Import data to cluster: 空
Backup: デフォルトのまま ※本格的に運用する際は要件に合わせて設定して下さい。
Maintenance: デフォルトのまま ※これも実運用の際は要件に合わせて設定して下さい。

ちなみにこれらのパラメータは 公式ドキュメント に解説がありますので、本格運用される場合は目を通しておく事をオススメします。

redis-cluster4.png

ここまでで全てのパラメータの設定が完了したので「Create」をクリックすると作成が開始されます。

作成すると下記のような画面になります。

redis-cluster5.png

しばらくするとステータスが「available」になり、利用出来る状態となります。

redis-cluster6.png

動作確認

作成したClusterに接続出来るサーバにログインを行い redis-cli で動作確認を行います。

作成したサーバを選択し、Configuration Endpoint を確認すると接続用のホスト名が分かります。

ここでは dev-sessions.abcde9.clustercfg.apne1.cache.amazonaws.com が接続用のホストだとします。

redis-cliでログイン
redis-cli -h dev-sessions.abcde9.clustercfg.apne1.cache.amazonaws.com -c
テストデータを1件入力
SET test "testValue"

-> Redirected to slot [6918] located at 192.0.51.155:6379
OK
192.0.51.155:6379>
テストデータを取得出来るか確認
GET test

"testValue"
追加したテストデータを削除し削除出来ているか確認する
DEL test
(integer) 1

GET test
(nil)

※余談ですが、FLUSHALL で全てのデータを削除出来ますので、テストデータを一度キレイにしたい場合は FLUSHALL を実行すれば大丈夫です。
無論、運用中のサーバに対して実行すると全てのデータが消えてしまうので注意して下さい。

まとめ

あっさりとRedisClusterを立ち上げる事が出来ました。
本格運用の際にはまだまだ考慮すべき点は多いですが、取っ掛かりとしてこの記事が参考になれば幸いです。

最後まで読んで頂きありがとうございました。

続きを読む

DataPipelineを使ってdockerコンテナを定期実行してみる

やること

cronでジョブを実行するのと同じような感じで、DataPipelineを使ってdockerコンテナを定期実行するようにしてみる。
ジョブを定時実行するパイプラインがさくっと出来上がるようなCloudFormationのテンプレートを作る。

用意するもの

Docker Imageの実行定義

TaskDefinitionをrunするためのクラスター

CloudFormation Template

CloudFormationパラメータ

パラメータ名
EcsClusterName タスクを実行するクラスタ名
EcsTaskDefinitioinArn クラスタ上で実行するタスク

30分ごとにDataPipelineがEC2インスタンスを立ち上げaws-cliのecs run-taskコマンドでTaskDefinitionを実行しています。

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EcsClusterName:
    Type: String
    Description: Enter ECS Cluster Name to run docker.
  EcsTaskDefinitioinArn:
    Type: String
    Description: Enter TaskDefinitionArn to run.
Resources:
  EcsRunTaskSample:
    Type: 'AWS::DataPipeline::Pipeline'
    Properties:
      Name: ecs-run-task-sample
      Description: "Pipeline to run task on ECS"
      Activate: true
      ParameterObjects:
        - 
          Id: "myAWSCLICmd"
          Attributes: 
            - 
              Key: "description"
              StringValue: "command to execute"
            - 
              Key: "type"
              StringValue: "String"
      ParameterValues:
        - 
          Id: "myAWSCLICmd"
          StringValue:
            Fn::Join:
              - ""
              - - "AWS_DEFAULT_REGION="
                - Ref: AWS::Region
                - " aws ecs run-task --cluster "
                - Ref: EcsClusterName
                - " --task-definition "
                - Ref: EcsTaskDefinitioinArn
      PipelineObjects:
        - 
          Id: "Default"
          Name: "Default"
          Fields: 
            - 
              Key: "type"
              StringValue: "Default"
            - 
              Key: "failureAndRerunMode"
              StringValue: "CASCADE"
            - 
              Key: "role"
              StringValue: "DataPipelineDefaultRole"
            - 
              Key: "schedule"
              RefValue: "DefaultSchedule"
            - 
              Key: "resourceRole"
              StringValue: "DataPipelineDefaultResourceRole"
            - 
              Key: "scheduleType"
              StringValue: "cron"
        - 
          Id: "DefaultSchedule"
          Name: "Every 30 minutes"
          Fields: 
            - 
              Key: "parent"
              RefValue: "Default"
            - 
              Key: "type"
              StringValue: "Schedule"
            - 
              Key: "period"
              StringValue: "30 Minutes"
            - 
              Key: "startAt"
              StringValue: "FIRST_ACTIVATION_DATE_TIME"
        - 
          Id: "Ec2Instance"
          Name: "Ec2Instance"
          Fields: 
            - 
              Key: "parent"
              RefValue: "Default"
            - 
              Key: "type"
              StringValue: "Ec2Resource"
            - 
              Key: "instanceType"
              StringValue: "t2.micro"
            - 
              Key: "terminateAfter"
              StringValue: "10 Minutes"
        - 
          Id: "CliActivity"
          Name: "CliActivity"
          Fields: 
            - 
              Key: "parent"
              RefValue: "Default"
            - 
              Key: "type"
              StringValue: "ShellCommandActivity"
            - 
              Key: "runsOn"
              RefValue: "Ec2Instance"
            - 
              Key: "command"
              StringValue: "(sudo yum -y update aws-cli) && (#{myAWSCLICmd})"

ParameterObjects&ParameterValues

DataPipeline用のParameterが使えるようなので宣言する。(変数はmyで始めなきゃいけないという決まりがある)
myAWSCLICmdを宣言してCliActivityで実行するコマンドとして使う。

PipelineObjects

実際に実行するパイプラインの内容。

パイプラインオブジェクトの種類 type やってること
Schedule Schedule 30分毎にActivityを実行する
Resource Ec2Resource t2.microインスタンスを用意する。
Activity ShellCommandActivity aws-cliのaws run-taskでECSクラスター上にタスクを走らせる。

続きを読む

Amazon ECSを用いたDocker本番運用の実現

はじめに

現在お手伝いしているアカウンティング・サース・ジャパンにて、ECSを使ったDockerの本番運用を始めたので、その一連の流れについてまとめました。

税理士向け会計システムを扱うアカウンティング・サース・ジャパンでは最近Scalaでの新規プロジェクトが立ち上がってきており、既存のプロジェクトはJavaであったり、Erlangであったりと様々な言語が用いられていますが、インフラ人員が少ないということもあり、なるべくシンプルなインフラ構成を実現する必要がありました。

そういった中、各アプリケーションをDocker化することでインフラとしては共通基盤としてのDockerクラスタのみの管理になり、運用コストが下がるのではないかという仮説からDocker化を進めることになりました。クラスタを実現するに辺りKubenatesなどの選択肢もありましたが、今回はECSを選択し、下記のようにAWSのマネージドサービスを最大限に活用しています。

  • オーケストレーションツール: Amazon EC2 Container Service (ECS)
  • サービスディスカバリ: Application Load Balancer (ALB)
  • Dockerレジストリ: Amazon ECR
  • ログ、メトリクス収集: CloudWatch, CloudWatch Logs
  • 監視: CloudWatch Alarms
  • Infrastructure as Code: CloudFormation
  • CIツール: Jenkins

各技術の選定理由

今回Docker化を行うに辺り、下記を優先的に技術選定を行いました。

  • 運用が楽であること
  • 構成がシンプルで、技術の学習コストが低いこと

まずは、オーケストレーションツールの選定です。候補に上がったのは、Docker Swarm、Kubernetes、ECSです。

DockerのSwarm modeは本番での運用例が技術選定時点であまり見当たらなかったので候補から落としました。次にKubernetesとECSですが、海外の事例などではどちらも多く使われているようです。

今回は多機能さよりも運用に手間がかからない方が良いと考え、マネージドサービスであるECSが第一候補にあがりました。ここは詳細に調査したというよりも、ある種勢いで決めています。その上でやりたいことが実現できるかどうか一つ一つ技術検証を行った上で導入判断を行いました。

同じようにマネージドサービスを優先的に使ったほうが良いという考えで、ログなどでもCloudWatchを使っています。

AWSインフラをコードで記述するものとしてはTerraformが良く取り上げられている気がしますが、個人的にはいくつかの理由でCloudFormationを推しているのでこちらを使っています。

CIツールですが、社内の標準であるJenkinsをそのまま使うことにしました。

全体構成

下記のような構成になっています。

スクリーンショット 2017-05-21 12.46.39.png

ざっくりと説明すると、developmentブランチにプッシュするとGithub HookでJenkinsがDockerイメージをビルドして、ECRにPushします。ユーザはJenkinsでDeployジョブを実行(あるいはBuildの後続ジョブとして自動実行)し、CloudFormationにyamlファイルを適用することでTask, Service, ALB, Route53設定, CloudWatch設定を一通り実行します。またECSのClusterはあらかじめCloudFormationテンプレートを作成して作っておきます。

Task/Serviceの更新についてはCloudFormationを経由しない方がシンプルかとは思いまいしたが、Service毎に管理するRoute53やCloudWatchと合わせて一つのテンプレートにしてしまうのが良いと判断しました。

ここまでやるなら専用のデプロイ管理ツールを作った方がとも思ったのですが、業務委託という立場で自分しかメンテができないものを残すものは躊躇されたため、あくまでAWSとJenkinsの標準的な機能を組み合わせて実現しています。

CloudFormationテンプレートの解説

上記の流れが全てなので理解は難しくないと思いますが、一連の処理で重要なポイントとなるのはCloudFormationテンプレートなのでこれについてだけ触れておきます。長いテンプレートなのでざっくりとだけ雰囲気を掴んでもらえればと思います。

ECSクラスタのテンプレート

cluster作成用のCloudFormationテンプレートは下記のようになっています。

gist:cluster.yaml

一見複雑に見えますが、Amazon EC2 Container Service テンプレートスニペットを参考に作ると簡単に作成できると思います。

(あまりそのまま書くと会社に怒られそうなため)省略していますが、実際にはここにECSクラスタの監視を行うCloudWatch Alarmなどを設定することで、監視設定までこのテンプレートだけで完了します。

ECSクラスタはインフラチーム側であらかじめ用意しておき、リソースが足りなくなったときなどには適宜インスタンス数を変更したりクラスタ自体を別途作ったりしていきます。オートスケーリングを導入すればそれすら必要なくなります(今回はDocker運用が初めてだったので知見がたまるまで手動での対応にしています)。

インフラ側としての責務はここまでで、下記のテンプレートで定義される個別のサービスについてはアプリ開発者側の責務として明確に責任境界を分けました。(もちろん実際にはサポートはかなりの部分でしています。)

これにより全員が今までよりインフラに近い領域まで意識するように個人の意識が変わっていくことを期待しています。

個別サービス用テンプレート

開発環境、ステージング環境、プロダクション環境などそれぞれで同一のテンプレートを使うようにし、パラメータを使用します。そのパラメータをJenkinsのジョブ内で注入することで実現します。VPCなどの環境で決まる値はJenkinsジョブで実行するスクリプト内で定義し、アプリケーションごとの値は environment.yaml というファイルを用意してスクリプトから読み込みます。

environment.yamlは例えば下記のようになっています。アプリケーション開発者は、特殊なことをしない限りは service.yaml をインフラチームが用意したservice.yamlをコピーして、environment.yamlだけ編集すれば良い形になっています。DSLですら無いのでアプリ側のメンバーも心理的な抵抗が少ないようで良かったです。

environment.yaml
images:
- xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hoge-image
parameters:
  default:
    TaskMemory: 512
    TaskMaxMemory: 990
    ImageRepositoryUrl: xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hoge-image
    ServiceDesiredCount: 1
  dev:
    ClusterName: dev-default
    JavaOpts: "-Xmx256MB"
  stg:
    ClusterName: stg-default
    JavaOpts: "-Xmx256MB"
  prod:
    ClusterName: default
    JavaOpts: "-Xmx1500MB -Xms1500MB"
    TaskMemory: 1990
    TaskMaxMemory: 1990
    ServiceDesiredCount: 2

そして service.yaml は下記のようなファイルです。

gist:service.yaml

これもAmazon EC2 Container Service テンプレートスニペットから作ればすぐにできるのではないかと思います。(もちろん全てのパラメータは一つ一つ値を検討します。)

こちらもCloudWatch周りや重要でないところは削除しています。色々と手で削ってるのでコピペだと動かない可能性大ですが雰囲気だけ掴んで貰えればと思います。

このファイルは全アプリケーションで同一ファイルを使うのではなく、アプリケーションごとにコピー/編集して利用します。全体の変更を行うときには全プロジェクトのファイルを更新しなければいけませんが、共通基盤がアプリケーション側を制約しないように、プロジェクト毎のyamlファイル管理としています。ファイルの配置場所は各Gitリポジトリに配置するのが理想ですが、現状ではDocker運用になれてくるまで全てのyamlファイルを管理するリポジトリを作成してインフラチーム側が主に編集する形を取っています。

デプロイ

あとは、このservice.yamlとenvironment.yamlを組み合わせてデプロイするRubyスクリプトでもJenkinsのPipelineのコードでも適当に書いてJenkinsのJobを登録すれば完了です。(environment.yamlファイルを読み込んで aws cloudformation create-stack でservice.yamlと共にパラメータとして渡すだけなので簡単です!)

新規アプリ開発時も社内標準のservice.yamlとenvironment.yamlをファイルを持ってきて、environment.yamlを修正した上で、Jenkinsにジョブを登録すればすぐにDockerクラスタへのデプロイ準備が整います。しかも、上記のテンプレート例では割愛していますが、テンプレートには監視項目/通知設定まで書かれているので、インフラ側で設定を行う必要もなく監視が開始されます。CloudFormation最高ですね。

おわりに

実際の運用ではミッションクリティカルなアプリケーションならではの品質管理のために、JenkinsのPipeline機能を利用して開発→検証→リリースまでのデプロイメントパイプラインを実現しています。

アプリケーションのSECRETなどコミットしない情報をどう管理するかも検討する必要がありますが、これは管理の仕方はチームによって異なると思ったため割愛しています。

また、ログ解析としてはS3に出されたALBのログをRedash+Amazon Athenaでエラー率やアクセス数を分析できるようにし、CPU使用率やメモリ使用率などのパフォーマンス状況をCloudWatchの内容をGrafanaで可視化しています。これによりログ収集の基盤などを作らずに必要な可視化を実現することができました。ベンチャーでは分析基盤の運用も大きなコストになってしまうため、こういった工夫も必要です。(もちろん重要なKPIについては別途分析する仕組みが整っています。)

今回の構成が最高とは思いませんが、ある程度満足行くところまではできたかなと思います。もっとよくできるよ!とか一緒にやりたいな!とかもっと詳細聞きたいな!いう方はぜひ @miyasakura_ までご一報ください。

続きを読む