1 启动

承接上文最后的 python 服务配置。

[root@icv-monitor-platform-dev flask-redis]# docker-compose up -d
 Creating network "flaskredis_default" with the default driver
 Creating flaskredis_redis_1 ... done
 Creating flaskredis_web_1   ... done
 [root@icv-monitor-platform-dev flask-redis]# docker-compose ps
        Name                     Command               State                    Ports                  
 ------------------------------------------------------------------------------------------------------
 flaskredis_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp                                
 flaskredis_web_1     python app.py                    Up      0.0.0.0:8084->5000/tcp,:::8084->5000/tcp
 [root@icv-monitor-platform-dev flask-redis]#

2 水平扩展

[root@icv-monitor-platform-dev flask-redis]# 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 flaskredis_web_1 ... 
 Starting flaskredis_web_1 ... done
 Creating flaskredis_web_2 ... error
 Creating flaskredis_web_3 ... error
 
 ERROR: for flaskredis_web_2  Cannot start service web: driver failed programming external connectivity on endpoint flaskredis_web_2 (b10d07ee0f306e673d569063bfa04194b8bc0d83c91d4822ebd6d9ce1554a73c): Bind for 0.0.0.0:8084 failed: port is already allocated
 
 ERROR: for flaskredis_web_3  Cannot start service web: driver failed programming external connectivity on endpoint flaskredis_web_3 (655d397521c6cfd1f89faeb34de7b01eccc70db76dc126841126a15bbd9013b2): Bind for 0.0.0.0:8084 failed: port is already allocated
 
 ERROR: for web  Cannot start service web: driver failed programming external connectivity on endpoint flaskredis_web_2 (b10d07ee0f306e673d569063bfa04194b8bc0d83c91d4822ebd6d9ce1554a73c): Bind for 0.0.0.0:8084 failed: port is already allocated
 ERROR: Encountered errors while bringing up the project.
 [root@icv-monitor-platform-dev flask-redis]#

显然是 docker-compose.yml中的如下语句导致的失败:

ports:
      - 8084:5000

将该段删除再重启。

[root@icv-monitor-platform-dev flask-redis]# vim docker-compose.yml
[root@icv-monitor-platform-dev flask-redis]# docker-compose up -d
Stopping and removing flaskredis_web_2 ... 
Stopping and removing flaskredis_web_2 ... done
Stopping and removing flaskredis_web_3 ... done
Recreating flaskredis_web_1 ... done
[root@icv-monitor-platform-dev flask-redis]# docker-compose up --scale web=3 -d
flaskredis_redis_1 is up-to-date
Starting flaskredis_web_1 ... done
Creating flaskredis_web_2 ... done
Creating flaskredis_web_3 ... done
[root@icv-monitor-platform-dev flask-redis]# docker-compose ps
       Name                     Command               State    Ports  
----------------------------------------------------------------------
flaskredis_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
flaskredis_web_1     python app.py                    Up      5000/tcp
flaskredis_web_2     python app.py                    Up      5000/tcp
flaskredis_web_3     python app.py                    Up      5000/tcp
[root@icv-monitor-platform-dev flask-redis]#

注意,这个 5000 端口是容器 namespace 的 5000 端口,而不是主机的 5000 端口。

所以,现在有 3 个 web 服务了,都在访问同一台 redis。假设现有 n 个 web 服务,同时访问一个 Redis

某次大促,访问量需求很大,如何快速操作呢?传统是需要加机器,而通过 docker-compose 就能快速水平扩展。

现在就能迅速扩展到 5 个:

[root@icv-monitor-platform-dev flask-redis]# docker-compose up --scale web=5 -d
flaskredis_redis_1 is up-to-date
Starting flaskredis_web_1 ... done
Starting flaskredis_web_2 ... done
Starting flaskredis_web_3 ... done
Creating flaskredis_web_4 ... done
Creating flaskredis_web_5 ... done
[root@icv-monitor-platform-dev flask-redis]# docker-compose ps
       Name                     Command               State    Ports  
----------------------------------------------------------------------
flaskredis_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
flaskredis_web_1     python app.py                    Up      5000/tcp
flaskredis_web_2     python app.py                    Up      5000/tcp
flaskredis_web_3     python app.py                    Up      5000/tcp
flaskredis_web_4     python app.py                    Up      5000/tcp
flaskredis_web_5     python app.py                    Up      5000/tcp
[root@icv-monitor-platform-dev flask-redis]#

为真实演绎该架构,现加上 LB。

现删除所有服务:

[root@icv-monitor-platform-dev flask-redis]# docker-compose down
Stopping flaskredis_web_4   ... done
Stopping flaskredis_web_5   ... done
Stopping flaskredis_web_2   ... done
Stopping flaskredis_web_3   ... done
Stopping flaskredis_web_1   ... done
Stopping flaskredis_redis_1 ... done
Removing flaskredis_web_4   ... done
Removing flaskredis_web_5   ... done
Removing flaskredis_web_2   ... done
Removing flaskredis_web_3   ... done
Removing flaskredis_web_1   ... done
Removing flaskredis_redis_1 ... done
Removing network flaskredis_default
[root@icv-monitor-platform-dev flask-redis]#

2.1 前置文件

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)
 

docker-compose.yml

version: "3"

services:

  redis:
    image: redis

  web:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      REDIS_HOST: redis

  lb:
    image: dockercloud/haproxy
    links:
      - web
    ports:
      - 8084:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Dockerfile

FROM python:2.7
LABEL maintaner="JavaEdge@"
COPY . /app
WORKDIR /app
RUN pip install flask redis
EXPOSE 80
CMD [ "python", "app.py" ]

2.2 操作

2.2.1 扩容

[root@icv-monitor-platform-dev flask-redis]# docker-compose up -d
 Creating network "flaskredis_default" with the default driver
 Pulling lb (dockercloud/haproxy:latest)...
 latest: Pulling from dockercloud/haproxy
 1160f4abea84: Pull complete
 b0df9c632afc: Pull complete
 a49b18c7cd3a: Pull complete
 Digest: sha256:040d1b321437afd9f8c9ba40e8340200d2b0ae6cf280a929a1e8549698c87d30
 Creating flaskredis_redis_1 ... done
 Creating flaskredis_web_1   ... done
 Creating flaskredis_redis_1 ... 
 Creating flaskredis_lb_1    ... done
 [root@icv-monitor-platform-dev flask-redis]# docker-compose ps
        Name                     Command               State                            Ports                         
 ---------------------------------------------------------------------------------------------------------------------
 flaskredis_lb_1      /sbin/tini -- dockercloud- ...   Up      1936/tcp, 443/tcp, 0.0.0.0:8084->80/tcp,:::8084->80/tcp
 flaskredis_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp                                               
 flaskredis_web_1     python app.py                    Up      5000/tcp                                               
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 1 times and my hostname is 8f3e8e1cb9a7.
 [root@icv-monitor-platform-dev flask-redis]#

hostname输出即是_web_1的 host name。

扩展到 3 个,再访问 8084 端口:

[root@icv-monitor-platform-dev flask-redis]# docker-compose up --scale web=3 -d
 flaskredis_redis_1 is up-to-date
 Starting flaskredis_web_1 ... done
 Creating flaskredis_web_2 ... done
 Creating flaskredis_web_3 ... done
 flaskredis_lb_1 is up-to-date
 [root@icv-monitor-platform-dev flask-redis]# docker-compose ps
        Name                     Command               State                            Ports                         
 ---------------------------------------------------------------------------------------------------------------------
 flaskredis_lb_1      /sbin/tini -- dockercloud- ...   Up      1936/tcp, 443/tcp, 0.0.0.0:8084->80/tcp,:::8084->80/tcp
 flaskredis_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp                                               
 flaskredis_web_1     python app.py                    Up      5000/tcp                                               
 flaskredis_web_2     python app.py                    Up      5000/tcp                                               
 flaskredis_web_3     python app.py                    Up      5000/tcp                                               
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 2 times and my hostname is 8f3e8e1cb9a7.
 [root@icv-monitor-platform-dev flask-redis]#

注意每次请求对应的 host name:

[root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 2 times and my hostname is 8f3e8e1cb9a7.
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 3 times and my hostname is 22b1d642d8a6.
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 4 times and my hostname is 57169f8a658f.
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 5 times and my hostname is 8f3e8e1cb9a7.
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 6 times and my hostname is 22b1d642d8a6.
 [root@icv-monitor-platform-dev flask-redis]# curl 127.0.0.1:8084
 Hello Container World! I have been seen 7 times and my hostname is 57169f8a658f.
 [root@icv-monitor-platform-dev flask-redis]#

显然触发了默认的轮询LB!

2.2.2 缩容

大促过了,我们又要缩容了:

[root@icv-monitor-platform-dev flask-redis]# docker-compose up --scale web=1 -dStopping and removing flaskredis_web_2 ... 
 Stopping and removing flaskredis_web_2 ... done
 Stopping and removing flaskredis_web_3 ... done
 Starting flaskredis_web_1 ... done
 flaskredis_lb_1 is up-to-date
 [root@icv-monitor-platform-dev flask-redis]#