The paradigm shift

saboyutaka’s diary なんかかく(ブログn回目)

macOSでの開発環境を全部Docker化したらリストア時間が1時間半になった

f:id:saboyutaka:20180823023857p:plain

どうも、リストア職人のさぼです。みなさんmacOSをどのぐらいの頻度でリストアしてますか?1年に1回はやってますよね?僕は3ヶ月に1回はやるようにしてます。綺麗な状態にしてOSが最大限のパフォーマンスで動いた方がいいし手元に入れたよくわからないアプリがずっと入ってるのって気持ちよくないじゃないですか。なのでMacを定期的にリストア(工場出荷状態に初期化)してます。

前回までは真っ白な状態からだいたい3時間ぐらいで普段開発している環境を構築できるようにしていたのですが今回から開発環境を全部Dockerにしてみようと思ってやってみたところ1時間半で開発環境を終えて作業開始できる状態までの最短記録を更新しました!


おわり(おわらない)






いつもやってる手順を振り返りがてら紹介していきます。

Brewfile

いつもリストア後は brew bundle コマンドでアプリやソフトウェアを入れるようにしていて、今回はその中から言語のRuntimeとMiddlewareを全部取り除きました。 またVagrantも試験的にリストア後には入れずに必要があれば入れる形にします。サブエディタとして使っていたAtomも使うのをやめました、メインはJetBrains系のエディタを使っていますが、サブとしてVisual Studio Codeを使うようにしてます。

少し前まではVagrantでMiddleware, PostgresやRedis を起動してMacのホスト上のRubyのruntimeでRailsを起動して開発したりしてましたが、最近は全部docker-compooseで動かして言語のRuntimeも全部Dockerで行うようになったのでMacに 言語のRuntimeを入れる必要がなくなりました。個人的に rbenvruby-buildMac上に入れなくなったのは時代の転換期を感じます。。

cask_args appdir: '/Applications'
tap 'caskroom/cask'

brew 'ctop'
brew 'curl'
brew 'ghq'
brew 'gist'
brew 'git'
brew 'htop'
brew 'hub'
brew 'jq'
brew 'mackup'
brew 'mas'
brew 'openssl'
brew 'peco'
brew 'rmtrash'
brew 'sshrc'
brew 'telnet'
brew 'tig'
brew 'tree'
brew 'z'
brew 'zsh-completions'
brew 'zsh'

# ココらへんを全部入れないことにした
# tap 'homebrew/php'
# brew 'automake'
# brew 'cmake'
# brew 'ctags'
# brew 'gcc'
# brew 'go'
# brew 'heroku'
# brew 'memcached'
# brew 'mongodb'
# brew 'mysql'
# brew 'node'
# brew 'nodenv'
# brew 'postgresql'
# brew 'pyenv-virtualenv'
# brew 'pyenv'
# brew 'python'
# brew 'rbenv'
# brew 'readline'
# brew 'redis'
# brew 'ruby-build'
# brew 'sqlite'
# brew 'v8'
# brew 'yarn'

cask 'alfred'
cask 'appcleaner'
# cask 'atom'
cask 'bartender'
cask 'bitbar'
cask 'caffeine'
cask 'cyberduck'
cask 'docker'
cask 'fantastical'
cask 'github'
cask 'google-chrome'
cask 'google-japanese-ime'
cask 'grandperspective'
cask 'gyazo'
cask 'iterm2'
cask 'karabiner-elements'
cask 'keycastr'
cask 'ngrok'
cask 'paw'
cask 'postico'
cask 'sequel-pro'
# cask 'vagrant'
# cask 'vagrant-manager'
# cask 'virtualbox'
cask 'visual-studio-code'
cask 'vlc'

mas 'Airmail 3', id: 918858936
mas 'Bandwidth+', id: 490461369
mas 'Be Focused Pro', id: 961632517
mas 'BetterSnapTool', id: 417375580
mas 'LanScan', id: 472226235
mas 'Night Owl', id: 428834068
mas 'Skitch', id: 425955336
mas 'Todoist', id: 585829637
mas 'Wireless Signal', id: 582840059

リストア, 開発環境構築の手順で使うツール

  • DiskMaker X
    • インストールディスク作成
  • Homebrew brew bundle でBrewfileからアプリとツールをダウンロードするのに使います
  • mackup
    • アプリやツールの設定ファイルを指定のフォルダ、デフォルトではDropbox上に作られる、に退避し、それらのファイルが元にあった場所にシンボリックリンクを作ってくれるツール。自分で新たに独自にバックアップするファイルも指定できる。
  • Docker for Mac
    • macOSでDockerを動かす
  • Dropbox
    • mackupで使うフォルダとBrewfileを置く。また基本的にmac上で使うすべてのファイルはDropboxiCloudに置くようにしている。いつMacが動かなくなっても良いようにローカルにしかファイルがない状態は基本的になくす
  • GitHub, または他のGit Repository Hostingサービス
  • 1password
    • パスワードはiCloud keychainと1passwordに両方保持してる。keychainはSafariでは便利。基本的には1passwordを使う。パスワードマネージャー使ってないとリストア後のログインがめちゃくちゃ面倒なので絶対使う。異なるサイトで同じパスワード使うとか絶対にあってはいけない。

リストア手順

  1. リストアして最新OSを入れる。
  2. macOSのシステム環境設定 Dock、トラックパッド、キーボード、言語設定などを好みに変更する。ここはOSが変わっていくと変化する可能性があるので自動化していない
  3. DropboxをインストールしてMacupフォルダとBrewfileを選択同期する。リストア作業に関係ないものは後日時間があるときに同期する。
  4. Homebrew をinstallする
  5. brew bundle でアプリとツールをインストールする
  6. mackup restore でアプリとツールの設定ファイルを復元する
  7. iTerm2を開いてデフォルトのshellをzshに変更する(お好み)
  8. 開発リポジトリgit clone する
  9. docker-compose で開発環境を立ち上げる
  10. JetBrainsのエディタをインストールして立ち上げる

ここまでで所要時間1時間半くらいで構築できるようになりました。

Docker

Dockerの構築を知りたい方は下のリポジトリとかを参考にしてください。Railsのアプリケーションです。最近は開発環境構築を make build とすると終わるようにするのが趣味になってます。

Railsのdocker-composeのサンプル

github.com

Laravelのdocker-composeサンプル

github.com

Dockerを学ぶにはこの本がおすすめです。Dockerやdocker-composeの使い方はこの本を読むことでだいぶ理解が進みました。

Dockerによるアプリケーション開発環境構築ガイド

Dockerによるアプリケーション開発環境構築ガイド

おわりに

リストア環境をちゃんと作っていれば1, 2時間でリストアから開発環境構築完了までいけるようになりました。ここまで来るとOSにほとんど依存しないのでMacである必要ないやんという感じなのですが、ぼく個人としてはApple信者であるためMac使い続けようと思います(今の所は)。LinuxとかWindowsのWSLはDockerサクサク動いていいなぁとは思う。

1時間半でリストアが終わるなら土曜日の午前中に時間があるときにやるか、というぐらい気軽にできるようになるので定期的にリストアをする習慣が作れると思います。新しいOSが1年に1度出るのでそのときにリストアすると良いと思います。リストアせずにOSのメジャーバージョンのアップデートするとだいたい遅くなったり壊れたりします。ツールに愛を持ってメンテンナンスを定期的にしましょう。エンジニアの中でさえOSをアップデートしない人とかがたまにいるんですけど、ほとんどの問題はリストアしたら直るのでやってあげてください。よろしくおねがいします。

Rubyエンジニアはsleep 1で殺せる、をngx_mrubyのAsync.sleepで乗り越える

そろそろ今年のISUCON、ISUCON8まであと1ヶ月ちょっとになったのでひとりリハーサルをそろそろはじめてるさぼです。去年ISUCON7に初挑戦してRubyを選択してsleep 1が乗り越えられず人権を失いました(原因は他にもあるけど...)。

ngx_lua での sleep

去年、予選終わったあとに感想戦で聞いた、Openresty、ngx_luaを使ったsleep方法を試したりしました。Rubyでsleepを行うと処理をブロッキングしてしまうので、nginx側で1秒待った上でRubyに処理を渡すことでRuby側では処理を待つ必要がなくって捌けるリクエストを増やす算段です。

Async.sleepを実装した ngx_mruby v2 がリリースされる

rubykaigi.org

hb.matsumoto-r.jp

今年のRubyKaigi2018での @matsumotory さんの発表で、nginxでのmruby実装である ngx_mruby module のv2をリリースする話をしていて、その中でnon-blockingなsleepが出来る Nginx::Async.sleep が出来るという話でした。今回はこれを次のISUCONまでには使えるようにして sleep 1 に対策出来るようにしておこうと思って実装してみました。

実装

github.com

@matsuu さんが公開しているVagrantfileからアプリケーションを立ち上げて、なんとなくDocker化するのが最近趣味なのでDocker composeで置き換えて実装しました。

dokcer-compose の設定

isucon7q/docker-compose.yml at 201808 · saboyutaka/isucon7q · GitHub

# dokcer-compose.yml 抜粋
version: '3'
services:
  web:
    build: .
    command: "bundle exec rackup -p 8000 -o 0.0.0.0"
    volumes:
      - .:/app
    ports:
      - 8000:8000
  ngx-mruby:
    image: saboyutaka/ngx-mruby
    ports:
      - 80:80
    volumes:
      - ./public:/var/www/public
      - ./config/ngx_mruby/nginx.conf:/usr/local/nginx/conf/nginx.conf
      - ./ngx_mruby/hook:/usr/local/nginx/hook

https://hub.docker.com/r/saboyutaka/ngx-mruby/

@matsumotoryさんもDockerfileを公開しているけど、latestが ngx_mruby 1.19.5 だった(気がする)ので2.1.1で作り直しました。

Ruby app.rb の処理を変更

https://github.com/saboyutaka/isucon7q/blob/0e6cc831d5cf1011d117598ab38536b377c53b34/ruby/app.rb#L154

def fetch
  ...

+  # sleep をコメントアウトする
+  # sleep 1
-  sleep 1

  ...
end

nginx の設定

https://github.com/saboyutaka/isucon7q/blob/0e6cc831d5cf1011d117598ab38536b377c53b34/config/ngx_mruby/nginx.conf

# nginx.confの抜粋
http {
  ...

  upstream app {
    server web:8000;
  }
  
  server {
    ...

  location /fetch {
    mruby_rewrite_handler_code '
      Nginx::Async.sleep 1000
      Nginx.return Nginx::DECLINED
    ';

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://app;
  } 
}

mruby_rewrite_handler_code directive 内でngx_mrubyを実行しています。ここでNginx::Async.sleep 1000を記述することで、nginxでリクエストをnon-blockingで止めて、時間経過後に処理を再開します。ちょっとハマった点は、rewriteを複数回行う場合、今回は proxy_pass も使っているので、明示的にNginx.return Nginx::DECLINED を書く必要があってそれに気づくのに時間がかかりました。nginxもうちょっと勉強して理解したい.. matsumotoryさん本人からリプライ頂いてありがたい🙏

実行結果

Before

f:id:saboyutaka:20180813215213p:plain

realtime: 1.157 apptime: 1.150

After

f:id:saboyutaka:20180813215021p:plain

realtime: 1.150 apptime: 0.140

apptime(Sinatraの処理時間)が1.150から0.140に変わりました!Rubyの処理が約1秒減ったのがわかります。これで/fetchへのリクエストが大量にきてもRubyの代わりにNginxが処理を止めるので、Rubyでリクエストが詰まることがなくなりました。

おわり

今年も去年と同じメンバー(@tompng, @_simanman, @saboyutaka)で挑戦しようという話になっていてRubyと今年はngx_mrubyも持っていけるようにしておきたいなと思ってやってみました。sleep 1 が2年連続は出ないだろーと思いつつも対策は万全で行きたいと思いますー💪

Hack Yourself ~グロースハックと学習のためのbrain hacking~

1月から始まったプログラミング講座で講師をさせて頂いてて1ヶ月半くらい経過して、受講者の間で日々コードを書いてる人とそんなに学習が進んでない人の差が大きくなったのでこういう話を受講者内Slackに書き込みしました。

以下内容

Hooked を紹介、ハマるしかけはHookedの日本語訳

心理学者が書いたものに対する依存性・中毒性をどう作るかを解説した本だけど

グロースハッカーはみんな読んでる良書で、サービス、商品にたいしてどうユーザー・消費者を中毒症状にさせるかという話

アプリをたくさん使ってもらいたい!自分のサービスを毎日使ってほしい!っていうのは心理学からすると中毒症状そのものなんですよねー

毎日FacebookTwitterを開くことの中毒症状をいかにつくるか

中毒症状にハメるステップとして外的トリガーと内的トリガーがあって、外的トリガーが外からの刺激、内的トリガーが内なる刺激、欲求

最初は外的トリガーで誘いつつ、じわじわと内的トリガーが発生する状態に持っていって、内的トリガーだけでぐるぐる回るようになると中毒症状の完成

で、なんでここでこれを出したかというと、勉強もこれと同じで。やりたいことがあるなら自分を中毒症状に持っていくと楽なんですよね

スクール通うとかは外的トリガーなんですけど、スクールの間で内的トリガーに切り替わる事が出来なければスクールが終了した後に学習をやめるのは目に見えてるので どうにか自分を中毒症状にするように脳をhackしていく必要があります

ぼくは何か学習したいと思ったら、毎日それを習慣にして、無意識に耳に入れたり、それをやってる人と何度もあったり、それに関するtweetを頻繁に目にするようにしたり。結構外的トリガーを整理して環境を作ると内的トリガーに切り替わりやすいという自分の中の実体験、自分の脳の仕組みを少し理解してるつもりなのでそういう感じで仕向けます

やる気って過大評価されますけど、やる気ってあまり関係なくて、脳を中毒症状に持っていければ勝手に自動的に学習する習慣がつきます(たぶん

本の中でも出てきますが、何か自分がアクション起こした時にインセンティブが発生するとスパイラルがぐるぐる回り始めます。

twitter、FB、Instagramだと投稿にいいねがつく、とか。

勉強した自分に何かインセンティブがつくような設計してたほうがいいです、あとはハードルを高く見積もらないこと、自分を褒めてあげること、やってない自分を責めないこと

happy brain hacking ❤

過去にすごい学習に時間を使ったことがある人は、自分を学習モードにするコツをなんとなく理解してたりするので、何か学ぼうとなった時自分をそう仕向ける術を知ってるので楽に学べたりします

逆にその経験がないと、学習できないことへの劣等感で先に進めない人もいます

若いうちに自分の学習パターンを把握してるとあとの人生が楽なので、若いうちに把握するのオススメ。学校教育ってそういうところでもあるんですけどね、何を学ぶかは何でも良くて、自分がどういう学習方法が得意かを自分で把握する期間

僕は資格たくさん取ろうと学生時代ずっと勉強してたのでその時に自分にあった学習パターンを見つけれてて、それが今でも活きてる感じ

紹介してる本はこちら

Hooked が原著

Hooked: How to Build Habit-Forming Products

Hooked: How to Build Habit-Forming Products

ハマるしかけ は Hooked の翻訳本

モチベーションでかなりパフォーマンスが変化すると自分の性格を自覚しているので、精神論苦手で"がんばる"とか"やる気"とかいう言葉はあまり信じないようにしていて。自分が学習する時に取り組んでる方法を書いてみました。

学習するのに外的トリガーを無理やり作る方法として、プログラミングスクールに入ったり、英語を学ぶんであれば海外の英会話スクールに入ったりはアリ。だけど長いあいだ技術を学ぶにはふとした時にやろうかなと内面から出てくる感情を育てる必要があってその感情、内的トリガーに切り替える必要がある。これがないとスクールが終わった途端にやらなくなる。みなさんも経験あるのでは。

ゲームやSNSって気づいたらハマってるんですけど、勉強って誰もハマるしかけを作ってくれないので自分で作る必要があります。(だいたいの場合

Progateとか初学者の方にとてもよくてオススメしてるんですけど、Progateはどんどん出来るけどそこから先がうまく進めないという人がたまにいて、それはProgateが丁寧にハマるしかけを作ってくれてるんですけど、それ以降の学習はそのしかけがなくなるので補助輪外されたような感覚で急になにも出来なくなる感じとか。あったりしません?

プログラミング学習のHookedモデル設計

f:id:saboyutaka:20180302023115p:plain

アクションにつながるような内的トリガーは超個人的な感情。○○さんがやってるからやりたいとか、○○するとモテるとか、かっこいいと思われるとか。恐怖の感情も、やらないと将来不安とか、普通の仕事は出来る気がしないからプログラミングしかないんだとか、絶対にこの状況を変えてやるとか。Hookedモデル的には快楽の感情よりも、負の感情の方がより強力。

以下はぼくが思いつくしかけをあげてみます。自分にあった環境を作ってみてください。

外的トリガー

  • スクールに通う(強制的にスケジュールに入る、意識の近い人と触れ合える)
  • シリコンバレーとか行く
  • 勉強会に行く
  • rebuild.fmを毎回聞く
  • Twitterで技術系の発信している人をフォローする
  • はてなブックマークのテクノロジーを毎日目に入れる
  • Githubの気になるプロジェクトの通知を受け取る
  • メンターを見つける
  • Youtubeの技術系チャンネルをお気に入り登録する
  • TED見る
  • エンジニアから起業した人とかの本を読む

トリガーは意識的に設計して環境整えるのが大切。普段の生活に取り入れる事が重要、やる気がなくても出来る事を準備しておく。

アクション

  • コード書く
  • 情報を見る、聞く
  • 勉強会、カンファレンスに参加する
  • 人と知り合う

あまり高い意識を持ってやらなくても良い。小さく始める。

リワード

  • 書いたコードが動いて嬉しい
  • わかる事が増える
  • できるだけゴールを短く見積もって達成感を得るようにする
  • 数値化出来るものは定期観測して成長を実感する
  • アクション出来たらカレンダーに○を付けてそれを眺める

楽しい、嬉しいが大切

インベストメント

  • アウトプットして人に見てもらう
  • ブログ書く
  • Githubで公開する
  • 自分のライブラリ公開する
  • 勉強会、カンファレンスで発表する

褒めてもらえる、共通点を持った人が増えてまたアクションに繋がる

みたいな感じ。

おわりに

今日この話をして、3月の講義が終わって5月のGW中の休みに、あ、これやってみようかなと自分で思ってコードを書いてるかどうか、が今後の学習を継続するにおけるKPIです、みたいな話をしました。

全員がうまくいく方法ではないとは思いますけど、理解出来る人はいるかも。 よかったら参考にしてみてください

Happy Brain Hacking❤️