Skip to content

Instantly share code, notes, and snippets.

@tonyskapunk
Last active September 20, 2019 20:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonyskapunk/99bf0c9ce054b7b9392e to your computer and use it in GitHub Desktop.
Save tonyskapunk/99bf0c9ce054b7b9392e to your computer and use it in GitHub Desktop.
ansible

Ansible

¿Qué es Ansible?

Ansible es una herramienta que facilita la automatización de diferentes etapas en la infrastructura de las Tecnologías de Información(TI), por ejemplo en el provisionamiento de servidores, en la administración de configuraciones, en el despliegue de aplicaciones, orquestación de actvidades entre otras cosas.

Ansible fue diseñado para modelar la infrastructura de TI de una manera descriptiva teniendo en consideracion multiples capas. Esto es mucho más común en ambientes empresariales.

Una de las caracteristicas más populares de Ansible es que no necesita un agente, ni tampoco necesita una infrastructura de seguridad adicional para su funcionamiento, aunado a esto utiliza un lenguaje muy sencillo(YAML) para definir las acciones a realizar. La simplicidad es una de las cosas que caracteriza a Ansible.

Ansible es el nombre de un "sistema de comunicación inmediato" ficticio basado en un libro "El Juego de Ender"(Ender's Game) escrito por Orson Scott Card.

¿Quién inventó Ansible?

Ansible es el hijo de Michael DeHann Creador de otras herramientas conocidas tales como Clobber, Func. Fue creado en 2012 aunque su influencia viene de muchos dias antes influenciado por diferentes situaciones y diferentes proyectos como Puppet y sus limitaciones en ese momento. Hoy en día Ansible es parte de Red Hat, despues de que ésta comprara AnsiblerWorks. Michael ya no forma parte de Ansible.

Arquitectura

                                                 +----------------+
                                                 | +----------------+
+-----------------------------+                  | |  +----------------+
|                             |                  | |  |                |
|        Ansible Server       |      ssh         +-|  |  +-------------+---+
|                             |                    |  |  |                 |
+-------+  +--------+ +-------+ +-------------->   +--|  |    Host N       |
||      |  |        | |      ||                       +--+                 |
||      |  |        | |      ||                          |                 |
|| Inv  |  | Play-  | | Roles||                          +-----------------+
||      |  | books  | |      ||
||      |  |        | |      ||
+-------+  +--------+ +-------|
| +----------+        +-------+
| | Custom   |        |       |
| | Modules  |        | Vault |
+-+----------+--------+-------+
  

Mejores Prácticas

Ansible se guía por 3 ideas principales:

  1. La complejidad mata la productividad (Complexity Kills Productivity)
  2. Optimiza la legibilidad (Optimize For Readability)
  3. Piensa de manera declarativa (Think Declaratively)

Estilo

  • Nombra cada tarea
  • Usa estilo yaml map y no llaves
  • Usar debug es aceptable, pero utiliza un verbosity adecuado
  • Evita interacción lo más que se pueda
  • Utiliza ansible-lint

Pruebas

  • Molecule o alguno otro proceso que permita hacer validaciones del código

Instalación

Distro

apt-get update && apt-get install ansible

$(type -P dnf yum | head -1) install ansible

pacman -S ansible

pip

# local
pip install ansible --user

# full
pip install ansible

# latest
pip install git+https://github.com/ansible/ansible.git@devel

virtualenv

https://gist.github.com/tonyskapunk/433762caf6669a2685aa686b487c4ea3

Inventario

Estatico

Doc: http://docs.ansible.com/ansible/latest/intro_inventory.html

Ejemplos

ini

mail.example.com
10.7.5.3

[webservers]
foo.example.com
bar.example.com
10.8.6.4

[dbservers]
one.example.com:2222
two.example.com
three.example.com
10.9.8.7

[streamingservers]
stream[a:z].example.com

yaml

all:
  hosts:
    mail.example.com
    10.7.5.3
  children:
    webservers:
      hosts:
        foo.example.com:
        bar.example.com:
        10.8.6.4:
    dbservers:
      hosts:
        one.example.com: 2222
        two.example.com:
        three.example.com:
        10.9.8.7:

Dinámico

Doc: http://docs.ansible.com/ansible/latest/intro_dynamic_inventory.html

Algunas de las infrastructuras soportadas en ansible para producir un inventario dinamico: EC2/Eucalyptus, Rackspace Cloud, OpenStack.

¿Creando tú propio script para el inventario? Doc: http://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html

Ejemplo

cat > inv.sh <<EOF
{
    "databases": {
    "hosts": ["host1.example.com", "host2.example.com"],
        "vars": {
            "a": true
        }
    },
    "webservers": ["host2.example.com", "host3.example.com"],
    "atlanta": {
        "hosts": ["host1.example.com", "host4.example.com", "host5.example.com"],
        "vars": {
            "b": false
        },
        "children": ["marietta", "5points"]
    },
    "marietta": ["host6.example.com"],
    "5points": ["host7.example.com"]
}
EOF

chmod u+x inv.sh

Ansible

Usando ansible

Ejemplos

Ping

ansible localhost -m ping

Ping(root)

ansible localhost -bK --become-method=sudo -m ping

Facts

ansible localhost -m setup

command

ansible localhost -m command -a 'whoami'

command(root)

ansible localhost -b -m command -a 'whoami'

ansible localhost -bK --become-method=sudo -m command -a 'whoami'

user

ansible localhost -bKm user -a "name=deleteme uid=1234 state=present"

ansible localhost -bKm user -a "name=deleteme uid=1234 state=absent remove=yes"

Configuración

Archivos y Jerarquías

  • ANSIBLE_* variables de ambiente
  • ./ansible.cfg
  • ~/.ansible.cfg
  • /etc/ansible/ansible.cfg

Ejemplos

[defaults]
inventory = ./inventory
remote_user = nonroot
nocows = 1
forks = 5
transport = ssh
host_key_checking = False
#private_key_file = ~/.ssh/id_rsa_example

[privilege_escalation]
become = False
become_method = sudo

[ssh_connection]
control_path = ~/.ssh/mux-%%r@%%h:%%p
#pipelining = True

Tips:

ansible-config dump
ansible-config dump --only-changed

Playbooks

Playbooks son archivos con grupos de tareas definidas, incluye los servidores que se van a utilizar para su ejecución. Mediante los playbooks es como se logra el despliegue y la orquestación de configuraciones en servidores.

Tareas(Tasks)

Unidad minima de acción en Ansible

Ejemplos

  • Playbook para crear un usuario en el host foo.example.com

Crea usuario

  • Playbook play_crea_usuario.yml:
    ---
    - name: Crear usuario
      hosts: foo.example.com
      tasks:
        - name: Crea usuario nonroot
          user:
            name: nonroot
            uid: 1234
            state: present
            group: admin
    ...
  • Ejecutando playbook:
    # Verificación de sintaxis
    ansible-playbook play_crea_usuario.yml --syntax-check
    
    # Ejecución de playbook
    ansible-playbook play_crea_usuario.yml

Instala ssh-keys

  • Playbook play_instala_sshkeys.yml:

    ---
    - name: Instalando ssh-keys
      become: "yes"
      hosts: all
      gather_facts: "no"
      vars:
        username: nonroot
        sshkey_path1: "~{{ username }}/.ssh/id_rsa_example.pub"
        sshkey_path2: "~/ansible/rax/id_rsa_ansible_test.pub"
      tasks:
      - name: Instalando ssh-key para {{ username }}
        authorized_key:
          user: "{{ username }}"
          state: present
          key: "{{ lookup('file', sshkey_path1 ) }}"
  • Ejecutando playbook:

    # Verificación de sintaxis
    ansible-playbook play_instala_sshkeys.yml --syntax-check
    
    # Ejecución de playbook
    ansible-playbook play_instala_sshkeys.yml

Variables

En el playbook anterior se puede ver el uso de dos variables, definidas bajo la sección: vars

vars:
    username: nonroot
    sshkey_path: "~{{ username }}/.ssh/id_rsa_example.pub"

Ejemplos

Definición de variables

# :)
vars:
  nombre_valido: ":)"
  nombrevalido0: ":)"
  arreglo0:
    - "elemento0"
    - "elemento1"
    - "elemento2"
  diccionario1:
    llave0: "valor0"
    llave1: "valor1"

# :(
vars:
  nombre-invalido: ":("
  nombre.invalido: ":("

Implementando variables

  • Creando un playbook para probar play_mensajes.yml:

    ---
    - name: Probando variables
      hosts: localhost
      become: "no"
      gather_facts: "yes"
      vars:
        mi_mensaje:
          inicial: "hola"
          final: "adios"
          sabor:
            - "mundo"
            - "cruel"
      tasks:
      - name: Primer mensaje de {{ ansible_user_id }}
        debug:
          msg: "{{ mi_mensaje.inicial }} {{ mi_mensaje.sabor[0] }}"
     
      - name: Ultimo mensaje en {{ ansible_hostname }}
        debug:
          msg: "{{ mi_mensaje.final }} {{ mi_mensaje.sabor[0] }} {{ mi_mensaje.sabor[1] }}"
    ...
  • Ejecutando playbook:

    # Verificación de sintaxis
    ansible-playbook play_mensaje.yml --syntax-check
    
    # Listando las tareas(tasks)
    ansible-playbook play_mensaje.yml --list-tasks
    
    # Ejecución de playbook
    ansible-playbook play_mensaje.yml

Registros

Esta es una manera de definir variables dentro de la ejecución, éstos registros son dinámicos:

  • Playbook play_registro.yml:
    ---
    - name: Registro
      become: "no"
      hosts: localhost
      gather_facts: "yes"
      tasks:
      - name: Muestra IP para RH-based
        command: last
        register: cmd_last
    
      - name: Muestra el último login
        debug:
          msg: "{{ cmd_last.stdout_lines[0] }}"
    ...

Condicionales(Conditionals)

  • Playbook play_cond.yml:

    ---
    - name: Condicionales
      become: "no"
      hosts: localhost
      gather_facts: "yes"
      tasks:
      - name: Muestra IP para RH-based
        debug:
          msg: "Tu IP por omisión es: {{ ansible_default_ipv4.address }}"
        when: ansible_os_family|lower in ['redhat']
      
      - name: Muestra la Hora para debian-based
        debug:
          msg: "La hora es: {{ ansible_date_time.iso8601 }}"
        when: ansible_os_family|lower in ['debian']
    ...
    • Ejecutando playbook:
    # Verificación de sintaxis
    ansible-playbook play_cond.yml --syntax-check
    
    # Listando las tareas(tasks)
    ansible-playbook play_cond.yml --list-tasks
    
    # Ejecución de playbook (verbose)
    ansible-playbook play_cond.yml -v

Bucles(Loops)

Doc: http://docs.ansible.com/ansible/latest/playbooks_loops.html

  • Playbook: play_loop.yml:

    ---
    - name: Bucles                     
      hosts: localhost                 
      gather_facts: "no"               
      vars:                            
        usuarios:                      
          - sysad                      
          - dba                        
          - developer                  
      tasks:                           
      - name: Lista usarios            
        command: echo {{ item }}       
        loop: "{{ usuarios }}"   
    ... 
  • Playbook play_create_rax.yml:

    ---
    - name: Creando servidores en Rackspace
      hosts: localhost
      gather_facts: "no"
      tasks:
      - name: Crea 3 servidores
        local_action:
          module: rax
          credentials: ~/ansible/rax/.raxkey
          name: web%02d.example.com
          flavor: general1-1
          image: Ubuntu 16.04 LTS (Xenial Xerus) (PVHVM)
          state: present
          count: 3
          count_offset: 0
          exact_count: yes
          group: test
          wait: yes
          region: IAD
          key_name: ansible_test
        register: rax
    
      - name: Dame la info
        debug:
          msg: >
            hostname: {{ item.name }}
              IP: {{ item.accessIPv4 }}
              root: {{ item.rax_adminpass }}
              id: {{ item.id }}
        with_items: "{{ rax.success }}"
        when: not rax.failed
    
      - name: Define hostnames
        set_fact:
          ips: "{{ ips|default([]) + [ item['accessIPv4'] ] }}"
        with_items: "{{ rax.success }}"
        when: not rax.failed
    
      - name: IPs
        debug:
          msg: "{{ ips }}"
    ...
  • Ejecutando playbook:

    # Verificación de sintaxis
    ansible-playbook play_create_rax.yml --syntax-check
    
    # Listando los servidores(hosts)
    ansible-playbook play_create_rax.yml --list-hosts
    
    # Ejecución de playbook
    ansible-playbook play_create_rax.yml

Plantillas(Templates)

El uso de plantillas/templates es generalmente usado para crear configuraciones/archivos similares que son re-utilizados cambiando algunas partes de ellos. Ansible hace uso de jinja2 un motor de plantillas para python.

Ejemplo:

  • Template "ansible_cfg.j2

    [defaults]
    stdout_callback={{ stdout_callback|default("default") }}
  • Playbook usando el template: play_ansible_cfg.yml

    ---
    - name: Create ansible config
      hosts: localhost
      become: no
      vars:
        stdout_callback: yaml
      tasks:
      - name: Create local ansible cfg
        template:
          src: templates/ansible_cfg.j2
          dest: "{{ lookup('env','HOME') }}/.ansible.cfg"
    ...

Bloques(Blocks)

Se usan para tener estructuras de código similares a try/except/else/finally o simplemente para agrupar tareas. Ejemplo

  • Simulando "Try/Catch": play_try.yml
- name: Optional packages
  block:
  - name: Install optional packages
    package:
      name: "{{ list_of_optional_packages }}"
  rescue:
  - name: Report error to API  
    uri:
       url: "{{ url_of_api }}"
    user: "{{ username }}"
    password: "{{ password }}"
    method: POST
    body:
      msg: "Optional packages failed"
    force_basic_auth: yes
    status_code: 201
    body_format: json
  • Como agrupación de código: play_block.yml
- name: Check connectivity
  block:
  - name: Check port 443
    wait_for:
      host: "{{ target_server }}"
      port: 443
      timeout: 5
    register: target_port_443
    ignore_errors: "yes"
    
  - name: Exit when unreachable
    fail:
      msg: "Unable to connect to {{ target_server }}"
    failed_when: target_port_443.failed
  
  when: check_connectivity is defined
  become: "no"
  

Roles

Los roles es un conjunto de playbooks con una estructura predefinida

role_name
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

Plugins

Mediante estos Ansible se vuelve una herramienta que puede ser extendida y ajustada a cada necesidad, está es la lista de los diferentes tipos de plugins que hay:

  • Action
  • Become
  • Cache
  • Callback
  • Cliconf
  • Connection
  • Filter
  • HTTPAPI
  • Inventory
  • Lookup
  • Test
  • Vars

Una de sus principales características es que en su mayoría se ejecutan del lado del nodo de control o "control node"

Modulos

De manera implicita hemos hecho uso de ellos. Cada tarea ejecuta algún modulo, algunos ejemplos:

  • ping
  • setup
  • user
  • package
  • uri

La lista es extensa, más de 2500 modulos: https://docs.ansible.com/ansible/latest/modules/list_of_all_modules.html

Una de sus principales características es que los modulos se ejecutan en el nodo objetivo o "target node".

Lint

ansible-lint revisa el código de los playbooks. Sugiere cambios en base a mejores prácticas

Es parte de ansible pero tiene que instalarse de manera independiente.

pip install --user ansible-lint

Molecule

Es un una heramienta que permite establecer un conjunto de pasos para llevar a cabo la validación de código de Ansible.

k4ch0 creó una muy buena presentación al respecto.

Referencias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment