准备环境
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 f"Hello Container World! I have been seen {redis.get('hits').decode('utf-8')} times and my hostname is {socket.gethostname()}.\n"
Dockerfile
FROM python:3.9.5-slim
RUN pip install flask redis && \
groupadd -r flask && useradd -r -g flask flask && \
mkdir /src && \
chown -R flask:flask /src
USER flask
COPY app.py /src/app.py
WORKDIR /src
ENV FLASK=app.py REDIS_HOST=redis
EXPOSE 5000
CMD ["flask", "run", "-h", "0.0.0.0"]
docker-compose.yml
version: "3.8"
services:
flask:
build:
context: ./flask
dockerfile: Dockerfile
image: flask-demo:latest
environment:
- REDIS_HOST=redis-server
redis-server:
image: redis:latest
client:
image: xiaopeng163/net-box:latest
command: sh -c "while true; do sleep 3600; done;"
环境清理
删除所有容器和镜像(想好再执行)
$ docker container rm -f $(docker container ps -aq)
$ docker system prune -a -f
启动
$ docker-compose pull
$ docker-compose build
$ docker-compose up -d
Creating network "compose-scale-example_default" with the default driver
Creating compose-scale-example_flask_1 ... done
Creating compose-scale-example_client_1 ... done
Creating compose-scale-example_redis-server_1 ... done
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------
compose-scale-example_client_1 sh -c while true; do sleep ... Up
compose-scale-example_flask_1 flask run -h 0.0.0.0 Up 5000/tcp
compose-scale-example_redis-server_1 docker-entrypoint.sh redis ... Up 6379/tcp
水平扩展 scale
添加flask容器,flask容器要有3个
$ docker-compose up -d --scale flask=3
compose-scale-example_client_1 is up-to-date
compose-scale-example_redis-server_1 is up-to-date
Creating compose-scale-example_flask_2 ... done
Creating compose-scale-example_flask_3 ... done
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------
compose-scale-example_client_1 sh -c while true; do sleep ... Up
compose-scale-example_flask_1 flask run -h 0.0.0.0 Up 5000/tcp
compose-scale-example_flask_2 flask run -h 0.0.0.0 Up 5000/tcp
compose-scale-example_flask_3 flask run -h 0.0.0.0 Up 5000/tcp
compose-scale-example_redis-server_1 docker-entrypoint.sh redis ... Up 6379/tcp
不光可以扩展容器,也可以删除容器
PS C:\Users\柏杉\Downloads\compose-scale-example-1> docker-compose up -d --scale flask=1
Stopping and removing compose-scale-example-1_flask_2 ...
Stopping and removing compose-scale-example-1_flask_3 ...
Stopping and removing compose-scale-example-1_flask_2 ... done
Stopping and removing compose-scale-example-1_flask_3 ... done
PS C:\Users\柏杉\Downloads\compose-scale-example-1> docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------------------
compose-scale-example-1_client_1 sh -c while true; do sleep ... Up
compose-scale-example-1_flask_1 flask run -h 0.0.0.0 Up 5000/tcp
compose-scale-example-1_redis-server_1 docker-entrypoint.sh redis ... Up 6379/tcp
PS C:\Users\柏杉\Downloads\compose-scale-example-1>
负载均衡
进入客户端容器,ping
flask容器,你就会发现ip
不同
以下实验中说明了,docker-compose仅仅动态添加容器,还做了负载均衡!
PS C:\Users\柏杉\Downloads\compose-scale-example-1> docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d8e830642038 redis:latest "docker-entrypoint.s…" 42 seconds ago Up 41 seconds 6379/tcp compose-scale-example-1_redis-server_1
3b4ba08739d7 flask-demo:latest "flask run -h 0.0.0.0" 42 seconds ago Up 40 seconds 5000/tcp compose-scale-example-1_flask_1
a2014c0914d5 xiaopeng163/net-box:latest "sh -c 'while true; …" 42 seconds ago Up 41 seconds compose-scale-example-1_client_1
104959cfe5c3 flask-demo:latest "flask run -h 0.0.0.0" 42 seconds ago Up 40 seconds 5000/tcp compose-scale-example-1_flask_2
066f38dd0e28 flask-demo:latest "flask run -h 0.0.0.0" 42 seconds ago Up 41 seconds 5000/tcp compose-scale-example-1_flask_3
PS C:\Users\柏杉\Downloads\compose-scale-example-1> docker container exec -it a2014c0914d5 sh
/omd # ping flask
PING flask (172.18.0.5): 56 data bytes
64 bytes from 172.18.0.5: seq=0 ttl=64 time=0.307 ms
64 bytes from 172.18.0.5: seq=1 ttl=64 time=0.079 ms
^C
--- flask ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.079/0.193/0.307 ms
/omd # ping flask
PING flask (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.227 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.079 ms
^C
--- flask ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.079/0.153/0.227 ms
/omd # ping flask
PING flask (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.119 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.072 ms
^C
--- flask ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.072/0.095/0.119 ms
/omd # ping flask
PING flask (172.18.0.6): 56 data bytes
64 bytes from 172.18.0.6: seq=0 ttl=64 time=0.287 ms
64 bytes from 172.18.0.6: seq=1 ttl=64 time=0.071 ms
^C
--- flask ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.071/0.179/0.287 ms
/omd #
curl
请求后,发现容器的ID都不同
/omd # curl flask:5000
Hello Container World! I have been seen 1 times and my hostname is 066f38dd0e28.
/omd # curl flask:5000
Hello Container World! I have been seen 2 times and my hostname is 3b4ba08739d7.
/omd # curl flask:5000
Hello Container World! I have been seen 3 times and my hostname is 104959cfe5c3.
/omd # curl flask:5000
Hello Container World! I have been seen 4 times and my hostname is 3b4ba08739d7.
/omd #
添加 nginx
nginx.conf
server {
listen 80 default_server;
location / {
proxy_pass http://flask:5000;
}
}
Dockerfile
修改成:
depends_on 驱动顺序,要等flask启动完成后,再启动Nginx
version: "3.8"
services:
flask:
build:
context: ./flask
dockerfile: Dockerfile
image: flask-demo:latest
environment:
- REDIS_HOST=redis-server
networks:
- backend
- frontend
redis-server:
image: redis:latest
networks:
- backend
nginx:
image: nginx:stable-alpine
ports:
- 8000:80
depends_on:
- flask
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./var/log/nginx:/var/log/nginx
networks:
- frontend
networks:
backend:
frontend:
PS C:\Users\柏杉\Downloads\compose-scale-example-2> docker-compose up -d
Creating network "compose-scale-example-2_backend" with the default driver
Creating network "compose-scale-example-2_frontend" with the default driver
Pulling nginx (nginx:stable-alpine)...
stable-alpine: Pulling from library/nginx
97518928ae5f: Pull complete
a15dfa83ed30: Pull complete
acae0b19bbc1: Pull complete
fd4282442678: Pull complete
b521ea0d9e3f: Pull complete
b3282d03aa58: Pull complete
Digest: sha256:74694f2de64c44787a81f0554aa45b281e468c0c58b8665fafceda624d31e556
Status: Downloaded newer image for nginx:stable-alpine
Creating compose-scale-example-2_flask_1 ... done
Creating compose-scale-example-2_redis-server_1 ... done
Creating compose-scale-example-2_nginx_1 ... done
PS C:\Users\柏杉\Downloads\compose-scale-example-2> docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------------------------------
compose-scale-example-2_flask_1 flask run -h 0.0.0.0 Up 5000/tcp
compose-scale-example-2_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8000->80/tcp
compose-scale-example-2_redis-server_1 docker-entrypoint.sh redis ... Up 6379/tcp
PS C:\Users\柏杉\Downloads\compose-scale-example-2>
浏览器访问:http://127.0.0.1:8000/
查看启动成功!
扩展3个flask,并且重启Nginx
PS C:\Users\柏杉\Downloads\compose-scale-example-2> docker-compose up -d --scale flask=3
compose-scale-example-2_redis-server_1 is up-to-date
Creating compose-scale-example-2_flask_2 ... done
Creating compose-scale-example-2_flask_3 ... done
compose-scale-example-2_nginx_1 is up-to-date
PS C:\Users\柏杉\Downloads\compose-scale-example-2> docker-compose restart nginx
Restarting compose-scale-example-2_nginx_1 ... done
PS C:\Users\柏杉\Downloads\compose-scale-example-2>
反向代理成功!
还可以在var\log\nginx
查看log