Introdução
O Docker revolucionou o desenvolvimento de aplicações, permitindo que os desenvolvedores criem, implementem e executem aplicações em ambientes isolados, chamados de containers. Usuários de Mac podem, por vezes, encontrar o erro "docker command not found" (comando docker não encontrado), o que pode ser frustrante ao iniciar com a containerização. Este laboratório irá guiá-lo através da compreensão dos conceitos do Docker, da verificação da sua instalação do Docker, da resolução de problemas comuns e da configuração de um ambiente Docker adequado para o seu trabalho de desenvolvimento.
Compreendendo os Fundamentos do Docker e Verificando a Instalação
O Docker fornece uma maneira padronizada de empacotar aplicações e suas dependências em containers, tornando-as portáteis em diferentes ambientes. Antes de solucionar quaisquer problemas com o Docker, vamos garantir que entendemos os fundamentos e verificar nossa instalação.
O que é Docker?
Docker é uma plataforma que usa a tecnologia de containerização para facilitar a criação, implantação e execução de aplicações. Ao contrário das máquinas virtuais, os containers Docker compartilham o kernel do sistema host, mas são executados em ambientes isolados, tornando-os leves e eficientes.
Componentes-chave do Docker incluem:
- Docker Engine: O runtime que constrói e executa containers
- Docker Images: Templates somente leitura usados para criar containers
- Docker Containers: Instâncias em execução de Docker images
- Docker Registry: Um repositório para armazenar e compartilhar Docker images
- Dockerfile: Um arquivo de texto contendo instruções para construir um Docker image
Verificando a Instalação do Docker
Nosso ambiente de laboratório já tem o Docker instalado. Vamos verificar isso checando a versão do Docker:
docker --version
Você deve ver uma saída semelhante a:
Docker version 20.10.21, build 20.10.21-0ubuntu1~22.04.3
Agora, vamos verificar se o daemon do Docker está em execução:
sudo systemctl status docker
Você deve ver uma saída indicando que o Docker está ativo (em execução). A saída será semelhante a:
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since ...
Pressione q para sair da visualização de status.
Se, por qualquer motivo, o Docker não estiver em execução, você pode iniciá-lo com:
sudo systemctl start docker
Executando seu Primeiro Container
Vamos verificar se o Docker está funcionando corretamente executando um container simples "hello-world":
docker run hello-world
Este comando baixa a imagem hello-world se ela ainda não estiver disponível localmente e a executa em um container. Você deve ver uma saída semelhante a:
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
A saída explica o que o Docker fez para executar este container, fornecendo uma boa introdução a como o Docker funciona.
Verificando Containers em Execução
Para ver todos os containers atualmente em execução, use:
docker ps
Como o container hello-world sai imediatamente após exibir sua mensagem, você provavelmente não o verá nesta lista. Para ver todos os containers, incluindo aqueles que foram parados, use:
docker ps -a
Isso mostra todos os containers, seus IDs, as imagens de onde foram criados, quando foram criados e seu status atual.
Agora você verificou que o Docker está instalado e funcionando corretamente em seu ambiente, e executou seu primeiro container!
Trabalhando com Docker Images e Containers
Agora que você verificou que o Docker está funcionando corretamente, vamos aprender como trabalhar com Docker images e containers com mais detalhes.
Compreendendo Docker Images
Docker images são os blueprints (plantas) para containers. Elas contêm o código da aplicação, bibliotecas, dependências, ferramentas e outros arquivos necessários para que uma aplicação seja executada.
Vamos explorar Docker images usando alguns comandos básicos:
Listando Imagens Disponíveis
Para ver todas as Docker images disponíveis em seu sistema:
docker images
Você deve ver uma saída semelhante a:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 X months ago 13.3kB
Obtendo Imagens do Docker Hub
Docker Hub é um serviço de registro baseado em nuvem onde você pode encontrar e compartilhar Docker images. Vamos obter uma imagem popular:
docker pull nginx
Este comando baixa a imagem mais recente do servidor web nginx. Você verá a saída do progresso à medida que várias camadas da imagem são baixadas:
Using default tag: latest
latest: Pulling from library/nginx
...
Digest: sha256:...
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
Execute docker images novamente para ver a imagem nginx recém-baixada em sua lista.
Trabalhando com Containers
Agora que temos algumas imagens, vamos aprender como criar e gerenciar containers.
Executando um Container
Vamos executar um container nginx que servirá uma página web:
docker run --name my-nginx -p 8080:80 -d nginx
Este comando faz várias coisas:
--name my-nginx: Nomeia o container "my-nginx"-p 8080:80: Mapeia a porta 8080 em seu host para a porta 80 no container-d: Executa o container em modo detached (em segundo plano)nginx: Especifica a imagem a ser usada
Verificando se o Container está em Execução
Verifique se seu container está em execução:
docker ps
Você deve ver seu container nginx na lista de containers em execução:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 nginx "/docker-entrypoint.…" X seconds ago Up X seconds 0.0.0.0:8080->80/tcp my-nginx
Acessando o Servidor Web
Você pode acessar o servidor web nginx abrindo um navegador web em seu ambiente de VM LabEx e navegando para:
http://localhost:8080
Alternativamente, você pode usar curl do terminal:
curl http://localhost:8080
Você deve ver a página HTML de boas-vindas padrão do nginx.
Visualizando Logs do Container
Para ver os logs do seu container:
docker logs my-nginx
Isso mostra os logs de acesso para o servidor nginx.
Parando e Removendo Containers
Para parar um container em execução:
docker stop my-nginx
Para remover um container (ele deve ser parado primeiro):
docker rm my-nginx
Verifique se o container foi removido:
docker ps -a
O container chamado "my-nginx" não deve mais aparecer na lista.
Agora você entende os fundamentos de como trabalhar com Docker images e containers. Você obteve imagens do Docker Hub, executou containers, mapeou portas, visualizou logs e gerenciou ciclos de vida de containers.
Criando suas Próprias Docker Images com Dockerfiles
Até agora, usamos Docker images pré-construídas do Docker Hub. Agora, vamos aprender como criar nossas próprias Docker images personalizadas usando Dockerfiles.
O que é um Dockerfile?
Um Dockerfile é um arquivo de texto que contém instruções para construir uma Docker image. Ele especifica a imagem base, adiciona arquivos, instala software, define variáveis de ambiente e configura o container que será criado a partir da imagem.
Criando seu Primeiro Dockerfile
Vamos criar uma aplicação web simples usando Node.js e empacotá-la como uma Docker image.
Primeiro, crie um novo diretório para seu projeto:
mkdir -p ~/project/node-app
cd ~/project/node-app
Agora, crie uma aplicação Node.js simples. Primeiro, crie um arquivo chamado app.js:
nano app.js
Adicione o seguinte código ao arquivo:
const http = require("http");
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello World from Docker!\n");
});
const port = 3000;
server.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Salve o arquivo pressionando Ctrl+O, depois Enter e saia do nano com Ctrl+X.
Em seguida, crie um arquivo package.json para definir sua aplicação Node.js:
nano package.json
Adicione o seguinte conteúdo:
{
"name": "docker-node-app",
"version": "1.0.0",
"description": "A simple Node.js app for Docker",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"author": "",
"license": "ISC"
}
Salve e saia do nano.
Agora, crie um Dockerfile:
nano Dockerfile
Adicione o seguinte conteúdo:
## Use an official Node.js runtime as the base image
FROM node:14-alpine
## Set the working directory in the container
WORKDIR /usr/src/app
## Copy package.json and package-lock.json
COPY package.json ./
## Install dependencies
RUN npm install
## Copy the application code
COPY app.js ./
## Expose the port the app runs on
EXPOSE 3000
## Command to run the application
CMD ["npm", "start"]
Salve e saia do nano.
Construindo sua Docker Image
Agora que você tem um Dockerfile, você pode construir sua Docker image:
docker build -t my-node-app .
Este comando constrói uma imagem a partir do seu Dockerfile:
-t my-node-app: Marca a imagem com o nome "my-node-app".: Especifica que o Dockerfile está no diretório atual
Você verá a saída mostrando o progresso da construção:
Sending build context to Docker daemon X.XXkB
Step 1/7 : FROM node:14-alpine
---> XXXXXXXXXX
Step 2/7 : WORKDIR /usr/src/app
---> XXXXXXXXXX
...
Successfully built XXXXXXXXXX
Successfully tagged my-node-app:latest
Executando sua Docker Image Personalizada
Agora, execute um container usando sua imagem recém-construída:
docker run --name node-app-container -p 3000:3000 -d my-node-app
Verifique se o container está em execução:
docker ps
Você deve ver seu container na lista:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
XXXXXXXXXX my-node-app "npm start" X seconds ago Up X seconds 0.0.0.0:3000->3000/tcp node-app-container
Testando sua Aplicação
Teste a aplicação fazendo uma requisição HTTP para ela:
curl http://localhost:3000
Você deve ver:
Hello World from Docker!
Compreendendo o Dockerfile
Vamos revisar os componentes-chave do nosso Dockerfile:
FROM node:14-alpine: Especifica a imagem base a ser usadaWORKDIR /usr/src/app: Define o diretório de trabalho dentro do containerCOPY package.json ./: Copia arquivos do host para o containerRUN npm install: Executa um comando dentro do container durante o processo de construçãoEXPOSE 3000: Documenta que o container escuta na porta 3000CMD ["npm", "start"]: Especifica o comando a ser executado quando o container inicia
Limpeza
Vamos limpar parando e removendo o container:
docker stop node-app-container
docker rm node-app-container
Você agora aprendeu como criar suas próprias Docker images usando Dockerfiles, construir essas imagens e executar containers com base nelas. Esta é uma habilidade fundamental para o desenvolvimento com Docker.
Gerenciando Dados com Docker Volumes
Um desafio ao trabalhar com containers Docker é a persistência de dados. Containers são efêmeros, o que significa que qualquer dado criado dentro de um container é perdido quando o container é removido. Docker volumes resolvem esse problema, fornecendo uma maneira de persistir dados fora dos containers.
Compreendendo Docker Volumes
Docker volumes são o mecanismo preferido para persistir dados gerados e usados por containers Docker. Eles são completamente gerenciados pelo Docker e são isolados da estrutura de diretórios do sistema de arquivos do host.
Benefícios de usar volumes incluem:
- Volumes são mais fáceis de fazer backup ou migrar do que bind mounts
- Você pode gerenciar volumes usando comandos da Docker CLI
- Volumes funcionam em containers Linux e Windows
- Volumes podem ser compartilhados com mais segurança entre vários containers
- Drivers de volume permitem que você armazene volumes em hosts remotos, provedores de nuvem ou criptografe o conteúdo dos volumes
Criando e Usando Docker Volumes
Vamos criar um container de banco de dados MySQL simples que usa um volume para persistir seus dados.
Criando um Volume
Primeiro, crie um Docker volume:
docker volume create mysql-data
Você pode listar todos os volumes com:
docker volume ls
Você deve ver seu novo volume na lista:
DRIVER VOLUME NAME
local mysql-data
Executando um Container com um Volume
Agora, vamos executar um container MySQL que usa este volume:
docker run --name mysql-db -e MYSQL_ROOT_PASSWORD=mysecretpassword -v mysql-data:/var/lib/mysql -p 3306:3306 -d mysql:5.7
Este comando:
--name mysql-db: Nomeia o container "mysql-db"-e MYSQL_ROOT_PASSWORD=mysecretpassword: Define uma variável de ambiente para configurar o MySQL-v mysql-data:/var/lib/mysql: Monta o volume "mysql-data" no diretório onde o MySQL armazena seus dados-p 3306:3306: Mapeia a porta 3306 no host para a porta 3306 no container-d: Executa o container em modo detachedmysql:5.7: Especifica a imagem a ser usada
Aguarde um momento para o container iniciar e, em seguida, verifique se ele está em execução:
docker ps
Interagindo com o Banco de Dados
Vamos criar um banco de dados e uma tabela para demonstrar a persistência de dados. Primeiro, conecte-se ao container MySQL:
docker exec -it mysql-db bash
Dentro do container, conecte-se ao servidor MySQL:
mysql -u root -pmysecretpassword
Crie um novo banco de dados e tabela:
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255));
INSERT INTO users (name) VALUES ('John'), ('Jane'), ('Bob');
SELECT * FROM users;
Você deve ver os dados inseridos:
+----+------+
| id | name |
+----+------+
| 1 | John |
| 2 | Jane |
| 3 | Bob |
+----+------+
Saia do prompt do MySQL e do container:
exit
exit
Testando a Persistência do Volume
Agora, vamos parar e remover o container e, em seguida, criar um novo usando o mesmo volume:
docker stop mysql-db
docker rm mysql-db
Crie um novo container usando o mesmo volume:
docker run --name mysql-db-new -e MYSQL_ROOT_PASSWORD=mysecretpassword -v mysql-data:/var/lib/mysql -p 3306:3306 -d mysql:5.7
Agora, conecte-se ao novo container e verifique se nossos dados persistiram:
docker exec -it mysql-db-new bash
mysql -u root -pmysecretpassword
USE testdb
SELECT * FROM users
Você deve ver os mesmos dados que inserimos anteriormente:
+----+------+
| id | name |
+----+------+
| 1 | John |
| 2 | Jane |
| 3 | Bob |
+----+------+
Saia do prompt do MySQL e do container:
exit
exit
Isso demonstra que os dados persistiram mesmo após a remoção do container original, porque foram armazenados em um Docker volume.
Inspecionando e Gerenciando Volumes
Você pode inspecionar um volume para obter mais informações sobre ele:
docker volume inspect mysql-data
Isso mostrará detalhes como o ponto de montagem e o driver usado:
[
{
"CreatedAt": "YYYY-MM-DDTHH:MM:SS+00:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/mysql-data/_data",
"Name": "mysql-data",
"Options": {},
"Scope": "local"
}
]
Para limpar, vamos parar e remover o container:
docker stop mysql-db-new
docker rm mysql-db-new
Se você também quiser remover o volume:
docker volume rm mysql-data
Você agora aprendeu como usar Docker volumes para persistir dados entre os ciclos de vida dos containers, o que é essencial para aplicações com estado (stateful applications) como bancos de dados.
Explorando o Docker Networking
O Docker networking permite que os containers se comuniquem entre si e com o mundo exterior. Compreender as capacidades de networking do Docker é crucial para construir aplicações multi-container.
Tipos de Rede Docker
O Docker fornece vários drivers de rede prontos para uso:
- bridge: O driver de rede padrão. Containers na mesma rede bridge podem se comunicar.
- host: Remove o isolamento de rede entre o container e o host.
- none: Desabilita todo o networking para um container.
- overlay: Conecta múltiplos daemons Docker e permite que os serviços Swarm se comuniquem.
- macvlan: Atribui um endereço MAC a um container, fazendo com que ele apareça como um dispositivo físico na rede.
Explorando a Rede Bridge Padrão
Quando você instala o Docker, ele cria automaticamente uma rede bridge padrão. Vamos explorá-la:
docker network ls
Você deve ver uma saída semelhante a:
NETWORK ID NAME DRIVER SCOPE
XXXXXXXXXXXX bridge bridge local
XXXXXXXXXXXX host host local
XXXXXXXXXXXX none null local
Você pode inspecionar a rede bridge padrão:
docker network inspect bridge
Este comando fornece informações detalhadas sobre a rede, incluindo os containers conectados a ela, o intervalo de endereços IP e o gateway.
Criando e Usando Redes Bridge Personalizadas
Vamos criar uma rede bridge personalizada para um melhor isolamento de containers:
docker network create my-network
Verifique se a rede foi criada:
docker network ls
Você deve ver sua nova rede na lista:
NETWORK ID NAME DRIVER SCOPE
XXXXXXXXXXXX bridge bridge local
XXXXXXXXXXXX host host local
XXXXXXXXXXXX my-network bridge local
XXXXXXXXXXXX none null local
Agora, vamos executar dois containers nesta rede e demonstrar a comunicação entre eles.
Primeiro, inicie um container NGINX na rede personalizada:
docker run --name web-server --network my-network -d nginx
Em seguida, vamos executar um container Alpine Linux e usá-lo para testar a conectividade com o container NGINX:
docker run --name alpine --network my-network -it alpine sh
Dentro do container Alpine, instale o curl e teste a conectividade com o container NGINX:
apk add --update curl
curl web-server
A saída deve ser o HTML da página de boas-vindas do NGINX. Isso funciona porque o Docker fornece DNS embutido para containers em redes personalizadas, permitindo que eles resolvam nomes de containers para endereços IP.
Digite exit para sair do container Alpine:
exit
Conectando Containers a Múltiplas Redes
Containers podem ser conectados a múltiplas redes. Vamos criar outra rede:
docker network create another-network
Conecte o container web-server existente a esta nova rede:
docker network connect another-network web-server
Verifique se o container agora está conectado a ambas as redes:
docker inspect web-server -f '{{json .NetworkSettings.Networks}}' | json_pp
Você deve ver que o container está conectado a my-network e another-network.
Executando Containers com Publicação de Portas
Quando você deseja tornar o serviço de um container acessível de fora do host Docker, você precisa publicar suas portas:
docker run --name public-web -p 8080:80 -d nginx
Este comando mapeia a porta 8080 no host para a porta 80 no container. Você pode acessar o servidor web NGINX usando:
curl http://localhost:8080
Você deve ver a página de boas-vindas do NGINX.
Limpeza
Vamos limpar os containers e redes que criamos:
docker stop web-server alpine public-web
docker rm web-server alpine public-web
docker network rm my-network another-network
Verifique se os containers e redes foram removidos:
docker ps -a
docker network ls
Compreendendo a Comunicação entre Containers
Este passo demonstrou como o Docker networking permite:
- Comunicação container-para-container usando redes personalizadas
- Resolução de DNS usando nomes de containers
- Conexão de containers a múltiplas redes
- Exposição de serviços de container para o mundo exterior usando publicação de portas
Essas capacidades de networking são essenciais para construir aplicações complexas, multi-container, onde os componentes precisam se comunicar entre si e com serviços externos.
Resumo
Parabéns por concluir este laboratório Docker! Você aprendeu conceitos e habilidades essenciais do Docker que formam a base do desenvolvimento e implantação baseados em containers.
Neste laboratório, você:
- Verificou a instalação do Docker e executou seu primeiro container
- Trabalhou com imagens e containers Docker, incluindo a busca de imagens do Docker Hub e o gerenciamento do ciclo de vida dos containers
- Criou sua própria imagem Docker personalizada usando um Dockerfile
- Usou Docker volumes para persistir dados entre os ciclos de vida dos containers
- Explorou o Docker networking para habilitar a comunicação container-para-container
Essas habilidades permitirão que você:
- Empacote aplicações e suas dependências em containers portáteis
- Crie ambientes padronizados para desenvolvimento, teste e produção
- Implemente arquiteturas de microsserviços onde cada componente é executado em seu próprio container
- Garanta a persistência de dados para aplicações com estado (stateful applications)
- Construa aplicações complexas multi-container com isolamento e comunicação adequados
O Docker se tornou uma ferramenta essencial no desenvolvimento moderno de software, e o conhecimento que você adquiriu será valioso em uma ampla gama de cenários de desenvolvimento e operações.



