Blog de Obi Madu
Volver a todos los artículos
InfrastructureDevOpsProjects

Despliegue automático de Jenkins en un servidor remoto (con SSL gratuito) mediante Ansible (Guía)

Aprenda a desplegar automáticamente un servidor Jenkins autohospedado con certificados SSL gratuitos de renovación automática utilizando Ansible.

Despliegue automático de Jenkins en un servidor remoto (con SSL gratuito) mediante Ansible (Guía)

Jenkins es una de las herramientas de CI/CD (Integración Continua y Despliegue Continuo) más populares que existen. Es muy apreciada en la comunidad tecnológica porque es gratuita, de código abierto y autohospedada. Hay muchas razones por las que podría querer desplegar un servidor Jenkins: para construir proyectos personales, practicar con el software, para uso en producción de la empresa, etc. Sea cual sea su razón, una cosa es segura, desplegar su servidor con Ansible hará que el proceso sea automático, repetible, reutilizable, versionable y compartible. Hoy veremos cómo crear un playbook de Ansible que despliegue Jenkins en un servidor remoto, con un certificado SSL gratuito de Letsencrypt (que se renueva automáticamente).

He subido todo el código de este proyecto aquí en Github.

Vamos a empezar 🚀

1. Adquirir un servidor remoto

El primer paso para desplegar Jenkins en un servidor es adquirir el propio servidor. Un servidor remoto puede ser aprovisionado desde muchos lugares diferentes. Proveedores de la nube como DigitalOcean, Google Cloud, AWS, etc., ofrecen algunos de los planes de VPS (servidor privado virtual) más rentables del mercado. Dependiendo de sus necesidades, puede aprovisionar un servidor ya sea manualmente o a través de IaC (Infraestructura como Código) desde cualquiera de estos proveedores.

Para el propósito de este tutorial, asegúrese de aprovisionar su instancia de servidor con acceso a la internet pública (y por lo tanto a una dirección IPv4 pública).

Se considera una buena práctica ejecutar comandos de ansible en un nodo a través de un usuario dedicado. Para ayudar a acelerar el proceso de creación de un usuario dedicado con los permisos adecuados para Ansible, utilice el siguiente script de inicio userdata para lanzar su VPS.

#cloud-config
ssh_pwauth: false

users:
  - name: ansible
    gecos: Ansible User
    groups: users,admin,wheel
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    lock_passwd: true
    ssh_authorized_keys:
      - "ssh-public-key"

Reemplace "ssh-public-key" con la clave pública SSH adecuada para la conexión a su servidor.

2. Configuración para Ansible

Antes de sumergirnos en la creación de nuestro Playbook, necesitamos configurar algunas cosas para asegurarnos de que nuestro flujo de trabajo tenga éxito.

2.1 Verificar la conectividad SSH al servidor remoto

Ansible se conecta a los servidores de nodo a través de SSH. Dado que estamos tratando con un solo servidor para este tutorial, necesitaremos conectarnos a él inicialmente, de forma manual, para verificar la conectividad.

Parte del proceso de despliegue de un VPS es configurar el acceso SSH a él. Dondequiera que despliegue su VPS, debe tener acceso al archivo de clave privada para la conexión SSH a su servidor.
Inicie una conexión SSH a su servidor utilizando

ssh -i location/to/keyfile username@server_ip 

Asegúrese de guardar su clave privada SSH de forma segura en su host de Ansible, y haga un seguimiento de su ubicación porque se utilizará en un paso posterior para otorgar a Ansible acceso a su VPS.

2.2 Configurar registros DNS para nuestro dominio Jenkins

Para asegurar el acceso a su servidor Jenkins desde el dominio apropiado, necesita apuntar su nombre de dominio a la dirección IP de su servidor. Esto se logrará creando un A record DNS. Esto se puede hacer de varias maneras diferentes (a través de una variedad de interfaces) dependiendo del Servicio de Nombres de Dominio a cargo de su dominio. Los detalles específicos están fuera del alcance de este tutorial.

Sin el registro DNS configurado correctamente, su Playbook fallará al emitir SSL para su servidor Jenkins porque Certbot (el cliente utilizado para emitir los certificados) será incapaz de verificar que usted controla el dominio para el cual se emitirá el certificado SSL. Esto causará que su despliegue falle, así que asegúrese de configurar el registro DNS apropiado.

2.3 Crear un archivo de configuración de Ansible

Para funcionar correctamente, Ansible necesita configurar algunas cosas importantes. Hacemos esto en el archivo ansible.cfg. Ansible revisa este archivo automáticamente antes de la ejecución, para encontrar las cosas importantes que necesita para funcionar. Nuestro archivo ansible.cfg tendrá el siguiente contenido.

[defaults]
inventory = inventory.txt
private_key_file = key.txt
remote_user = ansible

Este archivo configura las siguientes cosas importantes:

  • Le dice a Ansible que nuestro archivo de inventario, el archivo que lista las direcciones de todos los servidores que nos gustaría que ansible administrara, es un archivo llamado inventory.txt y se encuentra en el directorio actual.
  • Le dice a ansible que el archivo de clave privada para la conectividad SSH al host es un archivo llamado key.txt, ubicado también en el directorio actual
  • Configura el nombre de usuario ansible para la conexión SSH al servidor. Este será el caso si configuró su servidor con el script cloud-init proporcionado anteriormente, si no, siéntase libre de cambiar este valor a lo que sea su username.

De acuerdo con esta configuración, debe almacenar el archivo de clave privada SSH para la conexión al servidor en un archivo llamado key.txt en el directorio actual, para que Ansible pueda encontrarlo.

Recuerde NO registrar su archivo key.txt en el control de versiones. Especialmente en un repositorio público en Github.

Una vez que haya verificado la conectividad SSH a su servidor, haya configurado el registro DNS apropiado y haya creado un archivo de configuración, está listo para crear su Playbook.

3. Crear el Playbook

Es hora de crear su Playbook de Ansible. Para mantener nuestra solución simple y modular, vamos a hacer uso de los roles de Ansible. Aquí hay un resumen de los pasos que conducen a nuestro resultado deseado:

  • Configurar un proxy Nginx para Jenkins
  • Adquirir un certificado SSL para nuestro servidor
  • Instalar Jenkins


Ahora en código:

---
- hosts: all
  become: true
  roles:
    - nginx-proxy

- hosts: all
  become: true
  roles:
    - certbot

- hosts: all
  become: true
  roles:
    - jenkins

4. Crear Roles complementarios

A continuación, necesita crear los roles para los diferentes aspectos del flujo de trabajo. La estructura de directorios para sus roles debería verse así:

tree

4.1 Dentro del rol nginx-proxy

Cree un archivo tasks/mail.yml

Con el siguiente contenido:

- name: Install NginX
  tags: nginx,install
  ansible.builtin.apt:
    name: nginx
    state: latest
    update_cache: true

- name: Enable NginX
  ansible.builtin.service:
    name: nginx
    enabled: true

- name: Config Jenkins Proxy
  ansible.builtin.template:
    src: "jenkins-proxy.j2"
    dest: /etc/nginx/sites-available/jenkins-proxy.conf
    owner: root
    group: root
    mode: 0644
  notify: restart_nginx

- name: Enable Proxy
  ansible.builtin.file:
    src: /etc/nginx/sites-available/jenkins-proxy.conf 
    dest: /etc/nginx/sites-enabled/jenkins-proxy.conf
    state: link
  notify: restart_nginx

Cree un archivo handlers/mail.yml

Con el siguiente contenido:

- name: restart_nginx
  ansible.builtin.service:
    name: nginx
    state: restarted

Cree un archivo templates/jenkins-proxy.j2

Con el siguiente contenido:

server { 

    listen 80; # Port for incoming traffic (e.g., 80 for HTTP, 443 for HTTPS)
    server_name {{ server_name }}; # Your domain name or IP address

    # Location block for handling proxied requests

    location / {
        proxy_pass {{ jenkins_localhost }}; # Upstream server address (e.g., http://127.0.0.1:8080)
        
        # Optional settings:
        
        proxy_set_header Host $host; # Preserve host header for upstream server
        proxy_set_header X-Real-IP $remote_addr; # Forward client IP address
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Forward proxy chain

        # Additional settings as needed (e.g., caching, rewrites)
    }

}

4.2 Dentro del rol certbot

Cree un archivo tasks/mail.yml

Con el siguiente contenido:

- name: Install Snapd
  ansible.builtin.apt:
    name: snapd
    state: latest

- name: Install Certbot
  community.general.snap:
    name: certbot
    classic: true
    state: present

- name: Create symlink    
  ansible.builtin.file:
    src: /snap/bin/certbot 
    dest: /usr/bin/certbot
    state: link

- name: Run certbot
  ansible.builtin.shell: 
    cmd: certbot --nginx -n --agree-tos --email {{ server_email }} --domains {{ server_name }}

4.3 Dentro del rol jenkins

Cree un archivo tasks/mail.yml

Con el siguiente contenido:

- name: Install JDK
  ansible.builtin.apt:
    pkg:
      - fontconfig
      - openjdk-17-jre

- name: Get Jenkins Repo Key
  ansible.builtin.get_url:
    url: https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
    dest: /usr/share/keyrings/jenkins-keyring.asc

- name: Set Jenkins Source
  ansible.builtin.lineinfile:
    path: /etc/apt/sources.list.d/jenkins.list
    line: deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/
    create: yes

- name: Install Jenkins
  ansible.builtin.apt:
    name: jenkins
    state: present
    update_cache: true

- name: Enable Jenkins
  ansible.builtin.service:
    name: jenkins
    enabled: true

5. Configurar las salidas de depuración de Jenkins

La primera vez que configura su servidor Jenkins, para comenzar a usar la interfaz de usuario web, debe recuperar una clave secreta de un archivo en el servidor Jenkins, para demostrar que controla el servidor. Podemos recuperar esta clave y hacer que Ansible nos la muestre agregando las siguientes líneas a nuestro archivo role/jenkins/tasks/main.yml:

- name: Check Jenkins Status
  ansible.builtin.shell:
    cmd: systemctl status jenkins
  register: check_jens

- name: Debug
  debug:
    msg: "{{ check_jens.stdout_lines }}"

Esta adición imprime el valor de

systemctl status jenkins

6. Desplegar su playbook

Aquí es donde despliega su Playbook y hace que Jenkins se configure automáticamente. Para desplegar su Playbook debe proporcionar los valores apropiados a las 3 variables definidas en nuestros roles.

  • La variable {{jenkins_localhost}} apunta a la dirección de host local de Jenkins. Esta suele ser http://localhost:8080
  • La variable {{server_name}} proporciona el nombre de dominio en el que el servidor Jenkins será accesible. Este es el dominio para el que configuró los registros DNS anteriormente.
  • La variable {{server_email}} proporciona la dirección de correo electrónico del administrador del servidor (esto es obligatorio).

Puede elegir proporcionar el valor a estas variables de diferentes maneras. Podría proporcionarlos en tiempo de ejecución, en cuyo caso desplegaría su Playbook con el siguiente comando:

ansible-playbook --extra-vars "server_name=domain-name jenkins_localhost=http://127.0.0.1:8080 
server_email=email" playbook.yml 

Reemplazando domain-name y email con los valores apropiados.

Aquí hay un ejemplo:

ansible-playbook --extra-vars "server_name=jen.obimadu.pro 
jenkins_localhost=http://127.0.0.1:8080 
server_email=hello@obimadu.pro" playbook.yml

Para formas adicionales de proporcionar el valor de las variables, visite Using Variables

Y ESO ES TODO 🎉 🎉 ¡Ahora tiene una forma totalmente automatizada de desplegar (y/o re-desplegar) su Servidor Jenkins!