Salve das Beleza! Continuamos a nossa saga aqui no nosso módulo de Docker. Para finalizar esse módulo do curso, nós vamos ver como criar imagens otimizadas para a produção. Porque um dos grandes benefícios de se utilizar o Docker é já criar a imagem com todo o aparato ali que a gente precisa para poder rodar a aplicação. todo o aparato ali que a gente precisa para poder rodar a aplicação. Então, inicia-se o container, a aplicação já rodou sem fazer nenhuma configuração. Tudo já está dentro da imagem. A gente mais que aprendeu isso durante as aulas. Então, nessa aula aqui, eu reuni uma série de boas práticas para poder mostrar como criar essa imagem de produção. A gente vai criar essa imagem nessa aula e na próxima aula nós vamos fechar com o Multistage Build, que é um recurso essencial para otimizar ainda mais as nossas imagens. Então, bora aqui para o VSCode. Eu criei Esse Readme aqui Que vocês podem dar uma olhada Que são várias boas práticas Que é o que eu vou passar aqui exatamente nessa aula Então eu estou pegando um app Node.js Depois eu vou pegar Na próxima aula Um Golang Mais um Python A imagem em Python inclusive vai ser bem complexa E nós vamos ter Tr três linguagens de programação para ver ali como que se gera a imagem com o Docker. Então aqui eu tenho o mesmo projeto NestJS, ele está zeradinho ali, e nós vamos criar uma imagem de produção para ele. Então aqui nós vamos criar um Dockerfile. Eu vou colocar prod apenas para poder enfatizar. A gente sabe que pode passar o "-f", no build, para poder gerar essa imagem a partir do prod. A primeira dica é sobre a imagem. E aqui, quando a gente está falando de objetivos para produção, a gente quer a imagem mais leve e a menor possível. Porque imagens mais leves e menores, elas vão ser compiladas, buildadas mais rapidamente, viewdadas mais rapidamente, vão tender a... subirem mais rapidamente para o image registry. Se eu tenho uma imagem menor, ela sobe mais fácil. E para poder montar o container, também é mais rápido. Eu consigo subir uma aplicação mais rapidamente. Então nós temos uma série de benefícios. Além que é uma coisa que eu não posso esquecer, aqui no Image Registry a gente acaba utilizando algum lead terceiro, um DocHub, GitHub Package ou do sua cloud, image registry custa armazenamento. Dinheiro. Então, quanto menor as imagens, menor o custo delas também. Então, o nosso objetivo aqui é pegar uma imagem, verifique, como eu falei lá em desenvolvimento, que a gente vai pegar também uma imagem menor, mas aqui, pegue a menor que você puder. Então, no caso do Node, nós temos as imagens Alpine e Slim, que seriam entre as duas que eu escolheria. Eu prefiro Slim aí porque é mais fácil mexer com o Debian. Mas a gente tem imagens ainda menores, mas aí elas vão se tornando mais difíceis de manusear também. Então, mas quanto a imagem menor, melhor é. Inclusive eu coloquei aqui, que você pode dar uma pesquisada dependendo da sua linguagem, acho que eu coloquei na verdade acho que isso eu coloquei... Na verdade, acho que isso eu coloquei no outro documento lá de Dev, mas as imagens... Procure imagens oficiais. Essa imagem Node oficial, que é oficial também, é mais segura, porque tem verificações ali de vulnerabilidade e outras coisas assim. Mas vou até acrescentar aqui. possibilidade outras coisas sim mas não vou te acrescentar que eu procure imagens e tem um o slim e etc. Outra boa dica é usar uma instrução chamada de label. Label define metadados para essa imagem. Então posso colocar o mantenedor dessa imagem aqui vai ser o Luiz Carlos. colocar assim aqui o mantenedor dessa imagem aqui vai ser o Luiz Carlos eu posso colocar também qualquer informação que eu quiser e-mail vai ser argentinaluiz.gmail.com qual a versão dessa? 1.0.0 Essas informações aqui vão servir como metadados Outras ferramentas, ferramentas de CI e outras ferramentas vão capturar Então acaba documentando a imagem, que é uma boa prática Agora nós vamos instalar o que é necessário para poder rodar a nossa aplicação de ferramentas. Porque, às vezes, não é só linguagem de programação. Posso ter extensões e coisas assim. Então, é aquela mesma história lá do Devin, que a gente vai fazer um run instalando o que é necessário. Então, nesse caso aqui, eu faria um apt update, menos y. E aí, eu coloco apt install aí posso colocar aqui uma opção no install ferramentas não recomendadas na verdade isso aqui é importante porque as vezes o apt instala ferramentas não recomendadas. Na verdade, isso aqui é importante, porque às vezes o apt instala ferramentas recomendadas. Então, eu estou falando aqui para ele, ele não instala recomendados, não. Vamos supor que eu precisasse aqui um OpenSSL. Aqui no caso do Nest, eu até não coloquei o Prisma, que é um RM bem famoso. Precisaria do OpenSSL para poder trabalhar. Então, a gente poderia ir colocando outras coisas. Mas aqui vem um comando muito importante. Vou dar um rm-rf barra var lib apt-lists qualquer coisa. Esse caminho aqui vai ter uma série de listas de pacotes que a gente consegue apontar para vários servidores. Isso aqui acaba ocupando um certo espaço na imagem. Quanto menos coisas na imagem, menor ela vai ser. E aí, aquela mesma dica de colocar tudo o que você precisa num um só. Porque se você coloca dois runs, o que vai acontecer? A gente vai ter duas camadas até o momento. Quanto mais camadas, mais armazenamento essa imagem vai ocupar. Aí agora vem uma outra dica muito importante que é o princípio do mínimo privilégio. Esse princípio do mínimo ou do menor privilégio é muito conhecido por pessoas de infraestrutura, que é você fechar todas as portas da casa e abrir somente as que a pessoa vai usar. Então, por princípio, você fecha tudo. Então, a ideia aqui é não trabalhar com o usuário root e restringir ao máximo o que esse usuário pode fazer. Porque dessa forma, com o usuário limitado, qualquer invasão, qualquer script malicioso que tiver dentro dessa imagem vai ter a sua execução limitada também. Então, sempre execute imagens com não root. Essa é a primeira questão. Às vezes, pode acontecer de não ter que um usuário, que esse aqui é o mil, né? O que a gente já conversou aqui durante as aulas. Então, é um usuário que tem a restrição a partir do mil ali, são os usuários que a gente usa no Linux. Se não tiver, faça um user add, um add user, cada distribuição aí tem um comando para poder fazer a criação do usuário, faça aí com o próprio run, até para fazer aqui, nesse caso. Beleza. Uma vez que eu fiz isso, agora chegou a hora de determinar a pasta de trabalho. Então, a pasta de trabalho é essencial, a gente já falou disso, é o lugar onde a gente vai rodar a nossa aplicação. Nesse caso aqui, eu estou jogando para a pastinha app, mas aqui, eu vou fazer um run antes com o mkdir para poder criar essa app, porque senão ele não cria pertencendo ao usuário, mesmo que daqui para baixo a gente executa tudo com o usuário Node. Eu estou fazendo essa execução aqui com esse usuário Node, a pasta de app pertence a ele, e coloco esse diretório de trabalho. Isso aqui não vai ter nenhuma influência ali para aumentar a imagem, porque eu tenho outro run que é muito simples também, que eu não estou fazendo mais nada a não ser criar uma pasta. Uma dica aqui é que às vezes tem pessoas que gostam de colocar em outros lugares, por exemplo, um lugar muito comum é o SRSource App, eu não vejo problema também. Aí é questão, porque o SRSource é um padrão muito utilizado com o Linux. Aqui agora nós vamos trabalhar com o npm install. Eu poderia rodar aqui um copy, ponto, ponto, copiando tudo, e depois fazendo o npm install, que a gente já tem que deixar no de mods ali dentro. Isso aqui é um problema, pessoal, porque, vamos colocar assim, toda vez que você estiver criando essa imagem para poder subir para a produção, provavelmente você está modificando um arquivo aqui. Esquece a NodeMods, você está modificando algum arquivo no seu projeto. Então, ele vai fazer o copy e vai fazer o npm install, mas vamos supor que a gente não tenha mudado nenhuma dependência aqui no package.json. Essa regra que ela vale para qualquer gerenciador de pacotes da sua linguagem de programação. Composer, Maven, enfim. Aí, ele estaria fazendo o npm install. Posso ter várias coisas lá. Então, o tempo de build também é muito importante então a gente não deve fazer essa situação aqui que a gente dificilmente vai aproveitar o cache das camadas, olha só o que a gente vai fazer aqui então eu vou fazer um copy de qualquer coisa que tenha package qualquer nomezinho no meio, ponto JSON para poder pegar esses dois, o lock é que vai ter ali as versões, os hashes das dependências. Então, a gente copia ele para barra 1, barra node, barra app. Beleza. Aqui é bom, quando a gente está em produção, fazer um chow para falar que esse arquivo deve ser copiado e as propriedades dele pertencem ao usuário Node. Eu comando isso aqui, ele copia com o chow do Linux. Então, a gente está copiando para cá. Aí eu posso fazer um npm install, e até para poder otimizar, eu posso colocar um npm cache clean first, isso aqui acaba sendo algo específico do npm, mas quero que ele limpe ele cache, porque ele acaba colocando um cache local, que é armazenamento desnecessário. Então, uma dica importante, às vezes você tem alguma tarefa para poder fazer, sempre tente remover coisas necessárias, faça rm-rf, faça algum comando que remova alguma coisa desnecessária. Isso aqui é muito legal, porque o que vai acontecer? A gente vai fazer agora o copy com o xau. o copy com o xau. . Mas aqui, se no próximo build não mudar nada no package.json, porque vamos colocar um ponto, a gente vai passar a maior parte do tempo mudando o código e não instalando dependências. Isso é óbvio, né? Então, quando eu mudei algo aqui na source, ele vai fazer o copy, ele vai ver se os arquivos são iguais, são iguais, então ele pula o run pegando a camada que ele já tem aqui em cache. Então, isso aqui, o npm install, vai ser adotar essas que mais vai consumir tempo. Então, a gente aproveita essa estratégia de cache de camadas aqui. Beleza. Então, está aqui copiado. A gente vai fazer um npm run build para poder gerar aqui a versão de produção. E é bom colocar um expose para poder documentar que a gente vai rodar essa aplicação aqui na porta 3000. E aí o comando para poder rodar a nossa aplicação, a gente já quer rodá-la, vai ser o npm run startprod, que vai rodar aqui o... Na verdade esse startprod vai rodar apenas um node.js de este main.js, que é o que ele gerou aqui de produção, beleza então, vamos fazer aqui o build disso a gente vai fazer um docker build menos t test node menos f aí eu passo prod e ponto que ele vai pegar o docker file prod dessa mesma pasta o que que ele eu pegar o dockerfile prod dessa mesma pasta. Eu estou na pasta certa? Ah não, tem que ser no webnode. Por enquanto ele só pegou do cache a imagem que eu já tenho na minha máquina. Agora ele está fazendo um install. Ele vai fazer o copy, tudo bonitinho. Faz o export, beleza. Então vamos simular aqui. Eu estaria dentro de um container. Eu vou lá e faço um npm install. O que não tem aqui? Será que eu tenho o Axios? Acho que eu não tenho o Axios. Aqui eu fiz o install do Axios, né? Então, ele vai acrescentar o Axios dentro do package JSON. Está aqui, ó, como dependência, né? Então, se eu fizer o build novamente, aí ele vai aproveitar o cache da primeira camada lá do apt que não mudou, o mkdir também não mudou. Aqui já mudou, porque ele viu a mudança lá, faz o npm install. Passou, né? Mas agora a gente vai ver se eu mudar alguma coisa aqui. Se eu fizer um console.log com qualquer coisa, a gente vai ver que aquela etapa lá, está vendo que ele já passou o npm install, que é muito custoso, e foi somente para o copy. Então, show de bola. Uma outra dica importante, isso aqui é um perigo, porque quando a gente faz o copy ponto ponto, ele copia tudo para dentro da workgear. a gente faz o copy ponto ponto, ele copia tudo para dentro da workdir. Então, ele está copiando aqui pastinha git, node modules, readme e coisas que a gente não precisaria ter dentro dessa imagem. Então, nós podemos gerar aqui um arquivinho ponto docker ignore, que ele tem o mesmo efeito de um git ignore. Então, a gente vai ignorando coisas que tem que ignorar a git. Sim, ignore a sua Git. Ignore a NodeMod também, que às vezes pode estar uma NodeMod, principalmente se você está testando o local, né? Então eu não quero que ele copie a NodeMod. Tem que gerar ela do zero lá. Eu quero ignorar também Docker Compose. Provavelmente eu tenho ali um Dockercker-compose-dev, alguma coisa assim. Ah, eu vou ignorar também um git-ignore, ou aquele prior-rc ali também não tem necessidade, o próprio docker-file não precisa copiar, enfim, eu vou até passar esses pontos aqui para cima. Então a gente ignora tudo que não tem necessidade nenhuma. Então agora eu rodo novamente. Ele vai fazer aqui o build e vai gerar rápido. Eu não mudei nada aqui, então ele só... Na verdade, eu mudei, acrescentei o docker ignore. Então, ele foi direto para o copy. Olha que ele faz um cache em tudo. Então, essas estratégias fazem com que a gente gere uma imagem mais rápido. Quanto mais rápido ela gerar, mais rápido vai ser o seu processo de CI para poder publicar essa aplicação. Beleza. Deixa eu ver se tem alguma dica que eu não cobri aqui. Juntar os Docker Runs, mover arquivos necessários, o usuário não root, aqui a estratégia do multistage build a gente vai ver na próxima aula, e as imagens de Strollers também na próxima aula. Então vamos dar uma olhada nessa imagem aqui, se eu fizer um grep em test node, nós vamos conseguir ver o tanto que ela tem. Ela tem 383 megas. Parece muito, e as imagens node, principalmente com o nest, acaba tendo isso mesmo, porque a gente acabou instalando tudo aqui. Ele pegou até dependências de desenvolvimento, que a gente não precisaria, mas não dá para remover. Eu vou falar disso na próxima aula. Isso acontece também com outras linguagens de programação. Até que não está tão grande assim, mas está um tamanho aceitável. Se eu não me engano, acho que a imagem Slim deve ter uns 150 por aí. Então, está ok. Na próxima aula, nós vamos utilizar o multistage build e falar também das imagens distroless para reduzir ainda mais. A gente pode ter estratégias mais agressivas e, às vezes, em algumas situações, a gente quer que a imagem tenha o... seja o menor possível. A gente quer retirar basicamente tudo. Então, vamos continuando aqui no finalzinho da nossa saga. É isso aí. E até a próxima.