エンジニアが暗号理論を学んでみた。〜共通鍵暗号と公開鍵暗号〜

こんにちは、神山です!

先日GWでしたが、皆さんはいかがでしたか。
自分は2日目から風邪を引いて、GWの最後まで寝ておりました。

東京の風邪と夜通しのモノポリーほど長引くものはないですね。

さて、前回は暗号理論の基礎的な内容を書いたので、今回は2種類の暗号方式(共通鍵暗号公開鍵暗号)について説明しようと思います。

前回の記事はこちら

f:id:cluex-developers:20170512201053j:plain

では、まず共通鍵暗号について解説していきます。

共通鍵暗号

共通鍵暗号とは暗号化と復号に同じ鍵を使用する暗号方式です。秘密鍵暗号とも言います。

身近な例

合言葉や共通認識等は共通鍵暗号です。

よくお酒を飲みに行くときに「一杯ひっかけます?」と言ったりしますよね。これは「お酒を飲みに居酒屋に寄って行きます?」ということを暗号化しております。
「お酒を飲みに居酒屋に寄って行きます?」を「一杯ひっかけます?」と暗号化していることを受け手が知っていれば、きちんと復号して飲みに行くことを理解出来ます。

あまりに身近な例なので、今度は有名な共通鍵暗号を紹介します。

シーザー暗号

これは英文を伝える時に、全てのアルファベットを指定数分ずらして英文を送ることです。

シフトさせる文字数を3文字としたとき。
a -> d
k -> n
のように、3文字シフトさせて暗号化する。

「THE ALFEE」
をシーザー暗号(文字数3)で暗号化すると、
「WKH DOIHH」
となる。

鍵は文字数(今回だと「3」)です。
受け手がこの鍵を知っていれば、送られてきた英文を3文字前に戻すことで「THE ALFEE」を得ることが出来ます。

しかし、共通鍵暗号には重大な欠点があります。

鍵共有問題

これは肝心の鍵を共有する安全な方法がないということです。
共有鍵暗号はお互いに鍵を知っているという前提のもと成り立ちます。その為、まず鍵を安全に伝える手段がないと使う事ができません。

口頭で伝えるという原始的な手段はあります。しかしこれはあくまで伝えたい人が近くに居る状態で、誰にも聞かれない状態でなければなりません。
そもそもこの状態であれば、暗号化する必要もないでしょう。

通信手段を使うには、安全に伝えられる方法を探さなければなりません。安全に伝える手段こそ暗号なのですが、皮肉なことに暗号を使うために暗号が必要になってしまいました。
これでは鶏が先か、卵が先か問題になってしまいます。

f:id:cluex-developers:20170512201217j:plain

さてこの問題を解決してくれるのが、公開鍵暗号です。

公開鍵暗号

公開鍵暗号とは、暗号化する鍵と復号する鍵が違う暗号方式です。暗号化する鍵(公開鍵)は公開し、復号する鍵(秘密鍵)は秘密に管理します。
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の盛り上がりを支えているようです。

f:id:cluex-developers:20170428200508p:plain

Go 2016 Survey Results - The Go Blog

本番環境のインフラストラクチャ

実際に本番環境で使用するにあたって、 インフラの構成やデプロイ周りは必ず考慮しなければなりません。

これまで本番環境にはAWSのEC2を使用していましたが、今年の3月にAWSのECSによるDockerでのサーバー運用にインフラを全面移行しました。

cluex-developers.hateblo.jp

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 RailsAPIを組む大きな理由がそこまでありません。 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でいうSinatraRailsのような、立ち位置が定まっているフレームワークがまだはっきりしていない状況です。 またirisのような、スター数は多くてもOSSでの開発方針として、一般的な方針とは乖離が大きいフレームワークもあったりします。

ORM

ORMに関しては、現状Golangの主なWebアプリケーションフレームワークにはORMが入っていません。 ORMのライブラリとしてはいくつも候補がありますが、gormはActiveRecordに近い書き方で実装出来るようになっている為、Railsエンジニアも比較的手をつけやすいと思います。

サードパーティパッケージ

フレームワークやORMを含めて、GolangサードパーティのパッケージはGemに比べるとまだまだ発展途上で、似たようなものが乱立している状況です。

下手にアプリケーションに取り込んで後に更新が止まったりしてしまうと、負債となってしまいそうなので、可能な限り少ないライブラリで対応するようにしています。

ライブラリもフレームワークも、別のパッケージに乗り換えやすいようなコードベースへの配慮が必要かと思います。

まとめ

Golangの導入の背景や、導入に際して考慮した点などを簡単にまとめました。

また近いうちに、実際に開発していく上で良かった面や大変だった面などを記事にしていければと思います。

Docker with ECS × Railsを実現させるために考えたこと(デプロイ編)

こんにちは。エンジニアの志村です。

cluex-developers.hateblo.jp

の続きとなります。 今回はタイトル通り、デプロイ辺りを執筆していければと思います。

Blue-Green Deployment

Blue-Green Deploymentはマーチン・ファウラー氏が提唱したデプロイ方式です。 blue, greenとほぼ同じ本番環境を2系統用意してデプロイを行います。このデプロイ方式ですが、

  1. ダウンタイムの極小化
  2. ロールバックが容易

という大きな2つの利点があります。

Dockerizeへのモチベーションとして前回の記事にも書いたのですが、徐々にドッグフーディング環境・本番環境で差異が出てきました。
そのような状況だと、ドッグフーディングでは正しく動作したのに本番環境では意図した挙動とは違うという場面も出てきます。
上記のようなトラブルがあった際に今までのIn place型のデプロイ方式だとロールバックに時間がかかり、ユーザーに迷惑をかけてしまう時間が長くなるという問題がありました。
Blue−Green Deploymentでは特に2.の「ロールバックが容易」という点が非常に魅力でした。
何かトラブルがあったとしてもELB設定を変えてしまえば瞬時に旧環境に戻せるという点で、デプロイに対する心理的ハードルが社内全体で下がりました。

また、ECSの仕組みにより今までのようにCapistranoによるSSHを用いたデプロイが難しかったという理由も相俟って、弊社でもBlue−Green Deploymentを用いております。

ECSによるBlue-Green Deployment

前回の記事にも書いた通り、ECSを使用した際のBlue−Green Deploymentにはいくつかやり方が存在します。

  1. ECSのMaximum healthy percent, Minimum healthy percentを調整し、徐々にタスクが切り替わるように調整する。
  2. CLB(Classic Load Balancer)× Autoscaling Groupを使用して切り替える
  3. Routes53を使用し、Standby, ActiveのELBを切り替える
  4. ALBに紐付いているTarget groupの優先順位を切り替える

ECSのMaximum healthy percent, Minimum healthy percentを調整し、徐々にタスクが切り替わるように調整する。

利点

  • ECSデフォルトの機能を用いるので、他に余計な操作をする必要が一切ない
  • タスクの増減を元にデプロイを行うのでインスタンス料金を低く抑えることが出来る

欠点

ECSの特徴が最大限発揮されたデプロイ方式だと考えます。
ECSには「タスク」という概念があります。タスクはDocker imageを起動させる際の設定、またそのリビジョンです。
タスクは

  1. 使用するdocker image
  2. コンテナ間のリンク
  3. コンテナのコマンド
  4. データボリューム

等が設定できます。 リビジョンが用意された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が使用できない雰囲気ではありました。 しかしながら、現在では下記のように使用できるようです。

dev.classmethod.jp

これで課題は1つクリアしましたが、SpotFleetがAutoscaling Groupに登録出来ない為、今回この方式は断念しました。
ロールバックを容易かつスピーディにするにはインスタンスの数が単純に倍必要となります。SpotFleetの使用は予算の都合上、必要でした。 またこの方式だとヘルスチェックの観点から、Blue, Greenが重なるタイミングがどうしても出てきます。
マイグレーション・モデルの変更をした際に、旧稼働系・新稼働系が混ざるとエラーを引き起こし兼ねません。この観点からも今回は見送りました。

Route53を使用し、Standby, ActiveのELBを切り替える

利点

  • ダウンタイムほぼ無し
  • シンプル

欠点

一番古典的かつ確実方式です。 Route53のWeightを利用し、Blue→GreenのELBに徐々に切り替える方式です。
実装がシンプルではありますが、一番の問題点はDNSキャッシュです。
キャッシュサーバによってはTTLを無視して一定期間キャッシュするものもあるらしいので、実際にデプロイが完全に完了したかを確認するのが難しくなります。
上記のようなキャッシュのコントロールの難しさから、今回この方式は見送りました。

ALBに紐付いているTarget groupの優先順位を切り替える

利点

  • ダウンタイムほぼ無し
  • ロールバックが早い
  • メンテナンスにすぐ切り替えられる

欠点

  • 実装が面倒

結論から言うとこの方式を採用しました。
いくらか利点はありますが、特にロールバックが容易な点が大きいかと思います。
ALBにはパスベースルーティング、ホストベースルーティングという機能があります。
パスベースルーティングは下記にある通り、パスによってどのターゲットグループにトラフィックを流すかを決定できます。

tartget.png

例えば、

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. デプロイ
  2. 単発のタスク起動
  3. ロールバック
  4. ステータス表示

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に導入してみました。
今回は開発環境だけですが、次回本番運用に関して書いていきたいと思います。

環境

  • Ruby 2.3.3
  • Rails 5.0.2
  • Node.js 6.9.1
  • npm 3.10.8

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

f:id:cluex-developers:20170329110722p:plain

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 モジュールと、CSSJavaScriptでロードせずに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.jsclient/src/stylesheets/application.css をrequireさせます。
画像などもwebpackで配信したい場合は、同様に application.js にrequireさせます。

client/src/javascripts/application.js

/**
 * Require stylesheets
 */
require('../stylesheets/application.css');

Rails側の設定

assets部分は webpack-dev-server から取得するため、 app/views/layouts/application.html.erb のheadタグの stylesheet_link_tagjavascript_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 snpm 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 に変更した時に自動でブラウザの更新を行い色が変わりました。

f:id:cluex-developers:20170330171922g:plain

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.jspostcss の 方でこちらのプラグインを最初に読み込ませておくようにしましょう。

@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ではエンジニアサイド、ビジネスサイド共にメンバーを募集しています! お気軽にご連絡下さいませ! エンジニアの方、ぜひ情報交換しましょう!

www.wantedly.com

www.wantedly.com

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については割愛しますが、

  1. ロールバックが容易
  2. デプロイ時のダウンタイムを極力抑えることが出来る

のような特徴があげられます。 ロールバックの容易さ、ダウンタイム極小化の観点から弊社でもBG Deployment方式にしました。

BG Deploymentは良いことずくめに見えますが、デプロイの戦略を立てる上では中々苦労した部分です。
ECSを使用した際のBG Deploymentには以下の3種類が考えられるかと思います。

  1. ECSのMaximum healthy percent, Minimum healthy percentを調整し、徐々にタスクが切り替わるように調整する。
  2. CLB(Classic Load Balancer)× Autoscaling Groupを使用して切り替える
  3. ALBに紐付いているTarget groupの優先順位を切り替える
  4. Routes53を使用し、Standby, ActiveのELBを切り替える

結論から言うと弊社は3を選択しました。 選んだ理由やそれぞれのメリット・デメリットに関しては別の記事で書きたいと思います。

スクリプト

今までの環境であれば、Capistranoという素晴らしいツールが存在するのでそこまでデプロイ環境で悩むことも無かったですが、DockerになるとCapistrano単体でのデプロイ環境の構築は中々難しいと感じました。
デプロイの手順としては下記の通りになります。

  1. Task definitionの更新
  2. ECSのServiceをupdate
  3. TaskがRUNNINGになっているか確認
  4. インスタンスの状況を見て、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を張ってキャッシュをさせるようにしました。

devcenter.heroku.com

ログ周り

fluentdコンテナを立て、Kinesis, BigQueryにログを流すように変更しました。
厳密なログの記録が必要ないサービスに関しては、Cloudwatchにそのまま流して記録しております。

監視

zabbix-agentコンテナを立て、そこからzabbixにデータを流すようにしています。
勿論zabbix, grafana自体もDockerizeしております。

https://hub.docker.com/r/monitoringartist/dockbix-agent-xxl-limited/

非常に使い勝手が良いので、上記のイメージを使用しております。
インスタンス起動時に勝手に登録してくれてとても使い勝手が良いのですが、インスタンス消えた時にホスト情報をどう削除するか未だに悩んでおります…

以上になります。
次回からは項目ごとに具体的な事例と共に執筆していきたいと考えています。

エンジニアが暗号理論を学んでみた。〜暗号の基礎編〜

f:id:cluex-developers:20170228215203j:plain

こんにちは、神山です。
今まで週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ではビジネスサイド、エンジニアサイド共にメンバーを募集しています!
お気軽にご連絡下さいませ! エンジニアの方、ぜひ情報交換しましょう!

www.wantedly.com

www.wantedly.com

GrafanaでZabbix/CloudWatchのメトリクス監視を一元化する

f:id:cluex-developers:20170213113941p:plain

Grafanaかっこいいですよね。いつまでも見ていられそうです。

今回は統合監視ツールZabbixとAWSのCloudWatchメトリクス群を Grafanaで一元的に可視化して見れるようにしてみます。

今回の背景

CloudWatchやEC2のメトリクスを見るのに、 AWSにコンソールで入っていちいち確認するの面倒じゃないですか。 加えてサービスごとにAWSアカウントが分かれているとなると更に不便じゃないですか。

・よりリアルタイムなデータを見たいものはZabbixのメトリクスを使用したい

・ELBにアタッチされてるホストの数も見たい

・オートスケーリングどんな感じか見たい

インスタンス毎のメトリクスも見たい

・ついでにサービス全体でどれくらいの負荷がかかってるかも見たい

・なんなら複数のAWSのアカウントを跨いで見れると尚良い

 

・・・ということで全部grafanaに突っ込みました。

 

構成

今回のメインはzabbix-server、Grafana及びCloudWatchあたりになります。

構成はこんな感じです。

f:id:cluex-developers:20170213111236p:plain

Grafanaは標準でCloudWatchをサポートしていて、 Zabbixもプラグインを入れることでデータソースとして使用することが可能です。

ちなみにGrafanaで標準サポートされているデータソースがこちら

・CloudWatch

・Elasticsearch

・Graphite

・InfluxDB

・OpenTSDB

・Prometheus

Zabbixも標準でサポートしてくれると嬉しいです。

grafanaをインストールする

インストールはOSはUbuntuベースで話を進めていきます。

Ubuntu以外に関してのGrafanaのインストールは、詳しくはこちらをご覧ください。

Grafana - Installation

$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_4.1.1-1484211277_amd64.deb
$ sudo dpkg -i grafana_4.1.1-1484211277_amd64.deb
$ sudo apt-get install grafana

   

grafanaにZabbixのプラグインをインストール

$ sudo grafana-cli plugins install alexanderzobnin-zabbix-app

GitHub - alexanderzobnin/grafana-zabbix: Zabbix plugin for Grafana dashboard

   

grafanaを起動

$ sudo service grafana-server start

 

Grafana自体にHTTPサーバーの機能も内臓されているので、これでGrafanaが立ち上がります。 デフォルトでは3000番ポートを使用するので、適宜リバースプロキシでnginxを前にかませるといいかと思います。そのままでも問題なく使えます。

 

では次にZabbixのデータを取り込んでいこうと思います。

Zabbix側でgrafana用のユーザーを作成

Zabbix側の手順としては

・grafana用のユーザーを作成する。

・grafana用ユーザーにREAD権限を付与。

といった流れになります。

 

ちなみにZabbix側でgrafanaユーザーに適切なパーミッションを与えていなかった結果、grafanaからAPI叩いてもデータが取れずに2時間ばかり無駄にしたのは私です。 パーミッションを与えてください。

 

Zabbixのパーミッションなどは本家にドキュメントがあります。

www.zabbix.com

grafanaでZabbixデータソースの設定

左上のロゴから、[Data Sources] → [Add data source]と辿っていきます。

設定はこんな感じです。

f:id:cluex-developers:20170213123526p:plain

 

Zabbixには標準でAPIが用意されているので

http://エンドポイント/zabbix/api_jsonrpc.php をURLのところに設定してあげます。

 

Zabbix API Detailsには先ほどZabbix側で作成したgrafana用ユーザーのUsernameとPasswordを設定してください。

今回は便宜上、Zabbix Serverが入っているEC2インスタンスにGrafanaも入れているのでVPCやSGなどは特に気にせず、GrafanaをプロキシとしてlocalhostでZabbixのエンドポイントを叩いています。

 

Zabbix用のダッシュボードを作成

ダッシュボードの作り方などはServerworksさんのこちらのブログが詳しいです。

blog.serverworks.co.jp

個人的な要件:EC2のメトリクス表示をオートスケーリングに対応させたい

Grafanaでダッシュボード作ったのはいいものの、 オートスケーリングでインスタンスが増減するたびにグラフの設定し直すのとかめちゃめちゃ面倒ですよね。

そもそもオートスケーリングしなくてもインスタンス多いとグラフ作るのが面倒。

でも1つのパネルで全インスタンスのCPU利用率とか表示させたい。

解決策:正規表現でフィルタリングができる。

f:id:cluex-developers:20170213111421p:plain

文字が黄色くなっている箇所ですが、Host名でフィルタをかけて、ホスト名がマッチするサーバー群のメトリクスを一発で表示することができます。

上の設定だけでこんなグラフがすぐに出来上がります。

f:id:cluex-developers:20170213111439p:plain

これだけでもパネル設定がかなりラクになりました。

そのほかの色々なグラフなどの作り方はgrafana-zabbix.orgが出しているデモの設定が参考になります。

http://play.grafana-zabbix.org/dashboard/db/grafana-zabbix-demo

GrafanaでCloudWatchをデータソースに設定する

続いてGrafanaにCloudWatchのデータを取り込んで、グラフを表示させていきます。

AWS IAMでgrafana用のユーザーを作成

CloudWarchReadOnlyAccess ポリシーをアタッチしたユーザーをIAMで作成します。 Grafanaの方で使用する認証情報はアクセスキー及びシークレットキーになります。

GrafanaでCloudWatchデータソースの設定

本家Grafanaのドキュメントではaws-cliのクレデンシャルファイルを使用した設定方法となっていますが、 設定画面から直接IAMユーザーのアクセスキーとシークレットキーを入れることも可能です。

Grafana - AWS CloudWatch

個人的にはサーバーの中に credential を置く必要ないので、GUIで設定しちゃうとがラクかなと思います。 GUIで設定しても、再度設定を開くとアクセスキーなどは見れないようになっています。

f:id:cluex-developers:20170213111502p:plain

これでCloudWatchの方からもメトリクスを表示が可能となりました。

複数のAWSアカウントを設定する際も同じ要領でIAMユーザーを作成し、データソースを追加していくことでGrafanaからデータを取り出せます。

   

ELBのHealthyHostCountをパネルに表示する

試しにCloudWatchからのメトリクスとしてELBにアタッチされているHealthyHostCountのメトリクスを表示させてみます。

設定としてはこんな感じです。 f:id:cluex-developers:20170213121249p:plain

これでZabbix及びCloudWatchからデータが取れるようになったので、あとはパネルを一通り作れば、完成です!

f:id:cluex-developers:20170213111537p:plain

     

【番外編】 AWSの請求情報をgrafanaで確認する

AWSの請求情報、ついでにGrafanaで見たくないですか? 私は見たいです。

例えばこんな感じ。 f:id:cluex-developers:20170213112148p:plain

Grafanaの公式サイトにあるテンプレートを使えばすぐに表示させることができます。

   

grafana.net

上記のものだとインポートした後にカスタマイズができないので、 インポートした後にカスタマイズしたいという方には、カスタマイズできるやつ置いておきます。

よかったら使ってください。

GitHub - yoshi42662/Grafana-AWS-Billing-Dashboard

We’re hiring!!

Cluexではビジネスサイド、エンジニアサイド共にメンバーを募集しています! お気軽にご連絡下さいませ! エンジニアの方、ぜひ情報交換しましょう!

www.wantedly.com

www.wantedly.com

www.wantedly.com

www.wantedly.com