0
0

More than 3 years have passed since last update.

別ドメインのWebページのホストをdockerの力でEC2インスタンス1つに統合したときの話

Last updated at Posted at 2019-12-24

このエントリは学生LT Advent Calendar 2019 25日目(最後)の記事です。

最後がこんなド初心者でいいのか分からない、誕生日なので許しておくれ

本エントリでは、いろんな辛さからWebページの配信をOS直下のnginxからdockerのnginxとかに移設した話をします。長いかも。

背景

1年以上前にドメインを取得して以降、用途に合わせて以下の2つのドメインにコンテンツを追加しています。

  • huequica.xyz ブログ兼ポートフォリオ
  • works.huequica.xyz 作ったおもちゃを動かす場所

この2つのドメインにコンテンツを配信するのに今までGitHub Pagesと自前で立てたEC2インスタンスに分断して配信を行っていました。
以下の図がわかりやすいかと思います。
1.001.png

さて、これを運用してきて半年以上が経過したところで幾つかのつらい事案を抱えることになりました。

なにがつらい?

以下の事情があり、けっこう悩みのタネになっていました。

GitHub Pages、単純にアップロードがしんどい

Jekyllでの生成、運用をしていた時期がありましたがデザインが気に入らなかったので自分ですべて生成しています。

そのため手元でコンテンツをBuildして、それをリポジトリに突っ込んでpushしてようやく公開される形になっていますが、ファイルパスが大文字小文字を識別していたり?とかで404が帰ってくることがあったりしてつらかったです。

最大の問題は pushする前の事前チェックができない ことで、pushしてはアクセスして確認みたいな地獄みたいなことをしていたので大変つらいです。マジで。

EC2インスタンスの環境が再現しづらい

某PHP製のWebアプリを開発した際、デプロイにVPS的なものが必要だった為とりあえずEC2インスタンスを取得していましたが、環境の不揃いが原因のバグが発生したりした為これもつらさの原因になっていました。
アプリケーションのビジネスロジックの問題ではなく権限エラーが大半のためFixがしづらく余計にしんどかったです。

証明書の更新の自動化

調べるとCronでスクリプトを定期で回して更新させるパターンが多いみたいですが、手元で動かすのに失敗していたままほったらかしになっていた為手動更新をしていました。

おまけに毎回コマンドを忘れているので調べる手間もかかってダルい。これもつらかったです。


といった感じで環境を見直すには十分だろう、ということで以下の構成に変更しました。

おニュー環境

dockerであればMacやWindowsであっても簡単に環境を揃えることができ、また新しくドメインを増やす形でOSSのSaaSサービスを展開することも簡単にできるようになります。そのため今回docker、及び管理を楽にするためにdocker-composeを使いました。

構成は超短的に表すと以下になります。

2.002.png

今回の場合huequica.xyzworks.huequica.xyz の2つのドメインの行き先をEC2の1つに集中させ、URLで識別してdockerコンテナの中のnginxに流しています。

ただし、dockerの中にはHTTPアクセスを識別して仕分ける(リバースプロキシ)みたいな機能は無いのでそっちは別で用意することになります。ここで出てくるのが nginx-proxyです。

nginx-proxy

jwilder/nginx-proxy - GitHub

nginx-proxy はリバースプロキシの仕組みを超簡単に導入するためのdockerイメージです。
ここからは実際のdocker-compose.ymlと図を交えて説明します。

実際のコンテナ構成

だいたいで図にすると以下になります。
h.001.png

まずはHTTPの仕分け役をしているproxyのymlから見ていきます。

proxy/docker-compose.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です。

portfolio/docker-compose.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_HOSTLETSENCRYPT_EMAILを追加するとSSL証明書の取得、定期更新を自動で行います。

あとはproxyで設定したnginx-proxyのいるネットワークに、コンテンツ配信用のnginxコンテナを所属させることも必要になります。


さきほどとあんまり変わりませんが、worksの方のymlも掲載しておきます。

works/docker-compose.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_HOSTLETSENCRYPT_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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0