Nginx在docker中的网络以及如何在OSI的应用层和传输层的load balance

Xiao Qiang Lv4

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暴露
      image
      • 创建一个新的nginx.conf文件,启动docker的时候将会覆盖default文件,在conf中定义一个server,使用proxy_pass设置其转发地址

        1
        2
        3
        4
        5
        6
        7
        server {
        listen 8080;
        server_name localhost;
        location / {
        proxy_pass http://nodebackend/;
        }
        }
      • 在定义一个upstream对象,其中放置的是集群的地址,放置多个地址时可以使用负载均衡算法

        1
        2
        3
        4
        5
        6
        upstream nodebackend {

        server nodeapp1:8080;
        server nodeapp2:8080;
        server nodeapp3:8080;
        }
      • 配置好NGINX的代理之后,就可以使用docker run命令把Nginx镜像run起来,然后再使用-voption,将本地的nginx.conf挂载到容器中
        error in nginx container

        • 出现上述原因是因为,NGINX和其他三个容器没有在同一个network中,所以我们需要创建一个网络,然后把nginx和其余的node app放到同一个network中,他们之间就可以相互通信,rundocker network create <network name>,然后在rundocker network connect <network name> <your app>
        • 重启nginx容器docker start nginx
        • nginx will pass through the traffic
    • 多个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
    • 创建一个带子网的网络,rundocker network <network name> --subnet <ip/24>
    • 将容器和创建的网络关联,rundocker 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,run docker run --name <container name> -d --network <network name> --cap-add=NET_ADMIN -d myhttpd
    • 添加需要通信容器的两个路由,runip route add <destination> via <gateway>这里要注意每个服务都需要添加上述命令,因为每个容器也需要知道它自己能访问谁,另外一个服务接受到请求时要知道给谁反应(response),这个也可以添加脚本在dockerfile中来避免每次的手动操作,如果下述图片不够清楚,原图
      image

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 balance

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
      http {
    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同一个用户的相关资源

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
On this page
Nginx在docker中的网络以及如何在OSI的应用层和传输层的load balance