项目中使用SpringBoot开发web应用,打包部署采用docker;之前看到通过docker-compose 来扩展容器,通过scale命令来扩展容器:

docker-compose scale test-app=4

但是试了下发现直接报错了,端口冲突,因为每个docker容器都映射宿主机的8080端口,所以端口冲突了;于是通过这篇文章找到了解决办法,https://deployeveryday.com/2016/09/28/composing-docker-environments-scale.html

基本的思路是:web容器不再映射宿主机的8080端口,而是通过nginx来进行负载均衡;需要启动一个nginx容器,所有的请求都先发送到nginx,然后再进行请求的转发,比如宿主机的ip对外ip是192.168.140.5,那么请求请求192.168.140.5,nginx把请求再进行转发,根据启动了的web容器地址,比如我们扩展了3个web容器,那么nginx把请求转发到对应的一台上面去;但是这样nginx需要记录扩展了几个容器,以及对应的容器的ip,还是很麻烦的,于是文章引入了一个 nginx-proxy 镜像,它承担了nginx的功能,同时它会调用docker的api来发现现有的容器和对应的ip地址,当容器启动和停止的时候,会reload生成的nginx配置文件;

下面是完整的docker-compose.yml 文件

version: '2'
services:
    my-app:
        image: app-image
        environment:
            - VIRTUAL_HOST= 172.16.140.5
            - SPRING_PROFILES_ACTIVE=prod,swagger
            - SPRING_DATASOURCE_URL=jdbc:mysql://172.16.140.5:3306/app_test?useUnicode=true&characterEncoding=utf8&useSSL=false
            - SPRING_DATASOURCE_USERNAME=app
            - SPRING_DATASOURCE_PASSWORD=123
            - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application
        expose:
            - 8080
        depends_on:
            - nginx
    nginx:
        image: jwilder/nginx-proxy
        volumes:
            - /var/run/docker.sock:/tmp/docker.sock:ro
            - /mnt/aaa/nginx:/etc/nginx/conf.d/
        ports:
            - 80:80


这里的VIRTUAL_HOST指的是容器的外网访问地址,也可以是域名,比如你的web的域名是www.aaaa.com,也是可以的;docker-compose 启动之后,它会根据这个配置生成一个nginx的配置文件;下面            - /mnt/aaa/nginx:/etc/nginx/conf.d/,是将生成的nginx配置文件给挂载出来了,目的是方便我们观察调试问题,当时可以去掉,是不需要也可以工作的;之后通过下面的命令扩展出3个web容器

docker-compose -f app.yml scale my-app=3 

下面是生成的nginx的配置文件

proxy_set_header Proxy "";
server {
	server_name _; # This is just an invalid value which will never trigger on a real hostname.
	listen 80;
	access_log /var/log/nginx/access.log vhost;
	return 503;
}
# 172.16.140.5
upstream 172.16.140.5 {
				## Can be connected with "default" network
			# my-app_3
			server 172.19.0.5:8080;
				## Can be connected with "default" network
			# my-app_2
			server 172.19.0.4:8080;
				## Can be connected with "default" network
			# my-app_1
			server 172.19.0.3:8080;
}
server {
	server_name 172.16.140.5;
	listen 80 ;
	access_log /var/log/nginx/access.log vhost;
	location / {
		proxy_pass http://172.16.140.5;
	}
}

解释下上面的配置:server_name表示Http请求的host中有172.16.140.5这个信息的都会被proxy_pass 的upstream处理,再upstream制定了三个容器的地址去处理请求,根据负载均衡,会路由到其中的一个上面去;这个server_name是根据docker-compose 中的

- VIRTUAL_HOST= 172.16.140.5

指定的;server_name就是对应请求中如下所示的地方

在根据https://deployeveryday.com/2016/09/28/composing-docker-environments-scale.html文章配置成localhost的测试的时候,发现只能在172.16.140.5这个服务器上,通过“localhost”才可以访问,外网通过地址一直“503”错误;就是因为外网访问的时候地址中带的是172.16.140.5,然而nginx只接受localhost的访问,这个地方困惑了我好久;其实VIRTUAL_HOST参数可以任意配置,只需要你的请求host中包含这个就好了;比如

- VIRTUAL_HOST= tomcat-service

然后,使用curl -H "host:tomcat-service" 172.16.140.5也是可以访问的;curl -H 是添加请求的host信息;这样就可以了,之后先启动docker-compose -f app.yml up -d ,然后docker-compose -f app.yml scale 服务名=3 就是扩展出3个容器来;其他的不用管了,很方便有木有;需要注意的是,如果采用的是session的方式,会存在session丢失的情况,需要进行其他的配置的;推荐使用jwt的登录方式;

 

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐