Flannel+Etcd+Docker – Como criar e configurar uma sub-rede para fazer a comunicação entre containers Docker utilizando o Flannel

O objetivo deste tutorial é criar uma sub-rede utilizando o Flannel para fazer a comunicação entre os containers e consecutivamente entre aplicações, bancos de dados e etc.
E tem mais, se você vai criar um cluster com Kubernetes, CoreOS ou Docker Swarm+Compose é fundamental ter uma sub-rede para comunicação, e o Flannel é uma excelente opção; para não dizer a melhor.

Rede-Flannel

1. Introdução

Flannel é uma rede virtual (overlay network) utilizada para provisionar uma sub-rede para cada host do cluster; no nosso caso são hosts Docker.
Esta sub-rede vai permitir a alocação de ips para os containeres da rede.
O objetivo ao utilizar uma rede com Flannel é fazer a comunicação entre os containeres.

Quando você instala o Docker ele cria uma rede interna isolada, geralmente é uma rede 172.17.X.X. Se você tiver outros hosts Docker na rede os containeres não conseguirão se comunicar, por isto que precisamos do Flannel.

O Flannel utiliza como backend o Etcd para fazer o armazenamento das informações de rede. O Etcd é um sistema distribuído de armazenamento do tipo key=valor.

Então neste tutorial vamos utilizar o Flannel para fazer a comunição entre os containeres e o Etcd para o armazenamento das informações de rede.

2. Infraestrutura e pré-requisitos

Pré-requisitos.
* Docker instalado. Se preferir pode seguir este tutorial de instalação do Docker.
* 1 servidor para o Etcd.
* X servidores rodando o Docker. X são quantos hosts Docker você quiser.
* Sistema Operacional Centos 7 X86_64.

Infraestrutura deste Lab.

Etcd
etcd-01.devopslab.com.br

Hosts Docker
docker-engine-01.devopslab.com.br
docker-engine-02.devopslab.com.br
docker-engine-03.devopslab.com.br

3. Instalação do Etcd e definição de rede

Instalar o Etcd é fácil, você precisa apenas ter o repositório “extras” ativo no seu CentOS 7. O repositório extras já vem configurado mas de qualquer forma segue abaixo.

#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
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

Instalação do Etcd.

# yum install etcd

Altere o Bind do etcd para 0.0.0.0. Segue meu arquivo de configuração do etcd.

# cat /etc/etcd/etcd.conf |grep -v ^#

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"

Habilite o startup e inicie o Etcd.

systemctl enable etcd.service
systemctl start.service

Libera a porta 2379/tcp no firewall.

# firewall-cmd –add-port=2379/tcp
# firewall-cmd --permanent --add-port=2379/tcp

3.1 – Definição de rede

Crie um arquivo .json em qualquer pasta e defina sua rede.
#vi flannel-config.json

{
    "Network": "10.0.0.0/16",
    "SubnetLen": 24,
    "Backend": {
        "Type": "vxlan",
        "VNI": 1
     }
}

Agora crie uma chave (key=valor) no etcd com as informações da rede.

# etcdctl set /redeinternadevopslab.com.br/network/config < flannel-config.json

Key – /redeinternadevopslab.com.br/network/config
Valor – Conteúdo do arquivo flannel-config.json

Faça um “get” para verificar a criação da key=valor.

# etcdctl get /redeinternadevopslab.com.br/network/config
{
    "Network": "10.0.0.0/16",
    "SubnetLen": 24,
    "Backend": {
        "Type": "vxlan",
        "VNI": 1
     }
}

Seu Etcd já está com a rede definida, o próximo passo é configurar o Flannel nos clientes.

4. Instalação e configuração do Flannel nos hosts Docker

Agora precisamos instalar o agente Flannel em todos os hosts Docker. O repositório é o “extras”, o mesmo utilizado na instalação do Etcd, que provavelmente já exista no seu Centos 7.

# yum install flannel

Configuração do Flannel.
Edite o arquivo “/etc/sysconfig/flanneld” e altere as variáveis
FLANNEL_ETCD = Servidor do Etcd.
FLANNEL_ETCD_KEY = Key definida no Etcd.

Segue meu arquivo.

# cat  /etc/sysconfig/flanneld | grep -v ^#
FLANNEL_ETCD="http://etcd-01.devopslab.com.br:2379"
FLANNEL_ETCD_KEY="/redeinternadevopslab.com.br/network"

Habilite o startup e inicie o Flanneld.

# systemctl enable flanneld
# systemctl start flanneld

Se tudo correu bem, você vai ter uma nova interface de rede no seu host.

# ip addr | grep flannel
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
    inet 10.0.82.0/16 scope global flannel.1

Verifique se foi criado o arquivo “/run/flannel/subnet.env”, pois nele consta as definições de rede que serão cosultadas pelo Docker.

# cat /run/flannel/subnet.env 
FLANNEL_NETWORK=10.0.0.0/16
FLANNEL_SUBNET=10.0.82.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=false

4.1 – Configuração do Docker para a utilização do Flannel

Vamos editar o arquivo de definição do serviço Docker e informar para utilizar a rede Flannel.
Você pode consultar o arquivo docker.service com o comando “systemctl status docker”.
O que precisa ser alterado são estes 2 campos:
EnvironmentFile=-/run/flannel/subnet.env

ExecStart=/usr/bin/docker daemon -H fd:// $OPTIONS $DOCKER_STORAGE_OPTIONS –bip=${FLANNEL_SUBNET} –mtu=${FLANNEL_MTU}

Segue meu arquivo “/usr/lib/systemd/system/docker.service”.
# cat /usr/lib/systemd/system/docker.service

[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 reinicie o Docker para ele pegar a nova rede.

# systemctl restart docker

Eu tive que reiniciar o Docker umas 3 ou 4 vezes para ele assumir a nova rede.
Ou se você preferir reinicie todo o host Docker.

# ip addr | grep docker
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    inet 10.0.82.1/24 scope global docker0

Veja que agora existe a internface “docker0“.

5. Teste de comunicação entre containeres

Com o Flannel configurado, crie alguns containeres em hosts diferentes e faça teste de ping e telnet.
Cuidado com Firewall ativo nos hosts Docker pois pode bloquear sua comunicação. Crie as regras de Firewall ou simplesmente desative.

Teste 1.
Origem
Host Docker 1: 10.0.2.201
Container 1: 10.0.82.2

Destino:
Host Docker 2: 10.0.2.202
Container 2: 10.0.24.3

root@31bf8abfa529:/# ip a l eth0| grep inet' '
    inet 10.0.82.2/24 scope global eth0

root@31bf8abfa529:/# ping 10.0.24.3
PING 10.0.24.3 (10.0.24.3) 56(84) bytes of data.
64 bytes from 10.0.24.3: icmp_seq=1 ttl=62 time=6.25 ms
64 bytes from 10.0.24.3: icmp_seq=2 ttl=62 time=0.810 ms
64 bytes from 10.0.24.3: icmp_seq=3 ttl=62 time=1.72 ms

Teste 2.
Origem
Host Docker 2: 10.0.2.202
Container 2: 10.0.24.3

Destino:
Host Docker 1: 10.0.2.201
Container 1: 10.0.82.2

root@8b43f759f5d2:/# ip a l eth0| grep inet' '
    inet 10.0.24.3/24 scope global eth0

root@8b43f759f5d2:/# ping 10.0.82.2
PING 10.0.82.2 (10.0.82.2) 56(84) bytes of data.
64 bytes from 10.0.82.2: icmp_seq=1 ttl=62 time=4.77 ms
64 bytes from 10.0.82.2: icmp_seq=2 ttl=62 time=1.11 ms
64 bytes from 10.0.82.2: icmp_seq=3 ttl=62 time=1.18 ms

Teste 3.
Origem:
Host Docker 3: 10.0.2.203
Container 3: 10.0.81.3

Destino:
Host Docker 1: 10.0.2.201
Container 1: 10.0.82.2

root@c9c0a823ddf0:/# ip a l eth0| grep inet' '
    inet 10.0.81.3/24 scope global eth0

root@c9c0a823ddf0:/# ping 10.0.82.2
PING 10.0.82.2 (10.0.82.2) 56(84) bytes of data.
64 bytes from 10.0.82.2: icmp_seq=1 ttl=62 time=1.79 ms
64 bytes from 10.0.82.2: icmp_seq=2 ttl=62 time=1.15 ms
64 bytes from 10.0.82.2: icmp_seq=3 ttl=62 time=1.17 ms

Pronto! A comunicação entre seus containeres está funcionando, as aplicações vão alcançar umas às outras e sucesso.

Qualquer coisa estamos aí.

Leonardo Macedo Cerqueira