Recursos básicos do LXD - sistemas de contêineres Linux

Recursos básicos do LXD - sistemas de contêineres Linux

LXD é o gerenciador de contêineres do sistema da próxima geração, é o que diz fonte. Ele oferece uma interface de usuário semelhante às máquinas virtuais, mas em vez disso usa contêineres Linux.

Núcleo LXD é um daemon privilegiado (um serviço executado com direitos de root) que fornece uma API REST através de um soquete unix local, bem como através da rede se a configuração apropriada estiver instalada. Os clientes, como a ferramenta de linha de comando fornecida com o LXD, fazem solicitações por meio desta API REST. Isso significa que, quer você esteja acessando um host local ou remoto, tudo funciona da mesma forma.

Neste artigo não nos deteremos detalhadamente nos conceitos do LXD, não consideraremos todos os recursos disponíveis descritos na documentação, incluindo a recente implementação nas versões mais recentes do LXD de suporte para máquinas virtuais QEMU em paralelo com contêineres. Em vez disso, aprenderemos apenas o básico do gerenciamento de contêineres – configurar pools de armazenamento, rede, executar um contêiner, aplicar limites de recursos e como usar instantâneos para que você possa obter uma compreensão básica do LXD e usar contêineres no Linux.

Para informações completas, consulte a fonte oficial:

Navegação

Instalação LXD ^

Instalando LXD em distribuições Ubuntu ^

No pacote de distribuição Ubuntu 19.10 lxd tem uma transmissão em pacote instantâneo:

apt search lxd

lxd/eoan 1:0.7 all
  Transitional package - lxd -> snap (lxd)

Isso significa que dois pacotes serão instalados ao mesmo tempo, um como pacote de sistema e outro como pacote snap. A instalação de dois pacotes em um sistema pode criar alguns problemas em que o pacote do sistema pode ficar órfão se o pacote snap for removido pelo gerenciador de pacotes snap.

Encontrar pacote lxd no repositório snap você pode usar o seguinte comando:

snap find lxd

Name             Version        Summary
lxd              3.21           System container manager and API
lxd-demo-server  0+git.6d54658  Online software demo sessions using LXD
nova             ocata          OpenStack Compute Service (nova)
nova-hypervisor  ocata          OpenStack Compute Service - KVM Hypervisor (nova)
distrobuilder    1.0            Image builder for LXC and LXD
fabrica          0.1            Build snaps by simply pointing a web form to...
satellite        0.1.2          Advanced scalable Open source intelligence platform

Executando o comando list você pode ter certeza de que o pacote lxd ainda não instalado:

snap list

Name  Version    Rev   Tracking  Publisher   Notes
core  16-2.43.3  8689  stable    canonical✓  core

Apesar do LXD ser um pacote instantâneo, ele deve ser instalado através do pacote do sistema lxd, que criará o grupo correspondente no sistema, os utilitários necessários em /usr/bin и т.д.

sudo apt update
sudo apt install lxd

Vamos ter certeza de que o pacote está instalado como um pacote snap:

snap list

Name  Version    Rev    Tracking  Publisher   Notes
core  16-2.43.3  8689   stable    canonical✓  core
lxd   3.21       13474  stable/…  canonical✓  -

Instalando LXD em distribuições Arch Linux ^

Para instalar o pacote LXD no sistema, é necessário executar os seguintes comandos, o primeiro irá atualizar a lista de pacotes do sistema disponíveis no repositório, o segundo irá instalar diretamente o pacote:

sudo pacman -Syyu && sudo pacman -S lxd

Depois de instalar o pacote, para gerenciar o LXD por um usuário regular, ele deve ser adicionado ao grupo de sistemas lxd:

sudo usermod -a -G lxd user1

Vamos garantir que o usuário user1 adicionado ao grupo lxd:

id -Gn user1

user1 adm dialout cdrom floppy sudo audio dip video plugdev netdev lxd

Se o grupo lxd não estiver visível na lista, será necessário ativar a sessão do usuário novamente. Para fazer isso, você precisa sair e fazer login com o mesmo usuário.

Ativar em systemd carregando o serviço LXD na inicialização do sistema:

sudo systemctl enable lxd

Iniciamos o serviço:

sudo systemctl start lxd

Verificando o status do serviço:

sudo systemctl status lxd

Armazenamento LXD (Armazenamento) ^

Antes de iniciar a inicialização, precisamos entender como o armazenamento no LXD é organizado logicamente.

Armazenar (Armazenamento) consiste em de um ou mais Pool de armazenamento que usa um dos sistemas de arquivos suportados, como ZFS, BTRFS, LVM ou diretórios regulares. Todo Pool de armazenamento é dividido em volumes (Volume de Armazenamento) que contenham imagens, contêineres ou dados para outros fins.

  • Imagens - estas são distribuições especialmente montadas sem o kernel Linux e disponíveis em fontes externas
  • Containers - são distribuições implantadas a partir de imagens, prontas para uso
  • Instantâneos - estes são instantâneos do estado dos contêineres aos quais você pode retornar

Recursos básicos do LXD - sistemas de contêineres Linux

Para gerenciar o armazenamento no LXD, use o comando lxc storage um certificado que pode ser obtido especificando a chave - lxc storage --help

O comando a seguir exibe uma lista de todos Pool de armazenamento no armazenamento LXD:

lxc storage list

+---------+-------------+--------+--------------------------------+---------+
|  NAME   | DESCRIPTION | DRIVER |             SOURCE             | USED BY |
+---------+-------------+--------+--------------------------------+---------+
| hddpool |             | btrfs  | /dev/loop1                     | 2       |
+---------+-------------+--------+--------------------------------+---------+
| ssdpool |             | btrfs  | /var/lib/lxd/disks/ssdpool.img | 4       |
+---------+-------------+--------+--------------------------------+---------+

Para ver uma lista de todos Volume de Armazenamento no selecionado Pool de armazenamento atende a equipe lxc storage volume list:

lxc storage volume list hddpool

+-------+----------------------------------+-------------+---------+
| TYPE  |          NAME                    | DESCRIPTION | USED BY |
+-------+----------------------------------+-------------+---------+
| image | ebd565585223487526ddb3607f515... |             | 1       |
+-------+----------------------------------+-------------+---------+

lxc storage volume list ssdpool

+-----------+----------------------------------+-------------+---------+
|   TYPE    |            NAME                  | DESCRIPTION | USED BY |
+-----------+----------------------------------+-------------+---------+
| container | alp3                             |             | 1       |
+-----------+----------------------------------+-------------+---------+
| container | jupyter                          |             | 1       |
+-----------+----------------------------------+-------------+---------+
| image     | ebd565585223487526ddb3607f515... |             | 1       |
+-----------+----------------------------------+-------------+---------+

Além disso, se por Pool de armazenamento Ao criar, o sistema de arquivos BTRFS foi selecionado e, em seguida, obtenha uma lista Volume de Armazenamento ou subvolumes na interpretação do BTRFS, você pode usar o kit de ferramentas deste sistema de arquivos:

sudo btrfs subvolume list -p /var/lib/lxd/storage-pools/hddpool

ID 257 gen 818 parent 5 top level 5 path images/ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3

sudo btrfs subvolume list -p /var/lib/lxd/storage-pools/ssdpool

ID 257 gen 1820 parent 5 top level 5 path images/ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3
ID 260 gen 1819 parent 5 top level 5 path containers/jupyter
ID 263 gen 1820 parent 5 top level 5 path containers/alp3

Inicializando LXD ^

Antes de criar e usar contêineres, você deve realizar uma inicialização geral do LXD que cria e configura a rede e o armazenamento. Isso pode ser feito manualmente usando comandos de cliente padrão que estão disponíveis na lista chamando o comando lxc --help ou usando o assistente de inicialização lxd init respondendo algumas perguntas.

Selecionando um sistema de arquivos para pool de armazenamento ^

Durante a inicialização, o LXD faz várias perguntas, incluindo a determinação do tipo de sistema de arquivos padrão Pool de armazenamento. Por padrão, o sistema de arquivos BTRFS é selecionado para ele. Será impossível mudar para outro FS após a criação. Para selecionar um FS sugere-se tabela de comparação de recursos:

Característica
Diretório
Btrfs
LVM
ZFS
CEPH

Armazenamento de imagens otimizado
não
sim
sim
sim
sim

Criação de instância otimizada
não
sim
sim
sim
sim

Criação otimizada de snapshots
não
sim
sim
sim
sim

Transferência de imagem otimizada
não
sim
não
sim
sim

Transferência de instância otimizada
não
sim
não
sim
sim

Cópia na gravação
não
sim
sim
sim
sim

Baseado em bloco
não
não
sim
não
sim

Clonagem instantânea
não
sim
sim
sim
sim

Driver de armazenamento utilizável dentro de um contêiner
sim
sim
não
não
não

Restaurar de snapshots mais antigos (não os mais recentes)
sim
sim
sim
não
sim

Cotas de armazenamento
sim(*)
sim
sim
sim
não

Inicializando a rede e o pool de armazenamento usando o assistente ^

O próximo comando que veremos sugere a configuração dos principais componentes do LXD respondendo a perguntas simples usando o assistente de inicialização.

Comando de execução lxc init e insira as respostas às perguntas após os dois pontos conforme mostrado no exemplo abaixo ou altere-as de acordo com suas condições:

lxd init

Would you like to use LXD clustering? (yes/no) [default=no]: 
Do you want to configure a new storage pool? (yes/no) [default=yes]: 
Name of the new storage pool [default=default]: ssdpool         
Name of the storage backend to use (lvm, btrfs, dir) [default=btrfs]: 
Create a new BTRFS pool? (yes/no) [default=yes]: 
Would you like to use an existing block device? (yes/no) [default=no]: 
Size in GB of the new loop device (1GB minimum) [default=15GB]: 10GB
Would you like to connect to a MAAS server? (yes/no) [default=no]: 
Would you like to create a new local network bridge? (yes/no) [default=yes]: 
What should the new bridge be called? [default=lxdbr0]: 
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 10.0.5.1/24
Would you like LXD to NAT IPv4 traffic on your bridge? [default=yes]: 
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: none
Would you like LXD to be available over the network? (yes/no) [default=no]: 
Would you like stale cached images to be updated automatically? (yes/no) [default=yes] no
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: 

Criando um pool de armazenamento adicional ^

Na etapa anterior criamos Pool de armazenamento que recebeu o nome ssdpool e cujo arquivo está localizado no meu sistema em /var/lib/lxd/disks/ssdpool.img. Este endereço do sistema de arquivos corresponde à unidade SSD física do meu PC.

As ações a seguir, para ampliar a compreensão do papel desempenhado pela Pool de armazenamento no repositório, criaremos um segundo Pool de armazenamento que estará fisicamente localizado em um tipo diferente de disco, HDD. O problema é que o LXD não permite criar Pool de armazenamento fora de endereço /var/lib/lxd/disks/ e mesmo links simbólicos não funcionarão, veja a resposta do desenvolvedor. Podemos contornar esta limitação durante a inicialização/formatação Pool de armazenamento especificando o valor como um dispositivo de bloco em vez do caminho para o arquivo de loopback, especificando isso na chave source.

Então, antes de criar Pool de armazenamento você precisa definir um arquivo de loopback ou uma partição existente em seu sistema de arquivos que ele usará. Para fazer isso, criaremos e usaremos um arquivo cujo tamanho limitaremos a 10 GB:

dd if=/dev/zero of=/mnt/work/lxd/hddpool.img bs=1MB count=10000

10000+0 records in
10000+0 records out
10000000000 bytes (10 GB, 9,3 GiB) copied, 38,4414 s, 260 MB/s

Vamos conectar o arquivo de loopback a um dispositivo de loopback gratuito:

sudo losetup --find --show /mnt/work/lxd/hddpool.img

/dev/loop1

Graças à chave --show a execução do comando retorna à tela o nome do dispositivo ao qual nosso arquivo de loopback está conectado. Se necessário, podemos exibir uma lista de todos os dispositivos ocupados deste tipo para ter certeza de que nossas ações estão corretas:

losetup -l

NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE                      DIO LOG-SEC
/dev/loop1         0      0         0  0 /mnt/work/lxd/hddpool.img        0     512
/dev/loop0         0      0         1  0 /var/lib/lxd/disks/ssdpool.img   0     512

Na lista você pode descobrir que o dispositivo possui /dev/loop1 arquivo de loopback incluído /mnt/work/lxd/hddpool.img, e no dispositivo /dev/loop0 arquivo de loopback incluído /var/lib/lxd/disks/ssdpool.img que corresponde ao padrão Pool de armazenamento.

O comando a seguir cria um novo Pool de armazenamento no LXD com base no arquivo de loopback que acabamos de preparar. LXD irá formatar o arquivo de loopback /mnt/work/lxd/hddpool.img no dispositivo /dev/loop1 para o sistema de arquivos BTRFS:

lxc storage create hddpool btrfs size=10GB source=/dev/loop1

Vamos exibir uma lista de todos Pool de armazenamento para tela:

lxc storage list

+---------+-------------+--------+--------------------------------+---------+
|  NAME   | DESCRIPTION | DRIVER |             SOURCE             | USED BY |
+---------+-------------+--------+--------------------------------+---------+
| hddpool |             | btrfs  | /dev/loop1                     | 0       |
+---------+-------------+--------+--------------------------------+---------+
| ssdpool |             | btrfs  | /var/lib/lxd/disks/ssdpool.img | 0       |
+---------+-------------+--------+--------------------------------+---------+

Aumentando o tamanho do pool de armazenamento ^

Após a criação Pool de armazenamento, se necessário, pode ser expandido. Para Pool de armazenamento com base no sistema de arquivos BTRFS, execute os seguintes comandos:

sudo truncate -s +5G /mnt/work/lxd/hddpool.img
sudo losetup -c /dev/loop1
sudo btrfs filesystem resize max /var/lib/lxd/storage-pools/hddpool

Inserção automática de um arquivo de loopback em um slot de dispositivo de loopback ^

Temos um pequeno problema: ao reiniciar o sistema host, o arquivo /mnt/work/lxd/hddpool.img vai "voar" para fora do dispositivo /dev/loop1 e o serviço LXD irá travar ao carregar porque não o verá neste dispositivo. Para resolver este problema você precisa criar um serviço de sistema que irá inserir este arquivo no dispositivo /dev/loop1 quando o sistema host é inicializado.

vamos criar unidade tipo de arquivo serviço в /etc/systemd/system/ para o sistema de inicialização SystemD:

cat << EOF | sudo tee -a /etc/systemd/system/lxd-hddpool.service
[Unit]
Description=Losetup LXD Storage Pool (hddpool)
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/sbin/losetup /dev/loop1 /mnt/work/lxd/hddpool.img
RemainAfterExit=true

[Install]
WantedBy=local-fs.target
EOF

Ative o serviço:

sudo systemctl enable lxd-hddpool

Created symlink /etc/systemd/system/local-fs.target.wants/lxd-hddpool.service → /etc/systemd/system/lxd-hddpool.service.

Após reiniciar o sistema host, verificamos o status do serviço:

systemctl status lxd-hddpool.service 

● lxd-hddpool.service - Losetup LXD Storage Pool (hddpool)
     Loaded: loaded (/etc/systemd/system/lxd-hddpool.service; enabled; vendor preset: disabled)
     Active: active (exited) since Wed 2020-04-08 03:43:53 MSK; 1min 37s ago
    Process: 711 ExecStart=/sbin/losetup /dev/loop1 /mnt/work/lxd/hddpool.img (code=exited, status=0/SUCCESS)
   Main PID: 711 (code=exited, status=0/SUCCESS)

апр 08 03:43:52 manjaro systemd[1]: Starting Losetup LXD Storage Pool (hddpool)...
апр 08 03:43:53 manjaro systemd[1]: Finished Losetup LXD Storage Pool (hddpool).

A partir da saída podemos verificar que o estado do serviço é ativo, apesar de a execução do nosso script a partir de um comando ter sido concluída, a opção nos permitiu fazer isso RemainAfterExit=true.

Segurança. Privilégios de contêiner ^

Como todos os processos de contêiner são executados isoladamente no sistema host usando seu kernel, para proteger ainda mais o acesso dos processos de contêiner ao sistema host, o LXD oferece privilégios de processo, onde:

  • Contêineres Privilegiados - são contêineres nos quais os processos com UID e GID correspondem ao mesmo proprietário do sistema host. Por exemplo, um processo em execução em um contêiner com UID 0 tem todos os mesmos direitos de acesso que um processo no sistema host com UID 0. Em outras palavras, o usuário root no contêiner tem todos os direitos, não apenas em no contêiner, mas também no sistema host, se ele puder sair do namespace isolado do contêiner.

  • Contêineres sem privilégios - são contêineres nos quais os processos pertencem ao proprietário do UID e GID com um número de 0 a 65535, mas para o sistema host o proprietário é mascarado usando os bits SubUID e SubGID adicionados, respectivamente. Por exemplo, um usuário com UID=0 em um contêiner será visto no sistema host como SubUID + UID. Isso protege o sistema host porque se qualquer processo no contêiner for capaz de escapar de seu namespace isolado, ele só poderá se comunicar com o sistema host como um processo com um UID/GID desconhecido e muito alto.

Por padrão, os contêineres recém-criados têm um status sem privilégios e, portanto, devemos definir um SubUID e um SubGID.

Vamos criar dois arquivos de configuração nos quais definiremos a máscara para SubUID e SubGID, respectivamente:

sudo touch /etc{/subuid,/subgid}
sudo usermod --add-subuids 1000000-1065535 root 
sudo usermod --add-subgids 1000000-1065535 root

Para aplicar as alterações, o serviço LXD deve ser reiniciado:

sudo systemctl restart lxd

Criando um switch de rede virtual ^

Como inicializamos a rede anteriormente usando o assistente de inicialização lxd init e criou um dispositivo de rede lxdbr0, nesta seção iremos simplesmente nos familiarizar com redes no LXD e como criar um switch virtual (ponte) usando o comando do cliente.

O diagrama a seguir demonstra como um switch (ponte) conecta o host e os contêineres em uma rede:

Recursos básicos do LXD - sistemas de contêineres Linux

Os contêineres podem se comunicar através de uma rede com outros contêineres ou com o host no qual esses contêineres são servidos. Para fazer isso, você precisa vincular as placas de rede virtuais dos contêineres a um switch virtual. Criaremos um switch primeiro, e as interfaces de rede do contêiner serão vinculadas nos capítulos subsequentes, após a criação do próprio contêiner.

O comando a seguir cria um switch com uma sub-rede 10.0.5.0/24 e endereço IPv4 10.0.5.1/24, e também inclui ipv4.nat para que os contêineres possam acessar a Internet através do host usando o serviço NAT:

lxc network create lxdbr0 ipv4.address=10.0.5.1/24 ipv4.nat=true ipv6.address=none

Verificando a lista de dispositivos de rede disponíveis no LXD:

lxc network list

+--------+----------+---------+-------------+---------+
|  NAME  |   TYPE   | MANAGED | DESCRIPTION | USED BY |
+--------+----------+---------+-------------+---------+
| eno1   | physical | NO      |             | 0       |
+--------+----------+---------+-------------+---------+
| lxdbr0 | bridge   | YES     |             | 0       |
+--------+----------+---------+-------------+---------+

Você também pode verificar se um dispositivo de rede foi criado usando a ferramenta padrão da distribuição Linux - ip link ou ip addr:

ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether bc:ee:7b:5a:6b:44 brd ff:ff:ff:ff:ff:ff
    altname enp0s25
    inet6 fe80::9571:11f3:6e0c:c07b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether c2:38:90:df:cb:59 brd ff:ff:ff:ff:ff:ff
    inet 10.0.5.1/24 scope global lxdbr0
       valid_lft forever preferred_lft forever
    inet6 fe80::c038:90ff:fedf:cb59/64 scope link 
       valid_lft forever preferred_lft forever
5: veth3ddab174@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000
    link/ether ca:c3:5c:1d:22:26 brd ff:ff:ff:ff:ff:ff link-netnsid 0

Perfil de configuração ^

Cada contêiner no LXD tem sua própria configuração e pode estendê-la com configurações declaradas globalmente chamadas perfis de configuração. A aplicação de perfis de configuração a um contêiner possui um modelo em cascata, o exemplo a seguir demonstra isso:

Recursos básicos do LXD - sistemas de contêineres Linux

Neste exemplo, três perfis foram criados no sistema LXD: default, hddpool и hostfs. Todos os três perfis são aplicados a um contêiner que possui configuração local (área cinza). Perfil default tem um dispositivo root que tem um parâmetro pool é igual a ssdpool, mas graças ao modelo de aplicação de configuração em cascata, podemos aplicar um perfil ao contêiner hddpool que tem um parâmetro pool substituirá o mesmo parâmetro do perfil default e o contêiner receberá a configuração do dispositivo root com parâmetro pool igual hddpoole o perfil hostfs simplesmente adiciona um novo dispositivo ao contêiner.

Para ver a lista de perfis de configuração disponíveis, use o seguinte comando:

lxc profile list

+---------+---------+
|  NAME   | USED BY |
+---------+---------+
| default | 1       |
+---------+---------+
| hddroot | 0       |
+---------+---------+
| ssdroot | 1       |
+---------+---------+

Uma lista completa de comandos disponíveis para trabalhar com um perfil pode ser obtida adicionando a chave --help:

lxc profile --help

Description:
  Manage profiles

Usage:
  lxc profile [command]

Available Commands:
  add         Add profiles to instances
  assign      Assign sets of profiles to instances
  copy        Copy profiles
  create      Create profiles
  delete      Delete profiles
  device      Manage instance devices
  edit        Edit profile configurations as YAML
  get         Get values for profile configuration keys
  list        List profiles
  remove      Remove profiles from instances
  rename      Rename profiles
  set         Set profile configuration keys
  show        Show profile configurations
  unset       Unset profile configuration keys

Editando seu perfil ^

Perfil de configuração padrão default não possui configuração de placa de rede para o container e todos os containers recém-criados não possuem rede, para eles é necessário criar dispositivos de rede locais (dedicados) com um comando separado, mas podemos criar um dispositivo de rede global na configuração perfil que será compartilhado entre todos os contêineres que usam esse perfil. Desta forma, imediatamente após o comando de criação de um novo container, eles terão uma rede com acesso à rede. Ao mesmo tempo, não há restrições; podemos sempre criar um dispositivo de rede local posteriormente, se necessário.

O comando a seguir adicionará o dispositivo ao perfil de configuração eth0 digite nic conectado à rede lxdbr0:

lxc profile device add default eth0 nic network=lxdbr0 name=eth0

É importante observar que, como adicionamos o dispositivo ao perfil de configuração, se especificarmos um endereço IP estático no dispositivo, todos os contêineres que usarão esse perfil compartilharão o mesmo endereço IP. Se houver necessidade de criar um contêiner com um endereço IP estático alocado para o contêiner, você deverá criar uma configuração de dispositivo de rede no nível do contêiner (configuração local) com o parâmetro de endereço IP, e não no nível do perfil.

Vamos verificar o perfil:

lxc profile show default

config: {}
description: Default LXD profile
devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic
  root:
    path: /
    pool: ssdpool
    type: disk
name: default
used_by: []

Neste perfil podemos ver que para todos os containers recém-criados serão criados dois dispositivos:

  • eth0 - Tipo de dispositivo nic conectado a um switch (ponte de rede) lxdbr0
  • root - Tipo de dispositivo disk que usa um pool de armazenamento ssdpool

Criando novos perfis ^

Para usar criado anteriormente Pool de armazenamento contêineres, crie um perfil de configuração ssdroot no qual adicionaremos um dispositivo como disk com ponto de montagem / (root) usando o criado anteriormente Pool de armazenamento - ssdpool:

lxc profile create ssdroot
lxc profile device add ssdroot root disk path=/ pool=ssdpool

Da mesma forma, criamos um dispositivo como disk, mas neste caso usando Pool de armazenamento - hddpool:

lxc profile create hddroot
lxc profile device add hddroot root disk path=/ pool=hddpool

Verificando perfis de configuração:

lxc profile show ssdroot

config: {}
description: ""
devices:
  root:
    path: /
    pool: ssdpool
    type: disk
name: ssdroot
used_by: []

lxc profile show hddroot

config: {}
description: ""
devices:
  root:
    path: /
    pool: hddpool
    type: disk
name: hddroot
used_by: []

Repositório de imagens ^

Os contêineres são criados a partir de imagens que são distribuições especialmente montadas que não possuem um kernel Linux. Portanto, antes de executar o contêiner, ele deverá ser implantado a partir desta imagem. A fonte das imagens é um repositório local no qual as imagens são baixadas de repositórios externos.

Repositórios de imagens remotos ^

Por padrão, o LXD está configurado para receber imagens de três fontes remotas:

  • Ubuntu: (para imagens estáveis ​​do Ubuntu)
  • ubuntu-diariamente: (para imagens diárias do Ubuntu)
  • fotos: (para um monte de outras distros)

lxc remote list

+-----------------+------------------------------------------+--------+--------+
|      NAME       |                   URL                    | PUBLIC | STATIC |
+-----------------+------------------------------------------+--------+--------+
| images          | https://images.linuxcontainers.org       | YES    | NO     |
+-----------------+------------------------------------------+--------+--------+
| local (default) | unix://                                  | NO     | YES    |
+-----------------+------------------------------------------+--------+--------+
| ubuntu          | https://cloud-images.ubuntu.com/releases | YES    | YES    |
+-----------------+------------------------------------------+--------+--------+
| ubuntu-daily    | https://cloud-images.ubuntu.com/daily    | YES    | YES    |
+-----------------+------------------------------------------+--------+--------+

Por exemplo, repositório ubuntu: tem as seguintes imagens:

lxc image -c dasut list ubuntu: | head -n 11

+----------------------------------------------+--------------+----------+------------+
|                   DESCRIPTION                | ARCHITECTURE |   SIZE   |   TYPE     |
+----------------------------------------------+--------------+----------+------------+
| ubuntu 12.04 LTS amd64 (release) (20150728)  | x86_64       | 153.72MB | CONTAINER  |
+----------------------------------------------+--------------+----------+------------+
| ubuntu 12.04 LTS amd64 (release) (20150819)  | x86_64       | 152.91MB | CONTAINER  |
+----------------------------------------------+--------------+----------+------------+
| ubuntu 12.04 LTS amd64 (release) (20150906)  | x86_64       | 154.69MB | CONTAINER  |
+----------------------------------------------+--------------+----------+------------+
| ubuntu 12.04 LTS amd64 (release) (20150930)  | x86_64       | 153.86MB | CONTAINER  |
+----------------------------------------------+--------------+----------+------------+

Para exibir um número limitado de colunas usamos a opção -c com parâmetros dasute também limitou o comprimento da lista com o comando head.

A filtragem está disponível para exibir uma lista de imagens. O comando a seguir listará todas as arquiteturas de distribuição disponíveis Alpine Linux:

lxc image -c ldast list images:alpine/3.11

+------------------------------+--------------------------------------+--------------+
|            ALIAS             |             DESCRIPTION              | ARCHITECTURE |
+------------------------------+--------------------------------------+--------------+
| alpine/3.11 (3 more)         | Alpine 3.11 amd64 (20200220_13:00)   | x86_64       |
+------------------------------+--------------------------------------+--------------+
| alpine/3.11/arm64 (1 more)   | Alpine 3.11 arm64 (20200220_13:00)   | aarch64      |
+------------------------------+--------------------------------------+--------------+
| alpine/3.11/armhf (1 more)   | Alpine 3.11 armhf (20200220_13:00)   | armv7l       |
+------------------------------+--------------------------------------+--------------+
| alpine/3.11/i386 (1 more)    | Alpine 3.11 i386 (20200220_13:01)    | i686         |
+------------------------------+--------------------------------------+--------------+
| alpine/3.11/ppc64el (1 more) | Alpine 3.11 ppc64el (20200220_13:00) | ppc64le      |
+------------------------------+--------------------------------------+--------------+
| alpine/3.11/s390x (1 more)   | Alpine 3.11 s390x (20200220_13:00)   | s390x        |
+------------------------------+--------------------------------------+--------------+

Repositório de imagens locais ^

Para começar a usar o contêiner, você precisa adicionar uma imagem do repositório global ao local local:. Agora que o repositório local está vazio, o comando irá garantir isso lxc image list. Se o método list não especifique um repositório, então o repositório local será usado por padrão - local:

lxc image list local:

+-------+-------------+--------+-------------+--------------+------+------+
| ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCHITECTURE | TYPE | SIZE |
+-------+-------------+--------+-------------+--------------+------+------+

As imagens no repositório são gerenciadas usando os seguintes métodos:

Equipe
descrição

imagem lxc aliás
Gerenciar aliases de imagens

imagem lxc cópia
Copie imagens entre servidores

imagem lxc excluir
Apagar imagens

imagem lxc editar
Editar propriedades da imagem

imagem lxc exportar
Exportar e baixar imagens

imagem lxc importar
Importe imagens para o armazenamento de imagens

imagem lxc info
Mostrar informações úteis sobre imagens

imagem lxc Lista
Listar imagens

imagem lxc refrescar
Atualizar imagens

imagem lxc mostrar
Mostrar propriedades da imagem

Copie a imagem para o repositório local do global images::

lxc image copy images:alpine/3.11/amd64 local: --alias=alpine3

Image copied successfully!

Vamos exibir uma lista de todas as imagens atualmente disponíveis no repositório local local::

lxc image -c lfdatsu list local:

+---------+--------------+------------------------------------+--------------+
|  ALIAS  | FINGERPRINT  |            DESCRIPTION             | ARCHITECTURE |
+---------+--------------+------------------------------------+--------------+
| alpine3 | 73a3093d4a5c | Alpine 3.11 amd64 (20200220_13:00) | x86_64       |
+---------+--------------+------------------------------------+--------------+

Configuração LXD ^

Além do modo interativo, o LXD também suporta um modo de instalação de configuração não interativo, ou seja, quando a configuração é especificada na forma de um arquivo YAML, um formato especial que permite instalar toda a configuração de uma vez, ignorando a execução de muitos comandos interativos que foram discutidos acima neste artigo, incluindo configuração de rede, criação de perfis de configuração, etc. Não cobriremos esta área aqui, você pode conferir por conta própria. na documentação.

Próximo comando interativo lxc config que veremos permite que você defina a configuração. Por exemplo, para garantir que as imagens baixadas para o repositório local não sejam atualizadas automaticamente a partir dos repositórios globais, podemos ativar esse comportamento com o seguinte comando:

lxc config set images.auto_update_cached=false

Criando e gerenciando um contêiner ^

Para criar um contêiner use o comando lxc init para o qual os valores são passados репозиторий:образ e, em seguida, o ID desejado para o contêiner. O repositório pode ser especificado como local local: assim como qualquer global. Se o repositório não for especificado, por padrão o repositório local será usado para procurar a imagem. Se a imagem for especificada no repositório global, a imagem será primeiro baixada no repositório local e depois usada para criar o contêiner.

Vamos executar o seguinte comando para criar nosso primeiro contêiner:

lxc init alpine3 alp --storage=hddpool --profile=default --profile=hddroot

Vejamos as teclas de comando que usamos aqui em ordem:

  • alpine3 — Um alias (alias) é especificado para a imagem que foi carregada anteriormente no repositório local. Se o alias não foi criado para esta imagem, você sempre poderá referir-se à imagem pelo seu Impressão digital que é exibido na tabela.
  • alp — Define o identificador do contêiner
  • --storage — Esta chave indica em que Pool de armazenamento um contêiner será criado
  • --profile — Essas chaves aplicam em cascata a configuração de perfis de configuração criados anteriormente ao contêiner

Lançamos o contêiner, que começa a lançar o sistema init da distribuição:

lxc start alp

Você também pode usar o comando lxc launch que permite combinar equipes lxc init и lxc start em uma operação.

Verificando o estado do contêiner:

lxc list -c ns46tb
+------+---------+------------------+------+-----------+--------------+
| NAME |  STATE  |       IPV4       | IPV6 |   TYPE    | STORAGE POOL |
+------+---------+------------------+------+-----------+--------------+
| alp  | RUNNING | 10.0.5.46 (eth0) |      | CONTAINER | hddpool      |
+------+---------+------------------+------+-----------+--------------+

Verificando a configuração do contêiner:

lxc config show alp

architecture: x86_64
config:
  image.architecture: amd64
  image.description: Alpine 3.11 amd64 (20200326_13:39)
  image.os: Alpine
  image.release: "3.11"
  image.serial: "20200326_13:39"
  image.type: squashfs
  volatile.base_image: ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3
  volatile.eth0.host_name: vethb1fe71d8
  volatile.eth0.hwaddr: 00:16:3e:5f:73:3e
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.last_state.idmap: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.last_state.power: RUNNING
devices:
  root:
    path: /
    pool: hddpool
    type: disk
ephemeral: false
profiles:
- default
- hddroot
stateful: false
description: ""

Na seção profiles podemos ter certeza de que este contêiner usa dois perfis de configuração - default и hddroot. Na seção devices só podemos detectar um dispositivo porque o dispositivo de rede foi criado no nível do perfil default. Para ver todos os dispositivos usados ​​pelo contêiner você precisa adicionar uma chave --expanded:

lxc config show alp --expanded

architecture: x86_64
config:
  image.architecture: amd64
  image.description: Alpine 3.11 amd64 (20200326_13:39)
  image.os: Alpine
  image.release: "3.11"
  image.serial: "20200326_13:39"
  image.type: squashfs
  volatile.base_image: ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3
  volatile.eth0.host_name: vethb1fe71d8
  volatile.eth0.hwaddr: 00:16:3e:5f:73:3e
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.last_state.idmap: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.last_state.power: RUNNING
devices:
  eth0:
    name: eth0
    network: lxdbr0
    type: nic
  root:
    path: /
    pool: hddpool
    type: disk
ephemeral: false
profiles:
- default
- hddroot
stateful: false
description: ""

Configurando um endereço IP estático ^

Se tentarmos definir um endereço IP para um dispositivo de rede eth0 a equipe lxc config device set alp destinado à configuração do contêiner, receberemos um erro informando que o dispositivo não existe porque o dispositivo eth0 que é usado pelo contêiner pertence ao perfil default:

lxc config device set alp eth0 ipv4.address 10.0.5.5

Error: The device doesn't exist

É claro que podemos definir um endereço IP estático para eth0 dispositivos no perfil, mas será o mesmo para todos os contêineres que usarão esse perfil. Portanto, vamos adicionar um dispositivo dedicado ao container:

lxc config device add alp eth0 nic name=eth0 nictype=bridged parent=lxdbr0 ipv4.address=10.0.5.5

Então você precisa reiniciar o contêiner:

lxc restart alp

Se observarmos a configuração do contêiner agora, não precisamos usar a opção --expanded para ver o dispositivo de rede eth0, já que o criamos no nível do contêiner e ele foi colocado em cascata no mesmo dispositivo a partir do perfil default:

lxc config show alp

architecture: x86_64
config:
  image.architecture: amd64
  image.description: Alpine 3.11 amd64 (20200326_13:39)
  image.os: Alpine
  image.release: "3.11"
  image.serial: "20200326_13:39"
  image.type: squashfs
  volatile.base_image: ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3
  volatile.eth0.host_name: veth2a1dc59d
  volatile.eth0.hwaddr: 00:16:3e:0e:e2:71
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.last_state.idmap: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":65536}]'
  volatile.last_state.power: RUNNING
devices:
  eth0:
    ipv4.address: 10.0.5.5
    name: eth0
    nictype: bridged
    parent: lxdbr0
    type: nic
  root:
    path: /
    pool: hddpool
    type: disk
ephemeral: false
profiles:
- default
- hddroot
stateful: false
description: ""

Removendo um contêiner ^

Para remover um contêiner, use o comando lxc delete, mas antes de remover o contêiner, ele deve ser interrompido usando o comando lxc stop:

lxc stop alp

lxc list

+------+---------+-------------------+------+-----------+-----------+
| NAME |  STATE  |       IPV4        | IPV6 |   TYPE    | SNAPSHOTS |
+------+---------+-------------------+------+-----------+-----------+
| alp  | STOPPED | 10.0.5.10 (eth0)  |      | CONTAINER | 0         |
+------+---------+-------------------+------+-----------+-----------+

Depois de verificarmos que o estado do contêiner se tornou PARADO, ele pode ser removido de Pool de armazenamento:

lxc delete alp

Acesso ao contêiner ^

Para executar comandos diretamente em um contêiner, ignorando as conexões de rede, use o comando lxc exec que executa comandos no contêiner sem iniciar o shell do sistema. Se você precisar executar um comando em um shell usando padrões de shell, como variáveis, redirecionamentos de arquivos (pipe), etc., será necessário iniciar explicitamente o shell e passar o comando como uma chave, por exemplo:

lxc exec alp -- /bin/sh -c "echo $HOME"

O comando usou um caractere de escape especial para caractere especial $ para que a variável $HOME não foi interpretado na máquina host, mas foi interpretado apenas dentro do contêiner.

Também é possível iniciar o modo shell interativo e encerrar a sessão executando a tecla de atalho CTRL+D:

lxc exec alp -- /bin/sh

Gerenciamento de recursos de contêiner ^

No LXD, você pode gerenciar recursos de contêiner usando um conjunto especial de configurações. Uma lista completa de parâmetros de configuração do contêiner pode ser encontrada na documentação.

Limitação de recursos de RAM ^

Parâmetro limits.memory limita a quantidade de RAM disponível para o contêiner. O valor é um número e um dos sufixos disponíveis.

Vamos definir o limite de RAM do contêiner para 256 MB:

lxc config set alp limits.memory 256MB

Além disso, existem outros parâmetros para limitar a memória:

  • limits.memory.enforce
  • limits.memory.hugepages
  • limits.memory.swap
  • limits.memory.swap.priority

Equipe lxc config show permite exibir toda a configuração do contêiner, incluindo o limite de recursos aplicado que foi definido:

lxc config show alp

architecture: x86_64
config:
  image.architecture: amd64
  image.description: Alpine 3.11 amd64 (20200220_13:00)
  image.os: Alpine
  image.release: "3.11"
  image.serial: "20200220_13:00"
  image.type: squashfs
  limits.memory: 256MB
  volatile.base_image: 73a3093d4a5ce0148fd84b95369b3fbecd19a537ddfd2e2d20caa2eef0e8fd60
  volatile.eth0.host_name: veth75b6df07
  volatile.eth0.hwaddr: 00:16:3e:a1:e7:46
  volatile.idmap.base: "0"
  volatile.idmap.current: '[]'
  volatile.idmap.next: '[]'
  volatile.last_state.idmap: '[]'
  volatile.last_state.power: RUNNING
devices: {}
ephemeral: false
profiles:
- default
stateful: false
description: ""

Limite de recursos da CPU ^

Existem várias maneiras de limitar os recursos da CPU. tipos de restrições:

  • limit.cpu - vincula um contêiner a um ou mais núcleos de CPU
  • limits.cpu.allowance - gerencia as cotas do agendador CFS quando o limite de tempo tiver passado ou o mecanismo universal de compartilhamento de recursos da CPU quando a porcentagem tiver passado
  • limits.cpu.priority - prioridade do escalonador quando múltiplas instâncias que compartilham um conjunto de processadores recebem a mesma porcentagem de processadores

lxc config set alp limits.cpu.allowance 40%

lxc config show alp

architecture: x86_64
config:
  image.architecture: amd64
  image.description: Alpine 3.11 amd64 (20200220_13:00)
  image.os: Alpine
  image.release: "3.11"
  image.serial: "20200220_13:00"
  image.type: squashfs
  limits.cpu.allowance: 40%
  limits.memory: 256MB
  volatile.base_image: 73a3093d4a5ce0148fd84b95369b3fbecd19a537ddfd2e2d20caa2eef0e8fd60
  volatile.eth0.host_name: veth75b6df07
  volatile.eth0.hwaddr: 00:16:3e:a1:e7:46
  volatile.idmap.base: "0"
  volatile.idmap.current: '[]'
  volatile.idmap.next: '[]'
  volatile.last_state.idmap: '[]'
  volatile.last_state.power: RUNNING
devices: {}
ephemeral: false
profiles:
- default
stateful: false
description: ""

Limitação de espaço em disco ^

Além de restrições como limits.read, limits.write também podemos limitar a quantidade de espaço em disco consumido pelo contêiner (funciona apenas com ZFS ou BTRFS):

lxc config device set alp root size=2GB

Após a instalação, no parâmetro devices.root.size Podemos verificar o limite definido:

lxc config show alp
...
devices:
  root:
    path: /
    pool: hddpool
    size: 2GB
    type: disk
ephemeral: false
profiles:
- default
- hddroot
stateful: false
description: ""

Para visualizar as cotas de disco usadas, podemos obter no comando lxc info:

lxc info alp
...
Resources:
  Processes: 5
  Disk usage:
    root: 1.05GB
  CPU usage:
    CPU usage (in seconds): 1
  Memory usage:
    Memory (current): 5.46MB
  Network usage:
    eth0:
      Bytes received: 802B
      Bytes sent: 1.59kB
      Packets received: 4
      Packets sent: 14
    lo:
      Bytes received: 0B
      Bytes sent: 0B
      Packets received: 0
      Packets sent: 0

Apesar de termos definido um limite para o dispositivo raiz do contêiner em 2 GB, utilitários de sistema como df não verá esta restrição. Para isso, faremos um pequeno teste e descobriremos como funciona.

Vamos criar 2 novos containers idênticos no mesmo Pool de armazenamento (pool de disco rígido):

lxc init alpine3 alp1 --storage=hddpool --profile=default --profile=hddroot
lxc init alpine3 alp2 --storage=hddpool --profile=default --profile=hddroot

lxc list
+------+---------+------------------+------+-----------+-----------+
| NAME |  STATE  |       IPV4       | IPV6 |   TYPE    | SNAPSHOTS |
+------+---------+------------------+------+-----------+-----------+
| alp1 | RUNNING | 10.0.5.46 (eth0) |      | CONTAINER | 0         |
+------+---------+------------------+------+-----------+-----------+
| alp2 | RUNNING | 10.0.5.30 (eth0) |      | CONTAINER | 0         |
+------+---------+------------------+------+-----------+-----------+

Vamos criar um arquivo de 1GB em um dos containers:

lxc exec alp1 -- dd if=/dev/urandom of=file.img bs=1M count=1000

Vamos ter certeza de que o arquivo foi criado:

lxc exec alp1 -- ls -lh
total 1000M  
-rw-r--r--    1 root     root     1000.0M Mar 27 10:16 file.img

Se olharmos no segundo container, verificarmos a existência de um arquivo no mesmo local, então esse arquivo não estará lá, o que é esperado, pois os containers são criados por conta própria Volume de Armazenamento no mesmo Pool de armazenamento:

lxc exec alp2 -- ls -lh
total 0

Mas vamos comparar os valores que ele produz df em um e outro contêiner:

lxc exec alp1 -- df -hT
Filesystem           Type            Size      Used Available Use% Mounted on
/dev/loop1           btrfs           9.3G   1016.4M      7.8G  11% /
...

lxc exec alp2 -- df -hT
Filesystem           Type            Size      Used Available Use% Mounted on
/dev/loop1           btrfs           9.3G   1016.4M      7.8G  11% /
...

O dispositivo /dev/loop1 montado como a partição raiz é Pool de armazenamento que estes contentores utilizam, pelo que partilham o seu volume entre dois.

Estatísticas de consumo de recursos ^

Você pode visualizar estatísticas de consumo de recursos de um contêiner usando o comando:

lxc info alp

Name: alp
Location: none
Remote: unix://
Architecture: x86_64
Created: 2020/04/08 18:05 UTC
Status: Running
Type: container
Profiles: default, hddroot
Pid: 19219
Ips:
  eth0: inet    10.0.5.5        veth2a1dc59d
  eth0: inet6   fe80::216:3eff:fe0e:e271        veth2a1dc59d
  lo:   inet    127.0.0.1
  lo:   inet6   ::1
Resources:
  Processes: 5
  Disk usage:
    root: 495.62kB
  CPU usage:
    CPU usage (in seconds): 1
  Memory usage:
    Memory (current): 4.79MB
  Network usage:
    eth0:
      Bytes received: 730B
      Bytes sent: 1.59kB
      Packets received: 3
      Packets sent: 14
    lo:
      Bytes received: 0B
      Bytes sent: 0B
      Packets received: 0
      Packets sent: 0

Trabalhando com instantâneos ^

O LXD tem a capacidade de criar instantâneos e restaurar o estado do contêiner a partir deles.

Para criar um instantâneo, execute o seguinte comando:

lxc snapshot alp snapshot1

O time lxc snapshot nenhuma chave disponível list, portanto, para visualizar a lista de snapshots você precisa usar o comando que exibe informações gerais sobre o container:

lxc info alp
...
...
Snapshots:
  snapshot1 (taken at 2020/04/08 18:18 UTC) (stateless)

Você pode restaurar um contêiner a partir de um instantâneo usando o comando lxc restore especificando o contêiner para o qual a restauração será executada e o alias do snapshot:

lxc restore alp snapshot1

O comando a seguir é usado para excluir um instantâneo. Observe que a sintaxe do comando não é semelhante a todas as outras; aqui você precisa especificar uma barra após o nome do contêiner. Se a barra for omitida, o comando para excluir um instantâneo será interpretado como um comando para excluir um contêiner!

lxc delete alp/snapshot1

No exemplo acima, vimos os chamados snapshots sem estado. O LXD possui outro tipo de snapshots - stateful, que salva o estado atual de todos os processos no contêiner. Há vários recursos interessantes e úteis associados aos snapshots com estado.

O que mais? ^

  • Um módulo está disponível para desenvolvedores Python PyLXD que fornece uma API para LXD

ATUALIZAÇÃO 10.04.2020/15/00 XNUMX:XNUMX: Navegação adicionada

Fonte: habr.com

Adicionar um comentário