Tabla de Contenidos

Automatización de Despliegue

Docker

Docker es una plataforma de contenedores que permite empaquetar y ejecutar aplicaciones en un entorno aislado del sistema real, independientemente del software que haya instalado en el sistema. Podemos tener en un mismo host, diferentes contenedores Docker ofreciendo diferentes servicios.

Los contenedores de Docker permiten a los empaquetar y enviar fácilmente sus aplicaciones junto con todas las dependencias necesarias, lo que garantiza que funcionen de la misma manera en cualquier entorno en el que se ejecuten. De esta manera, Docker simplifica el proceso de desarrollo, prueba y distribución de aplicaciones.

Funcionamiento

Docker funciona creando contenedores que contienen todas las dependencias necesarias para ejecutar una aplicación. Estos contenedores son como máquinas virtuales ligeras que se ejecutan en el mismo host que la aplicación, lo que permite que se compartan recursos y se ejecuten de manera más eficiente.

Para utilizar Docker, primero se crea un archivo de configuración llamado Dockerfile que contiene instrucciones sobre cómo construir el contenedor: indicamos qué tipo de servicios queremos que contenga. Una vez que se tiene el Dockerfile, se construye el contenedor. Y cuando ya lo tenemos, podemos ejecutar la aplicación en el contenedor.

Docker facilita exportar el despliegue completo de una aplicación, de modo que podemos importar el contenedor en otro equipo.

La infraestructura Docker se compone de los siguientes elementos:

Instalación

El procedimiento de instalación está extraido de la documentación del sitio oficial de Docker. Está revisado el 22/1/2023.

En caso de que hayamos trabajado previamente con Docker, podemos revisar si las versiones anteriores están desinstaladas:

$ apt-get remove docker docker-engine docker.io containerd runc

Si apt-get nos indica que no hay paquetes instalados, todo está correcto.

Para realizar una desinstalación completa revisar el siguiente apartado.

Configurar repositorio de Docker

Antes de instalar, necesitamos una serie de dependencias:

$ sudo apt-get install ca-certificates curl gnupg lsb-release

Añadimos la clave GPG del repositorio oficial de Docker. Esto es requisito para asegurarnos del origen de la descarga:

$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Añadimos el repositorio oficial de Docker para la herramienta apt:

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Ya tenemos el repositorio de Docker configurado.

Instalación desde repositorio oficial

$ sudo apt-get update

Podemos ver que docker aun no está instalado pero podemos ver el paquete candidato para la instalación es del repositorio oficial de Docker.

Procedemos a instalar Docker:

$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Comprobamos su funcionamiento correcto ejecutando una imagen de ejemplo:

$ sudo docker run hello-world

También podemos comprobar el estado del servicio:

$ systemctl status docker

Al instalar Docker no solo instalamos el servicio de contenedores, sino también la utilidad de línea de comandos y el cliente.

Configuraciones finales

Para utilizar docker necesitamos permisos administrativos (sudo o root). Si queremos configurar un usuario estándar para que trabaje con docker debemos añadir a dicho usuario al grupo docker:

# Crear el grupo si no existe y añadir al usuario
$ addgroup docker
$ adduser nombre_usuario docker

Por último, cuando estamos aprendiendo a utilizar Docker, realizaremos diversas pruebas y cambios que harán que los ficheros de log crezcan considerablemente. Los logs de docker se mantienen de manera indefinida, y poco a poco, tu disco se irá llenando, y tu sistema acaba colapsando por falta de disco. Podemos evitarlo configurando la rotación de los logs.

El siguiente ejemplo de fichero daemon.json configura la gestión de logs controlando las propiedades max-size y max-file para activar la rotación de logs automáticamente. El fichero se encuentra en etc/docker, debemos crearlo si no existe:

/etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3" 
  }
}

Esto generará tres ficheros de log por contenedor con un máximo de 10 Megabytes cada uno, lo cual es suficiente para la mayoría de los logs.

Después de realizar cualquiera de estas dos configuraciones en docker, debemos reiniciar el servicio:

$ sudo systemctl restart docker

Uso

Para usar Docker utilizamos el comando seguido de una serie de opciones, subcomandos y argumentos:

$ docker [option] [command] [arguments]

Si queremos ver los comandos disponibles escribimos simplemente:

$ docker

Comandos útiles

# Buscar imagenes en Docker Hub
$ docker search nombre
 
# Descargar una imagen desde Docker Hub
$ docker pull nombre_imagen
 
# Listas imagenes descargadas
$ docker images
 
# Lista de contenedores en ejecución
$ docker ps -a
 
# Iniciar un contenedor a partir de una imagen
$ docker run nombre_imagen
 
# Reiniciar un contenedor
$ docker restart nombre_contenedor
 
# Parar un contenedor
$ docker stop nombre_contenedor
 
# Iniciar un contenedor parado
$ docker start nombre_contenedor

Docker Files

Un DockerFile es un fichero de texto que contiene instrucciones para crear una imagen de Docker. En cada linea se indica una instrucción en al forma: Comando - valor.

Algunos de los comandos que puedo usar son:

Ejemplos:

# Imagen de sistema operativo que quiero
FROM ubuntu
# Comandos que quiero ejecutar al crear la imagen
RUN apt-get update
RUN apt-get install apache2 -y
RUN apt-get install mariadb-server -y
RUN apt-get install php libapache2-mod-php php-mysql -y
 
# Indicar el directorio en el que me situo
WORKDIR /home
 
# Incluir ficheros de mi sistema en el contenedor
COPY /home/despliegue/bd.sql /etc/mariadb/bd.sql

Para contruir una imágen a partir de un fichero dockerfile, debes situarte en el directorio que contiene el fichero y los recursos, y ejecutar lo siguiente:

$ docker build -t nombre_imagen .

El directorio solo debe contener un solo fichero dockerfile.

Dockerfile para Apache

Dockerfile para lanzar crear una imagen con Apache conteniendo ya mi aplicación web

FROM httpd:2.4
 
# Emplazo el contenido del directorio local src al directorio del servidor
COPY src/ /usr/local/apache2/htdocs/
 
# Abro el puerto 80 para conexiones entrantes al contenedor
EXPOSE 80

Dockerfile para MariaDB

El siguiente dockerfile crea una imagen con una base de datos ya creada a partir de un script. Puedo conectarme a dicho servidor mediante la ip de ese contenedor:

$ mariadb -h ip_contenedor -u root -p
dockerfile
FROM mariadb:latest
 
ENV MYSQL_ROOT_PASSWORD=root_password
ENV MYSQL_DATABASE=basedatos.sql
 
COPY basedatos.sql /docker-entrypoint-initdb.d/
 
RUN chown -R mysql:mysql /docker-entrypoint-initdb.d/
 
CMD ["mysqld"]
basedatos.sql
CREATE DATABASE IF NOT EXISTS basedatos;
CREATE USER usuario@'%' IDENTIFIED BY 'pass';
GRANT ALL ON basedatos.* TO usuario@'%';
USE basedatos;
 
CREATE TABLE ...

Imágenes

Una imagen de Docker contiene el código fuente ejecutable de una aplicación, así como las herramientas, librerías y dependencias que la aplicación necesita para ejecutarse en un contenedor. Cuando se ejecuta una imagen se genera uno o varios contenedores.

# Descargar imagen de Docker Hub
$ docker pull [nombre]
 
# Listar imágenes disponibles
$ docker images
 
# Eliminar imagen
$ docker rmi [nombre o id]
 
# Eliminar todas las imágenes
$ docker rmi -f $(docker images -q)
 
# Crear imagen a partir de un contenedor
$ docker commit nombre_contenedor nombre_imagen

Contenedores

Un contenedor es un paquete ejecutable ligero y aislado que contiene todo lo necesario para ejecutar una aplicación: código, entorno de ejecución, herramientas de systema, librerias y configuraciones.

# Listar contenedores activos
$ docker ps -a
 
# Eliminar contenedor
$ docker rm [nombre o id (3 primeros digitos)]
 
# Eliminar todos los contenedores
$ docker rm $(docker ps -aq) 
 
# Crear un contenedor desde una imagen
$ docker create [nombre-imagen]
 
# Arrancar un contenedor existente
$ docker start [nombre o id (3 primeros digitos)]
 
# Parar un contenedor
$ docker stop [nombre o id (3 primeros digitos)]
 
# Parar todos los contenedores
$ docker stop $(docker ps -aq) 
 
# Reiniciar contenedor
$ docker restart [nombre o id (3 primeros digitos)]
 
# Crear e iniciar contenedor desde una imagen (primer plano)
$ docker run -it [imagen] --name [nombre-contenedor]
 
# Crear e iniciar contenedor y eliminar el anterior
$ docker run --rm -it [imagen] --name [nombre-contenedor]
 
# Crear e iniciar contenedor creando una carpeta compartida
$ docker run -it -v /directorio_local:/directorio_contenedor [imagen]
 
# Crear e inciiar contenedor desde una imagen (segundo plano)
$ docker run -d [imagen]
 
# Arrancar un contenedor existente y volverme a conectar por bash 
$ docker start [nombre o id (3 primeros digitos)]
$ docker exec -it [nombre o id (3 primeros digitos)] bash

Logs de un Contenedor

$ docker logs [opciones] nombre_contenedor

Contenedor Apache

dockerfile
FROM httpd:2.4
COPY ./src /usr/local/apache2/htdocs/
# Mapeo el puerto 80 del sistema con el puerto 80 del contenedor
$ docker build -t imagen-apache .
$ docker run -dit --name contenedor-apache -p 80:80 imagen-apache

Contenedor MariaDB

$ docker pull mariadb
$ docker run -d --name contenedor-mariadb --env MARIADB_USER=example-user --env MARIADB_PASSWORD=user-pass --env MARIADB_ROOT_PASSWORD=root-pass mariadb

Repositorio de Docker

Podemos crear una cuenta en DockerHub para crear nuestras propias imágenes y subirlas a nuestro repositorio. De esta forma podemos obtenerlas desde cualquier sistema en el que tengamos Docker.

Una vez tengamos creada nuestra cuenta, desde docker nos logueamos con nuestras credenciales:

$ docker login

Para subir las imágenes, necesitamos que cumplan unos requisitos en cuanto al nombre:

nombre_de_usuario/nombre_del_repositorio:etiqueta

Podemos cambiar el nombre de una imágen con la opción tag:

docker tag nombre_imagen_origen usuario/repositorio:v1

Este comando crea un alias sobre la imagen original, ya que el id es el mismo.

Ahora ya podemos publicarla en docker hub:

docker push usuario/repositorio:v1

Si queremos importarla en otro equipo:

docker pull usuario/repositorio:v1

Docker Compose

Docker Compose es una herramienta que permite ejecutar múltiples contenedores como un único servicio. Ejecuta cada contenedor de forma aislada pero permitiendo las interacciones necesarias entre ellos.

Para usar Docker Compose necesitamos crear un proyecto, el cual al menos contiene un fichero docker-compose.yml. Ese fichero indica las imágenes necesarias y las dependencias y configuraciones necesarias para lanzar la aplicación.

Para revisar la versión de Docker compose puedo consultar la siguiente referencia.

Estructura del fichero

Aquí hay una explicación de cada sección:

docker-compose.yml
version: '3.8'
services:
  php-apache-environment:
    container_name:
docker-compose.yml
version: "3.8"
services:
    db:
        image: mariadb
        ports: 
            - "3306:3306"
        command: --default-authentication-plugin=mysql_native_password
        environment:
            MYSQL_DATABASE: dbname
            MYSQL_PASSWORD: test
            MYSQL_ROOT_PASSWORD: test 
        volumes:
            - ./bd:/docker-entrypoint-initdb.d
            - persistent:/var/lib/mysql
        networks:
            - default
    www:
        build: .
        ports: 
            - "80:80"
        volumes:
            - ./www:/var/www/html
        links:
            - db
        networks:
            - default
dockerfile
FROM php:8.0.0-apache
ARG DEBIAN_FRONTEND=noninteractive
RUN docker-php-ext-install mysqli
# Include alternative DB driver
# RUN docker-php-ext-install pdo
# RUN docker-php-ext-install pdo_mysql
RUN apt-get update \
    && apt-get install -y sendmail libpng-dev \
    && apt-get install -y libzip-dev \
    && apt-get install -y zlib1g-dev \
    && apt-get install -y libonig-dev \
    && rm -rf /var/lib/apt/lists/* \
    && docker-php-ext-install zip
 
RUN docker-php-ext-install mbstring
RUN docker-php-ext-install zip
RUN docker-php-ext-install gd
 
RUN a2enmod rewrite

Para iniciar un microservicio con Docker Compose puedo usar los siguientes comandos:

# Para iniciar
$ docker compose up -d
 
# Parar
$ docker compose down

Ejemplo de proyecto completo

git pull https://github.com/jersonmartinez/docker-lamp


Prácticas


© 2024 Fernando Valdeón