====== Docker ====== Herramienta que permite desplegar aplicaciones en contenedores de forma rápida y portable. * [[https://www.docker.com/|Web oficial]] 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 ===== {{ :informatica:sistemas_operativos:virtualizacion:docker:docker-arquitectura.jpg?nolink |}} ===== 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 [[https://hub.docker.com/|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 base * ''RUN'': cualquier comando disponible en Linux * ''COPY'': 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 entorno * ''WORKDIR'': directorio actual de trabajo en la imagen * ''EXPOSE'': 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 ===== 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: 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 * [[https://docs.docker.com/compose/install/|Documentación oficial]] * [[https://github.com/docker/compose|Repositorio oficial]] ==== 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 fallo * ''unless-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