dockerでnginx導入と複数サービスの展開
dockerでのnginx導入から外部に複数サービスのを公開するやり方のメモです。
ローカル、サーバ(VPS)ともにUbuntuです。
ローカルで起動
ひとまず何も設定せずnginxコンテナを作成して起動できることを確認します。
以下のように記述してdocker-compose up -d
します。
version: "2"
services:
app:
image: nginx:latest
container_name: "app"
ports:
- "8080:80"
ローカルの開発環境で動かしていますが、ブラウザでlocalhost:8080
にアクセスしてみると初期ページが表示されました。
独自ページを表示
デフォルトの設定では初期ページが表示されるようになっているので、別途confファイルを用意して指定したHTMLファイルが表示されるように設定します。
この設定ファイルは/etc/nginx/nginx.conf.d
以下に置くことで機能します。
server {
listen 80;
listen 443;
server_name localhost;
location / {
root /app;
index index.html index.htm;
}
error_page 404 /404.html;
location = /40x.html {
root /usr/share/nginx/html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
表示用のHTMLファイルを用意します。
<html>
<body>
This is index.html.<br />
<a href="pageA.html">next</a>
</body>
</html>
<html>
<body>
This is pageA.html.
</body>
</html>
docker-compose.yml
にvolumes
の記述を追加して、上記の設定ファイルとHTMLファイルをマウントします。
先述したとおり、設定ファイルは/etc/nginx/nginx.conf.d
以下に配置されるようします。
HTMLファイルについては、deafult.conf
で指定したrootのパスに置いてください。
version: "3"
services:
app:
image: nginx:latest
container_name: "app"
ports:
- "8080:80"
volumes:
- ./nginx/html:/app
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
これでlocalhost:8080
にアクセスすると先程のHTMLが表示されるようになりました。
ドメインの取得
外部公開に向けて事前にどこかのレジストラでドメインの取得をしておきます。
それぞれの紐付けとして以下の作業が必要ですが、利用サービスによって違うので各々のマニュアルを参照してください。
- ドメインにVPSのネームサーバを設定
- VPS側でドメイン、DNSレコードの登録
リバースプロキシとSSL
今回は1つのサーバ上で複数サービスを稼働させる想定をしています。
構成としてはリバースプロキシを用意してアクセスしてきたリクエストを各々のDockerコンテナに振り分けます。
また例のごとくLet's Encryptで無料のSSL対応も行います。
詳しくはここらへんのサイトを参考していただければ分かると思うのですが、要点だけ書きます。
サブドメインの設定
事前にVPS側でDNSレコードを追加しサブドメインの設定を行います。
Aレコードの設定でいけると思います。
これもVPS等のマニュアルに書いてあると思います。
ポート開放
ポートの80
と443
が開いていない場合、開放しておきます。
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables-save > /etc/iptables.rules
リバースプロキシの設定
Dockerで行うに当たって以下の2つのイメージを使うことで実現します。
前者がnginxのリバースプロキシで、後者はLet's EncyptのSSLサーバ証明書を自動取得・更新してくれるものです。
SSLサーバ証明書は手動でもできますがせっかくなので楽なやり方を採用します。
以下のようなdocker-compose.yml
になりました。
基本的には公式のGitHubに書いてある通りです。
なおvolumes_from
を使っていますが、version: "3"
から廃止されたそうなので、version: "2"
にしておかないと動きません。(今後のことを考えると何らかの対策が必要ですが、今回は試験的な試みなのでスルーします・・・)
補足(2019/09/08)
最近思ったのですがリバースプロキシをするnginxはわざわざDockerコンテナである必要はないかもしれません。
この時は複数のサブドメインの証明書の取得するのが面倒で全部面倒見てくれる上記のコンテナ2つを使いました。しかしワイルドカード証明書を使えば証明書は1組で済むし自動更新はcertbotやlegoを使えばそこまで手間ではないです。
またリバースプロキシのためにDockerネットワークの記述をそれぞれのdocker-compose.ymlに記述するのは本質的ではない気がするし外部のライブラリにがっつり依存するのもどうかなという思いがあります(分かっていて使うのであれば問題ない)。
そういうわけで今自分がやるのであればサブドメインに割り当てるサービスは独立したコンテナとして立ち上げてリバースプロキシはホスト側にnginxを建てて127.0.0.1:{PORT}
を見に行くのが良いかなという感じです。
version: "2"
services:
nginx-proxy:
image: jwilder/nginx-proxy
container_name: nginx-proxy
privileged: true
ports:
- "80:80"
- "443:443"
volumes:
- /srv/docker/nginx-proxy-with-encrypt/certs:/etc/nginx/certs:ro
- /etc/nginx/vhost.d
- /usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
restart: always
letsencrypt-nginx:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: letsencrypt-nginx
privileged: true
volumes:
- /srv/docker/nginx-proxy-with-encrypt/certs:/etc/nginx/certs:rw
- /var/run/docker.sock:/var/run/docker.sock:ro
volumes_from:
- nginx-proxy
restart: always
networks:
default:
external:
name: shared
Docker内で通信に使うネットワークを作成します。上で設定しているnetworks
で使います。
$ docker network create --driver bridge shared
アプリ作成
振り分け先としてサイトAとサイトB用のdocker-compose.yml
を用意します。
サイトA
ベースは一番最初に作成したdocker-compose.yml
です。
version: "2"
services:
app1:
image: nginx:latest
container_name: "app1"
environment:
VIRTUAL_HOST: app1.example.com
LETSENCRYPT_HOST: app1.example.com
LETSENCRYPT_EMAIL: [email protected]
restart: always
volumes:
- ./app/html:/app
- ./app/default.conf:/etc/nginx/conf.d/default.conf
networks:
default:
external:
name: shared
port
の設定がなくなり、代わりにVIRTUAL_HOST
, LETSENCRYPT_HOST
, LETSENCRYPT_EMAIL
を追加しました。
VIRTUAL_HOST
には用意したサブドメインを設定します。
LETSENCRYPT_HOST
, LETSENCRYPT_EMAIL
にはLet's EncryptでSSLを取得する時に使用する情報です。
またnetworks
も上で作ったものを設定して通信を疎通させます。
サイトB
ほぼ同様です。app1
の部分をapp2
に変えています。
version: "2"
services:
app1:
image: nginx:latest
container_name: "app2"
environment:
VIRTUAL_HOST: app2.example.com
LETSENCRYPT_HOST: app2.example.com
LETSENCRYPT_EMAIL: [email protected]
restart: always
volumes:
- ./app/html:/app
- ./app/default.conf:/etc/nginx/conf.d/default.conf
networks:
default:
external:
name: shared
起動してみる
順番にdocker-compose up -d
して起動していきます。
volume
の設定で/var/run/docker.sock
をマウントすることによって、Dockerコンテナの起動/終了等を検知して自動的に振り分けの設定を行ってくれます。具体的にはnginxのdefault.conf
を都度書き換えているようです。
またSSLサーバ証明書の取得に多少時間がかかるので少し待ったほうがいいと思います。
cd proxy
$ docker-compose up -d
cd app1
$ docker-compose up -d
cd app2
$ docker-compose up -d
さて、これでapp1.example.com
などでアクセスし、ページが振り分けられていれば成功です。
またhttps通信が成功していればリダイレクトされ、ブラウザの保護されていない通信
という表示も消えていると思います(Chromeの場合)。
その他、困ったこと
- カーネルのバージョン
- 3.1以上じゃないとdockerが動かない(
uname -r
で確認) - 古いバージョンだった場合に利用しているVPSがOpenVZ方式だったら利用者側でアップデートできないので詰み。
- 3.1以上じゃないとdockerが動かない(
- dockerおよびdocker-composeは公式サイトに従って入れる。
- apt-getしたら古かったので動かなかった。
-
sudo: unable to resolve host hostname
で怒られた。-
/etc/hosts
に127.0.1.1 hostname
を追加で消える。
-
Author And Source
この問題について(dockerでnginx導入と複数サービスの展開), 我々は、より多くの情報をここで見つけました https://qiita.com/asylum/items/05d8dc4cc4671d7a5d4f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .