Introdução:
Antes de iniciar este exemplo prático, é necessário que você tenha o docker instalado na sua máquina. Docker é um software de containers, já o swarm é uma de suas ferramentas de clusterização.
Para um teste completo do material apresentado aqui, seria necessário termos diversas máquinas, isso pode ser feito usando máquinas virtuais, mas nem todos possuem disponível máquinas capazes de rodar mais de um sistema operacional ao mesmo tempo, portanto vamos focar apenas no exemplo de swarm rodando em apenas uma máquina.
Aqui vamos construir um cluster docker swarm, que servirá como guia de como fazer isso com sua aplicação. Por isso, o primeiro passo será construir as imagens do Docker, necessárias para rodar nosso teste.
Para aproveitar bem o material apresentado aqui, é importante que você tenha conhecimento do que são e quais são as ferramentas de container, o que já foi mostrado anteriormente aqui mesmo no blog.
Docker Swarm
O Swarm já faz parte da instalação do Docker, então nada mais é necessário para acompanhar este tutorial, além de uma instalação básica do Docker.
Para testar se está tudo ok, acesse o terminal da sua máquina e digite:
$ docker swarm init
Swarm initialized: current node (yj7woptvnye02ad0cckypiozw) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4w6b5ebqb8bgydglgtrc1kwqbq33ady86bbvz2qxjd7dqovgga-5ts220sngpt4ptzssux7upp2z 192.168.1.45:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Pronto, se a mensagem de inicialização aparecer como mostrado acima, está tudo certo e podemos continuar. Se o docker não estiver instalado na sua máquina, procure um tutorial de como fazer isso na sua máquina, é um processo bem simples.
Para o Swarm, computadores serão chamados de nós, e estes nós podem ter dois papéis em um cluster swarm:
- Manager node - são os nós administratores, onde temos disponíveis os comandos de administração e controle do Swarm
- Worker node - que são os nós onde o seu software será realmente executado, por exemplo se estivermos falando de um webservice, é aqui que vai rodar o seu servidor web.
Construção das imagens:
Neste primeiro teste, vamos criar uma imagem simples com os seguintes arquivos:
$ ls -al
├──
Dockerfile ├── docker-compose.yml├── node_modules
(diretório) ├── package.json
├── package-lock.json
├── server.js
Conteúdo dos arquivos:
Dockerfile é o arquivo que contem as instruções de build da nossa imagem, nela definiremos quais são as dependencias, qual imagem será usada como base, quais comandos serão executados ao executar a nossa imagem.
docker-compose.yml é onde definiremos os serviços que estarão em nossa aplicação, aqui teremos a definição de qual serviço vai rodar e em qual porta da imagem, isso acontecerá.
package-(lock).json estes dois arquivos json são dependencias do npm, que é a ferramenta que estamos usando aqui para constuir e executar nosso serviço. Package.json contem dependencias e metadados do nosso projeto, package-lock.json é um arquivo que tem travadas em versões específicas que não podem ser alteradas.
Os arquivos package.json e package-lock.json serão criados durante a inicialização do nosso container.
$ docker run --rm -v $(pwd):/home/node -w /home/node node:11.1.0-alpine npm init -y
$ docker run --rm -v $(pwd):/home/node -w /home/node node:11.1.0-alpine
npm i -S express
O primeiro comando irá criar o arquivo package.json com os valores padrão e o segundo irá baixar e instalar a imagem express, assim como suas dependencias, no arquivos package.json.
Agora vamos criar os conteúdo do arquivos server.js:
const express = require("express");
const os = require("os");
const app=express();
app.get("/", (req, res) => {
res.send("Olá do Swarm " + os.hostname());
});
app.listen(3000, () => {
console.log("O servidor está rodando na porta 3000");
});
Este pequeno pedaço de código, irá iniciar um servidor Express e irá mostrar uma mensagem que contem o identificador do container, o que é feito pelo os.hostname. Estranho não, o comando que chama hostname, retorna o id do container? Bom isso acontece no Docker para ser possível identificar de qual conteiner veio aquela mensagem, e é exatamente isso que queremos aqui. Quando tivermos mais de uma instancia rodando, eu gostaria de saber de onde veio aquela mensagem.
Agora ainda falta criar o Dockerfile, que é onde colocamos as instruções necessárias para criar nossas imagens do docker. Nela vamos pegar uma imagem do Node, e copiar nossos arquivos package.json, package-lock.json e server.js, e fazer ela instalar as dependencias, além de especificar o comando npm start como comando padrão de inicialização.
FROM node:11.1.0-alpine
WORKDIR /home/node
COPY . .
RUN npm install
CMD npm start
Repare que o comando Copy, está copiando os arquivos do diretório corrente, apra o diretório da imagem, para que este comando funcione, você deve rodá-lo obrigatoriamente, no diretório onde foram criados os arquivos deste post.
Como último passo, criaremos o arquivos docker-compose, que é quem contem o comportamento de build e de execução do nosso projeto:
version: '3'
services:
web:
build: .
image: dirceuprofessor/exemplo-swarm:1.0
ports:
- 80:3000
networks:
- mynet
networks:
mynet:
Aqui definimos um roteamento da porta http 80 para a 3000, ou seja, nosso servidor express, que estará rodando na porta 3000 da imagem, será exposto para fora, pela porta 80. Um outro ponto importante aqui, foi a definição da rede padrão desta imagem.
A construiçao desta imagem é feita pelo comando:
$ docker-compose build
Building web
Step 1/5 : FROM node:11.1.0-alpine
---> 4b3c025f5508
Step 2/5 : WORKDIR /home/node
---> Running in 5aff5c6ce487
Removing intermediate container 5aff5c6ce487
---> 41d6018e73d8
Step 3/5 : COPY . .
---> e839ab4d7f74
Step 4/5 : RUN npm install
---> Running in fa1fd458b20e
npm WARN node@1.0.0 No description
npm WARN node@1.0.0 No repository field.
audited 50 packages in 0.819s
found 0 vulnerabilities
Removing intermediate container fa1fd458b20e
---> 64607c63cf41
Step 5/5 : CMD npm start
---> Running in e7bc55781581
Removing intermediate container e7bc55781581
---> 2c8c0cd30ba7
Successfully built 2c8c0cd30ba7
Successfully tagged dirceuprofessor/exemplo-swarm:1.0
Para subir o serviço agora vamos usar o Swarm, note que usamos o docker-compose para fazer o build da nossa imagem, e isso aconteceu pois o Swarm não faz builds. O compose também é usado para criar imagens, porém apenas imagens que rodem localmente, o Swarm adiciona a possibilidade das imagens criadas, rodarem em várias máquinas diferentes, e com isso abre a possibilidade de construirmos um cluster.
$ docker stack deploy exemplo_swarm -c docker-compose.yml
Ignoring unsupported options: build
Creating service exemplo_swarm_web
Docker stack é o comando responsável por administrar as imagens do Swarm, e o comando deploy é responsável por colocar em execução uma imagem, aqui passamos o argumento -c que é para usar o arquivo de compose para isso. A última parte do comando é o nome que terá o nosso container, exemplo_swarm.
Repare também que a primeira mensagem que ele mostra é:
Isso acontece pois temos comando de build no arquivo de compose, mas o Swarm, como dito anteriormente, não faz os builds, então aqui ele ignora esses comandos.Ignoring unsupported options: build
A partir de agora, você já pode abrir o seu browser e testar se o serviço está funcionando, para isso basta acessar localhost.
A resposta será exibida on browser e conforme foi mostrado antes, a gente está mostrando o id do componente onde ele está rodando.
Repare que, ao listar as instancias dockers da minha máquina, eu obtenho o mesmo id que foi mostrado lá pelo browser, como era esperado.
Agora chegou a hora de criarmos um cluster com o docker, assim a gente pode scalar e criar quantas instâncias a gente quiser, no nosso caso estaremos testando com 4, para fazer isso basta executar o comando:
$ docker service scale exemplo_swarm_web=4
exemplo_swarm_web scaled to 4
overall progress: 4 out of 4 tasks
1/4: running
2/4: running
3/4: running
4/4: running
verify: Service converged
As 4 instâncias vão mudando de status, até chegar ao ponto onde todas estão executando, assim que todas estiverem rodando, ele fará uma checagem do status das aplicações e depois, se tudo estiver correto, ele mostra a mensagem de Serviço convergiu.
Para checar se todos as instâncias estão rodando, usamos o seguinte comando:
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
nuffnzzogy9y exemplo_swarm_web replicated 4/4 dirceuprofessor/exemplo-swarm:1.0 *:80->3000/tcp
Vejam que, com este comando, ele mostra metadados do nosso serviço, como id, nome, modo, quantidade de réplicas, a imagem que está sendo usada inclusive as portas que foram roteadas na nossa rede.
Também podemos listar todas as instancias e os status de cada uma delas, isso é feito através deste comando:
$ docker service ps exemplo_swarm_web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
wynr0t1zymdl exemplo_swarm_web.1 dirceuprofessor/exemplo-swarm:1.0 noteeleflow-dirceu Running Running 11 minutes ago
ibel5ffapl9m exemplo_swarm_web.2 dirceuprofessor/exemplo-swarm:1.0 noteeleflow-dirceu Running Running 9 minutes ago
mj3gwxoeqwy6 exemplo_swarm_web.3 dirceuprofessor/exemplo-swarm:1.0 noteeleflow-dirceu Running Running 9 minutes ago
rwh5m1yd1jo5 exemplo_swarm_web.4 dirceuprofessor/exemplo-swarm:1.0 noteeleflow-dirceu Running Running 9 minutes ago
Agora, se você pegar o seu navegador, e acessar localhost algumas vezes, ele irá mostrar ids diferentes da imagem, isso não é muito determinístico, mas atualizando a página você verá que os ids uma hora irão mudar.
O interessante é pensar no motivo deles mudarem, por que será que isso acontece? Bom o swarm possui um load balancer interno e hora ou outra ele repassa a chamada para um outro container.
Vejam que este teste foi feito em apenas uma máquina, mas isso poderia ser facilmente replicado em mais de uma máquina e você conseguiria construir um cluster de maneira muito fácil.
Apresentação
Nenhum comentário:
Postar um comentário