¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Docker avanzado
Notas sobre el curso Docker avanzado de 30 horas organizado por el 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
-
- 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: El porqué de los contenedores
- Módulo 2: Instalación
- Módulo 3: Primeros pasos
- Módulo 4: Fundamentos de Docker
- Módulo 5: Uso de Docker en Desarrollo
- Módulo 7: Distribución de imágenes
- Módulo 9: Despliegue de containers
- Módulo 10: Networking y Service Discovery
- Módulo 11: Orquestación, clustering y gestión
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 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 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: Docker Desktop.
En Linux tenemos instrucciones diferentes según la distro que escojamos:
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 JSONPath.
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 <ID_CONTENEDOR>|<NOMBRE_CONTENEDOR>
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 <ID_CONTENEDOR>|<NOMBRE_CONTENEDOR>
docker exec
Para entrar en un contenedor existente usamos docker exec:
docker exec -it <ID_CONTENEDOR> sh
Eliminar un contenedor
docker rm <ID_CONTENEDOR>|<NOMBRE_CONTENEDOR>
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 <ID_CONTENEDOR>|<NOMBRE_CONTENEDOR>
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):
hostnamecat /etc/hostsifconfig(hay que instalar el paquetenet-tools)
- Instala el editor de textos
vim:apt-get updateapt-get install vim
- Sal del entorno con el comando
exity repite el paso 1. Tenemos el comandovim?
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.
- Play with Docker: probar Docker desde el navegador.
