环境准备,上一节中的flask-redis项目,将项目启动:
docker-compose up -d
Starting flask-redis_web_1 ... done
Starting flask-redis_redis_1 ... done
查看状态:
docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------
flask-redis_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
flask-redis_web_1 python app.py Up 0.0.0.0:8080->5000/tcp
docker-compose scale
我们目前的docker-compose 中的service容器中各自只有一个,通过scale可以去扩展service。
docker-compose up --help
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.
例如将web服务的数量变为三个:
docker-compose up --scale web=3 -d
WARNING: The "web" service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash.
Starting flask-redis_web_1 ...
Starting flask-redis_web_1 ... done
Creating flask-redis_web_2 ... error
Creating flask-redis_web_3 ... error
ERROR: for flask-redis_web_2 Cannot start service web: driver failed programming external connectivity on endpoint flask-redis_web_2 (952f3eea8bdf14f0a94845fb6ef5039285f7ffe40620faca32f40643b802fa97): Bind for 0.0.0.0:8080 failed: port is already allocated
ERROR: for flask-redis_web_3 Cannot start service web: driver failed programming external connectivity on endpoint flask-redis_web_3 (50c776deb73b272d04181a8ab385f27cc31689aeeed804436fd2b92836cf25b9): Bind for 0.0.0.0:8080 failed: port is already allocated
ERROR: for web Cannot start service web: driver failed programming external connectivity on endpoint flask-redis_web_2 (952f3eea8bdf14f0a94845fb6ef5039285f7ffe40620faca32f40643b802fa97): Bind for 0.0.0.0:8080 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.
发现报错了,原因是接口已经被分配了。每个容器的端口都想绑定到8080上面,显然是不可能的。
将容器删除:
docker-compose down
Stopping flask-redis_web_1 ... done
Stopping flask-redis_redis_1 ... done
Removing flask-redis_web_3 ... done
Removing flask-redis_web_2 ... done
Removing flask-redis_web_1 ... done
Removing flask-redis_redis_1 ... done
Removing network flask-redis_default
将docker-compose.yml中端口绑定删除:
version: "3"
services:
redis:
image: redis
web:
build:
context: .
dockerfile: Dockerfile
environment:
REDIS_HOST: redis
执行命令docker-compose up --scale web=3 -d
docker-compose up --scale web=3 -d
Creating network "flask-redis_default" with the default driver
Creating flask-redis_web_1 ... done
Creating flask-redis_web_2 ... done
Creating flask-redis_web_3 ... done
Creating flask-redis_redis_1 ... done
可以成功执行。
docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
flask-redis_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
flask-redis_web_1 python app.py Up 5000/tcp
flask-redis_web_2 python app.py Up 5000/tcp
flask-redis_web_3 python app.py Up 5000/tcp
发现web端口并没有映射到主机的端口,全部是5000container端口。
想象一下假如有多个web服务,都会监听本地的5000端口,都会访问redis,那么我们就可以有一个负载均衡器,可以把访问量平均的分配到web服务,可以减轻单个服务的压力。如下图所示:
如果我们用这种方式来部署web服务的话,以后的扩展性是非常强的。例如我们开启10个web服务:
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis$ docker-compose up --scale web=10 -d
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Creating network "docker-compose-flask-redis_default" with the default driver
Creating docker-compose-flask-redis_redis_1 ... done
Creating docker-compose-flask-redis_web_1 ... done
Creating docker-compose-flask-redis_web_2 ... done
Creating docker-compose-flask-redis_web_3 ... done
Creating docker-compose-flask-redis_web_4 ... done
Creating docker-compose-flask-redis_web_5 ... done
Creating docker-compose-flask-redis_web_6 ... done
Creating docker-compose-flask-redis_web_7 ... done
Creating docker-compose-flask-redis_web_8 ... done
Creating docker-compose-flask-redis_web_9 ... done
Creating docker-compose-flask-redis_web_10 ... done
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------
docker-compose-flask-redis_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
docker-compose-flask-redis_web_1 python app.py Up 5000/tcp
docker-compose-flask-redis_web_10 python app.py Up 5000/tcp
docker-compose-flask-redis_web_2 python app.py Up 5000/tcp
docker-compose-flask-redis_web_3 python app.py Up 5000/tcp
docker-compose-flask-redis_web_4 python app.py Up 5000/tcp
docker-compose-flask-redis_web_5 python app.py Up 5000/tcp
docker-compose-flask-redis_web_6 python app.py Up 5000/tcp
docker-compose-flask-redis_web_7 python app.py Up 5000/tcp
docker-compose-flask-redis_web_8 python app.py Up 5000/tcp
docker-compose-flask-redis_web_9 python app.py Up 5000/tcp
我们为了演示真实的架构,使用HAproxy做负载均衡
将app.py的端口由5000改为80,app.py如下:
from flask import Flask
from redis import Redis
import os
import socket
app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
@app.route('/')
def hello():
redis.incr('hits')
return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'),socket.gethostname())
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80, debug=True)
Dockerfile的expose也改成80,内容如下:
FROM python:3.5
LABEL maintaner="vincent"
COPY . /app
WORKDIR /app
RUN pip install flask redis
EXPOSE 80
CMD [ "python", "app.py" ]
docker-compose.yml中添加haproxy,内容如下:
version: "3"
services:
redis:
image: redis
web:
build:
context: .
dockerfile: Dockerfile
environment:
REDIS_HOST: redis
lb:
image: dockercloud/haproxy
links:
- web
ports:
- 8082:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
将上面的容器先docker-compose down,将容器删掉。
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ docker-compose up -d
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Removing docker-compose-flask-redis-haproxy_lb_1
docker-compose-flask-redis-haproxy_redis_1 is up-to-date
docker-compose-flask-redis-haproxy_web_1 is up-to-date
Recreating d2b87be02ede_docker-compose-flask-redis-haproxy_lb_1 ... done
查看状态:
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------------------------------------
docker-compose-flask-redis-haproxy_lb_1 /sbin/tini -- dockercloud- ... Up 1936/tcp, 443/tcp, 0.0.0.0:8082->80/tcp
docker-compose-flask-redis-haproxy_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
docker-compose-flask-redis-haproxy_web_1 python app.py Up 80/tcp
测试访问:
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'1' times and my hostname is 9603ec0f2527.
测试通过。
接下来测试使用多个web服务:
先将之前的docker-compose down。
启动三个web服务:
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ docker-compose up --scale web=3 -d
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Creating network "docker-compose-flask-redis-haproxy_default" with the default driver
Creating docker-compose-flask-redis-haproxy_web_1 ... done
Creating docker-compose-flask-redis-haproxy_web_2 ... done
Creating docker-compose-flask-redis-haproxy_web_3 ... done
Creating docker-compose-flask-redis-haproxy_redis_1 ... done
Creating docker-compose-flask-redis-haproxy_lb_1 ... done
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------------------------------------
docker-compose-flask-redis-haproxy_lb_1 /sbin/tini -- dockercloud- ... Up 1936/tcp, 443/tcp, 0.0.0.0:8082->80/tcp
docker-compose-flask-redis-haproxy_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
docker-compose-flask-redis-haproxy_web_1 python app.py Up 80/tcp
docker-compose-flask-redis-haproxy_web_2 python app.py Up 80/tcp
docker-compose-flask-redis-haproxy_web_3 python app.py Up 80/tcp
依次访问我们的HAproxy:
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'1' times and my hostname is 9a2d714aadad.
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'2' times and my hostname is eda311882f3f.
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'3' times and my hostname is 43f69f733c5e.
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'4' times and my hostname is 9a2d714aadad.
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'5' times and my hostname is eda311882f3f.
iie4bu@hostdocker:~/ddy/docker-compose-flask-redis-haproxy$ curl 127.0.0.1:8082
Hello Container World! I have been seen b'6' times and my hostname is 43f69f733c5e.
发现是轮询我们的web服务,haproxy会转发请求到三个web服务上。
我们目前的扩展是单机环境下的scale,无论将service扩展到多少,只能限制在单机环境下。但是一台服务器的资源是有限的,那么如何扩展多台服务器?那么就是需要使用swarm技术了。