使用nginx+docker实现一个简单的负载均衡

流程图

图片
nginx+docker实现一个简单的负载均衡

技术栈:docker + nginx + jdk + tomcat

背景

一般来说,一个公司不可能只部署一个服务,如果是这个服务某些原因挂了,导致引起客诉。

也很少只部署一台机器上,假如这台机器宕机…,也会引起客诉。

所以当服务并发请求量较大时,一台服务器处理不过来,所以就需要加多台服务器,所以就有了集群。

但是对于这么多发服务器,我们怎么知道用户请求到了哪台机器,如果是请求到了这台机器,下一次打到别的机器,有需要重新验证吗?

所以这个时候就有了nginx负载均衡功能,负载均衡的方式有几种,这是是设置weight权重模式。可以配置服务器权重;配置低的服务器就设置低权重。

所以这里简单实现一个负载均衡,通过docker拉去2个jdk镜像+1个nginx镜像。用脚本形式启动。相当于实现了反向代理的功能。

目标:两台tomcat放在2个jdk镜像里面,1个nginx镜像

目的:通过浏览器成功访问80,nginx负载均衡访问两台tomcat服务器。

具体步骤:

  1. docker登录 harbor仓库,docker拉取jdknginx镜像
  2. 编写3个脚本挂起3个镜像。一个nginx镜像脚本,两个jdk镜像脚本(2个tomcat放里面)。通过脚本启动服务。
  3. 配置nginxtomcat的端口

先看效果:通过访问80端口,代理8080和8090端口,实现nginx负载均衡

访问nginx端口
图片
8080端口
图片
8090端口
图片

之前通过阿里云服务器linux系统上,通过原生配置nginx+3台tomcat可以实现负载均衡。

现在通过虚拟机上docker 拉取镜像,配置负载均衡。

一、环境准备

1.1 安装环境(docker)

yum update
yum-config-manager 
    --add-repo 
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

yum -y install docker-ce-19.03.11
systemctl start docker 
systemctl enable docker

mkdir -p /etc/docker
cd /etc/docker/

cat >> /etc/docker/daemon.json <<EOF
{
        "insecure-registries":["10.249.0.137:80","10.252.0.209:80","10.252.0.29:5000","10.245.0.253:5000"],
        "log-driver": "json-file",
        "log-opts": {
                "max-size": "1024m",
                "max-file": "1"
        }
}
EOF

systemctl daemon-reload && systemctl restart docker

1.2 登录harbor镜像仓库,拉取镜像

[root@localhost ~]# docker login 10.249.0.137:80
Username: admin
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@localhost ~]# docker pull 10.249.0.137/base/jdk-1.8:20210202
[root@localhost ~]# docker pull 10.249.0.137/base/nginx:1.13.8
图片

1.3 通过编写脚本启动镜像

通过编写脚本启动镜。这么做的目的是方便知道,当你容器内做了修改,然后你宿主机也会发生改变。

新建jdk,jdk2脚本,并且进入容器里面。docker exec -it 容器名

1.4 编写jdk1脚本

/opt/script/setup/jdk目录下,进行设置jdk1脚本

[root@localhost jdk]# pwd
/opt/script/setup/jdk
[root@localhost jdk]# vim install.sh 

# !/bin/bash
# 编写作者: 千羽的编程时光
# 程序说明:自动创建容器、并分配固定IP及开放端口
# ---------------------------------------------------------------------------
#
#设置容器相关变量
cname="test-jdk"
name="jdk1.8"
logs="/opt/data/"${cname}"/"
#创建目录
mkdir -p ${logs}
port1="8080"

#启动容器
echo -e "Start "${cname}" Container"
docker run -d -it -p ${port1}:${port1} --privileged=true  --restart=always --name ${cname} --hostname ${name}  -v ${logs}:/opt/data 10.249.0.137:80/base/jdk-1.8:20210202

保存退出 esc:wq!

使脚本生效,启动脚本

[root@localhost jdk]# chmod +x install.sh 
[root@localhost jdk]# ls
install.sh
[root@localhost jdk]# ./install.sh 
Start test-jdk Container
6add9e8b81d6cbd6ee7ddc6da9e50b4629c2ce58f2383c7a912c4b7403610c19
[root@localhost jdk]# docker ps
CONTAINER ID   IMAGE                                   COMMAND               CREATED         STATUS         PORTS                            NAMES
6add9e8b81d6   10.249.0.137:80/base/jdk-1.8:20210202   "/usr/sbin/sshd -D"   6 seconds ago   Up 5 seconds   22/tcp, 0.0.0.0:8080->8080/tcp   test-jdk

1.5 配置tomcat1

这里的通过把二进制包tomcat包上传到挂载目录(即存放到镜像里面),然后进入到镜像里面进行配置tomcat

当你把二进制包tomcat1丢进去挂载目录,相当于镜像里面也上传了一份tomcat1

[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root     220 7月  22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月  22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]#

修改tomcat的配置文件,改端口

[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root     220 7月  22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月  22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]# cd apache-tomcat-8.5.41
[root@localhost conf]# vim server.xml
<Connector port="8000" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />

启动tomcat

图片
图片

1.6 编写jdk2脚本

[root@localhost setup]# pwd
/opt/script/setup
[root@localhost setup]# ll
总用量 0
drwxr-xr-x. 2 root root 24 7月  22 14:14 jdk
drwxr-xr-x. 2 root root 24 7月  22 16:01 jdk2
drwxr-xr-x. 3 root root 77 7月  22 17:49 nginx
[root@localhost setup]#

进入java目录下:

cd /opt/script/setup/jdk

通过脚本启动容器

[root@localhost jdk]# vim install.sh
# !/bin/bash
# 编写作者: 千羽的编程时光
# 程序说明:自动创建容器、并分配固定IP及开放端口
# ---------------------------------------------------------------------------
# 设置容器相关变量
cname="test-jdk2"
name="jdk1.8"

logs="/opt/data/"${cname}"/"
#创建目录
mkdir -p ${logs}
port1="8090"
#启动容器
echo -e "Start "${cname}" Container"

docker run -d -it -p ${port1}:${port1} --privileged=true  --restart=always --name ${cname} --hostname ${name}  -v ${logs}:/opt/data 10.249.0.137:80/base/jdk-1.8:20210202

启动脚本

[root@localhost jdk2]# vim install.sh 
[root@localhost jdk2]# pwd
/opt/script/setup/jdk2
[root@localhost jdk2]# ll
总用量 4
-rwxr-xr-x. 1 root root 868 7月  22 15:59 install.sh
[root@localhost jdk2]# ./install.sh

1.7 配置tomcat2

[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root     220 7月  22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月  22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]#

修改tomcat的配置文件,改端口

[root@localhost test-jdk]# pwd
/opt/data/test-jdk
[root@localhost test-jdk]# ll
总用量 9472
drwxr-xr-x. 9 root root     220 7月  22 10:51 apache-tomcat-8.5.41
-rw-r--r--. 1 root root 9699102 7月  22 10:23 apache-tomcat-8.5.41.tar.gz
[root@localhost test-jdk]# cd apache-tomcat-8.5.41
[root@localhost conf]# vim server.xml
<Connector port="8090" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />

启动tomcat

图片
图片

二、编写nginx 脚本,启动nginx镜像

[root@localhost nginx]# pwd
/opt/script/setup/nginx
[root@localhost nginx]# vim install.sh

nginx脚本install.sh

#!/bin/bash
# 编写作者:千羽的编程时光
# 程序说明:虚拟主机启动时自动执行脚本,实现ovs初始化、增加IP路由、固定容器IP、端口开放等。
# ---------------------------------------------------------------------------
cname="test-nginx"
port1="80"
log="/opt/data/"${cname}
mkdir -p ${log}/conf
mkdir -p ${log}/data
cp -r nginx.conf ${log}/conf
cp -r html ${log}

docker run -it -d -v ${log}/conf/nginx.conf:/etc/nginx/nginx.conf -v ${log}/html:/usr/share/nginx/html -v ${log}/data:/opt/data --name ${cname} --hostname ${cname} -p ${port1}:${port1} --restart=always --privileged 10.249.0.137:80/base/nginx:1.13.8

修改nginx.conf 配置文件

[root@localhost conf]# pwd
/opt/data/test-nginx/conf
[root@localhost conf]# vim nginx.conf 

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;

upstream backserver {
#        ip_hash;
        server 10.8.46.197:8080;
        server 10.8.46.197:8090;

 }

server{
        listen 80;
        server_name 10.8.46.197;
        index index.html index.htm index.php;
          location /{
              proxy_pass  http://backserver;
              proxy_set_header Host   $host;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
              proxy_set_header   X-Real-IP        $remote_addr;
              proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
              fastcgi_buffer_size 512k;
              fastcgi_buffers 6 512k;
              fastcgi_busy_buffers_size 512k;
              fastcgi_temp_file_write_size 512k;
              proxy_set_header X-Forwarded-Proto $scheme;
              proxy_set_header X-Forwarded-Port $server_port;
           }

   }
}

启动脚本

[root@localhost nginx]# ll
总用量 8
drwxr-xr-x. 2 root root    6 7月  22 13:48 html
-rwxr-xr-x. 1 root root  975 7月  22 17:40 install.sh
-rw-r--r--. 1 root root 1527 7月  26 09:13 nginx.conf
[root@localhost nginx]# ./install.sh
图片
[root@localhost nginx]# docker stop test-nginx
test-nginx
[root@localhost nginx]# docker  ps
CONTAINER ID   IMAGE                                   COMMAND               CREATED        STATUS        PORTS                                               NAMES
9451c839f840   10.249.0.137:80/base/jdk-1.8:20210202   "/usr/sbin/sshd -D"   16 hours ago   Up 16 hours                                                       tomcat
c761e01333ba   10.249.0.137:80/base/jdk-1.8:20210202   "/usr/sbin/sshd -D"   3 days ago     Up 16 hours   22/tcp, 0.0.0.0:8090->8090/tcp, :::8090->8090/tcp   test-jdk2
6add9e8b81d6   10.249.0.137:80/base/jdk-1.8:20210202   "/usr/sbin/sshd -D"   3 days ago     Up 16 hours   22/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   test-jdk
[root@localhost nginx]# docker rm  test-nginx

查看主机端口映射

netstat -a

# 服务器端口                           容器端口
iptables -t nat -D  DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8081
                -D 删除
    -A 覆盖
iptables -t nat -A  DOCKER -p tcp --dport 8082 -j DNAT --to-destination 172.17.0.4:8082

查看容器端口

[root@jdk1 conf]# ss -ntl

验证

访问nginx端口808080端口8090端口
图片图片图片
  1. 先访问:8080
  2. 再访问:8090
  3. 最后通过访问80,看看效果。

八股文相关:

1.负载均衡,先知道什么是正向代理和反向代理

  1. 正向代理,代理的是用户(翻墙)
  2. 反向代理,代理的是服务器

2.nginx实现负载均衡的几种方式

轮询默认方式
weight权重方式
ip_hash依据ip分配方式
least_conn最少连接方式
fair(第三方)响应时间方式
url_hash(第三方)依据URL分配方式
  1. 轮询(默认)
    1. 缺省配置就是轮询策略。
    2. 此策略适合服务器配置相当,无状态且短平快的服务使用。
    3. 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
    4. 场景:在轮询中,如果服务器down掉了,会自动剔除该服务器。
    5. upstream backserver {
      # ip_hash;
      server 10.8.46.197:8080;
      server 10.8.46.197:8090;
      }
  2. weight权重指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。upstream backserver {
    server 10.8.46.197:8080 weight=3;
    server 10.8.46.197:8090 weight=7;
    }
    权重越高,在被访问的概率越大,如上例,分别是30%,70%。
    1. 权重越高分配到需要处理的请求越多。
    2. weight权重可以与least_conn和ip_hash结合使用。
    3. 比较适合服务器的硬件配置差别比较大的情况。
    4. 场景:
  3. 负载均衡系统中,如果用户在某台服务器A登录了,用户第二次请求时会请求到服务器b,这样导致用户登录信息将会丢失,可以采用ip_hash指令解决这个问题,如果客户访问服务器A,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。场景:upstream backserver {
    ip_hash;
    server 10.8.46.197:8080 weight=3;
    server 10.8.46.197:8090 weight=7;
    }
    1. ip_hash不能与backup同时使用。
    2. 适合有状态服务,比如session。
    3. 当有服务器需要剔除,必须手动down掉。
  4. least_conn
    1. 把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。upstream backserver {
      least_conn; #把请求转发给连接数较少的后端服务器
      server localhost:8080 weight=2; #tomcat 7.0
      server localhost:8081; #tomcat 8.0
      server localhost:8082 backup; #tomcat 8.5
      server localhost:8083 max_fails=3 fail_timeout=20s; #tomcat 9.0
      }
      注意:此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
  5. fair(第三方) 按后端服务器的响应时间来分配请求,响应时间短的优先分配。upstream backserver {
    server 10.8.46.197:8080;
    server 10.8.46.197:80907;
    fair;
    }
  6. url_hash(第三方) 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。upstream backserver {
    server 10.8.46.197:8080;
    server 10.8.46.197:80907;
    hash $request_uri;
    hash_method crc32;
    }
    每个设备的状态设置为:
    1. down 表示单前的server暂时不参与负载
    2. weight 默认为1.weight越大,负载的权重就越大。
    3. max_fails:允许请求失败的次数默认为1.当超过最大次数时,返回 proxy_next_upstream模块定义的错误
    4. fail_timeout:max_fails次失败后,暂停的时间。
    5. backup:其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

3.nginx有哪些限流的方式

  1. Nginx的限流主要是两种方式:限制访问频率和限制并发连接数
#速率限流配置
limit_req_zone $binary_remote_addr zone=ipRateLimit:10m rate=2r/s;
#并发量限流-单个IP控制
limit_conn_zone $binary_remote_addr zone=perip:10m;
#并发量限流-整个服务控制
limit_conn_zone $server_name zone=perserver:10m;
server {
listen 80;
server_name localhost;
location ~ .*.(woff|ico|css|js|gif|jpg|jpeg|png)$ {
root /usr/local/openrestyDir/pages/;
}
location /msitems/ {
#限流配置
#limit_req zone=ipRateLimit burst=5 nodelay;
#并发量限流
limit_conn perip 20;
limit_conn perserver 100;
root /usr/local/openrestyDir/pages/;
}
}

参考文献:

  1. 实现负载均衡的几种方式:http://aijishu.com/a/1060000000008890
  2. Nginx服务器之6种负载均衡策略:https://blog.csdn.net/xiaren_1988/article/details/123007245

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/213291.html

联系我们
联系我们
分享本页
返回顶部