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.
Entusiasta Open Source, seu principal foco é ir atrás de ideias novas e torna-las realidade através de soluções simples e eficientes, o menos é mais, e o dividir é multiplicar.
Uma das coisas que atormentam tanto a vida do pessoal de Dev quanto de Ops é saber o que está acontecendo com o seu ambiente. Como se resolve isso? Existem duas formas, que devem sempre trabalhar juntas, são elas: Monitoramento, para saber que vai dar problema antes do problema ocorrer :), e Gerencia de logs, para saber, depois de ocorrer algum problema, o que aconteceu com sua aplicação ou ambiente que ocasionou o comportamento inesperado.
Essa mesma abordagem deve ser utilizada quando se trabalha com containers também, para monitoria você já viu aqui e aqui algumas formas de como pode ser feito esse monitoramento. Para a gerencia de logs você deve pensar antes qual será a criticidade dessas informações para o debug de sua aplicação e resolução de algum imprevisto, outro ponto é: como preciso ou como gostaria de visualizar essas informações. Tendo resolvido essas duas questões você pode então optar:
Utilizar o comando docker logs: Com isso você terá as informações do que está sendo enviando para a console do container, ou seja,somente irá visualizar aquilo que estiver passando na console, você deve fazer com que sua aplicação envie as informações necessárias para a console do container. Caso sua aplicação salve o debug em arquivo de log você não conseguirá visualizar de forma fácil essa informação.
Utilizar plugins de log: Utilizando plugins você pode fazer com que qualquer log do container seja enviado para um serviço externo, isso garante que você poderá ter acesso a qualquer informação (seja do container ou app) de um único lugar.
O que vamos ver hoje é como você pode utilizar alguns dos plugins de logs mais conhecidos, isso é claro na prática
Fluentd
Um dos drivers de log mais fácil de se utilizar, com ele você pode enviar tanto o stderr quanto o stout para o serviço de logs externo, para isso basta você rodar:
docker run --log-driver=fluentd
É claro que você precisa passar alguns parâmetros, como por exemplo: “–log-opt fluentd-address=” onde você define qual será o destino de seus logs, geralmente será um host onde estará rodando o servidor Fluentd ou o endereço que esse serviço lhe fornecer. Por padrão a tag de busca será o id do container, com isso, quando você precisar consultar algum log deverá faze-lo pelo id do container que desejar.
Splunk
O Splunk é talvez uma das ferramentas para gerenciamento de log mais completo que se pode ter, e da mesma forma que o Fluentd, você precisa apenas definir esse driver como sendo de log:
docker run --log-driver=splunk
Você precisa definir algumas coisas antes, veja a lista:
splunk-token: Token utilizado para autenticação do container na API http;
splunk-url: Endereço do servidor de Splunk disponível, seja ele local ou na solução de cloud da Splunk;
splunk-source: Origem do log (se não definido ele coletará tudo);
splunk-sourcetype: Tipo do log (app, debug, etc);
splunk-index: Índice para os logs;
splunk-capath: Caminho do certificado;
splunk-caname: Nome para validação do certificado, por padrão ele pega pelo nome do splunk-url;
splunk-insecureskipverify: Desativa a verificação ssl para o seu host Splunk;
tag: Identificação do log na base, no caso do Docker você pode definir qualquer informação do container como tag, por exemplo: ID, Nome, Região, etc;
labels: Facilita a consulta do log posteriormente, você pode por exemplo consultar logs do container x que pertence a região Sul;
Claro que não poderia faltar a opção de enviar seus logs para o CloudWatch da AWS, e é o mais simples de se utilizar, por um motivo: Basta você ter conta na AWS e ativar o CloudWatch, não é necessário contratar um serviço cloud de terceiro ou subir um servidor de log local. Veja como você pode utiliza-lo:
docker run --log-driver=awslogs --log-opt awslogs-region=sa-east-1
Você deve definir para qual grupo de log deseja enviar os logs do container, e tenha cuidado pois dependendo do tipo de logs e quantidade, pode prejudicar a visualização do mesmo, então preste atenção no formato de log que estará enviando:
docker run --log-driver=awslogs --log-opt awslogs-region=sa-east-1 --log-opt awslogs-group=MeuGrupodeLog nginx
A autenticação é bem simples, você montar o seguinte volume: aws:~/.aws, dentro dessa pasta deve ter um arquivo chamado credentials com o seu AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, e AWS_SESSION_TOKEN Lembre-se que o usuário utilizado para isso deve ter no mínimo as seguintes permissões: logs:CreateLogStream e logs:PutLogEvents.
Espero ter ajudado, tenho alguma dúvida pode nos enviar por e-mail ou deixe nos comentários. E nos ajude divulgando o blog
Entusiasta Open Source, seu principal foco é ir atrás de ideias novas e torna-las realidade através de soluções simples e eficientes, o menos é mais, e o dividir é multiplicar.
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:
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.
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.
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.
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
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
Entusiasta Open Source, seu principal foco é ir atrás de ideias novas e torna-las realidade através de soluções simples e eficientes, o menos é mais, e o dividir é multiplicar.
O MundoDocker trás hoje para você um pequeno tutorial de como é possível criar uma imagem enxuta, somente com o que você precisa e utilizando menos espaço possível. Para isso será necessário utilizar uma das duas imagens mais limpas do Docker, são elas: Alpine ou BusyBox, nesse tutorial vamos focar na Alpine, uma das mais buscadas atualmente.
Para que não conhece, a Alpine é uma distribuição construída com musl libc e BusyBox, que é conhecida como canivete suíço, pois combina versões minúsculas de muitos utilitários comuns no UNIX em um único pequeno executável. Algumas características de Alpine:
Pequena
Enquanto a menor imagem para Docker precisa de cerca de 130MB de espaço em disco, a Alpine precisa de no máximo 8MB, isso faz com que, mesmo você montando todo o seu ambiente, ele nunca terá o mesmo tamanho do que se montando em um imagem tradicional, isso é ótimo, pois deixa o ambiente ainda mais enxuto e simples de migrar.
Simples
Você tem apenas aquilo que é necessário para o funcionamento de sua aplicação, se precisar de mais alguma biblioteca, é só instalar, você não precisa se preocupar em desativar ou remover lixos, eles simplesmente não existem.
Segura
Alpine foi desenvolvida pensando em segurança, e para garantir isso os desenvolvedores se preocuparam aprimorar os recursos de segurança do kernel como grsecurity/PaX, além disso, todos os binários foram compilados em executáveis independente de posição, isso previne alguns uso problemas relacionados a buffer overflow e outros tipos de ataques envolvendo estouro de pilha.
Mãos a obra?
Nosso exemplo consistirá em montarmos uma imagem de com Alpine e Nodejs, e vamos comparar o tamanho da nova imagem que montamos com Alpine e outras distros disponíveis.
A Aplicação:
Será algo bem simples, apenas uma aplicação olá mundo:
var http = require('http');
http.createServer(function(req,res) {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Exemplo Node.js Mundo Docker!');
}).listen(8080);
Colocamos o nome de app.js, não esqueça de criar o package.json com as dependências da aplicação:
{
"name": "docker_web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "First Last <[email protected]>",
"main": "app.js"
}
Agora criamos nosso Dockerfile:
FROM alpine:3.1
# Update
RUN apk add --update nodejs
# Cria a pasta da app
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Instala as dependencias da app
COPY package.json /usr/src/app/
RUN npm install
# copia a app
COPY . /usr/src/app
EXPOSE 8080
CMD ["node", "/usr/src/app/app.js"]
Não é nada muito complexo, basta você informar qual imagem base utilizará, e a diferença está no instalador de dependências, que para o Alpine é o apk. Agora vamos gerar a imagem:
docker build -t alpineteste .
Será gerado uma nova imagem com o nome de alpineteste, agora vamos comparar o tamanho dessa imagem com outras:
Lembrando, que utilizamos a imagem base de cada distribuição e em cima dela instalamos o node e subimos essa aplicação, note que a diferença é exorbitante, isso por que a Alpine tem apenas o que é necessário para essa aplicação rodar, nada além disso.
Como podem ver, utilizando essa abordagem seu ambiente fica ainda mais escalável, e claro ainda mais portável, pois quanto menos a sua imagem, melhor é para transitar ela entre os hosts (não é necessário baixar megas e megas da imagem no primeiro deploy por exemplo) .
Entusiasta Open Source, seu principal foco é ir atrás de ideias novas e torna-las realidade através de soluções simples e eficientes, o menos é mais, e o dividir é multiplicar.
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:
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
Trabalha em uma consultoria com foco em Plataforma como Serviço (PaaS), é especialista em Cloud Computing e Conteinerização, desenvolve todo dia uma nova maneira de resolver problemas e criar coisas novas.
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.
Entusiasta Open Source, seu principal foco é ir atrás de ideias novas e torna-las realidade através de soluções simples e eficientes, o menos é mais, e o dividir é multiplicar.
Começamos 2019 e ficou bem claro que o Docker Swarm perdeu para o Kubernetes na guerra de orquestradores de contêineres.
Não vamos discutir aqui motivos, menos ainda se um é melhor que outro. Cada um tem um cenário ótimo para ser empregado como já disse em algumas das minhas palestras sobre o assunto. Mas de uma maneira geral se considerarmos o requisito evolução e compararmos as duas plataformas então digo que se for construir e manter um cluster de contêineres é melhor já começarmos esse cluster usando Kubernetes.
O real objetivo desse artigo é mostrar uma das possíveis abordagens para que nossas aplicações hoje rodando num cluster Docker Swarm, definidas e configuradas usando o arquivo docker-compose.yml possam ser entregues também em um cluster Kubernetes.
Intro
Já é meio comum a comparação entre ambos e posso até vir a escrever algo por aqui mas no momento vamos nos ater a um detalhe simples: cada orquestrador de contêineres cria recursos próprios para garantir uma aplicação rodando. E apesar de em alguns orquestradores recursos terem o mesmo nome, como o Services do Docker Swarm e o Services do Kubernetes eles geralmente fazem coisas diferente, vem de conceitos diferentes, são responsáveis por entidades diferentes e tem objetivos diferentes.
O Kompose, uma alternativa
O kompose é uma ferramenta que ajuda muito a converter arquivos que descrevem recursos do Docker em arquivos que descrevem recursos do Kubernetes e até dá para utilizar diretamente os arquivos do Docker Compose para gerir recursos no Kubernetes. Também tenho vontade de escrever sobre ele, talvez em breve, já que neste artigo vou focar em como ter recursos do Docker Swarm e do Kubernetes juntos.
Um pouco de história
Sempre gosto de passar o contexto para as pessoas entenderem como, quando e onde foram feitas as coisas, assim podemos compreender as decisões antes de pré-julgarmos.
Na Dockercon européia de 2017, a primeira sem o fundador Solomon Hykes, foi anunciado e demostrado como usar um arquivo docker-compose.yml para rodar aplicações tanto num cluster Docker Swarm quanto num cluster Kubernetes usando a diretiva Stacks.
A demostração tanto na Dockercon quanto no vídeo acima foram sensacionais. Ver que com o mesmo comando poderíamos criar recursos tanto no Docker Swarm quanto no Kubernetes foi um marco na época. O comando na época:
Só tinha um problema, isso funcionava apenas em instalações do Docker Enterprise Edition ($$$) ou nas novas versões do Docker for Desktop que eram disponíveis apenas para OSX e Windows.
Aí você pergunta: Como ficaram os usuário de Linux nessa história, Wsilva?
Putos, eu diria.
Protecionismo?
Assim como outros também tentei fazer uma engenharia reversa e vi que o bootstrap desse Kubernetes rodando dentro do Docker for Mac e Windows era configurado usando o Kubeadm. Fucei, criei os arquivos para subir os recursos Kubernetes necessários e quase consegui fazer rodar mas ainda me faltava descobrir como executar o binário responsável por extender a api do Kubernetes com os parâmetros certos durante a configuração de um novo cluster, todas as vezes que rodei tive problemas diferentes.
Até postei um tweet a respeito marcando a Docker Inc mas a resposta que tive foi a que esperava: a Docker não tem planos para colocar suporte ao Compose no Linux, somente Docker for Desktop e Enterprise Edition.
Ainda bem antes de tentar fazer isso na mão, lá na Dockercon de 2018 (provavelmente também escreverei sobre ela) tive a oportunidade de ver algumas palestras sobre extender a API do Kubernetes, sobre como usaram Custom Resource Definition na época para fazer a mágica de interfacear o comando docker stack antes de mandar a carga para a API do Kubernetes ou para a API do Docker Swarm e também conversei com algumas pessoas no conference a respeito.
A desculpa na época para não termos isso no Docker CE no Linux era uma questão técnica, a implementação dependeria muito de como o Kubernetes foi instalado por isso que no Docker para Desktop e no Docker Enterprise, ambientes controlados, essa bruxaria era possível, mas nas diversas distribuíções combinadas com as diversas maneiras de criar um cluster Kubernetes seria impossível prever e fazer um bootstrap comum a todos.
Docker ainda pensando no Open Source?
Na Dockercon européia de 2018, praticamente um ano depois do lançamento do Kubernetes junto com o Swarm finalmente foi liberado como fazer a API do Compose funcionar em qualquer instalação de Kubernetes. Mesmo sem as instruções de uso ainda mas já com os fontes do instalador disponíveis (https://github.com/docker/compose-on-kubernetes) era possível ver que a estrutura tinha mudado de Custom Resource Definition para uma API agregada e relativamente fácil de rodar em qualquer cluster Kubernetes como veremos a seguir.
Mão na massa.
Para rodarmos essa API do Compose no Mac e no Windows, assim como no final de 2017, basta habilitar a opção Kubernetes na configuração conforme a figura e toda a mágica vai acontecer.
No Linux podemos trabalhar com o Docker Enterprise Edition ou com o Docker Community Edition.
Para funcinar com o Docker Community Edition primeiramente precisamos de um cluster pronto rodando kubernetes e podemos fazer teoricamente em qualquer tipo de cluster. Desde clusters criados para produção com Kops – (esse testei na AWS e funcionou), ou Kubespray, ou em clusteres locais como esse que criei para fins educativos: https://github.com/wsilva/kubernetes-vagrant/ (também funcionou), ou Minikube (também funcionou, está no final do post), ou até no saudoso play with kubernetes (também funcionou) criado pelo nosso amigo argentino Marcos Nils.
Para verificar se nosso cluster já não está rodando podemos checar os endpoints disponíveis filtrando pela palavra compose:
$ kubectl api-versions | grep compose
Pré requisitos
Para instalar a api do Compose em um cluster Kubernetes precisamos do etcd operator rodando e existem maneiras de instalar com e sem suporte a SSL. Mais informações podem ser obtidas nesse repositório.
Neste exemplo vamos utilizar o gerenciador de pacotes Helm para instalar o etcd operator.
Instalação
Primeiro criamos o namespace compose em nosso Kubernetes:
Se estivermos utilizando OSX, podemos instalar de maneira simples com homebrew.
$ brew install kubernetes-helm
Updating Homebrew...
Error: kubernetes-helm 2.11.0 is already installed
To upgrade to 2.12.3, run `brew upgrade kubernetes-helm`
$ brew upgrade kubernetes-helm
Updating Homebrew...
==> Upgrading 1 outdated package:
kubernetes-helm 2.11.0 -> 2.12.3
==> Upgrading kubernetes-helm
==> Downloading https://homebrew.bintray.com/bottles/kubernetes-helm-2.12.3.moja
######################################################################## 100.0%
==> Pouring kubernetes-helm-2.12.3.mojave.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
/usr/local/etc/bash_completion.d
zsh completions have been installed to:
/usr/local/share/zsh/site-functions
==> Summary
? /usr/local/Cellar/kubernetes-helm/2.12.3: 51 files, 79.5MB
No Linux podemos optar por gerenciadores de pacotes ou instalar manualmente baixando o pacote e colocando em algum diretório do PATH:
$ curl -sSL https://storage.googleapis.com/kubernetes-helm/helm-v2.12.1-linux-amd64.tar.gz -o helm-v2.12.1-linux-amd64.tar.gz
$ tar -zxvf helm-v2.12.1-linux-amd64.tar.gz
x linux-amd64/
x linux-amd64/tiller
x linux-amd64/helm
x linux-amd64/LICENSE
x linux-amd64/README.md
$ cp linux-amd64/tiller /usr/local/bin/tiller
$ cp linux-amd64/helm /usr/local/bin/helm
Estamos em 2019 então todos os clusters Kubernetes já deveriam estar rodando com RBAC (Role Base Access Control) por questões de segurança. Para isso devemos criar uma Service Account em nosso cluster para o tiller.
$ kubectl --namespace=kube-system create serviceaccount tiller
serviceaccount/tiller created
$ kubectl --namespace=kube-system
create clusterrolebinding tiller
--clusterrole=cluster-admin
--serviceaccount=kube-system:tiller
clusterrolebinding.rbac.authorization.k8s.io/tiller created
Neste exemplo fizemos o bind para o role cluster admin, mas seria interessante criar uma role com permissões mais restritas definindo melhor o que o helm pode ou não fazer em nosso cluster Kubernetes.
Podemos usar tando o kubectl como o docker cli para checar os status:
$ kubectl get stacks
NAME SERVICES PORTS STATUS CREATED AT
demo-stack 3 web: 80 Available (Stack is started) 2019-01-28T20:47:38Z
$ docker stack ls
--orchestrator=kubernetes
NAME SERVICES ORCHESTRATOR NAMESPACE
demo-stack 3 Kubernetes default
Podemos pegar o ip da máquina virtual rodando minikube com o comando minikube ip e a porta do serviço web-published e acessar no nosso navegador.
Se você está pensando em migrar seus workloads de clusters de Docker Swarm para clusters de Kubernetes você pode optar tanto pelo Kompose quanto pelo Docker Compose no Kubernetes.
Optando pelo Compose no Kubernetes podemos usar o Docker for Mac ou Docker for Windows, basta habilitar nas configurações a opção de cluster Kubernetes.
Se estiver no Linux pode optar por seguir os passos acima ou pagar pelo Docker Enterprise Edition.
Veja como cada uma dessas opções se adequa melhor aos seus processos e divirta-se.
Conhecido como Boina, Tom e Wsilva entre outros apelidos. Possui certificações Docker Certified Associate e ZCE PHP 5.3, autor do livro Aprendendo Docker, do básico à orquestração de contêineres publicado pela editora Novatec. Docker Community Leader em São Paulo, tem background em telecomunicações, programação, VoIP, Linux e infraestrutura.