As dicas que serão encontradas nesse artigo também poderiam ser válidas para o Docker puro mas como a linha de comando acaba ficando muito grande é raro que utilizem diretamente por ela. São dicas simples e conceitos interessantes utilizados mais no docker-compose do que na commandline.
Sumário
Comandos de healthcheck
Esse é um recurso fundamental que define condições de existência do contêiner. Uma ferramenta deve validar se o contêiner está ok e o Docker fará uso dessa ferramenta (ou linha de comando). Além disso há parâmetros como o intervalo entre as verificações, retentativas em caso de falha, a partir de quando começa e qual é o timeout. Veja o docker-compose.yml com o healthcheck.
services: web: build: app/aspnetapp ports: - 80:80 db: environment: ACCEPT_EULA: "Y" SA_PASSWORD: example_123 image: mcr.microsoft.com/azure-sql-edge:1.0.4 restart: always healthcheck: test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P example_123 -Q 'SELECT 1' || exit 1"] interval: 10s retries: 10 start_period: 10s timeout: 3s
Service_healthy
É possível indicar que o contêiner tem como dependência a sua saúde. Esse é um item muito relevante que se conecta diretamente com a ideia do healthcheck. Utiliza-se assim:
# Desse modo o backend depende do serviço db estar saudável, caso contrário ele também estará falho services: backend: depends_on: db: condition: service_healthy
Context e target
Em muitos casos o docker-compose carrega informações sobre uma imagem que se deseja dar build e não apenas de uma imagem pronta. Nesse caso basta adicionar uma entrada para build: imagem. Entretanto é possível ser mais específico, como no exemplo a seguir.
services: web: build: context: angular target: builder ports: - 4200:4200 volumes: - ./angular:/project - /project/node_modules
Context -> é a pasta onde está o dockerfile em questão
Target -> qual será o estágio a ser gerado no multistage building
Veja o dockerfile do cenário
# syntax=docker/dockerfile:1.4 FROM --platform=$BUILDPLATFORM node:17.0.1-bullseye-slim as builder RUN mkdir /project WORKDIR /project RUN npm install -g @angular/cli@13 COPY package.json package-lock.json ./ RUN npm ci COPY . . CMD ["ng", "serve", "--host", "0.0.0.0"] FROM builder as dev-envs RUN <<EOF apt-get update apt-get install -y --no-install-recommends git EOF RUN <<EOF useradd -s /bin/bash -m vscode groupadd docker usermod -aG docker vscode EOF COPY --from=gloursdocker/docker / / CMD ["ng", "serve", "--host", "0.0.0.0"]
Restart
É possível definir que o contêiner será reiniciado em algumas condições específicas. Esse recurso é importante para ambientes que não possuem um orquestrador (Docker Swarm ou Kubernets). Para mais informações consulte https://docs.docker.com/config/containers/start-containers-automatically/. Basicamente há quarto possíveis configurações para essa condição:
no -> Opção padrão. Nada acontece.
on-failure:n -> Após ocorrerem n falhas
always -> Sempre que ocorrer uma falha.
unless-stopped -> Igual ao always porém não reiniciando quando houver um stop manual no Docker.
Diferença entre Ports e Expose
A exposição de portas para consumo externo é algo natural e desejado quando se publica containers docker. Entretanto há uma questão que, por vezes, gera alguma confusão nas pessoas: qual é a diferença entre PORTS e EXPOSE.
PORTS é a exposição de uma porta do container para uma porta da maquina host. Ele tem um propósito de acesso externo.
EXPOSE é a exposição de uma porta para as maquinas linkadas ao conteiner em questão. Vale notar que esse parâmetro é irrelevante tendo carater apenas ilustrativo nas versões mais recentes do docker.
Uso do Dockerize
Não é incomum que na dependência entre contêineres seja necessário ter certeza se um deles efetivamente subiu ou não. O depends on não serve exatamente para isso: ele serve apenas para indicar a ordem de start dos containeres. A ferramenta dokerize segura o processo e não dá o ok para o Docker subir o próximo se os critérios configurados não estiverem validos.
Para usar o dockerize (https://github.com/jwilder/dockerize) é necessário criar um dockerfile que carregue essa dependência. O uso prático pode ser feito pelo dockerfile mas é mais fácil pelo docker-compose ao chamar essa imagem. Veja o exemplo a seguir:
# Dockerfile que baixa o dokerize RUN apt-get update && apt-get install -y wget ENV DOCKERIZE_VERSION v0.6.1 RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
# Esse é o entrypoint dentro do docker-compose.yml # substitua o 'docker-entrypoint.sh' pelo entrypoint que quiser. # Nesse caso uma maquina espera que o db esteja ativo na porta 3306, esperando por até 60s entrypoint: dokerize -wait tcp://db:3306 -timeout 60s docker-entrypoint.sh
Limites de recursos
Uma questão importante é a definição dos limites de consumo dos conteineres. Quando não há configuração que limite ele pode consumir 100% dos recursos do computador host. Para fazer a configuração é importante atentar-se às possibilidades: limits é o valor máximo, reservation é o valor mínimo caso seja necessário (se a maquina estiver consumindo menos do que isso, o recurso não fica preso); além disso é possível definir quantidade de CPU, RAM, Swap, memória para o Kernel, e outras particularidades. Para mais detalhes consulte https://docs.docker.com/config/containers/resource_constraints/. Veja a seguir um docker-compose.yml de exemplo.
services:
meuservico:
image: nginx
deploy:
resources:
limits:
cpus: 0.50
memory: 512M
reservations:
cpus: 0.25
memory: 128M
Para ver em tempo real como está a utilização dos recursos do docker utilize o comando:
docker stats
Utilizando Secrets
Há uma estrutura específica no Docker para lidar com tokens, senhas e outras informações sigilosas: essas são as secrets. São repositórios específicos que organizam e encriptam esses dados. Veja abaixo um exemplo do uso de secrets
services: backend: build: context: backend target: builder secrets: - db-password depends_on: db: condition: service_healthy db: image: mariadb:10-focal command: '--default-authentication-plugin=mysql_native_password' restart: always healthcheck: test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --password="$$(cat /run/secrets/db-password)" --silent'] interval: 3s retries: 5 start_period: 30s secrets: - db-password volumes: - db-data:/var/lib/mysql environment: - MYSQL_DATABASE=example - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password expose: - 3306 proxy: image: nginx volumes: - type: bind source: ./proxy/nginx.conf target: /etc/nginx/conf.d/default.conf read_only: true ports: - 80:80 depends_on: - backend volumes: db-data: secrets: db-password: file: db/password.txt
Esse é o arquivo ./db/password.txt
db-q5n2g
Ele atua/atuou como Dev Full Stack C# .NET / Angular / Kubernetes e afins. Ele possui certificações Microsoft MCTS (6x), MCPD em Web, ITIL v3 e CKAD (Kubernetes) . Thiago é apaixonado por tecnologia, entusiasta de TI desde a infância bem como amante de aprendizado contínuo.