第9章 使用Docker Compose 部署应用

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文件应该被当作代码,因此应该将其保存在源控制库中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容