Prévia do material em texto
Docker - Do básico à Certificação Docker DCA Certificação Docker DCA Caio Delgado Esse livro está à venda em http://leanpub.com/dockerdca Essa versão foi publicada em 2021-09-19 Esse é um livro Leanpub. A Leanpub dá poderes aos autores e editores a partir do processo de Publicação Lean. Publicação Lean é a ação de publicar um ebook em desenvolvimento com ferramentas leves e muitas iterações para conseguir feedbacks dos leitores, pivotar até que você tenha o livro ideal e então conseguir tração. © 2021 Caio Delgado http://leanpub.com/dockerdca http://leanpub.com/ http://leanpub.com/manifesto Tweet Sobre Esse Livro! Por favor ajude Caio Delgado a divulgar esse livro no Twitter! O tweet sugerido para esse livro é: Eu acabei de comprar Docker - Do básico a Certificação Docker DCA. Você também pode adquirir o livro de forma gratuita ou pagar o quanto desejar pelo livro. A hashtag sugerida para esse livro é #dockerdca. Descubra o que as outras pessoas estão falando sobre esse livro clicando nesse link para buscar a hashtag no Twitter: #dockerdca http://twitter.com https://twitter.com/intent/tweet?text=Eu%20acabei%20de%20comprar%20%20Docker%20-%20Do%20b%C3%A1sico%20a%20Certifica%C3%A7%C3%A3o%20Docker%20DCA.%20Voc%C3%AA%20tamb%C3%A9m%20pode%20adquirir%20o%20livro%20de%20forma%20gratuita%20ou%20pagar%20o%20quanto%20desejar%20pelo%20livro. https://twitter.com/intent/tweet?text=Eu%20acabei%20de%20comprar%20%20Docker%20-%20Do%20b%C3%A1sico%20a%20Certifica%C3%A7%C3%A3o%20Docker%20DCA.%20Voc%C3%AA%20tamb%C3%A9m%20pode%20adquirir%20o%20livro%20de%20forma%20gratuita%20ou%20pagar%20o%20quanto%20desejar%20pelo%20livro. https://twitter.com/intent/tweet?text=Eu%20acabei%20de%20comprar%20%20Docker%20-%20Do%20b%C3%A1sico%20a%20Certifica%C3%A7%C3%A3o%20Docker%20DCA.%20Voc%C3%AA%20tamb%C3%A9m%20pode%20adquirir%20o%20livro%20de%20forma%20gratuita%20ou%20pagar%20o%20quanto%20desejar%20pelo%20livro. https://twitter.com/search?q=%23dockerdca https://twitter.com/search?q=%23dockerdca Dedico este livro a todos que acreditaram em mim e me ajudaram a desenvolver na minha carreira, principalmente minha esposa Érika Correa que sempre esteve ao meu lado me apoiando e dando todo o suporte e a meu amigo Diego Sanches que me apresentou o mundo DevOps e fez acender a primeira fagulha de conhecimento desta área. Sem vocês nada disso seria possível. Conteúdo Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Sobre o Autor . . . . . . . . . . . . . . . . . . . . . . . . . 1 Capítulo 01 - Fundamentos . . . . . . . . . . . . . . . . . . . 3 O que é o Docker . . . . . . . . . . . . . . . . . . . . . . . 3 Por que usar Docker . . . . . . . . . . . . . . . . . . . . . 4 O que é um container . . . . . . . . . . . . . . . . . . . . 5 Versões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Instalação . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Instalando o Vagrant e Virtualbox . . . . . . . . . . . 8 Preparando o Ambiente . . . . . . . . . . . . . . . . . 9 Namespaces e Cgroups . . . . . . . . . . . . . . . . . . . . 11 Namespaces . . . . . . . . . . . . . . . . . . . . . . . 12 cgroups . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Instalação do Docker . . . . . . . . . . . . . . . . . . . . . 13 Instalando Docker no Ubuntu . . . . . . . . . . . . . 13 Instalando Docker no CentOS . . . . . . . . . . . . . 15 Instalando Docker através do script de Conveniência. 16 Teste de Execução . . . . . . . . . . . . . . . . . . . . 17 Componentes . . . . . . . . . . . . . . . . . . . . . . . . . 17 Docker Client . . . . . . . . . . . . . . . . . . . . . . 18 Docker Daemon . . . . . . . . . . . . . . . . . . . . . 18 Docker Registry . . . . . . . . . . . . . . . . . . . . . 19 Comandos Essenciais . . . . . . . . . . . . . . . . . . . . 19 Executando comandos . . . . . . . . . . . . . . . . . 20 CONTEÚDO Capítulo 02 - Imagens . . . . . . . . . . . . . . . . . . . . . . 25 Dockerhub . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Criando uma conta no Dockerhub . . . . . . . . . . . 26 Docker Image . . . . . . . . . . . . . . . . . . . . . . . . . 28 Gerenciar Imagens no Docker . . . . . . . . . . . . . . . . 30 Dockerfile . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Criando Dockerfiles . . . . . . . . . . . . . . . . . . . 34 Dockerfile Servidor WEB . . . . . . . . . . . . . . . . 35 Enviando a imagem para o Dockerhub . . . . . . . . . . 36 Melhores práticas com o Dockerfile . . . . . . . . . . . . 37 Entendendo o contexto de Build . . . . . . . . . . . . 38 Excluindo arquivos do build . . . . . . . . . . . . . . 41 Dicas . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Removendo todas as imagens . . . . . . . . . . . . . 54 Capítulo 03 - Storage Drivers . . . . . . . . . . . . . . . . . 55 Docker Volumes . . . . . . . . . . . . . . . . . . . . . . . 56 Gerenciar Volumes . . . . . . . . . . . . . . . . . . . . . . 58 Selinux Labels . . . . . . . . . . . . . . . . . . . . . . . . . 60 tmpfs mounts . . . . . . . . . . . . . . . . . . . . . . . . . 61 Backup & Restore . . . . . . . . . . . . . . . . . . . . . . . 63 Backup . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Restore . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Volume Plugins . . . . . . . . . . . . . . . . . . . . . 66 Capítulo 04 - Networking . . . . . . . . . . . . . . . . . . . . 70 Administrando Redes . . . . . . . . . . . . . . . . . . . . 70 Network Drivers . . . . . . . . . . . . . . . . . . . . . . . 71 Redes Básico . . . . . . . . . . . . . . . . . . . . . . . . . 72 Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Host . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 None . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Macvlan . . . . . . . . . . . . . . . . . . . . . . . . . . 77 CONTEÚDO Overlay . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Conectando Containers . . . . . . . . . . . . . . . . . . . 79 DNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Capítulo 05 - Docker Compose . . . . . . . . . . . . . . . . 84 O que é o Compose . . . . . . . . . . . . . . . . . . . . . . 84 Etapas de um Compose . . . . . . . . . . . . . . . . . . . 84 docker-compose.yml . . . . . . . . . . . . . . . . . . . . . 84 Instalando o Docker Compose . . . . . . . . . . . . . . . 86 Criando Composes . . . . . . . . . . . . . . . . . . . . . . 86 Compose Multi-containers . . . . . . . . . . . . . . . 89 Capítulo 06 - Docker Swarm . . . . . . . . . . . . . . . . . . 93 Conceitos . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Cluster . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Node . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Raft Consensus . . . . . . . . . . . . . . . . . . . . . . . . 94 Criando o Cluster . . . . . . . . . . . . . . . . . . . . . . . 97 Adicionando nós ao cluster. . . . . . . . . . . . . . . 98 Promovendo um node a Manager ou rebaixando a worker . . . . . . . . . . . . . . . . . . . . . 100 Private Registry . . . . . . . . . . . . . . . . . . . . . . . . 101 Preparando nosso Registry . . . . . . . . . . . . . . . 102 Deploy do Registry . . . . . . . . . . . . . . . . . . . 103 Enviando Imagens . . . . . . . . . . . . . . . . . . . . 104 Listando Imagens . . . . . . . . . . . . . . . . . . . . 104 Adicionando as imagens que iremos utilizar nos laboratórios . . . . . . . . . . . . . . . . . . 105 Services e Tasks . . . . . . . . . . . . . . . . . . . . . . . . 107 Tasks e Agendadores . . . . . . . . . . . . . . . . . . . . . 108 Serviços Replicados e Globais . . . . . . . . . . . . . . . . 109 Gerenciando Serviços . . . . . . . . . . . . . . . . . . . . 110 Escalando Serviços . . . . . . . . . . . . . . . . . . . . . . 113 Disponibilidade dos Nodes . . . . . . . . . . . . . . . . . 114 Secrets . . . . . . . . . . . . . . . . . .. . . . . . . . . . . 115 CONTEÚDO Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Volumes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Gerenciando Limites do container . . . . . . . . . . . . . 128 Traefik com Stack (Extra) . . . . . . . . . . . . . . . . . . 131 Capítulo 07 - Monitoramento . . . . . . . . . . . . . . . . . 135 Stack de Monitoramento . . . . . . . . . . . . . . . . . . . 135 Prometheus . . . . . . . . . . . . . . . . . . . . . . . . 135 node-exporter . . . . . . . . . . . . . . . . . . . . . . 135 CAdvisor . . . . . . . . . . . . . . . . . . . . . . . . . 136 Grafana . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Subindo a Stack de monitoramento . . . . . . . . . . . . 136 Configurando a Stack de Monitoramento . . . . . . . . . 140 Prometheus . . . . . . . . . . . . . . . . . . . . . . . . 140 Grafana . . . . . . . . . . . . . . . . . . . . . . . . . . 143 Importando Dashboards . . . . . . . . . . . . . . . . 148 Capítulo 08 - Ferramentas . . . . . . . . . . . . . . . . . . . 156 Play With Docker . . . . . . . . . . . . . . . . . . . . . . . 156 Swarmpit . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Instalação . . . . . . . . . . . . . . . . . . . . . . . . . 162 Dashboard . . . . . . . . . . . . . . . . . . . . . . . . 164 Registries . . . . . . . . . . . . . . . . . . . . . . . . . 164 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 Services . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 Networks . . . . . . . . . . . . . . . . . . . . . . . . . 170 Nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Volumes . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Secrets . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Config . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Portainer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Instalação . . . . . . . . . . . . . . . . . . . . . . . . . 172 Dashboard . . . . . . . . . . . . . . . . . . . . . . . . 173 CONTEÚDO App Templates . . . . . . . . . . . . . . . . . . . . . . 174 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Services . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Containers . . . . . . . . . . . . . . . . . . . . . . . . 177 Images . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Networks . . . . . . . . . . . . . . . . . . . . . . . . . 178 Volumes . . . . . . . . . . . . . . . . . . . . . . . . . . 179 Configs e Secrets . . . . . . . . . . . . . . . . . . . . . 180 Swarm . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Settings . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Harbor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Instalação . . . . . . . . . . . . . . . . . . . . . . . . . 182 Dashboard . . . . . . . . . . . . . . . . . . . . . . . . 184 Users . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 Enviando imagens . . . . . . . . . . . . . . . . . . . . 187 Docker Machine . . . . . . . . . . . . . . . . . . . . . . . 190 Instalando o Docker Machine . . . . . . . . . . . . . 190 Provisionando docker-machines em uma máquina virtual local . . . . . . . . . . . . . . . . . . 191 Interagindo com o Docker Machine . . . . . . . . . . 192 Provisionando Docker Machines em Cloud . . . . . 195 Capitulo 9 - Kubernetes . . . . . . . . . . . . . . . . . . . . . 198 O que é o Kubernetes . . . . . . . . . . . . . . . . . . . . 198 Pods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Minikube . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Recursos Necessários: . . . . . . . . . . . . . . . . . . 200 Instalação e Configuração . . . . . . . . . . . . . . . 201 Estrutura dos Comandos . . . . . . . . . . . . . . . . . . . 202 Descrevendo Aplicações . . . . . . . . . . . . . . . . . . . 205 Pod Multi-container . . . . . . . . . . . . . . . . . . . . . 207 ClusterIP e NodePort . . . . . . . . . . . . . . . . . . . . . 210 ClusterIP . . . . . . . . . . . . . . . . . . . . . . . . . 211 Node Port . . . . . . . . . . . . . . . . . . . . . . . . . 214 Deployments . . . . . . . . . . . . . . . . . . . . . . . . . 217 CONTEÚDO configMaps e secrets . . . . . . . . . . . . . . . . . . . . . 220 Criando um configMap . . . . . . . . . . . . . . . . . 220 Configurando Secrets . . . . . . . . . . . . . . . . . . . . 224 Persistent Storage . . . . . . . . . . . . . . . . . . . . . . . 227 Modos de Acesso . . . . . . . . . . . . . . . . . . . . 229 Criando PVs . . . . . . . . . . . . . . . . . . . . . . . . . . 230 Atrelando Pod a Volumes. . . . . . . . . . . . . . . . . . . 234 Destruindo o Ambiente . . . . . . . . . . . . . . . . . . . 237 Introdução Este livro/curso tem como objetivo ajudar a comunidade e difundir o conhecimento de Containeres. O curso por si só não tem fins lucrativos, podendo ser utilizado de forma totalmente gratuita, peço apenas que ao utilizá-lo em qualquer situação que seja feita a citação do autor do material. SPOILER ALERT (Soon) Caso você queira ajudar o autor a produzir mais conteúdos sinta-se a vontade em adquirir o curso na plataforma da udemy. Caso você não tenha condições de adquirir o curso, entre em contato comigo pelo twitter e eu irei gerar um cupom de 100% de desconto afinal a ideia não é lucrar e sim ajudar a comunidade. O Link será atualizado assim que começarmos as gravações! Neste livro/curso iremos cobrir todos os fundamentos de Docker bem como todo o conteúdo para a certificação Docker Certified Associate (DCA). Sobre o Autor Caio Delgado é graduado em Engenharia da Computação e Pós Graduado em Engenharia de Redes. Trabalhou por 12 Anos com ambientes Microsoft e Redes e em 2018 migrou para o mundo Open Source. Mantém um canal no youtube e um blog onde publica regularmente conteúdo sobre OpenSource, DevOps e Site Reliability Enginee- ring. Introdução 2 Fã de Zeldinha desde criança. Links: https://linktr.ee/caiodelgadonew Capítulo 01 - Fundamentos O que é o Docker Docker é uma plataforma Open Source escrita em Go (Linguagem de programação em alta performance desenvolvida pela Google) que ajuda a criação e a administração de ambientes isolados. Com a utilização do Docker podemos gerenciar toda a infraes- tutura de uma aplicação, bem como garantir que ambientes de desenvolvimento, homologação e produção contenham os mesmos componentes e versões de aplicações, a fim de minimizar impactos no processo de desenvolvimento e entrega de software. O Docker trabalha com uma virtualização a nível do sistema operacional, onde o mesmo utiliza de recursos como o kernel do sistema hospedeiro para executar seus containers. Diferente do modelo tradicional de Máquinas Virtuais, o Docker não necessita da instalação de um sistema operacional por completo, e sim apenas dos arquivos necessários para a aplicação ser executada. Capítulo 01 - Fundamentos 4 Weaveworks - VM x Containers Por que usar Docker Em 2013, Docker introduziu o que se tornou o padrão da indústria para containers, trouxe uma maneira simples, rápida e eficiente de executar aplicações sem a complexidade de uma máquina virtual. Docker garante um ecossistema consistente, fazendo com que o desenvolvedor possa trabalhar sem se preocupar, por exemplo, com a abertura de tickets para uma equipe de infraestrutura provisionar um ambiente por completo, atrasando o trabalho de entrega de software. Existem diversas engines e runtimes de containers e até é possível utilizar containers sem Docker, mas atualmente o Docker é a engine/runtime de container mais utilizada no mercado, o que torna o conhecimento do mesmo um “Must have” e dificilmente encontramos vagas na área de tecnologia que não pedem um conhecimento, mesmo que básico, de containers ou Docker. Capítulo 01 - Fundamentos 5 O que é um container Um container consiste de um ambiente completo (umaaplicação e todas suas dependências, bibliotecas, binários, arquivos de con- figuração) em um único pacote. Ao containerizar uma plataforma de aplicação e suas dependências as diferenças em distribuições de sistemas operacionais e camadas inferiores da infraestrutura são abstraídas. Imagine que o container Docker é como se fosse um con- tainer real em um navio (servidor), todos os containeres estão lado a lado, porém seu conteúdo (ecossistema) não tem interferência de outros containers. Podemos dizer também que um container é a unidade mínima computacional do Docker, ou seja, o menor recurso que o Docker pode fornecer. Capítulo 01 - Fundamentos 6 Container Versões ODocker possui basicamente duas versões, a versão da comunidade (Community Edition) e a versão empresarial (Enterprise Edition). A versão Community é de uso gratuito e também tem seu código aberto. Amaioria dos sistemas Docker em produção utiliza a versão Docker Community Edition. O licenciamento anual da versão Enterprise custa cerca de US$750 por nó, o que torna o processo inviável para algumas empresas. ATENÇÃO: Para fins da prova Docker Certified As- sociate (Docker DCA) a versão Community deve ser Capítulo 01 - Fundamentos 7 utilizada apenas em ambientes de desenvolvimento e não deve ser utilizada em produção. Para produção a única versão a ser utilizada é a Enterprise Edition. A versão Enterprise conta com recursos como o UCP (Universal Control Plane) e o DTR (Docker Trusted Registry), bem como suporte da Docker Inc. A recomendação mínima para a versão Enterprise do Docker EE é: • 8GB de RAM para nós Managers • 4GB de RAM para nós Workers • 2vCPUs para nós Managers • 10GB de espaço em disco livre para a partição /var em nós Managers (Minimo de 6GB Recomendado) • 500MB de espaço em disco livre para a partição /var em nós workers A recomendação para ambientes de produção do Docker EE é: • 16GB de RAM para nós Managers • 4vCPUs para nós Managers • 25 a 100GB de espaço livre em disco. Instalação Iremos instalar o Docker em máquinas virtuais para que possamos facilitar o estudo, para isto utilizaremos uma solução chamada Vagrant somado ao Virtualbox, você pode utilizar a solução de vir- tualização que preferir, porém eu indico que você siga exatamente como listado no curso porque caso você precise de suporte eu possa lhe ajudar. Lembre-se de habilitar a virtualização Intel VT-x ou AMD SVM na UEFI/BIOS. Capítulo 01 - Fundamentos 8 Instalando o Vagrant e Virtualbox Para instalar o Virtualbox siga os passos: 1. Acesse a página de Downloads do Virtualbox¹ e faça o down- load da versão coorespondente ao seu sistema operacional. 2. Execute a instalação do pacote do Virtualbox. 2.1. Para Linux execute o programa de instalação de pacotes (sudo dpkg -i <pacote>.deb para sistemas debian-like ou sudo rpm -i <pacote>.rpm) 2.2. Para Windows, clique sob o instalador e avance até o final da instalação. 2.3. Para MacOS, clique sob o instalador e avance até o final da instalação. Para Instalar o vagrant siga os passos: 1. Acesse a página de Downloads do Vagrant² e faça o download da versão correspondente ao seu sistema operacional. 2. Execute a instalação do pacote do vagrant. 2.1. Para Linux execute o programa de instalação de pacotes (sudo dpkg -i <pacote>.deb para sistemas debian-like ou sudo rpm -i <pacote>.rpm) 2.2. Para Windows, clique sob o instalador e avance até o final da instalação. 2.3. Para MacOS, clique sob o instalador e avance até o final da instalação. 3. Após a instalação abra um terminal ou um prompt de comando e execute o comando vagrant --version para verificar se o pacote foi instalado com sucesso. ¹https://www.virtualbox.org/wiki/Downloads ²https://www.vagrantup.com/downloads.html https://www.virtualbox.org/wiki/Downloads https://www.vagrantup.com/downloads.html https://www.virtualbox.org/wiki/Downloads https://www.vagrantup.com/downloads.html Capítulo 01 - Fundamentos 9 Preparando o Ambiente Após instalar oVagrant e oVirtualbox, podemos criar um diretório com um arquivo Vagrantfile. O Vagrantfile é o arquivo do Vagrant responsável por criar nossa infraestrutura. Caso queira utilizar os arquivos mais atualizados, basta clonar o repositório: https://github.com/caiodelgadonew/docker-dca 1 $ mkdir ~/docker 2 $ cd docker 3 $ vim Vagrantfile Adicione o conteúdo ao arquivo Vagrantfile 1 # -*- mode: ruby -*- 2 # vi: set ft=ruby : 3 4 machines = { 5 "master" => {"memory" => "2048", "cpu" => "2", "ip" =\ 6 > "100", "image" => "ubuntu/bionic64"}, 7 "node01" => {"memory" => "1024", "cpu" => "2", "ip" =\ 8 > "110", "image" => "ubuntu/bionic64"}, 9 "node02" => {"memory" => "1024", "cpu" => "2", "ip" =\ 10 > "120", "image" => "centos/7"}, 11 "registry" => {"memory" => "2048", "cpu" => "2", "ip" =\ 12 > "200", "image" => "ubuntu/bionic64"} 13 } 14 15 Vagrant.configure("2") do |config| 16 17 machines.each do |name, conf| 18 config.vm.define "#{name}" do |machine| Capítulo 01 - Fundamentos 10 19 machine.vm.box = "#{conf["image"]}" 20 machine.vm.hostname = "#{name}.docker-dca.example" 21 machine.vm.network "private_network", ip: "10.20.20\ 22 .#{conf["ip"]}" 23 machine.vm.provider "virtualbox" do |vb| 24 vb.name = "#{name}" 25 vb.memory = conf["memory"] 26 vb.cpus = conf["cpu"] 27 vb.customize ["modifyvm", :id, "--groups", "/Dock\ 28 er-DCA"] 29 end 30 machine.vm.provision "shell", inline: "hostnamectl \ 31 set-hostname #{name}.docker-dca.example" 32 config.vm.provision "shell", inline: <<-SHELL 33 HOSTS=$(head -n7 /etc/hosts) 34 echo -e "$HOSTS" > /etc/hosts 35 echo '192.168.200.10 master.docker.example' >> /\ 36 etc/hosts 37 echo '192.168.200.21 node01.docker.example' >> /\ 38 etc/hosts 39 echo '192.168.200.22 node02.docker.example' >> /\ 40 etc/hosts 41 echo '192.168.200.50 registry.docker.example' >>\ 42 /etc/hosts 43 SHELL 44 end 45 end 46 end Para criar o ambiente do laboratório, execute o comando vagrant up, e o vagrant irá criar todas as máquinas virtuais bem como configurar os hostnames e endereços IP’s Para se conectar asmáquinas utilize o comando vagrant ssh <host> informando o nome do host a ser conectado, lembre-se de estar dentro da pasta com o Vagrantfile. Capítulo 01 - Fundamentos 11 Para desligar as máquinas execute o comando vagrant halt. Para destruir o ambiente execute o comando vagrant destroy. Execute o comando vagrant up para criar nossa infraestrutura. 1 $ cd ~/docker 2 $ vagrant up Caso você queira saber mais sobre Vagrant eu tenho um post no meu blog onde ensino como utilizar o Vagrant para subir os laboratórios de estudo, para acessar basta clicar em Vagrant-101³ Adicione também as seguintes entradas ao arquivo hosts da sua máquina. 1 # Docker 2 192.168.200.10 master.docker.example 3 192.168.200.21 node01.docker.example 4 192.168.200.22 node02.docker.example 5 192.168.200.50 registry.docker.example Emmáquinas Linux eMacOS o arquivo fica localizado em /etc/hosts Em máquinas Windows o arquivo fica localizado em C:\Windows\System32\drivers\etc\hosts Namespaces e Cgroups O Docker utiliza de recursos do linux como por exemplo namespa- ces, cgroups dentre vários outros que iremos falar futuramente para isolar os containers que serão executados. ³https://caiodelgado.dev/vagrant-101 https://caiodelgado.dev/vagrant-101 https://caiodelgado.dev/vagrant-101 Capítulo 01 - Fundamentos 12 Namespaces Namespaces • PID: Process ID • MNT: Mount Points • IPC: Comunicação Inter Processos • UTS: Unix Timesharing System (Kernel e Identificadores) • NET: Networking Os Namespaces fornecem isolamento para os containers, limitando seu acesso aos recursos do sistema e a outros namespaces. Isto significa, por exemplo, que um usuário root dentro de um container é diferente de um usuário root da máquina hospedeira. Com o isolamento, os sistemas em execução nos containers tem suas próprias árvores de processo, sistemas de arquivos, conexões de rede e muito mais. cgroups cgroups • cpu: Divisão de CPU por containers. Capítulo01 - Fundamentos 13 • cpuset: CPU Masks, para limitar threads • memory: Memória • device: Dispositivos Os containers trabalham com cgroups (Control Groups) que fazem isolamento dos recursos físicos da máquina. Em geral os cgroups podem ser utilizados para controlar estes recursos tais como limites e reserva de CPU, limites e reserva de memória, dispositivos, etc… Instalação do Docker Existem duas maneiras de instalar o Docker • Script de Conveniência • Maneira Tradicional Iremos efetuar a instalação da maneira tradicional nas máquinas master e node02 e com o script de conveniência nas máquinas node01 e registry. Instalando Docker no Ubuntu Primeiramente vamos acessar a máquina master 1 $ cd ~/docker 2 $ vagrant ssh master Uma vez conectado na máquina docker, execute os seguintes co- mandos: Capítulo 01 - Fundamentos 14 1 $ sudo apt update 2 $ sudo apt install \ 3 apt-transport-https \ 4 ca-certificates \ 5 curl \ 6 gnupg2 \ 7 software-properties-common \ 8 bash-completion -y 9 $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg\ 10 | sudo apt-key add - 11 $ sudo add-apt-repository \ 12 "deb [arch=amd64] https://download.docker.com/linux/ub\ 13 untu \ 14 $(lsb_release -cs) \ 15 stable" 16 $ sudo apt update 17 $ sudo apt-get install docker-ce docker-ce-cli containerd\ 18 .io Após a conclusão da instalação, podemos configurar agora nosso usuário para fazer parte do grupo docker, isso garantirá que possa- mos executar os comandos do docker sem a necessidade de elevar os privilégios. 1 $ sudo usermod -aG docker $USER Vamos também instalar o recurso de Bash Completion através do comando: 1 $ sudo curl https://raw.githubusercontent.com/docker/mach\ 2 ine/v0.16.0/contrib/completion/bash/docker-machine.bash -\ 3 o /etc/bash_completion.d/docker-machine Saia do terminal e inicie uma nova sessão e o usuário já poderá executar o comando como super user. Capítulo 01 - Fundamentos 15 1 $ exit 2 $ vagrant ssh master Instalando Docker no CentOS Abra um novo terminal e acesse a máquina node02 1 $ cd ~/docker 2 $ vagrant ssh node02 Uma vez conectado na máquina docker, execute os seguintes co- mandos: 1 $ sudo yum install -y yum-utils curl vim bash-completion 2 $ sudo yum-config-manager \ 3 --add-repo \ 4 https://download.docker.com/linux/centos/docker-ce.re\ 5 po 6 $ sudo yum install docker-ce docker-ce-cli containerd.io Nos sistemas RHEL like, precisamos habilitar e iniciar o serviço após a instalação do mesmo 1 $ sudo systemctl enable docker 2 $ sudo systemctl start docker Após a conclusão da instalação, podemos configurar agora nosso usuário para fazer parte do grupo docker, isso garantirá que possa- mos executar os comandos do docker sem a necessidade de elevar os privilégios. 1 $ sudo usermod -aG docker $USER Vamos também instalar o recurso de Bash Completion através do comando: Capítulo 01 - Fundamentos 16 1 $ sudo curl https://raw.githubusercontent.com/docker/mach\ 2 ine/v0.16.0/contrib/completion/bash/docker-machine.bash -\ 3 o /etc/bash_completion.d/docker-machine Saia do terminal e inicie uma nova sessão e o usuário já poderá executar o comando como super user. 1 $ exit 2 $ vagrant ssh node02 Instalando Docker através do script de Conveniência. Os passos a seguir devem ser executados nas máquinas node01 e registry, não esqueça de abrir um terminal novo para cada máquina e executar o comando vagrant ssh <host> A Docker disponibiliza um script de conveniência, que trata-se de uma maneira simples e rápida para instalar o Docker para ambientes de desenvolvimento, este script faz a validação da dis- tribuição Linux bem como instala os pacotes necessários para o funcionamento do Docker. Para instalar o Docker através do script de conveniência basta executar o comando: 1 $ sudo curl -fsSL https://get.docker.com | bash Nos sistemas RHEL like, precisamos habilitar e iniciar o serviço após a instalação do mesmo 1 $ sudo systemctl enable docker 2 $ sudo systemctl start docker Capítulo 01 - Fundamentos 17 Após a conclusão da instalação, podemos configurar agora nosso usuário para fazer parte do grupo docker, isso garantirá que possa- mos executar os comandos do docker sem a necessidade de elevar os privilégios. 1 $ sudo usermod -aG docker $USER Vamos também instalar o recurso de Bash Completion através do comando: 1 $ sudo curl https://raw.githubusercontent.com/docker/mach\ 2 ine/v0.16.0/contrib/completion/bash/docker-machine.bash -\ 3 o /etc/bash_completion.d/docker-machine Teste de Execução Para garantirmos que o docker foi instalado corretamente e está funcional, podemos rodar nosso primeiro container e verificar o retorno na tela. 1 $ docker container run --rm -it hello-world Componentes Agora que rodamos nosso primeiro container, precisamos entender alguns componentes básicos da sua arquitetura e seu funciona- mento. Ao executar o container com a imagem hello-world o Docker fez os seguintes passos: 1. O Docker Client se comunicou com o Docker Daemon. Capítulo 01 - Fundamentos 18 2. O Docker Daemon fez o download da imagem hello-world no Docker Hub. 3. O Docker Daemon criou um novo container, através da imagem que rodou o executável que produz o texto que vimos no terminal. 4. O Docker Daemon enviou o texto diretamente para o Docker Client que enviou para nosso terminal. Componentes Docker Client O Docker Client é o pacote docker-ce-cli ele fornece os comandos do lado do cliente, como por exemplo o comando docker container run, que irá interagir com o Docker Daemon Docker Daemon O Docker Daemon é o pacote docker-ce ele é o servidor propria- mente dito, que receberá os comandos através do Docker Client e fornecerá os recursos de virtualização a nível de sistema operacio- nal. Capítulo 01 - Fundamentos 19 Docker Registry O Docker Registry é o local de armazenamento de imagens Docker, normalmente o Docker hub, de onde o Docker Daemon receberá as imagens a serem executadas no processo de criação de um container. Comandos Essenciais Iremos agora aprender alguns comandos essenciais do Docker. 1 docker --help O primeiro passo para entendermos os comandos do docker é visu- alizar sua lista de comandos, iremos falar dos seguintes comandos de gerenciamento: • docker container • docker image • docker network • docker system • docker volume Para cada comando de gerenciamento acima, temos diversos sub- comandos a serem executados, muitos deles são parecidos com comandos Linux como por exemplo ls, rm, dentre outros. Antigamente o comando utilizado para listar containers era o comando docker ps que ainda existe na documentação, porém é indicado que seja utilizado o novo comando docker container ls. PS é o abreviamento de Process Status enquanto LS é o abreviamento de LIST Existem diversos outros comandos que iremos ver ao longo do curso. Capítulo 01 - Fundamentos 20 Executando comandos Antes de executar os comandos do docker, vamos conectar na máquina node01. 1 vagrant ssh node01 Para visualizar informações do ambiente, podemos utilizar o co- mando docker system info o qual exibirá informações do Docker como versão, quantidade de containers em execução, storage dri- vers, entre outros. 1 docker system info 2 docker info Os comandos listados acima são equivalentes. Para listar containers, imagens, redes e volumes no docker, utiliza- mos o comando docker <comando> ls 1 docker container ls 2 docker image ls 3 docker network ls 4 docker volume ls • docker container ls - lista os containers • docker image ls - lista as imagens • docker network ls - lista as redes • docker volume ls - lista os volumes Para pesquisar por uma imagem, utilizamos o comando docker search Capítulo 01 - Fundamentos 21 1 docker search debian Para efetuar o download da imagem utilizamos o comando docker image pull 1 docker image pull debian Para executar um container, utilizamos o comando docker contai- ner run 1 docker container run -dit --name debian1 --hostname c1 de\ 2 bian Descrição do comando:• docker container run (…) debian - Executa um container, sendo o último parâmetro o nome da imagem a ser utilizada • -dit - Executa um container como processo (d = Detached), habilitando a interação com o container (i = Interactive) e disponibiliza um pseudo-TTY(t = TTY) • –name - Define o nome do container • –hostname - Define o hostname do container Agora que temos nosso primeiro container em execução, podemos listar os containers (docker container ls) e conectar ao mesmo através do comando docker container attach 1 docker container ls 2 docker container attach debian1 Note que ao se conectar ao container a PS1 será modificada para root@c1:/# . Execute alguns comandos no container: Capítulo 01 - Fundamentos 22 1 ip -c a 2 hostname 3 cat /etc/hosts 4 exit Liste novamente os containers 1 docker container ls -a Note que agora o container está parado, isto aconteceu pois o processo principal do container recebeu um return code diferente de 0 Inicie novamente o container e conecte-se ao mesmo 1 docker container start debian1 2 docker container attach debian1 O comando docker container start inicia um container parado, o comando docker container stop para um container que esteja em execução Utilize a sequencia de teclas <CTRL> + <P> + <Q> para se desconec- tar do container sem que ele seja parado. Este comando é chamado de Read escape sequence. 1 <CTRL> + <P> + <Q> 2 docker container ls Note que agora o container ainda está em execução. Para verificar os logs do container utilizamos o comando docker container logs Capítulo 01 - Fundamentos 23 1 docker container logs debian1 Pare e remova o container, após isto verifique os containers exis- tentes 1 docker container stop debian1 2 docker container rm debian1 3 docker container ls -a Podemos utilizar o parâmetro -f no comando docker container rm para que o container seja removido mesmo que esteja sendo executado Execute um novo container 1 docker container run -dit --name c1 --hostname server deb\ 2 ian 3 docker container ls Crie um arquivo de teste na pasta atual para enviar ao container c1 1 echo "Arquivo de teste" > /tmp/arquivo 2 docker container cp /tmp/arquivo c1:/tmp O comando docker container cp copia um arquivo da maquina host para o container ou vice-versa. Verifique se o arquivo existe dentro do container através do co- mando exec 1 docker container exec c1 ls -l /tmp 2 docker container exec c1 cat /tmp/arquivo O comando docker container exec executa um comando no container e envia o retorno na saída padrão(STDOUT) da máquina, caso o container não tenha sido iniciado com a opção -i o retorno não será mostrado no STDOUT Remova o container criado anteriormente Capítulo 01 - Fundamentos 24 1 docker container rm -f c1 Capítulo 02 - Imagens Dockerhub Estas imagens ficam armazenadas em repositórios locais e/ou re- motos, um exemplo de repositório remoto é o DockerHub que é um repositório publico de imagens docker onde podemos escolher e utilizar as imagens para subir nossos containers. Dockerhub Serviços Fornecidos pelo Dockerhub: • Hospedagem de Imagens Docker; • Autenticação de usuário Capítulo 02 - Imagens 26 • Automatização do processo de construção de imagens através de triggers (webhooks) • Integração com o Github e Bitbucket Criando uma conta no Dockerhub Acesse o endereço https://hub.docker.com e clique em Sign Up para criar uma conta, preencha com os seus dados e clique emContinue Registro Confirme o cadastro em seu e-mail e logue noDocker Hub através do link Sign In Capítulo 02 - Imagens 27 login Logue no terminal com o usuário criado através do comando docker login e digite sua senha 1 docker login -u <usuario_dockerhub> Verifique se um arquivo de autorização foi criado 1 cat ~/.docker/config.json Encerre o login na conta do Dockerhub no terminal Capítulo 02 - Imagens 28 1 docker logout Docker Image Uma imagem Docker é um pacote executável que inclui tudo o que é necessário para executar um aplicativo, incluindo o código, bibliotecas, variáveis de ambientes e arquivos de configuração. As imagens do Docker possuem camadas intermediárias que au- mentam a capacidade de reutilização, diminuem o uso do disco e aceleram a construção do docker, permitindo que cada etapa seja armazenada em cache. Essas camadas intermediárias não são mostradas por padrão. Docker Image A principal diferença entre um container e uma imagem é a camada gravável superior. Todas as gravações no container que adicionam novos dados ou modificam dados existentes são armazenados nessa Capítulo 02 - Imagens 29 camada gravável. Quando o container é excluido, a camada gravá- vel também é excluida. A imagem subjacente permanece inalterada. Docker Images e Containers Um ponto interessante é que em um cenário onde temos 1 container com a imagem ubuntu:18.04 por exemplo, ocuparia 200MB ( estamos considerando este tamanho para a imagem citada) somados a quantidade de dados específicos deste container ( vamos considerar 50MB para este exemplo) totalizando 250MB. o mesmo caso com 10 containers serão utilizados os 200MB da imagem somados aos 50MB de cada container em execução, pois suas camadas readonly é compartilhada, totalizando assim 750MB no total. O mesmo cenário em máquinas virtuais seria exponen- cialmente maior, uma vez que precisamos instalar todo o sistema operacional e parametrizar cada máquina individualmente. Capítulo 02 - Imagens 30 Gerenciar Imagens no Docker Liste as imagens e verifique o histórico de comandos utilizados para sua construção 1 docker image ls 2 docker image history debian O comando docker image history mostra as camadas que compoem uma imagem Para inspecionar uma imagem utilizamos o comando docker image inspect 1 docker image inspect debian O comando docker image inspect exibe informações detalhadas de uma imagem Vamos criar uma nova imagem a partir de um container existente, para vamos criar um container e instalar alguns pacotes 1 docker container run -dit --name servidor-debian debian 2 docker container exec servidor-debian apt-get update 3 docker container exec servidor-debian apt-get install ngi\ 4 nx -y Para criar uma nova imagem a partir das alterações feitas em um container podemos utilizar o parametro commit 1 docker container commit servidor-debian webserver-nginx 2 docker image ls Capítulo 02 - Imagens 31 O comando docker container commit <container> <imagem> cria uma imagem a partir de alterações realizadas em um container, este procedimento não é o recomendado para este fim, mais a frente veremos outras soluções Para salvar a imagem podemos utilizar o parâmetro save 1 docker image save webserver-nginx -o imagem-webserver-ngi\ 2 nx.tar 3 du -sh imagem-webserver-nginx.tar Remova o container e a imagem servidor web 1 docker container rm -f servidor-debian 2 docker image rm webserver-nginx 3 docker image ls Para carregar uma imagem salva a partir de um arquivo, podemos utilizar o parâmetro load 1 docker image load -i imagem-webserver-nginx.tar 2 docker image ls Para testar o funcionamento da imagem, podemos criar um contai- ner utilizando a mesma 1 docker container run -dit --name webserver webserver-nginx 2 docker container ls Remova todos os containers 1 docker container rm -f $(docker container ls -aq) 2 docker container ls No comando acima, estamos passando através de um subshell o comando docker container ls -aq que lista todos os containers por id, sendo assim, será feita a remoção de todos os containers Capítulo 02 - Imagens 32 Dockerfile O Dockerfile é um arquivo de instruções de como deve ser gerada a imagem Docker, através deste arquivo podemos criar novas imagens para serem utilizadas. Dockerfile ODocker pode criar imagens automaticamente, lendo as instruções de umDockerfile, que é um documento de texto que contém as ins- truções para a criação de uma imagem docker através docomando docker build. Sintaxe Capítulo 02 - Imagens 33 Parâmetro Valor FROM Distribuição:Versão COPY Arquivo_LocalCaminho_Absoluto_no_Container RUN Comando EXPOSE Porta do serviço CMD Comando executado ao iniciar o Container O arquivo de Dockerfile não é case-sensitive, no entanto por convenção utilizamos os parâmetros em maiúsculo para que sua leitura seja mais agradável e de fácil compreensão. O nome do arquivo deve se chamar Dockerfile apenas com a letra inicial D em maiúsculo. O Docker executará as instruções do Dockerfile em ordem (Top- down) e deverá sempre iniciar com a instrução FROM, as linhas que começam com # são tratadas como comentário a menos que a linha seja uma diretiva de analisador válida, o caractere # em qualquer outro lugar em uma linha é tratado como um argumento. Definições • FROM - Inicializa um novo estágio de compilação e define a imagem de base para instruções subsequentes; • COPY - Copia arquivos ou diretórios de origem local adicionando-os a imagem do container; • ADD - Similar ao parâmetro COPY porém possibilita que a origem seja uma URL bem como a alteração de permissiona- mento ao adicionar os arquivos a imagem do container; • RUN - Executa os comandos em uma nova camada na parte superior a imagem atual, é uma boa prática combinar diversos comandos em um unico RUN utilizando de ; e && para a combinação, assim criando apenas uma camada; • EXPOSE - Informa ao docker a porta na qual o container estará escutando enquanto estiver sendo executado, é possível especificar portas TCP e UDP, caso não seja declarado o tipo de porta, o padrão (TCP) é assumido. Capítulo 02 - Imagens 34 • CMD - Só pode existir uma unica instrução deste tipo em um arquivo, o propósito desta instrução é prover os padrões para a execução do container, podendo ser um executável ou até mesmo opções para o executável definido na instrução ENTRYPOINT • ENTRYPOINT - Possibilita configurar o container para ro- dar como um executável, o comando docker run <image> inicializará o container em seu entrypoint somado ao CMD se existente. Criando Dockerfiles Vamos criar um diretório para armazenar os dockerfiles e criar nosso primeiro Dockerfile 1 mkdir -p ~/dockerfiles/echo-container 2 cd ~/dockerfiles/echo-container 3 vim Dockerfile 1 FROM alpine 2 ENTRYPOINT ["echo"] 3 CMD ["--help"] Para criar a imagem a partir do Dockerfile, utilizamos o comando docker image build 1 docker image build -t echo-container . 2 docker image ls A opção -t significa TAG, após o nome da imagem:tag informamos qual o diretório em que o Dockerfile se encontra, utilizamos o ponto ( . ) para dizer que o Dockerfile está no diretório atual (PWD) Execute o container com a imagem criada Capítulo 02 - Imagens 35 1 docker container run --rm -it echo-container A opção –rm informa que o container será apagado após cumprir seu papel Execute o container com a imagem criada alterando seu CMD 1 docker container run --rm -it echo-container Se inscreva \ 2 no canal https://youtube.com/caiodelgadonew Ao passar um parâmetro após o nome da imagem estamos alterando o CMD do container, anteriormente echo –help para echo Container DevOps Dockerfile Servidor WEB Vamos criar um diretório para armazenar o dockerfile para nosso servidor WEB e criar o Dockerfile 1 mkdir ~/dockerfiles/webserver 2 cd ~/dockerfiles/webserver 3 vim Dockerfile 1 FROM debian 2 RUN apt-get update; \ 3 apt-get install wget git apache2 -yq 4 EXPOSE 80 5 CMD ["apachectl", "-D", "FOREGROUND"] Crie a imagem Capítulo 02 - Imagens 36 1 docker image build -t webserver . 2 docker image ls Enviando a imagem para o Dockerhub Para enviar uma imagem para o dockerhub é necessário que sejam feitos 3 passos: 1. docker login 2. docker image tag 3. docker push Vamos efetuar o login com nossa conta no dockerhub 1 docker login -u <usuario_dockerhub> Agora precisamos criar a tag da imagem, que deve seguir o padrão usuario/imagem:versao 1 docker image tag echo-container <usuario_dockerhub>/echo-\ 2 container:latest 3 docker image tag webserver <usuario_dockerhub>/webserver Caso não seja informada uma versão, o docker entende que a versão trata-se da latest Agora podemos enviar as imagens para o dockerhub 1 docker image push <usuario_dockerhub>/echo-container 2 docker image push <usuario_dockerhub>/webserver Ao finalizar, lembre-se de efetuar o logout em sua conta do doc- kerhub Capítulo 02 - Imagens 37 1 docker logout As imagens enviadas podem ser visualizadas na sua página do dockerhub e todos os usuários podem efetuar o download damesma com o comando docker image pull usuario/imagem:versao desde que o repositório seja público Repositório Melhores práticas com o Dockerfile Quando criamos uma imagem, através do comando docker image build , a imagem definida pelo Dockerfile deve gerar containers que são tão efêmeros quanto possível, isso quer dizer que o con- tainer deve poder ser parado e/ou destruido a qualquer momento, e reconstruido ou substituido com o mínimo de configuração ou atualização. Uma boa metodologia para conseguir chegar neste ponto é a do Twelve-factor App, ou Aplicação de Doze-fatores, e em sua seção Capítulo 02 - Imagens 38 de processos⁴ podemos verificar algumas das motivações para subir containers maneira stateless (não armazenam estado). Entendendo o contexto de Build Quando executamos o comando docker image build , o diretório no qual apontamos (muitas das vezes como . para referir o diretório atual) é chamado de build context. Por padrão oDocker espera que o Dockerfile esteja localizado nesta pasta, mas também podemos especificar uma nova localização através da flag -f. Independente- mente de onde o Dockerfile esteja, todo o conteúdo dos diretórios recursivamente e arquivos é enviado para o Docker daemon como build context. Por isto não devemos, por exemplo, criar um Dockerfile diretamente em nossa home ∼/Dockerfile , uma vez que todo o conteúdo, inclusive o cache de navegadores web e todas aplicações ∼/.cache será enviado para o Docker daemon, muitas das vezes falhando a build ou até mesmo fazendo com que ela demore muito tempo. Primeiramente vamos criar um diretório para guardar nosso doc- kerfile e criar um arquivo com um conteúdo estático 1 mkdir -p ~/dockerfiles/exemplo1 2 cd ~/dockerfiles/exemplo1 3 echo "Dockerfile Melhores Práticas" > conteudo.txt Agora podemos criar nosso Dockerfile: ⁴https://12factor.net/pt_br/processes https://12factor.net/pt_br/processes https://12factor.net/pt_br/processes Capítulo 02 - Imagens 39 1 vim Dockerfile 1 FROM busybox 2 COPY conteudo.txt / 3 RUN cat /conteudo.txt Agora vamos criar a imagem. 1 docker image build -t exemplo:v1 . Agora vamos criar novos diretórios e mover o arquivo conteudo.txt para um diretório diferente do dockerfile para construir uma se- gunda imagem. 1 mkdir -p image context 2 mv Dockerfile image 3 mv conteudo.txt context 4 docker image build --no-cache -t exemplo:v2 -f image/Dock\ 5 erfile context As duas imagens tem o mesmo tamanho e o mesmo conteúdo, porém note que as imagens tem o ID diferente porque criamos a imagem sem utilizar o cache --no-cache, ou seja, criamos uma imagem totalmente nova. Capítulo 02 - Imagens 40 1 $ docker image ls 2 3 REPOSITORY TAG IMAGE ID CREATED \ 4 SIZE 5 exemplo v2 589078e3e007 2 seconds \ 6 ago 1.24MB 7 exemplo v1 de0bdd45cb9a 3 minutes \ 8 ago 1.24MB Caso sejam incluidos arquivos que não são necesssários para a construção da imagem o build context se tornará maior e conse- quentemente uma imagem maior. Isso pode aumentar o tempo de construção, envio e download da imagem e do container runtime. Para ver o tamanho do build context basta verificar a mensagem exibida quando executar o build do seu Dockerfile. Vamos copiar todo o conteúdo do diretório /var/log para o context e construir a imagem. 1 sudo cp -r /var/log/ ~/dockerfiles/exemplo1/context/ 2 sudo chown -R vagrant:vagrant ~/dockerfiles/exemplo1/cont\ 3 ext/log 4 docker image build --no-cache -t exemplo:v3 -f image/Dock\ 5 erfile context Veja que o context que anteriormente era de apenas 2.6KB desta vez foi de 26,62MB, oque resulta em um tempo de buildmaior porém sua imagem continua do mesmo tamanho das outras já que o arquivo foi enviado para o context e não foi utilizado. 1 Sending build context to Docker daemon 2.607kB 2 Sending build context to Docker daemon 26.62MB Tratando de poucos MB o tempo de construção pode não ser muito expressivo, porém imagine em uma grande aplicação com diversos Capítulo 02 - Imagens 41 arquivos. Utilizando o comando time fiz a medição no caso de 2.6KB que gerou a build em 0m0.910s contra 0m1.368s do arquivo de 26,62MB. esse tempo pode ser superior caso a imagem execute diversos comandos em diversas camadas. Excluindo arquivos do build Para excluir arquivos que não são relevantes a build, podemos criar um arquivo .dockerignore contendo os padrões de exclusão similares aos do .gitignore possibilitando que ignoremos arquivos no build sem ter que modificar nosso repositório. Para a referência do Docker Ignore veja a Documenta- ção Oficial⁵ Vamos criar agora um arquivo .dockerignore para que o diretório log não seja enviado para a build. 1 vim context/.dockerignore 1 # Comentario: Ignorando arquivos do diretorio log 2 log 1 docker image build --no-cache -t exemplo:v4 -f image/Dock\ 2 erfile context Veja que o diretório log foi ignorado, uma vez que o build context ficou em 2.6kB (agora um pouco maior que a primeira por possuir o arquivo .dockerignore) ao invés dos 26MB anteriores. ⁵https://docs.docker.com/engine/reference/builder/#dockerignore-file https://docs.docker.com/engine/reference/builder/#dockerignore-file https://docs.docker.com/engine/reference/builder/#dockerignore-file https://docs.docker.com/engine/reference/builder/#dockerignore-file Capítulo 02 - Imagens 42 Dicas Vamos criar um diretório para o exemplo a seguir para guardar nosso Dockerfile e fazer o download de uma aplicação exemplo em java que conta o numero de caracteres de um texto. 1 mkdir -p ~/dockerfiles/dicas 2 cd ~/dockerfiles/dicas 3 git clone https://github.com/caiodelgadonew/java-wc-app.g\ 4 it app Dica #1: A ordem importa para o cache A ordem dos passos de build é importante, se o cache de um pri- meiro passo é invalidado pela modificação de arquivos ou linhas do Dockerfile, os arquivos subsequentes do build quebrarão. Sempre faça a ordenação dos passos do que sofrerá menos mudanças para o que sofrerá mais mudança. melhores-práticas-1 1 vim Dockerfile Capítulo 02 - Imagens 43 1 FROM debian:9 2 RUN apt-get update 3 RUN apt-get install -y openjdk-8-jdk wget ssh vim 4 COPY app /app 5 ENTRYPOINT ["java", "-jar", "/app/target/app.jar"] 1 docker image build -t dicas:v1 . Dica #2: COPY mais específico para limitar a quebra de cache Só copie o necessário. Se possível evite o COPY. Quando copiamos arquivos para nossa imagem, tenha certeza que você está sendo bem específico sob o que quer copiar, qualquer mudança no arquivo copiado quebrará o cache. Copiaremos então apenas a aplicação para a imagem, desta maneira as mudanças nos arquivos não afetarão o cache. melhores-práticas-2 1 vim Dockerfile Capítulo 02 - Imagens 44 1 FROM debian:9 2 RUN apt-get update 3 RUN apt-get install -y openjdk-8-jdk wget ssh vim 4 COPY app/target/app.jar /app/app.jar 5 COPY app/samples /samples 6 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v2 . Dica #3: Identifique as instruções que podem ser agrupadas Cada instrução RUN cria uma unidade de cache e uma nova camada de imagem, agrupar todos os comandos RUN em uma única instrução pode melhorar o desempenho e diminuir a quantidade de camadas uma vez que eles se tornarão uma unidade única cacheavel. melhores-práticas-3 1 vim Dockerfile Capítulo 02 - Imagens 45 1 FROM debian:9 2 RUN apt-get update \ 3 && apt-get install -y \ 4 openjdk-8-jdk wget \ 5 ssh vim 6 COPY app/target/app.jar /app/app.jar 7 COPY app/samples /samples 8 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v3 . Dica #4: Remova as dependências desnecessárias Remover as dependencias desnecessárias e não instalar pacotes de debug é uma boa prática, como por exemplo trocar o jdk (Java Development Kit) pelo jre (Java Runtime Environment) que é um pacote relativamente menor e contém apenas o necessário para execução. Você pode instalar as ferramentas de debug posterior- mente caso necessite. O instalador de pacotes apt possui uma flag --no-install-recommends que garante que dependencias que não são necessárias não sejam instaladas. Caso precise, adicione elas explicitamente. melhores-práticas-4 1 vim Dockerfile Capítulo 02 - Imagens 46 1 FROM debian:9 2 RUN apt-get update \ 3 && apt-get install -y --no-install-recommends \ 4 openjdk-8-jre 5 COPY app/target/app.jar /app/app.jar 6 COPY app/samples /samples 7 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v4 . Com a Dica #4 podemos notar uma diminuição consideravel no tamanho de nossa imagem. melhores-práticas-dica4 Dica #5: Remover o cache do gerenciador de pacotes O gerenciador de pacotes mantem seu próprio cache, o apt por exemplo guarda seu cache no diretório /var/lib/apt/lists e /var/cache/apt/. Uma das maneiras de lidar com este problema é remover o cache na mesma instrução que o pacote foi instalado. Remover este cache em outra instrução não irá diminuir o tamanho da imagem. Capítulo 02 - Imagens 47 melhores-práticas-5 1 vim Dockerfile 1 FROM debian:9 2 RUN apt-get update \ 3 && apt-get install -y --no-install-recommends \ 4 openjdk-8-jre \ 5 && rm -rf /var/lib/apt/lists \ 6 && rm -rf /var/cache/apt 7 COPY app/target/app.jar /app/app.jar 8 COPY app/samples /samples 9 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v5 . Agora com a Dica #5 nossa imagem ficou relativamente menor. melhores-práticas-dica5 Capítulo 02 - Imagens 48 Dica #6: Utilize imagens oficiais quando possível Imagens oficiais podem ajudar muito e reduzir bastante o tempo preparando a imagem, isto porque os passos de instalação já vem prontos e normalmente com as melhores praticas aplicadas, isto também fará você ganhar tempo caso tenha multiplos projetos, eles compartilham as mesmas camadas e utilizam a mesma imagem base. melhores-práticas-6 1 vim Dockerfile 1 FROM openjdk 2 COPY app/target/app.jar /app/app.jar 3 COPY app/samples /samples 4 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v6 . Dica #7: Utilize Tags mais específicas Nunca utilize a tag latest. Ela pode receber alguma atualização e em um momento de update sua aplicação pode quebrar, depen- dendo de quanto tempo passou do seu último build. Ao invés disso, utilize tags mais específicas. Capítulo 02 - Imagens 49 melhores-práticas-7 1 vim Dockerfile 1 FROM openjdk:8 2 COPY app/target/app.jar /app/app.jar 3 COPY app/samples /samples 4 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v7 . Dica #8: Procure por flavors mínimos Existem diversos flavors linux que fazem com que nossa imagem se torne cada vez menor, um bom exemplo são as imagens slim e alpine as quais são as menores encontradas. A imagem slim é baseada no Debian, enquanto a alpine é baseada em uma distribui- ção linux muito menor chamada Alpine. A diferença básica entre elas é que o debian utiliza a biblioteca GNU libc enquanto o alpine utiliza musl lbc, que apesar de muito menor, pode ter problemas de compatibilidade. Capítulo 02 - Imagens 50 1 docker image pull openjdk:8 2 docker image pull openjdk:8-jre 3 docker image pull openjdk:8-jre-slim 4 docker image pull openjdk:8-jre-alpine 5 docker image ls | egrep "REPOSITORY|openjdk" 1 REPOSITORY TAG SIZE 2 openjdk 8 510MB 3 openjdk 8-jre 265MB 4 openjdk 8-jre-slim 184MB 5 openjdk 8-jre-alpine 84.9MB 1 vim Dockerfile 1 FROM openjdk:8-jre-alpine 2 COPY app/target/app.jar /app/app.jar 3 COPY app/samples /samples 4 ENTRYPOINT ["java", "-jar", "/app/app.jar"] 1 docker image build -t dicas:v8 . Agora temos uma diminuição enorme em nossa imagempois estamos utilizando uma imagem base bem menor. melhores-práticas-dica8 Capítulo 02 - Imagens 51 Dica #9: Multi-stage build Multi-stage build é um recurso muito poderoso que apareceu a partir do docker 17.05. Multi-stage builds são uteis para quem quer otimizar Dockerfiles enquanto mantém eles fáceis de ler e manter. Antes do Multi-stage build o maior desafio das imagens é de fato manter as imagens pequenas, vimos nos exemplos anteriores que conseguimos, ao utilizar algumas das melhores práticas, diminuir bastante o tamanho da imagem. Utilizando imagens slim ou alpine resolvem boa parte dos nossos problemas mas quando precisamos resolver algo mais complexo podemos utilizar elas somadas ao multi-stage build. O multi-stage build faz com que possamos utilizar diversas instruções FROM em um Dockerfile, e cada instrução pode utilizar uma imagem diferente, fazemos isto por exemplo para subir uma imagem, dentro desta imagem instalar os pacotes e coletar apenas os arquivos necessários diretamente para a imagem subsequente. Com isso temos uma imagem muito mais enxuta e otimizada. Por exemplo vamos criar esta imagem emGO pelo processo normal: 1 git clone https://github.com/alexellis/href-counter.git ~\ 2 /dockerfiles/multistage 3 cd ~/dockerfiles/multistage 4 rm Docker* 5 vim Dockerfile Capítulo 02 - Imagens 52 1 FROM golang:1.7.3 2 WORKDIR go/src/github.com/alexellis/href-counter/ 3 RUN go get -d -v golang.org/x/net/html 4 COPY app.go . 5 RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuf\ 6 fix cgo -o app . 7 CMD ["./app"] 1 docker image build -t multistage:v1 . Esta imagem ficou com o tamanho de 700MB, po- rém o que precisamos nela é apenas o diretório /go/src/github.com/alexellis/href-counter/app, podemos então utilizar o multistage build para recolher estes arquivos, chamando a primeira imagem de builder através do parâmetro AS <nome> e depois invocar a imagem em um segundo estágio através do parâmetro --from=<nome>. 1 vim Dockerfile 1 FROM golang:1.7.3 AS builder 2 WORKDIR /go/src/github.com/alexellis/href-counter/ 3 RUN go get -d -v golang.org/x/net/html 4 COPY app.go . 5 RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuf\ 6 fix cgo -o app . 7 8 FROM alpine:latest 9 RUN apk --no-cache add ca-certificates 10 WORKDIR /root/ 11 COPY --from=builder /go/src/github.com/alexellis/href\ 12 -counter/app . 13 CMD ["./app"] Capítulo 02 - Imagens 53 melhores-práticas-9 1 docker image build -t multistage:v2 . Agora tivemos uma “pequena” redução de 700MB para 12MB 1 docker image ls | egrep "REPOSITORY|multistage" 1 REPOSITORY TAG IMAGE ID CREATED \ 2 SIZE 3 multistage v1 dae3f0761024 28 minute\ 4 s ago 700MB 5 multistage v2 a1108a2b5102 33 minute\ 6 s ago 11.7MB Caso deseje testar a imagem basta executar o comando 1 docker container run --rm -it -e url=https://youtube.com/\ 2 caiodelgadonew multistage:v1 3 docker container run --rm -it -e url=https://youtube.com/\ 4 caiodelgadonew multistage:v2 Outra coisa interessante é que ao invés de utilizar uma imagem completa podemos puxar um arquivo de uma imagem já criada anteriormente através da flag --from=<image>:<tag>, vamos fazer a cópia de um arquivo da imagem da dica 7 para a imagem do multistage, para isto criaremos um diretório chamado multistage2. Capítulo 02 - Imagens 54 1 mkdir -p ~/dockerfiles/multistage2 2 cd ~/dockerfiles/multistage2 3 vim Dockerfile 1 FROM alpine:latest 2 WORKDIR /root/ 3 COPY --from=dicas:v7 /samples/1.txt . 4 CMD ["cat", "1.txt"] 1 docker image build -t multistage:v3 . Podemos agora executar nosso container para verificar se o arquivo 1.txt é de fato o arquivo extraido da imagem dica:v7 1 docker container run --rm -it multistage:v3 É sempre bom tentar diminuir as imagens de docker e seguir as melhores práticas, isso faz com que nosso tempo de deploy ou scale da aplicação seja menor, bem como a necessidade de um armazenamento maior e diversos outros fatores. Removendo todas as imagens 1 docker image prune -a Capítulo 03 - Storage Drivers Storage Drivers possibilitam a criação de dados em uma camada gravável do container. Os arquivos não serão persistidos após o container ser deletado, ambas velocidades de leitura e escrita tem performance mais lentas que um sistema de arquivos. Storage Drivers • Device Mapper: Framework de gerenciamento de volumes linux • btrfs: CoW (copy-on-write) filesystem, pode ser utilizado para combinar diversos blocos físicos em um único sistema btrfs • aufs: Union Filesystem. Driver antigo, não deve ser utilizado em kernel > 4.0 , overlay2 é superior • OverlayFS: Union Filesystem morderno, também conhecido como overlay2, é o recomendado pelo docker. • ZFS: Next Generation filesystem, suporta gerenciamento de volume, snapshot, checksum, compressão, replicação, etc… • VFS: cada camada é diretamente um diretório no disco, sem suporte ao CoW (copy-on-write) CoW ou copy-on-write é uma tecnica de gestão de recursos criada para duplicar ou copiar em recursos Capítulo 03 - Storage Drivers 56 modificáveis. Se um recurso é duplicado mas não mo- dificado, não é preciso criar um novo recurso, é feito o compartilhamento do recurso atual. Para visualizar o storage driver em uso basta executar o comando 1 docker system info | grep Storage A alteração do storage driver padrão deve ser feita através do arquivo de parametrização daemon.json no qual falaremos mais adiante 1 { 2 "storage-driver": "overlay2" 3 } Docker Volumes Volume é um diretório especialmente designado, seja em um ou mais containers que compartilham o sistema de arquivos UnionFS Os volumes são projetados para manter os dados, independente- mente do ciclo de vida do container. O Docker nunca exclui um volume automaticamente quando você remove um container. Existem 3 tipos de Volumes: • host - Reside no sistema de arquivos do host do docker e pode ser acessado dentro de um container; • nomeado - Volume gerenciado e criado pelo Docker, na criação do volume é dado um nome para o mesmo. • anônimo - Volume gerenciado e criado pelo Docker, na criação do volume não é informado o nome para o mesmo e o Docker se encarrega de nomeá-lo com um hash de 64 caracteres. Capítulo 03 - Storage Drivers 57 Existem alguns tipos de montagem para os volumes. O volume do tipo host tem sua montagem realizada como um bind mount e existe ainda um volume do tipo tmpfs mount o qual reside na memória do sistema (volátil) Mounts Existem algumas vantagens ao se utilizar volumes do Docker ao invés de bind mounts • Volumes são mais fáceis de efetuar o backup ou migração que bind mounts; • É possível efetuar a gerência de volumes utilizando o Docker CLI ou o Docker API; • Volumes podem ser compartilhados de maneira mais segura entre múltiplos containers; • Drivers de Volumes podem habilitar o armazenamento em hosts remotos ou provedores de cloud, criptografar o con- teúdo ou adicionar novas funcionalidades; • Novos volumes podem ter seu conteúdo pré-populados por um container. Capítulo 03 - Storage Drivers 58 Gerenciar Volumes Para utilizar volumes no docker utilizamos a opção -v ou –volume para indicar qual volume deve ser montado no container. Também podemos montar um volume utilizando a opção --mount que é mais explicita e verbosa. A maior diferença é que a sintaxe do -v combina todas as opções no mesmo campo, enquanto a --mount separa elas. Contrário a bind mounts, todas as opções para volumes são disponíveis para ambas flags -v e --mount. Quando usamos volumes com serviços, somente a opção --mount é suportada. Primeiramente vamos montar um volume do tipo host através de um bind mount 1 docker container run -dit --name servidor -v /srv:/srv de\ 2 bian 3 docker container exec servidor df -Th O parâmetro -v seguido de um diretório em caminho absoluto ou relativo separado por : a um caminho absoluto faz com que o diretório /srv da máquina hospedeira seja montado dentro do container gerado. Vamos efetuar a cópia de alguns arquivos para o volume, verifi- cando o conteúdoda pasta antes e após a execução 1 docker container exec servidor ls -lR /srv 2 sudo cp -r ~/dockerfiles /srv 3 docker container exec servidor ls -lR /srv Note que os arquivos copiados para a pasta /srv do host estão sendo exibidos também na pasta /srv do container Capítulo 03 - Storage Drivers 59 Vamos remover o container e criá-lo novamente utilizando um volume anônimo 1 docker container rm -f servidor 2 docker container run -dit --name servidor -v /volume debi\ 3 an Podemos utilizar o comando docker container inspect para verifi- car o local e nome do volume criado 1 docker container inspect servidor | grep volume Por padrão, os volumes criados e gerenciados pelo docker se localizam no diretório /var/lib/docker/volumes Podemos também visualizar informações do volume através do comando docker volume inspect 1 docker volume ls 2 docker volume inspect <hash> Visualize o volume criado no container 1 docker container exec servidor df -Th 2 docker container exec servidor ls -lR /volume Copie os arquivos no host hospedeiro e verifique o conteúdo no container 1 sudo cp -r ~/dockerfiles /var/lib/docker/volumes/<hash>/_\ 2 data 3 docker container exec servidor ls -lR /volume Vamos remover o container e criá-lo novamente utilizando um volume nomeado Capítulo 03 - Storage Drivers 60 1 docker container rm -f servidor 2 docker container run -dit --name servidor -v volume:/volu\ 3 me debian 4 docker volume ls Perceba que a diferença de um volume nomeado para um anônimo é apenas o nome do volume Para criar o mesmo container utilizando a flag --mount precisamos passar o source e o target 1 docker container run -dit --name servidor2 --mount source\ 2 =volume2,target=/volume2 debian Podemos inspecionar o container filtrando o volume com a opção -f ou --format 1 docker container inspect servidor --format '{{json .Mount\ 2 s }}' 3 docker container inspect servidor2 -f '{{json .Mounts }}' Podemos também visualizar de uma maneira mais agradável ao instalar o jq e passar a saída dos comandos acima para o jq 1 sudo apt-get update && sudo apt-get install jq -y 2 docker container inspect servidor --format '{{json .Mount\ 3 s }}' | jq 4 docker container inspect servidor2 -f '{{json .Mounts }}'\ 5 | jq Selinux Labels O mode :z indica que o conteúdo do bind mount é compartilhado entre múltiplos containers Capítulo 03 - Storage Drivers 61 O mode :Z indica que o conteúdo do bind mount é privado e não compartilhado Para remover um volume no docker podemos utilizar a opção rm 1 docker volume ls 2 docker volume rm <hash> 3 docker volume rm $(docker volume ls -q) O comando docker volume ls -q lista os volumes por id ATENÇÃO: a remoção do volume através do comando docker volume rm faz com que o volume seja excluído, não sendo possível a recuperação dos dados. tmpfs mounts Volume e bind mounts permitem que compartilhemos arquivos entre a máquina hospedeira e o container, de maneira a persistir os dados após o container ser parado. Outro tipo de volume é o tmpfs. quando criamos um container com tmpfs mount, o container pode criar arquivos fora da camada de escrita do container. Diferente de volumes e bind mounts, um tmpfs é uma montagem temporária, e só persiste na memória do host. Quando o container para, o tmpfsmount é removido e os arquivos que foram criados lá não persistem em disco. tmpfs mounts são úteis para armazenar temporariamente informa- ção sensível das quais não gostaríamos de persistir no host ou na camada de escrita. Para criar uma montagem tmpfs utilizamos o comando --tmpfs Existem algumas diferenças que precisamos saber entre tmpfs e bind mounts. Capítulo 03 - Storage Drivers 62 • a flag --tmpfs não possibilita o uso de opções configuráveis. • a flag --tmpfs não pode ser utilizada com serviços swarm. (Apenas --mount) Utilizando uma montagem do tipo tmpfs 1 docker container run -dit --name tmpfstest1 --mount type=\ 2 tmpfs,destination=/app debian 3 docker container run -dit --name tmpfstest2 --tmpfs /app \ 4 debian Vamos inspecionar os containers 1 docker container inspect tmpfstest1 --format '{{json .Mou\ 2 nts }}' | jq 3 docker container inspect tmpfstest2 -f '{{json .HostConfi\ 4 g.Tmpfs }}' | jq Adiferença entre osmodos demontagem é vista através do docker container inspect e a seção de mounts e host config. Vamos remover os containers 1 docker container rm -f tmpfstest1 tmpfstest2 O tmpfs mount possibilita duas opções de configuração (Não obri- gatórias), que apenas funcionam através da opção --mount Opção Descrição tmpfs-size Tamanho em bytes, por padrão não existe limite tmpfs-mode Permissionamento do tmpfs em octal. Ex: 700 ou 0770. Padrão 1777 Capítulo 03 - Storage Drivers 63 Exemplo: 1 docker container run -dit --name tmpfstest --mount type=t\ 2 mpfs,destination=/app,tmpfs-size=100M debian 3 docker container inspect tmpfstest --format '{{json .Host\ 4 Config.Mounts }}' | jq 5 docker container exec tmpfstest df -Th 6 docker container rm -f $(docker container ls -aq) Backup & Restore Podemos utilizar volumes para fazer backups, restaurações ou migrações de sistemas, para isto utilizamos a flag --volumes-from para criar um novo container que utilize o mesmo volume utilizado anteriormente. Backup Vamos criar um container básico com o nome de webserver e copiar alguns arquivos para o mesmo 1 docker container run -dit -v /webdata --name webserver de\ 2 bian 3 docker container cp ~/dockerfiles webserver:/webdata 4 docker container exec webserver ls -lR /webdata 5 docker container exec webserver df -Th 6 docker volume ls Veja que foi criado um volume do tipo anônimo. Para entender como isto funciona, podemos subir um novo contai- ner utilizando este volume do container webserver Capítulo 03 - Storage Drivers 64 1 docker container run -dit --volumes-from webserver --name\ 2 volumetest debian 3 docker container exec volumetest df -Th 4 docker container exec volumetest ls -lR /webdata 5 docker container inspect webserver --format '{{json .Moun\ 6 ts }}' | jq 7 docker container inspect volumetest --format '{{json .Mou\ 8 nts }}' | jq 9 docker container rm -f volumetest Note que os volumes são os mesmos, com isso podemos efetuar o backup dos arquivos do container subindo um container extra com o propósito de empacotar os arquivos. 1 mkdir ~/backup 2 cd ~/backup 3 docker container run --rm --volumes-from webserver -v $(p\ 4 wd):/backup alpine tar cvf /backup/backup.tar /webdata 5 tar -tvf backup.tar O container com a imagem do alpine foi executado com a finalidade única de empacotar o conteúdo do diretório /webdata em um novo arquivo backup.tar 1 drwxr-xr-x root/root 0 2021-06-24 07:05 webdata/ 2 drwxrwxr-x 1000/1000 0 2021-06-24 07:05 webdata/d\ 3 ockerfiles/ 4 -rw-rw-r-- 1000/1000 0 2021-06-24 07:05 webdata/d\ 5 ockerfiles/arquivo2.txt 6 -rw-rw-r-- 1000/1000 0 2021-06-24 07:05 webdata/d\ 7 ockerfiles/arquivo3.txt 8 -rw-rw-r-- 1000/1000 0 2021-06-24 07:05 webdata/d\ 9 ockerfiles/arquivo1.txt 10 ```` 11 Capítulo 03 - Storage Drivers 65 12 Vamos agora remover todos os containers e volumes criados 13 ```bash 14 docker container rm -f $(docker container ls -aq) 15 docker volume rm -f $(docker volume ls -q) Restore Para restaurar o volume para um novo container primeiramente iremos criar o novo container com um novo volume. 1 docker container run -dit -v /webdata --name webserver2 d\ 2 ebian 3 docker container exec webserver2 ls -lR /webdata Agora podemos subir um novo container com o novo volume e restaurar o backup 1 docker container run --rm --volumes-from webserver2 -v $(\ 2 pwd):/backup alpine ash -c "cd /webdata && tar xvf /backu\ 3 p/backup.tar --strip 1" 4 5 docker container exec webserver2 ls -lR /webdata Plugins Plugins são utilizados para extender as funcionalidades do Docker. Atualmente o Docker suporta os plugins de Autorização, Redes e Volumes. Plugins são distribuidos como imagens docker e podem ser armaze- nados no Docker Hub ou em um private registry.Para gerenciamento de plugins, utilizamos o comando docker plugin Capítulo 03 - Storage Drivers 66 Para uma lista completa dos plugins veja Docker Engine Plugins⁶ Volume Plugins Lista completa com definições Volume Plugins⁷ Os plugins de volumes habilitam com que os volumes docker persistam através de diversos docker hosts. Instalando um plugin Iremos instalar um plugin chamado sshfs que trata-se de um plugin para sistema de arquivos baseado em SSH. O exemplo utilizado deve ser utilizado apenas para fins de estudo, uma vez que o volume seja criado, sua senha ssh para o host remoto será exposta como texto plano quando inspecionar o volume. 1. Instale o plugin sshfs 1 docker plugin install vieux/sshfs O plugin irá solicitar acesso a alguns privilégios. • Acesso a rede host • Acesso a capability CAP_SYS_ADMIN que habilita o plugin a executar o comando mount. • Acesso ao ponto de montagem • acesso ao dispositivo /dev/fuse ou Filesystem in Userspace 2. Verifique se o plugin foi instalado e está habilitado ⁶https://docs.docker.com/engine/extend/legacy_plugins/ ⁷https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins https://docs.docker.com/engine/extend/legacy_plugins/ https://docs.docker.com/engine/extend/legacy_plugins/ https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins https://docs.docker.com/engine/extend/legacy_plugins/ https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins Capítulo 03 - Storage Drivers 67 1 docker plugin ls 3. Na máquina destino, garanta que o ssh está habilitado com usuário e senha. Em um novo terminal 1 $ vagrant ssh node02 2 $ sudo yum install vim -y 3 $ sudo vim /etc/ssh/sshd_config 4 5 PasswordAuthentication yes 6 7 $ sudo systemctl restart sshd 4. Crie um volume utilizando o plugin. 1 $ docker volume create -d vieux/sshfs --name sshvolume -o\ 2 sshcmd=vagrant@10.20.20.120:/vagrant -o password=vagrant 3 $ docker volume ls 4 $ docker volume inspect sshvolume | jq 5. Inicie um container com o volume 1 $ docker container run --rm -v sshvolume:/data alpine ls \ 2 /data Volume NFS Na máquina master vamos instalar um servidor NFS e mapear um diretório Capítulo 03 - Storage Drivers 68 1 $ vagrant ssh master 2 $ sudo apt-get update 3 $ sudo apt-get install nfs-server -y 4 $ mkdir -p /home/vagrant/storage 5 $ echo "/home/vagrant/storage/ 10.20.20.0/24(rw)" | sudo \ 6 tee -a /etc/exports 7 $ echo "<h1> Volume NFS master.docker-dca.example</h1>" |\ 8 tee /home/vagrant/storage/index.html 9 $ sudo systemctl restart nfs-server 10 $ showmount -e Na máquina node01 vamos instalar o client nfs 1 $ vagrant ssh node01 2 $ sudo apt-get install nfs-common -y 3 $ sudo showmount -e master.docker-dca.example Na máquina node02 vamos instalar o client nfs 1 $ vagrant ssh node02 2 $ sudo yum install nfs-utils -y 3 $ sudo showmount -e master.docker-dca.example Instale o plugin NFS na máquina node01 e node02 1 $ docker plugin install trajano/nfs-volume-plugin --grant\ 2 -all-permissions O plugin irá solicitar acesso a alguns privilégios. • Acesso a rede host • Acesso a capability CAP_SYS_ADMIN que habilita o plugin a executar o comando mount. • Acesso ao ponto de montagem /sys/fs/cgroup Crie o volume na máquina node01 Capítulo 03 - Storage Drivers 69 1 $ docker volume create -d trajano/nfs-volume-plugin \ 2 --opt device=master.docker-dca.example:/home/vagrant/stor\ 3 age \ 4 --opt nfsopts=hard,proto=tcp,nfsvers=3,intr,nolock volum\ 5 e_nfs 6 7 $ docker volume inspect volume_nfs | jq Execute um container com o volume nfs 1 $ docker container run -dit --name webserver -v volume_nf\ 2 s:/usr/share/nginx/html/ -p 80:80 nginx 3 $ docker volume inspect volume_nfs | jq Verifique nas máquinas o conteudo 1 $ watch curl -s localhost Altere o conteudo do index.html na máquina master e verifique o conteudo em tempo real nas máquinas node01 e node02 1 $ echo "<h2> Novo conteudo para o volume compartilhado</h\ 2 2>" | tee -a /home/vagrant/storage/index.html 3 $ echo "<marquee> Se inscreva no canal https://youtube.co\ 4 m/caiodelgadonew</marquee>" | tee -a /home/vagrant/storag\ 5 e/index.html Remova os containers dos nodes 1 $ docker container rm -f webserver Capítulo 04 - Networking Um dos motivos pelos quais os contêineres e serviços do Docker são tão poderosos é que você pode conecta-los entre si ou a outros serviços. Para isso, utilizamos as redes docker. Recursos de Network utilizados pelo docker: Networking • veth: Virtual Ethernet • bridge: Interface Bridge • iptables: Regras de isolamento de redes Administrando Redes Por padrão quando um container é criado ele não publica nenhuma de suas portas para o mundo externo. Para disponibilizar uma porta para serviços fora do ambiente Docker ou para containers que não estejam conectados a mesma rede, utilizamos a flag –publish ou -p. Isso cria uma regra de firewall que mapeia uma porta de container para uma porta do host. Quando executamos um container, podemos definir a publicação de uma ou mais portas através da opção -p Capítulo 04 - Networking 71 hostaddress:hostport:containerport. Para expor as portas em qualquer endereço utilizamos o hostaddress 0.0.0.0. Vamos subir nosso container webserver expondo a porta para a nossa rede 1 $ docker container run -dit --name webserver -p 80:80 web\ 2 server Podemos acessar a aplicação no navegador pelo endereço http://node01.docker-dca.example Remova o container webserver 1 $ docker container rm -f webserver Network Drivers O sistema de redes do docker é “plugável” com a utilização de drivers. Existem diversos drivers para fornecer recursos e funcio- nalidades de rede: • bridge: Driver de rede padrão. Se não especificarmos um driver, é o tipo de rede que o docker irá utilizar. Geralmente utilizamos redes bridge quando a aplicação será executada em containers isolados que precisam de comunicação. • host: Para containers isolados, remove o isolamento de rede entre o container e o host Docker e utiliza a rede diretamente. • overlay: Redes utilizadas para conectar multiplos Docker Daemons e habilitar os serviços de swarm (cluster) para se comunicarem entre si. • macvlan: Redes Macvlan possibilitam que configuremos um endereço MAC a um container, fazendo com que ele apareça como um dispositivo físico na rede. O docker daemon faz o roteamento do trafégo entre containers pelo MAC Address. Capítulo 04 - Networking 72 • none: Redes do tipo none disabilitam toda parte de redes do container, não pode ser utilizada com swarm (cluster). • plugins: Utilizados para extender a funcionalidade de redes docker Redes Básico Para gerenciar as redes do docker, utilizamos o comando docker network Liste as redes disponiveis 1 $ docker network ls Bridge É a rede padrão do Docker, caso o container seja criado sem especificar um driver de rede a rede do tipo bridge é utilizada. Esta rede é criada utilizando um driver de rede de ponte que instancia uma interface de rede no linux chamada de dockerX sendo X um numero. Por padrão a rede bridge conta com um serviço interno de DNS, ou seja, os containers respondem internamente através de seu nome. Também é possivel conectar e desconectar containers on-the-fly. Capítulo 04 - Networking 73 bridge Para executar um container com a rede bridge podemos passar a flag --network bridge como parametro do comando docker container run 1 $ docker container run -dit --name webserver --network br\ 2 idge -p 80:80 webserver Verifique o serviço na porta 80 do host Capítulo 04 - Networking 74 1 $ sudo ss -ntpl | grep 80 O processo que é executado na porta através da rede bridge é o docker-proxy O que o docker faz por trás dos panos é a criação de uma série de regras do iptables para criar o isolamento dos processos de rede. Podemos verificar isto através do comando 1 $ sudo iptables -nL Remova o container webserver 1 $ docker container rm -f webserver Host É a rede onde o IP da máquina é compartilhado com o container, nesta rede não é