Nginx在docker中的网络以及如何在OSI的应用层和传输层的load balance
Nginx with Docker
How to Run it in docker
- docker cmd run docker image
docker run --name <container name> -p 80:80 --hostname <hostname> -d nginx
- 其中hostname是方便docker内部的容器之间的通信,如果不设置会有默认值
- 本地Nginx遇到问题
nginx: [error] open() "/usr/local/var/run/nginx.pid" failed (2: No such file or directory)
,先运行nginx -c /usr/local/etc/nginx/nginx.conf
指定好你的Nginx的配置的目录,然后重新reload即可 - 使用minikube挂载docker VM启动docker时,需要使用minikube的ip+暴露的端口号来访问对应的服务,获取minikube的ip可以运行
minikube ip
,现在有一个问题,当我改变映射端口号为非80端口是,容器无法从外部访问,why? - minikube如何做volume,run
minikube mount <path you want to mount>:/<path in the minikube>
,然后再使用docker run启动容器,再把挂载在minikube中的volume挂载到docker容器中,但是,minikube mount的那个session需要一直打开- 有什么替代方案?
- 如何在docker中使用NGINX代理不同的app
- 使用IPTABLE
- 只有一个Nginx暴露
创建一个新的
nginx.conf
文件,启动docker的时候将会覆盖default文件,在conf
中定义一个server,使用proxy_pass
设置其转发地址1
2
3
4
5
6
7server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://nodebackend/;
}
}在定义一个upstream对象,其中放置的是集群的地址,放置多个地址时可以使用负载均衡算法
1
2
3
4
5
6upstream nodebackend {
server nodeapp1:8080;
server nodeapp2:8080;
server nodeapp3:8080;
}配置好NGINX的代理之后,就可以使用docker run命令把Nginx镜像run起来,然后再使用
-v
option,将本地的nginx.conf
挂载到容器中- 出现上述原因是因为,NGINX和其他三个容器没有在同一个network中,所以我们需要创建一个网络,然后把nginx和其余的node app放到同一个network中,他们之间就可以相互通信,run
docker network create <network name>
,然后在rundocker network connect <network name> <your app>
- 重启nginx容器
docker start nginx
- 出现上述原因是因为,NGINX和其他三个容器没有在同一个network中,所以我们需要创建一个网络,然后把nginx和其余的node app放到同一个network中,他们之间就可以相互通信,run
- 多个Nginx暴露,并且Nginx之间还会相互指向
docker network
- network类型,bridge(docker default network),在容器内部如果没有特殊的设置是无法使用hostname来完成相互之间的访问,因为当使用hostname来访问服务时,会先去容器外面的DNS服务器查询对应hostname的ip,但是容器内部的hostname只是我们自定义的名称,在DNS服务器上是不可知的,所以访问不到,如果没有指定的话,只能使用ip互相通信
- 在 Docker 默认的 bridge 网络中,每个容器都被分配了一个 IP 地址,并且 Docker 引擎会在内部维护一个名为 docker0 的虚拟网桥,所有连接到 bridge 网络的容器都会加入到这个网桥中。由于 docker0 网桥中没有 DNS 服务或其他类似服务来维护容器名称和 IP 地址之间的映射关系,因此不能直接使用容器名称进行通信,而只能使用 IP 地址
- 查看当前网络中的容器的ip,run
docker inspect network bridge
- 创建一个带子网的网络,run
docker network <network name> --subnet <ip/24>
- 将容器和创建的网络关联,run
docker network connect <network name> <container name>
- 不同子网之间的容器的通信
- 这么做的原因可以做的保护自己的业务服务,所以可以把Nginx和其他的后端或者DB隔离开,如果要使两个隔离的network之间相互通信。
- 需要添加一个
gateway
,rundocker run --name gw --network snetwork -d myhttpd
, 用这个gateway来连接两个不同的网络。 - 创建好了之后再把另外的网络关联起来,run
docker network connect <another network name> gw
这样,gw就可以访问两个隔离网络 - 重启每个网络中的容器,并且设定网络,以及赋予该容器较大的权限使用
--cap-add=NET_ADMIN
,rundocker run --name <container name> -d --network <network name> --cap-add=NET_ADMIN -d myhttpd
- 添加需要通信容器的两个路由,run
ip route add <destination> via <gateway>
,这里要注意每个服务都需要添加上述命令,因为每个容器也需要知道它自己能访问谁,另外一个服务接受到请求时要知道给谁反应(response),这个也可以添加脚本在dockerfile中来避免每次的手动操作,如果下述图片不够清楚,原图
Nginx在OSI model中作为不同层的反向代理
server web
- 将Nginx服务作为一个静态代理服务器,用来管理一些静态资源,这些资源不会跟随业务而频繁变化。🌰,html中的css,js文件等。这里有一点需要注意,不同用户起的Nginx服务对于root的访问权限也是不一样的,🌰,使用
homebrew
安装的nginx无法使用Users
目录底下的文件,只能放在nginx的default文件夹下新建其他的folder- 使用
- 路由转发
proxy_pass
- 路由控制
location xxxx {}
,其中xxx
既可以是某个路径,也可以是一个regex
- 路由转发
- 使用
layer7 (http level)
配置都放在http中
http { upstream xxx server xxx }
,这样控制的就是应用层的load balance1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19http {
server {
listen 8080;
root /usr/local/var/test;
location ~ .jpg$ {
return 403;
}
}
server {
listen 8888;
location / {
proxy_pass http://localhost:8080;
}
location /img {
proxy_pass http://localhost:8080/images;
}
}
}
events { }负载均衡
- 配置upstream,当用户访问某个资源的时候,将会通过算法(
round-robin
)自动分给不同的upstream - 在upstream添加
ip_hash
,用来保证同一个ip的用户永远都是访问同一个upstream,这样可以避免upstream中的多个服务cache同一个用户的相关资源
- 配置upstream,当用户访问某个资源的时候,将会通过算法(
layer4
- 最外层是
stream
,直接把流传递给后端,所有不会关心前端是什么协议,这里要注意的就是,使用stream时,只会建立一次tcp通信,所以如果请求是从浏览器发起的,那么之后的所有请求都是请求的同一个后端服务
- Title: Nginx在docker中的网络以及如何在OSI的应用层和传输层的load balance
- Author: Xiao Qiang
- Created at : 2023-05-31 09:24:54
- Updated at : 2025-03-08 10:49:30
- Link: http://fdslk.github.io/tech/opps/nginx/2023/05/31/nginx-with-docker/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments