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

E os logs?

Oi Pessoal, tranquilo?

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;
  • env: Pode classificar por Dev, Test, Prod etc.

Veja um exemplo prático:

docker run --log-driver=splunk --log-opt splunk-token=SEUTOKENAQUI --log-opt splunk-url=https://servidor-splunk:8088 --log-opt splunk-capath=/etc/cert/cacert.pem --log-opt splunk-caname=SplunkDefaultCert --log-opt tag="{{.Name}}/{{.FullID}}" --log-opt labels=location --log-opt env=TESTE --env "TESTE=false" --label location=sul nginx

AWS Logs

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 😉

Abraço!

Resumo TDC-SP

Passando para informar que foi um prazer participar do TCP SP na trilha infra ágil. Este ano além de ajudar a coordenadar a trilha eu palestrei e abri o evento na sexta-feira em parceira com o Miguel Filho. Aproveitamos para lançar o site infragil.io durante a palestra, foi intenso e o feedback do pessoal foi bastante positivo.

Palestras apresentadas:

1) Infra Ágil do conceito a prática (Guto e Miguel)
2) Equipes Ágeis de infraestrutura (Guto)
3) Gerência de Configuração vs Orquestração (Miguel)

Gostei bastante de participar de um evento tão plural e diverso.

#‎Recomendo‬

[s]
Guto

Dockerizando aplicações – Processos

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

Com advento da automatização, e uma devida inteligência na manutenção das aplicações, hoje é esperado que a sua aplicação possa atender a picos de demandas com inicialização automática de novos processos, sem que isso afete negativamente o comportamento da mesma.

download (1)

Essa boa prática indica que processos de aplicações 12factor são stateless (não armazenam estado) e share-nothing. Quaisquer dados que precise persistir deve ser armazenado em um serviço de apoio stateful(que armazena o seu estado), tipicamente uma base de dados.

O objetivo final dessa prática é não fazer distinção se a aplicação está sendo executada na máquina do desenvolvedor ou em produção, pois nesse caso o que mudaria seria a quantidade de processos iniciados para atender as suas respectivas demandas, ou seja, na máquina do desenvolvedor poderia ser apenas um e em produção um número maior.

O 12factor indica que o espaço de memória ou sistema de arquivos do servidor pode ser usado brevemente como cache de transação única. Por exemplo, o download de um arquivo grande, operando sobre ele, e armazenando os resultados da operação no banco de dados.

Vale a pena salientar que um estado nunca deve ser armazenado entre requisições, não importando o estado do processamento da próxima requisição.

É importante salientar que ao seguir essa prática, uma aplicação nunca assume que qualquer coisa armazenada em cache de memória ou no disco estará disponível em uma futura solicitação ou job – com muitos processos de cada tipo rodando, as chances são altas de que uma futura solicitação será servida por um processo diferente, até mesmo em um servidor diferente. Mesmo quando rodando em apenas um processo, um restart (desencadeado pelo deploy de um código, mudança de configuração, ou o ambiente de execução realocando o processo para uma localização física diferente) geralmente vai acabar com todo o estado local (por exemplo, memória e sistema de arquivos).

Algumas aplicações demandam de sessões persistentes, para armazenar informações da sessão de usuários e afins. Essas sessões são usadas em futuras requisições do mesmo visitante, ou seja, se armazenado junto ao processo isso é uma clara violação dessa boa prática. Nesse caso o mais aconselhável é usar um serviço de apoio, tal como redis, memcached ou afins para esse tipo de trabalho externo ao processo, com isso será possível que o próximo processo, independente onde ele esteja, conseguirá obter as informações atualizadas.

A aplicação que estamos trabalhando não guarda nenhum dado local, e tudo que ela precisa é armazenado no Redis. Dessa forma não precisamos fazer adequação alguma nesse código para seguir essa boa prática, como podemos ver abaixo:

from flask import Flask
from redis import Redis
import 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__":
 app.run(host="0.0.0.0", debug=True)

Para acessar o código dessa prática, acesse o nosso repositório e acesse a pasta “factor6“.

Dockerizando aplicações – Construa, lance, execute

Seguindo a lista do modelo 12factor, temos “Construa, lance, execute” como quinta boa prática.

Em um processo de automatização de infraestrutura de implantação de software, precisamos ter alguns cuidados para que o comportamento do processo esteja dentro das expectativas e que erros humanos causem baixo impacto no processo completo do desenvolvimento ao lançamento em produção.

release

Visando organizar, dividir responsabilidade e deixar o processo mais claro, o 12factor indica que o código base para ser colocado em produção deva passar por três fases:

  • Construa é quando o código do repositório é convertido em um pacote executável. Nesse processo é onde se obtém todas as dependências, compila-se o binário e todos os ativos desse código.
  • Lance é quando o pacote produzido pela fase de construir é combinado com sua configuração. O resultado é o ambiente completo, configurado e pronto para ser colocado em execução.
  • Execute (também como conhecido como “runtime”) é quando um lançamento (aplicação + configuração daquele ambiente) é colocado em execução, iniciado com base nas configurações especificas do seu ambiente requerido.

Essa boa prática indica que sua aplicação tenha separações explícitas nas fases de Construa, Lance e Execute. Assim cada mudança no código da aplicação é construída apenas uma vez na etapa de Construa. Mudanças da configuração não necessitam de uma nova construção, sendo apenas necessário passar pelas etapas de lançar e executar.

Dessa forma é possível criar controles e processos claros em cada etapa, ou seja, caso algo ocorra na construção do código, uma medida pode ser tomada e até mesmo abortado o lançamento do mesmo, para que o código em produção não seja comprometido por conta do possível erro.

Com a separação das responsabilidades é possível saber exatamente em qual etapa o problema aconteceu e atuar manualmente caso necessário.

Os artefatos produzidos devem sempre ter um identificador de lançamento único, que pode ser o timestamp do seu lançamento (como 2011-04-06-20:32:17) ou um número incremental (como v100).

Com o uso de artefato único é possível garantir o uso de uma versão antiga, seja para um plano de retorno ou até mesmo para comparar comportamentos após mudanças no código.

Para atendermos essa boa prática precisamos primeiro construir a imagem Docker com a aplicação dentro, ou seja, ela será nosso artefato.

Teremos um script novo, que aqui chamaremos de build.sh, nesse arquivo teremos o seguinte conteúdo:

#!/bin/bash

USER="gomex"
TIMESTAMP=$(date "+%Y.%m.%d-%H.%M")

echo "Construindo a imagem ${USER}/app:${TIMESTAMP}"
docker build -t ${USER}/app:${TIMESTAMP} .

echo "Marcando a tag latest também"
docker tag ${USER}/app:${TIMESTAMP} ${USER}/app:latest

echo "Enviando a imagem para nuvem docker"
docker push ${USER}/app:${TIMESTAMP}
docker push ${USER}/app:latest

Como podem ver no script acima, além de construir a imagem ele envia a mesma para o repositório de imagem do docker.

Lembre-se que o código acima e todos os outros dessa boa prática estão nesse repositório na pasta “factor5“.

O envio da imagem para o repositório é parte importante da boa prática em questão, pois isso faz com que o processo seja isolado, ou seja, caso a imagem não fosse enviada para um repositório, ela estaria apenas no servidor que executou o processo de construção da imagem, sendo assim a próxima etapa precisaria necessariamente ser executada no mesmo servidor, pois ela precisará da imagem disponível.

No modelo proposto a imagem estando no repositório central, ela estará disponível para ser baixada no servidor caso ela não exista localmente. Caso você utilize uma ferramenta de pipeline é importante você ao invés de utilizar a data para tornar o artefato único, utilize variáveis do seu produto para garantir que a imagem que será consumida na etapa de Executar seja a mesma construída no Lançar. Ex. no GoCD temos as variáveis GO_PIPELINE_NAME e GO_PIPELINE_COUNTER que podem ser usadas em conjunto para garantir isso.

Com a geração da imagem podemos garantir que a etapa Construir foi atendida perfeitamente, pois agora temos um artefato construído e pronto para ser reunido a sua configuração.

E etapa de Lançamento é o arquivo docker-compose.yml em si, pois o mesmo deve receber as configurações devidas para o ambiente que se deseja colocar a aplicação em questão, sendo assim o arquivo docker-compose.yml muda um pouco e deixará de fazer construção da imagem, pois agora ele será utilizado apenas para Lançamento e Execução (posteriormente):

version: "2"
services:
  web:
    image: gomex/app:latest 
    ports:
     - "5000:5000"
    volumes:
     - .:/code
    labels:
     - 'app.environment=${ENV_APP}'
    environment:
     - HOST_RUN=${HOST_RUN}
     - DEBUG=${DEBUG}
     - PORT_REDIS=6379
     - HOST_REDIS=redis
  redis:
    image: redis:3.2.1
    volumes:
     - dados:/data
    labels:
     - 'app.environment=${ENV_APP}'
volumes:
  dados:
    external: false

No exemplo docker-compose.yml acima usamos a tag latest para garantir que ele usará sempre a ultima imagem construída nesse processo, mas como falei anteriormente, caso utilize alguma ferramenta de entrega contínua (Ex. GoCD) faça uso das suas variáveis para garantir o uso da imagem criada naquela execução específica do pipeline.

Dessa forma, lançamento e execução sempre utilizarão o mesmo artefato, a imagem Docker, construída na fase de construção..

E etapa de execução basicamente é executar o docker-compose com o comando abaixo:

docker-compose up -d

Dockerizando aplicações – Serviços de Apoio

Seguindo a lista do modelo 12factor, temos “Serviços de Apoio” como quarta boa prática.

Para contextualizar, serviços de apoio é qualquer aplicação que seu código consome para operar corretamente (Ex. Banco de dados, serviço de mensagens e afins).

attached-resources

Com objetivo de evitar que seu código seja demasiadamente dependente de uma determinada infraestrutura, essa boa prática indica que você, no momento da escrita do software, não faça distinção se o serviço é interno ou externo, ou seja, seu aplicativo deve estar pronto para receber parâmetros que farão a configuração do serviço correto e assim possibilitem o consumo de aplicações necessárias da solução proposta.

A aplicação exemplo sofreu algumas modificações para suportar essa boa prática:

from flask import Flask
from redis import Redis
import os
host_run=os.environ.get('HOST_RUN', '0.0.0.0')
debug=os.environ.get('DEBUG', 'True')
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__":
   app.run(host=host_run, debug=True)

Como você pode perceber no código acima, sua aplicação agora pode receber variáveis de ambiente para configurar o hostname e porta do serviço Redis, ou seja, nesse caso é possível configurar um host e porta da redis que você deseja conectar. E tudo isso pode, e deve, ser especificado no docker-compose.yml, que também passou por uma mudança para se adequar a essa nova boa prática:

version: "2"
services:
  web:
    build: .
    ports:
     - "5000:5000"
    volumes:
     - .:/code
    labels:
     - 'app.environment=${ENV_APP}'
    environment:
     - HOST_RUN=${HOST_RUN}
     - DEBUG=${DEBUG}
     - PORT_REDIS=6379
     - HOST_REDIS=redis
  redis:
    image: redis:3.2.1
    volumes:
     - dados:/data
    labels:
     - 'app.environment=${ENV_APP}'
volumes:
  dados:
    external: false

Como podemos observar nos códigos já explicados, a grande vantagem de se utilizar dessa boa prática é o fato da possibilidade de mudança de comportamento sem a necessidade de mudança do código, mais uma vez é possível viabilizar que o mesmo código que foi construído em um momento, possa ser reutilizado de forma semelhante tanto no notebook do desenvolvedor, como no servidor de produção.

Fique atento para armazenamento de segredos dentro do docker-compose.yml, pois esse arquivo será enviado para o repositório de controle de versão, ou seja, é importante pensar em outra estratégia de manutenção de segredos.

Uma estratégia possível é a manutenção de variáveis de ambiente no docker host e dessa forma você precisaria usar variáveis do tipo ${variavel} dentro do docker-compose.yml pra pode repassar essa configuração ou utilizar outro recurso mais avançado de gerenciamento de segredos.

Dockerizando aplicações – Configurações

Seguindo a lista do modelo 12factor, temos “Configurações” como terceira boa prática.

Quando estamos criando um software aplicamos um determinado comportamento dentro do código e normalmente ele não é parametrizável, ou seja, para que essa aplicação se comporte de uma forma diferente será necessário mudar uma parte do código.

docker1

A necessidade de modificar o código para trocar o comportamento da aplicação inviabiliza que a mesma seja executa em sua máquina (desenvolvimento) da mesma forma que será usada para atender os usuários (produção) e com isso acabamos com toda possibilidade de portabilidade, e sem isso qual seria a vantagem de se usar contêineres, certo?

O objetivo dessa boa prática é viabilizar a configuração da aplicação sem a necessidade de modificar o código da mesma.

Como o comportamento da aplicação varia de acordo com o ambiente onde ela está executando, sendo assim, as configurações devem ser feitas baseadas nisso.

Seguem abaixo alguns exemplo:

  • Configuração de banco de dados que normalmente são diferentes entre os ambientes
  • Credenciais para acesso a serviços remotos (Ex. Digital Ocean ou Twitter)
  • Qual nome de DNS será usado pela aplicação

Como já falamos anteriormente, quando a configuração está estaticamente explícita no código, será necessário modificar manualmente e efetuar um novo build dos binários a cada reconfiguração do sistema.

Como demonstramos na boa prática codebase, usamos uma variável de ambiente para modificar qual o volume que usaremos no redis, ou seja, de certa forma já estamos seguindo essa boa prática, mas iremos um pouco além e mudaremos não somente o comportamento da infraestrutura, mas sim algo inerente ao código em si.

Segue abaixo a aplicação modificada:

from flask import Flask
from redis import Redis
import os
host_run=os.environ.get('HOST_RUN', '0.0.0.0')
debug=os.environ.get('DEBUG', 'True')
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
   redis.incr('hits')
   return 'Hello World! %s times.' % redis.get('hits')
if __name__ == "__main__":
   app.run(host=host_run, debug=debug)

Lembrando! Para acessar o código dessa prática basta clonar esse repositório e acessar a pasta “factor3“.

Como podemos perceber, adicionamos alguns parâmetros na configuração do endereço usado para iniciar a aplicação web, que será parametrizado com base no valor da variável de ambiente “HOST_RUN” e a possibilidade de efetuar ou não o debug dessa aplicação com a variável de ambiente “DEBUG“.

Vale salientar que nesse caso a variável de ambiente precisa ser passada para o contêiner, ou seja, não basta ter essa variável no docker host. Ela precisa ser enviada para o contêiner usando o parâmetro “-e” caso utilize o comando “docker run” ou a instrução “environment” no docker-compose.yml:

version: "2"
services:
  web:
    build: .
    ports:
     - "5000:5000"
    volumes:
     - .:/code
    labels:
     - 'app.environment=${ENV_APP}'
    environment:
     - HOST_RUN=${HOST_RUN}
     - DEBUG=${DEBUG}
  redis:
    image: redis:3.2.1
    volumes:
     - dados:/data
    labels:
     - 'app.environment=${ENV_APP}'
volumes:
  dados:
    external: false

Para executar o docker-compose, deveríamos fazer da seguinte maneira:

export HOST_RUN="0.0.0.0"; export DEBUG=True ; docker-compose up -d

Como podem perceber no comando acima ele usará as variáveis de ambiente “HOST_RUN” e “DEBUG” do docker host para enviar para as variáveis de ambiente com os mesmos nomes dentro do contêiner, que por sua vez será consumido pelo código python. Em caso de não haver parâmetros ele assume os valores padrões estipulados no código.

Essa boa prática é seguida com ajuda do Docker, pois o código é o mesmo e a configuração é um anexo da solução, que pode ser parametrizada de maneira distinta com base no que for configurado nas variáveis de ambiente.

Se aplicação crescer bastante, as variáveis podem ser carregadas em arquivo e parametrizadas no docker-compose.yml com a opção “env_file”.

Dockerizando aplicações – Dependências

Seguindo a lista do modelo 12factor, logo após o base de código que tratamos nesse artigo, agora temos “Dependência” como segunda boa prática.
Na maioria das vezes que buscamos portar uma aplicação para modelo de contêiner uns dos retornos esperados é a portabilidade, ou seja, a ideia que você possa construir sua aplicação apenas uma vez e ela executar sem problemas em qualquer infraestrutura.

download

Essa boa prática sugere a declaração de todas as dependências necessárias para executar seu código, ou seja, você nunca deve assumir que algum componente já estará previamente instalado no ativo responsável por hospedar essa aplicação.
Para viabilizar o “sonho” da portabilidade, precisamos gerenciar corretamente as dependências da aplicação em questão, isso indica que devemos também evitar a necessidade de trabalho manual na preparação da infraestrutura que suportará sua aplicação.
Automatizar o processo de instalação de dependência é o grande segredo de sucesso para atender essa boa prática, pois caso a instalação da sua infraestrutura não seja automática o suficiente para viabilizar a inicialização sem erros, o atendimento dessa boa prática estará prejudicada.
Automatizar esses procedimentos colabora com a manutenção da integridade do seu processo, pois o nome dos pacotes de dependências e suas respectivas versões estariam especificadas explicitamente em um arquivo localizado no mesmo repositório que o código, que por sua vez seria rastreado em um sistema de controle de versão. Com isso podemos concluir que nada seria modificado sem que se tenha o devido registro.
O Docker se encaixa perfeitamente nessa boa prática, pois é possível entregar um perfil mínimo de infraestrutura para essa aplicação, que por sua vez se fará necessária a declaração explícita de suas dependências para que a aplicação funcione nesse ambiente.
A aplicação que usamos como exemplo foi escrita em Python. Como podem ver na parte do código abaixo ela necessita de duas bibliotecas para funcionar corretamente:

 from flask import Flask
 from redis import Redis

Essas duas dependências estão especificados no arquivo requirements.txt e esse arquivo será usado como um parâmetro do pip.
“O PIP é um sistema de gerenciamento de pacotes usado para instalar e gerenciar pacotes de software escritos na linguagem de programação Python” (Wikipedia)
O comando pip é usado, juntamente com o arquivo requirements.txt, na criação da imagem como foi demonstrado no Dockerfile da boa prática anterior (codebase):

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

Perceba que um dos passos do Dockerfile é instalar as dependências explicitamente descritas no arquivo requirements.txt com o gerenciador de pacotes pip do Python. Veja o conteúdo do arquivo requirements.txt:

flask==0.11.1
redis==2.10.5

É importante salientar a necessidade de se especificar as versões de cada dependência, pois como no modelo de contêiner as suas imagens podem ser construídas a qualquer momento, é importante saber qual versão específica a sua aplicação precisa, caso contrário poderemos encontrar problemas com compatibilidade caso uma das dependências atualize e não esteja mais compatível com a composição completa das outras dependências e a aplicação que a está utilizando.

Para acessar o código descrito aqui, baixe o repositório e acesse a pasta “factor2“.
Um outro resultado positivo do uso dessa boa prática é a simplificação da utilização do código por outro desenvolvedor. Um novo programador pode verificar nos arquivos de dependências quais os pré-requisitos para sua aplicação executar, assim como executar facilmente o ambiente sem a necessidade de seguir uma extensa documentação que raramente é atualizada.
Usando o Docker é possível configurar automaticamente o necessário para rodar o código da aplicação, seguindo com isso essa boa prática perfeitamente.

Dockerizando aplicações – Base de código

Estamos evoluindo continuamente para entregar aplicações cada vez melhores, em menor tempo, replicáveis e escaláveis. Porém os esforços e aprendizados para atingir esse nível de maturidade muitas vezes não são simples de se alcançar.

Atualmente notamos o surgimento de várias opções de plataformas para facilitar a implantação, configuração e escalabilidade das aplicações que desenvolvemos. Porém, para aumentar nosso grau de maturidade não podemos apenas depender da plataforma, precisamos construir nossa aplicação seguindo boas práticas.

Visando sugerir uma série de boas práticas comuns a aplicações web modernas, alguns desenvolvedores do Heroku escreveram o 12Factor app, baseado em uma larga experiência em desenvolvimento desse tipo de aplicação.

12factor (1)

“The Twelve-Factor app” (12factor) é um manifesto com uma série de boas práticas para construção de software utilizando formatos declarativos de automação, maximizando portabilidade e minimizando divergências entre ambientes de execução, permitindo a implantação em plataformas de nuvem modernas e facilitando a escalabilidade. Assim, aplicações são construídas sem manter estado (stateless) e conectadas a qualquer combinação de serviços de infraestrutura para retenção de dados (Banco de dados, fila, memória cache e afins).

Nesse capítulo falaremos sobre criação de aplicações como imagens docker com base no 12factor app, ou seja, a ideia é demonstrar as melhores práticas de como se realizar a criação de uma infraestrutura para suportar, empacotar e disponibilizar a sua aplicação com alto nível de maturidade e agilidade.

O uso do 12factor com Docker é uma combinação perfeita, pois muitos dos recursos do Docker são melhores aproveitados caso sua aplicação tenha sido pensada para tal. Dessa forma, nesse texto daremos uma ideia de como aproveitar todo potencial da sua solução.

Como exemplo, usaremos a aplicação abaixo:

from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
   redis.incr('hits')
   return 'Hello World! %s times.' % redis.get('hits')
if __name__ == "__main__":
   app.run(host="0.0.0.0", debug=True)

É uma aplicação simples, que será usada apenas como exemplo. Através de um serviço HTTP, ela exibe quantas vezes foi acessada. Essa informação é armazenada através de um contador numa instância Redis.

Agora vamos às boas práticas!

Base de código

Com o objetivo de facilitar o controle das mudanças de código, viabilizando a rastreabilidade das alterações, essa boa prática indica que cada aplicação deve ter apenas uma base de código e, a partir do mesmo, uma aplicação pode ser implantada em distintos ambientes, mas a base precisa ser a mesma. Vale salientar que essa boa prática é necessária caso pretenda praticar o Continuous Integration (CI), ou seja, o mesmo código deverá ser consumido pelo processo de integração contínua e posteriormente implantado em desenvolvimento, teste e produção, mudando apenas parâmetros específicos ao ambiente em questão.

Para essa explicação, criei um repositório de exemplo.

Perceba que todo nosso código está dentro desse repositório, organizado por prática em cada pasta, para facilitar a reprodução. Lembre de entrar na pasta correspondente a cada boa prática apresentada.

O Docker tem uma infraestrutura que permite a utilização de variável de ambiente para parametrização da infraestrutura, sendo assim o mesmo código terá um comportamento distinto com base no valor das variáveis de ambiente.

Aqui usaremos o Docker Compose para realizar a composição de todo ambiente, fazendo com que a configuração dos distintos serviços e sua comunicação seja facilitada.

codebase-deploys

Posteriormente, mais precisamente na terceira boa prática Configuração desse compêndio de sugestões, trataremos mais detalhadamente sobre parametrização da aplicação, por hora apenas aplicaremos opções via variável de ambiente para a arquitetura ao invés de utilizar internamente no código da aplicação.

Para configurar o ambiente de desenvolvimento para o exemplo apresentado temos esse arquivo docker-compose.yml:

version: '2'
services:
  web:
    build: .
    ports:
     - "5000:5000"
    volumes:
     - .:/code
    labels:
     - 'app.environment=${ENV_APP}'
  redis:
    image: redis
    volumes:
     - dados_${ENV_APP}:/data
    labels:
     - 'app.environment=${ENV_APP}'

O serviço redis será utilizado a partir da imagem oficial redis, sem modificação no momento e o serviço web será gerado a partir da construção de uma imagem Docker, que tem como base a imagem oficial do python 2.7. Criaremos nossa imagem através do seguinte Dockerfile:

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

Com posse de todos os arquivos na mesma pasta, iniciaremos o ambiente com o seguinte comando:

export ENV_APP=devel ; docker-compose -p $ENV_APP up -d

Como podemos perceber na configuração que acabamos de construir, a variável “ENV_APP” definirá qual volume será usado para persistir os dados que serão enviados pela aplicação web, ou seja, com base na mudança dessa opção teremos o serviço rodando com um comportamento diferente, mas sempre a partir do mesmo código, dessa forma seguindo perfeitamente a ideia dessa primeira boa prática.

SwarmKit

Oi Pessoal,

Hoje, você não pode pensar em utilizar Docker em produção em larga escala sem ter alguma forma de automação e orquestração dessa “coisa”, graças a comunidade e algumas empresas, temos ferramentas que podem nos auxiliar nessas tarefas, todas juntas ou em partes, é claro. Atualmente as ferramentas mais conhecidas para orquestração e scale em Docker são Kubernetes e Mesos, existem muitos projetos mantidos pela comunidade nesse sentido, mas nenhum deles com tanta representatividade quanto aos mencionados anteriormente. Para não ficar de fora desse mundo, a Docker vem trabalhando bastante em uma suite que atenda essa necessidade, e que futuramente seja incorporado ao Docker Data Center, o projeto chama-se Swarmkit, e hoje, aqui no MundoDocker, vamos ver um pouco mais sobre ele.

O Que é?

O Swarmkit é uma suite para escalonamento e orquestração para sistemas distribuídos, ele possui um sistema de descoberta de nós, agendamento de tarefas, e utiliza o raft-based consensus para coordenação do cluster.

O que tem de bom?

  • Como já mencionado, ele utiliza o raft-based consensus, isso garante uma melhor coordenação do cluster, eliminando assim o ponto único de falha.
  • Todo os nós do cluster Swarm conversam de forma segura, e para ajudar nisso o Swarmkit utiliza TLS para autenticação, autorização e transporte dos dados entre os nós.
  • Swarmkit foi projeto para ser simples, por isso ele é independente de base de dados externas, ou seja, tudo que você precisa para utiliza-lo já está nele.

Ele é composto basicamente de duas camadas: Worker e Manager nodes, para entender cada um:

Worker: Responsável por executar as tarefas utilizar um Executor, por padrão o Swarmkit vem com o Docker Container Executor, mas que pode ser trocado caso deseja.

Manager: Basicamente é o nó eleito pelo administrador para ser o ponto central de administração, lembrando que quanto você adiciona um nó no cluster de Swarm você define se esse nó será Manager ou não.

Como outras ferramentas, para o Swarmkit as tarefas são organizadas em serviços, e para esse serviço você define o que deseja fazer, por exemplo: Crie replicas desse serviço todo dia as 10h, ou: Atualize um container por vez baseado nessa nova imagem.

Features

  • Oquestração
  1. Estado desejado: O Swarmkit analise constantemente o cluster, garantindo que todos os serviços estejam de acordo com o pretendido pelo usuário, isso faz com que um serviço seja provisionado em outro nó caso algum falhe.
  2. Tipo de serviço: atualmente o Swarmkit suporta apenas 2 tipos: 1 – Replicas, onde você define quantas cópias daquele container deseja, e 2 – Global, onde você especifica o que deve ser executado em cada nó do cluster.
  3. Atualização: Você pode modificar a qualquer momento o estado de um serviço, seja para para-lo ou escala-lo, quando você atualiza um serviço, por padrão ele executa essa tarefa de atualização de uma vez só para todos os nós do cluster, mas você pode definir de outras duas formas essa atualização: 1 – Paralela, onde o administrador define quantas tarefas de atualização podem ser executadas por mês ou 2 – Delay, dessa forma o Swarmkit executará as tarefas de atualização de serviço de forma sequencial, ou seja, uma tarefa só será executada caso a anterior já tenha terminado.
  4. Politicas de restart: A camada de orquestração monitora o estado das tarefas e reage as falhas aplicando a regra definida pelo usuário, dentro dessas regras o administrador pode definir número máximo de tentativos de restart de um serviço, quanto tempo depois de uma falha esse serviço deve ser reiniciado, etc. Por padrão o Swarmkit reinicia o serviço dentro de outro nó disponível no cluster, isso garante que os serviços dos nós defeituosos sejam iniciados em outros nós o mais rápido possível.
  • Agendamento
  1. Recursos: O Swarmkit sabe, através das checagens constantes, como está a saúde de cada nó, com isso, quando um serviço precisa ser reiniciado ou realocado, por padrão essa tarefa será realizada no melhor nó do cluster;
  2. Restrições: O administrador pode limitar o reinicio de um serviço em determinados nós, isso pode ser feito através de labels, exemplo: node.labels.foo!=bar1
  • Gerenciamento de cluster
  1. State Store: Permite ter uma visão macro de todo o cluster, como suas informações ficam em memória, permite ao nó de gerenciamento tomar decisões de forma muito mais rápida e segura.
  2. Gerenciamento da topologia: O administrador pode alternar quais são os nós de gerenciamento e qual são os Workers através de chamadas de API ou CLI.
  3. Gerenciamento de nós: É possível definir um nó como pausado, por exemplo, com isso os serviços que estavam alocados neste nó serão iniciados nos demais nós, assim como a execução de novas tarefas permanece bloqueada.
  • Segurança
  1. TLS: Todos os nós se conversam através de TLS, e os nós de gerenciamento agem como autoridade certificadora de todos os demais nós, e são responsáveis pela emissão de certificados para os nós que entram no cluster.
  2. Politica de aceitação: O administrador pode aplicar regras de auto-aceitação, aceitação manual ou troca de chaves, isso claro na adição de novos nós ao cluster, por default o Swarmkit utiliza auto-aceitação.
  3. Troca de certificados: É possível definir a frequência com a qual serão alterados os certificados ssl utilizados para comunicação do cluster, por padrão o tempo é de 3 meses, mas pode-ser definir qualquer período maior que 30 minutos.

Vamos brincar?

Instalando

O Swarmkit foi desenvolvido em GO, então tenha todo o ambiente pré-configurado e claro, baixe os fontes para seu $GOPATH, você pode utilizar:

[root@docker1 ~]# go get github.com/docker/swarmkit/

Acesse o diretório, e execute:

[root@docker1 ~]# make binaries

Isso fará com que sejam instaladas as ferramentas para utilização do Swarmkit, em seguida você pode testar sua instalação:

[root@docker1 ~]# make setup
[root@docker1 ~]# make all

Agora adicione o swarmd e swarmctl ao seu $PATH e seja feliz utilizando ele, veja abaixo alguns exemplos.

Montando o Cluster

No primeiro nó, execute:

[root@docker1 ~]# swarmd -d /tmp/docker1 --listen-control-api /tmp/manager1/swarm.sock --hostname docker1

Nos demais nós, execute:

[root@docker2 ~]# swarmd -d /tmp/node-2 --hostname docker2 --join-addr 10.1.1.1:4242
[root@docker3 ~]# swarmd -d /tmp/node-3 --hostname docker3 --join-addr 10.1.1.1:4242

Você pode agora, utilizar outro host para administrar o cluster, no nosso exemplo utilizando o docker4, veja:

[root@docker4 ~]# export SWARM_SOCKET=/tmp/manager1/swarm.sock
[root@docker4 ~]# swarmctl node ls
ID             Name    Membership  Status  Availability  Manager status
--             ----    ----------  ------  ------------  --------------
6rj5b1zx4makm  docker1  ACCEPTED    READY   ACTIVE        REACHABLE *
91c04eb0s86k8  docker2  ACCEPTED    READY   ACTIVE        
nf6xx9hpf3s39  docker3  ACCEPTED    READY   ACTIVE        

Criando os serviços

Vamos começar devagar, veja como subir um ambiente em redis:

[root@docker4 ~]# swarmctl service create --name redis --image redis:3.0.5
6umyydpxwtzfs3ksgz0e

Listando os serviços:

[root@docker4 ~]# swarmctl service ls
ID                         Name   Image        Replicas
--                         ----   -----        ---------
6umyydpxwtzfs3ksgz0e      redis  redis:3.0.5  1

Inspecionando o serviço:

[root@docker4 ~]# swarmctl service inspect redis
ID                : 6umyydpxwtzfs3ksgz0e
Name              : redis
Replicass         : 1
Template
 Container
  Image           : redis:3.0.5

Task ID                      Service    Instance    Image          Desired State    Last State               Node
-------                      -------    --------    -----          -------------    ----------               ----
6umyydpxwtzfs3ksgz0e         redis      1           redis:3.0.5    RUNNING          RUNNING Up About an hour    docker1

Atualizando serviço:

Conforme mencionado anteriormente, podemos atualizar o status de um serviço, no nosso exemplo vamos aumentar o número de replicas dele, veja:

[root@docker4 ~]# swarmctl service update redis --replicas 6
6umyydpxwtzfs3ksgz0e

[root@docker4 ~]# swarmctl service inspect redis
ID                : 6umyydpxwtzfs3ksgz0e
Name              : redis
Replicas          : 6
Template
 Container
  Image           : redis:3.0.5

Task ID                      Service    Instance    Image          Desired State    Last State               Node
-------                      -------    --------    -----          -------------    ----------               ----
xaoyxbuwe13gsx9vbq4f         redis      1           redis:3.0.5    RUNNING          RUNNING Up About an hour     docker1
y8cu8nvl1ggh4sl0xxs4         redis      2           redis:3.0.5    RUNNING          RUNNING 10 seconds ago    docker2
ksv9qbqc9wthkrfz0jak         redis      3           redis:3.0.5    RUNNING          RUNNING 10 seconds ago    docker2
nnm9deh7t0op6rln3fwf         redis      4           redis:3.0.5    RUNNING          RUNNING 10 seconds ago    docker1
4ya5eujwsuc6cr7xlnff         redis      5           redis:3.0.5    RUNNING          RUNNING 10 seconds ago    docker3
9o4pmrz6q6pf9ufm59mk         redis      6           redis:3.0.5    RUNNING          RUNNING 10 seconds ago    docker3

Vamos atualizar a imagem do serviço?

[root@docker4 ~]# swarmctl service update redis --image redis:3.0.6
6umyydpxwtzfs3ksgz0e

[root@docker4 ~]# swarmctl service inspect redis
ID                : 6umyydpxwtzfs3ksgz0e
Name              : redis
Replicas          : 6
Template
 Container
  Image           : redis:3.0.6

Task ID                      Service    Instance    Image          Desired State    Last State                Node
-------                      -------    --------    -----          -------------    ----------                ----
xaoyxbuwe13gsx9vbq4f         redis      1           redis:3.0.6    RUNNING          RUNNING 5 seconds ago    docker3
y8cu8nvl1ggh4sl0xxs4         redis      2           redis:3.0.6    RUNNING          RUNNING 6 seconds ago    docker1
ksv9qbqc9wthkrfz0jak         redis      3           redis:3.0.6    RUNNING          RUNNING 5 seconds ago    docker2
nnm9deh7t0op6rln3fwf         redis      4           redis:3.0.6    RUNNING          RUNNING 6 seconds ago    docker1
4ya5eujwsuc6cr7xlnff         redis      5           redis:3.0.6    RUNNING          RUNNING 6 seconds ago    docker2
9o4pmrz6q6pf9ufm59mk         redis      6           redis:3.0.6    RUNNING          RUNNING 6 seconds ago    docker3

Por padrão todos os containers foram atualizados de uma única vez, isso tem suas vantagens e desvantagens, mas como explicado, você pode mudar essa execução para fazer em partes, veja:

[root@docker4 ~]# swarmctl service update redis --image redis:3.0.7 --update-parallelism 3 --update-delay 20s

Com isso, serão refeitos 3 containers por vez e entre eles terá um intervalo de 20 segundos.

Gerenciando nós

O Swarmkit monitora a saúde de cluster, e baseado nisso toma ações em cima dos serviços, você pode realizar ações manuais também, como por exemplo, retirar um nós do cluster, veja:

[root@docker4 ~]# swarmctl node drain docker1

[root@docker4 ~]# swarmctl node ls
ID             Name    Membership  Status  Availability  Manager status
--             ----    ----------  ------  ------------  --------------
6rj5b1zx4makm  docker1  ACCEPTED    READY   DRAIN         REACHABLE
91c04eb0s86k8  docker2  ACCEPTED    READY   ACTIVE        REACHABLE *
nf6xx9hpf3s39  docker3  ACCEPTED    READY   ACTIVE        REACHABLE

[root@docker4 ~]# swarmctl service inspect redis
ID                : 6umyydpxwtzfs3ksgz0e
Name              : redis
Replicas          : 6
Template
 Container
  Image           : redis:3.0.7

Task ID                      Service    Instance    Image          Desired State    Last State               Node
-------                      -------    --------    -----          -------------    ----------               ----
xaoyxbuwe13gsx9vbq4f         redis      1           redis:3.0.7    RUNNING          RUNNING 2 minute ago     docker2
y8cu8nvl1ggh4sl0xxs4         redis      2           redis:3.0.7    RUNNING          RUNNING 2 minute ago     docker3
ksv9qbqc9wthkrfz0jak         redis      3           redis:3.0.7    RUNNING          RUNNING 30 seconds ago    docker2
nnm9deh7t0op6rln3fwf         redis      4           redis:3.0.7    RUNNING          RUNNING 34 seconds ago    docker3
4ya5eujwsuc6cr7xlnff         redis      5           redis:3.0.7    RUNNING          RUNNING 28 minutes ago    docker2
9o4pmrz6q6pf9ufm59mk         redis      6           redis:3.0.7    RUNNING          RUNNING 29 seconds ago    docker3

O Swarmkit é uma ferramenta em desenvolvimento ainda, mas você pode utilizar ela em seus labs e entender um pouco melhor como pode trabalhar em cluster com Docker. Espero que tenham gostado, e nos ajude divulgando o blog 😉

Abraço!