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 を削除する方法が一番確実だなと思いました。

docker-comopse で Rails 5 (Puma) + Nginx + Mysql 構築 on Vagrant(Ubuntu)

docker-comopse で Rails 5 (Puma) + Nginx + Mysql 構築 on Vagrant(Ubuntu)

自身の Rails 開発環境の雛形として利用している docker-compose です。

以下設定手順です。

Vagrant 起動

1
2
3
4
macOS%$ git clone https://github.com/kenzo0107/vagrant-docker
macOS%$ cd ./vagrant-docker/
macOS%$ vagrant up
macOS%$ vagrant ssh

Rails プロジェクト作成

1
2
3
// on vagrant
vagrant%$ cd /vagrant/rails-puma-nginx-mysql
vagrant%$ docker-compose run --rm web rails new . --force --database=mysql --skip-bundle

puma 設定ファイルセット

1
vagrant%$ cp puma.rb ./rails/config/
  • ./rails/config/puma.rb
1
2
3
4
5
6
7
8
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

データベース設定ファイルセット

1
vagrant%$ cp database.yml ./rails/config/
  • ./rails/config/database.yml
1
2
3
4
5
6
7
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV['MYSQL_ROOT_PASSWORD'] %> # <--- MYSQL_ROOT_PASSWORD
host: db # <--- service name

データベース作成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vagrant%$ docker-compose run --rm web rails db:create
Created database 'app_development'
Created database 'app_test'

vagrant%$ docker-compose exec db mysql -u root -p -e'show databases;'
Enter password: (password)
+--------------------+
| Database |
+--------------------+
| information_schema |
| app_development | <--- add !
| app_test | <--- add !
| mysql |
| performance_schema |
| sys |
+--------------------+

以上で必要最低限の Rails プロジェクトの準備ができました!

Rails, Nginx, MySQL 全コンテナ起動

1
vagrant%$ docker-compose up -d

ブラウザより http://192.168.35.101 へアクセスし
Rails トップページが表示されることが確認できます。

総評

docker でコンテナ化しているので Nginx, MySQL 等、
バージョンアップしたい時でもコンテナを置き換えるだけで簡単に使用感を確認できたり
機能を確認できたりと便利です。

これに Elasticsearch + Kibana でログを可視化したり
Mailcatcher でメール送信を確認できるようにしたりと
開発するには十分な状況が用意できます。

是非開発の一助になれば幸いです。

MySQL 一定秒以上 Sleep しているプロセスを一括 kill

メモ

300秒以上 Sleep しているプロセスIDをまとめて表示

1
2
3
4
5
6
7
$ mysql -h <host> -u <user> -p -e'SELECT GROUP_CONCAT(ID) FROM information_schema.PROCESSLIST WHERE TIME > 300;'

+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| GROUP_CONCAT(ID) |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 2147,2143,2138,2113,2111,2104,2102,2098,2087,2085,2082,2081,2079,2078,2069,2068,2045,2037,2029,2025,2023,2016,2015,2006,2005,2003,2002,2001,1999,1998,1997,1995,1987,1986,1984,1982,1981,1974,1973,1968,1966,1963,1961,1959,1957,1955,1954,1949,1937,1936,1928,1925,1923,1920,1916,1914,1912,1908,1906,1898,1892,1869,1847,1842,1651,1650,1572,1570,1568,1566,1539,1522,1517,1516,1514,1511,1506,1483 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

プロセスIDをまとめて一括 kill

1
$ mysqladmin kill <pid,pid,pid...> -h <host> -u <user> -p
Vagrant + docker-compose で Rails 5.1.0 (Puma) + Nginx + MySQL 環境構築

Vagrant + docker-compose で Rails 5.1.0 (Puma) + Nginx + MySQL 環境構築

概要

簡易的に Rails 環境を構築・開発できる様にすべく構築しました。

こんな時に利用してます。

  • 新規プロジェクト開発
  • 新規 gem, その他ミドルウェアの試験
  • 簡単なモックを作ってディレクターに見せたい時とか

構築手順をまとめました。

環境

  • macOS Sierra 10.12.5
  • VirtualBox 5.1.18r114002
  • Vagrant 1.9.3
  • VagrantBox Ubuntu 14.04.5
  • Docker version 17.06.0-ce, build 02c1d87

Git Clone

1
2
3
4
5
macOS%$ git clone https://github.com/kenzo0107/vagrant-docker
macOS%$ cd vagrant-docker
macOS%$ vagrant up
macOS%$ vagrant ssh
vagrant%$ cd /vagrant/rails-puma-nginx-mysql/

Rails プロジェクト作成

1
2
// database = mysql
vagrant%$ docker-compose run --rm web rails new . --force --database=mysql --skip-bundle

puma.rb 設定

1
2
3
// backup
vagrant%$ cp ./rails/config/puma.rb ./rails/config/puma.rb.bk
vagrant%$ cp puma.rb ./rails/config/
  • ./rails/config/puma.rb
1
2
3
4
5
6
7
8
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

データベース接続情報設定

1
2
3
// backup
vagrant%$ cp ./rails/config/database.yml ./rails/config/database.yml.bk
vagrant%$ cp database.yml ./rails/config/
  • ./rails/config/database.yml
1
2
3
4
5
6
7
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV['MYSQL_ROOT_PASSWORD'] %> # <--- MYSQL_ROOT_PASSWORD
host: db # <--- service name

DB 作成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vagrant%$ docker-compose run --rm web rails db:create
Created database 'app_development'
Created database 'app_test'

vagrant%$ docker-compose exec db mysql -u root -p -e'show databases;'
Enter password: (password)
+--------------------+
| Database |
+--------------------+
| information_schema |
| app_development | <--- add !
| app_test | <--- add !
| mysql |
| performance_schema |
| sys |
+--------------------+

Rails 実行

1
vagrant%$ docker-compose up -d

http://192.168.35.101 にアクセスすると Rails のウェルカムページが表示されます。

rails g

rails g 実行時は基本 one-off container で実行するのが良いです。

例えば以下は articles テーブルを作成、また、関連する controller, view, model を作成します。

1
vagrant%$ docker-compose run --rm web rails g scaffold article title:string body:text

Gemfile 更新

Gemfile 更新した際はビルドし再起動します。

1
2
3
vagrant%$ docker-compose stop web
vagrant%$ docker-compose build web
vagrant%$ docker-compose up -d web

あとがき

Rack server との接続は一癖ありましたが、そこさえ乗り越えたら
すっと行きました ♪

DB は 3306 でオープンしてるので
Mac のローカルから Sequel Pro で接続して確認できます。

これをベースに EFK でログ確認できる様にしたり、
mailcatcher でメール機能を試験できる様にしたりと
何かと便利です。

Docker 有難や ♪

Go+Revelフレームワーク 非同期でS3へ画像リサイズ/アップロード

備忘録です。

概要

AWS 向けの go ライブラリが乱立していて
どれ使ったらいい?という感じだったので
本家の launchpad.net/goamz/aws を利用して
実装することにしました。

Controller

  • app/controllers/img.go

Component

画像アップロード部分を component 化しました。

  • app/utility/aws.go

Views

  • Views/Img/Index.html
  • public/js/ajax.js
  • public/js/jquery.uploadThumbs.js

GKEチュートリアルでサイト構築・運用

概要

以前さくらVPS上で tocoちゃんバスアプリを作成しました。

さくらVPSは個人プロジェクトを幾つか載せていましたが
一部終了した為、tocoちゃんバスアプリを GCP にお引越ししました。

その時の話を GKE チュートリアルを兼ねて改めてまとめました。

何故 GCP ?

toco ちゃんバスアプリはDBも持たない軽量なサイトです。
その為、GCPの無料枠が利用できると思い、移行に至りました。

構成

GCPでは Container Cluster を利用し
この様な構成を取っております。

以下、GCP のチュートリアルに倣い構築手順まとめました。

gcloud デフォルト設定

以前無料枠を利用して構築した際の記事を参照ください。
Pod 単体の寂しい構成ではありますが汗

コンテナクラスタ作成

こちらも以前の記事同様、無料枠を利用すべく
初めに3ノードで作成し完了後、1ノードにします。

クラスターバージョンは 1.7.2 を指定しました。((2017年8月2日時点で cluster version 最新は 1.7.2))

1
$ gcloud container get-server-config

Fetching server config for us-west1-b
defaultClusterVersion: 1.6.7
defaultImageType: COS
validImageTypes:

  • CONTAINER_VM
  • COS
  • UBUNTU
    validMasterVersions:
  • 1.7.2
  • 1.6.7
    validNodeVersions:
  • 1.7.2
  • 1.7.1
  • 1.7.0
  • 1.6.7
  • 1.6.6
  • 1.6.4
  • 1.5.7
  • 1.4.9
  • コンテナクラスタ作成
1
2
3
4
5
$ gcloud container clusters create tocochan-cluster-free \
--cluster-version=1.7.2 \
--machine-type f1-micro \
--disk-size=30 \
--num-nodes=3
  • Node 数を 1 に設定
1
$ gcloud container clusters resize tocochan-cluster-free --size=1
  • 確認
1
$ gcloud container clusters describe tocochan-cluster-free | grep currentNodeCount

currentNodeCount: 1

現在のノード数が 1 であることが確認できました。
これで無料枠!

クラスタ作成後、コンテナクラスタの認証情報を取得し
kubectl でクラスタ接続し操作できる様にします。

1
$ gcloud container clusters get-credentials tocochan-cluster-free

Container Registory 登録

ローカルで起動したコンテナからイメージ作成し
GCP 上の Private な Docker リポジトリである Container Registory に登録します。

以下リポジトリを利用します。

https://github.com/kenzo0107/toda-tocochan-bus

  • Docker コンテナ起動
1
2
3
$ git clone https://github.com/kenzo0107/toda-tocochan-bus
$ cd toda-tocochan-bus
$ docker-compose up --build -d
  • 起動した Docker コンテナからイメージ作成・GCR へ push ((プロジェクトIDは 「mametsubuservice-175801」 ))
1
2
3
$ container_id=$(docker ps | grep [f]lask | awk '{print $1}')
$ docker commit $container_id gcr.io/mametsubuservice-175801/tocochan:latest
$ gcloud docker -- push gcr.io/mametsubuservice-175801/tocochan:latest

Pod 単体デプロイ as チュートリアル①

基本単体でデプロイすることは稀です。
単純に Pod 内のコンテナが異常停止した場合などを管理できない為です。
今回は無料運用の為と内容理解の為のチュートリアルとしての作業です。

  • pod.yaml
1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Pod
metadata:
name: tocochan
spec:
containers:
- image: gcr.io/mametsubuservice-175801/tocochan:latest
imagePullPolicy: Always
name: tocochan

Pod 単体デプロイ実行

1
$ kubectl create -f pod.yaml

Pod 状態確認

1
$ kubectl get pods
  • アクセス設定

flask は 5000 ポートで起動します。

1
2
3
4
$ kubectl port-forward tocochan 5000

Forwarding from 127.0.0.1:5000 -> 5000
Forwarding from [::1]:5000 -> 5000
  • ブラウザから http://localhost:5000 にアクセス

トップページが取得できることが確認できます。

Pod 名指定し削除

Pod 単体デプロイが確認できましたので削除しましょう。

1
$ kubectl delete pods tocochan

ReplicaSet デプロイ as チュートリアル②

Pod 単体作成した場合、 Pod に異常停止したとしても特に何もリカバーされません。
ReplicaSet では常に正常に動作するコンテナ数を管理しており
異常停止があった場合は新たに Pod を追加します。

こちらもチュートリアルとして記載してます。こちらは終わったら削除します。

  • replicaset.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: tocochan
spec:
replicas: 1 # 常に動作するコンテナ数
template:
metadata:
labels:
name: tocochan
spec:
containers:
- image: gcr.io/mametsubuservice-175801/tocochan:latest
imagePullPolicy: Always
name: tocochan

ReplicaSet デプロイ実行

1
$ kubectl create -f replicaset.yaml

ReplicaSet 確認

1
$ kubectl get rs -l name=tocochan

NAME DESIRED CURRENT READY AGE
tocochan-4006188167 1 1 1 10m

仮に Pods を削除しようとすると?

1
$ kubectl delete pods -l name=tocochan

起動コンテナが 0 になることなく、新たに作成されていることがわかります。

NAME READY STATUS RESTARTS AGE
tocochan-14s3b 1/1 Running 0 4s
tocochan-tsvfn 1/1 Terminating 0 5m

ReplicaSet 削除

1
$ kubectl delete rs tocochan

Deployment デプロイ

ReplicaSet のデプロイは k8s 上に履歴が残りません。
Deployment デプロイでは履歴が残り、現行バージョンに異常があった場合は
バージョンを簡単に戻せます。

これまでの問題を解決しているのが Deployment デプロイです。

  • deployment.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: tocochan
spec:
replicas: 1
template:
metadata:
labels:
name: tocochan
spec:
containers:
- image: gcr.io/mametsubuservice-175801/tocochan:latest
imagePullPolicy: Always
name: tocochan

Deployment デプロイ実行

--record を付けることで操作履歴を残すことができます。
履歴に残すことで問題がある場合に kubectl の操作で過去のバージョンに戻すことができます。

1
$ kubectl create -f deployment.yaml --record

Deployment 確認

1
$ kubectl get deployments -l name=tocochan

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
tocochan 1 1 1 1 10m

ReplicaSet 確認

1
$ kubectl get rs -l name=tocochan

NAME DESIRED CURRENT READY AGE
tocochan-2006588533 1 1 1 10m

Pod 確認

1
$ kubectl get pods -l name=tocochan

NAME READY STATUS RESTARTS AGE
tocochan-4006188167-3zrn9 1/1 Running 0 10m

デプロイ結果確認

1
$ kubectl rollout status deployment/tocochan

deployment “tocochan” successfully rolled out

正しく Rollout 公開されたことがわかりました。

履歴確認

1
$ kubectl rollout history deployment tocochan

deployments “tocochan”
REVISION CHANGE-CAUSE
1 kubectl create –filename=deployment.yaml –record=true

編集

1
$ kubectl edit deployment tocochan

vim が起動し deployment の編集が可能です。

1
2
- image: gcr.io/mametsubuservice-175801/tocochan:latest
+ image: gcr.io/mametsubuservice-175801/tocochan:v0.0.1

上記の様に編集し保存して終了すると

NAME READY STATUS RESTARTS AGE
tocochan-1297744065-2qb87 1/1 Terminating 0 15m
tocochan-4006188167-3zrn9 1/1 Running 0 10s

既存コンテナが停止中となコンテナが新たに立ち上がったことがわかります。

  • 履歴確認
1
$ kubectl rollout history deployment tocochan

REVISION CHANGE-CAUSE
1 kubectl create –filename=all.yaml –record=true
2 kubectl edit deployment tocochan

Rollout 履歴を確認すると 編集内容が追加されていることがわかります。

バージョンを戻す

REVISION 1 に戻します。

1
$ kubectl rollout undo deployment tocochan --to-revision=1
1
$ kubectl get pods -l name=tocochan

NAME READY STATUS RESTARTS AGE
tocochan-1297744065-2qb87 1/1 Terminating 0 6m
tocochan-4006188167-zswcj 1/1 Running 0 7s

先ほどと同様に既存コンテナが停止しコンテナが新たに起動している様子がわかります。

外部から接続できる?

ここまでの Pod の状態で以下コマンドを実行します。

1
$ kubectl get svc

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.3.240.1 443/TCP 3h

kubernetes の cluster-ip が割り振られている以外は特に IP が割り振られておらず
外部からアクセスできない状態です。

外部からアクセス出来る様、設定する必要があります。

Service 作成

外部向けの IP を設定し、外部から Pod にアクセス出来る様にルーティングします。

  • service.yaml
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Service
metadata:
name: tocochan
spec:
type: LoadBalancer
selector:
name: tocochan
ports:
- port: 5000

Service 作成

1
$ kubectl create -f service.yaml

Service 確認

1
$ kubectl get svc

数分経過すると から IPになります。

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.3.240.1 443/TCP 10m
tocochan 10.3.240.70 xx.xxx.xxx.xxx 5000:32429/TCP 10m

以下コマンドで Web ページにアクセス出来ることが確認できます。

1
$ curl -v http://$EXTERNAL-IP:5000

ロードバランサー作成

ロードバランサーを立てることが可能です。
80 port で受け、5000 port をバックエンドに流します。

  • ingress.yaml
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-world
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: hello-world
servicePort: 5000

Ingress 作成

1
$ kubectl create -f ingress.yaml

Ingress 確認

1
$ kubectl get ingress tocochan

NAME HOSTS ADDRESS PORTS AGE
tocochan * yy.yyy.yy.yy 80 10m

以下アクセスで先ほど実施した curl -v http://$EXTERNAL-IP:5000 と同様の結果が取得できることがわかります。

1
$ curl http://$INGRESS_IP/

設定ファイルをまとめる

1
2
3
4
5
6
7
8
9
$ echo '---' > hyphen.txt; \
cat \
deployment.yaml \
hyphen.txt \
service.yaml \
hyphen.txt \
ingress.yaml \
> all.yaml; \
rm hyphen.txt
  • all.yaml
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
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: tocochan
spec:
replicas: 1
template:
metadata:
labels:
name: tocochan
spec:
containers:
- image: gcr.io/mametsubuservice-175801/tocochan:v0.0.1
imagePullPolicy: Always
name: tocochan
---
apiVersion: v1
kind: Service
metadata:
name: tocochan
spec:
type: LoadBalancer
selector:
name: tocochan
ports:
- port: 5000
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tocochan
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: tocochan
servicePort: 5000

以降、以下コマンドで OK !

1
$ kubectl create -f all.yaml --record

ドメイン取得

toda-tocochan-bus.tkfreenom で無料ドメイン取得し
Ingress の IP を設定し公開しています。

総評

ローカルで開発して〜デプロイ、という流れが本当に簡単になりました。
コンテナの理念遂行に kubernetes は大きく寄与しているなぁと実感しました。

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

I used Phinx, DB migration Tool on Docker!

I used Phinx, DB migration Tool on Docker!

Overview

This is Sandbox for DB Migration Tool Phinx.

Preparation

1
2
$ git clone https://github.com/kenzo0107/phinx-mysql
$ cd phinx-mysql

Create and Run Containers of Phinx, DB (MySQL).

1
$ make build
1
2
3
4
5
6
$ docker-compose ps

Name Command State Ports
-------------------------------------------------------------------------
phinxmysql_db-migrate_1 phinx --help Exit 0
phinxmysql_db_1 docker-entrypoint.sh mysqld Up 3306/tcp

The Container db-migrate is used as for one-off container, so its state is Exit 0.

Initialize Phinx Project

Phinx creates a default file called phinx.yml.

1
$ make init

In default setting, phinx select development environment.

1. Create Table

Create phinx definition file

1
2
3
4
5
6
$ make create DB=hogehoge CLASS=CreateTableUsers
$ make create DB=mogemoge CLASS=CreateTableMembers
...
...
created db/migrations/hogehoge/20170724065658_create_table_users.php
created db/migrations/mogemoge/20170724065738_create_table_members.php

Edit phinx definition file

  • db/migrations/hogehoge/20170724065658_create_table_users.php

Writing Migrations

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
<?php

use Phinx\Migration\AbstractMigration;
use Phinx\Db\Adapter\MysqlAdapter;

class CreateTableUsers extends AbstractMigration
{
public function up()
{
// Automatically generated id is excluded, and primary key is set as user_id
$t = $this->table('users', ['id' => 'user_id']);

$t->addColumn('last_name', 'string', ['limit' => 10, 'comment' => '姓'])
->addColumn('first_name', 'string', ['limit' => 10, 'comment' => '名'])
->addColumn('last_kana_name', 'string', ['null' => true, 'limit' => 10, 'comment' => '姓(カナ)'])
->addColumn('first_kana_name', 'string', ['null' => true, 'limit' => 10, 'comment' => '名(カナ)'])
->addColumn('username', 'string', ['limit' => 20, 'comment' => 'ユーザ名'])
->addColumn('password', 'string', ['limit' => 40, 'comment' => 'パスワード'])
->addColumn('email', 'string', ['limit' => 100, 'comment' => 'Email'])
->addColumn('postcode', 'string', ['limit' => 10, 'comment' => '郵便番号'])
->addColumn('birthday', 'date', ['comment' => '誕生日'])
->addColumn('gender', 'integer', ['limit' => MysqlAdapter::INT_TINY, 'comment' => '性別(1:男 2:女 3:その他)'])
->addColumn('card_number', 'string', ['null' => true, 'limit' => 20, 'comment' =>'クレジットカードNo'])
->addColumn('description', 'text', ['null' => true, 'limit' => MysqlAdapter::TEXT_LONG, 'comment' =>'説明'])
->addColumn('created', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
->addColumn('updated', 'datetime', ['null' => true])
->addIndex(['username', 'email'], ['unique' => true])
->create();
}

public function down()
{
$this->dropTable('users');
}
}
  • db/migrations/mogemoge/20170724065738_create_table_members.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

use Phinx\Migration\AbstractMigration;

class CreateTableMembers extends AbstractMigration
{
public function up()
{
$t = $this->table('members');
$t->addColumn('member_code', 'string', ['limit' => 20, 'comment' => '会員コード'])
->addColumn('created', 'timestamp', ['default' => 'CURRENT_TIMESTAMP'])
->addColumn('updated', 'datetime', ['null' => true])
->addIndex(['member_code'], ['unique' => true])
->create();
}

public function down()
{
$this->dropTable('members');
}
}

2. Add Column

Create phinx definition file

1
2
3
4
$ make create CLASS=AddTableUsersColumnsCity
...
...
created db/migrations/hogehoge/20170724065838_add_table_users_columns_city.php

Edit phinx definition file

  • db/migrations/hogehoge/20170724065838_add_table_users_columns_city.php

Add the column city after the column email.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

use Phinx\Migration\AbstractMigration;

class AddTableUsersColumnsCity extends AbstractMigration
{
public function up()
{
$t = $this->table('users');
$t->addColumn('city', 'string', ['limit' => 10, 'comment' => '都市', 'after' => 'postcode'])
->update();
}

public function down()
{
$t = $this->table('users');
$t->removeColumn('city')
->save();
}
}

Migration

1
$ make migrate
  • Result
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
mysql> use hogehoge
mysql> show full columns from users;
+-----------------+--------------+-----------------+------+-----+-------------------+----------------+---------------------------------+---------------------------------+
| Field | Type | Collation | Null | Key | Default | Extra| Privileges | Comment |
+-----------------+--------------+-----------------+------+-----+-------------------+----------------+---------------------------------+---------------------------------+
| user_id | int(11) | NULL | NO | PRI | NULL | auto_increment| select,insert,update,references | |
| last_name | varchar(10) | utf8_general_ci | NO | | NULL || select,insert,update,references | 姓 |
| first_name | varchar(10) | utf8_general_ci | NO | | NULL || select,insert,update,references | 名 |
| last_kana_name | varchar(10) | utf8_general_ci | YES | | NULL || select,insert,update,references | 姓(カナ) |
| first_kana_name | varchar(10) | utf8_general_ci | YES | | NULL || select,insert,update,references | 名(カナ) |
| username | varchar(20) | utf8_general_ci | NO | MUL | NULL || select,insert,update,references | ユーザ名 |
| password | varchar(40) | utf8_general_ci | NO | | NULL || select,insert,update,references | パスワード |
| email | varchar(100) | utf8_general_ci | NO | | NULL || select,insert,update,references | Email |
| city | varchar(255) | utf8_general_ci | NO | | NULL || select,insert,update,references | |
| postcode | varchar(10) | utf8_general_ci | NO | | NULL || select,insert,update,references | 郵便番号 |
| birthday | date | NULL | NO | | NULL || select,insert,update,references | 誕生日 |
| gender | tinyint(4) | NULL | NO | | NULL || select,insert,update,references | 性別(1:男 2:女 3:その他) |
| card_number | varchar(20) | utf8_general_ci | YES | | NULL || select,insert,update,references | クレジットカードNo |
| description | longtext | utf8_general_ci | YES | | NULL || select,insert,update,references | 説明 |
| created | timestamp | NULL | NO | | CURRENT_TIMESTAMP || select,insert,update,references | |
| updated | datetime | NULL | YES | | NULL || select,insert,update,references | |
+-----------------+--------------+-----------------+------+-----+-------------------+----------------+---------------------------------+---------------------------------+


mysql> use mogemoge
mysql> show full columns from members;
+-------------+-------------+-----------------+------+-----+-------------------+----------------+---------------------------------+-----------------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+-------------+-------------+-----------------+------+-----+-------------------+----------------+---------------------------------+-----------------+
| id | int(11) | NULL | NO | PRI | NULL | auto_increment | select,insert,update,references | |
| member_code | varchar(20) | utf8_general_ci | NO | UNI | NULL | | select,insert,update,references | 会員コード |
| created | timestamp | NULL | NO | | CURRENT_TIMESTAMP | | select,insert,update,references | |
| updated | datetime | NULL | YES | | NULL | | select,insert,update,references | |
+-------------+-------------+-----------------+------+-----+-------------------+----------------+---------------------------------+-----------------+

Rollback

1
$ make rollback

3. Create sample seeds for Multi Databases;

Create phinx definition file

1
2
3
4
5
6
$ make seed_create DB=hogehoge CLASS=UserSeeder
$ make seed_create DB=mogemoge CLASS=MembersSeeder
...
...
created ./db/seeds/hogehoge/UsersSeeder.php
created ./db/seeds/mogemoge/MembersSeeder.php

Edit phinx definition file

  • ./db/seeds/hogehoge/UsersSeeder.php
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
<?php

use Phinx\Seed\AbstractSeed;

class UsersSeeder extends AbstractSeed
{
public function run()
{
$t = $this->table('users');
$t->truncate();

$genders = [1,2,3];

$faker = Faker\Factory::create('ja_JP');
$d = [];
for ($i = 0; $i < 10; $i++) {
$d[] = [
'last_name' => $faker->lastName(10),
'first_name' => $faker->firstName(10),
'last_kana_name' => $faker->lastKanaName(10),
'first_kana_name' => $faker->firstKanaName(10),
'username' => $faker->userName(20),
'password' => sha1($faker->password),
'email' => $faker->email,
'postcode' => $faker->postcode,
'city' => $faker->city,
'birthday' => $faker->date($format='Y-m-d',$max='now'),
'gender' => $faker->randomElement($genders),
'card_number' => $faker->creditCardNumber,
'description' => $faker->text(200),
'created' => date('Y-m-d H:i:s'),
'updated' => date('Y-m-d H:i:s'),
];
}

$this->insert('users', $d);
}
}
  • ./db/seeds/hogehoge/MembersSeeder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

use Phinx\Seed\AbstractSeed;

class MembersSeeder extends AbstractSeed
{
public function run()
{
$t = $this->table('members');
$t->truncate();

$faker = Faker\Factory::create('ja_JP');
$d = [];
for ($i = 0; $i < 10; $i++) {
$d[] = [
'member_code' => $faker->regexify('[0-9]{20}'),
'created' => date('Y-m-d H:i:s'),
'updated' => date('Y-m-d H:i:s'),
];
}

$this->insert('members', $d);
}
}

Run seed

1
$ make seed
  • Result
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
mysql> use hogehoge;
mysql> select * from users;
+---------+-----------+------------+-----------------+-----------------+-------------+------------------------------------------+------------------------------+----------+--------------+------------+--------+------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
| user_id | last_name | first_name | last_kana_name | first_kana_name | username | password | email | postcode | city | birthday | gender | card_number | description | created | updated |
+---------+-----------+------------+-----------------+-----------------+-------------+------------------------------------------+------------------------------+----------+--------------+------------+--------+------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
| 1 | 佐々木 | 零 | ヤマダ | カナ | akira97 | e270038c94f231da7bca25dead3e386ba3984491 | hirokawa.rika@hotmail.co.jp | 1867251 | 佐々木市 | 1987-09-25 | 1 | 4024007116991463 | Dolor reiciendis fuga fugiat id molestiae eos. Dolores sint rem repudiandae perspiciatis. Ducimus aut mollitia aut asperiores laboriosam. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 2 | 宮沢 | 千代 | ノムラ | ヨウイチ | nagisa.taro | 695a90d1b84cf004357aad3eb37697b51afbf5cc | tanabe.hiroshi@kudo.org | 8639535 | 江古田市 | 1977-06-01 | 3 | 344103919563863 | Doloribus et recusandae quam accusantium pariatur nobis reiciendis quo. Eos quae et commodi quos accusamus ex. Ullam repellendus maiores vero sit sit et. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 3 | 斉藤 | 充 | ミヤケ | オサム | kana.suzuki | f309f34d08b4d0d686863fa38ed3d3af5e0b2104 | kana.kudo@mail.goo.ne.jp | 2763622 | 青田市 | 1997-01-30 | 1 | 4716886227252 | Veritatis voluptatem pariatur libero aut quia. Facere nemo quos enim amet ut ipsum sequi. Nobis natus et aspernatur aut. Natus pariatur deserunt voluptatum deserunt. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 4 | 吉田 | 太郎 | ウノ | ツバサ | naoko.uno | 45d04bda7ac79244c90a33ff68798b979138054a | taro.nagisa@hirokawa.com | 6099661 | 江古田市 | 2006-03-19 | 2 | 5372535333698250 | Nostrum velit nostrum eos magni. Reiciendis quos enim adipisci quisquam sed voluptas. Necessitatibus sint qui dolorem animi impedit consectetur commodi. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 5 | 野村 | 亮介 | サトウ | ミノル | rika.tanabe | dd3d50714c0775bfee453f7d9a9815ce26ba57db | wkudo@hotmail.co.jp | 6966314 | 渡辺市 | 1985-12-21 | 1 | 4929108488987091 | Id atque molestiae expedita omnis libero natus et. Repellendus ut tenetur molestias voluptas. Perspiciatis nisi et illum aut aut vel repudiandae. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 6 | 木村 | 裕美子 | タナカ | ヒロキ | hiroshi53 | 033bfd0493b72efd0ff60bc15c7eeb3b2e054501 | ztanabe@tanabe.biz | 3155238 | 山田市 | 1996-01-02 | 3 | 5476616628100007 | Assumenda consectetur ea sed et omnis alias fugiat quo. Porro nihil similique sint laudantium asperiores blanditiis. Error dolores vitae quia explicabo facilis deleniti distinctio. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 7 | 吉本 | 陽一 | キムラ | ヒデキ | akira27 | 51de6afc65f535ae58f927d698f07e60e04c7746 | rika59@suzuki.com | 6457702 | 田辺市 | 2010-04-12 | 2 | 5388155063289311 | Nesciunt qui beatae ut officia qui error autem. Temporibus alias earum ullam incidunt quo recusandae enim qui. Sed atque veritatis sed ad ullam qui. Repellendus est nostrum et pariatur. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 8 | 渡辺 | 翔太 | ササダ | クミコ | uno.momoko | fa2d16d5f2acffd5aeeaab6791fe64c9f70a9b2f | stanabe@uno.com | 5849600 | 伊藤市 | 2012-06-09 | 1 | 5274550197820022 | Odio quasi sunt tempora. Molestias aut qui sed quos beatae eum accusantium. Non dolores quam veniam et ab quidem nostrum repellendus. Qui ducimus et optio et. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 9 | 坂本 | 翔太 | ナカツガワ | ナオキ | akira.kudo | 4af41e536bf19fa3cb0527304adad0de76260e82 | suzuki.momoko@mail.goo.ne.jp | 8609563 | 宮沢市 | 2005-10-23 | 3 | 5231530310398512 | Qui id neque molestiae facere aut et consequatur. Delectus ea voluptatibus provident atque assumenda maxime eum. At quidem sint accusamus. Eaque sed voluptate quo sint non non. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
| 10 | 野村 | 翼 | ヒロカワ | ナオコ | taro.kudo | f8a63d0010c99d6403e0c1f458005b934ec03f8c | kana.tanabe@mail.goo.ne.jp | 5804069 | 桐山市 | 1988-12-25 | 2 | 5140671281503530 | Dolorem consequatur nulla alias perspiciatis ut. Tenetur modi cumque incidunt dolor. | 2017-07-25 12:22:50 | 2017-07-25 12:22:50 |
+---------+-----------+------------+-----------------+-----------------+-------------+------------------------------------------+------------------------------+----------+--------------+------------+--------+------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+



mysql> use mogemoge;
mysql> select * from members;

+----+----------------------+---------------------+---------------------+
| id | member_code | created | updated |
+----+----------------------+---------------------+---------------------+
| 1 | 86190539096622228312 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 2 | 77322186584623078448 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 3 | 17169562241415794809 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 4 | 86738824931379981947 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 5 | 23125815173540252188 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 6 | 81839177491562485300 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 7 | 82938165381845652192 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 8 | 87208503292784158954 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 9 | 80172779107984112104 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
| 10 | 22825755425594828330 | 2017-07-25 12:22:51 | 2017-07-25 12:22:51 |
+----+----------------------+---------------------+---------------------+

Reference

5分でできる♪ AWS Lambda で EC2 Event を Slack 通知

以前 AWS EC2 メンテ通知のイベントチェックスクリプトを作成しました。
合わせて、対象インスタンスを停止・起動する様にしました。

これを AWS Lamda で Slack 通知させる様にし
毎朝メンテの必要なイベントがわかる様にしました。

事前準備

1
2
macOS%$ pip install lambda-uploader awscli
macOS%$ aws configure --profile <profile>

プロジェクト clone

1
2
3
4
5
6
7
8
macOS%$ git clone https://github.com/kenzo0107/AWSEC2Events2Slack
macOS%$ tree AWSEC2Events2Slack
.
├── README.md
├── event.json
├── lambda.json
├── lambda_function.py
└── requirements.txt

各種環境に合わせて情報編集

  • lambda.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"name": "AWSEvent2Slack",
"description": "Notificate AWS events to Slack",
"region": "ap-northeast-1",
"handler": "lambda_function.lambda_handler",
"role": "arn:aws:iam::xxxxxxxxxxxx:role/lambda-check-events-to-slack",
"timeout": 60,
"memory": 128,
"variables":
{
"SLACK_INCOMING_WEBHOOK":"https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX",
"SLACK_CHANNEL":"#channel",
"SLACK_USERNAME":"AWSEvent2Slack",
"SLACK_ICON_URL":"http://i.imgur.com/6RCTdfi.png"
}
}
Item Explain
role EC2リソースをdescribeする権限を所持したポリシーをアタッチ
variables 通知先Slack情報

AWS Lambda へソースアップロード

1
2
3
4
5
macOS%$ lambda-uploader --profile <profile>

λ Building Package
λ Uploading Package
λ Fin

AWSコンソールより Lambda 確認

登録されていることがわかります。

テスト実行

イベントを取得しSlackに通知させる様にすることができました。

トリガー設定

CloudWatch スケジュール式で cron 設定し 毎朝届ける様に指定しました。

総評

lambda-uploader でのアップロードにより
ローカルで開発→テスト→デプロイ
とバージョン管理が明確になって良いです。

但し、一点気になる点はアップロード後、ソースがコンソール上で見えません。

具体的には

Lambda 関数 「AWSEvent2Slack」のデプロイパッケージが大きすぎて、インラインコード編集を有効にできません。ただし、関数を今すぐ呼び出すことはできます。

とコンソール上に表示されます。

前まで zip にまとめてアップロードするシェルを書いていたけど
その時はソースは見ることができました。

ローカルで挙動確認しておりコンソール上では見えなくても今のところ支障なしです。

以上
参考になれば何よりです。

Mackerel で Docker の起動状態確認

Mackerel で Docker の起動状態確認

概要

Docker コンテナがいつの間にか Exit していた!
なんてことを防ぐ為の Mackerel Agent の設定です。

mackerel-plugin-docker-state インストール

1
2
3
4
5
6
7
$ sudo mkdir -p /etc/mackerel-agent/conf.d
$ sudo curl https://raw.githubusercontent.com/ABCanG/mackerel-plugin-docker-state/master/mackerel-plugin-docker-state -o /etc/mackerel-agent/conf.d/mackerel-plugin-docker-state
$ sudo chmod +x /etc/mackerel-agent/conf.d/mackerel-plugin-docker-state
$ sudo cat <<'EOF'>/etc/mackerel-agent/conf.d/docker-state.conf
[plugin.metrics.docker-state]
command = "/etc/mackerel-agent/conf.d/mackerel-plugin-docker-state"
EOF

mackerel-agent.conf に include 設定追加

  • /etc/mackerel-agent/mackerel-agent.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
pidfile = "/var/run/mackerel-agent.pid"
root = "/var/lib/mackerel-agent"
verbose = false
apikey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
diagnostic = true

roles = ["xxxxxxxx:xxx"]

# include conf.d/*.conf
include = "/etc/mackerel-agent/conf.d/*.conf"

...
...

Mackrel Agent 再起動

1
$ sudo service mackerel-agent restart

グラフ確認

しばらくするとグラフが表示されます。
※0 or 1 のみのグラフなので積み重ねグラフの方が見やすかったです

※上記グラフではコンテナ 2 つが起動しています。

新規監視ルールを作成

running で検索すると出てきます。

3 分間の平均が 1 より低くなったら
コンテナが停止(Exit)と見なし通知する様にしました。

総評

今回たまたま Mackerel の入ったサービスを触る機会を頂きました。

Mackerel の様なマネージドサービスを利用するメリットは
監視サーバを監視しないで良い、
という省運用コストだなぁと改めて実感。

Install latest Nginx on Ubuntu

Install latest Nginx on Ubuntu

Just a memo.

Install Nginx

1
2
3
4
5
6
ubuntu%$ sudo su
ubuntu%$ curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add -
ubuntu%$ sh -c "echo 'deb http://nginx.org/packages/ubuntu/ trusty nginx' >> /etc/apt/sources.list"
ubuntu%$ sh -c "echo 'deb-src http://nginx.org/packages/ubuntu/ trusty nginx' >> /etc/apt/sources.list"
ubuntu%$ apt-get update
ubuntu%$ apt-get install -y nginx

Install sysv-rc-conf

SysV is a runlevel configuration tool.

1
ubuntu%$ apt-get install -y sysv-rc-conf

Configure runlevel of nginx.

The command chkconfig is no longer available in Ubuntu. The equivalent command to chkconfig is update-rc.d. This command nearly supports all the new versions of ubuntu.

  • chkconfig —> sysv-rc-conf
1
ubuntu%$ sysv-rc-conf nginx on

Show runlevel of nginx

1
2
ubuntu%$ sysv-rc-conf --list nginx
nginx 0:off 1:off 2:on 3:on 4:on 5:on 6:off