
SAP Cloud Platform + Docker
Trazendo agilidade ao seu desenvolvimento, além de tornar o deploy ainda mais simples no SCP
E aweeee meu povo. Antes de qualquer coisa, Feliz Ano Novo!
Preciso confessar que alguns assuntos deixam-me mais empolgado para escrever do que outros, e o assunto de hoje é um desses que me deixa muito animado para escrever.
O post de hoje é um complemento mais avançado do post:
Então, caso você ainda não conheça o SCP, é necessário que você dê uma lida no post acima (desta forma a assimilação deste post será muito melhor).
Docker sem dúvidas é uma das tecnologias que mais transformou o dia a dia dos desenvolvedores nos últimos anos. E a ideia hoje é que criemos uma aplicação em NodeJS e, daí então, realizemos o deploy da aplicação utilizando o SCP. Entretanto, antes disso, vamos dockerizar nosso app, fazendo com que o deploy — que já era tranquilo — passe a ser ainda mais sossegado.
O melhor de tudo é que depois desse post colocamos no passado a velha frase:
Essa funcionalidade funciona na minha máquina — Desenvolvedor, Qualquer.
E como disse James Turnbull em seu livro “The Docker Book: Containerization is the new virtualization”:
This reduces the risk of “worked in dev, now an ops problem”
É importante salientar que é impossível apresentar o que é Docker em apenas um post, então minha ideia aqui hoje é apenas contextualizar a tecnologia para você possa entender a magia que é utilizar Docker para realizar deploy de suas aplicações no SCP.
Introdução: Virtualização
Num passado não tão distante, quando queríamos montar uma aplicação, por vezes precisávamos de vários servidores físicos para hospedar nossas aplicações e seus respectivos serviços (como de banco de dados, autenticação, proxy e etc.…). Além disso, aplicações não rodam diretamente no hardware, ou seja, era necessário termos um sistema operacional (SO), que poderia ser diferente para cada aplicação ou serviço, mas o fato é que o SO sempre estava lá.
Nem vou entrar no mérito da configuração de rede e todos os outros custos necessários para fazer a aplicação rodar.
Com o passar do tempo, descobrimos a maravilha que é virtualizar, e com ela passamos a controlar melhor situações onde os servidores estavam sendo mal utilizados. Com isso, passa-se a ter uma diminuição na quantidade de servidores físicos, além de melhorar o custo e simplificar a gestão e manutenção de aplicações.
Antes de ilustrar como é a arquitetura de uma virtualização, precisamos primeiro falar de uma tecnologia que poucos conhecem a respeito, mas que é a responsável pela virtualização ser possível. Esta tecnologia é conhecida como Hypervisor.
O Hypervisor é uma camada de software entre o SO e o hardware, e é responsável por fornecer ao sistema operacional visitante a abstração da máquina virtual. É ele o responsável pelo acesso dos sistemas operacionais visitantes aos dispositivos de hardware.
Trocando em miúdos, o papel do hypervisor é o de virtualizar os recursos de hardware do nosso servidor físico. Desta forma, passamos a ter acesso ao processador, RAM, HD e etc.

Entretanto, como você já pode prever, se a virtualização fosse tão maravilhosa assim, eu não estaria escrevendo um post sobre Docker.
Apesar de resolver problemas como o da utilização de servidores físicos, ainda temos a seguinte questão: para a virtualização funcionar, é necessário que cada VM possua o seu próprio SO. De forma ilustrada, estou dizendo o seguinte:

Novamente: não vou entrar a fundo no mérito do custo que é termos tantos sistemas operacionais, ou mantê-los. Mas, apenas pense sobre o desperdício de recursos de hardware que acaba acontecendo, pois para cada nova aplicação precisamos instalar um novo SO que consome HD, Memória RAM, CPU e isso apenas para rodar uma aplicação.
Introdução — Contêiner
Agora que sabemos sobre as opções de utilizar servidores físicos ou virtualização para montar nossas aplicações, vamos entender o que é Docker e o que são contêineres.
Antes de qualquer coisa, o mais importante é saber que contêiner com Docker é, sem dúvida, realidade. Se você desenvolve em ambiente web/mobile com certeza já deve ter ouvido alguém falando sobre isso. Com Docker, uma galera (inclusive eu mesmo), ficou totalmente enlouquecida. O que ajudou a fomentar a tecnologia é que, participando dessa galera, estavam também empresas que amaram a ideia por conta da redução de custos proporcionada pela adoção da tecnologia.
Todo esse amor vem do fato de que Docker utiliza a tecnologia de contêineres, e isso funciona muito bem pois um contêiner funciona junto dos nossos sistemas operacionais, e conterá a nossa aplicação, ou seja, a aplicação será executada dentro dele. Criamos um contêiner para cada aplicação, e esses contêineres vão dividir as funcionalidades do sistema operacional. Abstrato demais? Veja a ilustração abaixo:

Não possuir um sistema operacional torna o contêiner muito mais leve. Isso, além de economizar recursos da máquina, passa a proporcionar uma gestão de subida e parada muito mais rápida ao contêiner (algo que não é possível quando estamos trabalhando com virtualização).
Com contêiner, conseguimos limitar o consumo de CPU das aplicações, melhorando o controle sobre o uso de cada recurso do nosso sistema (CPU, rede, HD e etc). Também temos uma facilidade maior em trabalhar com versões específicas de linguagens/bibliotecas.
Docker, Inc.
Primeiramente, devemos falar sobre a Docker, Inc. que, no início, era uma empresa de PaaS chamada dotCloud.
Inicialmente, para prover a parte de infraestrutura, a dotCloud utilizava o AWS, utilizando o serviço que nos disponibiliza máquinas virtuais e físicas. Para hospedar uma aplicação com esse sistema de virtualização, sabemos que precisamos do sistema operacional, mas a dotCloud introduziu o conceito de contêiner na hora de subir uma aplicação, dando origem ao Docker, tecnologia utilizada internamente para baratear o custo de hospedar várias aplicações em uma mesma máquina.
Então, o que era para ser uma tecnologia que visava economizar gastos da dotCloud ao subir várias aplicações em contêineres, tornou-se em pouco tempo muito interessante para o mercado de tecnologia e, posteriormente, tão poderosa que a tecnologia virou o carro chefe da empresa, que inclusive mudou o nome de dotCloud para Docker, Inc.
Docker
A tecnologia Docker nada mais é do que uma coleção de tecnologias para facilitar o deploy e a execução das nossas aplicações. A sua principal tecnologia é a Docker Engine. Abaixo um exemplo das ferramentas que compõem essa tecnologia:

Para mais informações deixarei nas referências mais alguns materiais sobre a tecnologia.
Vantagens de utilizar Docker
CI — Com Docker a possibilidade de realizarmos integração contínua ficou muito mais fácil. Se você não conhece sobre, conversamos um pouco sobre isso no seguinte post:
Padronização e Produtividade — Com Docker, somos capazes de garantir a consistência em vários ciclos de desenvolvimento e deploy, padronizando o ambiente de desenvolvimento.
Sem dúvida padronização é um dos maiores benefícios em adotar Docker no seu time. O Docker fornece ambientes de desenvolvimento, homologação e produção sem o risco de configurações diferentes em cada um deles. Isso significa que passamos a permitir que cada membro da equipe trabalhe em um ambiente em paridade com a produção.
Além disso, pense, por exemplo, em um novo desenvolvedor no seu time hoje: imagine a quantidade de detalhes que será necessário transmitir durante sua integração para que ele tenha um ambiente para iniciar suas atividades.
Isso muda completamente com Docker, pois você só precisará informar qual imagem ele precisará usar, e a integração que as vezes eram de dias, passarão a ocorrer em minutos.
Ao fazer isso, o time estará mais preparado para analisar e corrigir erros de forma eficiente, pois temos uma redução na quantidade de tempo desperdiçado em problemas de divergência entre configuração de ambientes e dificuldade em replicação de cenários de negócio em ambientes diferentes, aumentando, assim, a quantidade de tempo disponível para o desenvolvimento de novas funcionalidades.
Fora o que comentei anteriormente sobre a gestão da aplicação passar de minutos para segundos, isso porque agora parar um aplicativo e/ou subi-lo novamente se torna trivial.
Portabilidade — Sem dúvida, este é um atributo que faz toda a diferença quando estamos lidando com um ambiente tão volátil quanto os nossos ambientes de desenvolvimento de software.
Nos últimos anos, todos os principais provedores de computação em nuvem, como a Microsoft Azure, Amazon Web Services (AWS), Google Cloud Platform (GCP) e agora incluindo o SAP Cloud Platform (SCP) adotaram a disponibilidade do Docker e adicionaram suporte individual. Isso significa que você não ficará refém de plataformas, caso o serviço ou o preço não esteja satisfatório, você apenas precisar pegar seu contêiner e subir em uma outra plataforma.
Isolamento — Seus aplicativos e recursos estarão isolados e segregados. O Docker garante que cada contêiner tenha seus próprios recursos isolados de outros contêineres. Isso significa que agora temos a garantia de que cada aplicativo use apenas os recursos que foram atribuídos a eles.
Instalação
Windows:
MacOs:
Linux:
Uma dica muito importante para você que é usuário de Windows: além de precisar do recurso de Hypervisor, você precisa tomar cuidado caso já tenha instalado alguma ferramenta de virtualização como Virtualbox ou VMware, já que não é incomum acontecer conflitos. Nas referências deixarei links com thread de possíveis problemas reportados pela comunidade.
Docker na prática
Com o Docker instalado no nosso sistema operacional, já podemos testá-lo para ver o seu funcionamento. Como toda boa ferramenta vamos para o terminal e executar algumas linhas de comando.
Primeiro vamos verificar a versão do nosso Docker com o comando:
docker version

E então, para conhecermos um pouco mais sobre a tecnologia, vamos fazer nosso primeiro "Hello World". Para isso executaremos o seguinte comando:
docker run hello-world
O comando RUN está pedindo para executar algo, e que neste caso é uma imagem. E é assim que o Docker funciona, com base em uma imagem ele cria um novo contêiner.


Mas onde é que fica mesmo esse repositório externo? Entremos em:
Após acessar, vamos pesquisar por: Hello World, e então você deverá ter o seguinte resultado:

O Docker Hub é um repositório baseado em nuvem no qual usuários e parceiros do Docker criam, testam, armazenam e distribuem imagens de contêiner.
Existe a possibilidade de deixar suas imagens públicas ou privadas, e além disso existem outros fornecedores desse tipo, por exemplo aqui estamos no Docker Hub é uma versão hospedada na nuvem do Docker Registry, entretanto podíamos utilizar o Amazon Elastic Container Registry (ECR) que é o serviço da AWS para hospedagem de imagens.
Aproveite que já está na pagina do Docker hub e crie um usuário para você!
Entendido o que é e onde fica o repositório externo, vamos voltar para o nosso terminal e ver o que ocorreu após a instalação:

Perceba que abaixo da nossa mensagem de sucesso, é exibido algumas outras mensagens que são um descritivo do que acabou de acontecer.
Baixada a imagem é possível acessá-la no nosso repositório de imagens locais com o comando:
docker images

Para verificar quais contêineres estão rodando:
docker ps

Ou para verificar quais contêineres estão no ar ou parados também:
docker ps -a

Caso queira conhecer outros comandos, basta utilizar o comando:
docker -h

Contêiner x Imagem
Estou falando sobre contêineres e imagens, mas o que exatamente são eles?Vamos lá, quando executamos o comando:
docker run Hello-World
Eu citei que estávamos executando uma imagem para criação de um contêiner, o fato é que uma imagem é como se fosse uma receita de bolo, uma série de instruções que o Docker seguirá para criar um contêiner. Essas instruções ficaram mais claras quando criarmos a nossa própria imagem mais abaixo.
Há milhares de imagens no Docker Hub disponíveis para executarmos a nossa aplicação. Por exemplo vamos praticar um pouco mais com um outro exemplo clássico. Vamos executar uma imagem que contém o Ubuntu, sim um sistema operacional:
docker run ubuntu

Repare que durante o download da imagem não é feito somente um download, isso porque uma imagem é dividida em camadas.
Terminados os downloads, nenhuma mensagem é exibida, então significa que o contêiner não foi criado? Na verdade o contêiner foi criado, executado e parado. O que acontece é que a imagem do Ubuntu ao ser executada da forma como fizemos, não fica no ar rodando. Por isso nenhuma mensagem foi exibida.
Para termos um contêiner do ubunto rodando no ar vamos executar o seguinte comando:
docker run -it ubuntu /bin/bash

Com a opção -it
deixamos o bash do Ubuntu interativo com o nosso terminal. Isso significa que temos acesso direto do nosso terminal ao bash do Ubuntu.
Exemplo de comando no bash do Ubuntu pelo nosso terminal:

Para sair desse modo basta digitar: EXIT
Mas a parte mais incrível disso tudo: Sim senhores, vocês estão executando um sistema operacional dentro de um contêiner, e tudo isso pelo custo de:

Claro que este é uma versão de Ubuntu sem opções gráficas, e sem a maioria dos aplicações instaladas, é a opção mais simples que o Ubuntu poderia ser.
Como disse anteriormente este é apenas o básico para que você conheça um pouco sobre a tecnologia Docker. Tendo esse básico já somos capazes de seguir para dockerizar uma aplicação.
Dockerizando uma Aplicação
O que vamos fazer nesse passo é transformar nossa aplicação em uma imagem Docker para subirmos posteriormente no SCP.
A primeira coisa que vamos fazer é obter a aplicação em NodeJS que criei para esse exemplo. Clone esse projeto na sua maquina acessando o seguinte link:
Após clonar o projeto, vamos executá-lo. Entretanto, agora que temos o docker na nossa vida, porque gastar recurso da nossa maquina instalando o NodeJS? Vamos então baixar uma imagem que já contenha o NodeJS:
Vamos entrar no Docker Hub e buscar por Node

Voltemos ao terminal, e vamos executar o seguinte comando:
docker pull node


É possível testar essa imagem executando:
docker run -it node

Agora que já baixamos nossa imagem e já fomos capazes de testar, vamos criar o nosso contêiner com a nossa aplicação, passa isso executaremos o seguinte comando:
docker run -p <PORTA LOCAL>:<PORTA CONTEINER> -v "<DIRETORIO LOCAL DA APLICACAO:DIRETORIO DA APLICACAO NO CONTÊINER>" -w "<DIRETORIO DA APLICACAO NO CONTÊINER>" -it node npm start
Legenda por partes:
- docker run — Comando para criar e executar um contêiner baseado em uma imagem
- -p — Porta. Nesse ponto mapeamos qual porta da nossa maquina condiz com qual porta do contêiner
- -v — Volume. Nesse ponto mapeamos qual diretório da nossa maquina reflete no diretório do contêiner. Este comando é bom estar dentro de parênteses.
- -w — Workdir. Qual diretório será utilizado como referência para execução da aplicação. Este comando é bom estar dentro de parênteses.
- -it — Deixar a execução do contêiner interativo com o nosso terminal. Com esses comandos quando a aplicação rodar o nosso terminal ficará travado.
- node — Nome da nossa imagem.
- npm start — Comando que inicia a nossa aplicação.

Resultado no terminal:

Vamos agora no nosso navegador, e vamos verificar se a página está no ar:

Como disse enquanto explicava sobre os comandos -it
, enquanto a aplicação estiver rodando o nosso terminal irá ficar travado, para poder sair desse modo sem parar o contêiner e voltar ter acesso ao seu terminal sem ter que criar outra sessão, temos duas opções, são elas:
- CTRL + D
ou
- Durante execução do comando do RUN, insira o comando
-d

docker ps

Emocionante, eu sei.
Mas o que fizemos até aqui é apenas executar a nossa aplicação dentro de um contêiner. Os passos a seguir sim vamos iniciar o processo de dockerização.
E a primeira coisa que vamos fazer é na raiz do nosso projeto, criar um arquivo chamado:
Dockerfile
Dentro dele vamos inserir o seguinte trecho de código:

E o que é o Dockerfile?
O Dockerfile nada mais é do que um arquivo onde descrevemos o passo a passo na criação de imagem. Para quem é de Linux, esse processo é muito similar ao Makefile.
E como fizemos no nosso exemplo rodado por linha de comando, quero durante o processo de criação da imagem, colocar arquivos dentro da minha imagem ( referência -v
da indicação onde estão os arquivos que irão compôr a imagem), por exemplo:
Digamos que você quer subir um contêiner do NGINX, então você faz um PULL da imagem no Docker Hub, e posteriormente você vai precisar colocar arquivos de configuração.

Dessa forma utilizamos o Dockerfile para gerar uma imagem personalizada para a sua necessidade, para quando você for subir um contêiner, você passa a ter a capacidade de basear-se nessa imagem personalizada.
Voltando a nossa aplicação e o nosso Dockerfile, vamos entender o que significa cada passo:
- FROM — Esse comando é sempre a primeira linha de quando estamos criando uma imagem, ela indica a imagem base que vamos utilizar para criar a nossa imagem, além disso é possível especificar a versão da imagem que estamos querendo utilizar como base para a nossa, basta utilizar: <NOME_DA_IMAGEM>:<VERSAO>. No nosso caso estamos utilizando a ultima versão da imagem do Node.
- MAINTAINER — Nome do mantenedor da imagem. Este comando não é obrigatório.
- COPY — Este comando copia um ou vários arquivos ou pastas locais para o destino na imagem do Docker.
- WORKDIR — Este comando altera o diretório de execução do contêiner para um local especificado, caso você precise executar comandos de um local específico.
- ENTRYPOINT — Este é um comando que recebe um array, e é responsável por executar o contêiner após criação da imagem. Um comando similar é o CMD, estou deixando referências abaixo com mais detalhes.
A principio é apenas isso que precisamos para criar uma imagem, mas não se engane existem várias técnicas para criação de imagens otimizadas. A criação da imagem influência diretamente no Layered File System.
Feita a nossa receitinha chamada de dockerfile, vamos gerar a imagem. Para isso navegue via terminal onde está localizado o Dockerfile e então execute o seguinte comando:
docker build -t <ID_DOCKERHUB/NOME_DA_IMAGEM> <ENDERECO_DOCKERFILE>

Após execução temos o seguinte resultado:

Vamos verificar as nossas imagens:
docker images

Caso você queira executar a nossa imagem, basta rodar o comando e ser feliz:
docker run -p 3000:3000 <NOME_IMAGEM>

Publicando nossa imagem no Docker Hub
Com a imagem criada, o que precisamos fazer agora é publicá-la. Para isso é necessário que você tenha acesso ao Docker Hub. E então vamos executar os seguintes comandos:
docker login

Então executamos:
docker push <NOME_DA_IMAGEM>

E ai finalizado podemos acessar a nossa conta no Docker Hub, e teremos o seguinte:

Assim fizemos um ciclo de utilização do Docker desde a criação de uma imagem até a sua publicação. Entretanto existem vários detalhes que você só será capaz de compreender durante a utilização da ferramenta, por isso aconselho que você passe a utilizar Docker no seu dia a dia.
É possível automatizar esse processo acima integrando o seu repositório git com o Docker hub, então sempre que ocorrer um merge na master, automaticamente é gerado uma nova imagem. Caso interesse, irei deixar mais detalhes nas referências.
Deploy da nossa aplicação dockerizada no SCP
Agora que temos a nossa aplicação em uma imagem, já somos capazes de fazer o deploy em outros ambientes de forma bastante simples.
Vamos primeiro realizar o login no SCP:
cf login -a <ENDPOINT>

A primeira coisa que vamos conferir é se no nosso ambiente do Cloud Foundry a opção para trabalhar com contêineres está disponível. Para isso execute o comando abaixo:
cf feature-flags | grep diego

Caso sua opção não esteja habilitada basta utilizar os comandos enable-feature-flag ou disable-feature-flag. É possível obter mais detalhes seguindo a documentação do cloud foundry:
Agora que já conferimos que é possível utilizar contêiner, vamos fazer o deploy da nossa aplicação executando o seguinte comando:
cf push <APP_NAME_NO_SCP> --docker-image <IMAGE_NAME>:<TAG>
No meu caso ficou assim:
cf push bar8-docker --docker-image erickfc/bar8-cf-docker:latest
Resultado:



Acessando a rota que me foi criada, eu tenho o seguinte:

Podemos verificar nosso app via terminal ou SCP, da seguinte maneira:
- Via terminal
cf apps

cf logs <APP_NAME> --recent

E caso você ainda não acredite que foi tão fácil, você pode conferir acessando o SCP:

Dockerizando o MiniSAP
Antes da conclusão esse aqui é um tópico extra caso você tenha conseguido chegar até aqui.
Conseguimos trabalhar com contêineres em basicamente todos os cenários, eu pelo menos até agora não tive nenhum caso que não consegui rodar uma aplicação dentro de um contêiner, e quando digo basicamente todos cenários é porque é possível rodar aplicações como Skype, Navegadores (Safari, Chrome e etc).
Mas uma aplicação é verdadeira especial para nós, e graças ao Flávio Furlan e o Antelio I. Abe desenvolvedores abaps já não tinham desculpas para não terem o MiniSap:
Entretanto agora com Docker o que já era simples ficou ainda mais . Então caso você tenha interesse basta acessar os links abaixo e você poderá dockerizar o minisap também:
ou
Conclusão
A execução de aplicativos em contêineres em vez de máquinas virtuais é uma realidade, e principalmente pois suas vantagens agradam a todos, seja o desenvolvedor, o time ou a empresa. Na história recente não lembro de ter visto uma tecnologia que cresceu tão rápido na indústria do software.
Vimos hoje como ficou realmente mais facil criar, executar e fazer deploy de aplicações utilizando contêineres. Isso pois a praticidade que a tecnologia permite ao desenvolver empacotar um aplicativo com todas as necessidades (bibliotecas e outras dependências), e então enviá-la para qualquer outro ambiente com a segurança de que o aplicativo irá funcionar em qualquer outra máquina é maravilhoso.
Neste post tenho um agradecimento especial ao Victor Kawabata pela revisão fiel como sempre, e ao Flávio Furlan, pois esse post foi baseado em uma conversa que teríamos sobre Docker, ou tipo isso. Muito obrigado
E é isso ai, não deixe de conferir as referências abaixo, e se curtiu o post não deixe de participar comentando, compartilhando ou simplesmente segurando esse botão de aplausos para mostrar que é esse tipo de conteúdo que você deseja ter por aqui. Muito obrigado e até mais!