docker swarm 部署服务到集群

默北 容器docker swarm 部署服务到集群已关闭评论23,0813字数 8920阅读29分44秒阅读模式

在管理节点上执行docker service create命令将应用部署到集群。集群管理者将服务描述视为 应用程序所需的状态。内置的集群编排器和调度者将应用程序部署到集群并维持所需状态。

创建服务

$ docker service create <IMAGE>

集群协调者调度一个任务到可用节点上。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

$ docker service create --name my_web nginx

anixjtol6wdfn6yylbkrbj2nx

创建一个服务名为my_web。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

列出服务:文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

$ docker service ls

ID            NAME    REPLICAS  IMAGE  COMMAND
anixjtol6wdf  my_web  1/1       nginx

为了使web服务对外可用,需要发布集群监听web请求的端口。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

可以在镜像后面添加一个在容器内执行的命令。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

$ docker service create <IMAGE> <COMMAND>
$ docker service create --name helloworld alpine ping docker.com

9uk4639qpg7npwf3fn2aasksr

配置服务

在创建服务时,可以指定许多不同的配置选项和约束。可以通过docker service create --help查看。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

创建的服务并不总是立即运行。如果服务镜像不可用或者节点无法满足你为服务配置的要求或是其他原因,服务可能处于待处理状态。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

配置运行时环境

为容器配置以下运行环境选项:文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

  • 使用--env配置环境变量
  • 使用--workdir配置容器工作目录
  • 使用--user配置用户名或者uid
$ docker service create --name helloworld \
  --env MYVAR=myvalue \
  --workdir /tmp \
  --user my_user \
  alpine ping docker.com

9uk4639qpg7npwf3fn2aasksr

配置服务网络选项

swarm模式允许通过以下方式网络服务:文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

  • 使用ingress网络将端口发布到集群外部或者直连集群的每个节点
  • 使用overlay网络来连接集群中的服务和任务

发布端口

创建集群服务时,可以通过以下两种方式将该服务端口发布到集群外的主机:文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

  • 依靠路由网格 (https://docs.docker.com/engine/swarm/services/#publish-a services-ports-using-the-routing-mesh)当发布服务端口时,就去集群都会在每个节点上的目标端口上访问该服务,不管该节点上是否有运行该服务的任务。这不太复杂,是许多类型的服务的正确选择。
  • (https://docs.docker.com/engine/swarm/services/#publish-a-services-ports-directly-on-the-swarm-node)直接在该服务运行的集群节点上发布服务任务的端口。docker 1.13以及更高版本提供此功能。这绕过路由网格并提供最大的灵活性,包括开发自己的路由框架能力。但是,需要负责跟踪每个任务正在运行的位置,并将请求路由到该任务以及垮节点的负载均衡。

PUBLISH A SERVICE’S PORTS USING THE ROUTING MESH 要将服务端口发布到集群外部使用--publish :。集群使每个节点访问目标端口都可访问。如果外部主机连接到任何群集节点上的该端口,则路由网络将其路由到任务。外部主机不需要知道服务任务的IP地址或内部使用的端口与服务进行交互。当用户或进程连接到服务时,任何运行服务任务的工作节点都可能会响应。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

假设有10个节点的集群,在10个节点上部署一个运行三个任务的nginx服务:文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

$ docker service create --name my_web \
                        --replicas 3 \
                        --publish 8080:80 \
                        nginx

三个任务最多可运行在三个节点上。您不需要知道哪些节点正在运行该任务,连接到10个节点的任何一个的8080端口都将连接到三个nginx任务中的任何一个。可以使用curl测试:文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

$ curl localhost:8080

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...truncated...
</html>

PUBLISH A SERVICE’S PORTS DIRECTLY ON THE SWARM NODE 如果您需要根据应用程序状态进行路由决策,或者需要完全控制将请求路由到服务任务的过程,则使用路由网格可能不是你应用程序的正确选择。要直接在运行的节点上发布服务的端口,请使用--publish标志mode=host选项。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

注意:如果您使用mode = host直接在群集节点上发布服务的端口,并且还设置published = ,则会创建一个隐式限制,您只能在给定的群组节点上为该服务运行一个任务。另外,如果您使用mode = host,并且在docker服务创建时不使用--mode = global标志,那么很难知道哪些节点正在运行服务,以便将工作路由到它们。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

实例: 在每个集群节点上运行cadvisor监控服务文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

Google cAdvisor是监控linux主机上运行容器的工具。通常,cAdvisor作为独立容器运行,因为它被设计为监视给定的Docker Engine实例。如果您使用路由网格运行cAdvisor作为服务,则连接到任何群集节点上的cAdvisor端口将显示(有效地)运行该服务的随机群组节点的统计信息。这可能不是你想要的。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

以下示例将cAdvisor作为服务在群集中的每个节点上运行,并在每个群集节点上公开cAdvisor端口。连接到给定节点上的cAdvisor端口将显示该节点的统计信息。实际上,这类似于在每个节点上运行单个独立的cAdvisor容器,但不需要手动管理这些容器。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

$ docker service create \
  --mode global \
  --mount type=bind,source=/,destination=/rootfs,ro=1 \
  --mount type=bind,source=/var/run,destination=/var/run \
  --mount type=bind,source=/sys,destination=/sys,ro=1 \
  --mount type=bind,source=/var/lib/docker/,destination=/var/lib/docker,ro=1 \
  --publish mode=host,target=8080,published=8080 \
  --name=cadvisor \
  google/cadvisor:latest

如果将一个节点添加到集群中,则会启动一个cadvisor任务。在集群中无法再绑定另一个服务或者容器到8080端口。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

添加overlay网络

使用overlay网络来连接集群内的一个或多个服务。文章源自运维生存时间-https://www.ttlsa.com/docker/docker-swarm-deploy-services/

在管理节点上创建一个overlay网络。

$ docker network create --driver overlay my-network

etjpu59cykrptrgw0z0hk5snf

在集群模式下创建overlay网络后,所有的管理节点都可以访问网络。

当你创建服务并传递--network标志以将服务附加到overlay网络。

$ docker service create \
  --replicas 3 \
  --network my-network \
  --name my-web \
  nginx

716thylsndqma81j6kkkb5aus

集群将my-network扩展到运行服务的每个节点。

配置更新行为

创建服务时,可以指定滚动更新行为,以便在运行docker服务更新时,集群应如何应用更新服务。

回滚到之前的版本

如果服务的更新版本无法正常运行,可以使用docker service update的--rollback标志回滚到先前版本的服务。 其它选项可以与--rollback结合使用,如--update-delay 0s 执行回滚不在任务间延迟。

$ docker service update \
  --rollback \
  --update-delay 0s
  my_web

my_web

配置挂载

可以为集群服务创建两种类型的挂载:volume挂载和bind挂载。 在创建服务时通过--mount标志指定。如果不指定类型默认是volume挂载。

  • 卷是存储,在任务容器删除后仍保持活动。挂载卷的首选方法是利用现有卷:
$ docker service create \
  --mount src=<VOLUME-NAME>,dst=<CONTAINER-PATH> \
  --name myservice \
  <IMAGE>

如果创建卷,参见volume create CLI(https://docs.docker.com/engine/reference/commandline/volume_create/)

以下方法在调度任务时,在启动容器之前,在部署时创建卷:

$ docker service create \
  --mount type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=<DRIVER>,volume-opt=<KEY0>=<VALUE0>,volume-opt=<KEY1>=<VALUE1>
  --name myservice \
  <IMAGE>

重要提示: 如果你的卷驱动接受以逗号分隔列表选项,则必须从外部csv解析器中转义该值。请使用双引号包围它,并使用单引号围住整个挂载参数。

如,本地驱动接受挂载选项作为o参数的逗号分隔列表。此示例显示正确转义列表。

*&####&*_14_*&####&*
  • bind挂载是文件系统路径,来自调度器部署任务容器的主机。Docker挂载路径到容器。在集群初始化容器任务之前,文件系统路径必须存在。

以下显示bind挂载语法:

# Mount a read-write bind
$ docker service create \
  --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH> \
  --name myservice \
  <IMAGE>

# Mount a read-only bind
$ docker service create \
  --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH>,readonly \
  --name myservice \
  <IMAGE>

重要提示:bind挂载会很有用,但也很危险的。在大多数情况下,构建应用程序,从主机挂载路径是不必要的。主要是以下风险:

如果将主机路径挂载到服务的容器中,则该路径必须存在于每个服务器上。Docker群组模式调度程序可以在满足资源可用性要求的任何计算机上安排容器,并满足您指定的所有约束。

如果他们变得不健康或者无法访问,docker swarm模式调度器会在任何时候重新安排运行的服务容器。

主机bind挂载完全不可移植性。当使用bind挂载时,不能保证应用程序在开发环境与生产环境中的运行方式相同。

将服务添加到overlay网络

Docker Engine swarm模式支持overlay网络,因此可以启用容器到容器网络。在使用swarm模式时,不需要外部kv存储。swarm模式overlay网络包含以下特点:

  • 可以将多个服务添加到同一个网络。
  • 默认情况下,在集群中为每个服务的服务发现分配一个vip和DNS条目,使容器的服务名称在同一网络可用。
  • 可以配置服务使用DNS轮训而不是VIP。

未了在集群中使用overlay网络,在启用集群模式之前,集群节点间需要开放下面端口:

  • 7946 TCP/UDP 用于容器网络发现
  • 4789 UDP 用于容器overlay网络

创建集群overlay网络

从管理节点运行docker network create来创建overlay网络。如:

$ docker network create \
  --driver overlay \
  --subnet 10.0.9.0/24 \
  --opt encrypted \
  my-network

273d53261bcdfda5f198587974dae3827e947ccd7e74a41bf1f482ad17fa0d33

--subnet指定overlay网络使用的子网。

在将服务添加到网络之前,overlay网络只扩展到管理节点。 查看网络:

$ docker network ls

NETWORK ID          NAME        DRIVER   SCOPE
f9145f09b38b        bridge      bridge   local
..snip..
273d53261bcd        my-network  overlay  swarm

swarm SCOPE 表示网络可用于部署到集群的服务。在创建服务添加到网络后,集群只将网络扩展到服务任务的工作节点上。对于没有运行添加到网络的服务的工作节点,docker network ls是不会显示该网络的。

添加服务到overlay网络

在创建服务时,通过指定--network将服务添加到overlay网络。如:

$ docker service create \
  --replicas 3 \
  --name my-web \
  --network my-network \
  nginx

注意: 必须先创建网络,然后才能将服务添加到网络。

在overlay网络,服务任务的容器可以彼此连接。网络将扩展到运行服务任务的所有节点。

在管理节点上,执行docker service ps 查看服务任务运行在哪些节点上:

$ docker service ps my-web

NAME                                IMAGE  NODE   DESIRED STATE  CURRENT STATE               ERROR
my-web.1.63s86gf6a0ms34mvboniev7bs  nginx  node1  Running        Running 58 seconds ago
my-web.2.6b3q2qbjveo4zauc6xig7au10  nginx  node2  Running        Running 58 seconds ago
my-web.3.66u2hcrz0miqpc8h0y0f3v7aw  nginx  node3  Running        Running about a minute ago

docker

可以在运行该服务任务的任何节点上,运行docker network inspect 查看网络信息。

网络信息包含节点上添加到网络上的容器列表。如:

$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "273d53261bcdfda5f198587974dae3827e947ccd7e74a41bf1f482ad17fa0d33",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.9.0/24",
                    "Gateway": "10.0.9.1"
                }
            ]
        },
        "Internal": false,
        "Containers": {
            "404d1dec939a021678132a35259c3604b9657649437e59060621a17edae7a819": {
                "Name": "my-web.1.63s86gf6a0ms34mvboniev7bs",
                "EndpointID": "3c9588d04db9bc2bf8749cb079689a3072c44c68e544944cbea8e4bc20eb7de7",
                "MacAddress": "02:42:0a:00:09:03",
                "IPv4Address": "10.0.9.3/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "257"
        },
        "Labels": {}
    }
]

在上面的示例中,在node1节点上my-web服务添加到my-network网络的容器是my-web.1.63s86gf6a0ms34mvboniev7bs。

使用集群服务发现

默认情况下,当创建一个服务连接到网络时,集群为该服务分配一个vip,vip基于服务名称映射到DNS别名。网络上的容器服务通过gossip共享DNS映射,因此网络上的任何容器都可以通过其服务名称访问该服务。

在同一overlay网络,你不需要公开特定的服务的端口来使服务可用于其它服务。集群内部负载均衡会自动的将服务的vip请求分发到活动的任务上。

可以通过检索服务来查看vip,如:

$ docker service inspect \
  --format='{{json .Endpoint.VirtualIPs}}' \
  my-web

[{"NetworkID":"7m2rjx0a97n88wzr4nu8772r3" "Addr":"10.0.0.2/24"}]

以下示例显示如果在nginx服务相同的网络中添加busybox服务,并且busybox服务可以使用DNS名称my-web来访问nginx。

  • 在管理节点,部署my-web相同网络的busybox服务:
$ docker service create \
  --name my-busybox \
  --network my-network \
  busybox \
  sleep 3000
  • 查找运行my-busybox的节点:
$ docker service ps my-busybox

NAME                                    IMAGE    NODE   DESIRED STATE  CURRENT STATE          ERROR
my-busybox.1.1dok2cmx2mln5hbqve8ilnair  busybox  node1  Running        Running 5 seconds ago
  • 在运行busybox任务的节点上,打开busybox容器的交互式shell
$ docker exec -it my-busybox.1.1dok2cmx2mln5hbqve8ilnair /bin/sh

可以将容器名称推定为 + 。或者,可以在任务运行的节点上执行docker ps。

  • 在busybox容器内,查询DNS来查看my-web服务的vip地址:
$ nslookup my-web

Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      my-web
Address 1: 10.0.9.2 ip-10-0-9-2.us-west-2.compute.internal
  • 在busybox容器内,使用特殊查询 查询DNS,来查找my-web服务的所有容器的IP地址:
$ nslookup tasks.my-web

Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      tasks.my-web
Address 1: 10.0.9.4 my-web.2.6b3q2qbjveo4zauc6xig7au10.my-network
Address 2: 10.0.9.3 my-web.1.63s86gf6a0ms34mvboniev7bs.my-network
Address 3: 10.0.9.5 my-web.3.66u2hcrz0miqpc8h0y0f3v7aw.my-network
  • 在busybox容器内,执行wget访问在my-web服务中运行的nginx web服务器:
$ wget -O- my-web

Connecting to my-web (10.0.9.2:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...snip...

集群内部负载均衡自动将HTTP请求路由到活动任务的服务的VIP上。使用轮询将后续请求分发到其它任务。

服务使用DNS轮询

在创建服务时,可以设置--endpoint-mode dnsrr来将服务配置为直接使用DNS轮询而不使用VIP。 在想使用自己的负载均衡情况下,DNS轮询是很有用的。

以下示例显示具有dnsrr endpoint 模式的服务:

$ docker service create \
  --replicas 3 \
  --name my-dnsrr-service \
  --network my-network \
  --endpoint-mode dnsrr \
  nginx

当查询服务名的DNS时,DNS服务器将返回所有任务容器的IP地址:

$ nslookup my-dnsrr-service
Server:    127.0.0.11
Address 1: 127.0.0.11

Name:      my-dnsrr
Address 1: 10.0.9.8 my-dnsrr-service.1.bd3a67p61by5dfdkyk7kog7pr.my-network
Address 2: 10.0.9.10 my-dnsrr-service.3.0sb1jxr99bywbvzac8xyw73b1.my-network
Address 3: 10.0.9.9 my-dnsrr-service.2.am6fx47p3bropyy2dy4f8hofb.my-network

确认VIP连接

建议使用dig、nslookup或者其它DNS查询工具来测试通过DNS访问服务名称。因为vip是一个逻辑ip,ping不是确定vip连接的正确工具。

weinxin
我的微信
微信公众号
扫一扫关注运维生存时间公众号,获取最新技术文章~
默北
  • 本文由 发表于 21/05/2017 01:01:12
  • 转载请务必保留本文链接:https://www.ttlsa.com/docker/docker-swarm-deploy-services/