====== Docker avanzado ====== Notas sobre el curso **Docker avanzado** de 30 horas organizado por el [[https://www.clusterticgalicia.com|Cluster TIC de Galicia]]. * Horas: 30 * Fecha Inicio: 09/10/2023 * Fecha Fin: 19/10/2023 ===== Objetivos principales del curso ===== A lo largo del curso el alumno aprenderá los principales retos a los que se enfrenta cuando implementa soluciones basadas en contenedores desde el punto de vista de la seguridad y la escalabilidad ===== Temario oficial ===== * 1. [[informatica:sistemas_operativos:cursos:docker_avanzado:seguridad_contenedores|Seguridad de los contenedores]] * Kernel Namespaces * Root Capabilities * Modo informático seguro * Módulos de seguridad linux * 2. Seguridad de red * Cifrado de red predeterminado y personalizado * Aislamiento de aplicaciones * 3. Control de acceso basado en roles * Modelo de acceso discrecional * Integración LDAP * Aislamiento multitenancy * 4. Software Supply Chain * Auditorías de vulnerabilidades conocidas * Firma de identidades * 5. Monitorización * Streaming de logs * Seguimiento de métricas * Auditoría de la plataforma Docker ===== Temario real ===== * Módulo 1: [[informatica:sistemas_operativos:cursos:docker_avanzado:el_porque_de_los_contenedores|El porqué de los contenedores]] * Módulo 2: [[informatica:sistemas_operativos:cursos:docker_avanzado:instalacion|Instalación]] * Módulo 3: [[informatica:sistemas_operativos:cursos:docker_avanzado:primeros_pasos|Primeros pasos]] * Módulo 4: [[informatica:sistemas_operativos:cursos:docker_avanzado:fundamentos_docker|Fundamentos de Docker]] * Módulo 5: [[informatica:sistemas_operativos:cursos:docker_avanzado:uso_de_docker_en_desarrollo|Uso de Docker en Desarrollo]] * Módulo 6: [[informatica:sistemas_operativos:cursos:docker_avanzado:creacion_de_una_aplicacion_web_de_ejemplo|Creación de una aplicación web de ejemplo]] * Módulo 7: [[informatica:sistemas_operativos:cursos:docker_avanzado:distribucion_de_imagenes|Distribución de imágenes]] * Módulo 8: [[informatica:sistemas_operativos:cursos:docker_avanzado:integracion_continua_y_testing_con_docker|Integración continua y testing con Docker]] * Módulo 9: [[informatica:sistemas_operativos:cursos:docker_avanzado:despliegue_de_containers|Despliegue de containers]] * Módulo 10: [[informatica:sistemas_operativos:cursos:docker_avanzado:networking_y_service_discovery|Networking y Service Discovery]] * Módulo 11: [[informatica:sistemas_operativos:cursos:docker_avanzado:orquestacion_clustering_gestion|Orquestación, clustering y gestión]] * [[informatica:sistemas_operativos:cursos:docker_avanzado:ejercicios_practicos|Ejercicios prácticos / guiados]]. * [[informatica:sistemas_operativos:cursos:docker_avanzado:tests|Tests]] ===== Notas ===== Profesores: * Antonio Varela Nieto (antonio.varela@teslatechnologies.com) (está certificado en Docker) * ESTEBAN VAZQUEZ FERREIRO El profe usa Visual Studio Code para escribir los Dockerfiles. Los contenedores de Docker son una de las tecnologías más en auge en el mundo del desarrollo, ofreciendo métodos más sencillos, rápidos y robustos que los conocidos anteriormente para desarrollar, desplegar y distribuir software. A lo largo del curso el alumno aprenderá por qué los contenedores son tan importantes y cómo hacer que sean parte de su proceso de desarrollo. La formación trata desde las bases de Docker hasta la ejecución de docenas de contenedores sobre un sistema multi-host con networking y scheduling, además de revisar los pasos necesarios para desarrollar, testear y desplegar aplicaciones web con Docker. Requisitos para seguir el curso: * Estar familiarizado con SO base Linux * Estar familiarizado con la línea de comandos * Nociones básicas de desarrollo * Nociones básicas de despliegue de aplicaciones en servidores * Nociones básicas de redes Objetivos del curso: * Entender lo que es un contenedor y su filosofía * Instalar y configurar un entorno de despliegue de contenedores * Integrar los contenedores en el proceso de desarrollo. * Distribución de imágenes * Proceso de integración continua y despliegue continuo con Dockers * Manejo de redes y Service Discovery * Escalado de aplicaciones mediante orquestación, clustering y gestión. ===== El porqué de los contenedores ===== El objetivo de los contenedores es "hacer despliegues". ¿Qué es una aplicación web? En la ingeniería de software se denomina aplicación web a aquellas herramientas que los usuarios pueden utilizar accediendo a un servidor web a través de internet o de una intranet mediante un navegador. En otras palabras, es un programa que se codifica en un lenguaje interpretable por los navegadores web en la que se confía la ejecución al navegador. Es un proceso de ingeniería: - Requisitos - Diseño - Codificación - Pruebas - Despliegue - Mantenimiento La elaboración de una aplicación es un proceso de ingeniería dividido en fases. Cada fase involucra diferentes roles con necesidades de conocimiento dispares pero complementarios Las fases pueden ejecutarse de forma secuencial una única vez (metodología en Cascada) o pueden ejecutarse N veces de forma repetitiva (metodología en espiral). Múltiples tecnologías para el desarrollo: * Capa navegador * HTML * CSS * JavaScript * Capa servidor * PHP * Java * Python * Ruby * Node.js * ... * Capa persistencia * Bases de datos SQL (MySQL, PostgreSQL, Oracle...) * Bases de datos NoSQL (Cassandra, MongoDB, Redis...) Múltiples tecnologías para el despliegue: * Apache * Nginx * Apache Tomcat * GlassFish * Microsoft IIS * Oracle weblogic server ==== Desplegando una aplicación web ==== === Servidor dedicado === * Hace años era la opción predeterminada * Si todas las aplicaciones comparten arquitectura y tecnologías es más fácil de configurar y mantener * Todas las aplicaciones coexisten en la misma máquina (SO) * Puede suponer un problema de seguridad si no se manejan los permisos de forma adecuada * Una aplicación puede consumir todos los recursos disponibles * Un fallo crítico en una aplicación puede suponer la caída del resto de aplicaciones. * El despliegue en un nuevo entorno implica un gran trabajo de configuración * La escalabilidad, cuando es posible, es complicada y costosa === Virtualización === Partiendo de una máquina física, en un sistema operativo se instala un hipervisor donde se crearán máquinas virtuales. * Cada aplicación o conjunto de aplicaciones se despliega dentro de una máquina virtual (MV) * En el mismo servidor (host) pueden coexistir múltiples MV con tecnologías diferentes * El uso de recursos del host pueden limitarse por MV * Un fallo crítico dentro de una MV no afecta a otras (aislamiento) * Mover la MV a otro servidor (co nel mismo sistema de virtualización) es relativamente sencillo. * La escalabilidad es más sencilla: * Duplicar una MV es mucho más fácil que duplicar un servidor. * Se puede parar una instancia y relanzarla con más asignación de recursos. La escalabilidad vertical: ampliar capacidades de un servidor (más RAM, más disco...) La escalabilidad horizontal: duplicar una instancia / elemento. === Contenerización === No es necesario añadir sistemas operativos virtualizados sino lo que necesite cada aplicación: bibliotecas / runtimes y el propio código de la aplicación. * Existen varias opciones para la contenerización, pero sin duda la más extendida es Docker. * El objetivo principal es el mismo, el aislamiento entre aplicaciones y generar un entorno replicable * En este caso en lugar de albergar un SO completo lo que se busca es compartir directamente los recursos del SO host. * El **Docker Engine** es el encargado de lanzar y gestionar los contenedores buscando el uso óptimo de los recursos del host. * Docker funciona a partir de **imágenes** que se pueden reutilizar entre varias aplicaciones. * Docker aisla directamente aplicaciones, no sistemas operativos. Las imágenes base salen de los repositorios/registros. El oficial es el [[https://hub.docker.com/|Docker Hub]]. ==== Virtualización VS Contenerización ==== | | Virtualización | Contenerización | | Tamaño | Elevado debido a que tiene que embeber el SO huésped | Reducido al no necesitar SO huésped | | Reserva de recursos | Se hace previa al despliegue y es bloqueante |Es dinámica en función de las necesidades y la gestiona el engine | | Tiempo de despliegue |Varios minutos | Unos pocos segundos | | Portabilidad entre OS host | Permitida | NO se puede ejecutar contenedores / aplicaciones que no sean para ese mismo SO host | | Complejidad |Relativamente sencillo de empezar | La complejidad crece a medida que se requieren despliegues más escalabels | La migración en Docker debería hacerse de los volúmenes y no del docker en sí. ===== Qué es Docker ===== * Docker es un motor de código abierto que automatiza la implementación de aplicaciones en contenedores. * Fue escrito por el equipo Docker, Inc (anteriormente dotCloud Inc, uno de los primeros jugadores en el mercado de la Plataforma como Servicio (PaaS)). * Está diseñado para proporcionar un entorno ligero y rápido en el que ejecutar su código, así como un flujo de trabajo eficiente para llevar ese código de su computadora portátil a su entorno de prueba y luego a la producción. * Puede comenzar con Docker en un host mínimo que no ejecute nada más que un kernel de Linux compatible y un binario de Docker. ===== Por qué usar Docker ===== * Olvídate del SO y de las configuraciones manuales: * Con las máquinas físicas o virtuales hay que instalar el SO, todo el software y dependencias que se necesita para que nuestra aplicación funcione de forma manual. * Con Docker todo eso se puede especfificar en el Dockerfile y cada vez que se arranque el contenecor se garantiza su correcta configuración * Adiós al "en mi máquina funciona" * El contenedor de Docker proporciona consistencia. Lo que va dentro es siempre lo mismo independientemente de donde se despliegue. * Mucho más ligero y escalable que una MV * Uso más eficiente de los recursos del host * Transformar fácilmente un único contenedor en una granja mediante Docker Composer. * Más potencia aun con Kubernetes * Permite monitorizarlos, asegurarlos, ejecutarlos periódicamente, y muchas más cosas, para crear entornos empresariales con la complejidad que necesites. * Tan seguros como una MV * Disponen de una versión reducida del espacio de usuario del sistema operativo * Un contenedor no puede acceder a otros contenedores ni al SO subyacente (a excepción de los volúmenes de almacenamiento a los que les des permiso) * Control de versiones de la infraestructura * Dado que toda la configuración de la infraestructura se hace en ficheros de texto plano, este fichero puede ir al sistema de control de versiones junto con el propio código de la aplicación. * Concebido para trabajar en la nube * Los contenedores se pensaron con la nube en la mente * En la actualidad los principales actores cloud ofrecen completísimas opciones de despliegue de contenedores en sus infraestructuras (Amazon Web Services, Microsoft Azure, Google Compute Engine) * Todos ellos soportan Kubernetes para permitir despliegues más complejos de múltiples contenedores orquestados para trabajar y escalar de forma independiente. Podman, Buildah y skopeo es la alternativa que ofrece Red Hat a Docker containers. Docker y Podman respetan el estándar [[https://es.wikipedia.org/wiki/Open_Container_Initiative|OCI]]. La gran diferencia es que en Podman no existe un demonio como Docker Engine. ===== Instalación ===== En Windows y macOS los instaladores incluyen una plataforma de virtualización transparente para incorporar el núcleo Linux necesario para la ejecución del entorno de Docker: [[https://www.docker.com/products/docker-desktop/|Docker Desktop]]. En Linux tenemos instrucciones diferentes según la distro que escojamos: * [[https://docs.docker.com/engine/install/|Docker Engine]] * [[https://docs.docker.com/compose/|Docker Compose]] Requisitos: * Arquitectura 64 bits * Linux kernel 3.8 o posterior * El kernel debe admitir un controlador de almacenamiento apropiado: * Device Mapper (la opción por defecto) * AUFS * vfs * btrfs * Las características del núcleo de **cgroups** (permite aplicar cuotas al acceso a recursos) y **namespaces** (permite el aislamiento) deben ser compatibles y habilitadas. Para comprobar si la instalación ha sido correcta y tenemos funcionando Docker: docker info Ejemplo de salida: Client: Docker Engine - Community Version: 24.0.6 Context: default Debug Mode: false Plugins: compose: Docker Compose (Docker Inc.) Version: v2.21.0 Path: /usr/libexec/docker/cli-plugins/docker-compose Server: Containers: 31 Running: 22 Paused: 0 Stopped: 9 Images: 53 Server Version: 24.0.6 Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Using metacopy: false Native Overlay Diff: true userxattr: false Logging Driver: json-file Cgroup Driver: systemd Cgroup Version: 2 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: io.containerd.runc.v2 runc Default Runtime: runc Init Binary: docker-init containerd version: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870532 runc version: v1.1.9-0-gccaecfc init version: de40ad0 Security Options: seccomp Profile: builtin cgroupns Kernel Version: 6.1.0-0.deb11.11-amd64 Operating System: Debian GNU/Linux 11 (bullseye) OSType: linux Architecture: x86_64 CPUs: 8 Total Memory: 15.45GiB Name: omv ID: PW6N:HZDR:DKQF:HCWR:Z6GD:BSLC:K3TE:YEQF:6OAG:QWTR:FLHU:VJXE Docker Root Dir: /srv/dev-disk-by-uuid-d8848615-8168-4fba-8cce-d868e42e9fdb/docker Debug Mode: false Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false Docker Desktop limita el uso de CPU, RAM y disco, por defecto. También podemos ver la versión instalada con: docker version Ejemplo de salida: docker version Client: Docker Engine - Community Version: 24.0.6 API version: 1.43 Go version: go1.20.7 Git commit: ed223bc Built: Mon Sep 4 12:32:16 2023 OS/Arch: linux/amd64 Context: default Server: Docker Engine - Community Engine: Version: 24.0.6 API version: 1.43 (minimum version 1.12) Go version: go1.20.7 Git commit: 1a79695 Built: Mon Sep 4 12:32:16 2023 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.6.24 GitCommit: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870523 runc: Version: 1.1.9 GitCommit: v1.1.9-0-gccaecfc docker-init: Version: 0.19.0 GitCommit: de40ad0 ===== Uso ===== ==== Comando docker ==== El comando ''docker'' es nuestra herramienta para interactuar con toda la arquitectura de Docker. La sintaxis es la siguiente: docker [opción] [comando] [argumentos] Si introducimos únicamente el comando ''docker'' en la terminal, nos responderá con la lista de todos los subcomandos de los que dispone: docker https://labs.play-with-docker.com/ El comando ''docker'' solo puede ser ejecutado por root o un usuario que pertenezca al grupo ''docker'' (se crea automáticamente durante la instalación). Lo que vamos a administrar entra dentro de los siguientes grupos: * Imágenes * Contenedores * Volúmenes * Redes * El propio sistema ==== Hello, world ==== Todo empieza con un "hello, world": docker run hello-world - Verifica el repositorio local (nuestra máquina) si existe la imagen ''hello-world''. - No la encuentra, así que la descarga del Docker Hub. - Crea un contenedor y lo ejecuta. - Se muestra el resultado de la ejecución de dicho contenedor y se para el contenedor. Podríamos ejecutar de nuevo ''docker run'' y se creará un nuevo contenedor, pero la imagen será la misma. Normalmente, además de la imagen se le indica el nombre de la versión / etiqueta (//tag//). Por ejemplo, ''hello-world:latest''. Cuando no ponemos la etiqueta, Docker coge ''latest''. Para que un contenedor se mantenga en ejecución debe existir un proceso que quede en primer plano (si ejecutásemos un programa en modo demonio, el contenedor también se cerraría). Como las imágenes, los contenedores también tienen nombres / identificadores únicos. Podemos darle un nombre al contenedor que queremos crear con la opción ''%%--%%name'': docker run --name mi-contenedor -it ubuntu /bin/bash De esta manera, si volvemos a ejecutar el comando, no nos dejará porque no podemos tener dos contenedores con el mismo nombre. Recordemos que tanto el nombre como el ID identifica un contenedor. Crear un contenedor en modo "background" (de fondo) y ejecutando un bucle infinito para que no se pare: docker run --name mydaemon -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done" Miramos que esté en ejecución el contenedor anterior: docker ps Podemos ver la salida del contenedor: docker logs mydaemon Para ver en tiempo real la salida: docker logs -ft 10 mydaemon Para ver la lista de procesos dentro del contendor (sin tener que entrar en él): docker top mydaemon ==== docker inspect ==== Comando que da información extendida sobre un contenedor. docker inspect mi-contenedor Ejemplo de salida: [ { "Id": "08d1311242a61620b8dd03b951ef66f5dc63d82d35ba17fda9cdf80d3d9844d6", "Created": "2023-10-09T18:26:20.92818159Z", "Path": "/bin/sh", "Args": [ "-c", "while true; do echo hello world; sleep 1; done" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 192214, "ExitCode": 0, "Error": "", "StartedAt": "2023-10-09T18:26:21.354420029Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:3565a89d9e81a4cb4cb2b0d947c7c11227a3f358dc216d19fc54bfd77cd5b542", "ResolvConfPath": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-8cce-d868e42e9fdb/docker/containers/08d1311242a61620b8dd03b951ef66f5dc63d82d35ba17fda9cdf80d3d9844d6/resolv.conf", "HostnamePath": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-8cce-d868e42e9fdb/docker/containers/08d1311242a61620b8dd03b951ef66f5dc63d82d35ba17fda9cdf80d3d9844d6/hostname", "HostsPath": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-8cce-d868e42e9fdb/docker/containers/08d1311242a61620b8dd03b951ef66f5dc63d82d35ba17fda9cdf80d3d9844d6/hosts", "LogPath": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-8cce-d868e42e9fdb/docker/containers/08d1311242a61620b8dd03b951ef66f5dc63d82d35ba17fda9cdf80d3d9844d6/08d1311242a61620b8dd03b951ef66f5dc63d82d35ba17fda9cdf80d3d9844d6-json.log", "Name": "/mydaemon", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": {}, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "ConsoleSize": [ 36, 188 ], "CapAdd": null, "CapDrop": null, "CgroupnsMode": "private", "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": [], "BlkioDeviceWriteBps": [], "BlkioDeviceReadIOps": [], "BlkioDeviceWriteIOps": [], "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": null, "PidsLimit": null, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-cc8e-d868e42e9fdb/docker/overlay2/befdb5ff531519676951b62dcbaa449dc9a2fce322b05ba049f13475bc8132cf-init/diff:/srv/dev-disk-by-uuid-d8848615-8168-4fba-8cce-d868e42e9fdb/docker/overlay2/37e0fab9210ae886a0eff914fa60be829e336c6f4b201dd5141d6839f5898d79/diff", "MergedDir": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-cc8e-d868e42e9fdb/docker/overlay2/befdb5ff531519676951b62dcbaa449dc9a2fce322b05ba049f13475bc8132cf/merged", "UpperDir": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-cc8e-d868e42e9fdb/docker/overlay2/befdb5ff531519676951b62dcbaa449dc9a2fce322b05ba049f13475bc8132cf/diff", "WorkDir": "/srv/dev-disk-by-uuid-d8848615-8168-4fba-cc8e-d868e42e9fdb/docker/overlay2/befdb5ff531519676951b62dcbaa449dc9a2fce322b05ba049f13475bc8132cf/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "08d1311242a6", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/sh", "-c", "while true; do echo hello world; sleep 1; done" ], "Image": "ubuntu", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "org.opencontainers.image.ref.name": "ubuntu", "org.opencontainers.image.version": "22.04" } }, "NetworkSettings": { "Bridge": "", "SandboxID": "4a5cbec72d8ed785cab1167730d4872c9c5bf627b435566dee54548ea74cc8e9", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/4a5cbec72d8e", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "5cc996b631769af9085216ccc8ec1009c676e5033b7126612d72317482aa313c", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "3030bfecb10961fecc8ea4930975a55e4c4a7f5bd6e36bbf6682c5b1c8896696", "EndpointID": "5cc996b631769af90cc8e6c161ac1009c676e5033b7126612d72317482aa313c", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ] Para coger una parte de esa salida, por ejemplo, la dirección IP del contenedor: docker inspect -f='{{.NetworkSettings.IPAddress}}' mydaemon La sintaxis es [[https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html|JSONPath]]. ==== Busybox ==== [[https://hub.docker.com/_/busybox/|Busybox]] es una imagen Docker mínima que nos permite trastear de forma rápida. Para ejecutar un único comando dentro de una imagen podemos usar lo siguiente: docker run busybox echo hola mundo Lo que escribamos a continuación del nombre de la imagen, se lanzaría en una terminal del contenedor en ejecución. ''docker run'' siempre crea un contenedor cada vez que lo ejecutamos Si lo que queremos es abrir una terminal para trastear más en detalle: docker run -it busybox sh * ''-i'': modo interactivo. * ''-t'': reserva un TTY. Podemos crear contenedores de diferentes imágenes para: * Probar cierta herramienta sin instalarlo en nuestro sistema anfitrión. * Probar diferentes versiones de alguna aplicación. * Hacer pruebas desde un entorno aislado. ==== docker ps ==== Contenedores activos: docker ps Para ver todos los contenedores (tanto activos como no): docker ps -a Si queremos mostrar solo el identificador, usamos la opción ''-q'': docker ps -aq ==== Reutilizar un contenedor ==== Mientras exista un contenedor, los cambios que hagamos en él se mantendrán. Si está parado: docker start | La versión larga del comando de arriba: ''docker container start...'' Para saber el identificador del contenedor: docker ps -a A diferencia de las máquinas virtuales, los contenedores están pensados para mantenerlos en ejecución mientras se necesiten y eliminarlos cuando no sean necesarios. Veremos cómo gestionar la persistencia de los datos con los volúmenes (una carpeta en algún sistema de ficheros). Parar un contenedor: docker stop | ==== docker exec ==== Para entrar en un contenedor existente usamos ''docker exec'': docker exec -it sh ==== Eliminar un contenedor ==== docker rm | Eliminar todos los contenedores: docker rm $(docker ps -aq) Docker avisará que no puede eliminar los contenedores que estén en ejecución ==== docker diff ==== Para ver las modificaciones de un contenedores a partir de su imagen base: docker diff | Esto nos puede servir para saber qué perderíamos si eliminamos el contenedor. ==== Crear un contenedor con una Ubuntu ==== docker run ubuntu /bin/bash ==== docker attach ==== A diferencia de ''docker exec'', ''docker attach'' nos permite conectar a un contenedor en ejecución e interactura con el proceso del contenedor que tenga PID 1. Con ''docker exec'' crearmos un nuevo proceso en el contenedor. ==== Práctica ==== * **Iniciar un contenedor interactivo de Ubuntu**: ''docker run -it ubuntu /bin/bash'' * **Explora tu entorno** (el contenedor): * ''hostname'' * ''cat /etc/hosts'' * ''ifconfig'' (hay que instalar el paquete ''net-tools'') * **Instala el editor de textos** ''vim'': * ''apt-get update'' * ''apt-get install vim'' * **Sal del entorno con el comando** ''exit'' **y repite el paso 1**. **Tenemos el comando** ''vim''? Al volver a ejecutar ''docker run -it ubuntu /bin/bash'' se crea un nuevo contenedor por lo que no tendremos ninguno de los cambios que hicimos en el contenedor previo. Docker monta un puente para poder acceder a la IP de los contenedores desde nuestra máquina anfitriona. Por defecto, los contenedores que levantemos estarán en la red ''172.17.0.x''. ===== Imágenes ===== Obtener información de las imágenes descargadas: docker images ls ===== Recursos ===== * https://www.redhat.com/en/interactive-labs: laboratorios gratuitos de Red Hat * https://killercoda.com: laboratorios con contenedores. * [[https://labs.play-with-docker.com/|Play with Docker]]: probar Docker desde el navegador. * [[https://dockerlabs.collabnix.com/|Getting Started with Docker]]: laboratorios guiados de Docker.