ハトネコエ Web がくしゅうちょう

プログラミングとかAndroid

Hacking HR! #2 に参加して採用業務の失敗を聞いてきたよ

会社にとって 一番大事なもの ってなんでしょう?

間違いなく 採用 です!

ろくでもない人を雇うと、周りと衝突を起こしたりマネジメントコストが増えたり、
疲れて周りの人が辞めていったり……とまあ、ろくなことになりません。

そんなろくでもない人を部長職にでもしちゃおうものなら、
部単位でどんどん人が辞めていくし、ろくでもない部長がろくでもない人を入社させてしまうのでまあ簡単に会社が腐っていきます。

一人辞めると一人採用する必要があるわけで、それにかかるコストは
エージェントに支払う金額だけで 200 〜 300 万円ほど。(それ以外に掲載費用などもかかるわけですが)
会社の人材の質が下がるだけでなく実質的な費用もかかるので、
採用は本当に気をつけないと、すぐに大変なことになっていきます。

(そういえば昨年こんな記事を書きました)

0. Hacking HR! #2 に参加したよ

さて、前置きが長くなりましたが、
そんな採用に関するおもしろそうな勉強会を発見し、参加してきました。

Hacking HR! #2 です。

スタートアップ企業の人事の勉強会で、特に採用に関してのテーマでやっているようです。
今回のテーマは『実録!「採用」業務の失敗談』

いいですね、このテーマだけであと5回くらいはできるんじゃないかって気がします。

f:id:nekonenene:20180911232552j:plain

会場は Repro さんです。
トイレにミューズ泡ハンドソープが置かれていて、
「わかるわ〜、ビル備え付けのハンドソープって全然泡立たないよね、置くよね」って思いました。
(私の勤めてる会社にも置いてある)

1. scouty 伊藤さん (@tetsuyaito_2)

「合否判断が分かれて気付いた! 採用要件の明確化がもたらした2つの価値」

トップバッターは最近サービスが正式リリースを果たしました scouty さん。
(今までのってオープンβ版だったんですね)

scouty さんは 3〜4ヶ月前にお話を聞きに行ったばかりで、おもしろい人事制度をしているな〜と感じている企業さんです。
まさにこのイベントタイトルの「Hacking HR!」って会社ですね。

https://scouty.co.jp

そんな scouty さんで起こったのが、営業を雇うにあたって
メンバー間で判断が分かれたこと。

じゃあどうしたかと言うと、採用基準をもっと明確化しました。
超詳細な採用基準 です。

「なになにをこうやったことある」「こういう環境でこれをやったことある」といったファクトベースに基づいた、
解釈が人によって分かれないような採用基準を、
細かく細かく超詳細に落とし込んだそうです。(その項目リスト見てみたいですね!)

その結果として、採用すべきかの判断にかかる時間を少なくすることができたばかりでなく、
リファーラル(知人採用)がおこなわれやすくなりました。

どういうことかと言うと、採用要件が非常に明確になっているぶん、
「じゃあこういう人が合うんだ」と社員も理解しやすいので、人を連れてきやすくなる
ということです。

結果、月におこなわれた50件の面談のうち、採用担当由来の面談は13件、
つまり 70% 近い 37 件がリファーラルを元とする面談となったそうです。マジで?! すごい。

なお、scouty さんは採用候補者と社員全員がご飯を囲むのですが、
その際、全社員が書くその人に関する判断のチェックシートも非常に細かく項目があるそうですよ。

2. ナーブ 大野さん

「5回転職し6社で採用に関わって感じた、採用を失敗させる共通要因」

VR系スタートアップのナーブに勤める大野さんが、現在までの経験談を語ってくれました。

やはり多いのが、そもそも離職する組織構造になっている場合。

「とりあえず人が足りないから採用しよ」と採用を走らせたところで、
組織に問題がある場合は底の空いた桶に水を注ぐようなもので徒労。

採用するのであれば、

  • 候補者をどうアサインするか決まってるか?
  • 候補者が入社の時点でやるタスクは変わらないか?
    → 〇〇という技術が得意な候補者を、〇〇を使う△△プロジェクトに充てようと採用したが、入社時には△△プロジェクトが無くなっていた、というケースがあったらしい……
    → 〇〇をやりたいと思って入ってきた人は当然すぐ辞めてしまうし、悪い噂につながる
  • タスクが誰かに行きやすいような組織構造になっていないか?(タスクマネジメントが出来ているか)
    → 即戦力と言われたメンバーが必死で数々のタスクを巻き取っていたケースがある
    → よほどの超待遇なら別かもだが、ふつうは高負荷でつぶれて病み、会社に来なくなる

などを確認しましょう。という話をしていました。

いずれも当たり前の話ですが、
「どうアサインするか決まってるか?」は、けっこう見過ごしがちなポイントなので要注意です。

「いま人が足りていないんです、忙しいんです、だから少なくともあと○○人はください」という
現場の声をそのまま人事が受け取って採用すると、
(大方そういう場合タスクマネジメントが機能していないので)結局なぞに忙しいままだったり、ヒマになる人が出たり、
あまり良い結果につながりません。

最終的な解決はそのチームやその上長の手でおこなうとしても、
「○人欲しい」の要望に対してそのまま受け取らずに、
「それはどうして?」「どういうタスクをやってもらうの?」などのヒアリングは
人事として大事な仕事と言えるでしょう。

3. Speee りゅっくさん (@_kei_y_)

「元マーケターが採用で失敗した話」

こちらで記事にしてくださっています。ありがとうございます!

マーケターをやっていたので、つい、数字で見ればいい! と思って行動したところ、
広告業界と違ってユーザーまでの距離が近いので、相手の個人の人間としての気持ちの動きを見るのが大切 という結論に落ち着いたという話でした。
(例えばエンジニア採用で、人事からスカウトメールを送るよりも、エンジニアからスカウトメールを送るほうが、相手が心を開いて返信しやすいはず、などの心理的部分に着目するのが大事)

スカウトメールを送った際の遷移率(離脱率の逆。何割の人がメールから面接に至ったか、一次から二次に至ったかなどの値)を求め、
そこから募集人数を採用するために必要なスカウトメールを送信し……とやったところ、
質より量になってしまいスカウトメールが低質なテンプレ化。
返信率は下がってしまった、という苦い思い出を話されていました。

一方で、会場からは
「大企業の新卒採用のような母集団がでかい場合には、マーケティング的な発想が効くかもしれない」という案も出ました。

懇親会では、昔、私がエンジニア組織推進室(現在のものづくり組織推進室……ですよね?)の渡邊さんとお会いしていたので、
渡邉さんがプロダクト推進室に異動になり、りゅっくさんが6月にものづくり組織推進室へ異動になるまでの顛末などおもしろく聞かせていただきました。

渡邉さんとの話で、「エンジニアは極論、ネットですべてが完結してしまって会社で働く必要がない。
それならエンジニアに来てほしい会社はどうすればいいか、ネットとの隔たりを出来るだけなくしていく」
という思考の元、
社内で勉強会・ミートアップを人事主導で間髪入れず開催したり、
有名なエンジニアと会社で会えるようにしたりなどの施策を意識した。
という話は、1年前の面談での会話ながら今でも印象に残っています。

4. キュービック 森實(もりざね)さん

「組織拡大後に気付いた採用の失敗」

採用コンサルタントとして活躍されている森實さんです。
ITベンチャーにジョインし 30名から 300 名への組織拡大に携わる一方、それにともなう失敗も経験されたそうです。

4-1. 「〇〇さんと働きたい!」戦略の失敗

入社当時の会社は小さく、知名度が低く、給与が高いわけでもなく、採用で勝てる要素が少なかった。
そこで、「ざねさん(森實さん)と働きたい!」と言われるような状態を作り、
候補者の意欲を上げるために、自分の露出を増やしていったそうです。

その目論見は成功したものの、
会社規模が大きくなっていったときに組織がまとまらない問題が出てきました。

f:id:nekonenene:20180912013140j:plain

  • Philosophy:会社の理念
  • Profession:仕事内容・プロダクト
  • People:人・社風
  • Privilege:給与

組織の束ね方の 4P のうち、「この人と働きたい」という個人を推し出す採用の結果、
Philosophy や Profession の部分、つまり会社自体に魅力を感じて働く人が少なかったことに気付いたのです。

会社はその後、理念の浸透のために会社スローガンの作成をしたり、
でもスローガンは結局浸透しないので、社員にテストしたりと迷走したそうです……。 (当然、テストは「軍隊の洗脳みたい」と社員から大不評だった)

4-2. リファーラル意識の薄まり

もともとは 「採用や広報はみんなでやるもの」 という意識が社内にちゃんとあったのですが、
30名だった会社が100名になる頃にはその意識がすっかり無くなり、
現場は「人事がなんとかしてくれる」と思うようになり、リファーラルの文化が消滅(!)

リファーラルプロジェクトを発足させたものの、
マインドセットを取り戻すのには苦労したそうです。

人事だけががんばっていると、思考レベルでみんなから採用意識が無くなっていくので注意。

これ、カヤック社のぜんいん人事部化計画を思い出しますね。
「ぜんいん人事部化計画」「エイプリル採用」カヤックのユニーク人事を支えるたった1つの問い - ログミー

4-3. 「多様な価値観」問題

「多様な価値観を持った人を採用したい」という要望通りに採用していたら、
たしかに良く言えばいろんな人がいる会社になったのだが、
会社のカルチャーは薄まり、組織の結束力が弱くなってしまったという話。

多様な価値観という言葉は聞こえは良いけれど、
「私達は何をしたい集団なのか」の答えとなるような人材を集めることが本当は大切なこと。
だから、「多様な価値観を持った人を採用したい」に対しては下記のような質問に対する
答えを持ち合わせたほうがよい、というお話をされていました。

f:id:nekonenene:20180912014933j:plain

4-4. 福利厚生訴求採用の失敗

「福利厚生」が並んでるといい会社に見え応募者が増えるので、
職場に猫とかありとあらゆる福利厚生を求人票に書いていたそうです。

しかし、それで応募してくる人は会社に対して
「ホワイトな会社!」というイメージを強く持ち期待値が上がってしまうため、
(実際はベンチャーで土日出社もあるところだった)
少し何かあったときに「ホワイトじゃないんですね……」と裏切られた気持ちにさせてしまうことが起きたそうです。

あまり応募者の期待値を上げすぎてしまう求人票もそれはそれで良くないようです。

(ところで、「ベンチャーだから深夜残業や土日出社は当たり前」みたいに言う会社をたまに見ますが、やっぱ休むときは休んだほうがいいもの作れるんじゃないかなー、と思います個人的には)

4-5. 総括

「応募者を増やす戦術」を考えてしまうと失敗をしてしまう。

「会社がどうなりたいのか」の 戦略を考える人事 が必要だというまとめをされていました。

うちの会社はどこのポジションになっていくのか、競合はどこなのか、
それらの経営戦略を考えて採用に用いていくのが大事。
ということでした。

そのためには当然、経営層が関わってくるわけで、
経営層が人事に積極的でないと、採用は成功に至れない という話につながっていくかと思います。

森實さんの講演は濃かったですね。

5. Repro 畑中さん

「口説いたら引かれた ~超えられない壁~」

ラスト! Repro の畑中さんです。主催などありがとうございます。

登壇資料はこちらです!GitPitch のシェアURLはディレクトリ指定ができないっぽいので直接Markdownへのリンクです)

創業から2〜3年目、坊主と眼鏡のシニアメンバーばかりだったとき、
業務拡大に伴いコンサルを20名くらい採用する必要が発生しました。

その人数の経験者を採用するのは難しかったのでポテンシャル採用も含めた結果、
今度はその人達をマネジメントするマネージャーが必要となりました。

ここまででちょっと失敗してる気もしますが置いておいて、
今回はそのマネージャー採用に苦労した話です。

なんと驚きの圧倒的辞退率:90%
これには会場の皆さんから笑いが。

ヒアリングをおこなってみると、大きく理由は5つに大別されるとわかりました。

  1. ビジネス領域の違い
  2. 経験したいフェーズの違い
  3. 年収
  4. カルチャーアンマッチ
  5. 家族の理解が得られない

1. 〜 3. はどうにもできないとして、
4. と 5. についてはコントローラブルと考え、改善することにしました。

どうも候補者としては、

  • ベンチャー企業は結果が全て→悪かったら即座にひどいことになる
  • 土日も当たり前のように働かなくてはいけない
  • 妻から同様に「全ての時間が会社に取られる」という認識で、「仕事漬けなのに給料下がるし、ストックオプション本当にもらえるの?」などの嫁ブロック

という誤解があるようで、そこを説明。必要あらば奥さんにも説明。
そうして、採用に至れるよう改善していった、とのことでした。

会場からの質問では「口説き文句は?」というのがあがりました。
「『自分は会社のこういう良いところに惹かれて入社したんですよ』を言うと刺さる可能性が高い」というお答えでした。たしかにそうかも……

6. おわりに

懇親会もとても良かったですね。

採用担当の方が多いからなのか話し上手な方が多く、
非常に楽しい懇親会を過ごすことが出来ました。お食事もいっぱいありましたし。

Schoo の武井さんとお話して、適性分析の分野において
Schoo@me (2017/04設立)が大学との共同研究をしている話の子細を伺ったのは、最高に熱くて燃えましたね。

自分らしさを解析して、誰もが個性を活かせる社会をつくる | SchooMembers

まずベンチャーが R&D (研究開発)の子会社を作るって時点ですでにすごいですからね。
何を出してくれるか期待大です。

そして……

Hacking HR! #3 が 9/25 に開催されます!

ハッシュタグは前回同様 #hackinghrs です。

今回は私としては興味あるテーマではないので参加はしなさそうですが、
今後もぜひとも参加したい、とても良いイベントでした。

人事って最高ですね!

ブログをMixed Content対応しつつHTTPS化しました 🎉

今年の4月から、はてなブログドメインを使用している全ブログが HTTPS 化に対応しました。
(2月の時点ではまだ段階的に提供開始というステータスだった)

対応したいなと思いつつも、
「Mixed Content 対応のためには記事をひとつずつ保存し直してね、てへぺろ(ノ≧ڡ≦)」
という公式アナウンスだったので、「いや、きついっしょ……」と思い、
はてなブログの方で Mixed Content 対応のためのツールを出してくれるのではと期待していたのですが、
まだまだそんなものは出なさそうな気配でした。

しょうがないので、今日は時間もあったのでがんばって対応することにしました。

ブログの詳細設定 から行ける
エクスポートページ で、記事の一覧をテキストファイルでダウンロードできるので、
http://nekonenene.hatenablog.com」で全文検索したりして、地道にがんばりました。

最後に mcdetect という npm のパッケージを使って、 Mixed Content が残っていないか確認しました。

npm install -g mcdetect

でインストールした後、例えば Mixed Content を含むサンプルページ
https://googlesamples.github.io/web-fundamentals/fundamentals/security/prevent-mixed-content/passive-mixed-content.html を調べてみると、以下のようにWarningsが表示されます。

mcdetect https://googlesamples.github.io/web-fundamentals/fundamentals/security/prevent-mixed-content/passive-mixed-content.html

Checking https://googlesamples.github.io/web-fundamentals/fundamentals/security/prevent-mixed-content/passive-mixed-content.html ...
    Optionally Blockable: http://googlesamples.github.io/web-fundamentals/samples/discovery-and-distribution/avoid-mixed-content/puppy.jpg
    Optionally Blockable: http://googlesamples.github.io/web-fundamentals/samples/discovery-and-distribution/avoid-mixed-content/sleep.mp3
    Optionally Blockable: http://storage.googleapis.com/webfundamentals-assets/videos/chrome.webm
    Optionally Blockable: http://storage.googleapis.com/webfundamentals-assets/videos/chrome.webm

Targets checked: 1
Errors (blockable content): 0
Warnings (optionally blockable content): 4

ブログのURL一覧を、先ほどのエクスポートしたテキストファイルの
「BASENAME: 2018/09/09/160814」のように BASENAME: の右側に書かれている部分を用い、
正規表現の置換でいい感じにURLの一覧にします。

で、以下のようなブログURL一覧のjsonファイル blog_urls.json を作って

{
  "targets": [
    "https://nekonenene.hatenablog.com/2018/09/09/184352",
    "https://nekonenene.hatenablog.com/2018/09/09/160814",
    "https://nekonenene.hatenablog.com/2018/09/07/090818",
    "https://nekonenene.hatenablog.com/2018/09/02/215152",
    "https://nekonenene.hatenablog.com/2018/09/02/202115",
〜中略〜
    "https://nekonenene.hatenablog.com/2015/03/30/131915",
    "https://nekonenene.hatenablog.com/2015/03/30/125724",
    "https://nekonenene.hatenablog.com/"
  ]
}

mcdetect で全件チェックしました。

mcdetect --config ~/Documents/backup/blog_urls.json

Checking https://nekonenene.hatenablog.com/2018/09/09/184352 ...
Checking https://nekonenene.hatenablog.com/2018/09/09/160814 ...
Checking https://nekonenene.hatenablog.com/2018/09/07/090818 ...
Checking https://nekonenene.hatenablog.com/2018/09/02/215152 ...
Checking https://nekonenene.hatenablog.com/2018/09/02/202115 ...
〜中略〜
Checking https://nekonenene.hatenablog.com/2015/03/30/131915 ...
Checking https://nekonenene.hatenablog.com/2015/03/30/125724 ...
Checking https://nekonenene.hatenablog.com/ ...

Targets checked: 134
Errors (blockable content): 0
Warnings (optionally blockable content): 0

全件大丈夫そうですね。よかったよかった。

というわけで 今日から HTTPS でお届けいたします。最高ですね!

FirefoxとChromeは表示される色味が違う!!

ブログのデザインを微変更していて気付いたのですが、
Mac版だけかもしれませんが)FirefoxChromeの色味って違うんですね!

f:id:nekonenene:20180909182402p:plain

(左:Firefox、右:Chrome

FirefoxChrome よりもきらびやかな色になります。

Firefox でカラーを調整していたので、Chrome だとくすんだ色になってしまいます。

試しに SafariOpera で同じページを開いてみると
色味は Chrome と似ていることがわかります。Firefox だけ異色なんですね。

このページに詳しく書かれていました。

Firefoxのカラマネに関するパラメータについて - グーとモコの写真ブログ

gfx.color_management.mode の値をデフォルトである 2 から 1 に変えればいいようです。

この記事のときに使ったばかりですが、
またも about:config をアドレスバーに入力する時が来たようです。

f:id:nekonenene:20180909183741p:plain

前回同様、about:config にアクセスするとこんな表示が出ますが、気にせず青いボタンを押します。

検索ボックスに「gfx.color」と打つと、以下のように出てきますね。

f:id:nekonenene:20180909183812p:plain

gfx.color_management.mode の値を 1 に変えて、
Firefox を再起動します

それが終われば、Firefox は他のブラウザと同じような色味で表示してくれるようになります。

くすんだ色味になってしまって残念な気もしますが、
多数派に合わせてカラーデザインした方がいいですからね!

Docker Swarm モードはわかりやすい!

最近はDockerの勉強をしています。

以下の本(おすすめです!)の内容に沿う形で、Docker Swarm モード の動きを試してみたいと思います。

コンテナ・ベース・オーケストレーション Docker/Kubernetesで作るクラウド時代のシステム基盤

コンテナ・ベース・オーケストレーション Docker/Kubernetesで作るクラウド時代のシステム基盤

Swarm モードってなんじゃい? という方は、こちらのドキュメントを読んでくださるのが早いと思います。

Docker Swarm 概要 — Docker-docs-ja 17.06.Beta ドキュメント

かんたんに言うなら、複数のホスト(サーバー)で起動しているDockerを、
1つの司令塔となるサーバーから指示を出すことにより管理できる仕組みです。

1. VirtualBox を利用して複数ホストの構築

最初、「サーバー複数立てるとなるとお金が……」って思いましたが、
本の中で VirtualBox に複数ホストを立てる方法が案内されていました。
なるほど、それならゼロ円!

参考記事 : Docker Machine を使って VirtualBox に Dockerホストを立てる

docker-machine create -d virtualbox <machine-name> のコマンドで、
Docker がインストール済みの Linux イメージを持つ仮想マシンが、 Virtual Box 上に作られるそうです。便利!

しかし、やってみると boot2docker.iso のダウンロードがなぜかなかなか終わらず進めなかったので、
あきらめて https://github.com/boot2docker/boot2docker/releases から最新版をダウンロードしてきて
~/.docker/machine/cache ディレクトリ下に置き、再度コマンドを実行しました。

docker-machine create -d virtualbox manager1
docker-machine create -d virtualbox worker1
docker-machine create -d virtualbox worker2

に成功した後、 docker-machine ls

docker-machine ls

NAME       ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
manager1   -        virtualbox   Running   tcp://192.168.99.100:2376           v18.06.1-ce
worker1    -        virtualbox   Running   tcp://192.168.99.101:2376           v18.06.1-ce
worker2    -        virtualbox   Running   tcp://192.168.99.102:2376           v18.06.1-ce

それぞれのホストのプライベートIPアドレスが確認できますね。

2. manager1 を Swarm マネージャーに

それぞれのホストにて、Docker の Swarm モードを有効にするため、 swarm init をやりに行きます。

docker-machine ssh manager1

SSHログインした後、

docker@manager1:~$ docker swarm init

Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (12.34.56.78 on eth0 and 192.168.99.100 on eth1) - specify one with --advertise-addr

単純に docker swarm init をおこなうとエラーが出てしまいました。

ifconfig コマンドで確認するとわかるのですが、
このマシンには複数のネットワークインターフェイスが接続されており、
どのIPアドレスを外部との通信に使うのか確定ができないのです。

それを解決するため、 advertise-addr オプションを使います。

プライベートIPアドレスでホスト間通信をおこなってほしいので、
さっき docker-machine ls で見たこのマシンのプライベートIPアドレス 192.168.99.100 をここでは指定します。

docker@manager1:~$ docker swarm init --advertise-addr 192.168.99.100

Swarm initialized: current node (hkixhjon23s2xd1pvx57csa7q) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-57m3j6npg9ip54992xdo8pg9pt2yekmh3io92nji2nhysa5b6d-74ml40yfeahd2htj6rpk2hbx2 192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

これで Swarm モードが有効になりました。

docker@manager1:~$ docker node ls

ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
xxkdyatgiikov50oxy0qh1ir9 *   manager1            Ready               Active              Leader              18.06.1-ce

なお、逆に Swarm モードを無効にしたい場合は、 swarm leave をおこないます。
現在はマネージャーが 1 ノードのみですので、 force オプションを使う必要があります。

docker@manager1:~$ docker swarm leave --force

Node left the swarm.

docker node ls は、 Swarm マネージャーがクラスタ一覧を見るためのコマンドですので、
このホストが Swarm モードを無効にしマネージャーでもなくなった今、以下のようにエラーが出るようになります。

docker@manager1:~$ docker node ls

Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.

もう一度 Swarm モードを有効にするため docker swarm init --advertise-addr 192.168.99.100 をしておきます。

3. worker1, worker2 でも swarm init

worker1 および worker2 でも Swarm モードを有効にしたいのですが、
先ほどと同じようなコマンドをすると、新たな独立した Swarm マネージャーが出来てしまうだけです。
今回はもうマネージャーは必要ないので、別のコマンドを用います。

manager1 にて docker swarm join-token worker コマンドを使います。

docker@manager1:~$ docker swarm join-token worker

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-57m3j6npg9ip54992xdo8pg9pt2yekmh3io92nji2nhysa5b6d-74ml40yfeahd2htj6rpk2hbx2 192.168.99.100:2377

最終行にコマンドがありますね。これを使います。

まずはターミナルの別タブを開いて worker1 へログイン。

docker-machine ssh worker1

さっきのコマンドを使ってみます。

docker@worker1:~$ docker swarm join --token SWMTKN-1-57m3j6npg9ip54992xdo8pg9pt2yekmh3io92nji2nhysa5b6d-74ml40yfeahd2htj6rpk2hbx2 192.168.99.100:2377

This node joined a swarm as a worker.

無事に Swarm worker として加わってくれたようです。同じことを worker2 にもおこないます。

4. manager が docker node ls で確認

3. の手順が終わったら、 Swarm manager である manager1 が、
Swarm worker である worker1, worker2 を監視できる状態になっているかを確認します。

manager1 で docker node ls をおこないます。

docker@manager1:~$ docker node ls

ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
xxkdyatgiikov50oxy0qh1ir9 *   manager1            Ready               Active              Leader              18.06.1-ce
ra1nagb73mbusbpyxralb4fzj     worker1             Ready               Active                                  18.06.1-ce
ics08k65tcmwj1soe8y8c4887     worker2             Ready               Active                                  18.06.1-ce

逆に worker1 で docker node ls をおこなっても、 Swarm manager でないのでエラーが出るだけで終わります。

docker@worker1:~$ docker node ls

Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.

Swarm は日本語で「群れ」の意味です。
その群れに参加している manager1, worker1, worker2 はそれぞれ Node と呼びます。日本語で「ひとつの点」を意味します。

Swarm manager となる Node を manager node
Swarm worker となる Node を worker node と言うので覚えておくと有利です。

docker node ls コマンドは Node をすべて表示するコマンドだと理解すると覚えやすいでしょう。

5. Docker image を展開する

manager, worker それぞれの準備が整ったので Docker image を展開させてみましょう。

以下の2記事を参考にしました、ありがとうございます。

Docker Hub に存在する nginx のイメージを今回は利用します。

docker@manager1:~$ docker service create --name nginx_sample --replicas 2 --publish 8080:80 nginx:1.14

om5gg86083bfiwsi88ugcenm8
overall progress: 2 out of 2 tasks
1/2: running   [==================================================>]
2/2: running   [==================================================>]
verify: Service converged

どこのホストに作成されたか確認します。

docker@manager1:~$ docker service ps nginx_sample

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
0afwga4oks2q        nginx_sample.1      nginx:1.14          worker1             Running             Running 44 seconds ago
dcs7l9e3cdxq        nginx_sample.2      nginx:1.14          manager1            Running             Running 44 seconds ago

worker1, manager1 に作成されていました。
worker に優先的に作られると思っていたので、これは意外な結果でした。

6. Swarm Load Balancer

さて、nginx が動いていると思いますので、Webブラウザで確認してみましょう。

1. の手順で docker-machine ls をして見たプライベートIPアドレスを用います。
今回は8080番ポートで動かしてるので、 192.168.99.100:8080 にアクセスしてみます。

f:id:nekonenene:20180909125215p:plain

良いですね。

192.168.99.101:8080 , 192.168.99.102:8080 にも同様にアクセスできます。

worker2 では動いていないはずなのに 192.168.99.102:8080 でアクセスできるのは不思議ですが、
これは routing mesh のおかげです。

Swarmモードにした全てのノードは、リクエストがあると
現在 Active であるノードに、その要求を横流しし処理してもらいます。
いわば Swarm Node 間の Load Balancer です。

f:id:nekonenene:20180909131446p:plain

この図を見ると「内部で網目状(=mesh)につながるから routing mesh と呼ぶのか〜」とわかりやすいですね。

7. コンテナを増やす

さて、せっかくサーバーが3つあるのにDockerプロセスを2つのサーバーだけで動かしているようではもったいありません。
コンテナ数を増やしてみましょう。 docker service scale を使います。
縁起良く 7 つにしてみます。

docker@manager1:~$ docker service scale nginx_sample=7

nginx_sample scaled to 7
overall progress: 7 out of 7 tasks
1/7: running   [==================================================>]
2/7: running   [==================================================>]
3/7: running   [==================================================>]
4/7: running   [==================================================>]
5/7: running   [==================================================>]
6/7: running   [==================================================>]
7/7: running   [==================================================>]
verify: Service converged

どのホストで動いてるか確認します。

docker@manager1:~$ docker service ps nginx_sample

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
0afwga4oks2q        nginx_sample.1      nginx:1.14          worker1             Running             Running 44 minutes ago
dcs7l9e3cdxq        nginx_sample.2      nginx:1.14          manager1            Running             Running 44 minutes ago
tpxmli6n5xcy        nginx_sample.3      nginx:1.14          worker1             Running             Running 8 seconds ago
01x8uej3mabt        nginx_sample.4      nginx:1.14          manager1            Running             Running 8 seconds ago
pxn03gq3d2hu        nginx_sample.5      nginx:1.14          worker2             Running             Running 7 seconds ago
25kpj1yw9gsz        nginx_sample.6      nginx:1.14          worker2             Running             Running 7 seconds ago
bz5648esiqg7        nginx_sample.7      nginx:1.14          worker2             Running             Running 7 seconds ago

manager1 に2つ, worker1に2つ, worker2に3つ, おおむね均等になるように割り振られてますね。

8. プロセスを殺してみる

試しに worker1 での nginx を殺してみます。

docker@worker1:~$ ps ax | grep nginx
12902 ?        Ss     0:00 nginx: master process nginx -g daemon off;
13031 ?        S      0:00 nginx: worker process
13285 ?        Ss     0:00 nginx: master process nginx -g daemon off;
13363 ?        S      0:00 nginx: worker process
13619 pts/0    S+     0:00 grep nginx

docker@worker1:~$ sudo killall nginx

docker@worker1:~$ ps ax | grep nginx
13985 pts/0    S+     0:00 grep nginx

10秒程度待ってもう一度見ると、

docker@worker1:~$ ps ax | grep nginx
14006 ?        Ss     0:00 nginx: master process nginx -g daemon off;
14069 ?        Ss     0:00 nginx: master process nginx -g daemon off;
14143 ?        S      0:00 nginx: worker process
14188 ?        S      0:00 nginx: worker process
14274 pts/0    S+     0:00 grep nginx

勝手に復活していました。

manager1 で docker service ps nginx_sample コマンドから確認しましょう。

docker@manager1:~$ docker service ps nginx_sample

ID                  NAME                 IMAGE               NODE                DESIRED STATE       CURRENT STATE             ERROR                              PORTS
tfb84ly07nvb        nginx_sample.1       nginx:1.14          worker1             Running             Running 10 seconds ago
17slmexy1lry         \_ nginx_sample.1   nginx:1.14          worker1             Shutdown            Complete 16 seconds ago
〜中略〜
8eq2cnxa2mcz        nginx_sample.3       nginx:1.14          worker1             Running             Running 10 seconds ago
v80g7g7jq6k3         \_ nginx_sample.3   nginx:1.14          worker1             Shutdown            Complete 16 seconds ago
〜以下略〜

manager が、heartbeat の機能で worker1 でタスクの終了を確認したので、
期待状態(DESIRED STATE)を維持するために、worker1 に対し新しいタスクの開始を依頼しているのです。

9. nginx のバージョンを上げる

manager node で docker service update を用いて、nginx_sample service のアップデートをおこないたいと思います。

今回は、イメージを nginx:1.14 から nginx:1.15 にアップデートしたいと思います。

docker@manager1:~$ docker service update --image nginx:1.15 nginx_sample

nginx_sample
overall progress: 7 out of 7 tasks
1/7: running   [==================================================>]
2/7: running   [==================================================>]
3/7: running   [==================================================>]
4/7: running   [==================================================>]
5/7: running   [==================================================>]
6/7: running   [==================================================>]
7/7: running   [==================================================>]
verify: Service converged

このアップデート中も、 192.168.99.100:8080 などへのアクセスは変わらず可能です。

6. で説明したロードバランサーが上手く機能してくれているおかげです。

ドキュメントによれば

  1. タスクの停止
  2. アップデート
  3. タスクの再開
  4. タスクの開始が確認できるのであれば、少し時間を置いたのち、次のコンテナに対しこの一連の流れをおこなう

という流れでアップデート作業をしているようです。

この挙動(rolling update)であるなら、一定の時間はバージョンの混同が発生すると思いますので、
その点は留意が必要です。

10. service update を戻す

「あ、やべ、バージョンアップしたら挙動おかしくなったわ」という場合に1世代前に戻すことが出来ます。 docker service rollback です。

docker@manager1:~$ docker service rollback nginx_sample

nginx_sample
rollback: manually requested rollback
overall progress: rolling back update: 7 out of 7 tasks
1/7: running   [>                                                  ]
2/7: running   [>                                                  ]
3/7: running   [>                                                  ]
4/7: running   [>                                                  ]
5/7: running   [>                                                  ]
6/7: running   [>                                                  ]
7/7: running   [>                                                  ]
verify: Service converged

11. 使うポート番号を変えたい場合

8080 を指定していましたが、「やっぱり普通に 80 番ポートを使うようにしようかな〜」というときも docker service update で対応可能です。
publish-add オプションや publish-rm オプションを使います。

docker@manager1:~$ docker service update --publish-rm 8080:80 --publish-add 80:80 nginx_sample

nginx_sample
overall progress: 7 out of 7 tasks
1/7: running   [==================================================>]
2/7: running   [==================================================>]
3/7: running   [==================================================>]
4/7: running   [==================================================>]
5/7: running   [==================================================>]
6/7: running   [==================================================>]
7/7: running   [==================================================>]
verify: Service converged

すべてが running になった段階で
8080 番ポートへのアクセスはできなくなり、80 番ポートへのアクセスができるようになります。

192.168.99.100:8080 でなく、 192.168.99.100 (もしくは 192.168.99.100:80 )でアクセスできるようになっていることでしょう。

12. service を終了させる

ひととおり実験したので service を終了させます。 docker service rm でおこなえます。

docker@manager1:~$ docker service rm nginx_sample

nginx_sample

びっくりするほど一瞬で終わり、もう 192.168.99.100 などにはアクセスできなくなっています。

ついでに、VirtualBox を3台動かし続けているのもメモリの無駄遣いなので、
manager1 からログアウトしたら、以下のコマンドで仮想マシンを停止させちゃいましょう。

docker-machine stop manager1 worker1 worker2

Stopping "worker2"...
Stopping "worker1"...
Stopping "manager1"...
Machine "worker2" was stopped.
Machine "worker1" was stopped.
Machine "manager1" was stopped.

スッキリですね。

13. Docker Swarm vs. Kubernetes

Docker Swarm が非常に手軽に、死活監視および自動再起動や、無停止更新をおこなってくれることを確認しました。

では、 Kubernetes より優れているのでしょうか?

Docker Swarm を推す記事もあれば、
Kubernetes を推す記事もあります。

Kubernetes は Docker で正式サポートされ
AWSでも EKS こと Amazon Elastic Container Service for Kubernetes が登場したくらいですから、
Kubernetes がますますデファクトスタンダードになっていくでしょう。
ですので、業務で使うなら、長い目で考えて Kubernetes の方が良さそうです。

一方、特に新たな設定も必要なく、dockerコマンドだけで全てを終わらせることが出来る Docker Swarm は直感的でわかりやすく学習コストが大変少なく魅力的です。
個人プロジェクトなどでDocker管理をおこなう場合には、十分に選択肢のひとつとなり得るかと思います。

詳細な比較は「Docker Swarm vs. Kubernetes」で検索するとたくさん見つかるかと思います。
だいたいどれも、「簡単だけどカスタマイズ性の低いDocker Swarm、学習曲線が急だがカスタマイズ性が高く多機能なKubernetesという結論に落ち着いています。