资讯专栏INFORMATION COLUMN

Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包

TigerChain / 1622人阅读

摘要:与分布式应用捆绑包分布式应用捆绑包,或者简称,是一种多服务可分发镜像格式。而当中新推出的分布式应用捆绑包,或者简称,则属于一种新的概念,其专门面向多套容器的迁移需求。利用创建一个分布式应用捆绑包添加了一条新的命令。

在本文中数人云将带大家了解如何利用Docker Compose创建一套分布式应用捆绑包,并将其作为Docker Stack在Docker Swarm Mode中进行部署。

Docker 1.12的首套候选发行版于三周之前公布,而近期又有更多新功能计划被添加至该版本当中。

下面首先来看各项新的功能特性:

内置编排机制:通常来讲,应用利用一个Docker Compose文件进行定义。此定义由多个被部署在不同主机上的容器共同构成。这种作法除了能够避免单点故障(简称SPOF)之外,也能够让应用具备弹性。目前包括Docker Swarm、Kubernetes以及Mesos在内的多种编排框架都允许大家对此类应用进行编排。不过现在我们又有了新的选择——Docker Engine如今迎来了内置编排机制。更多细节内容将在后文中进行说明。

Service:现在大家可以利用docker service create 命令轻松创建一项复制且分布式的负载均衡服务。该应用可实现“理想状态”,例如运行三套Couchbase容器,并具备自我修复能力。Docker引擎能够确保必要容器数量始终运行于集群当中。如果某容器发生故障,那么另一容器将旋即启动。如果某台节点发生故障,则该节点上的容器会在另一节点上启动。稍后我们将详细说明其作用。

零配置安全性: Docker 1.12采用相互验证TLS,能够对swarm当中各节点间的通信内容进行验证、授权与加密。更多详尽内容将在后文中进行讨论。
Docker Stack与分布式应用捆绑包:分布式应用捆绑包,或者简称DAB,是一种多服务可分发镜像格式。在后文中我们会进一步讨论。

截至目前,大家已经可以选定一个Dockerfile,并利用docker build命令由此创建镜像。使用docker run命令则可启动容器。这条命令亦能够轻松同时启动多套容器。另外,大家也可以使用Docker Compose文件并利用docker-compose scale命令对容器进行规模扩展。

镜像属于单一容器的一种便携式格式。而Docker 1.12当中新推出的分布式应用捆绑包,或者简称DAB,则属于一种新的概念,其专门面向多套容器的迁移需求。每个捆绑包都可作为stack在运行时中进行部署。

感兴趣的朋友可以前往 docker.com/dab 了解更多与DAB相关的内容。为了简单起见,在这里我们利用类比来进行说明:

Dockerfile -> 镜像 -> 容器
Docker Compose -> 分布式应用捆绑包 -> Docker Stack

下面我们使用一个Docker Compose文件来创建DAB,并将其作为Docker Stack加以部署。

需要强调的是,这项实验性功能仅存在于1.12-RC2版本当中。

利用Docker Compose创建一个分布式应用捆绑包

Docker Compose CLI添加了一条新的bundle命令。下面来看其具体说明:

docker-compose bundle --help
Generate a Docker bundle from the Compose file.
Local images will be pushed to a Docker registry, and remote images
will be pulled to fetch an image digest.
Usage: bundle [options]
Options:
   -o, --output PATH          Path to write the bundle file to.
                              Defaults to ".dsb". 

现在,让我们选取一条Docker Compose定义并以此为基础创建DAB。以下为我们的Docker Compose定义内容:

version: "2"
services:
 db:
   container_name: "db"
   image: arungupta/oreilly-couchbase:latest
   ports:
     -8091:8091
     -8092:8092 
     -8093:8093 
     -11210:11210
 web:
   image: arungupta/oreilly-wildfly:latest
   depends_on:
     -db
   environment:
     -COUCHBASE_URI=db
   ports:
     -8080:8080

此Compose文件会启动WildFly与Couchbase服务器。其中WildFly服务器中已经预部署了一款Java EE应用,且接入Couchbase服务器并允许利用REST API执行CRUD操作。该文件的源代码来自:github.com/arun-gupta/oreilly-docker-book/blob/master/hello-javaee/docker-compose.yml。 利用它生成一个应用捆绑包:

docker-compose bundle
WARNING: Unsupported key "depends_on" in services.web - ignoring
WARNING: Unsupported key "container_name" in services.db - ignoring
Wrote bundle to hellojavaee.dsb

depends_on只负责创建两项服务之间的依赖性,并以特定顺序对二者进行启动。这能确保Docker容器首先启动,而运行在其中的应用则需要更长时间才能启动完成。因此,此属性只在一定程度上解决了这一问题。

container_name能够为该容器提供一个特定名称。对特定容器名称的依赖性为紧密耦合,且不允许我们对该容器进行规模伸缩。因此这里我们暂时忽略这两条警告。此命令会利用Compose项目名(也就是其目录名称)生成一个文件。因此在本示例中,生成的文件名为hellojavaee.dsb。此文件的扩展名在RC3中则为.dab。此生成的应用捆绑包内容如下所示:

{
 "services": {
   "db": {
     "Image": "arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c", 
     "Networks": [
       "default"
     ], 
     "Ports": [
       {
         "Port": 8091, 
         "Protocol": "tcp"
       }, 
       {
         "Port": 8092, 
         "Protocol": "tcp"
       }, 
       {
         "Port": 8093, 
         "Protocol": "tcp"
       }, 
       {
         "Port": 11210, 
         "Protocol": "tcp"
       }
     ]
   }, 
   "web": {
     "Env": [
       "COUCHBASE_URI=db"
     ], 
     "Image": "arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914", 
     "Networks": [
       "default"
     ], 
     "Ports": [
       {
         "Port": 8080, 
         "Protocol": "tcp"
       }
     ]
   }
 }, 
 "version": "0.1"
}

此文件为包含在应用内的各项服务提供完整的描述。当然,未来我们应该可以使用其它容器格式,例如Rkt或者VM等形式。不过就目前来讲,其还仅支持Docker这一种格式。

在Docker中进行Swarm Mode初始化

正如之前所提到,目前“理想状态”由Docker Swarm负责保持。而其现在已经被纳入Docker Engine当中。在本篇文章中,我们使用新增的一条命令,即docker swarm:

docker swarm --help
Usage: docker swarm COMMAND
Manage Docker Swarm
Options:
     --help   Print usage
Commands:
 init        Initialize a Swarm
 join        Join a Swarm as a node and/or manager
 update      Update the Swarm
 leave       Leave a Swarm
 inspect     Inspect the Swarm
Run "docker swarm COMMAND --help" for more information on a command.

在Docker Engine中对一个Swarm节点(作为工作节点)进行初始化:

docker swarm init
Swarm initialized: current node (ek9p1k8r8ox7iiua5c247skci) is now a manager.

关于该节点的更多细节信息可利用docker swarm inspect命令进行查看。

docker swarm inspect
[
   {
       "ID": "1rcvu7m9mv2c8hiaijr7an9zk",
       "Version": {
           "Index": 1895
       },
       "CreatedAt": "2016-07-01T23:52:38.074748177Z",
       "UpdatedAt": "2016-07-02T04:54:32.79093117Z",
       "Spec": {
           "Name": "default",
           "AcceptancePolicy":{
               "Policies": [
                   {
                       "Role": "worker",
                       "Autoaccept": true
                   },
                   {
                       "Role": "manager",
                       "Autoaccept":false
                   }
               ]
           },
           "Orchestration": {
               "TaskHistoryRetentionLimit":10
           },
           "Raft": {
               "SnapshotInterval": 10000,
               "LogEntriesForSlowFollowers":500,
               "HeartbeatTick":1,
               "ElectionTick":3
           },
           "Dispatcher": {
               "HeartbeatPeriod": 5000000000
           },
           "CAConfig": {
               "NodeCertExpiry": 7776000000000000
           }
       }
   }
]

从输出结果中可以看到,该节点只属于工作节点而非管理节点。如果在单节点集群当中,这样的设置并无不妥。不过在多节点集群当中,则应至少存在一个管理节点。

部署Docker Stack

利用docker deploy命令创建一个stack:

docker deploy -f hellojavaee.dsb hellojavaee
Loading bundle from hellojavaee.dsb
Creating network hellojavaee_default
Creating service hellojavaee_db
Creating service hellojavaee_web

下面来看各服务列表:

docker service ls
ID            NAME             REPLICAS  IMAGE                 COMMAND
2g8kmrimztes  hellojavaee_web  1/1       arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914    
46xhlb15cc60  hellojavaee_db   1/1       arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c

在输出结果中,我们可以看到正在运行的两项服务,分别为WildFly与Couchbase。 Service概念同样新增于Docker 1.12版本,其负责为我们提供“理想状态”,而具体实现则由Docker Engine负责。使用docker ps命令显示当前正在运行的容器列表:

CONTAINER ID        IMAGE                                                                                                 COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
622756277f40        arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c   "/entrypoint.sh /opt/"   3 seconds ago       Up 1 seconds        8091-8093/tcp, 11207/tcp, 11210-11211/tcp, 18091-18092/tcp   hellojavaee_db.1.19enwdt6i5m853m5675tx3z29
abf8703ed713        arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914     "/opt/jboss/wildfly/b"   3 seconds ago       Up 1 seconds        8080/tcp                                                     hellojavaee_web.1.70piloz6j4zt06co8htzisgyl

WildFly容器会在Couchbase容器启动并运行之前先行启动。这意味着Java EE应用会尝试接入Couchbase服务器但发生失败。因此,该应用将永远无法成功完成引导。

自我修复Docker Service

Docker Service负责保持应用的“理想状态”。在本示例中,我们的理想状态是确保特定服务有且只有一套容器与之对应且持续运行。如果我们移除该容器,而非服务,则该服务会自动重启容器。使用以下命令移除容器:

docker rm -f abf8703ed713

请注意,这里之所以要使用-f,是因为该容器已经处于运行状态。Docker 1.12自我修复机制会介入并自动重启此容器。现在再次打开运行容器列表:

CONTAINER ID        IMAGE                                                                                                 COMMAND                  CREATED             STATUS                  PORTS                                                        NAMES
db483ac27e41        arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914     "/opt/jboss/wildfly/b"   1 seconds ago       Up Less than a second   8080/tcp                                                     hellojavaee_web.1.ddvwdmojjysf46d4n3x4g8uv4
622756277f40        arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c   "/entrypoint.sh /opt/"   26 seconds ago      Up 25 seconds           8091-8093/tcp, 11207/tcp, 11210-11211/tcp, 18091-18092/tcp   hellojavaee_db.1.19enwdt6i5m853m5675tx3z29

结果显示新容器已经启动完成。检查WildFly服务:

docker service inspect hellojavaee_web
[
   {
       "ID": "54otfi6dc9bis7z6gc6ubynwc",
       "Version": {
           "Index": 328
       },
       "CreatedAt": "2016-07-02T01:36:35.735767569Z",
       "UpdatedAt": "2016-07-02T01:36:35.739240775Z",
       "Spec": {
           "Name": "hellojavaee_web",
           "Labels": {
               "com.docker.stack.namespace": "hellojavaee"
           },
           "TaskTemplate": {
               "ContainerSpec": {
                   "Image": "arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914",
                   "Env": [
                       "COUCHBASE_URI=db"
                   ]
               }
           },
           "Mode": {
               "Replicated": {
                   "Replicas": 1
               }
           },
           "Networks": [
               {
                   "Target": "epw57lz7txtfchmbf6u0cimis",
                   "Aliases": [
                       "web"
                   ]
               }
           ],
           "EndpointSpec": {
               "Mode": "vip",
               "Ports": [
                   {
                       "Protocol": "tcp",
                       "TargetPort": 8080
                   }
               ]
           }
       },
       "Endpoint": {
           "Spec": {},
           "Ports": [
               {
                   "Protocol": "tcp",
                   "TargetPort": 8080,
                   "PublishedPort": 30004
               }
           ],
           "VirtualIPs": [
               {
                   "NetworkID": "9lpz688ir3pzexubkcb828ikg",
                   "Addr": "10.255.0.5/16"
               },
               {
                   "NetworkID": "epw57lz7txtfchmbf6u0cimis",
                   "Addr": "10.0.0.4/24"
               }
           ]
       }
   }
]

Swarm会将随机端口分配给该服务,我们也可以利用docker service update命令进行手动更新。在本示例中,容器的端口8080被映射至主机上的端口30004。

进行应用验证

下面检查该应用是否已经成功部署:

curl http://localhost:30004/books/resources/book
[{"books":0}]

为该应用添加新的book:

再次验证该book:

curl http://localhost:30004/books/resources/book
    [{"books":{"name":"Minecraft Modding with Forge","cost":29.99,"id":"1","isbn":"978-1-4919-1889-0"}}, {"books":1}]

欲了解更多与此Java应用相关的信息,请访问github.com/arun-gupta/oreilly-docker-book/tree/master/hello-javaee。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26665.html

相关文章

  • 代码级干货 | 进阶Docker 1.12,全新的布式应用捆绑

    摘要:利用分布式应用捆绑包简称部署服务相较于利用大量参数创建网络及服务,这里我们选择使用一个文件。 在Docker 1.12版本中,全新的Swarm捆绑包相较于原有编排及调度机制做出了巨大改进。它不再需要运行一组独立的Swarm容器,这部分容器已经被直接捆绑在Docker Engine当中,故障转移策略更为可靠,服务发现机制实现内置,新的网络功能极为顺畅……看起来很棒是不是? 数人云这...

    2i18ns 评论0 收藏0
  • 基于 Docker 1.12 Swarm 的集群管理开发实践

    摘要:由于没有了中心化的负载均衡器,集群不会因某台机器异常而导致整个服务对外不可用,很好的避免了单点问题,同时也带了可扩展性。 Mesos/Marathon 折腾久了,我们一直希望有机会深入到 Swarm 内部一探究竟。 另外, Mesos 这一套东西虽然是久经企业级考验的, 但是安装、部署和使用相对复杂,上手有门槛。同时,在今年的 DockerCon 上,内置了Swarm 功能的 Dock...

    My_Oh_My 评论0 收藏0
  • 关于Docker Swarm,你可能需要了解更多实践经验

    摘要:虽然可以使用相同的方式部署应用到云端,使用外部负载均衡器,但动态添加或者减少负载均衡节点依旧是痛点。这对使用外部负载均衡器帮助巨大。 数人云今天带来的本篇文章将分享Docker在应用程序生命周期每个阶段中所扮演的角色,以及迁移到Swarm集群时需要考虑的问题。 利用Docker来开发 Docker让工作更轻松。如需要一个部署安装MySQL数据库,或者安装Ghost,又或者Redis数据...

    bitkylin 评论0 收藏0
  • Docker Swarm在生产环境中的进阶指南

    摘要:应该如何解决本文将给出若干提示,如何在生产环境中使用。路由匹配服务发现负载均衡跨容器通讯非常可靠。在单个端口上运行一个服务,节点的任意主机都可以访问,负载均衡完全在后台实现。 上周数人云给大家分享了——《你可能需要的关于Docker Swarm的经验分享》今天给大家带来这位作者大大的后续文章——《Docker Swarm在生产环境中的进阶指南》 当在本地开发环境中使用Docker,或者...

    galaxy_robot 评论0 收藏0
  • 生产环境中使用Docker Swarm的一些建议

    摘要:译者按实践中会发现,生产环境中使用单个节点是远远不够的,搭建集群势在必行。集群的网络通信服务发现,负载均衡以及容器间通信非常可靠。负载均衡也是由提供的。 译者按: 实践中会发现,生产环境中使用单个Docker节点是远远不够的,搭建Docker集群势在必行。然而,面对Kubernetes, Mesos以及Swarm等众多容器集群系统,我们该如何选择呢?它们之中,Swarm是Docker原...

    loonggg 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<