Entornos de desarrollo ágiles en local con Docker

dockerpostblog.jpg
Solucionex
18
Dic 18

Con este artículo voy a empezar una pequeña serie de artículos sobre cómo desarrollar una aplicación utilizando Docker como nuestro entorno de desarrollo en local. En este primer post nos enfocaremos en crear, configurar y levantar nuestro entorno Docker.

 

¿Por qué Docker?

Según la tipología de nuestros proyectos y las necesidades de nuestros clientes, necesitamos disponer de entornos de desarrollo rápidos de configurar, levantar y escalar, en definitiva, entornos ágiles.

En los últimos 15 años la evolución en el mundo del desarrollo de aplicaciones web ha sido vertiginosa y con ella multitud de herramientas llegaron para facilitarnos la vida. Y la verdad es que hay multitud de opciones para todos los gustos. Entornos en local utilizando herramientas como XAMPP, WAMP o MAMP, utilizar VirtualBox o VMWare para crear máquinas virtuales de desarrollo, utilizar Vagrant para facilitar la configuración y el despliegues de nuestros entornos virtuales y el uso de entornos basados en contenedores, concretamente Docker.

 

Pero ¿Qué nos ofrece Docker?

Hasta ahora veníamos utilizando Vagrant con Virtualbox como nuestro entorno de desarrollo, pero con el tiempo han ido surgiendo carencias que necesitábamos resolver y se traducían en utilizar una herramienta que utilice eficientemente los recursos de nuestros equipos aportándonos agilidad y una mayor productividad en nuestros desarrollos.

Docker nos ofrece:

  • Uso de los recursos nativos del sistema
  • Rapidez de despliegues de entornos
  • Entornos escalables
  • Alta portabilidad de los entornos de desarrollo
  • Entornos enfocados a proyectos

 

Crear un entorno de desarrollo local con Docker

A continuación vamos a crear una aplicación desde cero con un entorno de desarrollo portable. Para ello solamente es necesario tener Docker instalado en nuestro sistema anfitrión, tu PC o portátil, sea Windows, Linux o MacOS.

Arquitectura de nuestro entorno

Nuestro proyecto va a tener la siguiente estructura:

Estructura de directorio

Definición del entorno con Docker Compose

En el archivo docker-compose.yml vamos a declarar y definir nuestros servicios, uno dedicado para la base de datos y otro para el servidor web.

version: '3'

services:
  db:
    container_name: ${APP_NAME}-database
    image: ${DB_PROVIDER}:${DB_VERSION}
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_volume:/var/lib/mysql
    ports:
      - ${DB_PORT}:3306
    networks: 
      net:
        ipv4_address: 172.21.1.2
  
  www:
    build: 
      context: .docker/www
      args:
        - PHP_VERSION=${PHP_VERSION}
    container_name: ${APP_NAME}-www
    command: ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
    tty: true
    links:
      - db:${DB_PROVIDER}
    volumes:
      - ${APP_DIR}:/var/www/html:cached
    ports:
      - ${HTTP_PORT}:80
      - ${HTTPS_PORT}:443
    networks:
      net:
        ipv4_address: 172.21.1.3

networks: 
  net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.21.1.0/24

volumes:
  db_volume:

Creando nuestro propio Dockerfile

Nuestro servicio dedicado para el servidor web utilizará un archivo Dockerfile, en el que ampliaremos una imagen Docker ya predefinida.

# Base image
FROM ubuntu:18.04

ARG PHP_VERSION

# Update repositories index
RUN apt update --fix-missing && apt upgrade -y

# Install util tools
RUN ln -snf /usr/share/zoneinfo/UTC /etc/localtime && echo "UTC" > /etc/timezone
RUN apt install -y apt-utils git rsync nano vim unzip curl wget software-properties-common mysql-client

# Install Ondrej PHP Multiversions
RUN add-apt-repository ppa:ondrej/php
RUN add-apt-repository ppa:ondrej/apache2
RUN apt-get update
RUN apt-get install -y php$PHP_VERSION

# Install Apache
RUN apt-get install -y apache2

# Install PHP extensions
RUN apt-get install -y -m   php$PHP_VERSION-cli \
                            php$PHP_VERSION-dev \
                            php$PHP_VERSION-common \
                            php$PHP_VERSION-json \
                            php$PHP_VERSION-intl \
                            php$PHP_VERSION-curl \
                            php$PHP_VERSION-mysql \
                            php$PHP_VERSION-gd \
                            php$PHP_VERSION-imagick \
                            php$PHP_VERSION-ldap \
                            php$PHP_VERSION-soap\
                            php$PHP_VERSION-zip \
                            php$PHP_VERSION-mbstring \
                            php$PHP_VERSION-bcmath \
                            php$PHP_VERSION-xml \
                            php$PHP_VERSION-imap \
                            php$PHP_VERSION-bz2

# Install NodeJS and NPM
RUN apt-get install -y nodejs npm

# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin/ --filename=composer

# Config Apache
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2

RUN chown www-data:www-data -R /var/www
RUN chmod -R 755 /var/www

COPY config/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY config/php.ini /etc/php/$PHP_VERSION/apache2/php.ini
RUN a2enmod rewrite headers
RUN service apache2 start

WORKDIR /var/www/html

EXPOSE 80
EXPOSE 443

Configurando nuestro entorno Docker

En el archivo .env definiremos las variables de configuración para nuestro entorno Docker. Este paso puede omitirse si queremos introducir todos estos valores directamente en el archivo docker-compose.yml, pero de esta forma si queremos alojar nuestro proyecto en algún repositorio tendremos expuestas variables de tipo credencial.

APP_NAME=app
APP_DIR=.
HTTP_PORT=80
HTTPS_PORT=443
DB_PORT=3306
PMA_PORT=8080
DB_PROVIDER=mariadb
DB_VERSION=10.2
DB_ROOT_PASSWORD=root
DB_USER=developer
DB_PASSWORD=developer
DB_NAME=appdb
PHP_VERSION=7.1

Levantando nuestro nuestro entorno Docker

Una vez tenemos ya configurado nuestro entorno, abrimos la terminal y situándonos en la raíz de nuestro proyecto ejecutamos el siguiente comando:

docker-compose up --build -d

Este comando levanta nuestro entorno de trabajo, construyendo si fuera necesario y en segundo plano. Equivale a ejecutar los comandos:

docker-compose build && docker-compose up -d