selmertsxの素振り日記

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

(#1)ふつうのLINUXプログラミング

1.2 プログラミング環境の準備

gccを5系の最新入れる必要があるらしい

➜  ~ gcc -dumpversion
4.2.1
➜  ~ brew install gcc5
==> Pouring gcc@5-5.4.0_1.el_capitan.bottle.tar.gz
🍺  /usr/local/Cellar/gcc@5/5.4.0_1: 1,391 files, 253.3MB
➜  ~ ln -s /usr/local/bin/gcc-5 /usr/local/bin/gcc
➜  ~ source ~/.zshrc
➜  ~ gcc -dumpversion
5.4.0

ということで、5.4.0のGCCを入れることができた。

1.3 gccを使ったbuild(1)

IDEを使わずに、コンパイルして実行してみる

# hello.cの作成
➜  c mkdir hello
➜  c cd hello
➜  hello vi hello.c
#include <stdio.h>

int main(int argc, char *argv[]){
  printf("Hello, World\n");
  return 0;
}
# build
➜  hello gcc hello.c
➜  hello ls
a.out   hello.c
➜  hello ./a.out
Hello, World

gccでbuildして ./xxx.out コマンドでコードを実行する。

1.4 gccを使ったbuild(2)

# -o optionを使って作るファイル名を指定する
➜  hello rm a.out
➜  hello gcc -o hello hello.c
➜  hello ls
hello   hello.c
➜  hello ./hello
Hello, World

1.5 コマンドライン引数

➜  hello touch args.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
  int i;
  printf("argc=%d\n", argc);
  for(i = 0; i<argc; i++){
    printf("argv[%d]=%s\n", i, argv[i]);
  }
  exit(0);
}
➜  hello gcc -o args args.c
➜  hello ./args
argc=1
argv[0]=./args
➜  hello ./args x y z #3つのコマンドライン引数 x, y, z
argc=4
argv[0]=./args
argv[1]=x
argv[2]=y
argv[3]=z
➜  hello ./args "x y z" # `"`で囲むと一つの文字列として扱える
argc=2
argv[0]=./args
argv[1]=x y z
➜  hello ./args *.c # globを使って引数を渡すこともできる。
argc=3
argv[0]=./args
argv[1]=args.c
argv[2]=hello.c

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