两周前宣布了Docker 1.12的第一个发布候选版本 。 此版本计划了几个新功能。
该博客将展示如何从Docker Compose创建分布式应用程序捆绑包,并将其作为Docker堆栈以Docker Swarm模式部署。 非常感谢@friism帮助我理解这些概念。
让我们先来看一下这些功能:
- 内置编排 :典型的应用程序是使用Docker Compose文件定义的。 该定义由多个容器组成,并部署在多个主机上。 这样可以避免单点故障(SPOF),并保持应用程序的弹性。 多个编排框架(例如Docker Swarm,Kubernetes和Mesos)使您可以编排这些应用程序。 但是,这正是应用程序的重要特性,Docker Engine现在具有内置的编排。 在以后的博客中,有关此主题的更多详细信息。
- 服务 :可以使用
docker service create
命令轻松创建复制,分布式和负载平衡的服务。 提供了应用程序的“所需状态”,例如运行3个Couchbase容器,并且自我修复的Docker引擎确保群集中正在运行许多容器。 如果某个容器发生故障,则将启动另一个容器。 如果某个节点发生故障,则该节点上的容器将在另一个节点上启动。 有关更多信息,请参见后面的博客。 - 零配置安全性 :Docker 1.12随附经过相互认证的TLS,可为现存集群中每个参与节点的通信提供认证,授权和加密。 有关更多信息,请参见后面的博客。
- Docker堆栈和分布式应用程序捆绑包 :分布式应用程序捆绑包(DAB)是一种多服务可分发映像格式。 进一步阅读以获取更多详细信息。
到目前为止,您可以获取一个Dockerfile
并使用Dockerfile
docker build
命令Dockerfile
创建映像。 可以使用docker run
命令启动容器。 通过多次给出该命令,可以轻松启动多个容器。 或者,您也可以使用Docker Compose文件并使用docker-compose scale
命令docker-compose scale
容器。
图像是单个容器的可移植格式。 分布式应用程序捆绑包 (DAB)是Docker 1.12中引入的新概念,是一种可移植的格式,用于多个容器。 然后可以在运行时将每个捆绑软件部署为堆栈 。
在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服务器。 Java EE应用程序已在WildFly服务器中预先部署,该服务器连接到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
为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"
}
该文件提供了应用程序中包含的服务的完整描述。 我不太确定Distributed Application Bundle是否是最合适的名称,请在#24250中进行讨论。 如果可以在这里支持其他容器格式,例如Rkt,甚至VM,那就太好了。 但就目前而言,Docker是唯一受支持的格式。
在Docker中初始化Swarm模式
如上所述,“所需状态”现在由Docker Swarm维护。 现在,它已经被移植到Docker Engine中了。
Docker Swarm概念也在不断发展,可以在Swarm模式下的关键概念中阅读。 稍后将发布有关此内容的更详细的博客。
但对于此博客,现在添加了新命令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堆栈
使用docker deploy
命令创建堆栈:
docker deploy -f hellojavaee.dsb hellojavaee
Loading bundle from hellojavaee.dsb
Creating network hellojavaee_default
Creating service hellojavaee_db
Creating service hellojavaee_web
如#24249中所述,可以肯定地简化命令用法。
请参阅服务列表:
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正在运行。 服务也是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
在Couchbase容器启动并运行之前,WildFly容器启动。 这意味着Java EE应用程序尝试连接到Couchbase服务器并失败。 因此,应用程序永远无法成功启动。
自我修复Docker服务
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}]
向应用程序添加一本新书:
curl -v \
&qt; -H "Content-Type: application/json" \
&qt; -X POST -d '{
&qt; "isbn": "978-1-4919-1889-0",
&qt; "name": "Minecraft Modding with Forge",
&qt; "cost": 29.99
&qt; }' \
&qt; http://localhost:30004/books/resources/book
* Trying ::1...
* Connected to localhost (::1) port 30004 (#0)
&qt; POST /books/resources/book HTTP/1.1
&qt; Host: localhost:30004
&qt; User-Agent: curl/7.43.0
&qt; Accept: */*
&qt; Content-Type: application/json
&qt; Content-Length: 92
&qt;
* upload completely sent off: 92 out of 92 bytes
<HTTP/1.1 200 OK
<Connection: keep-alive
<X-Powered-By: Undertow/1
<Server: WildFly/10
<Content-Type: application/octet-stream
<Content-Length: 88
<Date: Sat, 02 Jul 2016 01:39:49 GMT
<
* Connection #0 to host localhost left intact
{"name":"Minecraft Mhttp://localhost:30004/books/resources/book-1-4919-1889-0"}
再次验证书籍:
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}]
在github.com/arun-gupta/oreilly-docker-book/tree/master/hello-javaee上了解有关此Java EE应用程序的更多信息。
该博客展示了如何从Docker Compose创建分布式应用程序捆绑包,并在Docker Swarm模式下将其作为Docker Stack部署。
翻译自: https://www.javacodegeeks.com/2016/07/docker-services-stack-distributed-application-bundle.html