selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

Revieee開発日記 [20170725]

今日の作業

  • RDSへの置き換えを行う

1pomo 9:50 - 10:15

cloudformationでRDSの設定をする.

RevieeeDB:
    Type: AWS::RDS::DB::Instance
    Properites:
      DBSecurityGroups:
        - Ref: #TODO: SET Security Group
        - Ref: #TODO: SET Security Group
      AllocatedStorage: '' #TODO:
      DBInstanceClass: db.m1.small #TODO: set correct instance type
      Engine: MySQL
      MasterUsername: #TODO: secure settings
      MasterUserPassword: #TODO: secure settings
    DeletionPolicy: Snapshot

ベースはこれ。このあと、下記の項目について対応する

  • 適切なDBInstanceClassの指定
  • SecurityGroupの設定
  • AllocatedStorageの設定
  • Username, Passwordの設定(暗号化必須?)

ほとんどデータも格納しないだろうし、一旦 t2.microにした。 vCPU 1, ECU 1, Memory 1GB.

次はSecurityGroupsの設定を行う。 アクセスする必要があるのは、nginxとLambdaであり、nginx RevieeeAppServerSecurityGroupに入っているので、一旦これだけ設定。 Lambdaについては、やりながら考える

AllocatedStorageについて調べる。

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html#cfn-rds-dbinstance-allocatedstorage

The allocated storage size, specified in gigabytes (GB). If any value is set in the Iops parameter, AllocatedStorage must be at least 100 GB, which corresponds to the minimum Iops value of 1,000.

よくIOPSを忘れるのでメモ :sweat_smile: 
IOPS => 1秒あたりに捌けるI/Oの数.
https://en.wikipedia.org/wiki/IOPS

2pomo 10:25 - 10:50

引き続きAllocatedStorageから。 Iopの設定すると、AllocatedStorageの値は最低100GBで、Iopsの値は1000になるよ! とのこと。AllocatedStorageの値って、最低何GBが適正なんだろ….

http://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/CHAP_Storage.html

汎用 (SSD) – gp2 とも呼ばれる汎用 (SSD) ボリュームは、さまざまなワークロードに対応できるコスト効率の高いストレージとして使用できます。これらのボリュームでは、レイテンシーは 1 桁台のミリ秒であり、長時間 3,000 IOPS にバーストできます。最小 100 IOPS (33.33 GiB 以下) から最大 10,000 IOPS (3,334 GiB 以上) まで、ベースラインパフォーマンスは 3 IOPS/GiB (ボリュームサイズ) の割合で線形に拡大します。gp2 ボリュームのサイズ範囲は、1 GiB ~ 16 TiB です。

ふーむ。汎用SSDだと1GB ~ 16 TiBと…

Provisioned IOPS – Provisioned IOPS ストレージは、ランダムアクセス I/O スループットにおけるストレージのパフォーマンスと整合性が重視される大量の I/O を伴うワークロード (特にデータベースワークロード) の要件を満たすように設計されています。Provisioned IOPS ボリュームのサイズは、100 GB〜6 TB (MySQLMariaDBPostgreSQL、および Oracle DB エンジン用) です。

なるほど、IOPSの設定をすると、Provisioned IOPSになるのかな。 となると、100GBがミニマムスタートになる。

今回は汎用SSDで良さげだな。容量と金額の関係性が分からないが、1GBでも十分かな。 足りなくなったら、後で増やそう。

次は Username, Passwordの設定 に入る。 これは外部引数として渡す方法でやるかなぁ。

一旦 Parametersを使った。 次のポモドーロで Conditionsを使う方法を調査する。

3pomo 11:00 - 11:25

Conditionsの設定を見て、書いてみた。 https://github.com/speee/webapp-revieee/pull/75 ここから先は、実行しながら確認していく。

このあとは、今後の設計に関する議論になったので、今日の作業はここまで

revieee開発日記[20170713]

やりたいこと

現状整理

  • curlを実行すると http://127.0.0.1:80 が返ってきてる
  • 実際は、mysqlにはport3000が入っている
  • http://127.0.0.1:3000 が返ってきて欲しい
# curl
curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.01
http://127.0.0.1:80
# container log
nginx-proxy      | nginx.1    | endpoint-1.reviewapps.speee.jp 172.21.0.1 
- - [13/Jul/2017:01:11:01 +0000] "GET / HTTP/1.1" 200 20 "-" "curl/7.43.0"

問題ありそうな場所

  • nginx-proxyがリクエストを掴んじゃって、revieee_nginx_container にリクエストを返していない
  • ちゃんとcacheを消せていない

確認方法

  • revieee_nginx_containerのキャッシュが消せていない問題
    • キャッシュを物理的に削除してみる。

1pomo 10:40 - 11:05

ちゃんとcacheが消せていない可能性を潰す。

% docker exec -it revieee_nginx_container /bin/bash
root@06ec8eb57c9f:/# rm /var/tmp/localmemcache/*.lmc
mysql> select * from endpoints;
+------+-----------+------+---------+
| id   | ip        | port | task_id |
+------+-----------+------+---------+
|    1 | 127.0.0.1 | 3000 |       1 |
+------+-----------+------+---------+
1 row in set (0.01 sec)

これで、アクセスしたら、http://127.0.0.1:3000が返ってくるはず。

% curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.01
http://127.0.0.1:3000
http://127.0.0.1:3000

つまり、cacheがちゃんと消せてないということが分かった。 もう一度、revieee/clear時のエラーログを確認する。

nginx-proxy      | nginx.1    | 2017/07/13 01:49:04 [error] 
39#39: *7 upstream prematurely closed connection while reading 
response header from upstream, client: 172.21.0.1, 
server: *.reviewapps.speee.jp, request: "GET /revieee/clear HTTP/1.1", 
upstream: "http://172.21.0.4:80/revieee/clear", 
host: "endpoint-1.reviewapps.speee.jp"
nginx-proxy      | nginx.1    | 
endpoint-1.reviewapps.speee.jp 172.21.0.1 - - 
[13/Jul/2017:01:49:04 +0000] "GET /revieee/clear HTTP/1.1" 
502 173 "-" "curl/7.43.0"

今からは上のエラーの原因調査のみに集中する

upstream prematurely closed connection while reading response header from upstream

エラーログはこれ。upstreamのresponse headerを読み込んでいる最中に、upstreamが早まってconnectionをclosedにしたぞと。どういうことよ…

revieee_nginx側のlogが欲しい。なので、revieee_nginx側のlog設定を見直す。

 なので、下記の設定を nginxのcontainerに追記する。

access_log /var/log/nginx/access.log;

nginx 再起動

docker exec revieee_nginx_container /usr/local/nginx/sbin/nginx -s reload
root@06ec8eb57c9f:/var/log# tail -f nginx/access.log
172.21.0.3 - - [13/Jul/2017:02:16:07 +0000] "GET / HTTP/1.1" 200 22 "-" "curl/7.43.0"
172.21.0.3 - - [13/Jul/2017:02:16:10 +0000] "GET /revieee/clear HTTP/1.1" 000 0 "-" "curl/7.43.0"

logが流れている….どうやら、このnginx containerまでは到達した模様. もうちょっとloggerの精度を高めたいなぁ。

2pomo 11:20 - 11:45

わざわざcontainer入らないと見れないのツライからもっと調査する。

https://docs.docker.com/engine/admin/logging/view_container_logs/

を熟読。access_logを↓のように設定する。

access_log /dev/stdout;

すると、accessしたときに、下記のようなlogが流れた。

revieee_nginx_container | 172.21.0.3 - - [13/Jul/2017:02:39:09 +0000] "GET /sample HTTP/1.1" 200 32 "-" "curl/7.43.0"
nginx-proxy      | nginx.1    | sample.reviewapps.speee.jp 172.21.0.1 - - [13/Jul/2017:02:39:09 +0000] "GET /sample HTTP/1.1" 200 32 "-" "curl/7.43.0"

大体目的どおり。

Revieee開発日記 [20170711]

やりたいこと

引き続き、infratasterでhttp://endpoent-xxx.reviewapps.speee.jp のroutingがテストできるようにする。

そのために確認したいこと

テスト環境において、下記の挙動となることを確認したい

1pomo 10:20 - 10:45

docker-compose downで、誤ってテスト用データ消しちゃったので、もう一度作り直す。

% docker-compose up -d
% mysql -u root -A -h 127.0.0.1 -P 33306
mysql> create database revieee_development;
Query OK, 1 row affected (0.00 sec)
mysql> use revieee_development;
Database changed
mysql> create table endpoints(id int, ip varchar(15), port int, task_id int);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into endpoints(id, ip, port, task_id) values (1, '127.0.0.1', 80, 1);
Query OK, 1 row affected (0.00 sec)

できた。とりあえず挙動を確認したい。curlを実行する。

% curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.0.1                                                                                                         [10:24:28]
<html>
<head><title>500 Internal Server Error</title></head>
<body bgcolor="white">
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.11.13</center>
</body>
</html>

なぞのエラー。 エラーログはこんな感じ。

revieee_nginx_container | 2017/07/11 01:24:28 [error] 5#0: *2128 upstream prematurely closed connection while reading response header from upstream, client: 127.0.0.1, server: ~^endpoint-(?<endpoint_id>\d+)\.reviewapps\.speee\.jp$, request: "GET / HTTP/1.0", upstream: "http://127.0.0.1:80/", host: "endpoint-1.reviewapps.speee.jp"

キャッシュが問題かも知れないので、それを消してみる。

% curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.0.1/revieee/clear

そのときのログはこちら。

revieee_nginx_container | 2017/07/11 01:27:44 [error] 5#0: *2175 mrb_run failed: return 500 HTTP status code to client: error: /usr/local/nginx/hook/clear.rb:21: lmc_set_lock_flag: Failed to lock shared memory--may be corrupt! (Cache::ShmLockFailed), client: 172.21.0.2, server: ~^endpoint-(?<endpoint_id>\d+)\.reviewapps\.speee\.jp$, request: "GET /revieee/clear HTTP/1.1", host: "endpoint-1.reviewapps.speee.jp"
nginx-proxy      | nginx.1    | endpoint-1.reviewapps.speee.jp 172.21.0.1 - - [11/Jul/2017:01:27:44 +0000] "GET /revieee/clear HTTP/1.1" 500 194 "-" "curl/7.43.0"

なぞのエラー。とりあえず動いていたころまでコードを戻してみるが、やっぱりダメだった。 コードでは無いところで問題が発生していそう。

 mrb_run failed: 
 return 500 HTTP status code to client: 
 error: /usr/local/nginx/hook/clear.rb:21: 
 lmc_set_lock_flag: Failed to lock shared memory--may be corrupt! 

このエラーから問題を探っていこう。 同じようなエラーに遭遇している人があんまりいないし、issueも無いのでコードを読む。

https://github.com/matsumotory/mruby-localmemcache/blob/master/src/localmemcache.c#L17-L28

3pomo 14:10 - 14:35

https://github.com/matsumotory/mruby-localmemcache/blob/ae9e0f0816a7610a1237e86ad18db01d1459498b/src/localmemcache.h#L120

このあたりにファイルが作られてた。 エラーログを見るとshared memoryが壊れているらしい。 なので、一旦消してみる。このエラーに戻ってきた。

% curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.0.1/                                                                                                        [15:39:03]
<html>
<head><title>400 Request Header Or Cookie Too Large</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>Request Header Or Cookie Too Large</center>
<hr><center>nginx/1.11.13</center>
</body>
</html>

やっぱり原因が不明….

今日の開発の振り返り

エラーに振り回されてしまった。 知らない分野でも、もう少し狙いをつけて調査する癖を付けなければ。

とりあえず、動くところまで戻した。 エラーが起きた原因を考えながら、もう一度実装してみる。 Nginx for revieee bugfix by selmertsx · Pull Request #74 · speee/webapp-revieee · GitHub

Revieee開発日記 [20170710]

やりたいこと

1pomo 10:20 - 10:45

  • テストで動くことを確認する
  • テスト用データを投入できるようにする。
  • テスト用データは作り直しができるようにする
docker exec revieee_nginx_container /usr/local/nginx/sbin/nginx -s reload

とりあえず、http://endpoint-1.reviewapps.speee.jp にアクセスしたら、 http://127.0.0.1:3000 が返ってくるところまでやった。 IPは127.0.0.1、PORTは3000で良さそう。

次は、proxy_passに http://127.0.0.1:3000 が入ってるか確認したい。 とはいえ、proxy_passを入れないときに出てくるエラーを見ておく。

revieee_nginx_container | 2017/07/10 01:26:36 [error] 18#0: *6 invalid URL prefix in "", client: 172.21.0.3, server: ~^endpoint-(?<endpoint_id>\d+)\.reviewapps\.speee\.jp$, request: "GET / HTTP/1.1", host: "endpoint-1.reviewapps.speee.jp"

ということで、proxy_passに何も入ってなかったのかと思い、ちょっといじってみる。 https://github.com/speee/webapp-revieee/commit/d5ce8f9ffb7feeea4745f4b4771af05cb32860d0

revieee_nginx_container | 2017/07/10 01:36:36 [error] 28#0: *7 connect() failed (111: Connection refused) while connecting to upstream, client: 172.21.0.3, server: ~^endpoint-(?<endpoint_id>\d+)\.reviewapps\.speee\.jp$, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "endpoint-1.reviewapps.speee.jp"

エラーが変わった。http://127.0.0.1:3000 に接続できなかったよ!ってエラーっぽい。 なので、テスト用の環境があると良さそう… 一旦、同一nginx内のリクエストに飛ばし直して、今存在しているコードも少し手をいれておく。

% docker exec -it revieee_nginx_container /bin/bash                           [10:43:18]
root@ebf6209b9bf2:/# curl http://127.0.0.1
This is test for ngx_mruby hoge

テストコードを作って動作を確認。どうやら大丈夫そうだ。 次は、mysql serverに入って、データをちょっといじっておく。

% mysql -u root --port 33306 -h 127.0.0.1

mysql> use revieee_development;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

mysql> select * from endpoints;
+------+-----------+------+---------+
| id   | ip        | port | task_id |
+------+-----------+------+---------+
|    1 | 127.0.0.1 | 3000 |       1 |
+------+-----------+------+---------+
1 row in set (0.00 sec)

mysql> update endpoints set port=80 where id=1;

Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

で、もう一度やってみる。

revieee_nginx_container | 2017/07/10 01:49:46 [error] 57#0: *13 connect() failed (111: Connection refused) while connecting to upstream, client: 172.21.0.3, server: ~^endpoint-(?<endpoint_id>\d+)\.reviewapps\.speee\.jp$, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3000/", host: "endpoint-1.reviewapps.speee.jp"

2pomo 10:50 - 11:15

またportが変わってない。そうか nginxのメモリにキャッシュされてるんだ。 キャッシュクリアしないと。

http://qiita.com/zaru/items/c41072e29b9550c2e6a8

↑を読んでみるが、僕たちの実装と結構大きく違う… ふーむ… nginxのキャッシュ周りは後で勉強しないと。 実践 nginxが、今ならちゃんと読みたいと思えるはず。

とりあえず今は、cache clear用のコードを書こう。

% curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.0.1/revieee/clear
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.13.0</center>
</body>
</html>

clearにつかったコードはこちら https://github.com/speee/webapp-revieee/pull/73/commits/205c1e956df7d33e56bf4ecf50e1743011cbd962

がっつり重複しているので、いい感じに整理したい。

3pomo 11:20 - 11:45

挙動を整理する。

  • キャッシュは消せたのか?
  • 消せてたら、502問題だけどうにかする
  • 消せてなかったら、何がいけないのか調査する
% curl -H "Host: endpoint-1.reviewapps.speee.jp" http://127.0.0.1             [11:25:18]
<html>
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.11.13</center>
</body>
</html>
revieee_nginx_container | 2017/07/10 02:25:53 [error] 99#0: *4479 upstream prematurely closed connection while reading response header from upstream, client: 172.21.0.3, server: ~^endpoint-(?<endpoint_id>\d+)\.reviewapps\.speee\.jp$, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:80/", host: "endpoint-1.reviewapps.speee.jp"

ふーむ…とりあえず、今日はここまで。 テストデータ作成用のscriptは用意したい。

20170706_今日の素振り

Amazon EC2 System Managerのパラメータストアを使って、settings.local.ymlを消せないか考えてみる。今日は、System Manager、パラメータストアのドキュメントを読んで、ちょっと確かめるまでやる。

Amazon EC2 System Managerとは

System Managerでは、マネージドインスタンスの設定を安全にリモートで管理することができるツール。今回は、その中のパラメータストアを使いたい。パラメータストアは、設定データの管理を一元化するもの。settings.local.ymlのパラメータを、こいつで簡単に運用できないか考えたい。

セットアップ

Amazon Linux 2015.09、2015.03 以降でのみ、利用可能。

IAMロールの設定

コマンドを処理するEC2インスタンスのIAMロールと、コマンドを実行するユーザーのロールが必要。

手順は下の3ステップ

ユーザーの作成

  • ユーザー名: SystemsManagerUserFullAccessみたいなやつ
  • Permission: AmazonSSMFullAccess, AmazonSSMReadOnlyAccess
  • Management Consoleアクセスはいらない。

EC2インスタンス用のロール設定

AmazonEC2RoleforSSMポリシーを適用したRoleを作る。

EC2インスタンスにロールをアタッチする

普通にアタッチすれば良い。

SSMエージェントのインストー

既に起動しているインスタンスにインストールする方法。

mkdir /tmp/ssm
cd /tmp/ssm
sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
sudo status amazon-ssm-agent #これだけで動くのか確認しておく

↑で起動しなければ、下記コマンドを実行する。

sudo start amazon-ssm-agent

手元で試してみる

大体概要が分かった気がするので、一旦手元で確かめてみる。

aws> ssm put-parameter --name "sample" --type String --value "hogehoge"
aws> ssm get-parameters --names "sample" --query "Parameters[0].Value" --output text
hogehoge

namesは、wildcard指定はできない。ふーむ。

このあとのアクション

Rails起動時に、色々できないか見てみる。今考えているのは、config/initializer/consts.rb とかに、諸々突っ込むこと。できれば環境変数に全部突っ込んでほしいなぁ。

electronについて、appの作成までやってみた

概要

  • ちまたで流行りの electronについて、試してみました
  • 設定からappの作成まで、最低限の確認をやりました

この記事のターゲット

electronにて appを作成する際に、最低限何が必要が、すぐ知りたい人

必要なpackageのinstall

npm install -g electron-prebuilt 
npm install -g electron-packager

初期設定

# 必要なファイルの配置
mkdir electron_sample
cd electron_sample
npm install
touch main.js
touch index.html

#配置確認
[@electron_sample]$ tree
.
├── index.html
├── main.js
└── package.json

コーディング

下記URLの通りです. http://electron.atom.io/docs/latest/tutorial/quick-start/

main.js

var app = require('app');
var BrowserWindow = require('browser-window');
require('crash-reporter').start();

var mainWindow = null;

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({width: 800, height: 600});
  mainWindow.loadUrl('file://' + __dirname + '/index.html');
  mainWindow.openDevTools();
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <script>document.write(process.version)</script>
    and Electron <script>document.write(process.versions['electron'])</script>.
  </body>
</html>

package.json

{
  "name": "electron_sample",
  "version": "0.1.0",
  "main": "main.js"
}

appの作成

# mac用のapp作成
electron-packager electron_sample(directory名) sample(アプリ名) --platform=darwin --arch=x64 --version=0.34.0(electronのバージョン)

すると sample-darwin-x64 なるdirectoryが生成される. 確認してみると下記のファイルが生成されていることが分かる

[@sample-darwin-x64]$ ls
LICENSE     sample.app  version

appの実行

上記 appの作成で作られた sample.app をopenしてみると、 hello world!が表示されます.

f:id:selmertsx:20151020220244p:plain:w500

clean coder 黙読会始めました

概要

社内の新卒氏向けに、clean coderの黙読会を始めました。 参加者は、新卒氏1人、3年目1人 (私) 、経験豊富なエンジニアさん1人の、計三人です。

Amazon.co.jp: Clean Coder プロフェッショナルプログラマへの道: Robert C. Martin, 角征典: 本

目的

  • 新卒氏が継続的に学習できる場を作る
  • 今すぐに役に立つ訳ではないけど大切な知識を身につける機会を用意する
  • 同じ本を読むことで、同じ文化を共有する下地を作りたい

黙読会のやり方

  • 司会はローテーションで決めます。
  • 時間・読む章を決めてただひたすら読み込み、読み終わったらそのときの司会がまとめて発表。
  • その後、それぞれが感想・疑問点を話し合ったり、新卒氏が質問したりします。
  • 時間は業務後30分程度。週2〜3回、それぞれの都合があったときに開催します。

なぜ黙読会なのか

  • 準備してこなくて良い

とにかくこれに尽きます。 新卒氏が最初に経験する定期勉強会みたいなものは、 ハードルが低く、継続しやすいものにしたかったので、 このようなフォーマットで勉強会をすることにしました。

なぜ clean coder を選んだのか

  • 技術的な前提知識が(あんまり)無くても読める
  • エンジニアとして、身につけて欲しい知識・考え方が網羅されている

1点目に関しては、ハードルを下げるという目的のために。 2点目に関しては、エンジニアとしてキャリアを積んでいく中で、 この本が、一つの指標を形成するに足りうると判断したためです。

経験しなければ理解できないこともあるかと思いますが、 数年後何か行き詰ったときに、 「そういえば、あの本に書いてあったなぁ。もう一度読み返してみよう」 と思ってもらえるような本になってくれればよいな、と思って選びました。

(僕自身、尊敬する先輩に薦められてこの本を読んで以来、事ある毎にめくってます。)

やってみた所感

  • 思ったより議論が活発だった(業務の中で、どこまで、どのように実現するかなど)

とりあえず、まずやってみようということで始めた第一回ですが、 当初思っていたよりも、活発に議論できました。

議論の内容は、大体以下のようなものでした。

  • 先輩社員は本で書かれていた内容を、具体的に業務でどのように実践しているか。何が出来ていないか。
  • 新卒社員は、どのようにすれば実践できるようになるのか。何から着手するか。

最後に

  • 新卒氏にとっては、本を読んで知識を深めると同時に、経験豊富な先輩エンジニアから経験談も聞けて、 ただ読むよりも印象に残ってくれたんじゃないかなという印象(願望)
  • 回を重ねる毎に、同じフォーマットだと刺激が少なくなってくる気もしているので、その前に何らかの方法を模索したい
  • とはいえ、事前に用意してくるなどすると、参加のハードルが上がっちゃうので、そこも考慮したい