Conhecendo O Kubernetes - Clusters De Containers

| Comments

O que é Kubernetes

Kubernetes é uma solução Open Source desenvolvida pelo Google, originalmente chamada de K8s, como uma ferramenta para gerenciar clusters de containers (ou containeres, como prefira). Em 2005, quando a ferramenta foi desenvolvida, originalmente para uso interno, o Google doou o código à recém fundada Cloud Native Computing Foundation, em parceria com a The Linux Foundation.

O motivo do leme em sua logomarca é devido à origem grega da palavra, que vem de Kuvernetes, que representa a pessoa que pilota o navio, timoneiro.

Como objetivo primário o Kubernetes provê uma plataforma de automação para deployments, escalonamento e operações de containers de aplicações em um cluster de hosts ou nodes.

Antes de seguir com a explicação, instalação e configuração do Kubernetes, estou supondo que você já possui algum conhecimento básico sobre o que sejam containers e tenha alguma familiaridade com o Docker. Caso não possua um entendimento básico sobre containers e Docker, sugiro que leia algo antes de seguir com este artigo. Possuo um post introdutório sobre containers com um exemplo básico e prático sobre como criar containers com Docker, bem como iniciar uma simples aplicação web – aqui.

O Kubernetes é formado por uma série de componentes ou blocos que, quando utilizados coletivamente, fornecem um método de deployment, manutenção e escalonamento de clusters de aplicações baseadas em containers. Estes componentes, ou primitives como o Kubernetes os chama, foram desenvolvidos com o intuito de serem independentes, de forma que quase não se faz necessário ter conhecimento entre si para que possam funcionar e trabalhar juntos, visto que todos se comunicam e interligam através de uma API, sejam componentes internos do Kubernetes ou mesmo extensões e containers.

Embora tenha sido inicialmente desenvolvido para o deployment e utilização de bilhões de containers internamente no Google, desde que seu código passou a ser distribuído abertamente com a licença Apache Commons o Kubernetes tem sido adotado formalmente por praticamente todos os grandes provedores de serviços em nuvem.

Arquitetura do Kubernetes

Dentre os principais componentes do Kubernetes, vamos destacar os seguintes:

  • Master ou Master Controller – Host que será o gerenciador principal do Kubernetes, responsável por gerenciar os Minions ou Nodes do Cluster;

  • Nodes ou Minions – Embora normalmente a nomenclatura em diversos serviços de tecnolocia seja Node, o Kubernetes prefere chamar de Minions os hosts que fazem parte de um Cluster gerenciado pelo próprio Kubernetes. Este minion pode ser um servidor físico ou virtual, necessitando possuir um serviço de gerenciamento de containers, como o Docker, por exemplo;

  • ETCD – Embora este seja um serviço independente, estou listando-o aqui pois este será fundamental em seu ciclo de desenvolvimento com o Kubernetes. Cada Minion deverá rodar o ETCD (serviço de comunicação e gerenciamento de configurações no formato par de Chave/Valor). O ETCD é utilizado para troca e armazenamento de informações sobre os containers, pods, minions, etc.

  • Pods – São grupos de containers (um ou mais) rodando em um único minion do cluster. Cada Pod receberá um endereço IP único no Cluster como forma de possibilitar a utilização de portas sem a necessidade de se preocupar com conflitos;

  • Labels – São informações de identificação na configuração e gerenciamento dos objetos (como Pods ou Minions) formados de pares “chave:valor”;

  • Controllers – Além do Master Controller, dependendo do tamanho de sua infraestrutura e quantidade de Pods e Minions, você pode optar por ter mais de um Controller para dividir a carga e tarefas de gerenciamento. Os Controllers gerenciam um grupo de pods e, dependendo do estado de configuração desejada, podem acionar outros Controllers para lidar com as replicações e escalonamento. Os Controllers também são responsáveis pela substituiçao de Pods, caso um entre em estado de falha.

Instalação

Vamos ao que interessa…

Novamente estou supondo que você já possui alguma familiaridade com Containers, Docker e, por consequência, com GNU/Linux.

Eestarei utilizando 4 servidores virtuais rodando CentOS 7 nos exemplos a seguir, mas fica a seu critério decidir quantos utilizar.

Certamente você optar por utilizar outra distribuição, seja Debian, Ubuntu, etc.. Uma vez que optei pelo CentOS 7, estarei utilizando comandos voltados para esta distro, mas sinta-se livre para adaptar seus comandos, como substituir o “yum” pelo “apt-get”, “pacman”, etc..

Em minha configuração chamarei os servidores da seguinte forma:

  • centos-master
  • centos-minion1
  • centos-minion2
  • centos-minion3

A primeira coisa que se deve fazer sempre que se pensa em trabalhar com clusters, independente de ser um cluster de containers ou não, é ter a certeza de que os servidores terão uma correta sincronização de relógios entre si. A forma mais simples e eficiente no nosso contexto é com a utilização do NTP, portanto comece instalando o NTP nos 4 servidores, bem como habilitando o serviço e iniciando-o:

1
# yum install -y ntp
1
# systemctl enable ntpd && systemctl start ntpd

Caso queira certificar-se de que o serviço está realmente rodando:

1
2
3
4
5
6
7
8
9
10
# systemctl status ntpd

● ntpd.service - Network Time Service
   Loaded: loaded (/usr/lib/systemd/system/ntpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2017-06-24 17:46:02 UTC; 3s ago
  Process: 1586 ExecStart=/usr/sbin/ntpd -u ntp:ntp $OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 1587 (ntpd)
   Memory: 2.1M
   CGroup: /system.slice/ntpd.service
           └─1587 /usr/sbin/ntpd -u ntp:ntp -g

Pinga?

É importante nos certificarmos de que os servidores conseguem se comunicar e de que conseguem resolver nomes corretamente.

Neste exemplo, conforme informado mais acima, estamos utilizando 4 servidores com os seguintes nomes: centos-master, centos-minion1, centos-minion2 e centos-minion3, portanto vamos editar o arquivo /etc/hosts de cada um deles para que possam se comunicar pelos nomes que desejamos:

Insira as seguintes linhas no arquivo /etc/hosts dos 4 servidores:

Lembre-se de substituir os IPs pelos IPs dos servidores em seu ambiente

1
2
3
4
5
6
7
8
9
10
11
# Ip local do servidor master
172.31.22.126   centos-master

# Ip local do minion1
172.31.120.16   centos-minion1

# Ip local do minion2
172.31.25.6     centos-minion2

# Ip local do minion3
172.31.123.22   centos-minion3

Feito isto, tente pingar do master para os 3 minions utilizando os nomes especificados no /etc/hosts:

1
2
3
4
5
6
7
8
9
10
11
[root@kalib1 ~]# ping centos-minion1
PING centos-minion1 (172.31.120.16) 56(84) bytes of data.
64 bytes from centos-minion1 (172.31.120.16): icmp_seq=1 ttl=64 time=1.06 ms

[root@kalib1 ~]# ping centos-minion2
PING centos-minion2 (172.31.25.6) 56(84) bytes of data.
64 bytes from centos-minion2 (172.31.25.6): icmp_seq=1 ttl=64 time=0.588 ms

[root@kalib1 ~]# ping centos-minion3
PING centos-minion3 (172.31.123.22) 56(84) bytes of data.
64 bytes from centos-minion3 (172.31.123.22): icmp_seq=1 ttl=64 time=1.24 ms

Você pode realizar o mesmo teste a partir dos minions, pingando entre si e também para o centos-master.

Uma vez que tenhamos certeza de que todos os hosts se comunicam, é hora de instalar mais alguns pacotes necessários.

Primeiramente, vamos configurar o repositório do Docker para o CentOS 7:

Vamos criar o seguinte arquivo de repositório:

1
# vim /etc/yum.repos.d/virt7-docker-common-release.repos

O conteúdo deste arquivo será o seguinte:

1
2
3
4
[virt7-docker-common-release]
name=virt7-docker-common-release
baseurl=http://cbs.centos.org/repos/virt7-docker-common-release/x86_64/os/
gpgcheck=0

Este arquivo deverá ser criado nos 4 servidores.

Em seguida, vamos atualizar a nossa base de repositórios e pacotes, também nos 4 servidores, bem como habilitar o novo repositório para instalar os pacotes docker e kubernetes:

1
# yum update
1
# yum install -y --enablerepo=virt7-docker-common-release docker kubernetes

Como dito na introdução, também precisaremos do etcd para o armazenamento e troca de configurações, portanto vamos instalá-lo também nos 4 hosts:

1
# yum instal -y etcd

Configuração

Vamos começar com a configuração básica dos serviços envolvidos. Primeiramente, vamos abrir o arquivo de configuração do kubernetes e fazer algumas alterações:

/etc/kubernetes/config

No arquivo config altere as seguintes linhas:

Edite o valor do parâmetro KUBE_MASTER, de forma que nosso master possa ser encontrado pelo nome que definimos no hosts file. O valor original é “—master=http://127.0.0.1:8080”, portanto mudaremos para o seguinte:

1
KUBE_MASTER="--master=http://centos-master:8080"

Ainda neste arquivo de configuração, vamos inserir a configuração do serviço ETCD, portanto inclua a seguinte linha ao final do arquivo:

1
KUBE_ETCD_SERVERS="--etcd-servers=http://centos-master:2379"

Seu arquivo de configuração deverá estar similar a este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"

# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"

# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=false"

# How the controller-manager, scheduler, and proxy find the apiserver
KUBE_MASTER="--master=http://centos-master:8080"

KUBE_ETCD_SERVERS="--etcd-servers=http://centos-master:2379"

Repita esta mesma configuração nos 4 hosts. Todos eles devem utilizar exatamente os mesmos valores utilizados aqui, apontando KUBE_MASTER e KUBE_ETCD_SERVERS para centos-master, visto que este será o responsável por gerenciar todos os nossos minions.

Uma vez que o arquivo de configuração do kubernetes esteja pronto nos 4 hosts, vamos configurar o serviço de API do kubernetes:

/etc/kubernetes/apiserver

Esta configuração abaixo será apenas para o Master.

Edite o valor do parâmetro KUBE_API_ADDRESS, que originalmente é “—insecure-bind-address=127.0.0.1”, de forma que possamos novamente receber comunicação dos demais hosts.

1
KUBE_API_ADDRESS="--address=0.0.0.0"

Descomente as linhas KUBE_API_PORT e KUBELET_PORT, para que possamos estabelecer as portas de comunicação com a API:

1
2
3
4
5
# The port on the local server to listen on.
KUBE_API_PORT="--port=8080"

# Port minions listen on
KUBELET_PORT="--kubelet-port=10250"

Em nosso exemplo não utilizaremos o parâmetro KUBE_ADMISSION_CONTROL, o qual nos permite ter mais controles e restrições sobre quais nodes ou minios podem entrar em nosso ambiente, portanto vamos apenas comentar esta linha por enquanto:

1
2
# default admission control policies
# KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

Nosso arquivo /etc/kubernetes/apiserver deverá estar assim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
##
# kubernetes system config
#
# The following values are used to configure the kube-apiserver
#

# The address on the local server to listen to.
KUBE_API_ADDRESS="--address=0.0.0.0"

# The port on the local server to listen on.
KUBE_API_PORT="--port=8080"

# Port minions listen on
KUBELET_PORT="--kubelet-port=10250"

# Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379"

# Address range to use for services
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"

# default admission control policies
# KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

# Add your own!
KUBE_API_ARGS=""

Salve e feche o arquivo. Novamente, esta configuração deve ser feita apenas para o Master.

Agora vamos configurar o serviço ETCD:

/etc/etcd/etcd.conf

Esta configuração abaixo será apenas para o Master.

Edite os valores dos parâmetros ETCD_LISTEN_CLIENT_URLS e ETCD_ADVERTISE_CLIENT_URLS, que originalmente apontam para localhost. Como desejamos que nosso etcd escute requisições dos demais hosts, altere para o seguinte:

1
2
3
4
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
...
...
ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"

Novamente, não é necessário alterar a configuração do etcd nos demais hosts, apenas no Master.

Uma vez que as configurações iniciais foram feitas, vamos habilitar e iniciar os serviços necessários no Master, sendo eles:

  • etcd
  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler
1
# systemctl enable etcd kube-apiserver kube-controller-manager kube-scheduler
1
# systemctl start etcd kube-apiserver kube-controller-manager kube-scheduler

Os 4 serviços devem estar rodando. Para termos certeza, vamos checar o status dos mesmos:

1
2
3
4
5
# systemctl status etcd kube-apiserver kube-controller-manager kube-scheduler | grep "(running)"
   Active: active (running) since Sat 2017-06-24 21:45:37 UTC; 1min ago
   Active: active (running) since Sat 2017-06-24 21:46:13 UTC; 1min ago
   Active: active (running) since Sat 2017-06-24 21:44:25 UTC; 1min ago
   Active: active (running) since Sat 2017-06-24 21:44:25 UTC; 1min ago

Novamente, estes serviços serão iniciados no Master, e não nos nodes/minions, visto que estes utilizarão outros serviços.

Agora vamos configurar o seguinte arquivo nos nodes/minions:

/etc/kubernetes/kubelet

Este arquivo apenas deverá ser editado nos nodes/minions, não no Master.

Vamos alterar o valor do parâmetro KUBELET_ADDRESS para que aceite comunicação não apenas do localhost:

1
KUBELET_ADDRESS="--address=0.0.0.0"

Descomentaremos também a linha KUBELET_PORT, para que possamos ter uma porta definida para a comunicação do kubelet:

1
2
# The port for the info server to serve on
KUBELET_PORT="--port=10250"

Vamos alterar o valor do parâmetro KUBELET_HOSTNAME para o nome que definimos para cada um dos minions, portanto em cada um deles este será um valor diferente. Supondo que este seja o minion1, utilizaremos:

1
KUBELET_HOSTNAME="--hostname-override=centos-minion1"

Vamos também alterar o valor para KUBELET_API_SERVER, apontando para o nosso Master:

1
KUBELET_API_SERVER="--api-servers=http://centos-master:8080"

Vamos comentar a linha KUBELET_POD_INFRA_CONTAINER, visto que não utilizaremos uma infraestrutura de containers externa, pois estaremos utilizando nossos próprios PODs e containers:

1
2
# pod infrastructure container
#KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

Nosso arquivo deverá estar assim: (Lembrando que o parâmetro KUBELET_HOSTNAME deverá ser diferente para cada um dos 3 minions, respectivamente: centos-minion1, centos-minion2 e centos-minion3)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
###
# kubernetes kubelet (minion) config

# The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)
KUBELET_ADDRESS="--address=0.0.0.0"

# The port for the info server to serve on
KUBELET_PORT="--port=10250"

# You may leave this blank to use the actual hostname
KUBELET_HOSTNAME="--hostname-override=centos-minion1"

# location of the api-server
KUBELET_API_SERVER="--api-servers=http://centos-master:8080"

# pod infrastructure container
#KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

# Add your own!
KUBELET_ARGS=""

Uma vez que estas configurações também estão feitas nos 3 minions, vamos habilitar e iniciar os serviços necessários nos minions:

  • kube-proxy
  • kube-kubelet
  • docker
1
# systemctl enable kube-proxy kubelet docker
1
# systemctl start kube-proxy kubelet docker

Novamente, vamos ter certeza de que os 3 serviços estão rodando:

1
2
3
4
# systemctl status kube-proxy kubelet docker | grep "(running)"
   Active: active (running) since Sat 2017-06-24 21:44:23 UTC; 1h 16min ago
   Active: active (running) since Sat 2017-06-24 21:44:27 UTC; 1h 16min ago
   Active: active (running) since Sat 2017-06-24 21:44:27 UTC; 1h 16min ago

Novamente, estes 3 serviços devem ser habilitados e iniciados nos 3 minions.

Neste momento já temos nosso cluster rodando, com um master e 3 minions. :D

Testando o Cluster com o Kubernetes

Agora que temos a configuração básica de nosso Master Controller e de 3 minions, vamos testar nosso cluster.

Utilizaremos o utilitário kubectl (KubeControl) disponível com o kubernetes. Caso tenha interesse em ver os parâmetros e funções do mesmo… $ man kubectl

Vamos verificar a lista dos nodes ou minions que temos neste momento registrados em nosso Cluster. Vamos digitar alguns comandos em nosso Master Controller (centos-master):

1
2
3
4
5
[root@kalib1 ~]# kubectl get nodes
NAME             STATUS    AGE
centos-minion1   Ready     17m
centos-minion2   Ready     15m
centos-minion3   Ready     10m

Os três nodes criados e configurados anteriormente já são reconhecidos pelo nosso Kubernetes através do Master Controller. Além de registrados, estão com o status Ready, o que indica que estão prontos para funcionar e executar o que precisarmos.

Caso deseje conhecer mais parâmetros que a função get do kubectl possui, podemos invocar o manual desta função: $ man kubectl-get

Além do status, podemos conseguir diversas outras informações dos nodes através do kubectl: (Ex: kubectl describe nodes) Isto lhe daria informações sobre todos os nodes. Vamos experimentar com um node em específico.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
[root@kalib1 ~]# kubectl describe node centos-minion1
Name:                   centos-minion1
Role:
Labels:                 beta.kubernetes.io/arch=amd64
                        beta.kubernetes.io/os=linux
                        kubernetes.io/hostname=centos-minion1
Taints:                 <none>
CreationTimestamp:      Tue, 20 Jun 2017 19:27:31 +0000
Phase:
Conditions:
  Type                  Status  LastHeartbeatTime                       LastTransitionTime                      Reason     Message
  ----                  ------  -----------------                       ------------------                      ------     -------
  OutOfDisk             False   Sun, 25 Jun 2017 01:39:38 +0000         Fri, 23 Jun 2017 17:31:44 +0000         KubeletHasSufficientDisk    kubelet has sufficient disk space available
  MemoryPressure        False   Sun, 25 Jun 2017 01:39:38 +0000         Tue, 20 Jun 2017 19:27:31 +0000         KubeletHasSufficientMemory  kubelet has sufficient memory available
  DiskPressure          False   Sun, 25 Jun 2017 01:39:38 +0000         Tue, 20 Jun 2017 19:27:31 +0000         KubeletHasNoDiskPressure    kubelet has no disk pressure
  Ready                 True    Sun, 25 Jun 2017 01:39:38 +0000         Fri, 23 Jun 2017 17:31:54 +0000         KubeletReady                        kubelet is posting ready status
Addresses:              172.31.120.16,172.31.120.16,centos-minion1
Capacity:
 alpha.kubernetes.io/nvidia-gpu:        0
 cpu:                                   1
 memory:                                1015348Ki
 pods:                                  110
Allocatable:
 alpha.kubernetes.io/nvidia-gpu:        0
 cpu:                                   1
 memory:                                1015348Ki
 pods:                                  110
System Info:
 Machine ID:                    f9afeb75a5a382dce8269887a67fbf58
 System UUID:                   EC2C8A0E-91D6-F54E-5A49-534A6A903FDA
 Boot ID:                       20961efd-c946-481a-97cb-7788209551ae
 Kernel Version:                3.10.0-327.28.2.el7.x86_64
 OS Image:                      CentOS Linux 7 (Core)
 Operating System:              linux
 Architecture:                  amd64
 Container Runtime Version:     docker://1.12.6
 Kubelet Version:               v1.5.2
 Kube-Proxy Version:            v1.5.2
ExternalID:                     centos-minion1
Non-terminated Pods:            (0 in total)
  Namespace                     Name            CPU Requests    CPU Limits      Memory Requests Memory Limits
  ---------                     ----            ------------    ----------      --------------- -------------
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.
  CPU Requests  CPU Limits      Memory Requests Memory Limits
  ------------  ----------      --------------- -------------
  0 (0%)        0 (0%)          0 (0%)          0 (0%)
Events:
  FirstSeen     LastSeen        Count   From                            SubObjectPath   Type            Reason             Message
  ---------     --------        -----   ----                            -------------   --------        ------             -------
  15m           15m             1       {kubelet centos-minion1}                        Normal          Starting           Starting kubelet.
  15m           15m             1       {kubelet centos-minion1}                        Warning         ImageGCFailed      unable to find data for container /
  15m           15m             2       {kubelet centos-minion1}                        Normal          NodeHasSufficientDisk       Node centos-minion1 status is now: NodeHasSufficientDisk
  15m           15m             2       {kubelet centos-minion1}                        Normal          NodeHasSufficientMemory     Node centos-minion1 status is now: NodeHasSufficientMemory
  15m           15m             2       {kubelet centos-minion1}                        Normal          NodeHasNoDiskPressure       Node centos-minion1 status is now: NodeHasNoDiskPressure
  15m           15m             1       {kubelet centos-minion1}                        Warning         Rebooted           Node centos-minion1 has been rebooted, boot id: 20961efd-c946-481a-97cb-7788209551ae

Obviamente recebemos um retorno com muitas informações em formato Json, o que nem sempre é como esperamos. Existem formas de filtrar os resultados e conseguir informações mais precisas, como o bom e velho grep:

1
2
[root@kalib1 ~]# kubectl describe node centos-minion1 | grep Addresses
Addresses:              172.31.120.16,172.31.120.16,centos-minion1

Você também pode utilizar expressões regulares e a sintaxe do próprio Kubernetes para consultas mais complexas, como por exemplo, formatar a minha saída Json de forma a pegar apenas a listagem de status dos meus nodes que estão com Ready = True:

1
2
3
4
5
[root@kalib1 ~]# kubectl get nodes -o jsonpath='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'| tr ';' "\n" | grep "Ready=True"

Ready=True
Ready=True
Ready=True

A sua criatividade é o limite. ;]

Não temos nenhum pod configurado, mas também poderíamos utilizar kubectl get para conseguir a listagem de nossos pods:

1
2
3
[root@kalib1 ~]# kubectl get pods

No resources found.

Criando pods

Assim como com o Docker, Ansible e algumas outras ferramentas, utilizaremos a linguagem YAML para criar nossos arquivos de configuração.

Criaremos um diretório chamado Builds em nosso Master Controller apenas para melhor organizar nossos arquivos de configuração e ficar mais fácil encontrá-los no futuro:

1
2
3
# mkdir Builds

# cd Builds

Para criarmos Pods, o que fazemos na verdade é criar arquivos de configuração que vão dizer ao Kubernetes qual o estado em que desejamos nossa infraestrutura. O papel do Kubernetes é ler esta configuração e assegurar que o estado de nossa infraestrutura reflita o estado desejado.

Para facilitar, vamos utilizar exemplos encontrados na própria documentação do Kubernetes. Comecemos com a criação de um Pod para um servidor web Nginx.

Vamos criar um arquivo chamado nginx.yaml dentro do diretório Builds que criamos anteriormente:

1
# vim nginx.yaml

No arquivo indicaremos alguns atributos ou variáveis, bem como seus respectivos valores:

  • apiVersion – Indica a versão da API do kubernetes utilizada
  • kind – o tipo de recurso que desejamos
  • metadata – dados referentes ao recurso desejado
  • spec – especificações sobre o que este recurso irá conter

Vamos criar um Pod contendo um único container rodando a versão 1.7.9 do nginx bem como disponibilizando a porta 80 para receber conexões. Este deverá ser o conteúdo do arquivo nginx.yaml:

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.7.9
      ports:
      - containerPort: 80

Antes de executarmos, vamos nos certificar novamente de duas coisas:

  • Que realmente não temos nenhum Pod criado e ativo;
  • Que não temos nenhum container rodando em nossos nodes.

No centos-master:

1
2
3
[root@kalib1 Builds]# kubectl get pods

No resources found.

No centos-minion1: (Execute o mesmo comando nos demais nodes (centos-minion2 e centos-minion3))

1
2
3
[root@kalib2 ~]# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Novamente: Se você não faz ideia do que acabei de digitar, (docker ps) volte e leia um pouco sobre Docker antes de seguir com este artigo.

Como podemos ver, não temos nenhum Pod, bem como nenhum container rodando em nossos nodes.

Vamos utilizar kubectl create para criar o Pod utilizando o arquivo que criamos nginx.yaml: Executaremos este comando no Master Controller – centos-master

1
2
3
[root@kalib1 Builds]# kubectl create -f nginx.yaml

pod "nginx" created

O Kubernetes está dizendo que nosso Pod “nginx” foi criado. Vamos verificar:

1
2
3
4
[root@kalib1 Builds]# kubectl get pods

NAME      READY     STATUS    RESTARTS   AGE
nginx     1/1       Running   0          1m

O pod está criado e rodando. Agora, execute novamente docker ps nos 3 nodes para identificar em qual deles o container foi criado. Sim, como não especificamos nada, o Kubernetes vai verificar os recursos disponíveis no momento e vai lançar onde ele achar mais adequado.

1
2
3
4
5
[root@kalib4 ~]# docker ps

CONTAINER ID        IMAGE                                      COMMAND                  CREATED             STATUS              PORTS               NAMES
6de8e22e1536        nginx:1.7.9                                "nginx -g 'daemon off"   2 minutes ago       Up 2 minutes                            k8s_nginx.b0df00ef_nginx_default_d4debd3a-594c-11e7-b587-06827a5b32d4_583881e0
ae49b36ae11b        gcr.io/google_containers/pause-amd64:3.0   "/pause"                 2 minutes ago       Up 2 minutes                            k8s_POD.b2390301_nginx_default_d4debd3a-594c-11e7-b587-06827a5b32d4_fb5c834f

Sim, existem dois containers rodando. Um deles é o nosso “nginx”, enquanto que o outro é um container padrão do google chamado “/pause”, o qual será responsável pela manutenção de alguns recursos de nosso cluster.

Podemos novamente pedir a descrição deste pod que acabamos de criar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
[root@kalib1 Builds]# kubectl describe pod nginx

Name:           nginx
Namespace:      default
Node:           centos-minion3/172.31.123.22
Start Time:     Sun, 25 Jun 2017 02:20:18 +0000
Labels:         <none>
Status:         Running
IP:             172.17.0.2
Controllers:    <none>
Containers:
  nginx:
    Container ID:               docker://6de8e22e153618271bb6e8095c68070126541331c8acfc3f5d1a654f4b978454
    Image:                      nginx:1.7.9
    Image ID:                   docker-pullable://docker.io/nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451
    Port:                       80/TCP
    State:                      Running
      Started:                  Sun, 25 Jun 2017 02:20:27 +0000
    Ready:                      True
    Restart Count:              0
    Volume Mounts:              <none>
    Environment Variables:      <none>
Conditions:
  Type          Status
  Initialized   True
  Ready         True
  PodScheduled  True
No volumes.
QoS Class:      BestEffort
Tolerations:    <none>
Events:
  FirstSeen     LastSeen        Count   From                            SubObjectPath           Type            Reason     Message
  ---------     --------        -----   ----                            -------------           --------        ------     -------
  6m            6m              1       {default-scheduler }                                    Normal          Scheduled  Successfully assigned nginx to centos-minion3
  6m            6m              1       {kubelet centos-minion3}        spec.containers{nginx}  Normal          Pulling    pulling image "nginx:1.7.9"
  6m            6m              2       {kubelet centos-minion3}                                Warning         MissingClusterDNS   kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to DNSDefault policy.
  6m            6m              1       {kubelet centos-minion3}        spec.containers{nginx}  Normal          Pulled     Successfully pulled image "nginx:1.7.9"
  6m            6m              1       {kubelet centos-minion3}        spec.containers{nginx}  Normal          Created    Created container with docker id 6de8e22e1536; Security:[seccomp=unconfined]
  6m            6m              1       {kubelet centos-minion3}        spec.containers{nginx}  Normal          Started    Started container with docker id 6de8e22e1536

Obviamente que isto é apenas a configuração mais básica que se possa imaginar, sem storage, mapeamentos de portas, redirecionamentos, rotas, etc. A ideia é apenas uma apresentação inicial..o que é o Kubernetes.

Happy Hacking

Comments