Docker na prática:
Criando um ambiente de desenvolvimento completo

Vinícius Campitelli

Sobre mim

Sobre mim

Vinícius Campitelli
  • Membro do PHPSP
  • Entusiasta em cibersegurança
  • Desenvolvedor há 15 anos
  • Consultor e instrutor de treinamentos em TI
Vinícius Campitelli

Preparação

Preparação

Acompanhamento do Workshop

Clone esse repositório do GitHub para acompanhar os slides e executar os scripts que serão demonstrados


                            $ git clone --recurse-sobmodules \
                                git@github.com:vcampitelli/workshop-containers.git
                        

Preparação

Instalação do Docker

Histórico do Desenvolvimento

Histórico do Desenvolvimento

Direto na máquina física

Instalando as ferramentas necessárias da linguagem direto em nossa máquina (exemplo: PHP, Java), as dependências envolvidas (bibliotecas e ferramentas) e suas configurações

Histórico do Desenvolvimento

Direto na máquina física

Problemas:

  • Projetos diferentes podem requisitar versões e configurações diferentes de linguagens, bibliotecas e até mesmo do Sistema Operacional
  • Compartilhar o código para que outras pessoas te ajudem é trabalhoso
  • Instalar a aplicação em um ambiente de produção real é ainda mais complexo

Histórico do Desenvolvimento

Máquinas Virtuais

Uma máquina virtual ou virtual machine (VM) é um ambiente virtualizado que funciona como um sistema de computação com sua própria CPU, memória, interface de rede e armazenamento. Um software chamado hipervisor separa do hardware os recursos utilizados pela máquina virtual e os provisiona adequadamente.
Red Hat

Histórico do Desenvolvimento

Máquinas Virtuais

A máquina física onde o hipervisor está instalado é chamada de host. As VMs que usam os recursos da máquina host são chamadas de guest. O hipervisor trata os recursos de computação (por exemplo, CPU, memória e armazenamento) como um pool que pode ser realocado com facilidade entre os guests existentes ou para novas máquinas virtuais.
Red Hat

Histórico do Desenvolvimento

Máquinas Virtuais

As máquinas virtuais são isoladas do restante do sistema, e várias delas podem coexistir em um único hardware, como um servidor. Dependendo da demanda, é possível migrá-las entre servidores host ou distribuir os recursos de maneira mais eficiente.
Red Hat

Histórico do Desenvolvimento

Máquinas Virtuais

Representação de VMs
Microsoft Azure

Histórico do Desenvolvimento

Máquinas Virtuais

Vantagens:

  • A separação entre máquina host e guest faz com que seja possível instalar e configurar separadamente diversos serviços
  • Maior segurança, pois cada aplicação está rodando em um ambiente virtualizado e agentes maliciosos não conseguem acesso à máquina física

Histórico do Desenvolvimento

Máquinas Virtuais

Problemas:

  • Alto consumo de recursos da máquina devido à necessidade de ter vários Sistemas Operacionais rodando
  • Performance ruim da máquina como um todo - e principalmente no compartilhamento de arquivos para execução dos serviços
  • O arquivo gerado para compartilhar as aplicações é geralmente gigantesco

Histórico do Desenvolvimento

Containers

Os contêineres são unidades executáveis de software nas quais o código do aplicativo é empacotado, junto às suas bibliotecas e dependências, de maneira semelhante para que possa ser executado em qualquer lugar, seja no desktop, na estrutura de TI tradicional ou na cloud.
IBM

Histórico do Desenvolvimento

Containers

Para isso, os contêineres utilizam um tipo de virtualização de sistema operacional (S.O.) na qual os recursos do S.O. (no caso do kernel do Linux, os namespaces e as primitivas de cgroups) são usados para ambos os processos isolados a fim de controlar a quantia de CPU, de memória e de disco à qual esses processos têm acesso.
IBM

Histórico do Desenvolvimento

Máquinas Virtuais vs Containers

Representação da VM tayfundeger.com

Histórico do Desenvolvimento

Containers

LXC

Lançado em agosto de 2008, Linux Containers (LXC) é um método de virtualização em nível de sistema operacional para executar vários sistemas Linux isolados (containers) em um host de controle usando um único kernel Linux.
Wikipédia

Histórico do Desenvolvimento

Containers

LXC

Vantagens:

  • Performance muito maior pela inexistência de Sistemas Operacionais para cada guest
  • Maior facilidade de compartilhar aplicações através da geração de imagens, que são uma representação da "receita" para criação daquele container

Histórico do Desenvolvimento

Containers

LXC

Problemas:

  • Mesmo com a criação de LXD, uma camada para facilitar o uso do LXC, o manuseio ainda é difícil e requer um alto grau de conhecimento de seu funcionamento
  • O compartilhamento de aplicações ainda é complexo, pois as configurações do hardware de cada imagem está relacionado à máquina física

Histórico do Desenvolvimento

Containers

Docker

Docker is an open platform for developing, shipping, and running applications.
docs.docker.com

Histórico do Desenvolvimento

Containers

Docker

Lançado em 2013, o Docker é uma plataforma completa para criação e gerenciamento de containers, criando abstrações dos recursos físicos do hardware para melhor compartilhamento e execução em ambientes distintos

Histórico do Desenvolvimento

Containers

Docker

LXC vs Docker Red Hat

Conceitos

Conceitos

Imagem

Template com instruções para criar um container

Dockerfile

Arquivo fonte para gerar uma imagem

Volumes

Mecanismo para realizar a persistência de dados em um container

docs.docker.com

Conceitos

Registry

Repositório que contém as imagens disponíveis para serem executadas

Quando criamos um container, especificamos a imagem para execução para que o Docker possa buscá-la nesse repositório

Conceitos

Registry

O registry oficial de imagens Docker é o Docker Hub, que é gratuito para repositórios públicos e possui planos pagos caso você queira hospedar imagens privadas

Existem imagens de Sistemas Operacionais, como Debian e Ubuntu, e das principais aplicações já instaladas, como MySQL e OpenJDK, que geralmente possuem versões para Sistemas Operacionais diferentes

Conceitos

Registry

Também é possível criar seu próprio registry (por exemplo, na rede de sua empresa) ou usar o serviço do seu provedor de Cloud, como:

Principais comandos

Principais comandos

docker ps

Lista os containers que estão em execução


                                $ docker ps
                                CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
                            

Informe o parâmetro -a para listar todos os containers, inclusive os parados


                            $ docker ps -a
                            CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
                            cd954dec23d0   hello-world   "/hello"   11 minutes ago   Exited (0) 11 minutes ago             frosty_nightingale
                        
docs.docker.com

Principais comandos

docker run

Cria um container a partir da imagem especificada, executa o comando passado (ou o padrão da imagem) e para o container após o término do comando


                            $ docker run hello-world
                            Unable to find image 'hello-world:latest' locally
                            latest: Pulling from library/hello-world
                            2db29710123e: Pull complete
                            Digest: sha256:13e367d31ae85359f42d637adf6da428f76d75dc9afeb3c21faea0d976f5c651
                            Status: Downloaded newer image for hello-world:latest

                            Hello from Docker!
                            This message shows that your installation appears to be working correctly.

                            ...
                        
docs.docker.com

Principais comandos

docker run

Cria um container a partir da imagem especificada, executa o comando passado (ou o padrão da imagem) e para o container após o término do comando


                            $ docker run debian cat /etc/debian_version
                            11.6

                            $ docker ps
                            CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
                        
docs.docker.com

Principais comandos

docker run

Após o término da execução, o container ficará parado, podendo ser visto ao executar docker ps -a e até mesmo reiniciado

Se quiser executar o comando do container e exclui-lo automaticamente ao final, informe o parâmetro --rm:


                            $ docker run --rm hello-world

                            Hello from Docker!
                            This message shows that your installation appears to be working correctly.

                            ...
                        
docs.docker.com

Principais comandos

docker run

Para manter o container rodando, você pode:

1. Executar tail -f /dev/null passando o parâmetro -d, que irá executar o container em segundo plano e imprimir o ID criado


                            $ docker run -d debian tail -f /dev/null
                            4c5a4daf08e6ea1d9f80f8a95c52e0920b635e1497b906ec2f0f9fde36d45935
                        
docs.docker.com

Principais comandos

docker run

Para manter o container rodando, você pode:

2. Executar sleep infinity passando o parâmetro -d, que irá executar o container em segundo plano e imprimir o ID criado (método recomendado)


                            $ docker run -d debian sleep infinity
                            d27d85ce24d64a684468fc6b34a8c97c0f95b66a112a96e0ae5b5a0d9dcbfacb
                        
docs.docker.com

Principais comandos

docker run

Nome

Cada vez que um container é criado, o Docker irá gerar um nome aleatório para ele (exemplo: frosty_nightingale)

Para definir o nome do seu container, informe o parâmetro --name:


                            $ docker run --name meu-nome hello-world

                            Hello from Docker!
                            This message shows that your installation appears to be working correctly.

                            ...

                            $ docker ps -a
                            CONTAINER ID   IMAGE          COMMAND     CREATED             STATUS                         PORTS      NAMES
                            53eb65021715   hello-world    "/hello"    19 seconds ago      Exited (0) 19 seconds ago                 meu-nome
                        
docs.docker.com

Principais comandos

docker run

Volumes

Para disponibilizar um arquivo ou diretório dentro do container, devemos montar um volume informando o parâmetro --volume (ou -v)

Esse argumento recebe basicamente dois argumentos separados por um dois-pontos: o diretório no host que você deseja montar e o caminho no container em que ele será disponibilizado

Principais comandos

docker run

Volumes

Para montar a pasta pessoal de seu usuário em um diretório /app no container, você pode executar:


                            $ docker run -it -v ~/:/app debian bash
                            root@abb014aeb5ae:/# ls -l /app
                            total 760140
                            drwxr-xr-x  2 1000 1000      4096 Jun 16  2021  Audio
                            drwxr-xr-x  2 1000 1000      4096 Jun 16  2021  Desktop
                            ...
                        
docs.docker.com

Principais comandos

docker run

Portas

Se seu container possui um serviço que escuta alguma porta, você deve utilizar o parâmetro --expose (ou -p) para mapear aquela porta para uma em sua própria máquina

Para mapear a porta 80 do container à 8080 da sua máquina, execute:


                            $ docker run -d -p 8080:80 nginx:alpine
                        

Sem esse mapeamento, você só conseguiria acessar esse serviço pelo IP interno do container, que pode ser descoberto com docker inspect <nome-do-container>

docs.docker.com

Principais comandos

docker images

Lista as imagens disponíveis localmente, que são as "receitas" utilizadas para configurar containers


                            $ docker images
                            REPOSITORY   TAG         IMAGE ID       CREATED       SIZE
                            php          8.2-cli     56b3ddeba8af   3 weeks ago   92.1MB
                            node         18          c4f3fb5f722f   4 weeks ago   172MB
                            debian       latest      4eacea30377a   5 weeks ago   124MB
                        
docs.docker.com

Principais comandos

docker build

Cria uma nova imagem a partir das informações provenientes do Dockerfile (que iremos ver em breve)


                            $ docker build .
                            Sending build context to Docker daemon    105kB
                            Step 1/5 : FROM node:18-alpine
                             ---> c4f3fb5f722f
                            Step 2/5 : WORKDIR /app
                             ---> c1829ed5a713
                            Step 3/5 : COPY . .
                             ---> 6e8d941cebb3
                            Step 4/5 : RUN npm install
                             ---> Running in eb7561cda394
                            Removing intermediate container eb7561cda394
                             ---> 18d0cbbb1c07
                             ---> d59ad3ba42d0
                            Step 6/5 : CMD ["npm", "start"]
                             ---> Running in c4b0e26044a1
                            Removing intermediate container c4b0e26044a1
                             ---> df6a836541d6
                            Successfully built df6a836541d6
                        
docs.docker.com

Principais comandos

docker build

No exemplo anterior, a imagem df6a836541d6 foi criada, o que é uma identificação não muito usável para um ser humano

Nesses casos, podemos criar uma tag para aquela imagem, dando um nome mais significativo a ela:


                            $ docker build -t nome-da-imagem:versao .
                        

Para criar uma tag em uma imagem já existente, use o comando:


                            $ docker image tag df6a836541d6 nome-da-imagem:versao
                        
docs.docker.com

Principais comandos

docker start

Inicializa o container especificado, executando o mesmo comando com que ele foi criado


                            $ docker ps -a
                            CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
                            cd954dec23d0   hello-world   "/hello"   11 minutes ago   Exited (0) 11 minutes ago             helloworld

                            $ docker start -i helloworld

                            Hello from Docker!
                            This message shows that your installation appears to be working correctly.

                            ...
                        
docs.docker.com

Principais comandos

docker stop

Para o container especificado, primeiro enviando o sinal SIGTERM para que ele possa finalizar seu processamento atual e, após 10 segundos, um sinal SIGKILL para forçar a parada


                            $ docker ps
                            CONTAINER ID   IMAGE     COMMAND            CREATED         STATUS        PORTS     NAMES
                            0808f1377a11   debian    "sleep infinity"   16 minutes ago  Up 16 minutes            meu-container

                            $ docker stop -t 1 meu-container
                            meu-container

                            $ docker ps
                            CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
                        
docs.docker.com signal(7) — Linux manual page

Principais comandos

docker rm

Remove um ou mais containers, opcionalmente forçando a parada se especificado o parâmetro -f e também seus volumes ao passar -v


                            $ docker rm meu-container
                            Error response from daemon: You cannot remove a running container 0808f1377a11b7a9287593eb0e3319ff69b81b7c9be2ab1f6ed312131ea3cffa. Stop the container before attempting removal or force remove

                            $ docker rm -fv meu-container
                            meu-container
                        
docs.docker.com

Principais comandos

docker rmi

Remove uma ou mais imagens, opcionalmente forçando a remoção de imagens que estão em uso por algum container se especificado o parâmetro -f


                            $ docker rmi df6a836541d6
                            Deleted: sha256:df6a836541d6da56a0678c439fbbb514fa443ccf6f9d83f56459320d5a064852
                            Deleted: sha256:d59ad3ba42d0738624804c0ac1b1240ca6868af8d487806e287336a829b5f702
                            Deleted: sha256:18d0cbbb1c0799afa06659260338f301157a7cf80748b81840340f910ef951c5
                            Deleted: sha256:eed0b1938739c1b4457b925121fef64622b3425b38b507760c20c0b3f399685a
                            Deleted: sha256:6e8d941cebb35ca2e56e7ebb89298b2a5716d838b9fbaee3b7e6d70eef6f2891
                            Deleted: sha256:3cfa372ac00348475b481d88a0b7647df6a41cd50e16ce43047d40f05b97ada4

                            $ docker rmi debian:latest
                            Error response from daemon: conflict: unable to remove repository reference "debian:latest" (must force) - container 0808f1377a11 is using its referenced image d2780094a226

                            $ docker rmi -f debian:latest
                            Untagged: debian:latest
                            Untagged: debian@sha256:859ea45db307402ee024b153c7a63ad4888eb4751921abbef68679fc73c4c739
                        
docs.docker.com

Principais comandos

docker exec

Executa o comando no container especificado, podendo receber também alguns dos parâmetros do docker run, como -d para rodar em segundo plano, -i para ler as entradas do STDIN e -t para alocar um pseudo-tty


                            $ docker exec meu-container cat /etc/debian_version
                            11.6

                            $ docker exec -it meu-container bash
                            root@0808f1377a11:/#
                        
docs.docker.com

Principais comandos

Mãos na massa

Dockerfile

Dockerfile

Arquivo com um conjunto de instruções para que o Docker possa fazer o build da imagem, sendo basicamente composto por:

  • A imagem base do seu container
    • Exemplo: debian:11
  • Os comandos para preparação do ambiente
    • Exemplos: instalação de pacotes e configurações do sistema
  • O comando principal da execução dessa imagem
    • Exemplo: php -S 0.0.0.0:80 -t public/
docs.docker.com

Dockerfile

Principais instruções

FROM <imagem>

Define a imagem que servirá de base para seu ambiente

Exemplos:


                            FROM debian:11
                            # ou
                            FROM php:8.2-cli-alpine
                        

Dockerfile

Principais instruções

WORKDIR /pasta/raiz

Caminho base onde as operações seguintes irão executar, que será automaticamente criado se não existir

Exemplos:


                            # Todos os comandos a seguir serão executados em /app
                            WORKDIR /app
                        

Dockerfile

Principais instruções

COPY <fonte> <destino>

Copia o arquivo (ou a pasta) da fonte para o destino

Exemplos:


                            COPY . ./

                            COPY arquivo.conf /etc/

                            COPY arquivo1 arquivo2 arquivo3 /destino/
                        

Dockerfile

Principais instruções

RUN <comando-a-ser-executado>

Comandos de configuração do ambiente

Exemplos:


                            RUN apt-get update && apt-get install -y php8.2-xml

                            RUN composer install
                        

Dockerfile

Principais instruções

EXPOSE <porta>

Porta(s) que seu container escuta com caráter informativo para quem está lendo o arquivo, já que não resulta em ações pelo Docker

Exemplo:


                            EXPOSE 80 443
                        

Dockerfile

Principais instruções

CMD [<comando>, <argumento>, <argumento>]

Comando principal a ser executado ao iniciar o container, só podendo existir um por Dockerfile, onde o <comando> deve ser um caminho para um executável

Exemplo:


                            CMD ["composer", "start"]
                            # ou
                            CMD php -S 0.0.0.0:80 -t public/
                        

Dockerfile

Principais instruções

CMD [<argumento-para-o-entrypoint>, <argumento-para-o-entrypoint>]

Nesse formato, em que o primeiro parâmetro do CMD não é um executável, o Docker assume que a lista inteira é composta de argumentos que serão passados para o entrypoint (que veremos a seguir)

Exemplo:


                            CMD ["start"]
                        

Dockerfile

Principais instruções

ENTRYPOINT <comando-principal>

Executável principal que irá receber o comando do CMD ou o informado pelo docker run

O padrão é /bin/sh -c, significando que ao passar um comando php, por exemplo, será executado /bin/sh -c php

Exemplo:


                            ENTRYPOINT ["/usr/local/bin/meu-entrypoint.sh"]
                        

Dockerfile

Exemplo de um Dockerfile simples


                            # Imagem base
                            FROM php:8.2-cli-alpine

                            # Diretório raiz da aplicação
                            WORKDIR /app

                            # Copiando todos os arquivos do contexto para /app
                            COPY . ./

                            # Instalando dependências
                            RUN apt-get update && \
                              apt-get -y install php8.2-xml && \
                              composer install

                            # Informando o parâmetro padrão para o entrypoint
                            CMD ["composer", "start"]
                        

Dockerfile

Dicas

As instruções RUN, COPY e ADD criam layers e as outras criam apenas imagens temporárias, não aumentando o tamanho do build.

Ao gerar um container, uma layer escrevível é criada, recebendo todas as modificações no sistema de arquivos.

docs.docker.com

Dockerfile

Dicas

Se possível, combine comandos em instruções RUN em uma só:


                                    RUN apt-get update
                                    RUN apt-get install php8.2-pdo
                                    RUN composer install
                                

Irá criar 3 layers


                                    RUN apt-get update && \
                                        apt-get install php8.2-pdo && \
                                        composer install
                                

Irá criar 1 layer

docs.docker.com

Dockerfile

Referências de arquivos

Dockerfile

Mãos na massa

Docker Compose

Docker Compose

Ferramenta utilizada para gerenciar containers, geralmente em cenários que a aplicação é constituída por sistemas diferentes (como banco de dados e aplicação)

docs.docker.com

Docker Compose

Também é útil para configurar políticas de reinicialização caso haja algum erro, facilitar a montagem de volumes, publicação de portas e dependências entre containers (por exemplo, que a aplicação deve aguardar o banco de dados ficar disponível primeiro)

docs.docker.com

Docker Compose

Apesar de ser possível utilizá-lo em ambientes de produção, não é recomendável em situações com grandes necessidades de escala, sendo preferível usar soluções como Kubernetes ou, se estiver rodando em cloud, as próprias soluções disponíveis nela, como o Amazon ECS

docs.docker.com

Docker Compose

Sua configuração é feita através de um arquivo compose.yaml, como o do exemplo a seguir, que gerencia um container com uma aplicação em PHP e outro com um banco de dados MySQL:


                            services:
                              # Aplicação
                              app:
                                image: php:8.2-cli-alpine
                                working_dir: /app
                                volumes:
                                  - ./backend:/app
                                env_file:
                                  - .env
                                depends_on:
                                  - db
                                ports:
                                  - "8080:8080"

                              # Banco de Dados
                              db:
                                image: mariadb:10
                                volumes:
                                  - dbVolume:/var/lib/mysql
                                env_file:
                                  - db.env

                            volumes:
                              dbVolume:
                                driver: local
                        
compose.yaml docs.docker.com/compose

Docker Compose

Comandos

Os comandos são executados como docker compose [comando] e devem ser executados dentro da pasta onde o arquivo compose.yaml se encontra

Para executar de outra pasta, você pode fornecer o caminho para o arquivo .yml com docker compose -f /caminho/para/o/compose.yaml [comando]

Docker Compose

Comandos

A versão 1 do Docker Compose utilizava um utilitário separado, então era preciso baixá-lo e executar docker-compose [comando]

A versão 2 transformou-o em um plugin embutido no binário, sendo acessível pelo subcomando docker compose

Docker Compose

Comandos

Inicializar serviços em primeiro plano:

                                    docker compose up
                                

Inicializar serviços em segundo plano:

                                    docker compose up -d
                                

Parar serviços:

                                    docker compose stop
                                

Verificar o estado dos serviços:

                                    docker compose ps
                                

Executar o comando em um serviço:

                                    docker compose exec <serviço> <commando>
                                

Acompanhar os logs:

                                    docker compose logs -f <serviço>
                                

Docker Compose

Mãos na massa

Materiais

Materiais

Workshops de TI

Gostou? Então conheça meus treinamentos corporativos sobre Desenvolvimento, Segurança da Informação, DevOps, Arquitetura de Sistemas e diversos outros assuntos
viniciuscampitelli.com

Obrigado!