动手学Docker-第五弹-Docker多容器部署

1,147 阅读6分钟

使用方式

您可以通过以下方式使用本书:

content


通过之前的案例我们也实现了Docker的多容器部署,但是有没有觉得仍然很麻烦,我们开发程序更习惯讲配置信息写到配置文件里再继续操作,那么Docker有没有实现这样的功能呢?答案是有的。

Docker Compose

Docker Compose是一个工具,它支持通过yml文件来定义和配置多个容器,而且在定义好容器之后我们可以通过跟简单的命令快速的搭建起一个基于Docker的多容器应用。 默认情况下我们是创建一个docker-compose.yml文件,在这个文件中我们会定义三个比较重要的东西。

  1. services:里面对应的每个service代表一个容器,容器对应的镜像可以通过DockerHub拉取,也可以通过build命令构建。并且在创建时我们还可以指定对应的network和volume。
  2. volumes:对应之前Docker持久化存储那里的-v参数
  3. networks:对应之前Docker网络那里的-net参数

其实我们在最开始的Docker初体验里就已经使用过这个Docker Compose了,不知道大家还记不记得,我们这里再回顾一下。

在这里插入图片描述

Docker Compose安装

一般情况下在mac和windows上安装Docker时会自动安装docker-compose,Linux上需要手动安装。 首先通过命令

docker-compose --version

查看你的服务器是否已经安装好了Docker Compose。若没有安装则继续阅读以下安装步骤

在这里插入图片描述

Centos安装Docker-Compose

  1. 获取Docker-Compose发行版
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  1. 修改权限
sudo chmod +x /usr/local/bin/docker-compose
  1. 查看是否安装成功
docker-compose --version

Docker Compose基本使用

在创建好docker-compose.yml文件后,可以通过这个命令将文件中定义的容器都启动起来,在docker compose中我们更习惯于将每一个容器叫做service。

docker-compose up

命令后会自动接一个默认值-f docker-compose.yml,也就是默认是使用docker-compose.yml文件的。我们也可以给文件起名为docke-test.yml,这样在使用时指定文件名,但是为了符合规范,还是统一为docker-compose.yml

docker-compose up -f docer-test.yml

但是直接通过这种方式的话会直接将启动时的输出打印到终端,所以我们常会加上-d参数。

docker-compose up -d

接下来可以查看一下我们创建的service状态

docker-compose ps

如何停止已经运行的services呢,可以使用以下两个命令

docker-compose stop
docker-compose down

其中stop是直接停止services,而down则会停止并删除创建的service,volume和network。

那么如何进入容器呢

docker-compose exec mysql bash

exec后面接的就是我们要进入具体的service的名字,名字后面就是我们要执行的命令。

flask-redis Docker Compose实战

我们在之前是使用docker的命令将flask和redis进行连接,详情见flask-redis实战

接下来我们使用docker-compose的方式实现同样的功能。

编写python文件

首先编辑好一个python文件,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=5000, debug=True)

编写Dockerfile

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

编写docker-compose

version: "3"

services:

  redis:
    image: redis

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

可以看到在文件中我们定义了两个service,一个叫做redis,一个叫做web,而且web的镜像常见方式是build。

创建服务

docker-compose up -d

可以看到这里我们也并没有像之前一样使用--link命令,是因为我们通过docker-compose up启动后会默认创建一个network。

在这里插入图片描述

我们再具体看一下网络中的具体内容,可以看到我们创建的两个service确实是连接到这个network中的。所以他们两个之间是可以直接通信的。

在这里插入图片描述

接下来我们访问一下,可以看到效果和之前是一样的

在这里插入图片描述

负载均衡

现在的需求是这样的,我们刚才创建的那个flask-redis服务因为访问的人多现在需要拓展几个容器来同时提供服务,以平衡单个容器的访问压力,我们如何实现这个需求呢?

水平拓展

我们先来看一下现在的情况

在这里插入图片描述

Docker Compose有一个scale参数,通过这个参数可以实现容器的水平拓展。

docker-compose up --scale web=3 -d

在这里插入图片描述

我们再通过命令查看一下现在的容器状态

在这里插入图片描述

现在可以看到我们有了三个web服务,这三个web会同时对外提供服务,以减轻访问单个容器的压力。

出现的问题

但是现在这样还有一个问题就是我们每个容器都是暴露出自己的端口5000,而且因为本地服务器只有一个8080端口,我们没法让多个容器都绑定上去,那我们如何通过访问服务器的地址来自动的映射到其他容器呢?

解决办法

这时我们就需要haproxy来支持。

HAProxy是一个免费的负载均衡软件,可以运行于大部分主流的Linux操作系统上。

HAProxy提供了L4(TCP)和L7(HTTP)两种负载均衡能力,具备丰富的功能。HAProxy的社区非常活跃,版本更新快速(最新稳定版1.7.2于2017/01/13推出)。最关键的是,HAProxy具备媲美商用负载均衡器的性能和稳定性。

因为HAProxy的上述优点,它当前不仅仅是免费负载均衡软件的首选,更几乎成为了唯一选择。

修改dokcer-compose.yml文件。

version: "3"

services:

  redis:
    image: redis

  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports: ["8080"]
    environment:
      REDIS_HOST: redis

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

修改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

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" ]

启动服务

docker-compose up -d

做水平拓展

docker-compose up --scale web=3 -d

我们先看一下service的具体情况

在这里插入图片描述

现在来访问一下服务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到我们在访问的过程中是近乎轮询式的,通过这样的方式来减轻单个服务器的压力,实现负载均衡。


欢迎大家关注我们的公众号:知识沉淀部落。

知识沉淀部落