Ciência da Computação, desenvolvedor fullstack e devops
Autor:Cauan Cabral
Desenvolvedor com 2 dígitos de experiências, especialista em PHP e CakePHP mas com bagagens em JavaEE, Node.js, Javascript (ES6, jQuery, Angular) e Python. Interessado em automação, Machine Learning e cozinha.
Como todos sabem, estamos no meio de uma pandemia. Todos os países com algum governante sério tem enfrentado essa emergência sanitária incentivando, ou até mesmo, impondo quarentena entre sua população. Infelizmente, não é esse o nosso caso aqui no Brasil, onde o líder máximo da nação boicota diariamente qualquer tentativa de barrar o avanço do novo coronavírus.
Felizmente, não dependemos só do chefe do executivo nacional para tentar conter a pandemia, então estados, municípios e a própria sociedade civil tem tido papel fundamental no incentivo e viabilização da quarentena, daqueles que podem faze-la.
Tenho o privilégio de trabalhar com TI, numa função que me permite trabalhar 100% de casa, e que, por uma peça do destino, tinha sido exatamente essa a forma que passei a trabalhar 20 dias antes da chegada do coronavírus no país.
O que esse isolamento acabou mudando na minha rotina que já era de trabalhar em casa? Não posso mais caminhar na orla da praia (pois é, e me mudei pro litoral pra isso); não posso sair para almoçar ou jantar fora, nem fazer passeios pela cidade (que nem tive tempo de conhecer direito). Sobra, pra ocupar o tempo e manter a cabeça boa, aprender coisas novas, mas cuidando sempre pra não ficar o tempo todo pró-trabalho.
Nesse meio tempo, procurei materiais e cursos sobre ciência de dados, aprendi a fazer pão, fiz exercícios de estatística para desenferrujar a cabeça, joguei xadrez contra meu celular (não fazia isso há uns 10 anos), li 3 livros (também não fazia isso há muito tempo), cuido de um quintal algumas vezes maior do que tinha anteriormente e passei mais tempo com minha família (esposa e 3 cachorros). Tudo isso, alternando com o horário de expediente.
Se o animo não acabar, quero fazer uma série de posts exatamente sobre cada uma dessas ocupações, tentando compartilhar o que me motivou e o que aprendi ou tirei de proveito.
Até a versão 12, o Gitlab CI conectava ao docker registry próprio usando conexão não segura (sem TLS) por padrão.
Com a versão 19.03 do Dind (Docker-in-Docker), a conexão com o repositório passou a utilizar TLS por padrão. Do nada seus jobs começarão a falhar com alguma das mensagens abaixo:
Error response from daemon: Client sent an HTTP request to an HTTPS server.
<code>time="2019-08-06T19:24:46Z" level=error msg="failed to dial gRPC: cannot connect to the Docker daemon. Is 'docker daemon' running on this host?: dial tcp <some address>:2375: connect: connection refused"</code>
Cannot connect to the Docker daemon at tcp://docker:2375/. Is the docker daemon running?
Para resolver isso, podemos desabilitar explicitamente o TLS (o que não é recomendado e não entrarei em detalhes) ou configurar o nosso executor (runner) para utilizar TLS e é isso que faremos.
DOCKER_HOST=tcp://docker:2376 : define o host interno do daemon e a porta no qual está conectado. A porta não-TLS (antiga padrão) é 2375. É ela que precisa ser alterada para 2376.
DOCKER_TLS_VERIFY=1 : define que o daemon deve verificar o certificado utilizado na comunicação.
DOCKER_TLS_CERTDIR=/certs/${CI_JOB_ID} : aqui definimos onde o serviço do docker irá gerar seus certificados. É um absoluto interno do container. Utilizamos a variável ${CI_JOB_ID} para que não haja conflito com execuções paralelas.
DOCKER_CERT_PATH=/certs/${CI_JOB_ID}/client : define o caminho onde o serviço deve procurar o certificado de cliente para conexão TLS. É um subdiretório gerado pela configuração anterior.
volumes = [“/tmp/gitlab/docker/certs:/certs”, “/cache”] : definimos um diretório no nosso host (máquina que possui o gitlab-runner instalado) que será compartilhado com os containers em execução para armazenar os certificados gerados.
Outra configuração importante que deve ser removida (e por isso não consta no meu exemplo) é a tls_verify = false .
E é isso, agora só reiniciar seu runner por garantia – embora ele já atualize as configurações automaticamente: sudo systemctl restart gitlab-runner
Para que uma variável definida no seu docker-compose.yml como args esteja disponível para seu Dockerfile e respectivos comandos (RUN/ENV), ele PRECISA ser enunciado no Dockerfile com o comando ARG.
No caso de enunciar antes da expressão FROM, você PRECISA repetir o enunciado após o mesmo – porque a imagem que você está estendendo pode ter removido/limpado as variáveis anteriores. Segue um exemplo:
ARG PHP_VERSION
FROM phusion/baseimage:latest
ARG PHP_VERSION
RUN apt-get install php${PHP_VERSION}-cli
Recentemente assumi a tarefa de avaliar e otimizar algumas tabelas e queries que apresentavam perfomance muito diferente no PostgreSQL e no MySQL (versão bem antiga).
Minha primeira suspeita foi justamente o fato do MySQL estar muito desatualizado. Para descartar ou confirmar essa suspeita, eu precisava rodar no mesmo hardware versões diferentes do MySQL – e com containers, isso é fácil e indolor.
A minha instância padrão (versão antiga) compartilha com o host (minha máquina) a porta padrão do MySQL, então, do próprio macOS eu consigo conectar nela (depois de estar em execução) com o comando:
mysql -h 127.0.0.1 -P 3306 -u root -p
Agora, para executar uma versão específica, primeiro precisamos iniciar o container:
docker run --name mysql-atual -e MYSQL_ROOT_PASSWORD=senha -p 3307:3306 -d mysql:latest
Isso executará a versão atual (latest) da imagem mysql, definindo a senha senha para o usuário root, mapeando a porta 3306 do container com a 3307 do host (meu macOS) em modo daemon, com o nome mysql-atual.
Pronto, temos duas versões diferentes no mesmo hardware para fazer comparações. Podemos conectar nesse novo container da mesma forma que o anterior, alterando apenas a porta:
Nos doisúltimos posts falei um pouco do porquê e como fiz para gerar as imagens docker. Agora gostaria de compartilhar um pouco das vantagens que tenho visto nessa abordagem em relação ao Vagrant + VirtualBox.
Reprodutibilidade
Com o passar do tempo, a tendência é que as dependências de nossos projetos mudem, algumas coisas são adicionadas, umas removidas e outras atualizadas. Em um ambiente tradicional, acabamos por seguir o caminho mais rápido no dia a dia para adequar o ambiente, geralmente fazendo essa adaptação manualmente.
Dessa forma, se em algum momento você precisar recriar seu ambiente de desenvolvimento, ele provavelmente não funcionará como você esperava.
Como os containers Dockers são criados a partir da imagem a cada vez que executamos, qualquer alteração feita durante uma execução não é persistida – excluindo disso, obviamente, os volumes persistentes. Cada dia de trabalho, cada vez que você inicia seus containers é como o primeiro dia – quase poético.
As atualizações precisam necessariamente ser definidas no Dockerfile ou script correspondente para atualizar a imagem e tudo fica registrado.
Performance
Esse foi o ponto que me fez pensar em uma alternativa ao setup antigo – a escrita em disco era sofrível pelo VirtualBox. Além disso, como uso o mesmo ambiente para trabalhar em diversos projetos, há diversos serviços em execução ao mesmo tempo: MySQL Server, Postgresql Server, Elasticsearch, Redis Server, PHP-FPM (duas versões), Nginx, dentre outros.
Ficar alternando entre serviços ativos e inativos para cada projeto seria tedioso, e o preço era um consumo alto de memória.
Com o Docker e o docker-compose, tenho aliases no terminal para iniciar os serviços (leia-se containers) para cada projeto. Se mais de um projeto usa o mesmo serviço, ele é iniciado uma única vez e compartilhado. A escrita em disco com o recente Docker for Mac é muito mais que aceitável, especialmente quando comparada com o Vagrant.
Conclusão
De inicio eu nem enxerguei a vantagem inerente do uso de containers, mas é por si só um grande benefício dessa abordagem. A questão da performance é mais perceptível em relação a escrita de dados – banco de dados, processamento batch e etc. O consumo de memória vai depender muito da quantidade de serviços/containers rodando simultaneamente.
Já comentei diversas vezes que sou um usuário adito do Gitlab – como dizem por aí, desde quando tudo aquilo ali era mato. E um dos recursos que foram adicionados ao longo dos anos e eu mais utilizo é o de CI. Com ele consigo definir processos automáticos para testes, builds e deploy (esse, infelizmente, fora da minha realidade por enquanto) que são executados em containers ou máquinas especificamente designadas.
Se você olhar o repositório do Laradock, encontrará um arquivo com nome .gitlab-ci.yml. Esse arquivo é o responsável por dizer ao CI do Gitlab o que fazer quando uma alteração no repositório é enviada – ou quando o CI é disparado manualmente. Infelizmente ele não funcionará – a versão ali definida para o docker, dind e docker-compose estão defasadas, além disso, se você, como eu, utilizar o container registry do próprio Gitlab, essa informação deve ser adicionada ao arquivo.
O .gitlab-ci.yml atual do laradock começa desta forma:
Atualizar a imagem usada por: jonaskello/docker-and-compose:17.03.0-1.18.0
Atualizar a versão do service para: docker:18-dind
Incluir a variável DOCKER_HOST com valor tcp://docker:2375/
Incluir junto ao before_script a autenticação no seu registry para que seja possível fazer o push da imagem ao fim da geração. No meu caso, a linha fica: docker login -u gitlab-ci-token –password $CI_JOB_TOKEN registry.meudominio.com.br
Além disso, dentro do arquivo docker-compose.yml é preciso definir o caminho de cada imagem que você quer enviar ao container registry.
Por exemplo, no caso da imagem workspace as configurações devem ficar:
Voltando ao .gitlab-ci.yml, em cada imagem que iremos construir devemos incluir o comando para fazer o push da imagem, todo o bloco de construção de uma imagem deve ficar parecido com o abaixo:
Talvez você esteja perguntando por que tem duas chamadas ao docker login no processo de construção. A resposta é bem simples: garantir que não haja problema com sessão expirada. No meu setup, algumas imagens levam um bom tempo para serem construídas (culpa dos sistemas monolíticos) e no inicio eu tinha problema de ao tentar fazer o push da imagem, receber como resposta um Unauthorized.
Recapitulando, nosso .gitlab-ci.yml deve ficar parecido com:
Sempre que troco de computador me vejo pensando: será que hoje tem uma forma melhor (leia-se mais moderna) de configurar um ambiente de trabalho pra programador?
No final de 2018 recebi um notebook novo para ser utilizado no trabalho e foi nesse contexto que minha saga começou.
Desde que comecei a usar macOS como sistema principal, optei por deixar o sistema o mais leve/intocado possível, facilitando atualizações e não sobrecarregando a máquina quando não estou usando a trabalho. Pra isso, utilizei algumas formas de virtualização ao longo do tempo.
No começo, optei pelo VirtualBox, gerenciando o provisionamento e configuração com o Vagrant. Por um tempo foi bom, mas toda vez que ia iniciar um projeto novo, precisava configurar DNS, VirtualHost e várias configurações dentro da vm. E isso cansou.
Depois de quebrar a cabeça com o provisionamento algumas vezes, descobri o projeto Laravel Homestead, que resolvia a maioria dos meus problemas: nele é possível configurar novos projetos usando o arquivo de configuração (incluindo criar banco de dados, VirtualHost etc), sem precisar nem logar dentro da vm. Outra grande vantagem do Homestead é fornecer uma vm com diversas versões do PHP pré-configuradas, e usáveis simultaneamente – você pode ter diversos projetos, cada um com a versão do PHP.
Mas um fator ainda me incomodava: o sistema de arquivos do VirtualBox. É extremamente lento, tarefas que depende de disco intensivo (banco de dados e testes unitários, por exemplo) são bastante penalizados. A solução mais “simples” seria abrir a carteira e gastar alguns centenas de dólares em uma solução mais robusta de virtualização – como não tenho esses dólares disponível, nem cogitei a hipótese.
Foi aí que surgiu a oportunidade de me aprofundar nos estudos sobre Docker. Coincidiu com o lançamento do Docker for Mac, que eliminou a necessidade do VirtualBox para rodar os containers. Agora eu tinha a possibilidade de virtualizar o ambiente, com ferramentas nativas do macOS, e containers específicos para cada recurso / serviço necessário – evitando desperdício de RAM/CPU.
Enquanto eu experimentava a construção da imagem perfeita, descobri o Laradock, uma espécie de Homestead voltado para Docker. Com ele, você pode definir diversas dependências pré-configuradas usando um arquivo de ambiente (.env), criar suas imagens de acordo com suas necessidades e executar apenas aquilo que precisa.
Estou usando essa solução a 2 meses e tem me atendido muito bem.
Tanto o CakePHP quanto o Elasticsearch fazem parte da minha vida a alguns anos. No começo foi um pouco traumático – era preciso fazer chamadas via REST sem nenhuma abstração, utilizando curl ou streams.
Há ainda um projeto de datasource oficial que, embora nunca tenha chego em um release final, já incorpora algumas funcionalidades importantes da integração para uso do Elasticsearch como um backend para os repositórios no CakePHP.
Este projeto se chama cakephp/elastic-search e nas últimas semanas tive a oportunidade de ajudar em uma grande refatoração para torna-lo compatível com o Elasticsearch > 6 – a versão anterior do projeto suportava versões até a 2.5.
Dentre as mudanças mais importantes estão:
Troca da entidade Type pela Index, seguindo a diretriz do ES de remover suporte e múltiplos tipos em um mesmo índice;
Cada Index passa a especificar seu nome e tipo, em um mapeamento 1×1, como é obrigatório no ES desde a versão 6.0;
Atualização da dependência Elastica, para versão corrente, permitindo uso de todos os recursos recentes tanto do ES quanto do client.
Caso tenham alguma dúvida sobre uso e não queiram utilizar o github (por conta da língua ou outro motivo), utilizem os comentários que tentarei responder o mais rápido possível.
Já tem um tempo que ensaio escrever algo aqui e a primeira coisa que vem a mente é: por que diabos eu só venho escrevendo 1 vez por ano e sempre no inicio do mesmo?
Não sei exatamente o motivo – talvez seja o famoso efeito mágico do reinicio de nosso calendário, mas de qualquer maneira, muita coisa aconteceu desde o último post.
Não consigo dizer que 2017 foi um grande ano: socialmente parecemos cada vez mais retrógrados, politicamente estamos desiludidos, trocando acusações pra defender falácias e pessoalmente passei por coisas boas mas também novas frustrações.
Em resumo
Yay, mudei pra uma casa melhor com minha esposa e tivemos nosso primeiro ano morando juntos depois de casado
Iniciei um mestrado e desisti em 2 míseros meses
Por conta do anterior, acabei saindo “do mundo enterprise” após nossa primeira entrega e voltando a trabalhar com meu trabalho anterior
Novamente, gostaria de voltar a escrever, de voltar a contribuir com projetos opensource e em especial nesse ano de eleição, com projetos ligados a ativismo social, ajudando a mim mesmo e outras pessoas entenderem e participarem de forma mais direta nas decisões da cidade/estado/país – desde a escolha do representante.
Agora, veremos se em 2019 estarei aqui mais uma vez fazendo um mea culpa ou agora vai.
Em Maio/2016 fiz uma mudança radical em minha carreira profissional – optei por sair de uma empresa que trabalha com PHP, CakePHP e outras tecnologias que faziam parte da minha vida desde pelo menos 2008 para embarcar em um projeto novo, com pessoas novas e tecnologias completamente novas para mim.
Passei desde então a trabalhar com Java EE, Oracle Database, Bitbucket/Jira/Bamboo (sempre trabalhei com Github e Gitlab), Angular 2 + Typescript. Foi uma mudança e tanto de paradigmas. Tudo em nome do tão falado “enterprise” (não, eu acho que PHP/CakePHP pode ser tão enterprise quanto JavaEE, mas nem todo o mercado pensa assim).
Aprender a trabalhar com servidor de aplicação, pipelines de compilação – compilação a cada pequena alteração de código, a maior reclamação de um programador acostumado com linguagens interpretadas quando mudam, concorrência em sistemas que não são stateless… é um mundo todo novo, mas interessante.
Quero aproveitar todos esses aprendizados e experiências para voltar a escrever aqui, veremos o que vem a seguir.