Escrevendo um livro digital como entrega contínua parte 2

Nesse artigo pretendo continuar a compartilhar um pouco da minha experiência de escrever um livro digital. Esse é o segundo artigo da série. O primeiro segue aqui.

Escolhendo a plataforma

Agora que já sabemos qual nosso assunto, foco e público alvo, só nos basta começar a escrever. E nesse momento você deve estar se perguntando qual melhor forma de fazer isso.

download-3

Eu não fiz uma pesquisa muito rebuscada sobre isso e acabei usando o primeiro que me foi apresentado. O leanpub é uma plataforma fantástica! Ela tem tudo que eu preciso e talvez você devesse dar uma chance a ela. Segue abaixo as coisas que acho bem relevante nela:

  • Você escreve em markdown e ela gera seus livros em PDF, Mobi (Formato pra Kindle) e ePub (Formato para maioria dos e-readers),
  • Ela pode exibir seus livros online na plataforma,
  • Você pode monetizar seus livros no Leanpub (você informa valor mínimo de contribuiçao, que pode ser zero), ele cobra uma porcentagem por cada “compra” e eu resgato o dinheiro usando paypal,
  • Você pode integrar com o Dropbox e Github para atualizar os arquivos markdown que serão usados para gerar seus livros,

Falando um pouco melhor sobre integração do Leanpub, eu gostei muito da possibilidade de manter meu livro no github. Isso pra mim foi crucial para eu de fato abrir o “código” do meu livro de forma mais fácil, ou seja, caso você deseje escrever um artigo novo no meu livro basta fazer um fork, atualizar e me mandar um PR no meu repositório.

Quando me cadastrei no Leanpub, ainda era de graça, mas hoje é um custo único de $99,00 por livro, que você paga no momento da criação do mesmo. Eu ainda acho que vale a pena, pois até o momento já arrecadei aproximadamente $500.

O Leanpub mantém o email das pessoas que baixam seu livro, ou seja, a cada vez que você atualizar o conteúdo eles podem ser notificados para baixar a versão mais nova e você pode inclusive informar no “Release Notes” o que tem de novidade nessa nova versão.

Resumindo, o leanpub pra mim tem sido uma ferramenta completa pra lidar com lançamento do meu livro.

Como opção gratuita ao Leanpub, temos o Papyrus:

screen-shot-2016-12-02-at-7-33-25-pm

Depois que descobri que o Leanpub se tornou pago, procurei uma opção sem custos e encontrei essa, mas ainda não utilizei para dar um bom feedback.

Caso você tenha usado o Papyrus e quiser nos ajudar, comente nesse artigo.

Porque meu livro é livre e pode ser baixado de graça

Quando comecei a escrever, pensei bastante sobre conhecimento aberto, preço do material e afins. Como falei no primeiro artigo, eu fiz de uma forma que não impactou exageradamente meu tempo livre e assim essa pressão por monetizar esse tempo gasto foi menor em mim.

Eu sei que nos trabalhadores vendemos a fatia do nosso tempo para viver nessa sociedade capitalista, mas quebrar essa lógica sempre que possível é um desafio gostoso que eu sempre que posso tentarei.

Me ajudou saber que nenhum dos escritores que escrevem livros técnicos ganharam dinheiro o suficiente para deixá-los “ricos”, mesmo aqueles que dedicaram bastante tempo diário, que poderia estar com suas crianças, pessoas companheiras, amigas e afins. Caso o dinheiro fosse grande o suficiente ele poderia viabilizar a “compra” de tempo no futuro, mas se nem isso é válido, qual motivo real de cobrar por livros digitais?

Alguns escritores me falaram que acham injusto pessoas que podem pagar não fazerem isso, mas meu contraponto é que pessoas que não podem pagar simplesmente não tem acesso aos livros pagos e o pior, as licenças proíbem compartilhamento para grupos de estudo, projetos em movimentos sociais e afins.

O meu maior objetivo na escrita do livro era compartilhar o que sei e me estabelecer como referência técnica no assunto. Qual melhor forma de fazer isso senão permitindo que meu livro circule da forma mais fácil e rápida possível?

Caso meu livro fosse completamente fechado eu fatalmente acabaria gastando uma boa fatia desse dinheiro obtido para impulsionar ele nas redes sociais e propaganda em sites. Sem contar que a maioria das pessoas que pensasse na possibilidade de escrever sobre meu livro, pensariam duas vezes, pois eles achariam que estaria colaborando financeiramente com alguém e não estaria ganhando nada em retorno. Infelizmente é assim que somos construídos para pensar no contexto dessa sociedade que “gira em torno” do dinheiro.

Porque eu permito que as pessoas ganhem dinheiro com meu livro

Um outro assunto polêmico é viabilizar na sua licença que ele possa ser usado comercialmente, ou seja, agora meu livro pode ser usado como base para um curso e o livro até ser usado como material didático, por exemplo. Tudo isso pode ser comercializado sem nenhum problema. Só tenho duas ressalvas:

  • A licença não pode ser modificada, ou seja, caso use meu livro, o que você modificou, adicionou ou afins deve ser liberado ainda livre,
  • Você deve mencionar que se baseou no meu material, citando eu como autor.

Eu faço isso por um motivo simples: As empresas que eu me incomodariam de usar meu material normalmente fazem isso mesmo em produtos fechados, pois eles tem força o suficiente para fazer isso sem sofrer consequências suficientes para incomodá-los. Sendo assim eu preferir que pessoas que precisam obter uma granam o façam comercializando meu livro.

Comercializar meu livro reforça a ideia que eu quero que mais pessoas tenham acesso a ele. Já pensou que massa seria alguém imprimir várias cópias do meu livro e lançar ele numa feira do livro no interior do Paraná? Eu nunca chegaria lá, mas uma pessoa motivada por ganhos financeiros fez isso e me ajudou bastante. Agora sou conhecido no interior do Paraná!

Possibilitar a comercialização é viabilizar que mais pessoas ajudem no projeto, pois sabem que poderão usar esse material para seu curso técnico, aula na faculdade ou afins, sem que isso inflija de alguma forma nenhuma lei. Não que infligir lei seja um problema para algumas pessoas (eu incluso), mas o ponto aqui é permitir e não negar.

Docker Global Mentor Week – Review

Oi Pessoal,

Gostaríamos de trazer hoje um apanhado geral do que foi o Docker Mentor Week esse ano. Quais as percepções dos participantes, conteúdo abordado, dentre muitas outras informações sobre esse grande evento sobre Docker.

Quem participou das edições no Rio de Janeiro, São Paulo, Goiânia e Gravataí, pôde ter a experiência de como é realizar um treinamento tão focado e ao mesmo tempo descontraído, podendo interagir com outros usuários de Docker que tiveram ou tem as mesmas dificuldades, dúvidas e soluções. Esse tipo de experiência reforça cada vez mais a ideia de comunidade aberta, onde todos são bem vindos e todos tem seu papel, sendo você um iniciante ou ainda alguém com uma bagagem maior de conhecimento nessa tecnologia.

Segundo Fernando Ike, um dos organizadores e mentors do evento em São Paulo, é possível descrever o evento como:
“Muito gratificante compartilhar um pouco da experiência com os outros e também aprender alguns truques novos sobre containers.”

Em todos os eventos notamos que o público era o mais variado possível, desde quem nunca tinha trabalhado com Docker, Devs, Ops, etc. E o mais interessante, e que ocorreu em quase todas as edições foi o caso do pessoal de desenvolvimento realizar trilhas de ops e vise-versa, o que acaba gerando ainda mais engajamento por ambas as partes.

Será que todo o mundo pensa da mesma forma?

Nós do MundoDocker não poderíamos ficar sem essa resposta, não é mesmo? ;). Para isso contamos com a ajuda do pessoal do Imasters, que estiveram presentes no evento que ocorreu em São Francisco, na Califórnia mesmo (Durante o DevTrip). O Matheus Moreira e o Romulo Scampini que participaram do DevTrip e foram até o evento na sede do Docker, resumiram a participação deles no evento como:

Romulo:
“Foi o meetup mais produtivo que já fui, pois normalmente em meetups só temos a apresentação de algum conteúdo, e levamos de lição de casa a prática do conhecimento obtido.
No Global Mentor Week, além de aprender pudemos colocar em prática todo o conhecimento obtido, e ainda tivemos o apoio de engenheiros especialistas.”

Matheus:
“Foi bem legal porque tinha um monte de mentores a nossa disposição pra tirar todas as duvidas que quissemos e ai adivinha os mentores eram os devs do core do Docker”.
#sortudos

Separamos algumas fotos dos eventos, em São Francisco.

21c93366-8b36-48c2-82b2-6a4a1d06e211 d732c3d3-b7bc-4813-b33b-3efbc250090b 337e3dc4-894d-4c4b-8e27-a7f2e02f8355 MentoRWeek-Geral b411fe2a-e264-4022-89da-543159351aff f397e6c4-4ed9-479d-b039-1cdba1e296ea fc0214c9-7afe-4db5-893e-0f7465c09f9d fb556af0-e6aa-4de2-a5f8-aba793f82d9b ced00bc4-dc4c-4530-8e4c-a434a96a4f5d 94f01231-2207-444a-b2c9-0eb651d01efa

Em São Paulo:

600_456185871 600_456185886 600_456185900 600_456185926 600_456185944 600_456214932 highres_456269914
Fonte: https://www.meetup.com/Docker-Sao-Paulo/events/235267786/

Em Goiânia:

803711244_141043_6802631868420469985 803712332_139739_11676414205401214099 803729920_104052_816614692202900550 803730915_103105_18360553536299592442

Estivemos presente no evento que ocorreu na sede da Umbler em Gravataí no último sábado (26/11), e claro que registramos tudo :). Foi uma experiência incrível participar como Mentors desse evento, nem tudo foi perfeito, mas a troca de conhecimento e networking foram demais, foi muito gratificante poder ajudar a comunidade e dar nossa contribuição para o esclarecimento de dúvidas e passagem de conhecimento. Vamos ver umas fotos?

dscn2530 dscn2536 dscn2542 dscn2549 dscn2557 dscn2558 dscn2586 dscn2599 dscn2627 dscn2629 dscn2638

Quer contribuir também? Então fique ligado nos meetup de Docker de sua cidade, não sabe onde tem? Comenta ai e vamos achar um o mais próximo de você.

Acabamos por aqui, e como sempre, nos ajude divulgando o blog 😉

Grande abraço a todos!

Docker Global Mentor Week

Olá Pessoal!

Para quem não viu ainda, na quinzena final de novembro será realizado uma das maiores ações do Docker para treinamento e troca de experiência entre seus usuários, esse evento foi chamado de Docker Global Mentor Week.

Essa é uma ação coordenada diretamente pela equipe do Docker com a ajuda dos organizadores dos grupos de meetup docker pelo mundo, o objetivo é simples: Dar treinamento técnico de alto nível de maneira abrangente e uniforme, ou seja, o conteúdo abordado em Singapura, é o mesmo no México, na Inglaterra e claro aqui no Brasil :). SIM teremos esse evento ocorrendo aqui no Brasil também, vou deixar abaixo os links desses eventos para que você possa se inscrever.

Mas afinal, esse é apenas mais um encontro do grupo de Meetup? Sim e Não, sim porque os canais utilizados para divulgação desse evento são os grupos de meetup e não porque esse evento tem conteúdo definido pela equipe do Docker e é repassado através de seus Mentors, que são pessoas ativas na comunidade docker e que auxiliam na divulgação de conteúdo, disseminação da tecnologia e enriquecimento da comunidade local. Você encontrará em cada evento no mínimo 1 Mentor, então não deixe de tirar suas dúvidas com ele(s).

Ok Cristiano, gostei, mas e valor? Bom, isso é um problema, por ser um evento oficial realizado no mundo inteiro, o valor para realizar esse treinamento é……. ZERO, sim é evento totalmente de graça, e agora, qual a sua desculpa? 😉

E o conteúdo?

A equipe do Docker definiu uma série de trilhas que podem ser abordadas durante o evento, é claro que todas é impossível de serem realizadas num período de 3 a 4 horas, então cada usuário defini o que deverá ver no evento, e os mentor auxiliaram na execução do treinamento e esclarecimento de dúvidas. Os conteúdos em si vão do básico (criação de containers, Dockerfile, etc) até o avançado (orquestração, serviços, rede, volume, etc).

Onde serão realizados aqui no Brasil?

Temos por enquanto, 4 eventos confirmados aqui no Brasil, são eles:

Docker Global Mentor Week – Goiania – 14/11

http://www.meetup.com/pt-BR/Docker-Goiania/events/234750966/?eventId=234750966

 

Docker Global Mentor Week – Rio de Janeiro  – 16/11

http://www.meetup.com/pt-BR/Docker-Rio-de-Janeiro/events/234784863/?eventId=234784863&chapter_analytics_code=UA-48368587-1

 

Docker Global Mentor Week – São Paulo – 19/11

https://www.meetup.com/pt-BR/Docker-Sao-Paulo/events/235267786/?eventId=235267786&chapter_analytics_code=UA-48368587-1

 

Docker Global Mentor Week – Porto Alegre – 26/11

http://www.meetup.com/pt-BR/Docker-Porto-Alegre/events/235451287/?eventId=235451287&chapter_analytics_code=UA-48368587-1

 

O MundoDocker estará presente? Claro! Vamos auxiliar o pessoal do grupo de Porto Alegre!

 

Era isso por hoje pessoal, ajude você também divulgando os eventos e claro o blog 🙂

 

Grande abraço!

Uma analise do texto “Docker in Production: A History of Failure”

Um texto (em inglês apenas) foi lançado na internet e isso causou um certo alvoroço na comunidade, pois já pelo título é bem impactante “Docker em produção: Uma história de fracasso”.

Pelo título eu imaginei que seria uma extensa e detalhada explicação sobre o que deu errado para eles, e apresentar os caminhos que eles seguiram para contornar, assim como demonstrar em qual momento foi impossível continuar.

Pra contextualizar, quero deixar claro que fui ler o texto realmente pensando em obter dados para me ajudar a trabalhar em projetos futuros. Coisas que eu poderia aprender previamente e ver se tinha soluções alternativas, mas infelizmente não foi isso que vi, ao menos não na maioria do texto.

Pra resumir bem, o texto tem um tom bem irônico e é claramente o desabafo de uma equipe frustada com o uso da tecnologia, que na minha opinião foi usada de forma equivocada e até mesmo sem uma pesquisa mais profunda sobre as possíveis soluções e contramedidas.

Pra organizar a minha argumentação, vou separar elas por tópicos do texto.

Docker Issue: Breaking changes and regressions

Nesse capítulo ele fala basicamente de problemas de retrocompatibilidade, que existe mesmo, mas não apresenta quais os problemas reais ele encontrou na regressão, apenas tocou superficialmente em redes, mas sequer mostrou um caso real.

No Bônus, faltou explicar que o Docker não foi removido do repositório do Debian, ele apenas não entrou na versão nova. Não achei o motivo ainda, mas arrisco dizer que a velocidade de lançamento do Docker não funciona bem com o esquema de empacotamento do repositório estável do Debian.

Aqui o link da situação do pacote no Debian: https://tracker.debian.org/pkg/docker.io.

O Docker oferece repositórios próprios com pacotes Debian, que aparentemente é seguro e a atualização é constante.

Docker Issue: Can’t clean old images

Isso é realmente chato e precisa ser corrigido, mas tem uma solução da Spotify que pode ajudar: https://github.com/spotify/docker-gc

Linux 3.x: Unstable storage drivers

Nesse capítulo ele fala de como os drives AUFS do kernel tem falhas e como causa kernel panic no sistema, ou seja, isso tem muito mais a ver com as versões do kernel que ele usa nas distribuições dele do que o Docker em sí.

Linux 4.x: The kernel officially dropped docker support

Ele explica que o AUFS não é mais suportado nos kernel 4.x e faz uma afirmação falsa:

“How does docker work without AUFS then? Well, it doesn’t.”

Funciona sim desde 2015, inclusive existem artigos falando para não usar mais AUFS. Achei esse no google na primeira página de busca: https://sthbrx.github.io/blog/2015/10/30/docker-just-stop-using-aufs/

The debacle of Overlay

Ele fala que para adotar o Docker você precisa constantemente modificar seu ambiente host, com atualização de kernel e afins. Infelizmente isso é verdade, mas acho que isso se dá mais por conta da velocidade como tudo foi construído nesse curto espaço de tempo. Em todo caso, não acredito que isso seja um problema, pois estamos em um momento de servidores descartáveis, ou seja, refazer um outro host com as configurações ideais, testar ele e então subir os containers nesse novo nó não deveria ser algo custoso para uma empresa moderna.

Bonus: The worldwide docker outage

Nesse capítulo ele fala sobre um grande downtime que o serviço do Docker gerou na instalação dos pacotes, pois a chave estava errada. Infelizmente isso é verdade e foi corrigido com uma certa lentidão. Ponto negativo total mesmo.

Docker Registry Issue: Abandon and Extinguish

Nesse capítulo ele fala como a v1 pra v2 do registry foi completamente reconstruída e ao abandonar a v1 o Docker não fez ofereceu mecanismos para uma migração, o que é mentira, pois existe ferramenta para auxiliar a migração: https://github.com/docker/migrator

Docker Registry Issue: Can’t clean images

Isso de fato é um problema, que tem bug aberto até hoje: https://github.com/docker/docker-registry/issues/1004

Docker Issue: The release cycle

O texto fala muito sobre falta de retrocompatibilidade, mas os poucos exemplos que ele apresentam são fracos ou inexistentes.

Banned from the core

Nesse capítulo ele descreve que aplicação erlang, que é core para o ambiente deles, não funcionou bem no Docker por alguns motivos e eles então concluíram que docker não está pronto para nada crítico. Constatação feita com base em uma única experiência.

Se você olhar esse comentário, verá que existe uma outra pessoa falando que roda erlang sem problemas no Docker.

Banned from the DBA

Nesse texto ele descreve o porque não usou Docker como banco de dados, mas novamente sem detalhar o suficiente para podermos inclusive aprender com a falha deles.

Eles provavelmente não usaram volumes para armazenar os dados, pois ele descreve o comportamento das camadas das imagens Docker, que de fato não foram pensadas para armazenar dados variáveis dentro dos containers.

É necessário utilizar volumes para esse tipo de ação.

Para quem quiser saber um pouco mais sobre MySQL no Docker, vejam esse artigo: http://mysqlserverteam.com/mysql-with-docker-performance-characteristics/

Outros capítulos

Ele repete um pouco o que já foi dito e deixar a ironia ficar ainda mais pesada, colocando gifs engraçados para reforçar o clima cômico da coisa.

Em resumo acho esperado que o Docker não funcione bem para a maioria dos casos, pois como já foi muito dito em vários espaços que o Docker NÃO É UMA BALA DE PRATA, ou seja, é possível sim que não será adequado para todos os casos, mas dai com base em uma experiência ruim, que muitas vezes foi fruto de uma má implementação inclusive, dizer que o Docker não está pronto para produção chega a ser hilária.

Novamente, juro que não tinha intenção de ler o texto para formular uma resposta para o artigo, mas foi inevitável dado a tantas pessoas que me marcaram para eu me posicionar sobre o ocorrido.

Agradecimentos

Quero agradecer a Somatório, que sempre me ajuda nas revisões dos artigos e Fukui por ter me marcado em uma postagem e assim me estimulou a de fato divulgar esse material.

Desenvolvimento com Docker

Oi Pessoal,

A intenção hoje é trazer para vocês um conteúdo mais voltado para as equipes de desenvolvimento, ilustrando como é possível automatizar alguns pontos do seu trabalho utilizando Docker e como ele tornará as equipes mais eficientes naquilo que precisam ser: Entrega de resultado, óbvio.

Neste exemplo abordaremos um pouco sobre como é fácil montar um ambiente de desenvolvimento local utilizando nginx, php e mysql, este será, é claro, o primeiro passo em seu caminho para utilizar docker no seu dia-a-dia. Bom, chega de conversa, mãos a obra :).

Obviamente, nesse post não abordaremos como você deve instalar o Docker, para isso temos esse post que vai lhe ajudar muito, veja também que vamos usar nesse ambiente o docker compose, e claro, levamos em consideração que você está utilizando Docker em seu host de desenvolvimento, seja ele Windows, Linux ou Mac, e não no servidor de produção.

A receita

Ok, atendo a esses requisitos, e agora Cristiano, o que faço?

Primeiramente você deve criar, dentro de seu diretório de trabalho um arquivo para que o Docker Compose possa dar inicio a sua stack, e como você viu no post sobre o docker compose, o formato dele é de um arquivo do tipo Yaml, vamos utilizar a versão 2 do Docker Compose, que trás algumas melhorias, mas que difere um pouco na sintaxe, veja o exemplo que vamos usar nesse post:

# Utilizando sintaxe da versão 2:
version: '2'

volumes:
 database_data:
 driver: local

services:
###########################
# Container Web (Nginx)
###########################
 nginx:
 image: nginx:latest
 ports:
 - 8080:80
 volumes:
 - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
 volumes_from:
 - php

###########################
# Container PHP
###########################
 php:
 build: ./php/
 expose:
 - 9000
 volumes:
 - .:/var/www/html

###########################
# Container de banco de dados (MySQL)
###########################
 mysql:
 image: mysql:latest
 expose:
 - 3306
 volumes:
 - database_data:/var/lib/mysql
 environment:
 MYSQL_ROOT_PASSWORD: senha
 MYSQL_DATABASE: projeto
 MYSQL_USER: projeto
 MYSQL_PASSWORD: projeto

A grande diferença entre a versão 1 e 2 do Docker Compose está relacionado a utilização de algumas tags especiais, entre elas: services e volumes. Essas tags obviamente foram adicionadas por um bom motivo, e esse motivo é você poder ter múltiplos serviços dentro de uma stack, mas ter a flexibilidade de escalonar ou modificar atributos de um único serviço dentro de sua stack, sem precisar mexer em toda ela, isso é muito bom, não?

Outro motivo está relacionado ao uso de volumes para a persistência de dados, você não quer perder todo seu trabalho se seu container for acidentalmente removido, certo? E uma das grandes vantagens nesse caso é que você pode especificar um driver para volume que seja persistente não apenas em seu host, mas distribuído em um cluster de volume, explicamos um pouco sobre isso aqui e aqui, em nosso exemplo vamos usar local mesmo.

Inside

Note que nas linhas que referem-se ao container PHP, não há referência para imagem, o motivo é simples, faremos o build da imagem no mesmo momento de subir a stack, ou seja, quando rodarmos o docker-compose up -d o docker realizará o build do Dockerfile que encontra-se dentro da pasta php e utilizará a imagem gerada por esse build para iniciar o container php.

Mas e o que tem nesse Dockerfile? Calma, não íamos deixar isso de lado, veja abaixo como é esse Dockerfile:

FROM php:7.0-fpm 
RUN docker-php-ext-install pdo_mysql \ 
&& docker-php-ext-install json

Em nosso lab, usaremos como base a imagem do php 7.0 em fpm, e baseado nisso instalaremos algumas extensões, para que posteriormente possamos utilizá-las. Note que não é algo muito elaborado, mas poderia, caso você tenha essa necessidade. Na imagem em questão, há um binário responsável pela instalação das extensões, que é o docker-php-ext-install, ele realiza o download e instalação da extensão e sua ativação no php.ini global.

Note também que definimos expor a porta 9000 do container php para que o container do serviço web possa acessa-lo e assim processar as requisições. O arquivo de configuração do servidor web deve ser assim:

server {

 # Set the port to listen on and the server name
 listen 80 default_server;

 # Set the document root of the project
 root /var/www/html/public;

 # Set the directory index files
 index index.php;

 # Specify the default character set
 charset utf-8;

 # Setup the default location configuration
 location / {
 try_files $uri $uri/ /index.php;
 }

 # Specify the details of favicon.ico
 location = /favicon.ico { access_log off; log_not_found off; }

 # Specify the details of robots.txt
 location = /robots.txt { access_log off; log_not_found off; }

 # Specify the logging configuration
 access_log /var/log/nginx/access.log;
 error_log /var/log/nginx/error.log;

 sendfile off;

 client_max_body_size 100m;

 # Specify what happens when PHP files are requested
 location ~ \.php$ {
 fastcgi_split_path_info ^(.+\.php)(/.+)$;
 fastcgi_pass php:9000;
 fastcgi_index index.php;
 include fastcgi_params;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 fastcgi_param APPLICATION_ENV development;
 fastcgi_intercept_errors off;
 fastcgi_buffer_size 16k;
 fastcgi_buffers 4 16k;
 }

 # Specify what happens what .ht files are requested
 location ~ /\.ht {
 deny all;
 }
}

Veja que na opção: fastcgi_pass definimos como php:9000 ou seja, o nome do container na porta que expomos no docker-compose. Lembrando que você pode ter acesso a stack completa baixando esse exemplo de nosso repositório no gitub.

Para o Container de banco de dados, utilizamos a imagem oficial do MySQL, definimos apenas os dados de acesso e nome do banco de dados que gostaríamos de criar, e claro definimos um volume onde serão persistidos os dados desse banco.

Agora finalmente basta você subir a sua stack, para isso:

docker-compose up -d

Depois do docker compose realizar todo o processo de build da sua stack, basta você acessar o ambiente web pelo endereço: http://localhost:8080 e você terá como retorno a pagina inicial do seu site (que em nosso teste é apenas um phpinfo).

Próximos passos

 Bom, agora você só precisar criar :), quando você ficar alguma modificação na pasta onde está o projeto, elas serão refletidas no site, ou seja, modificando o seu index.php será alterado no site que está rodando nos container, isso porque mapeamos a pasta local como sendo a public do servidor web/php. O mais interessante dessa abordagem é poder movimentar esse ambiente para onde quiser, imagem que isso tudo faz parte de seu código versionado no git, basta chegar em basta e rodar um git clone do seu projeto (ou pull) e você terá o mesmo ambiente de desenvolvimento.

Gostou? Não gostou? Tem dúvida? Deixa nos comentários que vamos conversando! E como sempre, nos ajude divulgando o blog.

Grande abraço!

Escrevendo um livro digital como entrega contínua parte 1

Objetivo

A ideia dessa série de artigos é compartilhar a minha experiência de escrever um livro digital sem esforço sobre-humano, ou seja, você não se sentirá necessariamente pressionado a depender de um resultado financeiro do seu livro, pois a ideia é que ele não impacte muito nas suas horas livres.

download-2

No meu caso a falta de tempo foi fruto de uma má distribuição e priorização das minhas atividades, e depois que organizei previamente minhas tarefas diárias e assim eu consegui realizar mais atividades no fim do dia. Eu não vou aprofundar nesse assunto, pois já existem diversas técnicas de como fazer isso disponível na internet.

Um outro assunto que pretendo falar é sobre a entrega contínua do material, pois eu entregava um livro atualizado a cada artigo produzido e assim ter um rápido retorno de críticas sobre o produto.

Com esse rápido retorno é possível inclusive você mudar a estrutura do conteúdo apresentado. Exemplo: Caso seu público já domine o conteúdo que você está construindo, você pode aumentar o nível nos próximos artigos.

Escolhendo o tema do livro

Antes de escrever, eu precisei decidir qual assunto seria tratado no livro. Não apenas superficialmente falando (Ex. Docker, NodeJS e afins), pois é necessário saber para qual foco será esse material.

Utilizando o exemplo do Docker, podem ser criados diversos livros, cada um com um foco distinto. No meu caso eu fiz um focado para o desenvolvedor, ou seja, a minha ideia era explicar o mínimo necessário para ele entender o que estava utilizando e então explicar como uma aplicação simples escrita em python deveria ser modificada para ser “Dockerizada”.

Escolher o foco é importante, inclusive para você saber se seu livro é relevante ou não, pois nada é mais frustrante do que dedicar tempo para algo e depois descobrir que já tem um produto igualzinho pronto. Não quero com isso desestimular que você escreva livros iniciantes, caso já existam vários para esse público.

Não menospreze conteúdo básico

A maioria das pessoas normalmente está sempre começando a aprender algo novo, sendo assim dedique um tempo para trabalhar em um conteúdo bem estruturado para transmitir de forma didática, simples, direta e com exemplos práticos o que você sabe.

A maioria do conteúdo que tenho lido pela internet são ótimos materiais de referência e consulta, mas normalmente não são bons para quem tá começando “do zero”. Se você realmente está interessado em compartilhar o que você sabe, para alguém que realmente não sabe nada do assunto, dedique um pouco de tempo para organizar um conteúdo que apresente gradualmente novos conceitos e ideias, sempre contextualizando termos e paradigmas novos. Evite achar que o leitor tem conhecimento intermediário em alguma parte do seu conteúdo técnico.

Organize seu conteúdo em um índice

Antes de começar a escrever qualquer artigo eu fiz um índice e me preparei psicologicamente para mudá-lo no futuro, caso necessário. E ele mudou bastante.

Ordenei os assuntos pensando no meu público alvo, ou seja, apresentei cada conteúdo e termo novo de forma gradual. Isso quer dizer que você deve pensar as dependências entre os capítulos. Exemplo: Caso seu público seja iniciante, e você precise falar de comunicação entre contêineres, é importante falar sobre redes no docker e afins.

Nos próximos artigos dessa série falarei mais sobre a estruturação de conteúdo e algumas dicas de como usar bem seu tempo para produzir de forma constante e não perder o ritmo.

 

Lançamento da versão estável do livro “Docker Para Desenvolvedores”

É com grande prazer que anuncio a versão estável, também conhecida como 1.0, do livro “Docker para Desenvolvedores”. Para baixar acesse esse link:

https://leanpub.com/dockerparadesenvolvedores

Entenda como versão estável a reunião do conteúdo mínimo para entendimento do funcionamento básico do Docker para um desenvolvedor de código que nunca interagiu com essa tecnologia de virtualização usando container. Essa versão trata também sobre as melhores práticas para construção de imagens docker, através da utilização de exemplos e evolução de uma base de código simples usada para ilustrar cada boa prática.

O livro segue a filosofia do conhecimento livre, ou seja, ele está licenciado em Creative Commons e sua exigência é apenas para citar o autor do conteúdo, isso significa que você pode até mesmo comercializar o material sem me solicitar permissão. E eu queria muito saber que as pessoas estão fazendo bom uso dele.

A licença é muito mais que apenas explicitar sobre como se pode fazer uso do material. Meu interesse com ela é criar uma comunidade ao redor da construção desse conhecimento, ou seja, caso você encontre problemas no livro, não hesite em registrar um bug ou envie um patch/pull request caso tenha tempo/disposição para tal. Segue abaixo o repositório do livro:

https://github.com/gomex/docker-para-desenvolvedores

A grande vantagem de fazer um livro digital é a possibilidade de atualização contínua do material. Sendo assim a minha proposta é manter o livro atualizado a medida que o Docker for adicionando/modificando/removendo elementos.

Se você está ansioso pela versão impressa. Fiquem atentos que logo virei com novidades.

Docker – Device mapper

Olá pessoal,

No primeiro post da série falamos sobre AUFS e hoje vamos falar um pouco sobre Device Mapper.

Origem

No começo o Docker era suportado apenas em distribuições Ubuntu, Debian e usavam AUFS para o seu armazenamento. Depois de algum tempo o Docker começou a se popularizar e as pessoas começaram a querer utilizar Docker com RedHat, porêm o AUFS era suportado apenas em sistemas (Debian,Ubuntu).

Então os engenheiros da Redhat baseados no código do AUFS decidiram desenvolver uma tecnologia própria de armazenamento baseado no já existente “Device mapper”. Então os engenheiros da RedHat colaboraram com o “Docker inc” para contribuir com um novo driver de armazenamento para containers. Então o Docker foi reprojetado para fazer a conexão automática com o dispositivo de armazenamento baseado em Device Mapper.

Layers

O Device Mapper armazena cada imagem e container em seu disco virtual, esses discos virtuais são dispositivos do tipo Copy-on-Write no nível de bloco e não a nível de arquivo. Isso significa que ao invés do Device Mapper copiar todo um arquivo para o seu dispositivo, ele vai copiando por blocos o que o torna muito rápido comparado ao AUFS. No processo de criação de uma imagem com o Device Mapper é criado um pool e em cima desse pool é criado um dispositivo base que é a partir dele que as imagens são construídas, a partir dai temos as imagens base do Docker que a cada modificação vão criando camadas de snapshots a cima da camada anterior. Conforme a imagem abaixo:

https://docs.docker.com/engine/userguide/storagedriver/images/two_dm_container.jpg

Read

Quando um container deseja ler algum arquivo que está nas camadas anteriores o Device Mapper cria um ponteiro na camada do container referenciando a camada da imagem onde possui esses dados colocando transferindo esse bloco para a memória do container.

Write

Quando o Docker faz uma alteração no arquivo utilizando Device Mapper esse arquivo é copiado apenas o que sera modificado cada bloco de modificação copiado é de no máximo 64KB. Por exemplo na escrita de um arquivo de 40KB de novos dados para o container o Device Mapper aloca um único bloco de 64KB para o container, caso a escrita seja de um arquivo maior que 64KB então o Device Mapper aloca mais blocos para realizar essa gravação.

O Device Mapper já é padrão nas em algumas distribuições do linux como:

  • RedHat/Centos/Fedora
  • Ubuntu 12.04 e 14.04
  • Debian

Docker e Device Mapper

O Device Mapper atribui novos blocos para um container por meio de uma operação chamada “Allocate-on-Demand”, isso significa que cada vez que uma aplicação for gravar em algum lugar novo dentro do container, um ou mais blocos vazios dependendo do tamanho de gravação terão que ser localizados a partir do pool mapeado para esse container. Como os blocos são de 64KB então muitas gravações pequenas podem sofrer com problemas de performance, pois acaba causando lentidões nas operações. Com isso aplicações que gravam arquivos pequenos sequencialmente podem ter performance piores com Device Mapper do que com AUFS.

Legal né? Se gostou nos ajude divulgando o blog.

Grande abraço!

 

Docker – AUFS

Olá pessoal,

AUFS foi o primeiro controlador de armazenamento em uso com Docker, como beneficio tem uma história longa com Docker. É muito estável, tem grandes implementações no mundo real e possui forte apoio da comunidade, o AUFS possui diversas características que acabam o tornando uma boa escolha para uso com Docker. Entre elas estão:

  • Tempo de inicialização do container rápido
  • Uso eficiente de armazenamento
  • Uso eficiente de memória

Apesar de ter uma ampla capacidade de caracteristicas com Docker, algumas distribuições não possuem suporte ao AUFS, pois ele não está incluído na linha principal do Kernel Linux, no caso do RHEL não é suporte AUFS.

Os tópicos seguintes demonstram algumas características do AUFS e como ele se relaciona com o Docker:

 

Layers de Imagens:

AUFS é um sistema de unificação de arquivos, isso quer dizer que ele leva vários diretórios em um único host linux, colocando um sobre o outro e fornece uma visão unificada desses arquivos para conseguir isso o AUFS usa uma união de montagem.

O AUFS driver de storage do Docker implementa Layers de imagens utilizando usando a união do sistema montado. Abaixo podemos ver um exemplo de Layers, onde para o cliente é apresentado a união de todas elas:

 

layer1

 

Utilizando arquivos:

O Docker utiliza a tecnologia de “AUFS CoW”  para conseguir compartilhar a imagem e minimizar o uso de disco. Como o AUFS trabalha em nível de arquivos então todos os dados são copiados por inteiros para a camada superior mesmo que modificando uma pequena parte do arquivo, isso faz com que dependendo do tamanho de arquivo que será copiado acabe penalizando um pouco o desempenho do container, pois um arquivo muito grande demorará algum tempo para que seja copiado. Ou também a imagem possui uma grande quantidade de camadas e o arquivo que você deseja utilizar está na primeira camada da imagem.

A ordem de procura é de cima para baixo, então caso seja a primeira vez que o usuário irá utilizar aquele arquivo, então o Docker vai procurar esse arquivo nas suas camadas abaixo e copiar todo o seu conteúdo para a camada gravável do container. Porém o arquivo só é copiado na primeira vez, após isso o esse arquivo já está na ultima camada então todas as demais operações são rápidas.

Deletando arquivos:

O driver do AUFS exclui um arquivo de dentro do container colocando um arquivo whiteout na camada gravável do container. O arquivo whiteout obscurece a existência do arquivo nas camadas inferiores de imagem:

 

 

layers2

 

 

Você pode adicionar o driver AUFS no seu daemon docker editando o arquivo de conf do docker e adicionando:

DOCKER_OPTS="--storage-driver=aufs"

systemctl restart docker

 

Então ta pessoal esse é nosso primeiro post dessa série que vai mostrar para vocês os drivers de armazenamento nativos do Docker.

 

MundoDocker – Eventos

Oi Pessoal,

Hoje o post é rápido, apenas para trazer a vocês nossa experiência no TcheLinux Caxias do Sul. Para quem nos acompanha nas rede sociais, ficou sabendo que iriamos participar de mais um edição do TcheLinux (um dos maiores eventos de tecnologia open source do Rio Grande do Sul), dessa vez em Caxias do Sul, na serra gaúcha.
O evento estava muito bem organizado, e o lugar não poderia ser melhor, com infraestrutura suficiente para atender os participantes, sem falar na localização. Com a ajuda de alguns amigos, conseguimos alguns registro fotográficos do evento, veja:

tchelinux-foto71 tchelinux-foto61 tchelinux-foto51 tchelinux-foto41 tchelinux-foto31 tchelinux-foto21 TcheLinux-Caxias tchelinux-foto10 tchelinux-foto11 tchelinux-foto12

A nossa contribuição ao evento foi com uma palestra: Escalonando o mundo com Kubernetes, como o Google sobrevive. Essa apresentação teve como objetivo mostrar aos presentes como o Kubernetes funciona, como ele é utilizado dentro do Google e como você utiliza ele sem nem saber 🙂 . Compartilhamos a apresentação em nosso Slideshare, para você, que não estava no evento, possa ver um pouco sobre o que levamos ao evento:

Escalonando o mundo com kubernetes from Mundo Docker

Gostaríamos de agradecer ao TcheLinux pela oportunidade e a Ftec que disponibilizou o local para o evento. Por hoje era isso, grande abraço! Ahhh e nos ajude divulgando o blog 😉

Docker Overlay

Oi Pessoal,

Como vimos nesse post, é possível utilizar plugins diversos para resolver o desafio da rede, e mostramos nesse post um pouco da teoria de como usar o driver de overlay, hoje queremos mostrar isso na prática, e para isso, nada melhor do que colocar a mão na massa, certo?  Claro, mas antes precisamos entender um pouco de teoria, e lá vamos nós.

Se você estiver utilizando o Swarm, não é necessário configurar um serviço de chave-valor externo, pois o próprio Swarm faz o controle e persistência das informações de rede que você utiliza. E você deve ter cuidado, pois se quiser utilizar o Overlay com um serviço externo de chave-valor, o modo de cluster via Swarm fica impossibilitado.

Veja abaixo uma tabela com algumas informações relevantes sobre o funcionamento do Overlay:

Protocolo Porta Descrição
udp 4789 Data plane (VXLAN)
tcp/udp 7946 Control plane

Ou seja, você deve cuidar para que em seus firewalls essas portas estejam liberadas, caso contrario a comunicação entre os nós não ocorrerá, o que impossibilitará o funcionando do Overlay.

Veja abaixo os principais parâmetros que você deve ter atenção:

Opção Descrição
--cluster-store=PROVIDER://URL
Endereço do seu servidor/serviço de chave-valor
--cluster-advertise=HOST_IP|HOST_IFACE:PORT
IP ou interface do host que será utilizado para comunicação do cluster
--cluster-store-opt=KEY-VALUE OPTIONS
Configuração opicional, onde é possível definir regras de monitoramento dos hosts e validação TLS

Ok Cristiano, entendi tudo isso, mas como vamos testar, qual será o ambiente de laboratório que vamos seguir? Vamos lá, para exemplificar como será o ambiente que vamos montar, segue abaixo uma imagem onde ilustra o funcionamento do Docker com o serviço de chave-valor, todos os hosts consultam esse serviço para identificar quais redes existem e qual bloco/ip deve ser alocado por container. Veja:

Engine on each host

Vamos colocar a mão na massa?

Dependências/Configuração

Você deve ter um serviço de chave valor, no qual o Docker persistirá as informações de rede que você criar, em nosso lab utilizamos o Consul dentro de um container Docker, rodando em um server a parte dos que participarão do ambiente multi-host, para isso executamos:

[root@consul ~]# docker run -d  -p "8500:8500"  -h "consul"  progrium/consul -server -bootstrap

Dessa forma iniciamos um container com Consul, mapeando a porta 8500 do host para o container, ou seja, para ter acesso ao serviço do Consul basta acessar ip-do-host:8500. Agora vamos ao nosso ambiente de Docker.

Nos hosts de Docker (obviamente você já tem o Docker instalado, mas se quiser saber como instalar, veja esse post 😉 ) você precisará configurar o daemon para consultar o Consul e buscar as informações de rede, em nosso laboratório utilizamos o CentOS, com isso, o arquivo a ser modificado é o: /lib/systemd/system/docker.service, e deixamos da seguinte forma:

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock --cluster-advertise=eth0:2376 --cluster-store=consul://ip-do-consul:8500
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process

[Install]
WantedBy=multi-user.target

Feito isso, basta reiniciar o serviço e seguirmos para o próximo passo.

Utilização/Testes

Agora que você já definiu um serviço de chave-valor a ser consultado, basta você criar a sua rede com o driver Overlay, para isso:

[root@docker01 ~]# docker network create --driver overlay rede1

Você pode definir ainda qual o bloco de ip que deseja para essa rede, caso não faça essa definição, o Docker associará um bloco automaticamente para você. Fácil certo? Basta testarmos, para isso vamos validar em todos os hosts se ambos estão visualizando a mesma rede, execute esse comando em qualquer outro host:

[root@docker01 ~]# docker network ls

Será retornando algo como isso:

NETWORK ID          NAME                DRIVER
64507d0be843f        rede1               overlay
d0bdae8fbe7bd        bridge              bridge
1c0eb8f68962d        none                null
3412c2496d0eb        host                host
697102a22e8d2        docker_gwbridge     bridge

 Vamos utilizar essa rede, crie os containers em pelo menos 2 hosts, informando essa nova rede, veja:

[root@docker01 ~]# docker run -it --net=rede1 centos /bin/bash

Agora basta pingar ou acessar os serviços entre os containers que estão nessa mesma rede.

Dessa forma você pode definir uma rede diferente por grupo de containers, e pode ainda isolar essas redes utilizando o método VXLAN, para isso deve passar como parâmetro na criação da rede o seguinte argumento: –opt “com.docker.network.driver.overlay.vxlanid_list=257″, esse parâmetro fará com que essa rede receba uma vlan, ou seja, todo o trafego direcionado a essa rede receberá uma identificação, impossibilitando que outros containers que não estejam nessa vlan tenha acesso a esse trafego. 

Legal né? Se gostou nos ajude divulgando o blog.

Grande abraço!

Nova Vagrant BOX com CentOS 7.2.1511 e GitLab CE 8.12.0

Divulgando nova box CentOS 7.2 com GitLab CE 8.12.0 no atlas. Agora fica mais fácil testar a última versão do Gitlab com o menor esforço possível :)

1. Instalando a box

Se você usa vagrant 1.8.x para fazer download da box digite

vagrant box add gutocarvalho/centos7x64-gitlab-ce

Crie um diretório para o projeto

mkdir centos7-gitlab-ce; cd centos7-gitlab-ce

Crie um arquivo Vagrantfile no diretorio com o conteúdo abaixo

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.hostname = "gitlab.hacklab"
  config.vm.box = "gutocarvalho/centos7x64-gitlab-ce"
  config.vm.network "private_network", ip: "192.168.250.44"
  config.vm.provider "virtualbox" do |virtualbox|
    virtualbox.customize [ "modifyvm", :id, "--cpus", "1" ]
    virtualbox.customize [ "modifyvm", :id, "--memory", "2048" ]
    virtualbox.gui = true
  end
  if Vagrant.has_plugin?("vagrant-cachier")
    config.cache.scope = :box
  end
end

Inicie o projeto

vagrant up

Acesse a vm

vagrant ssh

Acesse o GitLab

http://192.168.250.44   

2. Refs

Para acessar a box no atlas

https://atlas.hashicorp.com/gutocarvalho/boxes/centos7x64-gitlab-ce   

O repo git com o código para build da box

https://gitlab.com/gutocarvalho/packer-centos-gitlab

É isso, divirta-se.

[s]
Guto

Vagrant 1.8.5 ssh retrying bugfix

O Vagrant 1.8.5 tem um bug crítico em guests linux, o vagrant simplesmente não consegue terminar o vagrant up por causa de um bug na geração do arquivo authorized_keys que contém as chaves permitidas para acesso ssh por chaves no guest. O problema é que o vagrant está gerando o arquivo com a permissão errada e o subsistema ssh — neste casos — ignora o arquivo por questões de segurança.

Você provavelmente está tendo uma saíde similar após atualizar para o 1.8.5

centos: Waiting for machine to boot. This may take a few minutes...
    centos: SSH address: 127.0.0.1:2222
    centos: SSH username: vagrant
    centos: SSH auth method: private key
    centos: Warning: Remote connection disconnect. Retrying...
    centos: 
    centos: Vagrant insecure key detected. Vagrant will automatically replace
    centos: this with a newly generated keypair for better security.
    centos: 
    centos: Inserting generated public key within guest...
    centos: Removing insecure key from the guest if it's present...
    centos: Key inserted! Disconnecting and reconnecting using new SSH key...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...
    centos: Warning: Authentication failure. Retrying...

A solução é simples edite o arquivo public_key.rb

/opt/vagrant/embedded/gems/gems/vagrant-1.8.5/plugins/guests/linux/cap/public_key.rb    

Procure a linha

mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keys

Adicione abaixo dela

chmod 0600 ~/.ssh/authorized_keys

Salve, e suba a VM novamente, isso deve resolver o problema.

Refs

No vagrant 1.8.6 isto estará resolvido, mais info sobre o bug abaixo

[s]
Guto

Acessando a VM do Docker for Windows e Docker For Mac

Tenho usado o Docker for Mac desde que lançaram seu beta, já nas versões 1.11.* e agradeci muito por facilitarem minha vida no OS X, só que o processo de Debug nas VMs ficou um pouco mais oneroso.

VMs Debian e Ubuntu

Quando comecei com o Docker tive que subir muita VM na mão: Ubuntu, Debian, CentOS. Depois passei a usar o boot2docker e seu client que facilitava apontar o Docker Client para o Docker Daemon rodando dentro da VM.

Com Vagrant

Os problemas de performance me levaram a customizar o boot2docker com arquivos shell script para montar as shared folders manualmente e usando NFS. Acabei usando Docker por um tempo dentro do Vagrant para automatizar este processo.

Docker Machine

O Docker Machine foi uma baita invenção, com ele conseguia usar mais de uma VM na mesma máquina de maneira mais fácil e customizava cada uma delas conforme minha necessidade, além de poder rodar Docker remotamente em máquinas na Cloud usando minhas credenciais da Amazon Web Service ou meu token da Digital Ocean por exemplo.

Docker for Mac e Windows

Após este post da Docker https://blog.docker.com/2016/06/docker-mac-windows-public-beta rodar no OS X era bem parecido com rodar no Linux, mas alguns detalhes como a url para testar (local.docker) ou acesso apenas a pasta Home para montagem de volumes sempre me lembravam que estávamos em uma VM.

Na segunda frase deste mesmo post eles mencionam:

“Our major goal was to bring a native Docker experience to Mac and Windows, making it easier for developers to work with Docker in their own environments”.

Naquele momento a cabeça de muito Dev achava que o Docker estava rodando nativo no OS X e no Windows, o que na minha opinião seria uma mágica já que o kernel do OS X, o Darvin, e o kernel do Windows são fechados e não temos ideia se existe recurso para isolar recursos da máquina host.

Quando questionados como eles funcionavam a Docker sempre abriu o jogo e contou que havia uma máquina virtual rodando Alpine Linux mas que os aplicativos e a experiência de uso eram nativos. Nativos também eram os hypervisors utilizados para rodar essa mini VM com Linux e Docker, Hyper-V no Windows e xhyve no OS X.

Como debugar

Umb belo dia estava tentando fazer rodar um container que permitia acesso via http e não consegui acessar a porta da aplicação no navegador.

Depois de muito bater a cabeça achei que poderia ser algum problema na VM rodando o Docker, já tinha passado por algo parecido e dentro da VM rodando um simples curl no endereço da aplicação ela respondia. Mas como acessá-la para fazer esse teste? Com o Docker Machine bastava rodar o comando:

docker-machine ssh nome-da-vm

e bum, estava no shell da VM. Ai era só instalar os pacotes do boot2docker que precisava para debugar e testar. Por exemplo o htop:

tce-load -wi htop

No OS X

Com o Docker for Mac tive que buscar na documentação e acabei achando uma maneira de acessar a VM na página https://beta.docker.com/docs/mac/troubleshoot/ que já não existe mais, somos redirecionados para a página https://docs.docker.com/docker-for-mac/troubleshoot/ desde que encerrou o beta público e o Docker for Mac e Windows foram liberaram para o público em geral, nesta página a informação de acesso a VM foi removida.

Para acessar a VM no OS X basta utilizar o comando screen para anexar (attach) o terminal da VM:

screen $HOME/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty

Para sair devemos rodar os seguintes comandos em outro terminal para desanexar e limpar as sessões de screen terminadas.

screen -D 
screen -wipe

Exemplo mostrando o acesso:

No Windows

No Windows até hoje não achei uma maneira fácil, tipo ssh ou screen então apelei por usar um container Docker e compartilhar a maioria dos namespaces do host:

docker run --net=host --ipc=host --uts=host --pid=host -it --security-opt=seccomp=unconfined --privileged --rm -v /:/host alpine /bin/sh

Em seguida assumimos o controle do host (VM) rodando Docker.

chroot /host

Vale lembrar que esta maneira também funciona no OS X como no exemplo a seguir.

É isso ae galera, em algum próximo post explico melhor esse lance de namespaces e cgroups que faz toda a mágica de isolamento dos containers.

Bons debugs !!!


Vídeos com exemplos adicionados em 28 de setembro.

Rsync Unicode entre Mac e Linux

O problema

Case você use MacOS para trabalhar — com é o meu caso, e também para publicar sites em servidores Linux utilizando rsync, tenho uma dica preciosa para vocês.

Há alguns meses eu criei um novo blog utilizando Hugo, neste blog quando eu criava posts com palavras com acento eu percebia que o link no site quebrava após a cópia para o servidor linux. Inicialmente eu achei que era um problema no Apache HTTPd, eu até setei default chartset e nada de resolver, estava quase jogando a toalha quando resolvi usar o Google de verdade, após alguma pesquisa entendi o problema.

No FAQ ( https://rsync.samba.org/FAQ.html ) do projeto RSYNC já tem a dica de como resolver isso, mas é um pouco obscuro de entender.

rsync recopies the same files

Some people occasionally report that rsync copies too many files when they expect it to copy only a few. In most cases the explanation is that you forgot to include the --times (-t) option in the original copy, so rsync is forced to (efficiently) transfer every file that differs in its modified time to discover what data (if any) has changed.

Another common cause involves sending files to an Microsoft filesystem: if the file's modified time is an odd value but the receiving filesystem can only store even values, then rsync will re-transfer too many files. You can avoid this by specifying the --modify-window=1 option.

Yet another periodic case can happen when daylight-savings time changes if your OS+filesystem saves file times in local time instead of UTC. For a full explanation of this and some suggestions on how to avoid them problem, see this document.

Something else that can trip up rsync is a filesystem changeing the filename behind the scenes. This can happen when a filesystem changes an all-uppercase name into lowercase, or when it decomposes UTF-8 behind your back.

An example of the latter can occur with HFS+ on Mac OS X: if you copy a directory with a file that has a UTF-8 character sequence in it, say a 2-byte umlaut-u (\0303\0274), the file will get that character stored by the filesystem using 3 bytes (\0165\0314\0210), and rsync will not know that these differing filenames are the same file (it will, in fact, remove a prior copy of the file if --delete is enabled, and then recreate it).

You can avoid a charset problem by passing an appropriate --iconv option to rsync that tells it what character-set the source files are, and what character-set the destination files get stored in. For instance, the above Mac OS X problem would be dealt with by using --iconv=UTF-8,UTF8-MAC (UTF8-MAC is a pseudo-charset recognized by Mac OS X iconv in which all characters are decomposed).

If you think that rsync is copying too many files, look at the itemized output (-i) to see why rsync is doing the update (e.g. the 't' flag indicates that the time differs, or all pluses indicates that rsync thinks the file doesn't exist). You can also look at the stats produced with -v and see if rsync is really sending all the data. See also the --checksum (-c) option for one way to avoid the extra copying of files that don't have synchronized modified times (but keep in mind that the -c option eats lots of disk I/O, and can be rather slow).

Em resumo, quando você copia um arquivo do MacOS que usa sistema de arquivos HFS+ para um sistema linux há um problema pois o MacOS usa Unicode do tipo NFD enquanto o Linux usa Unicode do tipo NFC, com isso, dependendo do nome do arquivo, o Linux pode não reconhecer, em especial no meu caso em que um arquivo HTML possuia caracteres especiais.

Como resolver?

Eu copiava os arquivos dessa forma entre meu mac e o servidor linux

rsync -avz --stats --progress --delete /Mac/origem/* usuario@fqdn:/Linux/destino/

O segredo é acrescentar alguns parametros de conversão ao comando

--iconv=utf-8-mac,utf-8

O comando final ficará assim

rsync -avz --stats --progress --delete --iconv=utf-8-mac,utf-8 /Mac/origem/* usuario@fqdn:/Linux/destino/

Com isso meus arquivos são convertidos e transferidos corretamente.

Agora posso usar acento nos títulos dos posts sem receio de quebrar os links.

[s]
Guto

Inscreva-se no DevOpsDays Brasília

É isto mesmo que você leu, vai ter DevOpsDays em Brasília e as inscrições para o evento já estão abertas, são apenas 280 vagas a venda, não perca a oportunidade de participar do evento que criou o termo “devops”.

Site do evento

http://brasilia.devopsdays.com.br

Agenda no site devopsdays.org

https://www.devopsdays.org/events/2016-brasilia/welcome/

Caso queira palestrar no evento o CFP também está aberto

http://brasilia.devopsdays.com.br/about/cfp/ 

Site para inscrições (eventize)

http://brasilia.devopsdays.com.br/post/registration_open/

Use o código DC61975969 para ganhar 20% de desconto na inscrição (Early Bird), esse desconto é limitado, aproveite!

O que é o DevOpsDays?

O DevOpsDays Brasília, associado e reconhecido pelo DevOpsDays.org, tem como objetivo reunir os interessados no assunto DevOps através da apresentação de palestras, painéis, minicursos e outras atividades. Considerando o aumento do interesse no desenvolvimento de software e cultura Ágil no Brasil, acreditamos que falar sobre DevOps é uma necessidade. O DevOpsDays Brasília 2016 vem preencher essa lacuna, uma vez que esse assunto ainda não foi tratado de forma sistemática em um evento próprio, mesmo com a atual e crescente demanda no Brasil. Pretendemos para esse evento convidar profissionais de empresas e organizações conhecidas no cenário de tecnologia da informação, para assim motivar a ampla participação, não somente de pessoas que já conhecem a cultura DevOps, mas também despertar o interesse daqueles que ainda não conhecem.

Nos vemos lá!

[s]
Guto

Box vagrant para projeto PCP

Criei uma box vagrant para facilitar o uso do PCP.

https://atlas.hashicorp.com/gutocarvalho/boxes/centos7x64-pcp

Essa box contém o PCP com os pacotes nas seguintes versões

  • Pupper Agent 4.6.2
  • Mcollective 2.9.0
  • Hiera 3.2.1
  • Facter 3.4.1
  • Puppet Server 2.6.0
  • PuppetDB 4.2.2
  • R10k 2.4.3
  • PostgreSQL 9.5.4
  • PuppetBoard 0.2.0
  • ActiveMQ 5.14.0

Recomendo usar o vagrant 1.8.4 e virtualbox 5.0.26.

1. Instalando a box

Para instalar a box digite o comando abaixo no terminal

vagrant box add gutocarvalho/centos7x64-pcp

Crie um diretório para o projeto

mkdir pcp; cd pcp

Crie um arquivo Vagrantfile no diretorio com o conteúdo abaixo

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  if Vagrant.has_plugin?("vagrant-hosts")
    config.vm.provision :hosts do |provisioner|
      provisioner.add_localhost_hostnames = false
      provisioner.autoconfigure = true
      provisioner.sync_hosts = true
      provisioner.add_host '192.168.250.35', ['puppet']
      provisioner.add_host '192.168.250.35', ['puppetdb']
    end
  end

  config.vm.box = "centos7-pcp"

  # puppet community platform

  config.vm.define "puppetserver" do |puppetserver|
    puppetserver.vm.hostname = "puppet-pcpm.hacklab"
    puppetserver.vm.network :private_network, ip: "192.168.250.35"
    puppetserver.hostsupdater.aliases = ["puppetboard.hacklab", "puppetexplorer.hacklab"]
    puppetserver.vm.provider "virtualbox" do |v|
      v.customize [ "modifyvm", :id, "--cpus", "2" ]
      v.customize [ "modifyvm", :id, "--memory", "3072" ]
      v.customize [ "modifyvm", :id, "--name", "puppet-pcpm.hacklab" ]
    end
  end

end

Instale os seguintes plugins

vagrant plugin install vagrant-hosts
vagrant plugin install vagrant-hostsupdater

Inicie o projeto

vagrant up

Acesse a vm

vagrant ssh

Divirta-se.

2. refs

Box source

Project PCP

[s]
Guto

Novo PCP liberado com muitas novidades

O time do PCP acaba de finalizar uma atualização que traz as últimas versões de pacotes disponíveis.

  • Pupper Agent 4.6.2
  • Mcollective 2.9.0
  • Hiera 3.2.1
  • Facter 3.4.1
  • Puppet Server 2.6.0
  • PuppetDB 4.2.2
  • R10k 2.4.3
  • PostgreSQL 9.5.4
  • PuppetBoard 0.2.0
  • ActiveMQ 5.14.0

O PCP agora está de casa nova, a partir dessa versão estamos usando o GitLab.com como repositório.

Se tiver dúvidas entre na comunidade PCP no telegram

http://bit.ly/telegram-pcp

Divirta-se!

[s]
Guto

Nova box vagrant com Puppet Server 2.6.0 em CentOS 7

Divulgando nova box CentOS 7.2 com Puppet 4.6.2 e Puppet Server 2.6.0 no atlas. Agora fica mais fácil testar a última versão do Puppet Server com o menor esforço possível :)

1. Instalando a box

Se você usa vagrant 1.8.x para fazer download da box digite

vagrant box add gutocarvalho/centos7x64-puppetserver

Crie um diretório para o projeto

mkdir centos7-puppetserver; cd centos7-puppetserver

Crie um arquivo Vagrantfile no diretorio com o conteúdo abaixo

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.hostname = "puppetserver.hacklab"
  config.vm.box = "gutocarvalho/centos7x64-puppetserver"
  config.vm.network "private_network", ip: "192.168.250.47"
  config.vm.provider "virtualbox" do |virtualbox|
    virtualbox.customize [ "modifyvm", :id, "--cpus", "1" ]
    virtualbox.customize [ "modifyvm", :id, "--memory", "3072" ]
    virtualbox.gui = true
  end
  if Vagrant.has_plugin?("vagrant-cachier")
    config.cache.scope = :box
  end
end

Inicie o projeto

vagrant up

Acesse a vm

vagrant ssh

2. Refs

Para acessar dados da box

https://atlas.hashicorp.com/gutocarvalho/boxes/centos7x64-puppetserver   

O repo git com o código para build da box

https://gitlab.com/gutocarvalho/packer-centos7-puppetserver

É isso, divirta-se.

[s]
Guto

Auto Complete para Docker

Olá!

Hoje o post será um pouco diferente dos que geralmente publicamos, queremos mostrar para vocês como é possível utilizar a funcionalidade de auto complete do shell para os comandos Docker. Mas para que isso? Simples, facilidade e agilidade na execução de comandos, quem aqui nunca apertou o tab depois de digitar ‘./conf’? Então, você deve sentir falta dessa facilidade quando se utiliza os subcomandos do docker, certo? Queremos mostrar pra vocês como resolver isso.

Como você já viu aqui, existem diversos subcomandos do docker, e cada um possui diversos parâmetros que podem ser utilizados, com o docker –help você poderá visualizar as opções disponíveis.

Mas isso é chato algumas vezes, é mais fácil começar a digitar docker run --vol...[tab][tab]e deixar o autocomplete fazer o trabalho:

$ docker run --volume
--volume         --volume-driver  --volumes-from

#vamosinstalar?

No Mac OS X

O processo é simples, estando no Mac OS X temos que instalar o auto completion usando o brew:

$ brew install bash-completion

E em seguida adicionar as linhas em nosso arquivo de profile ($HOME/.bash_profile ou /Users//.bash_profile)

if [ -f $(brew --prefix)/etc/bash_completion ]; then
    . $(brew --prefix)/etc/bash_completion
fi

Você pode executar os seguintes comandos, que devem ser utilizados nesta sequência:

$ echo "if [ -f $(brew --prefix)/etc/bash_completion ]; then" | tee -a $HOME/.bash_profile
$ echo "    . $(brew --prefix)/etc/bash_completion" | tee -a $HOME/.bash_profile
$ echo "fi" | tee -a $HOME/.bash_profile

Atenção: Se não temos o homebrew instalado, veja em http://brew.sh/ mais informações de como instala-lo e utiliza-lo.

No Linux

No Linux, como sempre, é mais simples, basta instalar via gerenciador de pacotes da sua distribuição. Se for Debian like (Ubuntu, Mint, etc) usamos o apt-get:

$ sudo apt-get install bash-completion

Se for Red Hat like (RHEL, CentOS, Fedora, etc) então usamos yum:

$ sudo yum install bash-completion

Completion do Docker Engine

O arquivo está disponível em https://github.com/docker/docker/blob/master/contrib/completion/bash/docker portanto sempre que fizer uma atualização é recomendável que você baixe novamente esse arquivo para refletir os comandos e parâmetros novos disponibilizados pelo Docker.

Ao baixar devemos colocá-lo na pasta /etc/bash_completion.d/ se estivermos no Linux, se estivermos em um Mac OS X:  $(brew --prefix)/etc/bash_completion.d.

No Mac OS X
$ curl -L https://raw.githubusercontent.com/docker/docker/master/contrib/completion/bash/docker > $(brew --prefix)/etc/bash_completion.d/docker
No Linux
$ curl -L https://raw.githubusercontent.com/docker/docker/master/contrib/completion/bash/docker > /etc/bash_completion.d/docker

Completion do Docker Compose

De maneira similar o arquivo está disponível emhttps://github.com/docker/compose/blob/master/contrib/completion/bash/docker-compose . Reforçamos que sempre que fizer uma atualização é bom baixar novamente esse arquivo para refletir os comandos e parâmetros novos disponibilizados pelo Docker Compose.

Ao baixar também devemos colocá-lo na pasta /etc/bash_completion.d/ se estivermos no Linux ou devemos acrescentar a pasta do homebrew antes se estivermos em um Mac OS X: $(brew --prefix)/etc/bash_completion.d.

No Mac OS X
$ curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose > $(brew --prefix)/etc/bash_completion.d/docker-compose
No Linux
$ curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

Completion do Docker Machine

O processo é praticamente o mesmo porém o docker-machine possui 3 arquivos de auto complete. Os arquivos estão disponíveis em https://github.com/docker/machine/tree/master/contrib/completion/bash .

Como dito anteriormente devemos colocá-los na pasta /etc/bash_completion.d/ se estivermos no Linux ou devemos acrescentar a pasta do homebrew antes se estivermos em um Mac OS X: $(brew --prefix)/etc/bash_completion.d.

Como são mais arquivos recomendo utilizarmos um loop para baixarmos todos em sequência utilizando apenas um comando.

No Mac OS X
machineVersion=`docker-machine --version | tr -ds ',' ' ' | awk 'NR==1{print $(3)}'`
files=(docker-machine docker-machine-wrapper docker-machine-prompt)
for file in "${files[@]}"; do
  curl -L https://raw.githubusercontent.com/docker/machine/v$machineVersion/contrib/completion/bash/$file.bash > `brew --prefix`/etc/bash_completion.d/$file
done
unset machineVersion
No Linux
machineVersion=`docker-machine --version | tr -ds ',' ' ' | awk 'NR==1{print $(3)}'`
files=(docker-machine docker-machine-wrapper docker-machine-prompt)
for file in "${files[@]}"; do
  curl -L https://raw.githubusercontent.com/docker/machine/v$machineVersion/contrib/completion/bash/$file.bash > /etc/bash_completion.d/$file
done
unset machineVersion

Observe que:

  1. Se você utilizar alguma versão específica de uma dessas ferramentas basta baixar os arquivos da pasta correspondente.  Por exemplo o docker engine, da maneira que mostramos vamos pegar o arquivo que está na branch master, atualmente versão 1.12.1, para pegar na versão 1.11.0 por exemplo o arquivo fica em https://github.com/docker/docker/blob/v1.11.0/contrib/completion/bash/docker
  2. O Docker disponibiliza alguns arquivos de completion para outros shells. O Docker Engine disponibiliza bash, zsh, fish e powershell como podemos ver em https://github.com/docker/docker/tree/master/contrib/completion .
  3. O Docker Compose e o Docker Machine disponibilizam apenas para bash e zshcomo vemos nas urls https://github.com/docker/compose/tree/master/contrib/completionhttps://github.com/docker/machine/tree/master/contrib/completion .

E era isso por hoje pessoal, agradecimento especial ao @wsilva pela dica. Já sabe, ajude divulgando o blog, e tendo dúvidas ou sugestões deixa ai nos comentários 😉

Abraço!

Fonte: http://dumpscerebrais.com/2016/09/auto-complete-para-docker-engine-machine-e-compose/

Minhas imagens no Docker Hub

Criando minhas primeiras imagens para começar a estudar Docker de verdade.

Hub do Guto

https://hub.docker.com/u/gutocarvalho/

As duas imagens “-systemd” são bases para as imagens “-puppet”. A ideia é utilizar essas imagens para validar módulos Puppet dentro um pipeline que vai envolver dentre outras coisas do GitLab + GitLab CI.

Imagens disponíveis

Centos 7 + Puppet 4.6.2

https://hub.docker.com/r/gutocarvalho/centos-puppet/    

Ubuntu 16.04 + Puppet 4.6.2

  https://hub.docker.com/r/gutocarvalho/ubuntu-puppet/    

Vou postando minhas aventuras por aqui.

[s]
Guto

Por onde iniciar os estudos sobre DevOps?

Muitas pessoas perguntam o que devem estudar ou quais cursos devem fazer para entrar de cabeça no mundo DevOps.

Não é uma resposta fácil, mas tenho algumas indicações para ajudar quem está começando.

1. Vídeos

10 Deploys per day at Flickr

Esse palestra foi a ignição que faltava para a criação do movimento/cultura DevOps em 2009.

https://www.youtube.com/watch?v=LdOe18KhtT4

Entenda as origens DevOps

Vídeo rápido de Damon Edwards (devopsdays core member) acerca das origens do movimento, recomendo.

https://www.youtube.com/watch?v=o7-IuYS0iSE

What is DevOps? - In Simple English

Vídeo curtinho do rackspace que também ajuda.

https://www.youtube.com/watch?v=_I94-tJlovg

DevOpsConf - DevOps State of the Union (John Willis)

Palestra do John Willis (devopsdays core member) na DevOpsCon 2015 sobre o estado do DevOps após 5 anos de seu surgimento.

https://www.youtube.com/watch?v=8rM8lYaMVBE

Five Years of DevOps (Patrick Debois)

Patrick Debois o criador do DevOpsDays e do termo DevOps fala o que achou dos últimos 5 anos de DevOps.

https://www.youtube.com/watch?v=uRMV6tT_mu0

2. Acrônimos

Entenda o que é CAMS

http://devopsdictionary.com/wiki/CAMS

Entenda o que é CALMS

http://whatis.techtarget.com/definition/CALMS

Entenda o que é ICE

http://radar.oreilly.com/2015/01/devops-keeps-it-cool-with-ice.html

Entenda o que é DevSecOps

 http://www.devsecops.org/blog/2015/2/15/what-is-devsecops    

3. Roteiro de estudos

Essa sugestão de estudos é baseada na estrutura CAMS do Willis e Edwards.

3.1 Cultura

  • Estude a metodologia ágil de desenvovlimento
  • Estude metodologias ágeis em geral
  • Estude Scrum
  • Estude Kanban
  • Estude Lean
  • Entenda o que é uma cultura de colaboração e feedback.

Faça um exercicio e tente enxergar os principais problemas culturais do seu time/organização e encontre uma forma corrigir tais problemas adaptando esses métodos.

3.2 Automação

  • Estude virtualização
  • Estude cloud computing
  • Estude Mark Burgess e gerência de configurações
  • Estude infraestrutura como código
  • Conheça pelo menos duas ferramentas de Gerência de Configuração (CFEngine e Puppet)
  • Conheça pelo menos duas ferramentas de Orquestração (Fabric e Ansible)
  • Entenda o que é VCS (Version Control System)
  • Estude GIT pra valer
  • Estude workflows de desenvolvimento usando GIT (olhe os projetos opensource)
  • Estude Continuous Integration
  • Estude Continuous Delivery
  • Estude Continious Deployment
  • Estude TDD/BDD/ATDD
  • Estude Load Testing
  • Estude Stress Testing
  • Estude Security Testing
  • Estude Containers e Docker
  • Estude Microservicos
  • Estude ferramentas para fazer provisionamento automatizado
  • Estude ferramentas de autoserviço
  • Estude sistemas Unix e Linux
  • Estude networking
  • Estude e domine pelo menos 2 linguagens interpretadas (Ruby e Python)
  • Conheça pelo menos 1 stack de cada linguagem
  • Estude a linguagem shell

Labs sugeridos

  • Tente subir uma stack full de automação (ex. puppet)
    • Tente automatizar confs simples do OS (ex. centos)
    • Tente automatizar a instalacao e configuracao de um APP (ex. apache)
  • Tente provisionar VMs ou Containers de forma automatizada via autoserviço
  • Tente construir um pipeline de entrega
    • Indo desde o commit, passando por build, testes até o deploy em vm e container

3.3 Avaliação/Métricas

  • Entenda o que são métricas e pq são importantes
  • Estude real-time-metrics
  • Estude ferramentas APM
  • Conheca bem pelo menos duas ferramentas de monitoramento (Nagios/Zabbix)
  • Estude algum stack para tratamento de logs (ELK)
  • Estude algum stack para coleta e armazenamento métricas (Collectd/Statsd/Graphite/Graphana)

Labs sugeridos

  • Tente subir uma stack full de gestao de logs (ex. ELK)
    • Coloque diversos APPs para jogar dados lá
  • Tente subir um stack full de gestao de dados
    • Gere dados, colete, armazene e visualize com essa stack

3.4 Compartilhamento

  • Entenda a cultura de dividir responsabilidades
  • Entenda a cultura Blameless
  • Aprenda a compartilhar ferramentas entre todos os times
  • Aprenda a compartilhar código entre todos os times
  • Aprenda a compartilhar informações e dados
  • Procure sempre melhorar o processo de comunicação
  • Entenda como funcionam times de produtos
  • Ofereça feedback constante entre os times
  • Volte pra cultura e reinicie o ciclo até aqui
  • Entenda e pratique Dojos
  • Entenda os Hackerspaces
  • Entenda os Hackatons

Cada eixo desse do roteiro de estudos tem cursos disponíveis no mercado, documentação farta online, artigos variados na rede.

Evite procurar por uma formação DevOps no mercado, o ideal é que você mesmo crie um roteiro de estudos.

Se encontrar alguma formação DevOps no mercado, fique alerta, tome muito cuidado para não ser uma empresa inventando algo só para faturar em cima da Buzzword DevOps, não invista seu dinheiro nesses cursos mágicos, como voce viu DevOps é algo amplo, difícil de colocar em um curso de 24 ou 40 horas, procure cursos especializados em centros reconhecidos ou oficiais, vá passando um assunto por vez, um curso por vez se você for da linha dos cursos, se for da linha da autodidaxia, mergulhe nas comunidades, leia, pergunte, compartilhe e aprenda junto conosco.

Coloquei esse guia no GitLab para receber contribs, mande PRs quando quiser.

Agora é começar os estudos, divirta-se!

[s]
Guto

Conhece o projeto rancher?

Rancher é uma plataforma de gerenciamento para containers (funciona com docker).

http://rancher.com

O gerenciador é todo web/gráfico, com interface bem polida e fácil de usar.

Posso até dizer que parece um VMWare para Docker.

O Rancher fala de fábrica Swarm, Kubernetes, Mesos e Cattle (cluster de containers nativo do rancher).

Ele consegue criar clusters em qualquer uma dessas tecnologias.

Para criar um cluster você usa a interface web, ele abstrai tudo pro administrador.

Voce só escolhe qual o tipo de cluster e clica em criar e pronto, cluster rodando, sem dores.

Ele tem Load Balancer, HA, Discovery e tudo que uma ferramenta corporativa de gerenciamento de containers precisa.

Olhando por outro aspecto, ele parece até uma AWS nativa rodando na sua infra (ou no seu notebook).

E tem API para configurar e gerenciar tudo.

http://docs.rancher.com/rancher/v1.2/en/api/

Ele tem um CLI também.

http://docs.rancher.com/rancher/v1.2/en/cli/

Eles criaram o RancherOS para voce instalar um SO Rancher dedicado em BareMetal.

http://rancher.com/rancher-os/

É um OS um tanto quanto diferente, pois tirando o kernel, todo o resto roda em containers.

Fizemos um meetup de docker aqui em Brasília e escolhemos o Rancher para estudar, subimos o rancher server usando docker 1.12 e criamos um cluster de 8 hosts rancher em menos de 15 minutos, esforço mínimo. Após subir o cluster, gastamos mais 5 minutos para fazer o deploy de um APP wordpress+mysql distribuído com LB + discovery entre esses 8 hosts, só não deu tempo de testar o HA, mas pelo que li é tão fácil quanto.

Pra mim esse é o projeto que tem mais futuro nesse mundo dos containers

Se curtiu entre na comunidade ranche-br no telegram

http://telegram.me/rancherbr

#ficaadica #acompanhe #radar-do-guto

Obs.1: Nosso teste com o wordpress utilizou persistência simples de banco mysql, sem HA no banco containerizado, nosso foco foi distribuir o frontend entre vários hosts, somente isso, nem entramos no detalhe de compartilhar um volume para servir o wp-content entre todos os containers (usando convoy-nfs ou gluster-fs). Tem documentação farta para fazer esse lab completo com todos esses detalhes, só não deu tempo de fazer tudo isso no meetup. Enfim, é um projeto promissor, recomendo dar uma acompanhada.

[s]
Guto

Novas turmas de Puppet marcadas no Brasil

Muito leitores e amigos tem me perguntando sobre as datas de treinamento Puppet para o segundo semeste de 2016, sim elas já foram marcadas, seguem as datas!

Puppet Fundamentals

Brasília

Dias 25, 26 e 27 de Outubro

São Paulo

Dias 08, 09 e 10 de Novembro

Puppet Practitioner

São Paulo

Dias 27, 28, 29 de Setembro

Brasília

Dias 22, 23 e 24 de Novembro

Puppet Architect

São Paulo

Dias 13 e 14 de Dezembro

Essas são as últimas turmas do ano, se não aproveitar essa janela terá que esperar até abril de 2017, então aproveite!

http://instruct.com.br

[s]
Guto

Meus dotfiles para osx

Post #notamental, segue abaixo meu repo dotfiles!

https://gitlab.com/gutocarvalho/dotfiles

.bash_profile

https://gitlab.com/gutocarvalho/dotfiles/blob/master/bash_profile.sh

.gitconfig

https://gitlab.com/gutocarvalho/dotfiles/blob/master/gitconfig

.vimrc

https://gitlab.com/gutocarvalho/dotfiles/blob/master/vimrc

[s]
Guto

Boxes vagrant atualizadas no atlas

Meu repositório de box para vagrant foi atualizado ontem, agora todas as box tem Puppet 4 na última versão disponível para aquele sistema operacional.

Repositório Atlas

https://atlas.hashicorp.com/gutocarvalho/

CentOS

CentOS 5.11

https://atlas.hashicorp.com/gutocarvalho/boxes/centos5x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

CentOS 6.8

https://atlas.hashicorp.com/gutocarvalho/boxes/centos6x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

CentOS 7.2.1511

https://atlas.hashicorp.com/gutocarvalho/boxes/centos7x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

Debian

Debian 6.0.10

https://atlas.hashicorp.com/gutocarvalho/boxes/debian6x64
  • Puppet 4.4.1
  • Virtualbox Guest 5.0.26

Debian 7.11

https://atlas.hashicorp.com/gutocarvalho/boxes/debian7x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

Debian 8.5

https://atlas.hashicorp.com/gutocarvalho/boxes/debian8x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

Ubuntu

Ubuntu 12.04.5

https://atlas.hashicorp.com/gutocarvalho/boxes/ubuntu1204x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

Ubuntu 14.04.5

https://atlas.hashicorp.com/gutocarvalho/boxes/ubuntu1404x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

Ubuntu 16.04.1

https://atlas.hashicorp.com/gutocarvalho/boxes/ubuntu1604x64
  • Puppet 4.6.2
  • Virtualbox Guest 5.0.26

Para adicionar qualquer box digite o comando

vagrant box add gutocarvalho/nome-da-box

[s]
Guto

Docker e Flannel

Oi Pessoal!

A intenção hoje é chamar a atenção para um dos recursos que está presente no Docker e que as vezes passa despercebido para muitos dos utilizadores dessa tecnologia, que é trabalhar com rede. Já vimos aqui no blog como trabalhar com Docker Network, mas com a ascensão do docker 1.12 ficou ainda mais fácil mudar a forma de como se utilizar rede, você pode integrar o Docker com diversos plugins e tecnologias de rede, hoje veremos como utilizar o Flannel para ser seu backend de rede.

Para quem não conhece, o Flannel é um projeto que foi inicialmente desenvolvido pela CoreOS, mas que atualmente é mantido, além da própria empresa, pela comunidade. Ele utiliza um serviço de chave-valor para persistir as informações sobre alocação de ip entre hosts e containers, por padrão ele utiliza o Etcd (que por coincidência é desenvolvido e mantido pela CoreOS também 🙂 ), veja abaixo algumas das características do Flannel e a diferença em relação ao Docker Network:

                            Flannel              Docker Overlay Network
Modelo                        VxLAN ou UDP                            VxLAN
Isolamento de aplicação                        CIDR Schema                      CIDR Schema
Protocolos suportados                              Todos                            Todos
Serviço de nome                                Não                              Não
Requer backend externo                                Sim                              Sim
Tipo de encriptação                                TLS                              Não
 vNIC por Container                                Não                              Sim
Restrição de subnet por container                                Não                              Sim

Como podem notar o Flannel tem algumas vantagens e desvantagens em relação ao Docker Network, destacam-se a comunicação encriptada que ele provê e não ter a possibilidade de criar subnet diferente por cliente, ou seja, todos os containers fazem parte da mesma rede. Se você está pensando em utilizar Kubernetes, leve em consideração o Flannel, pois é um dos plugins mais utilizados com esse orquestrador. Vamos colocar a mão na massa?

Instalação e dependências

Servidor Etcd

Nosso exemplo foi baseado no Centos 7 64 bits, mas você pode utilizar em outro S.O sem problema. Vamos lá, primeiramente você deve habilitar o repositório Extras do CentOS, para isso edite o CentOS-Base.repo e coloque habilite-o, veja:

# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client. You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the
# remarked out baseurl= line instead.
#
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#released updates
[updates]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/
gpgcheck=1
enable=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

Agora vamos instalar o backend do Flannel, que é o etcd (serviço de chave valor em memória), o etcd é utilizada para armazenar as informações sobre as redes que serão distribuídas entre os containers. Vamos lá:

[root@host-etcd ~]#  yum install etcd

Edite o /etc/etcd/etcd.conf alterando o ETCD_LISTEN_CLIENT_URLS, em nosso teste colocamos 0.0.0.0, ou seja, o etcd estará acessível através de qualquer ip do host, veja:

ETCD_NAME=default
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"

Cuide para que a porta 2389 esteja liberado no firewall desse host. Agora vamos aproveitar que estamos no host de etcd e vamos já deixar configurado a rede que será utilizada pelos hosts de Docker. Para isso, crie um arquivo, em nosso lab: rede.json e adicione o seguinte código:

{
 "Network": "192.0.0.0/16",
 "SubnetLen": 22,
 "Backend": {
 "Type": "vxlan",
 "VNI": 1
 }
}

Onde:

  • Network – Bloco de rede que será distribuída para os containers;
  • SubnetLen – Tamanho do bloco alocada para cada host, ou seja, cada host receberá um /22 do bloco 192.0.0.0/16, isso que dizer que poderíamos ter até 1000 containers em 1 host.
  • Type – Tipo do canal que será utilizado, lembra que no Flannel você pode escolher em vxlan ou udp, pois bem, é aqui que você configura isso, por experiência própria, recomendamos utilizar vxlan, pois há menos overhead.

O que faço com isso agora? Importe no etcd ;), lembrando que o etcd trabalha com chave=valor, então execute:

[root@host-etcd ~]# etcdctl set /mundodocker/network/config < rede.json

Onde:

  • /mundodocker/network/config – chave
  • rede.json – valor

Agora vamos ver se essas informações foram persistidas no etcd:

[root@host-etcd ~]#etcdctl get /mundodocker/network/config
{
 "Network": "192.0.0.0/16",
 "SubnetLen": 22,
 "Backend": {
 "Type": "vxlan",
 "VNI": 1
 }
}
Servidores Docker

Não esqueça, em todos os hosts temos que ativar o repositório de extras do CentOS, da mesma forma que foi feita acima. Vamos as instalações das dependências, o docker é claro:

[root@host-docker01 ~]# curl -fsSL https://get.docker.com/ | sh

Agora o Flannel:

[root@host-docker01 ~]# yum install flannel -y

Vamos as configurações agora, começamos pelo Flannel, para isso, edite o arquivo: /etc/sysconfig/flanneld, modificando as linhas:

FLANNEL_ETCD = Servidor do Etcd.
FLANNEL_ETCD_KEY = Key definida no Etcd.

Veja como deve ficar:

[root@host-docker01 ~]# cat /etc/sysconfig/flanneld | grep -v ^#
FLANNEL_ETCD="http://host-etcd:2379"
FLANNEL_ETCD_KEY="/mundodocker/network"

Agora inicie o serviço do Flannel:

[root@host-docker01 ~]# systemctl enable flanneld
[root@host-docker01 ~]# systemctl start flanneld

Note que ele criará uma interface de rede chamada flannel.1, que será utilizada para comunicação entre os hosts. Note também que será criado um arquivo dentro de: /run/flannel/subnet.env com as informações sobre a rede que o host assumiu, esse arquivo será utilizado daqui a pouco.

Agora vamos configurar nosso serviço de Docker para utilizar a rede Flannel configurada anteriormente, para isso, edite o arquivo: /lib/systemd/system/docker.service adicionando a linha: EnvironmentFile=-/run/flannel/subnet.env e alterando a forma como o Docker será iniciado, veja como deve ficar:

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
 
[Service]
Type=notify
EnvironmentFile=-/run/flannel/subnet.env
ExecStart=/usr/bin/docker daemon -H fd:// $OPTIONS $DOCKER_STORAGE_OPTIONS --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=0
 
[Install]
WantedBy=multi-user.target

Agora basta iniciar/reiniciar o serviço do Docker:

[root@host-docker01 ~]# systemctl enable docker.service
[root@host-docker01 ~]# systemctl start docker.service

Não esqueça de fazer isso em todos os hosts de Docker que você quer colocar nessa rede.

Vamos testar?

Basta você criar um container em cada host, em nosso teste criamos um baseado na imagem do CentOS:

Host 1:

[root@host-docker01 ~]# docker run -it centos /bin/bash

Host 2:

[root@host-docker02 ~]# docker run -it centos /bin/bash

Agora basta você pingar de um container para o outro, ou se quiser fazer um teste mais real, você pode instalar um banco de dados ou servidor web em um dos containers e tentar acessar via ip da rede Flannel pelo outro container. Como você deve ter notado esse processo é bem simples e resolve grandes problemas com rede no Docker, como por exemplo a comunicação entre multi-host.

Por hoje era isso, espero que tenha ajudado, e como sempre, nos ajude divulgando o blog 😉

Abraço!

Auto complete para Docker Engine, Machine e Compose

Se você é como eu então adora o auto complete do bash e provavelmente digita sempre com o dedo anelar esquerdo sempre meio levantado. Por que wsilva? Porque a cada 2 ou 3 letras de um comando já uso o tab para auto completar ou pelo menos sugerir uma continuação.

Usando Docker o auto completion é vital, existem diversos subcomandos e cada subcomando tem seus parâmetros, um jeito de descobrir é digitar o seguinte comando para ver os subcomandos ou opções possíveis.

$ docker --help 

No fim do output exite a sugestão:

Run 'docker COMMAND --help' for more information on a command.

Ou seja, para ver as opções possíveis para o comando run fazemos de maneira similar:

$ docker run --help

Mas acho isso muito chato eu prefiro começar a digitar docker run --vol...[tab][tab] e o autocomplete fazer o trabalho:

$ docker run --volume
--volume         --volume-driver  --volumes-from

Instalando o Bash Completion

No Mac OS X

O processo é simples, estando no Mac OS X temos que instalar o auto completion usando o brew:

$ brew install bash-completion

E em seguida adicionar as linhas em nosso arquivo de profile ($HOME/.bash_profile ou /Users//.bash_profile)

if [ -f $(brew --prefix)/etc/bash_completion ]; then
    . $(brew --prefix)/etc/bash_completion
fi

Dá para fazer com os seguintes comandos que devem ser usados nesta sequência:

$ echo "if [ -f $(brew --prefix)/etc/bash_completion ]; then" | tee -a $HOME/.bash_profile
$ echo "    . $(brew --prefix)/etc/bash_completion" | tee -a $HOME/.bash_profile
$ echo "fi" | tee -a $HOME/.bash_profile

Atenção: Se não temos o homebrew instalado em http://brew.sh/ encontramos mais informações.

No Linux

No Linux como sempre mais simples é só instalar via gerenciador de pacotes da sua distribuição. Se for Debian like (Ubuntu, Mint, etc) usamos o apt-get:

$ sudo apt-get install bash-completion

Se for Red Hat like (RHEL, CentOS, Fedora, etc) então usamos yum:

$ sudo yum install bash-completion

Completion do Docker Engine

O arquivo está disponível em https://github.com/docker/docker/blob/master/contrib/completion/bash/docker portanto sempre que fizer uma atualização é bom baixar novamente esse arquivo para refletir os comandos e parâmetros novos disponibilizados pelo Docker.

Ao baixar devemos colocá-lo na pasta /etc/bash_completion.d/ se estivermos no Linux ou devemos acrescentar a pasta do homebrew antes se estivermos em um Mac OS X: $(brew --prefix)/etc/bash_completion.d.

No Mac OS X

$ curl -L https://raw.githubusercontent.com/docker/docker/master/contrib/completion/bash/docker > $(brew --prefix)/etc/bash_completion.d/docker

No Linux

$ curl -L https://raw.githubusercontent.com/docker/docker/master/contrib/completion/bash/docker > /etc/bash_completion.d/docker

Completion do Docker Compose

De maneira similar o arquivo está disponível em https://github.com/docker/compose/blob/master/contrib/completion/bash/docker-compose . Reforçamos que sempre que fizer uma atualização é bom baixar novamente esse arquivo para refletir os comandos e parâmetros novos disponibilizados pelo Docker Compose.

Ao baixar também devemos colocá-lo na pasta /etc/bash_completion.d/ se estivermos no Linux ou devemos acrescentar a pasta do homebrew antes se estivermos em um Mac OS X: $(brew --prefix)/etc/bash_completion.d.

No Mac OS X

$ curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose > $(brew --prefix)/etc/bash_completion.d/docker-compose

No Linux

$ curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

Completion do Docker Machine

O processo é praticamente o mesmo porém o docker-machine possui 3 arquivos de auto complete. Os arquivos estão disponíveis em https://github.com/docker/machine/tree/master/contrib/completion/bash . Reforçamos que sempre que fizer uma atualização é bom baixar novamente esse arquivo para refletir os comandos e parâmetros novos disponibilizados pelo Docker Machine.

Como dito anteriormente devemos colocá-los na pasta /etc/bash_completion.d/ se estivermos no Linux ou devemos acrescentar a pasta do homebrew antes se estivermos em um Mac OS X: $(brew --prefix)/etc/bash_completion.d.

Como são mais arquivos recomendo utilizarmos um loop para baixarmos todos em sequência utilizando apenas um comando.

No Mac OS X

machineVersion=`docker-machine --version | tr -ds ',' ' ' | awk 'NR==1{print $(3)}'`
files=(docker-machine docker-machine-wrapper docker-machine-prompt)
for file in "${files[@]}"; do
  curl -L https://raw.githubusercontent.com/docker/machine/v$machineVersion/contrib/completion/bash/$file.bash > `brew --prefix`/etc/bash_completion.d/$file
done
unset machineVersion

No Linux

machineVersion=`docker-machine --version | tr -ds ',' ' ' | awk 'NR==1{print $(3)}'`
files=(docker-machine docker-machine-wrapper docker-machine-prompt)
for file in "${files[@]}"; do
  curl -L https://raw.githubusercontent.com/docker/machine/v$machineVersion/contrib/completion/bash/$file.bash > /etc/bash_completion.d/$file
done
unset machineVersion

Considerações

Versões diferentes

Se você utilizar alguma versão específica de uma dessas ferramentas basta baixar os arquivos da pasta correspondente.

Por exemplo o docker engine, da maneira que mostramos vamos pegar o arquivo que está na branch master, atualmente versão 1.12.1, para pegar na versão 1.11.0 por exemplo o arquivo fica em https://github.com/docker/docker/blob/v1.11.0/contrib/completion/bash/docker

Utilizo outro shell

O Docker disponibiliza alguns arquivos de completion para outros shells. O Docker Engine disponibiliza bash, zsh, fish e powershell como podemos ver em https://github.com/docker/docker/tree/master/contrib/completion .

O Docker Compose e o Docker Machine disponibilizam apenas para bash e zsh como vemos nas urls https://github.com/docker/compose/tree/master/contrib/completion e https://github.com/docker/machine/tree/master/contrib/completion .

Demo

Segue um demo de como instalar o bash completion para o docker, para o docker-compose e para o docker-machine e como utilizá-los no Mac OS X.

É isso ae, curtiu, use, comente, compartilhe e contribua. Não curtiu, também comente e participe.

Abç

Docker Run – Avançado

Olá pessoal,

Hoje vamos falar um pouco mais sobre as opções que talvez muitas pessoas não conhecem sobre o Docker run e que podem ajudar você diariamente a subir suas aplicações com mais segurança e também com mais praticidade. A ideia por trás desse post não é mostrar como criar um container, mas sim quais as opções novas e que podemos utilizar em nosso dia a dia.

PID settings (–pid)

Por padrão todos os containers possuem o PID namespace habilitado. O Namespace PID remove o ponto de vista dos processos do sistema e permite ids de processos para ser utilizado. Em alguns casos você pode querer rodar alguma ferramenta de depuração em seu container para que ele consiga visualizar os processos do seu host, então basta iniciar o container com a opção de –pid ativado:

docker run -it --rm --pid=host imagem

É possível também utilizar o –pid para depurar as informações de outro container, para isso vamos iniciar a execução de um container com mongoDB e depois um container para realizar a depuração

docker run --name mongo -d mongodb 
docker run --it --pid=container:mongo imagem

–dns

Por padrão os containers irão compartilhar os mesmos servidores de DNS que estão sendo utilizados em seu host, então na hora de criação de cada container você pode utilizar o parâmetro –dns=”8.8.8.8″ por exemplo.

–add-host

O docker ja cria dentro de cada container em /etc/hosts o arquivo com algumas configurações de rede, como:

172.17.0.2 02ed3f564f1b
127.0.0.1 localhost
fe00::0 ip6-localnet

Porem é possivel na hora da criação do container você adicionar mais uma entrada dentro do arquivo de hosts para isso basta colocar a opção –add-host em seu “docker run”

 docker run -it --add-host entrada:ip -d centos

–security-opt

Nas versões mais recentes do Docker é possível você limitar para que os comandos que exigem privilégios dentro do Docker não sejam mais executado, como: su ou sudo para isso basta executar:

docker run --security-opt no-new-privileges -d centos

–restart

Utilizando essa opção é possível realizar a reinicialização de containers a partir de determinados evento, são esses: on-failure, always, unless-stopped.

  • On-failure: Reinicia somente se o status de saída do container por diferente de 0, é possível limitar o numero de tentativas de reinicialização. O docker irá esperar 100ms na primeira vez que tentar reiniciar o container, caso vá para segunda vez então irá esperar 200ms e depois 400ms e assim dependendo do número de tentativas.
 docker run --restart=on-failure:3 centos
  • Always: Sempre reinicie o container independentemente do status de saída. Na reinicialização do servidor, o container irá subir automaticamente após o serviço do docker ser startado.
 docker run --restart=always centos
  • Unless-Stopped: Inicialize o container independentemente do status de saída, porem na reinicialização do servidor ou do serviço do Docker o container não irá subir automaticamente;
 docker run --restart=unless-stopped centos

O status de saída exibido pelo Docker no docker run pode ser visto utilizando a seguinte opção:

 docker run redis; echo $?

Existem alguns números já conhecidos, 125 (Problema com o docker daemon), 126 (Comando não pode ser invocado), 127 (Comando não pode ser encontrado).

–isolation

Essa opção é útil quando você executar Docker no Windows essa opção define qual tecnologia ira ser usada para o isolamento do container, no caso do linux é default e no Windows temos: process e Hyper-v.

docker run -d --isolation process busybox top

–device

Um dia poderá aparecer a necessidade para que você anexe um disco a seu container, então com essa opção você pode anexar diretamente um disco a seu container:

docker run --device=/dev/sdb:/dev/xvdc -d centos

–rm

Por padrão quando você cria um container sem passar a opção de “–rm” quando esse container acaba parando por algum motivo, ele não é removido do Docker e também nem o seu volume. Porem caso você deseja que remova o container você poderá passar o parâmetro na hora da criação do container.

docker run -it -v /home/container:/home --rm -d centos

Nesse modo de criação de container, quando o container por algum motivo parar o docker irá excluir-lo e também apagar o volume junto. Para que NÃO APAGUE O VOLUME você deve criar um volume com a opção de docker volume create.... e na hora da criação desse container passar o nome do volume.

docker run -it --rm -v volume:/home -d centos

Então ta pessoal, por hoje era isso, espero que tenham gostado, em breve faremos posts mais focados no baixo nível do Docker para que você possa saber como todas as opções funcionam e como utiliza-las. Já sabe, nos ajude divulgando o blog 😉

Dockerizando aplicações – Processos de administração

Seguindo a lista do modelo 12factor, temos “Processos de administração” como décima segunda e ultima boa prática desse modelo.

admin

Toda aplicação demanda administração, isso quer dizer que uma vez implantada é possível que ela precise receber determinados comandos para corrigir possíveis problemas ou simplesmente mudar de comportamento. Como exemplos temos migrações de banco de dados, execução de scripts diversos como backup, e também execução de um console para inspeção do serviço.

Essa boa prática recomenda processos de administração executados em ambientes idênticos ao utilizado no código em execução, ou seja, seguindo todas as práticas explicadas até então.

Usando Docker, é possível rodar esses processos usando a mesma imagem base no ambiente de execução que se desejar. Tudo isso podendo se beneficiar da comunicação entre os contêineres, uso de volumes que forem necessários e afins.

Para exemplificar essa boa prática criamos o arquivo reset.py:

from redis import Redis
import signal, os

host_redis=os.environ.get('HOST_REDIS', 'redis')
port_redis=os.environ.get('PORT_REDIS', '6379')

redis = Redis(host=host_redis, port=port_redis)

redis.set('hits', 0)

Ele é responsável por reinicializar o contado de visitas do Redis. Esse comando será dado usando um contêiner diferente a partir da mesma imagem docker. Primeiro vamos iniciar o ambiente. Baixe o repositório e acesse a pasta factor12 e execute o comando abaixo:

docker-compose up 

Acesse a aplicação em seu navegador. Caso esteja usando GNU/Linux ou Docker For MAC e Windows acesse o endereço 127.0.0.1, caso esteja usando Docker Toolbox será necessário usar o ip 192.168.99.100. Você verá a seguinte frase:

“Hello World! 1 times.”

Acesse a aplicação mais algumas vezes para o marcado aumentar bastante.

Depois vamos executar o comando de administração a partir do serviço worker:

docker-compose exec worker python reset.py

O comando “python reset.py” será executado dentro de um novo contêiner, mas usando a mesma imagem de um worker regular.

Acesse novamente a aplicação e verifique se o marcado iniciou a partir de 1 novamente.

Troubleshooting e dicas de Docker

Olá pessoal,

Já faz mais de 1 ano que criamos esse blog e hoje resolvemos fazer um post referente a como solucionar algumas dificuldades e problemas que tivemos no começo, visto que trabalhamos a mais de 2 anos já com Docker, tivemos muitos problemas que queremos demonstrar para vocês.

Instalando a versão mais recente

A maioria das pessoas que acabam por usar Ubuntu, Centos, RedHat ou qualquer outra distribuição utiliza seus próprios comandos para realizar a instalação do Docker, com yum ou apt-get. Mas a forma de utilizar as versões mais recentes são essas:

Versão oficial para se utilizar em produção:

curl -sSL https://get.docker.com/ | sh

Versão que se encontra ainda em fase de testes:

curl -fsSL https://test.docker.com/ | sh

Versão alpha que está em constante desenvolvimento:

curl -fsSL https://experimental.docker.com/ | sh

 Como remover todos os containers parados:

docker rm $(docker ps -a -q)

 Sincronizar o relógio do host com o container:

Isso é um dos principais problemas que as pessoas acabam encontrando as vezes.

Para Centos (Na hora de criar o container mapeia o diretório do host com o do container)

docker run -v /etc/localtime:/etc/localtime:ro centos date

Para Ubuntu (Na hora da criar o container passa como variável o timezone(tz)

docker run -e "TZ=America/Salvador" ubuntu date

 Comunicação entre containers:

Por padrão no Docker a comunicação entre os containers na mesma rede é liberado através de IP interno. Mas caso você queira que os containers não se comuniquem diretamente basta mudar na hora da criação da rede colocar icc=false.

docker network create -o com.docker.network.bridge.enable_icc=false rede_isolada

Montando volumes com services:

Quando criamos um container simples com docker run, existe a opção do -v onde podemos passar como parâmetro o nosso volume, porém com a implementação do services no Docker 1.12 ficou um pouco mais complicado na hora de passar um volume para o serviço:

Como você pode ver na opção “type” temos o “bind” que seria um diretório em nosso host:

docker service create --mount type=bind,source=/diretoriohost,target=/diretoriocontainer imagem

E também temos a opção volume que é passado o volume que é criado com “docker volume create…..

docker service create --mount type=volume,source=meuvolume,target=/diretoriocontainer imagem

 Docker commit e volume:

O comando “docker commit” gera uma imagem do nosso container, porém ele NÃO vai armazenar os dados do volume que estão atrelados a aquele container. Então o docker commit não irá servir de backup para os seus dados que estão no volume.

Não rode containers com –privileged

Com a opção de –privileged o container consegue facilmente acessar diversas áreas do seu host na qual podem ser cruciais caso alguém ache alguma brecha de segurança em sua aplicação.

Um processo para cada container.

Não instale pacotes desnecessários em seus containers, se você quer ter um container para apache, só instale o apache nele. Quer ter o PHP também? então suba outro container.

Cuidado com as regras de IPTABLES

Como o Docker trabalha com toda a sua parte de redes através de iptables, é bem provável que se você fizer alguma manutenção em seu firewall e editar alguma regra errada, toda a sua estrutura de Docker pode parar de funcionar por algum problema.

Coloque o diretório do docker em outro disco:

O docker utiliza o caminho “/var/lib/docker” para colocar todos os seus arquivos de instalação e também toda a sua estrutura de containers, volumes e mais outros recursos que ele utiliza. Então não deixe esse diretório no mesmo disco do seu SO.

Gostaram do post? Deixe seu feedback e novamente, nos ajudem divulgando o blog.

Grande abraço!

Dockerizando aplicações – Logs

Seguindo a lista do modelo 12factor, temos “Logs” como décima primeira boa prática.

logs

No desenvolvimento de código, gerar dados para efeitos de log é algo bastante consolidado, ou seja, não acredito que existam pessoas desenvolvendo software que não se preocupem com isso, porém o uso correto do log vai além de apenas gerar os dados.

Para efeito de contextualização, de acordo com o 12factor o log é um: “…fluxo de eventos agregados e ordenados por tempo coletados dos fluxos de saída de todos os processos em execução e serviços de apoio.”

Logs normalmente são armazenados em arquivos, com eventos por linha (pilhas de exceção podem ocupar várias linhas), mas essa prática não é indicada, ao menos não na perspectiva da aplicação. Isso quer dizer que sua aplicação não deveria se preocupar em qual arquivo deve guardar os logs.

Especificar arquivos implica em informar o diretório correto desse arquivo, que por sua vez resulta em uma configuração prévia do ambiente e tudo isso junto impacta negativamente na portabilidade da sua aplicação, pois será necessário que o ambiente que receberá sua solução deve seguir uma série de requisitos técnicos para suportar a aplicação, ou seja, com isso enterrando a possibilidade do “Construa uma vez, rode em qualquer lugar”.

Essa boa prática indica que as aplicações não devem gerenciar ou rotear arquivos de log, ou seja, eles devem ser depositados sem nenhum esquema de buffer na saída padrão (STDOUT). Assim uma infraestrutura externa à aplicação, plataforma, deve gerenciar, coletar e formatar a saída desses logs para futura leitura. Isso é realmente importante quando a aplicação está rodando em várias instâncias.

Com o Docker, essa tarefa fica bem mais fácil, pois Docker já coleta logs da saída padrão e encaminha para algum dos vários drivers de log. Esse driver pode ser configurado na inicialização do container de forma a centralizar os logs num serviço remoto de logs, por exemplo syslog.

O código exemplo que está nesse repositório, na pasta factor11 já se encontra pronto para testar essa boa prática, pois o mesmo já envia todas as saídas de dados para STDOUT e você pode conferir iniciando o nosso serviço com o comando abaixo:

docker-compose up

Depois de iniciar acesse o navegador e verifique as requisições da aplicação aparecendo na console do docker-compose.

Docker Service

Oi Pessoal,

Hoje queremos trazer em detalhes para vocês uma das features implementadas no Docker 1.12 (que foi lançado no último dia 29), e que já mencionamos aqui, que é o Docker Service. Para quem ainda não leu o nosso post sobre as novidades do Docker 1.12, o Docker Service é uma feature que foi incorporada pela engine Docker em sua última versão e que permite ao administrador criar e administrar sua stack de serviço dentro de um cluster Swarm, sem precisar utilizar uma segunda ferramenta para isso. Ela é parte integrante de uma série de melhorias que permitiram ao Docker 1.12 ter a camada de orquestração nativa em sua engine.

Mas afinal, como isso me ajuda? Bem, nas versões anteriores do Docker, para você ter algum tipo de orquestração você teria que utilizar uma série de ferramentas, como por exemplo: Docker Swarm, Docker Compose isso sem falar, que, se você quisesse provisionar isso em larga escala mesmo, o recomendado era utilizar Kubernetes, Mesos ou alguma outra forma de orquestração mais adequada. Agora está tudo dentro da própria engine do Docker, o que permite você ter maior controle sob o que está utilizando, e claro, permite você manipular esse ambiente de forma mais simples.

Para serviço especificamente, foi adicionado o sub-comando: docker service, e dentro dele alguns itens, veja:

  1. docker service create: Possibilita a criação de sua stack de serviço, é ele o que você mais vai ver hoje ;)
  2. docker service inspect: Verifica as informações sobre seu serviço e retorna informações sobre parametro utilizados para inicialização do mesmo, imagem utilizada, etc.
  3. docker service ls: Lista todos os serviços que você tem criado, e lhe retorna informações sobre nome, quantidade de replicas, etc.
  4. docker service rm: Remove o serviço desejado do cluster
  5. docker service ps: 2° comando mais útil, retorna para você o status de cada container que atende um serviço, é muito parecido com o docker ps, com a diferença de lhe trazer apenas informações sobre os container que fazem parte de um serviço criado, você pode ainda utilizar filtros para ter um retorno mais simplificado.
  6. docker service scale: Com o scale é possível realizar o escalonamento de seu serviço, é possível você aumentar a quantidade de containers que atenderão o seu serviço.
  7. docker service update: Comando que lhe permite realizar modificações no serviço criado, através dele é possível modificar informações sobre quantidade de memória, cpu, dentre muitas outras coisas em seu serviço.

Tudo certo com a teoria? Então vamos a prática :), nosso problema: Queremos criar uma stack para nosso ElasticSearch, nosso objetivo é escalar esse ambiente quantas vezes eu quiser e atualiza-lo de forma consistente.

Primeiro temos que criar nosso service:

docker service create --replicas 1 --update-delay 10s --update-parallelism 1 --name elasticsearch elasticsearch

O que isso quer dizer? Vamos lá:

  • Replicas – Número de containers que eu quero criar nesse momento, deve ser no mínimo um (por motivos óbvios);
  • Update-delay – Quando for realizado uma procedimento de atualização do ambiente, qual será a cadência de atualização dos containers.
  • Update-parallelism – Quantidade de containers que desejamos atualizar por vez
  • Name – Nome do serviço e por último a imagem que vamos utilizar para esse serviço.

O retorno do comando será algo parecido com isso:

docker-service1

Certo, meu serviço está criado, como escalono ele agora? Fácil, olha o print 🙂

docker-service2

Note que para escalar, basta executar o comando: docker service scale $(seu-servico)=numero. Agora vamos atualizar o nosso ambiente, certo? Muito fácil, basta executar o comando: docker service update, com ele é possível modificar diversos atributos do serviço, como por exemplo: Portas publicadas, limites de recursos, número de replicas, imagem, politica de escalonamento, etc.

Em nosso exemplo vamos atualizar a imagem que nosso serviço utiliza, veja que quando criamos, a imagem utilizada era a elasticsearch:latest, agora queremos testar a última versão do elasticsearch, que está em alpha (no dia da criação desse post) que é a 5.0, para isso basta executar: docker service update –image elasticsearch:5.0 elasticsearch, veja o que aconteceu:

docker-service3

Veja que nosso serviço não foi atualizado de uma vez só, esse processo foi sendo realizado conforme os containers iam sendo atualizados, isso devido a nossa politica de update que definimos na criação do serviço. Com o update você pode realizar diversas ações, veja mais em: docker service update –help, ele lhe mostrará todas as opções disponíveis.

Como removemos um serviço? Bem, você já deve ter imaginado como: docker service rm nome_do_servico.

Ahh, você se lembra que falamos aqui que no Docker 1.12 era possível criar um serviço distribuído dentro Swarm e acessá-lo de qualquer lugar? Pois bem, quando você criar um serviço você pode especificar qual será a porta publica dele, no exemplo acima não utilizamos isso, mas você pode definir (através do parâmetro -p) que a porta 8080 seja a porta de seu serviço, com isso todo o trafego enviado para a porta 8080 nos ips de seus nós do cluster de Swarm será redirecionado para os containers que atendam esse serviço. Lembrando que para você criar um serviço distribuído é necessário ter um cluster de Swarm ativo.

Gostaram do post? Deixe seu feedback e novamente, nos ajudem divulgando o blog.

Grande abraço!

 

Dockerizando aplicações – Paridade entre desenv/produção

Seguindo a lista do modelo 12factor, temos “Paridade entre desenvolvimento/produção” como décima boa prática.

Untitled Diagram (3)

Infelizmente na maioria dos ambientes de trabalho com software, existe um grande abismo entre o desenvolvimento e a produção. Esse grande buraco não é um mero acaso ou falta de sorte. Ele existe por conta de algumas diferenças entre as equipes de desenvolvimento e infraestrutura. De acordo com o 12factor elas manifestam-se nos seguintes âmbitos:

  • Tempo: Um desenvolvedor pode trabalhar em código que demora dias, semanas ou até meses para ir para produção.
  • Pessoal: Desenvolvedores escrevem código, engenheiros de operação fazem o deploy dele.
  • Ferramentas: Desenvolvedores podem estar usando um conjunto como Nginx, SQLite, e OS X, enquanto o app em produção usa Apache, MySQL, e Linux.

O 12factor pretende colaborar com base em suas boas práticas reduzir esse abismo entre as equipes e equalizar os ambientes em questão. Com relação aos âmbitos apresentados, seguem as respectivas propostas:

  • Tempo: um desenvolvedor pode escrever código e ter o deploy feito em horas ou até mesmo minutos depois.
  • Pessoal: desenvolvedores que escrevem código estão proximamente envolvidos em realizar o deploy e acompanhar seu comportamento em produção.
  • Ferramentas: mantenha desenvolvimento e produção o mais similares possível.

A solução de contêiner tem como um dos principais objetivos colaborar com essa portabilidade entre ambiente de desenvolvimento e produção, pois a ideia é que a imagem seja construída e apenas o seu status modifique para que ela seja posta em produção. O nosso código atual já está pronto para esse tipo de comportamento, sendo assim não há muito o que precise ser modificado para garantir essa boa prática, que será como um bônus pela adoção do Docker e o seguimento das outras boas práticas do 12factor.

Docker e Jenkins para build de aplicações

Olá pessoal,

Hoje queremos demonstrar para vocês como podemos utilizar Docker e Jenkins para o build de aplicações de forma rápida e fácil, primeiro vamos entender como é o ambiente de diversas empresas de TI hoje e você que estiver lendo este post possivelmente estará se identificando com isso.

Hoje diversas empresas utilizam a ferramenta Jenkins para build e deploy de aplicações, muitas vezes (Se não forem todas) essa maquina de Jenkins é compartilhada entre diversos times, Java, PHP, Python, Rails e NodeJS acabam utilizando. O que deixa essa máquina com ferramentas desnecessárias para as equipes, sobrecarregando o sistema e qualquer problema acaba parando todas as equipes.

Porém existem alguns casos mais organizados que a maquina onde irá ocorrer o build será uma máquina para cada equipe, o que torna o processo um pouco melhor, porém sempre que sair uma nova versões de softwares alguém precisa ficar atualizando essa máquina, o que pode acabar por muitas vezes impactando em prazos do projeto.

Então existe o que acreditamos que seja a melhor solução que seria a utilização de containers para o build de suas aplicações. mas porque usar containers?

  • Só dependências para aquela aplicação
  • Fácil manutenção
  • Ambiente de produção e local iguais.
  • Escabilidade

Então visto o porque que devemos utilizar containers para realizar o build, vamos mostrar como podemos utilizar essas duas ferramentas em sincronia.

Primeiramente vamos até as configurações do nosso repositório e clicar em “WebHooks & Services:4

Vamos até “Add Service” e adicionar o “Jenkins (Github Plugin)”
5
Agora em nosso servidor com Docker instalado, vamos iniciar o container que terá o Jenkins Master instalado.

############# SERVIDOR1 #################
docker run -p 8080:8080 -p 50000:50000 -d jenkins

Iniciado, agora vamos até o nosso browser e digitar http://ipserver:8080 e vamos fazer a configuração base do Jenkins.

1

Para pegar a senha você irá executar

docker exec idcontainer cat /var/jenkins_home/secrets/initialAdminPassword

Na pŕoxima página você pode escolher a opção de usar os plugins recomendados, então depois irá pedir para você criar um usuário.

2

Feito isso agora estamos na página inicial do jenkins.

3

Esse será nosso servidor de Jenkins Master que sera o responsável por avisar e mandar rodar alguns comandos no nosso servidor onde estará o Docker. Para isso, vamos acessar o servidor 2 e realizar a instalação do Jenkins:

############# SERVIDOR2 #################
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
sudo yum install jenkins -y
sudo yum install java -y 
sudo service jenkins start/stop/restart
sudo chkconfig jenkins on
firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --reload
sudo yum install java-1.7.0-openjdk -y

Após realizar a instalação do servidor2, vamos até o nosso servidor de Jenkins Master e adicionar o outro nó nele, colocando o IP e a forma pela qual o agente fosse instalado: Para isso você deve ir até “Gerenciar Jenkins” >> “Gerenciar nós”

6

Após isso você irá clicar em novo nó, colocar o ip desse novo servidor e clicar na opção de “Permanent” e OK. Após isso irá aparecer algo parecido com a tela abaixo então, você tera que fazer download do slave.jar, ir até o outro servidor e executar o comando do java que é mostrado na imagem abaixo, porem com as suas configurações.

7

Feito isso, vamos até a tela da esquerda na opção de configurações e configurar parecido com a imagem abaixo: A parte mais importante dessa tela é a configuração do “rótulo” que é o apelido que vamos dar a esse servidor, e também o “uso” que estamos dizendo que vamos executar esse servidor apenas como jobs.

8

Agora vamos até a página inicial do nosso jenkins e então criar o nosso build. Vamos até “Novo Build”

9

Após selecionar “Novo Build” vamos até a opção de configuração:

10

Vamos colocar o nome do nosso servidor de slave na opção de “Restringe onde este projeto pode ser executado”

11

Abaixo vamos colocar o nosso caminho do “GitHub” e também de qual branch irá baixar o código.

12

Vamos marcar  a opção de “Build when a change is pushed to github” e também a opção de quanto em quanto tempo vamos ir consultar o nosso “SCM”.

14

Em nosso ultimo passo, vamos colocar os comandos que iremos executar em nosso servidor. Vamos criar uma imagem a partir do Dockerfile que está em nosso GitHub e após isso vamos iniciar o container com essa imagem.

15

Então por hoje era isso pessoal, espero que tenham gostado do post e gostaríamos que vocês interagissem através de comentários propondo novos posts e arquiteturas que vocês gostariam que a gente fizesse com Docker. Em breve teremos mais posts nesse estilo.

Obrigado!

Referências: https://www.docker.com/sites/default/files/RA_CI%20with%20Docker_08.25.2015.pdf

: https://jenkins.io/solutions/docker/

: https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins

Dockerizando aplicações – Descartabilidade

Seguindo a lista do modelo 12factor, temos “Descartabilidade” como nona boa prática.

Quando falamos de aplicações web, espera-se que mais de um processo atenda a todo tráfego que é requisitado para esse serviço, porém tão importante quanto a habilidade de iniciar novos processos, é a capacidade de que um processo defeituoso termine na mesma velocidade que iniciou, pois um processo que demora para finalizar pode comprometer toda solução, uma vez que ela pode ainda estar atendemos requisições de forma defeituosa.

descartabilidade

Em resumo podemos dizer que aplicações web deveriam ser capazes de remover rapidamente processos defeituosos.

Com objetivo de evitar que o serviço prestado esteja muito dependente das instâncias que o servem, esta boa prática indica que as aplicações devem ser descartáveis, ou seja, que o fato de desligar uma de suas instâncias não afete a solução como um todo.

No Docker tem a opção de descartar automaticamente um contêiner após seu uso, no docker run utilize a opção –rm. Vale salientar que essa opção não funciona em modo daemon (-d), ou seja, só fará sentido utilizar essa opção em modo interativo (-i).

Outro detalhe importante nessa boa prática é viabilizar que seu código esteja preparado para se desligar “graciosamente” e reiniciar sem erros. Dessa forma, ao escutar um SIGTERM seu código deveria terminar qualquer requisição em andamento e então desligar o processo sem problemas e de forma rápida, permitindo também que seja rapidamente atendido por outro processo.

Entendemos como desligamento “gracioso” quando uma aplicação é capaz de auto finalizar sem causar danos a solução, ou seja, ao receber um sinal para desligar ela imediatamente deve recusar novas requisições e apenas finalizar as tarefas pendentes em execução no momento. O que está implícito nesse modelo é que as requisições HTTP sejam curtas (não mais que alguns poucos segundos) e nos casos de conexões mais longas que o cliente possa se reconectar automaticamente caso a conexão seja perdida.

Nossa aplicação teve a seguinte mudança para atender a especificação:

from flask import Flask
from redis import Redis
from multiprocessing import Process
import signal, os

host_redis=os.environ.get('HOST_REDIS', 'redis')
port_redis=os.environ.get('PORT_REDIS', '6379')

app = Flask(__name__)
redis = Redis(host=host_redis, port=port_redis)

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello World! %s times.' % redis.get('hits')

if __name__ == "__main__":
    def server_handler(signum, frame):
        print 'Signal handler called with signal', signum
        server.terminate()
        server.join()
    
    signal.signal(signal.SIGTERM, server_handler)

    def run_server():
        app.run(host="0.0.0.0", debug=True)

    server = Process(target=run_server)
    server.start()

Como podem ver no código acima, adicionei um tratamento para quando receber um sinal de SIGTERM ele finalizar rapidamente o processo. Sem esse tratamento o código demoraria um pouco mais para ser desligado. Dessa forma podemos concluir que nossa solução já é descartável o suficiente, ou seja, podemos desligar e reiniciar os containers em outro docker host, e essa mudança não causará impacto na integridade dos dados.

Para fins de entendimento do que estamos trabalhando aqui, cabe falar um pouco sobre isso. De acordo com o Wikipedia, sinal é: “…uma notificação assíncrona enviada a processos com o objetivo de notificar a ocorrência de um evento.” E o SIGTERM é “…o nome de um sinal conhecido por um processo informático em sistemas operativos POSIX. Este é o sinal padrão enviado pelos comandos kill e killall. Ele causa o término do processo, como em SIGKILL, porém pode ser interpretado ou ignorado pelo processo. Com isso, SIGTERM realiza um encerramento mais amigável, permitindo a liberação de memória e o fechamento dos arquivos.”

Para realizar o teste de tudo que apresentado até então, realize o clone do repositório (https://github.com/gomex/exemplo-12factor-docker) e acesse a pasta factor8 (isso mesmo, a número 8, vamos demonstrar aqui a diferença pra o factor9), executando o comando abaixo para iniciar os contêineres:

docker-compose up -d

Depois execute o comando abaixo para finalizar os contêineres:

time docker-compose stop

Você verá que a finalização do worker demorará cerca de 11 segundos, isso porque o comportamento do docker-compose para finalizar é primeiro tentar um SIGTERM e esperar por 10 segundos que a aplicação finalize sozinha, caso contrário é enviado um SIGKILL que finalizar o processo mais bruscamente. Esse timeout é configurável. Caso deseje modificar basta usar o parâmetro “-t” ou “–timeout“. Vejam um exemplo:

docker-compose stop -t 5

Obs: O valor informado após o parâmetro deve ser considerado em segundos.

Agora para testar com o código modificado, basta mudar para a pasta factor9 e executar o seguinte comando:

docker-compose up -d

E depois solicitar seu término:

time docker-compose stop

Veja que o processo worker foi finalizar bem mais rápido, pois recebeu o sinal SIGTERM e a aplicação fez seu serviço de auto finalização e não precisou receber um sinal SIGKILL para ser de fato finalizado.

Docker no Windows 10

Oi pessoal!

Hoje o intuito é mostrar para vocês como instalar e utilizar o Docker for Windows no Windows 10 com apenas alguns cliques, com a ajuda do nosso amigo da Umbler, o Leo, estamos disponibilizando um vídeo com o passo-a-passo que deve ser seguido. Antes veja alguns requisitos que você precisa atender:

  1. Você deve ter o suporte a virtualização habilitado em seu computador;
  2. Seu Windows deve ser 64bits versão 1607 e build: 14393.0;
  3. Você deve habilitar o recurso do hyper-v;
  4. Baixe o Docker for Windows pelo link.

Basta você habilitar na Bios de seu computador o recurso de virtualização, para isso será necessário reiniciar seu computador. Em seguida habilite o recurso do hyper-v através do adicionar recursos do Windows (Painel de controle – programas – recursos do Windows). Execute o arquivo que você baixou lá do site do Docker e siga as instruções que aparecerem, logo em seguida aparecerá para você uma mensagem no canto inferior direito informando que o Docker está sendo iniciado, aguarde até a mensagem sair e pronto, o Docker estará instalado e configurado em seu computador.

Se você desejar, pode alterar as configurações dele pelo ícone que estará nos Ícones ocultos, por lá é possível parar e iniciar o serviço do Docker, assim como modificar o registry default, alterar configurações de rede, compartilhamento de volume, dentre outras opções.

Para usar é muito simples, abra o cmd e execute os comandos do Docker Cli, como se você estivesse em um terminal linux: docker ps -a, docker images, docker run xxx e assim por diante, note que a versão que ele instalará já é a 1.12 rc4, como você já viu nesse post, ela trás uma séria de melhorias e novas features, então bom divertimento :).

Esperamos que tenham gostado, e precisando nos enviem suas dúvidas para que possamos ajudar.

Grande abraço!

Dockerizando aplicações – Concorrência

Seguindo a lista do modelo 12factor, temos “Concorrência” como oitava boa prática.

Durante o processo de desenvolvimento de uma aplicação é difícil imaginar o volume de requisição que ela terá no momento que for colocada em produção. Por outro lado, ter um serviço que suporte grandes volumes de uso é algo esperado nas soluções modernas, pois nada é mais frustante do que solicitar acesso a uma aplicação e ela não estar disponível. Demonstra falta de cuidado e de profissionalismo na maioria dos casos.

Quando uma aplicação é colocada em produção normalmente ela é dimensionada para uma determinada carga esperada, porém é importante que o serviço esteja pronto para escalar, ou seja, a solução deve ser capaz de iniciar novos processo da mesma aplicação caso necessário, sem que isso afete negativamente o produto. A figura abaixo apresenta um gráfico de escalabilidade de serviços.

Untitled Diagram (2)

Com objetivo de evitar que exista qualquer problema na escalabilidade do serviço, esta boa prática indica que as aplicações devem suportar execuções concorrentes, tal que quando um processo está em execução deve ser possível instanciar um outro em paralelo e o serviço possa ser atendido sem perda alguma.

Para que isto aconteça, é importante dividir as tarefas corretamente. É interessante que os processos se atenham aos seus objetivos, ou seja, caso seja necessário executar alguma atividade em backend e depois retornar uma página para o navegador, é salutar que existam dois serviços que tratem as duas atividades de forma separada. O Docker torna essa tarefa mais simples, pois nesse modelo basta especificar um contêineres para cada função e configurar corretamente a rede entre eles.

Para exemplificar essa boa prática, usaremos a arquitetura demonstrada na figura abaixo:

Untitled Diagram (1)

O serviço web será responsável por receber a requisição e balancear entre os workers, os quais são responsáveis por processar a requisição, conectar ao redis e retornar uma tela de “Hello World” informando quantas vezes ela foi obtida e qual nome do worker que está respondendo essa requisição (Para ter certeza que está balanceando a carga), como podemos ver na figura abaixo:

Screen Shot 2016-07-25 at 11.18.25 PM

O arquivo docker-compose.yml exemplifica essa boa prática:

version: "2"
services:
  web:
    container_name: web
    build: web
    networks:
      - backend
    ports:
      - "80:80"

  worker:
    build: worker
    networks:
      backend:
        aliases:
          - apps
    expose:
      - 80
    depends_on:
      - web

  redis:
    image: redis
    networks:
      - backend

networks:
  backend:
      driver: bridge

Para efetuar a construção desse balanceador de carga, temos o diretório web contendo os arquivos Dockerfile (responsável por criar a imagem utilizada) e nginx.conf (arquivo de configuração do balanceador de carga utilizado).

Segue abaixo o conteúdo do DockerFile do web:

FROM nginx:1.9

COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Segue o conteúdo do arquivo nginx.conf:

user nginx;
worker_processes 2;

events {
  worker_connections 1024;
}

http {
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  resolver 127.0.0.11 valid=1s;

  server {
    listen 80;
    set $alias "apps";

    location / {
      proxy_pass http://$alias;
    }
  }
}

No arquivo de configuração acima, foram introduzidas algumas novidades. A primeira é o “resolver 127.0.0.11“, que é o serviço DNS interno do Docker. Usando essa abordagem será possível efetuar o balanceamento de carga via nome, usando um recurso interno do Docker.

Para mais detalhes sobre o funcionamento do DNS interno do Docker, veja esse documento (https://docs.docker.com/engine/userguide/networking/configure-dns/) (apenas em inglês).

A segunda novidade é a função set $alias “apps”; que é responsável por especificar o nome “apps” que será usado na configuração do proxy reverso em seguida “proxy_pass http://$alias;“. Vale salientar que o “apps” é o nome da rede especificada dentro do arquivo docker-compose.yml. Nesse caso o balanceamento será feito para a rede, ou seja, todo novo contêiner que entrar nessa rede será automaticamente adicionado no balanceamento de carga.

Para efetuar a construção do worker temos o diretório worker contendo os arquivos Dockerfile (responsável por criar a imagem utilizada), app.py (que é a aplicação que usamos em todos os outros capítulos) e requirements.txt (descreve todas as dependências do app.py).

Segue abaixo o conteúdo do arquivo app.py modificado para essa prática:

from flask import Flask
from redis import Redis
import os
import socket
print(socket.gethostname())
host_redis=os.environ.get('HOST_REDIS', 'redis')
port_redis=os.environ.get('PORT_REDIS', '6379')

app = Flask(__name__)
redis = Redis(host=host_redis, port=port_redis)

@app.route('/')
def hello():
   redis.incr('hits')
   return 'Hello World I am %s! %s times.' % (socket.gethostname(), redis.get('hits'))
if __name__ == "__main__":
   app.run(host="0.0.0.0", debug=True)

Segue abaixo o conteúdo do requirements.txt:

flask==0.11.1
redis==2.10.5

E por fim o Dockerfile do worker tem o seguinte conteúdo:

FROM python:2.7
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . /code
WORKDIR /code
CMD python app.py

No serviço redis, não há construção da imagem, pois usaremos a imagem oficial para efeitos de exemplificação.

Para realizar o teste de tudo que apresentado até então, realize o clone do repositório (https://github.com/gomex/exemplo-12factor-docker) e acesse a pasta factor8, executando o comando abaixo para iniciar os contêineres:

docker-compose up -d

Acesse os contêineres através do navegador na porta 80 (se utilizar toolbox é 192.168.99.100, caso contrário acesse a localhost). Tente atualizar a página e veja que apenas um nome aparecerá.

Por padrão o docker-compose executa apenas uma instância de cada serviço explicitado em seu docker-compose.yml. Para aumentar a quantidade de contêineres “worker” de apenas um para dois execute o comando abaixo:

docker-compose scale worker=2

Atualize a página no navegador novamente e verá que o nome do host vai alternar entre duas possibilidades, ou seja, as requisições estão sendo balanceadas para ambos contêineres.

Nessa nova proposta de ambiente, o serviço web se encarregará de receber todas requisições HTTP e fazer o balanceamento de carga. Então o worker será responsável por processar essas requisições, que basicamente é obter seu nome de host, acessar o redis e obter a contagem de quantas vezes esse serviço foi requisitado e então gerar o retorno, para então devolvê-lo para o serviço web, que por sua vez responderá ao usuário. Como podem perceber, cada instância desse ambiente tem sua função bem definida e com isso será muito mais fácil escalá-lo.

Aproveito para dar os créditos ao capitão Marcosnils, que foi a pessoa que me mostrou que é possível balancear carga pelo nome da rede docker.

Um agradecimento especial para @glesio@JFCostta e bemanuel_pe que fizeram uma ótima revisão desse texto.

Docker 1.12 – O que vem por aí

Oi Pessoal,
Já vimos aqui no blog algumas ferramentas e soluções, como por exemplo: Docker Compose, Docker Swarm, SwarmkitDocker Network, dentre outros. Bom, o que você sabe sobre elas é essencial para entender a nova versão do Docker, que será lançada em agosto e que está em RC4 atualmente.

A grande novidade no Docker 1.12 é ter a orquestração nativa, sem a necessidade de ter duas ou mais ferramentas para criar seu cluster de Docker, basta apenas que você tenha a engine instalada e a partir dela poderá montar seu ambiente. Outra grande novidade é o conceito de serviço, esse conceito nós já tratamos em Swarmkit, e é algo que foi incorporado ao Docker para facilitar o deploy e escalonamento das aplicações. Vamos ver o que muda?

Orquestração:

Agora para você criar um cluster de Docker, basta rodar:

docker swarm init

Com isso você iniciará o primeiro nó do cluster, para adicionar mais nós ao cluster execute o seguinte comando em outro nó:

docker swarm join IP-DO-MANAGER:2377

Veja na imagem abaixo a sequência de comandos:

docker_swarm

Serviços:

No Docker 1.12 foi introduzido o conceito de serviço, que já existe no Kubernetes, e que agora possibilita a criação, atualização e escalonamento da sua camada de serviço (seja ela de frondend ou backend) de forma muito mais fácil. Por exemplo:

docker service create --replicas 1 --name servico1 alpine echo "Ola Mundo"

Dessa forma você estará criando um serviço com um container de Alpine, você pode aumentar a quantidade de containers que irão atender este serviço, para isso execute:
docker_service

Além de poder criar e escalonar, você pode ainda realizar a atualização de seu ambiente, basta utilizar o comando update, e pode ainda definir uma politica de atualização (por exemplo, executar a atualização em um container por vez, com isso ele removerá um container e iniciará um novo baseado na nova imagem). Você pode ainda, definir um bloco de rede para cada serviço, com isso você isola totalmente os ambientes, veja:

docker service create --replicas 3 --name webservers --network web --publish 80:80/tcp nginx

Dessa forma, serão criados 3 containers (caso você tenha colocar 2 ou mais hosts no cluster de Swarm, será criado um container por host). O mais interessante nesse ambiente é que, se você acessar a porta 80 de qualquer host que esteja no cluster Swarm, seu acesso será redirecionado ao serviço, independente se o container esteja nele ou não, isso por que o Docker garante que o serviço esteja acessível mesmo que um nó venha a falhar. E como o Docker faz isso? Simples, através da 3 feature adicionada nessa versão:

Roteamento:

Quando você criar um cluster via Docker Swarm, o Docker se encarregará de atribuir ao serviço um identificador único dentro do cluster, com isso, quando for solicitado acesso á porta exposta na criação do serviço, o acesso será roteado para o container que é responsável por aquele serviço (ou mais de um é claro), ele faz isso através do algoritmo de routing mesh que está presente na engine, ele identifica quem possuí o container que atende o serviço e redireciona o trafego para ele, por isso é importante que, quando você criar um novo serviço define uma rede também, pois reduzirá o tempo de processamento que a engine precisará para identificar onde encontra-se o container.

Segurança:

Por último e não menos importante, vem a questão de segurança. No Docker 1.12, toda a comunicação do cluster é realizada via tls, e quem garante o rotacionamento desses certificados (renovação e deploy) assim como a criação de certificados para novos nós é o nó manager, que é eleito baseado em uma série de parâmetros (disponibilidade e saúde), mas que de maneira geral é o primeiro nó onde você iniciou o cluster. Os certificados são rotacionados de tempos em tempos, e você pode modificar essa politica também.

Há mais coisas? Claro! Foi adicionado também um sub comando do comando docker plugin que permite você plugar de forma mais fácil os plugins do Docker, quando você realizar um docker plugin install nome_do_plugin, lhe será informado ao que exatamente aquele plugin terá acesso, e poderá assim permitir ou não sua instalação.

Bacana né? Se gostou nos ajude divulgando o blog e caso tenha dúvida nos avise 😉

Grande Abraço!

Escalando o MySQL com Docker e MaxScale

Oi Pessoal,

Não, hoje o post não é nosso :). Mas queremos divulgar um ótimo conteúdo criado por um de nossos parceiros, o MySQLBox, que é um dos maiores blogs sobre o SGBD MySQL e é mantido por um grande amigo nosso.

Então não deixe de ler o post: Escalando Mysql com Docker e Maxscale e veja como o Docker pode ajudar a escalar seu ambiente de banco de dados de forma fácil e rápida.

Grande abraço!

Docker Machine

Olá!

Umas das ferramentas mais interessantes do ecossistema Docker, e que é mantido pela própria Docker é o Docker Machine, com ele é possível você fazer deploy de seu ambiente na infra-estrutura que desejar, você pode portar sua aplicação do seu notebook para AWS, Digital Ocean, ou o que for. Veja no vídeo um exemplo prático disso:

Você pode ainda integrar com Docker Compose, e automatizar ainda mais essas tarefas, legal né? Espero que tenham gostado, tendo dúvidas nos contatem, estamos dispostos a sanar todas as dúvidas.

Abraço!

Dockerizando aplicações – Vínculo de portas

Seguindo a lista do modelo 12factor, temos “Vínculos de portas” como sétima boa prática.

É comum encontrar aplicações que são executadas dentro de contêineres de servidores web, tal como Tomcat, ou Jboss, por exemplo. Normalmente essas aplicações são implantadas dentro desses serviços para que possam ser acessadas pelos usuários externamente.

Ego_network

Essa boa prática sugere que o aplicativo em questão seja auto-contido e dependa de um servidor de aplicação, tal como Jboss, Tomcat e afins. O software sozinho deve exportar um serviço HTTP e lidar com as requisições que chegar por ele. Isso quer dizer que nenhuma aplicação adicional deveria ser necessária para que seu código possa estar disponível para comunicação externa.

Tradicionalmente a implantação de aplicações em serviços de aplicação web, tal como Tomcat e Jboss, exigem que seja gerado um artefato e esse deve ser enviado para o serviço web em questão, mas no modelo de contêiner docker a idéia é que o artefato do processo de implantação seja o próprio contêiner em sí.

O processo antigo de implantação do artefato em um servidor de aplicação normalmente não tinha um retorno rápido e isso aumentava demasiadamente o processo de implantação de um serviço, pois cada alteração demandava enviar o artefato para o serviço de aplicação web, sendo que esse tinha como responsabilidade de importar, ler e executar o novo artefato.

Usando Docker facilmente torna a aplicação auto-contida. Já construímos um Dockerfile que descreve tudo que a aplicação precisa:

FROM python:2.7
ADD requirements.txt requirements.txt
RUN pip install -r requirements.txt
ADD . /code
WORKDIR /code
CMD python app.py
EXPOSE 5000

As dependências estão descritas no arquivo requirements.txt e os dados que devem ser persistidos são geridos por um serviço externo (serviços de apoio) à aplicação.

Um outro detalhe desta boa prática é que a aplicação deve exportar o serviço através da vinculação a uma única porta. Como podemos ver no código exemplo, a porta padrão do python (5000) é iniciada, mas você pode escolher outra, caso julgue necessário. Segue o recorte do código que trata desse assunto:

if __name__ == "__main__":
  app.run(host="0.0.0.0", debug=True)

Essa porta 5000 pode ser utilizada para servir dados localmente em um ambiente de desenvolvimento ou através de um proxy reverso quando for migrada para produção, com um nome de domínio adequado a aplicação em questão.

Utilizando esse modelo de vinculação de portas torna o processo de atualização de aplicação mais fluído, uma vez que na utilização de um proxy reverso inteligente, é possível adicionar novos nós gradativamente, com a nova versão, e remover os antigos a medida que as versões atualizadas estão sendo executadas em paralelo.

Convém salientar que mesmo que o Docker permita a utilização de mais do que uma porta por contêineres, essa boa prática é enfática ao afirmar que você só deve utilizar uma porta vinculada por aplicação.

Origens da Infra Ágil

Após o lançamento do site infraagil.io algumas pessoas me perguntaram sobre suas origens e sobre as motivações que levaram a criação do site e desse modelo.

Esse texto foi parte da versão “alpha” do site infraagil.io, hoje ele não está mais lá, foi retirado para deixar o conteúdo mais objetivo, contudo, seu contexto cabe neste blog.

Origens

Em 2011 eu dividi uma palestra com o colega Daniel Sobral (a.k.a Gandalf) no CONSEGI em Brasília/DF, o tema central da palestra era a gerência de configurações e os benefícios deste modelo para o Governo Federal. Tivemos um excelente quórum e o tema começou a se espalhar pela Esplanada de Ministérios, muitos profissionais queriam saber mais deste conceito e das tecnologias envolvidas.

Creio que aquela foi a primeira oportunidade que eu tive para abordar o momento em que eu vivia como sysadmin. O movimento DevOps estava no início da formação de sua cultura, não fazia nem um ano que John Willis e Damon Edwards haviam criado o acrônimo CAMS, iniciativa que deu norte para a comunidade DevOps. Sem nem saber ou conhecer direito este modelo, o time em que eu trabalhava já havia começado a estudar e experimentar algumas técnicas e métodos ágeis na operação, algo inovador dentro do governo brasileiro e principalmente inovador para a organização que havia nos contratado.

Marco Zero

Naquela época trabalhei em um time fantástico, pude aprender muito com profissionais experientes como Fernando Ike (@fernandoike), José Eufrásio Júnior (@coredump), Daniel Capó Sobral (@dcsobral), Daniel Negri (@danielnegri), Douglas Andrade (@douglasandrade) dentre outros.

Nós estudávamos constantemente, estávamos sempre experimentando e compartilhando experiências dentro e fora dos times. O @FernandoIke trabalhava na integração de todos os times de TI da organização, focando na comunicação, no compartilhamento de responsabilidades, na garantia de entrega e na disponibilidade de recursos para o time devel trabalhar traquilo e entregar o que o cliente precisava. Ele era o escudo da TI e nos ajudava a manter o foco. O @Coredump era o líder do time de infra, seu foco era inovação e autonomia, graças a ele nosso time começou a estudar automação de infraestrutura no final de 2010, testamos e usamos ali versões primitivas do Puppet e Chef. No final dos testes acabamos optando pelo Puppet e fizemos a primeira implantação em escala de centenas de nós no governo brasileiro.

Em 2010 nós já estávamos trabalhando com infraestrutura como código, gerência de configuração, orquestração, pipeline de deploys e métricas avançadas, respirávamos inovação dia-a-dia, e tudo isso foi construído em uma curta janela de um ano e meio.

 Foi um período fantástico da minha vida em que aprendi muito com todo o time.

Após a conclusão do projeto, cada um seguiu um rumo diferente , alguns foram morar no exterior, outros mudaram de área, outros se tornaram empresários, a vida seguiu seus rumos. Acredito que aquela experiência marcou todos daquele time, no meu caso foi um divisor claro, eu era um sysadmin artesão e comecei a dar os primeiros passos para um modelo de trabalho mais eficiente e autônomo.

Novos caminhos, novas parcerias

Alguns anos depois desta experiência, no início de 2014, depois de muitas aventuras pelo Governo Federal, eu conheci pessoalmente o Miguel Di Ciurcio Filho (@mciurcio), outro desses profissionais que pensam bem a frente do seu tempo. Enquanto eu desbravava datacenters na esplanada dos ministérios entre 2010 e 2014, na mesma época Miguel atuava com startups e incubadoras na região de Campinas e Barueri no estado de São Paulo. Ele trabalhou com tecnologias modernas e inovadoras na área de automação, banco de dados e virtualização. Sua experiência com desenvolvimento, em especial no Google Summer of Code, no qual ele atuou com o projeto QEMU, lhe deram um olhar único relativo a administração e gestão de infraestrutura de TI das organizações em que passou.

Todos esses caminhos , interesses comuns, a participação nas mesmas comunidades, os projetos que acompanhamos, tudo isto foi importante para o início de nossa parceria na Instruct, empresa que ele fundou em 2011 e empresa na qual faço parte desde 2014 após o seu convite.

Trabalhando com ele o espaço e o alcance que tive para estudar e aprimorar este modelo - dentro da Instruct - foi inimaginável, afinal, ambos tivemos experiências muito parecidas, seguimos escolas similares como sysadmins e através da Instruct encontramos as empresas que podiam se beneficiar da soma de nossas experiências.

De lá para cá temos construído e evoluído juntos essa abordagem da infra ágil que organizamos no site infraagil.io.

Não estamos mais sozinhos neste projeto, nós convidamos alguns parceiros que tem nos ajudado (Alliance Members) a organizar e melhorar esse modelo. O objetivo é fazer com o modelo cresça e alcance aqueles profissionais que precisam de uma referência clara para começar a transformar seus times e sua infraestrutura.

[s]
Guto

DevOpsDays POA Resumo

‪Galera o #‎DevOpsDays de ‪#‎PortoAlegre‬ foi um dos melhores eventos que participei nos últimos anos, focado, com público alinhado, tinha apenas 130 pessoas presentes, todos muito interessados, o evento manteve um alto nível em todas as suas palestras, teve humor, ignites, open spaces, fishbowl, networking e muito compartilhamento. ‪

#‎Recomendo‬

[s]
Guto

Novo projeto infraagil.io

Durante o TDC fizemos o lançamento do site infraagil.io.

Este site organiza boas práticas para serem aplicadas no seu time de operação e infraestrutura.

Recomendo a visita!

[]s
Guto

Grupos de TI no Telegram

No Brasil o Telegram acolheu grupos de comunidades de TI que discutem diversas tecnologias, seu crescimento tem sido espantoso e formidável, tem aproximado pessoas e ajudado a diminuir a curva de aprendizado de muitas tecnologias.

As listas de discussão ainda continuam vivas mas não são orgânicas e dinâmicas como o Telegram, talvez esse seja o segredo de seu sucesso somado ao seu conjunto incrível de recursos.

Grupos no telegram que eu recomendo!

Tecnologias

https://telegram.me/puppetbr
https://telegram.me/gitlabbr
https://telegram.me/vagrantbr
https://telegram.me/dockerbr
https://telegram.me/ansiblebr
https://telegram.me/chefbr
https://telegram.me/rancherbr
https://telegram.me/openshiftbr

elastic-users-br
mac-users-brasil

Comunidades

devops-br
infraagil.io

Linguagens

https://telegram.me/go_br
https://telegram.me/rubybrasil
https://telegram.me/pythonbr
https://telegram.me/PyCoding

Participe!

[s]
Guto