# DPTO. Despliegue web en DO con ansible ## Propuesta para despliegue de aplicaciones web para el curso 2021/22 ### Características generales * Cada alumno tiene un contenedor `lxc` en el droplet con Ubuntu Server/Alpine. De esa forma nos evitamos tener que crear un droplet para cada alumno y ahorramos costes. Cada contenedor tendrá una IP privada. * El contenedor tiene instalado ssh, php, nginx y mysql/mariadb, node, ... * En el servidor de DNS se le asigna a cada alumno un subdominio apuntndo al contenedor con nombre del tipo: `nombrealumno.daw1.infoalb.org`. **Todos** los nombres apuntan a la **IP pública** del droplet. * A cada contenedor se le redirecciona con `iptables` un puerto en el droplet que le redirecciona por ssh al contenedor. * En el droplet se crea un proxy inverso que redirecciona por nombre de dominio las peticiones http y https al contendor del alumno. * El alumno exporta su clave pública al contenedor para poder acceder por ssh al mismo sin contraseña. * El alumno tiene instalado ansible en el equipo desde el que desarrolla. * El alumno crea, en su equipo, para cada uno de sus proyectos un **playbook** de Ansible que al ejecutarlo hace que se despliegue de forma automática su aplicación. * Para el alumnado de 2º de SMR se pueden usar de forma similar los contenedores para las prácticas de **SOR** y **SRC** en Linux. ### Tutoriales #### 1. Instalación de lxd en DO * [Instalación de lxd en DO](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-lxd-on-ubuntu-20-04) #### 2. Redirección de puerto público A cada alumno se le da un puerto público para acceder por ssh a su Droplet. ```bash PUBLIC_PORT=20001 PORT=22 PUBLIC_IP=your_server_ip CONTAINER_IP=your_container_ip IFACE=eth0 sudo -E bash -c 'iptables -t nat -I PREROUTING -i $IFACE -p TCP -d $PUBLIC_IP --dport $PUBLIC_PORT -j DNAT --to-destination $CONTAINER_IP:$PORT -m comment --comment "forward to ssh server in container"' ``` El alumno para conectar ejecuta: ```bash $ ssh usuario@infoalb.org -p 20001 ``` #### 3. Configuración de haproxy como proxy inverso para reenviar peticiones http o https (Lets Encrypt) al host virtual del alumno Ejemplo de **haproxy.cfg** ```bash= frontend www-https bind *:80 bind *:443 ssl crt /etc/ssl/example.com/example.com.pem # Redirect HTTP to HTTPS redirect scheme https code 301 if !{ ssl_fc } #Lets Encrypt Renewal URI Test acl letsencrypt-acl path_beg /.well-known/acme-challenge/ use_backend letsencrypt-backend if letsencrypt-acl mode http use_backend example1 if { hdr(host) -i example1.deanlongstaff.com } use_backend example2 if { hdr(host) -i example2.deanlongstaff.com } use_backend example3 if { hdr(host) -i example3.deanlongstaff.com } #Backend to use if no URL specified default_backend example1 backend example1 server server1 192.168.40.2:80 backend example2 server example2 192.168.40.10:80 backend example3 server example3 192.168.40.30:443 check ssl verify none # Lets Encrypt Backend backend letsencrypt-backend server letsencrypt 127.0.0.1:8888 ``` * [Tutorial](https://deanlongstaff.com/haproxy-ubuntu/) #### 4. Playbook de ansible para instalar base de datos Fichero con definición de playbook para instalar mysql en servidor y crear base de datos ```yaml Fichero: db-server-playbook.yaml 1 --- 2 - hosts: nombrealumno.daw1.infoalb.org 3 4 vars: 5 mysql_root_password: password 6 7 tasks: 8 - name: install mysql 9 apt: name=mysql update_cache=yes cache_valid_time=3600 state=present 10 - name: start up the mysql service 11 shell: "service mysql start" 12 - name: ensure mysql is enabled to run on startup 13 service: name=mysql state=started enabled=true 14 - name: update mysql root password for all root accounts 15 mysql_user: 16 name: root 17 host: "{{ item }}" 18 password: "{{ mysql_root_password }}" 19 login_user: root 20 login_password: "{{ mysql_root_password }}" 21 check_implicit_admin: yes 22 priv: "*.*:ALL,GRANT" 23 with_items: 24 - "{{ ansible_hostname }}" 25 - 127.0.0.1 26 - ::1 27 - localhost 28 - name: create a new database 29 mysql_db: name=testdb state=present login_user=root login_password="{{ mysql_root_password }}" 30 - name: add sample data to database 31 copy: src=dump.sql dest=/tmp/dump.sql 32 - name: insert sample data into database 33 mysql_db: name=testdb state=import target=/tmp/dump.sql login_user=root login_password="{{ mysql_root_password }}" ``` Si además queremos importar datos a la base de datos, añadimos al playbook: ```yaml # Copy database dump file to remote host and restore it to database 'my_db' - copy: src=dump.sql.bz2 dest=/tmp - mysql_db: name=testdb state=import target=/tmp/dump.sql.bz2 ``` > El fichero dump.sql.bz2 está en el ordenador del alumno Una vez creado el fichero y configurado ansible para desplegar sólo hay que ejecutar: ```bash $ ansible-playbook -i hosts db-server-playbook.yml ``` * [Tutorial de instalación de mysql con ansible](https://medium.com/splunkuserdeveloperadministrator/creating-mysql-databases-with-ansible-925ab28598ab) #### 4. Playbook de ansible para instalar y configurar nginx incluyendo archivos de la aplicación web ```yaml= - hosts: nombrealumno.daw1.infoalb.org become: yes vars: domain: www.nombrealumno.daw1.infoalb.org tasks: - name: "apt-get update" apt: update_cache: yes cache_valid_time: 3600 - name: "install nginx" apt: name: ['nginx'] state: latest - name: "create www directory" file: path: /var/www/{{ domain }} state: directory mode: '0775' owner: "{{ ansible_user }}" group: "{{ ansible_user }}" - name: delete default nginx site file: path: /etc/nginx/sites-enabled/default state: absent notify: restart nginx - name: copy nginx site.conf template: src: site.conf.j2 dest: /etc/nginx/sites-enabled/{{ domain }} owner: root group: root mode: '0644' notify: restart nginx - name: "sync website" synchronize: src: site/ dest: /var/www/{{ domain }} archive: no checksum: yes recursive: yes delete: yes become: no handlers: - name: restart nginx service: name: nginx state: restarted ``` > La carpeta local **site** del equipo del alumno contiene los archivos del proyecto web > Contenido del fichero `site.conf.j2` con configuración del **hostvirtual**: ``` server { listen 80; listen [::]:80; server_name {{ domain }}; root /var/www/{{ domain }}; location / { try_files $uri $uri/ =404; } } ``` ###### tags: `dpto` `digital ocean` `despiegue` `ansible`