Ir diretamente para o conteúdo

Definições de cookies

Escolha que tipos de cookies permite. Pode alterar a sua escolha a qualquer momento em Definições de cookies, no fundo de cada página. Política de privacidade

Necessários

Sempre ativos

Necessários para iniciar sessão, manter o seu carrinho e memorizar as suas escolhas. Estão sempre ativos.

Que cookies?
  • weboke_sessie, weboke_klant, weboke_remember: a sua sessão e manter a sessão iniciada
  • weboke_basket: o seu carrinho
  • wkBtwIncl: mostrar preços com ou sem IVA
  • wok_cookies: a sua escolha de cookies, 12 meses

Mede que anúncio leva a uma visita ou encomenda, para não pagarmos por anúncios que não dão resultado.

Que cookies?
  • Google Ads via Google Tag Manager (_gcl_au, _gcl_aw), até 90 dias
  • OpenAI Ads, anúncios no ChatGPT
  • wok_aff: através de que parceiro chegou até nós (programa de afiliados), 60 dias

4,6

País e idioma

Cada país tem o seu próprio site, com os preços e o IVA desse país.

Ver

Docker compose e a firewall

Módulo 9: Docker e docker compose · Tempo de leitura: 12 minutos

Objetivo de aprendizagem: No final desta lição, saberá descrever serviços num ficheiro compose, iniciá-los, atualizá-los e pará-los, e saberá explicar porque é que as portas publicadas pelo Docker contornam o ufw e como evitar isso.

Conceitos-chave: compose.yaml, services, image, ports, volumes, environment, .env, restart, networks, depends_on, healthcheck, docker compose up -d, pull, logs, down, version: obsoleto, Docker e ufw, DOCKER-USER, publicar em 127.0.0.1, segredos, docker.sock

Porquê o compose?

Com docker run (lição 9.2) inicia um único contentor com uma longa linha de opções. Uma aplicação real é muitas vezes composta por vários contentores: um programa, uma base de dados, um proxy inverso. Memorizar essas linhas e voltar a escrevê-las após um reinício ou uma atualização acaba, mais cedo ou mais tarde, por correr mal.

O Docker Compose descreve todos os contentores de uma aplicação num único ficheiro: compose.yaml. Coloca esse ficheiro numa pasta própria, por exemplo /srv/status/compose.yaml, e gere tudo com docker compose. O ficheiro é ao mesmo tempo a sua documentação: o que está em execução, que imagem, que portas, onde estão os dados. Inclua essa pasta na sua cópia de segurança (lição 8.1) e poderá repor a aplicação num novo servidor em poucos minutos.

O plug-in chama-se docker compose (com um espaço, versão 2). O antigo programa independente docker-compose (com hífen) foi substituído; ainda o encontrará em manuais antigos. Também o campo version: "3.8" no topo de ficheiros antigos está obsoleto: o Compose utiliza sempre o esquema mais recente e, perante version:, apenas emite um aviso.

Ler um ficheiro compose

Um exemplo com um programa e uma base de dados PostgreSQL:

# /srv/notities/compose.yaml
services:
  app:
    image: ghcr.io/example/notities:1.4
    restart: unless-stopped
    ports:
      - "127.0.0.1:8081:8080"
    environment:
      DB_HOST: db
      DB_USER: notities
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_USER: notities
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U notities"]
      interval: 10s
      retries: 5

volumes:
  db-data:

Passo a passo:

  • services: cada serviço torna-se um contentor. O nome (app, db) é também o nome de anfitrião com que os contentores se encontram uns aos outros. O Compose cria uma rede própria para a aplicação, pelo que app se liga à base de dados em db:5432.
  • image: sempre com uma etiqueta de versão (lição 9.1).
  • restart: o que o Docker faz quando o contentor para ou o servidor reinicia. unless-stopped volta a iniciá-lo, exceto se o tiver parado deliberadamente. Sem política de reinício, a sua aplicação não volta após um reinício (lição 4.2).
  • ports: apenas a aplicação publica uma porta, e apenas em 127.0.0.1. A base de dados não publica nada: a aplicação chega a ela através da rede interna. Uma base de dados com ports: - "5432:5432" é um dos erros mais frequentes (ver abaixo).
  • environment: definições para o programa. A palavra-passe não está escrita literalmente, mas sim como ${DB_PASSWORD}.
  • volumes: o volume com nome db-data conserva a base de dados quando o contentor é substituído.
  • depends_on com healthcheck: a aplicação só inicia quando a base de dados está realmente pronta, e não apenas iniciada.

Segredos num ficheiro .env

O Compose lê variáveis como ${DB_PASSWORD} a partir de um ficheiro .env na mesma pasta:

# /srv/notities/.env
DB_PASSWORD=Kies-hier-een-lang-willekeurig-wachtwoord
anna@web1:/srv/notities$ sudo chmod 600 .env

Assim, a palavra-passe não fica no ficheiro compose que talvez guarde no Git ou cole num fórum para pedir ajuda. Coloque .env em .gitignore. Crie a palavra-passe com um gestor de palavras-passe ou com openssl rand -base64 24.

Utilização diária

Todos os comandos são executados na pasta que contém o ficheiro compose:

anna@web1:/srv/notities$ sudo docker compose config     # verificar o ficheiro, variáveis preenchidas
anna@web1:/srv/notities$ sudo docker compose up -d      # iniciar tudo (ou atualizar conforme o ficheiro)
anna@web1:/srv/notities$ sudo docker compose ps         # estado por serviço
anna@web1:/srv/notities$ sudo docker compose logs -f app
anna@web1:/srv/notities$ sudo docker compose pull       # obter novas imagens
anna@web1:/srv/notities$ sudo docker compose up -d      # substituir os contentores pelas novas imagens
anna@web1:/srv/notities$ sudo docker compose down       # parar e remover os contentores

down mantém os seus volumes. down -v remove também os volumes da aplicação e, com eles, a sua base de dados. Escreva isso apenas se quiser mesmo recomeçar do zero.

docker compose config é o equivalente de nginx -t e sshd -t: mostra como o Compose interpreta o seu ficheiro, com todas as variáveis preenchidas, antes de iniciar o que quer que seja. Tenha o cuidado de não colar esse resultado em lado nenhum, pois as palavras-passe constam dele.

O Docker contorna o ufw

Chegamos ao ponto de segurança mais importante deste módulo. Na lição 5.2 configurou o ufw para "recusar tudo, exceto SSH, 80 e 443". Seria de esperar que um contentor com ports: - "5432:5432" não ficasse acessível. Não é assim.

A documentação do Docker di-lo textualmente: o Docker e o ufw utilizam regras de firewall de uma forma que não é compatível entre si. Quando publica uma porta, o próprio Docker coloca regras na firewall do kernel. Essas regras reencaminham o tráfego para o contentor (tradução de endereços, DNAT) antes de as regras do ufw serem aplicadas. O pacote contorna, portanto, o ufw. ufw status não mostra nada de especial, enquanto a porta está acessível a partir de toda a Internet. O mesmo se aplica ao firewalld.

Além disso, sem endereço, o Docker publica em 0.0.0.0 e [::], ou seja, em IPv4 e também em IPv6 (lição 9.1).

Três formas de fazer isto corretamente, da mais simples à mais complexa:

  1. Não publique nada que não precise de ser público. Bases de dados, caches e serviços internos não recebem ports:. Os contentores da mesma aplicação compose chegam uns aos outros através da rede interna.
  2. Publique em loopback. "127.0.0.1:8081:8080". Assim, apenas o próprio servidor tem acesso, e coloca à frente um proxy inverso (nginx ou Caddy, módulo 7) que escuta na porta 443. O Docker também pode adotar isto por predefinição: uma definição do daemon faz com que todas as portas publicadas sem endereço fiquem em 127.0.0.1.
  3. Regras na cadeia DOCKER-USER. O Docker cria uma cadeia vazia DOCKER-USER que é percorrida antes das suas próprias regras. Aí pode colocar as suas próprias regras, por exemplo "apenas este endereço IP pode aceder às portas publicadas". Trata-se de trabalho avançado com iptables ou nftables, e é fácil errar. Para a maioria dos servidores pequenos, as opções 1 e 2 são suficientes.

Verifique sempre a partir do exterior, como na lição 5.1: nc -vz -w 3 <ip> 5432 a partir do seu portátil, ou a verificação do curso dos exercícios Z5.1 e Z10.4.

Mais duas coisas que não deve fazer

  • Não montar /var/run/docker.sock num contentor, a menos que saiba exatamente porquê. Um contentor com acesso ao socket do Docker pode ele próprio iniciar contentores, incluindo um com o disco inteiro do anfitrião (lição 9.2). Alguns utilitários (painéis, atualizadores automáticos) pedem-no; na prática, isso equivale a dar root a esse programa.
  • Não usar privileged: true nem network_mode: host só porque um manual o indica. Ambos retiram em grande parte o isolamento do contentor. Utilize-os apenas se o autor explicar porque é necessário.

Resumo

  • Um ficheiro compose (compose.yaml) descreve todos os contentores de uma aplicação; é ao mesmo tempo documentação e deve fazer parte da sua cópia de segurança.
  • Utilize etiquetas de versão, uma política de reinício, volumes com nome, um healthcheck sempre que possível e segredos num .env com permissões 600.
  • docker compose config, up -d, ps, logs, pull, down; down -v remove também os volumes.
  • As portas publicadas contornam o ufw e o firewalld. Publique apenas o que tem de ser público e, caso contrário, em 127.0.0.1 com um proxy inverso à frente.
  • Nada de docker.sock, privileged ou network_mode: host sem uma boa razão.

Questionário

1. O ufw está configurado para "recusar tudo exceto 22, 80 e 443". O seu ficheiro compose tem ports: - "5432:5432" na base de dados. A base de dados está acessível a partir da Internet?



2. Como é que o contentor app chega à base de dados na mesma aplicação compose, se a base de dados não publicar nenhuma porta?



3. Após um reinício do servidor, os seus contentores já não estão em execução. O que falta provavelmente no ficheiro compose?



4. Qual é a diferença entre docker compose down e docker compose down -v?



5. Um programa de painel pede, no seu manual, - /var/run/docker.sock:/var/run/docker.sock. O que significa isso para a segurança?



Exercício

Exercício Z9.3: Rever um ficheiro compose. O ficheiro de exemplo compose-nakijken.txt contém (como ficheiro de texto) o ficheiro compose de uma pequena loja online com uma aplicação, uma base de dados, uma cache e uma ferramenta de administração. Contém seis erros que foram abordados nesta lição ou nas lições 9.1 e 9.2. Indique, para cada bloco de linhas numerado, se está correto ou errado e, para cada erro, escolha a correção certa. O programa compara com a chave fixa. Se tiver o seu próprio ficheiro compose, reveja-o depois segundo os mesmos pontos.

Exercício Z9.3: Rever um ficheiro compose

Ficheiro deste exercício: compose-nakijken.txt





















O que preenche e o que encontramos não ficam guardados. O seu navegador memoriza as suas respostas e se concluiu o exercício com sucesso. Se tiver sessão iniciada, guardamos apenas que concluiu o exercício (quase) com sucesso em Os meus cursos; aí também o pode eliminar.

Para saber mais

Um momento…

Configurar os seus domínios

Para cada domínio, defina os servidores de nomes, a ligação ao seu alojamento e quem fica como titular.

A carregar os seus domínios…