読者です 読者をやめる 読者になる 読者になる

Goで同時実行数を制限しながらループを並列処理する。

Web+DB Press Vol95 のGoの記事を読んで理解するために自分でも書いてみた。

WEB+DB PRESS Vol.95

WEB+DB PRESS Vol.95

自分の環境は go1.7.3 darwin/amd64

同時実行数制限付きでループを並列処理する。

秒単位でスリープ処理を入れてしまっているので、実行時間は長いです。そこはお勉強用ということで。

出力結果

time:2016-12-02 14:40:49.5804542 +0900 JST      index:-1        item:-1
sleepなし。順番不定。
time:2016-12-02 14:40:49.580639488 +0900 JST    index:2 item:3
time:2016-12-02 14:40:49.580686796 +0900 JST    index:3 item:4
time:2016-12-02 14:40:49.580652343 +0900 JST    index:0 item:1
time:2016-12-02 14:40:49.580703936 +0900 JST    index:4 item:5
time:2016-12-02 14:40:49.580712672 +0900 JST    index:5 item:6
time:2016-12-02 14:40:49.580725039 +0900 JST    index:6 item:7
time:2016-12-02 14:40:49.580731445 +0900 JST    index:1 item:2
sleepあり。順番に出力。
time:2016-12-02 14:40:50.582086998 +0900 JST    index:0 item:1
time:2016-12-02 14:40:51.581872261 +0900 JST    index:1 item:2
time:2016-12-02 14:40:52.581816362 +0900 JST    index:2 item:3
time:2016-12-02 14:40:54.583265777 +0900 JST    index:3 item:4
time:2016-12-02 14:40:56.583142187 +0900 JST    index:4 item:5
time:2016-12-02 14:40:58.582018719 +0900 JST    index:5 item:6
time:2016-12-02 14:41:01.584457553 +0900 JST    index:6 item:7
sleepあり。Sleepの短い順番に出力。
time:2016-12-02 14:41:03.585628436 +0900 JST    index:1 item:2
time:2016-12-02 14:41:04.58563381 +0900 JST     index:0 item:3
time:2016-12-02 14:41:05.585852568 +0900 JST    index:3 item:2
time:2016-12-02 14:41:06.585637432 +0900 JST    index:2 item:5
time:2016-12-02 14:41:06.585995853 +0900 JST    index:5 item:1
time:2016-12-02 14:41:12.586825274 +0900 JST    index:4 item:8

セマフォ取得用のオブジェクトで、同時実行数の制限。deferで開放しないと詰まる。

WaitGroupでプログラムの待ちを設定。ないと、スリープ処理をしてる間にプログラムが終了してしまう。deferでセマフォを開放するタイミングで一緒にWaitGroupも減らす。

Certificate Managerを試す、、、ためのメール受信の設定

ケース

AWS Certificate Managerを使用して、SSL/TLS証明書を取得して、HTTPS接続を確立したい。

ドメインは、(お名前.comとかで)適当に取得しておいたものを使う。

問題

AWS Certificate Managerは、証明書の発行のときに、検証Eメールを送信する。自分(もしくは関係者)が、証明書の発行を承認する必要があるから。そりゃ当然なわけ。

送信先は、ヘルプにかかれている。2種類あって、WHOISに書かれたメールアドレスと、登録しようとしているドメインに適当なアカウント名をくっつけたメールアドレス。

Email is sent to the following three registered contact addresses in WHOIS:

  • Domain registrant
  • Technical contact
  • Administrative contact

Email is also sent to the following five common system administration addresses where your_domain is the domain name that you entered when you initially requested the certificate.

  • administrator@your_domain
  • hostmaster@your_domain
  • postmaster@your_domain
  • webmaster@your_domain
  • admin@your_domain

で、エンタープライズな人たちなら特に問題じゃないわけだけど。。。

その検証Eメールを受信できる状態じゃないと、前へ進めない。

お名前.comなんかでドメインを取得すると、whoisへの情報登録を代行してくれる。

代行してくれた登録情報は、お名前.comの会社の情報になるので、whoisの情報には、自分個人の情報は含まれていない、ということ。

個人利用にはありがたい代行サービスなんだけど、今回だけは、それが微妙。

目的

ということで、

AWS Certificate Managerが送信する送信先をつくります。

やり方

同じくAWSのサービスの、SESを使って、メールを受信する。

例として、example.jpというドメインを持っていて、そのサブドメインapp.example.jpSSL/TLS証明書を発行する。ために、admin@app.example.jpを受信できるようにする。

SESはこの記事を書いている時点(2016/11/08)では、まだ日本に提供されていないっぽいので、リージョンは適当に選んで使う。

事前準備:Route 53 の設定

もしDNSを設定していない状態であれば、Route 53にexample.jpを登録する。

とりあえずHosted Zoneにexample.jpを登録するだけでOK。

(ということで、Route 53を使う前提で書きます。)

ドメインの登録

  1. 左ペインのDomainsを選ぶ。
  2. Verify a New Domainボタンを押す。
  3. Domainを入力する。
    • 今回のケースで登録するドメインは、app.example.jp
  4. DNSの設定について書かれている画面に切り替わる。
  5. Use Route 53で先に進む。
  6. Domain Verification Record(TXTレコード) と Email Receiving Reocrd(MXレコード)どちらも登録したいので、両方チェックを入れて、Create Record Sets
  7. 少し待つと、ドメインのステータスがverifiedに変わる。

受信設定

  1. 左ペインのRule Setsを選ぶ。(Email Receivingの下)
  2. View Active Rule Setボタンを押す。
  3. Create Ruleボタンを押す。
  4. Recepientは空のままNext Step。(今回の場合は。本当は絞ったほうが良いはず。)
  5. Add actionで、S3を選ぶ。
    • S3のバケットとかは適当に。新しく作るなり、
    • prefixは、必要に応じて。app.example.jp/みたいにアカウント名を入れておくと便利そう。
    • 今回の場合は暗号化は不要。(本当は暗号化したほうが良いはず。)
  6. Next Stepで先に進む。
  7. Rule nameは適当に。
  8. 他、デフォルトのままで、Next Step
  9. Create Rule

テスト

  1. 左ペインのDomainsを選ぶ。(戻る)
  2. 登録したドメイン(例:app.example.jp)を選ぶ。
  3. Send a Test Emailを押す。
  4. メールの内容を適当に入力して、送信。
    • Toアドレスをadmin@app.example.jpみたいにしておくと、Certificate Managerが送信先に指定するメールアドレスみたくなる。
  5. S3をチェック。
    • Ruleで設定したバケット、prefixの場所にメールがあるか?
    • メールの内容が先ほど適当に入力したメールの内容に一致するか?

後は

Certificate Managerであれこれするだけ。

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をしないようにする。