Ubuntu Juju está empezando a tomar mucho peso en los entornos de despliegue de herramientas o servicios, tanto en local como en la nube, por lo que pasamos a describir un poco la aplicación y nos meteremos de lleno en su instalación y funcionamiento.
Juju es un framework de orquestación que habilita el despliegue de servicios de infraestructura cloud (o en la nube), orientado principalmente a entornos distribuidos de servicios interrelacionados. Aquí, a los paquetes que luego desplegaremos, el equipo que los “empaqueta” los llama “charms” (hechizos, ya que Juju hace referencia a la magia o brujería que se practica en algunas regiones de África), que además de ser reutilizables por otros usuarios, incluyen los metadatos del servicio, dependencias para otros servicios, paquetes que necesitará para su despliegue, etc…
Ubuntu Juju, está disponible para desplegar tanto en entornos cloud públicas como Amazon Web Services, Rackspace hosting, Hp Public clouds o Windows Azure; como en entornos en la nube privados del estilo de Openstack. Igualmente, también podemos llevar a cabo un despliegue de aplicaciones a nivel local, donde no necesitaremos de éstos servicios anteriormente mencionados.
Pasamos ahora a describir un proceso de instalación y despliegue de servicios, de la web www.rodenas.org, escrito por su administrador ‘Ferdy’, que cómo no, empezará con:
~$ sudo apt-get install juju
Ahora inicializamos el entorno de juju. Primero invocaremos al comando que nos creará un archivo de entorno por defecto:
~$ juju error: No environments configured. Please edit: /home/frodenas/.juju/environments.yaml
Y editaremos el archivo añadiendo algunas líneas:
~$ vi /home/frodenas/.juju/environments.yaml environments: sample: type: ec2 ec2-uri: https://ec2.eu-west-1.amazonaws.com access-key: --- INSERTAR AQUI VUESTRA ACCESS-KEY DE AMAZON EC2 --- secret-key: --- INSERTAR AQUI VUESTRA SECRET-KEY DE AMAZON EC2 --- control-bucket: --- ELIMINADO POR SEGURIDAD - DEJAR EL VALOR POR DEFECTO --- admin-secret: --- ELIMINADO POR SEGURIDAD - DEJAR EL VALOR POR DEFECTO --- default-image-id: ami-66f6c512 default-instance-type: m1.large
Lo que hemos añadido ha sido:
- ec2-uri: aquí hemos puesto el endpoint de la región de Amazon EC2 que nos interesa, en este caso, la región EU West (Irlanda).
- access-key y secret-key: vuestras credenciales de Amazon EC2.
- default-image-id: aquí ponemos el nombre de la AMI de Amazon EC2 que se utilizará por defecto, en este caso, utilizaremos una imágen de Ubuntu Cloud 11.10 de 64 bits disponible en la región de EU West. El nombre de la AMI varia cada día, por lo que os recomiendo que comprobéis la lista actual de imágenes antes de utilizar la que yo he puesto.
- default-instance-type: aquí ponemos el tipo de instancia de Amazon EC2 que se utilizará por defecto, en este caso, como la instancia contendrá Cloud Foundry y diversos servicios (MySQL, MongoDB y Redis), escogemos la instancia grande (m1.large).
Bien, ahora hemos de arrancar el entorno. Pero antes, y debido a que los charms de juju que nos permiten instalar el servidor de Cloud Foundry y sus servicios todavía no están publicadas en los repositorios oficiales, nos tocará instalarlas manualmente en local:
~$ sudo apt-get install bzr ~$ mkdir charms && cd charms ~/charms$ bzr branch lp:~canonical-sig/+junk/cloudfoundry-server
Ahora si podemos arrancar el entorno de juju (generar antes un par de claves en vuestro sistema sino lo habéis hecho, de lo contrario el entorno no arrancará):
~/charms$ ssh-keygen -t rsa -b 2048 ~/charms$ juju bootstrap 2011-09-22 00:46:54,161 INFO Bootstrapping environment 'sample' (type: ec2)... 2011-09-22 00:47:01,753 INFO 'bootstrap' command finished successfully
Esto proceso lo que hará es crear una instancia en Amazon EC2 e instalarle el servidor de juju mediante cloud-init. Con el comando status podremos ver si el entorno está ya arrancado:
~/charms$ juju status No machines have addresses assigned yet 2011-09-22 00:47:11,893 ERROR No machines have addresses assigned yet
Vemos que la instancia todavía no está levantada. Nos vamos a la consola web de Amazon EC2 y esperamos a que arranque:
Una vez esté en marcha, volvemos a ejecutar el comando status:
~/charms$ juju status 2011-09-22 00:49:00,215 INFO Connecting to environment. machines: 0: {dns-name: ec2-46-51-151-139.eu-west-1.compute.amazonaws.com, instance-id: i-af00e1e6} services: {} 2011-09-22 00:49:01,834 INFO 'status' command finished successfully
Como veis, ahora si nos indica que hay una máquina en marcha. Ahora vamos a desplegar el servidor de Cloud Foundry. Para ello utilizaremos el comando deploy y la charm que nos hemos descargado anteriormente:
~/charms$ juju deploy --repository . cloudfoundry-server 2011-09-22 00:49:25,033 INFO Connecting to environment. 2011-09-22 00:49:27,823 INFO Charm deployed as service: 'cloudfoundry-server' 2011-09-22 00:49:27,825 INFO 'deploy' command finished successfully
Igual que en el caso anterior, esperamos a que arranqué la instancia, se despliegue el servidor y servicios de Cloud Foundry, y estos se pongan en marcha (tened paciencia, es un proceso un poco lento). Podemos ir consultando periódicamente el estado hasta que el servicio está en marcha (el campo “state” pasará de “null” a “installed” y finalmente “started“):
~/charms$ juju status 2011-09-22 00:55:17,906 INFO Connecting to environment. machines: 0: {dns-name: ec2-46-51-151-139.eu-west-1.compute.amazonaws.com, instance-id: i-af00e1e6} 1: {dns-name: ec2-46-137-3-58.eu-west-1.compute.amazonaws.com, instance-id: i-0503e24c} services: cloudfoundry-server: charm: local:cloudfoundry-server-26 relations: {} units: cloudfoundry-server/0: machine: 1 relations: {} state: started 2011-09-22 00:55:20,236 INFO 'status' command finished successfully
El siguiente paso será abrir los puertos necesarios para que nos podamos conectar con el servidor de Cloud Foundry. Para ello utilizaremos el comando expose (y no es necesario indicar los puertos a abrir, ya que estos están indicados en la charm):
~/charms$ juju expose cloudfoundry-server 2011-09-22 00:55:41,155 INFO Connecting to environment. 2011-09-22 00:55:42,485 INFO Service 'cloudfoundry-server' was exposed. 2011-09-22 00:55:42,486 INFO 'expose' command finished successfully
Consultamos el estado del servicio y veremos como ahora nos indica los puertos que están abiertos:
~/charms$ juju status 2011-09-22 00:55:45,701 INFO Connecting to environment. machines: 0: {dns-name: ec2-46-51-151-139.eu-west-1.compute.amazonaws.com, instance-id: i-af00e1e6} 1: {dns-name: ec2-46-137-3-58.eu-west-1.compute.amazonaws.com, instance-id: i-0503e24c} services: cloudfoundry-server: charm: local:cloudfoundry-server-26 exposed: true relations: {} units: cloudfoundry-server/0: machine: 1 open-ports: [80/tcp, 443/tcp, 4222/tcp] relations: {} state: started 2011-09-22 00:55:48,101 INFO 'status' command finished successfully
En teoria ahora está todo levantado, pero por si acaso, vamos a comprobarlo conectándonos a la máquina que contiene el servidor de Cloud Foundry. Para ello utilizaremos el comando ssh del propio juju y el número de máquina que nos ha indicado el comando status:
~/charms$ juju ssh 1 2011-09-22 00:56:14,640 INFO Connecting to environment. 2011-09-22 00:56:16,265 INFO Connecting to machine 1 at ec2-46-137-3-58.eu-west-1.compute.amazonaws.com
Una vez hayamos entrado, miraremos si los servicios de Cloud Foundry están levantados:
ubuntu@ip-10-228-250-63:~$ cd /opt/cloudfoundry-server/vcap/bin ubuntu@ip-10-228-250-63:/opt/cloudfoundry-server/vcap/bin$ sudo ./vcap status router : RUNNING cloud_controller : RUNNING dea : RUNNING health_manager : RUNNING redis_gateway : RUNNING redis_node : RUNNING mysql_gateway : RUNNING mysql_node : RUNNING mongodb_gateway : RUNNING mongodb_node : RUNNING
Como vemos, todos los servicios de Cloud Foundry están en marcha. Ya nos podemos desconectar de la instancia de Amazon EC2:
ubuntu@ip-10-228-250-63:/opt/cloudfoundry-server/vcap/bin$ exit Connection to ec2-46-137-3-58.eu-west-1.compute.amazonaws.com closed.
Ahora vamos a proceder a conectarnos a Cloud Foundry para ver si responde. Lo primero que deberemos hacer es bajarnos el cliente vmc:
~/charms$ sudo apt-get install ruby-vmc
Pero para poder conectarnos remotamente necesitamos disponer de un registro wildcard DNS que redirija nuestras peticiones hacia el servidor de Cloud Foundry. En nuestro caso, como es solo un experimento low cost, vamos a utilizar un truco. Lo que vamos a hacer en crear un tunel ssh de manera que las peticiones al puerto 80 de nuestra máquina se redirijan al puerto 80 de la instancia de Amazon EC2 que contiene el servidor de Cloud Foundry (si en vuestra máquina ya estáis utilizando el puerto 80, lo podéis cambiar a otro, por ejemplo, el 8080). Pero para poder montar el túnel contra la instancia de Amazon EC2, necesitamos tener la clave privada y que esta coincida con la clave pública almacenada en la instancia de Amazon EC2. Como en el archivo de entorno de juju no hemos especificado ningún par de claves, este ha utilizado el par de claves de nuestro usuario (de ahí que os recordaba anteriormente el generar un par de claves). Así pues, lo que haremos es indicar al ssh que utilice la clave privada de nuestro usuario:
~/charms$ cd ~/.ssh ~/.ssh$ sudo ssh -i id_rsa -L 80:46.137.3.58:80 [email protected] -N
El problema de este método es que nos bloquea la sesión de terminal, por lo que nos tocará abrir una nueva sesión. Una vez la tengamos, procederemos a probar la conexión contra Cloud Foundry:
~$ vmc target api.vcap.me Succesfully targeted to [http://api.vcap.me] ~$ vmc info VMware's Cloud Application Platform For support visit http://support.cloudfoundry.com Target: http://api.vcap.me (v0.999) Client: v0.3.10
Bien, parece que el servidor responde. Ahora vamos a crear un usuario:
~$ vmc register Email: [email protected] Password: ******** Verify Password: ******** Creating New User: OK Successfully logged into [http://api.vcap.me] ~$ vmc info VMware's Cloud Application Platform For support visit http://support.cloudfoundry.com Target: http://api.vcap.me (v0.999) Client: v0.3.10 User: [email protected] Usage: Memory (0B of 2.0G total) Services (0 of 16 total) Apps (0 of 20 total)
Perfecto! El servidor de Cloud Foundry ya está listo para ser usado!
Podríamos finalizar el experimento aquí, pero vamos a ir un poco más allá. En un teórico entorno de producción, seguramente nos quedaremos cortos con solo 1 instancia de Cloud Foundry y que esta incluya todos los servicios. Lo que haríamos es crear más instancias y albergar en cada una de ellas alguno de los servicios disponibles. Vamos a ver cómo lo podemos hacer con juju.
En primer lugar, nos descargamos los charms que nos interesen. Aquí os pongo los charms de los servicios de DEA (el agente de Cloud Foundry que ejecutará nuestras aplicaciones),MySQL, MongoDB y Redis:
~$ cd charms ~/charms$ bzr branch lp:~canonical-sig/+junk/cloudfoundry-server-dea ~/charms$ bzr branch lp:~canonical-sig/+junk/cf-mysql ~/charms$ bzr branch lp:~canonical-sig/+junk/cf-mongodb ~/charms$ bzr branch lp:~canonical-sig/+junk/cf-redis
Vamos a utilizar como ejemplo la instalación de un nuevo servidor de MongoDB. Utilizaremos igual que antes el comando deploy:
~/charms$ juju deploy --repository . cf-mongodb 2011-09-22 01:04:42,031 INFO Connecting to environment. 2011-09-22 01:04:45,147 INFO Charm deployed as service: 'cf-mongodb' 2011-09-22 01:04:45,149 INFO 'deploy' command finished successfully
Y esperaremos a que el servicio de MongoDB esté levantado (cuando aparezca “state: started“):
~/charms$ juju status 2011-09-22 01:11:07,813 INFO Connecting to environment. machines: 0: {dns-name: ec2-46-51-151-139.eu-west-1.compute.amazonaws.com, instance-id: i-af00e1e6} 1: {dns-name: ec2-46-137-3-58.eu-west-1.compute.amazonaws.com, instance-id: i-0503e24c} 2: {dns-name: ec2-79-125-44-111.eu-west-1.compute.amazonaws.com, instance-id: i-7b04e532} services: cf-mongodb: charm: local:cf-mongodb-1 relations: {mongodb-cluster: cf-mongodb} units: cf-mongodb/0: machine: 2 relations: mongodb-cluster: {state: up} state: started cloudfoundry-server: charm: local:cloudfoundry-server-26 exposed: true relations: {} units: cloudfoundry-server/0: machine: 1 open-ports: [80/tcp, 443/tcp, 4222/tcp] relations: {} state: started 2011-09-22 01:11:11,105 INFO 'status' command finished successfully
Ahora lo que debemos hacer es informar al servidor de Cloud Foundry de que tiene una nueva instancia de MongoDB disponible para ser usada. Para realizar esta acción, simplemente debemos establecer una relación entre las 2 instancias mediante juju, y este, mediante las instrucciones contenidas en la charm, hará las modificaciones pertinentes en el archivo de configuración de Cloud Foundry. Así pués, vamos a ello:
~/charms$ ~/charms$ juju add-relation cloudfoundry-server cf-mongodb 2011-09-22 01:11:36,088 INFO Connecting to environment. 2011-09-22 01:11:37,997 INFO Added cf-server relation to all service units. 2011-09-22 01:11:37,997 INFO 'add_relation' command finished successfully
Consultamos ahora el estado y vemos que nos aparece la relación:
~/charms$ juju status 2011-09-22 01:11:51,639 INFO Connecting to environment. machines: 0: {dns-name: ec2-46-51-151-139.eu-west-1.compute.amazonaws.com, instance-id: i-af00e1e6} 1: {dns-name: ec2-46-137-3-58.eu-west-1.compute.amazonaws.com, instance-id: i-0503e24c} 2: {dns-name: ec2-79-125-44-111.eu-west-1.compute.amazonaws.com, instance-id: i-7b04e532} services: cf-mongodb: charm: local:cf-mongodb-1 relations: {cf-server: cloudfoundry-server, mongodb-cluster: cf-mongodb} units: cf-mongodb/0: machine: 2 relations: cf-server: {state: up} mongodb-cluster: {state: up} state: started cloudfoundry-server: charm: local:cloudfoundry-server-26 exposed: true relations: {cf-server: cf-mongodb} units: cloudfoundry-server/0: machine: 1 open-ports: [80/tcp, 443/tcp, 4222/tcp] relations: cf-server: {state: up} state: started 2011-09-22 01:11:55,279 INFO 'status' command finished successfully
Vamos a comprobar si el servicio está levantado en Cloud Foundry mediante una conexión ssh de juju:
~/charms$ juju ssh 2 2011-09-22 01:12:17,200 INFO Connecting to environment. 2011-09-22 01:12:18,813 INFO Connecting to machine 2 at ec2-79-125-44-111.eu-west-1.compute.amazonaws.com ubuntu@ip-10-58-121-108:~$ cd /opt/cloudfoundry-server/vcap/bin ubuntu@ip-10-58-121-108:/opt/cloudfoundry-server/vcap/bin$ sudo ./vcap status router : STOPPED cloud_controller : STOPPED dea : STOPPED health_manager : STOPPED redis_gateway : STOPPED redis_node : STOPPED mysql_gateway : STOPPED mysql_node : STOPPED mongodb_gateway : RUNNING mongodb_node : RUNNING ubuntu@ip-10-58-121-108:/opt/cloudfoundry-server/vcap/bin$ exit Connection to ec2-79-125-44-111.eu-west-1.compute.amazonaws.com closed.
Vemos cómo en esta instancia solamente se está ejecutando el servicio de MongoDB. Si viésemos que necesitamos otra instancia adicional de MongoDB, en este caso no haría falta ejecutar los comandos anteriores. Simplemente utilizando el comando add-unit nos crearía una nueva instancia que formaría parte de un cluster de MongoDb y con la relación con el servidor de Cloud Foundry creada por defecto:
~/charms$ juju add-unit cf-mongodb
Y hasta aquí llega el experimento. Si tenéis cualquier problema ejecutando alguno de los pasos anteriores y no sabéis que está pasando, podéis utilizar el comando debug-log para ver el log del servidor de juju e intentar determinar la causa del problema:
~/charms$ juju debug-log 2011-09-22 01:13:31,421 INFO Connecting to environment. 2011-09-22 01:13:32,588 INFO Enabling distributed debug log. 2011-09-22 01:13:32,696 INFO Tailing logs - Ctrl-C to stop.
Como último paso, como siempre, recordar que hay que finalizar el entorno. Utilizaremos para ello el comando destroy-environment:
~/charms$ juju destroy-environment WARNING: this command will destroy the 'sample' environment (type: ec2). This includes all machines, services, data, and other resources. Continue [y/N]yes 2011-09-22 01:14:02,900 INFO Destroying environment 'sample' (type: ec2)... 2011-09-22 01:14:04,644 INFO Waiting on 3 EC2 instances to transition to terminated state, this may take a while 2011-09-22 01:14:27,728 INFO 'destroy_environment' command finished successfully
Este comando debería eliminar también las instancias de Amazon EC2, pero por si acaso, no está de más que lo comprobéis vosotros mismos en la consola web de Amazon EC2.