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:
- Daemon Docker (dockerd): servicio encargado de escuchas peticiones de docker
- Cliente Docker (docker): herramienta con la que realizaremos las operaciones de docker
- Registro Docker: los registros almacenan las imágenes de Docker. Docker Hub es el registro principal desde el que podemos descargar imágenes o almacenar las nuestras.
- Imagenes: plantillas de solo lectura que contiene las instrucciones para crear un contenedor con unas especificaciones concretas.
- Contenedores: instancia ejecutable de una imagen. Podemos crear, iniciar, parar, mover o borrar los contenedores.
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:
- FROM: Especifica la imagen base que se utilizará para la nueva imagen.
- RUN: Ejecuta un comando durante el proceso de creación de la imagen.
- COPY: Copia archivos desde el host hasta la imagen.
- WORKDIR: Establece el directorio por defecto para las instrucciones siguientes.
- ENV: Establece una variable de entorno.
- EXPOSE: Abre un puerto del contenedor.
- CMD: Especifica el comando que se ejecutará cuando se inicie el contenedor.
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:
- version: Especifica la versión del formato de archivo de Docker Compose.
- services: Define los servicios que conforman tu aplicación. Cada servicio tiene un nombre (por ejemplo, service1) y un conjunto de propiedades que describen la configuración del servicio.
- image: Especifica el nombre de la imagen que se usará para el servicio.
- ports: Realiza un mapeo desde un puerto en la máquina host a un puerto en el contenedor. El formato es host_port:container_port.
- environment: Especifica las variables de entorno que se pasarán al contenedor.
- networks: Define las redes utilizadas por los servicios de tu aplicación.
- driver: Especifica el controlador utilizado para crear la red.
- volumes: Define los volúmenes con nombre utilizados por los servicios de tu aplicació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
Prácticas
- Práctica 4 Despliegue de contenedores con Docker
© 2024 Fernando Valdeón