如何解决Docker-Compose内置DNS负载均衡失效问题
作者:morris131
这篇文章主要介绍了如何解决Docker-Compose内置DNS负载均衡失效问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
Docker Compose实现负载均衡
- 还是对前面的例子
docker-compose.yml
稍微修改:
version: "3.8" services: flask-demo: build: context: . dockerfile: Dockerfile image: flask-demo:latest environment: - REDIS_HOST=redis-server - REDIS_PASS=${REDIS_PASS} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5000"] interval: 30s timeout: 3s retries: 3 start_period: 40s depends_on: - redis-server deploy: replicas: 3 networks: - backend - frontend redis-server: image: redis:latest command: redis-server --requirepass ${REDIS_PASS} networks: - backend nginx: image: nginx:stable-alpine ports: - 8000:80 depends_on: flask-demo: condition: service_healthy volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro - ./log/nginx:/var/log/nginx networks: - frontend networks: backend: frontend:
主要是修改flask-demo
启动3个容器。
nginx.conf
文件的内容如下:
server { listen 80 default_server; location / { proxy_pass http://flask-demo:5000; } }
- 启动服务:
$ docker-compose up -d Creating network "app8_backend" with the default driver Creating network "app8_frontend" with the default driver Creating app8_redis-server_1 ... done Creating app8_flask-demo_1 ... done Creating app8_flask-demo_2 ... done Creating app8_flask-demo_3 ... done Creating app8_nginx_1 ... done $ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------- app8_flask-demo_1 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_2 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_3 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8000->80/tcp,:::8000->80/tcp app8_redis-server_1 docker-entrypoint.sh redis ... Up 6379/tcp
- 访问服务:
$ curl localhost:8000 Hello Container World! I have been seen 4 times and my hostname is 448b5d70d3d8. $ curl localhost:8000 Hello Container World! I have been seen 5 times and my hostname is 77b2a2314533. $ curl localhost:8000 Hello Container World! I have been seen 9 times and my hostname is 4eee9c8d54f1.
从运行结果可以发现我们可以根据service的名称访问容器,Docker会使用内置的DNS服务器将service的名称解析成IP,如果service对应的容器有多个,nginx会进行负载均衡。
Docker带有一个内置的DNS服务器。默认情况下,可以通过127.0.0.11:53访问服务器。
这个DNS的IP可以通过进入容器内部查看/etc/resolv.conf
获得:
$ docker-compose exec nginx cat /etc/resolv.conf nameserver 127.0.0.11 options ndots:0
负载均衡的实现
- 在上面的例子中我们将
flask-demo
容器的个数提高到6个:
$ docker-compose up -d --scale flask-demo=6 app8_redis-server_1 is up-to-date Creating app8_flask-demo_4 ... done Creating app8_flask-demo_5 ... done Creating app8_flask-demo_6 ... done app8_nginx_1 is up-to-date $ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------- app8_flask-demo_1 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_2 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_3 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_4 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_5 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_flask-demo_6 flask run -h 0.0.0.0 Up (healthy) 5000/tcp app8_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:8000->80/tcp,:::8000->80/tcp app8_redis-server_1 docker-entrypoint.sh redis ... Up 6379/tcp $ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6e1494379165 flask-demo:latest "flask run -h 0.0.0.0" 53 seconds ago Up 51 seconds (healthy) 5000/tcp app8_flask-demo_6 62733bdccdb8 flask-demo:latest "flask run -h 0.0.0.0" 53 seconds ago Up 51 seconds (healthy) 5000/tcp app8_flask-demo_5 77e74622fa4e flask-demo:latest "flask run -h 0.0.0.0" 53 seconds ago Up 51 seconds (healthy) 5000/tcp app8_flask-demo_4 b67132189d90 nginx:stable-alpine "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8000->80/tcp, :::8000->80/tcp app8_nginx_1 448b5d70d3d8 flask-demo:latest "flask run -h 0.0.0.0" 2 minutes ago Up 2 minutes (healthy) 5000/tcp app8_flask-demo_1 4eee9c8d54f1 flask-demo:latest "flask run -h 0.0.0.0" 2 minutes ago Up 2 minutes (healthy) 5000/tcp app8_flask-demo_2 77b2a2314533 flask-demo:latest "flask run -h 0.0.0.0" 2 minutes ago Up 2 minutes (healthy) 5000/tcp app8_flask-demo_3 215beaad114a redis:latest "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp app8_redis-server_1
- 再次访问我们的服务:
$ curl localhost:8000 Hello Container World! I have been seen 28 times and my hostname is 448b5d70d3d8. $ curl localhost:8000 Hello Container World! I have been seen 29 times and my hostname is 77b2a2314533. $ curl localhost:8000 Hello Container World! I have been seen 30 times and my hostname is 4eee9c8d54f1. $ curl localhost:8000 Hello Container World! I have been seen 31 times and my hostname is 448b5d70d3d8. $ curl localhost:8000 Hello Container World! I have been seen 32 times and my hostname is 77b2a2314533. $ curl localhost:8000 Hello Container World! I have been seen 33 times and my hostname is 4eee9c8d54f1.
连续访问6次之后发现请求并没有转发到我们新启动的3个容器中,这是为什么呢?
负载均衡失效原因分析
- 初步怀疑是DNS解析失效,我们进入nginx容器查看DNS在解析
flask-demo
时解析出哪些IP:
$ docker-compose exec nginx sh / # apk update fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz v3.14.10-47-g7553b19fe26 [https://dl-cdn.alpinelinux.org/alpine/v3.14/main] v3.14.10-42-gd8ce7b89082 [https://dl-cdn.alpinelinux.org/alpine/v3.14/community] OK: 14983 distinct packages available / # apk add bind-tools (1/11) Installing fstrm (0.6.1-r0) (2/11) Installing krb5-conf (1.0-r2) (3/11) Installing libcom_err (1.46.2-r1) (4/11) Installing keyutils-libs (1.6.3-r0) (5/11) Installing libverto (0.3.2-r0) (6/11) Installing krb5-libs (1.18.5-r0) (7/11) Installing json-c (0.15-r1) (8/11) Installing protobuf-c (1.3.3-r6) (9/11) Installing libuv (1.41.0-r0) (10/11) Installing bind-libs (9.16.39-r0) (11/11) Installing bind-tools (9.16.39-r0) Executing busybox-1.33.1-r6.trigger OK: 31 MiB in 53 packages / # dig flask-demo ; <<>> DiG 9.16.39 <<>> flask-demo ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55582 ;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;flask-demo. IN A ;; ANSWER SECTION: flask-demo. 600 IN A 192.168.96.7 flask-demo. 600 IN A 192.168.96.2 flask-demo. 600 IN A 192.168.96.3 flask-demo. 600 IN A 192.168.96.4 flask-demo. 600 IN A 192.168.96.8 flask-demo. 600 IN A 192.168.96.6 ;; Query time: 0 msec ;; SERVER: 127.0.0.11#53(127.0.0.11) ;; WHEN: Tue Oct 10 08:45:53 UTC 2023 ;; MSG SIZE rcvd: 184
- 发现DNS解析出了6个IP,然后我们在nginx容器中访问
flask-demo
:
/ # curl flask-demo:5000 Hello Container World! I have been seen 281 times and my hostname is 77e74622fa4e. / # curl flask-demo:5000 Hello Container World! I have been seen 282 times and my hostname is 4eee9c8d54f1. / # curl flask-demo:5000 Hello Container World! I have been seen 283 times and my hostname is 62733bdccdb8. / # curl flask-demo:5000 Hello Container World! I have been seen 284 times and my hostname is 448b5d70d3d8. / # curl flask-demo:5000 Hello Container World! I have been seen 285 times and my hostname is 6e1494379165. / # curl flask-demo:5000 Hello Container World! I have been seen 289 times and my hostname is 77b2a2314533.
在nginx容器内访问就能访问到6个节点,那就说明nginx容器中DNS的解析没有问题,问题出在Nginx服务上。
Nginx在启动的时候会将代理服务器域名解析的ip地址缓存起来,后续不会再更新这个缓存,除非重启。
- 我们可以给nginx的缓存设置一个失效事件来解决这个问题,nginx.conf配置修改如下:
server { listen 80 default_server; location / { resolver 127.0.0.11 valid=1s; #设置dns服务器,缓存时间改为1s set $backend http://web:5000 proxy_pass $backend; } }
- 然后再让nginx重新加载配置,再访问服务,发现已经生效了:
$ docker-compose exec nginx nginx -s reload $ curl localhost:8000 Hello Container World! I have been seen 414 times and my hostname is 77b2a2314533. $ curl localhost:8000 Hello Container World! I have been seen 415 times and my hostname is 448b5d70d3d8. $ curl localhost:8000 Hello Container World! I have been seen 417 times and my hostname is 4eee9c8d54f1. $ curl localhost:8000 Hello Container World! I have been seen 420 times and my hostname is 77e74622fa4e. $ curl localhost:8000 Hello Container World! I have been seen 421 times and my hostname is 6e1494379165. $ curl localhost:8000 Hello Container World! I have been seen 422 times and my hostname is 62733bdccdb8.
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。