Docker 的部署方式

在使用 docker run 命令启动 Docker 容器时,若是须要进行端口映射、目录挂载、网络信息等配置,整条命令将变得很是长,而且因为是一条 shell 命令,修改和复用也不方便。咱们在大规模部署容器的时候不可能手动去输入众多的命令,因此须要一些工具来辅助咱们实现 docker run 命令的编写,同时实现简单快捷的大规模部署。node

docker-compose 部署

docker-compose 是一个读取特定格式的 yaml 文件并将其转换为 docker run 命令的工具,它有效的规避了上述的问题,而且它也是 docker swarmdocker stack 等技术的基石。docker-compose 须要一份 yaml 格式的脚本,若是在使用命令时不想指定具体的脚本名称,那就须要将脚本命名为 docker-compose.yml。下面是一份启动 MySQL 容器的 docker-compose 脚本。mysql

version: "3"
services:
 mysql:
 container_name: login_db
 image: mysql:5.7
 ports:
 - "3306:3306"
 environment:
 - MYSQL_ROOT_PASSWORD=123456
 volumes:
 - "mysql-data:/var/lib/mysql"
 networks:
 - my-bridge

volumes:
 mysql-data:

networks:
 my-bridge:
 driver: bridge
复制代码

全局配置

version 指定的是 docker-compose 的版本,因为 v2v3 在语法上存在一些不一样,因此须要明确告诉 docker-compose 当前脚本所使用的语法版本是多少。web

services 表示服务定义。一份脚本中能够定义多个服务,docker-compose 会一并启动。算法

volumes 下的名称列表就是服务启动时要建立的全部数据卷的名称,只有先建立了数据卷才能在下面的服务定义中的 volumes 配置中进行挂载使用。注意区分全局的 volumes 和服务定义下的 volumes 配置sql

networks 下配置的是服务启动时要建立的网络及其驱动类型。这里建立了一个驱动为 bridge、名称为 my-bridge 的桥接网络。只有先建立了网络才能在下面的服务定义中的 networks 配置中进行注册使用。注意区分全局的 networks 和服务定义下的 networks 配置docker

服务配置

mysql 表示定义一个名叫 mysql 的服务。shell

container_name 表示服务要启动的容器的名称,若是这个服务要动态扩展多个容器,则不能够指定容器名称,不然因为容器名称冲突将致使没法扩展。网络

image 表示服务要使用的镜像。负载均衡

ports 表示容器与宿主机的端口映射关系。凡是指定了端口映射关系的服务都不能动态扩展容器数量,由于会致使端口冲突。wordpress

environment 表示要设置到容器中的环境变量。这里设置的环境变量将被放置到容器的全局环境变量中,你能够在容器中读取并操做。

volumes 表示要挂载的目录或者数据卷。这里和 docker run 命令中的 -v 参数做用是一致的,便可以挂载数据卷,也能够挂载目录。这里使用到的数据卷必须在全局配置中先指定,若是是挂载目录则须要先手动建立。

networks 表示这个服务要注册到哪些网络上去,这里使用到的网络必须在全局配置中先指定。注册到同一个网络上的容器之间可使用服务名进行通讯。

使用 docker-compose

经过 docker-compose 能够对服务进行启动、中止、删除、扩容等操做。docker-compose 的操做必须依赖脚本,若是脚本存在于当前目录下且名为 docker-compose.yml 则不须要额外指定,不然须要使用 -f 参数进行指定。

启动服务

启动服务使用命令 docker-compose -f /path/to/script.yml up -dup 表示启动服务,-d 表示后台运行。这个命令会读取脚本文件并首先建立申明的数据卷和网络,而后再启动服务。

中止服务

中止服务使用命令 docker-compose -f /path/to/script.yml stop。这个命令会将脚本中的全部服务的全部容器都中止,但不会删除容器。

删除服务

删除服务使用命令 docker-compose -f /path/to/script.yml rm。这个命令会要求二次确认删除,而且没法删除未中止的服务。删除服务时不会关联删除服务启动时建立的网络和数据卷。

强行删除服务

强行删除服务使用命令 docker-compose -f /path/to/script.yml down。这个命令会将全部服务的全部容器都中止并删除,同时删除服务启动时建立的网络,但不会删除数据卷

扩容服务

随着业务量的上升,咱们可能须要将服务从一个容器扩展到多个容器以提升服务能力,这时候就可使用 docker-compose 来直接扩容服务。

docker-compose -f /path/to/script.yml up --scale orderService=3 -d
复制代码

这个命令表示将名为 orderService 的服务扩容至三个容器并后台启动。若是本来的容器数量大于 3 个,那么这个命令就是缩减容器数量操做。须要注意的是,支持服务扩容的要求是很是苛刻的,须要知足如下三点要求:

  1. 不可以指定 container_name,即容器名;
  2. 不可以指定端口映射关系;
  3. 不可以指定挂载数据卷或目录。

若是在脚本中指定了要挂在的目录或者数据卷,那么扩容后多个容器将共用一个数据卷和目录,这样就会致使数据出现混乱。解决方法是不指定任何数据卷和目录进行挂载,由 Docker 自行建立随机名称的数据卷。

Docker Swarm 部署

上文讲到的 docker-compose 部署方式还停留在单机部署上,但在实际生产环境中不一样系统的 Docker 容器都是垮宿主机部署,这时候就须要将这些宿主机造成集群统一管理,Docker Swarm 就是 Docker 原生提供的一种集群管理模式。除了 Docker Swarm 外,还有 Mesos、Kubernates 等不一样的集群管理模式。

在 Docker Swarm 集群模式下,当多个宿主机造成集群后,咱们就能够在管理节点(Manager Node)上经过管理命令将不一样服务的容器部署到集群内不一样的宿主机上,同一个服务的多个容器也能够分布到集群内不一样的宿主机上以实现负载均衡。

建立 Swarm 集群

建立集群以前须要先规划好集群内的节点角色,选择其中一台宿主机做为管理节点开始建立集群,执行以下命令:

docker swarm init --advertise-addr=本机IP
复制代码

--advertise-addr 用于指定管理节点所在宿主机的 eth0 网卡的 IP 地址,若是存在多个网卡,这个参数必定要指定,不然可能形成管理节点和工做节点之间没法通讯。命令执行完毕后会输出以下的提示信息:

Swarm initialized: current node (gmdscjfdlubanwl7i75z5cc85) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-6djatxtetutac68xd1u8v1icnyv6t0pcplhaph2irqqxqo1m2b-8w6lq2kpw6j1chqpu4vlf2cx3 \
    管理节点IP:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
复制代码

根据输出提示,咱们须要在其余宿主机上执行 docker swarm join … 操做以使其加入到集群做为工做节点。集群节点加入完成后在管理节点执行 docker node ls 能够看到全部的节点状态信息。

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
gmdscjfdlubanwl7i75z5cc85 *  docker-1  Ready   Active        Leader
xna7a0h6a0xhct95kh7v6p9pl    docker-3  Ready   Active
复制代码

使用标签标记节点

Docker Swarm 会根据本身的负载均衡算法将服务分散部署到不一样的集群节点上,但有时候咱们也但愿可以指定服务部署到指定的集群节点上,这时候就须要经过标签来指定具体的节点了。下面的名称尝试为 HOSTNAME 是 docker-3 的节点增长一个标签:

docker node update --label-add mytag=db xna7a0h6a0xhct95kh7v6p9pl
复制代码

这条命令为 ID 为 xna7a0h6a0xhct95kh7v6p9pl 的节点增长了一个标签,标签名称为 mytag,标签值为 db。标签的使用会在下文 Docker Stack 部署服务时讲解。

在 Swarm 集群中部署服务

有了集群就能够进行服务部署,下面尝试在集群中部署一个 MySQL 服务,在管理节点执行命令以下:

docker service create --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
复制代码

命令的参数和 docker run 命令的参数是基本一致的,只是命令换成了 docker service create。命令 docker service ls 用于查看全部已部署的服务;命令 docker service ps 服务名称 用于查看该服务容器的部署节点和状态:

ID            NAME     IMAGE      NODE      ESIRED STATE  CURRENT STATE          ERROR  PORTS
0m5erytxi6sa  mysql.1  mysql:5.7  docker-1  Running        Running 3 minutes ago
复制代码

上面的信息表示 MySQL 服务下共启动了 1 个容器,其部署在名为 docker-1 的节点上,容器ID 为 0m5erytxi6sa,当前状态是正在运行,而且与指望的状态一致。

扩容服务

与使用 docker-compose 部署服务相似,docker service 命令也可让指定的服务进行容量增减,下面的命令尝试将 MySQL 服务扩容至 3 个容器:

docker service scale mysql=3
复制代码

再次执行 docker service ps mysql 查看容器部署状况:

ID            NAME     IMAGE      NODE      DESIRED STATE  CURRENT STATE           ERROR  PORTS
0m5erytxi6sa  mysql.1  mysql:5.7  docker-1  Running        Running 13 minutes ago
idgvqymekwam  mysql.2  mysql:5.7  docker-3  Running        Running 3 minutes ago
fldlrega7p40  mysql.3  mysql:5.7  docker-3  Running        Running 3 minutes ago
复制代码

能够看到容器数量已经扩大至 3 个,其中两个部署在 docker-3 节点上。

更新服务

在服务使用多容器部署的状况下,可使用服务更新来发布新的版本或调整服务部署参数,这样能够避免先删除服务再启动服务形成的服务中断。以下命令尝试使用新版本镜像来更新服务:

docker service update --image mysql:5.8 mysql
复制代码

这个命令表示对名为 mysql 的服务使用使用 mysql:5.8 版本的镜像进行更新。须要注意的是,若是服务只部署了一个容器,那么更新过程当中,对外服务是确定会中断的。

删除服务

使用命令 docker service rm 服务名称 能够将已部署的服务删除。删除服务时服务下全部的容器都会被删除且不可恢复。

使用 Docker Stack 管理多个服务

Stack

在 Swarm 模式下,使用 docker service create 命令能够建立服务进行部署,当多个服务组合到一块儿时,咱们就把它们看做是一个 Stack。简单来讲,**Stack 就是多个 Service 的组合。在 Swarm 模式下可使用 Docker Stack 能够实现服务的批量部署。

Docker Stack 脚本

Docker Stack 并非新的技术点,它一样是使用 docker-compose 脚原本管理服务建立脚本,而且语法没有任何区别。下面的示例展现了怎么使用 Docker Stack 来部署一个 WordPress 和 MySQL 服务,其中 WordPress 服务须要引用 MySQL 服务进行数据读写:

version: '3'
services:
 wordpress:
 image: wordpress
 ports:
 - 80:80
 environment:
 - WORDPRESS_DB_HOST=mysql
 - WORDPRESS_DB_PASSWORD=123456
 networks:
 - my-network
 depends_on:
 - mysql
 deploy:
 mode: replicated
 replicas: 3
 restart_policy:
 condition: on-failure
 delay: 5s
 max_attempts: 3
 update_config:
 parallelism: 1
 delay: 10s

 mysql:
 image: mysql:5.7
 environment:
 - MYSQL_ROOT_PASSWORD=123456
 - MYSQL_DATABASE=wordpress
 volumes:
 - mysql-data:/var/lib/mysql
 networks:
 - my-network
 deploy:
 mode: global
 placement:
 constraints: [node.labels.mytag == db]

volumes:
 mysql-data:

networks:
 my-network:
 driver: overlay
复制代码

wordpress 服务的 environment 中配置的环境变量 WORDPRESS_DB_HOST 的值是 mysql,这个 mysql 表示的是下面的 mysql 服务。因为 wordpress 服务和 mysql 服务都注册到了 my-network 网络上,因此他们彼此能够经过服务名称进行通讯,而不须要指定容器 IP。

depends_on 用于配置依赖关系。这里的配置表示 wordpress 服务必须等 mysql 服务启动后才开始启动,经过这个指令能够组织服务的启动顺序。

deploy 指令下配置的是部署相关的策略信息。

  • mode 表示部署模式是多副本部署(replicated)仍是全局单节点部署(global)。
  • replicas 表示多副本部署时须要多少个副本,即该服务须要启动多少个容器。
  • restart_policy 用于指定服务下容器的重启策略,重启触发条件由 condition 定义,delay 表示每次重启的间隔时间,max_attempts 表示最大尝试重启次数。
  • update_config 用于指定服务更新的策略。parallelism 表示每次更新多少个容器,delay 表示两次更新的时间间隔。

placement 用于配置节点的部署位置。constraints 用于指定部署位置的判断条件,上文中的 node.labels.mytag == db 表示将 mysql 服务部署到标签 mytag 的值为 db 的节点上。

部署使用的网络 my-network 的驱动是 overlay,这是一种跨主机通讯的网络,在 Swarm 模式下为了让分布在集群内不一样节点上的容器可以互相通讯,他们就都必须注册到 overlay 驱动的网络上。咱们也能够预先手动建立一个 overlay 驱动的网络:

docker network create -d overlay my-network
复制代码

这样咱们在 docker-compose 脚本中声明网络时就须要进行以下变动:

networks:
 my-network:
	external: true
复制代码

external: true 这里的 my-network 网络引用的是预先建立好的同名网络。

部署 Stack

编写好 docker-compose 脚本后就可使用 docker stack 命令进行服务部署了,假设上文的脚本命名为 myweb.yml, 下面的命令使用上文的脚本进行服务部署:

docker stack deploy -c myweb.yml myweb
复制代码

-c 参数是 --compose-file 的缩写,用于指定部署脚本的位置,最后的 myweb 是这个 Stack 的名字,能够任意设置,一般建议和脚本名称保持一致,便于管理。命令 docker stack ls 能够查看部署的全部 Stack;命令 docker stack ps Stack名称 能够查看该 Stack 下全部服务的容器部署状况;命令 docker stack services Stack 名称 能够查看该 Stack 下全部服务的部署状况,如部署模式、副本数量等信息。

删除 Stack

命令 docker stack rm Stack名称 能够删除一个指定的 Stack。这个命令会删除该 Stack 下全部的服务及其全部的容器,没法恢复。

规划 Stack

上文提到删除 Stack 时,其下全部服务都会被删除,那么规划 Stack 就变得尤其重要。若是在规划时将全部服务都放到一个 Stack 下,那么当须要从新部署某个服务时就不得不将其余全部服务也所有从新部署。一般建议将高耦合的服务放到一个 Stack中,每一个中间件集群做为一个 Stack,这样能够避免从新部署时发生雪崩。总之,规划 Stack 与编写代码相似,都要减小相互的耦合,尽可能避免出现雪崩。

相关文章
相关标签/搜索