- 1 Instalação
- 2 Testando o Docker
- 3 Containers
- 3.1 O que são containers?
- 3.2 Verificando containers em execução e quais já foram executados
- 3.3 Executando container no modo Iterativo
- 3.4 Executando containers em background (detached)
- 3.5 Expondo portas de containers
- 3.6 Parando containers
- 3.7 Reiniciando containers
- 3.8 Definindo nome de container
- 3.9 Verificando os logs do container
- 3.10 Removendo containers
- 4 Imagens
- 4.1 O que são imagens?
- 4.2 Onde encontrar e como escolher boas imagens?
- 4.3 Criando uma imagem
- 4.4 Executando uma imagem
- 4.5 Listando e Executando imagens
- 4.6 Alterando uma imagem
- 4.7 Camadas das imagens
- 4.7.1 Cache de camadas
- 4.8 Download de imagens
- 4.9 Multiplas aplicações, mesmo container
- 4.10 Alterando o nome e tag de uma imagem
- 4.11 Iniciando imagem com um nome
- 4.12 Reiniciando container com iteratividade
- 4.13 Removendo imagens
- 4.14 Removendo imagens e containers
- 4.15 Removendo container após utilização
- 4.16 Copiando arquivos entre containers
- 4.17 Verificando processamento do container
- 4.18 Inspecionando um container
- 4.19 Verificando processamento do Docker
- 4.20 Informações sobre comandos
- 5 Docker Hub
- 6 Volumes
- 6.1 O que são volumes?
- 6.2 Tipos de volumes
- 6.3 O problema da persistência de dados
- 6.4 Criando uma aplicação que persiste dados no container
- 6.5 Volumes anônimos
- 6.6 Volumes nomeados
- 6.7 Bind mounts
- 6.8 O poder extra do bind mount
- 6.9 Criando volumes manualmente
- 6.10 Listando todos os volumes
- 6.11 Inspecionando volumes
- 6.12 Removendo volumes
- 6.13 Removendo volumes em massa
- 6.14 Volume apenas de leitura
- 7 Networks
- 7.1 O que são Networks no Docker?
- 7.2 Tipo de conexão
- 7.3 Tipo de rede (drivers)
- 7.4 Listando redes
- 7.5 Criando rede
- 7.6 Removendo redes
- 7.7 Removendo redes não utilizadas
- 7.8 Conexão externa
- 7.9 Conexão com o host
- 7.10 Conexão entre containers
- 7.11 Conectando um container a uma rede
- 7.12 Desconectando um container de uma rede
- 7.13 Inspecionando redes
- 8 YAML
- 8.1 O que é YAML?
- 8.2 Criando um arquivo YAML
- 8.3 Espaçamento e identação
- 8.4 Comentários no YAML
- 8.5 Dados numéricos
- 8.6 Strings no YAML
- 8.7 Valores nulos
- 8.8 Booleanos
- 8.9 Arrays
- 8.10 Dicionários
- 9 Gerenciando múltiplos containers com Docker Compose
- 9.1 O que é o Docker Compose
- 9.2 Instalando Docker Compose no Linux
- 9.3 Criando nosso primeiro arquivo do Compose
- 9.4 Rodando o Compose
- 9.5 Rodando o Compose em background
- 9.6 Parando o Compose
- 9.7 Variáveis de ambiente no Compose
- 9.8 Redes no Compose
- 9.9 Criando o Compose de um projeto
- 9.10 Build de imagens no Compose
- 9.11 Bind Mount no Compose
- 9.12 Verificando serviços no Compose
Comandos utilizados no terminal
Atualiza o package index:
sudo apt-get update
Instala as dependências:
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
Adiciona a chave GPG oficial do Docker:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Configura o repositório estável:
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Instala a engine do Docker:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
Verifica se a instalação teve sucesso:
sudo docker run hello-world
Output:
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/
sudo apt-get remove docker docker-engine docker.io containerd runc
Nome da imagem: whalaesay Comando utilizado no terminal:
sudo docker run docker/whalesay cowsay Olá, mundo!
Output:
_____________
< Olá, mundo! >
-------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
- Imagem(
Dockerfile
) é o "projeto" que será executado pelo container, todas as instruções estarão nela; - Container é o Docker rodando alguma imagem, consequentemente, executando algum códigoo proposto por ela;
- O fluxo é: programamos uma imagem e a executamos por meio de um container
- Container é um pacote de código que pode executar uma ação, por exemplo: rodar uma aplicação de Node.js, Ruby, Python e etc. Ou seja, nossos projetos são executados dentro dos containers que criamos/utilizamos;
- Containers utilizam imagens para poderem ser executados;
- Múltiplos containers podem rodar juntos, exemplo: um para Ruby e o outro para Postgres;
- O comando
docker ps
oudocker container ls
exibe quais containers estão sendo executados no momento; - Utilizando a flag
-a
, temos também todos os containers já executados na máquina, exemplo:docker ps -a
; - Este comando é útil para entender o que acontece e o que está sendo executado no nosso ambiente
- Podemos rodar um container e deixá-lo executando no terminal;
- Para isso utilizamos a flag
-it
; - Desta maneira podemos executar comandos disponíveis no container que estamos utilizando no comando
run
; - Podemos utilizar a imagem do Ubuntu para isso
Exemplo1: docker run -it ubuntu
o container continuará sendo executado e teremos acesso ao terminal do Ubuntu com todos os comandos existentes nele, como ls
, cd
e etc.
Exemplo2: docker run -it node
o container continuará sendo executado e teremos acesso ao terminal e teremos acesso aos comandos disponíveis pelo Node, como var x = 10
, console.log(x)
, 2 + 2
e etc
- Quando iniciamos um container que persiste, ele fica ocuando o terminal;
- Poodemos executar um container em background, para não precisar ficar com diversas abas de terminal abertas, utilizamos a flag
-d
- Verificamos containers em background com
docker ps
- Podemos utilizar
nginx
para este exemplo:docker run -d nginx
- Os containers de docker não tem conexão com nada fora deles
- Por isso precisamos expor portas utilizando a flag
-p
- Ao configurarmos a porta desta maneira:
-p <numero-da-porta-do-computador>:<numero-da-portado-docker>
Exemplo: docker run -p 3000:80 nginx
, o container estará acessível na porta 3000 no navegador
- Podemos parar um container com o comando
docker stop <id-ou-nome-do-container>
- Desta maneira estaremos liberando recursos que estão sendo gastos pelo mesmo
- Podemos verificar os containers rodando com o comando
docker ps
- Para voltar a rodar um container parado utilizamos o comando
docker start <id-ou-nome-do-container>
- Lembrando que o comando
docker run
sempre criará um novo container - Então caso seja necessário aproveitar um antigo, opte pelo
start
- Podemos definir um nome do container com a flag
--name
- Se não definido, um nome aleatório será atribuído, o que pode ser um problema para uma aplicação profissional
- A flag
run
é inserida junto do comando run
Exemplo: docker run -d -p 80:80 --name nginx_app nginx
- Podemos verificar o quie aconteceu em um container com o comando
logs
- Utilizando da seguinte maneira:
docker logs <id-ou-nome-do-container>
- As últimas ações realizadas no container, serão exibidas no terminal
- Adicionando a flag
-f
, de follow, o terminal permenecerá mostrando os logs e os atualizando em tempo real
Exemplo: docker logs -f nginx_app
- Podemos remover um container da máquina que estamos executando o Docker
- O comando é o
docker rm <id-ou-nome-do-container>
- Se o container ainda estiver rodando, podemos utilizar a flag
-f
(force) - O container removido não é mais listado em
docker ps -a
Exemplo: docker rm nginx_app -f
- Imagens são originadas de arquivos que programamos
Dockerfile
para que o Docker crie uma estrutura que execute determinadas ações em containers - Elas contém informações como: imagem base, diretório base, comandos a serem executados, portaa da aplicação e etc
- Ao rodar um container baseado na imagem, as instruções serão executadas em camadas
- No repositório oficial do Docker;
- Neste site podemos verificar quais imagens existem da tecnologia que estamos procurando, por exemplo: Node.js;
- E também aprender com utilizá-la;
- Executamos uma imagem em um container com o comando
docker run <nome-da-imagem>
- Porém qualquer pessoa pode fazer upload de uma imagem, isso é um problema
- Devemos então nos atentar as imagens oficiais
- Outro parâmetro interessante é a quantidade de downloads e a quantidade de stars que a imagem possui
- Para criar uma imagem vamos precisar de um arquivo Dockerfile em uma pasta que ficará o projeto
- Este arquivo vai precisar de algumas instruções para poder ser executado
- FROM: imagem base
- WORKDIR: diretório da aplicação
- EXPOSE: porta da aplicação
- COPY: quais arquivos precisam ser copiados
Exemplo: Primeiramente criaremos uma pequena aplicação em Node para ilustrarmos melhor o exemplo
# Cria um diretório para o projeto
mkdir ~/Projetos/primeira-imagem && cd ~/Projetos/primeira-imagem
# Inicializa um projeto em Node
npm init -y
# Instala o framework express
npm install express
# Cria o arquivo principal da aplicação
touch app.js
Já no arquivo app.js
:
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Olá, minha imagem')
});
app.listen(port, () => {
console.log(`Executand da porta ${port}`)
});
Então, no terminal, rodamos o comando node app.js
, que executará a aplicação.
E ao abrirmos o navegador em localhost:3000
podemos verificar a mensagem Olá, minha imagem
enviada da aplicação e que a mesma funciona corretamente.
Agora criaremos uma imagem que executará esta aplicação.
No terminal executamos o comando: touch Dockerfile
para criar o arquivo de configuração.
No arquivo Dockerfile
:
# Define a imagem base da aplicação
FROM node
# Define o diretório que será utilizado pela aplicação
WORKDIR /src
# Copia todos os arquivo package.json para o diretório de trabalho
COPY package*.json /src/
# Instala o projeto no container do Docker
RUN npm install
# Copia os demais arquivos para o diretório de trabalho
COPY . .
# Define a porta exposta
EXPOSE 3000
# Inicializa a aplicação
CMD ["node", "app.js"]
- Para executar uma imagem primeiramente vamos precisar fazer o build dela
- O comando para isso é o
docker build <diretorio-da-imagem>
- Depois utilizamos o
docker run <nome-da-imagem>
para executá-la
No terminal:
# Vai para o diretório do projeto
cd ~/Projetos/primeira-imagem
# Se estivermos no diretório com o Dockerfile
docker build .
# Ou se estivermos em outro diretório
docker build ~/Projetos/primeira-imagem
Ao buildarmos a imagem, obteremos algo como:
Sending build context to Docker daemon 2.015MB
Step 1/7 : FROM node
---> 1016313cda78
Step 2/7 : WORKDIR /src
---> Using cache
---> 63c180dedba9
Step 3/7 : COPY package*.json /src/
---> e5ae9d50761f
Step 4/7 : RUN npm install
---> Running in 678f23e2fbee
Removing intermediate container 678f23e2fbee
---> 61fb92c04453
Step 5/7 : COPY . .
---> 15f436a21259
Step 6/7 : EXPOSE 3000
---> Running in b1482c93bc1d
Removing intermediate container b1482c93bc1d
---> 7ecb5fa2364e
Step 7/7 : CMD ["node", "app.js"]
---> Running in 6f93bd827cfa
Removing intermediate container 6f93bd827cfa
---> 8a1cebce1ec0
Successfully built 8a1cebce1ec0
- Para listar as imagens utilizamos o comando
docker image ls
Exemplo:
docker image ls
Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 8a1cebce1ec0 7 minutes ago 914MB
Nossa imagem recém buildada é listada e podemos perceber que ela ainda não possui nome ou tag, mais tarde os definiremos, mas a executaremos pelo id
.
No console:
# Executa o container utilizando as flags:
# Detached(-d) que deixa o terminal livre para uso
# Port(-p) define a porta de execução <porta-no-computador>:<porta-definida-na-aplicação>
# Name(--name) define o nome do container
docker run -d -p 3000:3000 --name node_app 8a1cebce1ec0
# Verifica os containers em execução
docker ps
# Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09e2afb2d5f2 8a1cebce1ec0 "docker-entrypoint.s…" 18 seconds ago Up 18 seconds 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp node_app
- Sempre que alteramos o código de uma imagem precisamos fazer o build novamente
- Para o Docker é como se fosse uma imagem completamente nova
- Após fazer o build vamos executá-la por outro
id
único criado com odocker run
Exemplo:
Alteraremos a mensagem enviada pela aplicação no arquivo app.js
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Olá, minha imagem!!!!!!!')
});
app.listen(port, () => {
console.log(`Executand da porta ${port}`)
});
Se o container estiver sendo executado devemos pará-lo com o comando docker stop <id-ou-nome-do-container>
.
Com o container já parado rodaremos o comando docker build ~/Projetos/primeira-imagem
novamente.
Rodando o comando docker images
percebemos essa nova imagem presente.
Então poderemos executar essa nova imagem a partir do seu id
.
# Builda a imagem novamente
docker build ~/Projetos/primeira-imagem
# Output
Sending build context to Docker daemon 2.015MB
Step 1/7 : FROM node
---> 1016313cda78
Step 2/7 : WORKDIR /src
---> Using cache
---> 63c180dedba9
Step 3/7 : COPY package*.json /src/
---> Using cache
---> e5ae9d50761f
Step 4/7 : RUN npm install
---> Using cache
---> 61fb92c04453
Step 5/7 : COPY . .
---> 173faafe74e6
Step 6/7 : EXPOSE 3000
---> Running in 22d0425ad914
Removing intermediate container 22d0425ad914
---> f6c677d0ba19
Step 7/7 : CMD ["node", "app.js"]
---> Running in 9c2658b1d94c
Removing intermediate container 9c2658b1d94c
---> 90e62cc44004
Successfully built 90e62cc44004
# Verifica imagens
sudo docker images
# Output com a nova imagem buildada
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 90e62cc44004 30 seconds ago 914MB
<none> <none> 8a1cebce1ec0 56 minutes ago 914MB
# Para evitar conflito entre containers, devemos também modificar o nome dele ao executá-lo
sudo docker run -d -p 3000:3000 --name node_app2 90e62cc44004
- As imagens do Docker são divididas em camadas(layers)
- Cada instrução no
Dockerfile
representa um layer - Quando algo é atualizado apenas os layers depois da linha atualizada são refeitos
- O resto permanece em cache, tornando o build mais rápido
Exemplo:
Se mudar a camada de definição da porta para EXPOSE 3001
, então o Docker executará o Dockerfile
a partir dela até o final.
- Podemos fazer o download de alguma imagem do hub e deixá-la disponível em nosso ambiente
- Pra isso utilizamos o comando
docker pull <noma-da-imagem>
- Desta maneira, caso eu use em outro container, a imagem já estará pronta para ser utilizada
Exemplo:
docker pull python
# Output
Using default tag: latest
latest: Pulling from library/python
4c25b3090c26: Pull complete
1acf565088aa: Pull complete
b95c0dd0dc0d: Pull complete
5cf06daf6561: Pull complete
942374d5c114: Pull complete
64c0f10e4cfa: Pull complete
419e258e9e29: Pull complete
3fff52a3f4a6: Pull complete
9476e460b958: Pull complete
Digest: sha256:46a1f3fd3d713fc9151753a6a75da327d1c872152ace16e8b3225458f8754d07
Status: Downloaded newer image for python:latest
docker.io/library/python:latest
docker run -it python
# Output
Python 3.9.7 (default, Aug 31 2021, 18:27:13)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
- Podemos inicializar vários containers com a mesma imagem
- As aplicações funcionarão em paralelo
- Para testar isso, podemos determinar uma porta diferente para cada aplicação, e rodá-las no modo detached
Exemplo:
docker images
# Output
REPOSITORY TAG IMAGE ID CREATED SIZE
node <none> 8a1cebce1ec0 2 hours ago 914MB
# Criando três containers a partir da mesma imagem de id 8a1cebce1ec0
docker run -d -p 3000:3000 --name node_app1 8a1cebce1ec0
docker run -d -p 4000:3000 --name node_app2 8a1cebce1ec0
docker run -d -p 5000:3000 --name node_app3 8a1cebce1ec0
# Listando containers em execução
docker ps
# Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8d4454dc534f 8a1cebce1ec0 "docker-entrypoint.s…" 6 seconds ago Up 5 seconds 0.0.0.0:5000->3000/tcp, :::5000->3000/tcp node_app3
cfd48322c7b9 8a1cebce1ec0 "docker-entrypoint.s…" 14 seconds ago Up 13 seconds 0.0.0.0:4000->3000/tcp, :::4000->3000/tcp node_app2
c6a7270f0e8f 8a1cebce1ec0 "docker-entrypoint.s…" 30 seconds ago Up 29 seconds 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp node_app1
- Podemos utilizar o comando
docker tag <nome-da-imagem>
para isso - Também podemos modificar a tag, que seria como uma versão da imagem, semelhante ao git
- Para inserir a tag utilizamos:
docker tag <nome-da-imagem>:<tag>
Exemplo:
# Lista as imagens
docker images
# Output
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 90e62cc44004 2 hours ago 914MB
# Atualiza o nome da imagem
docker tag 90e62cc44004 imagem_node
# Lista as imagens
docker images
# Output
REPOSITORY TAG IMAGE ID CREATED SIZE
imagem_node latest 90e62cc44004 2 hours ago 914MB
# Atualiza o tag da imagem
docker tag 90e62cc44004 imagem_node:imagem_node_tag
# Lista as imagens
docker images
# Output
REPOSITORY TAG IMAGE ID CREATED SIZE
imagem_node imagem_node_tag 90e62cc44004 2 hours ago 914MB
- Podemos nomear a imagem já na sua criação
- Para isso utilizamos a flag
-t
- Sendo possível inserir o nome e a tag, na sintaxe
nome:tag
- Isso torna o processo de nomeação mais simples
Exemplo:
docker build -t outro_node:outra_tag ~/Projetos/primeira-imagem
- A flag
-i
pode ser utilizada com o comandostart
também - Ou seja, não precisamos criar um novo container para utilizá-lo no terminal
- O comando é o
docker start -i <id-ou-nome-do-container>
- Assim como nos containers, podemos remover imagens com um comando
- Ele é o
docker rmi <id-ou-nome-da-imagem>
- Imagens que estão sendo utilizadas por um container, apresentarão um erro no terminal
- Podemos utilizar a flag
-f
para forçar a remoção Exemplos:docker rmi app_nome
docker rmi -f ga97adsgha
- Com o comando
docker system prune
podemos remover imagens, containers e networks não utilizados - O sistema irá exigir uma confimação para realizar a remoção
- Todos os containers parados
- Todas as networks não usadas por pelo menos um container
- Todas as imagens pendentes (imagens pendentes são camadas que não têm relação com nenhuma imagem tageada)
- Todo o cache de build pendente
- Um container pode ser automaticamente deletado após sua utilização
- Para isso, utiliza-se a flag
-rm
- Desta maneira economizamos espaço no computador e deixamos o ambiente mais organizado
Exemplo: docker run -d -p 3000:3000 --name node_app --rm imagem_node
- Para cópia de arquivos entre contaaainers utilizamos o comando
docker cp
- Pode ser utilizado para copiar um arquivo de um diretório para um container ou de um container para um diretório
Exemplo:
# Primeiramente rodamos o container
docker run -d -p 3000:3000 --name node_app imagem_node
# E então copiaremos um arquivo do container para o computador
docker cp node_app:/src/app.js ~/Projetos/dir_para_copia/
- Para verificar dados de execução de um container utilizamos o comando
docker top <id-ou-nome-do-container>
- Desta maneira temos acesso a quando ele foi iniciado, id do processo, descrição do comando CMD e etc
Exemplo:
# Primeiramente rodamos o container
docker run -d -p 3000:3000 --name node_app imagem_node
# Então rodamos o comando top
docker top node_app
# Output
UID PID PPID C STIME TTY TIME CMD
root 25883 25860 0 12:57 ? 00:00:00 node app.js
- Para verificar diversas informações de um container como: id, data de criação, imagem e muito mais, utilizamos o comando
docker inspect <id-ou-nome-do-container>
- Desta maneira conseguimos entender como o container está configurado
Exemplo:
# Primeiramente rodamos o container
docker run -d -p 3000:3000 --name node_app imagem_node
# Então rodamos o comando inspect
docker inspect node_app
# Output
[
{
"Id": "c6a7270f0e8fdbf7679f90ba4d6a1d3796fd382639ec04145485f1ff3469a419",
"Created": "2021-09-01T15:57:24.208236121Z",
"Path": "docker-entrypoint.sh",
"Args": [
"node",
"app.js"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 25883,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-09-01T15:57:24.532630263Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:8a1cebce1ec01ec1274f217b1e6fe72f998cd639c5f46d109dd5ab773d63e097",
"ResolvConfPath": "/var/lib/docker/containers/c6a7270f0e8fdbf7679f90ba4d6a1d3796fd382639ec04145485f1ff3469a419/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/c6a7270f0e8fdbf7679f90ba4d6a1d3796fd382639ec04145485f1ff3469a419/hostname",
"HostsPath": "/var/lib/docker/containers/c6a7270f0e8fdbf7679f90ba4d6a1d3796fd382639ec04145485f1ff3469a419/hosts",
"LogPath": "/var/lib/docker/containers/c6a7270f0e8fdbf7679f90ba4d6a1d3796fd382639ec04145485f1ff3469a419/c6a7270f0e8fdbf7679f90ba4d6a1d3796fd382639ec04145485f1ff3469a419-json.log",
"Name": "/node_app1",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"3000/tcp": [
{
"HostIp": "",
"HostPort": "3000"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/360079c7f44498ba6238f1fe92c744a66d8313804152daf9fcbece255ef0f7c5-init/diff:/var/lib/docker/overlay2/eb784ba0954cf7c6e04ef6c3c85c03704d8320c67c728add50ecd1c582318682/diff:/var/lib/docker/overlay2/292a2485ddc87904e1d4b952ae978d90ebd22ad385f027557c8c3b81e2567cf3/diff:/var/lib/docker/overlay2/134ee1bcc9f1f00dafc09bd019f57fe94be1fdafcbc16ba1355b549d97197f49/diff:/var/lib/docker/overlay2/5f1588bfdd97b2f601b0a5b72f2008897258f1f5021653e695de10d395b181aa/diff:/var/lib/docker/overlay2/e8ea37de439e8ba79e99f009ce816f15692c547706de0fc2965ff7ff4e52acab/diff:/var/lib/docker/overlay2/cea47f1faa4b5523bb0e791e725dcfdf9bd9db93e02b4d1e69269f8deb30233f/diff:/var/lib/docker/overlay2/690e607bd38b1ae749130e0624e7c6bd0714eb8b551061b3f0539c65fc851007/diff:/var/lib/docker/overlay2/edca917eec0ce555aa09c649ded6c4d695b0470f9a6fae35f5706b0b41b83d19/diff:/var/lib/docker/overlay2/308b7abfe7773d584472bf6408ded36bffc1e79758ce2de5b4b82e5d247d13c1/diff:/var/lib/docker/overlay2/1c119afec87fb85da8509113e02dc792a491a8ce33c99dc618d715aa1c3e2d8e/diff:/var/lib/docker/overlay2/bbafad5017fa53277f25a9218e4b8ee0b94c8f37c94f7d04b201c2de7e4ca03b/diff:/var/lib/docker/overlay2/858df878124c5d12755b29a4154e8da001f1ecf6b76d3634b28a62ff9039e642/diff:/var/lib/docker/overlay2/5bf28f17d91364ede1d6b13514f3a9aa65904a823ab47ac86105a16888cbd116/diff",
"MergedDir": "/var/lib/docker/overlay2/360079c7f44498ba6238f1fe92c744a66d8313804152daf9fcbece255ef0f7c5/merged",
"UpperDir": "/var/lib/docker/overlay2/360079c7f44498ba6238f1fe92c744a66d8313804152daf9fcbece255ef0f7c5/diff",
"WorkDir": "/var/lib/docker/overlay2/360079c7f44498ba6238f1fe92c744a66d8313804152daf9fcbece255ef0f7c5/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "c6a7270f0e8f",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3000/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NODE_VERSION=16.8.0",
"YARN_VERSION=1.22.5"
],
"Cmd": [
"node",
"app.js"
],
"Image": "8a1cebce1ec0",
"Volumes": null,
"WorkingDir": "/src",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "7505c8fda380bad76e4a87ae71c0c61b62fdb29b990b12564c7c752ea826b475",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"3000/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "3000"
},
{
"HostIp": "::",
"HostPort": "3000"
}
]
},
"SandboxKey": "/var/run/docker/netns/7505c8fda380",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "d5083a9bc641e1ea1df54e829fdd856ee65dcfe01d06b4f5ea1ebad8a7c5b587",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "22a324e2d2fb9d4b374483792cde962eab0cd840150224ceeb11aad1dcbf9c44",
"EndpointID": "d5083a9bc641e1ea1df54e829fdd856ee65dcfe01d06b4f5ea1ebad8a7c5b587",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
- Para verificar os processos que estão sendo executados em um container, utilizamos o comando
docker stats
- Desta maneira temos acesso ao andamento do processamento e memória gasta pelo mesmo
Exemplo:
docker stats
# Output
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
c6a7270f0e8f node_app 0.00% 14.38MiB / 7.543GiB 0.19% 275kB / 0B 4.16MB / 0B 7
- Todo comando no Dopcker tem acesso a uma flag
--help
- Utilizando desta maneira, podemos ver todas as opções disponíveis nos comandos para relembrar algo ou executar uma tarefa diferente com o mesmo Exemplo:
# Comando start
docker start --help
# Output
Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
Start one or more stopped containers
Options:
-a, --attach Attach STDOUT/STDERR and forward signals
--detach-keys string Override the key sequence for detaching a container
-i, --interactive Attach container\'s STDIN
# Comando images
docker images --help
# Output
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images)
--digests Show digests
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print images using a Go template
--no-trunc Don't truncate output
-q, --quiet Only show image IDs
- Primeiramente precisamos de uma conta no Docker Hub
- Para se autenticar pelo terminal vamos utilizar o comando
docker login
, inserindo usuário e senha - Então poderemos enviar nossas próprias imagens para o Hub
Exemplo:
docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: ifasanelli
Password: meu-password
WARNING! Your password will be stored unencrypted in /home/italo/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
- Para remover a conexão entre nossa máquina e o Docker Hub, vamos utilizar o comando
docker logout
- Agora não poderemos mais enviar imagens, pois não estamos mais autenticados
Exemplo:
docker logout
# output
Removing login credentials for https://index.docker.io/v1
- Para enviar uma imagem nossa ao Docker Hub utilizamos o comando
docker push <id-ou-nome-da-imagem>
- Mas antes devemos criar um repositório para a mesma no site do Docker Hub aqui
- Também é necessário estar autenticado
Exemplo:
No site do Docker Hub criamos um repositório com nome de nodeteste
# Devemos buildar uma imagem com o mesmo nome do repositório
docker build -t ifasanelli/nodeteste ~/Projetos/imagem-node
# Então rodamos o comando push
docker push ifasanelli/nodeteste
Podemos verificar aqui o repositório com a imagem recém enviada.
- Para enviar uma atualização vamos primeiramente fazer o build
- Trocando a tag da imagem para a verão atualizada
- Depois vamos fazer um push novamente para o repositório
- Assim todas as versões estarão disponíveis para serem utilizadas
Exemplo:
# Buildamos a imagem novamente com o código já atualizado
docker build -t ifasanelli/nodeteste:novaversao ~/Projetos/imagem-node
# Então rodamos o comando push
docker push ifasanelli/nodeteste:novaversao
- Para baixar a imagem podemos utilizar o comando
docker pull <nome-da-imagem>
- Depois criar um novo container com o comando
docker run <nome-da-imagem>
- Uma forma prática de persistir dados em aplicações e não depender de containers para isso
- Todo dado criado por um container é salvo nele, quando o container é removido perdemos os dados
- Então precisamos dos volumes para gerenciar os dados e também conseguir fazer backups de forma mais simples
- Anônimos (anonymous volume): Diretórios criados pela flag
-v
, porém com um nome aleatório - Nomeados (named volume): São volumes com nomes, podemos nos referir a estes facilmente e saber para que são utilizaados no nosso ambiente
- Bind mounts: Uma forma de salvar dados na nossa máquina, sem o gerenciamento do Docker, informamos um diretório para este fim
- Se criarmos um container com alguma imagem, todos os arquivos que geramos dentro dele serão do container
- Quando o container for removido, perderemos estes arquivos
- Por isso precisamos dos volumes
Em um diretório ~/Projetos/app_persiste_dados
, criaremos um pequeno app em PHP com um input onde escreveremos mensagens e estas serão salvas em arquivos .txt
em um diretório messages
no container.
Os arquivos são:
Dockerfile
FROM php:8-apache
WORKDIR /var/www/html/
COPY . .
EXPOSE 80
RUN chown -R www-data:www-data /var/www
index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mensagens</title>
</head>
<body>
<h1>Escreva sua Mensagem</h1>
<form action="process.php" method="POST">
<input type="text" name="message" id="message">
<input type="submit" value="Enviar Mensagem">
</form>
</body>
</html>
process.php
<?php
$message = $_POST["message"];
$files = scandir("./messages");
$num_files = count($files) - 2; // . e ..
$fileName = "msg-{$num_files}.txt";
$file = fopen("./messages/{$fileName}", "x");
fwrite($file, $message);
fclose($file);
header("Location: index.php");
Devemos buildar e rodar a imagem:
# Comando para fazer o build da imagem
docker build -t phpmessages ~/Projetos/app_persiste_dados
# Comando para rodar o container
docker run -d -p 80:80 --name phpmessages_container phpmessages
Então acessamos localhost e para cada mensgem submetida, poderemos acessá-la em http://localhost:80/messages/msg-numero_da_msg.txt
.
Exemplo: http://localhost:80/messages/msg-0.txt
para a primeira mensagem salva.
Pra verificarmos os problema da persistência de dados na prática, primeiramente vamos parar e reiniciar o container para verificar se os dados ainda persistem nele.
# Comando para parar o container
docker stop phpmessages_container
# Comando para reiniciar o container
docker start phpmessages_container
Então podemos acessar a primeira mensagem salva pelo link http://localhost:80/messages/msg-0.txt e perceber que ainda está lá.
Mas caso o container seja removido e iniciado novamente, seguindo os comandos:
# Comando para parar o container
docker stop phpmessages_container
# Comando para remover o container
docker rm phpmessages_container
# Comando para rodar o container
docker run -d -p 80:80 --name phpmessages_container phpmessages
Uma mensagem de Not Found
será mostrada na página http://localhost:80/messages/msg-0.txt
- Podemos criar um volume anônimo(anonymous) com o seguinte comando
docker run -v /data
, onde/data
será o diretório que contém o volume anônimo sendo compatível com oWORKDIR
- E este container estará atrelado ao volume anônimo
- Com o comando
docker volume ls
, podemos ver todos os volumes do nosso ambiente
Exemplo: docker run -d -p 80:80 --name phpmessages_container -v /data phpmessages
Podemos verificar se o volume foi criado com o seguinte comando:
docker volume ls
# Output
DRIVER VOLUME NAME
local acae7ecb6eabdefb9eaaab9ea7eab53
- Podemos criar um volume nomeado(named) utilizando o seguinte comando
docker run -v nomedovolume:/data
- Agora o volume tem nome e pode ser facilmente referenciado
- Lembrando que o diretório definido para o volume precisa estar compatível com o diretório do
WORKDIR
Exemplo:
Dockerfile
FROM php:8-apache
WORKDIR /var/www/html/
COPY . .
EXPOSE 80
RUN chown -R www-data:www-data /var/www
Terminal:
# Comando para subir o container com o named volume
docker run -d -p 80:80 --name phpmessages_container -v nomedovolume:/var/www/html/messages phpmessages
Agora acessaremos a aplicação no http://localhost:80/index.php, salvar uma mensagem e acessá-la pelo http://localhost:80/messages/msg-0.txt.
E mesmo que o container seja removido, criaremos outro com acesso ao mesmo volume e poderemos acessar esta mensagem.
# Comando para parar o container
docker stop phpmessages_container
# Comando para remover o container
docker rm phpmessages_container
# Comando para subir o container acessando o volume do container anterior
docker run -d -p 80:80 --name phpmessages_container -v nomedovolume:/var/www/html/messages phpmessages
E já podemos acessar o http://localhost:80/messages/msg-0.txt e verificar a presença da mensagem salva pelo container já removido.
Além disso, também podemos criar um segundo container rodando simultaneamente com o primeiro, com acesso ao mesmo volume. E cada registro de mensagem feito em qualquer um dos containers, será de acesso de ambos.
# Comando para subir outro container acessando o volume do primeiro container
docker run -d -p 81:80 --name outro_phpmessages_container -v nomedovolume:/var/www/html/messages phpmessages
E acessando pelo segundo container http://localhost:81/messages/msg-0.txt verificamos também a presença da mensagem registrada pelo container já removido
Também podemos acessar o http://localhost:81/index.php da segunda aplicação, registrar uma mensagem e verificar a presença dela na primeira aplicação http://localhost:80/messages/msg-1.txt
- Bind mount também é um volume, porém ele fica em um diretório que nós especificamos
- Então não criamos um volume em si, apontamos um diretório
- O comando para criar um bind mount é
docker run /dir/data:/data
- Desta maneira o diretório /dir/data no nosso computador, será o volume deste container
Exemplo:
docker run -d -p 80:80 --name phpmessages_container -v ~/Projetos/app_persiste_dados/messages:/var/www/html/messages --rm phpmessages
Lembrando que já temos criado o diretório ~/Projetos/app_persiste_dados/messages
no computador.
Agora testaremos a persistência das mensagens no diretório acessando http://localhost:80/index.php e registrando uma mensagem qualquer.
Além de verificar sua presença em http://localhost:80/messages/msg-0.txt, também estará presente o arquivo msg-0.txt
no diretório especificado no computador com a mensagem registrada.
- Bind mount não serve apenas para volumes
- Podemos utilizar esta técnica para atualização em tempo real do projeto, sem ter que refazer o build a cada atualização do mesmo
Exemplo:
# Comando para rodar o container com bind mount definido agora pelo diretório raíz da aplicação e WORKDIR e não mais pelos diretórios "message" dentro deles.
# Antes: ~/Projetos/app_persiste_dados/messages:/var/www/html/messages
# Agora: ~/Projetos/app_persiste_dados:/var/www/html/
docker run -d -p 80:80 --name phpmessages_container -v ~/Projetos/app_persiste_dados:/var/www/html/ --rm phpmessages
E para testarmos a atualização do projeto, primeiramente acessaremos http://localhost:80/index.php, registraremos uma mensagem, verificaremos sua presença no arquivo ~/Projetos/app_persiste_dados/messages/msg-0.txt
.
Agora, no arquivo index.php
alteraremos o contéudo da tag <h1>
:
index.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mensagens</title>
</head>
<body>
<h1>Escreva sua Mensagem ATUALIZADO PELO BIND MOUNT</h1>
<form action="process.php" method="POST">
<input type="text" name="message" id="message">
<input type="submit" value="Enviar Mensagem">
</form>
</body>
</html>
E sem parar o container, atualizamos a página index da aplicação com F5
e verificamos o título da página atualizado sem a necessidade de buildar a imagem novamente.
- Podemos criar volumes manualmente também utilizando o comando
docker volume create <nome-do-volume>
- Desta maneira temos um named volume criado, podendo ser atrelado a algum container na execução do mesmo
Exemplo:
# Comando para criar um volume
docker volume create volumeteste
# Comando para listar volumes
docker volume ls
# Output
DRIVER VOLUME NAME
local volumeteste
# Comando para rodar um container atrelado ao volume recém criado
docker run -d -p 80:80 --name phpmessages_container -v volumeteste:/var/www/html/ --rm phpmessages
- Com o comando
docker volume ls
listamos todos os volumes, desta maneira temos acesso aos anonymous e aos named volumes - Não serão listados bind mounts
- É útil para saber quais volumes estão criados no nosso ambiente
Exemplo:
docker volume ls
# Output
DRIVER VOLUME NAME
local volumeteste
- Podemos verificar os detalhes de um volume em específico com o comando
docker volume inspect <nome-do-volume>
- Desta forma temos acesso ao local em que o volume guarda dados, nome, escopo e etc
- O Docker salva os dados dos volumes em algum diretório do nosso computador, desta forma podemos saber qual é
Exemplo:
# Comando para listar volumes
docker volume ls
# Output
DRIVER VOLUME NAME
local volumeteste
# Comando para inspecionar o volume
docker volume inspect volumeteste
# Output
[
{
"CreatedAt": "2021-09-02T15:23:34-03:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/volumeteste/_data",
"Name": "volumeteste",
"Options": {},
"Scope": "local"
}
]
- Podemos também remover um volume existente de forma fácil, para isso utilizamos o comando
docker volume rm <nome-do-volume>
- Observe que os dados serão removidos também, tome cuidado com este comando
Exemplo:
# Comando para listar volumes
docker volume ls
# Output
DRIVER VOLUME NAME
local volumeteste
# Comando para remover o volume
docker volume rm volumeteste
# Comando para listar volumes
docker volume ls
# Output
DRIVER VOLUME NAME
- Podemos remover todos os volumes que não estão sendo utilizados com apenas um comando
docker volume prune
- Ele é semlhante ao
prune
que remove as imagens
Exemplo:
# Comando para listar volumes
docker volume ls
# Output
DRIVER VOLUME NAME
local volumeteste
local volumeteste1
local volumeteste2
# Comando para remover o volume
docker volume prune
# Comando para listar volumes
docker volume ls
# Output
DRIVER VOLUME NAME
- Podemos criar um volume que tem apenas permissão de leitura, isso é útil em algumas aplicações
- Para realizar esta configuração devemos utilizar o comando
docker run -v volume:/data:ro
, onde:ro
significaread only
Exemplo:
docker run -d -p 80:80 --name phpmessages_container -v volumeleitura:/var/www/html:ro --rm phpmessages
Se tentarmos persistir dados via http://localhost:80/index.php, uma mensagem de erro aparecerá notificando a falta de permissão de escrita.
- Uma forma de gerenciar a conexão do Docker com outras plataformas ou até mesmo entre containers
- As redes ou networks são criadas separadas do container, como os volumes
- Além disso existem alguns drivers de rede, que veremos em seguida
- Uma rede deixa muito simples a comunicação entre containers
- Os containers costumam ter três principais tipos de comunicação
- Externa: conexão com uma API de um servidor remoto
- Com o host: comunicação com a máquina que está executando o Docker
- Entre containers: comunicação que utiliza o driver bridge e permite a comunicação entre dois ou mais containers
- bridge: o mais comum e default do Docker, utilizado quando containers precisam se conctar (na maioria das vezes optamos por este dirver)
- host: permite a conexão entre um container a uma máquina que está hosteando o Docker
- macvlan: permite a conexão a um container por um MAC address
- none: remove todas as conexões de rede de um container
- plugins: permite extensões de terceiros para criar outras redes
- Podemos verificar todas as redes do nosso ambiente com o comando
docker network ls
- Algumas redes já estão criadas, estas fazem parte da configuração inicial do Docker
Exemplo:
# Comando para listar as redes
docker network ls
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
7d3dd836f2cc none null local
- Para criar uma rede vamos utilizar o comando
docker network create <nome-da-rede>
- Esta rede será do tipo bridge, que é o mais utilizado
Exemplo:
# Comando para criar uma rede default
docker network create minharedeteste
# Output
99e3d08e78f3ea6960783afb593e726255d96cdeb79b43991544f4b483023a71
# Comando para listar redes
docker network ls
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
99e3d08e78f3 minharedeteste bridge local
7d3dd836f2cc none null local
# Comando para criar uma rede com driver especificado
docker network create -d macvlan minharedemacvlan
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
0dcfb559e6ea minharedemacvlan macvlan local
99e3d08e78f3 minharedeteste bridge local
7d3dd836f2cc none null local
- Podemos remover redes de forma simples com o comando
docker network rm <nome-da-rede>
, assim a rede não estará mais disponível para utilizarmos - Devemos tomar cuidado com containers já conectados
Exemplo:
# Comando para listar redes
docker network ls
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
0dcfb559e6ea minharedemacvlan macvlan local
99e3d08e78f3 minharedeteste bridge local
7d3dd836f2cc none null local
# Comando para criar uma rede com driver especificado
docker network rm minharedemacvlan
# Comando para listar redes
docker network ls
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
99e3d08e78f3 minharedeteste bridge local
7d3dd836f2cc none null local
- Podemos remover redes de forma simple também com o comando
docker network prune
, assim todas as redes não utilizadas no momento serão removidas - As redes criadas por padrão do Docker não serão removidas
- Receberemos uma mensagem de confirmação do Docker antes da ação ser executada
Exemplo:
# Comando para listar redes
docker network ls
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
0dcfb559e6ea minharedemacvlan macvlan local
99e3d08e78f3 minharedeteste bridge local
7d3dd836f2cc none null local
# Comando para remover redes não utilizadas
docker network prune
# Output
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
minharedemacvlan
minharedeteste
# Comando para listar redes
docker network ls
# Output
NETWORK ID NAME DRIVER SCOPE
33f340c389be bridge bridge local
c22aff5ea72f host host local
7d3dd836f2cc none null local
- Os containers podem se conectar livremente ao mundo externo
- Um caso seria uma API de código aberto
- Podemos acessá-la livremente e utilizar seus dados
Para exemplificar uma conexão externa criaremos um diretório para o projeto:
# Cria e muda para o diretório redeexterna
mkdir ~/Projetos/redeexterna && cd ~/Projetos/redeexterna
Neste diretório criamos dois arquivos:
Dockerfile
FROM python:3
RUN apt-get update -y && \
apt-get install -y python-pip python-dev
WORKDIR /app
RUN pip install Flask
RUN pip install requests
COPY . .
EXPOSE 5000
CMD ["python", "./app.py"]
app.py
import flask
from flask import request, json, jsonify
import requests
app = flask.Flask(__name__)
app.config["DEBUG"] = True
@app.route("/", methods=["GET"])
def index():
data = requests.get('https://randomuser.me/api')
return data.json()
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port="5000")
No terminal:
# Comando para buildar a imagem
docker build -t flaskexterno ~/Projetos/redeexterna
# Comando para rodar o container
docker run -d -p 5000:5000 --name flaskexternacontainer --rm flaskexterno
No Postman faremos uma requisição GET para http://localhost:5000/
e obteremos uma resposta parecida com:
{
"results": [
{
"gender": "male",
"name": {
"title": "Mr",
"first": "Alexander",
"last": "Wright"
},
"location": {
"street": {
"number": 4077,
"name": "White Oak Dr"
},
"city": "Denver",
"state": "Virginia",
"country": "United States",
"postcode": 88784,
"coordinates": {
"latitude": "84.9187",
"longitude": "-98.5076"
},
"timezone": {
"offset": "0:00",
"description": "Western Europe Time, London, Lisbon, Casablanca"
}
},
"email": "[email protected]",
"login": {
"uuid": "0f76f3ee-a8f5-43ed-8356-ae4dddf4324d",
"username": "greengorilla706",
"password": "chelsea1",
"salt": "QI0xp5ZV",
"md5": "388781e5fa6c95476d614d2a6703be99",
"sha1": "0504d3f9b1cea9514d3a20cae78beaf3c70641f2",
"sha256": "d8a28e737bf6fc701a49f0dfbbd4158603bc5c6ef0daad8e41d56e7ab54dd4ae"
},
"dob": {
"date": "1993-05-21T01:12:20.330Z",
"age": 28
},
"registered": {
"date": "2007-08-18T13:36:38.335Z",
"age": 14
},
"phone": "(889)-221-3883",
"cell": "(262)-126-5556",
"id": {
"name": "SSN",
"value": "777-44-2926"
},
"picture": {
"large": "https://randomuser.me/api/portraits/men/86.jpg",
"medium": "https://randomuser.me/api/portraits/med/men/86.jpg",
"thumbnail": "https://randomuser.me/api/portraits/thumb/men/86.jpg"
},
"nat": "US"
}
],
"info": {
"seed": "5b539454c72a2240",
"results": 1,
"page": 1,
"version": "1.3"
}
}
- Podemos também conectar um container com o host do Docker
- Host é a máquina que está executando o Docker
- Como ip de host utilizamod
host.docker.internal
Para esse exemplo é necessário ter instalado o MySQL, criar um banco de dados com nome flaskhost
, com uma tabela users
, com as colunas id(INT)
e name(VARCHAR)
Para exemplificar uma conexão com o host criaremos um diretório para o projeto:
# Cria e muda para o diretório redehost
mkdir ~/Projetos/redehost && cd ~/Projetos/redehost
Neste diretório criamos dois arquivos:
Dockerfile
FROM python:3
RUN apt-get update -y && \
apt-get install -y python-pip python-dev
WORKDIR /app
RUN pip install Flask requests flask_mysqldb
COPY . .
EXPOSE 5000
CMD ["python", "./app.py"]
app.py
import flask
from flask import request, json, jsonify
import requests
import flask_mysqldb
from flask_mysqldb import MySQL
app = flask.Flask(__name__)
app.config["DEBUG"] = True
app.config['MYSQL_HOST'] = 'host.docker.internal'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = ''
app.config['MYSQL_DB'] = 'flaskhost'
mysql = MySQL(app)
@app.route("/", methods=["GET"])
def index():
data = requests.get('https://randomuser.me/api')
return data.json()
@app.route("/inserthost", methods=['POST'])
def inserthost():
data = requests.get('https://randomuser.me/api').json()
username = data['results'][0]['name']['first']
cur = mysql.connection.cursor()
cur.execute("""INSERT INTO users(name) VALUES(%s)""", (username,))
mysql.connection.commit()
cur.close()
return username
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port="5000")
No terminal:
# Comando para buildar a imagem
docker build -t flaskhost ~/Projetos/redehost
# Comando para rodar o container
docker run -d -p 5000:5000 --name flaskhostcontainer --rm flaskhost
Agora podemos fazer uma requisição POST no Postman para http://localhost:5000/inserhost
e obteremos uma resposta parecida com:
Julia
No MySQL Workbench
podemos verificar a presença dos dados com a query SELECT * FROM flaskhost.users;
- Podemos também estabelecer uma conexão entre containers
- Duas imagens distintas rodando em containers separados que precisam se conectar para inserir um dado no banco, por exemplo
- Vamos precisar de uma rede bridge, para fazer esta conexão
- Para isso utilizamos o comando
--network <nome-da-rede>
- Agora nosso container de flask vai inserir dados em um MySQL que roda pelo Docker também
Para exemplificar uma conexão entre dois containers, criaremos um diretório ~/Projetos/conn_containers
e, dentro dele, mais dois diretórios: flask
e mysql
.
Dentro de ~/Projetos/conn_containers/flask
:
app.py
import flask
from flask import request, json, jsonify
import requests
import flask_mysqldb
from flask_mysqldb import MySQL
app = flask.Flask(__name__)
app.config["DEBUG"] = True
app.config['MYSQL_HOST'] = 'mysql_api_container'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = ''
app.config['MYSQL_DB'] = 'flaskdocker'
mysql = MySQL(app)
@app.route("/", methods=["GET"])
def index():
data = requests.get('https://randomuser.me/api')
return data.json()
@app.route("/inserthost", methods=['POST'])
def inserthost():
data = requests.get('https://randomuser.me/api').json()
username = data['results'][0]['name']['first']
cur = mysql.connection.cursor()
cur.execute("""INSERT INTO users(name) VALUES(%s)""", (username,))
mysql.connection.commit()
cur.close()
return username
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port="5000")
Dockerfile
FROM python:3
RUN apt-get update -y && \
apt-get install -y python-pip python-dev
WORKDIR /app
RUN pip install Flask requests flask_mysqldb
COPY . .
EXPOSE 5000
CMD ["python", "./app.py"]
E dentro de ~/Projetos/conn_containers/mysql
:
Dockerfile
FROM mysql:5.7
COPY schema.sql /docker-entrypoint-initdb.d/
EXPOSE 3306
VOLUME ["/backup/"]
schema.sql
CREATE DATABASE flaskdocker;
USE flaskdocker;
CREATE TABLE `flaskdocker`.`users` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (ID));
No terminal:
# Comando para buildar a imagem do mysql
docker build -t mysqlapinetwork ~/Projetos/conn_containers/mysql
# Comando para criar uma conexão bridge
docker network create flasknetwork
# Comando para rodar o container do mysql conectando a rede "flasknetwork"
docker run -d -p 3306:3306 --name mysql_api_container --rm --network flasknetwork -e MYSQL_ALLOW_EMPTY_PASSWORD=True mysqlapinetwork
# Obs.: O comando "-e MYSQL_ALLOW_EMPTY_PASSWORD=True" cria uma variável de ambiente que retira a necessidade de senha para o banco de dados.
# Comando para buildar a imagem do flask
docker build -t flaskapinetwork ~/Projetos/conn_containers/flask
# Comando para rodar o container do flask conectando a rede "flasknetwork"
docker run -d -p 5000:5000 --name flaskapicontainer --rm --network flasknetwork flaskapinetwork
Testaremos primeiramente o container do flask
com uma chamada GET
em http://localhost:5000
recebendo como resposta um JSON
com dados de um usuário utilizando o Postman
.
Agora testaremos a inserção de dados no container do mysql
através do container do flask
.
Faremos uma chamada POST
em http://localhost:5000/inserthost
e para verificarmos se esses dados foram persistidos corretamente, podemos acessar o banco de dados flaskdocker
pelo MySQL Workbench
na tabela users
, uma vez que externalizamos a porta 3306
- Podemos conectar um container a uma rede, para isso utilizamos o comando:
docker network connect <nome-da-rede> <id-ou-nome-do-container>
No terminal:
# Comando para rodar o container do flask'
docker run -d -p 5000:5000 --name flaskapicontainer --rm flaskapinetwork
# Comando para conectar o container do flask na rede flasknetwork
docker network connect flasknetwork flaskapicontainer
Para verificarmos se a conexão com a rede foi estabelecida, podemos rodar o comando docker inspect flaskapicontainer
e confirmar a presença do atributo "flasknetwork"
.
- Podemos desconectar um container a uma rede utilizando o comando
docker network disconnect <nome-da-rede> <id-ou-nome-do-container>
Usaremos o container do exemplo anterior para exemplificar a desconexão do container Exemplo:
docker network disconnect flasknetwork flaskapicontainer
E rodando o comando docker inspect flaskapicontainer
, não encontraremos mais o atributo "flasknetwork"
.
- Podemos analisar os detalhes de uma rede com o comando
docker network inspect <nome-da-rede>
- Receberemos informações como: data de criação, driver, nome e etc.
Exemplo:
docker network inspect flasknetwork
# Output
[
{
"Name": "flasknetwork",
"Id": "22f5fca63d7fbf8b721e363ad57bc927b3fa28629a1538170e4dcd7b81f7b477",
"Created": "2021-09-09T00:34:56.222025796-03:00",
"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,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
- Uma linguagem de serialização, seu nome é YAML ain't Markup Language (YAML não é uma linguagem de marcação)
- Usada geralmente para arquivos de configuração, inclusive no Docker, para configuraar o Docker Compose
- É de fácil leitura para nós humanos
- A extensão dos arquivos é .yml ou .yaml
- O arquivo .yaml geralmente possui chaves e valores, que é de onde vamos retirar as configurações do nosso sistema
- Para definir uma chave apenas inserimos o nome dela, em seguida colocamos dois pontos e depois o valor
Para exemplificar o funcionamento do YAML, criaremos um script em python
que imprimirá as chaves e valores do arquivo.
E para isso precisamos ter o python
instalado na máquina e o pacote pyyaml
com o comando pip3 install pyyaml
.
app.py
import yaml
if __name__ == '__main__':
stream = open("test.yaml", "r")
dictionary = yaml.safe_load(stream)
for key, value in dictionary.items():
print(key + " : " + str(value))
test.yaml
nome: "Mariana"
idade: 24
No terminal:
# Comando para rodar o script
python app.py
# Output
idade : 24
nome : Mariana
- O O fim de uma linha indica o fim de uma instrução, não há ponto e vírgula
- A identação deve conter um ou mais espaços, e não devemos utilizar
tab
- Cada identação define um bloco
- O espaço é obrigatório após a declaração da chave
test.yaml
objeto:
versao: 2
arquivo: "teste.txt"
- Podemos escrever comentários em YAML também, utilizando o símbolo #
- O processador do YAML ignora comentários
- Eles são úteis para escrever como o arquivo funciona e/ou foi configurado
test.yaml
# Dados pessoais
idade: 24
nome: Mariana
# Objeto de configuração
objeto:
versao: 2
arquivo: "teste.txt"
No terminal:
# Comando para rodar o script
python app.py
# Output
idade : 24
nome : Mariana
objeto : {'versao': 2, 'arquivo': 'teste.txt'}
- Em YAML podemos escrever dados numéricos com:
- Inteiros: 12
- Ex.:
versao: 12
- Ex.:
- Floats: 15.8
- Ex.:
versao: 15;8
- Ex.:
- Inteiros: 12
- Em YAML podemos escrever textos de duas formas:
- Sem aspas:
este é um texto válido
- Ex.:
nome: Mariana Flor
- Ex.:
- Com aspas:
"este também"
- Ex.:
nome: "Mariana Flor"
- Ex.:
- Sem aspas:
- Em YAML podemos definir um dado como nulo de duas formas: ~ ou null
- Ex.:
id: ~
- Ex.:
id: null
- Ex.:
- Os dois vão resultar em
None
, após a interpretação
- Podemos inserir booleanos em YAML das seguintes formas:
- Para
True
: True ou On- Ex.:
has_id: True
- Ex.:
has_id: On
- Ex.:
- Para
False
: False e Off- Ex.:
has_id: False
- Ex.:
has_id: Off
- Ex.:
- Para
- Os arrays, tipos de dados para listas, posssuem duas sintaxes:
items: [1, "teste", 3.14, outro teste, True]
-
items: - 1 - "teste" - 3.14 - outro teste - True
- Dicionários, tipo de dados para objetos ou listas com chaves e valores, podem ser escritos da seguintes formas:
obj: {a: 1, b: "teste", c: 3.14, d: outro teste, e: {x: True, y: False}}
-
obj: a: 1 b: "teste" c: 3.14 d: outro teste e: True f: x: ~ y: null g: Off
- O Docker Compose é uma ferramenta para rodar múltiplos containers
- Teremos apenas um arquivo de configuração, que orquestra totalmente esta situação
- É uma forma de rodar múltiplos builds e runs com um comando
- Em projetos maiores é essencial o uso do Compose
- Vamos segui as instruções da documentação oficial do Docker
- Primeiramente vamos criar um arquivo chamado docker-compose.yml na raiz do projeto
- Este arquivo vai coordenar os containers e imagens, e possui algumas chaves muito utilizadas:
- version: versão do Compose
- services: Containers/serviços que vão rodar nessa aplicação
- volumes: Possível adição de volumes
Primeiramente, criaremos um diretório para o projeto:
mkdir ~/Projetos/compose/criacao_compose && cd ~/Projetos/compose/criacao_compose
Então, criamos o arquivo do compose:
touch docker-compose.yaml
docker-compose.yaml
version: '3.3'
services:
db: # Container de MySQL
image: mysql:5.7 # FROM mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: italo
MYSQL_PASSWORD: secret
wordpress:
depends_on:
-db
image: wordpress:latest
ports:
"8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: italo
WORDPRESS_DB_PASSWORD: secret
WORDPRESS_DB_NAME: wordpress
volumes:
db_data: {}
- Para rodar nossa estrutura em Compose, vamos utilizar o comando
docker-compose up
- Isso fará com que as instruções no arquivo sejam executadas
- Da mesma forma que realizamos os builds e também os runs
- Podemos parar o Compose com o comando
ctrl+c
no terminal
No terminal:
docker-compose up
Receberemos diversas informações como:
- Criação da rede
- Criação do volume
- Criação do container do mysql
- Criação do container do wordpress
- Logs das operações
E ao acessar o localhost na porta 8000, uma instalação do wordpress será inicializada.
Então verificaremos os containers rodando:
# Verifica os containers em execução
docker ps
# Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09e2afb2d5f2 wordpress:latest "docker-entrypoint.s…" 18 seconds ago Up 18 seconds 0.0.0.0:8000->80/tcp, :::8000->80/tcp 1_criacao_compose_wordpress_1
2ac1e2b06660 mysql:5.7 "docker-entrypoint.s…" 18 seconds ago Up 18 seconds 0.0.0.0:3306/tcp, :::3000->3306/tcp 1_criacao_compose_db_1
- O Compose também pode ser executado em modo detached para isso utilizaremos a flag
-d
no comando - E então os containers estarão rodando em background e poderemos ver suas execuções com
docker ps
No terminal:
docker-compose up -d
- Podemos parar o Compose que roda em background com o comando
docker-compose down
- Desta maneira o serviço para e teremos os containers adicionados listados no
docker ps -a
No terminal:
docker-compose down
- Podemos definir variáveis de ambiente para o Docker Compose
- Para isso vamos definir um arquivo base em env_file
- As variáveis podem ser chamadas pela sintaxe: ${VARIAVEL}
- Esta técnica é útil quando o dado a ser inserido é sensível e/ou não pode ser compartilhado, como uma senha
Para esse item, criaremos um diretório variaveis
:
mkdir ~/Projetos/compose/variaveis && cd ~/Projetos/compose/variaveis
Dentro do diretório variaveis
, criaremos outro chamado config
com os arquivos db.env
e wp.env
:
mkdir config && cd config
touch db.env
touch wp.env
db.env
MYSQL_ROOT_PASSWORD=wordpress
MYSQL_DATABASE=wordpress
MYSQL_USER=italo
MYSQL_PASSWORD=secret
wp.env
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DB_NAME=italo
WORDPRESS_DB_PASSWORD=secret
WORDPRESS_DB_NAME=wordpress
Na raiz do projeto(~/Projetos/compose/variaveis) teremos um arquivo de Compose parecido com o das seções anteriores, mas com as variáveis de ambiente removidas e no lugar delas o caminho para o db.env
:
docker-compose.yaml
version: '3.3'
services:
db: # Container de MySQL
image: mysql:5.7 # FROM mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
env_file:
- ./config/db.env
wordpress:
depends_on:
-db
image: wordpress:latest
ports:
"8000:80"
restart: always
env_file:
- ./config/wp.env
volumes:
db_data: {}
- O Compose cria uma rede básica Bridge entre os containers da aplicação, porém podemos isolar as redes com a chave networks
- Desta maneira, podemos conectar apenas os containers que optarmos
- Podemos também definir drivers diferentes
Para esse item, criaremos um diretório networks
:
mkdir ~/Projetos/compose/networks && cd ~/Projetos/compose/networks
Na raiz do projeto(~/Projetos/compose/networks):
docker-compose.yaml
version: '3.3'
services:
db: # Container de MySQL
image: mysql:5.7 # FROM mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
env_file:
- ./config/db.env
networks:
- backend
wordpress:
depends_on:
-db
image: wordpress:latest
ports:
"8000:80"
restart: always
env_file:
- ./config/wp.env
networks:
- backend
volumes:
db_data: {}
networks:
backend:
driver: bridge
- Agora vamos inserir o nosso projeto da última seção no Compose para verificar na prática como fazer a transferência de Dockerfiles para Docker Compose
Para esse item, criaremos um diretório projeto
:
mkdir ~/Projetos/compose/projeto && cd ~/Projetos/compose/projeto
No diretório raíz teremos outros três diretórios flask
mysql
e config
.
No terminal:
mkdir flask
touch ./flask/app.py
touch ./flask/Dockerfile
mkdir mysql
touch ./mysql/schema.sql
touch ./mysql/Dockerfile
mkdir config
touch ./config/db.env
/flask/app.py
import flask
from flask import request, json, jsonify
import requests
import flask_mysqldb
from flask_mysqldb import MySQL
app = flask.Flask(__name__)
app.config["DEBUG"] = True
app.config['MYSQL_HOST'] = 'db'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = ''
app.config['MYSQL_DB'] = 'flaskdocker'
mysql = MySQL(app)
@app.route("/", methods=["GET"])
def index():
data = requests.get('https://randomuser.me/api')
return data.json()
@app.route("/inserthost", methods=['POST'])
def inserthost():
data = requests.get('https://randomuser.me/api').json()
username = data['results'][0]['name']['first']
cur = mysql.connection.cursor()
cur.execute("""INSERT INTO users(name) VALUES(%s)""", (username,))
mysql.connection.commit()
cur.close()
return username
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port="5000")
/flask/Dockerfile
FROM python:3
RUN apt-get update -y && \
apt-get install -y python-pip python-dev
WORKDIR /app
RUN pip install Flask requests flask_mysqldb
COPY . .
EXPOSE 5000
CMD ["python", "./app.py"]
/mysql/schema.sql
CREATE DATABASE flaskdocker;
USE flaskdocker;
CREATE TABLE `flaskdocker`.`users` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (ID));
/mysql/Dockerfile
FROM mysql:5.7
COPY schema.sql /docker-entrypoint-initdb.d/
EXPOSE 3306
/config/db.env
MYSQL_ALLAW_EMPTY_PASSWORD=True
Ainda no diretório raíz do projeto criaremos o arquivo do Compose. No terminal:
touch docker-compose.yaml
docker-compose.yaml
version: '3.3'
services:
db:
image: mysqlcompose
restart: always
env_file:
- ./config/db.env
ports:
- "3306:3306"
networks:
- dockercompose
backend:
depends_on:
- db
image: flaskcompose
ports:
- "5000:5000"
restart: always
networks:
- dockercompose
networks:
dockercompose:
Agora precisamos buildar a imagem do flask. No terminal:
cd ~/Projetos/compose/projeto/flask
docker build -t flaskcompose .
E também buildar a imagem do mysql. No terminal:
cd ~/Projetos/compose/projeto/mysql
docker build -t mysqlcompose .
E finalmente podemos rodar a aplicação. No terminal:
docker-compose up -d
- Podemos gerar o build durante o Compose também, isso vai eliminar o processo de gerar build da imagem a cada atualização
Para esse item, criaremos um diretório build_compose
:
mkdir ~/Projetos/compose/build_compose && cd ~/Projetos/compose/build_compose
No diretório raíz teremos outros três diretórios flask
mysql
e config
.
No terminal:
mkdir flask
touch ./flask/app.py
touch ./flask/Dockerfile
mkdir mysql
touch ./mysql/schema.sql
touch ./mysql/Dockerfile
mkdir config
touch ./config/db.env
/flask/app.py
import flask
from flask import request, json, jsonify
import requests
import flask_mysqldb
from flask_mysqldb import MySQL
app = flask.Flask(__name__)
app.config["DEBUG"] = True
app.config['MYSQL_HOST'] = 'db'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = ''
app.config['MYSQL_DB'] = 'flaskdocker'
mysql = MySQL(app)
@app.route("/", methods=["GET"])
def index():
data = requests.get('https://randomuser.me/api')
return data.json()
@app.route("/inserthost", methods=['POST'])
def inserthost():
data = requests.get('https://randomuser.me/api').json()
username = data['results'][0]['name']['first']
cur = mysql.connection.cursor()
cur.execute("""INSERT INTO users(name) VALUES(%s)""", (username,))
mysql.connection.commit()
cur.close()
return "Usuário inserido: " + username
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port="5000")
/flask/Dockerfile
FROM python:3
RUN apt-get update -y && \
apt-get install -y python-pip python-dev
WORKDIR /app
RUN pip install Flask requests flask_mysqldb
COPY . .
EXPOSE 5000
CMD ["python", "./app.py"]
/mysql/schema.sql
CREATE DATABASE flaskdocker;
USE flaskdocker;
CREATE TABLE `flaskdocker`.`users` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (ID));
/mysql/Dockerfile
FROM mysql:5.7
COPY schema.sql /docker-entrypoint-initdb.d/
EXPOSE 3306
/config/db.env
MYSQL_ALLAW_EMPTY_PASSWORD=True
Ainda no diretório raíz do projeto criaremos o arquivo do Compose. No terminal:
touch docker-compose.yaml
docker-compose.yaml
version: '3.3'
services:
db:
build: ./mysql/
restart: always
env_file:
- ./config/db.env
ports:
- "3306:3306"
networks:
- dockercompose
backend:
depends_on:
- db
build: ./flask/
ports:
- "5000:5000"
restart: always
networks:
- dockercompose
networks:
dockercompose:
Agora sem a necessidade de buildarmos as imagens, subiremos a aplicação pelo Compose. No terminal:
docker-compose up -d
- O volume de Bind Mount garante atualização em tempo real dos artquivos do container
- Podemos configurar nosso projeto de Compose para utilizar esta funcionalidade também
Para esse item, criaremos um diretório bind_mount_compose
:
mkdir ~/Projetos/compose/bind_mount_compose && cd ~/Projetos/compose/bind_mount_compose
No diretório raíz teremos outros três diretórios flask
mysql
e config
.
No terminal:
mkdir flask
touch ./flask/app.py
touch ./flask/Dockerfile
mkdir mysql
touch ./mysql/schema.sql
touch ./mysql/Dockerfile
mkdir config
touch ./config/db.env
/flask/app.py
import flask
from flask import request, json, jsonify
import requests
import flask_mysqldb
from flask_mysqldb import MySQL
app = flask.Flask(__name__)
app.config["DEBUG"] = True
app.config['MYSQL_HOST'] = 'db'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = ''
app.config['MYSQL_DB'] = 'flaskdocker'
mysql = MySQL(app)
@app.route("/", methods=["GET"])
def index():
data = requests.get('https://randomuser.me/api')
return data.json()
@app.route("/inserthost", methods=['POST'])
def inserthost():
data = requests.get('https://randomuser.me/api').json()
username = data['results'][0]['name']['first']
cur = mysql.connection.cursor()
cur.execute("""INSERT INTO users(name) VALUES(%s)""", (username,))
mysql.connection.commit()
cur.close()
return "Usuário inserido: " + username
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port="5000")
/flask/Dockerfile
FROM python:3
RUN apt-get update -y && \
apt-get install -y python-pip python-dev
WORKDIR /app
RUN pip install Flask requests flask_mysqldb
COPY . .
EXPOSE 5000
CMD ["python", "./app.py"]
/mysql/schema.sql
CREATE DATABASE flaskdocker;
USE flaskdocker;
CREATE TABLE `flaskdocker`.`users` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (ID));
/mysql/Dockerfile
FROM mysql:5.7
COPY schema.sql /docker-entrypoint-initdb.d/
EXPOSE 3306
/config/db.env
MYSQL_ALLAW_EMPTY_PASSWORD=True
Ainda no diretório raíz do projeto criaremos o arquivo do Compose. No terminal:
touch docker-compose.yaml
docker-compose.yaml
version: '3.3'
services:
db:
build: ./mysql/
restart: always
env_file:
- ./config/db.env
ports:
- "3306:3306"
networks:
- dockercompose
backend:
depends_on:
- db
build: ./flask/
ports:
- "5000:5000"
restart: always
volumes:
- ~/Projetos/compose/bind_mount_compose/flask/app
networks:
- dockercompose
networks:
dockercompose:
Subiremos a aplicação pelo Compose. No terminal:
cd ~/Projetos/compose/bind_mount_compose/
docker-compose up -d
- Podemos fazer a verificação do compose com o comando
docker-compose ps
- Receberemos um resumo dos serviços que subiram ao rodar o compose
- Desta maneira, podemos avaliar rapidamente o projeto
No terminal:
cd ~/Projetos/compose/bind_mount_compose/
docker-compose up -d
docker-compose ps
# Output
Name Command State Ports
---------------------------------------------------------------------------------------------------
6_bind_mount_compose_db_1 docker-entrypoint.sh mysql Up 0.0.0:3306->3306/tcp, 33060/tcp
6_bind_mount_compose_flask_1 python ./app.py Up 0.0.0.0:5000->5000/tcp