Salve, das Beleza! Continuamos a saga aqui do nosso módulo de Docker. Agora, vamos montar aqui um ambiente produtivo para poder desenvolver uma aplicação. E claro que todo mundo aí tem a sua linguagem de programação específica, predileta, mas a gente tem que usar uma. Eu vou usar ali o Node, que eu acho que é mais fácil para todo mundo entender. Então, bora lá! Eu peguei aqui um projeto para ter mais alguns desafios. Então, é um framework Node chamado de NestJS. É um framework back-end, a gente consegue criar APIs, aplicação web e tudo mais. Então, a gente vai doquerizar essa aplicação voltado para desenvolvimento. E a gente vai conversar aqui sobre as nossas necessidades e as recomendações, porque uma coisa é desenvolvimento, outra coisa é produção, são duas necessidades diferentes. Essas dicas que eu vou passar, eu consolidei elas nesse readme aqui. Então, vamos lá. A primeira coisa, obviamente, é criar o dockerfile. E aí, a primeira recomendação vai ser em questão da imagem. Desenvolvimento é um lugar que a gente não se preocupa tanto com o tamanho da imagem e otimização. Mas acaba que também pegar uma imagem, se eu pegar uma imagem, se é o Node20, vai vir um monte de coisas que eu não vou utilizar então use imagens que são menores para que você também só use o que é necessário então pesquise aí na sua linguagem de programação se você não tem, por exemplo, um traço alpine um traço slimpine, um traço slim, um buster também, que seria uma outra opção, e talvez até um outro nome. Normalmente esses são os menores. No caso do Node, normalmente eu tenho gostado mais de utilizar as imagens slim, que são derivadas do Debian e são imagens menores. O Alpine também seria uma outra opção interessante. Agora vamos falar de ferramentas que são úteis ali dentro do container, que a gente vai acabar precisando no decorrer do desenvolvimento. A gente pode trabalhar precisando do curll, de fazer um ping e no Slim não vem. Então, faça logo na segunda linha ali a instalação dessas ferramentas básicas. Como eu estou aqui no Debian, então faço um apt update, porque senão ele não vai conseguir encontrar essas ferramentas. Então, a gente pode fazer um apt install, menos y. Então, vamos supor que eu precisasse do Curl. Aí aqui eu posso colocar a barra ali para poder colocar outros, aí eu vou colocar o ip utils ping. É importante que você coloque isso aqui numa linha só, porque a preocupação do tamanho da imagem não é prioridade para desenvolvimento. Mas quanto menos camadas, a gente já conversou disso aqui no curso, quanto menos camadas a gente tiver, tende a imagem a ser menor. Para o caso aqui desse Nest, eu vou precisar do ProcPS, que é aquela ferramenta que eu posso fazer um PS, mas é porque o que acontece com o Nest? Nós temos ali TypeScript, que é compilado para JavaScript, e aí vai ter um hot reload quando eu vou atualizando o código, e aí ele utiliza ali o PS para poder matar o processo que tinha e recriar o novo e tal, então eu tenho que ter isso aqui senão ele não consegue trabalhar, beleza, então assim, não tem limite, é o que você precisar, você já coloca aqui. Mas a Glutini num run só para poder minimizar a sua imagem. Agora, a gente pode falar aqui sobre usuário. A gente já entendeu aqui no curso que as imagens vão ter as suas user lanes lá e nós vamos ter usuários criados lá dentro. E os usuários do Linux são identificados ali pelos IDs. Então, se eu tiver um usuário aqui dentro que é um node, que é 1000, equivale ao 1000 da minha máquina, que é um node, que é mil, equivale ao mil da minha máquina, que é o argem. Então, o que eu criar lá dentro do content e compartilhar com a minha máquina, eu vou ter permissão justamente por conta do pertencimento ali do ID. Então, esse detalhe é importante, a gente precisa de ter um usuário que nós tenhamos permissão de mexer com os arquivos na hora de compartilhar os volumes. E a ideia é sempre trabalhar com o non-root, porque root a gente tem acesso a tudo. Você às vezes pode estar instalando ou acontecer alguma coisa ali dentro do container e vai ter permissão para poder executar qualquer coisa. Então o non-root verdade, é uma regra tanto para desenvolvimento quanto para, ainda mais para produção. Então, procure ver na sua imagem se você tem alguma coisa que algum usuário já padrão que é o 1000 ali que normalmente é o da sua máquina, tem como a gente dinamizar esse usuário, mas aí essa parte eu não vou passar no curso. Tem como colocar opções ali via variável de ambiente, enfim. Então, vou determinar aqui um usuário não root, que é o Node, que já vem nessa imagem. Se por acaso não vier um 1000, por exemplo, aí você pode fazer um comando run logo aqui para poder fazer um user add, um add user. Tem cada distribuição aí. Tem um comando para poder criar um usuário, porque o usuário não root. Opa, aqui. Aí, com o usuário não root, é muito importante delimitar o diretório de trabalho, porque é onde a nossa aplicação vai rodar. Então, se eu não estou trabalhando com usuário root, eu tenho que determinar uma pasta que o usuário Node tem permissão, e que se eu tenho usuário Node, eu tenho barra home, barra Node, e posso colocar ali o app, porque aí eu tenho permissão de escrita, leitura e restrita. Então, isso aqui é muito importante. Isso aqui são informações cruciais. A próxima preocupação aqui seria agora instalar as bibliotecas e gerar a NodeMods aqui. Isso aqui é uma cilada bem grande. Vamos fazer aqui o seguinte. Eu estou dentro do montando, tem que ir pra app node, aí eu vou fazer um rm aqui na minha node modus, pra... A ideia é a gente sempre subir tudo de uma vez só, sem precisar ficar fazendo basicamente nada, a não ser, vou criar ali um arquivo de variável de ambiente. Eu pego e crio. Então, vamos criar aqui um... docker-compose. Eu vou copiar esse docker-compose eu vou copiar esse docker-compose aqui a gente vai colocar algumas informações juntos informações juntos. Então, eu vou apontar o meu build aqui para o meu Dockerfile, liberando a porta 3000, que é para poder rodar a minha aplicação. Então, tudo que eu tiver na minha aplicação, coloco aqui ponto só, eu vou mandar para o meu diretório de trabalho. Beleza. E aqui eu tenho o meu banco de dados, que até ele tem mais uma variável que essa aqui cria um banco padrão para a gente poder usar. E é muito recomendado também que a gente tenha um container, um volume na verdade configurado, para poder fazer o backup, ele faria o backup aqui em .docker DB dele. E essa opção aqui é porque o SMSQL8 fica fazendo uns warnings, isso aqui desabilita uma opção de segurança nele, mas não tem nenhuma influência aqui para o nosso desenvolvimento. Então, isso aqui seria uma configuração básica de banco para manter local, posso excluir os meus volumes e manter o meu volume ali. Beleza. O que vai acontecer se eu faço um npm run, ou melhor, antes aqui um copy, eu tenho que copiar o package JSON e o lock, tanto faz se tiver somente o JSON, mas copio os dois e depois faço o run do npm install. E vai gerar a NodeModules dentro da imagem. Mas na hora que o container subir, eu não tenho NodeModules aqui. Ele vai pegar isso aqui e vai substituir pelo que eu tenho em app. A NodeMod está lá, então ela vai ser como eu diria o outro, nerfada, ela vai ser destruída. E aí a gente vai tentar rodar a nossa aplicação com Node e o Node vai avisar lá que não tem a NodeMods e tudo mais. Então, tem formas de contornar isso, mas esse seria o primeiro problema de você fazer isso aqui. A gente está começando de desenvolvimento. Uma outra situação, trabalhando dessa forma também, imagina que o seu colega instalou uma nova lib, instalou o Axios lá, que é muito usado para requisições HTTP, e aí você foi rodar com Docker Compose Up. Mas como você já tem a sua imagem local feitinha lá, ele vai pegar o que tem local com a NodeMod local. E aí não vai ter o Axios. E aí vai forçar com que você entre na imagem, na verdade no container e faça o npm install para poder atualizar, ou fazendo sempre quando você tem que fazer o up com menos menos build, que acaba forçando ali o recompiler da imagem. Então, muitas vezes você vai subir a sua aplicação e a sua NodeMods não vai estar atualizada também. Então, muitas vezes você vai subir a sua aplicação e a sua node mod não vai estar atualizada também. Então, a ideia, pessoal, na verdade, é que a gente não tenha npm install aqui. Não tem. O que a gente vai fazer é esse npm install dentro do container. Então, daqui para frente, nós vamos, na verdade, ao invés de ter somente um comando aqui, porque eu posso ter necessidades ali na hora de subir a minha aplicação de rodar alguns comandos iniciais pra deixar a minha aplicação pronta. Então o que seria mais interessante é da gente criar aqui uma pastinha, por exemplo, .docker e aí eu posso ter aqui um start-dev.sh Então vai ser um JavaScript que vai rodar ali no início do container. Então a ideia desse camaradinho aqui vai ser eu posso colocar, rodar ele com o bash, né? eu posso colocar, rodar ele com o Bash, né? E aí eu posso preparar alguma variável de ambiente, algum Envy que esteja aqui na minha aplicação. Inclusive, às vezes, você já tem aí um Envy aqui, vou até pegar um que eu tenha. Posso ter um Envy Example aqui na raiz do meu projeto e aí ele já vai servir como molde pro env então quando o container inicia isso aqui é um if do shell script ele verifica se existe o env, ah não existe não, então ele gera pra já deixar prontinho ali. Aí depois, eu posso instalar as dependências. Instalar dependências. Então, aqui vai o npm install. Aí eu posso executar outros comandos, como... Executar outros comandos, como migração ali no banco de dados para poder levantar os meus dados, semeadores para poder colocar dados de teste, enfim. E eu tenho que ter algum comando que vai parar o meu container. Eu não quero rodar a aplicação aqui logo de cara, porque em desenvolvimento, às vezes eu vou querer rodar, eu vou parar para poder instalar dependências, a gente vai deixar livre. Então, é um comando aqui que pode ser um sleep infinite, um while infinito, tanto faz. O Tail que vai ficar lendo o dispositivo nulo do Linux indefinidamente. Então, a gente vai passar esse arquivinho aqui, vai ser barra home, barra node, barra app, ponto docker, start dev ponto sh. Ele vai executar esse arquivo diretamente com sh, então a gente precisa da permissão de execução nele. Então, eu preciso fazer aqui um chmod mais x para aplicar essa permissão de execução, senão quando eu for executar ali, ele vai dar um permission deny. Se eu executar um script PHP direto aqui do terminal, eu consigo fazer, se tiver o cabeçalho igual, tem o cabeçalho aqui, mas tem que ter permissão de execução ali no arquivo, que é algo inerente aí do Linux, tá? Então, pronto. Fizemos isso aqui, então, como o npm install sempre vai executar no início do container, nós vamos ter sempre as dependências atualizadas, sempre quando eu fizer um Git pull, vai estar tudo ok. Então já está beleza aqui, vamos rodar essa nossa aplicação. Então lembrando que a gente tem aqui o volume, que vai sincronizar tudo para barra app, e a gente já está pegando que aqui nesse comando que vai ser executado, o volume já vai estar lá montado no container. Então, vamos rodar aqui o up, aí ele vai executar lá o curr, vai instalar o ipout, os ping, que são pacotes muito simples, e aí ele subiu o banco de dados, pacotes muito simples, e aí ele subiu o banco de dados e o nosso Node não vai ter... ele vai até mostrar... acho que ele vai mostrar alguma coisinha. Mostrou aqui o npm install, porque o container já está de pé, mas não vai mostrar mais nada. Então agora eu consigo chegar aqui cap8 0.2 Então se eu fizer um docker com Na verdade eu tenho que entrar em app Node.js Se eu fizer um exec app bash Eu consigo entrar e consigo começar a desenvolver Então se eu quisesse rodar Essa minha aplicação aqui Rodaria lá o comando start dev que vai iniciar o meu projeto Pronto, iniciou bonitinho Ele não está conectado no banco de dados essa minha aplicação aqui, e rodaria lá o comando Start Dev, que vai iniciar o meu projeto. Pronto, iniciou bonitinho. Ele não está conectado no banco de dados, eu só criei o projeto NestJS aí, mas a gente já consegue acessar aqui na porta 3000. Vai mostrar o Hello World, que é a página de boas-vindas dele ali. Então, a gente faz tudo agora dentro do container. Ah, eu vou fazer o npm install. O Node acaba acontecendo isso. Você tem ele na sua máquina, aí você acaba sendo compilado a fazer na sua máquina. Pode não acontecer nenhum problema, mas às vezes você está instalando uma lib que depende de algo do próprio ambiente. Então, você acaba instalando essa lib com o seu host, mas ela deveria estar sendo executada lá dentro do container. Então, o desenvolvimento agora é tudo em container. Dá para você poder fazer qualquer coisa. Então, a gente já vê aqui que tem a NodeMod, isso foi criado, o dist também que foi gerado. Então, tem o volume sendo compartilhado. Aí, uma recomendação é trabalhar aqui com o cached, se você quer mais performance, porque o cached nós vamos deixar o container em modo read-only e o que vai ter escrita vai ser exatamente aqui na nossa máquina e vai sincronizando para lá. Então, isso aqui dá mais performance. E o delegated porque nós não precisamos de uma sincronização rápida para a nossa máquina que vai ter escrita dentro do container, ao contrário aqui no caso do app. Uma dúvida que nós podemos ter aqui em relação à dependência dos dois, mas eu não poderia colocar um health check como a gente aprendeu no curso? Pode colocar um health check, mas como a gente tem aqui o desenvolvimento que nós vamos escolher rodar a aplicação quando a gente quiser, então posso subir tudo aqui e rodar, vai dar um tempo que tudo já vai estar de pé. Então, a princípio, a não ser que você tenha uma situação específica, não tem necessidade de um health check, mas a gente a questão é que a gente já sabe que ele existe. Nós podemos também fazer uma otimização, porque olha só, aqui dentro nós vamos ter a pastinha .docker e tem o dbdeira também, que é o banco de dados. Então, acaba que ele está sincronizando o dbdeira aqui para dentro e como eu estou pegando tudo aqui do projeto e mandando para Node e AppCache, não adianta mudar essa pasta aqui de lugar. Então, isso aqui não teria, a princípio, problema nenhum, mas se eu quisesse fazer uma otimização para poder evitar que eu tenha mais coisas lá dentro do meu Node e fazer uma separação melhor, aí a gente pode fazer aqui o seguinte. Eu vou parar isso aqui e nós vamos pegar o nosso projeto e mandar para uma pastinha que vai ser a Project. Então a gente vai pegar essas duas pastinhas aqui mandar para cá tem a dist ali e pega aqui o restante então até aqui manda para a barra project. Esses dois também, esse readme é do próprio nest. Mandei para cá, então vou ter agora o meu projeto com a .docker, aí vou ter que ter uma .docker para poder ter aquele script.sh que a gente está fazendo. Eu gosto de trabalhar assim. Então, eu pego esse script e mando para cá. E essa .docker externa a gente deixa somente para configurações mais centrais aqui do nosso projeto. Mas eu passei minha .docker aqui local. E agora, esse docker-compose, ele vem aqui para fora. Ele vem para a raiz aqui do app. O docker-file fica aqui dentro, então eu vou ter agora um contexto que vai ser a própria pasta .barra-project. E aí ele vai saber pegar ali o docker-file. O volume não muda, porque eu quero pegar tudo que está na project e mandar .barra project. E aí ele vai saber pegar ali o Dockerfile. O volume não muda, porque eu quero pegar tudo que está na project e mandar para lá, mas agora a dbdata não vai para lá. Aqui também não vai mudar. E eu acho que é isso. Aqui o project está tudo certinho. Então, vamos rodar aqui novamente, deixa eu parar o container. Vamos rodar o docker-compose up, vou forçar aqui um build novamente para a gente ver se tudo está ok. E o Node crashou porque ele não tem o start devsh porque... Ah, aqui tá errado né, porque tem que ser .barra project. Tava... na ponta da língua tinha uma coisa que estava faltando. Está fazendo npm install, significa que ele já executou lá o script. Então, vamos fazer aqui o exec appbash, npm run, start, dois pontos dev. Aí o typescript que faltou, mas a gente pode copiar aqui agora. Então, deixa eu copiar esse arquivinho para cá. e tá faltando esse outro aqui. Pronto. Então agora do lado de fora somente docker-compose, aí vamos rodar novamente, tá ali funcionando. Senão ele nem compilaria. Show de bola. Então, agora aqui dentro da .docker, eu não tenho mais a DBdeira e o DBdeira tá aqui do lado de fora, né? Maravilha. Então, essas aqui são dicas básicas. A gente já tem aqui um ambiente pra poder desenvolver, pra poder rodar os nossos comandos, mas uma coisa que pode melhorar aqui vai ser ter um terminal um pouco melhor porque o Bash acaba sendo ruim para poder pesquisar comandos, as próprias cores então vou mostrar para vocês aqui uma forma que a gente pode colocar o ZShell, eu posso colocar um terminal que eu quiser dentro do container. Isso vai fazer com que, obviamente, a imagem acabe ficando maior e o container também. Mas é aquela história. A gente está aqui com propósitos para desenvolvimento. Eu posicionei mais algumas coisas aqui. Esse pacote, você pode acessar esse GitHub. Ele é o Zshell Indocker. O Zshell é um terminal em cima do próprio Bash, e aí nós temos muito mais recursos para poder trabalhar, muito melhor executar comandos. Então, a gente pode levar essa experiência também para dentro do container. Com esse script aqui, nós vamos executar um SH que vai fazer toda a configuração dos Shell, colocando um tema chamado de Power Level 10K e habilitando uns plugins para que a gente tenha autocompletado os comandos, uma experiência melhor. Ele depende também do fontes Powerline. E eu tenho que instalar os ishell antes aqui. Essa configuração deve ser executada depois que a gente tem esse user node. Então, por isso que eu separei, nesse caso, o run. Porque senão ele vai executar aqui com o root. Então, vamos lá. Dessa forma... Dessa forma... Eu tenho que executar de novo com build, agora ele vai... e tem alguma coisa errada aqui que... peraí, tem alguma coisa bem errada... ele nem executou nada que eu tenho ali a não ser que eu já tinha cache disso... capítulo 8 e tal... foi bem rápido... a não ser que eu já tinha... É o lance dos layers do Docker, né? Mas... Ainda estou desconfiando. Então eu posso colocar aqui, ó, vshel. Olha que legal. Então eu tenho esse power level 10k, que tem como configurar o... tema diferente. Eu, inclusive, gosto de colocar mais simples. O digitar de comando sempre na linha de baixo para poder ter mais espaço, aí você pode guardar a sua configuração aqui dele guardar o histórico de comando também, você vai digitando comando aqui, ele vai ficando verdinho, ele significa que está ok, você pode colocar plugins que vão te mostrar um monte de coisas, então a gente pode ter essa experiência também dentro de containers. Então, olha só, isso aqui é legal, porque independente se eu estiver usando o VS Code, IntelliJ ou qualquer outra IDE, não interessa. Essa imagem aqui vai funcionar independente do sistema operacional. Então, a gente pode fazer sim essas configurações e elas ajudam demais. Às vezes você pode instalar também de forma manual, mas isso aqui também já ajuda bastante, porque você só vai colocar os plugins, dá uma olhadinha no ZShell se você não conhece, você pode fazer a instalação com menos P, ele já copia o plugin e já coloca lá no ZSHRC, que é a configuração desse terminal. Então, de um modo geral, pessoal, o que a gente precisa é de um ambiente bacana para poder rodar comandos, a sincronização de volumes, trabalhar com o não-usuário root, instalar as ferramentas e sempre trabalhar dentro do container, a gente acaba localizando aqui a nossa aplicação. Dá uma olhadinha também tem outras dicas que eu acabei colocando aqui que eu não falei na aula sobre questão aqui de colocar múltiplos docker composes também que a gente pode acabar fazendo eu posso, inclusive aqui se eu quiser colocar um docker compose para dev e ter outro para prod eu posso, mas aí na hora de rodar tem que sempre lembrar que você não vai rodar mais fácil como é normalmente, você vai ter que passar aqui o seu docker compose .dev e fazer o up, fazer qualquer outra coisa. E aí, você pode criar um makefile também para poder te ajudar a fazer a execução. Você cria um makefile na raiz que vai abstrair esses comandos quando os comandos são mais complexos. Enfim, então, várias dicas aqui que foram mostradas para o desenvolvimento para a gente poder fechar no próximo aula. Nós vamos falar sobre o DevContainer, que é uma extensão aqui do VS Code que eu já tinha falado lá no comecinho do curso. Então, é isso aí e até a próxima.