ELBの資料を読んだメモ

自分が業務で使いそうな範囲でメモに起こす。

aws.typepad.com

ELB = L4のロードバランサー(Classic Load Balancer = CLB) + L7ベースのロードバランサー(Application Load Balancer = ALB)

ELB

ELBは複数AZをまたいで負荷分散が可能。

ヘルスチェックは細かく指定可能。以下の表は引用。 ウェブアプリケーションで未熟な状態なら、PingパスでDBの接続とかあれこれチェックできる状態にしておくのも一つの手か?

項目 メモ
Ping プロトコル HTTP 200が返るか?
Ping ポート 80
Ping パス /index.html HTTP/HTTPS利用の場合
タイムアウト時間 20秒
ヘルスチェック間隔 30秒
異常判定までの回数 4回
正常判定までの回数 2回

正常との判定が遅いと追加したインスタンスが使える前に時間がかかる。 逆に異常との判定が厳しすぎても過負荷時に処理できるインスタンスを減らしてしまうことも。

Route 53以外でDNSを使うときは、CNAMEで設定してELBに向ける。

サーバー証明書はELBにアップロード。Let's Encryptを使うときはどうする?的な話は別途調べる。→AWS Certificate Managerを使用する。証明書に対しての料金がかからない理解。アップロード作業も不要。

サーバーへの接続のソースIPはELBのIPアドレスになるので、X-Forwarded-Forヘッダーを見る。

ELBにもセキュリティグループを設定できるので、今までEC2に設定していたセキュリティグループはELBだけを受け付けるようにして、ELB側で制限をかける。

ALB

コンテクストベースルーティングで、ルールにURLのパスが使える。振り分け先にはターゲットグループ(バックエンドサーバーをまとめたグループ)を指定。

WebsocketやHTTP/2にも対応。

料金 ALBの使用時間と、Load Balancer Capacity Units (LCU) の使用量で課金。

LCU 以下の3つのディメンションを測定し、使用量が最も高いディメンションのみ請求。

とりあえず変なことしなければ、CLBよりちょろっと安く済ませられるらしい。

ディメンションの項目から考えると、HTTP/2にちゃんと対応したほうが安くなるのか?

Git(hub)でフォークしたリポジトリに、オリジナルリポジトリの変更を取り込む

いつも忘れて調べなおすことになるので、メモ。

ケース

例えば、こんなリポジトリ

github.com

オリジナルのプラグインでほんのすこしだけカスタマイズしたいから、ちょっとだけ修正して使ってる、みたいな。

で、時間が経って、変更されているものもあるから取り込みたい。

というときの作業。

参照

結論、Githubのヘルプを見ればいいわけですね。はい、いつも見ます。いつもたどり着くのに時間がかかりますが。

https://help.github.com/articles/fork-a-repo/help.github.com

https://help.github.com/articles/syncing-a-fork/help.github.com

この記事のこの後の内容は、ヘルプの内容をただただ自分のためにメモしたものです。

作業

ざっくり書くとこんな感じでしょうか。

git clone ${forked_repo} ${forked_repo_dir}
cd ${forked_repo_dir}
git remote add upstream ${original_repo}
git fetch upstream
git checkout master # forked master
git merge upstream/master

自分の(忘れた後の)理解のために、細かく書いていくと、、、

フォークしてカスタマイズしたリポジトリGitHub - sugilog/molokai: Molokai color scheme for Vimに、オリジナルのリポジトリGitHub - tomasr/molokai: Molokai color scheme for Vimの修正内容を取り込む。

自分のリポジトリclone

git clone git@github.com:sugilog/molokai.git ~/workspace/molokai
cd ~/workspace/molokai

オリジナルのリポジトリupstreamという名前でリモートブランチとして登録。名前はかぶらなきゃOK。

git remote add upstream https://github.com/tomasr/molokai.git
git fetch upstream

自分のリポジトリのブランチをcheckout。とりあえずmaster

git checkout master

最後に、オリジナルの内容をマージ。

git merge upstream/master

あとはコンフリクトを直すなりなんなり。

結論、マージ作業なわけです。

GithubのウェブUIからのプルリク作業に慣れてきった生活で、簡単なマージ作業でさえ忘れてしまう。。。

最後に

molokai、お世話になってます。

github.com

tmux 2.3のキーバインディングでちょっと困った

macでtmuxを使っていてエラーが出て解決してたら次の問題にハマって、ということがあったので一連の話をメモ。

タイトルにしたキーバインディングは結局ググってもよくわからずソースを見て解決した話。

github.com

流れ

macOS Sierra にバージョンアップ。そしたら変なWARNINGメッセージが出るようになった。

qiita.com

Qiitaのまとめどおり、tmuxをアンインストール&再インストールしてみた。

ちなみにこの作業をした時のHEADはDo not force symbols to width 1, from Yen Chi Hsuan. · tmux/tmux@178894b · GitHub

この時点で、tmuxのバージョンが2.3に更新された。元のバージョンは忘れたので省略。

tmux2.3を起動したら、またもや変なエラーメッセージが出始めた。

nyangryy.hatenablog.com

このときの自分のtmux.confdotfiles/.tmux.conf at 42f0b71a673aad45921912766acc963948d0027b · sugilog/dotfiles · GitHubこんな感じ。

ブログにまとめられているとおり、-t vi-copy-T copy-mode-viにしてあれこれして、使い始めた。

dotfiles/.tmux.conf at 33c847acf64889f012859e234576fc85d8e1d36c · sugilog/dotfiles · GitHub

で、本題

copy-modeのときに、スクロールアップがうまくできない。正確には、

  • copy-modeでのj, kでのカーソル移動でのスクロールはできる。
  • copy-modeでのCtrl+fでのスクロールダウンはできる。
  • copy-modeでのCtrl+bでのスクロールアップができない。

バインディングはvi)。

ググっても情報が見つからないのでソースにあたる。。。と見つけたコミット。

github.com

Ctrl+bはコンフリクトがあるから、初期設定するのやめよう、とのこと。なるほどね。

ちなみに自分は関係ない人なので、自分で追加しちゃいます。

github.com

ちなみに自分のtmuxで使うprefixキーはCtrl+tC-t)です。

解決!

お粗末さまでした。

git logをltsvにする

コミットの情報をもとにファイルチェックとかしてみよう、という感じからgitだとどうしようということでログから情報を取り出す。

subversionで、svn ls -v <URL>してとれるような情報のイメージ。

ついでにプログラムから加工しやすいようにLTSVにする。

git log -n 1 --format="hash:%H%x09author_date:%at" <file>

分解して理解

git log : 省略

-n 1 : とりあえず今回は、指定したファイルに対する最新のコミットを取得できればいいので、1つだけ。

--format : ログのフォーマットを指定する。続く引数内で、%なんとかみたいにすると情報を埋め込めたりする。くわしくは、git help log内のPRETTY FORMATSを参照。

hash: : ここまでは単なる文字列。LTSVのキー。

%H : コミットハッシュ。 %hにすると省略形(7桁くらいになってるやつ)のコミットハッシュ。

%x09 : %xはあとに続く16進数のコードに対応した文字を埋め込む。09はタブ。故にLTSVの区切り文字。

author_date: : ここも単なる文字列。LTSVのキー。

%at : author dateをunix timestampで表示する。rubyからなら、Time.atを使えばTimeオブジェクトに変換できる。comitter dateを使うかどうかみたいな話はここの主題ではないので省略。

使用上の前提条件というか、現在のこの記事の状況。

  • リモートリポジトリの情報をfetchしたりするのは別途必要ということで。
  • コミットメッセージ内にタブが含まれてたらどうしようとか思って、まだLTSV化するログの中にコミットメッセージを入れることは試していない。

Dockerを使って、AWS Lambda用のPhantomJSとfontconfigをビルドする

dockerを使ってみる。 やりたいことはこれ

AWS LambdaでPhantomJSを使ってあれこれしたいけど、日本語フォントを扱えるようにしないと、キャプチャがうまくできない。 日本語フォントを扱える夜にするのはリクルートさんの記事のとおりにできるけど、じゃあそのためのfontconfigのビルドは?

さらに、npmのphantomjs(現在はphantomjs-prebuilt)macの環境でインストールしてしまうと、lambdaの環境では動かない。

ということで、Linux環境であれこれして、Lambda用のパッケージのビルドする。

そのための簡易環境としてdockerを使ってみようという魂胆。

fontconfigやらPhantomJS自体のビルドの時間はそこそこかかるけど、それを待ちさえすれば、がっつり自動化できた。

dockerの設定

Dockerfile

Linux環境にはCentosを使いたいのでDocker HubのCentosのページを参考にする。

# https://hub.docker.com/_/centos/
FROM       centos:7
MAINTAINER "YOU" <you@example>
ENV        container docker
RUN        (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
           rm -f /lib/systemd/system/multi-user.target.wants/*;\
           rm -f /etc/systemd/system/*.wants/*;\
           rm -f /lib/systemd/system/local-fs.target.wants/*; \
           rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
           rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
           rm -f /lib/systemd/system/basic.target.wants/*; \
           rm -f /lib/systemd/system/anaconda.target.wants/*; \

           yum install -y openssh-server openssh-clients; \
           yum install -y iproute iproute-devel; \
           yum -y install epel-release; \
           yum -y install gperf freetype-devel libxml2-devel python-lxml git-all libtool; \
           yum -y install npm bzip2; \

           passwd root -d; \
           sed -i "s/^.*PermitEmptyPasswords.*$/PermitEmptyPasswords yes/g" /etc/ssh/sshd_config; \
           sed -i "s/^.*PasswordAuthentication.*$/PasswordAuthentication yes/g" /etc/ssh/sshd_config; \

           mkdir -p /src/python; mkdir -p /src/node; \

           cd /src/python; \
           curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py; \
           python get-pip.py; \
           pip install -U six; \

           cd /src/; \
           git clone http://anongit.freedesktop.org/git/fontconfig; cd /src/fontconfig; \
           ./autogen.sh --prefix=/tmp/fontconfig --sysconfdir=/tmp/fontconfig/etc --bindir=/tmp/fontconfig/usr/bin --enable-libxml2; \
           make; make install; \

           cd /src/node; \
           npm install phantomjs-prebuilt; \
           mv /src/node/node_modules/phantomjs-prebuilt /tmp/phantomjs-prebuilt;

VOLUME     [ "/run", "/tmp" ]
CMD        [ "/usr/sbin/init" ]

RUNの部分の話を自分が忘れないようにするレベルでまとめておく。

  • 前半のrmしまくってるのは、systemdまわりの対応。Docker HubのCentosのページを参照。
  • yumでインストールしているのは2種類。
    • opensshはあとでscpでファイルを取り出したいので、sshdがほしいからくらい。clientはいらないけどついで。
    • iprouteは、困ったときのipコマンドのため。デバッグ用途なので、実際には使わない。
    • 残りはfontconfigとPhantomJSをビルドするために必要なもの(いらないもの混じってるかもだけど精査してない)。
  • passwdでパスワード消したり、sshd_configでセキュリティ弱めているのは、ファイルを取り出すときにパスワードとかいろいろ聞かれたくないから。
    • 本番環境では「ダメ、絶対」な設定だけど、今回はこれで。
  • pipsixは、fontconfigのautogenのタイミングで必要なので入れておく。
  • あとは、fontconfigとPhantomJSをビルド。
  • ファイルを取り出しやすいように、それぞれtmpディレクトリに移動させてる。

デバッグ

簡易的に接続してみるなら、attachは使わずに、ssh感覚でexec+bash-it(= interactive, tty)オプションをつけて実行。 本来の用途ではないらしいので、あくまで簡易的に。

docker exec -it {container_id_or_name} /bin/bash

実行

以下の様なシェルスクリプトを作って実行してみた。

docker pull centos:7
docker build --rm -t local/centos7 .
docker create --name phantom --privileged -p 20022:22 local/centos7
docker start phantom

sleep 2

ssh-keygen -R "[localhost]:20022";
scp -o 'StrictHostKeyChecking no' -r -P 20022 root@localhost:/tmp/fontconfig fontconfig
scp -o 'StrictHostKeyChecking no' -r -P 20022 root@localhost:/tmp/phantomjs-prebuilt phantomjs-prebuilt

docker rm -f phantom
docker rmi local/centos7

ポイントといえば、、、

  • privilegedをつけてcreateしないとうまく動かない。systemdまわりの話(+SELinuxが絡んでたっけな?)
  • start後すぐにscpしてもうまく接続できない。1秒か2秒くらいあける。
  • scpで認証周りのことをきかれたくないから、ssh-keygen -Rknown-hostsをクリアして、StrictHostKeyCheckingをしないようにする。

AWS API GatewayのBody Mapping Templateで使えるテンプレート

AWSAPI Gatewayでは、リクエストをどう受けて、どう返すか、ということが設定できる。中間処理にLambdaを使う場合は、リクエストの情報をJSONオブジェクトに変換しておいて貰わないと、情報が来ない。

ということで、Body Mapping Template(後処理に渡すデータを生成するためのテンプレート)を使うわけだけど、以前には多分なかったテンプレートが追加されていたので試している。

Method Request Passthrough

2016/05/11時点では以下のような形をしている。cognitoの情報も追加できるようになっているので、おそらく今後も変化していくのだろうと想定。

##  See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
##  This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload
#set($allParams = $input.params())
{
"body-json" : "$input.json('$')",
"params" : {
#foreach($type in $allParams.keySet())
    #set($params = $allParams.get($type))
"$type" : {
    #foreach($paramName in $params.keySet())
    "$paramName" : "$util.escapeJavaScript($params.get($paramName))"
        #if($foreach.hasNext),#end
    #end
}
    #if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
    #if($foreach.hasNext),#end
#end
},
"context" : {
    "account-id" : "$context.identity.accountId",
    "api-id" : "$context.apiId",
    "api-key" : "$context.identity.apiKey",
    "authorizer-principal-id" : "$context.authorizer.principalId",
    "caller" : "$context.identity.caller",
    "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider",
    "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType",
    "cognito-identity-id" : "$context.identity.cognitoIdentityId",
    "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId",
    "http-method" : "$context.httpMethod",
    "stage" : "$context.stage",
    "source-ip" : "$context.identity.sourceIp",
    "user" : "$context.identity.user",
    "user-agent" : "$context.identity.userAgent",
    "user-arn" : "$context.identity.userArn",
    "request-id" : "$context.requestId",
    "resource-id" : "$context.resourceId",
    "resource-path" : "$context.resourcePath"
    }
}

ざっくりと展開すると、以下の様な感じになる。だいたい自分でわかった範囲で説明もつけておく。雰囲気なので間違ってたらごめんなさい。

{ "body-json": [object], "params": { "path": [Empty Object], "querystring": [object], "header": [object], }, "stage-variables": [object], "context": [object] }

Key Description Type
body-json BodyをJSON.parseしたもの。 object, array, ...
params リクエスト時のパラメーター情報。 object
params.path (おそらく)基本的に空のオブジェクト。 {}
params.querystring URLクエリを処理したオブジェクト。配列クエリ、ネストされたクエリには対応されてなさそう。 object
params.header ヘッダ情報。 Host, Origin, User-Agent, などなど。 object
stage-variables API Gateway で設定したstageの情報。 object
context API Gatewayでリクエストを受けた時の状態。 object
context.http-method リクエストメソッド。GET, POST, など。 string
context.stage API Gateway でデプロイしているステージのラベル。 string
context.source-ip リクエストしてきたIPアドレス string
context.user-agent ユーザーエージェント文字列。 string
context.resource-path URLパスの文字列。基本的にAPI Gatewayのリソースに一致するはず。 string

バグ?

テンプレートにはバグっぽい挙動が含まれていて、POST時のリクエストBodyのJSONで文字列を含んでいるとエラーする。ダブルクオーテーションで囲ってしまっているため。ダブルクオーテーションを外してしまったほうが多分良いと思われる(思われるけど落とし穴があるかも)。

ref: https://forums.aws.amazon.com/thread.jspa?threadID=221749

-"body-json" : "$input.json('$')",
+"body-json" : $input.json('$'),

ちなみにエラーすると、Lambdaは起動されない。Lambdaのログを監視していてもわからない問題になるので、検証は自己責任ということで。

VMware Fusion 8.1のNATポートフォワーディングまわりのエラー対応

事象

VMware Fusion 8.1にNATポートフォワーディングまわりでエラーがある。VMware BLOGSで修正が公開されているが、2016/02/01にパッケージをダウンロードした段階では、配布されているパッケージに修正は反映されていない。

ref: https://blogs.vmware.com/teamfusion/2016/01/workaround-of-nat-port-forwarding-issue-in-fusion-8-1.html

自分の手元では、VMware Fusionのネットワークを再起動すると、1度目のアクセスはできるが、そこでVMware Fusionのネットワークが落ちる、という現象。

MacをEl Capitanにアップデートして、VMware Fusionちゃんと動くか検証していて、うまくできたと思ったら落ちる、という突き落とされパターン。

事前作業

VMware Fusionのネットワーク周りの設定ファイルを再確認。変更されていたら、同じディレクトリ内に作られているバックアップファイルから必要な部分をコピーしてくるか設定し直す。

  • dhcpの設定ファイル /Library/Preferences/VMware\ Fusion/vmnet8/dhcpd.conf
  • natの設定ファイル /Library/Preferences/VMware\ Fusion/vmnet8/nat.conf

設定周りについては、過去にもエントリーを書いてるので、よろしければご参照を。

sugilog.hatenablog.com

修正ファイルの設置

  1. こちらから、vmnet-natdファイルをダウンロード
  2. ダウンロードしたvmnet-natdVMware Fusionのアプリケーションパッケージ内に移動(置き換え)。
  3. アプリケーションパッケージ内に設置したvmnet-natdの所有者とパーミッションを変更する。
# 移動
mv -i $HOME/Downloads/vmnet-natd /Applications/VMware\ Fusion.app/Contents/Library/

# 所有者情報とパーミッションを変更。(所有者情報の部分は、環境に併せてご変更を。)
sudo chown root:wheel /Applications/VMware\ Fusion.app/Contents/Library/vmnet-natd
sudo chmod 755 /Applications/VMware\ Fusion.app/Contents/Library/vmnet-natd

ネットワークの再起動

vmnet-cliで、stop&startする。

sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --stop
sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --start

状態を確認。できれば、ポートフォワーディングしているVMを立ち上げて、ネットワーク越しにアクセスして、その後に確認してみると良い。

sudo /Applications/VMware\ Fusion.app/Contents/Library/vmnet-cli --status

正常に動作していれば、以下のようなメッセージ。

DHCP service on vmnet1 is running
Hostonly virtual adapter on vmnet1 is enabled
DHCP service on vmnet8 is running
NAT service on vmnet8 is running
Hostonly virtual adapter on vmnet8 is enabled
All the services configured on all the networks are running

正常でない時:いくつかの行がエラーを表示する。

...
NAT service on vmnet8 is not running
...
Some/All of the configured services are not running