原文是来自qiitaetaro所写的系列文章。

从镜像和容器到docker-compose、docker-machine、docker swarm等将docker相关的概念一网打尽,理解docker的组成与结构。

相关配图没空P了>_<

docker是什么

docker是Docker公司提供的实现了容器型虚拟化技术的产品。

虚拟化?

指的是在PC或服务器所安装的OS(主机OS)上,虚拟化出了其他的机器。

简单的说虚拟化就是在一台笔电上启动了另一台虚拟化的笔电

以前的虚拟化(主机型虚拟化,即虚拟机)是像下图这样。在主机OS上使用虚拟化的软件/Hypervisor,创建虚拟机/访客OS,在其中构建应用执行环境后再执行应用程序。

容器型虚拟化?

除此之外,就是Docker所提供的容器型虚拟化了。

容器型虚拟化的构成由下图所示。

与以前的主机型虚拟化不同,不用启动访客OS,而是使用在主机OS上运行的Docker Engine,构建被称作容器的中间件环境,并在其中进行应用的各种操作。

这样一来,与之前的主机型虚拟化相比,容器型虚拟化具有非常显著的轻量化特征。

使用Docker的好处

现在的各种软件一般都不是凭一己之力开发出来的,均是由多个开发者协力完成的,那么如果协调多人的应用/系统开发工作呢?

最重要的是程序代码的共享。目前一般都是使用Git来进行版本管理,笔者所在团队使用的代码共享服务有Github、Bitbucket和Gitlab等等。不过,就算解决了代码的共享问题,还存在着不能共享代码执行环境的问题,这样一来代码可能就无法正常的跑起来。

共享执行环境并不简单,开发者使用的可能是Mac OSX、Windows等不同的系统,并且安装的软件也因人而异。因此,可以利用虚拟化创建扁平化的虚拟机,通过共享这个虚拟机的生成配置来共享执行环境。但在这之前由于主机型虚拟机的操作较为繁琐,并且共享的文件也较大,有着明显不轻量的问题。

另一方面,Docker的容器型虚拟化就可以实现轻量化的操作与环境文件的共享。Docker在管理程序执行环境应用的同时,也有一些像DockerHub等用于管理共享文件的服务。使用Docker的一个主要优点是: 不论是多么复杂的结构,都可以使用Docker轻松共享与管理任何机器上的软件执行环境。

下面,来看看Docker中的常见概念吧。

Docker Engine

使用Docker必须启动的程序。

在PC上安装Docker for mac、Docker for Windows或Docker Toolbox等软件,启动Docker Engine后便可使用Docker了。

镜像 image

启动容器(=应用的执行环境)时所需要的配置文件,可以理解为[镜像是容器的源,从镜像启动容器]。

通过在Docker中共享这个镜像,可以在不同的机器上运行相同的容器(执行环境)。

标签 Tag

Docker的镜像具有标签的概念,指的是镜像的版本。

比如说,在下面的这个nginx镜像中有着1.14-perlalpine等不同标签,可以根据情况选择使用的版本。

若不指定标签,则默认使用latest标签。

镜像名称与标签名称使用:分隔,如下所示:

nginx:latest
nginx:1.14-perl

镜像的组成

镜像有以下两个特点:

  1. 分层的结构
  2. 生成镜像后无法再次编辑(只读)

镜像是由不同层级组成的,每次安装一个中间件时都会叠加一层(一个安装命令会累积一层)。

并且镜像的层是只读不能编辑的,只有从镜像启动容器后的容器层是可以编辑的。

从镜像启动容器后,在容器内安装任何中间件的改动均会保存到容器层中,可以再次从容器中生成(commit)镜像。

准备镜像

使用如下命令确定本地主机中的镜像:

$ docker images

接下来为了执行容器,需要准备作为容器源的镜像。

镜像的获得方法:

  1. 获取别人制作的镜像(主要从Docker Hub中获取)
  2. 自己制作(修改他人镜像)

1. 从Docker Hub获取镜像

Docker Hub上公开了各种安装不同中间件的镜像,根据自己的需要使用如下命令获取镜像。

$ docker pull 镜像名     # 从docker hub(docker的托管服务器)获取镜像

2. 通过Dockerfile生成镜像

创建名为Dockerfiile的文本文件,在其中记录有关构建镜像的配置,就通过Dockerfile可以自己生成镜像了。

可以进行各种操作,下面仅介绍最基础的部分:

FROM 镜像名:标签名       # 引用的镜像
RUN 安装package等的命令     # 这里记录的命令会在安装中间件时执行,叠加镜像层
CMD 指定命令        # 生成容器后执行命令
$ docker build -t 构建后的镜像名称 .

-t选项用来命名生成的镜像。并且在生成image时传给docker daemon的文件区域称作构建上下文,在镜像名之后进行设置(例子中的.表示当前路径下)。

由于在build命令执行时需要在构建上下文中加载作为设置的Dockerfile,因此必须将Dockerfile放在构建上下文中。

在不更改Dockerfile的情况下进行构建会使用构建缓存,将看到之前构建的信息,需要注意的是就算在平时构建中的RUN指令后使用update命令也是不起作用的。

不使用缓存进行构建:

$ docker build —no-cache -t docker-whale

容器 container

准备好了镜像,就可以使用镜像来启动容器(应用的执行环境)了。

从image启动容器

通过镜像创建容器

$ docker create --name 起的容器名 镜像名

启动容器

$ docker start 容器名

到目前已经看到了如何从DockerHub获取想要的镜像,创建容器,与启动命令。有一个命令同时具有这些命令的效果:

$ docker run 镜像名

docker run包含了以下步骤:

  • docker pull : 从DockerHub取得镜像
  • docker create :使用取得的镜像创建容器
  • docker start :启动创建的容器

可以使用docker run命令简化操作,相当于依次执行了上述命令。

容器的操作命令

用途 命令 其他
查看容器 docker ps (-a) 默认显示运行中的容器,-a表示查看存在的所有容器
容器详情 docker inspect 容器名 -
创建容器 docker create —name 自定义的容器名 -it 镜像名 /bin/bash -
启动容器 docker start 容器名 -
暂停容器 docker pause 容器名 -
重启容器 docker restart 容器名 -
停止容器 docker stop 容器名 停止容器后仍会留存在本地磁盘中,变为Exit状态。若不删除未使用的容器会对硬盘产生压力。
删除容器 docker rm (-f) 容器名 -f表示强制删除
连接运行中容器shell(方法一) docker attach 运行中的容器名 可以通过exit命令停止容器
连接运行中容器shell(方法二) docker exec -it 运行中的容器名 /bin/bash 使用了-it后无法使用control + p, control + q终止容器
从容器生成镜像 docker commit 容器名 镜像名:标签名 将容器当前状态保存到指定的[镜像名:标签名]的镜像中
查看镜像历史 docker history 镜像名 使用docker commit生成镜像后,在容器内部不会保存任何变更记录。因此应该在Dockerfile中添加对应image的更改记录来生成镜像

Docker Hub

在Docker Hub共享镜像

与Github类似,需要有Dockerhub的账号。

操作步骤:

  1. 在Docker hub上创建仓库
  2. 在本地生成image
  3. 在本地CLI中登入docker hub

    $ docker login
    
  4. 给想要push的image加上标签

    $ docker tag <要push的image名> <docker hub ID>/<新的image名>:<标签名>
    
  5. 将本地镜像push到远程仓库

    $ docker push <docker hub ID> / <image名>:<标签名>
    

Docker数据管理

在操作运行中容器的数据时,可以进行读写的是最上一层(容器层)的数据。

这样操作的一些不足之处:

  • 删除容器也会删除容器内的数据
  • 容器间不能共享数据
  • 在容器层写入数据时,使用的是联合文件系统(Union File System),与一般的文件系统不同,写入速度较慢。

因此,想要用Docker管理主机上的数据,需要在容器上挂载主机的存储空间。这样的方法有三种,下面来具体介绍。

卷 volume

是一种在主机上将自动生成的指定路径(/var/lib/docker/volumes)挂载到容器上的方法。

主机上执行如下命令来创建卷(路径为/var/lib/docker/volumes)

$ docker volume create 卷名

在容器启动时设置挂载选项

$ docker run -itd --name 生成的容器名 --mount source=[挂载的卷名],target=[容器上挂载的目标路径] 镜像名

示例:
$ docker run -itd --name mount-test --mount source=volume1,target=/app nginx

--mount(也可以使用-v选项)选项用来设置所挂载的卷。需要注意的是对于所挂载的卷路径,不应该直接在主机上的源路径进行操作。

并且在同一主机内的不同容器,也可以通过分别挂载同一个卷来共享文件。

除此之外,在多个容器共享卷的情况下,可以设置不同容器对卷的编辑权限。像如下这样指定容器的编辑权限:

$ docker run -itd —name mount-c4 —mount source=copy-vol, destination=/etc/nginx,readonly nginx

卷的操作命令

用途 命令 其他
查看卷 docker volume ls
卷详情 docker volume inspect volume名
删除卷 docker volume rm volume名 删除容器后默认会保留卷,需要执行这个命令来手动删除卷

bind mount

bind mount可以挂载主机上的任意路径,与卷的挂载方式不同的是可以直接操作主机端的路径。

没必要像卷一样事先设置,在容器启动时使用如下命令指定挂载目录即可。

$ docker run -itd --name [容器名] --mount type=bind,source=[挂载源路径],target=[挂载目标路径] 镜像名

示例:
$ docker run -itd —-name bind-mount-test —-mount type=bind,source=“$(pwd)”/mount,target=/app nginx

在源路径不存在的情况下会报错,需要事先创建好(使用-v选项会自动生成)。

使用bind mount时需要注意,若将主机上的空路径挂载到容器的/user等的情况下,容器上的数据就会消失,导致容器无法正常运行。

除此之外,与卷一样也可以设置容器的编辑权限。

tmpfs(临时fs)

tmpfs是将主机的内存区域挂载到容器上的方法。

关闭主机时容器也会关闭,会释放所保存的数据。

$ docker run -itd --name [容器名] --mount type=tmpfs,destination=[挂载目标路径] 镜像名

具体例:
$ docker run -itd --name tmpfs-test --mount type=tmpfs,destination=/app nginx

在启动时,将–mount选项的type改为tmpfs即可挂载。

为了不让容器无限制的使用主机上的内存,需要做一些限制:

$ docker run -itd --name tmpfs-test --mount type=tmpfs,destination=/app,tmpfs-size=800000000,tmpfs-mode=800 nginx

在选项中可以设置所使用的内存大小。

Docker Network

至此为止,已经了解到了Docker可以使用多种镜像启动名为容器的应用执行环境,来方便的构建应用环境。

接下来介绍如何在建立的多个容器间进行通信的方法。比如在Web页面的场景中,创建Wordpress和MySQL容器后,Wordpress容器需要与MySQL容器进行通信。这里所说的容器间通信方式,指的就是连接多个容器进行通信的Docker网络。

Docker网络包含默认的三个网络(bridge, host, none)与自定义的独立网络。

bridge网络

bridge网络是默认存在的网络,在容器生成时会默认连接该网络,使用的是bridge driver。

在bridge网络中,可以指定同一网络内容器的IP地址进行通信。不过bridge网络中如果不定义DNS的话,就无法使用容器名与其它容器进行通信。也就是说,不指定网络启动的容器,可以使用IP地址进行通信,而不能使用容器名进行通信。

默认状态下网络是非对外公开,使用-p选项可以指定开放到外部的能访问容器的端口。

host网络

host网络是使用host driver的默认网络。

连接的容器将具有与docker host相同的网络设置。比如说,在连接到host网络的容器上执行nginx容器时,监听host主机IP的80端口与监听nginx容器的80端口效果是一样的。

因此,与bridge网络必须在容器启动时使用-p选项设置才能暴露外部端口不同,只要启动了容器,连接到Docker host IP的80端口就相当于连接了那个容器。

none网络

none网络是默认存在的网路,连接该网络的容器将没有任何网络接口。

需要注意的是,在连接none网络时,必须将其他网络全部断开。

独立网络

创建独立网络的话就可以使用容器名称进行容器间的通信了。

使用如下命令创建新的网络(默认的driver是bridge)

$ docker network create 网络名

连接指定网络中的指定容器

$ docker network connect 连接的网络名 容器名

在用户自定义的独立网络中,Docker Daemon内置的DNS会解析容器名称并与IP绑定,因此可以使用容器名与其他容器建立连接。

网络管理命令

用途 命令 其他
查看网络 docker network ls 在主机上执行该命令会看到所有主机上的网络
网络详情 docker network inspect 网络名
创建网络 docker network create 网络名 默认使用bridge driver
连接容器网络 docker network connect 连接的网络名 容器名
中断容器网络 docker network disconnect 网络名 容器名

Docker Compose

Docker Compose是个用于预配置和运行多容器Docker应用的工具。

若要在一个容器启动的同时,还要设置卷的挂载和所属的网络的话,需要使用如下这样的命令

$ docker run -itd —name mount-test —mount source=volume-test, destination=/etc/nginx,readonly nginx

可以看出,必须要在命令后面使用复杂的选项进行设置才行。

这种操作比较麻烦,而且容易出错,无法便捷的共享执行环境。

因此,可以进行自动化配置的Docker Compose油然而生。

在使用Docker构建Web服务的执行环境时,只要使用一个docker-compose.yml文件来定义Web服务,DB服务,缓存服务等的配置,根据这个文件就可以启动与设置所有需要的容器了。

操作流程如下:

  1. 准备Dockerfile,并且准备好在Docker Hub等的镜像
  2. 定义docker-compose.yml
  3. 在yml文件的所在路径下,执行$ docker-compose up

不使用Docker Compose时

必须要一个一个的设置各个容器的选项才能正常启动。

使用Docker Compose时

定义docker-compose.yml后,使用docker-compose up命令就可以一次启动多个容器了。

docker-compose管理命令

用途 命令 其他
查看使用docker-compose启动的容器 docker-compose ps
根据docker-compose.yml配置启动容器 docker-compose up 已启动的容器会重启
删除docker-compose创建的容器与网络 docker-compose down (-v) -v选项表示连同卷也一起删除
在指定的服务容器内执行命令 docker-compose run [容器名] [命令]
停止所有容器 docker-compose stop
启动所有容器 docker-compose start

docker-compose构建应用环境实例

以使用Python的Django构建Web应用的环境为例,介绍具体的流程:

1. 准备镜像

在创建的工作目录下创建Dockerfile。

FROM python:3  # 使用python3的执行环境镜像
ENV PYTHONUNBUFFERED 1 # 设置无缓冲的python标准输出环境变量
RUN mkdir /service  # 创建service目录
WORKDIR /service # 移动到service目录
COPY requirements.txt /service/  # 将requirements.txt(事先创建)放在service目录 
COPY . /service/ # 将构建所需文件全部放在`/service`目录下

2. 创建docker-compose.yml

创建如下的docker-compose.yml文件:

docker-compose.yml

version: '3' # 指定docker-compose的版本
services: # 配置要启动服务的容器
  db: # 启动db服务的容器
   image: postgres # 使用dockerhub上的postgres:latest镜像
  web: # 启动web服务的容器
   build: . # 使用当前目录下的dockerfile创建镜像
   command: python3 manage.py runserver 0.0.0.0:8000  # 指定容器启动时执行的命令
   volumes:
    - .:/app # 将当前路径通过bind mount的方式挂载到/app目录
   posts:
    - "8000:8000" # 映射主机的8000端口到容器的8000端口
   depends_on: # 启动web服务容器前优先启动db服务容器
    - db

3. 执行docker-compose

使用如下命令在启动使用docker-compose.yml定义的web服务容器同时,创建django项目。

$ docker-compose run web django-admin.py startproject test .

使用-d选项可以在detached模式下(在后台)启动一系列容器。

$ docker-compose up -d

共享这个docker-compose.yml文件,就可以在其他机器上通过$ docker-compose up命令来执行一系列容器了。

Docker Machine

Docker Machine是一个可以通过CLI的方式管理(创建、启动、停止、重启)Docker Engine上虚拟机的工具。

在macOS上Docker Machine使用虚拟机软件(Virtual Box)作为驱动来管理Docker Engine上搭载的虚拟机。

如下图所示,可以在PC机内启动多个docker-machine并在其中使用docker的功能,比如执行容器等。

此外,将由docker-machine启动的运行Docker Engine的虚拟机称为Docker主机

Docker Machine管理命令

用途 命令 其他
查看docker主机 docker-machine ls
创建docker主机 docker-machine create —driver virtualbox 所起的主机名
启动docker主机 docker-machine start 主机名
停止docker主机 docker-machine stop 主机名
显示指定docker主机的环境变量 docker-machine env 主机名 通过修改环境变量可以改变所操作的docker主机
激活指定docker主机 eval $(docker-machine env 虚拟主机名) 设置指定Docker主机的环境变量,激活指定的虚拟主机。反之,要解除docker主机的active状态需要先删除所设置的环境变量。
ssh连接docker主机 docker-machine ssh 主机名
查看docker主机IP docker-machine ip 主机名
在docker主机上启动容器 docker run 镜像名 在激活状态下的Docker主机启动容器的话会在Active的Docker主机上执行容器。

云平台上的docker主机

可以通过CLI使用Docker Machine来创建·管理AWS或GCE上搭载Docker Engine的虚拟机。

下面是在AWS EC2上使用Docker Machine搭建Docker主机的流程。

  1. 从AWS的IAM得到一个命名比如为docker-test的访问凭证

    访问ID : -----------------
    访问密钥: ----------------------
    
  2. 将身份验证密钥写入主目录下~/.aws目录中创建的credential文件中

    设置amazonec2 driver,启动指定名称的虚拟机

    $ docker-machine create --driver amazonec2 --amazonec2-open-port 8000 --amazonec2-region ap-northeast-1 虚拟机名
    
  3. 激活虚拟机

    激活AWS上创建虚拟机(docker主机)

    $ docker-machine env 在AWS上启动的虚拟机名
    $ eval $(docker-machine env AWS虚拟机名)
    
  4. 启动容器

    通过镜像启动容器

    $ docker run 镜像名
    
  5. 其他基本操作

    查看虚拟机IP

    $ docker-machine ip Docker主机名
    

    停止虚拟机

    $ docker-machine stop Docker主机名
    

    删除虚拟机

    $ docker-machine rm Docker主机名
    

Docker Swarm

Docker Swarm是用于自动化配置与管理多台Docker主机间或主机内容器间通信的一种方法(容器编排引擎, Container orchestration engine)。

除了Docker Swarm外,容器编排引擎还有Kubernetes和DC/OS等等,这里主要介绍Docker Swarm。

Swarm Mode是Docker Engine的一种操作模式,它具有的功能如下:

  • 集群管理功能:使用网络连接多台机器将其作为一个聚合的系统管理的功能
  • 编排功能: 自动化管理多台机器的功能(负载均衡,容器启动等)

更通俗的讲就是: 1. 用于连接Docker主机之间的网络 2. 在此基础上,提供了管理与操作多台主机与其内部容器的功能。

之前介绍的Docker Network是连接单个Docker主机内容器的网络。

Docker主机间的网络连接

一开始使用Docker Swarm的话,需要做的是使用网络连接多台Docker主机,使其成为一个名为Swarm的聚合系统

具体的来说,Docker主机从属于创建的Swarm,成为Swarm中节点的Docker主机是通过ingress overlay网络相互连接的。

节点的种类分为: 1. worker节点:执行容器 2. manager节点: 执行容器 + 管理其他节点

Swarm管理命令

  • 创建swarm集群

    $ docker-machine ip [Docker主机名]
    $ docker swarm init --advertise-addr 与其他节点通信所用IP(前面命令所显示的IP)
    

    执行在Active状态下的manager节点主机就可以创建Swarm集群了。

  • 查看swarm集群中的节点

    在manager节点上执行

    $ docker node ls
    
  • 添加swarm集群中的worker节点

    在Active状态下的manager节点上执行

    $ docker swarm join-token worker
    

    接着执行提示中的命令

    $ docker swarm join --token [TOKEN] [IP]
    

    激活成为worker节点的Docker主机,并执行

    $ eval $(docker-machine env [成为worker节点的docker主机名])
    
  • 添加swarm集群中的manager节点

    将上面添加worker节点的第一条命令变为

    $ docker swarm join-token manager
    

    其他步骤是一样的

※注意点

Swarm使用的端口号:

  • 集群管理通信:TCP 2377
  • 节点间通信:TCP/UDP 7946
  • overlay网络通信:UDP 4789

需要注意下加入Swarm的Docker主机(节点)必须要暴露这些端口

各种管理功能

可以通过各种各样的管理功能,使用网络将Docker主机像蜂群(Swarm)一样聚合在一起。

一般情况下,Web系统本地环境的服务是不止一台机器的,通常会将多台机器组合起来,将用户通过internet重定向到对应服务。

对于这个多台机器使用Docker machine进行启动与管理,至于Docker主机间的相互连接、将其作为一个整体的管理、在系统的本地环境对外部的重定向进行负载均衡与提供其他多种功能,这些都是Docker Swarm所做的工作。

使用Service与Task跨Docker主机启动容器

首先,使用Docker Swarm的Service与Task功能可以跨Docker主机的启动与管理容器。

Service是用来定义在什么节点上使用什么镜像启动几个容器,Task是用来将Service在容器上分别执行

Service是由manager节点创建的。

举个栗子:

$ docker service create --replicas 3 nginx

在上述命令中,使用manager节点生成了从nginx镜像启动三个容器的Service,那么会产生三个从nginx镜像启动容器的Task。

使用Service时并不需要在每个Docker主机上启动容器,一次启动后由哪个节点启动哪个容器(任务的分配)是自动决定的。这种将通过服务生成的任务分配给节点的功能称为调度(schedule)。

在没有特别指定的情况下,会根据CPU与内存的空闲资源状态进行调度,用户无需去管理docker主机配置等。

节点的可用性

查看Swarm集群中的所有节点:

$ docker node ls

每个节点都具有Availability状态,Availability状态包含Active, Pause, Drain三种。

  • Active表示调度时可以将任务分配给节点的状态
  • Pause表示调度时不能将任务分配给节点,并继续执行当前任务的状态
  • Drain表示调度时不能将任务分配给节点,并中断已有任务的状态,这种状态决定是否可以将任务分配给调度程序

可以通过以下命令修改指定节点的Availability状态:

$ docker node update --availability [修改的状态] [节点名]

global mode 和 replica mode

replica mode之前已经见过了,在创建服务时使用--replicas 3这样的tag来指定任务数。

另一方面,在global mode中必须在每个节点上都执行一个任务,不能指定复制的任务数。

$ docker service create --name web3 --mode global nginx

如上述命令那样,global mode不能指定复制数量,会在所有节点上都执行一个任务。

默认使用的是replica mode

Service管理命令

  • 创建服务

    $ docker service create --name [创建的服务名] --replicas [复制数量] [镜像名]
    $ docker service create --name [创建的服务名] --constraint 'node.role==[manager或worker]' --replicas [复制数量] --detach=true [镜像名]
    

    在命令中使用—constraint可以指定在服务创建和启动时任务分配的节点。

  • 查看所有服务

    $ docker service ls
    
  • 查看服务详情

    $ docker service inspect [服务名]
    
    $ docker service inspect —pretty [服务名]
    

    使用pretty会让输出内容以易读的方式展示

  • 修改已创建服务的设置

    $ docker service update —publish-add 8000:80 —detach=true [服务名]
    
  • 将指定服务滚动到之前的状态

    $ docker service rollback [服务名]
    
  • 显示指定服务内的进程

    $ docker service ps [服务名]
    
  • 删除服务

    $ docker service remove [服务名]
    

Rolling Update

在维护Web系统时,不能跳过的一项工作就是对系统所用软件版本的升级更新。

在维护一个管理多个Docker主机的Swarm系统时,不用去一下子更新所有服务的任务,只需设置更新每个任务的延迟时间即可,会逐个更新对应任务的容器,这就是滚动更新的功能。

这个功能会先排除执行中的容器,当执行中的容器接收到请求时,会按顺序更新其他容器。

下面以更新redis为例。

在创建服务时使用update-delay设置更新的时间间隔:

$ docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6

除以之外,也有可以设置更新任务最大数量的参数选项。

更新时使用如下命令就可以开始滚动更新了:

$ docker service update —image redis:3.0.7 redis 

Service scale / Resource management / Auto Scaling

当Swarm系统的整体负荷较大时,可以通过伸缩启动服务的容器数量来缓解。

修改指定服务的复制数量:

$ docker service scale [服务名]=[复制数量]

当然也可以设置自动伸缩(auto scaling)功能。

当机器本身资源不足的情况下,可以启动额外的机器(AWS实例)来解决。

Auto Healing

当Swarm中的节点出现由于大量请求导致负载过大等问题而down机时,该机器所启动的容器可以由其他机器上启动的容器替代,这就是自动修复(Auto Healing)功能。

对于manager节点down掉的情况,可以准备多个manager节点,未雨绸缪。

使用Docker compose创建Service

服务的创建可以使用$ docker service create命令,也可以通过docker-compose.yml文件中描述的定义来自动创建多个服务。

docker-compose.yml的文件内容如下:

version: '3.4'

services: # 记录要执行的容器
  wordpress: # wordpress容器
   image: wordpress # 使用wordpress:latest镜像
   ports:
    - 8080:80 # 映射主机8080端口到容器的80端口
   environment:
    WORDPRESS_DB_PASSWORD: ----- # 与mysql容器的密码一致
   deploy: # 在这里设置Docker Swarm的Service
    replicas: 2 # 复制数量
    placement:
      constraints: 
       - node.role == worker # 只在worker节点上执行
   depends_on:
     - mysql # 启动依赖于mysql容器

  mysql: # mysql容器
   image: mysql:5.7 # 指定镜像版本
   environment:
    MYSQL_ROOT_PASSWORD: ----- # 设置密码
   volumes:
    - mysql_vol:/var/lib/mysql # 生成名为mysql_vol的卷,挂载到容器的指定目录上
   deploy: # 在这里设置Docker Swarm的Service
    replicas: 1
    placement:
     constraints:
      - node.role == manager # 在manager节点上执行

volumes:
  mysql_vol: #定义卷

之后使用下面的$ docker stack deploy命令,来根据docker-compose.yml文件生成Swarm中的服务。stack的名称会作为所生成服务名的前缀。

$ docker stack deploy --compose-file docker-compose.yml(指定的compose文件) [生成的stack名]

stack是构成特定环境中的service集合, 它是自动部署多个相互关联的服务的简便方法,而无需单独定义每个服务。

stack的管理命令

用途 命令
创建stack docker stack deploy --compose-file [compose文件名] [生成的stack名]
查看所有stack docker stack ls
删除stack docker stack remove stack名

最终效果图

原文信息