Pages - Menu

Pages - Menu

Pages

医療用麻酔ロボット、医者の職を奪うとして市場から追い出される。メーカーは3000人規模のリストラへ

ジョンソン・エンド・ジョンソン(J&J)が、自動的に患者に麻酔を投与可能なロボット Sedasys の製造販売を終了すると発表しました。理由は売上不振。

Sedasys は麻酔科医にくらべ1/10のコストで患者への麻酔薬投与ができましたが、それは麻酔科医の仕事を奪うことでもありました。

J&J が開発した Sedasys は手術や検査の現場において麻酔科医の代わりに麻酔薬プロポフォールを投与するためのロボット。患者の状態を常に監視しつつ適切な量を投与するアルゴリズムを搭載していました。

Sedasys の大きなメリットはその運用コストの低さ。米国では1度の手技で麻酔科医に支払われるコストが約2000ドルとされるのに対し、Sedasys を使えば150~200ドルで済みます。このため医師不足を補い、病院や診療所の経営の助けとなることが期待されていました。
病院経営者や患者からすれば Sedasys は非常に魅力的な麻酔ロボットである一方、米麻酔医学会などは「Sedasys が誤って使われたときに患者を危険にさらす恐れがある」、「万が一のため麻酔科医がその場にいる必要がある」などと主張。Sedasys は大腸内視鏡検査や食道胃十二指腸内視鏡検査にその用途が限られてしまいました。

麻酔科医からの反対は、いわば Sedasys が彼らの職を奪いかねないという懸念が強く働いたとも考えられます。結果として Sedasys を導入する病院はほとんどありませんでした。

Sedasys だけが原因ではないものの、現在 J&J は売上の低迷により3000人規模のリストラを計画中と伝えられます。職を奪われるのが人の役に立つと思ってロボットを開発した側だというのはなんとも皮肉な話というほかありません。

2016年3月30日水曜日

小規模開発には git-flow よりも GitHub Flow で捗る

引用元:
http://tech.tmd45.jp/entry/2012/10/18/210941

git GitHub Flow github ワークフロー ソフトウェア開発
これまで CVS や Subversion ではなかなか敷居の高かった「ブランチを切って作業する」というワークフローが、分散型バージョン管理、とくに Git の登場でとても手軽に取り入れやすくなりました。
Git のブランチを活用するためのワークフローとして有名なものに git-flow と呼ばれているモデルがあります。正しい名称は「A successful Git branching model」で、git-flow はこのモデルの導入を補助してくれる Git 拡張の名称だそうです。
git-flow の解説~導入までは以下の記事に詳しく書かれています。
これはあくまで ”モデル” なので、自分(あるいは会社)で利用するときには、このモデルの中から必要な部分を上手く抽出して使えばよいのですが、それでも小規模開発や個人開発にはちょっと大仰な感じがして、とっつきにくい人もいるかと思います。
でも Git を使っているのにブランチを利用しないのはとても勿体ないですし、近年の GitHub などによるオープンな共同開発において、ある程度共通のブランチモデルを利用していると格段に作業がしやすくなります。

そこで、とても分かりやすく、個人でも共同開発でも導入しやすい最初のワークフローとして GitHub Flow をオススメしたいと思います。GitHub Flow とは、その名前のとおり GitHub Inc. が github.com の開発時にも利用しているワークフローです。
"Pro Git" という有名な Git 書籍の著者である Scott Chacon 氏が自身のサイトに掲載した詳しい説明があります。
そしてなんと素晴らしいことに、この文章を Gist 上で翻訳してくださった方々がいるのです!素敵すぎる!!
英語をスラスラ読むことのできない自分には本当に助かります。この Gist の URL を Twitter で知ったのですが、これを読んでから「ブランチを切って作業すること」がとても身近になりました。「難しくないんだ、とりあえずやってみよう」って思えるレベルのワークフローなのです。

まずはぜひ一度、上の翻訳を読んでいただきたいのですが、概要を抜粋します。
GitHub Flowとは何だろうか?

  • masterブランチのものは何であれデプロイ可能である
  • 新しい何かに取り組む際は、説明的な名前のブランチをmasterから作成する(例: new-oauth2-scopes)
  • 作成したブランチにローカルでコミットし、サーバー上の同じ名前のブランチにも定期的に作業内容をpushする
  • フィードバックや助言が欲しい時、ブランチをマージしてもよいと思ったときは、プルリクエストを作成する
  • 他の誰かがレビューをして機能にOKを出してくれたら、あなたはコードをmasterへマージすることができる
  • マージをしてmasterへpushしたら、直ちにデプロイをする

これがフローのすべてだ。とてもシンプルかつ効率的で、かなり大きなチームでも機能する。
GitHub Flow (Japanese translation) — Gist

プルリクエストを利用したレビュなどは、これが GitHub 上で実現されることを想定されているフローだからです。実際、プルリクエストを利用したレビュもとても有用な手法だと思います。
ただここで1番にオススメしたいのは、git-flow よりもはるかにお手軽な「ブランチのルール」です。

https://img.skitch.com/20110831-x5nyqid885aqnp7t2au5ckw929.png

master ブランチを(まさに)マスターとして、それ以外は作業ごとにブランチを切る。それだけです。
この方法の素晴らしいところは、私のようなぼっちプログラマーでも手軽に始められるということに尽きます。難しいことを一切考えず「作業を始めるときにブランチを作る」、とにかくそれだけです。
仕事で導入するなら、プルリクエストによるレビュや、master ブランチの自動デプロイなども参考になります。まずは GitHub Flow なやり方から始めてみて、慣れてきたら git-flow のエッセンスを取り入れるという方法、いかがでしょうか。

Git のブランチを使うために git-flow に目を通したものの「ちょっと胃もたれしちゃう・・・」という人やその他のもっともっと多くの開発者に GitHub Flow を知ってもらって、素敵な ブランチ ライフ を送っていただきたいと思います!

('ω`)

プログラマーが勉強用に、検索でサンプルソースコードのリソースを無料で手に入れる方法!

Pythonのサンプルソースコードを検索して手に入れるには!
https://github.com/
github の検索エリアに
tetris language:Python
をいれます。
結果の中から、スターの数、fork の数が多いものから見ていくと良いです。
だそうです。

github の検索窓には、
tetris意外にも、webserviceとしてみたり、Pythonを他の言語にして見たりして、色々とお試し下さい。

本物そっくりの偽物「MacBook充電器」の危険な内部はこうなっている





見た目はそっくりでも中身はまったく別物ということは多いもので、ハードウェアを充電するACアダプターもデザイン・性能・価格は千差万別です。高価なApple純正品と見た目だけそっくりな粗悪品(偽物)がどれほど違うのか、AppleのACアダプターをはじめとしてさまざまな電子機器を分解しまくってきた分解マニアが比較検証したところ、「安全はお金で買うべき」という結論に達しています。 

Counterfeit Macbook charger teardown: convincing outside but dangerous inside 
http://www.righto.com/2016/03/counterfeit-macbook-charger-teardown.html 

Apple純正品とそっくりな偽物のMacBook用ACアダプターを分解するのは分解マニアのケン・シリフさん。シリフさんがMacBook用の本物のACアダプターを分解したレポートは、以下の記事で確認できます。 

MacBookのApple純正ACアダプターの構造はどうなっているのか分解して確認 - GIGAZINE


シリフさんがハードウェアの分解レポートを掲載するブログ「Ken Shirriff's blog」の読者から、「偽物をつかまされたかもしれない」というメールとともに送られてきたMacBook用ACアダプターが下の画像です。側面部分にはそれらしい表記があり、フォントの美しさやアイコンの精密さはApple製品と見分けが付かないほど。 


エンボス加工されたAppleのリンゴマークもあり、側面の表記もなんとなく本物っぽいACアダプターですが、持ってみると疑わしいほどに軽いとのこと。また、金属パーツ横のシリアルナンバーが書かれたシールが微妙に傾いている点がAppleデザインじゃないのではないか、とシリフさんの疑念を倍増させています。 


そして、パーツの継ぎ目の非対称な隙間を見て「これはApple製品ではない」という疑いはますます濃厚に。さらに、コンセントをつないでMagsafeコネクターの電力を測定しようとした際にわずかに火花が飛んだことをシリフさんは見逃しませんでした。本物のApple純正品は3Vから6Vの低圧から充電を開始して、対応デバイスであることを確認してから電圧値を上げるそうで、いきなり14.75Vの高電圧で充電を開始するこのACアダプターは偽物だとシリフさんは確信しています。 


偽物だと確信したので遠慮なく分解。片側のケースを取り外すとこんな感じ。 


「偽物の中身は単純なフライバックスイッチング電源だ」とシリフさん。 


回路もフライバック電源のものとしては標準的。メガネケーブルから入力された電流は、フューズの横のブリッジ整流器で直流に変換され、フィルターコンデンサで平滑化されます。なお、画像右下の金属パーツ(グラウンドピン)は、ただの飾りであることも判明しています。 


基板の制御ICには「63G01 415」の文字があり「OB2263」というチップと判明。 


左が偽物の基板で右がApple純正品の基板。回路の細かさやチップやコンデンサーの集積密度などの違いは一目瞭然。 


偽物のACアダプターはお金のかかっていない簡素な作りですが、安全性に大きな問題があるとシリフさんは指摘しています。画像の下の部分が1次の高電圧側、上の部分が2次の低圧側ですが、左部分の回路があまりに接近しているため、はんだが落ちたり水分がついたりすることで結線されればたちまちショートして火が出る危険があるそうです。シリフさんは、「スペースにゆとりがないわけでもないのに、なぜこんなに複雑な回路形状にしてわざわざ危険性を高めているのか理解できない」と述べています。 


オシロスコープで電力を測定すると、スイッチングトランジスタのON/OFFで大きな スパイクが発生しており、予想通り劣悪な充電品質であることも確認されたそうです。 


一見、Apple純正品に見える偽物のACアダプターは充電品質が悪い以前に使用時に火災が発生する危険性があることが確認されました。純正品に比べてはるかに安い粗悪品ですがACアダプターとしての質の違いは明らかだとシリフさんは述べています。 

精子・卵子形成の為の減数分裂を開始させる仕組みを発見 埼玉医大


2016年3月30日
埼玉医大ロゴ(非公認)タテ.jpg
[概要]
 埼玉医科大学ゲノム医学研究センターの奥田晶彦教授・鈴木 歩助教らは、Maxタンパク質の消失が減数分裂を惹起することを明らかにしました。
 生殖細胞、特に生殖幹細胞は体細胞分裂により増殖し、かつ、必要に応じて精子・卵子を産生する為に体細胞分裂を止め減数分裂を始めますが、この生殖細胞における体細胞分裂からの減数分裂への切り替えの機構に関してはほとんどわかっていません。
 本発表では、この2種類の細胞分裂の切り替えにMaxタンパク質が関与していることを明らかにしました。この発見は、体細胞分裂から減数分裂への移行の仕組みの全容解明を促進し、かつ、そのことが精子・卵子形成不全という病態の理解や、精巣腫瘍などの生殖器系の腫瘍の原因の解明へと発展することが期待されます。

[研究の背景と経緯]
 精子幹細胞は京都大学教授篠原隆司博士が開発した生殖幹細胞ですが、自己増殖性はもちろんのこと、精細管内に移植すると生涯に渡って成熟した精子の供給源として機能することができます。しかしながら、精子幹細胞が最終的に精子に変換するまでの過程で呈する様々な変化が、どういった原理・原則に従って起こっているかという点に関してはほとんどわかっていません。
 特に、精子幹細胞が通常の幹細胞や体細胞と同様に細胞増殖の為に体細胞分裂を行っている状態から、精子形成の開始の為に体細胞分裂を止め減数分裂(注1)を始める仕組みに関しては全くといっていいほど何もわかっていません。
こういった状況の中で奥田らは、図1のモデル図にあるように精子幹細胞が幹細胞としての性質を維持している状態では、Maxタンパク質がその幹細胞において、減数分裂を起こさないにようにしていることを見出しました。すなわち奥田らは、精子幹細胞においてMaxタンパク質の量を減らすと、減数分裂が惹起されることを示しました。なお、このモデル図にあるようにMaxタンパク質はもともと細胞増殖促進に関わるc-Myc転写因子が機能する為に必須なパートナー因子として同定されたタンパク質であり、篠原隆司博士らの研究から、このc-Myc/Max転写複合体は精子幹細胞においてもこの幹細胞が幹細胞として自己増殖する為に重要な働きをしていることが証明されています。
 従って、精子幹細胞においてMaxタンパク質の量が低下することには2つの意味があることになります。その一つは、今回の発表で示されているように精子形成の為に減数分裂を誘導することであり、2つ目のMaxタンパク質の量の低下の生物学的な意味は、c-Mycの細胞増殖促進活性の減弱に伴って幹細胞状態が破綻することであります。なお、幹細胞状態は、精子形成という細胞分化と相反することなので、Max遺伝子の発現の低下に伴った精子幹細胞の幹細胞状態の破綻は、間接的に精子形成の促進に繋がっていると考えられます。

注1)減数分裂
 減数分裂は真核生物の細胞分裂の様式の一つである。精子もしくは卵子が形成される過程で起こる細胞分裂で、通常の体細胞分裂(有糸分裂とも呼ばれる)とは違って、2回連続して起こる細胞分裂のうちの2回目の分裂ではDNAの複製が行われない。それ故、精子・卵子に代表される減数分裂を終えた細胞は通常の細胞と比べ半分の数の染色体しか持たない。この減数分裂により精子、卵子の染色体の数が半減させることは、精子と卵子が融合して通常の数の染色体を持つ受精卵を作る上で必然的なことである。


[研究の内容]
 奥田らの今回の論文の成果は、奥田らが長年行ってきたES細胞におけるc-Mycの機能解析の過程で偶然得られた結果でした。事実、奥田らが今回の研究成果を得る上で用いたMaxホモ欠失ES細胞は、もともとES細胞におけるc-Myc活性の重要性を確認することを目的に樹立したものでした。
 しかしながら、奥田らはMaxホモ欠失ES細胞で生殖関連遺伝子の発現が顕著に上昇していることを発見しました(図2)。そして、この現象は、Maxホモ欠失ES細胞と同様にMyc活性を持たないc-Myc/N-Mycダブルホモ欠失ES細胞では全く認められていないこととは、極めて対照的なデータでした。また奥田らは、Maxホモ欠失ES細胞では生殖関連遺伝子の発現が上昇しているといっても、Blimp1遺伝子など始原生殖細胞で重要な働きをしている遺伝子の発現に関してはほとんど上昇しておらず、Stra8やDazl等、減数分裂関連の遺伝子に限定的に発現の上昇が見られることに気付きました(図2)。
 それ故、奥田らは、Maxホモ欠失ES細胞において異所性に減数分裂が開始しているのではないかと考え、減数分裂の初期に特徴的な染色体構造であるシナプトネマ複合体の主要な構成要素であるSycp3タンパク質に対する抗体を用いた免疫染色を行いました。その結果、生殖細胞からのものと区別できないほどの減数分裂の初期と思われる染色像が得られました(図3)。
 但し、Maxホモ欠失ES細胞が減数分裂様の細胞生物学的変化を示すといってもそれだけではその発見の生理的な意義がわからないので、まず、奥田らは、生体の中の生殖細胞における生理的な減数分裂の過程でMaxの発現が低下しているか否かを検討しました。その結果、一般的に恒常的な発現をする遺伝子として知られているMax遺伝子の発現が、雌の減数分裂の場である生殖隆起の中の始原生殖細胞において顕著に低下していることを見出しました(図4)。
同様に、雄の減数分裂の場である精巣においても減数分裂に先立ってMax遺伝子の発現が低下することも確認しました(data not shown)。かつ、冒頭に触れたように、精子幹細胞におけるMax遺伝子の強制的な低下によっても減数分裂様の変化が誘導されることを証明しました(図5)。
 また、メカニズム的な解析結果としては、Maxによる減数分裂の抑制は6種類のサブタイプが知られているポリコーム抑制複合体PRC1の中の最も非典型的な複合体であると言われているPRC1.6の機能を反映していることを証明しました(図1)。なお、6種類のPRC1複合体では、PRC1.6のみにMaxタンパク質がサブユニットの一つとして含まれています。


[今後の展開]
 今回の奥田らによる研究成果は、今までほとんどわかっていなかった生殖細胞の体細胞分裂から減数分裂への移行を決定する分子基盤の完全な解明へと発展していくと考えられます。そして、この減数分裂誘導機構におけるブレークスルーは、無精子症など、精子もしくは卵子形成に異常を持つヒトの病気の原因の解明へとつながると考えられます。かつ、生殖細胞の体細胞分裂から減数分裂への移行の欠陥と生殖器腫瘍の発生との因果関係について、解明される可能性が考えられます。
 さらには、奥田らの、生殖細胞のみならずES細胞も減数分裂を開始できる潜在能力を有するという発見は、極めて早い時期に発生が破綻(流産)するケースの中には着床前の発生初期の胚における異所性の減数分裂の誘導が流産の原因である場合があることを示唆します。


この研究成果は(2016年3月30日に英国雑誌Nature Communications オンライン版(http://www.nature.com/ncomms/index.html)にて掲載されました。本論文の解禁日時は日本時間で3月30日18:00です。なお、本論文のタイトル及びその日本語訳は以下の通りです。
「Loss of MAX results in meiotic entry in mouse embryonic and germline stem cells」
(日本語訳)Max遺伝子発現の消失はES細胞及び生殖幹細胞において減数分裂を惹起させる

また本研究は、主に私立大学研究基盤形成支援事業(文部科学省)、及び新学術領域(生殖細胞、領域代表:篠原隆司)(文部科学省)の支援を得て行われました。

[発表者]
奥田晶彦(埼玉医科大学ゲノム医学研究センター 教授)
鈴木 歩 (埼玉医科大学ゲノム医学研究センター 助教)

カテゴリ:
技術/研究・開発 医学/医薬/看護 全国

イモリの肢再生のしくみは変態によって切り替わる ~250年来の謎に迫る発見~


2016/03/30
筑波大学生命環境系 千葉親文准教授と大学院生田中響(生命環境科学研究科博士後期課程2年)は、筑波大学生命環境系 丸尾文昭助教、Martin Miguel Casco-Robles外国人特別研究員(JSPS)、および米国デイトン大学生物学部Panagiotis A. Tsonis教授らと共同で、イモリは幼生期と成体に変態した後では肢再生のメカニズムを切り替えていることを発見しました。これは250年近く明らかにされて来なかったイモリの卓越した再生能力の謎に迫る成果です。
160330-1
図 イモリは変態して成長すると、肢再生のメカニズムを、幹細胞システム(幼生モード)から、分化した細胞を利用する脱分化システム(成体モード)に切り替える。再生肢中の筋に着目すると、幼生期には衛星細胞のような筋に内在する筋幹細胞/前駆細胞を用いて新たな筋をつくるが、変態すると、分化した筋線維(収縮する多核の骨格筋細胞)を単核の細胞に脱分化し、これを材料にして新たな筋をつくる。

PDF資料

Dockerを使って1サーバで複数Webサービスを運用するためのマイベストプラクティス

はじめに

エンジニアやっていると色んなサービスを作りたくなると思うのですが、Herokuのフリープランが使えなくなってしまった影響で無料でのサービス運営は難しくなってきています。
もちろん、Google App Engineなど無料で運用できるものもあるのですが、サービスにロックインされてしまうのが多くちょうど良い物が見つかりませんでした。
ということである程度安く色々やろうとすると、1台のサーバでいい感じに複数サービスを立ち上げるという昔ながらの構成になるのですが、Dockerを使うことで環境セットアップなどサーバ管理の手間を最小限にしていこう、というのがこの記事の趣旨となります。

方針

要件
  • 安い
  • サービスにロックインされない
  • スケーラブル(もしサービスのアクセス量が増えたとしてスケールさせられる)
  • インフラ管理が容易
    • セキュリティとかなるべく気にしたくない
以上のことを踏まえた結果ConoHaのVPSを使う構成となりました。費用としては、
  • ドメイン1つ(4000円/year)
  • サーバ1台(900円/month)
  • RDB1台(500円/month)
  • S3 (数十円/month)
という構成で月2000円以下に抑えられています。

検討したこと

PaaSとか考えたのですが結局VPSが一番安いよねという話。

検討1 自宅サーバ

データ消えないような仕組みづくりとかそういうところに時間を使う時代じゃなくなってきてるので自分の中ではこれは無いかな。

検討2 PaaS

HerokuはFreeプランでできることが少なくなったので他のサービスを探しましたが、複数サービスを無料に近い金額でできるのがありませんでした。OpenShiftとかは複数アカウント作ればできるんだろうけどその管理がめんどくさい。調べた時は見つけられなかったけどIBM Bluemixは無料枠多いのでもしかしたら結構良いかもしれない。

検討3 AWS、GCPなど

価格が高いということでやめました。
特にDBサーバの管理をしたくないのでマネージド型のRDBが欲しかったのですが、コストが大分高くなってしまう感じでした。NoSQL系は安いのですが使いたくなかったのがあります。
#ちなみにAmazonとGoogleは調べたのですが他は調べてないのでもっと良いのがあるかも

検討4 VPSを使う

結局安く運用するならVPSだなという結論に。マネージド型のRDBサービスについては、ConoHaクラウドがDBサーバを500円という格安料金で提供していて、LBなども追加できるIaaS的なサービスでちょうど自分の要望を満たすことができたのでこちらにしました。DBがMariaDBだったりおそらく多くのユーザで共有しているのでパフォーマンスが期待できないなどの問題が気にならなければこれで良さそう。
自分の中ではDBサービスのあるVPSが無かったらたぶんAWS上でEC2+RDSの構成にしていたと思いますが(そのくらいDBの管理をしたくない)、自分でDBサーバを立てるのであればどこのVPSでも良いと思います。

構成

ということでこんな構成になりました。サーバの構成管理は1ファイルで完結します。Dockerのイメージ作成もDockerfileとnginx,supervisordの設定ファイルのみで簡単にできるようになっていて、必要な管理はそれだけなのが特徴です。
構成図.png
順に構成要素を説明していきます。

CoreOS

Dockerだけあれば良いのでCoreOSにしました。CoreOSの本質は分散システムを容易に構築できるところだと思うのですが、今回は
  • 必要十分な機能をもつOS
  • コンポーネントが少なくセキュリティリスクが少ない
  • 自動アップデートの仕組み
  • 構成を cloud-config.yml の1ファイルで管理できる
という点でこれしかないなと思って選びました。
特に cloud-config.yml でサービスの立ち上げなどが管理できるため、その1ファイルだけ Dropbox にいれておけばファイルの管理としては十分で、プライベートリポジトリも必要とせずに構成の管理ができてしまうのが個人的には気に入りました。

サービスのDockerイメージ

Dockerの考え方的にはおそらくアプリケーションサーバとnginxは別コンテナにするべきなのですが、nginxとrailsを別コンテナで管理するコストが高いのでシンプルさという点で避けることにしました。
そのため supervisord で nginx と rails を立ち上げるような構成にしています。
docker-composeを使うということも考えましたがCoreOSに入っていないのと、あくまでDevelopment向けに開発されているものなので使っていません。
Rails上のsecretやDB接続先はDocker実行時の環境変数として入れることで環境に依存しないイメージを作成するようにしています。

nginx-proxy

複数のサービスはそれぞれのコンテナで動いているので、各リクエストを振り分けるリバースプロキシが必要です。
通常だとnginxやapacheの設定でVirtual hostやディレクトリ毎の振り分け先を書いて、みたいなことをするわけですが、nginx-proxyを使うと立ち上がっているDockerコンテナに自動的に振り分けを行うことができます。
これによりサービスの投入が非常に楽になります。

docker-letsencrypt-nginx-proxy-companion

SSLが使えないサービスは今時ありえないので、それへの対応です。
Let's Encryptは最近注目の無料でSSL証明書を発行できるサービスです。Facebookを始めとした名高い企業がスポンサーとなっています。
このコンテナを動かすだけで自動でSSL証明書の発行・更新を行ってくれます。

New Relic

サーバ監視は最低限あったほうが良いと思うのでNew Relicを入れています。これもコンテナを動かすだけなので管理コストは少ないです。

Docker Registry

Dockerのイメージはパブリック領域ならDocker Hubを使えば良いのですが、いくら個人のクソサービスとはいえ全部が全部公開できるものではないと思います。しかしDocker Hubのプライベートリポジトリはお金がかかるので小さいサービスを量産していく形だと非常にお金がかかってしまいます。そのため別途 Docker Registry を立てることにしました。
ただ、外部からアクセスできる Docker Registry を立てるにはベーシック認証を入れたりSSL証明書を導入したりの手間が必要で(調べるのが)めんどくさかったので、S3のストレージを共有してPushはローカルのマシンで立ち上げたDocker Registryから、PullはVPS上で立ち上げたDocker Registryから、という構成にしています。
この構成は正直あまりイケてないので今後直したいです。CircleCIから自動でPushするとかもできないですし。ちなみにAWSやGCPにすると、各サービスが提供しているDocker Registryが使えるのでこんなコンポーネントは要らなくなります。とはいえConoHaだと1500円で済むサーバ構成がRDSだけで2000円を超えてしまうので、そのコストとDocker Registryを自前で立てる複雑さのどちらが良いかという選択でした。

環境セットアップ手順

以上を踏まえて環境セットアップ手順です。

1. CoreOSのインストール

VPSにCoreOSをインストールします。
ConoHaのサーバにインストールした時のメモがこちら。
http://qiita.com/miyasakura_/items/4d81dc5fe6f9de0f0dd5
基本となる cloud-config.yml は次のような感じです。
設定箇所としては
  • nginx-proxy と letsencrypt-nginx-proxy-companion の証明書のディレクトリパス
  • newrelic の NEW_RELIC_LICENSE_KEY
  • s3のAPIのアクセスキーやバケットの情報
があります。NewRelicとS3のアクセス情報はあらかじめ準備しておいてください。
cloud-config.yml
#cloud-config

ssh_authorized_keys:
  - ssh-rsa AAAAB3Nza...(sshする時の公開鍵)

coreos:
  update:
    reboot-strategy: best-effort
  units:
    - name: docker.service
      command: start

    - name: timezone.service
      command: start
      content: |
        [Unit]
        Description=timezone
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=/usr/bin/ln -sf ../usr/share/zoneinfo/Japan /etc/localtime

    - name: nginx-proxy.service
      content: |
        [Unit]
        Description=nginx-proxy

        [Service]
        Type=simple
        Restart=always
        ExecStartPre=-/usr/bin/docker stop nginx-proxy
        ExecStart=/usr/bin/docker run \
                    --rm \
                    --name="nginx-proxy" \
                    -p 80:80 \
                    -p 443:443 \
                    -v /home/core/certs:/etc/nginx/certs:ro \
                    -v /etc/nginx/vhost.d \
                    -v /usr/share/nginx/html \
                    -v /var/run/docker.sock:/tmp/docker.sock \
                    jwilder/nginx-proxy
        ExecStop=/usr/bin/docker stop nginx-proxy

        [Install]
        WantedBy=multi-user.target

    - name: letsencrypt.service
      content: |
        [Unit]
        Description=letsencrypt
        Requires=nginx-proxy.service
        After=nginx-proxy.service

        [Service]
        Type=simple
        Restart=always
        ExecStartPre=-/usr/bin/docker stop letsencrypt
        ExecStart=/usr/bin/docker run \
                    --rm \
                    --name="letsencrypt" \
                    -v /home/core/certs:/etc/nginx/certs:rw \
                    --volumes-from nginx-proxy \
                    -v /var/run/docker.sock:/var/run/docker.sock:ro \
                    jrcs/letsencrypt-nginx-proxy-companion
        ExecStop=/usr/bin/docker stop letsencrypt

        [Install]
        WantedBy=multi-user.target

    - name: newrelic.service
      command: start
      content: |
        [Unit]
        Description=newrelic
        Requires=docker.service
        After=docker.service

        [Service]
        Restart=always
        RestartSec=300
        TimeoutStartSec=10m
        ExecStartPre=-/usr/bin/docker stop newrelic
        ExecStartPre=-/usr/bin/docker rm -f newrelic
        ExecStartPre=-/usr/bin/docker pull uzyexe/newrelic:latest
        ExecStart=/usr/bin/docker run \
                    --rm \
                    --name="newrelic" \
                    --memory="64m" \
                    --memory-swap="-1" \
                    --net="host" \
                    --pid="host" \
                    --env="NEW_RELIC_LICENSE_KEY=ライセンスキー" \
                    --volume="/var/run/docker.sock:/var/run/docker.sock:ro" \
                    --volume="/sys/fs/cgroup/:/sys/fs/cgroup:ro" \
                    --volume="/dev:/dev" \
                    uzyexe/newrelic
        ExecStop=/usr/bin/docker stop newrelic

        [Install]
        WantedBy=multi-user.target

    - name: docker-registry.service
      command: start
      content: |
        [Unit]
        Description=docker registry
        Requires=docker.service
        After=docker.service

        [Service]
        Restart=always
        RestartSec=300
        TimeoutStartSec=10m
        ExecStart=/usr/bin/docker run \
                    --rm \
                    --name="docker-registry-service" \
                    -p 5000:5000 \
                    -e REGISTRY_STORAGE_S3_ACCESSKEY=アクセスキー \
                    -e REGISTRY_STORAGE_S3_SECRETKEY=シークレット \
                    -e REGISTRY_STORAGE_S3_BUCKET=バケット \
                    -e REGISTRY_STORAGE_S3_REGION=ap-northeast-1 \
                    -e REGISTRY_STORAGE_S3_ROOTDIRECTORY=/v2 \
                    -e REGISTRY_STORAGE=s3 \
                    registry:2.0
        ExecStop=/usr/bin/docker stop docker-registry-service

        [Install]
        WantedBy=multi-user.target


インストールが終わったら下記コマンドで各サービスが running になっていることを確認します。
systemctl list-units --type=service 

2. Dockerのベースイメージ作成

新しいアプリをインストールするたびに nginx や ruby をインストールするのは大変なのでベースイメージを作っておきます。
Dockerはローカルマシンにインストールしておいてください。
今回はRails+nginxの構成を想定しているので下記のような Dockerfile を準備。このDockerfileはnginxをaptで入れるなどの楽をしているので、古いバージョンのnginxが入ってしまう点は改善の余地ありです。
FROM ruby:2.3.0

RUN apt-get update
RUN apt-get install -y nodejs nginx supervisor
RUN apt-get install -y libssl-dev

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
        && ln -sf /dev/stderr /var/log/nginx/error.log

RUN gem update --system

CMD ["bash", "-l", "-c"]
ビルドします
$ docker build --no-cache -t localhost:5000/base-image .
Docker Registryを立ち上げてPushします。
$ docker run -d \
      --name="docker-registry" \
      -p 5000:5000 \
      -e REGISTRY_STORAGE_S3_ACCESSKEY= \
      -e REGISTRY_STORAGE_S3_SECRETKEY= \
      -e REGISTRY_STORAGE_S3_BUCKET= \
      -e REGISTRY_STORAGE_S3_REGION=ap-northeast-1 \
      -e REGISTRY_STORAGE_S3_ROOTDIRECTORY=/v2 \
      -e REGISTRY_STORAGE=s3 \
      registry:2.0
$ docker push localhost:5000/base-image
これでベースイメージの作成が完了です。

3. RailsアプリのDockerイメージ作成

複数サービスを立ち上げるのであればProcess式のものよりThread式のが良いかなと思ってなんとなくPumaにしています。
アプリ自体は普通に作るだけなのですが、Dockerを使うにあたっていくつかポイントがあります。

ログは標準出力に

Dockerでは基本標準出力にログを出すことで簡単にログを見ることができます。詳しくないのでもっと良い方法があったら教えて下さい。
config/environments/production.rb

...
config.logger = Logger.new(STDOUT)
...

DBなどの情報は環境変数を見るように

こんな感じにしてます。Productionだけでも良いわけですがそこは環境に応じて。
database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  reconnect: false
  pool: 5
  host:     <%= ENV['RAILS_DATABASE_HOST'] %>
  username: <%= ENV['RAILS_DATABASE_USER'] %>
  password: <%= ENV['RAILS_DATABASE_PASSWORD'] %>
  database: <%= ENV['RAILS_DATABASE'] %>

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

Dockerfileなどの設定

上記を踏まえてDockerfileとnginx.confとsupervisord.confが下記のような感じに。
Pumaもnginxの設定と合わせてセットアップが必要なのでうまいことやります。
FROM localhost:5000/base-image

ENV APP_HOME /webapp
WORKDIR $APP_HOME

ADD Gemfile* $APP_HOME/
RUN bundle install --without test development
RUN cat Gemfile.lock

ADD . $APP_HOME
RUN bundle exec rake assets:precompile

COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 80
CMD ["/usr/bin/supervisord"]
docker/nginx.conf
http {
  upstream puma {
    server unix:/webapp/tmp/sockets/puma.socket;
  }

  server {
    listen  80;

    location /assets {
      root /webapp/public;
    }

    location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
      proxy_redirect off;
      proxy_pass http://puma;
    }
  }

  error_log stderr;
  access_log /dev/stdout;
}

pid /var/run/nginx.pid;
worker_processes 2;
events {
    worker_connections  1024;
    # multi_accept on;
}
docker/supervisord.conf
[supervisord]
nodaemon=true

[program:nginx]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

[program:puma]
command=bundle exec puma -C config/puma.rb
directory=/webapp
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
config/puma.rb
# Start Puma with next command:
# RAILS_ENV=production bundle exec puma -C ./config/puma.rb

# uncomment and customize to run in non-root path
# note that config/puma.yml web path should also be changed
application_path = "#{File.expand_path("../..", __FILE__)}"

# The directory to operate out of.
#
# The default is the current directory.
#
directory application_path

# Set the environment in which the rack's app will run.
#
# The default is “development”.
#
environment 'production'

# Daemonize the server into the background. Highly suggest that
# this be combined with “pidfile” and “stdout_redirect”.
#
# The default is “false”.
#
daemonize false

# Store the pid of the server in the file at “path”.
#
pidfile "#{application_path}/tmp/pids/puma.pid"

# Use “path” as the file to store the server info state. This is
# used by “pumactl” to query and control the server.
#
state_path "#{application_path}/tmp/pids/puma.state"

# Redirect STDOUT and STDERR to files specified. The 3rd parameter
# (“append”) specifies whether the output is appended, the default is
# “false”.
#
# stdout_redirect "#{application_path}/log/puma.stdout.log", "#{application_path}/log/puma.stderr.log"
# stdout_redirect '/u/apps/lolcat/log/stdout', '/u/apps/lolcat/log/stderr', true

# Disable request logging.
#
# The default is “false”.
#
# quiet

# Configure “min” to be the minimum number of threads to use to answer
# requests and “max” the maximum.
#
# The default is “0, 16”.
#
# threads 0, 16

# Bind the server to “url”. “tcp://”, “unix://” and “ssl://” are the only
# accepted protocols.
#
# The default is “tcp://0.0.0.0:9292”.
#
# bind 'tcp://0.0.0.0:9292'
bind "unix://#{application_path}/tmp/sockets/puma.socket"

# Instead of “bind 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'” you
# can also use the “ssl_bind” option.
#
# ssl_bind '127.0.0.1', '9292', { key: path_to_key, cert: path_to_cert }

# Code to run before doing a restart. This code should
# close log files, database connections, etc.
#
# This can be called multiple times to add code each time.
#
# on_restart do
#   puts 'On restart...'
# end

# Command to use to restart puma. This should be just how to
# load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
# to puma, as those are the same as the original process.
#
# restart_command '/u/app/lolcat/bin/restart_puma'

# === Puma control rack application ===

# Start the puma control rack application on “url”. This application can
# be communicated with to control the main server. Additionally, you can
# provide an authentication token, so all requests to the control server
# will need to include that token as a query parameter. This allows for
# simple authentication.
#
# Check out https://github.com/puma/puma/blob/master/lib/puma/app/status.rb
# to see what the app has available.
#
# activate_control_app 'unix:///var/run/pumactl.sock'
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }



ビルドしてPushします。
$ docker build -t localhost:5000/hoge-project .
$ docker push localhost:5000/hoge-project //docker registryは立ち上げてある前提

4. サブドメインの設定

nginx-proxyはVIRTUAL HOSTでリバースプロキシを設定するのでお使いのネームサーバで今回のサービスに対するサブドメインを設定します。

5. CoreOS側でコンテナの立ち上げ

5.1 設定を cloud-config.yml に追記

書き方は systemd のヘルプを参照してください。
VIRTUAL_HOST は nginx-proxy のための設定、 LETSUENCRYPT_* はSSL証明書の発行のため、RAILS_*はrails用の環境変数なので環境に応じて設定してください。
cloud-config.yml
...
    - name: hoge.service
      content: |
        [Unit]
        Description=hoge
        Requires=docker-registry.service
        After=docker-registry.serivce

        [Service]
        Type=simple
        Restart=always
        ExecStartPre=-/usr/bin/docker stop hoge
        ExecStart=/usr/bin/docker run \
                    --rm \
                    --name="hoge" \
                    -e "VIRTUAL_HOST=hoge.mydomain.com" \
                    -e "LETSENCRYPT_HOST=hoge.mydomain.com" \
                    -e "LETSENCRYPT_EMAIL=hoge@mydomain.com" \
                    -e "TZ=Asia/Tokyo" \
                    -e "RAILS_ENV=production" \
                    -e "RAILS_DATABASE_USER=" \
                    -e "RAILS_DATABASE_PASSWORD=" \
                    -e "RAILS_DATABASE_HOST=" \
                    -e "RAILS_DATABASE=" \
                    -e "SECRET_KEY_BASE=" \
                    localhost:5000/hoge-project
        ExecStop=/usr/bin/docker stop hoge

        [Install]
        WantedBy=multi-user.target
...


5.2 cloud-config.ymlを読み込み

sudo coreos-cloudinit -from-file=cloud-config.yml
sudo cp cloud-config.yml /var/lib/coreos-install/user_data

5.3 サービスの起動

$ sudo systemctl start hoge.service
$ sudo systemctl status hoge.service
以上で、サービスインすることができます。
この状態で放置しておくと1時間に1回、SSLの証明書の更新が行われるのでhttpsでアクセスできるようになります。

更にサービスを追加する

上記3〜5を繰り返します

一定時間ごとに実行するサービスを作る

cron的なものも systemd で実現できるので cloud-config.yml に書きます。
oneshotのサービスを定義してtimerを作成します。
    - name: sample-job.service
      content: |
        [Unit]
        Description=sample-job
        Requires=docker-registry.service
        After=docker-registry.serivce
        [Service]
        Type=oneshot
        ExecStart=/usr/bin/docker run \
                    --rm \
                    -e "TZ=Asia/Tokyo" \
                    localhost:5000/sample-job
    - name: sample-job.timer
      command: start
      content: |
        [Unit]
        Description=Run sample-job
        [Timer]
        OnCalendar=*:*
確認はsystemctlを使う。
systemctl list-timers

スケール戦略

私の環境はまだスケールするような状況にはなってないですが、もしユーザ数が増えた時にそれに対応できるというのは重要ですよね。
今回Dockerコンテナはほぼ独立しているので、アクセスが増えてきたらサーバを増やして該当のサービスだけ切り出した cloud-config.yml を利用して簡単にセットアップできます。また、LBを追加して複数のサーバに負荷分散することも容易です。
それでもパフォーマンスが気になってきたら、AWSなどの他のクラウドに移すことを考えるとしてもDockerのイメージを持っていくことは大した作業にはならないと思います。基本的な汎用技術しか使っていないのでその時々に応じた最適な環境に持っていけるはずです。(DBのデータの移行は必要ですけどね!)

まとめ

以上、Dockerを使っての複数サービスを作る際のマイベストプラクティスでした。
一見複雑な気もしますが、サーバの状態は cloud-config.yml だけで定義されています。こういう使い方をすると cloud-config.yml が非常に縦長のファイルになってしまいますが、個人的には複数にわかれてるより管理しやすくて好きです。
各サービスの設定もほぼ定形の Dockerfile, nginx.conf, supervisord を置いておいて docker build をするだけなのでわかりやすいと思います。
実際の運用は
  • ローカルマシンでのビルド、プッシュ
  • CoreOS上でのcloud-config.ymlのアップデート
辺りは簡単なスクリプトにまとめています。
今回説明したものをなんとなくGitHubにまとめておきました。スクリプトの一部しか書かれてなくてよくわからない場合は参考にしてください。

おわりに

これを読んで、CoreOSじゃなくてもDockerとsystemdが入ってればいいじゃんとか、素直にAWS使えばいいじゃんとか色々意見はあると思いますし、私もこの環境での運用は長くはないので問題は色々出てくると思っています。ぜひみなさんが考えるベストなシステム構成を教えて下さい。
あなたもコメントしてみませんか :)
ユーザー登録(無料)
すでにアカウントを持っている方はログイン