Ratnopam Chakrabarti é um desenvolvedor de software que trabalha atualmente para a Ericsson Inc. Ele tem se concentrado em IoT, tecnologias máquina a máquina, carros conectados e domínios de cidades inteligentes por um bom tempo. Ele adora aprender novas tecnologias e colocá-las em prática. Quando não está trabalhando, gosta de passar o tempo com seu filho de 3 anos.
Introdução
Bem-vindo à segunda parte da série em que descrevo como desenvolver e executar um aplicativo da Web do Spring Boot totalmente funcional e alimentado pelo Couchbase usando o conjunto de ferramentas do Docker. Em primeira parte da série, demonstrei como executar dois contêineres do Docker para executar um aplicativo funcional com uma interface de usuário apresentável. Os dois contêineres do Docker que estávamos executando são:
- A Contêiner do Couchbase com configurações pré-configuradas
- Um contêiner de aplicativo que se comunica com o contêiner do Couchbase (executado na etapa 1)
Embora esse método seja útil, ele não é totalmente automatizado, o que significa que a orquestração automatizada não existe. Você precisa executar dois comandos diferentes de execução do Docker para executar toda a configuração.
Existe uma maneira de criar e executar o contêiner do aplicativo que também aciona a execução do contêiner do Couchbase? É claro que existe uma maneira.
Entre no Docker Compose
Usando Docker ComposeCom o Couchbase, você pode orquestrar a execução de ambientes com vários contêineres, que é exatamente o que precisamos para o nosso caso de uso. Precisamos executar o contêiner do Couchbase primeiro e, em seguida, o contêiner do aplicativo deve ser executado e conversar com o contêiner do Couchbase.
Aqui está o arquivo docker-compose.yml para fazer isso:
|
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 |
version: "2" services: app: build: . ports: - 8080:8080 environment: - BUCKET_NAME=books - HOST=192.168.99.100 depends_on: - db db: image: chakrar27/couchbase:books ports: - 8091:8091 - 8092:8092 - 8093:8093 - 8094:8094 - 11210:11210 |
Nosso aplicativo "depende" da imagem do banco de dados, que é o contêiner do Couchbase. Em outras palavras, o contêiner do Couchbase é executado primeiro e, em seguida, o contêiner do aplicativo começa a ser executado. Há um possível problema aqui: a palavra-chave "depends_on" não garante que o contêiner do Couchbase tenha terminado de configurar a imagem e iniciado a execução. Tudo o que ela garante é que o contêiner seja iniciado primeiro; ela não verifica se o contêiner está realmente em execução ou pronto para aceitar solicitações de um aplicativo. Para garantir que o contêiner do Couchbase esteja realmente em execução e que todas as etapas de pré-configuração, como a configuração da consulta, dos serviços de índice e do bucket, tenham sido concluídas, precisamos fazer uma verificação no contêiner do aplicativo.
Aqui está o Dockerfile do contêiner do aplicativo que invoca um script que, por sua vez, verifica se o bucket "books" já foi configurado ou não. Ele entra em um loop até que o bucket seja configurado e, em seguida, aciona o contêiner do aplicativo.
https://github.com/ratchakr/bookstoreapp/blob/master/Dockerfile-v1
O roteiro pode ser visto em https://github.com/ratchakr/bookstoreapp/blob/master/run_app.sh
O script faz as seguintes coisas:
Ele usa o endpoint REST suportado pelo Couchbase para consultar o bucket.
O Curl é usado para chamar os pontos de extremidade REST. A instalação do curl é abordada no Dockerfile do aplicativo.
O script analisa a resposta JSON da chamada REST usando uma ferramenta chamada jq.
Se o bucket estiver configurado, ele executará o contêiner do aplicativo; caso contrário, aguardará que o bucket seja configurado primeiro.
Vale a pena mencionar que mais verificações, como verificar se o serviço de índice e o serviço de consulta estão configurados corretamente ou não, podem ser adicionadas ao script de shell para torná-lo mais robusto. Uma palavra de cautela é confirmar seu caso de uso e requisito específico antes de seguir a abordagem docker-compose; não há uma maneira infalível de determinar se o contêiner do banco de dados do Couchbase está totalmente em funcionamento e pronto para atender às solicitações do aplicativo cliente. Algumas das abordagens que podem funcionar são as seguintes:
- Se você tiver um bucket pré-configurado, poderá testar se o bucket existe
- Verifique se os índices estão no lugar
- Se você souber a contagem de registros em um bucket (digamos, para um arquivo .csv que foi importado para um bucket no momento do carregamento inicial dos dados), poderá verificar se a contagem corresponde ao número de registros no arquivo .csv). Para o nosso caso de uso, o mencionado acima funciona muito bem.
Criar e executar
Agora que temos o arquivo docker-compose e o Dockerfile, podemos criar a imagem do aplicativo usando o simples comando docker-compose up comando.
Aqui está o trecho de saída do console do Docker:
|
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
$ docker-compose up Creating network "bookstoreapp_default" with the default driver Pulling db (chakrar27/couchbase:books)... books: Pulling from chakrar27/couchbase Digest: sha256:4bc356a1f2b5b3d7ee3daf10cd5c55480ab831a0a147b07f5b14bea3de909fd9 Status: Downloaded newer image for chakrar27/couchbase:books Building app Step 1/8 : FROM frolvlad/alpine-oraclejdk8:full full: Pulling from frolvlad/alpine-oraclejdk8 Digest: sha256:a344745faa77a9aa5229f26bc4f5c596d13bcfc8fcac051a701b104a469aff1f Status: Downloaded newer image for frolvlad/alpine-oraclejdk8:full ---> 5f7037acb78d Step 2/8 : VOLUME /tmp ---> Running in 7d18e0b90bfd ---> 6a43ccb712dc Removing intermediate container 7d18e0b90bfd Step 3/8 : ADD target/bookstore-1.0.0-SNAPSHOT.jar app.jar ---> a3b4bf7745e0 Removing intermediate container 0404f1d094d3 Step 4/8 : RUN sh -c 'touch /app.jar' ---> Running in 64d1c82a0694 ---> 1ec5a68cafa9 Removing intermediate container 64d1c82a0694 Step 5/8 : RUN apk update && apk add curl ---> Running in 1f912e8341bd fetch https://dl-cdn.alpinelinux.org/alpine/v3.5/main/x86_64/APKINDEX.tar.gz fetch https://dl-cdn.alpinelinux.org/alpine/v3.5/community/x86_64/APKINDEX.tar.gz v3.5.2-16-g53ad101cf8 [https://dl-cdn.alpinelinux.org/alpine/v3.5/main] v3.5.2-14-gd7ba0e189f [https://dl-cdn.alpinelinux.org/alpine/v3.5/community] OK: 7961 distinct packages available (1/4) Installing ca-certificates (20161130-r1) (2/4) Installing libssh2 (1.7.0-r2) (3/4) Installing libcurl (7.52.1-r2) (4/4) Installing curl (7.52.1-r2) Executing busybox-1.25.1-r0.trigger Executing ca-certificates-20161130-r1.trigger Executing glibc-bin-2.25-r0.trigger OK: 12 MiB in 18 packages ---> 8f99863af926 Removing intermediate container 1f912e8341bd Step 6/8 : ADD run_app.sh . ---> cedb8d545070 Removing intermediate container 8af5ac3ab0a0 Step 7/8 : RUN chmod +x run_app.sh ---> Running in 74a141de2f52 ---> 77ffd7425bea Removing intermediate container 74a141de2f52 Step 8/8 : CMD sh run_app.sh ---> Running in 6f81c8ebaa37 ---> 56a3659005ef Removing intermediate container 6f81c8ebaa37 Successfully built 56a3659005ef Image for service app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Creating bookstoreapp_db_1 Creating bookstoreapp_app_1 Attaching to bookstoreapp_db_1, bookstoreapp_app_1 db_1 | docker host ip = 192.168.99.100 db_1 | sleeping... app_1 | Starting application run script........... app_1 | couchbase is running on 192.168.99.100 app_1 | bucket to check is books db_1 | < Date: Fri, 24 Mar 2017 06:53:00 GMT db_1 | < Content-Length: 0 db_1 | < Cache-Control: no-cache db_1 | < 100 55 0 0 100 55 0 827 --:--:-- --:--:-- --:--:-- 833 db_1 | * Connection #0 to host 127.0.0.1 left intact db_1 | bucket set up done app_1 | response from cb app_1 | ************************************************ app_1 | ************************************************ app_1 | response from cb books app_1 | ************************************************ app_1 | ************************************************ app_1 | bucket is now ready bucket name books app_1 | Run application container now app_1 | ************************************************ app_1 | app_1 | . ____ _ __ _ _ app_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ app_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ app_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) ) app_1 | ' |____| .__|_| |_|_| |_\__, | / / / / app_1 | =========|_|==============|___/=/_/_/_/ app_1 | :: Spring Boot :: (v1.4.2.RELEASE) app_1 | app_1 | 2017-03-24 06:53:59.839 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=06bad9c4-85fc-4c0b-83a7-ad21b2fdd405, title=The Immortal Irishman, author=Timothy Egan, isbn=ISBN444, category=History] app_1 | 2017-03-24 06:53:59.839 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=328eaf44-edff-43c6-9f55-62d7e095256d, title=The Kite Runner, author=Khaled Hosseini, isbn=ISBN663, category=Fiction] app_1 | 2017-03-24 06:53:59.839 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=56882f5a-d466-457f-82c1-1c3bca0c6d75, title=Breaking Blue, author=Timothy Egan, isbn=ISBN777, category=Thriller] app_1 | 2017-03-24 06:53:59.839 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=845a2fe8-cbbf-4780-b216-41abf86d7d61, title=History of Mankind, author=Gabriel Garcia, isbn=ISBN123, category=History] app_1 | 2017-03-24 06:53:59.840 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=9d2833c3-e005-4c4f-98f9-75b69bbb7bf5, title=The Night Gardener, author=Eric Fan, isbn=ISBN333, category=Kids Books] app_1 | 2017-03-24 06:53:59.840 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=5756bf4d-551c-429e-8bc3-2339dc065ff8, title=Grit: The Power of Passion and Perseverance, author=Angela Duckworth, isbn=ISBN555, category=Business] app_1 | 2017-03-24 06:53:59.840 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Details = Book [id=e8e34f30-6fdf-4ca7-9cef-e06f504f8778, title=War and Turpentine, author=Stefan Hertmans, isbn=ISBN222, category=Fiction] app_1 | 2017-03-24 06:54:00.234 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Books by Timothy Egan = Book [id=06bad9c4-85fc-4c0b-83a7-ad21b2fdd405, title=The Immortal Irishman, author=Timothy Egan, isbn=ISBN444, category=History] app_1 | 2017-03-24 06:54:00.238 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Books by Timothy Egan = Book [id=56882f5a-d466-457f-82c1-1c3bca0c6d75, title=Breaking Blue, author=Timothy Egan, isbn=ISBN777, category=Thriller] app_1 | 2017-03-24 06:54:00.346 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Starting with title 'The' = Book [id=06bad9c4-85fc-4c0b-83a7-ad21b2fdd405, title=The Immortal Irishman, author=Timothy Egan, isbn=ISBN444, category=History] app_1 | 2017-03-24 06:54:00.349 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Starting with title 'The' = Book [id=328eaf44-edff-43c6-9f55-62d7e095256d, title=The Kite Runner, author=Khaled Hosseini, isbn=ISBN663, category=Fiction] app_1 | 2017-03-24 06:54:00.349 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book Starting with title 'The' = Book [id=9d2833c3-e005-4c4f-98f9-75b69bbb7bf5, title=The Night Gardener, author=Eric Fan, isbn=ISBN333, category=Kids Books] app_1 | 2017-03-24 06:54:00.443 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book in Fiction = Book [id=328eaf44-edff-43c6-9f55-62d7e095256d, title=The Kite Runner, author=Khaled Hosseini, isbn=ISBN663, category=Fiction] app_1 | 2017-03-24 06:54:00.453 INFO 31 --- [ main] c.chakrar.sample.books.BookStoreRunner : Book in Fiction = Book [id=e8e34f30-6fdf-4ca7-9cef-e06f504f8778, title=War and Turpentine, author=Stefan Hertmans, isbn=ISBN222, category=Fiction] app_1 | 2017-03-24 06:54:02.745 INFO 31 --- [nio-8080-exec-1] o.v.spring.servlet.Vaadin4SpringServlet : Could not find a SystemMessagesProvider in the application context, using default app_1 | 2017-03-24 06:54:02.753 INFO 31 --- [nio-8080-exec-1] o.v.spring.servlet.Vaadin4SpringServlet : Custom Vaadin4Spring servlet initialization completed app_1 | 2017-03-24 06:54:02.864 INFO 31 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet' app_1 | 2017-03-24 06:54:02.865 INFO 31 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started |
Neste ponto, nosso aplicativo está em funcionamento com um único comando de orquestração docker-compose.
Tipo 192.168.99.100:8080 no navegador; você deverá ver a tela a seguir:

O Docker Compose é uma boa maneira de orquestrar ambientes Docker com vários contêineres. Ele tem cadeias de comando quase semelhantes aos conjuntos de comandos do "docker". Por exemplo, para ver uma lista de contêineres em execução, basta digitar:
docker-compose ps > que lhe daria
|
1 2 3 4 5 6 7 8 9 |
$ docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bookstoreapp_app_1 /bin/sh -c sh run_app.sh Up 0.0.0.0:8080->8080/tcp bookstoreapp_db_1 /entrypoint.sh /opt/couchb ... Up 11207/tcp, 0.0.0.0:11210->11210/tcp, 11211/tcp, 18091/tcp, 18092/tcp, 18093/tcp, 0.0.0.0:8091->8091/tcp, 0.0.0.0:8092->8092/tcp, 0.0.0.0:8093->8093/tcp, 0.0.0.0:8094->8094/tcp |
O nome dos contêineres é mostrado em negrito aqui.
Se você precisar interromper ou derrubar seu ambiente orquestrado com o Docker Compose, poderá fazer isso com o comando docker-compose down conforme mostrado abaixo:
Uma execução de amostra produz:
|
1 2 3 4 5 6 7 8 9 10 11 |
$ docker-compose down Stopping bookstoreapp_app_1 ... done Stopping bookstoreapp_db_1 ... done Removing bookstoreapp_app_1 ... done Removing bookstoreapp_db_1 ... done Removing network bookstoreapp_default |
Agora, se você fizer um docker-compose ps, ele mostrará que nenhum contêiner está em execução no momento.
|
1 2 3 4 5 |
$ docker-compose ps Name Command State Ports --------------------------------------------------------------- |
Também é possível usar o Docker compose para um ambiente de teste automatizado, no qual você aciona os contêineres do Docker, executa os testes e, em seguida, desmonta a infraestrutura completa, tudo com o Compose. Para obter uma visão geral detalhada do Docker compose, visite o site site oficial.
Esta postagem faz parte do Programa de Redação da Comunidade Couchbase