Que é Docker: unha breve excursión á historia e as abstraccións básicas

Comezou o 10 de agosto en Slurm Curso de video docker, no que o analizamos por completo, desde abstraccións básicas ata parámetros de rede.

Neste artigo falaremos da historia de Docker e das súas principais abstraccións: Image, Cli, Dockerfile. A charla está pensada para principiantes, polo que é improbable que interese a usuarios experimentados. Non haberá sangue, apéndice ou inmersión profunda. O básico.

Que é Docker: unha breve excursión á historia e as abstraccións básicas

Que é Docker

Vexamos a definición de Docker da Wikipedia.

Docker é un software para automatizar a implantación e xestión de aplicacións en contornas contenedoras.

Nada queda claro desta definición. Non está especialmente claro o que significa "en ambientes que admiten a contenerización". Para descubrilo, volvamos no tempo. Comecemos pola época que eu chamo convencionalmente a "Era Monolítica".

Época monolítica

A era monolítica é a principios dos anos 2000, cando todas as aplicacións eran monolíticas, cunha morea de dependencias. O desenvolvemento levou moito tempo. Ao mesmo tempo, non había moitos servidores, todos os coñecíamos polo seu nome e os supervisabamos. Hai unha comparación tan divertida:

As mascotas son animais domésticos. Na era monolítica, tratabamos aos nosos servidores como mascotas, coidados e queridos, eliminando motas de po. E para unha mellor xestión dos recursos, utilizamos a virtualización: collemos un servidor e dividiuno en varias máquinas virtuais, garantindo así o illamento do ambiente.

Sistemas de virtualización baseados en hipervisores

Probablemente todo o mundo xa escoitou falar dos sistemas de virtualización: VMware, VirtualBox, Hyper-V, Qemu KVM, etc. Ofrecen illamento de aplicacións e xestión de recursos, pero tamén teñen desvantaxes. Para facer a virtualización, necesitas un hipervisor. E o hipervisor é unha sobrecarga de recursos. E a propia máquina virtual adoita ser todo un coloso: unha imaxe pesada que contén un sistema operativo, Nginx, Apache e posiblemente MySQL. A imaxe é grande e a máquina virtual é inconveniente para operar. Como resultado, traballar con máquinas virtuais pode ser lento. Para resolver este problema, creáronse sistemas de virtualización a nivel de núcleo.

Sistemas de virtualización a nivel de núcleo

A virtualización a nivel de núcleo é compatible con sistemas OpenVZ, Systemd-nspawn e LXC. Un exemplo rechamante desta virtualización é LXC (Linux Containers).

LXC é un sistema de virtualización a nivel de sistema operativo para executar varias instancias illadas do sistema operativo Linux nun só nodo. LXC non usa máquinas virtuais, senón que crea un ambiente virtual co seu propio espazo de proceso e pila de rede.

Esencialmente, LXC crea contedores. Cal é a diferenza entre máquinas virtuais e contedores?

Que é Docker: unha breve excursión á historia e as abstraccións básicas

O contedor non é axeitado para illar procesos: atópanse vulnerabilidades nos sistemas de virtualización a nivel do núcleo que lles permiten escapar do contenedor ao host. Polo tanto, se necesitas illar algo, é mellor usar unha máquina virtual.

As diferenzas entre virtualización e containerización pódense ver no diagrama.
Hai hipervisores de hardware, hipervisores enriba do SO e contenedores.

Que é Docker: unha breve excursión á historia e as abstraccións básicas

Os hipervisores de hardware son xeniais se realmente queres illar algo. Porque é posible illar a nivel de páxinas de memoria e procesadores.

Hai hipervisores como programa, e hai contedores, e deles falaremos máis adiante. Os sistemas de contenedores non teñen hipervisor, pero hai un Container Engine que crea e xestiona os contedores. Esta cousa é máis lixeira, polo que debido ao traballo co núcleo hai menos sobrecarga ou ningunha.

O que se usa para a contenerización a nivel do núcleo

As principais tecnoloxías que permiten crear un contedor illado doutros procesos son os espazos de nomes e os grupos de control.

Espazos de nomes: PID, Rede, Montaxe e Usuario. Hai máis, pero para facilitar a comprensión centrarémonos nestes.

O espazo de nomes PID limita os procesos. Cando, por exemplo, creamos un espazo de nomes PID e colocamos alí un proceso, pasa a ser con PID 1. Normalmente nos sistemas PID 1 é systemd ou init. En consecuencia, cando colocamos un proceso nun novo espazo de nomes, tamén recibe o PID 1.

O espazo de nomes de rede permítelle limitar/illar a rede e colocar as súas propias interfaces dentro. Mount é unha limitación do sistema de ficheiros. Usuario: restrición de usuarios.

Grupos de control: memoria, CPU, IOPS, rede: uns 12 axustes en total. En caso contrario, tamén se lles chama Cgroups ("grupos C").

Os grupos de control xestionan os recursos dun contedor. A través dos Grupos de Control podemos dicir que o contedor non debe consumir máis dunha determinada cantidade de recursos.

Para que a contenerización funcione plenamente, utilízanse tecnoloxías adicionais: Capacidades, Copy-on-write e outras.

As capacidades son cando dicimos a un proceso o que pode ou non. A nivel do núcleo, estes son simplemente mapas de bits con moitos parámetros. Por exemplo, o usuario root ten todos os privilexios e pode facer todo. O servidor de tempo pode cambiar a hora do sistema: ten capacidades na Time Capsule, e iso é todo. Usando privilexios, pode configurar restricións para procesos de forma flexible e, así, protexerse.

O sistema Copy-on-write permítenos traballar con imaxes de Docker e utilizalas de forma máis eficiente.

Docker ten actualmente problemas de compatibilidade con Cgroups v2, polo que este artigo céntrase especificamente en Cgroups v1.

Pero volvamos á historia.

Cando os sistemas de virtualización apareceron a nivel do núcleo, comezaron a utilizarse activamente. A sobrecarga do hipervisor desapareceu, pero quedaron algúns problemas:

  • imaxes grandes: empuxan un sistema operativo, bibliotecas, un montón de software diferente ao mesmo OpenVZ, e ao final a imaxe segue sendo bastante grande;
  • Non existe un estándar normal para o envasado e a entrega, polo que segue a ser o problema das dependencias. Hai situacións nas que dúas pezas de código usan a mesma biblioteca, pero con versións diferentes. Pode haber un conflito entre eles.

Para resolver todos estes problemas, chegou a próxima era.

Era dos contedores

Cando chegou a Era dos Containers, a filosofía de traballar con eles cambiou:

  • Un proceso - un recipiente.
  • Entregamos todas as dependencias que o proceso precisa no seu contedor. Isto require cortar monólitos en microservizos.
  • Canto menor sexa a imaxe, mellor: hai menos vulnerabilidades posibles, desenvólvese máis rápido, etc.
  • As instancias vólvense efémeras.

Lembras o que dixen sobre as mascotas contra o gando? Antes, os casos eran como animais domésticos, pero agora convertéronse como gando. Anteriormente, había un monolito - unha aplicación. Agora son 100 microservizos, 100 contedores. Algúns recipientes poden ter de 2 a 3 réplicas. Faise menos importante para nós controlar cada recipiente. O máis importante para nós é a dispoñibilidade do propio servizo: o que fai este conxunto de contedores. Isto cambia os enfoques do seguimento.

En 2014-2015, Docker floreceu, a tecnoloxía da que falaremos agora.

Docker cambiou a filosofía e normalizou o paquete da aplicación. Usando Docker, podemos empaquetar unha aplicación, enviala a un repositorio, descargala desde alí e implementala.

Poñemos todo o que necesitamos no contedor de Docker, así o problema de dependencia está resolto. Docker garante a reproducibilidade. Creo que moita xente atopouse coa irreproducibilidade: todo che funciona, empúxase á produción e alí deixa de funcionar. Con Docker este problema desaparece. Se o teu contedor Docker comeza e fai o que ten que facer, con moita probabilidade comezará en produción e fará o mesmo alí.

Digresión sobre os gastos xerais

Sempre hai disputas sobre gastos xerais. Algunhas persoas cren que Docker non leva unha carga adicional, xa que utiliza o núcleo de Linux e todos os seus procesos necesarios para a contenerización. Como, "se dis que Docker está enriba, entón o núcleo de Linux está enriba".

Por outra banda, se profundizas, hai de feito varias cousas en Docker que, cun tramo, pódese dicir que están por riba.

O primeiro é o espazo de nomes PID. Cando colocamos un proceso nun espazo de nomes, asígnaselle o PID 1. Ao mesmo tempo, este proceso ten outro PID, que está situado no espazo de nomes do host, fóra do contedor. Por exemplo, lanzamos Nginx nun contedor, converteuse en PID 1 (proceso mestre). E no host ten o PID 12623. E é difícil dicir cantos gastos xerais son.

A segunda cousa é Cgroups. Tomemos Cgroups por memoria, é dicir, a capacidade de limitar a memoria dun contedor. Cando está activado, actívanse os contadores e a contabilidade da memoria: o núcleo necesita comprender cantas páxinas foron asignadas e cantas aínda quedan libres para este contedor. Isto posiblemente sexa un sobrecarga, pero non vin estudos precisos sobre como afecta o rendemento. E eu mesmo non notei que a aplicación que se executaba en Docker experimentaba de súpeto unha forte perda de rendemento.

E unha nota máis sobre o rendemento. Algúns parámetros do núcleo pásanse do host ao contedor. En particular, algúns parámetros de rede. Polo tanto, se queres executar algo de alto rendemento en Docker, por exemplo, algo que utilice activamente a rede, polo menos debes axustar estes parámetros. Algúns nf_conntrack, por exemplo.

Sobre o concepto Docker

Docker consta de varios compoñentes:

  1. Docker Daemon é o mesmo Container Engine; lanza contedores.
  2. Docker CII é unha utilidade de xestión de Docker.
  3. Dockerfile - instrucións sobre como construír unha imaxe.
  4. Imaxe: a imaxe desde a que se desenrola o recipiente.
  5. Envase.
  6. O rexistro Docker é un repositorio de imaxes.

Esquemáticamente parece algo así:

Que é Docker: unha breve excursión á historia e as abstraccións básicas

O daemon Docker execútase en Docker_host e lanza contedores. Hai un Cliente que envía comandos: construír a imaxe, descargar a imaxe, lanzar o contedor. Docker daemon vai ao rexistro e execútaos. O cliente Docker pode acceder tanto localmente (a un socket Unix) como a través de TCP desde un host remoto.

Imos repasar cada compoñente.

Daemon Docker - esta é a parte do servidor, funciona na máquina host: descarga imaxes e lanza contedores desde elas, crea unha rede entre contedores, recolle rexistros. Cando dicimos "crear unha imaxe", o demo tamén o está facendo.

Docker CLI — Parte do cliente Docker, utilidade de consola para traballar co daemon. Repito, pode funcionar non só localmente, senón tamén a través da rede.

Comandos básicos:

docker ps: mostra os contedores que se están a executar actualmente no servidor Docker.
imaxes docker: mostra imaxes descargadas localmente.
docker search <> - busca unha imaxe no rexistro.
docker pull <>: descarga unha imaxe do rexistro á máquina.
compilación docker < > - recolle a imaxe.
docker run <>: inicia o contedor.
docker rm <> - elimina o contedor.
docker logs <> - rexistros do contedor
docker start/stop/restart <> - traballando co contedor

Se dominas estes comandos e confías en usalos, considérase un 70 % competente en Docker a nivel de usuario.

dockerfile - instrucións para crear unha imaxe. Case todos os comandos de instrucións son unha nova capa. Vexamos un exemplo.

Que é Docker: unha breve excursión á historia e as abstraccións básicas

Este é o aspecto do Dockerfile: comandos á esquerda, argumentos á dereita. Cada comando que está aquí (e xeralmente escrito no Dockerfile) crea unha nova capa en Image.

Aínda mirando para o lado esquerdo, podes entender aproximadamente o que está a suceder. Dicimos: "cree un cartafol para nós" - esta é unha capa. "Facer que o cartafol funcione" é outra capa, e así por diante. O bolo de capas fai a vida máis fácil. Se creo outro Dockerfile e cambio algo na última liña, executo algo que non sexa "python" "main.py" ou instalo dependencias desde outro ficheiro, entón as capas anteriores reutilizaranse como caché.

Imaxe - Trátase de envases de envases; os contedores lánzanse a partir da imaxe. Se miramos a Docker dende o punto de vista dun xestor de paquetes (como se traballásemos con paquetes deb ou rpm), entón a imaxe é esencialmente un paquete rpm. A través de yum install podemos instalar a aplicación, borrala, atopala no repositorio e descargala. Aquí pasa o mesmo: os contedores lánzanse desde a imaxe, gárdanse no rexistro de Docker (semellante a yum, nun repositorio) e cada imaxe ten un hash SHA-256, un nome e unha etiqueta.

A imaxe está construída segundo as instrucións do Dockerfile. Cada instrución do Dockerfile crea unha nova capa. As capas pódense reutilizar.

Rexistro docker é un repositorio de imaxes de Docker. Similar ao sistema operativo, Docker ten un rexistro estándar público: dockerhub. Pero podes crear o teu propio repositorio, o teu propio rexistro Docker.

Recipiente - o que se lanza dende a imaxe. Construímos unha imaxe segundo as instrucións do Dockerfile, despois lanzámola dende esta imaxe. Este recipiente está illado doutros recipientes; debe conter todo o necesario para que a aplicación funcione. Neste caso, un recipiente - un proceso. Ocorre que hai que facer dous procesos, pero isto é algo contrario á ideoloxía de Docker.

O requisito "un recipiente, un proceso" está relacionado co espazo de nomes PID. Cando se inicia un proceso con PID 1 no espazo de nomes, se morre de súpeto, tamén morre todo o contenedor. Se se están a executar alí dous procesos: un está vivo e o outro morto, o contedor seguirá vivo. Pero esta é unha cuestión de Boas Prácticas, delas falaremos noutros materiais.

Para estudar as características e o programa completo do curso con máis detalle, siga a ligazón: "Curso de video docker».

Autor: Marcel Ibraev, administrador certificado de Kubernetes, enxeñeiro en exercicio en Southbridge, locutor e desenvolvedor de cursos Slurm.

Fonte: www.habr.com

Engadir un comentario