長生村本郷Engineers'Blog

千葉県長生村本郷育ちのエンジニアが書いているブログ

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

f:id:kenzo0107:20170822123209p:plain

概要

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

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

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

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

環境

Git Clone

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 プロジェクト作成

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

puma.rb 設定

// backup
vagrant%$ cp ./rails/config/puma.rb ./rails/config/puma.rb.bk
vagrant%$ cp puma.rb ./rails/config/
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"

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

// backup
vagrant%$ cp ./rails/config/database.yml ./rails/config/database.yml.bk
vagrant%$ cp database.yml ./rails/config/
  • ./rails/config/database.yml
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作成

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 実行

vagrant%$ docker-compose up -d

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

f:id:kenzo0107:20170822123732p:plain

rails g

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

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

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

あとがき

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

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

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

Docker 有難や♪

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング

今更聞けない!CPU, Memory 使用率の見方

f:id:kenzo0107:20170810140724p:plain

気持ちを抑えられずありがちなタイトルを付けました。

サーバ負荷監視時のボトルネックの特定をする為、
実際に手を動かして自分で見て解決するというチュートリアルとして
本記事を参照いただければ何よりです。

サーバに接続し辛い

f:id:kenzo0107:20170810141554p:plain

  • ブラウザからURLを打ち込みサイトにアクセスするもページが表示されない
  • API が timeout する

上記の様な事象が発生した場合は
監視グラフに異変が起きているはずです。

その監視グラフを元に
アクセスしづらくなった徴候のある負荷状況を確認し
ボトルネックを特定していきます。

以下、出来るだけ原理を知る上で CLI を元に話を進めていきます。

サーバにCPU負荷を掛ける

f:id:kenzo0107:20170810142151j:plain

CPU負荷を掛けるツールとしてLinuxのI/OやCPUの負荷とロードアベレージの関係を詳しく見てみるスクリプトを拝借しました。
※ありがとうございます @kunihirotanaka 社長!

  • loadtest.pl
    • arg1: 並列実行するプロセス数
    • arg2: システムコールするプログラムを動作させるか判定
#!/usr/bin/perl

my $nprocs = $ARGV[0] || 1;
for( my $i=0; $i<$nprocs; $i++ ){
    my $pid = fork;
    die $! if( $pid < 0 );
    if( $pid == 0 ){
        while(1){
            if( $ARGV[1] ){
                open(IN, ">/dev/null");
                close(IN);
            }
        }
    }
}
wait;

ロードアベレージを 2 に近づける様にCPU負荷を掛ける

$ chmod +x ./loadtest.pl
$ ./loadtest.pl 2

CPU使用状況確認コマンド

  • リアルタイム監視 → top, vmstat
  • 過去確認 → sar

リアルタイム監視

top で概要確認

$ top
top - 12:12:39 up 592 days, 18:55,  4 users,  load average: 1.97, 1.13, 0.46
Tasks: 125 total,   3 running, 122 sleeping,   0 stopped,   0 zombie
Cpu(s): 99.7%us,  0.2%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.2%st
Mem:   1020052k total,   943132k used,    76920k free,   144136k buffers
Swap:  2097148k total,   466724k used,  1630424k free,   410784k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
29955 mameko_d  20   0 25196  520  184 R 99.9  0.1   4:04.91 loadtest.pl
29956 mameko_d  20   0 25196  516  180 R 99.5  0.1   4:04.86 loadtest.pl
24534 apache    20   0  425m  25m 7480 S  0.3  2.6   1:42.63 httpd
    1 root      20   0 19232  412  224 S  0.0  0.0   0:01.77 init
...
...

上記結果から
- Load Average が上昇している
- %CPU, COMMAND から上昇の原因は loadtest.pl

暫定的な対処としてはこのプロセスを kill することで負荷を止めることができます。

$ kill -9 6528
$ kill -9 6529

処理途中でプロセスを kill してしまい不整合が発生する様な処理の場合は
別途、CPU の増強等を検討する等、状況によりますが対応を検討する必要があります。

グラフで見る

これまで CLI で確認した考察の答え合わせとして確認しましょう。

f:id:kenzo0107:20170810121609p:plain

  • 12:07 辺りから負荷上昇
  • loadavg5 急上昇
  • CPU user 急上昇。 CPU system はそこまで上がっていない。 → アプリケーションのプロセスがCPUを食っている。
  • memory は消費していない

top コマンドの様にどのプロセスが原因かまではグラフからは不明です。
サーバにアクセスして12:07 あたりからのログを調査する等原因を特定していきます。

補足

ちなみに
Apache のモジュールとして PHP を利用している場合は COMMANDhttpd と表示されます。
fluentd は ruby で実行されているので ruby です。

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12376 apache 20 0 833m 115m 19m S 2.4 3.1 0:03.52 httpd
1455 td-agent 20 0 461m 74m 0 S 1.2 2.0 1098:30 ruby

vmstat で CPU 使用率確認

1秒ごとに出力

$ vmstat 1

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----  
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st  
0  0 515396  80756  37120 220320    0    0    12     2    0    0  0  0 100  0  0  
0  0 515396  80756  37120 220320    0    0     0     0  110  200  0  0 100  0  0  
0  0 515396  80756  37120 220320    0    0     0     0  103  205  0  0 100  0  1  
0  0 515396  80632  37120 220320    0    0     0     0  121  212  0  0 99  0  0  
0  0 515396  80632  37120 220320    0    0     0     0  114  216  0  0 100  0  0  
2  0 515328  80648  36944 220432    0    0     0     0 2092  237 100  0  0  0  0  
2  0 515328  80648  36944 220432    0    0     0     0 2071  224 100  0  0  0  0  
2  0 515328  81020  36952 220432    0    0     0     0 2162  381 100  1  0  0  0  
2  0 515328  80896  36952 220432    0    0     0     0 2164  266 100  0  0  0  0  
2  0 515328  80756  36952 220432    0    0     0     0 2139  308 100  0  0  0  0  
2  0 515328  80772  36952 220432    0    0     0     0 2111  237 100  0  0  0  0  
2  0 515328  80772  36952 220432    0    0     0     0 2087  238 100  0  0  0  0  
2  0 515328  80772  36952 220432    0    0     0     0 2077  237 100  0  0  0  0  
2  0 515328  80772  36952 220432    0    0     0     0 2076  232 99  1  0  0  0  
2  0 515328  80772  36952 220432    0    0     0     0 2078  235 100  0  0  0  0  
2  0 515328  80904  36952 220432    0    0     0     0 2081  231 85  0  0  0 15  
0  0 515328  81448  36952 220432    0    0     0     0  267  254  6  0 94  0  0  
0  0 515328  81448  36952 220432    0    0     0     0  151  250  0  0 99  0  0  
0  0 515328  81448  36952 220432    0    0     0     0  230  307  0  0 99  0  0  
0  0 515328  81456  36952 220432    0    0     0     0  123  230  0  0 100  0  0  

上記から以下のことが確認できます。
- ./loadtest.pl 2 を実行中は procs r (実行中プロセス) = 2 となっている
- cpu us が 100%, cpu id が 0%
- cpu id がなくなり、プログラムが 100% CPU を食いつぶしている
- system in (割り込み回数)、system cs (コンテキストスイッチ回数) が増加
- コンテキストスイッチ自体が CPU を食いシステムの負荷を上げている

過去確認

$ sar -u -s 21:00:00 -e 22:10:00 -f /var/log/sa/sa31

21:00:01      runq-sz  plist-sz   ldavg-1   ldavg-5  ldavg-15  
21:10:01            0       200      0.00      0.04      0.07  
21:20:01            0       203      0.00      0.00      0.01  
21:30:01            0       203      0.00      0.00      0.00  
21:40:01            0       211      0.00      0.03      0.00  
21:50:01            0       210      0.65      0.82      0.37  
Average:            0       205      0.13      0.18      0.09  

sar コマンドは過去まで遡って確認できるので便利です。

sar -q 実行結果各項目
Item Explain
runq-sz CPU を実行する為のメモリー内で待機中のカーネルスレッド数。
通常、この値は 2 未満になる。
値が常に 2 より大きい場合は、システムが CPU の限界に到達している可能性がある
plist-sz プロセスリストのプロセスとスレッド数
ldavg-1 過去1分間のロードアベレージ
ldavg-5 過去5分間のロードアベレージ
ldavg-15 過去15分間のロードアベレージ

システムコールを伴うCPU負荷

ロードアベレージを 2 に近づける & システムコールする様にCPU負荷を掛ける

$ ./loadtest.pl 2 1

vmstat で監視

$ vmstat 1

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----  
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st  
 0  0 597832 886856   3808  34844    0    0    12     2    0    0  0  0 100  0  0  
 1  0 597828 886856   3808  34908    0    0     0     0  134  233  1  0 99  0  0  
 0  0 597788 886684   3944  34876   20    0   156     0  238  307  1  1 96  4  0  
 0  0 597788 886684   3944  34904    0    0     0     0  109  219  0  0 100  0  0  
 2  0 597756 884044   3956  36296   96    0  1500     0 1075 1274 18 26 41 15  0  ← loadtest.pl 2 1 実行開始  
 2  0 597756 884044   3956  36296    0    0     0     0 2080 2265 42 58  0  0  0  
 2  0 597756 884076   3956  36296    0    0     0     0 2083 2458 41 60  0  0  0  
 2  0 597756 884200   3964  36292    0    0     0    32 2103 2458 42 59  0  0  0  
 2  0 597756 884200   3964  36296    0    0     0     0 2079 2588 41 60  0  0  0  
 3  0 597756 883952   3964  36296    0    0     0     0 2080 2209 40 60  0  0  1  
 2  0 597756 884216   3964  36296    0    0     0     0 2085 2395 42 58  0  0  0  
 2  0 597756 884216   3964  36296    0    0     0     0 2061 2399 43 57  0  0  0  
 3  0 597756 884092   3964  36296    0    0     0     0 2061 1991 44 57  0  0  0  
 2  0 597756 884216   3964  36296    0    0     0     0 2059 2333 42 58  0  0  1  
 2  0 597756 884216   3964  36296    0    0     0     0 2058 2211 42 58  0  0  1  
 2  0 597756 884092   3964  36296    0    0     0     0 2058 2461 43 58  0  0  0  
 2  0 597756 883844   3964  36296    0    0     0     0 2059 2641 42 58  0  0  0  
 2  0 597756 884216   3964  36296    0    0     0     0 2158 2715 42 59  0  0  0    ← loadtest.pl 2 1 実行終了  
 0  1 597744 884588   3964  36364   44    0   144     0 1995 2313 37 58  3  2  0  
 0  0 597724 884388   3964  36524  208    0   380     0  173  239  0  1 95  5  0  
 0  0 597724 884388   3964  36568    0    0     0     0  102  196  0  0 100  0  0  
 0  0 597636 884388   3964  36568    0    0     0     0  102  203  0  0 100  0  0  
 0  0 597636 884512   3964  36568    0    0     0     0  104  195  0  0 100  0  1  
  • loadtest.pl からシステムコールが多数実行される為、cpu sy 上昇している。

グラフで見る

f:id:kenzo0107:20170810123318p:plain

  • 12:25 辺りから負荷急上昇
  • loadavg5 急上昇
  • CPU user, system 共に急上昇。 system の割合が多い
    → システムコールを伴うアプリケーションのプロセスがCPUを食っている。
  • memory は消費していない

対応例

  • アプリケーションのCPU使用箇所の特定
    • datadog, NewRelic 等の APM(Aplication Performance Management) 導入しアプリケーションのボトルネック抽出し修正
      • コストこそ掛かりますが非常に有用です
  • CPU増設
  • 対象アプリのプロセスを kill (先ほどの プロセス kill )
    • 例)管理画面で集計処理し、DBに負荷掛けサービスに影響してしまった時に集計処理のプロセスを kill

サーバにメモリ負荷を掛ける

f:id:kenzo0107:20170810142217j:plain

  • memorytest.pl

1秒毎に 20MB 消費する様に設定

#!/usr/bin/perl

while(1){
    sleep 1;
    push @h  , 1 x 1024 x 1024 x 20
}
wait;
  • メモリ負荷実行
$ chmod +x ./memorytest.pl
$ ./memorytest.pl

メモリ使用状況確認コマンド

  • リアルタイム → top -a, free
  • 過去確認 → sar

残メモリ確認

top で概要確認

$ top -a

もしくは top 実行後、 Shift + m

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6780 mameko_d 20 0 385m 362m 1212 S 5.3 36.4 0:01.88 memorytest.pl

上記結果から
- %MEM, COMMAND から上昇の原因は memorytest.pl

暫定的な対処としては loadtest.pl と同様、プロセスを kill することで負荷を止めることができます。

$ kill -9 6780

free で残メモリ確認

$ free

             total       used       free     shared    buffers     cached  
Mem:       1020052     908664     111388        572      29764     204492  
-/+ buffers/cache:     674408     345644  
Swap:      2097148     517696    1579452  

何度か実行すると徐々に Mem
- used 上昇
- free 減少
- free 減少に引っ張られて buffers, cached 減少

free 実行結果各項目
  • Mem: 実メモリ
  • Swap: 仮想メモリ
Item Explain
shared プロセス間で共有できる領域用メモリ
buffers buffer に利用されるメモリ
I/Oアクセスする時に、直接I/Oに行くのではなく、キャッシュ経由でアクセスさせる為のメモリ
cached ページキャッシュ用メモリ
アプリで実メモリが必要な際は、 cached のメモリが破棄される

確認観点

上記 free コマンド実行結果から解放されたメモリは

Mem free 111388 kB = 108 MB  

これだけでは 108 MB が残りと思いがちですが
通常、各プロセスにメモリ割り振った残りを buffercache に利用して disk I/O を軽減している為、
buffer + cache も含まれます。

実質、残メモリはどこ見れば良い?

free + buffers + cached
= 111388 + 29764 + 204492 kB = 345644 kB
= 338 MB
= -/+ buffers/cache free

以上から
残メモリの目安は -/+ buffers/cache free 確認 or スラッシングを確認します。

Swap 発生は何を見ればわかる?

vmstat 実行してスラッシングが発生しているか確認

スラッシング確認方法
  • si (swap in from disk), so (swap out to disk) が多発している場合、スラッシングが発生しています
  • so が比較的高い場合、メモリ不足の可能性大
$ vmstat 1

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----  
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st  
 0  0 593244 211856   3704  34744    0    0     0     0  236  215  4  2 94  0  0  
 1  0 593244 211876   3704  34744    0    0     0     0  144  216  1  0 98  0  0  
 0  0 593244 160664   3704  34744    0    0     0     0  207  220  4  1 96  0  0  
 0  0 593244 109328   3704  34744    0    0     0     0  227  226  4  2 94  0  0  
 0  1 593052  58900   3704  33312    0    0     0     0  515  241  4  2 59 34  0  
 0  1 618460  55144   1224  15220    0 25416     0 25416 39357  528  5 24 34 37  1  ← ここで memorytest.pl 行開始
 0  1 670408  56644   1160  13732    0 51948     0 51948 37384  644  7 22 34 37  1  
 1  1 671048  59256    456  12480    0  640     0   640  182  254  1  1 49 50  0  
 0  0 735892  72040    436  10088    0 64844    96 64844 14559 1044  3 15 67 15  0  
 0  0 786748  71436    436   9596    0 50856   124 50856 13678  745  4 13 69 14  1  
 0  2 830880  63556    436   9504   32 44144   320 44144 15659  636  5 13 54 28  0  
 0  3 849932  48976    436   8652  304 19168  1104 19168 6568  661  6  6 32 55  1  
 0  1 900916  71564    776   8264   88 50992   560 50992 9549  706  1 10 27 62  0  
 0  3 941292  64152   1308   9880   80 40380  2564 40380 10800  622  5 11 29 56  1  
 0  1 993108  69908   1700  10656    0 51820  2024 51852 10208  848  5 12 43 40  1  
 2  0 994168  71536   1700  10428    0 1060     0  1060  216  257  3  1 82 15  0  
 0  0 1045720  71384   1700   9456    0 51552     0 51552 5356  789  2  9 77 12  1  
 0  0 1096468  71468   1332   9012    0 50748     0 50748 15385  857  6 13 72  9  1  
  • bo (block out to device) … ブロックデバイスに送られたブロック
  • bi (block in from device) … ブロックデバイスから受け取ったブロック

グラフで見る

f:id:kenzo0107:20170810125452p:plain

  • 12:35 辺りからメモリ急上昇
  • cached 減、 used 増

対応例

  • プロセスレベルで監視
    • datadog, mackerel, prometheus, zabbix 等監視ツール導入
  • メモリ増設
  • 対象アプリのプロセスを kill (先ほどの プロセス kill )

Disk I/O

I/Oディスク利用状況 確認

$ sar -b -s 13:00:00 -e 14:00:00 -f /var/log/sa/sa31

13:00:01          tps      rtps      wtps   bread/s   bwrtn/s
13:10:01         0.28      0.01      0.27      0.11      2.90
13:20:01         0.28      0.00      0.28      0.05      2.99
13:30:01         0.22      0.00      0.22      0.00      2.30
13:40:01         0.24      0.00      0.24      0.00      2.50
13:50:01         0.23      0.00      0.23      0.03      2.35
Average:         0.25      0.00      0.25      0.04      2.61

sar -b 実行結果項目

Item Explain
tps 1秒あたりの転送 (デバイスに対するIOリクエスト) 数の合計
rtps 1秒あたりの読み込みIOリクエストの回数の合計
wtps 1秒あたりの書き込みIOリクエストの回数の合計
bread/s 1秒あたりの(ブロック単位)読み込みIOリクエストのデータ量の合計
bwrtn/s 1秒あたりの(ブロック単位)書き込みIOリクエストのデータ量の合計

確認観点

  • I/O 待ち増加する原理
プロセスのメモリ消費量増
↓  
キャッシュにメモリが使えなくなる  
↓  
Disk I/O にメモリが使えなくなる  
↓  
Disk I/O 増加  
↓  
I/O 待ちプロセス増加  

対策

  • メモリの使用状況と Swap 確認

まとめ

CPU, Memory 使用率が上昇する原理を知った上で監視をすると
全然グラフの見え方が違うことを実感しました。

本来はグラフから見ることになるかと思います。
その際に top, vmstat, sar を実行した時の数値の変化の仕方をイメージすると
より原因追及に大きな一歩となると思います。

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

Reference

補足

Swap とは?

カーネルがほぼ利用されていないメモリを検出して排除している状態を表示しています。

  1. メモリの空きを入出力のバッファとキャッシュに使用
  2. さらに活動が少ない部分をメモリから排除して swap へ押し出す
  3. swap からバッファやキャッシュに転用

その為、 swap が発生している、といって慌てない。

Swap を利用する意義

メモリ不足でもメモリの一部をディスクに退避させて計算し続けることができます。
メモリを使い切った様に見せつつもまだ使える仕組みを 仮想メモリ と言います。

スラッシングとは?

実メモリ と Swap のメモリの移動が大量発生し処理が遅延する現象です。

sar コマンドがない場合はインストール

// CentOS
$ yum install -y sysstat

// Ubuntu
$ apt-get install -y sysstat

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

備忘録です。

概要

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

Controller

  • app/controllers/img.go

gist.github.com

Component

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

  • app/utility/aws.go

gist.github.com

Views

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

f:id:kenzo0107:20170803131821p:plain

概要

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

kenzo0107.hatenablog.com

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

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

何故 GCP

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

構成

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

f:id:kenzo0107:20170803142949p:plain

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

gcloud デフォルト設定

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

kenzo0107.hatenablog.com

コンテナクラスタ作成

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

クラスターバージョンは 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

$ gcloud container clusters create tocochan-cluster-free \
      --cluster-version=1.7.2 \
      --machine-type f1-micro \
      --disk-size=30 \
      --num-nodes=3 
  • Node 数を 1 に設定
$ gcloud container clusters resize tocochan-cluster-free --size=1
  • 確認
$ gcloud container clusters describe tocochan-cluster-free | grep currentNodeCount

currentNodeCount: 1

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

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

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

Container Registory 登録

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

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

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

  • Docker コンテナ起動
$ git clone https://github.com/kenzo0107/toda-tocochan-bus
$ cd toda-tocochan-bus
$ docker-compose up --build -d
  • 起動した Docker コンテナからイメージ作成・GCR へ push *2
$ 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 チュートリアル

f:id:kenzo0107:20170803142852p:plain

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

apiVersion: v1
kind: Pod
metadata:
  name: tocochan
spec:
  containers:
    - image: gcr.io/mametsubuservice-175801/tocochan:latest
      imagePullPolicy: Always
      name: tocochan

Pod 単体デプロイ実行

$ kubectl create -f pod.yaml

Pod 状態確認

$ kubectl get pods
  • アクセス設定

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

$ kubectl port-forward tocochan 5000

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

f:id:kenzo0107:20170804120645p:plain

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

Pod 名指定し削除

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

$ kubectl delete pods tocochan

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

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

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

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 デプロイ実行

$ kubectl create -f replicaset.yaml

ReplicaSet 確認

$ kubectl get rs -l name=tocochan

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

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

$ 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 削除

$ kubectl delete rs tocochan

Deployment デプロイ

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

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

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 の操作で過去のバージョンに戻すことができます。

$ kubectl create -f deployment.yaml --record

Deployment 確認

$ kubectl get deployments -l name=tocochan

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

ReplicaSet 確認

$ kubectl get rs -l name=tocochan

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

Pod 確認

$ kubectl get pods -l name=tocochan

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

デプロイ結果確認

$ kubectl rollout status deployment/tocochan

deployment “tocochan” successfully rolled out

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

履歴確認

$ kubectl rollout history deployment tocochan

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

編集

$ kubectl edit deployment tocochan

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

- 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

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

  • 履歴確認
$ kubectl rollout history deployment tocochan

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

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

バージョンを戻す

REVISION 1 に戻します。

$ kubectl rollout undo deployment tocochan --to-revision=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 の状態で以下コマンドを実行します。

$ kubectl get svc

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

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

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

Service 作成

f:id:kenzo0107:20170803142453p:plain

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

apiVersion: v1
kind: Service
metadata:
  name: tocochan
spec:
  type: LoadBalancer
  selector:
    name: tocochan
  ports:
    - port: 5000

Service 作成

$ kubectl create -f service.yaml

Service 確認

$ 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 ページにアクセス出来ることが確認できます。

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

ロードバランサー作成

f:id:kenzo0107:20170803142609p:plain

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

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hello-world
spec:
  rules:
  - http:
      paths:
       - path: /*
         backend:
           serviceName: hello-world
           servicePort: 5000

Ingress 作成

$ kubectl create -f ingress.yaml

Ingress 確認

$ kubectl get ingress tocochan

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

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

$ curl http://$INGRESS_IP/

設定ファイルをまとめる

$ echo '---' > hyphen.txt; \
  cat \
  deployment.yaml \
  hyphen.txt \
  service.yaml \
  hyphen.txt \
  ingress.yaml \
> all.yaml; \
rm hyphen.txt
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 !

$ kubectl create -f all.yaml --record

ドメイン取得

toda-tocochan-bus.tkFreenom - 誰でも利用できる名前 で無料ドメイン取得し
Ingress の IP を設定し公開しています。

総評

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

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

Docker入門

Docker入門

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)

Dockerエキスパート養成読本[活用の基礎と実践ノウハウ満載!] (Software Design plus)

*1:2017年8月2日時点で cluster version 最新は 1.7.2

*2:プロジェクトIDは 「mametsubuservice-175801」

I used Phinx, DB migration Tool on Docker!

f:id:kenzo0107:20170721210050p:plain

Overview

This is Sandbox for DB Migration Tool Phinx.

Preparation

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

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

$ make build
$ 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.

$ make init

In default setting, phinx select development environment.

1. Create Table

Create phinx definition file

$ 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

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

$ 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.

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

$ make migrate
  • Result
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

$ make rollback

3. Create sample seeds for Multi Databases;

Create phinx definition file

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

$ make seed
  • Result
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 メンテ通知のイベントチェックスクリプトを作成しました。
合わせて、対象インスタンスを停止・起動する様にしました。

kenzo0107.hatenablog.com

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

事前準備

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

プロジェクト clone

GitHub - kenzo0107/AWSEC2Events2Slack: AWS ec2 event notification to Slack

macOS%$ git clone https://github.com/kenzo0107/AWSEC2Events2Slack
macOS%$ tree AWSEC2Events2Slack
.
├── README.md
├── event.json
├── lambda.json
├── lambda_function.py
└── requirements.txt

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

{
    "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 へソースアップロード

macOS%$ lambda-uploader --profile <profile>

λ Building Package
λ Uploading Package
λ Fin

AWSコンソールより Lambda 確認

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

https://camo.githubusercontent.com/43c524e70a16dfafe29dfad03c3340afd75cc1db/687474703a2f2f692e696d6775722e636f6d2f473470383565622e706e67

テスト実行

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

https://camo.githubusercontent.com/a8d87244b9139795b02f3292044ee38a9783bf6b/687474703a2f2f692e696d6775722e636f6d2f456d65327577372e706e67

トリガー設定

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

f:id:kenzo0107:20170718213805p:plain

総評

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

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

具体的には

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

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

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

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

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

Mackerel で Docker の起動状態確認

f:id:kenzo0107:20170714223239p:plain

概要

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

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

$ 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
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 再起動

$ sudo service mackerel-agent restart

グラフ確認

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

f:id:kenzo0107:20170714222015p:plain

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

新規監視ルールを作成

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

f:id:kenzo0107:20170714223652p:plain

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

総評

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

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