Dockerが隆盛な状況において、コンテナを使った個人的なWebアプリケーションを構築したノウハウ

個人で運用している-web-サービスをどう管理しているか-2018年版-3486f3f69424

 個人でやっているWebサービスの管理方法を、オープンにしてくれている記事を見つけた。サービス選定の考え方とか非常に参考になった。サービス利用料を天秤にかけた判断をやっていて、個人でやるにはそこまではやっぱりねというところで安心したり。
 ぼくも趣味と勉強のためにこのブログのエンジン自体から開発して、ホスティングサービスを選んだりとやってきた。そのあたりで考えてきたことをここでまとめておく。


コンテナホスティングサービス
============================
 VPSとかIaaSとか避けたい。避けたい。
 このブログはDockerを使ってコンテナとして開発したものを、コンテナホスティングサービスを使って運用している。
 なぜコンテナを使ったかと言えば、サーバ構築がすんげー楽だし、構成管理もDockerfileを書けばそれでやっていける。AWS、Azure、GCPなどの巨大クラウドベンダが2017年のうちにこぞってクラウドでコンテナを使えるようにしただけでなく、そのさきの管理サービスを作っていたので、もうコンテナに手を出すのを待っている段階ではなくなったと思っている。コンテナ技術でサーバの用意が楽になるし、もうそれを利用する基盤は整ってきている。もしコンテナがこの世から消えるようなことがあるならどこかのPaaSを利用するまでである。このブログの初期はAzureのPaaSで運用していたので、移行はたいしたコストにならないとわかっている。
 まあそんなことを言ってもAzureなどの主要クラウドは利用料金が高い。ホビーユースはちょっとねというところ。だからさくらインターネットのArukasに期待していたが、ついにはベータから脱皮せずに消えていった。
 コンテナホスティングサービスはHyper.shを使っている。コンテナを動かす仕組みとしてはDockerとは別のものを使っているようなのだが、コマンドなどはDockerとほぼ同じようなもの。Dockerの中の人が「すげーDockerライク」と言うぐらいで、"docker restart mongodb"が"hyper restart mongodb"てな具合。dockerをhyperにしたら動く。
 Hyper.shの料金は、一コンテナ当たり、VPSと同等程度の金額。Price表。このブログはフロントのNginxコンテナと.NETCoreのアプリコンテナを使っていて月額1200円ぐらい。それに加えてVPSで付き600円ぐらいで運用しているデータベースがあるが、これもコンテナにしてしまおうかと考えている。
 Hyper.shの弱点は、まだアジアにリージョンがないことか。ロサンゼルスとドイツのフランクフルト。アジアリージョンは検討中らしい。このブログはロスのサーバを使っている。レイテンシはまあ、あきらめている。それよりコンテナ使いたかったし、ここ以上に手軽に使えるコンテナホスティングサービスが見つけられなかった。
 Hyper.shのいい点は、秒単位課金なこと、コンテナがすぐ立ち上がることあたりか。試験環境を用意するのも速いし、不必要になったタイミングでコンテナを落とせば大したコストはかからないだろう。

 まとめ。このブログはコンテナホスティングサービスで運用している。ちなみにHyper.shでMeltdownとSpectreの影響をフォーラムで質問してみたところ、一週間ぐらい経過してなにも返事がないのでちょっと考えておかなければという状況。


デプロイ
========
 構成管理はDockerの仕組みに任せているので、アプリのコードを整えたらdockerのビルドコマンドを実行するだけでコンテナイメージができあがる。あとはNginxコンテナとWebアプリコンテナをDockerのオーケストレーションツールのComposeのHyper.sh版でオーケストレーションしているので、そのcomposeコマンドを一行実行すればビルド済みイメージを使ったデプロイが行われる。
 アプリのコードはGithubへのプッシュによって、TravisCIへさらにプッシュされ、Seleniumを使った統合テスト的なUIテストが行われる。それにとおった場合かつ、masterブランチへのコミットだった場合のみcomposeでのデプロイが行われる。自動化。だからもうWebアプリに機能追加したくなったりしたら、コード変更してGithubへプッシュ、それをmasterブランチにマージしたらあと自動。楽。


まだ手を付けていないところ
==========================
 コンテナで運用している部分に監視をまだつけていない。データベースサーバにはMackerelを入れているのだが。コンテナの監視はkubernetesが機能多そうながらも便利そうで面白そうなので、これを導入する方向で考えている。
 あとはログの運用。ここは完全未タッチ。Fluentdの運用事例とかが目に入ってくのでそのあたりを参考にしようとは考えている。


まとめ
======
 環境の構築や管理を自動化したかった。コンテナをそれに使ってみてすごく満足いくものができた。あとはコンテナゆえにイミュータブルになっている状況でログをどうするかなど課題は残っているので、そこらの解決をしていきたい。
comment: 0

Hyper.shで運用しているこのブログの月額

 OSの構成管理を簡略化したい。だからDocker。だけどAWSやAzureのコンテナホスティングサービスが若干高い。だからこのブログのホスティングにHyper.shを使っている。秒課金で主要クラウドほど高くないのだが、実際に月額コストがどのぐらいになっているかというのを。

 まず、このブログはHTTPSのみで運用している。そのコンテナ構成として、HTTPS化を任せているNginxコンテナと、アプリコンテナの、二つのコンテナをDocker Composeで連携して運用している。
 Nginxコンテナは月額$2.59、アプリコンテナは月額$5.18のスペックで運用。
 あとはLet'sEncryptの証明書をキープしておくために拡張の外部ストレージを使っている。それとIPを一つおさえてある。
 ブログはバグを見つけたり機能を思いつくと改良している。TravisCIから自動でデプロイが行われるようになっている。デプロイとして、古いものをDocker Composeのコマンドで破棄、その直後に新しくまたDocker Composeでデプロイしている。
 そんなアプリの月額料金が↓。



 月の合計が$13ぐらい。なんだけど、使用開始から三カ月ぐらいはアプリ一つぶんのリソース料金がディスカウントされて、月$5程度。安いしホストOSとかも意識しなくていいのでかなり気に入っている。もうちょいなんか立てようかと思案中。
comment: 0

このブログについて

ソース: https://github.com/hMatoba/tetsujin

 ブログのバックエンドを作るのが趣味になっているような気がする。
 はじめはPython on GoogleAppEngineで作って、それのデータベースをNoSQLにしてみたらどうだとか始めた。そのあとでTornadoやFlask、BottleといったPythonのフレームワークをいろいろやってみて、Node.jsはasync,awaitが入る前にやってちょっときついと思ってストップした。
 その後WPFで好きだったC#で作ってみたくなって、.NET Coreのリリース直後にAzureに乗るものを作った。そして今回、.NET Core 2.0のリリースがあったのを契機にDocker運用するものに作り直した。

 ASP.NET Core MVCを使ってみた感想。モデル、ビュー(Razor)、コントローラのみを使うような、SinatraやFlaskのような、うっすい使い方もできる。スキャフォルディングとかあるけど無理に使う必要はない。フレームワークに縛られてるような感覚は強くない。その点、うまくやれるかは書き手次第。


 このブログはタグに並べた要素が全部盛りで実装されている。
 C#が好きなので、それがオープンソースになったのがうれしかった。だからほかのオープンソース技術をメインに組み合わせて、C#はMSの用意したセット(WindowsOSでIISとかSQLServerとかって構成)じゃないと使えないなんてことはないというのを実践してみたかった。DebianでNginx、MongoDBなどって構成。
 使用サービスの構成としては、Github、TravisCI、Docker Hub、Hyper.shが主なところ。
・Github→バージョン管理
・TravisCI→CIサービス
・Docker Hub→ビルドしたコンテナイメージの置き場所
・Hyper.sh→Docker開発者が「これほぼDockerやんけ」と言うぐらいにDockerライクなコンテナホスティングサービス。もちろんDockerで作ったコンテナをホスティングできる
 使用サービスの構成はシンプルなほうがいいという一般論も存在するだろうけど、これはこれで楽をするための構成を敷いている。Dockerを使ったサーバの構成管理、自動テスト、CIサービス上での自動テストからの自動デプロイなどなど。アプリの開発継続に注力できる。

 Githubへのプッシュで、TravisCIでのビルド、テストが行われる。テストにパスしてなおかつブランチがmasterだったらならDocker Hubへビルドされたコンテナイメージがアップされる。そののち、Hyper.shでそのコンテナイメージをプル、デプロイまでのコマンドが自動で流れる。Docker Hubを経由しているので、コンテナイメージがビルドの産物として残るようになっている。


・運用お値段
 VPSは安い。でもOSの管理が必要だからヤダ。AWSとかAzureのイカしたPaasを使いたいけど高い。
 DockerコンテナホスティングをしてくれるHyper.shというサービスがあり、これで月2000円以下で運用できている。リバースプロキシコンテナ+アプリコンテナの2コンテナをランニングさせるコスト1000円に加え、個人的にいろんなアプリで使うMongoDBを仕方なくVPSで運用しているコスト600円程度となっている。VPSとメジャーどころのPaasの中間あたりのお値段。
 問題としてHyper.shが日本にもアジアにもリージョンがないことによるレイテンシがががというのがあるけども妥協。


・構成
 ファイルはAzureStorage
 ↑にも書いたけどコンテナホスティングで運用していて、走っているコンテナはリバースプロキシ用一台とアプリ用一台
 証明書はLet's Encrypt
 コンテナのOSは、リバースプロキシのほうがAlpine、アプリはDebian
 テストはxUnitによる単体テストが実行できるようにしてある
 それに加えてSeleniumでのE2Eテストも用意してある。Seleniumは、一度C#で動かしたらきつかったのでPythonで動かしている
 バージョン管理はGithub
 Githubへのデプロイで、TravisCIでのデプロイが走る
 TravisCIではとりあえずSeleniumでE2Eテストをやっている
 TravisCIでテストに成功したら、そこからHyper.shへ自動デプロイが始まる
 ただし自動デプロイが始まるのはmasterブランチへのコミット時のみ


 いろいろ構成していて半分は趣味で試したかったものであるが、同時にデプロイの自動化という一年前から突き詰めたかった課題への挑戦もしている。これのおかげで、今後このブログエンジンを改良していくのにせっせと手作業でデプロイをする必要がなくなった。


・なおしたい点
 dotnetコマンドが現状docker composeを使ったプロジェクトをビルドしてくれない。だから一部プロジェクトでCI環境でのビルドができず、開発環境でビルドしたものをDocker Hub経由で使っている。CI環境でビルドができないのはSDKの不足が原因。そのSDKはVisualStudio Communityに用意されているのだが、SDKがオープンソースになっていないという理由でdotnet CLIに入れるかどうかもたついている。
'17/9/28追記
docker composeが入っているプロジェクトのビルド方法を変えて対応完了

comment: 0

継続的デプロイと継続認証のコンテナ

 DockerコンテナでLet's Encryptと継続的デプロイをなにも考えずに組み合わせたら大失敗だった。Let's Encryptには証明書取得数の上限があった。
https://absurd.azurewebsites.net/Article/118

 上記の問題を、証明書を外部ボリュームに入れて運用するDockerイメージを作ることで解決した。
https://github.com/hMatoba/cdcc

 下記はコンテナホスティングサービスHyper.sh上で、このDockerイメージを作って運用するときのdocker-compose。証明書を自動で取りに行って、WebアプリをHTTPS運用するコンテナとしてよしなにやってくれる。
docker-compose.yml

version: '2'

services:
cdcc:
image: matoba/cdcc
ports:
- '80:80'
- '443:443'
fip: 199.245.56.122
size: s4
links:
- webapp:webapp1
volumes:
- cdcc:/etc/letsencrypt
environment:
DOMAIN: 'example.com'
E_MAIL: 'foobar@example.com'
LINK_NAME: 'webapp1'
webapp:
image: some_webapp
ports:
- '80:80'
comment: 0

Hyper.shでSSL接続するアプリの継続的デプロイ(まだ決定打なしのイマイチな方法)

 Dockerコンテナでアプリを運用したい場合、Hyper.shがイカす。そのHyper.shで、Let's encryptで取得する証明書を使ってHTTPSで接続できるようにしてみる。

Serviceを使う
→コンテナ立ち上げコマンドで証明書を引数として渡している。Let's encryptは証明書の有効期間が短いから自動更新を繰り返していきたいんだけど、そのたびにコンテナを立ち上げ直さなきゃならない?それをクリアできるならば一番いい方法

・アプリコンテナにリバースプロキシを入れてごにょごにょ
→アプリコンテナがちょいややこしくなるのと後述する理由でナシ

・アプリコンテナの外にリバースプロキシコンテナを用意して接続
https-portalという、超簡単にLet's encryptの証明書でSSLを使えるようにしてくれるコンテナがある。これを使って今回はやってみるが、結果は問題が残った。

 https-portalのGithubページのサンプルをちょっといじったdocker-compose.ymlを書く。
docker-compose.yml

version: '2'

services:
https-portal:
image: steveltn/https-portal:1
ports:
- '80:80'
- '443:443'
environment:
DOMAINS: 'example.com -> http://dncindocker'
STAGE: 'production'
FORCE_RENEW: 'true'
fip: xxx.xxx.xxx.xxx
dncindocker:
image: matoba/dncindocker:latest

 こいつをHyper.shへ。
hyper compose -up d -p foo

これで一分ほど待てばアプリのデプロイが完了するだろう。このコマンドに加えて下記のコマンドでプロジェクト消去コマンドがあれば、デプロイを容易にサイクル化できる。
hyper compose rm -v -p foo


 で、この方法はデプロイするたびにhttps-portalコンテナが証明書を取りに行く。これが問題となる。じっさいデプロイを何度も試しているうちに遭遇したのが、証明書の期間あたりの取得上限。変更がなければ週に20回までのようだ。これに達すれば証明書の発行はいったんストップするので、https-portalコンテナが正常な動作をしなくなる。そういうわけで、https-portalコンテナをデプロイの度に動かし直すのはよくない。コンテナのデプロイを分けなければならない。そうしたらそうしたで、デプロイの度にどうやってhttps-portalコンテナからアプリコンテナへの接続をやるかという課題が生まれる。
 そういうわけでLet's encrypt + 継続的デプロイのプロセスの確立に失敗した。

解決のために取るべき方法
・Serviceで証明書の自動更新と継続的デプロイができるか調査
・リバースプロキシコンテナとアプリコンテナをComposeで管理しない。リバースプロキシコンテナは動かしっぱなし、アプリコンテナだけを更新。走りっぱなしのリバースプロキシコンテナからアプリコンテナへの接続手段を得る。
comment: 0