API FIRST

No meu último post “O que você precisa saber antes de desenvolver aplicações para a nuvem” apresentei de forma macro os 3 pilares na implantação de aplicativos em um ambiente em nuvem. Neste post o foco é aprofundar no entendimento do conceito de API (Application Programming Interface ou Interface de Programação de Aplicações) e como esse é o início da próxima revolução na tecnologia.

Uma interface de programação de aplicação (“API”) é um conjunto particular de regras (“code”) e especificações que os programas de software pode seguir para se comunicar uns com os outros. Ele serve como uma interface entre os diferentes programas de software e facilita sua interação, semelhante à maneira como a interface de usuário facilita interação entre humanos e computadores. Conceito bacana, mas enfim, o que isso muda em nosso dia a dia?

A resposta é tudo! – API são a nova quebra de paradigma que se desenha no mundo da tecnologia. IoT e Cloud só evoluíram por conta das APIs. Lembra quando se iniciou a revolução da comunicação empresarial, aquele que não possuísse um telefone para comunicar sua empresa com os seus consumidores e fornecedores estava fora do mercado, agora aquele que não conseguir fazer com que seu sistema se comunique com os demais ou quem não conseguir fazer com que sua “coisa” produto se comunique com outros, estará com certeza para trás.

Em um mundo hiperconectado é necessário termos a garantia de uma infraestrutura sólida, uma rede de comunicações evoluídas, uma cultura DevOps avançada, documentação e muito software. Para os sistemas se conversarem e que haja a evolução, você precisa ter acesso a API do seu concorrente. É preciso entender como a construção dos seus parceiros e concorrentes se comunicam e evoluir com eles.

Atualmente há muita discursão sobre desenvolvimento ágil que se preza pela velocidade de entrega do software, no alinhamento com as partes interessadas, no deply continuo etc. Toda essa discussão iniciou em um momento de destruição criativa. Para tal as APIs promove uma nova quebra de cultura nas empresas, onde será necessário um planejamento maior, talvez desenvolver algo mais demorado, mais caro, mais inteligente, mais resiliente….l

Hoje está em alta as APIs e a tecnologia é assim. Você precisa ter determinado recurso para sair na frente de sua concorrência. Amanhã, ela será commoditie. Repense na jornada de olho na indústria 4.0 e na transformação digital. Aprenda o próximo passo da tecnologia por meio de APIs e cultura DevOps.

Grande abraço.

Luiz Eduardo

Boas Práticas com Docker

No post sobre DevOps foram citadas inúmeras ferramentas que facilitam e permitem cultivar uma cultura DevOps. Minha escolha para iniciar esta jornada foi o Docker. Em vez de convencer que o Docker é bom ou explicar como instalar e subir o primeiro container, vou focar em questões da nossa experiência com o Docker. Questões simples mas importantes acabam passando desapercebidas e geram problemas em produção.

Se você está iniciando em Docker, recomendo começar pela documentação oficial, que melhorou bastante nos últimos tempos. Se você ainda está em dúvida para onde as coisas caminham, dê uma olhada neste gráfico. Containers já são uma realidade.

Entendendo Problemas de Consistência

Com todo o hype em torno de containers, é natural que existam sentimentos do tipo “precisamos usar Docker porque todo mundo está usando” ou “vamos usar Docker porque é legal”. Docker, como qualquer ferramenta, tem seus principais valores. E no caso, posso resumir o valor do Docker em uma palavra: consistência. É importante entender o que isso significa para implantar a ferramenta de forma adequada em seu ciclo produtivo.

Pré-Puppet (ou Chef, Ansible…)

Vamos supor que você precisa subir uma aplicação nova. Máquina provisionada, SO instalado, você loga na máquina e:

  • Atualiza o sistema operacional.
  • Instala os pacotes da sua aplicação (apt, yum, zip (!!) etc).
  • Edita os arquivos de configuração.
  • Coloca o serviço no boot.
  • Reboot.

Este fluxo representa a maioria dos casos, e é um bom exemplo.

Agora solicitaram subir mais máquinas idênticas… será tedioso.

Mecanizando o Processo

De posse de ferramentas de gestão de configuração, você escreve o código que mecaniza todo o processo. Maravilha! Máquinas novas provisionadas para produção em segundos!

Porém, saem novas versões da aplicação o tempo todo, problemas aparecem em produção e a únia solução é “formatar” a máquina…

Gerenciando Alterações

Vamos entender onde o problema ocorre. Você recebe a máquina M1, apenas com o SO (BareMetal):

M1 > BareMetal

Então, aplica a sua automação, v1, em cima:

M1 > BareMetal > v1

E leva a máquina para produção, na versão v1. Mas claro, vem a v2 da automação, e você aplica:

M1 > BareMetal > v1 > v2

Agora você adiciona uma nova máquina M2, para suportar a v3:

M1 > BareMetal > v1 > v2 > v3

M2 > BareMetal > v3

E de repente, a M1 funciona, mas a M2 não! Claramente, M1 foi submetida a um fluxo (v1 > v2 > v3) totalmente diferente da M2 (v3), e fatalmente o estado real e final da M2 não é o mesmo da M1, mesmo que ambas foram submetidas à mesma receita v3. Uma causa comum por exemplo, é que a v2 instala uma dependência, que a v3 não pede.

Para resolver o problema, só começando do zero.

Entregando Com Consistência

Achado o bug, criamos uma v4, e entregamos em uma máquina M3:

M3 > v4

Isso funciona porque o fluxo é mais consistente. Pra fechar a questão, matamos as máquinas M1 e M2, e provisionamos as máquinas M4 e M5, no mesmo fluxo da M3:

M4 > v4

M5 > v4

Maravilha! Um mês depois, você provisiona a M6, para suportar a carga crescente:

M6 > v4

E novamente, problemas! Como pode? M4 e M5 foram submetidas ao mesmo fluxo do M6! Fatalmente é algum fator externo, como por exemplo updates do SO que estão na receita. Alguma versão mais nova de dependência que está presente somente na M6 está gerando problemas.

“Que maravilha!”, você pensa. Agora vamos à estaca zero para versionar TODOS os pacotes do sistema operacional, repositórios, etc…. não vai ter fim.

Containers Para a Salvação!

Bem, é exatamente todo esse stress que containers evitam. Fazendo uma analogia, containers são como um snapshot de uma VM em um estado confiável. Este snapshot pode ser utilizado para instanciar quantas VMs forem preciso, de forma confiável. Na terminologia do Docker, os snapshots se chamam imagens e as VMs containers:

Dockerfile > Image > Containers

Uma vez com a imagem pronta, você pode instanciar quantos containers forem precisos, onde for preciso, rapidamente e com confiança!

Além do Ambiente de Produção

 

Um container é algo tão leve e rápido, que consegue ser utilizado na máquina do desenvolvedor e também no servidor em produção, com fidelidade altíssima entre os ambientes. Além disso, o Docker Registry resolve o problema de se compartilhar imagens. Imaginem que eu como desenvolvedor preciso fazer o QA do meu sistema, que tem dependência de um sistema terceiro. Eu posso simplesmente utilizar a imagem do container de produção deste sistema! Nada mais de “o QA está fora”, ou “o orçamento para máquinas de QA está alto”.

 

Docker traz assertividade, confiabilidade e redução de custos, levando para o início do ciclo de desenvolvimento a mesma tecnologia e performance que existem no ambiente de produção.

Pontos de Atenção Com Docker

Criar um Dockerfile e subir o primeiro container é quase trivial. Entretanto,alguns pontos importantes, triviais de se implementar, muitas vezes são esquecidos. Em especial, no Docker Hub, há imagens prontas para praticamente qualquer coisa. Entretanto, a maturidade e qualidade delas varia grotescamente. Olhe as imagens e valide se os Dockerfiles seguem bons princípios. Somente então as utilize.

 

Alguns dos pontos levantados aqui são parte do http://12factor.net/, vale a leitura complementar.

Não Executar Como root

Um dos anti-patterns mais comuns com o Docker é executar os processos do container como root. Há uma certa argumentação válida de que a kernel já garante isolamento entre containers, mesmo eles sendo executados como root. Vou dar crédito para isso. Porém, há uma série de abusos que podem ser feitos dentro do container, como sobrescrever binários, arquivos de configuração etc… Pense assim: para quê rodar como root? O único caso que consigo pensar é executar um container privilegiado, que por si só é algo tão fora do padrão, que pode ser até considerado um anti-pattern.

Logs Fora do Container

Apesar de não haver nada proibindo você de gravar logs dentro do container, isso fatalmente irá te causar problemas. Na próxima atualização, quando for entregue um novo container, TODO o conteúdo dos logs antigos será perdido. As opções são:

  • Mapear o diretório de logs para um volume que será persistente, e anexado a novas versões do container.
  • Enviar os logs para outra ferramenta externa (ex: Elastic Search, Splunk).
  • Enviar logs para o STDOUT / STDERR.

Este último é a boa prática com Docker, utilize se possível. É trivial configurar o Docker Engine para que os logs de TODOS os containers sejam redirecionados para algum local externo. Cuidado com esta configuração e garanta que os logs estão sendo devidamente rotacionados, e os antigos apagados.

Volumes de Dados

Pelo mesmo motivo dos logs, dados importantes persistidos pela aplicação devem sair do container (ex: /var/lib/mysql). Caso contrário serão perdidos quando o container for destruído.

 

Este ponto é melhor compreendido se olharmos para uma arquitetura completa:

Web Tier > App Tier > BD

Apenas a camada de BD persiste dados, logo deve ser a única elegível para utilizar volume de dados (sujeito a backup). Pense nas demais camadas como “imutáveis”: os containers nela devem poder ser destruídos sem qualquer tipo de prejuízo, a qualquer momento. Isso facilita bastante a administração e acaba sendo um requisito importante se você está pensando em qualquer tipo de auto-scaling.

Configurações Através de Variáveis de Ambiente

Outro anti-pattern comum é colocar um grande volume de configurações no container, em arquivos. Não há nada de errado nisso, mas você tem dois pontos a considerar:

  • O que muda do container de produção para o de QA?
  • A mesma imagem pode ser utilizada para criar containers em ambientes distintos (eg: Apache como proxy para 2 sistemas)?

O que for identificado como necessário para que a mesma imagem atenda mais de um cenário deve ser informado via variáveis de ambiente na criação do container (ver –env)! O seu ENTRYPOINT deve ser responsável por interpretar estas variáveis e fazer os ajustes necessários. Uma opção comum é colocar no ENTRYPOINT um shell script que lê as variáveis de ambiente (tipicamente usuário e senha), gera o arquivo de configuração adequado e depois executa o processo do container.

 

Permitir “reciclar” a mesma imagem em mais de um cenário tem sempre que estar em mente. Minimamente produção e QA acabarão existindo. Tome cuidado para não abusar deste modelo. Uma coisa é colocar os certificados HTTPS em variável (um pattern que já vi algumas vezes) e outra é colocar TODO o httpd.conf do Apache em uma variável de ambiente. Ambos funcionam, mas claramente há um pouco de bom senso nisso. A regra do dia a dia é: se é algo que muda entre cada ambiente, vai para variável de ambiente, caso contrário vai para o container diretamente.

Operating System updates

Já pensou o como corrigir o próximo bug nojento do OpenSSL em todos os seus containers em produção? A resposta é simples: não se corrige. Pense em containers como algo imutável. Se você precisa atualizar algo, inclua no seu Dockerfile um comando pra atualizar o SO e o que mais for necessário e entregue a nova versão do container. Tecnicamente é possível entrar em um container e atualizar o SO, mas faz pouco sentido pois viola o princípio da imutabilidade.

Nomes das Tags

Uma consequência de atualizar o SO diretamente do Dockerfile (ex: apt-get upgrade) é que um mesmo Dockerfile, utilizado para criar imagens em dois momentos distintos, gera duas imagens distintas. Isso ocorre devido a dependências externas na criação do container, que mudam com o tempo (ex: versão do OpenSSL). Uma opção seria controlar também a versão dos pacotes no repositório do SO porém uma solução mais simples, seria adotar um padrão para a tag de cada imagem:

[git tag]_[data]

Ex:

V1.0.10_2016-07-07_18-36

Apesar de um pouco extenso, o node permitirá melhor gestão. Ex: você só precisa atualizar o SO do container, mas a versão da aplicação é a mesma. Sem problemas. Fica claro pelo nome que é a mesma versão da aplicação, mas dependências externas são diferentes.

 

Utilizar a tag “latest”, além da tag específica, também é uma prática comum para indicar qual a versão de produção.

Pacotes de SO / Prateleira

Se você vai executar uma aplicação que não foi feita para ser executada em container, tenha os seguintes pontos em mente:

  • Os scripts de start / stop do SO não foram feitos para serem executados em container.
    • Eles irão fazer fork() do daemon, e você verá uma morte prematura do container.
    • Você deve invocar o binário do daemon diretamente no ENTRYPOINT do container.
  • Rotação e purga de logs geralmente funcionam via cron, porém não há cron no container.
    • Tente redirecionar os logs do daemon para stdout / stderr.
    • Se não por possível, a alternativa é usar um entrypoint que suba o cron no container, e depois execute o daemon.

Um Processo por Container

Esse é um mantra comum na comunidade Docker, mas é bastante mal compreendido. Pense em um Apache MPM, que abre diversos processos para atender requisições. Ele viola o princípio do Docker? Bem… não. Uma melhor formulação do mantra seria “uma aplicação por container”. Exemplo: se você tem um Apache e um Jetty para subir, coloque cada um em seu container. Este artigo explora o cenário de mais de um processo por container.

Tecnicamente, você pode rodar o init em um container, e “subir o SO do zero”. Nada te impede disso. Porém isso vai contra a mentalidade de containers serem leves, auto-contidos e descartáveis. Um SO completo sobe uma variedade de serviços que sua aplicação no container não precisa… inclusive o próprio init.

Conclusão

Não pense em Docker / containers como uma opção, mas sim como algo inevitável. Quanto antes você estiver nesta onda, melhor. Mas compreenda bem a mentalidade por trás e use a ferramenta certa, da maneira certa, para o problema certo. Não somente “siga o hype” cegamente.

DevOps – Colaboração é a chave da questão

Em ambientes com cada vez mais necessidade de mudanças e atualizações constantes, os times de tecnologia enfrentam desafios entre a agilidade das entregas para atender demandas de negócios e a estabilidade dos ambientes operacionais.

A falta de cooperação entre os grupos de tecnologia resultam em conflitos e ineficiências e precisamos criar uma ponte entre as necessidades de desenvolvimento ágil e os requisitos técnicos dos ambientes de produção.

Um ponto importante da mudança de filosofia é acabar com os silos e a cultura do “finger point” e investir de forma séria em automação.

Ao buscar oportunidades para automação do ciclo de desenvolvimento e operações podemos olhar para itens como por exemplo:

  • Builds
  • Tenting
  • Monitoring
  • Deployments
  • System Configuration

A necessidade por simplificar processos entre os grupos e garantir a eficiências das entregas é pauta constante na agenda dos profissionais de tecnologia.

Normalmente todo fluxo de evolução de produtos e soluções dependem de tecnologia e sistemas complexos e com diversas partes dependentes, essa realidade introduz desafios de comunicação entre os times e deixa claro que para atender ao novo mundo precisamos de mudanças e novos modelos mentais.

Times de tecnologia devem ser cada vez mais responsáveis pelo sucesso dos seus grupos e ter o contexto claro do seu papel no sucesso dos negócios.

Todos os envolvidos existem por um motivo principal, viabilizar o negócio.

Velocidade no processo de entregas de novas funcionalidades e ambientes é uma necessidade e requisito básico para atingir os resultados, porém esse ponto não é mais importante que a segurança e a disponibilidade dos ambientes.

As mudanças não devem representar “incêndios” e dias intermináveis de crises e instabilidades.

Diminuir a distância entre os times que desenvolvem software e as equipes operacionais requer uma mudança de cultura. Uma abordagem muito mais colaborativa , com liberdade , times capacitados e grande responsabilidade.

Nessa cultura, a comunicação, transparência e as relações humanas são indispensáveis.

Para facilitar a vida dos times de desenvolvimento e operações existem diversas categorias de soluções que devem ser consideradas, entre elas podemos citar:

  • Source Control
  • Continuous Integration
  • Deployment
  • Cloud / Iaas / Paas
  • Monitoring & Data visualization
  • Database lifecycle management
  • Repository Management
  • Provisioning / Configuration Management
  • Release Management
  • Logging
  • Build
  • Testing
  • Containerization
  • Collaboration
  • Security

Diversas ferramentas também apoiam nessa jornada, entre elas:

Source Control

  • Git
  • GitHub

Continuous Integration

  • Jenkins
  • Continuum
  • Hudson

Deployment

  • Jenkins
  • Chef
  • Capistrano

Cloud / Iaas / Paas

Monitoring & Data visualization

  • Kibana
  • Graphite
  • Splunk
  • Nagios
  • Zabbix
  • Grafana
  • Elasticsearch

Database lifecycle management

  • DBmaestro
  • Datical
  • Liquibase

Repository Management

  • Artifactory
  • Nexus
  • Archiva
  • NuGet
  • npm
  • Docker Hub

Provisioning / Configuration Management

  • Chef
  • Ansible
  • Puppet
  • Consul

Release Management

  • Continuum

Logging

  • Splunk
  • Logstash
  • Graylog
  • Loggly

Build

  • Continuum
  • Maven
  • ANT
  • Hudson
  • Broccoli
  • Make

Testing

  • Cucumber
  • Selenium
  • Gatling
  • JUnit
  • TestNG
  • JMeter

Containerization

  • Docker
  • Kubernetes
  • Mesos
  • Linux Containers
  • Swarm
  • Marathon
  • OpenVZ

Collaboration

  • Jira
  • Trello
  • Slack
  • HipChat

Security

  • Snort
  • Cyberark
  • Tripwire
  • Fortify
  • Vault
  • SecureAssist

 

Tabela de DevOps

 

Um ponto fundamental dessa revolução é entender que não é apenas um conjunto de ferramentas é uma mudança de cultura , onde novas formas de trabalho são buscadas, testadas , discartadas ou adotadas.

O que você precisa saber antes de desenvolver aplicações para a nuvem

Vivemos em uma sociedade hiperconectada, com smartphones, tables e outros dispositivos móveis fazendo parte de nosso dia a dia. A velocidade das transformações é aluciante e aumenta a cada dia. 🙂

Os antigos processos de desenvolvimento e gestão do ciclo de vida das aplicações foram baseados no conceito que o sistema era desenhado para ser praticamente estático na TI tradicional. As modificações, sejam por incremento de novas funcionalidade ou aspectos pertinentes a demanda do negócio, eram acumuladas e embutidas em nova versões do software, em ciclos de no mínimo um ano entre estas mudanças.

O mercado demanda mudanças urgentes e para vencer é necessário proporcionar uma boa experiência de uso aos usuários. A busca por melhores experiências deve ser contínua. As evoluções fazem com que o ciclo de vida das aplicações passem de longos períodos de requerimentos e desenvolvimento, para um modelo em contínuo “estado beta”, ou seja, em evolução constante, em intervalos cada vez mais curtos.

Atualizações não são mais anuais, mas sim mensais, semanais ou mesmo diárias!

É exatamente por causa dessa mudança de paradigma, onde características das aplicações tradicionais se distinguem das características da nova geração de aplicações que a implantação de aplicativos em um ambiente de nuvem pode ser muito diferente de implantá-los em um ambiente de TI tradicional.

É esperado que a nova geração de aplicativos em nuvem tenham a capacidade de adicionar e reduzir a elasticidade sem impactar a performance da infraestrutura.

Os aplicativos considerados cloud native utilizam:

  1. Recursos via API (Application Programming Interface)
  2. CLI (Command-line Interface)
  3. SDK (Software Developement Kit)

Tudo isso permite que os processos de desenvolvimento e operação do aplicativo funcionem de forma integrada, permitindo que o desenvolvedor atue inclusive como um DevOps.

O DevOps representa uma ruptura na cultura tradicional de desenvolvimento e gestão do ciclo de vida das aplicações. Ao utilizar os conceitos já consagrados de “agile development” e adiciona também as práticas de “lean startup”. E ao oferecer um conjunto de ferramentas aos desenvolvedores como as APIs, CLI e SDK possibilita a utilização de nuvens sem lock-in como o OpenStack – o maior orquestrador de nuvens em opensource para IaaS.

Com a nuvem OpenStack, por exemplo, os desenvolvedores possuem diversas possibilidades de criação dos seus aplicativos, podendo escolher diversas linguagens de programação tanto via SDK ou APIs.

A nova geração das aplicações permite a consolidação da nova TI. De modelos monolíticos, altamente integrados e fechados em si mesmo, para um modelo de serviços, com pontos de contato com o mundo exterior através de um ecossistema de APIs. Na prática, nenhuma aplicação é uma ilha isolada. Ela deve proporcionar experiências positivas para seus usuários.

As empresas responsáveis por produzir software estão cada vez mais alinhadas com o movimento DevOps.