web-dev-qa-db-ja.com

Dockerポートへの仮想ホストの割り当て

カスタムドメイン(* .foo)へのすべてのWeb要求がDockerホストのIPアドレスにマップされるように、ワイルドカードDNSをセットアップしています。 Apache(またはNginx)インスタンスを実行する複数のコンテナーがある場合、各コンテナーはApacheポート(80)を外部のインバウンドポートにマップします。

私がやりたいのは、コンテナ-1.fooにリクエストを行うことです。これは、カスタムDNSサーバーを介して(Dockerホストの)正しいIPアドレスに既にマップされていますが、デフォルトのポート80リクエストを正しいDocker外部にプロキシします指定されたコンテナからの正しいApacheインスタンスがカスタムドメインに基づいて応答できるようにポート。同様に、container-2.fooは2番目のコンテナーのApacheにプロキシします。

これに事前に構築されたソリューションはありますか、DockerホストでNginxプロキシを実行するのが最善の策ですか、またはDockerコンテナを管理する可能性のあるnode.jsプロキシを作成する必要があります(Web経由で開始/停止/再構築)、 または...? Dockerコンテナを、自然なイベントのように使用し、無関係なポートやコンテナジャグリングを使用するものではなく、どのようなオプションがありますか?

81
ringmaster

この答えは少し遅いかもしれませんが、必要なのは自動リバースプロキシです。そのために2つのソリューションを使用しました。

  • jwilder/nginx-proxy
  • トレフィク

時間の経過とともに、私の好みはTraefikを使用することです。主に、十分に文書化され維持されており、より多くの機能(さまざまな戦略と優先度を備えた負荷分散、ヘルスチェック、サーキットブレーカー、ACME/Let's Encryptによる自動SSL証明書など)が備わっているためです。


Jwilder/nginx-proxyを使用する

Dockerコンテナ Jason Wilderのnginx-proxy Docker image を実行すると、nginxサーバーが他のコンテナのリバースプロキシとして設定され、設定は維持されません。

VIRTUAL_Host環境変数で他のコンテナを実行するだけで、nginx-proxyはip:portを検出し、nginx設定を更新します。

*.test.localがDockerホストのIPアドレスにマップされるようにDNSが設定されているとします。次に、次のコンテナーを起動して、簡単なデモを実行します。

# start the reverse proxy
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

# start a first container for http://tutum.test.local
docker run -d -e "VIRTUAL_Host=tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -e "VIRTUAL_Host=deis.test.local" deis/helloworld

Traefikを使用する

Traefik コンテナーを実行すると、指定されたdockerラベルで指定された転送ルールを再構成するリバースプロキシサーバーが設定されますコンテナ。

*.test.localがDockerホストのIPアドレスにマップされるようにDNSが設定されているとします。次に、次のコンテナーを起動して、簡単なデモを実行します。

# start the reverse proxy
docker run --rm -it -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik --docker

# start a first container for http://tutum.test.local
docker run -d -l "traefik.frontend.rule=Host:tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -l "traefik.frontend.rule=Host:deis.test.local" deis/helloworld
78
Thomasleveil

考えられる2つの答えは次のとおりです。(1)Dockerでポートを直接設定し、Nginx/Apacheを使用して仮想ホストをプロキシするか、(2) Dokk を使用してポートと仮想ホストを管理します(これが私が学んだ方法です)方法1)を実行します。

方法1a(ドッカーでポートを直接割り当てる)

手順1:ホストでnginx.confまたはApacheをセットアップし、目的のポート番号を割り当てます。ホストで実行されているこのWebサーバーは、vhostプロキシを実行します。 Dockerに関してこれについて特別なことは何もありません-それは通常の仮想ホストホスティングです。次に、ステップ2の特別な部分で、Dockerに正しいホストポート番号を使用させます。

ステップ2:次のように、「-p」を使用してDockerでポート番号の割り当てを強制し、Dockerのポートマッピングを設定し、「-e」でDocker内のカスタム環境変数を設定します。

port=12345 # <-- the vhost port setting used in nginx/Apache
IMAGE=myapps/container-1
id=$(docker run -d -p :$port -e PORT=$port $IMAGE)
# -p :$port will establish a mapping of 12345->12345 from outside docker to
# inside of docker.
# Then, the application must observe the PORT environment variable
# to launch itself on that port; This is set by -e PORT=$port.

# Additional goodies:
echo $id # <-- the running id of your container
echo $id > /app/files/CONTAINER # <-- remember Docker id for this instance
docker ps # <-- check that the app is running
docker logs $id # <-- look at the output of the running instance
docker kill $id # <-- to kill the app

方法1bハードコーディングされたアプリケーションポート

...アプリケーションがハードコーディングされたポート、たとえばポート5000を使用している場合(つまり、方法1aのようにPORT環境変数を介して構成することはできません)、Dockerを介して次のようにハードコーディングできます:

publicPort=12345
id=$(docker run -d -p $publicPort:5000 $IMAGE)
# -p $publicPort:5000 will map port 12345 outside of Docker to port 5000 inside
# of Docker. Therefore, nginx/Apache must be configured to vhost proxy to 12345,
# and the application within Docker must be listening on 5000.

方法2(Dokkuにポートを把握させる)

現時点では、Docker vhostを管理するための非常に良いオプションは Dokk です。今後のオプションは Flynn を使用することかもしれませんが、現在のところ、Flynnはまだ始まったばかりで、まだ準備が整っていません。したがって、ここではDokkuを使用します。Dokkuのインストール手順に従って、単一ドメインで「VHOST」ファイルを作成してvhostsを有効にします。

echo yourdomain.com > /home/git/VHOST
# in your case: echo foo > /home/git/VHOST

これで、アプリがSSH経由でDokkuにプッシュされると(これを行う方法についてはDokkuのドキュメントを参照)、DokkuはVHOSTファイルを確認し、プッシュされた特定のアプリ(「container-1」をプッシュしたとしましょう)を生成します次のファイル:

/home/git/container-1/nginx.conf

また、次の内容が含まれます。

upstream container-1 { server 127.0.0.1:49162; }
server {
  listen      80;
  server_name container-1.yourdomain.com;
  location    / {
    proxy_pass  http://container-1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_Host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

サーバーが再起動されると、Dokkuは、Dockerが別のポートをランダムに割り当てられるのではなく、最初にデプロイされたポート(ここでは49162)にマップされたポートでアプリケーションを起動するようにします。この決定論的な割り当てを実現するために、Dokkuは最初に割り当てられたポートを/home/git/container-1/PORTに保存し、次回の起動時にPORT環境をこの値に設定し、Dockerのポート割り当てを両方のポートでこのポートにマッピングしますホスト側とアプリ側。これは、DokkuがPORT=5000を設定し、Voks側でDokkuがアプリ側で5000にマップするランダムポートを見つけ出す最初の起動とは反対です。ラウンド(および将来変更される可能性もあります)ですが、動作します!

VHOSTが内部で動作する方法は、SSHを介してアプリのgit Pushを実行すると、Dokkuは/var/lib/dokku/plugins/nginx-vhostsに存在するフックを実行します。これらのフックは、Dokkuソースコードにもあります here であり、正しいvhost設定でnginx.confファイルを書き込む役割を果たします。 /var/lib/dokkuの下にこのディレクトリがない場合は、dokku plugins-installを実行してみてください。

42
David Baird

Dockerでは、内部IPを通常のまま(たとえば80)にして、ランダムポートを接続する方法を見つけます。

それらを処理する1つの方法は、hipacheのようなリバースプロキシを使用することです。 DNSを指定して、コンテナーが上下するときにプロキシを再構成できます。 http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/ を見て、これがどのように機能するかを確認してください。

より堅牢なものを探している場合は、「サービスの発見」をご覧ください。 (dockerでのサービスディスカバリーを見る: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/

3
ben schwartz