当前位置: 首页 > 面试题库 >

如何配置Docker端口映射以将Nginx用作上游代理?

闽康安
2023-03-14
问题内容

现在是2015年7月16日,情况又发生了变化。我从Jason
Wilder
找到了这个自动魔术容器: https://github.com/jwilder/nginx- proxy它可以解决这个问题,只要将它带到docker run容器中即可。现在这是我用来解决此问题的解决方案。

更新资料

现在是2015年7月,关于联网Docker容器的情况已经发生了巨大变化。现在有许多不同的产品(以多种方式)解决了这个问题。

您应该使用这篇文章对docker --link服务发现的方法有一个基本的了解,它几乎是最基本的,很好的工作方式,并且实际上比大多数其他解决方案需要更少的花式跳舞。它的局限性在于,很难在任何给定群集中的单独主机上联网容器,并且一旦联网就无法重新启动容器,但是确实提供了一种快速且相对容易的方式来在同一主机上联网容器。这是了解您可能要使用的软件实际上是在做什么的一种好方法。

此外,您可能还需要查看Docker的新生network,Hashicorp的consul,Weaveworks
weave,Jeff
Lindsay的progrium/consulgliderlabs/registrator和Google的Kubernetes

另外还有CoreOS利用的产品etcdfleetflannel

如果您真的想开一个聚会,可以启动一个集群来运行Mesosphere,或者Deis,或者Flynn

如果您是网络新手(像我一样),那么您应该拿起老花镜,在Wi-Hi-Fi上弹出“用星星画天空-
最好的Enya”,然后喝点啤酒-
这将是过一会儿,您才真正了解要执行的操作。提示:你试图实现一个Service Discovery Layer在你的Cluster Control Plane。这是度过一个星期六晚上的好方法。

这很有趣,但是我希望我能花点时间在开始潜水之前,对自己的网络进行一般性的更好的学习。我最终从仁慈的《数字海洋教程》中找到了几篇文章:Introduction to Networking TerminologyUnderstanding ... Networking。我建议在潜水之前先阅读几次。

玩得开心!

原始帖子

我似乎无法掌握Docker容器的端口映射。特别是如何将请求从Nginx传递到另一个容器,在同一服务器上的另一个端口上侦听。

我有一个Nginx容器的Dockerfile像这样:

FROM ubuntu:14.04
MAINTAINER Me <me@myapp.com>

RUN apt-get update && apt-get install -y htop git nginx

ADD sites-enabled/api.myapp.com /etc/nginx/sites-enabled/api.myapp.com
ADD sites-enabled/app.myapp.com /etc/nginx/sites-enabled/app.myapp.com
ADD nginx.conf /etc/nginx/nginx.conf

RUN echo "daemon off;" >> /etc/nginx/nginx.conf

EXPOSE 80 443

CMD ["service", "nginx", "start"]

然后api.myapp.com配置文件如下所示:

upstream api_upstream{

    server 0.0.0.0:3333;

}


server {

    listen 80;
    server_name api.myapp.com;
    return 301 https://api.myapp.com/$request_uri;

}


server {

    listen 443;
    server_name api.mypp.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;

    }

}

然后还有另一个app.myapp.com

然后我运行:

sudo docker run -p 80:80 -p 443:443 -d --name Nginx myusername/nginx

一切都很好,但是请求没有传递到其他容器/端口。当我将其放入Nginx容器并检查日志时,我看不到任何错误。

有什么帮助吗?


问题答案:

@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链接到APIApp

其结果是更改了envvars和/etc/hosts位于APIand 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文件条目和envvar,它们包含所链接的任何容器的本地IP地址。据我所知,这是在运行带有声明的链接选项的容器时发生的所有情况。但是您现在可以使用此信息nginxNginx容器中进行配置。

配置Nginx

这是个棘手的地方,有两种选择。您可以选择将站点配置为指向/etc/hostsdocker创建文件中的条目,或者可以使用ENVvars
sednginx.conf文件/etc/nginx/sites- enabled夹中的conf文件和其他任何conf文件运行字符串替换(我用过)以插入IP。价值观。

选项A:使用ENV Vars配置Nginx

这是我选择的选项,因为我无法使用 /etc/hostsfile选项。我将尽快尝试选项B,并用任何发现更新本文。

此选项与使用/etc/hosts文件选项之间的主要区别在于,如何编写Dockerfile脚本以使用shell脚本作为CMD参数,而该脚本又处理字符串替换以将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-Startup.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.confapi.myapp.conf

魔术发生在Nginx- Startup.sh我们用来sedAPP_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文件,这些文件具有ENVdocker在启动容器时设置的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。据我有限的理解,此解决方案很可能会使用CoreOSetcd服务,并且它的服务就像ENV注册到同一CoreOS集群的所有计算机的共享一样。这是我要设置的下一个玩具。

选项B:使用/etc/hosts文件条目

应该
是更快,更轻松的方法,但是我无法使其正常工作。从表面上看,您只是将/etc/hosts条目的值输入到您的api.myapp.confapp.myapp.conf文件中,但是我无法使用此方法。

这是我所做的尝试api.myapp.conf

upstream api_upstream{
    server API:3000;
}

考虑到我的/etc/hosts文件中有一个这样的条目:172.0.0.2API我认为它只会提取值,但似乎没有。

Elastic LoadBalancer从所有可用区的采购也遇到了一些辅助问题,因此当我尝试此路线时可能就是问题所在。相反,我不得不学习如何在Linux中处理替换字符串,所以这很有趣。我将在一段时间内尝试一下,看看效果如何。



 类似资料:
  • 我不确定我是否误解了这里的某些东西,但似乎只有通过从映像创建一个新容器来设置端口映射才是可能的。是否有一种方法将一个端口映射分配给一个现有的Docker容器?

  • 背景: vue3+vite项目中:前后端联调的时候, 代理转发设置成功,但是由于接口文件中有多个文件,一个个加代理配置比较麻烦,所以想着给接口增加前缀的方式去统一设置代码 比如接口文件中有如下两个接口,url分别如下 统一增加前缀/sys 在本地.env.development文件中统一配置设置转发 接口可以正常响应,但是这个/sys是自己自定义的,而且这个设置是在.env.development

  • 问题内容: 我不确定在这里是否误解了一些东西,但是似乎只能通过从映像创建新容器来设置端口映射。是否可以将端口映射分配给现有Docker容器? 问题答案: 您可以通过直接在以下位置编辑文件 来更改端口映射 您可以通过命令确定[hash_of_the_container] ,“ Id”字段的值为哈希。 因此,您无需使用这种方法来创建图像。您也可以在此处更改重新启动标志。 PS:您可以访问 https:

  • 目标是运行两个容器的。一个容器应该映射到主机上的8080端口,另一个映射到8081端口。这是docker compose的

  • 本文向大家介绍Docker端口映射的实现,包括了Docker端口映射的实现的使用技巧和注意事项,需要的朋友参考一下 docker容器在启动的时候,如果不指定端口映射参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。 亦可使用Dockerfile文件中的EXPOSE指令来配置。 端口映射可使用-p、-P来实现: -p指定要映射的端口,一个指定端口上只可以绑定一个容器 -P将容器内部开放的

  • 问题内容: 我想在不同主机上的某些Docker容器中运行任务。而且我编写了一个管理器应用程序来管理容器(启动任务,停止任务,获取状态等)。容器启动后,它将向管理器发送一个http请求及其地址和端口,因此管理器将知道如何管理该容器。 由于同一主机上可能运行着多个容器,因此它们将被映射到不同的端口。要在我的经理上注册一个容器,我必须知道每个容器映射到哪个端口。 如何 在 Docker容器中获取映射的端