AboutOpinionesBlogLa Blockletter

Software Crafters® 2025 | Creado con 🖤 para elevar el nivel de la conversación sobre programación en español | Legal

Home » devops » Servidor de desarrollo Django con Vagrant y Ansible
Servidor de desarrollo Django con Vagrant y Ansible

Servidor de desarrollo Django con Vagrant y Ansible

Miguel A. Gómez
Miguel A. Gómez · Seguir12 min read ·

Al suscribirte a la newsletter comparto contigo los 10 libros más importantes de programación. Los que sin duda todo dev debería leer al menos una vez...

En este artículo vamos a ver cómo crear un entorno de desarrollo virtualizado utilizando Vagrant y Ansible. Esto nos permitirá tener una máquina virtual con todas las dependencias necesarias para nuestro proyecto, lo que facilita enormemente el trabajo en equipo y la portabilidad del entorno de desarrollo.

Cuando trabajamos en proyectos en equipo, es habitual encontrarnos con problemas relacionados con el entorno de desarrollo: "En mi máquina funciona", "No puedo instalar la versión X del programa Y porque tengo otros proyectos", etc. Además, si cambiamos de ordenador, tenemos que volver a configurar todo el entorno desde cero.

Para solucionar estos problemas, podemos utilizar Vagrant y Ansible:

  • Vagrant nos permite crear y configurar entornos de desarrollo virtualizados de forma sencilla.
  • Ansible es una herramienta de automatización IT que nos permite configurar sistemas de forma declarativa y controlada.

¿Por qué utilizar Vagrant y Ansible?

Vagrant y Ansible son herramientas complementarias que, utilizadas conjuntamente, nos permiten:

  • Crear máquinas virtuales de forma automatizada y reproducible
  • Configurar el sistema operativo y las aplicaciones necesarias
  • Compartir la configuración con el equipo de desarrollo
  • Asegurar que todos los miembros del equipo utilizan el mismo entorno
  • Aislar las dependencias del proyecto del sistema operativo anfitrión
  • Evitar conflictos entre versiones de software para distintos proyectos

Además, estas herramientas son de código abierto, multiplataforma y tienen una comunidad muy activa.

Requisitos previos

Para seguir este tutorial, necesitarás:

  • Un ordenador con Windows, macOS o Linux
  • Un software de virtualización (VirtualBox, VMware, etc.)
  • Vagrant instalado
  • Ansible instalado (solo en máquinas Linux/macOS)

Si estás en Windows, no te preocupes por Ansible, ya que se ejecutará dentro de la máquina virtual.

Instalación de VirtualBox

VirtualBox es un software de virtualización de código abierto que nos permitirá ejecutar máquinas virtuales en nuestro ordenador. Para instalarlo, simplemente descárgalo desde la página oficial y sigue las instrucciones de instalación para tu sistema operativo.

Instalación de Vagrant

Vagrant es una herramienta que nos permite crear y configurar entornos de desarrollo virtualizados de forma sencilla. Para instalarlo, descárgalo desde la página oficial y sigue las instrucciones de instalación para tu sistema operativo.

Una vez instalado, puedes comprobar que funciona correctamente ejecutando el siguiente comando en una terminal:

vagrant --version

Deberías ver algo como esto:

Vagrant 2.2.16

Instalación de Ansible (solo para Linux/macOS)

Ansible es una herramienta de automatización IT que nos permite configurar sistemas de forma declarativa y controlada. Para instalarlo en Linux/macOS, puedes usar el gestor de paquetes de tu distribución o seguir las instrucciones oficiales.

En macOS, puedes usar Homebrew:

brew install ansible

En Ubuntu/Debian:

sudo apt update
sudo apt install ansible

Una vez instalado, puedes comprobar que funciona correctamente ejecutando el siguiente comando en una terminal:

ansible --version

Deberías ver información sobre la versión de Ansible instalada.

Creando nuestro entorno de desarrollo

Ahora que tenemos todas las herramientas necesarias, vamos a crear nuestro entorno de desarrollo virtualizado. En este ejemplo, vamos a crear un entorno para una aplicación web basada en PHP y MySQL, pero puedes adaptarlo a tus necesidades.

Estructura del proyecto

Vamos a crear la siguiente estructura de directorios para nuestro proyecto:

miproyecto/
├── ansible/
│   ├── playbook.yml
│   └── roles/
│       ├── common/
│       ├── mysql/
│       ├── nginx/
│       └── php/
├── Vagrantfile
└── www/
    └── index.php

Puedes crear esta estructura ejecutando los siguientes comandos:

mkdir -p miproyecto/ansible/roles/{common,mysql,nginx,php}
mkdir -p miproyecto/www
touch miproyecto/Vagrantfile
touch miproyecto/ansible/playbook.yml
touch miproyecto/www/index.php

Configurando Vagrant

El archivo

Vagrantfile
es el encargado de configurar la máquina virtual que utilizaremos como entorno de desarrollo. Vamos a utilizar Ubuntu 20.04 como sistema operativo base y configuraremos la red y los recursos de la máquina virtual.

Abre el archivo

Vagrantfile
y añade el siguiente contenido:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  # Utilizamos Ubuntu 20.04 como base
  config.vm.box = "ubuntu/focal64"

  # Configuramos la red (IP privada)
  config.vm.network "private_network", ip: "192.168.33.10"

  # Configuramos los recursos de la máquina virtual
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "2048"
    vb.cpus = 2
  end

  # Montamos la carpeta del proyecto
  config.vm.synced_folder "./www", "/var/www/html", owner: "www-data", group: "www-data"

  # Provisionamos la máquina con Ansible
  config.vm.provision "ansible_local" do |ansible|
    ansible.playbook = "ansible/playbook.yml"
    ansible.install_mode = "pip"
    ansible.become = true
  end
end

Esta configuración:

  • Utiliza Ubuntu 20.04 como sistema operativo base
  • Configura la red para que la máquina virtual tenga la IP 192.168.33.10
  • Asigna 2GB de RAM y 2 CPUs a la máquina virtual
  • Monta la carpeta
    www
    del proyecto en
    /var/www/html
    de la máquina virtual
  • Utiliza Ansible para provisionar la máquina virtual

Configurando Ansible

Ahora vamos a configurar Ansible para que instale y configure todo lo necesario en la máquina virtual. Primero, vamos a crear el playbook principal.

Abre el archivo

ansible/playbook.yml
y añade el siguiente contenido:

---
- hosts: all
  become: true
  roles:
    - common
    - nginx
    - php
    - mysql

Este playbook indica que se aplicarán los roles

common
,
nginx
,
php
y
mysql
a la máquina virtual.

Rol Common

El rol

common
se encargará de instalar paquetes básicos y configurar el sistema operativo. Vamos a crear los archivos necesarios:

mkdir -p miproyecto/ansible/roles/common/tasks
touch miproyecto/ansible/roles/common/tasks/main.yml

Abre el archivo

miproyecto/ansible/roles/common/tasks/main.yml
y añade el siguiente contenido:

---
- name: Actualizar lista de paquetes
  apt:
    update_cache: yes
    cache_valid_time: 3600

- name: Instalar paquetes básicos
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - vim
    - git
    - curl
    - htop
    - zip
    - unzip
    - python3-pip

- name: Configurar zona horaria
  timezone:
    name: Europe/Madrid

Rol Nginx

El rol

nginx
se encargará de instalar y configurar el servidor web Nginx. Vamos a crear los archivos necesarios:

mkdir -p miproyecto/ansible/roles/nginx/{tasks,templates}
touch miproyecto/ansible/roles/nginx/tasks/main.yml
touch miproyecto/ansible/roles/nginx/templates/default.conf.j2

Abre el archivo

miproyecto/ansible/roles/nginx/tasks/main.yml
y añade el siguiente contenido:

---
- name: Instalar Nginx
  apt:
    name: nginx
    state: present

- name: Configurar virtual host
  template:
    src: default.conf.j2
    dest: /etc/nginx/sites-available/default
  notify: restart nginx

- name: Asegurar que Nginx está en ejecución
  service:
    name: nginx
    state: started
    enabled: yes

- name: Crear manejador para reiniciar Nginx
  meta: flush_handlers

Crea el archivo

miproyecto/ansible/roles/nginx/handlers/main.yml
con el siguiente contenido:

---
- name: restart nginx
  service:
    name: nginx
    state: restarted

Abre el archivo

miproyecto/ansible/roles/nginx/templates/default.conf.j2
y añade el siguiente contenido:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.php index.html index.htm;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /.ht {
        deny all;
    }
}

Rol PHP

El rol

php
se encargará de instalar y configurar PHP y las extensiones necesarias. Vamos a crear los archivos necesarios:

mkdir -p miproyecto/ansible/roles/php/{tasks,templates}
touch miproyecto/ansible/roles/php/tasks/main.yml
touch miproyecto/ansible/roles/php/templates/php.ini.j2

Abre el archivo

miproyecto/ansible/roles/php/tasks/main.yml
y añade el siguiente contenido:

---
- name: Instalar PHP y extensiones
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - php7.4-fpm
    - php7.4-cli
    - php7.4-common
    - php7.4-curl
    - php7.4-json
    - php7.4-mbstring
    - php7.4-mysql
    - php7.4-xml
    - php7.4-zip

- name: Configurar PHP
  template:
    src: php.ini.j2
    dest: /etc/php/7.4/fpm/php.ini
  notify: restart php-fpm

- name: Asegurar que PHP-FPM está en ejecución
  service:
    name: php7.4-fpm
    state: started
    enabled: yes

- name: Crear manejador para reiniciar PHP-FPM
  meta: flush_handlers

Crea el archivo

miproyecto/ansible/roles/php/handlers/main.yml
con el siguiente contenido:

---
- name: restart php-fpm
  service:
    name: php7.4-fpm
    state: restarted

Abre el archivo

miproyecto/ansible/roles/php/templates/php.ini.j2
y añade el siguiente contenido:

[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
disable_classes =
zend.enable_gc = On
expose_php = Off
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60

[CLI Server]
cli_server.color = On

[Date]
date.timezone = Europe/Madrid

[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=

[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = Off

[SQL]
sql.safe_mode = Off

[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = On
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off

[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off

[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off

[OPcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1

Rol MySQL

El rol

mysql
se encargará de instalar y configurar MySQL. Vamos a crear los archivos necesarios:

mkdir -p miproyecto/ansible/roles/mysql/{tasks,templates}
touch miproyecto/ansible/roles/mysql/tasks/main.yml
touch miproyecto/ansible/roles/mysql/templates/my.cnf.j2

Abre el archivo

miproyecto/ansible/roles/mysql/tasks/main.yml
y añade el siguiente contenido:

---
- name: Configurar variables para la instalación de MySQL
  debconf:
    name: mysql-server
    question: "{{ item.question }}"
    value: "{{ item.value }}"
    vtype: "{{ item.vtype }}"
  loop:
    - { question: 'mysql-server/root_password', value: 'root', vtype: 'password' }
    - { question: 'mysql-server/root_password_again', value: 'root', vtype: 'password' }

- name: Instalar MySQL
  apt:
    name: "{{ item }}"
    state: present
  loop:
    - mysql-server
    - mysql-client
    - python3-mysqldb

- name: Configurar MySQL
  template:
    src: my.cnf.j2
    dest: /etc/mysql/my.cnf
  notify: restart mysql

- name: Crear base de datos
  mysql_db:
    name: miproyecto
    state: present
    login_user: root
    login_password: root

- name: Crear usuario de la base de datos
  mysql_user:
    name: miproyecto
    password: miproyecto
    priv: 'miproyecto.*:ALL'
    state: present
    login_user: root
    login_password: root

- name: Asegurar que MySQL está en ejecución
  service:
    name: mysql
    state: started
    enabled: yes

- name: Crear manejador para reiniciar MySQL
  meta: flush_handlers

Crea el archivo

miproyecto/ansible/roles/mysql/handlers/main.yml
con el siguiente contenido:

---
- name: restart mysql
  service:
    name: mysql
    state: restarted

Abre el archivo

miproyecto/ansible/roles/mysql/templates/my.cnf.j2
y añade el siguiente contenido:

[mysqld]
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log
bind-address    = 0.0.0.0
symbolic-links  = 0
sql_mode        = NO_ENGINE_SUBSTITUTION
max_allowed_packet = 16M
innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M

[mysql]
default-character-set = utf8mb4

[mysqldump]
max_allowed_packet = 16M

Creando un archivo de prueba

Vamos a crear un archivo PHP de prueba para comprobar que todo funciona correctamente. Abre el archivo

www/index.php
y añade el siguiente contenido:

<?php
phpinfo();

Puesta en marcha

Ahora que tenemos todo configurado, vamos a poner en marcha nuestro entorno de desarrollo virtualizado. Para ello, abre una terminal en la carpeta del proyecto y ejecuta el siguiente comando:

vagrant up

Este comando creará la máquina virtual, la configurará según lo especificado en el

Vagrantfile
y ejecutará el playbook de Ansible para instalar y configurar todo lo necesario.

El proceso puede tardar varios minutos la primera vez, ya que tiene que descargar la imagen base y todos los paquetes necesarios.

Una vez finalizado, podrás acceder a tu entorno de desarrollo a través de la IP configurada en el

Vagrantfile
:

http://192.168.33.10

Deberías ver la página de información de PHP (phpinfo()), lo que indica que tu entorno de desarrollo está funcionando correctamente.

Comandos útiles de Vagrant

Aquí tienes algunos comandos útiles de Vagrant para gestionar tu entorno de desarrollo:

  • vagrant up
    : Inicia la máquina virtual
  • vagrant halt
    : Detiene la máquina virtual
  • vagrant reload
    : Reinicia la máquina virtual
  • vagrant provision
    : Vuelve a ejecutar el playbook de Ansible
  • vagrant ssh
    : Inicia una sesión SSH en la máquina virtual
  • vagrant destroy
    : Destruye la máquina virtual

Personalizando el entorno de desarrollo

El entorno de desarrollo que hemos creado es bastante básico, pero puedes personalizarlo según tus necesidades añadiendo más roles a Ansible, modificando la configuración de los servicios, etc.

Por ejemplo, podrías añadir roles para instalar:

  • Redis
  • Memcached
  • Elasticsearch
  • Node.js
  • Ruby
  • Python
  • etc.

También puedes modificar la configuración de los servicios existentes o añadir más bases de datos, usuarios, etc.

Compartiendo el entorno de desarrollo

Una de las ventajas de utilizar Vagrant y Ansible es que puedes compartir tu entorno de desarrollo con tu equipo de forma sencilla. Simplemente, añade los archivos

Vagrantfile
y la carpeta
ansible
al control de versiones (Git, por ejemplo), y cualquier persona podrá replicar exactamente el mismo entorno de desarrollo con un simple
vagrant up
.

Conclusión

En este artículo hemos visto cómo crear un entorno de desarrollo virtualizado utilizando Vagrant y Ansible. Esto nos permite tener una máquina virtual con todas las dependencias necesarias para nuestro proyecto, lo que facilita enormemente el trabajo en equipo y la portabilidad del entorno de desarrollo.

Utilizando estas herramientas, podemos asegurarnos de que todos los miembros del equipo utilizan el mismo entorno de desarrollo, evitando así los típicos problemas de "en mi máquina funciona".

Además, si cambiamos de ordenador, solo tenemos que clonar el repositorio y ejecutar

vagrant up
para tener exactamente el mismo entorno de desarrollo que antes.

En resumen, utilizar Vagrant y Ansible para crear entornos de desarrollo virtualizados es una práctica muy recomendable para cualquier equipo de desarrollo, ya que aporta numerosas ventajas y facilita enormemente el trabajo en equipo.

Al suscribirte a la newsletter comparto contigo los 10 libros más importantes de programación. Los que sin duda todo dev debería leer al menos una vez...

Quizás te interese

Tutorial de Python. Los fundamentos en 10 minutos

Tutorial de Python. Los fundamentos en 10 minutos

Testing de modelos en Django, buenas prácticas

Testing de modelos en Django, buenas prácticas