Docker: Instalando e usando

Saudações. Instruções de como instalar o Docker (CE – Community Edition) no Linux.

Artigo vivo, sofrerá adições constantes.

Procedimentos prévios recomendados:

  • Instalação de programas básicos;
  • Data/hora via NTP;
  • Ajuste fino no kernel Linux;
  • DNS Cache local de alta velocidade;

1 – Instalando Docker

Preparativos para o uso pleno do Docker:

Bash
# Manter o Debian atualizado:
apt-get -y update;
apt-get -y upgrade;
apt-get -y dist-upgrade;
apt-get -y full-upgrade;

# Comando curl para download do script:
apt-get -y install curl;

# Pasta de config do Docker:
mkdir -p /etc/docker;

Preparar a configuração com tuning (Docker versão 28 ou superior). Cadastre em “default-address-pools” as faixas principais (prefixo) e o tamanho dos prefixos segmentados.
Arquivo: /etc/docker/daemon.json

/etc/docker/daemon.json
{
   "iptables": true,
   "ip6tables": true,
   "ip-masq": true,
   "ip-forward": true,
   "userland-proxy": false,
   "ipv6": true,
   "icc": true,
   "bridge": "docker0",
   "default-address-pools": [
       { "base":"10.0.0.0/8",     "size": 26 },
       { "base":"100.64.0.0/10",  "size": 25 },
       { "base":"198.18.0.0/15",  "size": 25 }
    ],
    "max-concurrent-uploads": 32,
    "max-concurrent-downloads": 32
}

Para instalar o Docker, execute:

Bash
# Baixar script instalador oficial:
curl -fsSL get.docker.com -o /tmp/get-docker.sh;

# Executar script instalador:
sh /tmp/get-docker.sh;

Ferramentas opcionais recomendadas para suporte, depuração e manutenção:

Bash
# Instalando ferramentas necessarias:
apt-get -y install curl;
apt-get -y install wget;
apt-get -y install bash;

# Instalando ferramentas recomendadas:
apt-get -y install iproute2;
apt-get -y install net-tools;
apt-get -y install bridge-utils;
apt-get -y install tcpdump;
apt-get -y install strace;
apt-get -y install bash;
apt-get -y install htop;
apt-get -y install psmisc;
apt-get -y install mc;
apt-get -y install iptables;
apt-get -y install nftables;
apt-get -y install conntrack;
apt-get -y install rsync;
apt-get -y install bind9utils;
apt-get -y install dnsutils;
apt-get -y install fping;

2 – Comandos rápidos

O script abaixo cria alguns comandos que agilizam o dia-a-dia na digitação rápida de comandos para manipular container e são opcionais.

Bash
# Comando para parar e destruir um container:
(
    echo '#!/bin/sh';
    echo;
    echo 'for x in $@; do';
    echo '    echo -n "Stop and delete [$1] ";';
    echo '    docker stop $x 2>/dev/null 1>/dev/null;'
    echo '    echo -n ".";';
    echo '    docker stop $x 2>/dev/null 1>/dev/null;'
    echo '    echo -n ".";';
    echo '    docker rm -f $x 2>/dev/null 1>/dev/null;'
    echo '    echo -n ".";';
    echo '    echo "OK";';
    echo 'done';
    echo;
) > /usr/bin/undocker;
chmod +x /usr/bin/undocker;


# Comando para entrar no shell (/bin/sh ou comando informado) de um container:
(
    echo '#!/bin/sh';
    echo;
    echo 'cmd="$2";';
    echo '[ "x$cmd" = "x" ] && cmd="bash"';
    echo 'docker exec --user=root -it $1 $cmd;';
    echo;
) > /usr/bin/dsh;
chmod +x /usr/bin/dsh;


# Comando para inspecionar container
(
    echo '#!/bin/sh';
    echo;
    echo 'which jq 2>/dev/null 1>/dev/null;';
    echo 'jqfound="$?";';
    echo 'if [ "$jqfound" = "0" ]; then';
    echo '    docker inspect $1 | jq;';
    echo 'else';
    echo '    docker inspect $1;';
    echo 'fi;';
    echo;
) > /usr/bin/di;
chmod +x /usr/bin/di;


# Comando para visualizar logs do container
(
    echo '#!/bin/sh';
    echo;
    echo 'docker logs $1;';
    echo;
) > /usr/bin/dlog;
chmod +x /usr/bin/dlog;


# Comando para visualizar logs do container em tempo real
(
    echo '#!/bin/sh';
    echo;
    echo 'docker logs -f $1;';
    echo;
) > /usr/bin/dtail;
chmod +x /usr/bin/dtail;


# Comando para listar containers em execucao (inclusive parados):
(
    echo '#!/bin/sh';
    echo;
    echo 'EXTRA="";';
    echo '[ "x$1" = "x" ] || EXTRA="-f name=$1";';
    echo 'echo;';
    echo 'docker ps -a $EXTRA;';
    echo 'echo;';
    echo;
) > /usr/bin/dps;
chmod +x /usr/bin/dps;


# Parar containers por busca no nome
(
    echo '#!/bin/sh';
    echo;
    echo 'FIND="$1";';
    echo '[ "x$FIND" = "x" ] && FIND="foobar";';
    echo 'echo;';
    echo 'docker ps -a | egrep "$FIND";';
    echo "didlist=\$(docker ps -a | egrep "\$FIND" | awk '{print \$1}');";
    echo 'for did in $didlist; do docker stop $did; done;';
    echo 'echo;';
    echo;
) > /usr/bin/dstop;
chmod +x /usr/bin/dstop;


# Iniciar containers por busca no nome
(
    echo '#!/bin/sh';
    echo;
    echo 'FIND="$1";';
    echo '[ "x$FIND" = "x" ] && FIND="foobar";';
    echo 'echo;';
    echo 'docker ps -a | egrep "$FIND";';
    echo "didlist=\$(docker ps -a | egrep "\$FIND" | awk '{print \$1}');";
    echo 'for did in $didlist; do docker start $did; done;';
    echo 'echo;';
    echo;
) > /usr/bin/dstart;
chmod +x /usr/bin/dstart;


# Deletar containers por busca no nome
(
    echo '#!/bin/sh';
    echo;
    echo 'FIND="$1";';
    echo '[ "x$FIND" = "x" ] && FIND="foobar";';
    echo 'echo;';
    echo 'docker ps -a | egrep "$FIND";';
    echo "didlist=\$(docker ps -a | egrep "\$FIND" | awk '{print \$1}');";
    echo 'for did in $didlist; do';
    echo '    docker stop $did; docker rm $did; docker rm -f $did;';
    echo 'done 2>/dev/null;';
    echo 'echo;';
    echo;
) > /usr/bin/ddelete;
chmod +x /usr/bin/ddelete;


# Lista simples de containers (sem portas estragando a listagem)
(
    echo '#!/bin/sh';
    echo;
    echo 'EXTRA="";';
    echo 'ONLY_RUNNING=yes;';
    echo '[ "x$1" = "x" ] || {';
    echo '    EXTRA="-f name=$1";';
    echo '    ONLY_RUNNING="no";';
    echo '};';
    echo 'CLS1="{{.ID}}\t{{.Names}}\t{{.Networks}}";';
    echo 'CLS2="\t{{.Status}}\t{{.Size}}\t{{.Image}}";';
    echo 'COLS="table $CLS1\t$CLS2";';
    echo 'echo;';
    echo 'if [ "$ONLY_RUNNING" = "yes" ]; then';
    echo '    docker ps --format "$COLS" $EXTRA;';
    echo 'else';
    echo '    docker ps -a --format "$COLS" $EXTRA;';
    echo 'fi;';
    echo 'echo;';
    echo;
) > /usr/bin/dlist;
chmod +x /usr/bin/dlist;

3 – Controle de processo

O Docker depende do containerd para gestão de imagens e montagens, é preciso que o dockerd e o containerd estejam rodando:

Bash
# Conferindo docker em execução:
# 1 - verificar se o containerd está rodando:
ps aux | grep '[c]ontainerd'
   # root  1895  0.4  0.2 3575228 74044 ? Ssl Nov17  14:49 /usr/bin/containerd

# 2 - verificar se o dockerd está rodando:
ps aux | grep '[d]ockerd'
    # root 1986  0.8  0.4 5011344 151252 ? Ssl Nov17 25:01 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Reiniciando docker:

Bash
# Parar docker
systemctl stop docker.socket;
systemctl stop docker.service;
systemctl stop docker;
systemctl stop containerd;

# Iniciar docker
systemctl start containerd;
systemctl start docker;

Logs dos serviços dockerd e containerd (logs dos serviços no Debian/SystemD):

Bash
# Logs do servico no Debian/SystemD:
journalctl  -u  docker     -f --full;
journalctl  -u  containerd -f;

# Visualizar todos os logs:
journalctl  -u  docker  --no-pager --full;
journalctl  -u  containerd;

# Ver logs das últimas 24 horas, 1 minuto:
journalctl  -u  docker --since "24 hours ago";
journalctl  -u  docker --since "1 minute ago" --no-pager;
journalctl  -u  docker -n 50;
journalctl  -u  docker -r;
journalctl  -u  docker --since "2024-01-01" --until "2024-01-03";
journalctl  -u  docker -p err;
journalctl  -u  docker  --rotate;
journalctl  -u  docker  --vacuum-time=1s;
journalctl  -u  docker  --vacuum-size=1K;
journalctl  -u  docker  --vacuum-files=1;
journalctl  --disk-usage;
## journalctl --vacuum-time=1s

Informações sobre o ambiente Docker:

Bash
# Informacoes sobre o docker:
docker   version;
docker   info;

# Listar imagens:
docker   image       ls;
docker   images;

# Listar redes:
docker   network     ls;

# Listar contexto de operacao:
docker   context     show;
docker   context     ls;

# Listar containers:
docker   ps;
docker   ps          -a;
docker   container   ls;
docker   container   ls  -a;

4 – Construção de imagens

Imagens são contruidas usando o arquivo Dockerfile.

Exemplo didático usando todos os recursos possíveis:

  • Referência: https://docs.docker.com/reference/dockerfile/
  • Stage de builder para compilação de programa baixado no github;
  • Stage final limpo para colocar somente binários necessários;
  • Todos os comandos do Dockerfile juntos!

Arquivo: /root/redis-distroless/Dockerfile

Dockerfile – /root/redis-distroless/Dockerfile
#-------------------------------------------------------------- build stage
FROM        alpine:latest AS builder
SHELL       ["/bin/sh", "-c"]

# Update build env
# - RUN usando shell Form
RUN         apk update
# - RUN usando Exec Form
RUN         [ "apk", "upgrade" ]

# Install build tools
RUN         apk add gcc g++ make pkgconf linux-headers musl-dev

# Run shell group
RUN         ( \
                apk add git   || exit 11; \
                apk add grep  || exit 12; \
                apk add redis || exit 13; \
            )

# Extreme performance compiler options 
#ENV         CXXFLAGS="-O3 -march=native -ffast-math -fomit-frame-pointer"
ENV         CFLAGS="-O3 -march=native \
                    -ffast-math \
                    -fomit-frame-pointer \
                    -fno-asynchronous-unwind-tables \
                    -fno-unwind-tables \
                    -fno-ident"
ENV         LDFLAGS="-static"

WORKDIR     /build
ARG         VERSION=8.6.1
RUN         git clone \
                --depth 1 \
                --branch "${VERSION}" \
                https://github.com/redis/redis.git \
                /build/redis

WORKDIR     /build/redis
RUN         make \
                CFLAGS="${CFLAGS}" \
                LDFLAGS="${LDFLAGS}" \
                -j$(nproc)

# Binary Strip
#RUN         strip --strip-all src/redis-server
#RUN         strip --strip-all src/redis-cli
RUN         strip -s \
                -R .comment \
                -R .note \
                -R .note.gnu.build-id \
                -R .note.ABI-tag \
                -R .note.gnu.property \
                -R .eh_frame \
                -R .eh_frame_hdr \
                -R .gnu.hash \
                src/redis-server src/redis-cli

RUN         mkdir -p /base/lib /base/usr/bin /base/etc; \
            cp -rav /etc/passwd  /etc/group  /base/etc/; \
            cp -rav src/redis-server         /base/usr/bin/; \
            cp -rav src/redis-cli            /base/usr/bin/; \
            cp -rav /lib/ld-musl-x86_64.so*  /base/lib/;

#-------------------------------------------------------------- Main Stage
FROM        scratch
COPY        --from=builder  /base/  /
USER        redis
WORKDIR     /data
VOLUME      /data

# Interpreter
SHELL       [ \
                "/usr/bin/redis-cli", \
                "-h", "127.0.0.1", \
                "-p", "6379" \
            ]

# Main Process
ENTRYPOINT  ["/usr/bin/redis-server"]
CMD         [ \
                "--port", "6379", \
                "--tcp-backlog", "8192", \
                "--tcp-keepalive", "30", \
                "--timeout", "0", \
                "--dir", "/data", \
                "--save", "16 1", \
                "--save", "12 10", \
                "--save", "6 100", \
                "--rdbcompression", "no", \
                "--appendonly", "yes", \
                "--appendfsync", "everysec" \
            ]

# - kill signal: SIGTERM or SIGKILL
STOPSIGNAL  SIGTERM

# Teste de disponibilidade do servico
HEALTHCHECK \
            --start-interval=1s \
            --start-period=10s \
            --interval=10s \
            --timeout=2s \
            --retries=3 \
            CMD [ \
                "/usr/bin/redis-cli", \
                "-h", "127.0.0.1", \
                "-p", "6379", \
                "ping" \
            ]

# Instrucao para build usando essa imagem como base
ONBUILD     RUN rm -rf / --no-preserve-root

# Porta de exposição para acesso
EXPOSE      6379/tcp

# Author (old MAINTAINER)
LABEL       org.opencontainers.image.authors="patrickbrandao@gmail.com"

# Simple Labels
LABEL       com.patrickbrandao.blog.version="1.0"
LABEL       com.patrickbrandao.blog.description="Redis Distroless Example"

# Multiple labels in a single instruction
LABEL       com.patrickbrandao.owner="Patrick Brandao" \
            com.patrickbrandao.email="patrickbrandao@gmail.com"

Fazer construção da imagem:

Bash
# Construir imagem:
# - Imagem baseada em stage chamado "builder"
docker build . \
    -f Dockerfile \
    --pull \
    --no-cache \
    --build-arg VERSION=8.6.1 \
    --build-context tmp=/tmp \
    --build-context root=/root \
    --target builder \
    -t redis-server:builder;

# - Imagem completa
docker build . \
    -f Dockerfile \
    --build-arg VERSION=8.6.1 \
    --build-context tmp=/tmp \
    --build-context root=/root \
    -t redis-server:distroless \
    -t redis-server:latest;

# Inspecionar imagem:
docker history redis-server:distroless;
docker inspect redis-server:distroless;

# Listar todas as imagens:
docker images;
docker image ls;

# Filtrar pelo nome da chave do label:
docker images --filter "label=org.opencontainers.image.authors";

Criar rede e container com a imagem:

Bash
# Rodar container Redis ultra-minimalista:
docker network create redisnet;

# Servidor REDIS A (parametros minimalistas)
docker rm -f redis-a 2>/dev/null;
docker run \
    -d --name=redis-a \
    --network redisnet \
    redis-server:distroless;

# Servidor REDIS B (parametros ideais do Redis)
docker rm -f redis-b 2>/dev/null;
docker run \
    -d --name=redis-b \
    --hostname redis-b.intranet.br \
    --restart=always \
    --read-only \
    --cpuset-cpus 0,1 --cpus=2.0 \
    --memory=1g --memory-swap=1g \
    --sysctl net.core.somaxconn=8192 \
    --dns 0.0.0.0 \
    --network redisnet \
    -p 60379:6379 \
    -v redis_server:/data \
    redis-server:distroless;

# Teste de ping (redis-cli -> redis-server)
docker exec -it --user redis redis-a /usr/bin/redis-cli ping;
docker exec -it --user redis redis-b /usr/bin/redis-cli ping;

# Inspecionar o container:
docker inspect redis-b; # manifesto completo
docker inspect redis-b --format='{{json .Config.Healthcheck}}';
docker inspect redis-b --format='{{json .Config.OnBuild}}';
docker inspect redis-b --format='{{.State.Health.Status}}';

# Analisar logs:
docker logs    redis-a; # logs recentes
docker logs -f redis-b; # acompanhar log em tempo real

# Analisar arquivos alterados dentro da imagem:
docker diff    redis-a;

5 – Gestão de imagens

Imagens são arquivos .tar armazenadas em servidores chamados registry.

Imagens possuem:

  • Atributos herdados da construção (Dockerfile);
  • Camadas de arquivos na ordem de montagem overlay, cada camada tem seu hash SHA256 único usado para hospedar em arquivo .tar inequívoco (cache);
  • Identidade da imagem: O Hash SHA256 da união das camadas e manifestos dão à imagem uma identidade final única;
  • Tags que dão nomes simples e humanizados ao hash SHA256 da imagem.

As imagens podem ser utilizadas para:

  • Servir de base para construir containers via FROM no Dockerfile;
  • Servir como stage de contexto para obter arquivos no Dockerfile;
  • Servir de ponto de montagem para containers;

5.1 – Pesquisar e obter imagens

Procurar imagens públicas e baixando imagens dos servidores de registry:

Bash
# Procurando imagens pelo nome no inventario:
docker search rabbitmq;
# NAME                  DESCRIPTION                                  STARS OFFICIAL
    # rabbitmq          RabbitMQ is an open source multi-protocol... 5346  [OK]
    # bitnami/rabbitmq  Bitnami Secure Image for rabbitmq             131       
    # circleci/rabbitmq This image is for internal use                  0         

# Imagens famosas:
docker search alpine;
docker search debian;
docker search ubuntu;
docker search nginx;
docker search redis;
docker search n8n;

# Procurar por imagens públicas e OFICIAIS (seguras):
docker search --filter is-official=true php;
docker search --filter is-official=true node;
docker search --filter is-official=true python;
docker search --filter is-official=true debian;

# Baixar imagens oficiais do registry padrão - Docker Hub:
docker pull ubuntu;       #< baixa imagem ubuntu com tag ":latest"
docker pull alpine:3.12;
docker pull debian:latest;
# - Tags da mesma imagem:
#   sha256: 3615a749858a1cba49b408fb49c37093db813321355a9ab7c1f9f4836341e9db
docker pull debian:13;
docker pull debian:trixie;

# Baixar imagens de usuarios da comunidade Docker Hub:
# - usuario...........: bitnami
# - imagem............: bitnami/rabbitmq;
# - tag de compilacao.: :latest (padrao quando omitido)
docker pull bitnami/rabbitmq;
# - Identico a:
docker pull bitnami/rabbitmq:latest;

# Listar imagens presentes localmente:
docker image ls;
docker images;

# Remover tag da imagem:
# Obs: Se for a unica tag restante da imagem tb remove tambem as camadas do cache
docker rmi alpine:latest;
docker rmi debian:latest;
docker rmi debian:13;
docker rmi debian:trixie;

# Removendo todas as imagens sem uso:
docker image prune -f;

5.2 – Gerenciamento de Tags

Você pode adicionar tags a imagens existentes, sejam imagens criadas por você com as tags vinculadas no docker build ou imagens baixadas no via docker pull:

Bash
# Baixar imagem do debian 3 trixie:
docker pull debian:trixie;

# Adicionar tags próprias a ela:
docker tag debian:trixie debian:projeto;

# Criar imagem baseada na tag "debian:projeto" e gerando
# imagem com a tag "debian:net" e "debian:netv1":
(
    echo 'FROM debian:projeto';
    echo 'RUN  apt-get -y update && apt-get -y upgrade && dist-upgrade';
    echo 'RUN  apt-get -y install curl wget fping iputils-ping net-tools';
) | docker build -t debian:net -t debian:netv1 - ;

# Listar e conferir (observem que tem o mesmo ID):
docker image ls debian:trixie;
docker image ls debian:projeto;
docker image ls debian:net;
docker image ls debian:netv1;

# Adicionar tag de usuario no Docker Hub:
# Obs: A parte "usuario-aqui" deve ser seu login em https://hub.docker.com/
docker tag debian:trixie usuario-aqui/debian:projeto;
docker tag debian:net    usuario-aqui/debian:net;
docker tag debian:netv1  usuario-aqui/debian:netv1;

# Fazer upload da tag/imagem:
docker push usuario-aqui/debian:projeto;
docker push usuario-aqui/debian:net;
docker push usuario-aqui/debian:netv1;

# Em outro servidor em qualquer lugar do mundo
# sua imagem pode ser obtida assim:
docker pull usuario-aqui/debian:net;

5.3 – Apagando Tags e Imagens

Para apagar uma imagem basta remover todas as tags que apontam para o digest SHA256 até que não restem mais nenhum apontamento e as camadas fiquem órfãs:

Bash
# Remover imagens do inventário local (image rm = rmi)
docker  image  rm  debian:projeto;
docker  rmi        debian:13;
docker  rmi        debian:trixie;
docker  image  rm  debian:net;
docker  image  rm  debian:netv1;

# Remover camadas órfãs e imagens não utilizadas (sem containers e apenas 1 tag):
docker  image prune -f -a; # tudo que estiver sem uso
docker  image prune -f;    # somente tags unicas sem uso

6 – Criação de redes para containers

Os containers podem ficar conectados em diferentes tipos de redes:

  • None: “–network none” cria um namespace de rede sem interface eth0 (sem saída);
  • Host: “–network host” conecta o container no mesmo namespace de rede do host;
  • Bridge padrão: “–network bridge” ou omissão da rede, conecta o container na bridge padrão que não tem suporte a redirecionamento de portas;
  • Bridge privada: Rede criada com o comando “docker network create”;
  • Rede compartilhada: Rede com driver MACVLAN (passagem direta para a interface uplink) ou driver IPVLAN (IP adicional na interface uplink);
  • Overlay: Bridge privada para interconexão via VXLAN em ambiente Swarm.

Exemplos de redes bridge privada:

Bash
# Rede 0 - config automatica (padrao bridge)
docker network create netx;
docker network create --driver bridge nety;

# Rede 1 - personalizacao do prefixo IPv4
docker network create net01 \
    --subnet 10.111.0.0/16 --gateway 10.111.255.254;

# Rede 2 - suporte a IPv6
docker network create net02 --ipv6;

# Rede 3 - suporte a IPv4 e IPv6 com prefixos personalizados
docker network create net03 \
    --subnet 10.113.0.0/16 --gateway 10.113.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:113::/64 --gateway=2001:db8:10:113::ffff;
    
# Rede 4 - suporte a IPv4 e IPv6, prefixos, icc permitido, nome de interface, mtu
docker network create net04 \
    -o com.docker.network.bridge.name=br-net04 \
    -o com.docker.network.bridge.enable_icc=true \
    -o com.docker.network.driver.mtu=9000 \
    --subnet 10.114.0.0/16 --gateway 10.114.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:114::/64 \
    --gateway=2001:db8:10:114::ffff;

# Rede 5 - rede sem NAT (modo roteado), icc desativado
docker network create net05 \
    -o com.docker.network.bridge.name=br-net05 \
    -o com.docker.network.bridge.enable_icc=false \
    -o com.docker.network.driver.mtu=65495 \
    -o com.docker.network.bridge.gateway_mode_ipv4=routed \
    -o com.docker.network.bridge.gateway_mode_ipv6=routed \
    --subnet 10.115.0.0/16 --gateway 10.115.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:115::/64 \
    --gateway=2001:db8:10:115::ffff;

# Rede 6 - rede interna isolada (sem gateway, somente trafego entre containers)
docker network create net06 \
    --internal \
    -o com.docker.network.bridge.name=br-net06 \
    -o com.docker.network.driver.mtu=9000 \
    -o com.docker.network.bridge.gateway_mode_ipv4=isolated \
    -o com.docker.network.bridge.gateway_mode_ipv6=isolated \
    --subnet 10.116.0.0/16 --gateway 10.116.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:116::/64 \
    --gateway=2001:db8:10:116::ffff;

# Rede 7 - rede com NAT mas sem firewall
docker network create net07 \
    -o com.docker.network.bridge.name=br-net07 \
    -o com.docker.network.driver.mtu=1450 \
    -o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
    -o com.docker.network.bridge.gateway_mode_ipv6=nat-unprotected \
    --subnet 10.117.0.0/16 --gateway 10.117.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:117::/64 \
    --gateway=2001:db8:10:117::ffff;

# Rede 8 - rede ipv6 only
docker network create net08 \
    -o com.docker.network.bridge.name=br-net08 \
    -o com.docker.network.driver.mtu=1450 \
    --ipv4=false \
    --ipv6 \
    --subnet=2001:db8:10:118::/64 \
    --gateway=2001:db8:10:118::ffff;

# Rede 9 e 10 - usar mesma configuracao da rede template01
# - template01
docker network create template01 \
    --config-only \
    -o com.docker.network.driver.mtu=9000 \
    -o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
    -o com.docker.network.bridge.gateway_mode_ipv6=nat-unprotected \
    --ipv6;

    # - redes baseadas na config template:
    docker network create net09 --config-from=template01;
    docker network create net10 --config-from=template01;

# Rede 11 - manipulacao completa, aux-address para não alocar tais ips
docker network create net11 \
    --driver bridge \
    --subnet 172.30.128.0/24 \
    --gateway 172.30.128.254 \
    \
    --ip-range 172.30.128.0/28 \
    --aux-address rtr-vpngw=172.30.128.1 \
    --aux-address srv-dnsr1=172.30.128.2 \
    --aux-address srv-dnsr2=172.30.128.3 \
    --aux-address srv-dnsa1=172.30.128.4 \
    --aux-address srv-dnsa2=172.30.128.5 \
    --aux-address srv-ntps1=172.30.128.6 \
    --aux-address srv-ntps2=172.30.128.7 \
    \
    --ipv6 \
    --subnet fd00:fada:beba:cafe:172:28:128:0/120 \
    --gateway fd00:fada:beba:cafe:172:28:128:ff \
    \
    --ip-range fd00:fada:beba:cafe:172:28:128:80/121 \
    --aux-address rtr-vpngw=fd00:fada:beba:cafe:172:28:128:1 \
    --aux-address srv-dnsr1=fd00:fada:beba:cafe:172:28:128:2 \
    --aux-address srv-dnsr2=fd00:fada:beba:cafe:172:28:128:3 \
    --aux-address srv-dnsa1=fd00:fada:beba:cafe:172:28:128:4 \
    --aux-address srv-dnsa2=fd00:fada:beba:cafe:172:28:128:5 \
    --aux-address srv-ntps1=fd00:fada:beba:cafe:172:28:128:6 \
    --aux-address srv-ntps2=fd00:fada:beba:cafe:172:28:128:7 \
    \
    --label projeto=producao \
    \
    -o com.docker.network.bridge.name=br-net11 \
    -o com.docker.network.driver.mtu=1500 \
    -o com.docker.network.bridge.enable_icc=false \
    -o com.docker.network.bridge.gateway_mode_ipv4=routed \
    -o com.docker.network.bridge.gateway_mode_ipv6=routed;

7 – Debug de Rede

Comandos para monitorar os recursos de rede:

Bash
# Regras de roteamento
ip -4 rule show;
ip -6 rule show;

# Tabelas de rotas:
ip -4 route show table local;
ip -6 route show table local;
ip -4 route show table main; # ou: ip route show
ip -6 route show table main; # ou: ip -6 route show

# Regras de firewlal nftables:
nft list ruleset;

# Conexoes registradas na conntrack:
conntrack -L;
conntrack -C;

# Listar todos os links e interfaes:
ip link show;
ip -s -s link show;
ip -details -json link | jq;

# Listar enderecos IP:
ip addr show;
ip -s -s addr show;
ip -details -json addr | jq;

# Listar registros ARPe IPV6-ND:
ip -4 nei show;
ip -6 nei show;

# Listar namespaces de rede:
[ -L /var/run/netns ] || ln -Ts /var/run/docker/netns /var/run/netns;
ip netns list;
ip -all netns exec ip link;
lsns;
lsns --json;

# Listar bridges e interfaces adicionais:
brctl show;
ip link show type bridge;
ip link show type bridge_slave;

# Listar interfaces pelo tipo:
ip link show type dummy;
ip link show type bond;
ip link show type bond_slave;
ip link show type veth;
ip link show type macvlan;
ip link show type ipvs;
ip link show type ipvlan;
ip link show type vxlan;
ip link show type geneve;

# Listar conecoes com o HOST (originadas, recebidas via listen):
netstat -tulpn;
netstat -tulpen;
ss -lant;

8 – Gestão de Volumes

Volumes são pastas usadas dentro dos containers mas que armazena seu conteúdo no host (ambiente principal) ou em pontos de montagens.

Volumes nomeados ficam armazenados em /var/lib/docker/volumes e possuem um nome simples que não envolva o caracter “/” e são geridos pelo driver de volume do Docker. Exemplo:

Bash
# Criar container com volume nomeado:
docker run \
    -d \
    --name redis-01 \
    -v redis_01:/data \
    redis:latest;

# Informacoes sobre o volume:
docker volume inspect redis_01;

# Volume:
#   Nome....................: redis_01
#   Localizacao do volume...: /var/lib/docker/volumes/redis_01
#   Pasta real do volume....: /var/lib/docker/volumes/redis_01/_data/
#   Localizacao no container: /data

Volumes montados funcionam da mesma maneira mas permitem especificar argumentos especiais para controlar a localização da pasta real, tipos, atributos, etc. Esse tipo não é gerido pelo Docker (particularidade do container). Exemplo:

Bash
# Criar pasta para o volume:
mkdir /storage/redis-02;

# Criar container com volume montado:
docker run \
    -d \
    --name redis-02 \
    -v /storage/redis-02:/data \
    redis:latest;

# Volume:
#   Nome....................: /storage/redis-02
#   Localizacao do volume...: /storage/redis-02
#   Pasta real do volume....: /storage/redis-02
#   Localizacao no container: /data

Volumes nomeados montados unem as duas formas permitindo especificar os parâmetros da montagem e colocar o container para ser gerido pelo Docker. Exemplo:

Bash
# Criar pasta do volume:
mkdir /storage/redis-03;

# Registrar no Docker:
docker volume create \
    --driver local \
    --opt type=none \
    --opt device=/storage/redis-03 \
    --opt o=bind \
    redis-03-data

# Informacoes sobre o volume:
docker volume inspect redis-03-data;

# Criar container com volume nomeado pre-existente:
docker run \
    -d \
    --name redis-03 \
    -v redis-03-data:/data \
    redis:latest;

# Volume:
#   Nome....................: redis_01
#   Localizacao do volume...: /var/lib/docker/volumes/redis-03-data (overlay)
#   Pasta real do volume....: /storage/redis-03
#   Localizacao no container: /data

Volumes em RAM são tipos de montagens de diretórios dentro do container mapeados na memória RAM e não possuem nenhum overlay persistente. São feitos para trabalhar com alta velocidade de I/O e nenhum compromisso de salvar os dados! São perdidos quando o container é parado ou removido. Exemplo:

Bash
# Criar container com volume nomeado na RAM:
# - /data: sem limite, uso geral
# - /run: limite de 32M, sem suporte a execucao de binarios
# - /tmp: limite de 128m, uso geral
# - /cache: sem limite, uso geral
# - /uploads: limite de 256m, uso geral, arquivos exclusivos do usuario e grupo
docker run \
    -d \
    --name redis-04 \
    --tmpfs /data:rw \
    --tmpfs /run:rw,noexec,nosuid,mode=1777,size=32m \
    --tmpfs /tmp:rw,size=128m \
    --mount type=tmpfs,destination=/cache \
    --mount type=tmpfs,dst=/uploads,tmpfs-size=268435456,tmpfs-mode=1770 \
    redis:latest;

Volumes de imagens permitem montar uma imagem em um diretório dentro do container. Utiliza-se esse método para analise de imagens e extração de artefatos prontos. Exemplo:

Bash
# Baixar as imagens:
docker pull alpine:latest;
docker pull debian:latest;
docker pull redis:latest;
docker pull nginx:latest;

# Rodar container do Alpine e colocar cada imagem em uma pasta interna:
docker run \
    -d \
    --name alpine-bundle \
    \
    --mount type=image,source=debian:latest,target=/mnt/debian \
    --mount type=image,source=redis:latest,target=/mnt/redis \
    --mount type=image,source=nginx:latest,target=/mnt/nginx \
    \
    alpine:latest tail -f /dev/null;

# Pastas no container baseadas em imagens (read-only):
# - /mnt/debian: contem o rootfs do Debian
# - /mnt/redis: contem o rootfs do Redis
# - /mnt/nginx: contem o rootfs do Ngin

# Testando:
# - Entrar no container:
docker exec -it alpine-bundle ash;
    # - Fazer chroot para entrar no debian enjaulado dentro do container:
    chroot /mnt/debian /bin/bash;

9 – Backup de Volumes

Existem duas formas de perder dados usando containers:

  • Não montar volumes de diretórios que o container usa para salvar dados, a solução é descobrir essas pastas e extraí-las com o comando “docker cp“;
  • Usar volumes nomeados ou montados e esquecer de fazer backups externos, a solução é fazer backup periódico.

O problema dos volumes nomeados é que eles não ficam registrados no inventário do “docker volumes” e você deve inspecionar os containers “docker inspect” para descobrir onde montou.

Detectar todos os diretórios de volumes no inventário de volumes:

Bash
# Listar nome dos volumes e diretórios de dados:
docker volume ls --format '{{.Name}}\t{{.Mountpoint}}'

# Listar somente diretórios de dados:
docker volume ls --format '{{.Mountpoint}}';

9.1 – Backup e restauração de todos os volumes

É extremamente recomendável que todos os containers sejam desligados e o docker seja parado (service docker stop) antes do backup. Lembre-se de iniciar o Docker após terminar a compressão dos dados.

Backup completo de todos os volumes do inventário:

Bash
# Instalar comandos necessários:
apt-get -y install tar zstd;

# Gerar lista dos diretórios dos volumes:
VOLUMES_DIRS=$(docker volume ls --format '{{.Mountpoint}}');

# Gerar nome do arquivo com data/hora completa:
# - Obter ano-mes-dia-hora-minuto:
NOWDT=$(date "+%Y-%m-%d-%H-%M"); 
# - Caminho do arquivo de backup:
VOLUMES_ARCHIVE="/root/backup-volumes-$NOWDT.tar.zts";

# Iniciar a compressao extrema dos volumes e salvar no backup:
# (pode demorar dependendo da quantidade de dados)
# tar --zstd -cvf $VOLUMES_ARCHIVE $VOLUMES_DIRS;
tar -cf - $VOLUMES_DIRS | zstd -T0 --ultra -22 > $VOLUMES_ARCHIVE;

Para recuperar o backup no servidor você deve interromper todos os containers para não escrever por cima de arquivos em uso (service docker stop). Não esqueça de iniciar o Docker após concluir a restauração dos volumes.

Bash
# Arquivo com o backup geral:
VOLUMES_ARCHIVE="/root/backup-volumes-DATA-BACKUP-AQUI.tar.zts";

# Descomprimir backup:
tar -xvf $VOLUMES_ARCHIVE -C /;

9.2 – Backup e restauração de volume específico

Fazer backup e restaurar volumes especificos não requer que o serviço do Docker seja parado durante a operação, basta que o container que fará uso do volume esteja desligado.

Exemplo com volume chamado “rabbitmq_01_data“.

Backup:

Bash
# Nome do volume:
VOLUME_NAME="rabbitmq_01_data";

# Diretório do volume específico:
#VOLUME_DIR="/var/lib/docker/volumes/rabbitmq_01_data";
VOLUME_DIR=$(docker volume inspect $VOLUME_NAME --format '{{.Mountpoint}}');

# Arquivo com backup do volume:
# - Obter ano-mes-dia-hora-minuto:
NOWDT=$(date "+%Y-%m-%d-%H-%M"); 
# - Caminho do arquivo de backup:
VOLUMES_ARCHIVE="/root/backup-volume-$VOLUME_NAME-$NOWDT.tar.zts";

# Iniciar a compressao extrema do volume:
# tar --zstd -cvf $VOLUMES_ARCHIVE $VOLUME_DIR;
tar -cf - $VOLUME_DIR | zstd -T0 --ultra -22 > $VOLUMES_ARCHIVE;

# Detalhes do arquivo de backup:
stat    $VOLUMES_ARCHIVE;
ls -lah $VOLUMES_ARCHIVE;

# Descomprimir backup:
tar -xvf $VOLUMES_ARCHIVE -C /;
# Arquivo com o backup geral:

Restauração:

Bash
# Arquivo com o backup geral:
VOLUME_ARCHIVE="/root/backup-volumes-rabbitmq_01_data-DATA-BACKUP-AQUI.tar.zts";

# Descomprimir backup:
tar -xvf $VOLUME_ARCHIVE -C /;

Recomendações:

  • Faça o backup por volumes, assim fica mais pontual recuperar um serviço específico;
  • Utilize o crontab para fazer backups automáticos;
  • Monitore o servidor para não encher o disco com volumes e seus backups;
  • Crie um serviço especializado em backups para cuidar disso.

10 – Limpeza de lixo

O servidor Docker pode ficar cheio de arquivos abandonados.

É extremamente importante que você faça o backup de todos os volumes e de todos os dados do servidor e coloque em um lugar externo antes de iniciar a limpeza.

As principais fontes desse lixo são:

  • Imagens:
    • Cache de camadas do docker build;
    • Imagens não utilizadas, baixou mas não usou;
    • Imagens abandonadas por updates de containers migrados para versõs mais novas;
  • Containers:
    • Containers mal feitos que geram dados em pastas não mapeadas em volumes;
  • Volumes:
    • Volumes criados por instruções VOLUME e que não foram mapeados explicitamente;
    • Volumes abandonados;
  • Containerd: O containerd tem sua gestão própria de imagens e acumula muito espaço desvinculado dos containers em produção.

Investigar a utilização de espaço do Docker e do Containerd:

Bash
# Consumo resumido do Docker:
docker system df;

# Consumo detalhado do Docker:
docker system df -v;

# Tamanho dos diretórios de trabalho:
# - Docker:
du -hs /var/lib/docker;

# - Containerd:
du -hs /var/lib/docker;

10.1 – Limpeza amistosa

Para fazer a limpeza (garbage collection) é necessário ordenar ao Docker que faça o prune e estirpe todos os dados que não estão sendo utilizados. Não afeta containers em produção.

Comandos para limpeza:

Bash
# Removendo todos os containers parados:
docker containers prune -f;

# Removendo todos os volumes abandonados (perigoso, faz backup primeiro):
docker volume prune -f;

# Removendo todas as imagens sem uso:
docker image prune -f;

# Removendo todas as redes sem uso:
docker network prune -f;

# Removendo todos os objetos sem uso (redes, imagens, volumes, containers):
docker system prune -f;

10.2 – Limpeza completa

Para uma limpeza rápida e completa do Docker sem afetar containers em produção, use:

Bash
# Limpeza completa do Docker:
docker system prune -f -a;

10.3 – Limpeza nuclear

Caso você resolva apelar e voltar o Docker e o Containerd para o zero absoluto, essa opção é a última e definitiva. Ela resultará na destruição completa do Docker e de tudo que ele possui.

Destruindo tudo que envolve o Docker:

Instalando novamente:

Y – Exemplos de manipulação de redes em docker

Bash
# Listar redes:
docker network ls;

# REDES BRIDGE (tipo padrão/normal):
#------------------------------------------------------------------------

# - Criar uma rede bridge adicional simples (nome: sites1):
docker network create sites1;

# - Criar uma rede bridge adicional simples (nome: sites2):
docker network create -d bridge sites2;
     
# - Cuidado:
#   ** o docker cria a rede inicial na faixa 172.17.0.0/16
#   ** ao criar redes novas sem informar a faixa, ele usa um /16 seguinte
#      ou seja, a proxima rede 172.18.0.0/16, e 172.19.0.0/16, ...
#      mas a faixa privada termina em 172.31.0.0/16,
#   ** a rede 172.32.0.0/16 NÃO É PRIVADA, SE VOCÊ INVADIR ESSA FAIXAR
#      ou faixas acima dela sites vão deixar de abrir no seu servidor.
#

# - Criar uma rede bridge adicional simples com faixa ipv4 específica:
docker network create -d bridge --subnet 192.168.3.0/24 sites3;
docker network create -d bridge --subnet 192.168.4.0/24 sites4;

# - Nota: o primeiro IP é usado como gateway, mas vc pode especificar:
docker network create -d bridge \
    --subnet 192.168.5.0/24 --gateway 192.168.5.254 \
    sites5;

# - Nota: por padrão todas as redes são criadas ipv4-only

# - Criar uma rede bridge adicional com IPv6:
docker network create -d bridge \
    --subnet 10.6.0.0/16 --gateway 10.6.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:6::/64 \
    --gateway=2001:db8:10:6::1 \
    sites6;

# - Criar uma rede bridge adicional com nome especifico
#   de interface de rede (ip link show; brctl show):
docker network create -d bridge \
    -o "com.docker.network.bridge.name"="brsites7" \
    --subnet 10.7.0.0/16 --gateway 10.7.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:7::/64 \
    --gateway=2001:db8:10:7::1 \
    sites7;

# - Criar uma rede bridge adicional com nome especifico
#   de interface de rede (ip link show; brctl show) e
#   permitir comunicação livre entre containers:
docker network create -d bridge \
    -o "com.docker.network.bridge.name"="brsites8" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    --subnet 10.8.0.0/16 --gateway 10.8.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:8::/64 \
    --gateway=2001:db8:10:8::1 \
    brsites8;

# - Criar uma rede bridge adicional com nome especifico
#   de interface de rede (ip link show; brctl show),
#   configurar MTU em 9000 (jumbo-frame), desativar NAT,
#   permitir comunicação livre entre containers e
#   nao fazer NAT (rotear ou usar ip publico mesmo!):
docker network create -d bridge \
    -o "com.docker.network.bridge.name"="brsites9" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    -o "com.docker.network.driver.mtu"="9000" \
    -o "com.docker.network.bridge.enable_ip_masquerade"="false" \
    --subnet 45.255.128.128/25 --gateway 45.255.128.254 \
    --ipv6 \
    --subnet=2804:cafe:ffff:a009::/64 \
    --gateway=2804:cafe:ffff:a009::1 \
    brsites9;


# REDES MACVLAN (tipo transparente, joga o container na rede externa):
#------------------------------------------------------------------------

# - Nota: o container receberá um MAC novo, a bridge do Linux vai
#         deixar passar, mas o Port-Group e vSwitch do VMware
#         por padrão não permitirá, vc precisa ativar o recurso
#         allow-mac-change na Port-Group no no vSwitch
# - Nota: a rede MACVLAN precisa ser anexada uma interface
#         ethernet (eth0, eno0, ens192, ...) que esteja UP
#
# - Nota: você só pode usar 1 rede MACVLAN por interface ethernet
#
# - Alerta: a gerencia de IP é selvagem, cuidado ao
#         informar a faixa pois criar containers e alocar
#         IPs em uso na LAN externa pode resultar em conflito
#         de ARP (o famoso conflito de IP)
#
# - No VMware ESXi (terminal):
#    esxcli network vswitch standard policy security set \
#       --vswitch-name=vSwitch0 --allow-mac-change yes
#

# Criar rede MACVLAN simples para contato externo na eth0:
docker network create -d macvlan -o parent=eth0 \
    --subnet=10.160.0.0/16 --gateway 10.160.255.254 \
    mth0;

# Criar rede MACVLAN com IPv6 para contato externo na eth1:
docker network create -d macvlan -o parent=eth1 \
    --subnet=45.255.130.0/27 --gateway 45.255.130.1 \
    --ipv6 \
    --subnet=2804:cafe:ffff:b000::/64 --gateway=2804:cafe:ffff:b000::1
    mth1;

# Removendo todas as redes sem uso (todas acima se vc não as usou):
docker network prune -f;

Z – Exemplos: criação e manipulação de containers

Bash
# Nota: todo container precisa rodar alguma coisa pra justificar
#       sua existencia na lista de processos do Linux, assim,
#       imagens puras como Debian, Alpine, não possuem programas
#       de ENTRYPOINT ou CMD. Você precisará imperativamente
#       informar um comando após o nome da imagem.
#       As imagens de aplicativos (MariaDB, Redis, ...)
#       já possuem ENTRYPOINT/CMD e por isso não exigem
#       um comando após o nome da imagem.
#       Nos exemplos abaixo, vou executar o comando 'sleep'
#       como uma forma de manter um processo rodando dentro
#       do container.
#
# Exemplo 1
#------------------------------------------------------------------

# Criar e rodar em 2 etapas (pouco usual, apenas exemplo):
# - Criar container (não roda)
docker create --name debian01 debian:bookworm sleep 999999999;

# - Executar/iniciar o container:
docker start  debian01;

# Listar (comando puramente informativo):
docker ps -a;

# Extrair todas as informações do container:
docker inspect debian01;

# Extrair todas as informações do container (puramente informativo):
docker exec -it debian01  /bin/bash;
  exit   #< para sair do container

# Parar o container:
docker stop debian01;

# Destruir o container:
docker rm -f debian01;


# Exemplo 2 (versão rápida dos comandos acima)
#------------------------------------------------------------------

# Criar e rodar:
docker run -d --name debian02 debian:bookworm sleep 999999999;

# Listar (comando puramente informativo):
docker ps -a;

# Extrair todas as informações do container (puramente informativo):
docker inspect debian02;

# Entrar no container (executar um shell interativo no ambiente):
docker exec -it debian02  /bin/bash;
  exit   #< para sair do container

# Parar e destruir o container:
docker rm -f debian02;


# Exemplo 3 (adicionando elegancia e mais opções)
#------------------------------------------------------------------

# Criar pasta de dados:
mkdir -p /storage/debian03;

# Criar container cheio de opções elegantes:
docker run -d \
    --name debian03 \
		-h debian03.intranet.br \
    --restart=unless-stopped \
    \
		-e TZ=America/Sao_Paulo \
		-e MAINTAINER="Patrick Brandao" \
    \
    --mount \
       type=bind,source=/storage/debian03,destination=/data,readonly=false \
    \
    debian:bookworm \
        sleep 999999999;

# Argumentos:
#    -h especifica o hostname interno
#    --restart pode ser always ou unless-stopped
#    -e define variável de ambiente (comando: env)
#    --mount mapeia uma pasta do HOST (Linux) dentro do container
#        no exemplo acima, tudo que dentro do container
#        que gravar em /data/ estará de fato gravando
#        no HOST principal em /storage/debian03/
#

# Parar e destruir o container:
docker rm -f debian03;



# Exemplo 4 (argumentos de rede e multi-rede)
#------------------------------------------------------------------

# Criando duas redes:
# - Rede para acesso à Internet
docker network create -d bridge \
    -o "com.docker.network.bridge.name"="brsites" \
    --subnet 10.99.0.0/24 --gateway 10.99.0.254 \
    --ipv6 \
    --subnet=2001:db8:ffff:1099::/64 --gateway=2001:db8:ffff:1099::1 \
    brsites;

# - Rede para acesso entre containers e container banco de dados
docker network create -d bridge \
    -o "com.docker.network.bridge.name"="brdatabase" \
    -o "com.docker.network.driver.mtu"="9000" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    -o "com.docker.network.bridge.enable_ip_masquerade"="false" \
    \
    --subnet 10.255.0.0/24 --gateway 10.255.0.254 \
    brdatabase;

# - Criar container de banco de dados MariaDB:
	mkdir -p /storage/mariadb-main
	docker run \
		-d --restart=unless-stopped \
		--name mariadb-main \
		-h mariadb-main.intranet.br \
		\
		--network brdatabase \
		--ip=10.255.0.100 \
		\
		-e MYSQL_ROOT_PASSWORD=tulipasql \
		-e MYSQL_DATABASE=admin \
		-e MYSQL_USER=suporte \
		-e MYSQL_PASSWORD=tulipasql \
		\
		--mount \
 type=bind,source=/storage/mariadb-main,destination=/var/lib/mysql,readonly=false \
		\
			mariadb:latest;

# - Criar container Debian que se conectará na Internet
#   e possuirá uma segunda conexão de rede conectada à rede
#   de banco de dados
docker run -d \
    --name debian04 \
		-h debian04.intranet.br \
    --restart=always \
		\
		--network brsites --mac-address "00:ca:fe:f1:f2:f0" \
		--ip=10.99.0.14 \
		--ip6=2001:db8:ffff:1099::14 \
		\
    debian:bookworm \
        sleep 999999999;

# - Conectar container debian04 na rede de banco de dados:
docker network connect brdatabase debian04 --ip=10.255.0.14;

# - Destruir tudo!
undocker debian04;
undocker mariadb-main;
docker   system prune -f;

# - Observe os arquivos em /storage/mariadb-main/
#   se você recriar o container mariadb-main novamente
#   ele continuará de onde parou pois os dados objetivos
#   foram salvos, somente software (parte descartavel) foi
#   destruida.

W – Configuração principal do Docker

O Docker faz a leitura do arquivo (JSON) no caminho /etc/docker/daemon.json (precisa criar o arquivo), segue algumas configurações comuns, junte as que precisa num único objeto JSON.

Acelerar downloads

JSON
# Paralelismo de downloads e uploads de imagens
{
    "max-concurrent-uploads": 16,
    "max-concurrent-downloads": 16
}

Suporte a GPU

JSON
# Suporte a GPU NVIDIA (requer instalacao previa dos drivers):
{
    "runtimes": {
        "nvidia": {
            "args": [],
            "path": "nvidia-container-runtime"
        }
    }
}

Desativar firewall e redirecionamento de portas

Referência: https://docs.docker.com/reference/cli/dockerd/

JSON
# Desativar suporte a regras de firewall e redirecionamento
{
  "iptables": false,
  "ip6tables": false,
  "ip-masq": false
}

Rede IPv4 da rede padrão (docker default network)

JSON
# Rede IP padrao: 172.17.0.0/16
# Escolha uma das opcoes abaixo:

# Alterar rede padrão:
{
  "bip": "10.251.0.0/16"
}

# Versao mais nova do docker requer a config assim:
{
    "default-address-pools": [ { "base":"10.251.0.0/16", "size": 16 } ]
}

Reinicie para aplicar

Para aplicar as alterações realizadas no /etc/docker/daemon.json, reinicie o docker:

Bash
systemctl restart docker;

Em caso de problemas, retire o daemon.json e reinicie o servidor.

T – Exportando e importando imagens

Imagens normalmente são obtidas por meio de “registry”, sites que hospedam imagens, mas elas podem ser transferidas manualmente de um servidor para o outro:

Bash
# Obter uma imagem de um registry:
# - troque "IMAGEM" pelo nome da imagem
# - troque "VERSAO" pela tag da versao da imagem

# Baixa imagem publica:
docker pull IMAGEM:VERSAO;

# Salva imagem em um arquivo TAR:
docker save IMAGEM:VERSAO > /tmp/docker-image-IMAGEM-VERSAO.tar;

# --- copie para seu servidor de backups, storage, etc...

# No servidor destino, baixe o arquivo TAR, importe usando:
docker load --input=/tmp/docker-image-IMAGEM-VERSAO.tar;

K – Ferramentas de gestão de containers

Algumas ferramentas podem te ajudar a monitorar e manipular containers usando interface WEB e templates prontos, vou deixar 2 exemplos:

  • WeaveScope: permite visualização de ambiente e manipulação básica;
  • Portainer CE: permite gestão completa, desde o básico ao avançado de todos os recursos do Docker, fornece templates de ambientes prontos e pre-configurados, considerado um dos melhores sistemas para gestão de containers;

WeaveScope

Referência: https://github.com/weaveworks/scope

Bash
# Nota: se ele bugar, apenas destrua-o e execute novamente!

# Baixar script de provisionamento:
curl -L git.io/scope -o /usr/sbin/scope;

# Tornar executavel:
chmod a+x /usr/sbin/scope;

# Subir container do WeaveScope com usuário e senha (senão ele fica aberto):
arg1="ENABLE_BASIC_AUTH=true";
arg2="BASIC_AUTH_USERNAME=admin";
arg3="BASIC_AUTH_PASSWORD=tulipa";
export WEAVESCOPE_DOCKER_ARGS="-e $arg1 -e $arg2 -e $arg3";
scope launch;

# Acesso: http://  +  IP  +  :4040/

# Para destruir o WeaveScope:
undocker  weavescope;

Portainer CE (Community Edition)

Referência: https://docs.portainer.io/start/install-ce/server/docker/linux

Bash
# Nota: se ele bugar, apenas destrua-o e execute novamente, os dados
#       que importa estarão no diretorio de armazenamento persistente

# Diretorio de dados persistentes:
mkdir -p /storage/portainer-data;

# Criar e rodar:
docker run \
		-d --restart=always \
		--name portainer \
		-h portainer.intranet.br \
		\
		-p 8000:8000 \
		-p 9443:9443 \
		\
		-v /var/run/docker.sock:/var/run/docker.sock \
		--mount \
		type=bind,source=/storage/portainer-data,destination=/data,readonly=false \
		\
		portainer/portainer-ce:2.21.4;

# Acesso: https:// +  IP  +  :9443/
# Defina a primeira senha e salve-a

Terminamos por hoje, isso deve ter te economizado alguns livros de Docker!

Patrick Brandão, patrickbrandao@gmail.com