CONFIGURAR Y DESPLEGAR CONTENEDORES
Llevo tiempo que uso Digital Ocean (https://www.digitalocean.com/) más que nada para tener publicada esta web a modo de blog y lugar de "ensayo".
La primera versión del blog, ya que soy un tanto "cabezón", y que no me gusta que me den las cosas trilladas, pues en lugar de usar alguna solución estilo wordpress, decidí montármelo de cero a la par que volvía a usar groovy, un lenguaje que realmente me encanta, junto con docker que tenía mucha curiosidad.
Mi elección de Digital Ocean se basó en compatibilidad para desplegar contenedores junto a un precio asequible (conseguí un cupón de 20€ de regalo) pero eso es otra historia.
El tema es que quería montar una aplicación para ver cómo de fácil podía llegar a ser tenerlo con contenedores por las ventajas que ello puede darte. El objetivo era una arquitectura en la que un nginx hiciera de punto de entrada y que, por dentro, se comunicara con un tomcat. Ese tomcat a su vez serviría una aplicación grails conectada a un mysql y a un mongodb. Todos ellos como contenedores independientes pero conectados entre sí y solo exponiendo el contenedor del nginx. Interesante, ¿no?
Pues, ¡manos a la obra!
Después de crear un webapp chorra con grails (el de por defecto al crear un proyecto nuevo), comencé a añadir complejidad al asunto. Lo primero fue conectar la aplicación con un contenedor que tuviera un mysql. Una vez seteada la configuración apropiadamente (más abajo os comento), pasé al siguiente objetivo; otro contenedor pero con mongodb. Y así hasta llegar al punto de emplazar el nginx como único punto de entrada.
Dicho así podría parecer sencillo, pero para un tipo como yo, que estaba empezando con docker y con nociones mínimas de sistemas... fue algo más complicado con obligadas lecturas para llegar al objetivo, aunque como se suele decir, "sarna con gusto no pica".
Al final, ves el archivo de docker-compose resultado y te sorprendes de lo sencillo y legible que es:
nginx:
image: nginx:1.9
ports:
- "80:80"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf:ro"
- "./nginx/share/:/usr/share/nginx/:ro"
links:
- web:mallotore
web:
image: mallotore/tomcat8-openjdk7
links:
- mysql
- mongodb
volumes:
- "./tomcat/webapps/:/usr/local/tomcat/webapps/"
- "./tomcat/conf/:/usr/local/tomcat/conf/"
mysql:
image: mysql:5.5
environment:
- MYSQL_ROOT_PASSWORD=your_password
mongodb:
image: mongo:3.2
volumes:
- "./mongodb/data/db:/data/db"
Sin entrar a explicar docker, su sintaxis, que son los volúmenes, links y demás, que para eso tienes sitios mucho mejores que esta web, podrás observar que hay 4 contenedores, pero el único expuesto hacía fuera es el del nginx (ports: 80).
Este es un ejemplo customizado a mi objetivo pero, como ves, en un par de líneas puedes montar algo bastante potente. A resaltar, salvo la imagen de tomcat con el openjdk que me creé yo mismo, por entender cómo funciona docker, el resto son imágenes ya publicadas y listas para tu disfrute (la mía también). Probablemente querrás usar configuración propia en algunos casos, como por ejemplo tu propia configuración de nginx, así que ayudándote de los "volumes" puedes conseguirlo. Se podrían entender como "enlaces" desde tu máquina al contenedor que le obliga a usarlo, de tal manera que puedes sobreescribir la configuración del nginx del contenedor, por ejemplo, pasándole el tuyo. Es una alternativa, en mi opinión, flexible, ya que podrías optar por crear un contenedor, directamente, con la configuración deseada.
Recuerdo que uno de los puntos en donde estuve un "rato" fue en configurar por variables de entorno mi webapp con los valores de los contenedores del mysql y mongodb para su correcta comunicación. La clave fue acceder y conocer los contenedores que estaba usando ya que me ofrecían lo que necesitaba.
Un ejemplo de cómo quedó mi configuración de mi webapp grails es:
docker:
grails:
serverURL: http://localhost:8080
mongo:
host: ${MONGODB_PORT_27017_TCP_ADDR}
port: ${MONGODB_PORT_27017_TCP_PORT}
username: username
password: password
myCollection: myCollection
database: docker
dataSource:
dbCreate: update
url: jdbc:mysql://${MYSQL_PORT_3306_TCP_ADDR}:${MYSQL_PORT_3306_TCP_PORT}
password: password
properties:
jmxEnabled: true
initialSize: 5
maxActive: 50
minIdle: 5
maxIdle: 25
maxWait: 10000
maxAge: 600000
timeBetweenEvictionRunsMillis: 5000
minEvictableIdleTimeMillis: 60000
validationQuery: SELECT 1
validationQueryTimeout: 3
validationInterval: 15000
testOnBorrow: true
testWhileIdle: true
testOnReturn: false
jdbcInterceptors: ConnectionState
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
Perfecto, ya tenemos en local montado lo que queríamos. Ahora toca publicarlo en Digital Ocean. Para ello, la propia documentación que ofrecen es muy buena. Además, tengo que añadir que el trato con el cliente es más que bueno, al menos en mi caso.
A continuación os detallo los pasos que seguí:
- 1. docker-machine create --driver digitalocean --digitalocean-access-token YOUR_API_TOKEN mallotore
Creating CA: /home/mallotore/.docker/machine/certs/ca.pem
Creating client certificate: /home/mallotore/.docker/machine/certs/cert.pem
Running pre-create checks...
Creating machine...
(mallotore) Creating SSH key...
(mallotore) Creating Digital Ocean droplet...
(mallotore) Waiting for IP address to be assigned to the Droplet...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with ubuntu(systemd)...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env mallotore
- 2. docker-machine env mallotore
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://XXX.XXX.XXX.XX:XXXXX"
export DOCKER_CERT_PATH="/home/mallotore/.docker/machine/machines/mallotore"
export DOCKER_MACHINE_NAME="mallotore"
# Run this command to configure your shell:
# eval $(docker-machine env mallotore) - 3. eval $(docker-machine env mallotore)
- 4. docker-machine scp -r digitalOcean/ mallotore:/etc/local (copiado de todo mi proyecto al droplet)
- 5. docker-machine ssh mallotore (conexión al droplet)
- 6. apt install docker-compose
- 7. Como uso el droplet más básico (512Mb Memory, 1 Core Processor, 20Gb SSD disk, 1Tb transfer) que sale actualmente a 5€ al mes, necesité añadir swap para que funcionara correctamente todo https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04
sudo fallocate -l 4G /swapfile
ls -lh /swapfile
sudo chmod 600 /swapfile
ls -lh /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile- 8. docker-compose up
Después de estos pasos de publicación, sin entrar en la configuración del dominio que en mi caso compré, pude comprobar lo sencillo que puede llegar a ser montarse una aplicación en "producción" (es de andar por casa) usando docker.