このエントリは学生LT Advent Calendar 2019 25日目(最後)の記事です。
最後がこんなド初心者でいいのか分からない、誕生日なので許しておくれ
本エントリでは、いろんな辛さからWebページの配信をOS直下のnginxからdockerのnginxとかに移設した話をします。長いかも。
背景
1年以上前にドメインを取得して以降、用途に合わせて以下の2つのドメインにコンテンツを追加しています。
-
huequica.xyz
ブログ兼ポートフォリオ -
works.huequica.xyz
作ったおもちゃを動かす場所
この2つのドメインにコンテンツを配信するのに今までGitHub Pagesと自前で立てたEC2インスタンスに分断して配信を行っていました。
以下の図がわかりやすいかと思います。
さて、これを運用してきて半年以上が経過したところで幾つかのつらい事案を抱えることになりました。
なにがつらい?
以下の事情があり、けっこう悩みのタネになっていました。
GitHub Pages、単純にアップロードがしんどい
Jekyllでの生成、運用をしていた時期がありましたがデザインが気に入らなかったので自分ですべて生成しています。
そのため手元でコンテンツをBuildして、それをリポジトリに突っ込んでpushしてようやく公開される形になっていますが、ファイルパスが大文字小文字を識別していたり?とかで404が帰ってくることがあったりしてつらかったです。
最大の問題は pushする前の事前チェックができない ことで、pushしてはアクセスして確認みたいな地獄みたいなことをしていたので大変つらいです。マジで。
EC2インスタンスの環境が再現しづらい
某PHP製のWebアプリを開発した際、デプロイにVPS的なものが必要だった為とりあえずEC2インスタンスを取得していましたが、環境の不揃いが原因のバグが発生したりした為これもつらさの原因になっていました。
アプリケーションのビジネスロジックの問題ではなく権限エラーが大半のためFixがしづらく余計にしんどかったです。
証明書の更新の自動化
調べるとCronでスクリプトを定期で回して更新させるパターンが多いみたいですが、手元で動かすのに失敗していたままほったらかしになっていた為手動更新をしていました。
おまけに毎回コマンドを忘れているので調べる手間もかかってダルい。これもつらかったです。
といった感じで環境を見直すには十分だろう、ということで以下の構成に変更しました。
おニュー環境
dockerであればMacやWindowsであっても簡単に環境を揃えることができ、また新しくドメインを増やす形でOSSのSaaSサービスを展開することも簡単にできるようになります。そのため今回docker、及び管理を楽にするためにdocker-composeを使いました。
構成は超短的に表すと以下になります。
今回の場合huequica.xyz
と works.huequica.xyz
の2つのドメインの行き先をEC2の1つに集中させ、URLで識別してdockerコンテナの中のnginxに流しています。
ただし、dockerの中にはHTTPアクセスを識別して仕分ける(リバースプロキシ)みたいな機能は無いのでそっちは別で用意することになります。ここで出てくるのが nginx-proxyです。
nginx-proxy
nginx-proxy
はリバースプロキシの仕組みを超簡単に導入するためのdockerイメージです。
ここからは実際のdocker-compose.yml
と図を交えて説明します。
実際のコンテナ構成
まずはHTTPの仕分け役をしているproxy
のymlから見ていきます。
version: "3.5"
services:
nginx-proxy:
container_name: nginx-proxy
image: jwilder/nginx-proxy
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
# nginx-proxy-companionに共有させる
- certs:/etc/nginx/certs:ro
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
networks:
- proxy-network
labels:
- "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
# SSL証明書発行しないのであれば不要
letsencrypt-nginx:
container_name: letsencrypt-nginx
image: jrcs/letsencrypt-nginx-proxy-companion
privileged: true
depends_on:
- nginx-proxy
volumes:
- certs:/etc/nginx/certs:rw
- vhost:/etc/nginx/vhost.d
- html:/usr/share/nginx/html
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: always
volumes:
certs:
vhost:
html:
networks:
proxy-network:
name: proxy_network
キモになるのはこの3つです。
-
networks
の項目で他のディレクトリのdocker-composeとの連携場所を作る -
nginx-proxy
には上述のネットワークに所属させる - SSL証明書を発行する場合は
volumes
を共有させる(していないと警告が出る)
次にportfolio
のymlです。
version: "3.5"
services:
app:
container_name: portfolio_nginx
image: nginx
volumes:
- ./content:/usr/share/nginx/html
- ./conf.d:/etc/nginx/conf.d
- ./nginx.conf:/etc/nginx/nginx.conf
environment:
- VIRTUAL_HOST=huequica.xyz
- LETSENCRYPT_HOST=huequica.xyz
- LETSENCRYPT_EMAIL=hoge@dogemail.com
networks:
- proxy-network
networks:
proxy-network:
name: proxy_network
environment
の項目でVIRTUAL_HOST
という見慣れない変数を作っていますが、これが一番大事です。
具体的には、前述のnginx-proxy
が拾ったHTTPはVIRTUAL_HOST
のアドレスを元に制御してレスポンスを中継します。そのため、ローカルで稼働させる場合はlocalhost
に書き換えるなどしないとなりません。
また、先程のproxy
内でSSL証明書用のコンテナを入れている場合はLETSENCRYPT_HOST
とLETSENCRYPT_EMAIL
を追加するとSSL証明書の取得、定期更新を自動で行います。
あとはproxy
で設定したnginx-proxyのいるネットワークに、コンテンツ配信用のnginxコンテナを所属させることも必要になります。
さきほどとあんまり変わりませんが、works
の方のymlも掲載しておきます。
version: "3.5"
services:
works_nginx:
container_name: works_nginx
image: nginx
volumes:
- ./content:/usr/share/nginx/html
- ./conf.d:/etc/nginx/conf.d
- ./nginx.conf:/etc/nginx/nginx.conf
environment:
- VIRTUAL_HOST=works.huequica.xyz
- LETSENCRYPT_HOST=works.huequica.xyz
- LETSENCRYPT_EMAIL=hoge@dogemail.com
networks:
- proxy-network
networks:
proxy-network:
name: proxy_network
worksもやることは同じです。 VIRTUAL_HOST
とLETSENCRYPT_HOST
にドメインを設定して、LETSENCRYPT_EMAIL
に更新用のメールアドレスを渡してやるだけです。
ただし、PHPやRubyのコンテナと連携して動的なものを返そうと考えている方はそのコンテナとnginxコンテナのみをつなぐ為のネットワークの新設、所属が必要になるのでそれだけ注意してください。
これによって解決したこと
- 事前のコンテンツチェックができるようになった
- 証明書が自動更新になり、定期更新など何も気にしなくて良くなった
- 環境の統一がとれたことにより、デバッグがすこぶる楽になった
- GitLabなどを自前で動かすこともできるようになった
などなど、夢が広がりまくりです。dockerに感謝
これからの課題
いままでworksで配信していたクソアプリがAPIと静的コンテンツの2分化の必要がありそうな気がしてきているのでそれのコード改修などがあります。なので、Rubyコンテナをworksのdocker-compose.yml
に追加してとかしなければなりません…
最後に
誕生日プレゼント、待ってます。
https://www.amazon.jp/hz/wishlist/ls/3FGFSE5EZKEM3?ref_=wl_share