Temos 3 aplicações em nossas mãos, e queremos que todas elas rodem e possam interagir como esperado.
Para isso, poderíamos rodar todas elas diretamente, mas não é o que faremos hoje.
Gostaríamos na verdade de conteinerizar as aplicaçoes nas pastas server
, uploader
e downloader
, e usar os mecanismos de rede e volumes do docker para conectá-las.
Mas antes, precisamos saber o que elas fazem!
-
server: um servidor HTTP feito com Node.js e JavaScript. Este funcionará como a nossa 'database', pois ele se comporta como um dicionário, e provê as seguintes funcionalidades:
- PUT
http://<host>:3000/<chave>
: salva o conteúdo do corpo da mensagem dentro da dada chave para depois poder ser lido usando... - GET
http://<host>:3000/<chave>
: nos retorna um json válido que esta salvo nessa chave
- PUT
-
downloader: um script Python que ciclicamente faz pedidos GET no servidor, para pegar o conteudo nas chaves e baixar como arquivos json numa pasta. deve ser invocado simplesmente com
python main.py
, porém você deve ter as seguintes variáveis de ambiente definidas:SERVIDOR
: endereço do servidor que vai se consultarNOME_BASE
: base do nome dos arquivos para baixar do servidor
-
uploader: um binário, que varre os conteudos de certa pasta, lendo arquivos json com certo nome, incrementa o valor numa certa chave desses objetos, e realiza pedidos PUT no servidor, atualizando o dado que esta lá. deve ser invocado da seguinte maneira:
./dapp <servidor para se enviar> \
<pasta para verificar> \
<base do nome do arquivo> \
<chave para incrementar>
Então precisamos que o server esteja disponível para pedidos de ambos uploader e downloader, e que estes dois possam ler e escrever arquivos em uma pasta comum.
Este pequeno sistema pode ser considerado em funcionamento se:
- a pasta data contendo os arquivos
nome$i.json
, comi
de 0 a 9 - o conteúdo de cada arquivo for no formato
{"chave": N}
, com N crescendo o tempo todo!
Consegue dockerizar as aplicações e coordená-las para rodar corretamente sem usar docker-compose
?
Acredite, é um exercício válido, e vai fazer você valorizar mais o que o compose tem a oferecer...
MÃO NA MASSA!
Alguns comandos importantes do docker compose:
docker-compose up
Faz a magica funcionar. Utiliza como base o arquivo docker-compose.yml
.
Tambem é possivel definir um arquivo diferente usando o parametro -f ou --file
docker-compose --file baleia.yml up
docker-compose ps
Parecido com o docker ps
, mas mostra apenas os conteiners definidos no arquivo docker-compose.yml
.
Caso tenha sido informado um arquivo diferente no momento de iniciar, é preciso informar o mesmo arquivo novamente.
docker-compose --file baleia.yml ps
docker-compose stop
Para a execução dos conteiners sem perder o estado. Caso tenha sido informado um arquivo diferente no momento de iniciar, é preciso informar o mesmo arquivo novamente.
docker-compose --file baleia.yml stop
docker-compose start
Inicia os conteiners parados.
Caso tenha sido informado um arquivo diferente no momento de iniciar, é preciso informar o mesmo arquivo novamente.
docker-compose --file baleia.yml start
docker-compose logs
Com ele podemos ver os logs dos conteiners ativos.
É possivel informar o container desejado utilizando apenas o nome do servico.
docker-compose logs web
Também aceita o parametro -f
para ficar escutando o log em tempo real.
docker-compose logs -f web
docker-compose exec <servico> <comando>
Usado para executar comandos dentro dos conteiners.
docker-compose exec redis sh
docker-compose down
Para a execução dos conteiners e apaga as redes e volumes criados, limpando o estado da aplicação.
Caso tenha sido informado um arquivo diferente no momento de iniciar, é preciso informar o mesmo arquivo novamente.
docker-compose --file baleia.yml down
https://docs.docker.com/compose/compose-file/compose-versioning/
Arquivos do docker-compose possuem 3 diferentes versões, que não compativeis entre si.
Se não for especificado a versão, utilizando o version: 'x.x'
o compose considera que é a versão 1.
Na mesma linha, se for informado apenas o primeiro digito, o decimal sera considerado 0. Assim version: '2'
e version: '2.1'
são equivalentes.
https://docs.docker.com/compose/compose-file/
version: '2.0'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
networks:
new:
O arquivo de confiração tem 4 partes principais, version
, services
, volumes
e networks
.
services
: https://docs.docker.com/compose/compose-file/#service-configuration-reference
volumes
: https://docs.docker.com/compose/compose-file/#volume-configuration-reference
networks
: https://docs.docker.com/compose/compose-file/#network-configuration-reference
https://docs.docker.com/compose/compose-file/#build
Podemos fazer de dois modos.
Utilizando uma imagem já existente com a opção image
ou fazendo o build de um Dockerfile com a opção build
.
Também temos o parametro container_name
para definir um nome especifico para cada container.
É um parametro opcional, caso não seja informado sera gerado automaticamente.
Spoilers!
version: '3'
services:
web:
container_name: servidor-web
build: servidor-web/.
redis:
image: "redis:alpine"
docker-compose up
MÃO NA MASSA!
https://docs.docker.com/compose/environment-variables/
Chave de configuração environment
.
Esse é apenas um dos modos de se fazer. Tambem é possivel utilizar as variaveis ja existentes na maquina host.
Ou tambem definir elas em um arquivo.
Spoilers!
version: '3'
services:
redis:
image: "redis:alpine"
web:
container_name: servidor-web
build: servidor-web/.
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
MÃO NA MASSA!
https://docs.docker.com/compose/compose-file/#ports
Por padrão compose cria uma rede entre todos os container.
O nome dessa rede é definido pelo nome da pasta seguido de _default
, no nosso caso fica baleia-compositora_default
.
Nessa rede cada container pode acessar os outros pelo nome definido do serviço, assim teremos os hosts web
e redis
Para export as portas, podemos fazer utilizando a configuração ports
, seguindo o padrão [HOST:]CONTAINER
.
HOST
: Porta local. É opcional, caso não seja inserido, sera definido uma porta aleatória.
CONTAINER
: Porta do container a ser exposta.
Na documentação é possivel encontrar outros formatos de mapeamento aceitos.
Spoilers!
version: '3'
services:
redis:
image: "redis:alpine"
web:
image: servidor-web
build: servidor-web/.
ports:
- "5050:5000"
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
MÃO NA MASSA!
Em alguns casos com varios container vamos precisar que eles iniciem em uma determinada ordem.
Para garatir isso temos a keyword depends_on
Spoilers!
version: '3'
services:
redis:
image: "redis:alpine"
web:
build: servidor-web/.
depends_on:
- 'redis'
ports:
- "5000:5000"
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
Um porém, só é garantido a ordem que os conteiners sobem, mas não que o serviço dentro dele esteja efetivemente rodando.
Mais informações em: https://docs.docker.com/compose/startup-order/
https://docs.docker.com/compose/compose-file/#volumes
Dentro de um serviço podemos definir os volumes que o serviço vai tulizar. Temos duas opções de como definir os volumes, um modo resumido e um mais verboso.
Modo resumido segue o formatto [SOURCE:]TARGET[:MODE]
SOURCE
pode ser um local na maquina host ou um volume pré definido. Caso não seja informado sera criado um volume.
TARGET
é o cominho no container
MODE
é o modo de acesso, podendo ser ro
para somente leitura ou rw
leitura e escrita
Spoilers!
version: '3'
services:
redis:
image: "redis:alpine"
volumes:
- arquivos:/files
web:
image: servidor-web
build: servidor-web/.
depends_on:
- 'redis'
ports:
- "5000:5000"
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
volumes:
- ./servidor-web:/p
- arquivos:/files
volumes:
arquivos:
Nesse exemplo é feito o compartilhamento entre arquivos da maquina host da pasta servidor-web
com a pasta no container /p
.
E tambem foi criado um volume chamado arquivos
para compartilhar arquivos entre os dois conteiners na pasta /files
Podemos confirmar entrando nos conteiners e criando arquivos lá
docker-compose ps
docker-compose exec web sh
ls /files/
echo 'Hello' > /files/oie.txt
cat /files/oie.txt
exit
docker-compose exec redis sh
ls /files/
cat /files/oie.txt
exit
MÃO NA MASSA!
Sinta-se a vontade para abrir issues e submeter pull requests.