Herramientas de usuario

Herramientas del sitio


informatica:sistemas_operativos:cursos:docker_avanzado

¡Esta es una revisión vieja del documento!


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

    • 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

Notas

Profesores:

  • Antonio Varela (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:

  1. Requisitos
  2. Diseño
  3. Codificación
  4. Pruebas
  5. Despliegue
  6. 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.

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
  1. Verifica el repositorio local (nuestra máquina) si existe la imagen hello-world.
  2. No la encuentra, así que la descarga del Docker Hub.
  3. Crea un contenedor y lo ejecuta.
  4. 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 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.

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):
    • 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
informatica/sistemas_operativos/cursos/docker_avanzado.1696875640.txt.gz · Última modificación: por tempwin