5時間かかったぞw pic.twitter.com/NoZ904bQgb
— a-know (@a_know) 2017年5月4日
ちょっとワケあって「コンテナ環境の運用をしてみたい」と以前より考えており、その題材として今回 Mastodon を選び、環境構築を行ってみた。 (理想としては、アプリケーションも自分のものを使って試してみたかったのだけど、自分のアプリケーションの dockerize がうまくいかなかったので仕方なく、というかんじ。)
今回やってみたことのポイントとしては以下のようなところだろうか。
- jwilder/nginx-proxy を使ってリバースプロキシを立ち上げる
- jrcs/letsencrypt-nginx-proxy-companion を使って、今回割り当てるドメインで https 通信できるようにする
- Mastodon の docker-compose で扱う対象にも nginx コンテナを持たせる(リバースプロキシと通信するためのもの)
- メール配信のための外部サービスには SparkPost を利用
- インスタンスには Google Compute Engine US リージョン の micro インスタンスを用いることで(ほぼ)無料で運用できる
- ほぼ、というのは、ネットワーク転送量やディスクの無料枠までは確認していないため
基本的にはどれも先人の知恵が既に公開されていて、具体的には以下のようなページに大変お世話になった。
- Docker🐳でMastodon🐘のインスタンスを立てるドン (リバースプロキシにnginx-proxy + letsencrypt-nginx-proxy-companionを使う)
- GCEの無料枠を使って個人用Mastodonを立てる - 透明度50%
- 文系非エンジニアでも立てられるマストドン(Mastodon) CentOS7+Docker+SparkPost
- Mastodonインスタンス立てた時にメール設定でハマったこと - yumulog | 社会人博士の日記
- https://hackerslog.net/post/labs/docker-letsencrypt-on-docker-and-nginx/
ただ、今回僕がやってみたこととまるっきり一緒のことをやっている方は見当たらなかったので、今回の僕の試行錯誤もまた誰かの役に立てば、ということで、書き残しておく。
記述中の mstdn.a-know.me
というのは、あくまで今回の僕の設定例なので、そこは適宜読み替えて下さい。
各種バージョン
$ uname -a Linux mstdn 4.8.0-45-generic #48-Ubuntu SMP Fri Mar 24 11:46:39 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux $ docker -v Docker version 17.03.1-ce, build c6d412e $ docker-compose version docker-compose version 1.12.0, build b31ff33 docker-py version: 2.2.1 CPython version: 2.7.13 OpenSSL version: OpenSSL 1.0.1t 3 May 2016 $ git rev-parse HEAD d91ba3c8d067f0c16d09e21d6f727e4456457a8c
その他、記述内の情報は 2017-05-03 現在のものです。
1. GCE インスタンスを立てる
まずはこれがなくっちゃ始まらない、ってことで。基本的には GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。以下には、参考先に記述がなかった点についてのメモを残しておく。
- 名前
- 自由に付けて良し。GCP 内で管理のために使用するだけ。
- ゾーン
- 参考先にも書いてあるとおり、USリージョンの西側が良さそう。
us-west1-a
はなんとなく人気がありそうなので、us-west1-b
にした。
- マシンタイプ
micro
を選ぶ。それ以外を選ぶと無料枠の対象ではなくなるので注意。
- ブートディスク
- ファイアウォール
- HTTP / HTTPS 共に許可。
- 「管理、ディスク、ネットワーキング、SSH 認証鍵」のところをクリックすると、これらの詳細についても設定できる。
だいぶ詳細に書いたけど、ある程度こういうのを繰り返しやったことのある人なら、なんとなくポチポチっとやれば立てられるハズ。
2. 固定IPアドレスのAレコードを登録する
今回僕の場合は mstdn.a-know.me
という名前で 1. で作った IP アドレスにアクセスできるようにしたいので、そういう A レコードをこのタイミングで追加しておく。
DNS サーバには Route 53 を使った。
3. Docker CE(コミュニティエディション)と docker-compose のインストール
以下の作業は全て 1. で立てた GCE インスタンス内での作業。
3-1. 必要なパッケージのインストール
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
を実行するんだけど、1. で選択した OS イメージならいずれも既にインストール済みの模様。
3-2. Docker公式のGPGキーの追加
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-3. stableリポジトリの設定
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-4. パッケージインデックスの更新
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-5. Docker CEのインストール
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-6. Dockerの動作確認
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-7. Dockerコマンドをroot以外のユーザで実行できるようにする
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り、なんだけど、 $ sudo usermod -aG docker $USER
したあとは一度ログインしなおさないとうまく確認できないきがする。
3-8. Dockerの自動起動設定
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-9. Docker Composeのインストール
GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
3-10. network(2種)の作成
Docker🐳でMastodon🐘のインスタンスを立てるドン (リバースプロキシにnginx-proxy + letsencrypt-nginx-proxy-companionを使う) を参考にして実施。「リバースプロキシとアプリケーション(今回の場合は Mastodon)を繋ぐためのネットワーク」と「Mastodon を構成する各コンテナを繋ぐためのネットワーク」をそれぞれ作成しておく。
$ docker network create --driver bridge front $ docker network create --driver bridge back-mstdn
4. スワップ領域の作成
GCE の micro インスタンスはメモリが少ないため、この先の作業に向けて予めスワップ領域を作成しておく必要がある。これも GCEの無料枠を使って個人用Mastodonを立てる - 透明度50% にある通り。
$ sudo fallocate -l 2G /swap $ sudo chmod 0600 /swap $ sudo mkswap /swap Setting up swapspace version 1, size = 2 GiB (2147479552 bytes) no label, UUID= $ sudo swapon /swap
これに加えて、/etc/fstab
に下記の行を追記し、再起動後もスワップ領域が有効になるようにする。
/swap swap swap defaults 0 0
5. SparkPost の利用準備
Mastodon では、ユーザー登録の際の verify にメールを使用していることもあって、何らかの手段でメール送信が行えるようにしなければならない。
巷では postfix を自前で立てたり Sendgrid や SparkPost を使ったり、と様々な方法が共有されていたが、今回自分も SparkPost を使うことにした(ちなみに SparkPost のことは、今回の作業で初めて知った。。)。
基本的な手順としては 文系非エンジニアでも立てられるマストドン(Mastodon) CentOS7+Docker+SparkPost にある通りで、おおまかの流れとしては以下の通り。
- サインアップ(ユーザー登録)
- 登録に用いるメールアドレスは
mstdn.a-know.me
ドメインのメールアドレスではなくて ok。
- 登録に用いるメールアドレスは
- 今回利用するドメイン(
mstdn.a-know.me
)の登録 - ユーザー登録に使用したメールアドレスの verify
- のユーザー登録で使用したアドレスに「Welcome to your SparkPost account!」という件名のメールが届いているのでその中の「confirm your email address」というリンクをクリックする
- SENDING DOMAINS 画面にて、今回利用するドメイン(
mstdn.a-know.me
)に TXT レコードを追加し確認
2.のところで API キー(SMTP 認証のパスワードになる)が表示されるのでメモしておく。またここのタイミングで admin@mstdn.a-know.me
などのアドレスへのメール受信確認を促されるが、TXTレコードでのドメイン確認も行えるので、そっちで実施したい場合はこのタイミングでは skip してしまって ok。
6. Mastodon のセットアップ
続いて Mastodon のセットアップ。これも GCE インスタンス内での作業。
6-1. コードの clone とビルドの実施
GitHub リポジトリからコードを持ってくる。インスタンスに ssh したユーザのホームディレクトリ内に雑に clone している。
$ git clone https://github.com/tootsuite/mastodon.git (中略) $ cd mastodon $ docker-compose build
このビルドはそこそこ時間が掛かる(docker-compose pull
でも良い?)。
6-2. secret値を生成する(3種)
ビルドが完了したら、 $ docker-compose run --rm web rake secret
を3回実行し、三種類の secret 値を生成しておく。
6-3. 環境変数ファイルの編集
$ cp .env.production.sample .env.production
してから、以下を参考に .env.production を編集する。
6-4. Mastodon の docker-compose.yml を編集する
以下を参考に、リポジトリのルートにある docker-compose.yml を編集する。 nginx
サービスはまるまる追加なので注意。
6-5. Mastodon 用 nginx コンテナの設定ファイルの作成
6-4. で nginx の volumes に ./setting/nginx/conf.d
としているように、Mastodon のリポジトリルートに setting/nginx/conf.d
ディレクトリを掘り、そこに以下のような conf ファイルを作成する。
6-6. データベースのマイグレーションの実施
$ docker-compose run --rm web rails db:migrate
で ok。
6-7. アセットプリコンパイルの実行
$ docker-compose run --rm web rails assets:precompile
で ok。
7. Let's encrypt 用のファイアウォールルールの作成と適用
7-1. Let's encrypt 用のファイアウォールルールの作成
6-3. の VIRTUAL_PORT などで指定している任意のポート番号に対してアクセスを受け入れられるよう、以下のような GCP ファイアウォールルールを作成しておく。GCP の ネットワーキング メニューから作成できる。
- 名前・説明
- 任意の名前・説明を入力したらよい。
- ネットワーク
- で作成した GCE インスタンスが所属するネットワークを選択。特に設定変更などした覚えがなければ
default
で。
- で作成した GCE インスタンスが所属するネットワークを選択。特に設定変更などした覚えがなければ
- 優先度
- トラフィックの方向
- 外部からインスタンスに向けてのアクセスなので「上り」。
- 一致した時のアクション
- 許可したいわけなので「許可」。
- ターゲット
- 「指定されたターゲットタグ」を指定。
- ターゲットタグ
- ここで指定したタグを有するインスタンスに、このルールが適用される。わかりやすいタグ名を指定すればよさそう。
- ソースフィルタ
- アクセス元の指定の仕方。「IP 範囲」で。
- ソース IP の範囲
- 厳密には Let's encrypt からのアクセスのみをさばけられたらよさそうだけど、
0.0.0.0/0
として全部許可してしまった。
- 厳密には Let's encrypt からのアクセスのみをさばけられたらよさそうだけど、
- 2番目のソースフィルタ
- 「なし」。
- プロトコルとポート
- 「指定したプロトコルとポート」を選択。
- テキストエリアには
tcp:9090
と入力(9090
は、6-3. の VIRTUAL_PORT などで指定している任意のポート番号と一致している必要がある)。
以上のようなかたちでルールを作成できる。のだけど、これ、いまいち「なんでこれが必要なのか」が僕の中で腹落ちしきっていなかったりする。。
いちおう、Let's encrypt での証明書作成フロー(の概要)はわかっているつもりではいるのだけど、このルールの適用前だと /.well-known/acme-challenge/
へのアクセスがうまく捌けていなかった。ここらへん、落ち着いたらもう一度整理してみたいところ。
7-2. Let's encrypt 用のファイアウォールルールの適用
7-1. で作成したルールを、今回つくった GCE インスタンスに適用させる。
GCE インスタンスの一覧画面 から対象のインスタンスを選び、その後画面上部の「編集」をクリック。
「タグ」というところが編集可能状態になっているので、ここに 7-1. で指定した「ターゲットタグ」と同じ文字列を入力、画面最下部の「保存」ボタンを押してインスタンスに対してタグを付ける。
タグ付けすると同時に、7-1. で作成したファイアウォールルールも適用される。
8. リバースプロキシのセットアップ
8-1. リバースプロキシ用のワーキングディレクトリを作成する
別にどこでもよいのだけど、 ~/proxy
としてみた。
$ cd ~ $ mkdir proxy
8-2. リバースプロキシ用の docker-compose.yml の作成
こちら Docker🐳でMastodon🐘のインスタンスを立てるドン (リバースプロキシにnginx-proxy + letsencrypt-nginx-proxy-companionを使う) の記事の通りなのだけど、以下のような yml ファイルを作る。
9. コンテナ群の起動と動作確認
長々とやってきた準備作業もここまで。いざ起動して動作確認。まずはリバースプロキシ側の起動。
$ cd ~/proxy $ docker-compose up -d
このコマンドまで実行したら、 $ docker-compose logs -f
と打ってログの様子を眺めてみるのがよいかも。以下のようなかんじで出力されるので、どれがどのコンテナによるログなのかもすぐにわかる。
proxy-letsencrypt | 2017/05/04 02:07:19 Received event start for container 6ff6632adbd7 proxy-letsencrypt | 2017/05/04 02:07:19 Received event die for container 6ff6632adbd7 proxy-letsencrypt | 2017/05/04 02:07:20 Received event start for container 6ff6632adbd7 proxy-letsencrypt | 2017/05/04 02:07:20 Received event die for container 6ff6632adbd7 proxy-nginx | forego | starting dockergen.1 on port 5000 proxy-nginx | forego | starting nginx.1 on port 5100 proxy-nginx | dockergen.1 | 2017/05/04 01:40:01 Generated '/etc/nginx/conf.d/default.conf' from 2 containers proxy-nginx | dockergen.1 | 2017/05/04 01:40:01 Running 'nginx -s reload' proxy-nginx | dockergen.1 | 2017/05/04 01:40:01 Watching docker events
このログの流れが一通り落ち着いたようであれば、続いて Mastodon の起動。
$ cd ~/mastodon $ docker-compose up -d
こちらも起動後は $ docker-compose logs -f
でログを眺めてみるとよさそう。
あと、ここまでの設定が全てうまくいっていれば、 mstdn.a-know.me
用の SSL 証明書も作成されるはずなので、リバースプロキシ側の logs も見てみるとよさそう。
$ docker-compose ps
を実行して以下のような出力がされたら、準備は完了。
$ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------- mastodon_app_1 irb Exit 0 mstdn-db docker-entrypoint.sh postgres Up 5432/tcp mstdn-nginx nginx -g daemon off; Up 443/tcp, 80/tcp, 0.0.0.0:9090->9090/tcp mstdn-redis docker-entrypoint.sh redis ... Up 6379/tcp mstdn-sidekiq bundle exec sidekiq -q def ... Up 3000/tcp, 4000/tcp mstdn-streaming npm run start Up 3000/tcp, 0.0.0.0:4000->4000/tcp mstdn-web bundle exec rails s -p 300 ... Up 0.0.0.0:3000->3000/tcp, 4000/tcp
https://mstdn.a-know.me
にアクセスし、冒頭のツイートにあるような画面が表示されたら、晴れて Mastodon 環境の構築は完了!
今回の学びとか
おぼろげな全体像
今回この環境の構築をしながら、頭の中でなんとなくの構成を思い描きながら作業をしていたのだけど、それをここでも改めて整理してみる。
...こんなかんじかな?
network をここまでしっかり使ったのは初めてなので、あとで復習しておきたい。
jwilder/nginx-proxy がスゴイ
こちら にもまとめて頂いているのだけど、
- Dockerコンテナのプロキシとして機能させられる
VIRTUAL_HOST
で指定したドメインへのアクセスがあった場合、自動でVIRTUAL_PORT
で指定したポート番号へ通信を転送してくれる
- 新しいドメインが別コンテナに割り当てられた時に、それを検知して nginx の設定を自動で更新できる
といったところがスゴイ。
仕組み的には、nginx-proxy が /var/run/docker.sock
をウォッチしており、その結果何かしらの変更を検出した際に上述の設定の自動更新が行われるようなのだけど、この仕組み、とても興味深いのでまた別のタイミングで調べてみるなり詳しい人から話を聞いてみるなりしてみたい。
jrcs/letsencrypt-nginx-proxy-companion がスゴイ
これも nginx-proxy 同様、あるドメインでの通信があったらそのタイミングで SSL 証明書の取得を自動的に行ってくれるものらしい? 更新も自動でやってくれるというのだから素晴らしい。
ただこれも、7-1. で書いたようにまだよくわかってないところもあるので、nginx-proxy と同じく仕組みを詳しく知りたい。
docker-compose がべんり!
べんり。複数のコンテナを一括で扱えるということもそうだけど、コンテナ起動時の各種オプション類を yml に落とし込めるという点がいいなーと思った。仮に単独コンテナを扱うときでも積極的に使っていきたいきもち。
参考
あらためて、以下のサイトには本当に助けられました。ありがとうございました!
- Docker🐳でMastodon🐘のインスタンスを立てるドン (リバースプロキシにnginx-proxy + letsencrypt-nginx-proxy-companionを使う)
- GCEの無料枠を使って個人用Mastodonを立てる - 透明度50%
- 文系非エンジニアでも立てられるマストドン(Mastodon) CentOS7+Docker+SparkPost
- Mastodonインスタンス立てた時にメール設定でハマったこと - yumulog | 社会人博士の日記
- https://hackerslog.net/post/labs/docker-letsencrypt-on-docker-and-nginx/
今回はすべて手作業で完結させてしまったけど、これを全部コードに落とし込むのもやってみたいな!(大変そう。。笑)
関連するかも
プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化
- 作者: WINGSプロジェクト阿佐志保
- 出版社/メーカー: 翔泳社
- 発売日: 2015/11/19
- メディア: Kindle版
- この商品を含むブログ (3件) を見る