9.1 使用Docker Compose 部署应用——简介
多数的现代应用通过多个更小的服务相互协同来组成一个完整可用的应用。比如一个简单的示例应用可能由如下4个服务组成。
- Web前端
- 订单管理
- 品类管理
- 后台数据库
将以上服务组织在一起,那就是一个可用的应用。部署和管理繁多的服务是困难的。而这正式Docker Compose要解决的问题。
Docker Compose 并不是通过脚本和各种冗长的docker命令来将应用组件组织起来,而是通过一个声明式的配置文件描述整个应用,从而使用一条命令完成部署。
应用部署成功后,还可以通过一系列的命令实现对其完整声明周期的管理。甚至,配置文件还可以至于版本控制系统中进行存储和管理。这是显著的进步。
9.2 使用Docker Compose 部署应用——详解
9.2.1 Docker Compose 的背景
Docker Compose的前身是Fig,这是一家由Orchard公司开发的强有力的工具,用于进行多容器管理。在14年,该公司被Docker公司收购,Fig也改名为Docker Compose,该工具称为了绑定在Docker引擎之上的外部工具。
Docker Compose 是一个需要在Docker主机上进行安装的外部Python工具。使用它时,首先编写定义多容器(多服务)应用的YAML文件,然后将其交由给docker-compose命令处理,Docker Compose就会基于Docker引擎API完成应用的部署。
9.2.2 安装Docker Compose
我们可以直接下载Docker Compose的二进制包,然后修改下文件权限即可使用Docker Compose.
##下载二进制包,目前最新版本时1.24.1
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
##修改文件权限
sudo chmod +x /usr/local/bin/docker-compose
##查看docker-compose查看版本信息
docker-compose --version
9.2.3 Compose文件
Docker Compose使用YAML文件来定义多服务的应用。YAML是JSON的一个子集,因此也可以使用JSON。不过本章的例子全部采用YAML。Dockers Compose默认使用的文件名为 docker-compose.yml。当然,用户也可以使用 -f 参数指定具体文件。
下面是一个简单的Compose文件的示例,它定义了一个包含两个服务(web-fe和redis)的小型Flask应用。这是一个能够对访问者进行计数并将其保存到Redis的简单的Web服务。我们可以到GitHub上获取代码。
git clone https://github.com/nigelpoulton/counter-app.git
进入到拉取的代码目录,查看docker-compose.yml文件
version: "3.5"
services:
web-fe:
build: .
command: python app.py
ports:
- target: 5000
published: 5000
networks:
- counter-net
volumes:
- type: volume
source: counter-vol
target: /code
redis:
image: "redis:alpine"
networks:
counter-net:
networks:
counter-net:
volumes:
counter-vol:
首先我们可以看到这个文件的基本结构,这里包含了4个一级key:version、services、networks、volumes。
version时必须指定的,而且总是位于文件的第一行。它定义了Compose文件格式(主要时API)的版本。建议使用最新版。注意,version并非定义Dockers Compose或者Docker引擎的版本号。这里我们使用的Compose文件都使用3及以上的版本。
services用于定义不同的应用服务。上面定义了两个服务:一个名为web-fe的web前端服务以及一个名为redis的内存数据库服务。Docker Compose会将每个服务部署在各自的容器中。
networks用于指引Docker主机创建新的网络。默认情况下,Docer Compose会创建bridge网络。这是一种单主机网络,只能够实现同一主机上容器的连接。当然,也可以使用driver属性来指定不同类型的网络。
volumes用于指引Docker来创建新的卷。
这里分析下上面的Compose文件。
上面的例子中Compose文件使用的是v3.5版本的格式,定义了两个服务,一个名为counter-net的网络和一个名为counter-vol的卷。更多的信息是在services中,我们着重分析下。
在services部分定义了两个二级key:web-fe和redis。他们各自定义了一个应用程序服务。需要明确的是,Docker Compose会将每个服务部署为一个容器,并且会使用key作为容器名字的一部分。本例中定义了两个key,因此Docker Compose会部署两个容器。
其中web-fe的服务定义中,包含了以下指令。
build: .指定Docker基于当前目录下Dockrfile中定义的指令去构建一个新的镜像,该镜像会被用于启动该服务的容器。
command: python app.py指定Docker在容器中执行名为app.py的python脚本作为主程序。因此镜像中必须包含app.py文件以及python,这一点在Dockerfile中可以得到满足。
ports:指定Docker将容器内(-target)的5000端口映射到主机(published)的5000端口。这意味着发送到Docker主机5000端口的流量会被转发到容器的5000端口。
networks:使得Docker可以将服务连接到指定的网络上。这个网络就是我们下面定义的。
volumes:指定Docker将counter-vol卷挂载到容器内的 /code.这个卷也是我们下面定义的。
综上,Docker Compose会调用Docker来为web-fe服务部署一个独立的容器。该容器基于于Compose文件同一目录的Docker构建的镜像。基于该镜像启动的容器会运行app.py作为其主程序,将5000端口暴露给宿主机,连接到counter-net网络上,并且挂载一个卷到 /code。
事实上我们在Docker Compose中不用定义 command命令了,因为镜像的Dockerfile已经定义了。
redis服务的定义相对来说就比较简单了。
image:redis:alpine使得Docker可以基于redis:alpine镜像启动一个独立的名为redis的容器,这个容器会从Docker Hub上拉取下来。
networks:配置redis容器连接到counter-net网络。
由于两个服务都连接到counter-net网络,因此他们可以通过名称解析到对方的地址。了解这一点很重要,本例中上层应用被配置为通过名称与Redis服务通信。
9.2.4 使用Dockers Compose部署应用
上面我们已经把源码从github上面下载下来了,进入目录我们大概看下里面的那几个文件:
- app.py 是应用程序代码
- docker-compose.yml 是Compose文件,其中定义了Docker如何部署应用
- Dockerfile 定义了如何构建web-fe服务所使用的镜像。
- requirements.txt 列出了应用所依赖的python包
下面我们使用docker-compose来把应用给部署然后启动起来。
cd counter-app
docker-compose up &
常用的启动一个Compose应用的方式就是docker-compose up 命令。它会构建所需的镜像,创建网络和卷,并启动容器。默认情况下,docker-compose up 会查找名为docker-compose.yml或者docker-compose.yaml的Compose文件。如果使用其他的文件名,请使用 -f 参数去指定。要后台启动更加合理的方式是使用 -d 参数,使用 & 的话不大正规。
最后,这个命令会创建3个镜像(有个python基础镜像是Dockerfile拉取的),并且启动其中的两个(web-fe和redis).
[pangcm@docker01 ~]$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8f43b3727185 redis:alpine "docker-entrypoint.s…" 22 seconds ago Up 17 seconds 6379/tcp counter-app_redis_1
3e9d124ae4a5 counter-app_web-fe "python app.py" 22 seconds ago Up 17 seconds 0.0.0.0:5000->5000/tcp counter-app_web-fe_1
到这里,多容器的应用已经借助Docker Compose成功部署了。你可以是用浏览器打开Docker主机的5000端口查看成果。
9.2.5 使用Docker Compose 管理应用
本节会介绍如何使用Docker Compose 启动、停止和删除应用,以及获取应用状态。还会演示如何使用挂载的卷来实现对Web前端的更新。
前面我们启动了应用,接下来我们使用 docker-compose down 来关闭应用。
[pangcm@docker01 counter-app]$ docker-compose down
Stopping counter-app_redis_1 ... done
Stopping counter-app_web-fe_1 ... done
Removing counter-app_redis_1 ... done
Removing counter-app_web-fe_1 ... done
Removing network counter-app_counter-net
这里可以看到关闭的过程,停止并删除容器,然后删除网络。可以看到我们的卷并没有被删除掉,因为卷是用来做持久化存储的。如果你使用的是 docker-compose up & 来启动过的话,还可以看到更多的过程。
然后我们再次来启动,使用docker-compose ps 观察应用的状态。
[pangcm@docker01 counter-app]$ docker-compose up -d
Creating network "counter-app_counter-net" with the default driver
Creating counter-app_web-fe_1 ... done
Creating counter-app_redis_1 ... done
[pangcm@docker01 counter-app]$ docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------
counter-app_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
counter-app_web-fe_1 python app.py Up 0.0.0.0:5000->5000/tcp
输出的内容会显示容器的名称,其中运行的Command、当前状态以及其侦听的网络端口。
使用docker-compose top 命令可以列出各个服务内运行的进程。
[pangcm@docker01 counter-app]$ docker-compose top
counter-app_redis_1
UID PID PPID C STIME TTY TIME CMD
-------------------------------------------------------------------
polkitd 10501 10468 0 18:01 ? 00:00:00 redis-server
counter-app_web-fe_1
UID PID PPID C STIME TTY TIME CMD
--------------------------------------------------------------------------------------
root 10514 10492 0 18:01 ? 00:00:00 python app.py
root 10632 10514 0 18:01 ? 00:00:00 /usr/local/bin/python /code/app.py
这里需要注意的是PID编号是在Docker主机上的进程ID,而不是容器里面的。
使用docker-compose stop 可以停止应用,但是不会删除资源。
[pangcm@docker01 counter-app]$ docker-compose stop
Stopping counter-app_redis_1 ... done
Stopping counter-app_web-fe_1 ... done
[pangcm@docker01 counter-app]$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------
counter-app_redis_1 docker-entrypoint.sh redis ... Exit 0
counter-app_web-fe_1 python app.py Exit 0
已经停止的应用可以使用 docker-compose rm命令去删除资源,这里也一样不会删除卷和镜像的。使用docker-compose restart 可以重启应用。
docker-compose restart
上面多处提到卷不会被删除,那么我们来看下卷的情况。查看卷可以使用 docker volome ls命令查看。
[pangcm@docker01 counter-app]$ docker volume ls
DRIVER VOLUME NAME
local counter-app_counter-vol
这个卷我们把它挂载到容器的 /code 目录下,/code 目录是应用的工作目录,我们的项目文件就是存放在这个目录下,从Dockerfile文件可以得到确定。
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
这就是说我们的项目文件实际上持久化在对应的卷上的了,如果我们在Docker主机对卷中的文件做修改,会不会马上反应到应用中呢?下面验证下。
首先我们要找到我们这个卷所在的位置,使用 inspect 可以查看到。
[pangcm@docker01 counter-app]$ docker volume inspect counter-app_counter-vol |grep Mountpoint
"Mountpoint": "/var/lib/docker/volumes/counter-app_counter-vol/_data",
可以看到这个卷实际上在Docker主机的 /var/lib/docker/volumes/目录下,我们进入到该目录,然后修改里面的app.py文件,最后在页面上验证下结果即可。
##修改这行的内容即可
return "What's up PCM1 Docker Deep Divers! You've visited me {} times.\n".format(count)
在生产环境中我们不会这么做,但是在开发环境下能节省很多时间。这里可以看到,Docker Compose可以用来部署和管理复杂得多的应用。
9.3 使用Docker Compose 部署应用——命令
- docker-compose up 命令用于部署一个Compose应用。
- docker-compose stop 命令会停止Compose应用相关的所有容器,但不会删除他们。
- docker-compose rm 命令用于删除停止的Compose应用。
- docker-compose restart 命令会重启已停止的Compose应用。
- docker-compose ps 命令用于列出Compose应用中的各个容器。输出内容包括当前状态、容器运行的命令以及网络端口。
- docker-compose down 会停止并删除运行中的Compose应用。它会删除容器和网络,但是不会删除卷和镜像。
9.4 本章小结
本章介绍了如何使用Docker Compose 部署和管理一个多容器的应用。Docker Compose是一个基于Docker Engine进行安装的Python工具。该工具使得用户可以在一个声明式的配置文件中定义一个多容器的应用,并通过一个简单的命令完成部署。
Compose文件可以是YAML或者JSON格式,其中定义了所有的容器、网络、卷以及应用所需的密码。docker-compose命令行工具会解析该文件,并调用Docker来执行部署。
一旦应用完成部署,用户就可以使用不同的docker-compose子命令来管理应用的整个生命周期。
本章还介绍了如何使用挂载卷来修改容器内的文件。Docker Compose 在开发者中得到广泛使用,而且对应用来说,Compose文件也是一种非常不错的文档——其中定义了组成应用的所有服务,他们使用的镜像、网络和卷,暴露的端口,以及更多信息。基于此,我们可以弥合开发与运维之间的隔阂。Compose文件应该被当作代码,因此应该将其保存在源控制库中。