19、Docker Compose

  编排(Orchestration)功能是复杂系统实现灵活可操作性的关键。特别是docker应用场景中,编排意味着用户可以灵活地对各种容器资源实现定义和管理。

  在我们部署多容器的应用时:

  • 要从Dockerfile build image或者从dockerhub拉取image
  • 要创建多个container
  • 要管理这些container(启动、停止、删除)

  为了方便我们部署和管理多容器的应用,docker compose就出现了。

docker-compose

19.1 什么是docker compose

  docker compose项目是docker官方的开源项目,负责实现对docker容器集群的快速编排。其代码在GitHub上开源https://github.com/docker/compose

  • Docker Compose是一个工具
  • 这个工具可以通过一个yml文件定义多容器的docker应用
  • 通过一条命令就可以根据yml文件的定义去创建或者管理这多个容器

  Compose定位是“定义和运行多个docker容器的应用”。它允许用户通过一个单独的docker-compose.yml模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)。

Compose中有三个重要的概念:

  • 服务(services)

  一个service代表一个container,这个container可以从dockerhub的image创建,或者从本地的Dockerfile build出来的image来创建。

  service的启动类似docker run,我们可以给其指定network和volume,所以可以给service指定network和volume的引用。

  • 网络(networks)
  • 数据卷(volumes)

举例

  • service举例
services: 
  db:
    image: postgres:9.4
    volumes:
      - "db-data:/var/lib/postgresql/data"
    network:
      - back-tier

  这个例子类似于运行了下面这条命令:

docker run -d --network back-tier -v db-data:/var/lib/postgresql/data postgres:9.4
services:
  worker:
    build: ./worker    # 指定了Dockerfile的路径
    links:
      - db
      - redis

    networks:
      - back-tier

  安装WordPress的一个docker compose文件:

version: '3'  # 指定docker compose的版本

services:

  wordpress:
    image: wordpress
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_PASSWORD: root
    networks:
      - my-bridge

  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - my-bridge

volumes:
  mysql-data:

networks:
  my-bridge:
    driver: bridge

19.2 docker-compose安装

  docker compose 官方安装文档

curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

chmod +x /usr/local/bin/docker-compose

19.3 docker-compose命令说明

1. -f, --file           指定使用的Compose模板文件,默认为当前目录下的docker-compose.yml文件。
2. -p, --project-name   指定项目名称,默认将使用当前所在目录名称作为项目名。
3. --verbose            打印更多的日志输出
4. --log-level          设置日志级别,(DEBUG, INFO, WARNING, ERROR, CRITICAL)
5. -v, --version        打印版本并退出
6. -H, --host           指定连接到的守护进程
7. build                构建(重新构建)项目中的服务容器
8. logs                 查看服务容器的输出
9. kill                 强制停止服务容器
10. pause               暂停一个服务容器
11. port                打印某个容器端口所映射的公共端口
12. ps                  列出项目中目前的所有容器
13. pull                拉取服务依赖的镜像
14. restart             重启项目中的服务
15. rm                  删除所有(停止状态的)服务容器
16. run                 在指定服务上执行一个命令
17. exec                在指定服务上执行一个命令
17. scale               设置指定服务运行的容器个数
18. start               启动已经存在的服务容器
19. stop                停止已经处于运行状态的容器,但是不能删除
20. unpause             恢复处于暂停状态的服务
21. up                  自动完成包括构建镜像、创建服务、创建指定网络、启动服务并关联服务相关容器的一系列操作
22. migrate-to-labels   创建容器,并添加lable
23. version             打印版本信息
24. down                停止正在运行的容器并删除容器和网络

19.4 通过docker-compose scale实现负载均衡

  通过haproxy实现flask调用redis的负载均衡

  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:
      - 8080:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  Dockerfile:

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

  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 up -d启动:

[root@docker lb-scale]# docker-compose up -d
Creating network "lb-scale_default" with the default driver
Creating lb-scale_redis_1 ... done
Creating lb-scale_web_1   ... done
Creating lb-scale_lb_1    ... done
[root@docker lb-scale]# 

  通过docker-compose ps查看:

[root@docker lb-scale]# docker-compose ps
      Name                    Command               State                    Ports
---------------------------------------------------------------------------------------------------
lb-scale_lb_1      /sbin/tini -- dockercloud- ...   Up      1936/tcp, 443/tcp, 0.0.0.0:8080->80/tcp
lb-scale_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
lb-scale_web_1     python app.py                    Up      80/tcp
[root@docker lb-scale]# \

  通过 curl 127.0.0.1:8080

[root@docker lb-scale]# curl 127.0.0.1:8080
Hello Container World! I have been seen 1 times and my hostname is 857fdbc456fb.
[root@docker lb-scale]# curl 127.0.0.1:8080
Hello Container World! I have been seen 2 times and my hostname is 857fdbc456fb.
[root@docker lb-scale]# curl 127.0.0.1:8080
Hello Container World! I have been seen 3 times and my hostname is 857fdbc456fb.
[root@docker lb-scale]# 

  通过scale创建多个web服务的容器数,并且通过haproxy是爱你负载均衡:

[root@docker lb-scale]# docker-compose up --scale web=3 -d
lb-scale_redis_1 is up-to-date
Starting lb-scale_web_1 ... done
Creating lb-scale_web_2 ... done
Creating lb-scale_web_3 ... done
lb-scale_lb_1 is up-to-date
[root@docker lb-scale]# 

  再次通过 curl 127.0.0.1:8080

[root@docker lb-scale]# curl 127.0.0.1:8080
Hello Container World! I have been seen 4 times and my hostname is 857fdbc456fb.
[root@docker lb-scale]#curl 127.0.0.1:8080
Hello Container World! I have been seen 5 times and my hostname is 43f2925c52d1.
[root@docker lb-scale]# curl 127.0.0.1:8080
Hello Container World! I have been seen 6 times and my hostname is 354a407ee7b1.
[root@docker lb-scale]# curl 127.0.0.1:8080
Hello Container World! I have been seen 7 times and my hostname is 857fdbc456fb.
[root@docker lb-scale]#curl 127.0.0.1:8080
Hello Container World! I have been seen 8 times and my hostname is 43f2925c52d1.
[root@docker lb-scale]#curl 127.0.0.1:8080
Hello Container World! I have been seen 9 times and my hostname is 354a407ee7b1.
[root@docker lb-scale]#

  继续增加WEB容器的数量,并访问:

[root@docker lb-scale]# docker-compose up --scale web=10 -d
lb-scale_redis_1 is up-to-date
Starting lb-scale_web_1 ... done
Starting lb-scale_web_2 ... done
Starting lb-scale_web_3 ... done
Creating lb-scale_web_4  ... done
Creating lb-scale_web_5  ... done
Creating lb-scale_web_6  ... done
Creating lb-scale_web_7  ... done
Creating lb-scale_web_8  ... done
Creating lb-scale_web_9  ... done
Creating lb-scale_web_10 ... done
lb-scale_lb_1 is up-to-date
[root@docker lb-scale]#for i in `seq 10`;do curl 127.0.0.1:8080;done
Hello Container World! I have been seen 10 times and my hostname is 857fdbc456fb.
Hello Container World! I have been seen 11 times and my hostname is a529d9001556.
Hello Container World! I have been seen 12 times and my hostname is 43f2925c52d1.
Hello Container World! I have been seen 13 times and my hostname is 354a407ee7b1.
Hello Container World! I have been seen 14 times and my hostname is 25698b41ea54.
Hello Container World! I have been seen 15 times and my hostname is 4114fe5258fa.
Hello Container World! I have been seen 16 times and my hostname is 749e6918a6c5.
Hello Container World! I have been seen 17 times and my hostname is 7792a42d1219.
Hello Container World! I have been seen 18 times and my hostname is c91ab986a554.
Hello Container World! I have been seen 19 times and my hostname is 01fc4550b204.
[root@docker lb-scale]#

  可以看出,通过docker-compose的scale可以快速的实现某个服务容器数量的增加,在访问量突增的情况下可以轻松应对,减轻服务器压力。

当访问量恢复正常的时候也可以5个docker-compose up --scale来减少容器的数量:

[root@docker lb-scale]# docker-compose up --scale web=5 -d
lb-scale_redis_1 is up-to-date
Stopping and removing lb-scale_web_6  ... done
Stopping and removing lb-scale_web_7  ... done
Stopping and removing lb-scale_web_8  ... done
Stopping and removing lb-scale_web_9  ... done
Stopping and removing lb-scale_web_10 ... done
Starting lb-scale_web_1               ... done
Starting lb-scale_web_2               ... done
Starting lb-scale_web_3               ... done
Starting lb-scale_web_4               ... done
Starting lb-scale_web_5               ... done
lb-scale_lb_1 is up-to-date
[root@docker lb-scale]# docker-compose ps
      Name                    Command               State                    Ports
---------------------------------------------------------------------------------------------------
lb-scale_lb_1      /sbin/tini -- dockercloud- ...   Up      1936/tcp, 443/tcp, 0.0.0.0:8080->80/tcp
lb-scale_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
lb-scale_web_1     python app.py                    Up      80/tcp
lb-scale_web_2     python app.py                    Up      80/tcp
lb-scale_web_3     python app.py                    Up      80/tcp
lb-scale_web_4     python app.py                    Up      80/tcp
lb-scale_web_5     python app.py                    Up      80/tcp
[root@docker lb-scale]# 

  上述只是实现了单机的容器编排,毕竟单台服务器的资源是有限的,容器数量过多会导致单台服务器资源使用率不够用,但是,如果可以在多机服务器上编排容器数量,那么服务器的性能将会得到更好的利用,能够承受的并发将会呈指数上升。

  在docker-compose 3.0之前,docker-compose只支持单机的容器编排,到3.0的时候,docker-compose已经可以支持多机的容器编排了,也就是说利用3.0及以上的docker-compose可以实现多服务器上的容器编排。

posted @ 2019-01-16 22:13  StaryJie  阅读(423)  评论(0编辑  收藏  举报