Infraestructura como Código (IV): Ansible y OpenShift

Publicado por Ignacio Sánchez Ginés el

DevOpsAnsibleOpenShiftMicrosoft AzureInfraestructura como Código

En este blog hemos hablado de la importancia que tiene la Infraestructura como Código en entornos Agile.

Hoy veremos cómo hacer uso de Ansible para definir y modelar nuestra infraestructura, en concreto, la infraestructura necesaria para la instalación de OpenShift.

Ansible se está convirtiendo en un estándar para la automatización en IT y esta automatización es un componente esencial en la Transformación Digital de las empresas.

Con Ansible podemos automatizar fácilmente la provisión, el plataformado y la configuración de, prácticamente, cualquier aspecto en nuestra infraestructura.

El ritmo de adopción de Ansible está siendo espectacular pero casi todo el mundo empieza utilizando esta tecnología para la gestión de la configuración.

Infraestructura con Ansible

Ansible va más allá de la simple configuración de máquinas. Es posible que no conozcas el enorme número de módulos existentes para la creación y gestión de infraestructura, por ejemplo:

  • Amazon AWS
  • Azure
  • CloudStack
  • Digital Ocean
  • Google Cloud
  • OpenStack
  • Ovirt/RHV
  • RackSpace
  • VMware

Pero los módulos para nubes públicas y privadas no es todo lo que ofrece, también dispone de numerosos módulos para gestionar sistemas de networking, por ejemplo:

  • Aruba
  • Cisco
  • Citrix
  • F5
  • Juniper

Infraestructura para OpenShift

Para realizar un ejemplo, vamos a definir con Ansible la infraestructura necesaria para la instalación de OpenShift en Azure.

Para ello vamos a guiarnos por la Arquitectura de Referencia que nos propone Red Hat.

OpenShift Azure

La infraestructura necesaria es sencilla. Como podemos ver, necesitamos más de un máquina de cada tipo para conseguir un clúster en HA.

En concreto, necesitamos las siguientes máquinas:

  • 3 nodos Master
  • 3 nodos de Infra
  • 3 nodos de Aplicación

Adicionalmente, crearemos un máquina denominada Bastion,  desde donde instalaremos y gestionaremos OpenShift.

Vamos a crear una red que una todas estas máquinas. Partiremos esta red en 3 sub-redes para tener más control sobre cada tipo de nodo.

Sobre esta red tendrá existirán dos balanceadores, uno para repartir la carga entre los "masters" y el otro para balancear los nodos de "infra".

En los "masters" se expone el API y la Consola Web de OpenShift, por tanto, el balanceador de los "masters" expondrá una IP pública al exterior. De esta manera podremos utilizar OpenShift via CLI y Web. Es recomendable crear un balanceador privado adicional para este mismo propósito pero que se utilizará unicamente de forma interna en OpenShift.

En los nodos de "infra" se encuentran los Routers, proxys inversos que exponen las aplicaciones desplegadas en OpenShift. El otro balanceador se encargará de repartir la carga entre estos "routers". De la misma manera utilizaremos una IP pública para exponer este balanceador al exterior.

Tan sólo nos quedaría asignar una IP pública al nodo Bastion para poder acceder a él desde el exterior usando SSH (sólo para esta demo ya que para acceder via SSH es mejor usar VPNs).

Para simplificar, no montaremos almacenamiento compartido, utilizaremos por ahora el almacenamiento de cada host.

Implementación en Ansible y Azure

Todo el código necesario para esta demo se encuentra en GitHub:

https://github.com/drhelius/ansible-azure-openshift

Para ejecturalo podremos lanzar el siguiente comando:

$ ansible-playbook -e @configuration.yml openshift-infra.yml

Empezaremos con un fichero de configuración para definir nuestras variables:

azure:  
  location: "East US"
  resource_group: "openshift"
  image_publisher: "OpenLogic"
  image_offer: "CentOS"
  image_sku: "7.5"
  image_version: "latest"

openshift:  
  master_nodes: [1,2,3]
  master_size: "Standard_B2s"
  infra_nodes: [1,2,3]
  infra_size: "Standard_B2ms"
  app_nodes: [1,2,3]
  app_size: "Standard_B2s"
  bastion_size: "Standard_B2ms"
  admin_domain: "ocp.mydomain.com"
  router_domain: "mydomain.com"

Para el dominio podremos hacer uso de algún servicio gratuito de "Dyn DNS" como Duck DNS que nos permite crear wildcard DNS (*.mydomain.com) necesarios para los "routers" de OpenShift.

Antes de empezar tenemos que tener Azure CLI instalado.

También necesitaremos algunas dependencias y configuración de autenticación.

Cuando tengamos todo listo podemos empezar con el código. El primer paso es crear el Resource Group de Azure:

- name: Create resource group
  azure_rm_resourcegroup:
    name: "{{ azure.resource_group }}"
    location: "{{ azure.location }}"

Después las redes, aquí un ejemplo de la red principal y la subred para Masters:

- name: Create main virtual network
  azure_rm_virtualnetwork:
    resource_group: "{{ azure.resource_group }}"
    name: openshift-virtual-network
    address_prefixes: "10.0.0.0/16"

- name: Create master subnet
  azure_rm_subnet:
    resource_group: "{{ azure.resource_group }}"
    name: openshift-master-subnet
    address_prefix: "10.0.1.0/24"
    virtual_network: openshift-virtual-network

Podremos crear ya nuestro Bastion:

- name: Create Bastion VM
  azure_rm_virtualmachine:
    resource_group: "{{ azure.resource_group }}"
    name: openshift-bastion-vm
    vm_size: "{{ openshift.bastion_size }}"
    storage_account: "{{ openshift_storage_account }}"
    admin_username: "{{ openshift.os_user }}"
    ssh_password_enabled: false
    ssh_public_keys:
      - path: "/home/{{ openshift.bastion_admin }}/.ssh/authorized_keys"
        key_data: "{{ lookup('file', '../../certs/bastion.pub') }}"
    network_interfaces: openshift-bastion-nic
    image:
      offer: "{{ azure.image_offer }}"
      publisher: "{{ azure.image_publisher }}"
      sku: "{{ azure.image_sku }}"
      version: "{{ azure.image_version }}"

La creación de los Masters es similar, pero utilizaremos un loop asíncrono para crear más de una máquina a la vez:

- name: Create Master vm
  azure_rm_virtualmachine:
    resource_group: "{{ azure.resource_group }}"
    name: "openshift-master-vm-{{ item }}"
    availability_set: openshift-master-availability-set
    vm_size: "{{ openshift.master_size }}"
    storage_account: "{{ openshift_storage_account }}"
    admin_username: "{{ openshift.os_user }}"
    ssh_password_enabled: false
    ssh_public_keys:
      - path: "/home/{{ openshift.os_user }}/.ssh/authorized_keys"
        key_data: "{{ lookup('file', '../../certs/openshift.pub') }}"
    network_interfaces: "openshift-master-nic-{{ item }}"
    image:
      offer: "{{ azure.image_offer }}"
      publisher: "{{ azure.image_publisher }}"
      sku: "{{ azure.image_sku }}"
      version: "{{ azure.image_version }}"
  loop: "{{ openshift.master_nodes }}"
  async: 600
  poll: 0
  register: openshift_master_vm_result
  changed_when: False


- name: Wait for Master vm creation
  async_status:
    jid: "{{ item.ansible_job_id }}"
  loop: "{{ openshift_master_vm_result.results }}"
  register: openshift_master_vm_creation
  until: openshift_master_vm_creation.finished
  retries: 120
  delay: 5

Este sería el balanceador público de los Masters:

- name: Create Masters public load balancer
  azure_rm_loadbalancer:
    resource_group: "{{ azure.resource_group }}"
    name: openshift-master-public-load-balancer
    frontend_ip_configurations:
      - name: public
        public_ip_address: openshift-master-public-ip
    backend_address_pools:
      - name: openshift-master-public-address-pool
    probes:
      - name: master-lb-probe-8443-up
        port: 8443
    load_balancing_rules:
      - name: master-lb-public-rule-8443-8443
        frontend_ip_configuration: public
        backend_address_pool: openshift-master-public-address-pool
        frontend_port: 8443
        backend_port: 8443
        probe: master-lb-probe-8443-up
  register: openshift_master_public_lb_result

TL;DR

Como hemos visto, Ansible es una tecnología potente, muy sencilla de aprender, que nos proporciona una cantidad enorme de herramientas para poder escribir y versionar nuestra Infraestructura como Código para casi cualquier cloud pública o privada.

¡Síguenos en Twitter para estar al día de próximos posts!