Category Archives: Linux

Lanzar Workers de Jenkins en AWS

En esta entrada veremos lo sencillo que resulta configurar Jenkins para levantar instancias en AWS EC2 para el entorno de CI.

1. Crear la AMI con packer.

Tenemos ya algunos nodos en el entorno de CI que se provisionan con Ansible. Utilizamos packer y la receta de ansible para crear una imagen con todo lo necesario para los jobs de Jenkins.

El fichero Json para packer

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "{{user `aws_access_key`}}",
    "secret_key": "{{user `aws_secret_key`}}",
    "region": "eu-west-1",
    "source_ami": "ami-a8d2d7ce",
    "instance_type": "t2.small",
    "ssh_username": "ubuntu",
    "ami_name": "codeurjc-jenkins-worker {{ timestamp }}"
  }],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "sudo apt-get update",
        "sudo apt-get install -y python"
      ]
    },
    {
      "type": "ansible",
      "playbook_file": "./playbook.yml",
      "user": "ubuntu"
    }]
}
$ packer build -var 'aws_access_key=ACCESS_KEY' -var 'aws_secret_key=SECRET_KEY' packer-jenkins-worker.json

2. Configuración de seguridad

Por un lado tenemos que crear un usuario para manejar la API. Vamos a nuestra consola de AWS y clickamos AMI, en Users le damos a Add user, le damos un nombre por ejemplo jenkins y en Access type elegimos Programmatic access. En el siguiente paso otorgamos permisos al usuario para manejar el servicio de EC2 creando un grupo especifico para ello, si no lo tenemos creado previamente. Repasamos y creamos el usuario, veremos las claves para acceder, copiar y guardarlas en lugar seguro.

Ahora vamos a crear un grupo de seguridad para las instancias que levantemos de Jenkins. Tenemos que permitir acceso por SSH a la instancia, asi que nos vamos a la consola de EC2 en el apartado de Security group y creamos uno nuevo (si no está creado previamente) y damos permisos para acceder por SSH.

Por último tenemos que importar la clave pública que permitirá a Jenkins configurar los nodos que despleguemos en AWS. Vamos a la consola de EC2, Key Pairs y hacemos click en Import Key Pair, en el cuadro de diálogo pegamos la clave pública que usamos en los nodos de nuestra infraestructura. Le ponemos un nombre por ejemplo Jenkins

3. Plugin de Jenkins

En Jenkins necesitamos este plugin.

La configuración es secilla, vamos a Manage Jenkins -> Cloud -> New cloud

Le ponemos un nombre descriptivo.

Añadimos las credenciales que hemos creado en el paso 2.

Seleccionamos la región, en mi caso eu-west-1

Para la clave, como tenemos workers en nuestra infraestructura tenemos que pegar la clave privada que tiene Jenkins.

Podemos ahora probar que la conexión a la API de AWS funciona.

Pasamos a la configuración de la AMI.

De nuevo un nombre descriptivo

La ID de la AMI que hemos creado con Packer anteriormente.

El tipo de instancia, como tenemos mucha carga usamos T2Large.

De nuevo la zona de disponiblidad, eu-west-1a

Introducimos el grupo de seguridad que hemos creado en AWS para que nos permita acceder por SSH a la instancia.

En el usuario remoto, nosotros usamos jenkins.

El tipo de AMI es obviamente una UNIX, esto es necesario porque dependiendo del tipo, la conexión se hace de una forma u otra.

Añadir el label para asignar trabajos al nodo.

En el uso ponemos que solo ejecute jobs que coincidan con el nodo.

En Idle termination time establecemos los minutos que tiene que estar la instancia ociosa antes de que se apague (stop o terminate).

En Init script podemos escribir algunas instrucciones necesarias en tiempo de arranque para la instancia, por ejemplo podríamos provisionar la instancia haciendo que se clonara el repo de Ansible y ejecutarlo con conexión local, en nuestro caso la AMI ya viene completa y no necesitamos nada.

Desplegamos más opciones haciendo click en Advance. Las opciones que más nos interesan son:

Override temporary dir location nos permite establecer un directorio temporal donde copiar el slave.jar para ejecutar Jenkins.

User data, para pasar información a la instancia.

Number of Executors, depende del Instance type que hayamos elegido, en nuestro caso 8.

Stop/Disconnect on Idle Timeout, si elegimos esta opción la instancia se parará, no se destruirá, esto con los disco EBS puede repercutir en cargos adicionales a la factura.

Subnet ID for VPC, para establecer la red a la que debe estar conectada la instancia.

Instance Cap, el limite de instancias a levantar en AWS, a más instancias más factura.

Block device mapping, elegimos un volumen EBS personalizado porque el de 8 GB que viene de serie es demasiado pequeño, la línea queda de esta manera.

/dev/sda1=:120:true:::

De forma que el disco raiz se mapea a un dispositivo que se creara en el momento de lanzar la instancia con 120GB y se borrará cuando se destruya la instancia.

Podemos conservar el volumen con false. Si ya tenemos algún disco provisionado podemos poner el nombre entre el igual y los dos puntos.

4. Configurar el Job

Ahora solo nos quedaría configurar un job con el label que hemos elegido para las AMIs, esto se entrando en la configuración de Job en cuestión y en el campo Restrict where this project can be run colocar el label.

Figlet as a Service

Todo comenzó cuando quise poner un ASCII Art a las máquinas para el fichero /etc/motd. Para hacerlo quería usar un playbook de Ansible que me permitiera generar el código ASCII utilizando como entrada en nombre del host.

Me puse a investigar y a sopesar las opciones:

  1. Podía instalar figlet en cada máquina y generar el ASCII Art.
  2. Podía usar alguna API que proporcionara algún método para obtener los ASCII Art en remoto

La primera opción no me convence porque tengo que instalar un paquete que solo se va a usar una vez y la segunda menos porque las opciones que encontré eran de pago y algunas máquinas no tienen salida a Internet.

Así pensé utilizar una combinación de ambas y crearme mi propio servicio de figlet. No ha sido demasiado complicado crearme un par de contenedores docker que para ofrecer el servicio a la infraestructura.

Dockerizando Figlet

Lo primero que hemos hecho ha sido buscar en Docker Hub el contenedor para PHP que ejecute FPM. Delante de este contenedor colocamos otro contenedor NGINX que actúa como frontend de la aplicación.

Esto no es complicado, porque ya está hecho, el hub oficial de PHP tiene un tag para FPM. A este contenedor hay que instalarle el paquete de figlet. Con apt se hace. Se escribe este cambio en el Dockerfile y se construye la imagen.

El contenedor de NGINX hay que configurarlo para que haga de proxy al php-fpm

Escribimos el código para leer la URL de la que sacaremos el nombre del host. Tenemos en cuenta si viene vacía, o si es mayor a 32 caracteres, ya que la RFC considera que el tamaño máximo de nombre de host es de 32 caracteres. También para este caso se pasa un ancho de columna a figlet de 160 caracteres, para que no salga cortado, en cualquier caso es raro que un nombre de host sobrepase los 15 caracteres, al menos en las infraestructuras que yo administro.

Construida la imagen, se escribe el docker-compose.yaml para vincular el nginx con el php-fpm. Se establece la política de restart, se exponen los puertos y se habilitan los volumenes.

Publicado

Está publicado aquí

Fuentes

Y las fuentes en mi github por si alguien quiere investigar o montarlo en su infraestructura.

Publicar una Aplicación de DJango en un Contenedor Docker

Podemos estar tentados de pasar a producción el contenedor Docker con el runserver que proporciona el manager.py de DJango. Pero esto es un gravísimo error de seguridad. En la siguiente entrada explicaremos como crear el contenedor Docker con el módulo wsgi de Apache.

En la siguiente entrada veremos lo sencillo que es construir nuestra imagen para Docker de nuestra App de DJango con el Dockerfile que nos proporciona Graham Dumpleton.

Lo único que necesitamos es el código DJango de la aplicación (obviamente) y el fichero requirements.txt que debe estar en la raiz donde vamos a colocar nuestro Dockerfile.

Pongamos que nuestro requirements.txt tiene este aspecto:

numpy==1.6.2
Django==1.4.2
django-tastypie==0.9.14
pyes==0.19.1

Lo siguiente que necesitamos conocer es el dónde colocar los estáticos tanto la URL como la ubicación física en el directorio.

Lo típico es poner los estáticos bajo la URL /static/ y en el disco en el directorio static de nuestra aplicación. Debemos conocer estos datos para pasarlo al comando con el que arrancar la imagen.

Bien, como decíamos, partimos de la imagen siguiente

FROM grahamdumpleton/mod-wsgi-docker:python-2.7-onbuild

Usaremos onbuild porque tiene dos disparadores interesantes que nos simplifican muchísimo la vida. El primero copia el contenido del directorio actual a /app y el segundo ejecuta

pip install -r requirements.txt

Con el contenido de nuestro fichero de requirements.

La única línea que tenemos que añadir a nuestro Dockerfile sería la siguiente:

CMD ["--url-alias", "/static", "awesomeapp/static", "awesomeapp/wsgi.py"]

Y la construimos

# docker build -t awesomeapp-wsgi .

Ya podemos ponerla en producción sin riesgo.

# docker run -d -p 80:80 --name awesomeapp-pro awesomeapp-wsgi

Referencias:

  1. http://blog.dscpl.com.au/2014/12/hosting-python-wsgi-applications-using.html
  2. https://hub.docker.com/r/grahamdumpleton/mod-wsgi-docker/
  3. https://github.com/GrahamDumpleton/mod_wsgi-docker

VirtualBox: Levantar Máquinas Desde la Consola

En el caso que necesitemos levantar alguna máquina virtual de VirtualBox desde la consola, bien porque no tengamos entorno gráfico, bien porque estemos en una sesión SSH, el procedimiento es bastante sencillo.

En primer lugar debemos identificar el ID de la máquina en cuestión, que lo hacemos así.

vboxmanage list vms

Veremos algo como esto:

"DebianApache" {627b6646-6aa3-4db7-ae86-c05cbbd204ab}
"Debian-PXE-DHCP-FTP-Server" {f4882e22-9216-4b8d-a1ac-c160cbb60fe0}
"Debian-6.0-ClonBlog" {158cf271-87b7-4af2-b1c9-248520480ee7}
"Windows" {4b9523ad-a08a-4412-83c8-bd59ac3670df}
"Debian-JMeter-Cookbook" {46a89076-e079-4135-ac95-834e1fde7df0}
"Linux Mint" {c49d2f32-da3b-4243-af8a-e5e4e04f27bb}
"Debian 7 Django" {fa63dab2-4a12-48a6-9edc-6ed412989a7f}
"Debian 7 Asterisk OpenWebinars" {5e418161-7e3e-4b72-b980-7756fceaeedd}
"Debian NGINX" {07b812af-7dad-45cb-94e7-975df59b783d}
"Debian 7 Database" {07c41d80-bd81-4d84-8718-e441c06739b9}
"Debian 7 WebServer" {11435e1c-f421-45c4-89d6-5743596d2410}
"Ubuntu-LEMP-Varnish" {b3dbfb0d-d0d0-41bf-a36b-08db8fabdafc}
"Debian GlusterFS #1" {1d6206ad-b0c0-4a35-aea0-f990f76903ce}
"Debian GlusterFS #2" {75566833-2cb6-4279-aed1-9b6b374728fd}
"Debian GlusterFS Client" {3177a875-c5b3-4c56-b456-d9646d786f72}
"CentOS Gluster #1" {e58beaf2-4dba-4fc9-ad3d-5658f62b0dea}
"CentOS Gluster #2" {da99b182-884f-442e-91f6-877eb7dd8428}
"CentOS Gluster #3" {2d89ca31-bc31-4b41-831b-fec413c5abf9}
"CentOS GlusterFS Client" {2f396eab-8a02-47bb-bc53-761dad6a3a6a}
"Zentyal 3.5" {a5f70d06-f044-4969-8b57-e4bb9f963337}
"Ubuntu" {3b7d4c85-f4d4-4a42-a072-0bd143b55785}
"Centos LAMP WordPress" {7b45f364-ef43-4198-b047-7dcad484c812}
"Debian-7-Tomcat" {397eb08a-75b7-4ebe-b98a-69a89acbe122}

Y ya sólo elegimos la máquina que queremos levantar, por ejemplo la base de datos que tenemos en Debian 7

vboxmanage startvm 07c41d80-bd81-4d84-8718-e441c06739b9 --type headless

Y listo.

Monitorizar GlusterFS

Ayer vimos como construir un cluster de almacenamiento distribuido con GlusterFS y CentOS. Hoy vamos a ver las herramientas que ofrece el propio Gluster para monitorizar el rendimiento.

Preparando el volumen

Antes de poder consultar el rendimiento tenemos que habilitarlo en la definición del volumen. Para ello hacemos.

# gluster volume profile testvol start

Ahora veremos la siguiente información a la salida del estado del volumen.

# gluster volume info

Volume Name: testvol
Type: Stripe
Volume ID: f922da05-737d-4fb5-83cc-e50d6782b90c
Status: Started
Number of Bricks: 1 x 4 = 4
Transport-type: tcp
Bricks:
Brick1: server1.example.com:/data
Brick2: server2.example.com:/data
Brick3: server3.example.com:/data
Brick4: server4.example.com:/data
Options Reconfigured:
diagnostics.count-fop-hits: on
diagnostics.latency-measurement: on
auth.allow: 192.168.1.*

Mostrar la entrada/salida

# gluster volume profile testvol info
Brick: server1.example.com:/data
--------------------------------
Cumulative Stats:
   Block Size:               4096b+ 
 No. of Reads:                    0 
No. of Writes:                    4 
 %-latency   Avg-latency   Min-Latency   Max-Latency   No. of calls         Fop
 ---------   -----------   -----------   -----------   ------------        ----
      0.00       0.00 us       0.00 us       0.00 us              1        STAT
      0.00       0.00 us       0.00 us       0.00 us              2      FORGET
      0.00       0.00 us       0.00 us       0.00 us              3     RELEASE
      0.00       0.00 us       0.00 us       0.00 us             24  RELEASEDIR
      0.85     250.00 us     250.00 us     250.00 us              1     SETATTR
      1.50     440.00 us     440.00 us     440.00 us              1       FSTAT
      1.51     222.00 us     200.00 us     244.00 us              2       FLUSH
      1.66     488.00 us     488.00 us     488.00 us              1      STATFS
      1.70     500.00 us     500.00 us     500.00 us              1        READ
      2.47     363.00 us     306.00 us     420.00 us              2      UNLINK
      5.15     504.33 us     471.00 us     539.00 us              3      CREATE
      8.20     602.50 us     324.00 us    1221.00 us              4       WRITE
     15.00    4411.00 us    4411.00 us    4411.00 us              1       FSYNC
     16.82     235.48 us     154.00 us     344.00 us             21     OPENDIR
     45.15     282.43 us     129.00 us    1694.00 us             47      LOOKUP
 
    Duration: 4233 seconds
   Data Read: 0 bytes
Data Written: 16384 bytes
 
Interval 1 Stats:
   Block Size:               4096b+ 
 No. of Reads:                    0 
No. of Writes:                    4 
 %-latency   Avg-latency   Min-Latency   Max-Latency   No. of calls         Fop
 ---------   -----------   -----------   -----------   ------------        ----
      0.00       0.00 us       0.00 us       0.00 us              1        STAT
      0.00       0.00 us       0.00 us       0.00 us              2      FORGET
      0.00       0.00 us       0.00 us       0.00 us              2     RELEASE
      0.00       0.00 us       0.00 us       0.00 us             21  RELEASEDIR
      0.85     250.00 us     250.00 us     250.00 us              1     SETATTR
      1.50     440.00 us     440.00 us     440.00 us              1       FSTAT
      1.51     222.00 us     200.00 us     244.00 us              2       FLUSH
      1.66     488.00 us     488.00 us     488.00 us              1      STATFS
      1.70     500.00 us     500.00 us     500.00 us              1        READ
      2.47     363.00 us     306.00 us     420.00 us              2      UNLINK
      5.15     504.33 us     471.00 us     539.00 us              3      CREATE
      8.20     602.50 us     324.00 us    1221.00 us              4       WRITE
     15.00    4411.00 us    4411.00 us    4411.00 us              1       FSYNC
     16.82     235.48 us     154.00 us     344.00 us             21     OPENDIR
     45.15     282.43 us     129.00 us    1694.00 us             47      LOOKUP
 
    Duration: 3767 seconds
   Data Read: 0 bytes
Data Written: 16384 bytes

Esta información se repite por cada uno de los bricks que conforman el cluster.

Comandos TOP de Gluster

Hay una serie de comandos que nos muestran los picos de rendimiento del cluster, son los siguientes.

Ver los descriptores abiertos y la cuenta máxima de descriptores

# gluster volume top testvol open brick server1.example.com:/data
Brick: server1.example.com:/data
Current open fds: 1, Max open fds: 2, Max openfd time: 2014-07-30 09:39:44.312759

Ver ranking de llamadas a lectura de fichero

# gluster volume top testvol read brick server1.example.com:/data
Brick: server1.example.com:/data
Count		filename
=======================
1		/file.txt

Ver ranking de llamadas a escritura de fichero

# gluster volume top testvol write brick server1.example.com:/data
Brick: server1.example.com:/data
Count		filename
=======================
4		/.file.txt.swp

Ver ranking de llamadas abiertas en directorios

# gluster volume top testvol opendir brick server1.example.com:/data
Brick: server1.example.com:/data
Count		filename
=======================
21		/prueba

Ver ranking de llamadas de lecturas en directorio

# gluster volume top testvol readdir brick server1.example.com:/data
Brick: server1.example.com:/data
Count		filename
=======================
4		/prueba

Ver la lista del rendimiento en lectura en cada brick

# gluster volume top testvol read-perf bs 256 count 1 brick server1.example.com:/data
Brick: server1.example.com:/data
Throughput 6.24 MBps time 0.0000 secs
MBps Filename                                        Time                      
==== ========                                        ====                      
   0 /file.txt                                       2014-07-30 09:39:44.388815

Ver la lista del rendimiento en escritura en cada brick

# gluster volume top testvol write-perf bs 256 count 1 brick server1.example.com:/data
Brick: server1.example.com:/data
Throughput 8.26 MBps time 0.0000 secs
MBps Filename                                        Time                      
==== ========                                        ====                      
  27 /prueba/.file.xls.swp                           2014-07-30 10:50:37.671327
  18 /.file.swp                                      2014-07-30 10:50:13.860439
   0 /prueba/file.xls                                2014-07-30 10:52:13.528054
   0 /file                                           2014-07-30 10:50:13.829870

Fuente

Es una chuleta de la documentación oficial que se puede consultar aquí y está más documentada pero la sintaxis de los comandos no está actualizada a día de hoy.