Build Insiderオピニオン:花井志生(2)
自宅サーバーか、クラウドか ― 開発/テスト機の採用基準と最適なミックス
個人の開発/テスト機でもクラウド(調達)の方が安いといえるのだろうか? 自宅サーバー(所有)の方が割安なケースを考え、両者のメリットを生かす手法と実践手順の例を示す。
「クラウドを活用することでTCO(Total Cost of Ownership)の削減を」というのは、クラウド導入時の常套句であったが、最近はそういったセールストークより、柔軟な構成が可能なことや、必要に応じて瞬時にサーバーを調達できるといった点が評価されつつある。とはいえ、物理サーバーを自分で用意するよりもクラウドの方が安いという感覚は今でも健在であろう。
今回は、開発者の方が誰しも個人的に所有していると思われる自分専用の開発/テスト機に焦点を当て、果たしてクラウドが安いのかどうかを検討してみたい。
自宅サーバーを置く場合の問題点
今回検討する開発/テスト機には、例えば継続的統合(CI)のためのビルドサーバーや、あるいは新技術を一定期間評価してみるためのサーバー機を想定している。まずはこうしたサーバー機を自宅に置く場合の問題点を挙げてみたい。
固定IPアドレス
現在多くのコンシューマー向けのISP(インターネット・サービス・プロバイダー)は、固定IPアドレスの提供をしていないか、あるいは提供していても高額なケースが多い。逆に固定IPアドレスの提供を売りにしているISPもあるが、速度があまり出ないなど、他の面で不利なケースが少なくない。このため自宅サーバーを置こうと思うと、その点だけでISP代金がかさんでしまったり、ISP選択の幅が狭まったりしてしまう。DDNS(ダイナミック・ドメイン・ネーム・システム)の活用なども考えられるが、IPアドレスの切り替えの手間など課題が多い。
電気代
開発や評価に使用するサーバー機であれば、常に高負荷をかけるわけではないので、それほど多くの電力を使用するわけではないが、仮に平均で100Wと考えても、1カ月当たり2000円くらいかかる計算となる(26円/kwhとして、0.1×26×24×30=1872円)。
保守
SSDが一般的になる前までは、自宅サーバーを持つ上での懸念の筆頭が、HDDのクラッシュであった。PC用のHDDは2年も連続稼働すれば壊れるため、RAIDを用いる必要がある。しかも「RAIDを用いれば問題は解決」という単純な話ではない。RAIDであろうとエラーは、そのセクターにアクセスしてみなければ検出できないからだ。このため長年アクセスしていなかったファイルが知らないうちに壊れていて、いざ取り出そうとしたら復旧不可能という憂き目に遭遇する可能性がある。
業務であればテープやフラッシュメモリへの全セクターコピーを定期的に行うことになるが、自宅サーバーでこのような対策は大袈裟だろう。RAID製品によってはScrubという機能があって、定期的に全セクターを読み出してエラーを検出してくれる。SSDになって、信頼性は大幅に上がったが、とはいえ絶対に壊れないというわけではない。自宅サーバーを置く場合は、こうした保守回りを自分で考えておかなければならない。
クラウド化で解決されること、解決されないこと
自宅サーバーをクラウド化することで、上記の課題は解決されるのだろうか。一口にクラウドといっても、クラウドベンダーによって特性は異なる。例として、さくらのVPSを見てみよう。メモリ1GBytesでSSD 30GBytes、CPU 2Coreのプランだと月額972円(2016年5月現在、以下の金額表示については同様)となっている。これは上で試算した電気代と比較してみても驚異的である。もう1つの例として、Bluemixの料金を見てみよう。このページは料金計算ができるようになっているが、コンテナー(Docker)でメモリ512MBytes、固定のグローバルIPアドレス2つを選択した場合、無料と表示される(恐らくバーゲン価格なので、料金については常に最新の状況を確認してほしい)。なるほど確かに、これらを見るとクラウド化によってTCOが削減できるというのは間違いなさそうである。
ここで注意が必要なのは、上記はいずれも(主にメモリやディスクサイズの面で)低スペックの環境であるという点である。例えばインメモリデータグリッドが使い物になるかどうか、ある程度、長期間試験運用してみるため32GBytesのメモリが搭載されたサーバー機が必要だとしよう(多くのクラウドでは、メモリ量とCPUコア数を独立して選択できないので、32GBytesメモリ量を実現できる最低のスペックで比較)。さくらのVPSでは月額3万240円となる。VPSでない、さくらのクラウドで試算すると、月額2万6892円となる。AWSでリザーブドインタンスを使った場合、r3.xlarge(RAM 30.5GBytes)で月額$152.57である。
AWSの料金は一見、さくらより安く見えるが、AWSではネットワークトラフィックにも課金されるため。実際の請求額はこれよりも高くなるだろう。つまり、このクラスのクラウドを使おうと思うと月額料金は数万となってしまう。もしも2年間維持すれば総額は50万円前後となり、電気代を考えたとしてもハイエンドのPCを自宅に置く方が確実に安上がりとなるだろう。
もちろんハイスペックサーバーなら常にクラウドが割高というわけではない。きちんと準備をした上で、2時間だけ大量の計算を実行したいという用途であれば、料金は2時間分だけで済むのでクラウドの方が圧倒的に安くて済むだろう。要は特性を考えて適所に使わないとクラウドといえど、かえって割高になってしまうということだ。
最適な「クラウド+自宅サーバー」ミックスを考える
自宅サーバーとクラウドの強み・弱みが見えてきた。そもそもどちらかに統一する必要はない。最適なコストパフォーマンスを発揮できるような構成を考えてみよう。
クラウドをリバースプロキシにする
図1はNginxのようなWebサーバーをリバースプロキシとして使用し、自宅サーバーでAPサーバーを稼働する構成例である。この構成では自宅サーバーでは苦手な固定IPアドレスの取得をクラウド側に任せ、クラウドでは割高になってしまうハイスペックサーバーを自宅側に任せることで特性に合わせたすみ分けを実現している。今回はこの構成を実現するための実装を考えてみよう。
リバースプロキシを構成する
この構成で問題となるのは、自宅サーバー側に固定IPアドレスがないことだ。Nginxでリクエストを受けても、そのままでは自宅サーバー側にリクエストを転送できない。今回はSSHのリバースポートフォワードを用いて、これを解決することにする。図2はリバースプロキシの構成を詳細化したものである。
autossh
コマンドを自宅サーバー側で実行してリバースポートフォワードを用いることで、クラウド側のNginxから自宅サーバー側にリクエストを転送できるようにしている。autossh
コマンドは、SSHで接続しつつ、エラーが起きた際には自動的に再接続が実施される。図2で指定しているオプションの意味は以下の通りである。
-f
:autossh
コマンドをバックグラウンド実行する-M0
: 古いポート監視のやり方を無効化する-o "ServerAliveInterval 60" -o "ServerAliveCountMax 3"
: 監視方法の指定(1分に1回接続状態の調査。リトライを3回まで行う)-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
: Dockerでsshd
を動かすと、コンテナー実行ごとにSSHサーバー側のホスト鍵が変わって確認を求められるため、それを回避する設定-N
: SSHでリモートコマンドを実行できないようにする(ポート転送専用としてセキュリティを高める)-R3000:localhost:8000
: クラウド上でのポート3000へのアクセスを自宅PCのポート8000に転送する-i /path/to/id_rsa
: 秘密鍵ファイルnginx@cloud001
: SSHの接続先
HTTP/HTTPSポートへのアクセスを図3に示す。クラウド側のポート3000は、自宅サーバーのポート8000に転送されている。Nginxはあらかじめ(ポート80で受け取った)リクエストをポート3000に転送するように設定しておく。これによりクラウドのHTTP/HTTPSリクエストを自宅サーバー側で処理することが可能となる。
リバースプロキシを動かしてみる
今回は無料で使用できるBluemixを用いてリバースプロキシを構成してみることにする。図2に示したクラウド側の構成はあらかじめDockerコンテナー上に実装し、docker hub
コマンドでビルドしてある(イメージ名:「ruimo/reverse-proxy
」)。Dockerfileはこちらに置いてある。
1. キーペアの作成
あらかじめssh-keygen
コマンドを用いてキーペアを生成しておく。このときパスフレーズはなしにする。キーペアの生成の詳細については、ここでは割愛する。
2. ファイルの配置
ディレクトリを作成して、以下のようにファイルを配置する。
authorized_keys
Dockerfile
nginx
+-- conf.d
+-- my.conf
|
authorized_keys
ファイルは、1で生成した公開鍵の内容である(.pub
という拡張子の付いたファイル)。
Dockerfile
ファイルの内容は以下のように、ほぼ空である(必要な処理はベースにしているruimo/reverse-proxy
内で実行される)。
FROM ruimo/reverse-proxy
MAINTAINER Shisei Hanai<ruimo.uno@gmail.com>
|
Nginxの設定ファイル(my.conf
ファイル)にはNginxからAPサーバーへの転送設定を記述する(今回は、ポート3000に転送するようにしている)。
server {
listen 80 default_server;
index index.html index.htm;
location / {
proxy_pass http://localhost:3000;
proxy_set_header host $host;
}
}
|
3. Dockerイメージのビルド/タグ付け/プッシュ
docker build
コマンドを用いてイメージをビルドする(ruimo
の部分は、Dockerでの自分のユーザー名としてほしい。以降同様)。
$ docker build -t ruimo/my-reverse-proxy .
|
Bluemixのプライベートリポジトリに上げるためにタグ付けを行う。ここでregistry.ng.bluemix.net/ruimo/my-reverse-proxy
内のruimo
の部分は、Bluemix上でのprivate docker
イメージレポジトリの名前空間名である(BluemixでのDockerの使用方法については以下の4を参照のこと)。
$ docker tag ruimo/my-reverse-proxy registry.ng.bluemix.net/ruimo/my-reverse-proxy
|
Bluemixのプライベートリポジトリにpushする(なお、ここでauthentication errorが表示される場合は、cf ic login
コマンドを実行する。cf
コマンドについては以下の4を参照のこと)。
$ docker push registry.ng.bluemix.net/ruimo/my-reverse-proxy
|
4. Dockerイメージの実行
Bluemix上で実行する。なおBluemixのcf ic
コマンドのセットアップについては、ここでは省略するので適宜(「BluemixでDockerを使う」などを参照して)設定しておいてほしい。
$ cf ic run --name my-reverse-proxy -P -m 512 registry.ng.bluemix.net/ruimo/my-reverse-proxy
|
5. グローバルIPアドレスの取得とコンテナーへのバインド
グローバルIPアドレスを取得する(以降の解説では、169.44.8.170
の部分を、ここで得られたIPアドレスに読み替えてほしい)。
$ cf ic ip request
OK
The IP address "169.44.8.170" was obtained.
|
上で取得したグローバルIPアドレスを、4で実行したコンテナーにバインドする。
$ if ic ip bind 169.44.8.170 my-reverse-proxy
|
6. アプリが開始されるまで待機
cf ic ps
コマンドで、STATUS
がRunning
になるまで待つ。
$ cf ic ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a25a2b28-a68 registry.ng.bluemix.net/ruimo/my-reverse-proxy:latest "" 55 seconds ago Running 24 seconds ago 169.44.8.170:22->22/tcp, 169.44.8.170:80->80/tcp, 169.44.8.170:443->443/tcp my-reverse-proxy
|
cf ic ps
コマンドでSTATUS
がRunning
になっているかを確認する(強調書体部分)。
7. 自宅サーバーからリバースプロキシへの接続の確認
リバースプロキシ側が起動したので、自宅サーバーから接続する。今回は自宅サーバー側に、ポート8000で待ち受けるAPサーバーが存在すると仮定している。
まず1で作成した秘密鍵を、自宅サーバー上に転送しておく。そしてchomd
コマンドを用いて、ファイル属性を400に変更する(このファイルは他人から見えない場所に配置する。この処理専用にユーザーを作成するのがよい)。
$ chmod 400 id_rsa
$ ls -l id_rsa
-r-------- 1 shanai shanai 1679 5月 6 15:46 id_rsa
|
以下のコマンドを実行して、接続を確認する。
$ ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -N -g -R3000:localhost:8000 -i /path/to/id_rsa sshnginx@169.44.8.170
|
リバースプロキシ側ではNginxのリクエストをポート3000に転送するように設定し、自宅サーバー側のAPサーバーはポート8000をリッスンしているので、-R3000:localhost:8000
を指定している(必要に応じて変更してほしい)。「/path/to/id_rsa
」の部分には、上で配置した秘密鍵ファイルの場所を記述する。
ここまでできれば、http://169.44.8.170
にブラウザーでアクセスすることで、自宅サーバーのAPサーバーのコンテンツが見えるはずである。
8. 自宅サーバーの設定を変更
動作が確認できたら、自宅サーバーでリバースプロキシとの接続を自動実行するようにしておく。簡単なのは、/etc/rc.local
ファイルに以下のように記述を追加することである。
su - user -c "autossh -f -M0 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -N -R3000:localhost:8000 -i /path/to/id_rsa sshnginx@169.44.8.170"
|
su
コマンドに指定している「user
」というのは、今回のポート転送を実行するため専用に作成したユーザーである。また、id_rsa
ファイルをchown
コマンドを用いてこのユーザーの所有に変更しておくこと。
Bluemixは現在のところ日本にリージョンがないため、応答速度が若干遅いが、今のところは無料でリバースプロキシを運用することが可能だ。Dockerを使用しているので、Docker対応したクラウドであれば、他のクラウドでも、今回の仕組みをほぼそのままで利用可能のはずだ。もちろんIaaSの場合は自分でDockerをインストールすれば利用可能だ。
なお、クラウドによってはネットワーク転送に対して従量課金されるケースがあるので、今回のようにリバースプロキシとして利用するケースでは十分に注意してほしい。
まとめ
クラウドを活用することで、一般にはコストが削減できるが、適用箇所によっては割高になってしまう場合がある。今回は開発/テスト機に焦点を当て、高スペックなサーバー機のみを自宅で稼働することでトータルの料金を抑える方法を紹介した。これは業務でも同様で、クラウドの特性と価格体系をよく理解した上で、適切なクラウド+オンプレのミックスを考えないと、割高になってしまうケースも出てくるだろう。
花井 志生(はない しせい)
入社当時はC/C++を用いた組み込み機器(POS)用のアプリケーション開発に携わる。
10年ほどでサーバーサイドに移り、主にJavaを使用したWebアプリケーション開発に軸足を移す。
2015年夏からクラウドを用いたソリューションのテクニカル・コンサル、PoCを生業としている。
主な著書にJava、Ruby、C言語を用いたものがある。
1. Dockerでビルドを改善する
開発現場で役立つ記事や書籍を多数著している花井志生氏がオピニオンコラム初登場。今回は、コンテナー型の仮想実行環境「Docker」を使ってCIを行うことのメリットを考察。