Você está na página 1de 19

Criando volumes com Docker

19 de julho de 2018
/
Infra
/
2 Comments

(Last Updated On: 19 de julho de 2018)

Estou estudando Docker. Por isso, subi dois containers, um com uma aplicação construída em Java e outro com o banco de dados MySQL.
Subi os dois containers e salvei alguns dados no banco, no outro dia, quando subi a aplicação de novo, percebi que os dados do banco tinham
sumido.

Toda a vez que um container é removido, ele perde todas as suas informações, isto é, tudo que estava salvo no container é deletado, o que faz
sentido já que, pensando em escalabilidade, um container pode ser, quando necessário, tanto criado ou excluído.

Contudo existem algumas informações que não devemos perder, os dados do banco são exemplo, neste caso, essa era uma aplicação de teste,
mas e se estivesse em produção?

O usuário poderia acessar a aplicação um dia e notar que todos os dados sumiram. Já pensou ter que realizar todos os cadastros de novo, sem
falar de informações, como dados de vendas, que seriam perdidos.

Será que existe alguma forma de salvar os dados de um container?

Criando nosso volume


Nós queremos criar uma cópia dos dados que estão no container para a nossa máquina. Caso o container venha a cair ou seja removido,
podemos falar para ele onde está os dados. Dessa forma, nossas informações ficam salvas independente do estado do container.

Ou seja, queremos falar para o Docker criar um repositório de dados para os containers, ou, como é chamado volume.

Vamos falar para o docker que queremos criar um volume volume create chamado dados-do-banco, no meu caso:

docker volume create dados-do-banco

Aparentemente deu tudo certo, mas como podemos saber quais são nossos volumes? Bem, podemos falar para o docker listá-los (ls):

docker volume ls

Neste comando o Docker nos mostra qual o nome do volume e o seu driver. Isto é, qual é a forma que ele deve montar o volume. No meu
caso, este é o driver local, o driver padrão (built-in) do Docker.

Bacana, já temos um volume criado, mas como podemos atribuí-lo a um container?


Referenciando um volume
Já temos o nosso volume criado, então, vamos falar para o docker rodar um container container run, chamado db (--name db), no meu
caso, com o nosso volume (-v) dados-do-banco associado ao diretório do container que guarda as informações que desejamos salvar,
/var/lib/mysql, neste caso:

docker container run --name db -v dados-do-banco:/var/lib/mysql

Dessa forma, estamos falando para o Docker criar um container e associar o diretório /var/lib/mysql ao volume dados-do-banco. Nossa
aplicação precisa de uma senha para se logar no banco de dados, então vamos falar que este container, em seu ambiente (-e, environment),
terá a senha alura:

docker container run --name db -v dados-do-banco:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=alura

Legal, agora basta falarmos qual é a imagem que criará nosso container, no nosso caso, é a imagem do MySQL:

docker container run --name db -v dados-do-banco:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=alura mysql

Legal nosso container está rodando, vamos fazer alguns testes para testar nosso volume. Em uma outra aba no terminal, vamos falar para o
docker que queremos executar alguns comandos em um container (container exec) com um terminal interativo (-ti) no nosso container
bd com o interpretador /bin/bash:

docker container exec -it db /bin/bash

Vamos logar no mysql com o usuário (-u) root e com a senha -p alura:

Vamos criar (create) um banco de dados (database) para fazer o nosso teste, no meu caso, vou chamar esse banco de dados de loja:

Vamos sair do nosso container, para isso, podemos apertar as teclas CTRL + D até voltarmos ao nosso terminal, ou então, utilizar o atalho
Ctrl + P + Q. Falamos para o docker parar o nosso container (container stop) db e em seguida falar para ele removê-lo (container rm):
docker container stop db

docker container rm db

Mesmo tendo removido o container, as informações dele devem ter ficado salvas no volume. Vamos criar um novo container, dessa vez vou
nomeá-lo de banco e referenciar o mesmo volume dados-do-banco ao diretório /var/lib/mysql:

docker container run --name banco -v dados-do-banco:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=alura mysql

Vamos ver se nossas informações ficaram salvas, vamos acessar esse novo container com o comando docker container exec -it banco
/bin/bash e acessar o mysql

docker container exec -it banco /bin/bash

mysql -u root -p

Vamos falar para o banco de dados mostrar (show) as bases de dados existentes (databases):

show databases;

Veja que nossa base de dados loja está aparecendo normalmente, ou seja, conseguimos manter os dados mesmo após o container ter sido
excluído.
Para saber mais
Nós podemos referenciar mais de um container para o mesmo volume. Ou seja, nós podemos ter dois ou mais container referenciando para o
mesmo volume.

Esses nosso volumes ficam guardados no diretório /var/lib/docker/volumes/, porém, conseguimos também criar volumes em outros
diretórios, basta que na hora da criação do container, passar como parâmetro o caminho da pasta, ao invés do nome do volume:

docker container run --name db -v /outro/diretorio/:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql

Nós vimos como criar um volume, mas como podemos removê-lo? Nós podemos falar para o docker remover o volume (volume rm):

docker volume rm dados-do-banco

Lembrando que para remover um volume, nenhum container pode estar utilizando-o.

O Docker ganhou muito espaço tanto no cenário de desenvolvimento quanto no de infra, isso porque ele vem com o objetivo de facilitar o
desenvolvimento de aplicações.

Aqui na Alura, temos um curso Docker, nele você aprenderá tudo sobre o que é um container, como fazer eles se comunicarem, além de
aprender como criar suas próprias imagens para personalizar seus container.

Replicando ambientes com Docker


19 de abril de 2018
/
Infra
/
0 Comments

(Last Updated On: 3 de abril de 2018)

Nossa equipe escreveu alguns testes para o programa que estamos desenvolvendo entrar em produção. Toda nova funcionalidade do sistema
deve antes passar por esses testes para depois entrar em produção.

Quando testei o código na minha máquina, funcionou. Porém, quando passei o código para outros desenvolvedores, ele não funcionou!

Por que na minha máquina funciona e nas outras não?

Investigando um pouco mais, percebi que existiam dependências e versões específicas de frameworks e bibliotecas que não eram resolvidas
nas máquinas dos outros desenvolvedores.

Nesse caso o problema ocorreu com os testes, mas e se fosse o código em produção?

Precisamos de ambientes iguais, tanto para desenvolvimento, testes e produção. Ou seja, em todos esses ambientes, a versão das bibliotecas,
frameworks e demais dependências devem ser iguais. Do contrário, podem causar erros.

Mas como conseguimos ter ambientes iguais?


Conhecendo os containers
Nós podemos criar especificações que devem ser seguidas para manter todos os ambientes o mais igual possível. Dessa forma, todos os
desenvolvedores criam seus ambientes por meio dessas especificações, porém, isso pode levar muito tempo de todos os desenvolvedores.

Outra forma de fazer isso é criar apenas um ambiente e replicá-lo para todos do time. Ou seja, criamos apenas uma vez esse ambiente e ele é
repassado para todos da equipe. Para isso, podemos utilizar containers.

Num primeiro contato, definimos containers como uma “virtualização não convencional”. Isto é, em uma virtualização tradicional,
colocamos outro sistema operacional em cima do nosso.

Esse sistema virtualizado possuí o proprio kernel e hardwares virtual. Já quando criamos containers, estamos compartilhando o kernel e o
hardware da máquina com os containers.

Ou seja, nosso container possui apenas as bibliotecas e binários necessários para seu funcionamento. Por isso, são mais leves do que a
virtualização tradicional.

Um desses sistemas de criação de containers é o Docker. Com ele conseguimos criar nossos containers a partir de imagens, que nada mais
são do que especificações de containers.

Dessa forma, quando precisarmos testar nosso programa, basta criar um container (ou containers) baseado na nossa imagem. Portanto,
precisamos criar uma imagem.

Criando nossa própria imagem


Para criar imagens no Docker, podemos utilizar o Dockerfile para criar um imagem baseada em uma imagem existente.

Por exemplo, podemos criar uma imagem da nossa aplicação e rodá-la em um container. Para isso, vamos criar um arquivo chamado
aplicacao.dockerfile.

Nesse arquivo, temos que falar qual a imagem que estamos nos baseando para criar nossa imagem. Como minha aplicação é em Python, vou
dizer que ela se baseia (FROM) na imagem do python.

FROM python

Nossa aplicação utiliza um microframework Python para web chamado Flask. Ou seja, nossa imagem precisa ter esse framework para a
aplicação funcionar. Logo, dizer para o Dockerfile rodar (RUN) o comando para instalá-lo:

RUN pip install flask

Queremos que o container rode nossa aplicação. Portanto precisamos copiar (COPY) o código da nossa aplicação para a nossa imagem. No
meu caso, o código está na pasta src, logo, vou copiar esse diretório para o diretório /src:

COPY src /src

Temos que acessar nossa aplicação de alguma forma. Para isso, nós podemos expor (EXPOSE) uma porta do nosso container. Dessa forma,
sempre que quisermos acessar a aplicação podemos utilizar essa porta do container.

Já temos o interpretador do Python, o código da aplicação e uma porta para conseguir acessá-la. Falta alguma coisa?

Falta iniciarmos a aplicação! Para fazer isso, podemos dizer que quando o container for criado, isto é, no seu ponto de entrada do container
(ENTRYPOINT) vamos pedir para o "python”, executar nossa aplicação: ”/src/app.py”

ENTRYPOINT ["python", “/src/app.py”]

Nosso arquivo final fica dessa forma:


FROM python

RUN pip install flask

COPY src /src

EXPOSE 5000

ENTRYPOINT ["python", "/src/app.py"]

Copy

Pronto! Temos um Dockerfile file especificando uma imagem. Contudo, perceba que não temos a imagem pronta. Para isso, precisamos falar
para o Docker construí-la.

Construindo uma imagem


Para construir nossa imagem, pelo terminal vamos até o diretório onde criamos o Dockerfile.

Lá pedimos para o Docker construir (build), baseado no arquivo (-f) aplicacao.dockerfile, com o nome (-t) que, no meu caso, vou
chamar de yurimatheus/app (nome-do-usuário/nome-da-imagem) já que é um padrão no Docker.

Também precisamos dizer que todos os arquivos para construir a imagem estão neste diretório, para isso, utilizamos o ponto (.) no final do
comando:

docker build -f aplicacao.dockerfile -t yurimatheus/app .

Legal! Criamos nossa imagem! Vamos criar um container dessa imagem para testar se nossas configurações funcionaram.

Portanto, vamos falar para o docker rodar (run) um container baseado na imagem que acabamos de criar (yurimatheus/app):

docker run yurimatheus/app


Lembra que colocamos uma porta no container para conseguir acessar a aplicação? Logo, temos que mapear uma porta da nossa máquina
host para o container. Isto é, dizer que quando alguém acessar uma porta na máquina host, na verdade estará acessando o container.

Neste caso, vou falar que a porta (-p) 8080 da nossa máquina host vai ser mapeada para a porta 5000 do container, que foi a porta que
especificamos no Dockerfile:

docker run -p 8080:5000 yurimatheus/app

Funcionou! Temos nossa aplicação rodando em um container com uma imagem que nós mesmos criamos.

Para saber mais


Criamos um Dockerfile bem simples. Podemos criar Dockerfiles para criar imagens complexas, com diversos outros recursos.

Além de copiar arquivos para a imagem, podemos também criar volumes. Como o container é um processo isolado do sistema host, quando
salvamos algo no container e este é reiniciado, ou desativado, nós perdemos esses dados.

É aí que os volumes entram em cena. Com volumes fazemos uma cópia dos dados do container na nossa máquina local. Dessa forma, mesmo
se o container parar, ainda temos os dados disponíveis.

Podemos também utilizar o Docker para reduzir nossos gastos como, por exemplo, os gastos com servidores. Ao invés de ter um servidor
para cada aplicação, podemos ter containers.

Podemos tem um container para cada ambiente, testes, homologação, produção. Ou então, podemos ter diversos containers nesses ambientes.
Um para cada serviço, criando assim, uma arquitetura de microserviços.

Para gerenciar esses diversos containers, o Docker nos oferece uma ferramenta chamada de Docker Compose. Com ele, conseguimos compor
uma aplicação com diversos containers.

No curso de Docker da Alura, além de aprender sobre como o Docker funciona, como criar suas imagens, a como subir seus container na
nuvem, você também aprende a utilizar o Docker Compose.

Porém, quando o número de containers começa a crescer muito, mesmo com o Docker Compose é difícil de gerenciá-los. Por isso, foram
surgindo outras ferramentas, uma muito utilizada é o Kubernetes.

Com ele conseguimos orquestrar nossos containers com base em um único arquivo de configuração.

Aqui na Alura, temos um curso de Kubernetes, onde você aprenderá a realizar essa orquestração. A realizar a comunicação de containers da
aplicação com banco de dados, a escalar seus containers e realizar o balanceamento de carga, entre outras coisas.
Criando um repositório local de imagens Docker
7 de fevereiro de 2018
/
Infra
/
0 Comments

(Last Updated On: 30 de janeiro de 2018)

Criei algumas imagens no Docker e queria compartilhá-las com os outros desenvolvedores da empresa. Para isso, consigo usar os próprios
repositórios do Docker, como o Docker Hub, ou o Docker Store. Lá nós colocamos nossas imagens e elas ficam disponíveis para download.

Porém se eu colocar minha imagens nesses repositórios, só vou conseguir baixá-las se estiver com internet. Quero que essas imagens fiquem
sempre disponíveis na minha rede local. Dessa forma mesmo sem internet terei acesso a elas.

Mas como posso criar um repositórios de imagens local?

Criando o repositório
O Docker trabalha com containers. Então, nada mais justo, que seu repositório de imagens também seja um container. Então para criarmos
nosso repositório local basta iniciarmos um container.

No Docker, esse repositório local se chama Registry. Então para criarmos nosso repositório local, basta ir até o servidor e digitar:

docker run registry

Mas dessa maneira travamos o terminal com a execução desse container, ou seja, não podemos utilizar esse terminal enquanto nosso
container estiver rodando. Para que isso não ocorra, basta falar para o Docker rodar nosso container no background (-d).

docker run -d registry

Nosso Registry está rodando, mas como vamos acessá-lo? Quando nós acessamos um serviço na rede, por exemplo o site da Alura,
precisamos ter acesso a esse serviço. Ou seja, precisamos de uma porta de acesso.

No caso de sites, a porta padrão é a porta 80. Já o nosso registry utiliza por padrão a porta 5000.

Então vamos dizer ao Docker para ele iniciar nosso repositório mapeando a porta (-p) 5000 do nosso host para a porta **5000 **do nosso
container.

docker run -d -p 5000:5000 registry

Uma boa prática quando criamos containers é dar nomes para eles. Isso facilita sua administração. Como estamos criando um repositório de
imagens, podemos dar o nome (--name) repositorio.

docker run -d -p 5000:5000 --name repositorio registry

Se nosso container do Registry cair, será um problema? Precisamos garantir que mesmo se o container caia, outro suba em seu lugar. Ou
seja, queremos reiniciar (--restart) nosso container sempre que ele cair:

docker run -d -p 5000:5000 --restart=always --name repositorio registry


Legal, temos nosso container rodando! Contudo, quando mapeamos a porta do container com a porta do host, apenas dissemos para o Docker
qual a porta do host corresponde a porta do container. Ainda precisamos liberar essa porta no servidor.

Para liberar essa porta, basta dizer para o firewall (firewall-cmd) adicionar uma regra, que no nosso caso pode ser permanente (--
permanent), e adicionar a porta (--add-port) que queremos liberar. Também precisamos dizer qual o protocolo de comunicação que, neste
caso, é o protocolo tcp

firewall-cmd --permanent --add-port=5000/tcp

Agora temos que reiniciar o firewall para que nossa alteração fique válida:

firewall-cmd --reload

Pronto nosso repositório foi criado. Agora os computadores da nossa rede podem enviar imagens para ele. Mas como enviamos uma imagem
para o registry?

Enviando imagens para o registry


Vamos tentar enviar uma imagem para o nosso repositório. Em outra máquina vamos pegar uma imagem, por exemplo a imagem do
WordPress, e criar uma referência entre ela e o nosso repositório.

Logo, queremos dizer para o docker criar uma referência (tag) da imagem do wordpress com o nosso repositório. Neste caso, vou utilizar o
endereço IP do nosso registry, que no meu caso é o 192.168.0.10, na porta 5000. E o nome dessa imagem no repositório também será
wordpress.

docker tag wordpress 192.168.0.10:5000/wordpress

Agora tudo que precisamos fazer é enviar, de fato, a imagem para o repositório. Para isso, utilizamos o comando docker push passando a
imagem que queremos colocar no servidor que no nosso é 192.168.0.10:5000/wordpress

docker push 192.168.0.10:5000/wordpress

Hum… por que não funcionou? No nosso servidor criamos o nosso registry, liberamos a porta no firewall e mesmo assim não conseguimos
enviar a imagem para ele.

Como nós não utilizamos nenhum método de autenticação, nem certificados de segurança, o Docker considera esse nosso repositório
inseguro.

Para conseguir enviar imagens para o nosso repositório, precisamos dizer para o controlador do Docker que confiamos nesse registry. Ou
seja, precisamos dizer isso para o Docker Daemon.

Para dizer para o Docker Daemon que confiamos no nosso repositório, precisamos editar o seu arquivo de configuração. No Ubuntu 16.04,
esse arquivo fica em /lib/systemd/system/docker.service.

Neste arquivo existe uma linha escrita ExecStart, vamos comentar essa linha (#) e em baixo vamos realizar nossa configuração.
Vamos dizer que quando o Docker iniciar (ExecStart) o daemon do Docker (/usr/bin/dockerd) vai adicionar um repositório considerado
inseguro (--insecure-registry):

ExecStart=/usr/bin/dockerd --insecure-registry 192.168.0.10:5000

Agora vamos pedir para o sistema (systemctl) reiniciar o daemon (daemon-reload) para que nossas configurações passem a valer. Como
essas são as configurações do Docker, vamos reiniciar (restart) esse serviço também:

systemctl daemon-reload

systemctl restart docker

Agora se tentarmos enviar nossa imagem para o servidor, obteremos sucesso:

docker push 192.168.0.10:5000/wordpress

Para saber mais


Colocar um repositório inseguro não é uma boa prática de segurança. Neste caso, só utilizamos para entender como funciona o registry.

Para aumentar a segurança do nosso repositório, podemos criar sistemas de autenticação e utilizar certificados de segurança. Um exemplo de
como faz essas configurações, está na documentação do Docker.

Perceba que as imagens ficam no container repositorio que está no servidor. Ou seja, se esse container for excluído as imagens se
perderão.

Por isso, uma boa prática é criar volumes entre o container e a máquina host. Pois, mesmo se o container for excluído, temos uma cópia das
imagens na máquina.

Neste caso utilizamos o endereço IP para se comunicar com o repositório. Porém, podemos utilizar um nome como uma URI. Para isso,
temos que configurar um serviço de DNS.
Docker e containers são um dos assuntos mais comentados nos dias de hoje. Muitas coisas foram facilitadas pelos containers, tanto na parte
de infraestrutura, quanto na parte do desenvolvimento.

Por isso aqui na Alura temos um curso de Docker. Nele você aprenderá sobre como o Docker funciona, como utilizar e criar containers,
como criar suas próprias imagens e muito mais.

Como os containers estão sendo muito utilizados, algumas ferramentas foram criadas para facilitar sua administração. Uma ferramenta muito
utilizada é o Kubernetes.

Com ele conseguimos gerenciar nossos containers, criar balanceamento de cargas entre nossos container e realizar sua comunicação de uma
forma mais simples.

No curso de Kubernetes você vê algumas dessas técnicas e, no final, consegue realizar o deploy da aplicação na nuvem.

Compondo uma aplicação com o Docker Compose


11 de janeiro de 2018
/
Infra
/
5 Comments

(Last Updated On: 14 de dezembro de 2017)

Estou com um container com uma aplicação PHP que se comunica com um banco de dados para efetuar alguns testes antes de ir para
produção. Então, fui rodar o container, porém quando realizei o login me deparei com os seguintes erros:

A aplicação precisa de um banco de dados para rodar, como estamos utilizando o Docker, o jeito mais simples é subir outro container para
representar o banco de dados. Mas por que não consigo fazer esses dois containers se comunicarem?

Conhecendo o Docker Compose


Para realizar a comunicação entre os containers, podemos utilizar uma ferramenta do próprio Docker chamada de Docker Compose. Com o
Docker Compose podemos criar um arquivo e especificar as propriedades de cada container, como comandos, variáveis de ambiente,…
O Docker Compose já vem instalado por padrão quando instalamos o Docker no Windows ou no Mac, porém no Linux, precisamos realizar
sua instalação.

Com o docker composer instalado, podemos dizer como queremos subir esses dois containers.

O arquivo YAML
Queremos falar para o Docker Compose como ele deve subir nosso containers, para isso, temos que criar um arquivo com a extensão YAML,
neste caso, vou chamar de aplicacao.yaml.

A primeira coisa que devemos informar no arquivo é a versão do Docker Compose que estamos utilizando. Nesse caso, vou utilizar a versão
3.4 que é a mais recente.

version: '3.4'
Copy

Já dissemos qual versão estamos utilizando, agora precisamos indicar quais containers vamos criar, ou seja, quais serão os serviços
(services) que o Compose vai subir.

Temos dois serviços que queremos subir, o banco de dados e a aplicação web. Então vamos começar especificando o serviço da nossa
aplicação.

Neste caso, vou nomeá-la como app.

version: '3.4'
services:
app:
Copy

Nossa aplicação está baseada na imagem (image) yuri/web, e podemos dar o nome (container_name) de app por exemplo:

version: '3.4'
services:
app:
image: yuri/web
container_name: app
Copy

Nós precisamos também mapear as portas (ports) que nosso container vai usar. Neste caso, vou mapear a porta 8080 do nosso host, para a
porta 80 do nosso container:

version: '3.4'
services:
app:
image: yuri/web
container_name: app
ports:
- 8080:80
Copy

Bom, nosso container depende (depends_on) de um banco de dados, então vamos falar isso em nosso arquivo do Compose. Neste caso, vou
falar que ele depende do serviço db:

version: '3.4'
services:
app:
image: yuri/web
container_name: app
ports:
- 8080:80
depends_on:
- db
Copy

Mas o que é esse db?

db é o nome do nosso serviço de banco de dados. Ele nada mais é do que outro container, logo, podemos especificar no mesmo arquivo
.yaml do serviço de aplicação.

version: '3.4'
services:
app:
image: yuri/web
container_name: app
ports:
- 8080:80
depends_on:
- db
db:
Copy

Se ele também é um container, então é igualmente baseado em uma imagem. Neste caso, nosso banco de dados será baseado na imagem do
MySQL. E vou nomeá-lo de db

#Restante da configuração
db:
image: mysql
container_name: db
Copy

Mas como conseguiremos acessar nosso banco de dados? Ele precisa de um usuário, correto?

Quando a imagem do MySQL está subindo como um container, ela lê algumas variáveis de ambiente (environment). Essas variáveis
definem algumas informações como usuário, senha, entre outras. Podemos especificar essas variáveis no próprio arquivo do Compose.

Neste caso, por se tratar de um teste, vou utilizar o usuário **root **(MYSQL_USER=root) e não vou alocar nenhuma senha
(MYSQL_ALLOW_EMPTY_PASSWORD=yes). Mas lembrando, nunca devemos usar isso em produção por motivos de segurança:

#Restante da configuração
db:
image: mysql
container_name: db
environment:
- MYSQL_USER=root
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
Copy

Também podemos falar para o Compose criar o banco de dados automaticamente quando ele subir o container. Neste caso, vou criar o banco
de dados loja:

#Restante da configuração
db:
image: mysql
container_name: db
environment:
- MYSQL_USER=root
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
- MYSQL_DATABASE=loja
Copy

Pronto! Configurações terminadas. E agora como conseguimos fazer o Docker subir esses dois containers?

No terminal conseguimos falar para o docker-compose baseado no arquivo (-f, file) aplicacao.yaml, subir (up) os containers
especificados:

Aplicação rodando! Vamos tentar fazer login e ver se obtemos sucesso:

Hum… não obtemos sucesso. Será que o Docker Compose não criou nosso banco de dados?

Na verdade ele criou! Porém, como não existem tabelas, a aplicação não funcionou.

Para resolver esse problema basta falar para o docker executar (exec) um terminal (-t) interativo (-i) com o nosso container, db no caso.
Mas qual terminal vamos executar?

Neste caso, podemos executar o bash:

docker exec -it db bash

Agora, basta executar o mysql com o usuário (-u) root que teremos acesso ao banco de dados.

Nele, nós podemos criar nossas tabelas.

Agora se tentarmos logar em nossa aplicação, obteremos sucesso:


Para saber mais
Neste caso, as informações contidas no container do banco de dados não são persistidas, ou seja, caso o container pare de funcionar, essas
informações serão perdidas.

Caso for necessário persistir essas informações, podemos criar um volume entre nossa máquina local e o container. Dessa forma, todas as
informações salvas no container serão salvas na nossa máquina local.

Neste caso utilizamos o Docker Compose para subir nossos dois containers e realizar a comunicação entre eles.

Porém nós podíamos utilizar o próprio Docker para isso. Basta criar uma rede (network) e atribuir nossos container a ela. Contudo, com o
Docker Compose, temos mais facilidade para a orquestração desses containers.

Aqui na Alura temos um curso sobre Docker que nos mostra como utilizar o Docker Compose, como criar nossas imagens, entre muitas
outras coisas.

Ah, é! Não deixe de compartilhar conosco o que achou do Docker Compose nos comentários.

http://blog.alura.com.br/category/infra/page/4/

Começando com Docker


21 de junho de 2017
/
Infra
/
13 Comments

(Last Updated On: 22 de junho de 2017)

Quando falamos em desenvolvimento de softwre é comum ter diversos ambientes, por exemplo:

Desenvolvimento
Teste
Homologação
Produção

E outra coisa comum no mundo de desenvolvimento é ter divergências entre estes ambientes.

Quem nunca ouviu a frase:

“Na minha máquina funciona!”?


Nesse post vamos abordar o Docker como uma alternativa para minimizar essa divergência.

Mas o que é o Docker?


O Docker é um sistema de virtualização não convencional. Mas o que isso quer dizer?
Em virtualizações convencionais temos um software instalado na máquina Host que irá gerenciar as máquinas virtuais (ex.: VirtualBox,
VMWare, Parallels e etc…).

Para cada máquina virtual temos uma instalação completa do S.O. que queremos virtualizar, além de ter o próprio hardware virtualizado.

Se por exemplo eu precisar de uma biblioteca comum para todas as máquinas virtuais, preciso instalar em cada uma delas.

O Docker usa uma abordagem diferente, ele utiliza o conceito de container. Como assim container?

Compreendendo o conceito de containers


Se pensarmos em transporte de cargas, container foi uma revolução nessa àrea. Pois antes deles o tempo de carregar e descarregar um navio
era gigantesco e o trabalho era feito manualmente. Sem contar perdas (devido a quebras ou deterioração), desvio e outros problemas.

Com a chegada dos containers foi possível transportar mercadorias de uma forma segura, de fácil manipulação e com pouco, ou nenhum,
trabalho braçal no carregamento ou descarregamento. E é justamente isso que o Docker tenta fazer com nossos softwares.

Ganhos ao usar containers do Docker


Imagine nosso software como uma mercadoria a ser transportar como por exemplo, do ambiente de Desenvolvimento para Produção.

Para fazer isso precisamos garantir que nosso ambiente de Produção tenha todos os pré-requisitos instalados, de preferência uma versão do
S.O. parecida com a do ambiente de Desenvolvimento entre outros cuidados que devem ser tomados (relacionados a permissionamento,
serviços dependentes e etc…).

Com o Docker temos um container com nosso software. Esse container é levado inteiro para o outro ambiente.

Com isso não precisamos nos preocupar com pré-requisitos instalados no outro ambiente, versão do S.O., permissionamento e se quisermos
podemos ter containers para os serviços dependentes também. Dessa forma minimizamos muito a divergência entre os ambientes.

Mas como o Docker faz isso?


Essa ideia de container já é bem antiga e a princípio o Docker usava internamente um projeto chamado LXC (Linux Container).

O projeto LXC usa por baixo dos panos diversas funcionalidades presentes no Kernel do Linux. Abaixo vou listar algumas dessas
funcionalidades:

chroot – Reponsavel por mapear os diretórios do S.O. e criar o ponto de montagem (/, /etc, /dev, /proc entre outros).
cgroup – Reponsável por controlar os recursos por processo. Com ele podemos por exemplo limitar o uso de memória e/ou processador para
um processo específico.
kernel namespace – Com ele podemos isolar processos, ponto de montagem entre outras coisas. Com esse isolamento, conseguimos a
sensação de estar usando uma máquina diferente da máquina host. Pois enxergamos somente o ponto de montagem especifico e processos
especificos, inclusive nossos processos começam com PID baixo.
kernel capabilities – Entre outras coisas, conseguimos rodar alguns comandos de forma privilegiada.

Mão na massa
Agora que temos uma noção do que é e para que serve o Docker, vamos fazer o download da ferramenta e começar nesse mundo de
containers.
Instalando o Docker

Atualmente Docker está disponível em duas versões Docker Community Edition(CE) e Docker Enterprise Edition(EE).

Em ambas as versões temos acesso a toda a API, basicamente a diferença entre as duas versões é o perfil desejado de aplicações. No EE
temos um ambiente homologado pela Docker com toda infraestrutura certificada, segura pensada para o mundo enterprise. Já na versão CE
podemos chegar ao mesmo nível que EE porém de uma forma manual.

Nesse link você pode encontrar as distribuições para downloads em cada sistema operacional disponível e os passos para instalação.

Feito a instalação, execute esse comando no terminal docker --version. Se a instalação ocorreu com sucesso deve ser impresso algo
semelhante a isso Docker version 17.03.1-ce, build c6d412e.

Imagens

O Docker trabalha com o conceito de images, ou seja, para colocar um container em funcionamento o Docker precisa ter a imagem no host.

Essas imagens podem ser baixadas de um repositório (a nomenclatura para esse repositório é registry) ou criadas localmentes e compiladas.
Esse é o link para o registry do Docker.

Nesse registry podemos ter imagens oficiais e não oficiais. Além de podermos criar nossas próprias imagens, também é possível fazer upload
dela em um registry.

Baixando Imagens

Para baixar uma imagem podemos usar o comando docker pull e o nome da imagem que queremos baixar. Vamos baixar a imagem do
Ubuntu, para isso execute o seguinte comando no terminal: docker pull ubuntu.

Resultado docker pull ubuntu

Aqui o Docker baixou nossa imagem. Percebam que uma imagem é composta de várias camadas, por esse motivo teve que fazer vários
Downloads/Pulls.

Listando imagens baixadas

Para listar todas as imagens podemos usar o comando docker images. O retorno desse comando é algo semelhante a isso:

O nome da imagem é exibido na coluna REPOSITORY, cada imagem tem um identificador único que é exibido na coluna IMAGE ID. A coluna
TAG indica a “versão” da imagem do ubuntu. O latest quer dizer que é a última “versão” da imagem (a mais recente).
Executando Containers

A partir da imagem podemos iniciar quantos containers quisermos através do comando docker run.

Para acessarmos um terminal do Ubuntu podemos usar o comando docker run -i -t ubuntu ou docker run -it ubuntu. O parâmetro -
i indica que queremos um container interativo, o -t indica que queremos anexar o terminal virtual tty do container ao nosso host.

Listando containers em execução

Para ver os containers em execução podemos usar o comando docker ps (em outro terminal ou aba), e ele exibirá um retorno parecido com
esse:

Aqui temos informações sobre os containers em execução, como id, imagem base, comando inicial, há quanto tempo foi criado, status, quais
portas estão disponíveis e/ou mapeadas para acesso e o nome do mesmo. Quando não especificamos um nome ao iniciá-lo, será gerado um
nome aleatóriamente.

Quando encerramos um container ele não será mais exibido na saida do comando docker ps, porém isso não significa que o container não
existe mais. Para verificar os containers existentes que foram encerrados podemos usar o comando docker ps -a e teremos uma saída
parecida com essa:

Como o próprio status do container informa, o mesmo já saiu de execução e no nosso caso saiu com status 0 (ou seja saiu normalmente).

Removendo containers

Para remover o container podemos usar o comando docker rm e informar o id do container ou o nome dele. Para nosso caso poderíamos
executar o comando docker rm 43aac92b4c99 ou docker rm dreamy_bassi para remover o container por completo.

Caso tenhamos a necessidade de remover todos os container (em execução ou encerrados) podemos usar o comando docker rm $(docker
ps -qa). A opção -q do comando docker ps tem como saída somente os ids dos containers, essa lista de ids é passado para o docker rm e
com isso será removido todos os containers.

Só será possível remover um container caso o mesmo não esteja em execução, do contrário temos que encerrar o container para removê-lo.

Como são feitas as imagens?

Nesse momento podemos pensar que o Docker é meio mágico (e é…kkk). Dado uma imagem ele pode rodar um ou mais containers com
pouco esforço, mas como são feitas as images?

Uma imagem pode ser criada a partir de um arquivo de definição chamado de Dockerfile, nesse arquivo usamos algumas diretivas para
declarar o que teremos na nossa imagem. Por exemplo se olharmos a definição da imagem do Ubuntu podemos ver algo semelhante a isso:

FROM scratch

ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /

.
RUN mkdir -p /run/systemd && echo 'docker' > /run/systemd/container

CMD ["/bin/bash"]

Para ver o Dockerfile completo consulte aqui.

Com um arquivo Dockerfile podemos compilá-lo com o comando docker build. Ao compilar um arquivo Dockerfile temos uma
imagem. Mas isso é um assunto para um próximo post.

E você já usa o Docker? Conte-nos sobre suas aventuras com essa técnologia. Se não conhece não deixe de conferir nosso curso de docker na
Alura.