Tabla de Contenidos
Docker
Herramienta que permite desplegar aplicaciones en contenedores de forma rápida y portable.
Utiliza contenedores e imágenes. En las imágenes se define toda la configuración del software, bibliotecas, etc., todo lo que necesita la aplicación para funcionar. En un contenedor se vuelve realidad.
- Aplicaciones de bolsillo
- Desplegar y escalar aplicaciones
- Destruir y recrear.
Ejemplo de uso:
docker run -d -p 80:80 --name web httpd
Para eliminarlo:
docker rm -fv web
Arquitectura de Docker
Imágenes
Una imagen es un paquete que contiene toda la configuración necesaria para que funcione el servicio/aplicación.
Las imágenes se componen de capas y son de solo lectura. En la primera capa definimos qué sistema operativo tendremos en la imagen.
Las capas se definen través de un fichero Dockerfile:
FROM centos:7 # Instalación del servidor web Apache RUN yum -y install httpd # Definimos el comando que ejecutará Apache. Es importante que se ejecute en primer plano o el contenedor finalizará en el momento en que se haya ejecutado lo que hay en ''CMD'' CMD ["apachectl", "-DFOREGROUND"]
Cuando no se especifica una etiqueta/tag, por defecto se descarga la latest
Imágenes oficiales
Las imágenes se alojan en el Docker Hub
Para descargarlas:
docker pull nombre-imagen
Para saber las imágenes que tenemos descargadas o en el sistema:
docker images
Para eliminar una imagen:
docker rmi nombre-imagen|identificador-imagen
Imágenes propias
Creamos un fichero Dockerfile:
FROM centos:latest RUN yum -y install httpd
Para convertirla en imagen:
docker build --tag nombre-nueva-imagen .
Para ver las capas que se crearon en una imagen:
docker history -H nombre-imagen
Operaciones
Eliminar imágenes:
docker rmi nombre-imagen
Imágenes huérfanas:
docker images -f dangling=true
Y para eliminarlas:
docker images -f dangling=true -q | xargs docker rmi
Para eliminar las imágenes que no están en uso ni referenciadas también se puede utilizar docker image prune
Dockerfile
Fichero para la creación de imágenes.
FROM: imagen de baseRUN: cualquier comando disponible en LinuxCOPY: copia archivos desde la máquina local hacia la imagen (opción recomendada por Docker).ADD: copia archivos desde la máquina local o remota (se puede indicar una URL) hacia la imagen.ENV: variables de entornoWORKDIR: directorio actual de trabajo en la imagenEXPOSE: puerto que se expondrá desde el contenedor.LABEL: etiquetas para mostrar alguna información, metadatos.USER: indica el usuario que ejecutará la tarea (por defecto es root)VOLUME: permite indicar qué datos serán persistentes en la creación del contenedor (volúmenes anónimos).CMD: comando o script para mantener un contenedor en ejecución
FROM centos LABEL version=1.0 LABEL description="This is an apache imagen" LABEL vendor=yo RUN yum install httpd -y WORKDIR /var/www # No ponemos /var/www/html como destino de la copia porque # con WORKDIR nos hemos posicionado en /var/www, así que solo # quedaría indicar html COPY app html/ # variable valor ENV contenido prueba RUN echo "$contenido" > /var/www/html/prueba.html RUN useradd pepito # A partir de aquí, todo lo que se ejecuté, será por el # usuario pepito USER pepito RUN echo "$(whoami)" > /tmp/user.html # Volvemos a ser root USER root RUN cp /tmp/user.html /var/www/html/user.html CMD apachectl -DFOREGROUND
En CMD solo se puede indicar un comando, así que si necesitamos más, habría que crear un script con todo lo necesario y luego colocar ese script en CMD
Con el Dockerfile creado, para crear la nueva imagen a partir de él:
docker build -t apache .
Si nuestro Dockerfile tiene otro nombre, hay que indicarlo a la hora de crear la imagen:
docker build -t prueba -f mi-dockerfile .
.dockerignore
Fichero que permite ignorar cualquier cosa que esté en el directorio actual y no incluirlo en una imagen:
fichero-ignorado
Multi-Stage Build
Permite utilizar varios FROM en el Dockerfile:
# La imagen de centos ya ocupa unos 200 MB FROM centos as test RUN fallocate -l 10M /opt/file1 RUN fallocate -l 20M /opt/file2 RUN fallocate -l 30M /opt/file3 # La imagen de alpine son poco más de 4 MB FROM alpine COPY --from=test /opt/file2 /opt/file
Cuando se cree la imagen, tendrá el tamaño de la imagen alpine y el fichero que hemos copiado de la anterior imagen
Buenas prácticas
- Un contenedor por servicio
.dockerignore- Pocas capas
- Multilínea (
\) para facilitar la lectura - Varios argumentos en una sola capa
- No instalar paquetes innecesarios
- Utilizar labels para añadir metadatos a la imagen
Contenedores
Sería la siguiente capa de una imagen. Ejecución de la imagen. Es de lectura y escritura. Podemos modificar cosas en el contenedor, pero no en la imagen.
Un contenedor contiene:
- Imagen
- Volúmenes
- Redes
Creación
Para crear un contenedor:
docker run -d -p 80:80 --name mi-contenedor imagen
-d: ejecuta el contenedor en segundo plano.-p: puerto local:puerto de la imagen--name: nombre que tendrá el contenedor
Podemos ver los contenedores en ejecución:
docker ps
Si queremos ver también los que se han detenido o finalizado:
docker ps -a
Eliminar
docker rm -f nombre-contenedor
Si queremos eliminar todos a la vez:
docker rm -fv $(docker ps -aq)
También se pueden eliminar los contenedores detenidos con docker container prune
Renombrar
docker rename nombre-antiguo nombre-nuevo
Detener
docker stop nombre-contenedor|id-contenedor
Iniciar
docker start nombre-contenedor|id-contenedor
Entrar en el contenedor
docker exec -it contenedor bash
Si queremos entrar como cierto usuario:
docker exec -u root -it contenedor bash
El usuario tiene que existir en la imagen o en el contenedor.
Variables de entorno
Si queremos especificar variables de entorno a la hora de crear un contenedor:
docker run -d -e "prueba:1234" --name mi-contenedor imagen
Es útil para imágenes que ya tienen definidas algunas variables:
docker run -d -e "MYSQL_ROOT_PASSWORD=123456" mysql
Copiar archivos
Si queremos copiar archivos desde nuestro equipo local hacia el contenedor:
docker cp fichero1 mi-contenedor:/ruta/contenedor/fichero1
Para copiar desde el contenedor a nuestra máquina:
docker cp mi-contenedor:/ruta/contenedor/fichero1 fichero1
Eliminar contenedores automáticamente
Para indicar que el contenedor que queremos crear es temporal y que al finalizar, lo borre:
docker run --rm -ti --name mi-contenedor imagen bash
Cuando salgamos del terminal bash del contenedor, Docker lo eliminará.
Recursos consumidos
docker stats nombre-contenedor|id-contenedor
Ejemplo de salida:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 9aa067025bbe cloud.tempwin.net 0.00% 121.2MiB / 7.791GiB 1.52% 669MB / 375MB 0B / 0B 146
Para limitar el uso de RAM que podrá hacer un contenedor:
docker run -d --memory "1gb" --name mi-contenedor imagen
Para limitar el número de CPUs:
docker run -d --cpuset-cpus 0-1 --name mi-contendor imagen
Le hemos indicado que ese contenedor solo podrá usar la CPU 0 y la CPU 1
Registros
Para centrarnos en los registros de un único servicio:
docker logs -t -f <name-of-service>
Volúmenes
Herramienta para almacenar datos del contenedor de forma persistente en nuestra máquina local.
Volúmenes de host
Residen en una carpeta del sistema de ficheros de la máquina local
docker run -d -v /opt/mysql:/var/lib/mysql -p 3306:3306 --name mi-contenedor mysql
De esa manera indicamos que el directorio /var/lib/mysql del contenedor va a estar disponible desde el directorio /opt/mysql de la máquina local.
Volúmenes anónimos
docker run -d -v /var/lib/mysql -p 3306:3306 --name mi-contenedor mysql
Al no definir en qué carpeta quedará asociada la del contenedor, Docker le dará una al azar.
No es recomendable utilizar este tipo de volúmenes ya que, además de tener nombres difíciles de memorizar, en el momento de eliminar el contenedor, Docker borrará el volumen también.
Volúmenes nombrados
Volúmenes creados por el usuario.
Para crear un volumen llamado mysql-data:
docker volume create mysql-data
Para eliminarlo:
docker volume rm mysql-data
Para asociarlo a un contenedor:
docker run -d --name mi-contenedor -v mysql-data:/var/lib/mysq -p 3306:3306 mysql
La ventaja de este tipo de volúmenes es que no se borran al eliminar el contenedor
Volúmenes huérfanos
Se llaman volúmenes dangling, no están referenciados por ningún contenedor. Para encontrarlos:
docker volume ls -f dangling=true
Para borrarlos todos de una vez:
docker volume ls -f dangling=true -q | xargs docker volume rm
-q: muestra el identificador del volumen
Redes
Con la instalación de Docker se crea una nueva interfaz de red:
$ ip a | grep docker
11: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
Todos los contenedores que creemos, estarán dentro de esa red:
docker inspect nombre|id-contenedor
Consultamos el valor IPAddress para saber la IP que usa el contenedor
La red por defecto se llama bridge
Para ver todas las redes:
docker network ls
Tipos
- Bridge
- Host: la red de la propia máquina
- None: los contenedores que se metan ahí no tendrán red
- Overlay
Creación
docker network create nombre-red
Podemos configurar la subred:
docker network create --subnet 172.120.0.0/24 --gateway 172.120.0.1 nombre-red
Inspeccionar
docker network inspect nombre-red
Eliminación
docker network rm nombre-red
Para poder eliminar una red, no debe haber ningún contendor que esté usándola
Asignación
Si queremos crear un contenedor en una determinada red:
docker run --network nombre-red -d --name mi-contenedor centos
En las redes creadas por el usuario, podemos ver los contenedores por su nombre.
Esto no es posible en la red por defecto de Docker, solo se podría por IP
Asignar IP
docker run --network mi-red --ip 172.120.0.10 -d --name mi-contendor imagen
Conectar contenedor distintas redes
docker network connect nombre-red contenedor
De esa manera, indicamos a Docker que contenedor también está en la red nombre-red
Si queremos desconectarlo de cierta red:
docker network disconnect nombre-red contenedor
Docker Compose
Herramienta que ayuda a crear aplicaciones multicontenedor. Aplicaciones como aplicaciones web utilizan bases de datos, algún lenguaje de programación y servidor web. Crearíamos un contenedor por cada elemento necesario. En lugar de hacerlo por separado, Docker Compose nos permite definirlo en un único archivo de texto y él gestionará la creación de contenedores, volúmenes, redes, etc.
Instalación
Actualizar el proceso de instalación manual, el que aquí se muestra está desfasado
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
Y le damos permisos de ejecución:
sudo chmod +x /usr/local/bin/docker-compose
Uso
El fichero de configuración de Docker Compose se llama docker-compose.yml. El fichero se compone de 4 bloques:
# Obligatorias: version: services: # Opcionales: volumes: networks:
docker run -d --name nginx -p 80:80 nginx
Traducido al docker-compose.yml:
version: '3'
services:
web:
image: nginx
container_name: nginx
ports:
- "80:80"
En Docker Compose, los contenedores que se crean se ejecutan en segundo plano, como cuando indicamos la opción -d
Para arrancar todo lo definido en el fichero docker-compose.yml:
docker-compose up -d
Si queremos darle un nombre, en lugar del que defina Docker Compose, lo lanzaremos así:
docker-compose -p nombre-proyecto up -d
Si utilizamos un Docker Compose diferentes al esperado (docker-compose.yml), añadimos la opción -f:
docker-compose -f docker-compose-mysql.yml up -d
Eliminar contenedores
docker-compose down
Variables de entorno
Podemos definirlas desde el propio fichero docker-compose.yml:
version: '3' services: web: image: mysql container_name: mysql ports: - "3306:3306" environment: - "MYSQL_ROOT_PASSWORD=abc123."
O en un fichero externo, por ejemplo, en .env:
MYSQL_ROOT_PASSWORD=abc123. MYSQL_USER=pepito
Y luego hacemos referencia a él desde docker-compose.yaml:
version: '3' services: web: image: mysql container_name: mysql ports: - "3306:3306" env_file: .env
Volúmenes
Volúmenes nombrados:
version: 3 services: web: image: nginx container_name: nginx ports: - "80:80" volumes: - "mi-volumen:/usr/share/nginx/html" volumes: mi-volumen:
Para definir un volumen de host:
version: 3 services: web: image: nginx container_name: nginx ports: - "80:80" volumes: - "/mi/ruta/:/usr/share/nginx/html"
Políticas de reinicio
version: '3' services: servicio: ... restart: no
Por defecto, Docker Compose no reinicia los contenedores si se han detenido.
Otras opciones:
always: el contenedor siempre se reiniciaráon-failure: el contenedor se reinicia si hubo un fallounless-stopped: el contenedor se reinicia solo si no ha sido detenido
Administración
Docker root dir
El directorio raíz de Docker (Docker Root Dir) es por defecto /var/lib/docker. Podemos saberlo:
docker info | grep -i "root"
Antes de hacer ningún cambio, detenemos el servicio de Docker:
systemctl stop docker
Para indicar un nuevo directorio, vamos a /lib/systemd/system/docker.service:
ExecStart=/usr/bin/dockerd --data-root /nuevo/docker-root-dir
Recargamos la nueva configuración:
systemctl daemon-reload
Y reiniciamos el servicio de Docker:
systemctl restart docker
