@ T0xicCode的答案是正确的,但是我认为我会扩展细节,因为实际上花了大约20个小时才能最终实现可行的解决方案。
如果您希望在自己的容器中运行Nginx并将其用作反向代理以在同一服务器实例上负载均衡多个应用程序,那么您需要遵循的步骤如下:
链接您的容器
当docker run
您使用容器时,通常可以通过在中输入shell脚本User Data
来声明指向任何其他正在运行的容器的链接。这意味着您需要按顺序启动容器,只有后者才能链接到前者。像这样:
#!/bin/bash
sudo docker run -p 3000:3000 --name API mydockerhub/api
sudo docker run -p 3001:3001 --link API:API --name App mydockerhub/app
sudo docker run -p 80:80 -p 443:443 --link API:API --link App:App --name Nginx mydockerhub/nginx
因此,在此示例中,该API
容器未链接到任何其他App
容器,但是该
容器已链接到API
并且Nginx
链接到API
和App
。
其结果是更改了env
vars和/etc/hosts
位于API
和App
容器内的文件。结果看起来像这样:
/ etc / hosts
cat /etc/hosts
在您的Nginx
容器中运行将产生以下结果:
172.17.0.5 0fd9a40ab5ec
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 App
172.17.0.2 API
ENV Vars
env
在您的Nginx
容器中运行将产生以下结果:
API_PORT=tcp://172.17.0.2:3000
API_PORT_3000_TCP_PROTO=tcp
API_PORT_3000_TCP_PORT=3000
API_PORT_3000_TCP_ADDR=172.17.0.2
APP_PORT=tcp://172.17.0.3:3001
APP_PORT_3001_TCP_PROTO=tcp
APP_PORT_3001_TCP_PORT=3001
APP_PORT_3001_TCP_ADDR=172.17.0.3
我已经截断了许多实际的var,但是以上是您需要将流量代理到容器的键值。
要获取一个shell在运行中的容器中运行上述命令,请使用以下命令:
sudo docker exec -i -t Nginx bash
您可以看到您现在同时具有/etc/hosts
文件条目和env
var,它们包含所链接的任何容器的本地IP地址。据我所知,这是在运行带有声明的链接选项的容器时发生的所有情况。但是您现在可以使用此信息nginx
在Nginx
容器中进行配置。
配置Nginx
这是个棘手的问题,这里有两个选择。您可以选择将站点配置为指向/etc/hosts
所docker
创建文件中的条目,也可以使用ENV
varssed
对nginx.conf
文件/etc/nginx/sites-enabled
夹中的conf文件和其他conf文件运行字符串替换(我用过)以插入IP。价值观。
选项A:使用ENV Vars配置Nginx
这是我选择的选项,因为我无法使用
/etc/hosts
file选项。我将尽快尝试选项B,并用任何发现更新本文。
此选项与使用/etc/hosts
file选项之间的主要区别在于,如何编写Dockerfile
脚本以使用shell脚本作为CMD
参数,而shell脚本依次处理字符串替换以将IP值复制ENV
到conf文件中。
这是我最终得到的一组配置文件:
Docker文件
FROM ubuntu:14.04
MAINTAINER Your Name <you@myapp.com>
RUN apt-get update && apt-get install -y nano htop git nginx
ADD nginx.conf /etc/nginx/nginx.conf
ADD api.myapp.conf /etc/nginx/sites-enabled/api.myapp.conf
ADD app.myapp.conf /etc/nginx/sites-enabled/app.myapp.conf
ADD Nginx-Startup.sh /etc/nginx/Nginx-Startup.sh
EXPOSE 80 443
CMD ["/bin/bash","/etc/nginx/Nginx-Startup.sh"]
nginx.conf
daemon off;
user www-data;
pid /var/run/nginx.pid;
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 33;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/xml text/css application/x-javascript application/json;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# Virtual Host Configs
include /etc/nginx/sites-enabled/*;
# Error Page Config
#error_page 403 404 500 502 /srv/Splash;
}
注意:重要的是要包含daemon off;
在nginx.conf
文件中,以确保容器在启动后不会立即退出。
api.myapp.conf
upstream api_upstream{
server APP_IP:3000;
}
server {
listen 80;
server_name api.myapp.com;
return 301 https://api.myapp.com/$request_uri;
}
server {
listen 443;
server_name api.myapp.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_pass http://api_upstream;
}
}
Nginx-启动.sh
#!/bin/bash
sed -i 's/APP_IP/'"$API_PORT_3000_TCP_ADDR"'/g' /etc/nginx/sites-enabled/api.myapp.com
sed -i 's/APP_IP/'"$APP_PORT_3001_TCP_ADDR"'/g' /etc/nginx/sites-enabled/app.myapp.com
service nginx start
我把它留给你做你的最多的内容作业nginx.conf
和api.myapp.conf
。
魔术发生在Nginx-Startup.sh
我们用来sed
在APP_IP
已写入到文件和文件upstream
块中的占位符上进行字符串替换的地方。api.myapp.conf
app.myapp.conf
这个ask.ubuntu.com问题很好地说明了这一点:
使用命令在文件中查找和替换文本
GOTCHA
在OSX上,以sed
不同方式处理选项,特别是-i
标志。在Ubuntu上,该-i
标志将处理“就地”替换;它将打开文件,更改文本,然后“保存”相同的文件。在OSX上,该-i
标志需要您想要结果文件具有的文件扩展名。如果使用的文件没有扩展名,则必须输入''作为-i
标志值。
GOTCHA
要在sed
用于查找要替换的字符串的正则表达式中使用ENV变量,需要将变量包装在双引号中。因此,正确的,尽管看上去有些古怪的语法如上所述。
因此docker启动了我们的容器并触发了Nginx-Startup.sh
脚本运行,该脚本用于sed
将值更改为我们在命令中提供APP_IP
的相应ENV
变量sed
。现在我们的/etc/nginx/sites-enabled
目录中有conf文件,这些文件具有ENV
docker在启动容器时设置的vars的IP地址。在api.myapp.conf
文件中,您将看到upstream
块已更改为:
upstream api_upstream{
server 172.0.0.2:3000;
}
您看到的IP地址可能有所不同,但是我注意到它通常是172.0.0.x
。
现在,您应该正确路由所有路由。
GOTCHA
一旦运行了初始实例启动,就无法重新启动/重新运行任何容器。Docker在启动时为每个容器提供了一个新IP,并且似乎没有重复使用以前使用的任何容器。因此api.myapp.com
,第一次将获得172.0.0.2,而下次将获得172.0.0.4。但是Nginx
将已经在其conf文件或该/etc/hosts
文件中设置了第一个IP ,因此它将无法确定的新IP api.myapp.com
。据我有限的理解,此解决方案很可能会使用CoreOS
其etcd
服务,并且它的服务就像ENV
注册到同一CoreOS
群集的所有计算机的共享一样。这是我要设置的下一个玩具。
选项B:使用/etc/hosts
文件条目
这应该是更快,更轻松的方法,但我无法使其正常工作。从表面上看,您只是将/etc/hosts
条目的值输入到您的api.myapp.conf
和app.myapp.conf
文件中,但是我无法使用此方法。
更新:
有关如何使此方法起作用的说明,请参见@Wes Tod的答案。
这是我所做的尝试api.myapp.conf
:
upstream api_upstream{
server API:3000;
}
考虑到我的/etc/hosts
文件中有一个这样的条目:172.0.0.2 API
我认为它只会提取值,但似乎没有。
我Elastic Load Balancer
从所有可用区的采购也遇到了一些辅助问题,因此当我尝试此路线时可能就是问题所在。相反,我不得不学习如何在Linux中处理替换字符串,所以这很有趣。我将在一段时间内尝试一下,看看效果如何。