コードを書くのは好きだけどインフラ弱いって人は、まずItamaeを触ってみるといいと思う

概要

はじめまして、17 新卒エンジニアの中嶋です。

イエウール のサーバサイドの開発を行っています。 コードを書くのは好きだけど、インフラ・ミドルウェア系は弱い感じのエンジニアです。

これまで趣味では、Heroku や Elastic Beanstalk でシュッとデプロイして済ましていたので、AWS、ネットワーク、ミドルウェアあたりの知識が皆無でした。

先日、イエウールのホスティング環境が、IDCFrontier から AWS へ移行しました。

tech.speee.jp

このようなインフラ移行に関わる機会は、そう多くあることではないので、これに便乗してインフラにちゃんと触れてみようと思いました。

そこで、少しでもインフラに近づくべく、社内で実績のあったプロビジョニングツール Itamae を使って、イエウールのサーバ構成の一部を、できる範囲でコード化しました。

結果、コードを書くのは好きだけど、インフラ・ミドルウェアが弱い感じの人は、Itamae から触るのがいいのでは、という結論に至りました。

インフラへの入り口に Itamae は最適

Itamae は、Ruby で書ける構成管理ツールです。 アプリケーションに必要なパッケージのインストール、設定ファイルの配置等を Ruby で記述し 用意されたコマンドを通して実行すると、サーバ構成を記述通りにバシッと作ってくれます。

Itamae はコード好きインフラ弱者にとって、二つの嬉しい部分があります。

  • インフラ道を邪魔しない単純さ
  • プログラマの特技が、サーバ構築の世界でも通用する

インフラ道を邪魔しない単純さ

Itamae は、シンプルなので低い学習コストで習得できます。 それゆえ、本当に大事な OS・ミドルウェアの仕様を知ることと、アプリケーションの開発に時間を費やすことができます。 実際、一時間ほどのペアプロで Itamae の大体の仕様を理解することができました。

nginx のセットアップを例にとり、Itamae のシンプルさを示します。 セットアップには以下の手順があります。

  • nginx をインストールし
  • nginx の設定ファイルを所定の場所に転送する
  • 設定に変更があれば、nginx を reload する(新しい設定を反映させる)

この手順を Itamae で記述すると

package 'nginx' # nginx をインストール

# ローカルの所定の場所にあるファイルを、リモートサーバに転送する。ただし、ファイルに変更がなければ実行しない
remote_file '/etc/nginx/conf.d/default.conf' do
  # ファイルの所有者、権限の設定
  owner 'root'
  group 'root'
  mode '644'

  # 変更があった場合は、設定を反映させる ($ service nginx reload)
  notifies :reload, 'service[nginx]'
end

このように、Ruby DSL でサーバ構成を記述できます。 Itamae では、サーバ構築に使うプログラムをレシピといい、 packageremote_file などの定義をリソースといいます。

リモートサーバにレシピを適用するには、以下のような Itamae コマンドを実行します。

$ itamae ssh -h xxx.jp -u username server.rb

これでレシピ通りのサーバ構成を、リモートサーバに構築することができます。

シェルスクリプトで構成管理は難しい

Itamae は、上のような単純な例であれば、Linux コマンドを一切書く必要がありません。 シェルスクリプトで書いたとしても、さほど複雑にならないと思います。

しかし、より複雑なことをしたり、以下を考慮した構成管理を一からシェルスクリプトで行うのは困難です。

  • 様々な OS やディストリビューションで動くような移植性
  • コマンドの冪等性

例えば、パッケージをインストールするコマンドは、yumapt-getbrew など OS やディストリビューションごとに、異なるコマンドです。同じ名前のコマンドでも仕様が異なる場合があります。構成管理を別の環境に移植するには、初めから移植性を意識して、構成管理を行う必要があります。

また、構成管理では、サーバの状態をなるべく壊さないようにするため、パッケージがインストール済みなら、インストールコマンドの実行を省略したり、設定ファイルに変更がなければ、サービスを再起動したりします。 このような、同じ操作を何度行っても結果が変わらない性質を冪等性と言います。 パッケージのインストールや、サービスの再起動など、副作用のあるコマンドは、冪等性を意識する必要があります。

シンプルに書ける Itamae の仕組み

Itamae には、移植性や冪等性をプログラマが意識しなくても良い仕組みがあります。そのうち移植性の部分は、 Specinfra がよしなに解決してくれます。 Specinfra は、コマンド実行フレームワークで、OS やディストリビューションのコマンドの違いや、コマンドの実行方法(ローカル上、SSH 経由など)を抽象化します。 Itamae のリソースは、Specinfra のラッパーコマンドを組み合わせて、冪等性を意識して実装されています。

Itamae はこうした仕組みによって、より大事な OS・ミドルウェアの設定方法を知ることや、アプリケーションの開発に時間を費やすことができます。

プログラマの特技が、サーバ構築の世界でも通用する

これは、Itamae に限った話ではないのですが、大事な部分なので書いておきます。 Itamae は Ruby プログラムで構成手順が書けるので、プログラマの特技をサーバ構築の世界に持ち込むことができます

プログラマの特技をサーバ構築の世界に持ち込むことで、以下のようなメリットがあります。

  • 自動化
    • 一度コード化しておけば、同じ環境を簡単にミスなく再現できる
  • DRY (Don’t Repeat Yourself)
    • いつも通りの Ruby で、変数やループを使って簡潔に構成手順を表現できる
  • バージョン管理
    • 構成手順がうまく動かなかったら、いつも通りの $ git revert
  • レビューができる
    • いつもの GitHub で、プルリクエストをレビューしてもらえる
  • コードがドキュメントだ
    • コードを見れば、構成手順がひと目で分かる
    • 先輩エンジニアが書いた構成を盗める

特に最後の項目は、イエウールのサーバ構成のコード化を通じて、いいなと思った部分です。 何がいいかというと、

  • コードは厳密に書く必要があるので、細かい手順が「暗黙の了解」として省かれることがない
  • Web サーバをちゃんと運用するなら、これはやっておけ的な設定を知ることができる

という点です。

サーバの構築には、細かい手順が多くあります。

  • ミドルウェアを動かすために設定を記述する
  • ディレクトリを用意してパーミッションを適切に設定する
  • 必要に応じて、ミドルウェアを再起動する

などです。入門サイトや口頭での説明では、こうした細かい手順が省かれることがあるので、躓くポイントになってしまいますが、構築手順がコードなら、細かい手順や設定を含め網羅的に知ることができます

構築手順をコードとして書いておけば、それ自体が生きたドキュメントになるので、作業メモとして自分の思考を整理してくれるし環境自動構築プログラムにもなります。ちょうど、仕様を示すため、自動テストのためにテストコードを書くようなものだと思っています。

以上は、Itamae に限らず Infrastructure as a Code 全般のメリットですが、 Itamae は簡単なので、これらのメリットをすぐに享受できると思います。

まとめ

  • インフラへの入り口に Itamae は最適
    • 学習コストが低いので、本当に大事な OS・ミドルウェアの仕様把握、アプリケーションの開発に時間を割ける
    • 自動化、バージョン管理などプログラマの領分が活かせる
    • コード自体が生きたドキュメントになるので、説明なら省かれるだろう細かい手順も把握できるし、作業メモとして自分の思考を整理できる
    • Ruby で書ける!

コードを書くのは好きだけどインフラ弱いって人は まず Itamae 触っとくといいと思うよ

参考リンク

不動産一括査定サイト「イエウール」のインフラをIDCFクラウドからAWSへ移行しました

Speeeエンジニアの id:takanamito です。
今年7月にSpeeeが運営する不動産一括査定サイト「イエウール」のインフラ移行をしました。

今回は移行に伴って見直したInfrastructure as Codeの話について書こうと思います。

f:id:takanamito:20170829172208p:plain

移行背景

イエウールは事業がスタートした当初よりIDCFクラウドを利用していました。
今回、以下のような背景から移行するに至りました。

  • AWSは社内で採用事例の多いクラウドサービスで知見が豊富なため、イエウールもそれにのっかりたい
  • 事業スタートから丸3年が経ち、不必要なサーバーがあったので一度構成を見直して整理したい
  • RDSやELBなどのマネージドサービスを活用して運用コストを減らしたい

以前から移行するモチベーション自体はあったのですが、工数不足で実行できていませんでした。
私がイエウールにjoinした5月のタイミングで、少しエンジニアの工数に余裕ができたので実行に移りました。

Infrastructure as Code化

以前のイエウールは

  • IDCFのWebコンソールから手動で用意したサーバー(22台)やネットワーク
  • 一部Itamae化されているものの、大半が手動で環境構築

このような状態で運用されていました。

サーバーの整理後も台数が10台を超えることや、純粋に「コードレビューしたい」というモチベーションから
今回の移行では CloudFormationとItamaeを活用し、完全なInfrastructure as Code化を目指しました。※一部例外あり。後述します。

またItamaeを採用するにあたって、mitamaeも候補にあったのですが
今回は、移行スケジュール的にmitamaeを検証する余裕があまりなかったこと、また対応pluginがItamaeの方が豊富なことから
mitamaeは使わずに、Itamaeを採用することにしました。

いざInfrastructure as Code化を進める中で迷ったのがItamaeの実行に関する以下のような問題です。

  • どのサーバーからItamaeを実行するのか
  • Railsのsecret_key_baseやDB接続のためのパスワードなどの秘匿情報をどうやって設置するか
  • Itamae初回実行前にレシピをどのように実行サーバーに設置するか

それぞれ解説していきます。

どのサーバーからItamaeを実行するのか

Itamaeの実行方式には
自分自身に対してレシピを適用する $ itamae local
リモートホストに対して適用する $ itamae sshの2つがあります。

本番環境で利用するサーバーに対して実行することを想定すると、Itamae実行ユーザーに対してできるだけ大きな権限を渡したくないです。

例えば $ itamae sshを利用する場合、Itamae実行対象であるリモートホストにssh可能なユーザーに対して任意のコマンドを実行可能なroot権限を渡すことになります。
対して $ itamae localを利用する場合、Itamae実行ユーザーに対してroot権限での $ itamae localコマンド実行を許可するだけで済みます。

# fuga-serverのitamae-userにsudo ALL権限(絞ることも出来るが現実的でない)を付与する必要がある
[hoge-server] $ itamae ssh -u itamae-user -h fuga-server recipe.rb

# この場合、fuga-serverのitamae-userには`itamae local`のsudo権限だけ付与しておけば良い
[hoge-server] $ ssh itamae-user@fuga-server 'sudo itamae local /path/to/recipe.rb'

また純粋に $ itamae localの方が実行が高速。といった背景もあります。

このような理由から、今回は $ itamae localの実行方式を採用しました。

秘匿情報の設置と初回実行までの準備

Railsの secret_key_baseやDB接続のためのパスワードなどの秘匿情報は itamae-secretsを使って管理しています。
itamae-secretsを使えば開発者が複数いる場合も、暗号化に使った秘密鍵を共有するだけで手元のマシンで秘匿情報を複合することができます。

競合としてはよく dotenvが比較されますが、公式で本番環境に利用するのを推奨していないため
今回はitamae-secretsを採用するに至りました。

また $ itamae localを実行するためにはレシピをサーバーに設置しておく必要があります。
イエウールではCloudFormationのテンプレートやItamaeのレシピはGitHub上のリポジトリで管理しているので $ git cloneしたいわけなんですが
当然CloudFormationでただ立ち上げただけのEC2インスタンスにはGitHubのDeploy keyが存在しないため、秘密鍵を設置する必要があります。

EC2ユーザーデータとパラメータストアで起動時にItamae適用

ここまででItamae実行のために

  • $ itamae localで実行したい
  • 秘密鍵などの秘匿情報を設置したい

という動機が生まれました。

そこでイエウールチームが使った方法が EC2 ユーザーデータパラメータストアを利用する方法です。

以下のような手順でインスタンス起動時に自動でItamaeレシピを適用しています。

  • パラメータストアからGitHubのDeploy keyを取得
  • Itamaeレシピを含むリポジトリをclone
  • パラメータストアからitamae-secretsの複合用 秘密鍵を取得
  • $ itamae local実行

実際にユーザーデータで使用しているシェルスクリプトは以下のようなものです。

#!/bin/bash -xe
yum update -y
yum install -y git ruby-devel gcc-c++
gem install --no-ri --no-rdoc bundler
gem install --no-ri --no-rdoc io-console
aws ssm get-parameters \
    --names '${env}.${github_deploy_key_name}' \
    --with-decryption \
    --region ${AWS::Region} \
    --query 'Parameters[0].Value' \
    --output text \
    | perl -pe 's/\\n/\n/g' > /root/.ssh/github_deploy_key
chmod 600 /root/.ssh/github_deploy_key
ssh-keyscan -H github.com >> /root/.ssh/known_hosts
git clone git@github.com:speee/xxxx /root/xxxx
aws ssm get-parameters \
    --names '${env}.${itamae_secrets_key_name}' \
    --with-decryption \
    --region ${AWS::Region} \
    --query 'Parameters[0].Value' \
    --output text \
    > /root/xxxx/itamae/secrets/production/keys/default
cd /root/xxxx/itamae
/usr/local/bin/bundle install --path vendor/bundle --without development test
/usr/local/bin/bundle exec itamae local -y nodes/${env}/${role}.yml bootstrap.rb
reboot

ユーザーデータに渡しているシェルスクリプトはrootユーザーが実行してくれるため
仮にインスタンス起動後に新しいレシピを適用したくなった場合も、実行ユーザーに $ sudo itamae localする権限を付与すればいいだけなので
不用意に任意のコマンドを実行できる権限を与える心配が少なくなります。

まとめ

イエウールではこうしてインフラ群の構成管理をしています。
しかし、Route53などの設定はCloudFormation利用前から存在したリソースなため、まだコードで管理するに至っていません。
現在、roadworkerなどのツールを使ってコードで管理できるよう計画中です。

一度に全てを理想形にすることは難しいですが、ひとつずつ理想に近づけていければと思っています。

社内技術プレゼン大会SpeeeKaigi#3 開催レポート

SpeeeKaigiを開催しました(半年ぶり三回目)

エンジニア組織推進室の渡辺です。エンジニア組織推進室では採用や広報を中心に、開発部をより良くすることをミッションにしています。本日は半年ぶりの実施となった第三回SpeeeKaigiについて、レポートします。


f:id:yt-tanabe:20170831163942j:plain:w600

SpeeeKaigi is 何?

Speee開発部で実施される技術のお祭りです。ざっくりいうと社内エンジニアの技術プレゼン大会で今回でめでたく3回目を迎えました。第1回から半年ペースで開催しています。

tech.speee.jp tech.speee.jp

概要

前回レポートからの引用

Speeeでは様々な事業部にエンジニアが属しているため、他チームの業務の深い部分まで完全に理解することができないのが課題の一つです。Speeeではエンジニア全体mtgというものが週に一度あり、事業部持ち回りで毎週発表しているのですが、開発部の人も増える中で業務内外問わず、自身の技術をよりオープンに発信する文化にしたい・・ 暗黙知が増えることへの打ち手として、あーだこーだ言ってた中で、 「だったら社内で全員発表する機会を創れば良いのでは?」という方向になり、 どうせやるなら本気でやろう。と思い、審査員、賞品を用意して実施したのがSpeeeKaigiとなります。エンジニアによる技術のお祭りと位置づけてます。

第二回SpeeeKaigiを開催しました - Speee DEVELOPER BLOG

目的

過去の2回は開発部の中で楽しくやってきたのですが、今回は Speee全体で技術の可能性、おもしろさを理解し技術に寄り添うこと を1つの目的としています。お笑い好きな人だけが見てるオンエアバトルからクリスマスの風物詩だったM-1のように、全社視点でより多くの人に楽しめるような場にすることを一つの目的としました。

もうひとつの目的として普段から業務内外で学習、開発していることをSpeeeとして正しく認識、評価したいというのがあります。業務内外問わず、日常的な学習が特に必要とされるエンジニアだからこそ、日頃の功夫(クンフー)の成果を、遺憾なく発揮できる機会を用意すべき、と考えています。

ルール

ルールは下記のとおりです。約2ヶ月前に開催概要を告知し、ネタを用意してもらっています。

- 業務内外問わず、自身が技術を用いて取り組んだものを発表
- 発表時間:10分
- エンジニアは原則、全員発表
    - エンジニア以外の参戦も可
- 顧問の井原氏を含む、外部からの審査員による審査を行い、各賞を決定する
    - 総合優勝
        - 総合的に最もよかったテーマに贈られる賞。
    - 部門賞
    - 技術賞:有用性を問わず、技術を駆使したテーマに贈られる賞
    - 課題解決賞:技術を用いて課題をクールに解決したテーマに贈られる賞
    - エンタメ賞:エンタメ性が高く、技術を用いてわくわくさせたテーマに贈られる賞
- 受賞者には「日々の生産性が向上する」賞品を贈呈。
    - ルンバ、オーダーメイドまくら、LaQuaスパチケット、シリコンバレーで買ったbb8

プログラム

当日は下記のような形で24テーマを8時間にわたって発表しました。
誰でも見れるように弊社イベントスペースでもあるSpeee Loungeで実施し、社内メンバーを対象に入退場自由で観戦できるようにしました。

f:id:yt-tanabe:20170831163946j:plain:w800

発表資料一例

id:miyachik による「Make Me HAPPY, Live Photos!」です。 「エンジニアから見たLive Photos」という切り口で、動画からLive Photosを作成するuploaderと、Live Photosを一覧で見れるviewerを作成した発表でした。 趣味と技術が爆発して、実況チャンネルは大いに盛り上がった発表となりました。

実況の様子

f:id:yt-tanabe:20170831163951j:plain:w350

このように「技術を使ってれば、テーマは何でもOK」がSpeeeKaigiの特徴です。技術の無駄遣いは褒め言葉。

Re:dashやCloudFormationなど技術に関する発表はもちろんのこと、 ビットコインや競馬、スプラトゥーン、人工生命、リーマン球面などなど、とにかく多様なテーマで自身の興味関心と技術を結びつけています。 好きの臨界点を超えた発表は聴く人を多分(に)魅了していました。

それぞれ別途、エントリが出る予定ですが、一部ご紹介すると下記のような発表がありました。

SwiftでRiemann球面を扱う

実装の話はいくつか出てきたものの、どちらかと言うとリーマン球面が何故必要なのか、の部分について熱く語られたテーマ。 発表者は数学の教員免許を持っていることもあり、プレゼンの途中でホワイトボードに書き出しながら、数式について説明する姿に会場も大盛り上がりでした。

Applying the famous BI tool to Ruby on Rails applications

BIツール、Re:dash。そこにRailsという新たな Datasource を導入する、という話でした。
現状、弊社社内でもいくつかのプロダクトで利用させていただいている Re:dash。
Re:dash 上でスクリプトも同時に管理でき、 Rails のコードを実行できるのでモデルに記述されたドメインロジックなどを利用できるのは大きなメリットでとても幅が広がりそうだな、と感じました。

GoogleMaps ( heat )

SpeeeKaigi初、名刺の肩書きがエンジニアではないメンバーの発表。
世の中にはヒートマップツールがいくつか存在しますが、それを自前で構築できないか、という試みでした。
業務での課題策定から解決まで実現できていたことが素晴らしく、各種サービスの特性をよく理解し上手に組み合わせているところや、Firebaseを活用するなどエンジニアも顔負けの発表でした!

前回同様、審査員のはずのyoshioriさんもその場でご準備いただき、登壇してくれました。いつもありがとうございます!

f:id:yt-tanabe:20170831164002j:plain:w600

所感

平日開催、エンジニア以外のメンバーも参戦可能にした今回でしたが、過去二回よりも多くの社員を巻き込んで、技術の無駄遣いの可能性を楽しむことができました。選りすぐりのネタが普通におもしろいし、技術と遊び心が結びついた先のわくわくに夢を見ました。

別視点で「アウトプットする場」があることはとても重要。アウトプットを前提としないインプットは学びが弱く、このような機会を通じて、学びを血肉に変えていくことを機会として支援することは大切だと感じています。

一方で、3回目ということもあり、幾つかのシーンで新鮮味が欠けてしまった部分もありました。こういった場は得てして、惰性という引力によってマンネリ化、形骸化していくので、良いモノを残しながら、変化、改良を生み出していくことも今後の課題として感じました。

翻って何年も続くような、技術カンファレンスや勉強会のような愛され続けるコミュニティのすごさを漠然と感じ、改めて尊敬と感謝の意を示したいと思います。いつも素敵なコミュニティを運営してくださる皆さん、本当にありがとうございます。

余談ですが、長時間発表を聞くイベントはハンドスピナーがとても良い働きをしてくれます。 今回、在庫のハンドスピナーを参加者には配布したのですが、良い感じに廻しながら発表を集中して聞くことができました。 (ベアリングの性能によっては摩擦音が気になるものもあるので、TPOをわきまえましょう)

まとめ

以上、第三回SpeeeKaigiのレポートでした!次回は半年後を予定しております。
次回はよりpublicに社外の方も含めてやっていけると良いなと思ってます。


f:id:yt-tanabe:20170831164007j:plain:w600


株式会社 Speee はSpeeeKaigiで技術の無駄遣いについてお話したい エンジニア やSpeeeKaigiのようなイベントを企画運営するエンジニア組織推進室メンバーを募集しております。

美味しいコーヒーを飲みたいエンジニアの皆さん、ぜひ遊びに来てください。
Speee のラウンジで一緒にコーヒーを飲みながらお話しましょう。

ECSとGoとDocker multistage build

Speeeエンジニアの義田(@yoppiblog)です。SpeeeではUZOUというアドネットワークである広告配信システムを開発・運用しています。 今回は広告配信システムを裏で支えるバッチのDocker imageの作り方のtipsをお届けしようと思います。

GoのバッチをECSで動かす

UZOUのシステムは広範囲に渡ってGoを採用しており、広告配信サーバや配信する広告を選定するバッチもGoで書いて運用しています。 UZOUを導入されるメディアさんが増えるにつれて、処理するデータ量が段階的に増加していくシステムなので、常にバッチサーバを稼働させ続けるよりは、バッチ動作時に必要な台数だけ起動して実行するほうがコストパフォーマンスが良くメンテナンスも不要なため、ECS(Amazon EC2 Container Service)で動作させています。

GoはクロスコンパイルをGoのtool chain上で実行可能なので、開発マシンやデプロイサーバでカジュアルに本番のプラットフォームに合わせて実行ファイルを作成できることが強みです。 しかし、そのバッチでCGOを使っているとクロスコンパイルは基本的に実行できず、本番環境のプラットフォーム上でビルドしなければなりません。 UZOUでは広告配信するにあたり、記事や広告を形態素解析するフェーズがあり、形態素解析器はMeCabを採用しています。そのためMeCabのshared libraryをGoから扱わなければならず、CGOが必要になるというわけです。

GoのDocker imageを作る

方法としては、

  • ECS上で動作するDocker imageにCGOのビルド環境を整備(Goやgcc等)してそこでビルドしてそのまま使用する

といったものが考えられ、愚直に書くと次のようなDockerfileになると思います。

FROM amazonlinux

ENV GOPATH /go
ENV PATH /usr/local/go/bin:/go/bin:$PATH

RUN curl https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz > /go1.8.3.linux-amd64.tar.gz && \
    tar zxf /go1.8.3.linux-amd64.tar.gz -C /usr/local/ && \
    yum update -y && \
    yum install -y epel-release && \
    rpm -ivh http://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm && \
    yum install -y \
      mecab \
      mecab-devel \
      mecab-ipadic \
      gcc \
      git \
      make && \
    go get -u github.com/golang/dep/cmd/dep

WORKDIR /go/src/path/to/repository

COPY . /go/src/path/to/repository

RUN go build -o /app app.go

CMD ["/app"]

しかし、この方法はDockerのstageが大きくなるのでなるべく避けたいところですし、Goを採用しているメリットの一つである、実行ファイル(+設定ファイル等)さえあれば動作できる、という点を薄れさせてしまいます。

そこで、

  • ビルド用imageでGoプログラムをビルドし実行ファイルを作成したあと、ECSで動作させるimageビルド時に実行ファイルをCOPYする

方法を採用する人も多いのではと思います。

base/Dockerfile

FROM amazonlinux

RUN yum update -y && \
    yum install -y epel-release && \
    rpm -ivh http://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm && \
    yum install -y \
      mecab \
      mecab-devel \
      mecab-ipadic

build/Dockerfile

FROM amazonlinux

ENV GOPATH /go
ENV PATH /usr/local/go/bin:/go/bin:$PATH

RUN curl https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz > /go1.8.3.linux-amd64.tar.gz && \
    tar zxf /go1.8.3.linux-amd64.tar.gz -C /usr/local/ && \
    yum update -y && \
    yum install -y epel-release && \
    rpm -ivh http://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm && \
    yum install -y \
      mecab \
      mecab-devel \
      mecab-ipadic \
      gcc \
      git \
      make && \
    go get -u github.com/golang/dep/cmd/dep

WORKDIR /go/src/path/to/repository

COPY . /go/src/path/to/repository

RUN go build -o /app app.go

app/Dockerfile

FROM base:latest

COPY ./dest/app /

CMD ["/app"]

docker_build.sh

# 実行ファイルをコンパイル
docker build -f docker/build/Dockerfile -t build .

# 実行ファイルをホストにコピー
docker create --name extract build:latest
docker cp extract:/go/src/github.com/path/to/repository/dest/app dest/app
docker rm -f extract

# ECSで動作させるimageを作成
docker build -f docker/app/Dockerfile -t app .

こうするとDockerfileだけで完結せず、(その部分はshell script化とかすると思うのですが)少し見通しの悪い形になってしまいます。*1

Docker multistage build

そこで、Docker 17.05 から導入されたDocker multistage buildを適用してみましょう。 この機能を使うと、先程のDcokerファイルをひとつにまとめられます。

FROM golang:1.8.3

RUN yum update -y && \
    yum install -y epel-release && \
    rpm -ivh http://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm && \
    yum install -y \
      mecab \
      mecab-devel \
      mecab-ipadic \
      gcc \
      git \
      make && \
    go get -u github.com/golang/dep/cmd/dep

WORKDIR /go/src/path/to/repository

COPY . /go/src/path/to/repository

RUN go build -o dest/app app.go


FROM base:latest

COPY --from=0 /go/src/path/to/repository/dest/app /app

CMD ["/app"]
  • FROM をDockerfile内に複数書けるようになり、
  • それぞれの FROM は違うベースを指定でき、
  • それぞれのstageは新規で作成され、
  • 各stage間でのファイルのコピーも可能

といった機能を備えているので、今まで分割されていたものが一つになり見通しも良くなったと思います。

ところで、2つめのFROMCOPY--from=0 のように引数を付けて実行しています。これはstageが0番目のもの、つまりDockerfileの先頭の FROM のstageを示しています。 stage数が少ない場合はindex指定でも問題ありませんが、多くなるとindexで指定するのはDockerファイル全体を精査しなければなりませんし、stageを入れ替えた場合indexも再番しなくてはならず運用が逆に手間になるかもしれません。 そのため、各stageに名前を付けられるように実装されています。

FROM golang:1.8.3 as builder

RUN yum update -y && \
    yum install -y epel-release && \
    rpm -ivh http://packages.groonga.org/centos/groonga-release-1.3.0-1.noarch.rpm && \
    yum install -y \
      mecab \
      mecab-devel \
      mecab-ipadic \
      gcc \
      git \
      make && \
    go get -u github.com/golang/dep/cmd/dep

WORKDIR /go/src/path/to/repository

COPY . /go/src/path/to/repository

RUN go build -o dest/app app.go


FROM base:latest

COPY --from=builder /go/src/path/to/repository/dest/app /app

CMD ["/app"]

FROM {base} as {name}as で指定したものがstage名となり、他のstageから参照できるようになります。

まとめ

Docker multistage buildを使ってCGOを使うGoアプリケーションのDockerfileを整理しました。 煩雑になりがちなDockerfileの見通しがよくなったので運用負荷を下げられそうですね。

*1:ちなみに、このようにビルドするものと実行するものとでimageを分けることを builder pattern と呼ぶそうです。

#rejectkaigi2017 を開催しました

Speeeエンジニアの id:takanamitoid:miyachik です。 8/19(土)に弊社のSpeeeラウンジで「RejectKaigi 2017」を開催しました。

イベントの詳細はこちらをご覧ください。

RejectKaigi 2017 - connpass

tech.speee.jp

SpeeeはPre Kaigi Sponsorとして、RubyKaigiのお手伝いをさせていただいております。

RubyKaigiのRejectKaigiが開催されるのは youchanさんいわく初開催の2007年から10年目とのことで
運営側も手探りでの開催となりました。(開催されていない年もあります)

RejectKaigiならではのコンテンツも

今回、普段Speeeで開催されるエンジニアイベントと違い、
RubyKaigiの事前イベントとして開催されていたため
RubyKaigi本番を盛り上げるコンテンツを用意していました。

タイムテーブル徹底解説

その中のひとつとして非常に人気のあった発表が @a_matsudaさんと @takahashimさんによる RubyKaigi 2017タイムテーブル徹底解説です。

この発表はRubyKaigiのスケジュールを見ながらお二人に見どころを話してもらうコンテンツでした。
運営側ならではのCFPを採用する判断したポイントや見どころ、また発表者がどんな人なのかまで触れていることもあり、なかなか聞けないようなお話がたくさん聞けました。
個人的には「ヘルシープログラマの著者なのでエモい話をするのかと思いきや、JRubyのノンブロッキングI/Oについて発表をしてくれます。」という一幕がおもしろかったです。

このコンテンツは大変盛り上がり予定時間を少しオーバーしてしまうほどでした。懇親会でも参加者からとてもよかったという声を多くいただく、大変よいコンテンツだったと思います。

QuineによるRejectKaigiアスキーアート

youchanさんの発表はQuineについてのお話でした。
RejectKaigiという文字のアスキーアートを出力するデモを披露していただきました。

f:id:takanamito:20170819150113j:plain

抽選会

休憩時間にはコンテンツとして抽選会を開催いたしました 🎉 景品としては、RejectKaigi特製ネックピロー および、 カンファレンスなどで配布しているSpeee特製コーヒー豆 Speeeブレンド をお配りさせて頂きました!

f:id:tigger501st:20170824163339j:plain

司会の @mrkn による素数推しなどもあり当日は非常に盛り上がりました。

kamipoさんRailsコミッター就任式

懇親会の最中に @kamipoさんRailsコミッター就任をお祝いする一幕もありました。

f:id:takanamito:20170819190752j:plain

@a_matsudaさんからのご好意で日本酒が振る舞われる非常にめでたい場面でした 🤗

アンケート結果も好評

今回のイベントではアンケートを取っていたのですが
5段階の満足度評価でも最高の「大変満足」「満足」を選んだ参加者が91%
さらに次回も開催希望の参加者が96%と、非常に良い結果となりました。

また懇親会などで「このイベントに参加して、RubyKaigiに行くことを決めました」と言ってくださった参加者もいらっしゃるなどほんとに開催してよかったと思える会になりました 🙌

次は前夜祭

前夜祭とは、RubyKaigi 2017の前日に実施するRubyコミッター、本編のスピーカー、海外からの来場者を中心にお招きし、実施する公式イベントです!

参加登録はコチラから。 connpass.com

前夜祭、もしくはRubyKaigiでお会いできること楽しみにしています!