読者です 読者をやめる 読者になる 読者になる

えいのうにっき

主に Web 系技術ネタ。背景画像 is powered by grass-graph.shitemil.works

リバースプロキシ + https + 全てコンテナ、な Mastodon インスタンス(無料)を構築してみたメモ

ちょっとワケあって「コンテナ環境の運用をしてみたい」と以前より考えており、その題材として今回 Mastodon を選び、環境構築を行ってみた。 (理想としては、アプリケーションも自分のものを使って試してみたかったのだけど、自分のアプリケーションの dockerize がうまくいかなかったので仕方なく、というかんじ。)

今回やってみたことのポイントとしては以下のようなところだろうか。

  • jwilder/nginx-proxy を使ってリバースプロキシを立ち上げる
  • jrcs/letsencrypt-nginx-proxy-companion を使って、今回割り当てるドメインhttps 通信できるようにする
  • Mastodon の docker-compose で扱う対象にも nginx コンテナを持たせる(リバースプロキシと通信するためのもの)
  • メール配信のための外部サービスには SparkPost を利用
  • インスタンスには Google Compute Engine US リージョン の micro インスタンスを用いることで(ほぼ)無料で運用できる
    • ほぼ、というのは、ネットワーク転送量やディスクの無料枠までは確認していないため

基本的にはどれも先人の知恵が既に公開されていて、具体的には以下のようなページに大変お世話になった。

ただ、今回僕がやってみたこととまるっきり一緒のことをやっている方は見当たらなかったので、今回の僕の試行錯誤もまた誰かの役に立てば、ということで、書き残しておく。

記述中の 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% にある通り。以下には、参考先に記述がなかった点についてのメモを残しておく。

f:id:a-know:20170505133330p:plain

  • 名前
    • 自由に付けて良し。GCP 内で管理のために使用するだけ。
  • ゾーン
    • 参考先にも書いてあるとおり、USリージョンの西側が良さそう。
    • us-west1-a はなんとなく人気がありそうなので、us-west1-b にした。
  • マシンタイプ
    • micro を選ぶ。それ以外を選ぶと無料枠の対象ではなくなるので注意。
  • ブートディスク
    • OSは「Ubuntu 16.10」を選ぶとして、種類も「標準」か「SSD」かを選べる。
    • 無料枠からはハミ出ちゃうなー、とは思ったけど、ちょっとした時間をお金で買うつもりで「SSD」にした。
    • サイズも、デフォルトの「10GB」から「30GB」にした。
      • 完全に適当。
  • ファイアウォール
    • HTTP / HTTPS 共に許可。
  • 「管理、ディスク、ネットワーキング、SSH 認証鍵」のところをクリックすると、これらの詳細についても設定できる。
    • 「ネットワーキング」タブ内「外部IP」で「新しい静的アドレス」を選択。この場で固定IPアドレスを取得できる。
    • SSH認証鍵」タブ内で、自分のローカルマシンの ~/.ssh/id_rsa.pub の内容を貼り付けておく。
      • gcloud コマンドを使わなくても 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を使う) - Qiita を参考にして実施。「リバースプロキシとアプリケーション(今回の場合は 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 - Qiita にある通りで、おおまかの流れとしては以下の通り。

  1. サインアップ(ユーザー登録)
    • 登録に用いるメールアドレスは mstdn.a-know.me ドメインのメールアドレスではなくて ok
  2. 今回利用するドメインmstdn.a-know.me)の登録
  3. ユーザー登録に使用したメールアドレスの verify
      1. のユーザー登録で使用したアドレスに「Welcome to your SparkPost account!」という件名のメールが届いているのでその中の「confirm your email address」というリンクをクリックする
  4. 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ネットワーキング メニューから作成できる。

f:id:a-know:20170505134040p:plain

  • 名前・説明
    • 任意の名前・説明を入力したらよい。
  • ネットワーク
      1. で作成した GCE インスタンスが所属するネットワークを選択。特に設定変更などした覚えがなければ default で。
  • 優先度
    • 複数のファイアウォールルールを組み合わせる場合に、この値でコントロールする必要がある。今回のような場合はデフォルト値のままでいいはず。
  • トラフィックの方向
  • 一致した時のアクション
    • 許可したいわけなので「許可」。
  • ターゲット
    • 「指定されたターゲットタグ」を指定。
  • ターゲットタグ
    • ここで指定したタグを有するインスタンスに、このルールが適用される。わかりやすいタグ名を指定すればよさそう。
  • ソースフィルタ
    • アクセス元の指定の仕方。「IP 範囲」で。
  • ソース IP の範囲
    • 厳密には Let’s encrypt からのアクセスのみをさばけられたらよさそうだけど、 0.0.0.0/0 として全部許可してしまった。
  • 2番目のソースフィルタ
    • 「なし」。
  • プロトコルとポート
    • 「指定したプロトコルとポート」を選択。
    • テキストエリアには tcp:9090 と入力( 9090 は、6-3. の VIRTUAL_PORT などで指定している任意のポート番号と一致している必要がある)。

以上のようなかたちでルールを作成できる。のだけど、これ、いまいち「なんでこれが必要なのか」が僕の中で腹落ちしきっていなかったりする。。

いちおう、Let’s encrypt での証明書作成フロー(の概要)はわかっているつもりではいるのだけど、このルールの適用前だと /.well-known/acme-challenge/ へのアクセスがうまく捌けていなかった。ここらへん、落ち着いたらもう一度整理してみたいところ。

7-2. Let’s encrypt 用のファイアウォールルールの適用

7-1. で作成したルールを、今回つくった GCE インスタンスに適用させる。

GCE インスタンスの一覧画面 から対象のインスタンスを選び、その後画面上部の「編集」をクリック。

f:id:a-know:20170505134101p:plain

「タグ」というところが編集可能状態になっているので、ここに 7-1. で指定した「ターゲットタグ」と同じ文字列を入力、画面最下部の「保存」ボタンを押してインスタンスに対してタグを付ける。

タグ付けすると同時に、7-1. で作成したファイアウォールルールも適用される。

8. リバースプロキシのセットアップ

8-1. リバースプロキシ用のワーキングディレクトリを作成する

別にどこでもよいのだけど、 ~/proxy としてみた。

$ cd ~
$ mkdir proxy

8-2. リバースプロキシ用の docker-compose.yml の作成

こちら Docker🐳でMastodon🐘のインスタンスを立てるドン (リバースプロキシにnginx-proxy + letsencrypt-nginx-proxy-companionを使う) - Qiita の記事の通りなのだけど、以下のような 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 環境の構築は完了!

今回の学びとか

おぼろげな全体像

今回この環境の構築をしながら、頭の中でなんとなくの構成を思い描きながら作業をしていたのだけど、それをここでも改めて整理してみる。

f:id:a-know:20170505134155p:plain

…こんなかんじかな?

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 に落とし込めるという点がいいなーと思った。仮に単独コンテナを扱うときでも積極的に使っていきたいきもち。

参考

あらためて、以下のサイトには本当に助けられました。ありがとうございました!

今回はすべて手作業で完結させてしまったけど、これを全部コードに落とし込むのもやってみたいな!(大変そう。。笑)

関連するかも



follow us in feedly