Docker (1/2): contêineres, imagens e aplicações

Docker (1/2): contêineres, imagens e aplicações

Aviso: Este post foi traduzido para o português usando um modelo de tradução automática. Por favor, me avise se encontrar algum erro.

📚 **Esta entrada faz parte da série _Guia de Docker_**, dividida em dois capítulos que são lidos em ordem:

> * 👉 **Parte 1: Contêineres, imagens e aplicações**

* Parte 2: Docker Compose e tópicos avançados

Contêinereslink image 77

Olá mundolink image 78

Executar o primeiro contêiner do tipo Hello World com o comando docker run hello-world

	
< > Input
Python
!docker run hello-world
Copied
>_ Output
			
Unable to find image 'hello-world:latest' locally
>_ Output
			
latest: Pulling from library/hello-world
85e32844: Pull complete 457kB/2.457kBBDigest: sha256:dcba6daec718f547568c562956fa47e1b03673dd010fe6ee58ca806767031d1c
Status: Downloaded newer image for hello-world:latest
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/

Como não temos o contêiner salvo localmente, o Docker o baixa do Docker Hub. Se agora voltarmos a executar o contêiner, a primeira mensagem já não aparecerá, na qual se indica que está sendo feito o download

	
< > Input
Python
!docker run hello-world
Copied
>_ 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/

Para ver os contêineres que estão em execução, executar docker ps

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Como vemos, não há nenhum contêiner aberto. No entanto, se executarmos docker ps -a (all), vemos que sim aparecem

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1efb51bbbf38 hello-world "/hello" 10 seconds ago Exited (0) 9 seconds ago strange_thompson
5f5705e7603e hello-world "/hello" 15 seconds ago Exited (0) 14 seconds ago laughing_jang

Vemos que aparecem dois contêineres chamados hello-world, que são os dois que executámos anteriormente. Portanto, cada vez que executamos o comando run, o Docker cria um novo contêiner, não executa um que já exista.

Se quisermos ter mais informações de um dos dois contêineres, podemos executar docker inspect <id>, onde <id> corresponde ao ID do contêiner que foi mostrado na lista anterior

	
< > Input
Python
!docker inspect 1efb51bbbf38
Copied
>_ Output
			
[
{
"Id": "1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e",
"Created": "2023-09-04T03:59:17.795499354Z",
"Path": "/hello",
"Args": [],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-09-04T03:59:18.406663026Z",
"FinishedAt": "2023-09-04T03:59:18.406181184Z"
},
"Image": "sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d",
"ResolvConfPath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/hostname",
"HostsPath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/hosts",
"LogPath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e-json.log",
"Name": "/strange_thompson",
...
}
}
}
]

Como lembrar IDs é complicado para nós, o Docker atribui nomes aos contêineres para facilitar nossa vida. Assim, na lista anterior, a última coluna corresponde ao nome que o Docker atribuiu a cada contêiner, de modo que, se agora executarmos docker inspect <name>, obteremos a mesma informação que com o ID

Vou executar novamente docker ps -a para ver a lista novamente

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1efb51bbbf38 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago strange_thompson
5f5705e7603e hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago laughing_jang

E agora executo docker inspect <name> para ver as informações do contêiner

	
< > Input
Python
!docker inspect strange_thompson
Copied
>_ Output
			
[
{
"Id": "1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e",
"Created": "2023-09-04T03:59:17.795499354Z",
"Path": "/hello",
"Args": [],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-09-04T03:59:18.406663026Z",
"FinishedAt": "2023-09-04T03:59:18.406181184Z"
},
"Image": "sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d",
"ResolvConfPath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/hostname",
"HostsPath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/hosts",
"LogPath": "/var/lib/docker/containers/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e/1efb51bbbf38917affd1b5871db8e658ebfe0b2efa5ead17545680b7866f682e-json.log",
"Name": "/strange_thompson",
...
}
}
}
]

Mas por que com docker ps não vemos nenhum contêiner e com docker ps -a sim. Isso acontece porque docker ps mostra apenas os contêineres que estão em execução, enquanto docker ps -a mostra todos os contêineres, os que estão em execução e os que estão desligados

Podemos criar um contêiner atribuindo a ele um nome por meio do comando docker run --name <name> hello-world

	
< > Input
Python
!docker run --name hello_world hello-world
Copied
>_ 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/

Isso será mais cômodo para nós, já que poderemos controlar nós mesmos os nomes dos contêineres

Se agora quisermos criar outro contêiner com o mesmo nome, não poderemos, porque o Docker não permite que os nomes dos contêineres se repitam. Assim, se quisermos renomear o contêiner, podemos usar o comando docker rename <old name> <new name>

	
< > Input
Python
!docker rename hello_world hello_world2
Copied

Temos agora um monte de contêineres iguais. Então, se quisermos apagar algum, temos que usar o comando docker rm <id> ou docker rm <name>

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f432c9c2ca21 hello-world "/hello" 9 seconds ago Exited (0) 8 seconds ago hello_world2
1efb51bbbf38 hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago strange_thompson
5f5705e7603e hello-world "/hello" 4 minutes ago Exited (0) 4 minutes ago laughing_jang
	
< > Input
Python
!docker rm hello_world2
Copied
>_ Output
			
hello_world2

Se voltarmos a ver a lista de contêineres, o contêiner hello_world2 já não estará

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1efb51bbbf38 hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago strange_thompson
5f5705e7603e hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago laughing_jang

Se quisermos apagar todos os contêineres, podemos fazê-lo um por um, mas, como isso é muito trabalhoso, podemos apagar todos por meio do comando docker container prune. Este comando elimina apenas os contêineres que estiverem parados

	
< > Input
Python
!docker container prune
Copied
>_ Output
			
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y

O Docker pergunta se você tem certeza, e se você disser que sim, ele apaga todos. Se agora listar todos os contêineres, não aparece nenhum

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

O modo interativolink image 79

Vamos a executar um Ubuntu por meio do comando docker run ubuntu

	
< > Input
Python
!docker run ubuntu
Copied
>_ Output
			
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
Digest: sha256:20fa2d7bb4de7723f542be5923b06c4d704370f0390e4ae9e1c833c8785644c1[1A
Status: Downloaded newer image for ubuntu:latest

Como vemos, agora demorou mais para baixar. Se listarmos os contêineres usando o comando docker ps, vemos que o contêiner que acabamos de criar não aparece, ou seja, não está em execução.

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Listamos agora todos os contêineres

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da16b3a85178 ubuntu "bash" 4 seconds ago Exited (0) 3 seconds ago hardcore_kare

Vemos que o estado do contêiner é Exited (0)

Se olharmos para o comando do contentor, aparece bash e, juntamente com o estado Exited (0), indica-nos que o Ubuntu foi iniciado, executou o seu *bash*, terminou a execução e devolveu um 0. Isto acontece porque ao Bash do Ubuntu não lhe foi dito nada para fazer. Para resolver isso, agora vamos executar o contentor através do comando docker run -it ubuntu; com it, o que lhe estamos a indicar é que o queremos executar em modo interativo

	
< > Input
Python
!docker run -it ubuntu
Copied
>_ Output
			
root@5b633e9d838f:/#

Agora vemos que estamos dentro do bash do Ubuntu. Se executarmos o comando cat /etc/lsb-release podemos ver a distribuição do Ubuntu

	
< > Input
Python
!root@5b633e9d838f:/# cat /etc/lsb-release
Copied
>_ Output
			
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.1 LTS"

Se abrirmos outro terminal e vermos a lista de contêineres, agora sim aparecerá o contêiner executando Ubuntu

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5b633e9d838f ubuntu "bash" 3 minutes ago Up 3 minutes funny_mirzakhani

Vemos o contêiner com Ubuntu e, em seu estado, podemos ver UP

Se agora vemos a lista de todos os contêineres, veremos que aparecem os dois contêineres com Ubuntu, o primeiro desligado e o segundo o que está em execução

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5b633e9d838f ubuntu "bash" 3 minutes ago Up 3 minutes funny_mirzakhani
da16b3a85178 ubuntu "bash" 3 minutes ago Exited (0) 3 minutes ago hardcore_kare

Se voltarmos ao terminal onde tínhamos o Ubuntu sendo executado dentro de um Docker, se digitarmos exit sairemos do Ubuntu.

	
< > Input
Python
!root@5b633e9d838f:/# exit
Copied
>_ Output
			
exit

Se executarmos docker ps, o contêiner já não aparece

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Mas se eu executar docker ps -a, ele aparece. Isso quer dizer que o contêiner foi desligado

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5b633e9d838f ubuntu "bash" 4 minutes ago Exited (0) 27 seconds ago funny_mirzakhani
da16b3a85178 ubuntu "bash" 4 minutes ago Exited (0) 4 minutes ago hardcore_kare

Isso acontece porque, ao digitar exit, na verdade estamos escrevendo isso no console do bash do Ubuntu, o que significa que estamos encerrando o processo bash do Ubuntu.

Ciclo de vida de um contêinerlink image 80

No Docker, quando o processo principal de um contêiner termina, o contêiner é desligado. Dentro de um contêiner podem ser executados vários processos, mas somente quando o processo principal termina o contêiner é desligado

Portanto, se quisermos executar um contêiner que não desligue quando um processo terminar, devemos fazer com que seu processo principal não termine. Neste caso, que o bash não finalize

Se quisermos executar um contêiner com Ubuntu, mas que não termine quando o processo do Bash finalizar, podemos fazer da seguinte maneira

	
< > Input
Python
!docker run --name alwaysup -d ubuntu tail -f /dev/null
Copied
>_ Output
			
ce4d60427dcd4b326d15aa832b816c209761d6b4e067a016bb75bf9366c37054

O que fazemos é primeiro dar-lhe o nome alwaysup, em segundo lugar passar-lhe a opção -d (detach) para que o contêiner seja executado em segundo plano e, por último, dizemos-lhe o processo principal que queremos que seja executado no contêiner, que neste caso é tail -f /dev/null que equivale a um comando nop

Isso nos devolverá a ID do contêiner, mas não estaremos dentro do Ubuntu como acontecia antes

Se agora vemos a lista de contêineres que estão em execução, aparece o contêiner que acabamos de criar

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 18 seconds ago Up 17 seconds alwaysup

Como já temos um contêiner em execução o tempo todo, podemos nos conectar a ele por meio do comando exec. Indicamos o nome ou o ID do contêiner e passamos o processo que queremos que seja executado. Além disso, passamos a opção -it para indicar que ele seja interativo

	
< > Input
Python
!docker exec -it alwaysup bash
Copied
>_ Output
			
root@ce4d60427dcd:/#

Agora voltamos a estar dentro do Ubuntu. Se executarmos o comando ps -aux, podemos ver uma lista dos processos que estão sendo executados dentro do Ubuntu.

	
< > Input
Python
!ps -aux
Copied
>_ Output
			
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 2820 1048 ? Ss 13:04 0:00 tail -f /dev/null
root 7 0.0 0.0 4628 3796 pts/0 Ss 13:04 0:00 bash
root 15 0.0 0.0 7060 1556 pts/0 R+ 13:05 0:00 ps -aux

Vemos apenas três processos, o ps -aux, o bash e o tail -f /dev/null

Este contêiner vai estar sempre ligado enquanto o processo tail -f /dev/null continuar em execução

Se sairmos do contêiner com o comando exit e executarmos o comando docker ps, vemos que o contêiner continua ligado

	
< > Input
Python
!exit
Copied
>_ Output
			
exit
	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 2 minutes ago Up 2 minutes alwaysup

Para poder finalizar o processo e poder desligar o contêiner, devemos usar o comando docker stop <name>

	
< > Input
Python
!docker stop alwaysup
Copied
>_ Output
			
alwaysup

Se agora voltarmos a listar os contêineres em execução, o contêiner com Ubuntu já não aparece.

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

E se listarmos todos os contêineres, aparece o contêiner com Ubuntu, e seu estado Exited

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 14 minutes ago Exited (137) About a minute ago alwaysup
5b633e9d838f ubuntu "bash" 19 minutes ago Exited (0) 15 minutes ago funny_mirzakhani
da16b3a85178 ubuntu "bash" 20 minutes ago Exited (0) 20 minutes ago hardcore_kare

Também podemos pausar um contêiner usando o comando docker pause <name>

	
< > Input
Python
!docker run --name alwaysup -d ubuntu tail -f /dev/null
Copied
>_ Output
			
8282eaf9dc3604fa94df206b2062287409cc92cbcd203f1a018742b5c171c9e4

Agora pausamos

	
< > Input
Python
!docker pause alwaysup
Copied
>_ Output
			
alwaysup

Se voltarmos a ver todos os contêineres, vemos que o contêiner com Ubuntu está pausado

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8282eaf9dc36 ubuntu "tail -f /dev/null" 41 seconds ago Up 41 seconds (Paused) alwaysup
5b633e9d838f ubuntu "bash" 19 minutes ago Exited (0) 15 minutes ago funny_mirzakhani
da16b3a85178 ubuntu "bash" 20 minutes ago Exited (0) 20 minutes ago hardcore_kare

Contentores de uso únicolink image 81

Se ao executar um contêiner, adicionamos a opção --rm, esse contêiner será excluído quando terminar de ser executado.

	
< > Input
Python
!docker run --rm --name autoremove ubuntu:latest
Copied

Se agora vemos quais contêineres temos

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Vemos que o contêiner que acabamos de criar não está presente

Expor contêineres ao mundo exteriorlink image 82

Vamos criar um novo contêiner com um servidor

	
< > Input
Python
!docker run -d --name proxy nginx
Copied
>_ Output
			
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
f1ad4ce1: Pulling fs layer
b079d0f8: Pulling fs layer
5fbbebc6: Pulling fs layer
ffdd25f4: Pulling fs layer
32c8fba2: Pulling fs layer
24b8ba39: Pull complete 393kB/1.393kBB[5ADigest: sha256:2888a97f7c7d498bbcc47ede1ad0f6ced07d72dfd181071dde051863f1f79d7b
Status: Downloaded newer image for nginx:latest
1a530e04f14be082811b72ea8b6ea5a95dad3037301ee8a1351a0108ff8d3b30

Isso cria um servidor, vamos listar novamente os contêineres que estão em execução

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a530e04f14b nginx "/docker-entrypoint.…" 1 second ago Up Less than a second 80/tcp proxy

Agora aparece uma nova coluna com a porta, e nos diz que o servidor que acabamos de criar está na porta 80 sob o protocolo tcp.

Se abrirmos um navegador e tentarmos nos conectar ao servidor por meio de http://localhost:80 não conseguimos conectar. Isso acontece porque cada contêiner tem sua própria interface de rede. Ou seja, o servidor está escutando na porta 80 do contêiner, mas nós estamos tentando conectar à porta 80 do host

Paramos o contêiner para relançá-lo de outra forma

	
< > Input
Python
!docker stop proxy
Copied
>_ Output
			
proxy

Se listarmos os contêineres, não aparece em execução

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Nós o apagamos para criá-lo novamente

	
< > Input
Python
!docker rm proxy
Copied
>_ Output
			
proxy

Se listarmos todos os contêineres, eles já não estão presentes

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 19 minutes ago Exited (137) 5 minutes ago alwaysup
5b633e9d838f ubuntu "bash" 24 minutes ago Exited (0) 20 minutes ago funny_mirzakhani
da16b3a85178 ubuntu "bash" 24 minutes ago Exited (0) 24 minutes ago hardcore_kare

Para recriar o contêiner com o servidor e poder vê-lo a partir do host, temos de usar a opção -p (publish), indicando em primeiro lugar a porta na qual queremos vê-lo no host e, a seguir, a porta do contêiner, ou seja, -p <ip host>:<ip contenedor>

	
< > Input
Python
!docker run -d --name proxy -p 8080:80 nginx
Copied
>_ Output
			
c199235e42f76a30266f6e1af972e0a59811806eb3d3a9afdd873f6fa1785eae

Listamos os contêineres

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c199235e42f7 nginx "/docker-entrypoint.…" 22 seconds ago Up 21 seconds 0.0.0.0:8080-&gt;80/tcp, :::8080-&gt;80/tcp proxy

Vemos que a porta do contêiner é 0.0.0.0:8080->80/tcp. Se agora abrirmos um navegador e introduzirmos 0.0.0.0:8080, poderemos acessar o servidor do contêiner

Ao listar os contêineres, na coluna PORTS indica 0.0.0.0:8080->80/tcp, o que nos ajuda a ver a relação de portas

Para ver os logs do contêiner, por meio do comando docker logs <name> posso ver os registros do contêiner

	
< > Input
Python
!docker logs proxy
Copied
>_ Output
			
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/09/13 13:24:06 [notice] 1#1: using the "epoll" event method
2022/09/13 13:24:06 [notice] 1#1: nginx/1.23.1
2022/09/13 13:24:06 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/09/13 13:24:06 [notice] 1#1: OS: Linux 5.15.0-46-generic
2022/09/13 13:24:06 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/09/13 13:24:06 [notice] 1#1: start worker processes
2022/09/13 13:24:06 [notice] 1#1: start worker process 31
2022/09/13 13:24:06 [notice] 1#1: start worker process 32
2022/09/13 13:24:06 [notice] 1#1: start worker process 33
2022/09/13 13:24:06 [notice] 1#1: start worker process 34
2022/09/13 13:24:06 [notice] 1#1: start worker process 35
2022/09/13 13:24:06 [notice] 1#1: start worker process 36
2022/09/13 13:24:06 [notice] 1#1: start worker process 37
2022/09/13 13:24:06 [notice] 1#1: start worker process 38
2022/09/13 13:24:06 [notice] 1#1: start worker process 39
2022/09/13 13:24:06 [notice] 1#1: start worker process 40
2022/09/13 13:24:06 [notice] 1#1: start worker process 41
...
172.17.0.1 - - [13/Sep/2022:13:24:40 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://0.0.0.0:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [13/Sep/2022:13:25:00 +0000] "üâV$Zqi'×ü[€ïºåÇè÷&amp;3nSëÉì‘ÂØÑ‰ž¾ Ç?áúaΐ˜uã/ØRfOHì’+“\»±¿Òm°9 úúÀ+À/À,À0̨̩ÀÀœ/5“šš localhostÿ" 400 157 "-" "-" "-"
172.17.0.1 - - [13/Sep/2022:13:25:00 +0000] "ü)šbCÙmñ†ëd"ÏÄE‡#~LÁ„µ‘k˜«lî[0 ÐÒ`…Æ‹…R‹‡êq{Pòû⨝IôtH™~Ê1-|Ž êêÀ+À/À,À0̨̩ÀÀœ/5“" 400 157 "-" "-" "-"
172.17.0.1 - - [13/Sep/2022:13:26:28 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"

Agora posso ver todas as requisições que foram feitas ao servidor. Mas, se quero ver os logs em tempo real, com docker logs -f <name> posso fazer isso

	
< > Input
Python
!docker logs -f proxy
Copied

Agora posso ver os logs em tempo real. Para sair, introduzir CTRL+C

Como pode chegar um momento em que haja muitos logs, se você só quiser os últimos logs, por meio da opção --tail <num> você pode ver os últimos <num> logs. Se eu adicionar a opção -f estaremos vendo sempre os últimos <num> logs

	
< > Input
Python
!docker logs --tail 10 proxy
Copied
>_ Output
			
2022/09/13 13:24:06 [notice] 1#1: start worker process 41
2022/09/13 13:24:06 [notice] 1#1: start worker process 42
172.17.0.1 - - [13/Sep/2022:13:24:16 +0000] "üE޶ EgóɚœÊì§y#3’•ÜQïê$¿# ƒ÷-,s!rê|®ß¡LZª4y³t«ÀÎ_¸çÿ'φ êêÀ+À/À,À0̨̩ÀÀœ/5“ŠŠ localhostÿ" 400 157 "-" "-" "-"
172.17.0.1 - - [13/Sep/2022:13:24:16 +0000] "ü}©Dr{Œ;z‚­¼ŠzÂxßšæl?§àDoK‘'g»µ %»ýق?ۀ³TöcJ÷åÂÒ¼¢£ë½=R¼ƒ‰… ÊÊÀ+À/À,À0̨̩ÀÀœ/5“šš localhostÿ" 400 157 "-" "-" "-"
172.17.0.1 - - [13/Sep/2022:13:24:39 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"
2022/09/13 13:24:40 [error] 34#34: *3 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: "0.0.0.0:8080", referrer: "http://0.0.0.0:8080/"
172.17.0.1 - - [13/Sep/2022:13:24:40 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://0.0.0.0:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"
172.17.0.1 - - [13/Sep/2022:13:25:00 +0000] "üâV$Zqi'×ü[€ïºåÇè÷&amp;3nSëÉì‘ÂØÑ‰ž¾ Ç?áúaΐ˜uã/ØRfOHì’+“\»±¿Òm°9 úúÀ+À/À,À0̨̩ÀÀœ/5“šš localhostÿ" 400 157 "-" "-" "-"
172.17.0.1 - - [13/Sep/2022:13:25:00 +0000] "ü)šbCÙmñ†ëd"ÏÄE‡#~LÁ„µ‘k˜«lî[0 ÐÒ`…Æ‹…R‹‡êq{Pòû⨝IôtH™~Ê1-|Ž êêÀ+À/À,À0̨̩ÀÀœ/5“" 400 157 "-" "-" "-"
172.17.0.1 - - [13/Sep/2022:13:26:28 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"

Se também adicionarmos a opção -t, podemos ver a data e a hora de cada log; dessa maneira, se tivermos tido um problema, podemos saber em que momento ocorreu.

	
< > Input
Python
!docker logs --tail -t 10 proxy
Copied
>_ Output
			
2022-09-13T13:24:06.573362728Z 2022/09/13 13:24:06 [notice] 1#1: start worker process 41
2022-09-13T13:24:06.651127107Z 2022/09/13 13:24:06 [notice] 1#1: start worker process 42
2022-09-13T13:24:16.651160189Z 172.17.0.1 - - [13/Sep/2022:13:24:16 +0000] "üE޶ EgóɚœÊì§y#3’•ÜQïê$¿# ƒ÷-,s!rê|®ß¡LZª4y³t«ÀÎ_¸çÿ'φ êêÀ+À/À,À0̨̩ÀÀœ/5“ŠŠ localhostÿ" 400 157 "-" "-" "-"
2022-09-13T13:24:16.116817914Z 172.17.0.1 - - [13/Sep/2022:13:24:16 +0000] "ü}©Dr{Œ;z‚­¼ŠzÂxßšæl?§àDoK‘'g»µ %»ýق?ۀ³TöcJ÷åÂÒ¼¢£ë½=R¼ƒ‰… ÊÊÀ+À/À,À0̨̩ÀÀœ/5“šš localhostÿ" 400 157 "-" "-" "-"
2022-09-13T13:24:39.117398081Z 172.17.0.1 - - [13/Sep/2022:13:24:39 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"
2022-09-13T13:24:39.117412408Z 2022/09/13 13:24:40 [error] 34#34: *3 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: "0.0.0.0:8080", referrer: "http://0.0.0.0:8080/"
2022-09-13T13:24:40.117419389Z 172.17.0.1 - - [13/Sep/2022:13:24:40 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://0.0.0.0:8080/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"
2022-09-13T13:25:00.117434249Z 172.17.0.1 - - [13/Sep/2022:13:25:00 +0000] "üâV$Zqi'×ü[€ïºåÇè÷&amp;3nSëÉì‘ÂØÑ‰ž¾ Ç?áúaΐ˜uã/ØRfOHì’+“\»±¿Òm°9 úúÀ+À/À,À0̨̩ÀÀœ/5“šš localhostÿ" 400 157 "-" "-" "-"
2022-09-13T13:25:00.223560881Z 172.17.0.1 - - [13/Sep/2022:13:25:00 +0000] "ü)šbCÙmñ†ëd"ÏÄE‡#~LÁ„µ‘k˜«lî[0 ÐÒ`…Æ‹…R‹‡êq{Pòû⨝IôtH™~Ê1-|Ž êêÀ+À/À,À0̨̩ÀÀœ/5“" 400 157 "-" "-" "-"
2022-09-13T13:26:25.223596738Z 172.17.0.1 - - [13/Sep/2022:13:26:28 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36" "-"

Paramos e removemos o contêiner

	
< > Input
Python
!docker rm -f proxy
Copied
>_ Output
			
proxy
	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 26 minutes ago Exited (137) 13 minutes ago alwaysup
5b633e9d838f ubuntu "bash" 31 minutes ago Exited (0) 27 minutes ago funny_mirzakhani
da16b3a85178 ubuntu "bash" 32 minutes ago Exited (0) 32 minutes ago hardcore_kare

Dados no Dockerlink image 83

Montagens bindlink image 84

Vamos ver os contêineres que temos parados

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 26 minutes ago Exited (137) 13 minutes ago alwaysup
5b633e9d838f ubuntu "bash" 31 minutes ago Exited (0) 28 minutes ago funny_mirzakhani
da16b3a85178 ubuntu "bash" 32 minutes ago Exited (0) 32 minutes ago hardcore_kare

Vamos eliminar os dois do Ubuntu em que o comando principal é o Bash e vamos deixar o que deixamos como não operação

	
< > Input
Python
!docker rm funny_mirzakhani
Copied
>_ Output
			
funny_mirzakhani
	
< > Input
Python
!docker rm hardcore_kare
Copied
>_ Output
			
hardcore_kare
	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce4d60427dcd ubuntu "tail -f /dev/null" 27 minutes ago Exited (137) 14 minutes ago alwaysup

Vamos voltar a executar o contêiner do Ubuntu que deixamos, isso é feito por meio do comando start

	
< > Input
Python
!docker start alwaysup
Copied
>_ Output
			
alwaysup

Nos metemos outra vez dentro do

	
< > Input
Python
!docker exec -it alwaysup bash
Copied
>_ Output
			
root@ce4d60427dcd:/#

No contêiner, posso criar uma nova pasta chamada dockerfolder

	
< > Input
Python
!mkdir dockerfolder
Copied

Se listarmos os arquivos, a nova pasta aparecerá

	
< > Input
Python
!ls
Copied
>_ Output
			
bin boot dev dockerfolder etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var

Se sairmos do contêiner

	
< > Input
Python
!exit
Copied
>_ Output
			
exit

E apagamos isso

	
< > Input
Python
!docker rm -f alwaysup
Copied
>_ Output
			
alwaysup

Se listarmos todos os contêineres, o último que criamos já não aparece.

	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Vamos a voltar a fazer tudo, mas primeiro vamos criar uma pasta no host na qual compartilharemos os dados com o contêiner

	
< > Input
Python
!mkdir dockerHostFolder
Copied

Vemos que dentro da pasta não há nada

	
< > Input
Python
!ls dockerHostFolder
Copied

Agora obtemos nosso caminho absoluto

	
< > Input
Python
!pwd
Copied
>_ Output
			
/home/wallabot/Documentos/web/portafolio/posts

Voltamos a criar o contêiner, mas adicionando a opção -v (bind mount). Em seguida, adiciona-se o caminho absoluto da pasta do host e o caminho absoluto da pasta no contêiner, -v <host path>:<container path>

	
< > Input
Python
!docker run -d --name alwaysup -v ~/Documentos/web/portafolio/posts/dockerHostFolder:/dockerContainerFolder ubuntu tail -f /dev/null
Copied
>_ Output
			
4ede4512c293bdcc155e9c8e874dfb4a28e5163f4d5c7ddda24ad2863f28921b

Entramos no contêiner, listamos os arquivos e já aparece a pasta que tínhamos criado

	
< > Input
Python
!docker exec -it alwaysup bash
Copied
>_ Output
			
root@4ede4512c293:/#
	
< > Input
Python
root@4ede4512c293:/# ls
Copied
>_ Output
			
bin dev etc lib lib64 media opt root sbin sys usr
boot dockerContainerFolder home lib32 libx32 mnt proc run srv tmp var

Vamos ao diretório do contêiner que compartilhamos, criamos um arquivo e saímos do contêiner

	
< > Input
Python
root@4ede4512c293:/# cd dockerContainerFolder
Copied
	
< > Input
Python
root@4ede4512c293:/dockerContainerFolder# touch bindFile.txt
Copied
	
< > Input
Python
root@4ede4512c293:/dockerContainerFolder# exit
Copied
>_ Output
			
exit

Vamos ver o que há dentro da pasta compartilhada

	
< > Input
Python
!ls dockerHostFolder
Copied
>_ Output
			
bindFile.txt

Mas ainda mais, se apagarmos o contêiner, o arquivo continua lá

	
< > Input
Python
!docker rm -f alwaysup
Copied
>_ Output
			
alwaysup
	
< > Input
Python
!ls dockerHostFolder
Copied
>_ Output
			
bindFile.txt

Se eu recriar um contêiner compartilhando as pastas, todos os arquivos estarão no contêiner

	
< > Input
Python
!docker run -d --name alwaysup -v ~/Documentos/web/portafolio/posts/dockerHostFolder:/dockerContainerFolder ubuntu tail -f /dev/null
Copied
>_ Output
			
6c021d37ea29d8b23fe5cd4968baa446085ae1756682f65340288b4c851c362d
	
< > Input
Python
!docker exec -it alwaysup bash
Copied
>_ Output
			
root@6c021d37ea29:/#
	
< > Input
Python
!root@6c021d37ea29:/# ls dockerContainerFolder/
Copied
>_ Output
			
bindFile.txt:/#

Eliminamos o contêiner

	
< > Input
Python
!docker rm -f alwaysup
Copied
>_ Output
			
alwaysup
	
< > Input
Python
!docker ps -a
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Volumeslink image 85

Os volumes foram criados como uma evolução dos bind mounts para oferecer mais segurança. Podemos listar todos os volumes do Docker por meio de docker volume ls

	
< > Input
Python
!docker volume ls
Copied
>_ Output
			
DRIVER VOLUME NAME

Vamos criar um novo volume para o contêiner do Ubuntu, para isso usamos o comando docker volume create <volume name>

	
< > Input
Python
!docker volume create ubuntuVolume
Copied
>_ Output
			
ubuntuVolume

Se voltarmos a listar os volumes, aparecerá o que acabamos de criar

	
< > Input
Python
!docker volume ls
Copied
>_ Output
			
DRIVER VOLUME NAME
local ubuntuVolume

No entanto, ele não aparece como uma pasta no sistema de arquivos do host. Com ls -d */ listamos todas as pastas

	
< > Input
Python
!ls -d */
Copied
>_ Output
			
dockerHostFolder/ __pycache__/

Vamos a voltar a criar um contêiner, mas agora vamos criá-lo com o volume que acabamos de criar com a opção --mount, indicando o volume de origem por meio de src=<volume name> (se o volume não existisse, o docker o criaria), a seguir o destino separado por uma ,, dst=<container path>, ou seja --mount src=<volume name>,dst=<container path>

	
< > Input
Python
!docker run -d --name alwaysup --mount src=ubuntuVolume,dst=/dockerVolumeFolder ubuntu tail -f /dev/null
Copied
>_ Output
			
42cdcddf4e46dc298a87b0570115e0b2fc900cb4c6db5eea22a61409b8cb271d

Uma vez criado, podemos ver os volumes do contêiner usando o comando inspect e filtrando por '{{.Mounts}}'

$ docker inspect --format '{{.Mounts}}' alwaysup
[
{
volume ubuntuVolume /var/lib/docker/volumes/ubuntuVolume/_data /dockerVolumeFolder local z true
}
]

Vemos que o volume se chama ubuntuVolume e também podemos ver o caminho onde ele está armazenado, neste caso em /var/lib/docker/volumes/ubuntuVolume/_data. Fazemos o mesmo que antes, entramos no contêiner, criamos um arquivo no caminho do volume, saímos e vemos no host se ele foi criado

$ docker exec -it alwaysup bash
root@42cdcddf4e46:/# touch dockerVolumeFolder/volumeFile.txt
root@42cdcddf4e46:/# exit
$ sudo ls /var/lib/docker/volumes/ubuntuVolume/_data
volumeFile.txt

O arquivo está criado

Inserir e extrair arquivos de um contêinerlink image 86

Primeiro vamos criar um arquivo que queremos copiar para dentro de um contêiner

	
< > Input
Python
!touch dockerHostFolder/text.txt
Copied

Entramos no contêiner

$ docker exec -it alwaysup bash
root@42cdcddf4e46:/#

Criamos uma nova pasta onde vamos copiar o arquivo e saímos

root@42cdcddf4e46:/# mkdir folderToCopy
root@42cdcddf4e46:/# ls
bin boot dev dockerVolumeFolder etc folderToCopy home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr varroot@42cdcddf4e46:/# exit
exit

Copiamos dentro do contêiner o arquivo por meio do comando cp, indicando o arquivo que **quero** copiar, o contêiner onde queremos copiá-lo e o caminho dentro do contêiner, docker cp <file> <container>:<container path>

	
< > Input
Python
!docker cp dockerHostFolder/text.txt alwaysup:/folderToCopy
Copied

Voltamos a entrar no contêiner e verificamos se o arquivo está lá

$ docker exec -it alwaysup bash
root@42cdcddf4e46:/# ls folderToCopy/text.txt

Saímos do contêiner

/# exit
exit

Agora vamos a extrair o arquivo do contêiner e vamos salvá-lo no host com outro nome, para isso usamos novamente o comando cp, mas indicando agora o contêiner, o caminho do arquivo no contêiner e o caminho e nome que queremos que o arquivo tenha no host, docker cp <container>:<docker file path> <host file path>

	
< > Input
Python
!docker cp alwaysup:/folderToCopy/text.txt dockerHostFolder/fileExtract.txt
Copied

Vemos que está no host

	
< > Input
Python
!ls dockerHostFolder
Copied
>_ Output
			
bindFile.txt fileExtract.txt text.txt

Embora o contêiner esteja parado, também é possível copiar arquivos

Por fim, removemos o contêiner

	
< > Input
Python
!docker rm -f alwaysup
Copied
>_ Output
			
alwaysup

Imagenslink image 87

Conceitos fundamentaislink image 88

As imagens são os arquivos ("templates") com toda a configuração para criar um contêiner. Cada vez que criamos um contêiner, ele é criado a partir de uma imagem. Quando criávamos contêineres novos, na primeira vez aparecia uma mensagem dizendo que não tínhamos a imagem e que ela seria baixada. No Docker Hub existem inúmeras imagens com todos os tipos de máquinas, mas para um ambiente de desenvolvimento muito específico podemos criar nosso próprio template para passá-lo a alguém e trabalhar em um contêiner com a mesma configuração que o nosso

Podemos ver todas as imagens que temos guardadas no nosso computador através do comando docker image ls

	
< > Input
Python
!docker image ls
Copied
>_ Output
			
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 2d389e545974 8 hours ago 142MB
ubuntu latest 2dc39ba059dc 11 days ago 77.8MB
hello-world latest feb5d9fea6a5 11 months ago 13.3kB

Podemos ver os tamanhos, e podemos ver como a de nginx ocupa muito e por isso demorou mais para ser baixada do que o resto

Outra coluna que podemos ver é a de TAG, isso indica a versão da imagem. Em todas aparece latest, isso quer dizer que é a última. Ou seja, no momento de baixá-la, nós baixamos a última versão que há no Docker Hub. Isso em um ambiente de desenvolvimento não é ideal, porque nós podemos baixar uma imagem do Ubuntu e, se não especificarmos a versão, é baixada a última, por exemplo a 20.04. Mas depois de um tempo alguém pode querer desenvolver contigo e baixar essa imagem, mas, ao não especificar a versão, será baixada novamente a última, que no caso pode ser a 22.04. Isso pode dar origem a problemas e a que coisas que para uma das pessoas funcione e para a outra não

Podemos ver todas as imagens que existem no Docker Hub acessando https://hub.docker.com/. Lá você poderá procurar a imagem que melhor se adapte ao projeto que você queira fazer. Se navegarmos até a imagem do Ubuntu, por exemplo, podemos ver as versões (tags) das imagens.

Vamos baixar, **mas não executar** uma imagem. Para isso usamos o comando docker pull <hub> <image name>:<tag>. Se não indicarmos o hub, ele fará o download do Docker Hub por padrão, mas podemos indicar outro, por exemplo um privado da nossa organização. Também, se não indicarmos o tag, por padrão baixará a última versão

	
< > Input
Python
!docker pull ubuntu:20.04
Copied
>_ Output
			
20.04: Pulling from library/ubuntu
Digest: sha256:35ab2bf57814e9ff49e365efd5a5935b6915eede5c7f8581e9e1b85e0eecbe16[1A
Status: Downloaded newer image for ubuntu:20.04
docker.io/library/ubuntu:20.04

Se voltarmos a listar as imagens, vemos que agora temos duas imagens do Ubuntu, uma com a tag 20.04 e outra com a tag latest

	
< > Input
Python
!docker image ls
Copied
>_ Output
			
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 2d389e545974 8 hours ago 142MB
ubuntu latest 2dc39ba059dc 11 days ago 77.8MB
ubuntu 20.04 a0ce5a295b63 11 days ago 72.8MB
hello-world latest feb5d9fea6a5 11 months ago 13.3kB

Criar imagens por meio de Dockerfilelink image 89

Criamos um diretório no host chamado dockerImages para trabalhar nele

	
< > Input
Python
!mkdir dockerImages
Copied

Criamos um arquivo Dockerfile com o qual criaremos uma imagem

	
< > Input
Python
!touch dockerImages/Dockerfile
Copied

Abrimos o arquivo criado com nosso editor preferido e escrevemos o seguinte:

FROM ubuntu:latest

Isso diz ao Docker para criar a imagem com base na imagem latest do Ubuntu

A seguir, escrevemos um comando que será executado em tempo de compilação

RUN touch /test.txt

Isso quer dizer que, quando o Dockerfile for compilado, esse comando será executado, mas não quando o contêiner da imagem for executado

No final, o Dockerfile fica assim:

FROM ubuntu:latest
RUN touch /test.txt

Compilamos o Dockerfile mediante o comando build, com a opção -t podemos atribuir-lhe um tag. Por último, é preciso indicar o caminho do contexto de build; mais adiante explicaremos isso

	
< > Input
Python
!docker build -t ubuntu:test ./dockerImages
Copied
>_ Output
			
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM ubuntu:latest
---&gt; 2dc39ba059dc
Step 2/2 : RUN touch /test.txt
---&gt; Using cache
---&gt; a78cf3ea16d8
Successfully built a78cf3ea16d8
Successfully tagged ubuntu:test
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Como vemos, ele é compilado em 2 etapas, cada uma tem um id, cada um desses ids são camadas da imagem, isso também veremos mais adiante

Voltamos a ver as imagens que temos guardadas no nosso computador e aparece a que acabámos de criar

	
< > Input
Python
!docker image ls
Copied
>_ Output
			
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu test a78cf3ea16d8 8 minutes ago 77.8MB
nginx latest 2d389e545974 8 hours ago 142MB
ubuntu latest 2dc39ba059dc 11 days ago 77.8MB
ubuntu 20.04 a0ce5a295b63 11 days ago 72.8MB
hello-world latest feb5d9fea6a5 11 months ago 13.3kB

Executamos o contêiner a partir da imagem que acabamos de criar

$ docker run -it ubuntu:test
root@b57b9d4eedeb:/#

Entramos no bash do contêiner. Como dissemos, o comando RUN é executado em tempo de compilação da imagem, portanto o arquivo que pedimos para ser criado deve estar em nosso contêiner

root@b57b9d4eedeb:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys test.txt tmp usr var

É importante entender que esse arquivo foi criado quando a imagem foi construída, ou seja, a imagem do contêiner já tem esse arquivo. Ele não é criado quando o contêiner é iniciado

Saímos do contêiner

root@b57b9d4eedeb:/# exit
exit

Como já temos uma imagem, poderíamos enviá-la para o Docker Hub, mas vamos listar as imagens novamente antes disso.

	
< > Input
Python
!docker image ls
Copied
>_ Output
			
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu test a78cf3ea16d8 20 minutes ago 77.8MB
nginx latest 2d389e545974 8 hours ago 142MB
ubuntu latest 2dc39ba059dc 11 days ago 77.8MB
ubuntu 20.04 a0ce5a295b63 11 days ago 72.8MB
hello-world latest feb5d9fea6a5 11 months ago 13.3kB

Se virmos, ele está nos dizendo que a imagem que acabamos de criar pertence ao repositório do ubuntu, mas nós não temos acesso ao repositório do ubuntu, por isso no Docker Hub precisamos criar uma conta para poder enviar a imagem para o nosso repositório. No meu caso, meu repositório se chama maximofn, então altero o repositório da imagem por meio do comando tag, indicando a imagem da qual queremos mudar o repositório e o novo repositório. No novo repositório, costuma-se indicar o nome do repositório seguido do tipo de imagem e da tag, no meu caso maximofn/ubuntu:test

	
< > Input
Python
!docker tag ubuntu:test maximofn/ubuntu:test
Copied

Se agora voltarmos a listar as imagens

	
< > Input
Python
!docker image ls
Copied
>_ Output
			
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu test a78cf3ea16d8 24 minutes ago 77.8MB
maximofn/ubuntu test a78cf3ea16d8 24 minutes ago 77.8MB
nginx latest 2d389e545974 8 hours ago 142MB
ubuntu latest 2dc39ba059dc 11 days ago 77.8MB
ubuntu 20.04 a0ce5a295b63 11 days ago 72.8MB
hello-world latest feb5d9fea6a5 11 months ago 13.3kB

Agora devemos fazer login no Docker Hub para poder enviar a imagem; para isso usamos o comando login

$ docker login
Faça login com seu Docker ID para enviar e baixar imagens do Docker Hub. Se você não tiver um Docker ID, acesse https://hub.docker.com para criar um.
Nome de usuário: maximofn
Senha:

Login realizado com sucesso

Agora podemos enviar a imagem por meio do comando push

	
< > Input
Python
!docker push maximofn/ubuntu:test
Copied
>_ Output
			
The push refers to repository [docker.io/maximofn/ubuntu]
06994357: Preparing
06994357: Pushed from library/ubuntu test: digest: sha256:318d83fc3c35ff930d695b0dc1c5ad1b0ea54e1ec6e3478b8ca85c05fd793c4e size: 735

Subiu apenas a primeira camada; a segunda, como a usei a partir da imagem do Ubuntu, o que faz é colocar um ponteiro para essa imagem para não ter camadas enviadas mais de uma vez

É preciso ter em conta que este repositório é público, pelo que não deves enviar imagens com dados sensíveis. Além disso, se uma imagem não tiver uso em 6 meses, será apagada

O sistema de camadaslink image 90

Através do comando history podemos ver as camadas de uma imagem. Se virmos as camadas da imagem que acabamos de criar, usamos docker history ubuntu:test

	
< > Input
Python
!docker history ubuntu:test
Copied
>_ Output
			
IMAGE CREATED CREATED BY SIZE COMMENT
a78cf3ea16d8 3 minutes ago /bin/sh -c touch /test.txt 0B
2dc39ba059dc 12 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
&lt;missing&gt; 12 days ago /bin/sh -c #(nop) ADD file:a7268f82a86219801… 77.8MB

Vemos que a primeira camada tem o comando que introduzimos no Dockerfile, além disso diz que foi criada há 3 minutos. No entanto, o restante das camadas foram criadas há 12 dias, e são as camadas da imagem do Ubuntu na qual nos baseamos

Ao Dockerfile que criamos anteriormente, adicionamos a linha

RUN rm /test.txt

No final, o Dockerfile fica assim:

FROM ubuntu:latest
RUN touch /test.txtRUN rm /test.txt

Se recompilarmos, veremos o que acontece

	
< > Input
Python
!docker build -t ubuntu:test ./dockerImages
Copied
>_ Output
			
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM ubuntu:latest
---&gt; 2dc39ba059dc
Step 2/3 : RUN touch /test.txt
---&gt; Using cache
---&gt; a78cf3ea16d8
Step 3/3 : RUN rm /test.txt
---&gt; Running in c2e6887f2025
Removing intermediate container c2e6887f2025
---&gt; 313243a9b573
Successfully built 313243a9b573
Successfully tagged ubuntu:test
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Como vemos, há uma camada a mais com a nova linha que adicionamos. Se voltarmos a ver as camadas da imagem com history

	
< > Input
Python
!docker history ubuntu:test
Copied
>_ Output
			
IMAGE CREATED CREATED BY SIZE COMMENT
313243a9b573 About a minute ago /bin/sh -c rm /test.txt 0B
a78cf3ea16d8 3 minutes ago /bin/sh -c touch /test.txt 0B
2dc39ba059dc 12 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
&lt;missing&gt; 12 days ago /bin/sh -c #(nop) ADD file:a7268f82a86219801… 77.8MB

Vemos que as primeiras camadas são iguais às anteriores e ele adicionou uma nova camada com o novo comando

Pesquisa no Docker Hublink image 91

Não é necessário acessar a página do Docker Hub para procurar imagens; isso pode ser feito pelo terminal. Para isso, usamos o comando docker search <image name>

	
< > Input
Python
!docker search ubuntu
Copied
>_ Output
			
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 16425 [OK]
websphere-liberty WebSphere Liberty multi-architecture images … 297 [OK]
open-liberty Open Liberty multi-architecture images based… 62 [OK]
neurodebian NeuroDebian provides neuroscience research s… 104 [OK]
ubuntu-debootstrap DEPRECATED; use "ubuntu" instead 52 [OK]
ubuntu-upstart DEPRECATED, as is Upstart (find other proces… 115 [OK]
ubuntu/nginx Nginx, a high-performance reverse proxy &amp; we… 98
ubuntu/squid Squid is a caching proxy for the Web. Long-t… 66
ubuntu/cortex Cortex provides storage for Prometheus. Long… 4
ubuntu/apache2 Apache, a secure &amp; extensible open-source HT… 60
ubuntu/kafka Apache Kafka, a distributed event streaming … 35
ubuntu/mysql MySQL open source fast, stable, multi-thread… 53
ubuntu/bind9 BIND 9 is a very flexible, full-featured DNS… 62
ubuntu/prometheus Prometheus is a systems and service monitori… 51
ubuntu/zookeeper ZooKeeper maintains configuration informatio… 12
ubuntu/postgres PostgreSQL is an open source object-relation… 31
ubuntu/redis Redis, an open source key-value store. Long-… 19
ubuntu/grafana Grafana, a feature rich metrics dashboard &amp; … 9
ubuntu/memcached Memcached, in-memory keyvalue store for smal… 5
ubuntu/dotnet-aspnet Chiselled Ubuntu runtime image for ASP.NET a… 11
ubuntu/dotnet-deps Chiselled Ubuntu for self-contained .NET &amp; A… 11
ubuntu/prometheus-alertmanager Alertmanager handles client alerts from Prom… 9
ubuntu/dotnet-runtime Chiselled Ubuntu runtime image for .NET apps… 10
ubuntu/cassandra Cassandra, an open source NoSQL distributed … 2
ubuntu/telegraf Telegraf collects, processes, aggregates &amp; w… 4

Uso do Docker para criar aplicativoslink image 92

Exposição de portaslink image 93

Anteriormente vimos como podíamos vincular uma porta de um contêiner a uma porta do computador (-p 8080:80). Mas, para que isso seja possível, ao criar a imagem é necessário expor a porta; isso é feito adicionando ao Dockerfile a linha EXPOSE <port>, no caso anterior

EXPOSE 80

Usar imagens como base que já tenham portas expostas

Reuso do cache de camadas ao compilarlink image 94

Ao compilarmos uma imagem, se alguma das camadas que definimos já tiver sido compilada antes, o Docker detecta isso e as utiliza, não voltando a compilá-las. Se voltarmos a compilar a imagem que definimos no Dockerfile, agora levará muito pouco tempo, porque todas as camadas já estão compiladas e o Docker não as recompila.

	
< > Input
Python
!docker build -t ubuntu:test ./dockerImages
Copied
>_ Output
			
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM ubuntu:latest
---&gt; 2dc39ba059dc
Step 2/3 : RUN touch /test.txt
---&gt; Using cache
---&gt; a78cf3ea16d8
Step 3/3 : RUN rm /test.txt
---&gt; Using cache
---&gt; 313243a9b573
Successfully built 313243a9b573
Successfully tagged ubuntu:test
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Na segunda e terceira camada aparece o texto Using cache

Como este é um caderno Jupyter, ao executar as células, ele fornece informações sobre o tempo que levam para serem executadas. Na vez anterior que compilei a imagem, demorou 1,4 segundos, enquanto agora demorou 0,5 segundos.

Mas se agora eu alterar o Dockerfile, e na primeira linha, onde dizia que nos baseávamos na última versão do Ubuntu e mudamos para a versão 20.04

FROM ubuntu:20.04

No final, o Dockerfile fica assim:

FROM ubuntu:20.04
RUN touch /test.txtRUN rm /test.txt

Se recompilarmos, vai demorar muito mais

	
< > Input
Python
!docker build -t ubuntu:test ./dockerImages
Copied
>_ Output
			
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM ubuntu:20.04
---&gt; a0ce5a295b63
Step 2/3 : RUN touch /test.txt
---&gt; Running in a40fe8df2c0d
Removing intermediate container a40fe8df2c0d
---&gt; 0bb9b452c11f
Step 3/3 : RUN rm /test.txt
---&gt; Running in 2e14919f3685
Removing intermediate container 2e14919f3685
---&gt; fdc248fa833b
Successfully built fdc248fa833b
Successfully tagged ubuntu:test
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

Demorou 1,9 segundos e já não aparece o texto Using cache

Ao alterar a primeira camada, o Docker recompila todas as camadas. Isso pode ser um problema porque, ao desenvolver código, pode ocorrer o seguinte caso

  • Desenvolvemos o código no nosso computador
  • Ao construir a imagem, copiamos todo o código do nosso computador para o contêiner
  • Depois pedimos à imagem que instale as bibliotecas necessárias

Isso pode fazer com que, ao alterar qualquer parte do código, ao ter que recompilar a imagem, a camada na qual as bibliotecas são instaladas tenha que ser recompilada, já que uma camada anterior foi alterada

Para resolver isso, a ideia seria que, na hora de criar a imagem, primeiro peçamos que as bibliotecas sejam instaladas e depois que o código do nosso computador seja copiado para o contêiner. Assim, cada vez que mudarmos o código e voltarmos a compilar a imagem, só será recompilada a camada em que o código é copiado, de modo que a compilação será mais rápida

Poderás pensar que é melhor compartilhar uma pasta entre o host e o contêiner (bind mount) onde teremos o código e assim não é preciso recompilar a imagem toda vez que alterarmos o código. E a resposta é que isso é verdade, só coloquei este exemplo porque é muito fácil de entender, mas é para ilustrar que, na hora de criar imagens, é preciso pensar bem, de forma que, se for necessário recompilá-la, recompila-se o número mínimo de camadas

Escrever corretamente um Dockerfilelink image 95

Como vimos, o Docker não recompila camadas de um Dockerfile se já as compilou antes, então as carrega do cache. Vamos ver qual é a forma correta de escrever um Dockerfile para aproveitarmos isso.

Vamos a partir deste Dockerfile para ir comentando possíveis correções

FROM ubuntu
      COPY ./sourceCode /sourceCode
      RUN apt-get update
      RUN apt-get install -y python3 sshCMD ["python3", "/sourceCode/sourceApp/app.py"]

Como se pode ver, parte-se de uma imagem do Ubuntu, copia-se a pasta com o código, atualizam-se os repositórios, instala-se o Python, instala-se também o ssh e executa-se a aplicação

Copie o código antes da execuçãolink image 96

Como dissemos antes, se primeiro copiarmos o código e depois instalarmos o Python, toda vez que fizermos uma alteração no código e compilarmos a imagem, ela será compilada por completo. Mas, se copiarmos o código depois de instalar o Python, toda vez que mudarmos o código e compilarmos a imagem, ela só compilará a partir da cópia do código e não voltará a instalar o Python. Portanto, o Dockerfile deveria passar a ser assim

FROM ubuntu
      RUN apt-get update
      RUN apt-get install -y python3 sshCOPY ./sourceCode /sourceCode
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Copiar apenas o código necessáriolink image 97

Estamos copiando a pasta com todo o código, mas talvez dentro tenhamos código de que não precisamos, por isso devemos copiar apenas o código de que realmente precisemos para a aplicação; dessa maneira, a imagem ocupará menos memória. Assim, o Dockerfile ficaria assim

FROM ubuntu
      RUN apt-get update
      RUN apt-get install -y python3 sshCOPY ./sourceCode/sourceApp /sourceCode/sourceApp
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Atualizar repositórios e instalar Python na mesma linhalink image 98

Estamos atualizando os repositórios em uma linha e, em outra, instalando python3.

FROM ubuntu
      RUN apt-get update && apt-get install -y python3 ssh
      COPY ./sourceCode/sourceApp /sourceCode/sourceApp
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Não instalar sshlink image 99

Instalámos SSH na imagem para poder depurar caso seja necessário, mas isso faz com que a imagem ocupe mais memória. Caso seja necessário depurar, deveríamos entrar no contentor, instalar SSH e, em seguida, depurar. Por isso, removemos a instalação do SSH

FROM ubuntu
      RUN apt-get update && apt-get install -y python3
      COPY ./sourceCode/sourceApp /sourceCode/sourceApp
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Usar --no-install-recommendslink image 100

Quando instalamos algo no Ubuntu, ele instala pacotes recomendados, mas que não precisamos, fazendo com que a imagem ocupe mais espaço. Então, para evitar isso, adicionamos à instalação --no-install-recommends

FROM ubuntu
      RUN apt-get update && apt-get install -y python3 --no-install-recommends
      COPY ./sourceCode/sourceApp /sourceCode/sourceApp
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Apagar lista de repositórios atualizadoslink image 101

Atualizamos a lista de repositórios e instalamos o python, mas, uma vez feito isso, já não precisamos da lista de repositórios atualizados, porque o único efeito será fazer com que a imagem ocupe mais espaço; por isso, removemo-los depois de instalar o python e na mesma linha.

FROM ubuntu
      RUN apt-get update && apt-get install -y python3 --no-install-recommends && rm -rf /var/lib/apt/lists/*
      COPY ./sourceCode/sourceApp /sourceCode/sourceApp
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Usar uma imagem de Pythonlink image 102

Tudo o que fizemos de atualizar a lista de pacotes e instalar Python não é necessário, já que já existem imagens de Python sobre Ubuntu, que seguramente também seguiram boas práticas, que até o fizeram melhor do que nós e que foi escaneada em busca de vulnerabilidades pelo Docker Hub. Por isso removemos tudo isso e partimos de uma imagem de Python

DE python
      COPY ./sourceCode/sourceApp /sourceCode/sourceAppCMD ["python3", "/sourceCode/sourceApp/app.py"]

Especificar a imagem do Pythonlink image 103

Ao não especificar a imagem do Python, está sendo baixada a mais recente, mas, dependendo de quando o contêiner for construído, pode-se baixar uma ou outra. Portanto, é necessário adicionar o tag com a versão do Python desejada

FROM python:3.9.18
      COPY ./sourceCode/sourceApp /sourceCode/sourceAppCMD ["python3", "/sourceCode/sourceApp/app.py"]

Escolher uma tag pequenalink image 104

Escolhemos a tag 3.9.18, mas essa versão do Python tem uma série de bibliotecas que talvez não precisemos; por isso, podemos usar as versões 3.9.18-slim, que têm muito menos bibliotecas instaladas, ou a versão 3.9.18-alpine, que é uma versão do Python sobre Alpine e não sobre Ubuntu. Alpine é uma distribuição Linux muito leve, que tem muito poucos pacotes instalados e que costuma ser muito usada em contêineres Docker para ocuparem muito pouco espaço

A imagem Python 3.9.18 ocupa 997 MB, a 3.9.18-slim ocupa 126 MB e a 3.9.18-alpine ocupa 47,8 MB

FROM python:3.9.18-alpine
      COPY ./sourceCode/sourceApp /sourceCode/sourceApp
      CMD ["python3", "/sourceCode/sourceApp/app.py"]

Indicar o workspacelink image 105

Em vez de indicar o caminho da imagem /sourceCode/sourceApp, estabelecemos que esse caminho seja o workspace da imagem. Assim, quando copiarmos o código ou executarmos a aplicação, não é necessário indicar o caminho

FROM python:3.9.18-alpine
      WORKDIR /sourceCode/sourceApp
      COPY ./sourceCode/sourceApp .
      CMD ["python3", "app.py"]

Indicar o workspacelink image 106

Em vez de indicar o caminho da imagem /sourceCode/sourceApp, estabelecemos que esse caminho seja o workspace da imagem. Assim, quando copiarmos o código ou executarmos a aplicação, não é necessário indicar o caminho

FROM python:3.9.18-alpine
      WORKDIR /sourceCode/sourceApp
      COPY ./sourceCode/sourceApp .
      CMD ["python3", "app.py"]

Código compartilhado em uma pasta bind mountlink image 107

Tínhamos criado uma pasta chamada dockerHostFolder na qual tínhamos compartilhado arquivos entre o host e um contêiner. Dentro, além disso, deveriam haver três arquivos

	
< > Input
Python
!ls dockerHostFolder
Copied
>_ Output
			
bindFile.txt fileExtract.txt text.txt

Vamos aproveitar o arquivo text.txt para ver isso. Vamos ver o que há dentro de text.txt

	
< > Input
Python
!cat dockerHostFolder/text.txt
Copied

Não há saída, o arquivo está vazio. Vamos criar novamente um contêiner do Ubuntu compartilhando a pasta dockerHostFolder

	
< > Input
Python
!docker run --name alwaysup -d -v ~/Documentos/web/portafolio/posts/dockerHostFolder:/dockerContainerFolder ubuntu tail -f /dev/null
Copied
>_ Output
			
24adbded61f507cdf7f192eb5e246e43ee3ffafc9944b7c57918eb2d547dff19

Vemos que o contêiner está em execução

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
24adbded61f5 ubuntu "tail -f /dev/null" 16 seconds ago Up 15 seconds alwaysup

Entramos no contêiner, vemos que está text.txt e que está vazio

$ docker exec -it alwaysup bash
root@24adbded61f5:/# ls dockerContainerFolder/
bindFile.txt fileExtract.txt text.txt
root@24adbded61f5:/# cat dockerContainerFolder/text.txt
root@24adbded61f5:/#

Agora abrimos no host o arquivo text.txt com o editor de textos que quisermos, escrevemos Hola mundo e salvamos. Se agora virmos o que há dentro do arquivo no contêiner, veremos o mesmo texto

root@24adbded61f5:/# cat dockerContainerFolder/text.txt
Olá mundo

Agora editamos o arquivo no contêiner e saímos do contêiner

root@24adbded61f5:/# echo hola contenedor > dockerContainerFolder/text.txt
root@24adbded61f5:/# cat dockerContainerFolder/text.txt
olá contêiner
root@24adbded61f5:/# exit
exit

Se olharmos para o arquivo no host, veremos o texto que escrevemos no contêiner

	
< > Input
Python
!cat dockerHostFolder/text.txt
Copied
>_ Output
			
hola contenedor

Apagamos o contêiner

	
< > Input
Python
!docker rm -f alwaysup
Copied
>_ Output
			
alwaysup

Conectar contêineres por redelink image 108

No caso de quisermos ter vários contêineres em execução e quisermos que eles se comuniquem, podemos fazer com que se comuniquem por rede. O Docker nos dá a possibilidade de fazer isso por meio de suas redes virtuais

Vamos ver quais redes o Docker tem por meio do comando docker network ls

	
< > Input
Python
!docker network ls
Copied
>_ Output
			
NETWORK ID NAME DRIVER SCOPE
de6e8b7b737e bridge bridge local
da1f5f6fccc0 host host local
d3b0d93993c0 none null local

Vemos que por padrão o Docker tem três redes

  • bridge: Está por retrocompatibilidade com versões anteriores, mas não deveríamos usá-la já
  • host: É a rede do host
  • none: Esta é a opção que devemos usar se quisermos que um contêiner não tenha acesso à Internet

Podemos criar novas redes às quais outros contêineres possam se conectar; para isso usamos o comando docker network create <name>, para que outros contêineres possam se conectar também devemos adicionar a opção --attachable

	
< > Input
Python
!docker network create --attachable myNetwork
Copied
>_ Output
			
2f6f3ddbfa8642e9f6819aa0965c16339e9e910be7bcf56ebb718fcac324cc27

Podemos inspecioná-la mediante o comando docker network inspect <name>

	
< > Input
Python
!docker network inspect myNetwork
Copied
>_ Output
			
[
{
"Name": "myNetwork",
"Id": "2f6f3ddbfa8642e9f6819aa0965c16339e9e910be7bcf56ebb718fcac324cc27",
"Created": "2022-09-14T15:20:08.539830161+02: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": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]

Agora precisamos criar dois contêineres para que possam se comunicar.

Vamos a criar um novo contêiner, que chamaremos container1, com uma pasta compartilhada e que em seu interior se chamará folder1

	
< > Input
Python
!docker run --name container1 -d -v ~/Documentos/web/portafolio/posts/dockerHostFolder:/folder1 ubuntu tail -f /dev/null
Copied
>_ Output
			
a5fca8ba1e4ff0a67002f8f1b8cc3cd43185373c2a7e295546f774059ad8dd1a

Agora criamos outro contêiner, chamado container2, com outra pasta compartilhada, mas que se chame folder2

	
< > Input
Python
!docker run --name container2 -d -v ~/Documentos/web/portafolio/posts/dockerHostFolder:/folder2 ubuntu tail -f /dev/null
Copied
>_ Output
			
6c8dc18315488ef686f7548516c19b3d716728dd8a173cdb889ec0dd082232f9

Vemos os contêineres em execução e vemos que estão os dois

	
< > Input
Python
!docker ps
Copied
>_ Output
			
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6c8dc1831548 ubuntu "tail -f /dev/null" 3 seconds ago Up 2 seconds container2
a5fca8ba1e4f ubuntu "tail -f /dev/null" 4 seconds ago Up 3 seconds container1

Agora temos que conectar os contêineres à rede; para isso usamos o comando docker network connect <network name> <container name>

	
< > Input
Python
!docker network connect myNetwork container1
Copied
	
< > Input
Python
!docker network connect myNetwork container2
Copied

Para verificar se foram conectados corretamente, podemos inspecionar a rede, mas filtrando pelos contêineres conectados

$ docker network inspect --format '{{.Containers}}' myNetwork
map
[
6c8dc18315488ef686f7548516c19b3d716728dd8a173cdb889ec0dd082232f9:
{
container2
f828d211e894f7a5a992ce41a2a0def8e2424e9737fb4e1485fc09cc2d607b69
02:42:ac:12:00:03
172.18.0.3/16
}
a5fca8ba1e4ff0a67002f8f1b8cc3cd43185373c2a7e295546f774059ad8dd1a:
{
container1
cff762e6286ebc169804b2a675bbff904102de796751d367c18d4b490c994c45
02:42:ac:12:00:02
172.18.0.2/16
}
]

Como podemos ver, o contêiner container1 tem o IP 172.18.0.2 e o contêiner container2 tem o IP 172.18.0.3

Entramos no contêiner container1 e instalamos ping

$ docker exec -it container1 bash
root@a5fca8ba1e4f:/# apt update
...
root@a5fca8ba1e4f:/# apt install iputils-ping
...
root@a5fca8ba1e4f:/#

Entramos no contêiner container2 e instalamos ping

$ docker exec -it container2 bash
root@a5fca8ba1e4f:/# apt update
...
root@a5fca8ba1e4f:/# apt install iputils-ping
...
root@a5fca8ba1e4f:/#

Agora, a partir do contêiner container1, fazemos um ping para o IP 172.18.0.3, que pertence ao contêiner container2

root@a5fca8ba1e4f:/# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes de dados.
64 bytes de 172.18.0.3: icmp_seq=1 ttl=64 time=0.115 ms
64 bytes de 172.18.0.3: icmp_seq=2 ttl=64 time=0.049 ms
64 bytes de 172.18.0.3: icmp_seq=3 ttl=64 time=0.056 ms
64 bytes de 172.18.0.3: icmp_seq=4 ttl=64 time=0.060 ms
^C
--- estatísticas de ping de 172.18.0.3 ---
4 pacotes transmitidos, 4 recebidos, 0% de perda de pacotes, tempo 3068ms
rtt min/avg/max/mdev = 0.049/0.070/0.115/0.026 ms

E, a partir do contêiner container2, fazemos um ping para o IP 172.18.0.2, que pertence ao contêiner container1

root@6c8dc1831548:/# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes de dados.
64 bytes de 172.18.0.2: icmp_seq=1 ttl=64 time=0.076 ms
64 bytes de 172.18.0.2: icmp_seq=2 ttl=64 time=0.045 ms
64 bytes de 172.18.0.2: icmp_seq=3 ttl=64 time=0.049 ms
64 bytes de 172.18.0.2: icmp_seq=4 ttl=64 time=0.051 ms
^C
--- estatísticas de ping de 172.18.0.2 ---
4 pacotes transmitidos, 4 recebidos, 0% de perda de pacotes, tempo 3074ms
rtt min/avg/max/mdev = 0.045/0.055/0.076/0.012 ms

Mas há uma coisa melhor que o Docker nos permite fazer: se eu não souber o IP do contêiner ao qual quero me conectar, em vez de escrever seu IP, posso escrever seu nome

Agora, a partir do contêiner container1, fazemos um ping para o IP de container2

root@a5fca8ba1e4f:/# ping container2
PING container2 (172.18.0.3) 56(84) bytes de dados.
64 bytes de container2.myNetwork (172.18.0.3): icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from container2.myNetwork (172.18.0.3): icmp_seq=2 ttl=64 time=0.050 ms
64 bytes de container2.myNetwork (172.18.0.3): icmp_seq=3 ttl=64 time=0.052 ms
64 bytes de container2.myNetwork (172.18.0.3): icmp_seq=4 ttl=64 time=0.053 ms
^C
--- estatísticas de ping do container2 ---
4 pacotes transmitidos, 4 recebidos, 0% de perda de pacotes, tempo 3071ms
rtt min/avg/max/mdev = 0.048/0.050/0.053/0.002 ms

Como vemos, o Docker sabe que o IP do contêiner container2 é 172.18.0.3

E do contêiner container2 fazemos um ping para o IP de container1

root@6c8dc1831548:/# ping container1
PING container1 (172.18.0.2) 56(84) bytes de dados.
64 bytes de container1.myNetwork (172.18.0.2): icmp_seq=1 ttl=64 tiempo=0.051 ms
64 bytes from container1.myNetwork (172.18.0.2): icmp_seq=2 ttl=64 time=0.058 ms
64 bytes de container1.myNetwork (172.18.0.2): icmp_seq=3 ttl=64 time=0.052 ms
64 bytes de container1.myNetwork (172.18.0.2): icmp_seq=4 ttl=64 time=0.056 ms
^C
--- estatísticas de ping do container1 ---
4 pacotes transmitidos, 4 recebidos, 0% de perda de pacotes, tempo 3057ms
rtt min/média/máx/desvio = 0.051/0.054/0.058/0.003 ms

Como vemos, o Docker sabe que o IP do contêiner container1 é 172.18.0.2

Saímos dos contêineres e os apagamos

	
< > Input
Python
!docker rm -f container1 container2
Copied
>_ Output
			
container1
container2

Também apagamos a rede que criamos

	
< > Input
Python
!docker network rm myNetwork
Copied
>_ Output
			
myNetwork

Uso de GPUslink image 109

Para poder usar as GPUs do host dentro dos contêineres Docker, é necessário realizar os passos descritos na página de instalação do Nvidia container toolkit

Configurar o repositório e a chave GPGlink image 110

Temos que configurar o repositório do nvidia container toolkit e a chave GPG; para isso executamos o seguinte comando no console

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
&& curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' |
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

Instalação do nvidia container toolkitlink image 111

Uma vez que atualizamos o repositório e a chave, atualizamos os repositórios por meio do comando

sudo apt update

E instalamos nvidia container toolkit

sudo apt install -y nvidia-docker2

Reinicialização do Dockerlink image 112

Uma vez terminemos, temos que reiniciar o daemon do Docker mediante

sudo systemctl restart docker

Uso de GPUslink image 113

Agora que configuramos o Docker para poder usar as GPUs do host dentro dos contêineres, podemos testá-lo usando a opção --gpus all. Se houver mais de uma GPU e quiser usar apenas 1, isso deve ser especificado, mas por enquanto aqui só explicamos como usar todas

Criamos um contêiner que não vai ser executado em segundo plano, mas sim o que ele vai fazer é executar o comando nvidia-smi para que possamos ver se ele tem acesso às GPUs

	
< > Input
Python
!docker run --name container_gpus --gpus all ubuntu nvidia-smi
Copied
>_ Output
			
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
6a12be2b: Pull complete .54MB/29.54MBBDigest: sha256:aabed3296a3d45cede1dc866a24476c4d7e093aa806263c27ddaadbdce3c1054
Status: Downloaded newer image for ubuntu:latest
Mon Sep 4 07:10:36 2023
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 510.39.01 Driver Version: 510.39.01 CUDA Version: 11.6 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 Quadro T1000 On | 00000000:01:00.0 Off | N/A |
| N/A 44C P0 15W / N/A | 9MiB / 4096MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 2545 G 4MiB |
| 0 N/A N/A 3421 G 4MiB |
+-----------------------------------------------------------------------------+

Apagamos o contêiner

	
< > Input
Python
!doker rm container_gpus
Copied

---

➡️ **Continue na Parte 2: Docker Compose e temas avançados**, onde você orquestrará vários contêineres ao mesmo tempo e aprofundará em Docker.

Continuar lendo

Últimos posts -->

Você viu esses projetos?

Gymnasia

Gymnasia Gymnasia
React Native
Expo
TypeScript
FastAPI
Next.js
OpenAI
Anthropic

Aplicativo móvel de treino pessoal com assistente de IA, biblioteca de exercícios, acompanhamento de rotinas, dieta e medidas corporais

Horeca chatbot

Horeca chatbot Horeca chatbot
Python
LangChain
PostgreSQL
PGVector
React
Kubernetes
Docker
GitHub Actions

Chatbot conversacional para cozinheiros de hotéis e restaurantes. Um cozinheiro, gerente de cozinha ou serviço de quarto de um hotel ou restaurante pode falar com o chatbot para obter informações sobre receitas e menus. Mas também implementa agentes, com os quais pode editar ou criar novas receitas ou menus

Naviground

Naviground Naviground
Ver todos os projetos -->
>_ Disponível para projetos

Tem um projeto com IA?

Vamos conversar.

maximofn@gmail.com

Especialista em Machine Learning e Inteligência Artificial. Desenvolvo soluções com IA generativa, agentes inteligentes e modelos personalizados.

Quer assistir alguma palestra?

Últimas palestras -->

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Flow edit

Flow edit Flow edit

Edite imagens com este modelo de Flow. Baseado em SD3 ou FLUX, você pode editar qualquer imagem e gerar novas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos os contêineres -->
>_ Disponível para projetos

Tem um projeto com IA?

Vamos conversar.

maximofn@gmail.com

Especialista em Machine Learning e Inteligência Artificial. Desenvolvo soluções com IA generativa, agentes inteligentes e modelos personalizados.

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

HuggingFace

Dataset com piadas em inglês

Uso: Fine-tuning de modelos de geração de texto humorístico

231K linhas 2 colunas 45 MB
Ver no HuggingFace →

opus100

HuggingFace

Dataset com traduções de inglês para espanhol

Uso: Treinamento de modelos de tradução inglês-espanhol

1M linhas 2 colunas 210 MB
Ver no HuggingFace →

netflix_titles

HuggingFace

Dataset com filmes e séries da Netflix

Uso: Análise de catálogo Netflix e sistemas de recomendação

8.8K linhas 12 colunas 3.5 MB
Ver no HuggingFace →
Ver mais datasets -->