Pular para o conteúdo principal

Configuração de Acesso Externo ao Cluster via Criação de Kubernetes Ingress

É possível utilizar dois tipos de ingress controllers para o Kubernetes gerenciado NNumbers Cloud: o ingress controller nativo da plataforma — que aparece como NNumbers Cloud Ingress Controller ou, em versões anteriores do painel, One Cloud Ingress Controller — e o Traefik.

Com base no tutorial Acessando o Cluster Infra (Kubernetes), vamos configurar nosso deploy para utilizar a classe Ingress do cluster. O ingress possibilita que as aplicações estejam acessíveis externamente ao cluster (e.g. via web).

O ingress nativo NNumbers Cloud configura um balanceador de carga de alta disponibilidade como serviço.

NNumbers Cloud Native Ingress sem TLS​

O comando abaixo cria e instala uma aplicação, seu serviço e seu ingress via um descritor de implantação (Deployment) de aplicação, um descritor de serviço (Service) e um descritor de ingress (Ingress).

cat <<EOF | kubectl apply -f -
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: webserver
namespace: default
labels:
app: webserver
spec:
replicas: 3
selector:
matchLabels:
app: webserver
template:
metadata:
labels:
app: webserver
spec:
containers:
- name: webserver
image: lingxiankong/alpine-test
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: webserver
spec:
type: NodePort
ports:
- name: http
targetPort: 8080
port: 8080
selector:
app: webserver
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: one-cloud-test-ingress-no-tls
annotations:
# NNumbers Cloud native ingress controller implementa o padrão openstack
kubernetes.io/ingress.class: "openstack"
# indica que deve ser ter IP flutuante visível para internet
octavia.ingress.kubernetes.io/internal: "false"
# define o IP flutuante que deve ser usado (precisa ser reservado antes
# da criação do ingress)
octavia.ingress.kubernetes.io/floatingip: "<IP-FLUTUANTE-PRE-RESERVADO>"
# indica que deve ser mantido o IP flutuante quando o ingress for excluído
octavia.ingress.kubernetes.io/keep-floatingip: "true"
# lista de CIDRs permitidos separados por vírgula
octavia.ingress.kubernetes.io/whitelist-source-range: "<LISTA-DE-CIDRS-SEPARADOS-POR-VIRGULA>"
# configuracoes de timeout do listener
octavia.ingress.kubernetes.io/timeout-client-data: "60000"
octavia.ingress.kubernetes.io/timeout-member-connect: "6000"
octavia.ingress.kubernetes.io/timeout-member-data: "60000"
octavia.ingress.kubernetes.io/timeout-tcp-inspect: "300000"
spec:
className: "openstack"
rules:
### Endereço do site para expor a aplicação
- host: app.meusite.com
http:
paths:
### Caso deseje acessar: meusite.com/ping
- path: /ping
pathType: Exact
backend:
service:
name: webserver
port:
number: 8080
EOF

Verificar se a porta 8080 do POD foi exposta:

Comando
kubectl get svc

Retorno:

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

webserver NodePort 10.254.60.247 <none> 8080:31770/TCP 9s

Obs.:

  • A anotação kubernetes.io/ingress.class com valor openstack é obrigatória para o uso do NNumbers Cloud Native Ingress, o qual segue os padrões Openstack de API e neste caso, a API de balanceamento de carga que é chamada de Octavia.

  • A anotação octavia.ingress.kubernetes.io/internal permite expor a aplicaçao para a WEB (valor false) ou somente para a rede interna (valor: true)

aviso

Uma vez que o valor seja alterado para true, um IP flutuante é atribuído e mesmo que false seja novamente atribuído, o IP flutuante não será automaticamente removido do balanceador de carga.

  • A anotação octavia.ingress.kubernetes.io/floatingip permite informar um IP pré-alocado. Para que esta anotação funcione é necessário que a anotação octavia.ingress.kubernetes.io/internal esteja definida como false.

  • A anotação octavia.ingress.kubernetes.io/keep-floatingip permite manter o IP flutuante após a exclusão do ingress. Para que esta anotação funcione é necessário que a anotação octavia.ingress.kubernetes.io/internal esteja definida como false.

  • A anotação “octavia.ingress.kubernetes.io/whitelist-source-range” permite informar uma lista de CIDRs que serão permitidos acessar os IPs do ingress e é opcional.

  • A anotação octavia.ingress.kubernetes.io/timeout-client-data refere-se a configuração do tempo limite de espera de inatividade do cliente em milissegundos. O valor padrão é 50000.

  • A anotação octavia.ingress.kubernetes.io/timeout-tcp-inspect refere-se a configuração do tempo de espera por pacotes TCP adicionais para inspeção de conteúdo em milissegundos. O valor padrão é 0.

  • A anotação octavia.ingress.kubernetes.io/timeout-member-connect refere-se a configuração do tempo limite de conexão do back-end membro de pool em milissegundos. O valor padrão é 5000.

  • A anotação octavia.ingress.kubernetes.io/timeout-member-data refere-se a configuração do tempo limite de inatividade do back-end membro de pool em milissegundos. O valor padrão é 50000.

  • Em .spec.rules[].host (app.meusite.com) é o endereço que estamos expondo o serviço. Ao acessar o endereço, ele deverá abrir a aplicação.

  • Em .spec.rules[].http.paths[].path (/ping) será o endereço final para acessar a aplicação, ficando da seguinte forma: app.meusite.com/ping

  • A anotação octavia.ingress.kubernetes.io/whitelist-source-range irá configurar o(s) CIDR(s) permitido(s) no listener do balanceador de carga (quando utilizado o ingress controller nativo da plataforma).

Aguarde um tempo e verifique se foi criado o ingress:

Comando
kubectl get ingress -n default

Retorno:

NAME CLASS HOSTS ADDRESS PORTS AGE

test-ingress <none> app.meusite.com 187.33.21.143 80 8m35s

Se tudo ocorreu de forma certa, você verá um endereço de IP. Esse endereço de ip pode ser usado no DNS do domínio para expor a aplicação na web. Ex.: app.meusite.com

Nossa aplicação de teste já está configurada no descritor de implantação (deployment descriptor) para ter 3 réplicas, entretanto, é possível aumentar ou reduzir esse número escalando horizontalmente (existem ainda formas de escalar verticalmente um pod, ou seja, aumentando a quantidade de recursos de CPU/VCPU e RAM, entretanto, para demonstrar o uso do ingress e balanceamento de carga iremos focar em escalonamento horizontal) para fora (scale out) ou para dentro (scale in) a aplicação via descritor de implantação (Deployment), via HPA (Horizontal Pod Autoscale) ou ainda com o comando abaixo:

kubectl scale deployment webserver -n default --replicas=<numero-de-replicas>

Para verificar quantas réplicas existem do pod da aplicação utilize o comando abaixo:

Comando
kubectl get pods -n default

Retorno:

AME READY STATUS RESTARTS AGE
webserver-69b47b55f5-qmztl 1/1 Running 0 10s
webserver-69b47b55f5-xrjlx 1/1 Running 0 29m
webserver-69b47b55f5-z4cwl 1/1 Running 0 10s

Para testar o balanceamento de carga da aplicação, iremos utilizar o código abaixo onde será realizado diversas requisições para a aplicação e como resultado deverá retornar o nome do pod (conforme lista anterior):

for _ in $(seq 1 8); do
curl -H "Host: app.meusite.com" \
http://$(kubectl get ing one-cloud-test-ingress-no-tls -o jsonpath='{.status.loadBalancer.ingress[].ip}')/ping;
done;

Exemplo de retorno:

webserver-69b47b55f5-xrjlx
webserver-69b47b55f5-z4cwl
webserver-69b47b55f5-xrjlx
webserver-69b47b55f5-qmztl
webserver-69b47b55f5-z4cwl
webserver-69b47b55f5-qmztl
webserver-69b47b55f5-z4cwl
webserver-69b47b55f5-xrjlx

NNumbers Cloud Native Ingress com TLS​

Para demonstrar quais artefatos e como configurar o Ingress com TLS, serão gerados certificados auto-assinados. Os comandos abaixo irão criar um arquivo chamado gen_certs.sh e a seguir gerar os certificados de autoridade certificadora (CA), o qual será usado posteriormente para teste e certificado auto-assinado com sua chave, os quais serão utilizados neste tutorial e no tutorial a seguir (TLS+SNI):

cat <<EOF> gen_certs.sh
#!/bin/sh

if [ "\$1" == "" ]; then
DEFAULT_DOMAIN="www.example.com"
read -p "Enter your server domain [\$DEFAULT_DOMAIN]: " DOMAIN
DOMAIN="\${DOMAIN:-\$DEFAULT_DOMAIN}"
else
DOMAIN=\$1
fi

echo \$DOMAIN
echo "Please enter your private key password: "
read -sr KEY_PASS

if [ ! -f ca.crt ]; then
echo "Create CA cert(self-signed) and key..."
CA_SUBJECT='/C=BR/ST=Sao Paulo/L=Sao Paulo/O=Nnumbers/OU=Cloud/CN=CA'
openssl req -new -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout ca.key -out ca.crt -subj "\$CA_SUBJECT" >/dev/null 2>&1
fi

echo "Create server key..."
openssl genrsa -des3 -out \${DOMAIN}-encrypted.key -passout pass:\${KEY_PASS} 2048 >/dev/null 2>&1
echo "Remove password..."
openssl rsa -in \${DOMAIN}-encrypted.key \
-traditional -out \${DOMAIN}.key -passin pass:\${KEY_PASS} \
-passout 'pass:' >/dev/null 2>&1

echo "Create server certificate signing request..."
SUBJECT='/C=BR/ST=Sao Paulo/L=Sao Paulo/O=Nnumbers/OU=Cloud/CN='\$DOMAIN
openssl req -new -nodes -subj "\$SUBJECT" \
-key \$DOMAIN.key \
-out \$DOMAIN.csr >/dev/null 2>&1

echo "Sign SSL certificate..."
openssl x509 -req -days 3650 -in \$DOMAIN.csr -CA ca.crt -CAkey ca.key \
-set_serial 01 -out \$DOMAIN.crt >/dev/null 2>&1

echo "Succeed!"
EOF


chmod +x gen_certs.sh

./gen_certs.sh
Enter your server domain [www.example.com]: app.meusite.com
Create CA cert(self-signed) and key...
Create server key...
Enter PEM pass phrase: <DIGITE-QUALQUER-SENHA> (e.g. 12345)
Verifying - Enter PEM pass phrase: <REPITA-A-SENHA>
Remove password...
Enter pass phrase for app.meusite.com-encrypted.key: <REPITA-A-SENHA>
Create server certificate signing request...
Sign SSL certificate...
Succeed!

ls

app.meusite.com-encrypted.key app.meusite.com.crt app.meusite.com.csr app.meusite.com.key ca.crt ca.key gen_certs.sh


./gen_certs.sh
Enter your server domain [www.example.com]: app.seusite.com
Create CA cert(self-signed) and key...
Create server key...
Enter PEM pass phrase: <DIGITE-QUALQUER-SENHA> (e.g. 12345)
Verifying - Enter PEM pass phrase: <REPITA-A-SENHA>
Remove password...
Enter pass phrase for app.meusite.com-encrypted.key: <REPITA-A-SENHA>
Create server certificate signing request...
Sign SSL certificate...
Succeed!

ls

app.meusite.com-encrypted.key app.meusite.com.crt app.meusite.com.csr app.meusite.com.key app.seusite.com-encrypted.key app.seusite.com.crt app.seusite.com.csr app.seusite.com.key ca.crt ca.key gen_certs.sh
aviso

Para que o balanceador de carga da cloud reconheça o certificado, o mesmo deve estar dentro do período de validade e ter pelo menos 2048 bits

Assumindo que você esteja de posse de arquivos de certificado (.crt) e chave (.key) sem senha, crie o segredo no Kubernetes contendo o certificado e a chave:

kubectl create secret tls meu-tls-secret \
--cert app.meusite.com.crt \
--key app.meusite.com.key
``

Em seguida crie o arquivo abaixo contendo a configuração do ingress, backend e serviço padrão para requisições não encontradas e checagem de saúde:

cat > tls.yaml << EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: default-http-backend
labels:
app: default-http-backend
version: "v1"
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: default-http-backend
template:
metadata:
labels:
app: default-http-backend
spec:
containers:
- name: default-http-backend
# Qualquer imagem é permitida, com tanto que:
# 1. Sirva uma página 404 em /
# 2. Sirva uma página 200 no endpoint /healthz
image: registry.k8s.io/defaultbackend-amd64:1.5
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: default-http-backend
namespace: default
labels:
app: default-http-backend
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
selector:
app: default-http-backend
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: one-cloud-test-ingress-tls
annotations:
# NNumbers Cloud native ingress controller implementa o padrão openstack
kubernetes.io/ingress.class: "openstack"
# indica que deve ser ter IP flutuante visível para internet
octavia.ingress.kubernetes.io/internal: "false"
spec:
defaultBackend:
service:
name: default-http-backend
port:
number: 80
tls:
- secretName: meu-tls-secret
hosts:
- app.meusite.com
rules:
- host: app.meusite.com
http:
paths:
- path: /ping
pathType: Exact
backend:
service:
name: webserver
port:
number: 8080
EOF

Por último, faça o deploy do backend, serviço e ingress:

kubectl apply -f tls.yaml

Você pode acompanhar a implantação do ingress verificando os eventos e/ou acompanhando o log do pod do ingress controller no namespace kube-system

kubectl get event -w
#
kubectl logs -v=5 -f -n openstack-system -l \
app.kubernetes.io/name=octavia-ingress-controller

Quando finalizado o processo de implantação, então você pode fazer o teste. O comando abaixo irá obter o IP flutuante do balanceador de carga e armazená-lo na variável de ambiente FLOATING_IP para ser utilizado nos testes seguintes:

FLOATING_IP=$(kubectl get ing one-cloud-test-ingress-tls -o jsonpath="{.status.loadBalancer.ingress[0].ip}" )

Execute os testes abaixos e verifique os resultados:

Comando
kubectl get pod

Retorno:

NAME READY STATUS RESTARTS AGE
default-http-backend-5b77d4454d-kfgps 1/1 Running 0 17h
webserver-5c74674fb8-kr8zf 1/1 Running 0 9d
webserver-5c74674fb8-m4wlt 1/1 Running 0 9d
webserver-5c74674fb8-vzfmh 1/1 Running 0 9d
Comando
curl --cacert certs/ca.crt \
--resolve app.meusite.com:443:${FLOATING_IP} \
https://app.meusite.com/ping && echo

Retorno:

webserver-5c74674fb8-vzfmh
Comando
curl --cacert ~/ingress/certs/ca.crt \
--resolve app.meusite.com:443:${FLOATING_IP} \
https://app.meusite.com && echo

Retorno:

default backend - 404
Comando
curl --cacert ~/ingress/certs/ca.crt \
--resolve app.meusite.com:443:${FLOATING_IP} \
https://app.meusite.com/healthz && echo

Retorno:

ok

NNumbers Cloud Native Ingress com TLS e extensão SNI[\6]​

Em caso de certificados específicos, crie um novo segredo (secret) para o novo certificado no cluster Kubernetes:

kubectl create secret tls seu-tls-secret \
--cert app.seusite.com.crt \
--key app.seusite.com.key
``

Edite o arquivo com a configuração de ingress criado anteriormente e inclua as configurações em negrito:

vi tls.yaml
---
. . .
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: one-cloud-test-ingress-tls
annotations:
# NNumbers Cloud ingress controller implementa o padrão openstack
kubernetes.io/ingress.class: "openstack"
# indica que deve ser ter IP flutuante visível para internet
octavia.ingress.kubernetes.io/internal: "false"
spec:
defaultBackend:
service:
name: default-http-backend
port:
number: 80
tls:
- secretName: meu-tls-secret
hosts:
- app.meusite.com
- secretName: seu-tls-secret
hosts:
- app.seusite.com
rules:
- host: app.meusite.com
http:
paths:
- path: /ping
pathType: Exact
backend:
service:
name: webserver
port:
number: 8080
- host: app.seusite.com
http:
paths:
- path: /ping
pathType: Exact
backend:
service:
name: webserver
port:
number: 8080
``

Para implantar as novas alterações no ingress execute o comando abaixo:

kubectl apply -f tls.yaml

Para testar as alterações acima, copie e execute o código abaixo:

for h in m s; do
for _ in $(seq 1 2); do
curl --cacert ~/ingress/certs/ca.crt \
--resolve app.${h}eusite.com:443:${FLOATING_IP} \
https://app.${h}eusite.com/ping;
done;
done;

O código acima deverá retornar algo similar a seguinte saída:

webserver-5c74674fb8-kr8zf
webserver-5c74674fb8-m4wlt
webserver-5c74674fb8-vzfmh
webserver-5c74674fb8-m4wlt

Acesso ao Kubernetes Dashboard​

Ao criar o cluster é possível especificar a instalação do kubernetes-dashboard através da seleção do addon software adequado. Ainda é possível instalá-lo de outras maneiras como por exemplo via helm. Entretanto, outras formas de instalação do kubernetes-dashboard que não sejam via as próprias ferramentas da NNumbers Cloud (console administrativo, API e CLI) poderão habilitá-lo em um namespace diferente, logo, a URL de acesso também será diferente da apresentada neste tutorial. Este tutorial irá focar no modo de instalação realizado pelas ferramentas do NNumbers Cloud durante a criação do cluster.

Uma vez que o cluster tenha sido criado com a opção de kubernetes-dashboard habilitada para ser instalado, podemos seguir os passos abaixo:

  1. Crie o arquivo dashboard-adminuser.yaml com o conteúdo abaixo:
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
  1. Execute o comando a seguir para criar a service account e a cluster role binding definidas acima
kubectl -n kube-dashboard apply -f dashboard-adminuser.yaml
  1. Crie o token de acesso para o usuário admin
kubectl -n kube-system create token admin-user
  1. Ative o kubernetes proxy
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard 8443:443
  1. Acesse o browser na URL e informe o token obtido:

    https://localhost:8443

  2. Utilize o token gerado para fazer o login:

Painel da NNumbers Cloud, Acesso externo com Ingress: 6. Utilize o token gerado para fazer o login

Painel da NNumbers Cloud, Acesso externo com Ingress: 6. Utilize o token gerado para fazer o login

Acesso ao Dashboard de Monitoramento​

Ao criar o cluster é possível especificar a instalação das ferramentas de monitoramento (Grafana, Alertmanager, Loki e Prometheus) através da seleção do addon software adequado. Ainda é possível instalá-lo de outras maneiras como por exemplo via helm. Entretanto, outras formas de instalação das ferramentas de monitoramento que não sejam via as próprias ferramentas da NNumbers Cloud (console administrativo, API e CLI) poderão habilitá-lo em um namespace diferente, logo, a URL de acesso também será diferente da apresentada neste tutorial. Este tutorial irá focar no modo de instalação realizado pelas ferramentas do NNumbers Cloud durante a criação do cluster.

Uma vez que o cluster tenha sido criado com a opção de habilitada para ser instalado, podemos seguir os passos abaixo:

  1. Obtenha a senha do usuário admin
kubectl get secret -n monitoring-system kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" |base64 -d
  1. Execute o port-forward para ter acesso ao dashboard.
kubectl port-forward --namespace monitoring-system service/kube-prometheus-stack-grafana 3000:80
  1. Acesso o browser na URL: http://localhost:3000/

  2. Execute o login com usuário admin e senha recuperada

Painel da NNumbers Cloud, Acesso externo com Ingress: 4. Execute o login com usuário admin e senha recuperada

Redimensionamento do Cluster​

Mesmo que a opção Auto Scaling tenha sido selecionada durante a criação, é possível definir o tamanho do nosso cluster estaticamente acessando a lista de cluster (tutorial Gerenciamento de Clusters Kubernetes), após localizar o cluster, do lado direito, clique na “seta” para baixo (item 1) e em seguida clique na opção “Resize Cluster” (item 2).

Painel da NNumbers Cloud, Acesso externo com Ingress: mesmo que a opção Auto Scaling tenha sido selecionada

Na nova janela aberta informe o tamanho do cluster (Item 1). Após isso, no rodapé, clique em “Submit” (item 2)

Painel da NNumbers Cloud, Acesso externo com Ingress: na nova janela aberta informe o tamanho do cluster

O cluster será redimensionado para o tamanho informado.

informação

Os deploys de aplicações realizados anteriormente no cluster podem não funcionar corretamente caso a quantidade de deploy aloque mais recurso (CPU, Memória e storage) do que o novo tamanho disponível no cluster (grande quantidade de aplicações / pouco recurso computacional).

Upgrade do Cluster Kubernetes​

Para executar o upgrade do cluster clique no menu (1) e em seguida em Rolling Cluster Upgrade (2).

aviso

Para realizar o upgrade de um cluster de produção recomendamos que seja realizado antes em ambiente não produtivo, pois, algumas de suas aplicações podem não funcionar conforme o esperado ou até mesmo deixar de funcionar.

aviso

Fique atento, o cluster só pode ser atualizado para uma versão menor e patch

(e.g. v1.31.1 -> v1.32.5, v1.31.1 -> v1.31.2) nunca mais de uma versão menor (e.g. v1.31.1 -> v1.33.2).

aviso

Não deixe de manter seu cluster atualizado, pois as versões suportadas serão apenas a última versão menor[\7] disponibilizada pela Nnumbers (N) até a última versão menor - 5 (N-3).

Painel da NNumbers Cloud, Acesso externo com Ingress: não deixe de manter seu cluster atualizado, pois as

A seguir em New Cluster Template selecione a versão desejada e clique em seguida clique no botão Submit.

informação

Apenas versões superiores a versão atual dos cluster Kubernetes deverão ser disponibilizadas para seleção.

Painel da NNumbers Cloud, Acesso externo com Ingress: apenas versões superiores a versão atual dos cluster

aviso

O upgrade poderá levar diversos minutos até completar dependendo do tamanho do seu cluster e aplicações nele configuradas.

Próximos passos​