https://www.udemy.com/curso-docker/learn/v4/overview
"No curso você aprenderá os principais conceitos do Docker com vários exercícios práticos, todos descritos detalhadamente na apostila que será disponibilizada no curso. Tudo que for ministrado no curso estará disponível na apostila, e ter esse suporte a mais, será um diferencial fantástico."
- Seção: 1 - Introdução (5)
- Seção: 2 - Conceitos (6)
- Seção: 3 - Instalação (4)
- Seção: 4 - Uso Básico do Docker (14)
- Seção: 5 - Deixando de Ser Apenas um Usuário (11)
- Seção: 6 - Redes (4)
- Seção: 7 - Coordenando Múltiplos Containers (2)
- Seção: 8 - Projeto Cadastro Simples (3)
- Seção: 9 - Projeto para Envio de E-mails com Workers (11)
É uma ferramenta que se apoia em recursos existentes no kernel, inicialmente Linux, para isolar a execução de processos. As ferramentas que o Docker traz são basicamente uma camada de administração de containers, baseado originalmente no LXC.
Alguns isolamentos possíveis:
- Limites de uso de memória
- Limites de uso de CPU
- Limites de uso de I/O
- Limites de uso de rede
- Isolamento da rede (que redes e portas são acessíveis)
- Isolamento do file system
- Permissões e Políticas
- Capacidades do kernel
Podemos concluir dizendo que estes recursos já existiam no kernel a um certo tempo, o que o Docker nos trouxe foi uma maneira simples e efetiva de utiliza-los.
Containers Docker empacotam componentes de software em um sistema de arquivos completo, que contêm tudo necessário para a execução: código, runtime, ferramentas de sistema - qualquer coisa que possa ser instalada em um servidor.
Isto garante que o software sempre irá executar da mesma forma, independente do seu ambiente.
O Docker tende a utilizar menos recursos que uma VM tradicional, um dos motivos é não precisar de uma pilha completa como vemos em Comparação VMs × Containers. O Docker utiliza o mesmo kernel do host, e ainda pode compartilhar bibliotecas.
Mesmo utilizando o mesmo kernel é possível utilizar outra distribuição com versões diferentes das bibliotecas e aplicativos.
Virtual Machine (máquina virtual), recurso extremamente usado atualmente para isolamento de serviços, replicação e melhor aproveitamento do poder de processamente de uma máquina física.
Devo trocar então minha VM por um container? Nem sempre, os containers Docker possuem algumas limitações em relação as VMs:
- Todas as imagens são linux, apesar do host poder ser qualquer SO que use ou emule um kernel linux, as imagens em si serão baseadas em linux.
- Não é possível usar um kernel diferente do host, o Docker Engine estará executando sob uma determinada versão (ou emulação) do kernel linux, e não é possível executar uma versão diferente, pois as imagens não possuem kernel.
Container é o nome dado para a segregação de processos no mesmo kernel, de forma que o processo seja isolado o máximo possível de todo o resto do ambiente.
Em termos práticos são File Systems, criados a partir de uma "imagem" e que podem possuir também algumas características próprias.
Uma imagem Docker é a materialização de um modelo de um sistema de arquivos, modelo este produzido através de um processo chamado build.
Esta imagem é representada por um ou mais arquivos e pode ser armazenada em um repositório.
Docker File Systems
O Docker utiliza file systems especiais para otimizar o uso, transferência e armazenamento das imagens, containers e volumes.
O principal é o AUFS, que armazena os dados em camadas sobrepostas, e somente a camada mais recente é gravável.
- https://pt.wikipedia.org/wiki/Aufs
- https://docs.docker.com/engine/userguide/storagedriver/aufs-driver/
De maneira simplificada podemos dizer que o uso mais básico do Docker consiste em:
- Ter o serviço Docker Engine rodando
- Ter acesso a API Rest do Docker Engine, normalmente através do Docker Client
- Baixar uma imagem do Docker Registry, normalmente do registry público oficial: https://hub.docker.com
- Instanciar um container a partir da imagem baixada
Figura 2. Arquitetura do Docker
A primeira versão do Docker é de 13 de março de 2013, tendo um pouco mais de 4 anos (na epóca que este curso foi escrito).
Nestes 4 anos ele tem se tornado cada vez mais popular e uma solução real para desenvolvedores (manter o seu ambiente mais simples e próximo à produção), administradores de sistema e ultimamente para uso enterprise, sendo avaliado pelos principais players do mercado uma alternativa mais econômica em relação as soluções atuais. Em sua maioria virtualização.
- Instalação (Linux, Microsoft Windows e MacOS)
- Uso do Docker Machine
- Uso do Docker na nuvem, Amazon, possivelmente outros
Conforme vimos em Arquitetura, o Docker Engine expõe uma API Rest que pode ser consumida pelas mais diversas ferramentas. A ferramenta inicial fornecida com a própria engine é o Docker Client, utilitário de linha de comando.
Vamos confirmar o funcionamento do nosso Docker.
# docker container run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Na documentação oficial, o passo para verificação da instalação é este Hello World, porém até a publicação deste curso a documentação ainda utilizava a sintaxe antiga: docker run hello-world
Testar correto funcionamento do Docker, incluindo a recuperação de imagens e execução de containers.
O comando run é a nossa porta de entrada no Docker, agrupando diversas funcionalidades básicas, como:
- Download automático das imagens não encontradas: docker image pull
- Criação do container: docker container create
- Execução do container: docker container start
- Uso do modo interativo: docker container exec
A partir da versão 1.13, o Docker reestruturou toda a interface da linha de comando, para agrupar melhor os comandos por contexto.
Apesar dos comandos antigos continuarem válidos, o conselho geral é adotar a nova sintaxe.
Até a versão 17.03 (corrente na publicação do curso), ainda é possível utilizarmos a sintaxe antiga, porém precisamos pensar nela como atalhos:
docker pull
docker image pull
docker create
docker container create
docker start
docker container start
docker exec
docker container exec
Podemos usar containers em modo interativo, isto é extremamente útil para processos experimentais, estudo dinâmico de ferramentas e de desenvolvimento.
Exemplos de Uso
- Avaliação do comportamento ou sintaxe de uma versão específica de linguagem.
- Execução temporária de uma distribuição linux diferente
- Execução manual de um script numa versão diferente de um interpretador que não a instalada no host.
Principais opções do Docker para este fim
- docker container run -it
- docker container start -ai
- docker container exec -t
Exercício 2 - Ferramentas diferentes
# bash --version
GNU bash, version 4.4.19(1)-release (x86_64-alpine-linux-musl)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
# docker container run debian bash --version
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
f606d8928ed3: Pull complete
Digest: sha256:e538a2f0566efc44db21503277c7312a142f4d0dedc5d2886932b92626104bff
Status: Downloaded newer image for debian:latest
GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Confirmar que o conjunto de ferramentas disponíveis em um container são diferentes das disponíveis no host.
Exercício 3 - run cria sempre novos containers
# docker container run -it debian bash
root@53a6df47194e:/# touch /curso-docker.txt
root@53a6df47194e:/# exit
exit
# docker container run -it debian bash
root@85d396adffcf:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@85d396adffcf:/# ls /curso-docker.txt
ls: cannot access '/curso-docker.txt': No such file or directory
Demonstrar que o run sempre irá instanciar um novo container. Como vimos em Docker File Systems, o container e a imagem são armazenados em camadas, o processo de instanciar um container basicamente cria uma nova camada sobre a imagem existente, para que nessa camada as alterações sejam aplicadas.
Assim sendo o consumo de espaço em disco para instanciar novos containers é relativamente muito baixo.
Exercício 4 - Containers devem ter nomes únicos
# docker container run --name mydeb -it debian bash
root@b6b62dbe8453:/# exit
exit
# docker container run --name mydeb -it debian bash
docker: Error response from daemon: Conflict. The container name "/mydeb" is already in use by container "b6b62dbe84539c2dd13a5feddf9bd29682b0d5913cf18694396428fc3f8bbbb3". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
Exercício 5 - Reutilizar containers
# docker container start -ai mydeb
root@b6b62dbe8453:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@b6b62dbe8453:/# touch /curso-docker.txt
root@b6b62dbe8453:/# ls
bin curso-docker.txt etc lib media opt root sbin sys usr
boot dev home lib64 mnt proc run srv tmp var
root@b6b62dbe8453:/# exit
exit
# docker container start -ai mydeb
root@b6b62dbe8453:/# ls /curso-docker.txt
/curso-docker.txt
root@b6b62dbe8453:/# exit
exit
Demonstrar o uso do start em modo interativo, reutilizando um container previamente criado, além de confirmar que o mesmo consegue reter modificações em seu file system.
Remover depois que executar (não salav na lista de containers) -> --rm
# docker container ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b6b62dbe8453 debian "bash" 3 minutes ago Exited (0) 51 seconds ago mydeb
85d396adffcf debian "bash" 6 minutes ago Exited (127) 3 minutes ago nice_gates
53a6df47194e debian "bash" 7 minutes ago Exited (0) 6 minutes ago vigorous_varahamihira
831a32f8c858 debian "bash --version" 8 minutes ago Exited (0) 8 minutes ago fervent_wright
# docker container run --rm debian bash --version
GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
# docker container ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b6b62dbe8453 debian "bash" 5 minutes ago Exited (0) 2 minutes ago mydeb
85d396adffcf debian "bash" 8 minutes ago Exited (127) 5 minutes ago nice_gates
53a6df47194e debian "bash" 8 minutes ago Exited (0) 8 minutes ago vigorous_varahamihira
831a32f8c858 debian "bash --version" 9 minutes ago Exited (0) 9 minutes ago fervent_wright
Um container normalmente roda com o máximo de isolamento possível do host, este isolamento é possível através do Docker Engine e diversas características provídas pelo kernel.
Mas normalmente não queremos um isolamento total, e sim um isolamento controlado, em que os recursos que o container terá acesso são explicitamente indicados. Principais recursos de controle do isolamento
- Mapeamento de portas
- Mapeamento de volumes
- Copia de arquivos para o container ou a partir do container
- Comunicação entre os containers
É possível mapear tanto portas TCP como UDP diretamente para o host, permitindo acesso através de toda a rede, não necessitando ser a mesma porta do container. O método mais comum para este fim é o parâmetro -p no comando docker container run, o -p recebe um parâmetro que normalmente é composto por dois números separados por : (dois pontos). O primeiro é no host e o segundo é no container
# docker container run -p 8080:80 nginx
172.17.0.1 - - [18/Octo/2022:19:31:00 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)
2022/10/18 19:31:01 [error] 9#9: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "localhost:8080", referrer: "http://localhost:8080/"
172.17.0.1 - - [18/Octo/2022:19:31:01 +0000] "GET /favicon.ico HTTP/1.1" 404 556 "http://localhost:8080/" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ...
Mapeamento de portas
- Acessar a url http://localhost:8080 por um browser
- Receber a mensagem: Welcome to nginx no browser
- Verificar o log de acesso no terminal executando
- Tentar acessar a url http://localhost ou http://localhost:80
- Receber um erro do browser
- Parar a execução do container
É possível mapear tanto diretórios no host como entidades especiais conhecidas como volumes para diretórios no container. Por enquanto vamos nos concentrar no mapeamento mais simples, uma diretório no host para um diretório no container. O método mais comum para este fim é o parâmetro -v no comando docker container run, o -v recebe um parâmetro que normalmente é composto por dois caminhos absolutos separados por : (dois pontos). Assim como diversos outros parâmetros, o primeiro é no host e o segundo é no container.
O trecho do comando chamado "pwd". Esse comando retorna o caminho atual da pasta onde o terminal está localizado. Porém, esse "pwd" não irá funcionar em todos os terminais ou sistemas operacionais. Caso não funcione será necessário utilizar o comando absoluto da pasta em questão. Ou seja, algo como "c/users/SeuNome/docker", variando com a localização da pasta em questão.
Exercício 7 - Mapear diretórios para o container
# docker container run -p 8080:80 -v $(pwd)/html:/usr/share/nginx/html nginx
2022/10/18 20:34:49 [error] 9#9: *2 "/usr/share/nginx/html/index.html" is forbidden (13: Permission denied), client: 172.17.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost:8080"
172.17.0.1 - - [18/Octo/2022:20:34:49 +0000] "GET / HTTP/1.1" 403 556 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)
# docker container run -p 8080:80 -v $(pwd)/html:/usr/share/nginx/html:Z nginx
172.17.0.1 - - [18/Octo/2022:20:36:37 +0000] "GET / HTTP/1.1" 200 287 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)
*(:Z dá permissão de escrita a pasta) 👈
Mapeamento de volumes
- Executar o run.sh
- Acessar a url http://localhost:8080 por um browser
- Receber o erro: 403 Forbidden
- Verificar o log de acesso no terminal executando
- Parar a execução do container
- Executar o run-alt.sh (que mapea o diretório com o index.html)
- Tentar acessar a url http://localhost:8080
- Receber o texto: Hello World
- Bônus: Editar o html/index.html a partir de um editor de textos e atualizar o browser
- Parar a execução do container
Agora sim, aonde o Docker começa a brilhar!
Antes de conhecer opções mais avançadas de compartilhamento de recursos, isolamento, etc, precisamos entender como rodar os containers em background. O parâmetro -d do docker container run indica ao Docker para iniciar o container em background (modo daemon).
Para entender melhor estes containers precisaremos conhecer um novo comando: docker container ps, que lista containers em execução.
Exercício 8 - Rodar um servidor web em background
# docker container run -d --name ex-daemon-basic -p 8080:80 -v $(pwd)/html:/usr/share/nginx/html:Z nginx
ex-daemon-basic,nginx
Up 28 seconds, PORTA: 0.0.0.0:8080->80/tcp
# docker container stop ex-daemon-basic
ex-daemon-basic
Execução em background
- Levanta o container em background
- Tentar acessar a url http://localhost:8080 via browser
- Receber o texto: Hello World
- Verificar os containers em execução
Exercício 9 - Gerenciar o container em background
# docker container restart ex-daemon-basic
# docker container stop ex-daemon-basic
# docker container start ex-daemon-basic
Reiniciar, parar e iniciar
- Reinicia o container e verifica que acabou de iniciar pelo tempo do status
- Para o container e através do docker container ps vemos que não está mais em execução
- Podemos também tentar acessar pelo browser a url http://localhost:8080, confirmando que não responde mais
- Inicia novamente o container, um observação importante é que não é mais necessário configurar os mapeamentos
- Verificar os containers em execução, também é possível confirmar a execução pelo browser.
Existem diversos comandos que nos ajuda a acompanhar a execução dos containers, entre eles:
- docker container ls
- docker container ls -a
- docker container inspect
- docker container exec
- docker container logs
Vários comandos Docker possuem aliases, por exemplo o container ls tem os seguintes apelidos:
- docker container list
- docker container ps
- docker ps (antiga sintaxe)
Agora que já vimos diversos comandos, incluindo tanto a sintaxe nova quanto a velha, podemos entender os principais motivos para esta mudança e a preferência pela nova sintaxe:
- Melhor utilização de comandos similares em contextos diferentes:
- docker container ls
- docker image ls
- docker volume ls
- Maior clareza nos comandos:
- docker container rm ao invés de docker rm
- docker image rm ao inveś de docker rmi
- docker image ls ao invés de docker images
- Mais simplicidade para criação de novos subcomandos
- Segregação da documentação e helps por contexto
Agora vamos ao conceitos necessários para deixar de apenas utilizar imagens prontas e começar a produzir nossas próprias imagens.
Exemplos de uso
- DevOps - Imagens para processos de integração contínua
- Portabilidade - Imagens de aplicação para ser utilizada em todos os ambientes (staging, prodution, etc)
- Desenvolvimento - Imagens que aproximam todos os devs do ambiente de produção e diminuem a curva de entrada de novos membros
- Imagens customizadas a partir de imagens públicas
Utilizando uma analogia com OOP, podemos comparar um container a um objeto (instância), enquanto a imagem seria uma classe (modelo).
Todos os subcomandos relativos ao container podem ser listados através do parâmetro --help, bem como imagens:
- docker container --help
- docker image --help
Toda imagem (bem como os containers) possuem um identificador único em formato hash usando sha256. Porém seu uso não é muito prático, então para simplificar isto o docker utiliza uma tag para identificar imagens.
A tag normalmente é formada por um nome, seguido de : dois pontos e depois uma versão. É extremamente comum utilizar uma versão chamada latest para representar a versão mais atual.
Exemplos de tags de imagens:
- nginx:latest
- redis:3.2
- redis:3
- postgres:9.5
Na prática uma tag é apenas um ponteiro para o hash da imagem, e várias tags podem apontar para o mesmo hash. Com isto é comum o uso de alguns apelidos nas tags, tomando como exemplo as imagens oficiais do redis. Existem 10 imagens e 30 tags.
Tags do redis
- 3.0.7, 3.0
- 3.0.7-32bit, 3.0-32bit
- 3.0.7-alpine, 3.0-alpine
- 3.0.504-windowsservercore, 3.0-windowsservercore
- 3.0.504-nanoserver, 3.0-nanoserver
- 3.2.8, 3.2, 3, latest
- 3.2.8-32bit, 3.2-32bit, 3-32bit, 32bit
- 3.2.8-alpine, 3.2-alpine, 3-alpine, alpine
- 3.2.100-windowsservercore, 3.2-windowsservercore
- 3-windowsservercore, windowsservercore
- 3.2.100-nanoserver, 3.2-nanoserver, 3-nanoserver, nanoserver
fonte: https://hub.docker.com/_/redis/
# docker image pull redis:latest
latest: Pulling from library/redis
bd159e379b3b: Already exists
729b630784ac: Pull complete
065c77bf222a: Pull complete
961784053f68: Pull complete
b42f16846808: Pull complete
0f1fa5bb0033: Pull complete
Digest: sha256:c95835a74c37b3a784fb55f7b2c211bd20c650d5e55dae422c3caa9c01eb39fa
Status: Downloaded newer image for redis:latest
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest f8528f17261c 2 weeks ago 117MB
# docker image tag redis:latest redis-claudiomendonca
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest f8528f17261c 2 weeks ago 117MB
redis-claudiomendonca latest f8528f17261c 2 weeks ago 117MB
# docker image rm redis:latest redis-claudiomendonca
Untagged: redis:latest
Untagged: redis@sha256:c95835a74c37b3a784fb55f7b2c211bd20c650d5e55dae422c3caa9c01eb39fa
Untagged: redis-claudiomendonca:latest
Deleted: sha256:f8528f17261c4a2c94ef702ff483ba7e4b998aa734cba60fa689ca5ecc14705f
Deleted: sha256:ee56963c6d7b3a0282a5fa661ff94f9d85cee3c52058246ed243af49e724a55a
Deleted: sha256:716572502758d2842fc9a1f4211a54c649babfdaea435e3f30b9b5aaf87cb06d
Deleted: sha256:e44a83ab8337d6a95fcad0c1d250366c4079759ae5be8f6ce321dc4ea613217f
Deleted: sha256:4267b0eb985fc1c59e8f523eb77202c30a6504d86186b1377d22e736061b321c
Deleted: sha256:fc24995fdc7260d59418714deda07229a703bca3d64f6f19c7ade1e3c0fb2d55
Já usamos de maneira implícita o recurso de download de imagens docker, agora vamos entender melhor o gerenciamento de imagens.
docker image pull
Baixa a imagem solicitada, este comando pode ser executado implicitamente, quando o docker precisa de uma imagem para outra operação e não consegue localiza-la no cache local.
docker image ls
Lista todas as imagens já baixadas, é possível ainda usar a sintaxe antiga: docker images
docker image rm
Remove uma imagem do cache local, é possível ainda usar a sintaxe antiga: docker rmi
docker image inspect
Extrai diversas informações utilizando um formato JSON da imagem indicada.
docker image tag
Cria uma nova tag baseada em uma tag anterior ou hash.
docker image build -t
Permite a criação de uma nova imagem, como veremos melhor em build.
docker image push
Permite o envio de uma imagem ou tag local para um registry.
Docker Registry
É uma aplicação server side para guardar e distribuir imagens Docker.
Docker Hub
É uma serviço de registro de imagens Docker em nuvem, que permite a associação com repositórios para build automatizado de imagens. Imagens marcadas como oficiais no Docker Hub, são criadas pela própria Docker Inc. E o código fonte pode ser encontrado em:
A linha de comando possui o comando docker search para procurar imagens no Docker Hub.
Processo para gerar uma nova imagem a partir de um arquivo de instruções. O comando docker build é o responsável por ler um Dockerfile e produzir uma nova imagem Docker.
Dockerfile
Nome default para o arquivo com instruções para o build de imagens Docker. Documentação do Dockerfile — https://docs.docker.com/engine/reference/builder
# docker image build -t ex-simple-build .
[+] Building 1.0s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 122B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/nginx:1.13 0.0s
=> [1/2] FROM docker.io/library/nginx:1.13 0.2s
=> [2/2] RUN echo '<h1>Hello World !</h1>' > /usr/share/nginx/html/index.html 0.5s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:250bdd713c909deb323989c4572297d5f8a73eb5e8ba117d9752d86c 0.0s
=> => naming to docker.io/library/ex-simple-build 0.0s5
Status: Downloaded newer image for docker.io/nginx:1.13
---> ae513a47849c
Step 2/2 : RUN echo '<h1>Hello World !</h1>' > /usr/share/nginx/html/index.html
---> Running in 65d04840a156
---> 74f08697b0a1
Removing intermediate container 65d04840a156
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ex-simple-build latest 250bdd713c90 2 minutes ago 109MB
# docker container run -p 8080:80 ex-simple-build
172.17.0.1 - - [19/Oct/2022:21:54:11 +0000] "GET / HTTP/1.1" 200 23 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36" "-"
Exemplo básico de um build e sua execução.
O comando build exige a informação do diretório aonde o build será executado bem como aonde o arquivo de instruções se encontra
FROM
Especifica a imagem base a ser utilizada pela nova imagem.
LABEL
Especifica vários metadados para a imagem como o mantenedor. A especificação do mantenedor era feita usando a instrução específica, MAINTAINER que foi substituída pelo LABEL.
ENV
Especifica variáveis de ambiente a serem utilizadas durante o build.
ARG
Define argumentos que poderão ser informados ao build através do parâmetro --build-arg.
FROM debian
LABEL maintainer 'Claudio Mendonça. <contato@claudiomendonca.eng.br>'
ARG S3_BUCKET=files
ENV S3_BUCKET=${S3_BUCKET}
# docker image build -t ex-build-args .
[+] Building 0.2s (5/5) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 175B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/debian:latest 0.0s
=> [1/1] FROM docker.io/library/debian 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:3ee35ed74a5dd27593c2c8c2b1485ecf040220e8a523a9a48d31e0ed 0.0s
=> => naming to docker.io/library/ex-build-args 0.0s
# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ex-build-args latest 3ee35ed74a5d 2 weeks ago 124MB
ex-simple-build latest 250bdd713c90 10 minutes ago 109MB
# docker container run ex-build-args bash -c 'echo $S3_BUCKET'
files
# docker image build --build-arg S3_BUCKET=myapp -t ex-build-arg .
[+] Building 0.2s (5/5) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 32B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/debian:latest 0.0s
=> CACHED [1/1] FROM docker.io/library/debian 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:0bdabbed8392aa154cdc930419c71af591984bec76d768a348ad066c 0.0s
=> => naming to docker.io/library/ex-build-arg 0.0s
# docker container run ex-build-arg bash -c 'echo $S3_BUCKET'
myapp
# docker image inspect --format="{{index .Config.Labels \"maintainer\"}}" ex-build-args
Claudio Mendonça. <contato@claudiomendonca.eng.br>
COPY
Copia arquivos e diretórios para dentro da imagem.
ADD
Similar ao anterior, mas com suporte extendido a URLs. Somente deve ser usado nos casos que a instrução COPY não atenda.
RUN
Executa ações/comandos durante o build dentro da imagem
Exercício 12 - Uso das instruções de povoamento
FROM nginx:1.13
LABEL maintainer 'Juracy Filho <juracy at gmail.com>'
RUN echo '<h1>Sem conteúdo</h1>' > /usr/share/nginx/html/conteudo.html
COPY *.html /usr/share/nginx/html/
# docker image build -t ex-build-copy .
[+] Building 0.9s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 230B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/nginx:1.13 0.0s
=> CACHED [1/3] FROM docker.io/library/nginx:1.13 0.0s
=> [internal] load build context 0.1s
=> => transferring context: 413B 0.0s
=> [2/3] RUN echo '<h1>Sem conteúdo</h1>' > /usr/share/nginx/html/conteudo.html 0.5s
=> [3/3] COPY *.html /usr/share/nginx/html/ 0.1s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:9fe5a71b4b7809f91838ac6912eed50b845c2aa33ce2d48bc28b054b 0.0s
=> => naming to docker.io/library/ex-build-copy 0.0s
# docker container run -p 8080:80 ex-build-copy
172.17.0.1 - - [19/Oct/2022:22:21:03 +0000] "GET / HTTP/1.1" 200 374 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36" "-"
EXPOSE
Informa ao Docker que a imagem expõe determinadas portas remapeadas no container. A exposição da porta não é obrigatória a partir do uso do recurso de redes internas do Docker. Recurso que veremos em Coordenando múltiplos containers. Porém a exposição não só ajuda a documentar como permite o mapeamento rápido através do parâmetro -P do docker container run.
WORKDIR
Indica o diretório em que o processo principal será executado.
ENTRYPOINT
Especifica o processo inicial do container.
CMD
Indica parâmetros para o ENTRYPOINT.
USER
Especifica qual o usuário que será usado para execução do processo no container (ENTRYPOINT e CMD) e instruções RUN durante o build.
VOLUME
Instrui a execução do container a criar um volume para um diretório indicado e copia todo o conteúdo do diretório na imagem para o volume criado. Isto simplificará no futuro, processos de compartilhamento destes dados para backup por exemplo.
Exercício 13 - Uso das instruções para execução do container
FROM python:3.6
LABEL maintainer 'José Malcher JR. <contato@josemalcher.net>'
RUN useradd www && \
mkdir /app && \
mkdir /log && \
chown www /log
USER www
VOLUME /log
WORKDIR /app
EXPOSE 8000
ENTRYPOINT ["/usr/local/bin/python"]
CMD ["run.py"]
# docker image build -t ex-build-dev .
[+] Building 75.1s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 320B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3.6 2.6s
=> [auth] library/python:pull token for registry-1.docker.io 0.0s
=> [1/3] FROM docker.io/library/python:3.6@sha256:f8652afaf88c25f0d22354d547d892591067aa4026a7fa9a6819 66.4s
=> => resolve docker.io/library/python:3.6@sha256:f8652afaf88c25f0d22354d547d892591067aa4026a7fa9a6819d 0.0s
=> => sha256:f8652afaf88c25f0d22354d547d892591067aa4026a7fa9a6819df9f300af6fc 1.86kB / 1.86kB 0.0s
=> => sha256:d097a4907a8ec079df5ac31872359c2de510f82214c0448e926393b376d3b60d 2.22kB / 2.22kB 0.0s
=> => sha256:0e29546d541cdbd309281d21a73a9d1db78665c1b95b74f32b009e0b77a6e1e3 54.92MB / 54.92MB 22.8s
=> => sha256:54260638d07c5e3ad24c6e21fc889abbc8486a27634c0892086ff71f3f44b104 9.27kB / 9.27kB 0.0s
=> => sha256:9b829c73b52b92b97d5c07a54fb0f3e921995a296c714b53a32ae67d19231fcd 5.15MB / 5.15MB 3.2s
=> => sha256:cb5b7ae361722f070eca53f35823ed21baa85d61d5d95cd5a95ab53d740cdd56 10.87MB / 10.87MB 3.8s
=> => sha256:6494e4811622b31c027ccac322ca463937fd805f569a93e6f15c01aade718793 54.57MB / 54.57MB 21.8s
=> => sha256:6f9f74896dfa93fe0172f594faba85e0b4e8a0481a0fefd9112efc7e4d3c78f7 196.51MB / 196.51MB 41.2s
=> => sha256:5e3b1213efc56598e78bd602983945c164de2a37205e06a62dada823124dc743 6.29MB / 6.29MB 26.2s
=> => sha256:9fddfdc56334f2e6efad7e241bf5e7459c40ed105c5478676f41c1244bd96752 14.21MB / 14.21MB 26.8s
=> => extracting sha256:0e29546d541cdbd309281d21a73a9d1db78665c1b95b74f32b009e0b77a6e1e3 16.6s
=> => sha256:404f02044bac0432ca522cbb9f254b1c91fcea6806bfeef0be0b243b2f31bab7 235B / 235B 26.8s
=> => sha256:c4f42be2be53b900ebffc040c1df13de538434ccc5f5d954a56848a6169a3a3f 2.21MB / 2.21MB 28.5s
=> => extracting sha256:9b829c73b52b92b97d5c07a54fb0f3e921995a296c714b53a32ae67d19231fcd 0.6s
=> => extracting sha256:cb5b7ae361722f070eca53f35823ed21baa85d61d5d95cd5a95ab53d740cdd56 0.5s
=> => extracting sha256:6494e4811622b31c027ccac322ca463937fd805f569a93e6f15c01aade718793 5.1s
=> => extracting sha256:6f9f74896dfa93fe0172f594faba85e0b4e8a0481a0fefd9112efc7e4d3c78f7 14.8s
=> => extracting sha256:5e3b1213efc56598e78bd602983945c164de2a37205e06a62dada823124dc743 0.5s
=> => extracting sha256:9fddfdc56334f2e6efad7e241bf5e7459c40ed105c5478676f41c1244bd96752 1.1s
=> => extracting sha256:404f02044bac0432ca522cbb9f254b1c91fcea6806bfeef0be0b243b2f31bab7 0.0s
=> => extracting sha256:c4f42be2be53b900ebffc040c1df13de538434ccc5f5d954a56848a6169a3a3f 0.5s
=> [2/3] RUN useradd www && mkdir /app && mkdir /log && chown www /log 5.6s
=> [3/3] WORKDIR /app 0.1s
=> exporting to image 0.2s
=> => exporting layers 0.1s
=> => writing image sha256:345ac8f24cbbcc996f9deebc607481a0a768a040d4cd2e8169e4abda7ad6b6fd 0.0s
=> => naming to docker.io/library/ex-build-dev 0.0s
# docker container run -it -v $(pwd):/app:Z -p 8080:8000 --name python-server ex-build-dev
inicializando...
escutando a porta: 8000
usuário: www
172.17.0.1 - - [19/Oct/2022 22:31:20] "GET / HTTP/1.1" 200 -
# docker container run -it --volumes-from=python-server debian cat /log/http-server.log
2022-10-19 22:30:26,763 - INFO - inicializando...
2022-10-19 22:30:26,764 - INFO - escutando a porta: 8000
2022-10-19 22:30:26,765 - INFO - usuário: www
2022-10-19 22:31:20,686 - INFO - 172.17.0.1 - - [19/Oct/2022 22:31:20] "GET / HTTP/1.1" 200 -
2022-10-19 22:31:20,703 - INFO - 172.17.0.1 - - [19/Oct/2022 22:31:20] "GET / HTTP/1.1" 200 -
Neste exemplo temos um pequeno servidor web atendendo na porta 8000 e exposta via instrução EXPOSE.
Também temos o uso do ENTRYPOINT e CMD definindo exatamente que processo será executado ao subir o container, podemos notar que o container consegue encontrar o run.py, por conta da instrução WORKDIR que define o diretório aonde o processo principal será executado.
Ao executar o container, uma das informações colocados no log (stdout e arquivo em disco) é o usuário corrente, e podemos notar que o processo não está rodando como root e sim www, conforme foi definido pela instrução USER.
Por último temos o comando VOLUME que instrui o docker a expor o diretório /log como um volume, que pode ser facilmente mapeado por outro container. Podemos verificar isto seguindo os seguintes passos:
- Construir a imagem e executar o container: run.sh
- Acessar a URL http://localhost:8000 via browser
- Verificar o log gerado na saída do container criado
- Criar e rodar um segundo container mapeando os volumes do primeiro e checar o arquivo de log: docker run -it --volumes-from= debian cat /log/http-server.log
- Importante substituir a referência do volumes_from pelo hash do primeiro container criado
- O resultado do cat será o mesmo log já gerado pelo primeiro container
# docker image tag img-exemplo claudio/img-exemplo:1.0
// Login
# docker login --username=claudio
Password:
# docker image push claudio/img-exemplo:1.0
# docker network ls
NETWORK ID NAME DRIVER SCOPE
01d182c53758 bridge bridge local
b709d632246d host host local
f835sw4c2415 node-mogo-compose_default bridge local
c8a9baq37245 none null local
# docker container run --rm alpine ash -c "ifconfig"
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
213ec9aee27d: Already exists
Digest: sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad
Status: Downloaded newer image for alpine:latest
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:180 (180.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# docker container run --rm --net none alpine ash -c "ifconfig"
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "3981e00224758dfbf4dc3a6dwdwfw222e9848e5f8356e49726488e67a73bb8809",
"Created": "2022-10-17T12:10:47.3672611Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16", # <<<<---------------------------------------------------------------------------
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
# docker container run -d --name container01 alpine sleep 1000
dd69565f557a89b17e720......
# docker container exec -it container01 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 # <<<<<<<<------------------------------------------------
inet6 addr: fe10::33:acfd:f211:4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:52 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:6862 (6.7 KiB) TX bytes:656 (656.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# docker container run -d --name container02 alpine sleep 1000
8eeb554082442929d0dba9423........
# docker container exec -it container02 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0 # <<<<<<<<------------------------------------------------
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:27 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:4032 (3.9 KiB) TX bytes:586 (586.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# docker container exec -it container01 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.099 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.139 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.180 ms
--- 172.17.0.3 ping statistics ---
6 packets transmitted, 6 packets received, 0% packet loss
round-trip min/avg/max = 0.099/0.167/0.317 ms
- Criando uma nova REDE
# docker network create --driver bridge rede_nova
59be679c79e00a3........
# docker network ls
NETWORK ID NAME DRIVER SCOPE
3981e0022475 bridge bridge local
487332528d4f host host local
9847792b86b3 none null local
eb6c477e6bcf rede_nova bridge local
# docker network inspect rede_nova
[
{
"Name": "rede_nova",
"Id": "eb6c477e6bcfe08741c0b77f6df5a9e6003c24f726561731d59be679c79e00a3",
"Created": "2022-10-17T12:10:47.3672611Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16", # <<<<<<<<------------------------------------------------
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
# docker container run -d --name container03 --net rede_nova alpine sleep 1000
36064231927250b7acbedf17045......
# docker container exec -it container03 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:94 errors:0 dropped:0 overruns:0 frame:0
TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:11480 (11.2 KiB) TX bytes:726 (726.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# docker container exec -it container03 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
^C
--- 172.17.0.3 ping statistics ---
12 packets transmitted, 0 packets received, 100% packet loss
# docker network connect bridge container03
# docker container exec -it container03 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.098 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.222 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.189 ms
^C
--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.098/0.169/0.222 ms
# docker container exec -it container03 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:139 errors:0 dropped:0 overruns:0 frame:0
TX packets:24 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:15509 (15.1 KiB) TX bytes:2084 (2.0 KiB)
eth1 Link encap:Ethernet HWaddr 02:42:AC:11:00:04
inet addr:172.17.0.4 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:44 errors:0 dropped:0 overruns:0 frame:0
TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:5967 (5.8 KiB) TX bytes:1104 (1.0 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# docker network disconnect bridge container03
# docker container exec -it container03 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:183 errors:0 dropped:0 overruns:0 frame:0
TX packets:24 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:18125 (17.7 KiB) TX bytes:2084 (2.0 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Modo mais inseguro.
# ifconfig
br-xxxxxxxxxxxxx: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.18.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether XX:4X:X7:X8:ac:7X txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether XX:4X:X7:X8:ac:7X txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp1s0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether XX:4X:X7:X8:ac:7X txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueudelen 1000 (Loopback Local)
RX packets 936 bytes 82309 (80.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 936 bytes 82309 (80.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether XX:4X:X7:X8:ac:7X txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wlp0s29u1u3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.102 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fxx0::xx8f:fxx4:bxxd:8f96 prefixlen 64 scopeid 0x20<link>
ether XX:4X:X7:X8:ac:7X txqueuelen 1000 (Ethernet)
RX packets 1026597 bytes 1437469887 (1.3 GiB)
RX errors 0 dropped 54 overruns 0 frame 0
TX packets 570844 bytes 71806063 (68.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wlp2s0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether XX:4X:X7:X8:ac:7X txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# docker container run -d --name container04 --net host alpine sleep 1000
7f8e17eef8e8d9e0645a307c481...............
# docker container exec -it container04 ifconfig
br-xxxxxxxxxxxxx Link encap:Ethernet HWaddr XX:4X:X7:X8:ac:7X
inet addr:172.18.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
docker0 Link encap:Ethernet HWaddr XX:4X:X7:X8:ac:7X
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
enp1s0 Link encap:Ethernet HWaddr XX:4X:X7:X8:ac:7X
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:967 errors:0 dropped:0 overruns:0 frame:0
TX packets:967 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:85037 (83.0 KiB) TX bytes:85037 (83.0 KiB)
virbr0 Link encap:Ethernet HWaddr XX:4X:X7:X8:ac:7X
inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
wlp0s29u1u3 Link encap:Ethernet HWaddr XX:4X:X7:X8:ac:7X
inet addr:192.168.0.102 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: dddd::2fff78f:xxxx:b35xxxd:8f96/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1026697 errors:0 dropped:54 overruns:0 frame:0
TX packets:570926 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1437499770 (1.3 GiB) TX bytes:71820982 (68.4 MiB)
wlp2s0 Link encap:Ethernet HWaddr E6:41:85:80:07:77
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Como já foi discutido um bom container Docker roda apenas um serviço, tendo um único processo principal, aplicações em geral são compostos por diversos processos específicos, como por exemplo:
- Banco de dados
- Gerenciamento de filas
- Servidor Web
- Aplicação em si
- Workers diversos
Estes serviços devem rodar cada qual em seu container. Porém carrega-los um a um, não só é enfadonho como propenso a erros, sejam eles:
- Sequência de inicialização
- Esquecimento de um dos serviços
- Parada e/ou reinicialização de um ou mais serviços
Para sanar este problema temos a disposição o docker-compose.
Antes de mergulharmos nos exemplos e comandos do docker-compose, vamos entender melhor o que são microsserviços.
A definition of this new architectural term
The term "Microservice Architecture" has sprung up over the last few years to describe a particular way of designing software applications as suites of independently deployable services. While there is no precise definition of this architectural style, there are certain common characteristics around organization around business capability, automated deployment, intelligence in the endpoints, and decentralized control of languages and data. — Martin Fowler, Microservices: https://martinfowler.com/articles/microservices.html
Segundo Martin Fowler, microsserviços ou arquitetura de microsserviços é uma forma de design de aplicações de serviços independentes distribuíveis. Entre suas principais características:
- Deploy automatizado
- Inteligência no uso das API's
- Controle descentralizado de dados
- Independência de linguagens
O Docker Compose é uma ferramenta para definir e gerenciar aplicações docker com múltiplos containers. Neste contexto os containers são chamados de serviços.
- 5-8-Projeto-Cadastro-Simples/backend/package.json
# ls
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 19/10/2022 20:12 backend
d----- 19/10/2022 20:07 frontend
-a---- 19/10/2022 20:14 341 docker-compose.yml
# docker-compose up
- Network 5-8-projeto-cadastro-simples_default C... 0.9s
- Container 5-8-projeto-cadastro-simples-backend-1 Created 0.6s
- Container 5-8-projeto-cadastro-simples-frontend-1 Created 0.6s
- Container 5-8-projeto-cadastro-simples-db-1 Cr... 0.6s
(...)
Exemplo completo de uma aplicação com múltiplos serviços em docker.
Componentes
- Servidor web
- Banco de dados
- Gerenciamento de filas
- Workers para envio de e-mail (escalável)
- Aplicação principal
# docker-compose up -d
- db Pulled 23.4s
- 1cb79db8a9e7 Pull complete 11.9s
- f6bae7873dd7 Pull complete 12.6s
- 8f7722dc50a7 Pull complete 12.8s
- e8622b8cb6f3 Pull complete 13.0s
- d6d74bba3a57 Pull complete 14.0s
- 874d4d2a09fd Pull complete 14.2s
- 2d87c3a4038c Pull complete 14.3s
- f955a6cf127b Pull complete 14.5s
- f62dc55c568d Pull complete 18.2s
- 4e2c4902efbd Pull complete 18.4s
- 01c676df543a Pull complete 19.1s
- 1e3d335ef0b7 Pull complete 19.3s
- 11087f2b0d87 Pull complete 19.5s
- 4b9a74ac6ea0 Pull complete 19.6s
[+] Running 2/2
- Network 9-default Created 0.8s
- Container db-1 Started 2.9s
# docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------
9-db_1 docker-entrypoint.sh postgres Up 5432/tcp
# docker-compose exec db psql -U postgres -c '\l'
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+------------+------------+-----------------------
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
(3 rows)
# docker-compose down
[+] Running 2/2
- Container db-1 Removed 0.4s
- Network 9-default Removed 0.6s
# docker-compose ps
Name Command State Ports
------------------------------
# docker-compose up -d
Creating network "9-default" with the default driver
Creating 9-db_1 ... done
# docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------
9-db_1 docker-entrypoint.sh postgres Up 5432/tcp
# docker-compose exec db psql -U postgres -f scripts/check.sql List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
--------------+----------+----------+------------+------------+-----------------------
email_sender | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
| | | | | postgres=CTc/postgres
(4 rows)
You are now connected to database "email_sender" as user "postgres".
Table "public.emails"
Column | Type | Modifiers
----------+-----------------------------+-----------------------------------------------------
id | integer | not null default nextval('emails_id_seq'::regclass)
data | timestamp without time zone | not null default now()
assunto | character varying(100) | not null
mensagem | character varying(250) | not null
psql:scripts/check.sql:2: \connect: FATAL: database "email_sender" does not exist
- 9-ProjetoparaEnviodeE-mailscomWorkers/web
docker-compose ps
Name Command State Ports
------------------------------
# docker-compose up -d
Creating network "9-default" with the default driver
Creating 9-db_1 ... done
Creating 9-frontend_1 ... done
# docker-compose logs -f -t
db-1 | 2022-10-23T18:14:59.331862200Z
db-1 | 2022-10-23T18:14:59.331931500Z PostgreSQL Database directory appears to contain a database; Skipping initialization
db-1 | 2022-10-23T18:14:59.331944900Z
db-1 | 2022-10-23T18:15:00.020299000Z LOG: database system was shut down at 2022-10-23 18:12:47 UTC
db-1 | 2022-10-23T18:15:00.091458400Z LOG: MultiXact member wraparound protections are now enabled
db-1 | 2022-10-23T18:15:00.096101300Z LOG: autovacuum launcher started
db-1 | 2022-10-23T18:15:00.096404500Z LOG: database system is ready to accept connections
$ docker-compose ps
Name Command State Ports
------------------------------
# docker-compose up -d
Creating network "9-default" with the default driver
Creating 9-app_1 ... done
Creating 9-db_1 ... done
Creating 9-frontend_1 ... done
# docker-compose logs -f -t
Attaching to 9-frontend_1, 9-app_1, 9-db_1
db_1 | 2019-05-31T00:42:06.363286000Z LOG: database system was shut down at 2019-05-29 13:44:49 UTC
db_1 | 2019-05-31T00:42:06.573055000Z LOG: MultiXact member wraparound protections are now enabled
db_1 | 2019-05-31T00:42:06.887140000Z LOG: autovacuum launcher started
db_1 | 2019-05-31T00:42:06.887370000Z LOG: database system is ready to accept connections
app_1 | 2019-05-31T00:42:09.632657000Z Collecting bottle==0.12.13
Um proxy reverso lida com solicitações de clientes e, em seguida, encaminha essas solicitações para outro servidor executado no back-end. Esse servidor de origem de backend processa a solicitação e fornece uma resposta de volta ao Nginx, que então envia a resposta de volta ao cliente.
No aquivo default.conf dentro da pasta nginx faz a configuração:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location /api {
proxy_pass http://app:8080/;
proxy_http_version 1.1;
}
}
E no arquivo docker-compose.yml acrecentamos em volumes:
# Configuração do proxy reverso
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
Criação das rede WEB, rede BANCO e o APP com a persistência no banco de dados que foi submetida pelo formulario do front-end.
OBS: teve um ERRO ao importar pycopg:
| Requirement already satisfied: bottle==0.12.13 in /usr/local/lib/python3.6/site-packages (0.12.13)
| Requirement already satisfied: psycopg2==2.7.1 in /usr/local/lib/python3.6/site-packages (2.7.1)
| Requirement already satisfied: redis==2.10.5 in /usr/local/lib/python3.6/site-packages (2.10.5)
| WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
| WARNING: You are using pip version 21.2.4; however, version 21.3.1 is available.
| You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.
| Traceback (most recent call last):
| File "sender.py", line 1, in <module>
| import psycopg2
| File "/usr/local/lib/python3.6/site-packages/psycopg2/__init__.py", line 50, in <module>
| from psycopg2._psycopg import ( # noqa
| ImportError: /usr/local/lib/python3.6/site-packages/psycopg2/.libs/libresolv-2-c4c53def.5.so: undefined symbol: __res_maybe_init, version GLIBC_PRIVATE
app-1 exited with code 1
Resolvi este problema mudando a versão do python para 3.7.2 no arquivo docker-compose.yml.
Criação das rede FILAS e dois containers (worker e queue)
worker = versão simulada de entrega de e-mail.
queue = que se basear em Redis:3.2
TESTE DO ENVIO DO FORMULARIO:
| Mandando a mensagem: Teste 01 Assunto!
| Mensagem registrada !
| 172.31.0.1 - - [23/Oct/2022:21:09:09 +0000] "POST /api HTTP/1.1" 200 82 "http://localhost/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36" "-"
| 172.31.0.3 - - [23/Oct/2022 21:09:09] "POST / HTTP/1.1" 200 82
| Mensagem Teste 01 Assunto! enviada
Apartir de um container criar varias estâncias worker_1, worker_2 e worker_3, para escalar de forma individual. Começando com a criação de uma imagem personalizada WORK.
# docker-compose up -d --scale worker=3
[+] Running 10/10
- Network 9-fila Created 0.7s
- Network 9-banco Created 0.8s
- Network 9-web Created 0.8s
- Container queue-1 Started 4.4s
- Container db-1 Started 4.4s
- Container worker-3 Started 7.4s
- Container worker-1 Started 6.6s
- Container app-1 Started 7.9s
- Container worker-2 Started 7.6s
- Container frontend-1 Started 8.0s
# logs -f -t worker
worker-2 | 2022-10-23T21:34:39.464728000Z Aguardando mensagens ...
worker-1 | 2022-10-23T21:34:38.470684400Z Aguardando mensagens ...
worker-3 | 2022-10-23T21:34:39.103390700Z Aguardando mensagens ...
TESTE DO ENVIO DO FORMULARIO:
-worker-1 | 2022-10-23T21:38:49.738603300Z Mandando a mensagem: Teste 01 Assunto!
-worker-3 | 2022-10-23T21:39:00.474410000Z Mandando a mensagem: Teste 02 Assunto!
-worker-2 | 2022-10-23T21:39:07.290081600Z Mandando a mensagem: Teste 03 Assunto!
-worker-3 | 2022-10-23T21:39:22.494580600Z Mensagem Teste 02 Assunto! enviada
-worker-1 | 2022-10-23T21:39:34.774432600Z Mensagem Teste 01 Assunto! enviada
-worker-2 | 2022-10-23T21:39:43.326426800Z Mensagem Teste 03 Assunto! enviada
Seria aula de personalizar as variaveis de ambiente.
Visualização do banco de dados:
# docker-compose exec db psql -U postgres -d email_sender -c 'select * from emails'
id | data | assunto | mensagem
----+----------------------------+-------------------------+-------------------------
1 | 2022-10-23 20:46:24.362197 | Teste de texto assunto! | Teste do texto mensagem
2 | 2022-10-23 21:09:09.60662 | Teste 01 Assunto! | Teste 01 Mensagem.....
3 | 2022-10-23 21:38:49.726346 | Teste 01 Assunto! | Teste 01 Mensagem.....
4 | 2022-10-23 21:39:00.466614 | Teste 02 Assunto! | Teste 02 Mensagem.....
5 | 2022-10-23 21:39:07.282295 | Teste 03 Assunto! | Teste 03 Mensagem.....
(5 rows)
Escrever outo arquivo compose sobreescrever uma variavel de ambiente local.
O docker-compose.override.ymlé o arquivo de configuração onde você pode substituir as configurações existentes docker-compose.ymlou até mesmo adicionar serviços completamente novos.
Por padrão, esse arquivo não existe e você deve criá-lo. Você pode copiar o existente docker-compose.override.yml-exampleou criar um novo.
Como funciona o docker-compose.override.yml? Quando você executa , ele procura um arquivo chamado e lê todos os serviços, redes, volumes etc. configurados para criar sua pilha do Docker. Se você também tiver um arquivo chamado , ele também será lido e usado como um arquivo de substituição para complementar. Funciona na seguinte ordem:docker-compose updocker-compose.ymldocker-compose.override.yml
- Todas as definições de docker-compose.ymlserão usadas
- Todas as definições que também são definidas em docker-compose.override.ymlsubstituirão automaticamente as configurações dedocker-compose.yml
- Todas as definições disponíveis apenas em docker-compose.override.ymlserão adicionadas adicionalmente.
Para iniciar sua pilha do Docker Compose, não há etapas adicionais ou argumentos de linha de comando necessários. Se ambos os arquivos existirem, eles serão lidos automaticamente.
Copyright © 2022 ClaudioMendonca.eng.br . All rights reserved.