Usando Docker para testar versões diferentes do MySQL

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:

mysql -h 127.0.0.1 -P 3307 -u root -p

Qual o saldo de usar Docker no lugar do Vagrant para desenvolvimento?

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.

Como fiz o Gitlab gerar minhas imagens do Laradock

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:

# image: docker:latest
# services:
#   - docker:dind
image: jonaskello/docker-and-compose:1.12.1-1.8.0
services:
  - docker:1.12.1-dind

before_script:
  - docker info
  - docker-compose version
  - cp env-example .env
  - sed -i -- "s/=false/=true/g" .env
  - cat .env
  - env | sort

build:5.6:php-fpm:
  variables:
    PHP_VERSION: "5.6"
  script:
- docker-compose build php-fpm

Precisamos corrigir então:

  • 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:

php-fpm:
      image: registry.meudominio.com.br/php-fpm:${PHP_VERSION}"
      build:
        context: ./php-fpm

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:

build:7.2:php-fpm:
  variables:
    PHP_VERSION: "7.2"
  script:
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker pull "registry.meudominio.com.br/php-fpm:${PHP_VERSION}" || true
    - docker-compose build php-fpm
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker-compose push php-fpm

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:

image: jonaskello/docker-and-compose:17.03.0-1.18.0
services:
  - docker:18-dind

variables:
  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2

before_script:
  - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
  - docker info
  - docker-compose version
  - cp env-example .env
  - cat .env
  - env | sort

build:7.2:php-fpm:
  variables:
    PHP_VERSION: "7.2"
  script:
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker pull "registry.meudominio.com.br/php-fpm:${PHP_VERSION}" || true
    - docker-compose build php-fpm
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker-compose push php-fpm

Último detalhe importante: o runner que vai executar esse build precisa ser do tipo Docker e deve ser executado em modo privilegiado (root), o que é não-recomendado em ambientes compartilhados – use uma máquina exclusivamente para CI, minimizando os riscos dessa configuração.
Agora você só precisa fazer o envio do seu código para instância do Gitlab que deseja usar e aguardar o build.

Se tiver alguma dica de como melhorar o setup, ou alguma dificuldade para fazer seu setup funcionar, deixe um comentário.

Ambientes de desenvolvimento

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.

CakePHP 3 e Elasticsearch

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.

Hoje contamos com diversas camadas intermediárias para facilitar a integração entre ambos, como o cliente em baixo nível oficial e o cliente em alto nível (Elastica).

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.

Todo ano começa sempre igual

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

  1. Yay, mudei pra uma casa melhor com minha esposa e tivemos nosso primeiro ano morando juntos depois de casado
  2. Iniciei um mestrado e desisti em 2 míseros meses
  3. 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.

Entrando no mundo “enterprise”

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.

De “webmaster” a “fullstack”

Num passado remoto, tínhamos o (D)HTML, Frontpage, Macromedia Flash, Fireworks, banco de dados MySQL junto ao ASP ou PHP. Tudo era novidade. Nem tudo funcionava. Duas categorias de trabalho surgiam: o webmaster e o webdesign. Cada um no seu quadrado, trabalhando com ferramentas bem delimitadas.

Os anos foram passando, o mundo evoluindo e novas novas novas novas tecnologias surgindo – HTML, JS, CSS amadureceram, bancos de dados especializados se popularizaram, como Redis, MongoDB, Cassandra; linguagens se multiplicaram.

Ser especialista em PHP não é mais suficiente; é preciso ter domínio de Bash, Python, Ruby, Java, Javascript, Scala, Go e por aí vai.

Querer desenvolver sem saber configurar uma máquina do zero com todos os seus requisitos é impensável – e olha que não são poucos os requisitos: um servidor http (nginx ou apache), o módulo para processamento da linguagem desejada, seu(s) banco(s) de dados (mysql, postgresql, mongodb, redis), ativar cache, serviço de fila de processos, monitoramento de logs, compilador para linguagens intermediárias (typescript, scss, sass).

Acho que só os detalhes para configuração da máquina já renderia um curso superior. Enfim, o mundo da TI está cada vez mais heterogêneo, graças a necessidade de interoperabilidade e em especial, ao movimento opensource – não há como lutar contra.

Nos idos dos anos 2004 iniciei minha carreira como webmaster – embora já me interessasse pelas áreas correlatas.

Hoje, após  13 anos, caminho cada vez mais para o perfil fullstack: gerenciando configurações de máquinas de desenvolvimento e produção, com ferramentas como o Ansible e SaltStack; utilização de linguagens que vão do Javascript ao C++, passando por PHP, Java(EE), Python; bancos de dados diversos (uso e gerenciamento); definição, configuração e acompanhamento de ferramentas para QA (builds e testes automatizados) – como Gitlab + CI, Jenkins, Trevis-CI, Bamboo e SonarQube.

Quando paro para pensar na quantidade de projetos que já participei e nas tecnologias envolvidas, tenho uma imensa satisfação, acompanhada de descrença. No dia-a-dia não vemos o quanto nos adaptamos, e quão rápido é o processo, por isso é legal parar vez ou outra para pensar no que já construímos.

Não consigo imaginar qual será o nome da minha função no futuro, mas espero ter uma lista ainda mais interessante de estudos e trabalhos realizados: que venham novas linguagens, patterns e cervejas.

CakePHP 3.0 – O Fim do Locale

 

A nova versão do meu framework favorito está em estágio avançado e trás uma infinidade de coisas legais.

Dentre as novidades, quero deixar uma dica rápida para um problema comum a qualquer um que não use data/decimais em formato dos EUA: até hoje, para o Cake 1.3 e 2.x eu utilizo o plugin Locale, que já falei a respeito aqui antes.

Com o CakePHP 3.0, o plugin é completamente desnecessário: o novo ORM é capaz de interpretar os dados enviados em formato local para o formato nativo da máquina, de forma transparente.

Você só precisa registrar que os tipos do ORM deve utilizar localização…

Diga ao seu ambiente qual seu locale (pode fazer isso no bootstrap.php):

ini_set('intl.default_locale', 'pt_BR');

Inclua as linhas abaixo no início do seu AppController:

use Cake\Database\Type;
// Habilita o parseamento de datas localizadas
Type::build('date')
 ->useLocaleParser()
 ->setLocaleFormat('dd/MM/yyyy');
Type::build('datetime')
 ->useLocaleParser()
 ->setLocaleFormat('dd/MM/yyyy HH:mm:ss');
Type::build('timestamp')
 ->useLocaleParser()
 ->setLocaleFormat('dd/MM/yyyy HH:mm:ss');
 
// Habilita o parseamento de decimal localizaddos
Type::build('decimal')
 ->useLocaleParser();
Type::build('float')
 ->useLocaleParser();

Pronto, os dados do seu formulário serão interpretados e convertidos antes de serem salvos.

Para alterar a validação de data, você deve usar algo assim:

$validator->add('birthday', 'valid', [
 'rule' => ['date', 'dmy'], // esse é o importante, onde você avisa que a data estará localizada
 'message' => __('Informe uma data válida')
 ]);

E em substituição ao LocaleHelper, você pode formatar suas datas com o método format disponível (já que o registro agora é um objeto), e no caso de float/decimal, você usa a lib Number.

use Cake\I18n\Number;
$data = $user->birthday->format('d/m/Y');
$salary = Number::format($user->salary);

E é isso, sem nenhum plugin, sua aplicação estará falando português (ou qualquer outra linguagem/localização que você deseje utilizar).

PHPMS Conf’14

banner de divulgaçãoÉ isso mesmo galerinha, seguindo bravamente a frente da organização, meu brother Marcelo Siqueira assumiu a responsa e juntamente com a SUCESU-MS está organizando a edição 2014 do nosso evento favorito: PHPMS Conf’14.

A grande novidade deste ano é que não vamos ficar preso a capital do estado, desta vez o evento ocorre em Dourados. Mas se você está em Campo Grande, tem ônibus grátis para os primeiros inscritos, que coisa linda não? O evento ocorre então dias 11 e 12 de Setembro de 2014, e a grade completa você confere na página dele.

Terei a honra de palestrar no sábado sobre a linguagem e tópicos relacionados (posto link para ela depois). Varias feras irão palestrar no evento como o Bruno PorKaria, Ricardo Coelho, Saulo Arruda, Alê Borba e o próprio Marcelo Siqueira. Imperdível.

Se quiser bater um papo, eu e quase toda a equipe da Radig estaremos lá nos dois dias.

Ainda da tempo de se inscrever, mas corra!

Até breve!