Primeira versão candidata do Docker 1.12 foi anunciado em duas semanas atrás. Vários novos recursos são
planejado para esta versão.
Este blog mostrará como criar um Aplicativo distribuído Bundle do Docker Compose e implante-o como Docker Stack em Docker Swarm Modo. Muito obrigado a @friismo por me ajudar a entender esses conceitos.
Vamos dar uma olhada nos recursos primeiro:
- Orquestração integrada: Um aplicativo típico é definido usando um arquivo Docker Compose. Essa definição consiste em vários contêineres e é implantada em vários hosts. Isso evita o ponto único de falha (SPOF) e mantém seu aplicativo
resiliente. Várias estruturas de orquestração, como Docker Swarm, Kubernetes e Mesos, permitem orquestrar esses aplicativos. No entanto, como essa é uma característica tão importante do aplicativo, o Docker Engine agora tem orquestração integrada.
Mais detalhes sobre esse tópico em um blog posterior. - Serviço: Um serviço replicado, distribuído e com balanceamento de carga pode ser facilmente criado usando
serviço docker createcomando. Um "estado desejado" do aplicativo, como a execução de 3 contêineres do Couchbase, é fornecido e o comando
O mecanismo de autocorreção do Docker garante que muitos contêineres estejam em execução no cluster. Se um contêiner for desativado, outro contêiner será iniciado. Se um nó for desativado, os contêineres desse nó serão iniciados em um nó diferente. Mais sobre isso em um próximo
blog. - Segurança de configuração zero: O Docker 1.12 vem com TLS mutuamente autenticado, fornecendo autenticação, autorização e criptografia para as comunicações de todos os nós que participam do enxame, prontos para uso. Mais sobre isso em
em um blog posterior. - Pilha do Docker e pacote de aplicativos distribuídos: O Distributed Application Bundle, ou DAB, é um formato de imagem distribuível de vários serviços. Leia mais para obter mais detalhes.
Até o momento, você pode pegar um Dockerfile e criar uma imagem a partir dela usando o construção de docas comando. Um contêiner pode ser iniciado usando o comando execução do docker comando. Vários contêineres podem ser iniciados facilmente com o comando
esse comando várias vezes. Ou você também pode usar o arquivo Docker Compose e aumentar a escala dos seus contêineres usando o comando escala do docker-compose comando.

A imagem é um formato portátil para um único contêiner. Pacote de aplicativos distribuídosou DAB, um novo conceito introduzido no Docker 1.12, é um formato portátil para vários contêineres. Cada pacote pode ser implantado como
a Pilha em tempo de execução.
Saiba mais sobre o DAB em docker.com/dab. Para simplificar, aqui está uma analogia que pode ser feita:
Dockerfile -> Imagem -> Contêiner
Docker Compose -> Pacote de aplicativos distribuídos -> Docker Stack
Vamos usar um arquivo Docker Compose, criar um DAB a partir dele e implantá-lo como um Docker Stack.
É importante observar que esse é um recurso experimental na versão 1.12-RC2.
Criar um pacote de aplicativos distribuídos a partir do Docker Compose
O Docker Compose CLI adiciona um novo feixe comando. Mais detalhes podem ser encontrados:
|
1 2 3 4 5 6 7 8 9 10 11 |
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". |
Agora, vamos pegar uma definição do Docker Compose e criar um DAB a partir dela. Aqui está nossa definição do Docker Compose:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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 |
Esse arquivo Compose inicia um servidor WildFly e um servidor Couchbase. Um aplicativo Java EE é pré-implantado no servidor WildFly que se conecta ao servidor Couchbase e permite executar operações CRUD usando a API REST. A fonte desse arquivo está em:
github.com/arun-gupta/oreilly-docker-book/blob/master/hello-javaee/docker-compose.yml. Gere um pacote de aplicativos com ele:
|
1 2 3 4 |
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 |
depende_de apenas cria dependência entre dois serviços e os faz iniciar em uma ordem específica. Isso só garante que o contêiner do Docker seja iniciado, mas o aplicativo dentro do contêiner pode demorar mais para iniciar. Portanto, esse atributo apenas
resolve parcialmente o problema. nome_do_contêiner fornece um nome específico para o contêiner. Depender de um nome de contêiner específico é um acoplamento rígido e não permite dimensionar o contêiner. Portanto, ambos os avisos podem ser ignorados,
por enquanto. Esse comando gera um arquivo usando o nome do projeto Compose, que é o nome do diretório. Portanto, no nosso caso, hellojavaee.dsb é gerado. Essa extensão de arquivo foi renomeada para .dab no RC3. O código gerado
pacote de aplicativos é semelhante:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
{ "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" } |
Esse arquivo fornece uma descrição completa dos serviços incluídos no aplicativo. Não tenho certeza se Distributed Application Bundle é o nome mais apropriado; discuta isso em #24250. Ele
seria ótimo se outros formatos de contêineres, como o Rkt, ou mesmo VMs, pudessem ser suportados aqui. Mas, por enquanto, o Docker é o único formato compatível.
Inicializar o modo Swarm no Docker
Conforme mencionado acima, o "estado desejado" agora é mantido pelo Docker Swarm. E isso já está incorporado ao Docker Engine. Os conceitos do Docker Swarm também evoluíram e podem ser lidos em Conceitos-chave do modo Swarm. A
um blog mais detalhado sobre isso será publicado posteriormente. Mas para este blog, um novo comando enxame de docas foi adicionado:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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. |
Inicialize um nó do Swarm (como um gerenciador) no Docker Engine:
|
1 2 |
docker swarm init Swarm initialized: current node (ek9p1k8r8ox7iiua5c247skci) is now a manager. |
Mais detalhes sobre esse nó podem ser encontrados em inspeção de nó doca autocomando.
A saída detalhada é detalhada, mas a seção relevante é:
|
1 2 3 4 5 |
"Spec": { "Role": "manager", "Membership": "accepted", "Availability": "active" }, |
A saída mostra que o nó é um gerente. Em um cluster de nó único, esse nó também atuará como um trabalhador.
Mais detalhes sobre o cluster podem ser obtidos usando o comando inspeção de enxame de docas comando.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
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 } } } ] |
Política de aceitação mostra que outros trabalhador Os nós podem entrar nesse cluster, mas um gerente precisa de aprovação explícita.
Implantar uma pilha do Docker
Crie uma pilha usando implantação de docas comando:
|
1 2 3 4 5 |
docker deploy -f hellojavaee.dsb hellojavaee Loading bundle from hellojavaee.dsb Creating network hellojavaee_default Creating service hellojavaee_db Creating service hellojavaee_web |
O uso do comando certamente pode ser simplificado, conforme discutido em #24249. Veja a lista de serviços:
|
1 2 3 4 |
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 |
A saída mostra que dois serviços, WildFly e Couchbase, estão em execução. Serviços também é um novo conceito introduzido no Docker 1.12. É isso que dá a você o
"estado desejado", e o Docker Engine trabalha para fornecer isso a você. docker ps mostra a lista de contêineres em execução:
|
1 2 3 |
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 |
O contêiner WildFly é iniciado antes que o contêiner do Couchbase esteja em funcionamento. Isso significa que o aplicativo Java EE tenta se conectar ao servidor Couchbase e falha. Portanto, o aplicativo nunca é inicializado com êxito.
Serviço do Docker com autocorreção
O Docker Service mantém o "estado desejado" de um aplicativo. No nosso caso, o estado desejado é garantir que um, e somente um, contêiner para o serviço esteja em execução. Se removermos o contêiner, e não o serviço, o serviço será
iniciar automaticamente o contêiner novamente. Remova o contêiner como:
|
1 |
docker rm -f abf8703ed713 |
Observe que você deve dar -f porque o contêiner já está em execução. Os mecanismos de autocorreção do Docker 1.12 entram em ação e reiniciam automaticamente o contêiner. Agora, se você listar os contêineres novamente:
|
1 2 3 |
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 |
Isso mostra que um novo contêiner foi iniciado. Inspecione o serviço WildFly:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
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" } ] } } ] |
O Swarm atribui uma porta aleatória ao serviço, ou isso pode ser atualizado manualmente usando Atualização do serviço de docker comando. No nosso caso, a porta 8080 do contêiner é mapeado para 30004 no host.
Verificar o aplicativo
Verifique se o aplicativo foi implantado com êxito:
|
1 2 |
curl https://localhost:30004/books/resources/book [{"books":0}] |
Adicione um novo livro ao aplicativo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
curl -v > -H "Content-Type: application/json" > -X POST -d '{ > "isbn": "978-1-4919-1889-0", > "name": "Minecraft Modding with Forge", > "cost": 29.99 > }' > https://localhost:30004/books/resources/book * Trying ::1... * Connected to localhost (::1) port 30004 (#0) > POST /books/resources/book HTTP/1.1 > Host: localhost:30004 > User-Agent: curl/7.43.0 > Accept: */* > Content-Type: application/json > Content-Length: 92 > * 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 Mhttps://localhost:30004/books/resources/book-1-4919-1889-0"} |
Verifique os livros novamente:
|
1 2 |
curl https://localhost:30004/books/resources/book [{"books":{"name":"Minecraft Modding with Forge","cost":29.99,"id":"1","isbn":"978-1-4919-1889-0"}}, {"books":1}] |
Saiba mais sobre esse aplicativo Java EE em github.com/arun-gupta/oreilly-docker-book/tree/master/hello-javaee.
Este blog mostrou como criar um pacote de aplicativos distribuídos a partir do Docker Compose e implantá-lo como Docker Stack no modo Docker Swarm.
Referências de serviço e pilha do Docker
- Criação de serviço do Docker
- Livro GRATUITO da O'Reilly: Docker para desenvolvedores Java
- Couchbase em contêineres
- Portal do desenvolvedor do Couchbase
- Faça perguntas sobre @couchbasedev ou Stackoverflow

