sábado, marzo 24, 2018

Desplegar máquinas en Amazon EC2 con ayuda de Ansible

Para hacer ciertas tareas, despliego máquinas en la nube EC2 de Amazon. Con ayuda de varios scripts y ssh, desde mi ordenador voy realizando trabajos necesito. Cuando acabo, destruyo las máquinas virtuales para que no tenga coste para la empresa.

Llevaba un tiempo pensando como automatizar de una manera sencilla esta operación. Sé que en Amazon se puede hacer algo similar con CloudFormation e incluso llamar a ese API de Amazon desde scripts escritos en Python, pero quería ver si fuera posible hacer algo más sencillo y con lo que tuviese alguna experiencia previa.

Conozco la herramienta de automatización Ansible de otro proyecto en el que estuve trabajando hace dos años. Hacía bastante tiempo que no la usaba, pero letendo su documentación he visto que tiene dos módulos,ec2 y ec2_instance_facts que me podían servir para lo que quería.

Mi idea era desarrollar un playbook de Ansible, que ejecutándolo en el ordenador local, se encargara de:

  • Desplegar una determinada instancia de EC2, si no hay ninguna instancia con un nombre dado.
  • Esta instancia se desplegará en una red asociada a una VPC de Amazon determinada, con una clave ssh que se usará para acceder a la misma y con un grupo de seguridad asociado a dicho VPC.
  • La imagen AMI que vamos a usar corresponde a Ubuntu 16.04.3 LTS (xenial), usando virtualización de tipo hvm.
  • Una vez desplegada la instancia, el playbook entrará en el sistema donde realizará las siguientes operaciones:
    • Instarlar el git
    • Bajarse el JDK de Java e instalarlo.
    • Bajarse el maven e instalarlo.
    • Copiar desde el ordenador local la configuración de maven, el fichero situado en $HOME/.m2/settings.xml , al ordenador remoto.
    • Clonar varios repositorios desde el git.

Instalar Ansible

Para instalar ansible, lo más cómodo es usar entorno virtual de Python gestionado por un programa como virtualenv. Si se tiene este programa instalado hay que hacer lo siguiente para crear el entorno virtual e instalar dentro del mismo Ansible:

$virtualenv vansible
$source vansible/bin/activate
(vansible)$pip install ansible
(vansible)$ansible --version

El script

Al final de esta entrada podéis encontrar el script que he desarrollado para que se despliegue la máquina y me la deje configurada de acuerdo a lo que quiero. El formato del fichero que utiliza los playbooks de Ansible es yaml. Es un poco peculiar como podéis y el parser de ansible a veces hace cosas raras leyéndolo, con lo cual hay que tener bastante cuidado con lo que se pone.

Otra particularidad es que hago uso de los comandos ssh-agent y ssh-keyscan, así como la del reenvío del agente ssh sobre el túnel ssh para no tener que subir claves privadas a la máquina de Amazon.

Tampoco soy un usuario muy hardcode de Ansible. En cierta manera, quería tener algo que me ayudara a realizar mis tareas sin perder demasiado tiempo en la herramienta que fuera a usar. El script admite varias mejoras:

  • Comprobar antes de bajarse el JDK o maven que ya están instalados en la máquina.
  • Usar algunas opciones ssh para evitar tener que añadir al known_hosts las claves públicas de las máquinas remotas.
  • Ver si hay alguna construcción en las expresiones jinja2 que se usan, especialmente aquellas que usan la construccion expresion | default.
  • Comprobar si existe los repositorios git antes de bajarlos.

Para ejecutar el script:

(vansible)$ansible-playbook script.yml

Código fuente
- hosts: 127.0.0.1
  connection: local
  gather_facts: False
  vars:
    ec2machinename: <<ec2 instance name>>
    ec2sshkey: <<ssh key name to use in the instance>>
    ec2instancetype: "t2.xlarge" # instance type
    ec2region: "us-east-1"  # Amazon region
    ec2ami: "ami-43a15f3e" # AMI (this is the ubuntu one)
    ec2subnetid: <<subnet id>>
    ec2securitygroup: <<security group id>>
    privatekeypath: "~/.ssh/drizzt.key.pem"
    gitkeypath: "~/.ssh/id_drizzt_bitbucket"
    mavenconfigpath: "~/.m2/settings.xml"
    sshoptions: "-oForwardAgent=yes -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null"
    rcmd:
      - "sudo apt-get update"
      - "sudo apt-get -y install git-core"
      - "curl -L -O -# -H  'Cookie: oraclelicense=accept-securebackup-cookie' http://download.oracle.com/otn-pub/java/jdk/8u162-b12/0da788060d494f5095bf8624735fa2f1/jdk-8u162-linux-x64.tar.gz"
      - sudo mkdir -p /usr/local/java/
      - sudo tar zxvf jdk-8u162-linux-x64.tar.gz -C /usr/local/java/
      - sudo ln -sf /usr/local/java/jdk1.8.0_162/bin/* /usr/local/bin/
      - curl   -L -O -#  https://archive.apache.org/dist/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz
      - curl   -L -O -#  https://archive.apache.org/dist/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz.asc
      - sudo tar zxvf apache-maven-3.3.3-bin.tar.gz -C /usr/local/java
      - sudo ln -sf /usr/local/java/apache-maven-3.3.3/bin/* /usr/local/bin/
      - mkdir -p /home/ubuntu/{.m2,prog/atlas}
    remoterepos:
      - git@bitbucket.org:repo1/repo1.git
      - git@bitbucket.org:repo2/repo2.git



  tasks:
   - ec2_instance_facts:
      filters:
         "tag:Name": "{{ec2machinename}}"
         "instance-state-name": ["pending","running"]
     register: result
   - ec2:
      region: "{{ec2region}}"
      key_name: "{{ec2sshkey}}"
      instance_type: "{{ec2instancetype}}"
      image: "{{ec2ami}}"
      wait: yes
      count: 1
      group: "{{ec2securitygroup}}"
      vpc_subnet_id: "{{ec2subnetid}}"
      instance_tags:
        "Name": "{{ec2machinename}}"
     when: (result["instances"]|length == 0)
     register: ec2
   - name: Wait for SSH to come up
     wait_for:
        host: "{{ item.public_ip_address| default(item.public_ip) }}"
        port: 22
        delay: 10
        timeout: 60
        state: started
     with_items: "{{ ec2.instances |default(result.instances) }}"

   - name: Add the keys to ~/.ssh/known_host
     shell: ssh-keyscan -H {{item.public_ip_address|default(item.public_ip)}}  >> ~/.ssh/known_hosts
     with_items: "{{ ec2.instances |default(result.instances) }}"

   - name: Install git, java
     shell: ssh -i "{{privatekeypath}}" -l ubuntu "{{item[0].public_ip_address|default(item[0].public_ip)}}" "{{item[1]}}"
     with_nested:
      - "{{ ec2.instances |default(result.instances) }}"
      - "{{rcmd}}"
   - name: Copy the Maven config
     shell: "scp -i {{privatekeypath}} {{mavenconfigpath}} ubuntu@{{item.public_ip_address|default(item.public_ip)}}:.m2/"
     with_items: "{{ ec2.instances |default(result.instances) }}"
   - name: Add remote git key to ssh-agent
     shell: "ssh-add {{gitkeypath}}"



   - name: Copy the remote repositories
     shell: ssh -oForwardAgent=yes -i "{{privatekeypath}}" "ubuntu@{{item[0].public_ip_address|default(item[0].public_ip)}}" "cd /home/ubuntu/prog/atlas;env GIT_SSH_COMMAND='ssh {{sshoptions}}' git clone {{item[1]}}"
     with_nested:
      - "{{ ec2.instances |default(result.instances) }}"
      - "{{remoterepos}}"

No hay comentarios: