dotfiles に Ansible Playbook を導入した

最近、4年間使っていた MacBook Air が突然壊れてしまい、新しい MacBook Pro を購入しました。

新しいマシンを手に入れたらまず最初にやることは dotfiles のデプロイです。これまでの dotfiles のデプロイはお手製のシェルスクリプトによって行っていましたが、色々問題を抱えていたため、機会があれば Ansible Playbook を導入したいと考えていました。今がそのタイミングだなと感じたので実際にやってみました。

github.com

各 role の紹介

Best Practices — Ansible Documentation に従い ansible-playbook/roles 以下に各 role を配置しています。

ansible-playbook/roles
├── anyenv
├── apt
├── cli
├── dotfiles
├── homebrew
├── homebrew_cask
├── powerline
├── system
├── vscode
└── zsh

anyenv

anyenv と anyenv によってインストールされる xxenv をインストールするための role です。
anyenv の README にある通りに git cloneanyenv install --init を実行しています。
anyenv のインストール先を anyenv.install_dir という変数で指定できる仕組みにしています。この状態で anyenv install --init を実行するには PATH に anyenv があるディレクトリへのパスを追加する必要がありますが、 このパスに ~ が含まれていると anyenv コマンドの lookup ができないという問題がありました。そこで今回は regex_replace を使って ~lookup('env', 'HOME') の値で置き換えるようにしています。

https://github.com/odanado/dotfiles/blob/145ff7278708f7a0cd5f1cf6e18ba145f0cdaef4/ansible-playbook/roles/anyenv/tasks/main.yml#L20

apt

apt でインストールするパッケージを管理する role です。
特に変なことはしていません。

cli

cli ツールのインストールを管理する role です。
GitHub Releases にアップロードされている cli ツールのバイナリファイルダウンロードし、指定のディレクトリに配置する機能があります。この機能は ansible-playbook/roles/cli/files/installer.sh に実装しています。複数あるファイルの中から OS と CPU の種類を判定して適切なファイルをダウンロードする仕組みはかなり雑になっています。今後インストールする cli ツールが増えるたびにちょっとずつ改善していくつもりです。

dotfiles

dotfiles をデプロイする role です。
.tmux.conf や .gitconfig のシンボリックリンクをホームディレクトリに向けて生成しています。

homebrew/homebrew_cask

homebrew/homebrew_cask でインストールするパッケージを管理する role です。
特に変なことはしていません。

powerline

powerline を導入するための role です。
pip で powerline をインストールして、config を ~/.config/powerlineシンボリックリンクを作成しています。

system

Macdefaults の値などを管理する role です。
スクリーンキャプチャの名前や保存先の変更などをここで行っています。

vscode

VSCode拡張機能を管理する role です。
code --list-extensions でインストール済みの拡張機能を取得して、インストールしていない拡張機能だけをインストールするようにしています。

https://github.com/odanado/dotfiles/blob/145ff7278708f7a0cd5f1cf6e18ba145f0cdaef4/ansible-playbook/roles/vscode/tasks/main.yml#L10

そのうち設定ファイルのデプロイも行うようにしたいです。

zsh

zshrc のデプロイや zplug のインストールを行う role です。
zsh の plugin 管理には zplug を使用しているのでインストールを行っています。
zplug install の実行も ansible から行いたかったのですが、エラーが出て解決できなかったためここでは行っていません。

Github Action によるテスト自動化

Github Action では Linux だけでなく macOS のサーバを用いたテストを実行できるため、macOSUbuntu の両方でセットアップが成功することをテストしています。

Ubuntu のテストは Docker コンテナ上で実行しています。最初は docker-compose を用いてホストマシンからコンテナ内に対してコマンドを実行していました。しかしこの方法ではローカルでは再現しない tty 周りエラーでハマりました。ググっても解決策が見つからず時間もなかったため、docker コマンドを直接実行する方法に変更しました。

https://github.com/odanado/dotfiles/blob/145ff7278708f7a0cd5f1cf6e18ba145f0cdaef4/.github/workflows/ubuntu.yml

今のところ trigger は push だけですが、cron で定期的に壊れていないことをチェックするようにしたいです。

参考

Ansible Playbook を使って macOS の初期化を行う話はネット上に数多く存在し大変参考になりました。

ISUCON 9 予選 参加記

ISUCON 9 の予選にチーム「5000兆IOPS欲しい!」で参加してきました。 メンバーは「@shora_kujira16」と「@smiken_61」です。

最終的に7000点ちょっとのスコアでした。バックエンド何もわからない...。

やったこと

だいたい時系列順

nginx とか mysql の設定

kataribe を使えるようにしたり、slow query の設定をやりました。練習で一度やっていたのでスムーズにできました。 あと restart.sh というシェルスクリプトを用意して systemd のサービスのリスタートや、設定ファイルの cp を一発で出来るようにしました。

categories のインメモリ化

getCategoryByID の実装がやばいので手を付けたいとなって、categories テーブルは件数少ないかつ変更されないのでメモリに載せて良いことがわかりました。 実装してベンチ投げると4000点ぐらいが返ってきました。

その他

自分がやったのは↑2つぐらいで他は大体 @shora_kujira16 さんがやってくれました

  • 画像を nginx から配信
  • select する時に不要な column を削除
  • 3台構成
    • 1台目が nginx + mysql
    • 2台目と3台目が app server
  • 適宜 index 付与
  • getNewItems の N+1解決
  • campaign の値を 0-4 に変えてスコアガチャ

考えていたこと

  • クエリの実行が遅いしどこかでロックが発生してそう?
  • ユーザーにあった商品を並べることで、売上は上がりそうだけど、これは ISUCON なのか??

VSCodeのRemote Development Extension Pack を試した

概要

この前Meguro.es # 20で開発環境をDockerで用意しても、静的解析のためにホストマシンにnode.jsのランタイムを用意する必要があるという話をしました。 speakerdeck.com

つい先日、この問題が解決されそうなRemote Development Extension Packという拡張機能がリリースされました。この拡張機能VSCodeで開発環境をコンテナーやリモートのマシン上に置いて開発が可能になるものです。 code.visualstudio.com

早速触ってみました。

環境

  • VSCode Version: 1.34.0-insider
  • Local OS Version: macOS Mojave 10.14.4
  • Docker Desktop for Mac: 2.0.0.2 (30215)
  • Docker Engine: 18.09.1

サンプルリポジトリ

VS Code Remote - Containersのnode.jsのサンプルが用意されているので、試すならこれを使うのが楽です。 github.com

Dockerコマンドが見つからない問題

自分の環境でDockerコマンドは /usr/local/bin にインストールされていました。しかし、VSCode拡張機能における環境変数 PATH の中身は /usr/bin:/bin:/usr/sbin:/sbin であるため、VS Code Remote - Containers 上ではDockerコマンドが見つからずエラーになってしまいます。

/usr/bin にDockerコマンドのaliasを張っておけば、一時的にこの問題は解決します。 一応issueを立てておきました。

github.com

感想

実際にセミコロンを削ってみるとeslintが動いていてすごい...。 f:id:odan3240:20190504001109p:plain Webフロントエンドの開発環境をDockerで用意すると、IOが遅くwebpackのbuildが重いという問題が残っていますが、それ以外の環境だとかなり楽に開発環境を用意できそうで良さそうです。

ghkw-webという変数名で迷った時に使えるWebサービスを開発した

概要

サイト

ghkw-web.firebaseapp.com

ソースコード

github.com

モチベーション

コードを書いていると変数名で迷うことがしばしばあります。例えば「除外条件」を表す変数名として exclusion_conditionexclude_conditionexcluded_condition のどれが適切かわからないなどです。そんな時にGitHubソースコードに対してキーワード検索し、そのヒット件数でもっともらしい変数名を選択するというテクが存在します。
今回開発したWebサービスの元ネタである https://github.com/kyoshidajp/ghkwCLIツールとしてこれを実現しています。
CLIツールはプログラマに馴染みの深いツールですが、インストールが不要でサクッとwebから問題を解決できてもいいのでは?と考え、ghkw-webを開発しました。

実際に使ってみる

https://ghkw-web.firebaseapp.com/ にアクセスすることで実際に使うことが出来ます。

アクセスするとGitHubでのログインが求められます。これはGitHub APIを認証なしで使用するとAPIの呼び出し回数に制限があるためです。ユーザー個別のtokenを発行し、そのtokenで検索APIを叩いています。 f:id:odan3240:20190129221638p:plain

調べたいキーワードを空白区切りで入力して検索します。検索結果は表形式で表示されます。 f:id:odan3240:20190129221818p:plain

使用している技術

適当に開発の感想を書きます。

Firebase

サイトのホスティングと、API tokenを得るためのGitHub認証にHostingとAuthenticationを使用しています。今回始めてFirebaseを触ったんですが、認証周りをサクッと実装できて体験が良かったです。

vue cli v3

普段vueを書く時は基本的にnuxtを採用することが多いんですが、一度vue cliを体験したくなったので触ってみました。vue cli v3のplugin(vueのpluginとは別)をgoogle検索で見つけるのが難しかったです。

Tailwind CSS

Tailwind CSSはUtility系のCSSライブラリです。様々なclassが定義されてるため、基本的にcssを書かずにclassを適切に付与してやるだけでレイアウトを構成出来ます。classの順番をlintツールで補正出来ない、結局自分でcssを書く労力と変わらないといった理由から、次使うことはないかなと思いました。 tailwindcss.com

CSS Grid Layout

検索結果の表にCSS Grid Layoutを使用しています。今回は単純な形だったためflexboxで十分ですが、一度経験してみたかったので使用しました。 前述したTailwind CSSCSS Grid Layoutをサポートしておらず、ここだけはstyleタグを使用しました。

GitHub Actions

CI/CDにはGitHub Actionsを使用しました。 画像のようなworkflowを構築しました。

f:id:odan3240:20190129223033p:plain

詳しいことはscrapboxに書いてあります。 scrapbox.io

アイコン

アイコンはGIMPで30秒ぐらいで作成しました。700x700でアイコンを書き出し、以下のサイトで各プラットフォーム向けのアイコンに変換しました。 かっこいいアイコンを作ってくれる人を募集しています。

ao-system.net

終わり

変数名の使用回数をGitHubから取得することで、変数名に迷った時に使えるWebサービスを開発したことを紹介しました。
もしよければ迷った時に使ってみてください!

あと気に入っていただいたらGitHubにスターをいただけると嬉しいです。 GitHub - odanado/ghkw-web

2018年振り返り

1月

NLPに出す原稿を書いてたと思う。あんまり記憶がない

2月

卒業研究の発表準備などでごたごたしてた

3月

NLPの全国大会や引越し先を決めるなどのイベントがあった

4月

上京した。五反田のIT企業に入社した。
技術研修でのお題がTwitter Cloneを作るだったんだけど、DDDを勉強しつつ実装したのは楽しかった。またDDDちゃんと実践したい。
Gotanda.pmでLTした。

64GBという巨大なRead OnlyのKVSぽいものをS3上に構築することでサーバレス化に成功したって話 speakerdeck.com

5月

配属があった。ブロックチェーンをやることになった。

6月

Gotanda.pmでLTした。

会社には競技プログラミング部という部活があって、そこでPerl競技プログラミングするときに便利だなというライブラリを作ったという話 speakerdeck.com

7月

お仕事で作ってたサイトを公開した。html5やらcssやらOGPやらCloudFrontやら、知らないことばかりで勉強になった。

8月

お仕事してた。暑い。

9月

お仕事でサンプルアプリを公開した。vueやpythonとかを書いた。学生の頃からの貯金が役立った。

PyConでLTした。

パーティを文とみなすことでポケモンの役割ベクトルを計算する話 speakerdeck.com

10月

お仕事してた。難しい。

11月

お仕事してた。過ごしやすい。

NuxtMeetUpで登壇した。お仕事の内容について登壇することが夢だったので満足

nuxt-i18nというライブラリを使ってnuxt製のwebサイトを多言語化するという話 speakerdeck.com

12月

お仕事してた。寒い。

自炊について

上京して基本的に夕飯は自炊しています。

入社して1ヶ月時点で社内LTで話したスライドがこれ speakerdeck.com

ガス使った経験がなく初日は納豆ご飯だったり、パスタを茹でたら麺が燃えたりした人なんですが、8ヶ月も続けるとだいぶ慣れてきました。 大晦日なのでいちごのタルトを作ったりとか。

料理は自分のレベルアップが目に見えるところがプログラミングに通じていますし、食材を余らなさないために献立の最適化をするのが楽しいです。

まとめ

新卒入社した年でした。最初は新人気分だったけど今はもうそうは言ってられないよなーって感じです。
来年はもっとアウトプットを増やしていきたいです。今年のアウトプットは学生の頃の貯金を切り崩している部分があって、このままだと来年は何もないという状態になりかねないです。そのためにも、お仕事や趣味で手を動かしてネタを作りたいと考えています。

上京時や上京後に得た知見について

この記事は、OIT Advent Calendar 2018の3日目の記事です。

adventar.org

遅刻してしまい申し訳ありません...。

この記事では自分が奈良から就職のために上京した時の知見について紹介します

上京前

引越し先の決定

自分はいろいろな理由で3月中旬に東京に上京し物件を決めました。最初は敷金と礼金がない物件を探していましたが、時期が遅かったこともあり見つかりませんでした。良い物件を探そうとする方はもう少し早めに上京し物件を決めると良いです。 また、自分は物件を決めるときに保護者が必須だと思いこんでいましたが実は不要な場合があります。事前に仲介業者に確認しておきましょう。

物件の決めるポイント

住んでみてよかった物件の特徴を挙げます

駅チカ

言わずもがな

スーパーが近い

自炊するなら必須レベルです。今住んでいるところは徒歩3分圏内にスーパーがあるのですが、自炊が続いている理由の9割がこの近さです。

お風呂乾燥機

定期的なお風呂掃除からの開放 + 洗濯物が圧倒的な速さで乾きます。

広いキッチン

狭いキッチンだと料理が大変です。swap領域が洗濯機の上に生えたりします。 あと広いキッチンだと自ずと収納が広くなり、色んな種類の食器が収納できたりして便利です。

1K

料理するなら臭いのことを考えると必要になります。

家電

家電は家電量販店で購入した後に住居予定地に郵送すると良いです。重い物を持つ必要がなくなります。 また家電を購入したものの家に入らなかったというケースが最悪なので、物件の下見時には洗濯機や冷蔵庫を置くスペースのサイズを採寸しておきましょう。

引っ越し業者

布団や家具家電を住居予定地に郵送し洋服をキャリーバッグに詰め込んで上京することで、自分は引越し業者を使わずに上京しました。実家から上京する人はこれが可能かと思います。

引っ越し当日

お金があったので新幹線を使って上京しました。節約するなら18切符を使うのも手です。 遅刻しそうになるとキャリーバッグを担いでダッシュすることになるので、時間には余裕を持って家を出ると良いです。

上京後

日用品

基本的にCan Doなどの100円均一のお店に行くことで揃います。自分はCan Doでお皿や菜箸や文房具などを買いました。

調理道具

Can Doで購入できなかったフライパンや包丁は近所のスーパーで揃えました。キッチンペーパーやティッシュなども揃います。 ただ、ゴミ袋を買う時は注意が必要です。間違って大きなサイズ(45L)のゴミ袋を買ってしまうと、中身が埋まらず悲しい想いをします。

終わりに

思ったよりも知見が少なかったです...。 今後上京される方の参考になれば幸いです。

第2回 Cpaw AI competitionに参加しました

Cpaw AI competitionが何かとか、Cpawとは?みたいは話は下のリンクを見て下さい

connpass.com

雑に説明すると競プロ(ハーフマラソン系)+機械学習コンペです。当日はさくらインターネットさんからCPU 12Core,メモリ96GBのマシンが貸し出されており、その上で競技に取り組みました。問題は合計4問用意されており、正解率の合計で総合順位が決定する形式でした。 ただし4問のうち1問はとても難しいらしく正解率を8倍した値が合計する時に使われる仕様でした(300+800=1100点満点)。

環境構築

クリーンインストールされたUbuntuが与えられただけだったので、まず自力で環境構築をする必要がありました。 zshをインストールしてGitHub - odanado/dotfilesをcloneすることで手軽に開発環境を作りました。 Pythonを実行する環境にはDockerとMinicondaのどちらを使うか少し考えましたが、Minicondaを選びました。Minicondaは env.yml ファイルに必要なパッケージを書いておけば、 conda env create -f env.yml で仮想環境を構築できるのでとても便利です。

Programming

この問題は6種類のいずれかのプログラミング言語で書かれたプログラムが与えられるので、そのプログラムの言語を予測する問題でした。 研究で自然言語処理をやっていたこともあってまずこの問題に手をつけました。 直感でそんなに難しくないだろうと考え、sklearnのCountVectorizerでBoWを構築、xgboostで分類しました。 精度はおおよそ97%程度で、この時点(1時間経過)では暫定1位で嬉しくなりました。

omniglot

この問題は実際のomniglotのデータセットから40種類のハングル文字を取ってきて、画像分類を行う問題でした。 この問題の難しい点は学習データが各クラス1枚しか用意されていない点でした(いわゆるone-shot learning)。 自分は最近画像の類似度計算について勉強していたこともあって、次にこの問題に取り組みました。 AKAZE特徴量を抽出して特徴点のマッチングや、テンプレートマッチングを行うコードを実装しても、ほぼチャンスレートの正解率しか得ることが出来ませんでした。

実は4問のうち特に難しいために正解率が8倍される問題はこの問題でした。

一度この問題は諦めて他の問題に移りましたが、最終的にはIMSATを使った手法を提出しました。 omniglotはMNISTと同じく手書き文字認識っぽいデータであることと、IMSATのchainer実装を運営のshunk031さんがgithubに公開していることを知っていたため、この方針を採用しました。 この選択は結果的に正解で、提出したところ8倍された正解率で31%を記録しました。

hand-RPS

この問題は真上からの手の甲の画像から、じゃんけんのグーチョキパーのどれに分類されるか予測する問題でした。 環境として提供されていたサーバにはGPUが搭載されておらず、取り組むのにためらっていましたが、CNNによる手法を試しました。 ネットワークは keras/cifar10_cnn.py at master · keras-team/keras · GitHub を使いました。
ネットワークが小さいことや学習データが多くないこともあって、数十分で10epochの学習が終わり、提出した結果98%の正解率が得られました。

cifar-100

この問題は問題名の通りデータセットにcifar-100を使った問題でした。ただ、データはcifar-100そのままではなく、クラス名は00,01,...,98,99のように連番の数字で匿名化されていました。 cifar-100に対しては様々なネットワークが提案されていますが、今回GPUがない環境でいかに精度を上げるかという点が重要だったようです。

自分はまず最初にcifar-100の学習済みモデルを探しました。学習済みモデルがあれば多数決により匿名化されたクラスを特定することができると考えたからです。30分程度探しましたが、見つからず普通に1からCNNを学習することにしました。

hand-RPSと同じネットワークを20epochほど学習させ提出したところ9%程度の正解率を得ました。これを見て自分はこの方針は良くないと思い込み、他の問題に時間を使い、これ以上の改善はできませんでした。

結果

f:id:odan3240:20180402235644p:plain 結果は3位でした。1,2位は商品が用意されていたのですごい悔しいです。

懇親会で他の方の話を聞いた結果、1位になれなかったのはcifar-100の学習epochを20で打ち切ったことだと結論付けました。これはomniglotでよい正解率を出していたことと、cifar-10,cifar-100ではモデルを数千epoch学習させることがあり、最初20epochでは良い解が得られないと考えられるからです。結果論ですが、他の問題に取り組んでいる時間に裏でcifar-100の学習を回し続けていれば十分1位が狙えたのかなと思いました。

感想

普通のコンペは競プロのマラソンマッチのように長い期間行われるのに対して、ハーフマラソンのように短い時間でコーディングが忙しいコンペでした。 コードを書いてる時や、提出した時に良い精度が出た時はとても楽しく勉強になるので、次回も開催されるなら参加したいと思いました。

kaggleやるやる詐欺辞めないとなあ