docker下nginx反向代理和负载均衡配置

本文已迁移至segmentfault

1. 镜像安装

可以通过以下命令拉取nginx和tomcat镜像作为测试

[root@docker /]# docker pull nginx
[root@docker /]# docker pull tomcat

2. nginx启动

  1. 镜像下载完后,执行以下命令启动nginx
[root@docker /]# docker run --name=my_nginx -p 8000:80 -d nginx

--name: 为nginx容器指定一个名称方便管理
-p: 将nginx内部80端口代理到宿主机8000端口,可以通过宿主机:8000访问nginx 80端口
-d: 后台运行

  1. 可以通过docker ps 命令查看容器运行情况
[root@docker /]# docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                            NAMES
1833fcff605b        nginx                 "nginx -g 'daemon off"   2 minutes ago       Up 2 minutes        0.0.0.0:8000->80/tcp             my_nginx
  1. 浏览器访问http://192.168.43.32:8000/查看是否能够访问,或者使用curl命令(推荐)
[root@docker /]# curl http://192.168.43.32:8000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
....

nginx配置文件

进入nginx容器后台

[root@docker /]# docker exec -it my_nginx bash
root@1833fcff605b:/# cd /etc/nginx/
root@1833fcff605b:/etc/nginx# ls -l
total 36
drwxr-xr-x. 2 root root   26 Dec 26 18:16 conf.d
-rw-r--r--. 1 root root 1007 Dec 26 11:11 fastcgi_params
-rw-r--r--. 1 root root 2837 Dec 26 11:11 koi-utf
-rw-r--r--. 1 root root 2223 Dec 26 11:11 koi-win
-rw-r--r--. 1 root root 5170 Dec 26 11:11 mime.types
lrwxrwxrwx. 1 root root   22 Dec 26 11:11 modules -> /usr/lib/nginx/modules
-rw-r--r--. 1 root root  643 Dec 26 11:11 nginx.conf
-rw-r--r--. 1 root root  636 Dec 26 11:11 scgi_params
-rw-r--r--. 1 root root  664 Dec 26 11:11 uwsgi_params
-rw-r--r--. 1 root root 3610 Dec 26 11:11 win-utf

nginx.conf是nginx主要配置文件,可以通过more命令查看nginx.conf(容器默认不安装vi工具)

root@1833fcff605b:/etc/nginx# more 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;
}

注意到最后一行配置
include /etc/nginx/conf.d/*.conf;
include可以将其他配置文件导入,进入/etc/nginx/conf.d/目录下查看

root@1833fcff605b:/etc/nginx# cd /etc/nginx/conf.d/
root@1833fcff605b:/etc/nginx/conf.d# ls
default.conf

default.conf

root@1833fcff605b:/etc/nginx/conf.d# more default.conf
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

#表示注释可以忽略
server:代表虚拟服务器,下面会解释什么是虚拟服务器
server_name:服务器名称
location:访问路径匹配规则,这也是nginx最灵活的地方,可以使用正则表达式
解释下什么是虚拟服务器
如果给nginx服务器在dns上配置两个域名
domain1.nginx.com
domain2.nginx.com
用户访问这两个域名,你可能希望他们访问同一个后台服务,也可能希望访问不同的后台服务
那么在nginx里就可以配置两个虚拟服务器也就是两个server节点

server {
    listen       80;
    server_name  domain1.nginx.com;
    ...
}
server {
    listen       80;
    server_name  domain2.nginx.com;
    ...
}

两个虚拟服务器监听同一个端口80.nginx可以根据用户访问的host(http头部host)字段代理到不同服务器上

location->root:静态资源目录,web静态资源如图片,js,html可通过该方式存放
location->index:如用户未指定请求资源名称,默认访问index指定的文件,如访问http://host:port/html/则默认访问http://host:port/html/index.html

3. 测试场景

我们假设有以下三个场景

  1. 场景1
    宿主机有个目录存储静态资源,需要通过nginx代理出去,用户访问http://host:port/resource/xxxx访问
  2. 场景2
    tomcat服务器(docker容器)上运行一个web程序,需要通过nginx代理出去,web程序context root为WebTestApp
  3. 场景3
    该web程序运行在两个tomcat容器中,需要通过nginx做负载均衡

4. nginx配置文件挂载

docker容器每次重启都是一个新的环境,也就是说在docker容器内做的任何修改都将被还原,但nginx的配置文件是在docker容器内,我们如果直接进行修改每次重启后都会被还原,这并不是我们所希望的,所以首先需要将配置文件从docker容器中"搬到"宿主机上,这里会通过docker的卷(volume)实现。
volume可以将本地文件挂载到docker容器内,这样容器重启后信息不会丢失
对于nginx,可以将nginx.conf文件和conf.d目录从容器内部"搬"出来
在本地创建nginx.conf文件和conf.d目录

[root@docker /]# mkdir -p /u01/nginx
[root@docker /]# mkdir -p /u01/nginx/conf.d
[root@docker /]# touch /u01/nginx/nginx.conf
[root@docker /]# touch /u01/nginx/conf.d/default.conf

nginx.conf文件和default.conf内容可以直接从容器内部复制

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;
}

default.conf

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

重新启动nginx

[root@docker /]# docker stop my_nginx
my_nginx
[root@docker /]# docker rm my_nginx
my_nginx
[root@docker nginx]# docker run --name=my_nginx -v /u01/nginx/nginx.conf:/etc/nginx/nginx.conf -v /u01/nginx/conf.d:/etc/nginx/conf.d -p 8000:80 -d nginx
6efe91858f071a50197da104cdccf8500234f1bf6d0f4f56d3dc5de02261272c
[root@docker /]# curl http://192.168.43.32:8000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
....

注意到执行了一个 docker rm my_nginx 命令,这是因为容器每次启动需要指定不同的名字,一个名字不能使用多次,可以通过 docker ps -a查看所有容器,包括未运行的容器。rm命令可以删除指定容器
下面正式配置上面三个场景

5. 场景1-静态资源代理

在u01目录下创建目录resource,并上传静态资源

[root@docker resource]# pwd
/u01/resource
[root@docker resource]# ll
total 164
-rw-r--r--. 1 root root 147291 Oct  8  2015 angular.min.js
-rw-r--r--. 1 root root  17189 Nov  3 10:32 docker.jpg
[root@docker resource]#

修改/u01/nginx/conf.d/default.conf文件

default.conf

server {
    listen       80;
    server_name localhost;
    location /resource {
        root   /u01;
        index  index.html index.htm;
    }
}

ps:root是/u01不是/u01/resource。如果root配置成/u01/resource/则nginx会去/u01/resource/resource目录下寻找文件
重新启动nginx容器,将resource目录挂载到容器内部

[root@docker u01]# docker stop my_nginx
my_nginx
[root@docker u01]# docker rm my_nginx
my_nginx
[root@docker u01]# docker run --name=my_nginx -v /u01/nginx/nginx.conf:/etc/nginx/nginx.conf -v /u01/nginx/conf.d:/etc/nginx/conf.d -v /u01/resource:/u01/resource -p 8000:80 -d nginx

访问
http://192.168.43.32:8000/resource/docker.jpg
http://192.168.43.32:8000/resource/angular.min.js
测试配置是否成功(将上面ip替换成宿主机ip)

6. 场景2-tomcat代理

准备一个servet作为测试

package com.df.demo;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.*;
import javax.servlet.http.*;

public class WebTestService extends HttpServlet {
    private static final String CONTENT_TYPE = "text/html; charset=UTF-8";

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                                                           IOException {
        response.setContentType(CONTENT_TYPE);
        PrintWriter out = response.getWriter();
        out.print("hello docker tomcat");
        out.close();
    }
}

打成war包,包名为WebTestApp.war,在u01上创建webapps目录并上传war包

[root@docker webapps]# pwd
/u01/webapps
[root@docker webapps]# ls
WebTestApp.war

启动tomcat容器,并将/u01/webapps目录挂载到tomcat的/usr/local/tomcat/webapps目录下

[root@docker ~]# docker run --name=my_tomcat1 -v /u01/webapps:/usr/local/tomcat/webapps -p 8001:8080 -d tomcat
[root@docker ~]# curl http://localhost:8001/WebTestApp
hello docker tomcat

程序已经成功部署到tomcat上
修改/u01/nginx/conf.d/default.conf文件

default.conf

server {
    listen       80;
    server_name localhost;
    location / {
        proxy_pass   http://tomcat_server;
    }
}

修改/u01/nginx/nginx.conf在http配置节点中增加以下配置

upstream tomcat_server {
      server t1:8080;
    }

upstream 可以定义一组服务器
proxy_pass 设置代理的服务器,格式为http://upstream_name

重启nginx容器,这里我们需要使用一个新的docker参数--link

[root@docker u01]# docker run --name=my_nginx1 --link=my_tomcat1:t1 -v /u01/nginx/nginx.conf:/etc/nginx/nginx.conf -v /u01/nginx/conf.d:/etc/nginx/conf.d -p 8000:80 -d nginx
[root@docker ~]# curl http://192.168.43.32:8000/WebTestApp
hello docker tomcat

ps:这里换了一个名字my_nginx1,用原来的名字my_nginx无法启动容器,会报以下错误

2018/01/27 08:40:44 [emerg] 1#1: host not found in upstream "t1:8080" in /etc/nginx/nginx.conf:30
nginx: [emerg] host not found in upstream "t1:8080" in /etc/nginx/nginx.conf:30

t1无法找到,但如果不使用--name指定名称可正常启动,原因未知。
link参数可以在两个容器之间建立网络连接,格式为--link=my_tomcat1:t1 my_tomcat1为容器名称,t1为取的别名
可登录nginx容器查看/etc/hosts文件,docker会将t1加入到hosts文件中

[root@docker ~]# docker exec -it my_nginx1 bash
root@fa5f782b9448:/# more /etc/hosts
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.5  t1 1f9b1d432ab0 my_tomcat1
172.17.0.6  fa5f782b9448

7. 场景3-tomcat负载均衡

  1. 修改/u01/nginx/nginx.conf在场景2的基础上增加新的服务器
upstream tomcat_server {
      server t1:8080;
      server t2:8080;
    }
  1. 在启动一个tomcat容器my_tomcat2
[root@docker ~]# docker run --name=my_tomcat2 -v /u01/webapps:/usr/local/tomcat/webapps -d tomcat
  1. 重启nginx
[root@docker /]# docker stop my_nginx1
[root@docker /]# dcoker rm my_nginx1
[root@docker /]# docker run --name=my_nginx1 --link=my_tomcat1:t1 --link=my_tomcat2:t2 -v /u01/nginx/nginx.conf:/etc/nginx/nginx.conf -v /u01/nginx/conf.d:/etc/nginx/conf.d -p 8000:80 -d nginx
[root@docker ~]# curl http://192.168.43.32:8000/WebTestApp
hello docker tomcat
  1. 可以分别登录两个tomcat容器查看access.log可以查看结果,nginx在两台服务器之间做轮询.轮询是nginx默认的负载均衡方式。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 本文介绍在Docker上配置简单的负载均衡,宿主机为CentOS和两个CentOS容器,宿主机安装Nginx,两台...
    GoGooGooo阅读 1,146评论 0 2
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 《像我这样的人》,第一次听到毛不易唱这首歌时,莫名的被触动了。 我们都是普通的人,所以不甘于平凡。 像我这...
    一只爱吃猫的鱼阅读 405评论 0 1
  • 想想一趟旅行给我留下的痕迹,不过说一座青山蓬勃的绿意,还有青青的草散发着香气,几朵野花和路人共呼吸,两只鸟林间飞来...
    李一十八阅读 235评论 1 4
  • 美好的一天又开始了,集体打卡第四天。 今天的时间管理课:清空大脑与应用4D原则摆脱紧急事务。清空大脑就是指给自己的...
    幸福就是刚刚好阅读 220评论 0 0