Go Revelフレームワーク jQuery非同期処理

概要

Go RevelフレームワークでAjax非同期処理を実装します。

CSRF 対策

以下コマンドにより
RevelフレームワークでCSFR対策する為のライブラリをインストール

1
$ go get github.com/cbonello/revel-csrf
  • app/init.go

ajax実行時にCSRFチェックする為、init.goでのチェックを外すように設定

以下CSRFのFilter設定

1
2
3
4
5
6
func init()
revel.Filters = []revel.Filter{
...
...
csrf.CSRFFilter, // CSRF prevention.
...

conf/routes で実行するAPIのURLはAjax実行時にCSRFチェックする為、
init.goではチェックを対象外とする様に設定

1
csrf.ExemptedFullPath("/api_execute")

View側の設定

  • views/header.html

<head>〜</head> 内にCSRFチェック用ハッシュ値をmeta情報として埋め込みます。

1
<meta name="csrf-token" content="{{ .csrf_token }}">

jQueryファイル

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
function setAjaxToken( token ) {
// ajax --- start --------------------------------------------------
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", token );
}
}
});
}

$(document).ready(function () {
$(document).on("click", ".ajax_execute", function (event) {
event.preventDefault();

setAjaxToken( postData['_token'] );

var ajaxParamas = {};
ajaxParamas["type"] = "POST";
ajaxParamas["url"] = action;
ajaxParamas["data"] = postData;
ajaxParamas["cache"] = false;
ajaxParamas["dataType"] = "json";

$.ajax(ajaxParamas)
.success( function(res) {
console.log("(^-^) OK")
}).error ( function() {
console.log("(>_<) NG")
});
return false;
})

簡単…とは行ってない気がしますが
CSRF対策ができました。

fluentd設定ハマった所あるある

以下随時追加。

環境

  • CentOS Linux release 7.1.1503 (Core)
  • Fluentd 0.12.12
  • Nginx 1.8.0

Permission denined

  • パーミッションエラー!
1
2
3
4
# tail -f /var/log/td-agent/td-agent.log

2015-08-19 14:17:14 +0900 [error]: Permission denied @ xxxxxxx - /var/log/nginx/error.log
2015-08-19 14:17:14 +0900 [error]: suppressed same stacktrace

対策

td-agent実行ユーザをrootに変更する。

1
2
3
4
5
6
7
$ sudo vim /etc/init.d/td-agent

- TD_AGENT_USER=td-agent
- TD_AGENT_GROUP=td-agent

+ TD_AGENT_USER=root
+ TD_AGENT_GROUP=root

デーモンリロード

1
sudo systemctl daemon-reload

動作確認

以下のようにtailが正しく実行できていることが確認できます。

1
2
3
4
# tail -f /var/log/td-agent/td-agent.log

2015-08-19 14:17:15 +0900 [info]: following tail of /var/log/nginx/access.log
2015-08-19 14:17:15 +0900 [info]: following tail of /var/log/nginx/error.log

[warn]: pattern not match

これかなりハマりました。

Nginxのlogを流すときに以下のようにfomatするように書かれている記事を多く見たので
設定してみたらエラー発生(; >_<)

  • /etc/td-agent/td-agent.conf
1
2
3
4
5
6
7
<source>
type tail
format nginx
path /var/log/nginx/access.log
pos_file /var/log/td-agent/nginx-access.pos
tag nginx.access
</source>

対策

以下のように修正

  • /etc/td-agent/td-agent.conf
1
2
3
4
5
6
7
8
<source>
type tail
format /^(?<remote>[^ ]*) (?<host>[^ ]*) (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^ ]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)" "(?<forwarder>[^\"]*)")?/
time_format %d/%b/%Y:%H:%M:%S %z
path /var/log/nginx/access.log
pos_file /var/log/td-agent/nginx-access.pos
tag nginx.access
</source>

td-agent再起動

1
$ sudo systemctl restart td-agent

これで大丈夫。

buffer_path 重複

1
[error]: failed to configure sub output redshift: Other '' plugin already use same buffer_path: type = , buffer_path = *

元々の設定は以下の様にしていました。
td-agent の送信先にトラブルがあり buffer が溜まり重複しエラーとなっていました。

1
buffer_path /logs/td-agent/nginx/logs

例)以下の様な tag があった場合、buffer_path は同じく /logs/td-agent/nginx/logs となってしまう

hogehoge.20170101.log
hogehoge.20170102.log

対策

tag_parts を用い、以下の様に tag 毎に buffer_path をユニークにすることで解決

1
buffer_path /logs/td-agent/nginx/logs_${tag_parts[0]}_${tag_parts[1]}

引き続き何か発生したら追記していきます。

Go初心者におすすめ本

概要

身の回りであまり Go を積極的にやっている人がいないので
やってみたいなぁ、気になってはいる、
という方に本をおすすめしてみたいと思いました。

この一冊!

以下をチョイスしました!

よかった点

  • 全部で 34 ページ!1 日で読み終わり、逆引きとしても利用できる。(Go のオフィシャルのチュートリアルをまとめてくれてる感じ)
  • Go の成り立ちを簡潔に説明しており、クロスコンパイルや並列処理サポートなどがあり Go の使いどころがわかる。
  • ちょうど「Web API デザインの鉄則」という特集があり、API 開発にはちょうど良い内容の一冊だった。

特に本を紹介して自分にお金が入ることはないので
斜めから見ずにまず本見てみてください ♪

Go を使いたくなる記事

JSON シリアライズし秒間のレスポンス回数測定

以下 Qiita 記事でまとめてくれていました。

「最速」フルスタック Web フレームワーク「revel」の紹介

個人的に好きな所

  • while や do/while 、参考演算子がなく for のみ、とか冗長なコーディングを許さない
  • gofmt でフォーマット化してくれる。いつもコミット前にやってます。
  • ライブラリ増えてる。 Python のpip installみたく go getでインストール可。
  • ネイティブなのでアプリケーションが大きくなってもさほど遅くならない。

以上
Gopher とお話できる機会が増えると何よりです。

Kibana4 インストール on CentOS7

前提

  • Nginx インストール済み

環境

  • CentOS Linux release 7.0.1406 (Core)
  • Nginx 1.9.3
  • Kibana 4.1.1

Kibana インストール

1
2
3
$ cd /usr/local/src
$ sudo wget https://download.elastic.co/kibana/kibana/kibana-4.1.1-linux-x64.tar.gz
$ sudo tar xvzf kibana-4.1.1-linux-x64.tar.gz

Kibana 設定ファイル修正

1
$ vi /usr/local/src/kibana-4.1.1-linux-x64/config/kibana.yml
  • host指定

デフォルトでは 0.0.0.0 となっています。
今回は同サーバに構築するので localhost とし保存します。

1
2
- host: "0.0.0.0"
+ host: "localhost"

上記の設定により、kibanaがlocalhostにアクセスできるようになります。

Kibana 実行パス作成

1
2
$ sudo mkdir -p /opt/kibana
$ sudo cp -R /usr/local/src/kibana-4.1.1-linux-x64/* /opt/kibana/

上記設定により以下コマンドでkibana実行可能になります。

1
/opt/kibana/bin/kibana

上記でも十分ですが、再起動した際にはkibanaは停止してしまいます。
なので、起動スクリプトを作成し、サービス登録します。

起動スクリプト作成

1
$ sudo vi /etc/systemd/system/kibana4.service
  • kibana4.service
1
2
3
4
5
6
7
8
9
10
11
12
[Service]
ExecStart=/opt/kibana/bin/kibana
Restart=always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=kibana4
User=root
Group=root
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

上記保存します。

起動/サービス登録

1
2
$ sudo systemctl start kibana4
$ sudo systemctl enable kibana4

Nginx インストール

以下参考にしてください。

Nginx設定ファイル修正

リーバスプロキシでKibana4用ポート(5601)へ向ける。

1
$ sudo vi /etc/nginx/conf.d/default.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name ec2-xx-xx-xxx-xxx.ap-northeast-1.compute.amazonaws.com;

auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/htpasswd.users;

location / {
proxy_pass http://localhost:5601;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

}

以上設定保存後、Nginx再起動

1
$ sudo systemctl restart nginx

アクセスして確認

以下のように表示されれば問題ありません。

以上

参考記事

Systemd入門(4) - serviceタイプUnitの設定ファイル

起動スクリプトについて 各項目説明

[Unit] について
オプション 説明
Description Unitの説明文
Documentation ドキュメントのURI
Requires このUnitが必要とする前提Unit
Wants このUnitが必要とする前提Unit
After このUnitより先に起動するべきUnit
Before このUnitより後に起動するべきUnit
[Install] について
オプション 説明
WantedBy enable時にこのUnitの.wantsディレクトリにリンク作成
RequiredBy enable時にこのUnitの.requiredディレクトリにリンク作成
Also enable/disable時に同時にenable/disableするUnit
Alias enable時にこのUnitの別名を用意

↓この本とってもお世話になりました♪

CentOS7 に Nginx インストール

Kibana構築用に書いときました。

環境

  • CentOS7

Nginxインストール

  • Nginx用リポジトリ作成
1
# vim /etc/yum.repos.d/nginx.repo
  • 以下追記
1
2
3
4
5
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

Nginx モジュールインストール

1
$ sudo yum install --enablerepo=nginx nginx
サービス登録

サーバ起動時・再起動時にNginxが起動するようにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ sudo systemctl disable httpd
$ sudo systemctl enable nginx
$ sudo systemctl start nginx
$ systemctl status nginx

nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled)
Active: active (running) since Mon 2015-08-03 06:07:44 UTC; 2s ago
Docs: http://nginx.org/en/docs/
Process: 12642 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Process: 12641 ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
Main PID: 12645 (nginx)
CGroup: /system.slice/nginx.service
├─12645 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx....
└─12646 nginx: worker process

Aug 03 06:07:44 ip-172-31-19-253 systemd[1]: Starting nginx - high performan....
Aug 03 06:07:44 ip-172-31-19-253 nginx[12641]: nginx: the configuration file...k
Aug 03 06:07:44 ip-172-31-19-253 nginx[12641]: nginx: configuration file /et...l
Aug 03 06:07:44 ip-172-31-19-253 systemd[1]: Failed to read PID from file /r...t
Aug 03 06:07:44 ip-172-31-19-253 systemd[1]: Started nginx - high performanc....
Hint: Some lines were ellipsized, use -l to show in full.

アクセス確認

http://<IPアドレス or ドメイン>

以下のように表示されればOK

以上です。

go get で 「exec: "bzr": executable file not found in $PATH」エラー対策

結論

bzrモジュールインストールした後、再度go getして問題なく動作しました。

1
# yum install -y bzr

概要

EC2のCentOS7で
以下のように go get した際にbzrが見当たらないというエラーが発生した。

1
2
3
4
5
$ go get launchpad.net/goamz/aws

[centos@ip-xxx-xx-xx-xx src]$ go get launchpad.net/goamz/aws
go: missing Bazaar command. See http://golang.org/s/gogetcmd
package launchpad.net/goamz/aws: exec: "bzr": executable file not found in $PATH

ちょこっとしたつまづきでした。

ちなみに

bzrはgitと同様、分散バージョン管理システムです。

今回インストールしようとしたPackageがBazaarで管理していたから必要になったのでしょう。

以下参照
Bazaarユーザーリファレンス

Golang Revelフレームワークエラー 「server.go:1775: http: TLS handshake error from 127.0.0.1:36799: tls: first record does not look like a TLS handshake」対応

結論

[prod]モード以外で http.ssl = true とし起動すると発生するエラーでした。
その為、[prod]以外では http.ssl = false として起動することとしました。

概要

テスト環境で app.conf にて[test]モードを追加し
そこでオレオレ SSL 証明書作成して https リンクの動作確認をしようとしてました。

ですが、起動こそするものの一向にアクセスできず汗

dev モードではアクセス出来るのでその差分を見たところ、上記の結論に至りました。

エラー内容

revel 起動し url にアクセスすると以下のような TLS ハンドシェイクができずアクセスできない状況になる。

1
2
3
4
5
6
7
$ revel run myapp test

...
...

INFO 2015/08/19 14:48:38 harness.go:165: Listening on :9000
2015/08/19 14:48:40 server.go:1775: http: TLS handshake error from 127.0.0.1:36799: tls: first record does not look like a TLS handshake
go-sql-driver/mysqlでcreated_at (datetime) がUTCで登録されてしまう件

go-sql-driver/mysqlでcreated_at (datetime) がUTCで登録されてしまう件

環境

  • go-sql-driver/mysql version 1.2

結論

以下のように parseTime=trueloc=Asia%2FTokyoを設定する。

1
db, err := sql.Open("mysql", "user:passward@/dbname?parseTime=true&loc=Asia%2FTokyo")

loc=xxxxの指定がない場合、localが指定され、
datetime に time.Now()を指定して INSERT しても
UTC 時間に書き直されてしまう。

ちょっとハマりました。

Golang Revelフレームワーク ホットデプロイ方法

概要

Revel Official サイトにあるデプロイ方法を検証しました。

Revel Deployment

  1. ローカルでアプリをビルドしサーバにコピーする
  2. サーバーで更新したコードを pull し、ビルド・起動する
  3. Heroku を利用しデプロイ管理する

1. ローカルビルド

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# アプリを実行しテストする
$ revel run import/path/to/app

# パッケージ化
$ revel package import/path/to/app
Your archive is ready: app.tar.gz

# 対象マシンへコピー
$ scp app.tar.gz target:/srv/

# ターゲットマシンで起動
$ ssh target
$ cd /srv/
$ tar xzvf app.tar.gz
$ bash run.sh

開発しているアーキテクチャと同じ環境へデプロイする場合、
もしくは go インストールを設定し、デフォルトで希望するアーキテクチャへビルドするための唯一の方法です。

2. 追加デプロイメント

フルセットアセット付きの静的にリンクされたバイナリが巨大になる可能性があるので、
追加デプロイをサポートしています。

1
2
3
4
5
6
7
8
# アプリを一時ディレクトリにビルド
$ revel build import/path/to/app /tmp/app

# サーバのhomeディレクトリにその一時ディレクトリにrsync
$ rsync -vaz --rsh="ssh" /tmp/app server

# サーバーに接続しアプリを再起動
...

rsync は ssh でのコピーをサポートしているので、以下のように複雑にはなりますがデプロイ可能です。

1
2
# カスタム証明書、ログイン名、対象ディレクトリを指定しrsync
$ rsync -vaz --rsh="ssh -i .ssh/go.pem" /tmp/myapp2 ubuntu@ec2-50-16-80-4.compute-1.amazonaws.com:~/rsync

3. サーバでビルド

この方法はバージョンコントロールシステムに依存します。
Go をインストールしているサーバーが必要です。
その代わり、クロスコンパイルを回避することができます。

1
2
3
4
5
6
7
8
$ ssh server
... install go ...
... configure your app repository ...

# appディレクトリに移動し pullしサーバー起動する
$ cd gocode/src/import/path/to/app
$ git pull
$ revel run import/path/to/app prod

総評

現在社内では、1. ローカルビルド のデプロイ方法を選択しています。

2. 追加デプロイメント は、再起動時の瞬断が懸念されます。
大規模アクセスを捌く目的で利用する Go には向いていないと思います。

3. サーバでビルド は、運用方法にもよりますが、
本番環境でコンフリクトが起きてしまったらコンパイルもストップしてしまう懸念があります。

1. ローカルビルド方法を Jenkins で管理して運用しており
現状特に問題ないです。

Jenkins の設定等まとめてから公開したいと思います。

Ruby インストール on CentOS7

環境

  • AWS
  • CentOS Linux release 7.0.1406 (Core)

必要モジュールインストール

1
$ sudo yum -y install git libffi libffi-dev gcc openssl-devel readline-devel zlib-devel

rbenv, ruby-build ダウンロード

1
2
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

rbenv PATH指定

1
2
3
4
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ exec $SHELL
$ source ~/.bash_profile
1
2
3
4
5
6
7
8
9
10
11
12
$ rbenv install -list

Available versions:
:
:
2.0.0-p643
2.0.0-p645 ← 2.0.0の最新 (※2015/08/06時点)
2.1.0-dev
2.1.0-preview1
2.1.0-preview2
2.1.0-rc1
:

ruby インストール

1
$ rbenv install -v 2.0.0-p645

再読込

1
$ rbenv rehash

インストールしたバージョンに切り替え

1
$ rbenv global 2.0.0-p645

確認

1
2
$ ruby -v
ruby 2.0.0p645 (2015-04-13 revision 50299) [x86_64-linux]

以上