自己紹介 - 高島
はじめまして!入社3ヶ月目のエンジニアの高島です。
今回は初ブログ記事ということで、技術記事は免除してもらい、自己紹介をさせて頂きたいと思います。
と言いましても、入社までの経緯や理由に関しては以前Wantedlyのインタビュー記事を書かせて頂きましたので、興味がおありでしたらぜひご覧ください。 www.wantedly.com
ここでは入社してからの所感について書かせて頂きますね。
入社してからの振り返り
振り返ってみて、この2ヶ月は今までの経験や考え方とのギャップを埋める期間だったなと感じます。
前提
自分の今までの開発経験は、専門学校で作成していたものを含めても(クオリティはさておき)、
機種 | 言語 | 内容 |
---|---|---|
Windows | C,C++ | シューティング2D,3D |
C++ | ノベルゲーム | |
音ゲー要素持たせたブロック崩し | ||
C# | 帳票アプリ | |
Xbox | C# | アクション2D,3D |
iPhone | C++ | ミニゲーム |
アクション |
など、思い出せる限りでこのような感じなので、今までWebに関わったことがありませんでした。 通信周りもなかなか理解ができなくて、避けて通って来ていましたし、ほぼWebの知識はないと言っても過言ではないところからスタートしました。
ギャップ1: Git
今までの開発環境で使っていたバージョン管理は、Subversionでした。 大した違いはないだろうと思っていたのですが、PullRequestやrebaseなど、耳慣れない言葉がポンポン出て来て戸惑いました。 SVNを使ってる時も、既にあるブランチにぽんぽんコミットしていったり、マージしたりしかしていなかったので、リポジトリに対しての意識もなかったですし、どうにもブランチ切るのがおっかなびっくりになります。 未だにPR出すのもドキドキします。
ギャップ2: インプットの習慣
これは本当にお恥ずかしい話なのですが、今までは自分の興味のある情報をたまーにチラ見したりする程度で、最新技術を追ったり、常に情報を仕入れたりはしてきませんでした。
最新ゲームや最近のゲームの動向は掴もうとしていましたが、それも海外のサイト見たりしてた訳でもないですし、今思えば甘かったなと思います。
Web界隈は範囲も広ければ、流行り廃りも早く、常に情報収集は当たり前の世界なので、生活の中でインプットしていく習慣をつけないとついていけないと思いますが、この習慣をつけることに今一番苦労しています。
技術系の基礎を身につけながら、情報のキャッチアップをしていくという2本立てにどう時間配分をするか、早く落としどころを見つけたいと思います。
ギャップ3: 公開までの工程
サイトの開発だと、Staging環境で動作確認をして、その後即リリースという流れですよね。 このリリースの早さが良くもあり、怖くもあります。 というのも、α→β→マスター版の工程や、テスターの存在になれきっていたのもあって、「ここで全部のバグを検知出来ないと本気でまずい!」という危機意識が薄いところがあったからです。 Cluexではコードレビューがあるのですが、それがなかったらと思うとぞっとしますね。もっと慎重さを持って、気をつけていかないといけないなと思います。 レビューは、まだまだ分からないところが多く、人がレビューしたのを見たり、質問するばかりですが、早く有意義なレビューをしていきたいと思います。
ギャップ4: ベンチャーでの開発
一人の采配が大きいという理由もあって、ベンチャーを選択しましたが、自分が予想している以上で、戸惑う程でした。
任せて頂いたタスクがユーザーに直結しているというのを日々痛感します。
また、苦手なところも自分でやらなくてはいけないのも、ベンチャーならではかなと思います。
今までは行き詰まって、ここで詰まっててこのくらい遅れそうですと報告すると、そのタスクは掬い取られて他のタスクを回される、ということが多かったので、苦手なものはあまり回されてきませんでした。
しかし、人数がそこまでいない状況だと自分が必要な分は自分で準備する必要があるので、苦手とも言ってられず、やるしかありません。
追い込まないと動かない(自分のような)人にはうってつけですね。ちょっと焦りますけど。
これから
大きくギャップがあったのはこの辺りでしょうか。
入社して2ヶ月と少しが経ち、今ようやく概要を掴めたかなと感じています。
これからは、使われている各技術についての基礎知識をつけていかなければと思います。
焦ると碌なことにならないのは今までの経験から分かっているので、焦らず急いで、しっかりアウトプットしながら一つずつ技術を習得していきます。
これからもよろしくお願いします。
We’re hiring!!
Cluexではエンジニアサイド、ビジネスサイド共にメンバーを募集しています!
お気軽にご連絡下さいませ!エンジニアの方、ぜひ情報交換しましょう!
www.wantedly.com
www.wantedly.com
エンジニアが暗号理論を学んでみた。〜共通鍵暗号と公開鍵暗号〜
こんにちは、神山です!
先日GWでしたが、皆さんはいかがでしたか。
自分は2日目から風邪を引いて、GWの最後まで寝ておりました。
東京の風邪と夜通しのモノポリーほど長引くものはないですね。
さて、前回は暗号理論の基礎的な内容を書いたので、今回は2種類の暗号方式(共通鍵暗号と公開鍵暗号)について説明しようと思います。
前回の記事はこちら
では、まず共通鍵暗号について解説していきます。
共通鍵暗号
共通鍵暗号とは暗号化と復号に同じ鍵を使用する暗号方式です。秘密鍵暗号とも言います。
身近な例
合言葉や共通認識等は共通鍵暗号です。
よくお酒を飲みに行くときに「一杯ひっかけます?」と言ったりしますよね。これは「お酒を飲みに居酒屋に寄って行きます?」ということを暗号化しております。
「お酒を飲みに居酒屋に寄って行きます?」を「一杯ひっかけます?」と暗号化していることを受け手が知っていれば、きちんと復号して飲みに行くことを理解出来ます。
あまりに身近な例なので、今度は有名な共通鍵暗号を紹介します。
シーザー暗号
これは英文を伝える時に、全てのアルファベットを指定数分ずらして英文を送ることです。
シフトさせる文字数を3文字としたとき。 a -> d k -> n のように、3文字シフトさせて暗号化する。 「THE ALFEE」 をシーザー暗号(文字数3)で暗号化すると、 「WKH DOIHH」 となる。
鍵は文字数(今回だと「3」)です。
受け手がこの鍵を知っていれば、送られてきた英文を3文字前に戻すことで「THE ALFEE」を得ることが出来ます。
しかし、共通鍵暗号には重大な欠点があります。
鍵共有問題
これは肝心の鍵を共有する安全な方法がないということです。
共有鍵暗号はお互いに鍵を知っているという前提のもと成り立ちます。その為、まず鍵を安全に伝える手段がないと使う事ができません。
口頭で伝えるという原始的な手段はあります。しかしこれはあくまで伝えたい人が近くに居る状態で、誰にも聞かれない状態でなければなりません。
そもそもこの状態であれば、暗号化する必要もないでしょう。
通信手段を使うには、安全に伝えられる方法を探さなければなりません。安全に伝える手段こそ暗号なのですが、皮肉なことに暗号を使うために暗号が必要になってしまいました。
これでは鶏が先か、卵が先か問題になってしまいます。
さてこの問題を解決してくれるのが、公開鍵暗号です。
公開鍵暗号
公開鍵暗号とは、暗号化する鍵と復号する鍵が違う暗号方式です。暗号化する鍵(公開鍵)は公開し、復号する鍵(秘密鍵)は秘密に管理します。
RSA暗号が公開鍵暗号の代表的な例です。
身近な例だと難しいので、少し特殊ですが分かり易い例を用意しました。
南京錠
ある南京錠があります。この南京錠を開ける鍵はAさんが持っている一本の鍵のみです。もちろん複製や他の手段では開けられません。
またこの南京錠自体はどこでも手に入るものだとします。
Aさんに秘密のメッセージを送りたいときは、メッセージを適当な箱に入れてこの南京錠でロックします。
すると当然ながらこの箱を開けられるのは鍵を持っているAさんしかいません。つまりAさんに安全にメッセージを伝えることが出来ます。
これが公開鍵暗号の仕組みです。南京錠自体はいくら公開しても問題ありません。
では実際に使われている公開鍵暗号が、具体的にどのような仕組みになっているか説明します。
※ ここからは数学の話が出てきます。ただ出来るだけ分かり易く言葉で説明するので、数学に抵抗意識がある人もどうか読んで頂ければと思いますm( )m
一方向性関数
一方向性関数とは、一方の計算は簡単なのにもう一方の計算は極度に難しい関数のことです。
たとえば、1454867
を素因数分解してみてください。
PCを使わずに、出来た人はすごいです。答えは911 × 1597
です。
さて、では911 × 1597
を計算してみてください。こちらはPC使わなくても簡単ですね。もちろん1454867
です。
みなさんも体感したように、素数を掛け合わせるのは簡単ですが、それを素因数分解するのはとても難しいことです。
これは人間だけでなくPCも同じです。桁数は大きくなりますが、数百桁の素数を掛け合わせた数をPCに素因数分解をさせると、解くのに何万年という膨大な時間が掛かります。
時間が無限にあればいつかは解けますが、現実的に考えると難しいと言えます。
一方向性関数を使った南京錠
先程、南京錠の例を用いたので、今回はそれに類似させた例を作りました。
Aさんのアドレスが書かれている50桁のダイヤルが付いた南京錠があります。また謎の数百桁の数が書かれてあります。これを開けるにはこの数を素因数分解して、一番大きい素数の最初の50桁をダイヤルにセットしなくてはいけません。
(桁数の50は適当です。。)
Aさんにメッセージを送りたいときは、同じように適当な箱にメッセージを入れてこの南京錠で閉じます。
もうお分かりかと思いますが、この南京錠を開けられるのは素因数分解の答えを知っているAさんのみです。
つまり相手の公開鍵さえ知っていれば、自分の情報をその人に安全に伝える事ができます。
RSA暗号
公開鍵暗号を使用した暗号の代表例です。 現在の安全な通信技術にはRSA暗号が使用されております。 仕組みは素因数分解を用いているのですが、理解するには数学の高度な知識が必要になるので、また別の機会にでも説明しようと思います。
まとめ
共通鍵暗号と公開鍵暗号について説明しました。理解をして頂くことに重点を置いたので直感的な内容になってしまったかも知れません。
間違いなどがありましたらご指摘をお願い致します。
APIにGolangを導入しました
こんにちは、Cluexの高橋です。
社内で開発を進めているモバイルバックエンドのAPIに初めてGolangを導入しました。
Cluexでは創業から現在に至るまでの3年間、Webアプリケーションの開発にRuby on Railsを使用してきました。 Golangの導入自体はそこまで真新しいものでも無くなりましたが、Golangに関して社内に開発ノウハウはまだなく、Gopherももちろんいません。
そうした状況の中でGolangを導入した理由や、実際にGolangで開発をスタートしてからの事などを、複数に分けて書いていきます。
今回はGolangの導入に至る背景や、導入に際して考慮した事などを簡単にまとめていきます。
公式ブログによると、
1. 簡潔さ
2. 並行処理
3. 処理速度
がGolangの盛り上がりを支えているようです。
Go 2016 Survey Results - The Go Blog
本番環境のインフラストラクチャ
実際に本番環境で使用するにあたって、 インフラの構成やデプロイ周りは必ず考慮しなければなりません。
これまで本番環境にはAWSのEC2を使用していましたが、今年の3月にAWSのECSによるDockerでのサーバー運用にインフラを全面移行しました。
Dockerによるサーバー運用に切り替えたことで、従来のEC2での運用に比べてサーバーの運用・管理が楽になりました。
Infrastructure as Codeの浸透
これまでもChefやAnsibleのようなInfrastructure as Codeを導入してインフラの構築を行なっていましたが、 徐々にコードが管理されなくなってしまったり、どうしても障害発生時の急な対応などからサーバー間の環境差異が発生していました。
今回の移行によってサーバー環境も全てDockerfileとyamlによる管理になり、常にコードでインフラ環境を管理するようになりました。
本番環境と開発環境の差異
開発環境も全てDocker及びDocker Composeによる管理にしたことで、コマンド一発でポータブルな開発環境の構築が可能になり、 本番環境との差異も以前に比べて格段に無くすことができていると思います。
本番稼働系も全てDockerで管理している為、別の(新しい)言語に移る時もインフラ構築の障壁が低くなったことがGolangの導入を後押しする大きな要因となっています。
モノリシックサービス化の予兆とマイクロサービス化
これまで運営しているサービスが一つだったということもあり、1つのRailsアプリケーションに全てのソースコードが入っていました。 しかしコードベースが増えていくにつれて全容の把握が難しくなり、エラーやバグを生む温床となっていきます。
複数サービス間での連携を踏まえたサービスの多角化を行う上では、このような状況はより一層好ましくありません。
小さなアプリケーションの集合体として全体のアプリケーションを管理していく為にも、 今回は別アプリケーションとしてAPIのアプリケーションを組むことにしました。
APIとしての実行パフォーマンス
ちょうど今日、バージョン5.1が正式に発表されましたがRuby on Railsは依然として、とても素晴らしいフレームワークです。コミュニティも非常に盛んで、欲しい機能はgemを探せば大体見つかりますし、スタートアップにおけるwebアプリケーション開発には欠かせない、非常に頼もしい存在です。
ですが、今回のようなモバイルバックエンドのAPIだとRuby on Railsはパフォーマンスの面でデメリットが大きくなってきます。 マイクロサービス化していく中で今回のAPIも別アプリケーションにするので、慣れ親しんでいるという理由の他にRuby on RailsでAPIを組む大きな理由がそこまでありません。 Rubyだとマルチスレッド処理の実装が大変である故にマルチプロセスで処理を行なったり、メモリの消費量が多くなったりという事がずっと言われており、言語自体の処理パフォーマンスにおいてGolangが良さそうです。
ライブラリ選定
WebアプリケーションフレームワークにはEcho、ORMにはgormを採用しました。
GitHub - labstack/echo: High performance, minimalist Go web framework
GitHub - jinzhu/gorm: The fantastic ORM library for Golang, aims to be developer friendly
またrevelなどフレームワークに入っているようなホットリロードの機能がない為、開発環境にはfreshを使用したホットリロードを行なっています。
GitHub - pilu/fresh: Build and (re)start go web apps after saving/creating/deleting source files.
フレームワーク
Webアプリケーションフレームワークに関しては、APIを構築するということで、フルスタックな機能は必要ありません。 とはいえhttpサーバーとしての機能やルーティングなど、基本的なリクエストとレスポンスの処理はフレームワークに任せたいところです。スター数や更新頻度、issueなども勘案して今回はEchoを選びました。
GolangのフレームワークはRubyでいうSinatraやRailsのような、立ち位置が定まっているフレームワークがまだはっきりしていない状況です。 またirisのような、スター数は多くてもOSSでの開発方針として、一般的な方針とは乖離が大きいフレームワークもあったりします。
ORM
ORMに関しては、現状Golangの主なWebアプリケーションフレームワークにはORMが入っていません。 ORMのライブラリとしてはいくつも候補がありますが、gormはActiveRecordに近い書き方で実装出来るようになっている為、Railsエンジニアも比較的手をつけやすいと思います。
サードパーティパッケージ
フレームワークやORMを含めて、GolangでサードパーティのパッケージはGemに比べるとまだまだ発展途上で、似たようなものが乱立している状況です。
下手にアプリケーションに取り込んで後に更新が止まったりしてしまうと、負債となってしまいそうなので、可能な限り少ないライブラリで対応するようにしています。
ライブラリもフレームワークも、別のパッケージに乗り換えやすいようなコードベースへの配慮が必要かと思います。
まとめ
Golangの導入の背景や、導入に際して考慮した点などを簡単にまとめました。
また近いうちに、実際に開発していく上で良かった面や大変だった面などを記事にしていければと思います。
Docker with ECS × Railsを実現させるために考えたこと(デプロイ編)
こんにちは。エンジニアの志村です。
の続きとなります。 今回はタイトル通り、デプロイ辺りを執筆していければと思います。
Blue-Green Deployment
Blue-Green Deploymentはマーチン・ファウラー氏が提唱したデプロイ方式です。 blue, greenとほぼ同じ本番環境を2系統用意してデプロイを行います。このデプロイ方式ですが、
- ダウンタイムの極小化
- ロールバックが容易
という大きな2つの利点があります。
Dockerizeへのモチベーションとして前回の記事にも書いたのですが、徐々にドッグフーディング環境・本番環境で差異が出てきました。
そのような状況だと、ドッグフーディングでは正しく動作したのに本番環境では意図した挙動とは違うという場面も出てきます。
上記のようなトラブルがあった際に今までのIn place型のデプロイ方式だとロールバックに時間がかかり、ユーザーに迷惑をかけてしまう時間が長くなるという問題がありました。
Blue−Green Deploymentでは特に2.の「ロールバックが容易」という点が非常に魅力でした。
何かトラブルがあったとしてもELB設定を変えてしまえば瞬時に旧環境に戻せるという点で、デプロイに対する心理的ハードルが社内全体で下がりました。
また、ECSの仕組みにより今までのようにCapistranoによるSSHを用いたデプロイが難しかったという理由も相俟って、弊社でもBlue−Green Deploymentを用いております。
ECSによるBlue-Green Deployment
前回の記事にも書いた通り、ECSを使用した際のBlue−Green Deploymentにはいくつかやり方が存在します。
- ECSのMaximum healthy percent, Minimum healthy percentを調整し、徐々にタスクが切り替わるように調整する。
- CLB(Classic Load Balancer)× Autoscaling Groupを使用して切り替える
- Routes53を使用し、Standby, ActiveのELBを切り替える
- ALBに紐付いているTarget groupの優先順位を切り替える
ECSのMaximum healthy percent, Minimum healthy percentを調整し、徐々にタスクが切り替わるように調整する。
利点
- ECSデフォルトの機能を用いるので、他に余計な操作をする必要が一切ない
- タスクの増減を元にデプロイを行うのでインスタンス料金を低く抑えることが出来る
欠点
- デプロイがまずまず遅い?→ロールバックが遅い
ECSの特徴が最大限発揮されたデプロイ方式だと考えます。
ECSには「タスク」という概念があります。タスクはDocker imageを起動させる際の設定、またそのリビジョンです。
タスクは
- 使用するdocker image
- コンテナ間のリンク
- コンテナのコマンド
- データボリューム
等が設定できます。
リビジョンが用意されたdocker-composeだと考えると分かりやすいかと思います。
タスクに関しては公式のドキュメントが分かりやすいです。
Amazon ECS タスク定義
そのタスクを管理するのがサービスという概念です。
サービスはざっくり言うと、ロードバランサーとの連携、上記のタスクをインスタンスにどう配置するか、最大・最小・維持タスク数をいくつにするかの取り決めです。
ECSのサービスのデプロイメントオプションに、maximum helathy percent(最大率), minimum healthy percent(最小ヘルス率)という項目があります。
この値を調整することによって、Blue-Green Deploymentを実現することが出来ます。
例えば
* maximum healthy percent: 200%
* minimum healthy percent: 100%
と設定すれば、
デプロイ時に通常のタスク数の2倍、デプロイ終了後にタスク数1倍という形になります。
仮に1インスタンス1タスクという戦略であれば、デプロイ時に2倍のインスタンス数が必要ということになります。
* maximum healthy percent: 50%
* minimum healthy percent: 100%
個人的な感触ですが、既存のタスクをkillして新しいタスクに入れ替えるのに結構な時間がかかっている印象でした。
つまりは、ロールバック時にも同じ作業をしなければならない≒ロールバックに時間がかかると予想される為、今回は見送りました。
CLB(Classic Load Balancer)× Autoscaling Groupを使用して切り替える
利点
- 設定がほとんど必要ない。実装が楽
- ロールバックが早い
- ダウンタイム無し
欠点
- SpotFleetが使用できない
- Blue, Greenが重なるタイミングがある
恐らく現時点で最もポピュラーなBG Deploymentの方式かと思います。 実装もAutoscaling Groupを作成すればOKという簡便さです。
ALBを今回使用したいと考えていましたが、コンソールを見てもALBが使用できない雰囲気ではありました。 しかしながら、現在では下記のように使用できるようです。
これで課題は1つクリアしましたが、SpotFleetがAutoscaling Groupに登録出来ない為、今回この方式は断念しました。
ロールバックを容易かつスピーディにするにはインスタンスの数が単純に倍必要となります。SpotFleetの使用は予算の都合上、必要でした。
またこの方式だとヘルスチェックの観点から、Blue, Greenが重なるタイミングがどうしても出てきます。
マイグレーション・モデルの変更をした際に、旧稼働系・新稼働系が混ざるとエラーを引き起こし兼ねません。この観点からも今回は見送りました。
Route53を使用し、Standby, ActiveのELBを切り替える
利点
- ダウンタイムほぼ無し
- シンプル
欠点
- キャッシュを考慮するのが面倒
- ロールバックに時間がかかる
一番古典的かつ確実方式です。
Route53のWeightを利用し、Blue→GreenのELBに徐々に切り替える方式です。
実装がシンプルではありますが、一番の問題点はDNSキャッシュです。
キャッシュサーバによってはTTLを無視して一定期間キャッシュするものもあるらしいので、実際にデプロイが完全に完了したかを確認するのが難しくなります。
上記のようなキャッシュのコントロールの難しさから、今回この方式は見送りました。
ALBに紐付いているTarget groupの優先順位を切り替える
利点
- ダウンタイムほぼ無し
- ロールバックが早い
- メンテナンスにすぐ切り替えられる
欠点
- 実装が面倒
結論から言うとこの方式を採用しました。
いくらか利点はありますが、特にロールバックが容易な点が大きいかと思います。
ALBにはパスベースルーティング、ホストベースルーティングという機能があります。
パスベースルーティングは下記にある通り、パスによってどのターゲットグループにトラフィックを流すかを決定できます。
例えば、
IF: /target1/*, THEN: target1 IF: /target2/*, THEN: target2
のように設定すると、
host/target1/の際にはtarget1に紐付いたインスタンスに、
host/target2/の際にはtarget2に紐付いたインスタンスにトラフィックを分岐することが出来ます。
また、このルーティングでは優先順位というものがあります。
同じパスであっても優先順位が高い(数字が小さい)方にトラフィックが流すということが可能になります。この特徴を活かし、
優先順位 | パス | ターゲットグループ |
---|---|---|
1 | * | target-blue |
2 | * | target-green |
last | Requests otherwise not routed | target-maintenance |
上記のように設定しました。
こうすると通常、blueにトラフィックが流れます。
デプロイ時にこの優先順位を切り替えると、green系にトラフィックが変わります。
ロールバック時も同じように優先順位を変更するだけで、一瞬で切り替わります。
メンテナンスページを出したい場合、他のルーティングルールを削除すればOKです。
上述の通り、ALBの特徴を使用すれば一瞬でロールバックが可能になり、さらにメンテナンスページまで容易に出すことが出来ます。
欠点としてはこの部分の実装が面倒だという点です。
今回、harmonikというデプロイツールを用意しました。
harmonik
事情によりGithub等に公開はしておりません…(早くしたい)
harmonikは今回のBG Deploymentを使用するにあたって新しく作成したデプロイツール(CLI)です。
主に下記のような機能があります
- デプロイ
- 単発のタスク起動
- ロールバック
- ステータス表示
1.は他のECS向けデプロイツールとほぼ同じです。
ALBの優先順位からデプロイ先を決定 ↓ task definitionを更新 ↓ serviceを更新 ↓ taskがRUNNING状態かどうか判別 ↓ target groupのヘルスチェックがhealthyかどうか判別 ↓ ALBの優先順位切り替え
上記のようにしてBG Deploymentを実現しております。
2.はマイグレーション等の単発のタスクに使用します。
CIでは、単発のタスク→Blue or Greenにデプロイ
という流れをとっております。
3.は単純で、ALBの優先順位を変更してロールバックさせているだけです
4.は稼働系のステータス(クラスタ名・インスタンス数・デプロイ履歴等)を表示させるものです。
以上になります。
この実装により、Capistranoとほぼ同じような感覚で簡単にデプロイをすることが可能になりました。
Dockerの運用に切り替えてからサーバのメンテナンス等に時間を割かなくて済むようになったので非常に運用が楽になりました。
※まだ運用から日が浅く、間違えている箇所があるかもしれません。
その際はお手数ですがコメント頂けますと幸いです。
Ruby on Railsにwebpackを使ってPostCSSを導入してみた【ローカル環境編】
こんにちは、エンジニアの井戸田です。
今回はモダンなCSS環境を構築するために流行っていると言われているPostCSS×webpackをRailsに導入してみました。
今回は開発環境だけですが、次回本番運用に関して書いていきたいと思います。
- 環境
- PostCSSとは
- Railsプロジェクトを作る
- webpack環境のためのディレクトリを作成
- npmで必要なライブラリをインストール
- webpack.config.jsにビルドの設定を書く
- Rails側の設定
- テスト
- PostCSSのプラグインの導入方法
- PostCSSのプラグインの紹介
- We’re hiring!!
環境
PostCSSとは
PostCSSはJSプラグインでスタイルを変換するためのツールです。特徴として下記のことが挙げられます。
- PostCSS自体が変換するのではなくCSSパーサーとASTを操作するためのAPIを提供しているだけで、実際にCSSに変換するのはPostCSSのプラグインが行います。
- Sassでよく使う
mixin
extend
変数($)
などの機能がそれぞれ1つ1つのプラグインになっており、それらを入れることで使用が可能になります。 - メタ言語の中でも特にPostCSSは速度が速いです。
ref) https://github.com/postcss/benchmark
Railsプロジェクトを作る
$ rails new sample-postcss -BJ $ bundle install --path vendor/bundle
とりあえず $ bundle exec rails s -b 0.0.0.0 -p 3000
webpack環境のためのディレクトリを作成
プロジェクトルートに client
というディレクトリを作成。ここがwebpack環境のためのディレクトリになっています。
clientディレクトリの構成については下記のようになります。
client |-- webpack.config.js |-- node_modules |-- package.json └── src |-- images |-- javascripts └── stylesheets
npmで必要なライブラリをインストール
client
ディレクトリに移動し、下記のコマンドを入力して package.json
を生成します。
$ npm init -y
webpackをインストール。webpackでは1系を使用したかった為、バージョンの指定をしています。
$ npm install -D webpack@1.14.0
ローカル環境では下記ことを可能にする webpack-dev-server
が、便利なので使っていきます。 webpack-dev-server
はポート8080を使うNode.jsのexpressサーバーです。
- ファイルの変更を検知して自動でビルドをしたのち、ブラウザを自動でリロードする
- HMR(
Hot Module Replacement
)という編集したモジュールを自動で更新する
$ npm install -D webpack-dev-servser
cssやpostcssに必要な style-loader
css-loader
postcss-loader
モジュールと、CSSをJavaScriptでロードせずにlinkタグでロードさせるため、 extract-text-webpack-text
をインストール。
$ npm install -D style-loader css-loader postcss-loader extract-text-webpack-plugin@1.0.1
webpack.config.jsにビルドの設定を書く
- デバッグ用のSourceMapの設定
- entryポイントの設定
- 出力先を設定
- トランスパイルの設定
exstract-text-webpack-plugin
の設定webpack-dev-server
でファイル変更した際に検知し、自動でビルド、自動でブラウザをリロードしてくれるように設定
client/webpack.config.js
/** * Require basic plugins */ const path = require('path'); const webpack = require('webpack'); /** * webpack plugins */ const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { devtool: 'inline-source-map', context: path.join(__dirname + '/../client/src'), entry: { application: [ 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/dev-server', './javascripts/application.js' ] }, output: { filename: '[name].js', publicPath: 'http://localhost:8080/assets/' }, module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract('style', 'css!postcss') } ] }, plugins: [ new ExtractTextPlugin('[name].css'), new webpack.HotModuleReplacementPlugin() ], devServer: { headers: { 'Access-Control-Allow-Origin': 'http://localhost:3000', 'Access-Control-Allow-Credentials': 'true' } } };
webpack-dev-serverの起動用にpackage.jsonに追記
client/package.json
{ ... "scripts": { "dev": " ./node_modules/.bin/webpack-dev-server --debug --hot --inline --devtool --public --host 0.0.0.0 --port 8080 --config ./webpack.config.js", ... }, ... }
webpack.config.js
のentryは client/src/javascripts/application.js
なので、 application.js
に client/src/stylesheets/application.css
をrequireさせます。
画像などもwebpackで配信したい場合は、同様に application.js
にrequireさせます。
client/src/javascripts/application.js
/** * Require stylesheets */ require('../stylesheets/application.css');
Rails側の設定
headタグ内のjavascript_include_tag, stylesheet_link_tagを変更
assets部分は webpack-dev-server
から取得するため、 app/views/layouts/application.html.erb
のheadタグの stylesheet_link_tag
と javascript_include_tag
部分を変更。
app/views/layouts/application.html.erb
<!DOCTYPE html> <html> <head> <title>SamplePostcss</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'http://localhost:8080/application.css', media: 'all' %> <%= javascript_include_tag 'http://localhost:8080/application.js' %> </head> <body> <%= yield %> </body> </html>
Railsの起動設定
rails s
と npm run dev
の2つのコマンドを打てば起動できるのですが、面倒くさいので foreman
というgemを使っていきます。
group :development do gem 'foreman' end
ルートディクトリに Procfile
という名前でファイルを作成し編集していきます。
rails: bundle exec rails server -b 0.0.0.0 -p 3000 webpack: npm --prefix ./client run dev
$ bundle exec foreman start
のコマンドで立ち上がります。
テスト
以上でローカル環境の構築は完了したので、テストしていきましょう。
config/routes.rb
Rails.application.routes.draw do root 'static_pages#about' end
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController # GET / def about end end
app/views/static_pages/about.html.erb
<h1>about</h1>
client/src/stylesheets/application.css
h1 { color: red; }
http://localhost:3000
にアクセスした結果
h1
タグのcolorが red
になっているのと、 gray
に変更した時に自動でブラウザの更新を行い色が変わりました。
PostCSSのプラグインの導入方法
autoprefixer
というprefixをつけてくれるプラグインを入れていきます。
まず client
ディレクトリに移りnpmで autoprefixer
をインストールします。
$ npm install -D autoprefixer
webpack.config.js
を編集していきます。下記の記述でPostCSSのプラグインを導入することができます。
client/webpack.config.js
... /** * postcss plugins */ const autoprefixer = require('autoprefixer'); module.exports = { ... postcss: [autoprefixer], ... }
それではcssファイルの方に flex
を書いてみます。
client/src/stylesheets/application.css
div { display: flex; }
webpackのビルド後は以下のようになります。
dev { display: -webkit-box; display: -ms-flexbox; display: flex; }
PostCSSのプラグインの紹介
postcss-import
ref) https://github.com/postcss/postcss-import
@import
が使用できるプラグインになっています。postcss-simple-vars
など他のプラグインを使用したファイルをimportした時にエラーになる可能性があるので、config.webpack.js
の postcss
の 方でこちらのプラグインを最初に読み込ませておくようにしましょう。
@import 'componsents/button.css'; @import 'base.css';
postcss-simple-vars
ref) https://github.com/postcss/postcss-simple-vars
SCSSのような $
を使って変数が定義できます。また弊社では変数( $
)はcolorの色を定義時に使用しています。
before
$red-color: #ff0000; $column: 200px; h1 { color: $red-color; } .column-400px { width: calc(2 * column); }
after
h1 { color: #ff0000; } .column-400px { width: calc(2 * 200px); }
postcss-nested
ref) https://github.com/postcss/postcss-nested
SCSSの様にネストを使用できるpluginです。
before
.item { &_title { width: 500px; @media (max-width: 500px) { width: auto; } body.is_dark & { color: white; } } img { display: block; } }
after
.item_title { width: 500px; } @media (max-width: 500px) { .item_title { width: auto; } } body.is_dark .item_title { color: white; } .item img { display: block; }
postcss-mixins
ref) https://github.com/postcss/postcss-mixins
SCSSの様に @mixin
で定義し、 @include
で呼び出す形ではないので注意が必要です。
before
@define-mixin margin-10px { margin: 10px; } .column { @mixin margin-10px; }
after
.column { margin: 10px }
また引数を指定することも可能です。
@define-mixin
引数で 0
を指定しています。 @mixin
の方で $px
の値を指定しなければ 0
になり、指定すればその指定した数値になります。
今回の場合は margin: 10px
となります。
@define-mixin margin $px: 0 { margin: $px } .column { @mixin margin 10px; }
PostCSS Sassy Mixinsと言うプラグインもあり、こちらだとSCSSの時と同じ記法で書けますので検討してみてください。
postcss-extend
ref) https://github.com/travco/postcss-extend
SCSSで使っていたextendと同じ記法で書けます。
before
%padding { padding: 10px; } .margin { margin: 10px; } .item { @extend %padding; @extend .margin; }
after
.item { padding: 10px; margin: 10px; }
いかがでしたでしょうか?
PostCSSのプラグインの種類は豊富で、 mixin
の機能を使いたい思った時には上記で書いた様に、 postcss-mixins
, postCSS-sassy-mixins
など複数ブラグインが存在するので、記法やコードを読んで選んでいく必要がありそうですね。
また拡張しすぎると本来のCSSの記法とかけ離れてしまうため使うプラグインは最小限に抑えるべきだと考えます。
We’re hiring!!
Cluexではエンジニアサイド、ビジネスサイド共にメンバーを募集しています! お気軽にご連絡下さいませ! エンジニアの方、ぜひ情報交換しましょう!
Docker with ECS × Railsを実現させるために考えたこと(導入編)
こんにちは。エンジニアの志村です。
今回から私は「Docker on Rails with ECSを実現させるために考えたこと」と題して、実際にDockerをProductionで運用する際にハマったポイント、また考慮すべき点に関して、数記事に渡って執筆していこうかなと考えております。
弊社では開発環境はDocker + compose、その他はItamae × EC2の構成でしたが、現在ドッグフーディング・本番環境をDocker with ECSに移行しております。
ProductionをDockerで運用しようと思った背景
今回インフラ環境を見直した背景として、
- プロビジョニングツールの管理つらい
→緊急で直接サーバ内で作業をした際にプロビジョニングツールとサーバ側の差異が発生。 - OSにインストールしているライブラリのアップデートが完全手動になっている。
→自動化したい - Productionとドッグフーディング環境の差異
→ドッグフーディング環境で新規ミドルウェアや設定の実験を繰り返していたため
といった理由が挙げられます。
プロビジョニングツール、本番環境とドッグフーディング環境の差異に関してはルールを決めて厳密に管理、またライブラリのアップデートも定期的に新規インスタンスを自動起動するスクリプトを作成すれば問題ないとは思います。
しかし、規模が大きくなったタイミングで導入するのはかなりのコストがかかる、またなるべく上記のようなことを考えずに実装に集中したいという思いから今回のインフラ刷新に踏み切りました。
ProductionをDockerで運用する際に考慮した点
開発環境は既にDockerizeしておりましたが、実際にProductionをDockerにて運用する為には様々な障壁にぶつかりました。
デプロイ
Blue-Green Deployment
恐らく、ECSを使用する際に最も悩むのがデプロイの方式をどのようにするかだと思います。
今まででの環境であればCapistranoを叩いてgitをpullして〜のようにデプロイ出来ましたが、コンテナの場合そのようなデプロイ方法は難しいです。
ECSのデプロイ方法として真っ先に挙げられるのがBlue-Green Deploymentです。
BG Deploymentについては割愛しますが、
- ロールバックが容易
- デプロイ時のダウンタイムを極力抑えることが出来る
のような特徴があげられます。 ロールバックの容易さ、ダウンタイム極小化の観点から弊社でもBG Deployment方式にしました。
BG Deploymentは良いことずくめに見えますが、デプロイの戦略を立てる上では中々苦労した部分です。
ECSを使用した際のBG Deploymentには以下の3種類が考えられるかと思います。
- ECSのMaximum healthy percent, Minimum healthy percentを調整し、徐々にタスクが切り替わるように調整する。
- CLB(Classic Load Balancer)× Autoscaling Groupを使用して切り替える
- ALBに紐付いているTarget groupの優先順位を切り替える
- Routes53を使用し、Standby, ActiveのELBを切り替える
結論から言うと弊社は3を選択しました。 選んだ理由やそれぞれのメリット・デメリットに関しては別の記事で書きたいと思います。
スクリプト
今までの環境であれば、Capistranoという素晴らしいツールが存在するのでそこまでデプロイ環境で悩むことも無かったですが、DockerになるとCapistrano単体でのデプロイ環境の構築は中々難しいと感じました。
デプロイの手順としては下記の通りになります。
- Task definitionの更新
- ECSのServiceをupdate
- TaskがRUNNINGになっているか確認
- インスタンスの状況を見て、ALBのTarget groupの優先順位を切り替える
現在では様々なECS向けのデプロイツールが出ておりますが、上述している通りALBのTarget groupの優先順位を切り替えるという作業が発生する為、社内専用のデプロイツールを作成する方針にしました。
この辺りも詳しくは別の記事で書いていきたいと思います。
CI
現在、CircleCIをはじめとして様々なCIサービスが出ていますね。
弊社でもCircleCIを使用し、Rubocop -> scss-lint -> RSpec -> capistranoという流れでデプロイを行っておりました。
今回の移行にあたって、Jenkinsへシフトさせました。
Jenkins移行の理由として、カスタマイズ性が一番の理由です。
弊社では、ドッグフーディング環境においてはテスト有りデプロイ、テスト無しデプロイの2種類が存在します。
cap dogfooding deploy 〜
のように手動デプロイをし、テストを通す前からディレクターに動作を確認して貰う手順をとっております。
勿論テストを通して完璧な状態で見てもらうのが一番ですが、確認を早め早めにすることによって、実装の最終段階でディレクターの意図と違う!というような不一致を極力減らすことが出来ます。
テストを通してからデプロイだとその回数が減ってしまい、リリーススピードが結果的に落ちてしまうのでテスト無しデプロイを可能にする環境を構築したいという背景がありました。
CircleCIでこのような環境を作成するのは結構な手間だったため、今回はJenkinsのパラメータ付きビルドで処理することにしました。
マイグレーション
RailsではDBスキーマの変更、データのクレンジングにActiveRecord::Migrationを使用します。
一定規模になると ActiveRecord::Migrationを使わない例が多いですが、弊社ではロールバックが容易なのとRubyで記述出来るという点で未だに使用しております。
以前の環境であればcapistranoがよしなにやってくれたのですが、今回の環境の場合、稼働用のTask definitionで実行するのは難しいと判断しました。
そこでbatch, migration専用のインスタンス・クラスタを作成し、デプロイスクリプトを走らせた際にまずmigrationを当該クラスタで実行させるようにしました。
こちらはデプロイスクリプトにバッチ専用のコマンドを実装しました。
バッチ
上記のマイグレーションに使用しているインスタンス・クラスタと併用しております。
cronによるバッチ処理+sidekiqをこのインスタンスで管理しています。
環境変数の扱い
環境変数はEC2 Systems Manager・EC2のインスタンスメタデータ・S3と様々な方法があるかと思います。
今回は管理の手軽さ、実装の容易さというメリットから、S3を選択しました。
具体的にはビルド前にS3からenvファイルをダウンロード→ビルド→デプロイ
という流れになります。
また環境によってnginxのconfやfluentdのconfの中身を変えたいという場合がありますが、
これに関してはenvsubstコマンドを使用し、ビルド時にconfの中身を動的に変えるようにしています。
assets周り
弊社ではwebpackを使用し、assetsをビルドしております。
webpackにてビルド→asset_syncを使用し、S3にアップロード→CloudfrontのInvalidationを走らせる
というフローでデプロイを行っておりました。
デプロイフローが複雑になる + Herokuも推奨していないという点から今回はこのasset_syncを使用するのをやめ、Webサーバから直接配信→サイト前段にCloudfrontを張ってキャッシュをさせるようにしました。
ログ周り
fluentdコンテナを立て、Kinesis, BigQueryにログを流すように変更しました。
厳密なログの記録が必要ないサービスに関しては、Cloudwatchにそのまま流して記録しております。
監視
zabbix-agentコンテナを立て、そこからzabbixにデータを流すようにしています。
勿論zabbix, grafana自体もDockerizeしております。
https://hub.docker.com/r/monitoringartist/dockbix-agent-xxl-limited/
非常に使い勝手が良いので、上記のイメージを使用しております。
インスタンス起動時に勝手に登録してくれてとても使い勝手が良いのですが、インスタンス消えた時にホスト情報をどう削除するか未だに悩んでおります…
以上になります。
次回からは項目ごとに具体的な事例と共に執筆していきたいと考えています。
エンジニアが暗号理論を学んでみた。〜暗号の基礎編〜
こんにちは、神山です。
今まで週3日運動してたのですが、今冬、寒さのあまり週1日のみになってしまいました。極端に寒さに弱いです。
今回は暗号理論についてブログを書かせて頂きました。
暗号理論とは
暗号理論は暗号の仕組みを研究する分野になります。Wikipediaを引用させて頂きました。
暗号理論では主に次の二つを扱う。
- 暗号系 (cryptosystem) の構成方法や性能・安全性などに関する研究
- 暗号や電子署名といった守秘 (confidentiality) や完全性 (integrity) を実現する、 暗号アルゴリズムや暗号プロトコルの研究
暗号理論では、主として、アルゴリズムやプロトコルによってセキュリティ機能を実現する研究(情報セキュリティ)がなされており、 OSやネットワークの特徴を生かしてセキュリティ機能を実現する研究(コンピュータセキュリティやネットワークセキュリティ)と区 別される。
暗号理論には、情報理論、符号理論、計算複雑性理論といった計算機科学、数論や代数幾何、離散数学といった数学、時には 力学系などの物理学の知見が用いられることもある。
引用元: https://ja.wikipedia.org/wiki/%E6%9A%97%E5%8F%B7%E7%90%86%E8%AB%96
要するに、暗号のアルゴリズムの仕組みと安全性を学ぶ学問ということです。ただ、学ぶには大学レベルの数学(主に代数分野)の知識が必要になります。
自分は数学科出身の為、大学時代に少しだけかじりました(専門外だったので習熟度は低いですが…)。最近になって、HTTPSの仕組みを学ぶのに必要になり再度勉強しております。
暗号の代表例
例えば、シーザー暗号とかRSA暗号とか聞いたことある人も多いのではないでしょうか。また合言葉も暗号の一種と言えます。
そこまで詳しくない人もいると思うのでシーザー暗号について説明しようと思います。 シーザー暗号はもとのメッセージ(アルファベットの文字列)を適当に決めた数字の数だけシフトさせて暗号化する方法です。
シフトさせる文字数を3文字としたとき。 a -> d k -> n のように、3文字シフトさせて暗号化する。 「THE ALFEE」 をシーザー暗号(文字数3)で暗号化すると、 「WKH DOIHH」 となる。
メッセージを送りたい人に事前に「3文字シフトで」と伝えておけば、暗号を送り合うことができます。
ちなみにシーザー暗号の由来は、ジュリアス・シーザーから来ております。 ジュリアス・シーザーは紀元前に活躍したとされる政治家、軍人です。「賽は投げられた」という有名な言葉を残しております。
馴染み深い例として、シェイクスピアの戯曲「ジュリアス・シーザー」はご存知でしょうか?
「ブルータス、お前もか」というセリフが出て来る有名なものです。
その「ブルータス、お前もか」のセリフを放った人こそ、ジュリアス・シーザーです。
用語
基本的な知っておくべき用語を挙げました。先程のシーザー暗号を例に取り説明します。
平文
暗号化したいメッセージのことです。「THE ALFEE」が平文です。暗号化
平文を暗号化することです。「THE ALFEE」を「WKH DOIHH」とすることです。復号
暗号文を正規の方法で平文に戻すことです。シーザー暗号で「3文字シフトした」と共有されていた場合、「WKH DOIHH」から「THE ALFEE」という平文を取り出すことを指しております。
ちなみに復号化という言葉が使われることもありますが同じ意味になります。ただ復号という言葉に「暗号を平文に戻す」という意味があるので、復号「化」とすると意味が2重になる為、本当は間違いらしいです。暗号化方式
暗号の名称です。シーザー暗号やRSA暗号などにあたります。鍵
平文を暗号化するのに使うもの、また暗号文を復号するのに使うものです。暗号化方式がシーザー暗号の場合、シフトさせる文字数が鍵です。上の例だと「3」が鍵になります。解読
これは復号と似て非なるものなので注意してください。暗号文から平文を取り出すことではあるのですが、鍵を知らない状態で取り出すことです。
例えば、「探偵が暗号を解読した」というセリフがドラマ等であると思います。これは探偵が鍵を知らない状態で暗号を読み取るからです。基本的に探偵がするのは「解読」です。
もし「復号」としたら、探偵自身が重要参考人ですね(暗号を平文に戻す方法を知っているということなので)。
そもそも暗号とは?
最後に暗号を数学的に説明しようと思います。
暗号化方式とは。 P: 平文の集合(plaintext) C: 暗号化文の集合(ciphertext) K: 鍵の集合(key) E: 暗号化関数の集まり(encryption function) (暗号化関数とは、平文を暗号化するもの。シーザー暗号(文字数3)で暗号化することだと考えればよい。) D: 復号関数の集まり (decryption function) (復号関数とは、暗号文を復号するもの。暗号文をシーザー暗号(文字数3)で復号することだと考えればよい。) この5つからなるものを暗号化方式という。また下記を満たさなくてはいけない。 ∀k ∈ K, ∀p ∈ P, ∃e ∈ E => ∃d ∈ D, d(k, e(k, p)) = p (直訳すると、適当な鍵を用いて平文を暗号化したとき、必ず復号できる方法があるということ。)
数学用語で書いてみましたが、基本的に最後の直訳を理解して頂ければ大丈夫です。 数学こそ、簡単な言葉をただ難しくする暗号ですね。
他にも、秘密鍵暗号(共通鍵暗号)とか公開鍵暗号とか書きたいことがあるのですが、内容が重くなりすぎるのでまた別の機会で書こうと思います。
We’re hiring!!
Cluexではビジネスサイド、エンジニアサイド共にメンバーを募集しています!
お気軽にご連絡下さいませ! エンジニアの方、ぜひ情報交換しましょう!