Ratnopam Chakrabarti es un desarrollador de software que trabaja actualmente para Ericsson Inc. Lleva bastante tiempo centrado en IoT, tecnologías máquina a máquina, coches conectados y dominios de ciudades inteligentes. Le encanta aprender nuevas tecnologías y ponerlas en práctica. Cuando no está trabajando, le gusta pasar tiempo con su hijo de 3 años.
Introducción
Bienvenido a la segunda parte de la serie en la que describo cómo desarrollar y ejecutar una aplicación web Spring Boot totalmente funcional y potenciada por Couchbase utilizando el conjunto de herramientas Docker. En primera parte de la serie, demostré cómo ejecutar dos contenedores Docker para ejecutar una aplicación funcional con una interfaz de usuario presentable. Los dos contenedores Docker que estábamos ejecutando son:
- A Contenedor Couchbase con ajustes preconfigurados
- Un contenedor de aplicación hablando con el contenedor Couchbase (Ejecutado en el paso 1)
Aunque este método es útil, no está totalmente automatizado, es decir, no existe la orquestación automatizada. Tienes que ejecutar dos comandos de ejecución de Docker diferentes para ejecutar toda la configuración.
¿Hay alguna forma de construir y ejecutar el contenedor de la aplicación que también active la ejecución del contenedor de Couchbase? Por supuesto que hay una manera.
Entrar en Docker Compose
Utilizando Docker Composepuedes orquestar la ejecución de entornos multicontenedor, que es exactamente lo que necesitamos para nuestro caso de uso. Necesitamos ejecutar el contenedor Couchbase primero, y luego el contenedor de la aplicación debe ejecutarse y hablar con el contenedor Couchbase.
Aquí está el archivo docker-compose.yml para lograr esto:
|
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 |
Nuestra app "depende_de" la imagen db que es el contenedor Couchbase. En otras palabras, el contenedor Couchbase se ejecuta primero y luego el contenedor de la aplicación. Hay un problema potencial aquí: la palabra clave "depends_on" no garantiza que el contenedor Couchbase haya terminado de configurar la imagen y haya empezado a ejecutarse. Todo lo que asegura es que el contenedor se inicie primero; no comprueba si el contenedor está realmente ejecutándose o listo para aceptar peticiones de una aplicación. Para asegurarnos de que el contenedor de Couchbase se está ejecutando y que todos los pasos de preconfiguración, como la configuración de la consulta, los servicios de índice y el bucket, se han completado, necesitamos hacer una comprobación desde el contenedor de la aplicación.
Este es el Dockerfile del contenedor de la aplicación que invoca un script que, a su vez, comprueba si el bucket "books" ya ha sido configurado o no. Entra en un bucle hasta que el bucket está configurado y entonces activa el contenedor de la aplicación.
https://github.com/ratchakr/bookstoreapp/blob/master/Dockerfile-v1
El guión puede verse en https://github.com/ratchakr/bookstoreapp/blob/master/run_app.sh
El script hace lo siguiente
Utiliza el endpoint REST soportado por Couchbase para consultar el bucket.
Curl se utiliza para llamar a los puntos finales REST. La instalación de curl está cubierta en el Dockerfile de la aplicación.
El script analiza la respuesta JSON de la llamada REST utilizando una herramienta llamada jq.
Si el cubo está configurado, ejecuta el contenedor de aplicaciones; de lo contrario, espera a que el cubo se configure primero.
Vale la pena mencionar que se pueden añadir más comprobaciones, como verificar si el servicio de índice y el servicio de consulta están configurados correctamente o no, en el script de shell para hacerlo más robusto. Una palabra de precaución es confirmar tu caso de uso particular y los requisitos antes de seguir el enfoque docker-compose; no hay una manera segura de determinar si el contenedor db Couchbase está completamente en marcha y listo para servir peticiones de la aplicación cliente. Algunos de los enfoques que podrían funcionar son los siguientes:
- Si dispone de un bucket preconfigurado, puede comprobar si el bucket existe
- Compruebe si los índices están en su sitio
- Si conoce el recuento de registros de un bucket (digamos que de un archivo .csv que se ha importado a un bucket en el momento de la carga inicial de datos), puede comprobar si el recuento coincide con el número de registros del archivo .csv). Para nuestro caso de uso, el mencionado anteriormente funciona bien.
Construir y ejecutar
Ahora que tenemos nuestro archivo docker-compose y Dockerfile, podemos construir la imagen de la aplicación mediante el simple comando docker-compose up mando.
Aquí está el fragmento de salida de la consola 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 |
En este punto, nuestra aplicación está en funcionamiento con un único comando de orquestación docker-compose.
Tipo 192.168.99.100:8080 en el navegador; debería ver la siguiente pantalla:

Docker Compose es una buena forma de orquestar entornos Docker multicontenedor. Tiene cadenas de comandos casi similares a los conjuntos de comandos "docker". Por ejemplo, para ver una lista de contenedores en ejecución, simplemente escriba:
docker-compose ps > que le daría
|
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 |
Los nombres de los contenedores aparecen aquí en negrita.
Si necesita detener o desmantelar su entorno orquestado con Docker Compose, puede hacerlo con el comando docker-compose down como se muestra a continuación:
Una ejecución de muestra produce:
|
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 |
Ahora, si haces un docker-compose ps, muestra que ningún contenedor se está ejecutando actualmente.
|
1 2 3 4 5 |
$ docker-compose ps Name Command State Ports --------------------------------------------------------------- |
También puede utilizar Docker compose para un entorno de pruebas automatizado en el que se encienden los contenedores Docker, se ejecutan las pruebas y, a continuación, se desmonta toda la infraestructura, todo ello con Compose. Para obtener una descripción detallada de Docker compose, visite la página sitio web oficial.
Este post forma parte del Programa de Escritura de la Comunidad Couchbase