Docker

Manual de Uso

O que é um container?

"Um container é um padrão de unidade de software que empacota código e todas as dependências de uma aplicação, fazendo com que a mesma seja executada rapidamente de forma confiável de um ambiente computacional para outro." - Fonte: docker.com

Como funciona?

  • Criação de ambientes isolados (container);
  • Containers expõe portas para comunicação;

Principais conceitos

  • Imagem (serviço disponível, exemplo: SQL, Postgres, REdis)
  • Container (instância de uma imagem)
  • Docker Registry (Docker Hub)
  • Dockerfile:
    • Receita de uma imagem

Comandos

Para listar todos os containers que estão rodando

$ docker ps

Para listar todos os containers (incluindo os que não estão rodando)

$ docker ps -a

Para parar um container usa-se $ docker stop NOME_DO_CONTAINER, exemplo:

$ docker stop database

Para iniciar um container parado, usa-se:

$ docker start NOME_DO_CONTAINER

Para rodar um container

$ docker run --name nginx -d -p 8080:80 nginx
# A flag -p serve para redirecionar a porta localhost para a porta do container
# A flag -d significa detached, para que o container não fique preso ao terminal
# A flag --name serve para nomear o container

Acessando e alterando arquivos de um container

$ docker exec -it nginx bash
# A flag -it representa a interação com o container
# O comando "exec" representa a execução do comando para com o próprio container
# O comando "bash" aponta que deverá rodar o bash dentro dele

Bind mounts

O bind mount serve para montar um container com arquivos pré definidos, por exemplo: Ao carregar um container Nginx, o exemplo abaixo montará o arquivo index.html (localhost:8080) com um arquivo index.html pré setado localmente:

$ docker run -d --name nginx -p 8080:80 -v ~/Desktop/PESSOAL/Cursos/fullcycle/docker/bind-mounts/:/usr/share/nginx/html nginx

De forma segura (sem criar a pasta localmente):

$ docker run -d --name nginx -p 8080:80 --mount type=bind,source="$(pwd)",target=/usr/share/nginx/html nginx

Trabalhando com volumes

Para criar um volume:

$ docker volume create meuvolume

Para listar os volumes:

$ docker volume ls

Para inspecionar um volume:

$ docker volume inspect meuvolume

Para criar um container apontando para um volume em específico:

$ docker run --name nginx -d --mount type=volume,source=meuvolume,target=/app nginx
# ou
$ docker run --name nginx -d -v meuvolume:/app nginx
  • Caso seja criado um segundo container usando o mesmo volume, ele compartilhará as informações pré existentes

Para limpar os volumes

$ docker volume prune

Entendendo imagens e DockerHub

As imagens ficam armazenadas no Docker Registry, ou Docker Hub. Lá contém as versões (sendo estas latest ou releases fixas).

Para consultas as imagens existentes na máquina, deve rodar o comando:

$ docker images
# OUTPUT:
#
# REPOSITORY TAG IMAGE ID CREATED SIZE
# ubuntu latest a7870fd478f4 33 hours ago 69.2MB
# nginx latest 8f05d7383593 11 days ago 134MB
# hello-world latest 46331d942d63 2 months ago 9.14kB

Para baixar uma imagem para a máquina

$ docker pull php

Com uma tag específica

$ docker pull php:rc-alpine

Para excluir imagens

$ docker rmi php:latest # É necessário incluir a tag

Para publicar uma imagem no Dockerhub deve rodar o comando:

$ docker push nomedaimagem

Criando serviço de Banco de dados Postgres:

https://hub.docker.com/_/postgres

Inicialização:

$ docker run --name database -e POSTGRES_PASSWORD=docker -p 5432:5432 -d postgres:11

Ao finalizar, exibirá o id do container

Dockerfile e Docker Compose

Arquivo Dockerfile

É o arquivo de configurações que executará os comandos iniciais do conteiner.

Para rodar o Dockerfile, basta rodar o comando abaixo no terminal:
$ docker build -t usuario-no-dockerhub/nginx-com-vim:latest .
# A flag -t representa Tag

Tipos de network

  • Bridge
  • Host
  • Overlay
  • Maclan
  • None

Para listar as networks:

$ docker network ls

Para matar as networks não utilizadas:

$ docker network prune

Para criar uma rede deve rodar o seguinte comando:

$ docker network create --driver bridge minharede

Criando um container com a rede criada

# Exemplo
$ docker run -dit --name ubuntu1 --network minharede bash

Acessando o container e descobrindo o IP

$ docker exec -it ubuntu1 bash
$ bash-5.1# ping ubuntu2 # Só funcionará com a rede previamente criada, caso contrário deve rodar: $ ip addr show

Conectando um container em uma rede

$ docker network connect minharede ubuntu3
# minharede: Nome da rede
# ubuntu3: Nome do container

Criando um container com a network Host

$ docker run --rm -d --name nginx --network host nginx

Container acessando nossa maquina

$ docker run --rm -it --name ubuntu ubuntu bash
# Dentro do container, pode rodar o comando abaixo para acessar a máquina local (exemplo utilizando o curl)
$ curl http://host.docker.internal:8000

Criando aplicação Node sem o Node

Com o Docker é possível rodar uma aplicação sem ter o framework instalado de fato. Com o exemplo abaixo, será replicado na pasta pwd (current folder) o que acontece na pasta usr/src/app, ou seja, se lá dentro estiver rodando uma aplicação Node.js, assim será feito na pasta ./ (pwd).

$ docker run --rm -it -v $(pwd)/:/usr/src/app -p 3000:3000 node:15 bash

Otimização utilizando Multistage Building

Exemplo de um comando de build usando multistage (para produção)

$ docker build -t user_dockerhub/project:prod laravel -f folder/Dockerfile.prod

Exemplo:

# Imagem de referência
FROM node:alpine
RUN mkdir -p /home/node/api/node_modules && chown -R node:node /home/node/api
WORKDIR /home/node/api
COPY package.json yarn.* ./
USER node
RUN yarn
COPY --chown=node:node . .
CMD ["yarn", "start"]
EXPOSE 3001

Docker compose

Arquivo docker-compose.yml

É o arquivo que instancia o conteiner.

Exemplo:

version: '3.6'
networks:
minhanetwork:
driver: bridge
services:
meubackend: # Nome do conteiner
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: meubackend # Chamada do conteiner
restart: unless-stopped
env_file: .env
ports:
- "3001" # Porta ouvida pelo conteiner
volumes:
- .:/home/node/api
networks:
- minhanetwork
command: yarn start # Comando executado para rodar o serviço

Criando banco de dados MySQL

# docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
command: --innodb-use-native-aio=0
container_name: db
restart: always
tty: true
volumes:
- ./mysql:var/lib/mysql
environment:
- MYSQL_DATABASE=nodedb
- MYSQL_ROOTPASSWORD=root
networks:
- node-network
networks:
node-network:
driver: bridge

Dependência entre containers

No docker-compose.yml é possível incluir o parâmetro depends_on e passar o nome de uma imagem de dependência. Além disso, é possível utilizar o Dockerize como comando para aguardar um container terminar de ser montado para um outro iniciar. Por exemplo:

# docker-compose.yml
version: '3'
services:
app:
build:
context: node
container_name: app
# Entrypoint usando o dockerize abaixo
entrypoint: dockerize -wait tcp://db:3306 -timeout 20s docker-entrypoint.sh
networks:
- node-network
volumes:
- ./node:/usr/src/app
tty: true
ports:
- "3000:3000"
# Exemplo de depends_on abaixo
depends_on:
- db

Arquivo .dockerignore

Arquivo responsável para ignorar arquivos/pastas não requiridas para execução do projeto

Exemplo:

node_modules