From cccf5f22e8a0ffdfe547ca62f45f4f455029ea8d Mon Sep 17 00:00:00 2001 From: Jeferson Fernando Date: Thu, 18 Jan 2024 12:48:44 +0100 Subject: [PATCH] adicionando novos days e atualizando alguns assuntos --- README.md | 485 ++-- pt/CONTRIBUTING.md | 0 pt/README.md | 185 +- pt/SUMMARY.md | 32 +- pt/{day_one => day-1}/README.md | 0 .../files/desafio/meu-primeiro-pod.yaml | 0 pt/day-10/README.md | 0 pt/day-11/README.md | 362 +++ pt/day-12/README.md | 337 +++ pt/day-13/README.md | 458 ++++ pt/{day_two => day-2}/README.md | 0 pt/{day_three => day-3}/README.md | 0 pt/{day_four => day-4}/README.md | 0 .../files/nginx-deployment.yaml | 0 .../files/nginx-liveness.yaml | 0 .../files/nginx-readiness.yaml | 0 .../files/nginx-replicaset.yaml | 0 .../files/nginx-startup.yaml | 0 .../files/nginx-todas-probes.yaml | 0 .../files/node-exporter-daemonset.yaml | 0 pt/{day_four => day-4}/nginx-daemonset.yaml | 0 pt/{day_four => day-4}/nginx-deployment.yaml | 0 pt/{day_four => day-4}/nginx-replicaset.yaml | 0 pt/{day_five => day-5}/README.md | 0 pt/{day_six => day-6}/README.md | 0 .../files/giropops-senhas-deployment.yaml | 0 .../files/giropops-senhas-service.yaml | 0 pt/{day_six => day-6}/files/pod.yaml | 0 pt/{day_six => day-6}/files/pv-nfs.yaml | 0 pt/{day_six => day-6}/files/pv.yaml | 0 pt/{day_six => day-6}/files/pvc.yaml | 0 .../files/storageclass-nfs.yaml | 0 pt/{day_six => day-6}/files/storageclass.yaml | 0 pt/{day_seven => day-7}/README.md | 0 .../files/headless-service.yaml | 0 .../files/nginx-clusterip-svc.yaml | 0 .../files/nginx-deployment.yaml | 0 .../files/nginx-loadbalancer-svc.yaml | 0 .../files/nginx-nodeport-svc.yaml | 0 .../files/nginx-statefulset.yaml | 0 pt/{day_eight => day-8}/README.md | 2 +- pt/day-9/README.md | 360 +++ pt/day_nine/README.md | 41 - .../azure/aks-helloworld-one.yaml | 33 - .../azure/aks-helloworld-two.yaml | 33 - .../azure/hello-world-ingress.yaml | 53 - pt/extras/cloud-providers/cloud-providers.md | 180 -- pt/extras/exame_tips.md | 96 - pt/extras/pod_security_policy.md | 153 -- pt/old/day_five/descomplicando_kubernetes.md | 898 ------- pt/old/day_four/descomplicando_kubernetes.md | 2118 ----------------- pt/old/day_one/descomplicando_kubernetes.md | 1791 -------------- pt/old/day_one/extras-day1.md | 42 - pt/old/day_six/descomplicando_kubernetes.md | 566 ----- pt/old/day_three/descomplicando_kubernetes.md | 1540 ------------ pt/old/day_two/descomplicando_kubernetes.md | 1484 ------------ 56 files changed, 2020 insertions(+), 9229 deletions(-) mode change 100644 => 100755 pt/CONTRIBUTING.md mode change 100644 => 100755 pt/README.md mode change 100644 => 100755 pt/SUMMARY.md rename pt/{day_one => day-1}/README.md (100%) mode change 100644 => 100755 rename pt/{day_one => day-1}/files/desafio/meu-primeiro-pod.yaml (100%) mode change 100644 => 100755 mode change 100644 => 100755 pt/day-10/README.md create mode 100644 pt/day-11/README.md create mode 100644 pt/day-12/README.md create mode 100644 pt/day-13/README.md rename pt/{day_two => day-2}/README.md (100%) mode change 100644 => 100755 rename pt/{day_three => day-3}/README.md (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/README.md (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/nginx-deployment.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/nginx-liveness.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/nginx-readiness.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/nginx-replicaset.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/nginx-startup.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/nginx-todas-probes.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/files/node-exporter-daemonset.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/nginx-daemonset.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/nginx-deployment.yaml (100%) mode change 100644 => 100755 rename pt/{day_four => day-4}/nginx-replicaset.yaml (100%) mode change 100644 => 100755 rename pt/{day_five => day-5}/README.md (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/README.md (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/giropops-senhas-deployment.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/giropops-senhas-service.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/pod.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/pv-nfs.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/pv.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/pvc.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/storageclass-nfs.yaml (100%) mode change 100644 => 100755 rename pt/{day_six => day-6}/files/storageclass.yaml (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/README.md (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/files/headless-service.yaml (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/files/nginx-clusterip-svc.yaml (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/files/nginx-deployment.yaml (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/files/nginx-loadbalancer-svc.yaml (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/files/nginx-nodeport-svc.yaml (100%) mode change 100644 => 100755 rename pt/{day_seven => day-7}/files/nginx-statefulset.yaml (100%) mode change 100644 => 100755 rename pt/{day_eight => day-8}/README.md (99%) mode change 100644 => 100755 create mode 100755 pt/day-9/README.md delete mode 100644 pt/day_nine/README.md delete mode 100644 pt/extras/cloud-providers/azure/aks-helloworld-one.yaml delete mode 100644 pt/extras/cloud-providers/azure/aks-helloworld-two.yaml delete mode 100644 pt/extras/cloud-providers/azure/hello-world-ingress.yaml delete mode 100644 pt/extras/cloud-providers/cloud-providers.md delete mode 100644 pt/extras/exame_tips.md delete mode 100644 pt/extras/pod_security_policy.md delete mode 100644 pt/old/day_five/descomplicando_kubernetes.md delete mode 100755 pt/old/day_four/descomplicando_kubernetes.md delete mode 100644 pt/old/day_one/descomplicando_kubernetes.md delete mode 100644 pt/old/day_one/extras-day1.md delete mode 100644 pt/old/day_six/descomplicando_kubernetes.md delete mode 100644 pt/old/day_three/descomplicando_kubernetes.md delete mode 100644 pt/old/day_two/descomplicando_kubernetes.md diff --git a/README.md b/README.md index 6042040d..ca71c475 100644 --- a/README.md +++ b/README.md @@ -93,227 +93,265 @@ Principais links da LINUXtips: * [Descomplicando o Kubernetes](https://livro.descomplicandokubernetes.com.br) +# Descomplicando o Kubernetes + +Esse material é parte do treinamento Descomplicando Kubernetes da LINUXtips. Ele foi desenhado para capacitar a pessoa estudante ou a pessoa profissional de TI a trabalhar com o Kubernetes em ambientes criticos. + +O Treinamento é composto por material escrito, aulas gravadas em vídeo e aulas ao vivo. Durante o treinamento a pessoa será testada de forma prática, sendo necessário completar desafios reais para dar continuidade no treinamento. + +O foco do treinamento é capacitar a pessoa para trabalhar com Kubernetes de maneira eficiente e totalmente preparada para trabalhar em ambientes críticos que utilizam containers. +Fique à vontade para aprender muito sobre Kubernetes utilizando esse livro! ## Conteúdo
DAY-1 -- [DAY-1](pt/day_one/README.md#day-1) - - [O quê preciso saber antes de começar?](pt/day_one/README.md#o-quê-preciso-saber-antes-de-começar) - - [Inicio da aula do Day-1](pt/day_one/README.md#inicio-da-aula-do-day-1) - - [Qual a distro GNU/Linux que devo usar?](pt/day_one/README.md#qual-a-distro-gnu/linux-que-devo-usar?) - - [Alguns sites que devemos visitar](pt/day_one/README.md#alguns-sites-que-devemos-visitar) - - [O Container Engine](pt/day_one/README.md#o-container-engine) - - [OCI - Open Container Initiative](pt/day_one/README.md#oci---open-container-initiative) - - [O Container Runtime](pt/day_one/README.md#o-container-runtime) - - [O que é o Kubernetes?](pt/day_one/README.md#o-que-é-o-kubernetes?) - - [Arquitetura do k8s](pt/day_one/README.md#arquitetura-do-k8s) - - [Instalando e customizando o Kubectl](pt/day_one/README.md#instalando-e-customizando-o-kubectl) - - [Instalação do Kubectl no GNU/Linux](pt/day_one/README.md#instalação-do-kubectl-no-gnu/linux) - - [Instalação do Kubectl no MacOS](pt/day_one/README.md#instalação-do-kubectl-no-macos) - - [Instalação do Kubectl no Windows](pt/day_one/README.md#instalação-do-kubectl-no-windows) - - [Customizando o kubectl](pt/day_one/README.md#customizando-o-kubectl) - - [Auto-complete do kubectl](pt/day_one/README.md#auto-complete-do-kubectl) - - [Criando um alias para o kubectl](pt/day_one/README.md#criando-um-alias-para-o-kubectl) - - [Criando um cluster Kubernetes](pt/day_one/README.md#criando-um-cluster-kubernetes) - - [Criando o cluster em sua máquina local](pt/day_one/README.md#criando-o-cluster-em-sua-máquina-local) - - [Minikube](pt/day_one/README.md#minikube) - - [Requisitos básicos para o Minikube](pt/day_one/README.md#requisitos-básicos-para-o-minikube) - - [Instalação do Minikube no GNU/Linux](pt/day_one/README.md#instalação-do-minikube-no-gnu/linux) - - [Instalação do Minikube no MacOS](pt/day_one/README.md#instalação-do-minikube-no-macos) - - [Instalação do Minikube no Microsoft Windows](pt/day_one/README.md#instalação-do-minikube-no-microsoft-windows) - - [Iniciando, parando e excluindo o Minikube](pt/day_one/README.md#iniciando,-parando-e-excluindo-o-minikube) - - [Ver detalhes sobre o cluster](pt/day_one/README.md#ver-detalhes-sobre-o-cluster) - - [Descobrindo o endereço do Minikube](pt/day_one/README.md#descobrindo-o-endereço-do-minikube) - - [Acessando a máquina do Minikube via SSH](pt/day_one/README.md#acessando-a-máquina-do-minikube-via-ssh) - - [Dashboard do Minikube](pt/day_one/README.md#dashboard-do-minikube) - - [Logs do Minikube](pt/day_one/README.md#logs-do-minikube) - - [Remover o cluster](pt/day_one/README.md#remover-o-cluster) - - [Kind](pt/day_one/README.md#kind) - - [Instalação no GNU/Linux](pt/day_one/README.md#instalação-no-gnu/linux) - - [Instalação no MacOS](pt/day_one/README.md#instalação-no-macos) - - [Instalação no Windows](pt/day_one/README.md#instalação-no-windows) - - [Instalação no Windows via Chocolatey](pt/day_one/README.md#instalação-no-windows-via-chocolatey) - - [Criando um cluster com o Kind](pt/day_one/README.md#criando-um-cluster-com-o-kind) - - [Criando um cluster com múltiplos nós locais com o Kind](pt/day_one/README.md#criando-um-cluster-com-múltiplos-nós-locais-com-o-kind) - - [Primeiros passos no k8s](pt/day_one/README.md#primeiros-passos-no-k8s) - - [Verificando os namespaces e pods](pt/day_one/README.md#verificando-os-namespaces-e-pods) - - [Executando nosso primeiro pod no k8s](pt/day_one/README.md#executando-nosso-primeiro-pod-no-k8s) - - [Expondo o pod e criando um Service](pt/day_one/README.md#expondo-o-pod-e-criando-um-service) - - [Limpando tudo e indo para casa](pt/day_one/README.md#limpando-tudo-e-indo-para-casa) +- [DAY-1](pt/day-1/README.md#day-1) + - [O quê preciso saber antes de começar?](pt/day-1/README.md#o-quê-preciso-saber-antes-de-começar) + - [Inicio da aula do Day-1](pt/day-1/README.md#inicio-da-aula-do-day-1) + - [Qual a distro GNU/Linux que devo usar?](pt/day-1/README.md#qual-a-distro-gnu/linux-que-devo-usar?) + - [Alguns sites que devemos visitar](pt/day-1/README.md#alguns-sites-que-devemos-visitar) + - [O Container Engine](pt/day-1/README.md#o-container-engine) + - [OCI - Open Container Initiative](pt/day-1/README.md#oci---open-container-initiative) + - [O Container Runtime](pt/day-1/README.md#o-container-runtime) + - [O que é o Kubernetes?](pt/day-1/README.md#o-que-é-o-kubernetes?) + - [Arquitetura do k8s](pt/day-1/README.md#arquitetura-do-k8s) + - [Instalando e customizando o Kubectl](pt/day-1/README.md#instalando-e-customizando-o-kubectl) + - [Instalação do Kubectl no GNU/Linux](pt/day-1/README.md#instalação-do-kubectl-no-gnu/linux) + - [Instalação do Kubectl no MacOS](pt/day-1/README.md#instalação-do-kubectl-no-macos) + - [Instalação do Kubectl no Windows](pt/day-1/README.md#instalação-do-kubectl-no-windows) + - [Customizando o kubectl](pt/day-1/README.md#customizando-o-kubectl) + - [Auto-complete do kubectl](pt/day-1/README.md#auto-complete-do-kubectl) + - [Criando um alias para o kubectl](pt/day-1/README.md#criando-um-alias-para-o-kubectl) + - [Criando um cluster Kubernetes](pt/day-1/README.md#criando-um-cluster-kubernetes) + - [Criando o cluster em sua máquina local](pt/day-1/README.md#criando-o-cluster-em-sua-máquina-local) + - [Minikube](pt/day-1/README.md#minikube) + - [Requisitos básicos para o Minikube](pt/day-1/README.md#requisitos-básicos-para-o-minikube) + - [Instalação do Minikube no GNU/Linux](pt/day-1/README.md#instalação-do-minikube-no-gnu/linux) + - [Instalação do Minikube no MacOS](pt/day-1/README.md#instalação-do-minikube-no-macos) + - [Instalação do Minikube no Microsoft Windows](pt/day-1/README.md#instalação-do-minikube-no-microsoft-windows) + - [Iniciando, parando e excluindo o Minikube](pt/day-1/README.md#iniciando,-parando-e-excluindo-o-minikube) + - [Ver detalhes sobre o cluster](pt/day-1/README.md#ver-detalhes-sobre-o-cluster) + - [Descobrindo o endereço do Minikube](pt/day-1/README.md#descobrindo-o-endereço-do-minikube) + - [Acessando a máquina do Minikube via SSH](pt/day-1/README.md#acessando-a-máquina-do-minikube-via-ssh) + - [Dashboard do Minikube](pt/day-1/README.md#dashboard-do-minikube) + - [Logs do Minikube](pt/day-1/README.md#logs-do-minikube) + - [Remover o cluster](pt/day-1/README.md#remover-o-cluster) + - [Kind](pt/day-1/README.md#kind) + - [Instalação no GNU/Linux](pt/day-1/README.md#instalação-no-gnu/linux) + - [Instalação no MacOS](pt/day-1/README.md#instalação-no-macos) + - [Instalação no Windows](pt/day-1/README.md#instalação-no-windows) + - [Instalação no Windows via Chocolatey](pt/day-1/README.md#instalação-no-windows-via-chocolatey) + - [Criando um cluster com o Kind](pt/day-1/README.md#criando-um-cluster-com-o-kind) + - [Criando um cluster com múltiplos nós locais com o Kind](pt/day-1/README.md#criando-um-cluster-com-múltiplos-nós-locais-com-o-kind) + - [Primeiros passos no k8s](pt/day-1/README.md#primeiros-passos-no-k8s) + - [Verificando os namespaces e pods](pt/day-1/README.md#verificando-os-namespaces-e-pods) + - [Executando nosso primeiro pod no k8s](pt/day-1/README.md#executando-nosso-primeiro-pod-no-k8s) + - [Expondo o pod e criando um Service](pt/day-1/README.md#expondo-o-pod-e-criando-um-service) + - [Limpando tudo e indo para casa](pt/day-1/README.md#limpando-tudo-e-indo-para-casa)
DAY-2 -- [DAY-2](pt/day_two/README.md#day-2) - - [O que iremos ver hoje?](pt/day_two/README.md#o-que-iremos-ver-hoje) +- [DAY-2](pt/day-2/README.md#day-2) + - [O que iremos ver hoje?](pt/day-2/README.md#o-que-iremos-ver-hoje) - [O que é um Pod?](o-que-e-um-pod?) - - [Criando um Pod](pt/day_two/README.md#criando-um-pod) - - [Visualizando detalhes sobre os Pods](pt/day_two/README.md#visualizando-detalhes-sobre-os-pods) - - [Removendo um Pod](pt/day_two/README.md#removendo-um-pod) - - [Criando um Pod através de um arquivo YAML](pt/day_two/README.md#criando-um-pod-atraves-de-um-arquivo-yaml) - - [Visualizando os logs do Pod](pt/day_two/README.md#visualizando-os-logs-do-pod) - - [Criando um Pod com mais de um container](pt/day_two/README.md#criando-um-pod-com-mais-de-um-container) - - [Os comandos `attach` e `exec`](pt/day_two/README.md#os-comandos-attach-e-exec) - - [Criando um container com limites de memória e CPU](pt/day_two/README.md#criando-um-container-com-limites-de-memoria-e-cpu) - - [Adicionando um volume EmptyDir no Pod](pt/day_two/README.md#adicionando-um-volume-emptydir-no-pod) + - [Criando um Pod](pt/day-2/README.md#criando-um-pod) + - [Visualizando detalhes sobre os Pods](pt/day-2/README.md#visualizando-detalhes-sobre-os-pods) + - [Removendo um Pod](pt/day-2/README.md#removendo-um-pod) + - [Criando um Pod através de um arquivo YAML](pt/day-2/README.md#criando-um-pod-atraves-de-um-arquivo-yaml) + - [Visualizando os logs do Pod](pt/day-2/README.md#visualizando-os-logs-do-pod) + - [Criando um Pod com mais de um container](pt/day-2/README.md#criando-um-pod-com-mais-de-um-container) + - [Os comandos `attach` e `exec`](pt/day-2/README.md#os-comandos-attach-e-exec) + - [Criando um container com limites de memória e CPU](pt/day-2/README.md#criando-um-container-com-limites-de-memoria-e-cpu) + - [Adicionando um volume EmptyDir no Pod](pt/day-2/README.md#adicionando-um-volume-emptydir-no-pod)
DAY-3 -- [DAY-3](pt/day-three/README.md#day-3) - - [Inicio da aula do Day-3](pt/day-three/README.md#inicio-da-aula-do-day-3) - - [O que iremos ver hoje?](pt/day-three/README.md#o-que-iremos-ver-hoje) - - [O que é um Deployment?](pt/day-three/README.md#o-que-é-um-deployment) - - [Como criar um Deployment?](pt/day-three/README.md#como-criar-um-deployment) - - [O que cada parte do arquivo significa?](pt/day-three/README.md#o-que-cada-parte-do-arquivo-significa) - - [Como aplicar o Deployment?](pt/day-three/README.md#como-aplicar-o-deployment) - - [Como verificar os Pods que o Deployment está gerenciando?](pt/day-three/README.md#como-verificar-os-pods-que-o-deployment-está-gerenciando) - - [Como verificar o ReplicaSet que o Deployment está gerenciando?](pt/day-three/README.md#como-verificar-o-replicaset-que-o-deployment-está-gerenciando) - - [Como verificar os detalhes do Deployment?](pt/day-three/README.md#como-verificar-os-detalhes-do-deployment) - - [Como atualizar o Deployment?](pt/day-three/README.md#como-atualizar-o-deployment) - - [E qual é a estratégia de atualização padrão do Deployment?](pt/day-three/README.md#e-qual-é-a-estratégia-de-atualização-padrão-do-deployment) - - [As estratégias de atualização do Deployment](pt/day-three/README.md#as-estratégias-de-atualização-do-deployment) - - [Estratégia RollingUpdate](pt/day-three/README.md#estratégia-rollingupdate) - - [Estratégia Recreate](pt/day-three/README.md#estratégia-recreate) - - [Fazendo o rollback de uma atualização](pt/day-three/README.md#fazendo-o-rollback-de-uma-atualização) - - [Removendo um Deployment](pt/day-three/README.md#removendo-um-deployment) - - [Conclusão](pt/day-three/README.md#conclusão) +- [DAY-3](pt/day-3/README.md#day-3) + - [Inicio da aula do Day-3](pt/day-3/README.md#inicio-da-aula-do-day-3) + - [O que iremos ver hoje?](pt/day-3/README.md#o-que-iremos-ver-hoje) + - [O que é um Deployment?](pt/day-3/README.md#o-que-é-um-deployment) + - [Como criar um Deployment?](pt/day-3/README.md#como-criar-um-deployment) + - [O que cada parte do arquivo significa?](pt/day-3/README.md#o-que-cada-parte-do-arquivo-significa) + - [Como aplicar o Deployment?](pt/day-3/README.md#como-aplicar-o-deployment) + - [Como verificar os Pods que o Deployment está gerenciando?](pt/day-3/README.md#como-verificar-os-pods-que-o-deployment-está-gerenciando) + - [Como verificar o ReplicaSet que o Deployment está gerenciando?](pt/day-3/README.md#como-verificar-o-replicaset-que-o-deployment-está-gerenciando) + - [Como verificar os detalhes do Deployment?](pt/day-3/README.md#como-verificar-os-detalhes-do-deployment) + - [Como atualizar o Deployment?](pt/day-3/README.md#como-atualizar-o-deployment) + - [E qual é a estratégia de atualização padrão do Deployment?](pt/day-3/README.md#e-qual-é-a-estratégia-de-atualização-padrão-do-deployment) + - [As estratégias de atualização do Deployment](pt/day-3/README.md#as-estratégias-de-atualização-do-deployment) + - [Estratégia RollingUpdate](pt/day-3/README.md#estratégia-rollingupdate) + - [Estratégia Recreate](pt/day-3/README.md#estratégia-recreate) + - [Fazendo o rollback de uma atualização](pt/day-3/README.md#fazendo-o-rollback-de-uma-atualização) + - [Removendo um Deployment](pt/day-3/README.md#removendo-um-deployment) + - [Conclusão](pt/day-3/README.md#conclusão)
DAY-4 -- [DAY-4](day-4/README.md) -- [Inicio da aula do Day-4](day-4/README.md#inicio-da-aula-do-day-4) -- [O que iremos ver hoje?](day-4/README.md#o-que-iremos-ver-hoje) - - [ReplicaSet](day-4/README.md#replicaset) - - [O Deployment e o ReplicaSet](day-4/README.md#o-deployment-e-o-replicaset) - - [Criando um ReplicaSet](day-4/README.md#criando-um-replicaset) - - [Apagando o ReplicaSet](day-4/README.md#apagando-o-replicaset) - - [O DaemonSet](day-4/README.md#o-daemonset) - - [Criando um DaemonSet](day-4/README.md#criando-um-daemonset) - - [Criando um DaemonSet utilizando o comando kubectl create](day-4/README.md#criando-um-daemonset-utilizando-o-comando-kubectl-create) - - [Aumentando um node no cluster](day-4/README.md#aumentando-um-node-no-cluster) - - [Removendo um DaemonSet](day-4/README.md#removendo-um-daemonset) - - [As Probes do Kubernetes](day-4/README.md#as-probes-do-kubernetes) - - [O que são as Probes?](day-4/README.md#o-que-sao-as-probes) - - [Liveness Probe](day-4/README.md#liveness-probe) - - [Readiness Probe](day-4/README.md#readiness-probe) - - [Startup Probe](day-4/README.md#startup-probe) - - [A sua lição de casa](day-4/README.md#a-sua-licao-de-casa) -- [Final do Day-4](day-4/README.md#final-do-day-4) +- [DAY-4](pt/day-4/README.md) +- [Inicio da aula do Day-4](pt/day-4/README.md#inicio-da-aula-do-day-4) +- [O que iremos ver hoje?](pt/day-4/README.md#o-que-iremos-ver-hoje) + - [ReplicaSet](pt/day-4/README.md#replicaset) + - [O Deployment e o ReplicaSet](pt/day-4/README.md#o-deployment-e-o-replicaset) + - [Criando um ReplicaSet](pt/day-4/README.md#criando-um-replicaset) + - [Apagando o ReplicaSet](pt/day-4/README.md#apagando-o-replicaset) + - [O DaemonSet](pt/day-4/README.md#o-daemonset) + - [Criando um DaemonSet](pt/day-4/README.md#criando-um-daemonset) + - [Criando um DaemonSet utilizando o comando kubectl create](pt/day-4/README.md#criando-um-daemonset-utilizando-o-comando-kubectl-create) + - [Aumentando um node no cluster](pt/day-4/README.md#aumentando-um-node-no-cluster) + - [Removendo um DaemonSet](pt/day-4/README.md#removendo-um-daemonset) + - [As Probes do Kubernetes](pt/day-4/README.md#as-probes-do-kubernetes) + - [O que são as Probes?](pt/day-4/README.md#o-que-sao-as-probes) + - [Liveness Probe](pt/day-4/README.md#liveness-probe) + - [Readiness Probe](pt/day-4/README.md#readiness-probe) + - [Startup Probe](pt/day-4/README.md#startup-probe) + - [A sua lição de casa](pt/day-4/README.md#a-sua-licao-de-casa) +- [Final do Day-4](pt/day-4/README.md#final-do-day-4)
DAY-5 -- [DAY-5](day-5/README.md#day-5) -- [Conteúdo do Day-5](day-5/README.md#conteúdo-do-day-5) -- [Inicio da aula do Day-5](day-5/README.md#inicio-da-aula-do-day-5) - - [O que iremos ver hoje?](day-5/README.md#o-que-iremos-ver-hoje) - - [Instalação de um cluster Kubernetes](day-5/README.md#instalação-de-um-cluster-kubernetes) - - [O que é um cluster Kubernetes?](day-5/README.md#o-que-é-um-cluster-kubernetes) - - [Formas de instalar o Kubernetes](day-5/README.md#formas-de-instalar-o-kubernetes) - - [Criando um cluster Kubernetes com o kubeadm](day-5/README.md#criando-um-cluster-kubernetes-com-o-kubeadm) - - [Instalando o kubeadm](day-5/README.md#instalando-o-kubeadm) - - [Desativando o uso do swap no sistema](day-5/README.md#desativando-o-uso-do-swap-no-sistema) - - [Carregando os módulos do kernel](day-5/README.md#carregando-os-módulos-do-kernel) - - [Configurando parâmetros do sistema](day-5/README.md#configurando-parâmetros-do-sistema) - - [Instalando os pacotes do Kubernetes](day-5/README.md#instalando-os-pacotes-do-kubernetes) - - [Instalando o Docker e o containerd](day-5/README.md#instalando-o-docker-e-o-containerd) - - [Configurando o containerd](day-5/README.md#configurando-o-containerd) - - [Habilitando o serviço do kubelet](day-5/README.md#habilitando-o-serviço-do-kubelet) - - [Configurando as portas](day-5/README.md#configurando-as-portas) - - [Iniciando o cluster](day-5/README.md#iniciando-o-cluster) - - [Entendendo o arquivo admin.conf](day-5/README.md#entendendo-o-arquivo-adminconf) - - [Instalando o Weave Net](day-5/README.md#instalando-o-weave-net) - - [O que é o CNI?](day-5/README.md#o-que-é-o-cni) - - [Visualizando detalhes dos nodes](day-5/README.md#visualizando-detalhes-dos-nodes) - - [A sua lição de casa](day-5/README.md#a-sua-lição-de-casa) -- [Final do Day-5](day-5/README.md#final-do-day-5) +- [DAY-5](pt/day-5/README.md#day-5) +- [Conteúdo do Day-5](pt/day-5/README.md#conteúdo-do-day-5) +- [Inicio da aula do Day-5](pt/day-5/README.md#inicio-da-aula-do-day-5) + - [O que iremos ver hoje?](pt/day-5/README.md#o-que-iremos-ver-hoje) + - [Instalação de um cluster Kubernetes](pt/day-5/README.md#instalação-de-um-cluster-kubernetes) + - [O que é um cluster Kubernetes?](pt/day-5/README.md#o-que-é-um-cluster-kubernetes) + - [Formas de instalar o Kubernetes](pt/day-5/README.md#formas-de-instalar-o-kubernetes) + - [Criando um cluster Kubernetes com o kubeadm](pt/day-5/README.md#criando-um-cluster-kubernetes-com-o-kubeadm) + - [Instalando o kubeadm](pt/day-5/README.md#instalando-o-kubeadm) + - [Desativando o uso do swap no sistema](pt/day-5/README.md#desativando-o-uso-do-swap-no-sistema) + - [Carregando os módulos do kernel](pt/day-5/README.md#carregando-os-módulos-do-kernel) + - [Configurando parâmetros do sistema](pt/day-5/README.md#configurando-parâmetros-do-sistema) + - [Instalando os pacotes do Kubernetes](pt/day-5/README.md#instalando-os-pacotes-do-kubernetes) + - [Instalando o Docker e o containerd](pt/day-5/README.md#instalando-o-docker-e-o-containerd) + - [Configurando o containerd](pt/day-5/README.md#configurando-o-containerd) + - [Habilitando o serviço do kubelet](pt/day-5/README.md#habilitando-o-serviço-do-kubelet) + - [Configurando as portas](pt/day-5/README.md#configurando-as-portas) + - [Iniciando o cluster](pt/day-5/README.md#iniciando-o-cluster) + - [Entendendo o arquivo admin.conf](pt/day-5/README.md#entendendo-o-arquivo-adminconf) + - [Instalando o Weave Net](pt/day-5/README.md#instalando-o-weave-net) + - [O que é o CNI?](pt/day-5/README.md#o-que-é-o-cni) + - [Visualizando detalhes dos nodes](pt/day-5/README.md#visualizando-detalhes-dos-nodes) + - [A sua lição de casa](pt/day-5/README.md#a-sua-lição-de-casa) +- [Final do Day-5](pt/day-5/README.md#final-do-day-5)
DAY-6 -- [DAY-6](day-6/README.md#day-6) - - [Conteúdo do Day-6](day-6/README.md#conteúdo-do-day-6) - - [Inicio da aula do Day-6](day-6/README.md#inicio-da-aula-do-day-6) - - [O que iremos ver hoje?](day-6/README.md#o-que-iremos-ver-hoje) - - [O que são volumes?](day-6/README.md#o-que-são-volumes) - - [EmpytDir](day-6/README.md#empytdir) - - [Storage Class](day-6/README.md#storage-class) - - [PV - Persistent Volume](day-6/README.md#pv---persistent-volume) - - [PVC - Persistent Volume Claim](day-6/README.md#pvc---persistent-volume-claim) - - [A sua lição de casa](day-6/README.md#a-sua-lição-de-casa) - - [Final do Day-6](day-6/README.md#final-do-day-6) +- [DAY-6](pt/day-6/README.md#day-6) + - [Conteúdo do Day-6](pt/day-6/README.md#conteúdo-do-day-6) + - [Inicio da aula do Day-6](pt/day-6/README.md#inicio-da-aula-do-day-6) + - [O que iremos ver hoje?](pt/day-6/README.md#o-que-iremos-ver-hoje) + - [O que são volumes?](pt/day-6/README.md#o-que-são-volumes) + - [EmpytDir](pt/day-6/README.md#empytdir) + - [Storage Class](pt/day-6/README.md#storage-class) + - [PV - Persistent Volume](pt/day-6/README.md#pv---persistent-volume) + - [PVC - Persistent Volume Claim](pt/day-6/README.md#pvc---persistent-volume-claim) + - [A sua lição de casa](pt/day-6/README.md#a-sua-lição-de-casa) + - [Final do Day-6](pt/day-6/README.md#final-do-day-6)
DAY-7 -- [DAY-7](day-7/README.md#day-7) -- [Conteúdo do Day-7](day-7/README.md#conteúdo-do-day-7) - - [O que iremos ver hoje?](day-7/README.md#o-que-iremos-ver-hoje) - - [O que é um StatefulSet?](day-7/README.md#o-que-é-um-statefulset) - - [Quando usar StatefulSets?](day-7/README.md#quando-usar-statefulsets) - - [E como ele funciona?](day-7/README.md#e-como-ele-funciona) - - [O StatefulSet e os volumes persistentes](day-7/README.md#o-statefulset-e-os-volumes-persistentes) - - [O StatefulSet e o Headless Service](day-7/README.md#o-statefulset-e-o-headless-service) - - [Criando um StatefulSet](day-7/README.md#criando-um-statefulset) - - [Excluindo um StatefulSet](day-7/README.md#excluindo-um-statefulset) - - [Excluindo um Headless Service](day-7/README.md#excluindo-um-headless-service) - - [Excluindo um PVC](day-7/README.md#excluindo-um-pvc) - - [Services](day-7/README.md#services) - - [Tipos de Services](day-7/README.md#tipos-de-services) - - [Como os Services funcionam](day-7/README.md#como-os-services-funcionam) - - [Os Services e os Endpoints](day-7/README.md#os-services-e-os-endpoints) - - [Criando um Service](day-7/README.md#criando-um-service) - - [ClusterIP](day-7/README.md#clusterip) - - [ClusterIP](day-7/README.md#clusterip-1) - - [LoadBalancer](day-7/README.md#loadbalancer) - - [ExternalName](day-7/README.md#externalname) - - [Verificando os Services](day-7/README.md#verificando-os-services) - - [Verificando os Endpoints](day-7/README.md#verificando-os-endpoints) - - [Removendo um Service](day-7/README.md#removendo-um-service) - - [A sua lição de casa](day-7/README.md#a-sua-lição-de-casa) -- [Final do Day-7](day-7/README.md#final-do-day-7) +- [DAY-7](pt/day-7/README.md#day-7) +- [Conteúdo do Day-7](pt/day-7/README.md#conteúdo-do-day-7) + - [O que iremos ver hoje?](pt/day-7/README.md#o-que-iremos-ver-hoje) + - [O que é um StatefulSet?](pt/day-7/README.md#o-que-é-um-statefulset) + - [Quando usar StatefulSets?](pt/day-7/README.md#quando-usar-statefulsets) + - [E como ele funciona?](pt/day-7/README.md#e-como-ele-funciona) + - [O StatefulSet e os volumes persistentes](pt/day-7/README.md#o-statefulset-e-os-volumes-persistentes) + - [O StatefulSet e o Headless Service](pt/day-7/README.md#o-statefulset-e-o-headless-service) + - [Criando um StatefulSet](pt/day-7/README.md#criando-um-statefulset) + - [Excluindo um StatefulSet](pt/day-7/README.md#excluindo-um-statefulset) + - [Excluindo um Headless Service](pt/day-7/README.md#excluindo-um-headless-service) + - [Excluindo um PVC](pt/day-7/README.md#excluindo-um-pvc) + - [Services](pt/day-7/README.md#services) + - [Tipos de Services](pt/day-7/README.md#tipos-de-services) + - [Como os Services funcionam](pt/day-7/README.md#como-os-services-funcionam) + - [Os Services e os Endpoints](pt/day-7/README.md#os-services-e-os-endpoints) + - [Criando um Service](pt/day-7/README.md#criando-um-service) + - [ClusterIP](pt/day-7/README.md#clusterip) + - [ClusterIP](pt/day-7/README.md#clusterip-1) + - [LoadBalancer](pt/day-7/README.md#loadbalancer) + - [ExternalName](pt/day-7/README.md#externalname) + - [Verificando os Services](pt/day-7/README.md#verificando-os-services) + - [Verificando os Endpoints](pt/day-7/README.md#verificando-os-endpoints) + - [Removendo um Service](pt/day-7/README.md#removendo-um-service) + - [A sua lição de casa](pt/day-7/README.md#a-sua-lição-de-casa) +- [Final do Day-7](pt/day-7/README.md#final-do-day-7)
DAY-8 -- [Descomplicando o Kubernetes](day-8/README.md#descomplicando-o-kubernetes) - - [DAY-8](day-8/README.md#day-8) - - [Conteúdo do Day-8](day-8/README.md#conteúdo-do-day-8) - - [O que iremos ver hoje?](day-8/README.md#o-que-iremos-ver-hoje) - - [O que são Secrets?](day-8/README.md#o-que-são-secrets) - - [Como os Secrets funcionam](day-8/README.md#como-os-secrets-funcionam) - - [Tipos de Secrets](day-8/README.md#tipos-de-secrets) - - [Antes de criar um Secret, o Base64](day-8/README.md#antes-de-criar-um-secret-o-base64) - - [Criando nosso primeiro Secret](day-8/README.md#criando-nosso-primeiro-secret) - - [Usando o nosso primeiro Secret](day-8/README.md#usando-o-nosso-primeiro-secret) - - [Criando um Secret para armazenar credenciais Docker](day-8/README.md#criando-um-secret-para-armazenar-credenciais-docker) - - [Criando um Secret TLS](day-8/README.md#criando-um-secret-tls) - - [ConfigMaps](day-8/README.md#configmaps) - - [Final do Day-8](day-8/README.md#final-do-day-8) +- [Descomplicando o Kubernetes](pt/day-8/README.md#descomplicando-o-kubernetes) + - [DAY-8](pt/day-8/README.md#day-8) + - [Conteúdo do Day-8](pt/day-8/README.md#conteúdo-do-day-8) + - [O que iremos ver hoje?](pt/day-8/README.md#o-que-iremos-ver-hoje) + - [O que são Secrets?](pt/day-8/README.md#o-que-são-secrets) + - [Como os Secrets funcionam](pt/day-8/README.md#como-os-secrets-funcionam) + - [Tipos de Secrets](pt/day-8/README.md#tipos-de-secrets) + - [Antes de criar um Secret, o Base64](pt/day-8/README.md#antes-de-criar-um-secret-o-base64) + - [Criando nosso primeiro Secret](pt/day-8/README.md#criando-nosso-primeiro-secret) + - [Usando o nosso primeiro Secret](pt/day-8/README.md#usando-o-nosso-primeiro-secret) + - [Criando um Secret para armazenar credenciais Docker](pt/day-8/README.md#criando-um-secret-para-armazenar-credenciais-docker) + - [Criando um Secret TLS](pt/day-8/README.md#criando-um-secret-tls) + - [ConfigMaps](pt/day-8/README.md#configmaps) + - [Final do Day-8](pt/day-8/README.md#final-do-day-8) + -
DAY-9 +- [Descomplicando o Kubernetes](pt/day-9/README.md#descomplicando-o-kubernetes) + - [DAY-9: Descomplicando o Ingress no Kubernetes](pt/day-9/README.md#day-9-descomplicando-o-ingress-no-kubernetes) + - [Conteúdo do Day-9](pt/day-9/README.md#conteúdo-do-day-9) + - [O que iremos ver hoje?](pt/day-9/README.md#o-que-iremos-ver-hoje) + - [Conteúdo do Day-9](pt/day-9/README.md#conteúdo-do-day-9-1) +- [O Que é o Ingress?](pt/day-9/README.md#o-que-é-o-ingress) + - [Teoria: O que é Ingress?](pt/day-9/README.md#teoria-o-que-é-ingress) + - [Prática: Mãos à Obra](pt/day-9/README.md#prática-mãos-à-obra) + - [Criando um Serviço Simples](pt/day-9/README.md#criando-um-serviço-simples) +- [Seção 2: Componentes do Ingress](pt/day-9/README.md#seção-2-componentes-do-ingress) + - [Introdução](pt/day-9/README.md#introdução) + - [Teoria: Componentes Chave](pt/day-9/README.md#teoria-componentes-chave) + - [Ingress Controller](pt/day-9/README.md#ingress-controller) + - [Ingress Resources](pt/day-9/README.md#ingress-resources) + - [Annotations e Customizations](pt/day-9/README.md#annotations-e-customizations) + - [Prática: Montando o Quebra-Cabeça](pt/day-9/README.md#prática-montando-o-quebra-cabeça) + - [Instalando um Nginx Ingress Controller](pt/day-9/README.md#instalando-um-nginx-ingress-controller) + - [Instalando o Nginx Ingress Controller no Kind](pt/day-9/README.md#instalando-o-nginx-ingress-controller-no-kind) + - [Introdução](pt/day-9/README.md#introdução-1) + - [Criando o Cluster com Configurações Especiais](pt/day-9/README.md#criando-o-cluster-com-configurações-especiais) + - [Instalando um Ingress Controller](pt/day-9/README.md#instalando-um-ingress-controller) + - [Criando um Recurso de Ingress](pt/day-9/README.md#criando-um-recurso-de-ingress) + - [Annotations para Customização](pt/day-9/README.md#annotations-para-customização) +- [Seção 3: Configurando Rotas](pt/day-9/README.md#seção-3-configurando-rotas) + - [Introdução](pt/day-9/README.md#introdução-2) + - [Teoria: O Que São Rotas?](pt/day-9/README.md#teoria-o-que-são-rotas) + - [Prática: Configurando Rotas Simples](pt/day-9/README.md#prática-configurando-rotas-simples) + - [Prática: Configurando Rotas Avançadas](pt/day-9/README.md#prática-configurando-rotas-avançadas) +
@@ -324,6 +362,121 @@ Principais links da LINUXtips:
DAY-11 +- [Descomplicando o Kubernetes](pt/day-11/README.md#descomplicando-o-kubernetes) + - [DAY-11](pt/day-11/README.md#day-11) + - [Conteúdo do Day-11](pt/day-11/README.md#conteúdo-do-day-11) + - [Início da aula do Day-11](pt/day-11/README.md#início-da-aula-do-day-11) + - [O que iremos ver hoje?](pt/day-11/README.md#o-que-iremos-ver-hoje) + - [Introdução ao Horizontal Pod Autoscaler (HPA)](pt/day-11/README.md#introdução-ao-horizontal-pod-autoscaler-hpa) + - [Como o HPA Funciona?](pt/day-11/README.md#como-o-hpa-funciona) + - [Introdução ao Metrics Server](pt/day-11/README.md#introdução-ao-metrics-server) + - [Por que o Metrics Server é importante para o HPA?](pt/day-11/README.md#por-que-o-metrics-server-é-importante-para-o-hpa) + - [Instalando o Metrics Server](pt/day-11/README.md#instalando-o-metrics-server) + - [No Amazon EKS e na maioria dos clusters Kubernetes](pt/day-11/README.md#no-amazon-eks-e-na-maioria-dos-clusters-kubernetes) + - [No Minikube:](pt/day-11/README.md#no-minikube) + - [No KinD (Kubernetes in Docker):](pt/day-11/README.md#no-kind-kubernetes-in-docker) + - [Verificando a Instalação do Metrics Server](pt/day-11/README.md#verificando-a-instalação-do-metrics-server) + - [Obtendo Métricas](pt/day-11/README.md#obtendo-métricas) + - [Criando um HPA](pt/day-11/README.md#criando-um-hpa) + - [Exemplos Práticos com HPA](pt/day-11/README.md#exemplos-práticos-com-hpa) + - [Autoscaling com base na utilização de CPU](pt/day-11/README.md#autoscaling-com-base-na-utilização-de-cpu) + - [Autoscaling com base na utilização de Memória](pt/day-11/README.md#autoscaling-com-base-na-utilização-de-memória) + - [Configuração Avançada de HPA: Definindo Comportamento de Escalonamento](pt/day-11/README.md#configuração-avançada-de-hpa-definindo-comportamento-de-escalonamento) + - [ContainerResource](pt/day-11/README.md#containerresource) + - [Detalhes do Algoritmo de Escalonamento](pt/day-11/README.md#detalhes-do-algoritmo-de-escalonamento) + - [Configurações Avançadas e Uso Prático](pt/day-11/README.md#configurações-avançadas-e-uso-prático) + - [Integrando HPA com Prometheus para Métricas Customizadas](pt/day-11/README.md#integrando-hpa-com-prometheus-para-métricas-customizadas) + - [A sua lição de casa](pt/day-11/README.md#a-sua-lição-de-casa) + - [Final do Day-11](pt/day-11/README.md#final-do-day-11) + +
+ + +
+DAY-12 + +- [Descomplicando o Kubernetes](pt/day-12/README.md#descomplicando-o-kubernetes) + - [DAY-12: Dominando Taints e Tolerations](pt/day-12/README.md#day-12-dominando-taints-e-tolerations) + - [Conteúdo do Day-12](pt/day-12/README.md#conteúdo-do-day-12) + - [Introdução](pt/day-12/README.md#introdução) + - [O que são Taints e Tolerations?](pt/day-12/README.md#o-que-são-taints-e-tolerations) + - [Por que usar Taints e Tolerations?](pt/day-12/README.md#por-que-usar-taints-e-tolerations) + - [Anatomia de um Taint](pt/day-12/README.md#anatomia-de-um-taint) + - [Anatomia de uma Toleration](pt/day-12/README.md#anatomia-de-uma-toleration) + - [Aplicando Taints](pt/day-12/README.md#aplicando-taints) + - [Configurando Tolerations](pt/day-12/README.md#configurando-tolerations) + - [Cenários de Uso](pt/day-12/README.md#cenários-de-uso) + - [Isolamento de Workloads](pt/day-12/README.md#isolamento-de-workloads) + - [Nodes especializados](pt/day-12/README.md#nodes-especializados) + - [Evacuação e Manutenção de Nodes](pt/day-12/README.md#evacuação-e-manutenção-de-nodes) + - [Combinando Taints e Tolerations com Affinity Rules](pt/day-12/README.md#combinando-taints-e-tolerations-com-affinity-rules) + - [Exemplos Práticos](pt/day-12/README.md#exemplos-práticos) + - [Exemplo 1: Isolamento de Workloads](pt/day-12/README.md#exemplo-1-isolamento-de-workloads) + - [Exemplo 2: Utilizando Hardware Especializado](pt/day-12/README.md#exemplo-2-utilizando-hardware-especializado) + - [Exemplo 3: Manutenção de Nodes](pt/day-12/README.md#exemplo-3-manutenção-de-nodes) + - [O que são Selectors?](pt/day-12/README.md#o-que-são-selectors) + - [Tipos de Selectors](pt/day-12/README.md#tipos-de-selectors) + - [Equality-based Selectors](pt/day-12/README.md#equality-based-selectors) + - [Set-based Selectors](pt/day-12/README.md#set-based-selectors) + - [Selectors em Ação](pt/day-12/README.md#selectors-em-ação) + - [Em Services](pt/day-12/README.md#em-services) + - [Em ReplicaSets](pt/day-12/README.md#em-replicasets) + - [Em Jobs e CronJobs](pt/day-12/README.md#em-jobs-e-cronjobs) + - [Selectors e Namespaces](pt/day-12/README.md#selectors-e-namespaces) + - [Cenários de Uso](pt/day-12/README.md#cenários-de-uso-1) + - [Roteamento de Tráfego](pt/day-12/README.md#roteamento-de-tráfego) + - [Scaling Horizontal](pt/day-12/README.md#scaling-horizontal) + - [Desastre e Recuperação](pt/day-12/README.md#desastre-e-recuperação) + - [Dicas e Armadilhas](pt/day-12/README.md#dicas-e-armadilhas) + - [Exemplos Práticos](pt/day-12/README.md#exemplos-práticos-1) + - [Exemplo 1: Selector em um Service](pt/day-12/README.md#exemplo-1-selector-em-um-service) + - [Exemplo 2: Selector em um ReplicaSet](pt/day-12/README.md#exemplo-2-selector-em-um-replicaset) + - [Exemplo 3: Selectors Avançados](pt/day-12/README.md#exemplo-3-selectors-avançados) + +
+ + +
+DAY-13 + +- [Descomplicando o Kubernetes](pt/day-13/README.md#descomplicando-o-kubernetes) + - [DAY-13: Descomplicando Kyverno e as Policies no Kubernetes](pt/day-13/README.md#day-13-descomplicando-kyverno-e-as-policies-no-kubernetes) + - [Conteúdo do Day-13](pt/day-13/README.md#conteúdo-do-day-13) + - [O que iremos ver hoje?](pt/day-13/README.md#o-que-iremos-ver-hoje) + - [Inicio do Day-13](pt/day-13/README.md#inicio-do-day-13) + - [Introdução ao Kyverno](pt/day-13/README.md#introdução-ao-kyverno) + - [Instalando o Kyverno](pt/day-13/README.md#instalando-o-kyverno) + - [Utilizando Helm](pt/day-13/README.md#utilizando-helm) + - [Verificando a Instalação](pt/day-13/README.md#verificando-a-instalação) + - [Criando a nossa primeira Policy](pt/day-13/README.md#criando-a-nossa-primeira-policy) + - [Mais exemplos de Policies](pt/day-13/README.md#mais-exemplos-de-policies) + - [Exemplo de Política: Adicionar Label ao Namespace](pt/day-13/README.md#exemplo-de-política-adicionar-label-ao-namespace) + - [Detalhes da Política](pt/day-13/README.md#detalhes-da-política) + - [Arquivo de Política: `add-label-namespace.yaml`](pt/day-13/README.md#arquivo-de-política-add-label-namespaceyaml) + - [Utilização da Política](pt/day-13/README.md#utilização-da-política) + - [Exemplo de Política: Proibir Usuário Root](pt/day-13/README.md#exemplo-de-política-proibir-usuário-root) + - [Detalhes da Política](pt/day-13/README.md#detalhes-da-política-1) + - [Arquivo de Política: `disallow-root-user.yaml`](pt/day-13/README.md#arquivo-de-política-disallow-root-useryaml) + - [Implementação e Efeito](pt/day-13/README.md#implementação-e-efeito) + - [Exemplo de Política: Gerar ConfigMap para Namespace](pt/day-13/README.md#exemplo-de-política-gerar-configmap-para-namespace) + - [Detalhes da Política](pt/day-13/README.md#detalhes-da-política-2) + - [Arquivo de Política: `generate-configmap-for-namespace.yaml`](pt/day-13/README.md#arquivo-de-política-generate-configmap-for-namespaceyaml) + - [Implementação e Utilidade](pt/day-13/README.md#implementação-e-utilidade) + - [Exemplo de Política: Permitir Apenas Repositórios Confiáveis](pt/day-13/README.md#exemplo-de-política-permitir-apenas-repositórios-confiáveis) + - [Detalhes da Política](pt/day-13/README.md#detalhes-da-política-3) + - [Arquivo de Política: `registry-allowed.yaml`](pt/day-13/README.md#arquivo-de-política-registry-allowedyaml) + - [Implementação e Impacto](pt/day-13/README.md#implementação-e-impacto) + - [Exemplo de Política: Require Probes](pt/day-13/README.md#exemplo-de-política-require-probes) + - [Detalhes da Política](pt/day-13/README.md#detalhes-da-política-4) + - [Arquivo de Política: `require-probes.yaml`](pt/day-13/README.md#arquivo-de-política-require-probesyaml) + - [Implementação e Impacto](pt/day-13/README.md#implementação-e-impacto-1) + - [Exemplo de Política: Usando o Exclude](pt/day-13/README.md#exemplo-de-política-usando-o-exclude) + - [Detalhes da Política](pt/day-13/README.md#detalhes-da-política-5) + - [Arquivo de Política](pt/day-13/README.md#arquivo-de-política) + - [Implementação e Efeitos](pt/day-13/README.md#implementação-e-efeitos) + - [Conclusão](pt/day-13/README.md#conclusão) + - [Pontos-Chave Aprendidos](pt/day-13/README.md#pontos-chave-aprendidos) +
  \ No newline at end of file diff --git a/pt/CONTRIBUTING.md b/pt/CONTRIBUTING.md old mode 100644 new mode 100755 diff --git a/pt/README.md b/pt/README.md old mode 100644 new mode 100755 index fd22cc2f..52242588 --- a/pt/README.md +++ b/pt/README.md @@ -83,23 +83,23 @@ Fique à vontade para aprender muito sobre Kubernetes utilizando esse livro! DAY-3 - [DAY-3](day-3/README.md#day-3) - - [Inicio da aula do Day-3](#inicio-da-aula-do-day-3) - - [O que iremos ver hoje?](#o-que-iremos-ver-hoje) - - [O que é um Deployment?](#o-que-é-um-deployment) - - [Como criar um Deployment?](#como-criar-um-deployment) - - [O que cada parte do arquivo significa?](#o-que-cada-parte-do-arquivo-significa) - - [Como aplicar o Deployment?](#como-aplicar-o-deployment) - - [Como verificar os Pods que o Deployment está gerenciando?](#como-verificar-os-pods-que-o-deployment-está-gerenciando) - - [Como verificar o ReplicaSet que o Deployment está gerenciando?](#como-verificar-o-replicaset-que-o-deployment-está-gerenciando) - - [Como verificar os detalhes do Deployment?](#como-verificar-os-detalhes-do-deployment) - - [Como atualizar o Deployment?](#como-atualizar-o-deployment) - - [E qual é a estratégia de atualização padrão do Deployment?](#e-qual-é-a-estratégia-de-atualização-padrão-do-deployment) - - [As estratégias de atualização do Deployment](#as-estratégias-de-atualização-do-deployment) - - [Estratégia RollingUpdate](#estratégia-rollingupdate) - - [Estratégia Recreate](#estratégia-recreate) - - [Fazendo o rollback de uma atualização](#fazendo-o-rollback-de-uma-atualização) - - [Removendo um Deployment](#removendo-um-deployment) - - [Conclusão](#conclusão) + - [Inicio da aula do Day-3](day-3/README.md#inicio-da-aula-do-day-3) + - [O que iremos ver hoje?](day-3/README.md#o-que-iremos-ver-hoje) + - [O que é um Deployment?](day-3/README.md#o-que-é-um-deployment) + - [Como criar um Deployment?](day-3/README.md#como-criar-um-deployment) + - [O que cada parte do arquivo significa?](day-3/README.md#o-que-cada-parte-do-arquivo-significa) + - [Como aplicar o Deployment?](day-3/README.md#como-aplicar-o-deployment) + - [Como verificar os Pods que o Deployment está gerenciando?](day-3/README.md#como-verificar-os-pods-que-o-deployment-está-gerenciando) + - [Como verificar o ReplicaSet que o Deployment está gerenciando?](day-3/README.md#como-verificar-o-replicaset-que-o-deployment-está-gerenciando) + - [Como verificar os detalhes do Deployment?](day-3/README.md#como-verificar-os-detalhes-do-deployment) + - [Como atualizar o Deployment?](day-3/README.md#como-atualizar-o-deployment) + - [E qual é a estratégia de atualização padrão do Deployment?](day-3/README.md#e-qual-é-a-estratégia-de-atualização-padrão-do-deployment) + - [As estratégias de atualização do Deployment](day-3/README.md#as-estratégias-de-atualização-do-deployment) + - [Estratégia RollingUpdate](day-3/README.md#estratégia-rollingupdate) + - [Estratégia Recreate](day-3/README.md#estratégia-recreate) + - [Fazendo o rollback de uma atualização](day-3/README.md#fazendo-o-rollback-de-uma-atualização) + - [Removendo um Deployment](day-3/README.md#removendo-um-deployment) + - [Conclusão](day-3/README.md#conclusão)
@@ -224,11 +224,41 @@ Fique à vontade para aprender muito sobre Kubernetes utilizando esse livro! - [Criando um Secret TLS](day-8/README.md#criando-um-secret-tls) - [ConfigMaps](day-8/README.md#configmaps) - [Final do Day-8](day-8/README.md#final-do-day-8) + -
DAY-9 +- [Descomplicando o Kubernetes](day-9/README.md#descomplicando-o-kubernetes) + - [DAY-9: Descomplicando o Ingress no Kubernetes](day-9/README.md#day-9-descomplicando-o-ingress-no-kubernetes) + - [Conteúdo do Day-9](day-9/README.md#conteúdo-do-day-9) + - [O que iremos ver hoje?](day-9/README.md#o-que-iremos-ver-hoje) + - [Conteúdo do Day-9](day-9/README.md#conteúdo-do-day-9-1) +- [O Que é o Ingress?](day-9/README.md#o-que-é-o-ingress) + - [Teoria: O que é Ingress?](day-9/README.md#teoria-o-que-é-ingress) + - [Prática: Mãos à Obra](day-9/README.md#prática-mãos-à-obra) + - [Criando um Serviço Simples](day-9/README.md#criando-um-serviço-simples) +- [Seção 2: Componentes do Ingress](day-9/README.md#seção-2-componentes-do-ingress) + - [Introdução](day-9/README.md#introdução) + - [Teoria: Componentes Chave](day-9/README.md#teoria-componentes-chave) + - [Ingress Controller](day-9/README.md#ingress-controller) + - [Ingress Resources](day-9/README.md#ingress-resources) + - [Annotations e Customizations](day-9/README.md#annotations-e-customizations) + - [Prática: Montando o Quebra-Cabeça](day-9/README.md#prática-montando-o-quebra-cabeça) + - [Instalando um Nginx Ingress Controller](day-9/README.md#instalando-um-nginx-ingress-controller) + - [Instalando o Nginx Ingress Controller no Kind](day-9/README.md#instalando-o-nginx-ingress-controller-no-kind) + - [Introdução](day-9/README.md#introdução-1) + - [Criando o Cluster com Configurações Especiais](day-9/README.md#criando-o-cluster-com-configurações-especiais) + - [Instalando um Ingress Controller](day-9/README.md#instalando-um-ingress-controller) + - [Criando um Recurso de Ingress](day-9/README.md#criando-um-recurso-de-ingress) + - [Annotations para Customização](day-9/README.md#annotations-para-customização) +- [Seção 3: Configurando Rotas](day-9/README.md#seção-3-configurando-rotas) + - [Introdução](day-9/README.md#introdução-2) + - [Teoria: O Que São Rotas?](day-9/README.md#teoria-o-que-são-rotas) + - [Prática: Configurando Rotas Simples](day-9/README.md#prática-configurando-rotas-simples) + - [Prática: Configurando Rotas Avançadas](day-9/README.md#prática-configurando-rotas-avançadas) +
@@ -239,6 +269,127 @@ Fique à vontade para aprender muito sobre Kubernetes utilizando esse livro!
DAY-11 +- [Descomplicando o Kubernetes](day-11/README.md#descomplicando-o-kubernetes) + - [DAY-11](day-11/README.md#day-11) + - [Conteúdo do Day-11](day-11/README.md#conteúdo-do-day-11) + - [Início da aula do Day-11](day-11/README.md#início-da-aula-do-day-11) + - [O que iremos ver hoje?](day-11/README.md#o-que-iremos-ver-hoje) + - [Introdução ao Horizontal Pod Autoscaler (HPA)](day-11/README.md#introdução-ao-horizontal-pod-autoscaler-hpa) + - [Como o HPA Funciona?](day-11/README.md#como-o-hpa-funciona) + - [Introdução ao Metrics Server](day-11/README.md#introdução-ao-metrics-server) + - [Por que o Metrics Server é importante para o HPA?](day-11/README.md#por-que-o-metrics-server-é-importante-para-o-hpa) + - [Instalando o Metrics Server](day-11/README.md#instalando-o-metrics-server) + - [No Amazon EKS e na maioria dos clusters Kubernetes](day-11/README.md#no-amazon-eks-e-na-maioria-dos-clusters-kubernetes) + - [No Minikube:](day-11/README.md#no-minikube) + - [No KinD (Kubernetes in Docker):](day-11/README.md#no-kind-kubernetes-in-docker) + - [Verificando a Instalação do Metrics Server](day-11/README.md#verificando-a-instalação-do-metrics-server) + - [Obtendo Métricas](day-11/README.md#obtendo-métricas) + - [Criando um HPA](day-11/README.md#criando-um-hpa) + - [Exemplos Práticos com HPA](day-11/README.md#exemplos-práticos-com-hpa) + - [Autoscaling com base na utilização de CPU](day-11/README.md#autoscaling-com-base-na-utilização-de-cpu) + - [Autoscaling com base na utilização de Memória](day-11/README.md#autoscaling-com-base-na-utilização-de-memória) + - [Configuração Avançada de HPA: Definindo Comportamento de Escalonamento](day-11/README.md#configuração-avançada-de-hpa-definindo-comportamento-de-escalonamento) + - [ContainerResource](day-11/README.md#containerresource) + - [Detalhes do Algoritmo de Escalonamento](day-11/README.md#detalhes-do-algoritmo-de-escalonamento) + - [Configurações Avançadas e Uso Prático](day-11/README.md#configurações-avançadas-e-uso-prático) + - [Integrando HPA com Prometheus para Métricas Customizadas](day-11/README.md#integrando-hpa-com-prometheus-para-métricas-customizadas) + - [A sua lição de casa](day-11/README.md#a-sua-lição-de-casa) + - [Final do Day-11](day-11/README.md#final-do-day-11) + +
+ + +
+DAY-12 + +- [Descomplicando o Kubernetes](day-12/README.md#descomplicando-o-kubernetes) + - [DAY-12: Dominando Taints e Tolerations](day-12/README.md#day-12-dominando-taints-e-tolerations) + - [Conteúdo do Day-12](day-12/README.md#conteúdo-do-day-12) + - [Introdução](day-12/README.md#introdução) + - [O que são Taints e Tolerations?](day-12/README.md#o-que-são-taints-e-tolerations) + - [Por que usar Taints e Tolerations?](day-12/README.md#por-que-usar-taints-e-tolerations) + - [Anatomia de um Taint](day-12/README.md#anatomia-de-um-taint) + - [Anatomia de uma Toleration](day-12/README.md#anatomia-de-uma-toleration) + - [Aplicando Taints](day-12/README.md#aplicando-taints) + - [Configurando Tolerations](day-12/README.md#configurando-tolerations) + - [Cenários de Uso](day-12/README.md#cenários-de-uso) + - [Isolamento de Workloads](day-12/README.md#isolamento-de-workloads) + - [Nodes especializados](day-12/README.md#nodes-especializados) + - [Evacuação e Manutenção de Nodes](day-12/README.md#evacuação-e-manutenção-de-nodes) + - [Combinando Taints e Tolerations com Affinity Rules](day-12/README.md#combinando-taints-e-tolerations-com-affinity-rules) + - [Exemplos Práticos](day-12/README.md#exemplos-práticos) + - [Exemplo 1: Isolamento de Workloads](day-12/README.md#exemplo-1-isolamento-de-workloads) + - [Exemplo 2: Utilizando Hardware Especializado](day-12/README.md#exemplo-2-utilizando-hardware-especializado) + - [Exemplo 3: Manutenção de Nodes](day-12/README.md#exemplo-3-manutenção-de-nodes) + - [O que são Selectors?](day-12/README.md#o-que-são-selectors) + - [Tipos de Selectors](day-12/README.md#tipos-de-selectors) + - [Equality-based Selectors](day-12/README.md#equality-based-selectors) + - [Set-based Selectors](day-12/README.md#set-based-selectors) + - [Selectors em Ação](day-12/README.md#selectors-em-ação) + - [Em Services](day-12/README.md#em-services) + - [Em ReplicaSets](day-12/README.md#em-replicasets) + - [Em Jobs e CronJobs](day-12/README.md#em-jobs-e-cronjobs) + - [Selectors e Namespaces](day-12/README.md#selectors-e-namespaces) + - [Cenários de Uso](day-12/README.md#cenários-de-uso-1) + - [Roteamento de Tráfego](day-12/README.md#roteamento-de-tráfego) + - [Scaling Horizontal](day-12/README.md#scaling-horizontal) + - [Desastre e Recuperação](day-12/README.md#desastre-e-recuperação) + - [Dicas e Armadilhas](day-12/README.md#dicas-e-armadilhas) + - [Exemplos Práticos](day-12/README.md#exemplos-práticos-1) + - [Exemplo 1: Selector em um Service](day-12/README.md#exemplo-1-selector-em-um-service) + - [Exemplo 2: Selector em um ReplicaSet](day-12/README.md#exemplo-2-selector-em-um-replicaset) + - [Exemplo 3: Selectors Avançados](day-12/README.md#exemplo-3-selectors-avançados) + +
+ + +
+DAY-13 + +- [Descomplicando o Kubernetes](day-13/README.md#descomplicando-o-kubernetes) + - [DAY-13: Descomplicando Kyverno e as Policies no Kubernetes](day-13/README.md#day-13-descomplicando-kyverno-e-as-policies-no-kubernetes) + - [Conteúdo do Day-13](day-13/README.md#conteúdo-do-day-13) + - [O que iremos ver hoje?](day-13/README.md#o-que-iremos-ver-hoje) + - [Inicio do Day-13](day-13/README.md#inicio-do-day-13) + - [Introdução ao Kyverno](day-13/README.md#introdução-ao-kyverno) + - [Instalando o Kyverno](day-13/README.md#instalando-o-kyverno) + - [Utilizando Helm](day-13/README.md#utilizando-helm) + - [Verificando a Instalação](day-13/README.md#verificando-a-instalação) + - [Criando a nossa primeira Policy](day-13/README.md#criando-a-nossa-primeira-policy) + - [Mais exemplos de Policies](day-13/README.md#mais-exemplos-de-policies) + - [Exemplo de Política: Adicionar Label ao Namespace](day-13/README.md#exemplo-de-política-adicionar-label-ao-namespace) + - [Detalhes da Política](day-13/README.md#detalhes-da-política) + - [Arquivo de Política: `add-label-namespace.yaml`](day-13/README.md#arquivo-de-política-add-label-namespaceyaml) + - [Utilização da Política](day-13/README.md#utilização-da-política) + - [Exemplo de Política: Proibir Usuário Root](day-13/README.md#exemplo-de-política-proibir-usuário-root) + - [Detalhes da Política](day-13/README.md#detalhes-da-política-1) + - [Arquivo de Política: `disallow-root-user.yaml`](day-13/README.md#arquivo-de-política-disallow-root-useryaml) + - [Implementação e Efeito](day-13/README.md#implementação-e-efeito) + - [Exemplo de Política: Gerar ConfigMap para Namespace](day-13/README.md#exemplo-de-política-gerar-configmap-para-namespace) + - [Detalhes da Política](day-13/README.md#detalhes-da-política-2) + - [Arquivo de Política: `generate-configmap-for-namespace.yaml`](day-13/README.md#arquivo-de-política-generate-configmap-for-namespaceyaml) + - [Implementação e Utilidade](day-13/README.md#implementação-e-utilidade) + - [Exemplo de Política: Permitir Apenas Repositórios Confiáveis](day-13/README.md#exemplo-de-política-permitir-apenas-repositórios-confiáveis) + - [Detalhes da Política](day-13/README.md#detalhes-da-política-3) + - [Arquivo de Política: `registry-allowed.yaml`](day-13/README.md#arquivo-de-política-registry-allowedyaml) + - [Implementação e Impacto](day-13/README.md#implementação-e-impacto) + - [Exemplo de Política: Require Probes](day-13/README.md#exemplo-de-política-require-probes) + - [Detalhes da Política](day-13/README.md#detalhes-da-política-4) + - [Arquivo de Política: `require-probes.yaml`](day-13/README.md#arquivo-de-política-require-probesyaml) + - [Implementação e Impacto](day-13/README.md#implementação-e-impacto-1) + - [Exemplo de Política: Usando o Exclude](day-13/README.md#exemplo-de-política-usando-o-exclude) + - [Detalhes da Política](day-13/README.md#detalhes-da-política-5) + - [Arquivo de Política](day-13/README.md#arquivo-de-política) + - [Implementação e Efeitos](day-13/README.md#implementação-e-efeitos) + - [Conclusão](day-13/README.md#conclusão) + - [Pontos-Chave Aprendidos](day-13/README.md#pontos-chave-aprendidos) + +
+ + +
+DAY-14 +
  diff --git a/pt/SUMMARY.md b/pt/SUMMARY.md old mode 100644 new mode 100755 index d9ad8774..0ddea892 --- a/pt/SUMMARY.md +++ b/pt/SUMMARY.md @@ -4,23 +4,21 @@ * [Introdução](README.md) ## Capítulos -* [Descomplicando Kubernetes dia 1](day_one/README.md) -* [Descomplicando Kubernetes dia 2](day_two/README.md) -* [Descomplicando Kubernetes dia 3](day_three/README.md) -* [Descomplicando Kubernetes dia 4](day_four/README.md) -* [Descomplicando Kubernetes dia 5](day_five/README.md) -* [Descomplicando Kubernetes dia 6](day_six/README.md) -* [Descomplicando Kubernetes dia 7](day_seven/README.md) -* [Descomplicando Kubernetes dia 8](day_eight/README.md) -* [Descomplicando Kubernetes dia 9](day_nine/README.md) -* [Descomplicando Kubernetes dia 10](day_ten/README.md) -* [Descomplicando Kubernetes dia 11](day_eleven/README.md) - - -## Extras -* [Cloud providers](extras/cloud-providers/cloud-providers.md) -* [Dicas para o exame](extras/exame_tips.md) -* [Pod security policy](extras/pod_security_policy.md) +* [Descomplicando Kubernetes dia 1](day-1/README.md) +* [Descomplicando Kubernetes dia 2](day-2/README.md) +* [Descomplicando Kubernetes dia 3](day-3/README.md) +* [Descomplicando Kubernetes dia 4](day-4/README.md) +* [Descomplicando Kubernetes dia 5](day-5/README.md) +* [Descomplicando Kubernetes dia 6](day-6/README.md) +* [Descomplicando Kubernetes dia 7](day-7/README.md) +* [Descomplicando Kubernetes dia 8](day-8/README.md) +* [Descomplicando Kubernetes dia 9](day-9/README.md) +* [Descomplicando Kubernetes dia 10](day-10/README.md) +* [Descomplicando Kubernetes dia 11](day-11/README.md) +* [Descomplicando Kubernetes dia 12](day-12/README.md) +* [Descomplicando Kubernetes dia 13](day-13/README.md) +* [Descomplicando Kubernetes dia 14](day-14/README.md) +* [Descomplicando Kubernetes dia 15](day-15/README.md) ## Contribuir * [Como ajudar](CONTRIBUTING.md) \ No newline at end of file diff --git a/pt/day_one/README.md b/pt/day-1/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_one/README.md rename to pt/day-1/README.md diff --git a/pt/day_one/files/desafio/meu-primeiro-pod.yaml b/pt/day-1/files/desafio/meu-primeiro-pod.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_one/files/desafio/meu-primeiro-pod.yaml rename to pt/day-1/files/desafio/meu-primeiro-pod.yaml diff --git a/pt/day-10/README.md b/pt/day-10/README.md old mode 100644 new mode 100755 diff --git a/pt/day-11/README.md b/pt/day-11/README.md new file mode 100644 index 00000000..c8d0085b --- /dev/null +++ b/pt/day-11/README.md @@ -0,0 +1,362 @@ +# Descomplicando o Kubernetes +## DAY-11 + +  + +## Conteúdo do Day-11 + +- [Descomplicando o Kubernetes](#descomplicando-o-kubernetes) + - [DAY-11](#day-11) + - [Conteúdo do Day-11](#conteúdo-do-day-11) + - [Início da aula do Day-11](#início-da-aula-do-day-11) + - [O que iremos ver hoje?](#o-que-iremos-ver-hoje) + - [Introdução ao Horizontal Pod Autoscaler (HPA)](#introdução-ao-horizontal-pod-autoscaler-hpa) + - [Como o HPA Funciona?](#como-o-hpa-funciona) + - [Introdução ao Metrics Server](#introdução-ao-metrics-server) + - [Por que o Metrics Server é importante para o HPA?](#por-que-o-metrics-server-é-importante-para-o-hpa) + - [Instalando o Metrics Server](#instalando-o-metrics-server) + - [No Amazon EKS e na maioria dos clusters Kubernetes](#no-amazon-eks-e-na-maioria-dos-clusters-kubernetes) + - [No Minikube:](#no-minikube) + - [No KinD (Kubernetes in Docker):](#no-kind-kubernetes-in-docker) + - [Verificando a Instalação do Metrics Server](#verificando-a-instalação-do-metrics-server) + - [Obtendo Métricas](#obtendo-métricas) + - [Criando um HPA](#criando-um-hpa) + - [Exemplos Práticos com HPA](#exemplos-práticos-com-hpa) + - [Autoscaling com base na utilização de CPU](#autoscaling-com-base-na-utilização-de-cpu) + - [Autoscaling com base na utilização de Memória](#autoscaling-com-base-na-utilização-de-memória) + - [Configuração Avançada de HPA: Definindo Comportamento de Escalonamento](#configuração-avançada-de-hpa-definindo-comportamento-de-escalonamento) + - [ContainerResource](#containerresource) + - [Detalhes do Algoritmo de Escalonamento](#detalhes-do-algoritmo-de-escalonamento) + - [Configurações Avançadas e Uso Prático](#configurações-avançadas-e-uso-prático) + - [Integrando HPA com Prometheus para Métricas Customizadas](#integrando-hpa-com-prometheus-para-métricas-customizadas) + - [A sua lição de casa](#a-sua-lição-de-casa) + - [Final do Day-11](#final-do-day-11) + +  + +### Início da aula do Day-11 + +#### O que iremos ver hoje? + +Hoje é um dia particularmente fascinante! Vamos desbravar os territórios do Kubernetes, explorando a magia do Horizontal Pod Autoscaler (HPA), uma ferramenta indispensável para quem almeja uma operação eficiente e resiliente. Portanto, afivelem os cintos e preparem-se para uma jornada de descobertas. A aventura #VAIIII começar! + +#### Introdução ao Horizontal Pod Autoscaler (HPA) + +O Horizontal Pod Autoscaler, carinhosamente conhecido como HPA, é uma das joias brilhantes incrustadas no coração do Kubernetes. Com o HPA, podemos ajustar automaticamente o número de réplicas de um conjunto de pods, assegurando que nosso aplicativo tenha sempre os recursos necessários para performar eficientemente, sem desperdiçar recursos. O HPA é como um maestro que, com a batuta das métricas, rege a orquestra de pods, assegurando que a harmonia seja mantida mesmo quando a sinfonia do tráfego de rede atinge seu crescendo. + +#### Como o HPA Funciona? + +O HPA é o olheiro vigilante que monitora as métricas dos nossos pods. A cada batida do seu coração métrico, que ocorre em intervalos regulares, ele avalia se os pods estão suando a camisa para atender às demandas ou se estão relaxando mais do que deveriam. Com base nessa avaliação, ele toma a decisão sábia de convocar mais soldados para o campo de batalha ou de dispensar alguns para um merecido descanso. + +Certamente! O Metrics Server é uma componente crucial para o funcionamento do Horizontal Pod Autoscaler (HPA), pois fornece as métricas necessárias para que o HPA tome decisões de escalonamento. Vamos entender um pouco mais sobre o Metrics Server e como instalá-lo em diferentes ambientes Kubernetes, incluindo Minikube e KinD. + +--- + +## Introdução ao Metrics Server + +Antes de começarmos a explorar o Horizontal Pod Autoscaler (HPA), é essencial termos o Metrics Server instalado em nosso cluster Kubernetes. O Metrics Server é um agregador de métricas de recursos de sistema, que coleta métricas como uso de CPU e memória dos nós e pods no cluster. Essas métricas são vitais para o funcionamento do HPA, pois são usadas para determinar quando e como escalar os recursos. + +### Por que o Metrics Server é importante para o HPA? + +O HPA utiliza métricas de uso de recursos para tomar decisões inteligentes sobre o escalonamento dos pods. Por exemplo, se a utilização da CPU de um pod exceder um determinado limite, o HPA pode decidir aumentar o número de réplicas desse pod. Da mesma forma, se a utilização da CPU for muito baixa, o HPA pode decidir reduzir o número de réplicas. Para fazer isso de forma eficaz, o HPA precisa ter acesso a métricas precisas e atualizadas, que são fornecidas pelo Metrics Server. +Portanto, precisamos antes conhecer essa peça fundamental para o dia de hoje! :D + +### Instalando o Metrics Server + +#### No Amazon EKS e na maioria dos clusters Kubernetes + +Durante a nossa aula, estou com um cluster EKS, e para instalar o Metrics Server, podemos usar o seguinte comando: + +```bash +kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml +``` + +Esse comando aplica o manifesto do Metrics Server ao seu cluster, instalando todos os componentes necessários. + +#### No Minikube: + +A instalação do Metrics Server no Minikube é bastante direta. Use o seguinte comando para habilitar o Metrics Server: + +```bash +minikube addons enable metrics-server +``` + +Após a execução deste comando, o Metrics Server será instalado e ativado em seu cluster Minikube. + +#### No KinD (Kubernetes in Docker): + +Para o KinD, você pode usar o mesmo comando que usou para o EKS: + +```bash +kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml +``` + +#### Verificando a Instalação do Metrics Server + +Após a instalação do Metrics Server, é uma boa prática verificar se ele foi instalado corretamente e está funcionando como esperado. Execute o seguinte comando para obter a lista de pods no namespace `kube-system` e verificar se o pod do Metrics Server está em execução: + +```bash +kubectl get pods -n kube-system | grep metrics-server +``` + +#### Obtendo Métricas + +Com o Metrics Server em execução, agora você pode começar a coletar métricas de seu cluster. Aqui está um exemplo de como você pode obter métricas de uso de CPU e memória para todos os seus nodes: + +```bash +kubectl top nodes +``` + +E para obter métricas de uso de CPU e memória para todos os seus pods: + +```bash +kubectl top pods +``` + +Esses comandos fornecem uma visão rápida da utilização de recursos em seu cluster, o que é crucial para entender e otimizar o desempenho de seus aplicativos. + +### Criando um HPA + +Antes de nos aprofundarmos no HPA, vamos recapitular criando um deployment simples para o nosso confiável servidor Nginx. + +```yaml +# Definição de um Deployment para o servidor Nginx +apiVersion: apps/v1 # Versão da API que define um Deployment +kind: Deployment # Tipo de recurso que estamos definindo +metadata: + name: nginx-deployment # Nome do nosso Deployment +spec: + replicas: 3 # Número inicial de réplicas + selector: + matchLabels: + app: nginx # Label que identifica os pods deste Deployment + template: + metadata: + labels: + app: nginx # Label aplicada aos pods + spec: + containers: + - name: nginx # Nome do contêiner + image: nginx:latest # Imagem do contêiner + ports: + - containerPort: 80 # Porta exposta pelo contêiner + resources: + limits: + cpu: 500m # Limite de CPU + memory: 256Mi # Limite de memória + requests: + cpu: 250m # Requisição de CPU + memory: 128Mi # Requisição de memória +``` + +Agora, com nosso deployment pronto, vamos dar o próximo passo na criação do nosso HPA. + +```yaml +# Definição do HPA para o nginx-deployment +apiVersion: autoscaling/v2 # Versão da API que define um HPA +kind: HorizontalPodAutoscaler # Tipo de recurso que estamos definindo +metadata: + name: nginx-deployment-hpa # Nome do nosso HPA +spec: + scaleTargetRef: + apiVersion: apps/v1 # A versão da API do recurso alvo + kind: Deployment # O tipo de recurso alvo + name: nginx-deployment # O nome do recurso alvo + minReplicas: 3 # Número mínimo de réplicas + maxReplicas: 10 # Número máximo de réplicas + metrics: + - type: Resource # Tipo de métrica (recurso do sistema) + resource: + name: cpu # Nome da métrica (CPU neste caso) + target: + type: Utilization # Tipo de alvo (utilização) + averageUtilization: 50 # Valor alvo (50% de utilização) +``` + +Neste exemplo, criamos um HPA que monitora a utilização da CPU do nosso `nginx-deployment`. O HPA se esforçará para manter a utilização da CPU em torno de 50%, ajustando o número de réplicas entre 3 e 10 conforme necessário. + +Para aplicar esta configuração ao seu cluster Kubernetes, salve o conteúdo acima em um arquivo chamado + + `nginx-deployment-hpa.yaml` e execute o seguinte comando: + +```bash +kubectl apply -f nginx-deployment-hpa.yaml +``` + +Agora, você tem um HPA monitorando e ajustando a escala do seu `nginx-deployment` baseado na utilização da CPU. Fantástico, não é? + +### Exemplos Práticos com HPA + +Agora que você já entende o básico sobre o HPA, é hora de rolar as mangas e entrar na prática. Vamos explorar como o HPA responde a diferentes métricas e cenários. + +#### Autoscaling com base na utilização de CPU + +Vamos começar com um exemplo clássico de escalonamento baseado na utilização da CPU, que já discutimos anteriormente. Para tornar a aprendizagem mais interativa, vamos simular um aumento de tráfego e observar como o HPA responde a essa mudança. + +```bash +kubectl run -i --tty load-generator --image=busybox /bin/sh + +while true; do wget -q -O- http://nginx-deployment.default.svc.cluster.local; done +``` + +Este script simples cria uma carga constante no nosso deployment, fazendo requisições contínuas ao servidor Nginx. Você poderá observar como o HPA ajusta o número de réplicas para manter a utilização da CPU em torno do limite definido. + +#### Autoscaling com base na utilização de Memória + +O HPA não é apenas um mestre em lidar com a CPU, ele também tem um olho afiado para a memória. Vamos explorar como configurar o HPA para escalar baseado na utilização de memória. + +```yaml +# Definição do HPA para escalonamento baseado em memória +apiVersion: autoscaling/v2 # Versão da API que define um HPA +kind: HorizontalPodAutoscaler # Tipo de recurso que estamos definindo +metadata: + name: nginx-deployment-hpa-memory # Nome do nosso HPA +spec: + scaleTargetRef: + apiVersion: apps/v1 # A versão da API do recurso alvo + kind: Deployment # O tipo de recurso alvo + name: nginx-deployment # O nome do recurso alvo + minReplicas: 3 # Número mínimo de réplicas + maxReplicas: 10 # Número máximo de réplicas + metrics: + - type: Resource # Tipo de métrica (recurso do sistema) + resource: + name: memory # Nome da métrica (memória neste caso) + target: + type: Utilization # Tipo de alvo (utilização) + averageUtilization: 70 # Valor alvo (70% de utilização) +``` + +Neste exemplo, o HPA vai ajustar o número de réplicas para manter a utilização de memória em cerca de 70%. Assim, nosso deployment pode respirar livremente mesmo quando a demanda aumenta. + +#### Configuração Avançada de HPA: Definindo Comportamento de Escalonamento + +O HPA é flexível e permite que você defina como ele deve se comportar durante o escalonamento para cima e para baixo. Vamos explorar um exemplo: + +```yaml +# Definição de HPA com configurações avançadas de comportamento +apiVersion: autoscaling/v2 # Versão da API que define um HPA +kind: HorizontalPodAutoscaler # Tipo de recurso que estamos definindo +metadata: + name: nginx-deployment-hpa # Nome do nosso HPA +spec: + scaleTargetRef: + apiVersion: apps/v1 # A versão da API do recurso alvo + kind: Deployment # O tipo de recurso alvo + name: nginx-deployment # O nome do recurso alvo + minReplicas: 3 # Número mínimo de réplicas + maxReplicas: 10 # Número máximo de réplicas + metrics: + - type: Resource # Tipo de métrica (recurso do sistema) + resource: + name: cpu # Nome da métrica (CPU neste caso) + target: + type: Utilization # Tipo de alvo (utilização) + averageUtilization: 50 # Valor alvo (50% de utilização) + behavior: + scaleUp: + stabilizationWindowSeconds: 0 # Período de estabilização para escalonamento para cima + policies: + - type: Percent # Tipo de política (percentual) + value: 100 # Valor da política (100%) + periodSeconds: 15 # Período da política (15 segundos) + scaleDown: + stabilizationWindowSeconds: 300 # Período de estabilização para escalonamento para baixo + policies: + - type: Percent # Tipo de política (percentual) + value: 100 # Valor da política (100%) + periodSeconds: 15 # Período da política (15 segundos) +``` + +Neste exemplo, especificamos um comportamento de escalonamento onde o HPA pode escalar para cima imediatamente, mas vai esperar por 5 minutos (300 segundos) após o último escalonamento para cima antes de considerar um escalonamento para baixo. Isso ajuda a evitar flutuações rápidas na contagem de réplicas, proporcionando um ambiente mais estável para nossos pods. + + +#### ContainerResource + +O tipo de métrica `ContainerResource` no Kubernetes permite que você especifique métricas de recursos específicas do container para escalar. Diferente das métricas de recurso comuns que são aplicadas a todos os contêineres em um Pod, as métricas `ContainerResource` permitem especificar métricas para um contêiner específico dentro de um Pod. Isso pode ser útil em cenários onde você tem múltiplos contêineres em um Pod, mas quer escalar com base na utilização de recursos de um contêiner específico. + +Aqui está um exemplo de como você pode configurar um Horizontal Pod Autoscaler (HPA) usando uma métrica `ContainerResource` para escalar um Deployment com base na utilização de CPU de um contêiner específico: + +```yaml +apiVersion: autoscaling/v2beta2 +kind: HorizontalPodAutoscaler +metadata: + name: nginx-hpa +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: nginx + minReplicas: 3 + maxReplicas: 10 + metrics: + - type: ContainerResource + containerResource: + name: cpu + container: nginx-NOME-COMPLETO-DO-CONTAINER + target: + type: Utilization + averageUtilization: 50 +``` + +No exemplo acima: + +- O tipo de métrica é definido como `ContainerResource`. +- Dentro do bloco `containerResource`, especificamos o nome da métrica (`cpu`), o nome do contêiner (`my-container`) e o alvo de utilização (`averageUtilization: 50`). + +Isso significa que o HPA vai ajustar o número de réplicas do Deployment `my-app` para manter a utilização média de CPU do contêiner `nginx-NOME-COMPLETO-DO-CONTAINER` em torno de 50%. + +Este tipo de configuração permite um controle mais granular sobre o comportamento de autoscaling, especialmente em ambientes onde os Pods contêm múltiplos contêineres com diferentes perfis de utilização de recursos. + + +#### Detalhes do Algoritmo de Escalonamento + +**Cálculo do Número de Réplicas** +O núcleo do Horizontal Pod Autoscaler (HPA) é o seu algoritmo de escalonamento, que determina o número ideal de réplicas com base nas métricas fornecidas. A fórmula básica utilizada pelo HPA para calcular o número desejado de réplicas é: + +\[ \text{desiredReplicas} = \lceil \text{currentReplicas} \times \left( \frac{\text{currentMetricValue}}{\text{desiredMetricValue}} \right) \rceil \] + +**Exemplos com Valores Específicos:** +1. **Exemplo de Escala para Cima:** + - Réplicas atuais: 2 + - Valor atual da métrica (CPU): 80% + - Valor desejado da métrica (CPU): 50% + - Cálculo: \(\lceil 2 \times (80\% / 50\%) \rceil = \lceil 3.2 \rceil = 4\) réplicas + +2. **Exemplo de Escala para Baixo:** + - Réplicas atuais: 5 + - Valor atual da métrica (CPU): 30% + - Valor desejado da métrica (CPU): 50% + - Cálculo: \(\lceil 5 \times (30\% / 50\%) \rceil = \lceil 3 \rceil = 3\) réplicas + +**Considerações Sobre Métricas e Estado dos Pods:** +- **Métricas de Recurso por Pod e Personalizadas:** O HPA pode ser configurado para usar métricas padrão (como CPU e memória) ou métricas personalizadas definidas pelo usuário, permitindo maior flexibilidade. +- **Tratamento de Pods sem Métricas ou Não Prontos:** Se um Pod não tiver métricas disponíveis ou não estiver pronto, ele pode ser excluído do cálculo de média, evitando decisões de escalonamento baseadas em dados incompletos. + +#### Configurações Avançadas e Uso Prático + +**Configurando Métricas Personalizadas e Múltiplas Métricas:** +O HPA não se limita apenas a métricas de CPU e memória; ele pode ser configurado para usar uma variedade de métricas personalizadas. + +**Uso de Métricas Personalizadas: Exemplos e Dicas:** +- **Exemplo:** Suponha que você tenha um serviço que deve escalar com base no número de solicitações HTTP por segundo. Você pode configurar o HPA para escalar com base nessa métrica personalizada. +- **Dicas:** Ao usar métricas personalizadas, assegure-se de que as métricas sejam um indicador confiável da carga de trabalho e que o serviço de métricas esteja corretamente configurado e acessível pelo HPA. + +**Escalonamento com Base em Várias Métricas:** +- O HPA pode ser configurado para levar em conta várias métricas ao mesmo tempo, permitindo um controle mais refinado do escalonamento. +- Por exemplo, você pode configurar o HPA para escalar com base tanto na utilização de CPU quanto na memória, ou qualquer combinação de métricas padrão e personalizadas. + + +#### Integrando HPA com Prometheus para Métricas Customizadas + +Para levar o autoscaling para o próximo nível, podemos integrar o HPA com o Prometheus. Com essa integração, podemos usar métricas do Prometheus para informar nossas decisões de autoscaling. + +A integração geralmente envolve a configuração de um adaptador de métricas personalizadas, como o `k8s-prometheus-adapter`. Uma vez configurado, o HPA pode acessar métricas do Prometheus e usá-las para tomar decisões de autoscaling. A documentação completa sobre como integrar o HPA com o Prometheus pode ser encontrada [aqui](#adicionar-link). + +### A sua lição de casa + +Agora que você foi equipado com o conhecimento sobre o HPA, é hora de colocar esse conhecimento em prática. Configure um HPA em seu ambiente e experimente com diferentes métricas: CPU, memória e métricas personalizadas. Documente suas observações e compreenda como o HPA responde a diferentes cargas e situações. + +### Final do Day-11 + +E assim, chegamos ao fim do Day-11, uma jornada repleta de aprendizado e exploração. Hoje, você descobriu o poder do Horizontal Pod Autoscaler e como ele pode ajudar a manter seu aplicativo performando de maneira eficiente, mesmo sob diferentes condições de carga. Você não apenas aprendeu como ele funciona, mas também colocou a mão na massa com exemplos práticos. Continue praticando e explorando, e nos vemos no próximo dia da nossa aventura pelo Kubernetes! #VAIIII \ No newline at end of file diff --git a/pt/day-12/README.md b/pt/day-12/README.md new file mode 100644 index 00000000..540663b1 --- /dev/null +++ b/pt/day-12/README.md @@ -0,0 +1,337 @@ +# Descomplicando o Kubernetes +## DAY-12: Dominando Taints e Tolerations + +## Conteúdo do Day-12 + +- [Descomplicando o Kubernetes](#descomplicando-o-kubernetes) + - [DAY-12: Dominando Taints e Tolerations](#day-12-dominando-taints-e-tolerations) + - [Conteúdo do Day-12](#conteúdo-do-day-12) + - [Introdução](#introdução) + - [O que são Taints e Tolerations?](#o-que-são-taints-e-tolerations) + - [Por que usar Taints e Tolerations?](#por-que-usar-taints-e-tolerations) + - [Anatomia de um Taint](#anatomia-de-um-taint) + - [Anatomia de uma Toleration](#anatomia-de-uma-toleration) + - [Aplicando Taints](#aplicando-taints) + - [Configurando Tolerations](#configurando-tolerations) + - [Cenários de Uso](#cenários-de-uso) + - [Isolamento de Workloads](#isolamento-de-workloads) + - [Nodes Especializados](#nodes-especializados) + - [Evacuação e Manutenção de Nodes](#evacuação-e-manutenção-de-nodes) + - [Combinando Taints e Tolerations com Affinity Rules](#combinando-taints-e-tolerations-com-affinity-rules) + - [Exemplos Práticos](#exemplos-práticos) + - [Exemplo 1: Isolamento de Workloads](#exemplo-1-isolamento-de-workloads) + - [Exemplo 2: Utilizando Hardware Especializado](#exemplo-2-utilizando-hardware-especializado) + - [Exemplo 3: Manutenção de Nodes](#exemplo-3-manutenção-de-nodes) + - [Conclusão](#conclusão) + - [Tarefas do Dia](#tarefas-do-dia) +- [Descomplicando o Kubernetes](#descomplicando-o-kubernetes-1) + - [DAY-12+1: Entendendo e Dominando os Selectors](#day-121-entendendo-e-dominando-os-selectors) + - [Conteúdo do Day-12+1](#conteúdo-do-day-121) + - [Introdução](#introdução-1) + - [O que são Selectors?](#o-que-são-selectors) + - [Tipos de Selectors](#tipos-de-selectors) + - [Equality-based Selectors](#equality-based-selectors) + - [Set-based Selectors](#set-based-selectors) + - [Selectors em Ação](#selectors-em-ação) + - [Em Services](#em-services) + - [Em ReplicaSets](#em-replicasets) + - [Em Jobs e CronJobs](#em-jobs-e-cronjobs) + - [Selectors e Namespaces](#selectors-e-namespaces) + - [Cenários de Uso](#cenários-de-uso-1) + - [Roteamento de Tráfego](#roteamento-de-tráfego) + - [Scaling Horizontal](#scaling-horizontal) + - [Desastre e Recuperação](#desastre-e-recuperação) + - [Dicas e Armadilhas](#dicas-e-armadilhas) + - [Exemplos Práticos](#exemplos-práticos-1) + - [Exemplo 1: Selector em um Service](#exemplo-1-selector-em-um-service) + - [Exemplo 2: Selector em um ReplicaSet](#exemplo-2-selector-em-um-replicaset) + - [Exemplo 3: Selectors Avançados](#exemplo-3-selectors-avançados) + - [Conclusão](#conclusão-1) + + +### Introdução + +Olá, galera! No capítulo de hoje, vamos mergulhar fundo em um dos conceitos mais poderosos e flexíveis do Kubernetes: Taints e Tolerations. Prepare-se, pois este capítulo vai além do básico e entra em detalhes que você não vai querer perder. #VAIIII + +### O que são Taints e Tolerations? + +Taints são "manchas" ou "marcações" aplicadas aos Nodes que os marcam para evitar que certos Pods sejam agendados neles. Por outro lado, Tolerations são configurações que podem ser aplicadas aos Pods para permitir que eles sejam agendados em Nodes com Taints específicos. + +### Por que usar Taints e Tolerations? + +Em um cluster Kubernetes diversificado, nem todos os Nodes são iguais. Alguns podem ter acesso a recursos especiais como GPUs, enquanto outros podem ser reservados para workloads críticos. Taints e Tolerations fornecem um mecanismo para garantir que os Pods sejam agendados nos Nodes apropriados. + +### Anatomia de um Taint + +Um Taint é composto por uma `chave`, um `valor` e um `efeito`. O efeito pode ser: + +- `NoSchedule`: O Kubernetes não agenda o Pod a menos que ele tenha uma Toleration correspondente. +- `PreferNoSchedule`: O Kubernetes tenta não agendar, mas não é uma garantia. +- `NoExecute`: Os Pods existentes são removidos se não tiverem uma Toleration correspondente. + +### Anatomia de uma Toleration + +Uma Toleration é definida pelos mesmos elementos de um Taint: `chave`, `valor` e `efeito`. Além disso, ela contém um `operador`, que pode ser `Equal` ou `Exists`. + +### Aplicando Taints + +Para aplicar um Taint a um Node, você utiliza o comando `kubectl taint`. Por exemplo: + +```bash +kubectl taint nodes node1 key=value:NoSchedule +``` + +### Configurando Tolerations + +Tolerations são configuradas no PodSpec. Aqui está um exemplo: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: my-pod +spec: + tolerations: + - key: "key" + operator: "Equal" + value: "value" + effect: "NoSchedule" +``` + +### Cenários de Uso + +#### Isolamento de Workloads + +Imagine um cenário onde você tem Nodes que devem ser dedicados a workloads de produção e não devem executar Pods de desenvolvimento. + +Aplicar Taint: + +```bash +kubectl taint nodes prod-node environment=production:NoSchedule +``` + +Toleration em Pod de produção: + +```yaml +tolerations: +- key: "environment" + operator: "Equal" + value: "production" + effect: "NoSchedule" +``` + +#### Nodes Especializados + +Se você tem Nodes com GPUs e quer garantir que apenas Pods que necessitem de GPUs sejam agendados ali. + +Aplicar Taint: + +```bash +kubectl taint nodes gpu-node gpu=true:NoSchedule +``` + +Toleration em Pod que necessita de GPU: + +```yaml +tolerations: +- key: "gpu" + operator: "Equal" + value: "true" + effect: "NoSchedule" +``` + +#### Evacuação e Manutenção de Nodes + +Se você precisa realizar manutenção em um Node e quer evitar que novos Pods sejam agendados nele. + +Aplicar Taint: + +```bash +kubectl taint nodes node1 maintenance=true:NoExecute +``` + +### Combinando Taints e Tolerations com Affinity Rules + +Você pode combinar Taints e Tolerations com regras de afinidade para um controle ainda mais granular. + +### Exemplos Práticos + +#### Exemplo 1: Isolamento de Workloads + +Vamos criar um Node com um Taint e tentar agendar um Pod sem a Toleration correspondente. + +```bash +# Aplicar Taint +kubectl taint nodes dev-node environment=development:NoSchedule + +# Tentar agendar Pod +kubectl run nginx --image=nginx +``` + +Observe que o Pod não será agendado até que uma Toleration seja adicionada. + +#### Exemplo 2: Utilizando Hardware Especializado + +Vamos criar um Node com uma GPU e aplicar um Taint correspondente. + +```bash +# Aplicar Taint +kubectl taint nodes gpu-node gpu=true:NoSchedule + +# Agendar Pod com Toleration +kubectl apply -f gpu-pod.yaml +``` + +Onde `gpu-pod.yaml` contém a Toleration correspondente. + +#### Exemplo 3: Manutenção de Nodes + +Vamos simular uma manutenção, aplicando um Taint em um + + Node e observando como os Pods são removidos. + +```bash +# Aplicar Taint +kubectl taint nodes node1 maintenance=true:NoExecute +``` + +### Conclusão + +Taints e Tolerations são ferramentas poderosas para o controle refinado do agendamento de Pods. Com elas, você pode isolar workloads, aproveitar hardware especializado e até gerenciar manutenções de forma mais eficaz. + +### Tarefas do Dia + +1. Aplique um Taint em um dos seus Nodes e tente agendar um Pod sem a Toleration correspondente. +2. Remova o Taint e observe o comportamento. +3. Adicione uma Toleration ao Pod e repita o processo. + +# Descomplicando o Kubernetes +## DAY-12+1: Entendendo e Dominando os Selectors + +## Conteúdo do Day-12+1 + + + + + +### Introdução + +E aí, pessoal! No capítulo de hoje, vamos nos aprofundar em um dos recursos mais versáteis e fundamentais do Kubernetes: os Selectors. Preparados? Então #VAIIII! + +### O que são Selectors? + +Selectors são formas de selecionar recursos, como Pods, com base em suas labels. Eles são a cola que une vários componentes do Kubernetes, como Services e ReplicaSets. + +### Tipos de Selectors + +#### Equality-based Selectors + +Estes são os mais simples, usando operadores como `=`, `==`, e `!=`. + +Exemplo: + +```bash +kubectl get pods -l environment=production +``` + +#### Set-based Selectors + +Estes são mais complexos e usam operadores como `in`, `notin`, e `exists`. + +Exemplo: + +```bash +kubectl get pods -l 'environment in (production, qa)' +``` + +### Selectors em Ação + +#### Em Services + +Services usam selectors para direcionar tráfego para Pods específicos. + +Exemplo: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app: MyApp +``` + +#### Em ReplicaSets + +ReplicaSets usam selectors para saber quais Pods gerenciar. + +Exemplo: + +```yaml +apiVersion: apps/v1 +kind: ReplicaSet +metadata: + name: my-replicaset +spec: + selector: + matchLabels: + app: MyApp +``` + +#### Em Jobs e CronJobs + +Jobs e CronJobs também podem usar selectors para executar tarefas em Pods específicos. + +### Selectors e Namespaces + +É crucial entender que os selectors não atravessam namespaces; eles são eficazes apenas dentro do namespace atual, a menos que especificado de outra forma. + +### Cenários de Uso + +#### Roteamento de Tráfego + +Use selectors em Services para direcionar tráfego para versões específicas de uma aplicação. + +#### Scaling Horizontal + +Use selectors em Horizontal Pod Autoscalers para escalar apenas os Pods que atendem a critérios específicos. + +#### Desastre e Recuperação + +Em casos de failover, você pode usar selectors para direcionar tráfego para Pods em um cluster secundário. + +### Dicas e Armadilhas + +- Não mude as labels de Pods que são alvos de Services sem atualizar o selector do Service. +- Use selectors de forma consistente para evitar confusões. + +### Exemplos Práticos + +#### Exemplo 1: Selector em um Service + +Vamos criar um Service que seleciona todos os Pods com a label `frontend`. + +```bash +kubectl apply -f frontend-service.yaml +``` + +#### Exemplo 2: Selector em um ReplicaSet + +Vamos criar um ReplicaSet que gerencia todos os Pods com a label `backend`. + +```bash +kubectl apply -f backend-replicaset.yaml +``` + +#### Exemplo 3: Selectors Avançados + +Vamos fazer uma query complexa para selecionar Pods com base em múltiplas labels. + +```bash +kubectl get pods -l 'release-version in (v1, v2),environment!=debug' +``` + +### Conclusão + +Selectors são uma ferramenta poderosa e flexível no Kubernetes, permitindo um controle fino sobre como os recursos interagem. Dominar este conceito é fundamental para qualquer um que trabalhe com Kubernetes. diff --git a/pt/day-13/README.md b/pt/day-13/README.md new file mode 100644 index 00000000..73b6512a --- /dev/null +++ b/pt/day-13/README.md @@ -0,0 +1,458 @@ +# Descomplicando o Kubernetes +## DAY-13: Descomplicando Kyverno e as Policies no Kubernetes + +## Conteúdo do Day-13 + +- [Descomplicando o Kubernetes](#descomplicando-o-kubernetes) + - [DAY-13: Descomplicando Kyverno e as Policies no Kubernetes](#day-13-descomplicando-kyverno-e-as-policies-no-kubernetes) + - [Conteúdo do Day-13](#conteúdo-do-day-13) + - [O que iremos ver hoje?](#o-que-iremos-ver-hoje) + - [Inicio do Day-13](#inicio-do-day-13) + - [Introdução ao Kyverno](#introdução-ao-kyverno) + - [Instalando o Kyverno](#instalando-o-kyverno) + - [Utilizando Helm](#utilizando-helm) + - [Verificando a Instalação](#verificando-a-instalação) + - [Criando a nossa primeira Policy](#criando-a-nossa-primeira-policy) + - [Mais exemplos de Policies](#mais-exemplos-de-policies) + - [Exemplo de Política: Adicionar Label ao Namespace](#exemplo-de-política-adicionar-label-ao-namespace) + - [Detalhes da Política](#detalhes-da-política) + - [Arquivo de Política: `add-label-namespace.yaml`](#arquivo-de-política-add-label-namespaceyaml) + - [Utilização da Política](#utilização-da-política) + - [Exemplo de Política: Proibir Usuário Root](#exemplo-de-política-proibir-usuário-root) + - [Detalhes da Política](#detalhes-da-política-1) + - [Arquivo de Política: `disallow-root-user.yaml`](#arquivo-de-política-disallow-root-useryaml) + - [Implementação e Efeito](#implementação-e-efeito) + - [Exemplo de Política: Gerar ConfigMap para Namespace](#exemplo-de-política-gerar-configmap-para-namespace) + - [Detalhes da Política](#detalhes-da-política-2) + - [Arquivo de Política: `generate-configmap-for-namespace.yaml`](#arquivo-de-política-generate-configmap-for-namespaceyaml) + - [Implementação e Utilidade](#implementação-e-utilidade) + - [Exemplo de Política: Permitir Apenas Repositórios Confiáveis](#exemplo-de-política-permitir-apenas-repositórios-confiáveis) + - [Detalhes da Política](#detalhes-da-política-3) + - [Arquivo de Política: `registry-allowed.yaml`](#arquivo-de-política-registry-allowedyaml) + - [Implementação e Impacto](#implementação-e-impacto) + - [Exemplo de Política: Require Probes](#exemplo-de-política-require-probes) + - [Detalhes da Política](#detalhes-da-política-4) + - [Arquivo de Política: `require-probes.yaml`](#arquivo-de-política-require-probesyaml) + - [Implementação e Impacto](#implementação-e-impacto-1) + - [Exemplo de Política: Usando o Exclude](#exemplo-de-política-usando-o-exclude) + - [Detalhes da Política](#detalhes-da-política-5) + - [Arquivo de Política](#arquivo-de-política) + - [Implementação e Efeitos](#implementação-e-efeitos) + - [Conclusão](#conclusão) + - [Pontos-Chave Aprendidos](#pontos-chave-aprendidos) + +## O que iremos ver hoje? + +Hoje, exploraremos as funcionalidades e aplicações do Kyverno, uma ferramenta de gerenciamento de políticas essencial para a segurança e eficiência de clusters Kubernetes. Com uma abordagem detalhada e prática, você aprenderá a usar o Kyverno para automatizar tarefas cruciais, garantir a conformidade com normas e regras estabelecidas e melhorar a administração geral de seus ambientes Kubernetes. + +**Principais Tópicos Abordados:** + +1. **Introdução ao Kyverno:** Uma visão geral do Kyverno, destacando sua importância e as principais funções de validação, mutação e geração de recursos. + +2. **Instalação e Configuração:** Passo a passo para a instalação do Kyverno, incluindo métodos usando o Helm e arquivos YAML, e como verificar se a instalação foi bem-sucedida. + +3. **Desenvolvendo Políticas Eficientes:** Aprenda a criar políticas para diferentes cenários, desde garantir limites de CPU e memória em Pods até aplicar automaticamente labels a namespaces e restringir a execução de containers como root. + +4. **Exemplos Práticos:** Vários exemplos de políticas, ilustrando como o Kyverno pode ser aplicado para resolver problemas reais e melhorar a segurança e conformidade dos clusters Kubernetes. + +5. **Dicas de Uso e Melhores Práticas:** Orientações sobre como aproveitar ao máximo o Kyverno, incluindo dicas de segurança, eficiência e automatização de processos. + +Ao final deste e-book, você terá uma compreensão abrangente do Kyverno e estará equipado com o conhecimento e as habilidades para implementá-lo efetivamente em seus próprios clusters Kubernetes. Este e-book é projetado tanto para iniciantes quanto para profissionais experientes, proporcionando informações valiosas e práticas para todos os níveis de expertise. + +--- + +## Inicio do Day-13 + +### Introdução ao Kyverno + +Kyverno é uma ferramenta de gerenciamento de políticas para Kubernetes, focada na automação de várias tarefas relacionadas à segurança e configuração dos clusters de Kubernetes. Ele permite que você defina, gerencie e aplique políticas de forma declarativa para garantir que os clusters e suas cargas de trabalho estejam em conformidade com as regras e normas definidas. + +**Principais Funções do Kyverno:** + +1. **Validação de Recursos:** Verifica se os recursos do Kubernetes estão em conformidade com as políticas definidas. Por exemplo, pode garantir que todos os Pods tenham limites de CPU e memória definidos. + +2. **Mutação de Recursos:** Modifica automaticamente os recursos do Kubernetes para atender às políticas definidas. Por exemplo, pode adicionar automaticamente labels específicos a todos os novos Pods. + +3. **Geração de Recursos:** Cria recursos adicionais do Kubernetes com base nas políticas definidas. Por exemplo, pode gerar NetworkPolicies para cada novo Namespace criado. + +--- + +### Instalando o Kyverno + +A instalação do Kyverno em um cluster Kubernetes pode ser feita de várias maneiras, incluindo a utilização de um gerenciador de pacotes como o Helm, ou diretamente através de arquivos YAML. Aqui estão os passos básicos para instalar o Kyverno: + +#### Utilizando Helm + +O Helm é um gerenciador de pacotes para Kubernetes, que facilita a instalação e gerenciamento de aplicações. Para instalar o Kyverno com Helm, siga estes passos: + +1. **Adicione o Repositório do Kyverno:** + + ```shell + helm repo add kyverno https://kyverno.github.io/kyverno/ + helm repo update + ``` + +2. **Instale o Kyverno:** + + Você pode instalar o Kyverno no namespace `kyverno` usando o seguinte comando: + + ```shell + helm install kyverno kyverno/kyverno --namespace kyverno --create-namespace + ``` + +### Verificando a Instalação + +Após a instalação, é importante verificar se o Kyverno foi instalado corretamente e está funcionando como esperado. + +- **Verifique os Pods:** + + ```shell + kubectl get pods -n kyverno + ``` + + Este comando deve mostrar os pods do Kyverno em execução no namespace especificado. + +- **Verifique os CRDs:** + + ```shell + kubectl get crd | grep kyverno + ``` + + Este comando deve listar os CRDs relacionados ao Kyverno, indicando que foram criados corretamente. + +Lembrando que é sempre importante consultar a documentação oficial para obter as instruções mais atualizadas e detalhadas, especialmente se estiver trabalhando com uma configuração específica ou uma versão mais recente do Kyverno ou do Kubernetes. + +--- + +### Criando a nossa primeira Policy + +Kyverno permite que você defina, gerencie e aplique políticas de forma declarativa para garantir que os clusters e suas cargas de trabalho estejam em conformidade com as regras e normas definidas. + +As políticas, ou as policies em inglês, do Kyverno podem ser aplicadas de duas maneiras principais: a nível de cluster (`ClusterPolicy`) ou a nível de namespace específico (`Policy`). + +1. **ClusterPolicy**: Quando você define uma política como `ClusterPolicy`, ela é aplicada a todos os namespaces no cluster. Ou seja, as regras definidas em uma `ClusterPolicy` são automaticamente aplicadas a todos os recursos correspondentes em todos os namespaces, a menos que especificamente excluídos. + +2. **Policy**: Se você deseja aplicar políticas a um namespace específico, você usaria o tipo `Policy`. As políticas definidas como `Policy` são aplicadas apenas dentro do namespace onde são criadas. + +Se você não especificar nenhum namespace na política ou usar `ClusterPolicy`, o Kyverno assumirá que a política deve ser aplicada globalmente, ou seja, em todos os namespaces. + +--- + +**Exemplo de Políticas do Kyverno:** + +1. **Política de Limites de Recursos:** Garantir que todos os containers em um Pod tenham limites de CPU e memória definidos. Isso pode ser importante para evitar o uso excessivo de recursos em um cluster compartilhado. + +**Arquivo `require-resources-limits.yaml`:** + ```yaml + apiVersion: kyverno.io/v1 + kind: ClusterPolicy + metadata: + name: require-cpu-memory-limits + spec: + validationFailureAction: enforce + rules: + - name: validate-limits + match: + resources: + kinds: + - Pod + validate: + message: "CPU and memory limits are required" + pattern: + spec: + containers: + - name: "*" + resources: + limits: + memory: "?*" + cpu: "?*" + ``` + + +Depois do arquivo criado, agora bastar realizar o deploy em nosso cluster Kubernetes. + +```bash +kubectl apply -f require-resources-limits.yaml +``` + +Agora, tenta realizar o deploy de um simples Nginx sem definir o limite para os recursos. + +**Arquivo `pod.yaml`:** +```bash +apiVersion: v1 +kind: Pod +metadata: + name: exemplo-pod +spec: + containers: + - name: exemplo-container + image: nginx +``` + +```bash +kubectl apply -f pod.yaml +``` +--- + +### Mais exemplos de Policies +Continuando com a explicação e exemplos de políticas do Kyverno para gerenciamento de clusters Kubernetes: + +Entendi, vou formatar o texto para que esteja pronto para ser copiado para o Google Docs: + +--- + +#### Exemplo de Política: Adicionar Label ao Namespace + +A política `add-label-namespace` é projetada para automatizar a adição de um label específico a todos os Namespaces em um cluster Kubernetes. Esta abordagem é essencial para a organização, monitoramento e controle de acesso em ambientes complexos. + +##### Detalhes da Política + +O label adicionado por esta política é `Jeferson: "Lindo_Demais"`. A aplicação deste label a todos os Namespaces facilita a identificação e a categorização dos mesmos, permitindo uma gestão mais eficiente e uma padronização no uso de labels. + +##### Arquivo de Política: `add-label-namespace.yaml` + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: add-label-namespace +spec: + rules: + - name: add-label-ns + match: + resources: + kinds: + - Namespace + mutate: + patchStrategicMerge: + metadata: + labels: + Jeferson: "Lindo_Demais" +``` + +##### Utilização da Política + +Esta política garante que cada Namespace no cluster seja automaticamente etiquetado com `Jeferson: "Lindo_Demais"`. Isso é particularmente útil para garantir a conformidade e a uniformidade na atribuição de labels, facilitando operações como filtragem e busca de Namespaces com base em critérios específicos. + +--- + +#### Exemplo de Política: Proibir Usuário Root + +A política `disallow-root-user` é uma regra de segurança crítica no gerenciamento de clusters Kubernetes. Ela proíbe a execução de containers como usuário root dentro de Pods. Este controle ajuda a prevenir possíveis vulnerabilidades de segurança e a reforçar as melhores práticas no ambiente de contêineres. + +##### Detalhes da Política + +O principal objetivo desta política é garantir que nenhum Pod no cluster execute containers como o usuário root. A execução de containers como root pode expor o sistema a riscos de segurança, incluindo acessos não autorizados e potenciais danos ao sistema host. + +##### Arquivo de Política: `disallow-root-user.yaml` + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: disallow-root-user +spec: + validationFailureAction: Enforce + rules: + - name: check-runAsNonRoot + match: + resources: + kinds: + - Pod + validate: + message: "Running as root is not allowed. Set runAsNonRoot to true." + pattern: + spec: + containers: + - securityContext: + runAsNonRoot: true +``` + +##### Implementação e Efeito + +Ao aplicar esta política, todos os Pods que tentarem executar containers como usuário root serão impedidos, com a exibição de uma mensagem de erro indicando que a execução como root não é permitida. Isso assegura uma camada adicional de segurança no ambiente Kubernetes, evitando práticas que possam comprometer a integridade e a segurança do cluster. + +--- + +#### Exemplo de Política: Gerar ConfigMap para Namespace + +A política `generate-configmap-for-namespace` é uma estratégia prática no gerenciamento de Kubernetes para automatizar a criação de ConfigMaps em Namespaces. Esta política simplifica a configuração e a gestão de múltiplos ambientes dentro de um cluster. + +##### Detalhes da Política + +Esta política é projetada para criar automaticamente um ConfigMap em cada Namespace recém-criado. O ConfigMap gerado, denominado `default-configmap`, inclui um conjunto padrão de chaves e valores, facilitando a configuração inicial e a padronização dos Namespaces. + +##### Arquivo de Política: `generate-configmap-for-namespace.yaml` + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: generate-configmap-for-namespace +spec: + rules: + - name: generate-namespace-configmap + match: + resources: + kinds: + - Namespace + generate: + kind: ConfigMap + name: default-configmap + namespace: "{{request.object.metadata.name}}" + data: + data: + key1: "value1" + key2: "value2" +``` + +##### Implementação e Utilidade + +A aplicação desta política resulta na criação automática de um ConfigMap padrão em cada Namespace novo, proporcionando uma forma rápida e eficiente de distribuir configurações comuns e informações essenciais. Isso é particularmente útil em cenários onde a consistência e a automatização de configurações são cruciais. + +--- + +#### Exemplo de Política: Permitir Apenas Repositórios Confiáveis + +A política `ensure-images-from-trusted-repo` é essencial para a segurança dos clusters Kubernetes, garantindo que todos os Pods utilizem imagens provenientes apenas de repositórios confiáveis. Esta política ajuda a prevenir a execução de imagens não verificadas ou potencialmente mal-intencionadas. + +##### Detalhes da Política + +Esta política impõe que todas as imagens de containers usadas nos Pods devem ser originárias de repositórios especificados e confiáveis. A estratégia é crucial para manter a integridade e a segurança do ambiente de containers, evitando riscos associados a imagens desconhecidas ou não autorizadas. + +##### Arquivo de Política: `registry-allowed.yaml` + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: ensure-images-from-trusted-repo +spec: + validationFailureAction: enforce + rules: + - name: trusted-repo-check + match: + resources: + kinds: + - Pod + validate: + message: "Only images from trusted repositories are allowed" + pattern: + spec: + containers: + - name: "*" + image: "trustedrepo.com/*" +``` + +##### Implementação e Impacto + +Com a implementação desta política, qualquer tentativa de implantar um Pod com uma imagem de um repositório não confiável será bloqueada. A política assegura que apenas imagens de fontes aprovadas sejam usadas, fortalecendo a segurança do cluster contra vulnerabilidades e ataques externos. + +--- + +##### Exemplo de Política: Require Probes + +A política `require-readinessprobe` desempenha um papel crucial no gerenciamento de tráfego e na garantia da disponibilidade de serviços em um cluster Kubernetes. Ela exige que todos os Pods tenham uma sonda de prontidão (readiness probe) configurada, assegurando que o tráfego seja direcionado para os Pods apenas quando estiverem prontos para processar solicitações. + +##### Detalhes da Política + +Esta política visa melhorar a confiabilidade e eficiência dos serviços executados no cluster, garantindo que os Pods estejam prontos para receber tráfego antes de serem expostos a solicitações externas. A sonda de prontidão verifica se o Pod está pronto para atender às solicitações, ajudando a evitar interrupções e problemas de desempenho. + +##### Arquivo de Política: `require-probes.yaml` + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: require-readinessprobe +spec: + validationFailureAction: Enforce + rules: + - name: require-readinessProbe + match: + resources: + kinds: + - Pod + validate: + message: "Readiness probe is required." + pattern: + spec: + containers: + - readinessProbe: + httpGet: + path: "/" + port: 8080 +``` + +##### Implementação e Impacto + +Com a aplicação desta política, todos os novos Pods ou Pods atualizados devem incluir uma configuração de sonda de prontidão, que normalmente envolve a especificação de um caminho e porta para checagem HTTP. Isso assegura que o serviço só receba tráfego quando estiver totalmente operacional, melhorando a confiabilidade e a experiência do usuário. + +--- + +#### Exemplo de Política: Usando o Exclude + +A política `require-resources-limits` é uma abordagem proativa para gerenciar a utilização de recursos em um cluster Kubernetes. Ela garante que todos os Pods tenham limites de recursos definidos, como CPU e memória, mas com uma exceção específica para um namespace. + +##### Detalhes da Política + +Essa política impõe que cada Pod no cluster tenha limites explícitos de CPU e memória configurados. Isso é crucial para evitar o consumo excessivo de recursos, que pode afetar outros Pods e a estabilidade geral do cluster. No entanto, esta política exclui especificamente o namespace `giropops` desta regra. + +##### Arquivo de Política + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: require-resources-limits +spec: + validationFailureAction: Enforce + rules: + - name: validate-limits + match: + resources: + kinds: + - Pod + exclude: + resources: + namespaces: + - giropops + validate: + message: "Precisa definir o limites de recursos" + pattern: + spec: + containers: + - name: "*" + resources: + limits: + cpu: "?*" + memory: "?*" +``` + +##### Implementação e Efeitos + +Ao aplicar esta política, todos os Pods novos ou atualizados precisam ter limites de recursos claramente definidos, exceto aqueles no namespace `giropops`. Isso assegura uma melhor gestão de recursos e evita situações onde alguns Pods possam monopolizar recursos em detrimento de outros. + +--- + +### Conclusão + +Ao longo deste artigo, exploramos as capacidades e funcionalidades do Kyverno, uma ferramenta inovadora e essencial para o gerenciamento de políticas em clusters Kubernetes. Compreendemos como o Kyverno simplifica e automatiza tarefas críticas relacionadas à segurança, conformidade e configuração, tornando-se um componente indispensável na administração de ambientes Kubernetes. + +#### Pontos-Chave Aprendidos + +1. **Automação e Conformidade:** Vimos como o Kyverno permite definir, gerenciar e aplicar políticas de forma declarativa, garantindo que os recursos do Kubernetes estejam sempre em conformidade com as regras e normas estabelecidas. Esta abordagem reduz significativamente o esforço manual, minimiza erros e assegura uma maior consistência em todo o ambiente. + +2. **Validação, Mutação e Geração de Recursos:** Aprendemos sobre as três funções principais do Kyverno – validação, mutação e geração de recursos – e como cada uma delas desempenha um papel vital na gestão eficaz do cluster. Estas funções proporcionam um controle granular sobre os recursos, desde a garantia de limites de CPU e memória até a aplicação automática de labels e a criação dinâmica de ConfigMaps. + +3. **Flexibilidade de Políticas:** Discutimos a diferença entre `ClusterPolicy` e `Policy`, destacando como o Kyverno oferece flexibilidade para aplicar políticas em todo o cluster ou em namespaces específicos. Isso permite uma gestão personalizada e adaptada às necessidades de diferentes partes do cluster. + +4. **Instalação e Verificação:** Abordamos as várias maneiras de instalar o Kyverno, com foco especial no uso do Helm, um gerenciador de pacotes popular para Kubernetes. Também exploramos como verificar a instalação correta do Kyverno, assegurando que tudo esteja funcionando conforme esperado. + +5. **Práticas de Segurança:** O artigo enfatizou a importância da segurança em Kubernetes, demonstrada por políticas como a proibição de execução de containers como usuário root e a exigência de imagens provenientes de repositórios confiáveis. Essas políticas ajudam a prevenir vulnerabilidades e garantir a integridade do cluster. + +6. **Automatização e Eficiência:** Por fim, aprendemos como o Kyverno facilita a automatização e a eficiência operacional. As políticas do Kyverno reduzem a necessidade de intervenção manual, aumentam a segurança e ajudam na conformidade regulatória, tornando a administração do Kubernetes mais simples e confiável. + +Em resumo, o Kyverno é uma ferramenta poderosa que transforma a maneira como as políticas são gerenciadas em Kubernetes. Seu enfoque na automação, flexibilidade e segurança o torna um componente essencial para qualquer administrador de Kubernetes que deseja otimizar a gestão de clusters, assegurar a conformidade e reforçar a segurança. Com o Kyverno, podemos atingir um nível mais alto de eficiência e confiança nos nossos ambientes Kubernetes, preparando-nos para enfrentar os desafios de um ecossistema em constante evolução. + +--- \ No newline at end of file diff --git a/pt/day_two/README.md b/pt/day-2/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_two/README.md rename to pt/day-2/README.md diff --git a/pt/day_three/README.md b/pt/day-3/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_three/README.md rename to pt/day-3/README.md diff --git a/pt/day_four/README.md b/pt/day-4/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/README.md rename to pt/day-4/README.md diff --git a/pt/day_four/files/nginx-deployment.yaml b/pt/day-4/files/nginx-deployment.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/nginx-deployment.yaml rename to pt/day-4/files/nginx-deployment.yaml diff --git a/pt/day_four/files/nginx-liveness.yaml b/pt/day-4/files/nginx-liveness.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/nginx-liveness.yaml rename to pt/day-4/files/nginx-liveness.yaml diff --git a/pt/day_four/files/nginx-readiness.yaml b/pt/day-4/files/nginx-readiness.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/nginx-readiness.yaml rename to pt/day-4/files/nginx-readiness.yaml diff --git a/pt/day_four/files/nginx-replicaset.yaml b/pt/day-4/files/nginx-replicaset.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/nginx-replicaset.yaml rename to pt/day-4/files/nginx-replicaset.yaml diff --git a/pt/day_four/files/nginx-startup.yaml b/pt/day-4/files/nginx-startup.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/nginx-startup.yaml rename to pt/day-4/files/nginx-startup.yaml diff --git a/pt/day_four/files/nginx-todas-probes.yaml b/pt/day-4/files/nginx-todas-probes.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/nginx-todas-probes.yaml rename to pt/day-4/files/nginx-todas-probes.yaml diff --git a/pt/day_four/files/node-exporter-daemonset.yaml b/pt/day-4/files/node-exporter-daemonset.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/files/node-exporter-daemonset.yaml rename to pt/day-4/files/node-exporter-daemonset.yaml diff --git a/pt/day_four/nginx-daemonset.yaml b/pt/day-4/nginx-daemonset.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/nginx-daemonset.yaml rename to pt/day-4/nginx-daemonset.yaml diff --git a/pt/day_four/nginx-deployment.yaml b/pt/day-4/nginx-deployment.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/nginx-deployment.yaml rename to pt/day-4/nginx-deployment.yaml diff --git a/pt/day_four/nginx-replicaset.yaml b/pt/day-4/nginx-replicaset.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_four/nginx-replicaset.yaml rename to pt/day-4/nginx-replicaset.yaml diff --git a/pt/day_five/README.md b/pt/day-5/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_five/README.md rename to pt/day-5/README.md diff --git a/pt/day_six/README.md b/pt/day-6/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/README.md rename to pt/day-6/README.md diff --git a/pt/day_six/files/giropops-senhas-deployment.yaml b/pt/day-6/files/giropops-senhas-deployment.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/giropops-senhas-deployment.yaml rename to pt/day-6/files/giropops-senhas-deployment.yaml diff --git a/pt/day_six/files/giropops-senhas-service.yaml b/pt/day-6/files/giropops-senhas-service.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/giropops-senhas-service.yaml rename to pt/day-6/files/giropops-senhas-service.yaml diff --git a/pt/day_six/files/pod.yaml b/pt/day-6/files/pod.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/pod.yaml rename to pt/day-6/files/pod.yaml diff --git a/pt/day_six/files/pv-nfs.yaml b/pt/day-6/files/pv-nfs.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/pv-nfs.yaml rename to pt/day-6/files/pv-nfs.yaml diff --git a/pt/day_six/files/pv.yaml b/pt/day-6/files/pv.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/pv.yaml rename to pt/day-6/files/pv.yaml diff --git a/pt/day_six/files/pvc.yaml b/pt/day-6/files/pvc.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/pvc.yaml rename to pt/day-6/files/pvc.yaml diff --git a/pt/day_six/files/storageclass-nfs.yaml b/pt/day-6/files/storageclass-nfs.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/storageclass-nfs.yaml rename to pt/day-6/files/storageclass-nfs.yaml diff --git a/pt/day_six/files/storageclass.yaml b/pt/day-6/files/storageclass.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_six/files/storageclass.yaml rename to pt/day-6/files/storageclass.yaml diff --git a/pt/day_seven/README.md b/pt/day-7/README.md old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/README.md rename to pt/day-7/README.md diff --git a/pt/day_seven/files/headless-service.yaml b/pt/day-7/files/headless-service.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/files/headless-service.yaml rename to pt/day-7/files/headless-service.yaml diff --git a/pt/day_seven/files/nginx-clusterip-svc.yaml b/pt/day-7/files/nginx-clusterip-svc.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/files/nginx-clusterip-svc.yaml rename to pt/day-7/files/nginx-clusterip-svc.yaml diff --git a/pt/day_seven/files/nginx-deployment.yaml b/pt/day-7/files/nginx-deployment.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/files/nginx-deployment.yaml rename to pt/day-7/files/nginx-deployment.yaml diff --git a/pt/day_seven/files/nginx-loadbalancer-svc.yaml b/pt/day-7/files/nginx-loadbalancer-svc.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/files/nginx-loadbalancer-svc.yaml rename to pt/day-7/files/nginx-loadbalancer-svc.yaml diff --git a/pt/day_seven/files/nginx-nodeport-svc.yaml b/pt/day-7/files/nginx-nodeport-svc.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/files/nginx-nodeport-svc.yaml rename to pt/day-7/files/nginx-nodeport-svc.yaml diff --git a/pt/day_seven/files/nginx-statefulset.yaml b/pt/day-7/files/nginx-statefulset.yaml old mode 100644 new mode 100755 similarity index 100% rename from pt/day_seven/files/nginx-statefulset.yaml rename to pt/day-7/files/nginx-statefulset.yaml diff --git a/pt/day_eight/README.md b/pt/day-8/README.md old mode 100644 new mode 100755 similarity index 99% rename from pt/day_eight/README.md rename to pt/day-8/README.md index 6ccf6085..bd8c345d --- a/pt/day_eight/README.md +++ b/pt/day-8/README.md @@ -1065,7 +1065,7 @@ Antes de instalar o ESO, precisamos adicionar o repositório External Secrets ao ```bash helm repo add external-secrets https://charts.external-secrets.io -helm repo update +helm repo update ``` ##### Instalando o External Secrets Operator diff --git a/pt/day-9/README.md b/pt/day-9/README.md new file mode 100755 index 00000000..a7e11792 --- /dev/null +++ b/pt/day-9/README.md @@ -0,0 +1,360 @@ +# Descomplicando o Kubernetes +## DAY-9: Descomplicando o Ingress no Kubernetes + +## Conteúdo do Day-9 +  + +## O que iremos ver hoje? + +Se você está aqui, provavelmente já tem alguma noção do que o Kubernetes faz. Mas como expor seus serviços ao mundo externo de forma eficiente e segura? É aí que entra o nosso protagonista do dia: o Ingress. Nesta seção, vamos desvendar o que é o Ingress, para que serve e como ele se diferencia de outras formas de expor aplicações no Kubernetes. + + +  +### Conteúdo do Day-9 + +- [Descomplicando o Kubernetes](#descomplicando-o-kubernetes) + - [DAY-9: Descomplicando o Ingress no Kubernetes](#day-9-descomplicando-o-ingress-no-kubernetes) + - [Conteúdo do Day-9](#conteúdo-do-day-9) + - [O que iremos ver hoje?](#o-que-iremos-ver-hoje) + - [Conteúdo do Day-9](#conteúdo-do-day-9-1) +- [O Que é o Ingress?](#o-que-é-o-ingress) + - [O que é Ingress?](#o-que-é-ingress) +- [Componentes do Ingress](#componentes-do-ingress) + - [Componentes Chave](#componentes-chave) + - [Ingress Controller](#ingress-controller) + - [Ingress Resources](#ingress-resources) + - [Annotations e Customizations](#annotations-e-customizations) + - [Instalando um Nginx Ingress Controller](#instalando-um-nginx-ingress-controller) + - [Instalando o Nginx Ingress Controller no Kind](#instalando-o-nginx-ingress-controller-no-kind) + - [Criando o Cluster com Configurações Especiais](#criando-o-cluster-com-configurações-especiais) + - [Instalando um Ingress Controller](#instalando-um-ingress-controller) + - [Instalando o Giropops-Senhas no Cluster](#instalando-o-giropops-senhas-no-cluster) + - [Criando um Recurso de Ingress](#criando-um-recurso-de-ingress) +- [TBD](#tbd) + +  + + +# O Que é o Ingress? + +## O que é Ingress? + +O Ingress é um recurso do Kubernetes que gerencia o acesso externo aos serviços dentro de um cluster. Ele funciona como uma camada de roteamento HTTP/HTTPS, permitindo a definição de regras para direcionar o tráfego externo para diferentes serviços back-end. O Ingress é implementado através de um controlador de Ingress, que pode ser alimentado por várias soluções, como NGINX, Traefik ou Istio, para citar alguns. + +Tecnicamente, o Ingress atua como uma abstração de regras de roteamento de alto nível que são interpretadas e aplicadas pelo controlador de Ingress. Ele permite recursos avançados como balanceamento de carga, SSL/TLS, redirecionamento, reescrita de URL, entre outros. + +Principais Componentes e Funcionalidades: +Controlador de Ingress: É a implementação real que satisfaz um recurso Ingress. Ele pode ser implementado através de várias soluções de proxy reverso, como NGINX ou HAProxy. + +**Regras de Roteamento:** Definidas em um objeto YAML, essas regras determinam como as requisições externas devem ser encaminhadas aos serviços internos. + +**Backend Padrão:** Um serviço de fallback para onde as requisições são encaminhadas se nenhuma regra de roteamento for correspondida. + +**Balanceamento de Carga:** Distribuição automática de tráfego entre múltiplos pods de um serviço. + +**Terminação SSL/TLS:** O Ingress permite a configuração de certificados SSL/TLS para a terminação de criptografia no ponto de entrada do cluster. + +**Anexos de Recurso:** Possibilidade de anexar recursos adicionais como ConfigMaps ou Secrets, que podem ser utilizados para configurar comportamentos adicionais como autenticação básica, listas de controle de acesso etc. + + +# Componentes do Ingress + +Agora que já sabemos o que é o Ingress e o porquê de usá-lo, é hora de mergulharmos nos componentes que o compõem. Como um bom "porteiro" do nosso cluster Kubernetes, o Ingress não trabalha sozinho; ele é composto por várias "peças" que orquestram o tráfego. Vamos explorá-las! + +## Componentes Chave + +### Ingress Controller + +O Ingress Controller é o motor por trás do objeto Ingress. Ele é responsável por aplicar as regras de roteamento definidas no recurso de Ingress. Exemplos populares incluem Nginx Ingress Controller, Traefik e HAProxy Ingress. + +### Ingress Resources + +Os Ingress Resources são as configurações que você define para instruir o Ingress Controller sobre como o tráfego deve ser roteado. Estas são definidas em arquivos YAML e aplicadas no cluster. + +### Annotations e Customizations + +Annotations permitem personalizar o comportamento padrão do seu Ingress. Você pode, por exemplo, forçar o redirecionamento de HTTP para HTTPS, ou ainda adicionar políticas de segurança, como proteção contra ataques DDoS. + +### Instalando um Nginx Ingress Controller + +Vamos instalar o Nginx Ingress Controller. É importante observar a versão do Ingress Controller que você está instalando, pois as versões mais recentes ou mais antigas podem não ser compatíveis com o Kubernetes que você está usando. Para este tutorial, vamos usar a versão 1.8.2. +No seu terminal, execute os seguintes comandos: + +```bash +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml +``` + +Verifique se o Ingress Controller foi instalado corretamente: + +```bash +kubectl get pods -n ingress-nginx +``` + +Você pode utilizar a opção `wait` do `kubectl`, assim quando os pods estiverem prontos, ele irá liberar o shell, veja: + +```bash +kubectl wait --namespace ingress-nginx \ + --for=condition=ready pod \ + --selector=app.kubernetes.io/component=controller \ + --timeout=90s +``` + +No comando acima, estamos esperando que os pods do Ingress Controller estejam prontos, com o label `app.kubernetes.io/component=controller`, no namespace `ingress-nginx`, e caso não estejam prontos em 90 segundos, o comando irá falhar. + +#### Instalando o Nginx Ingress Controller no Kind + +KinD é uma ferramenta muito útil para testes e desenvolvimento com Kubernetes. Nesta seção atualizada, fornecemos detalhes específicos para garantir que o Ingress funcione como esperado em um cluster KinD. + +###### Criando o Cluster com Configurações Especiais + +Ao criar um cluster KinD, podemos especificar várias configurações que incluem mapeamentos de portas e rótulos para nós. + +1. Crie um arquivo chamado `kind-config.yaml` com o conteúdo abaixo: + +```yaml +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + node-labels: "ingress-ready=true" + extraPortMappings: + - containerPort: 80 + hostPort: 80 + protocol: TCP + - containerPort: 443 +``` + +2. Em seguida, crie o cluster usando este arquivo de configuração: + +```bash +kind create cluster --config kind-config.yaml +``` + +##### Instalando um Ingress Controller + +Vamos continuar usando o Nginx Ingress Controller como exemplo, que é amplamente adotado e bem documentado. + +```bash +kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/kind/deploy.yaml +``` + +Você pode utilizar a opção `wait` do `kubectl`, assim quando os pods estiverem prontos, ele irá liberar o shell, veja: + +```bash +kubectl wait --namespace ingress-nginx \ + --for=condition=ready pod \ + --selector=app.kubernetes.io/component=controller \ + --timeout=90s +``` + +No comando acima, estamos esperando que os pods do Ingress Controller estejam prontos, com o label `app.kubernetes.io/component=controller`, no namespace `ingress-nginx`, e caso não estejam prontos em 90 segundos, o comando irá falhar. + + +### Instalando o Giropops-Senhas no Cluster + +Para a instalação do Giropops-Senhas, vamos utilizar os arquivos abaixo: + +Arquivo: app-deployment.yaml + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: giropops-senhas + name: giropops-senhas +spec: + replicas: 2 + selector: + matchLabels: + app: giropops-senhas + template: + metadata: + labels: + app: giropops-senhas + spec: + containers: + - image: linuxtips/giropops-senhas:1.0 + name: giropops-senhas + env: + - name: REDIS_HOST + value: redis-service + ports: + - containerPort: 5000 + imagePullPolicy: Always +``` + +Arquivo: app-service.yaml + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: giropops-senhas + labels: + app: giropops-senhas +spec: + selector: + app: giropops-senhas + ports: + - protocol: TCP + port: 5000 + targetPort: 5000 + name: tcp-app + type: ClusterIP +``` + +Arquivo: redis-deployment.yaml + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: redis + name: redis-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: redis + template: + metadata: + labels: + app: redis + spec: + containers: + - image: redis + name: redis + ports: + - containerPort: 6379 + resources: + limits: + memory: "256Mi" + cpu: "500m" + requests: + memory: "128Mi" + cpu: "250m" +``` + +Arquivo: redis-service.yaml + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: redis-service +spec: + selector: + app: redis + ports: + - protocol: TCP + port: 6379 + targetPort: 6379 + type: ClusterIP +``` + +Com os arquivos acima, estamos criando um Deployment e um Service para o Giropops-Senhas, e um Deployment e um Service para o Redis. + +Para aplicar, basta executar: + +```bash +kubectl apply -f app-deployment.yaml +kubectl apply -f app-service.yaml +kubectl apply -f redis-deployment.yaml +kubectl apply -f redis-service.yaml +``` + +Para verificar se os pods estão rodando, execute: + +```bash +kubectl get pods +``` + +Para verificar se os serviços estão rodando, execute: + +```bash +kubectl get services +``` + +Você pode acessar a app do Giropops-Senhas através do comando: + +```bash +kubectl port-forward service/giropops-senhas 5000:5000 +``` + +Isso se você estiver usando o Kind, caso contrário, você precisa pegar o endereço IP do seu Ingress, que veremos mais adiante. + +Para testar, você pode acessar o endereço http://localhost:5000 no seu navegador. + +### Criando um Recurso de Ingress + +Agora, vamos criar um recurso de Ingress para nosso serviço `giropops-senhas` criado anteriormente. Crie um arquivo chamado `ingress-1.yaml`: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: giropops-senhas + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + rules: + - http: + paths: + - path: /giropops-senhas + pathType: Prefix + backend: + service: + name: giropops-senhas + port: + number: 5000 + +``` + +Após criar o arquivo, aplique-o: + +```bash +kubectl apply -f ingress-1.yaml +``` + +Agora vamos ver se o nosso Ingress foi criado corretamente: + +```bash +kubectl get ingress +``` + +Para ver com mais detalhes, você pode usar o comando `describe`: + +```bash +kubectl describe ingress giropops-senhas +``` + +Tanto na saída do comando `get` quanto na saída do comando `describe`, você deve ver o endereço IP do seu Ingress no campo `Address`. + +Você pode pegar esse IP através do comando: + +```bash +kubectl get ingress giropops-senhas -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' +``` + +Caso você esteja utilizando um cluster gerenciado por algum provedor de nuvem, como o GKE, você pode utilizar o comando: + +```bash +kubectl get ingress giropops-senhas -o jsonpath='{.status.loadBalancer.ingress[0].ip}' +``` + +Isso porque quando você possui um cluster EKS, AKS, GCP, etc, o Ingress Controller irá criar um LoadBalancer para você, e o endereço IP do LoadBalancer será o endereço IP do seu Ingress, simples assim. + +Para testar, você pode usar o comando curl com o IP, hostname ou load balancer do seu Ingress: + +```bash +curl ENDEREÇO_DO_INGRESS/giropops-senhas +``` + +# TBD \ No newline at end of file diff --git a/pt/day_nine/README.md b/pt/day_nine/README.md deleted file mode 100644 index 0330002c..00000000 --- a/pt/day_nine/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Descomplicando o Kubernetes - -## DAY-9 -  - -### O que iremos ver hoje? - -Durante o dia de hoje, - - - -  -### Conteúdo do Day-9 - -- [Por que ?](#por-que-) - - -  -### Por que ? - -  - -  - -### A sua lição de casa - -A sua lição de casa é - -  -## Desafio do Day-9 - -Não esqueça de - -  - -## Final do Day-9 - -Durante o Day-9 você aprendeu - - -  diff --git a/pt/extras/cloud-providers/azure/aks-helloworld-one.yaml b/pt/extras/cloud-providers/azure/aks-helloworld-one.yaml deleted file mode 100644 index e97953ce..00000000 --- a/pt/extras/cloud-providers/azure/aks-helloworld-one.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: aks-helloworld-one -spec: - replicas: 1 - selector: - matchLabels: - app: aks-helloworld-one - template: - metadata: - labels: - app: aks-helloworld-one - spec: - containers: - - name: aks-helloworld-one - image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 - ports: - - containerPort: 80 - env: - - name: TITLE - value: "Welcome to Azure Kubernetes Service (AKS)" ---- -apiVersion: v1 -kind: Service -metadata: - name: aks-helloworld-one -spec: - type: ClusterIP - ports: - - port: 80 - selector: - app: aks-helloworld-one diff --git a/pt/extras/cloud-providers/azure/aks-helloworld-two.yaml b/pt/extras/cloud-providers/azure/aks-helloworld-two.yaml deleted file mode 100644 index 74cc4bed..00000000 --- a/pt/extras/cloud-providers/azure/aks-helloworld-two.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: aks-helloworld-two -spec: - replicas: 1 - selector: - matchLabels: - app: aks-helloworld-two - template: - metadata: - labels: - app: aks-helloworld-two - spec: - containers: - - name: aks-helloworld-two - image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 - ports: - - containerPort: 80 - env: - - name: TITLE - value: "AKS Ingress Demo" ---- -apiVersion: v1 -kind: Service -metadata: - name: aks-helloworld-two -spec: - type: ClusterIP - ports: - - port: 80 - selector: - app: aks-helloworld-two diff --git a/pt/extras/cloud-providers/azure/hello-world-ingress.yaml b/pt/extras/cloud-providers/azure/hello-world-ingress.yaml deleted file mode 100644 index ead5ad0d..00000000 --- a/pt/extras/cloud-providers/azure/hello-world-ingress.yaml +++ /dev/null @@ -1,53 +0,0 @@ -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - name: hello-world-ingress - annotations: - kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/rewrite-target: /$1 - nginx.ingress.kubernetes.io/use-regex: "true" - cert-manager.io/cluster-issuer: letsencrypt -spec: - tls: - - hosts: - - giropops-live.eastus.cloudapp.azure.com - secretName: tls-secret - rules: - - host: giropops-live.eastus.cloudapp.azure.com - http: - paths: - - backend: - serviceName: aks-helloworld-one - servicePort: 80 - path: /hello-world-one(/|$)(.*) - - backend: - serviceName: aks-helloworld-two - servicePort: 80 - path: /hello-world-two(/|$)(.*) - - backend: - serviceName: aks-helloworld-one - servicePort: 80 - path: /(.*) ---- -apiVersion: networking.k8s.io/v1beta1 -kind: Ingress -metadata: - name: hello-world-ingress-static - annotations: - kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/rewrite-target: /static/$2 - nginx.ingress.kubernetes.io/use-regex: "true" - cert-manager.io/cluster-issuer: letsencrypt -spec: - tls: - - hosts: - - giropops-live.eastus.cloudapp.azure.com - secretName: tls-secret - rules: - - host: giropops-live.eastus.cloudapp.azure.com - http: - paths: - - backend: - serviceName: aks-helloworld-one - servicePort: 80 - path: /static(/|$)(.*) diff --git a/pt/extras/cloud-providers/cloud-providers.md b/pt/extras/cloud-providers/cloud-providers.md deleted file mode 100644 index 1151a626..00000000 --- a/pt/extras/cloud-providers/cloud-providers.md +++ /dev/null @@ -1,180 +0,0 @@ -> Esta documentação foi baseada na live #AULAOKUBERNETES realizado no YouTube no canal da LINUXtips #VAIIII - -Esta documentação tem como objetivo descrever como é feito a criação e a configuração de um cluster com Kubernetes rodando no Azure AKS. - -# Sumário - -- [Sumário](#sumário) -- [Pré-requisitos](#pré-requisitos) -- [Configurando o ambiente](#configurando-o-ambiente) - - [Instalando o Azure CLI](#instalando-o-azure-cli) - - [Configurando o Azure CLI](#configurando-o-azure-cli) - - [Instalando o Helm](#instalando-o-helm) -- [Criação do Cluster](#criação-do-cluster) - - [Criando Resource Group](#criando-resource-group) - - [Criando Cluster AKS](#criando-cluster-aks) -- [Configuração do Cluster](#configuração-do-cluster) - - [Instalando as dependências](#instalando-as-dependências) - - [Gerenciando a conexão com o Cluster](#gerenciando-a-conexão-com-o-cluster) - - [Listando todos os nodes](#listando-todos-os-nodes) -- [Habilitando acesso externo](#habilitando-acesso-externo) - - [Criando o ingress controller](#criando-o-ingress-controller) - - [Criando namespace](#criando-namespace) - - [Instalando o nginx-ingress](#instalando-o-nginx-ingress) - - [Visualizando o nginx externamente](#visualizando-o-nginx-externamente) - - -# Pré-requisitos - -Para configurar um cluster do zero na Azure através do AKS, é necessário ter uma conta na Azure. Caso não tenha, pode estar criando no link abaixo: - -> https://azure.microsoft.com/en-us/free/ - -Você pode estar criando uma conta para testar os serviços de forma gratuita, válida por 12 meses. - -# Configurando o ambiente - -## Instalando o Azure CLI - -Primeiro, instale o azure-cli na sua máquina através do link abaixo: - -> https://docs.microsoft.com/en-us/cli/azure/install-azure-cli - -Você poderá escolher qual sistema operacional deseja instalar o ``azure-cli``. Basta clicar no link do respectivo sistema operacional, que será redirecionado para a página de instalação. Caso você esteja utilizando Linux, basta instalar com o ``curl``. Simples e rápido. - -## Configurando o Azure CLI - -Com o ``azure-cli`` instalado e sua conta já criada, precisamos agora fazer o login do Azure por linha de comando. Abra seu terminal e rode o seguinte comando: - -``` -az login -``` - -Este comando, irá fazer com que você se autentique com sua conta do Azure, podendo assim utilizar os serviços providos por eles. O comando abrirá uma página no navegador para que você realize o login. Então, basta você preencher os campos com seu usuário e senha correspondentes da conta Azure. Ao efetuar o login, será informado uma série de informações sobre a sua conta como o seu ID da conta, o nome da conta (exemplo: "Free-Trial"), o estado (exemplo: "Enable"), informações do nome do usuário, entre outras. - -## Instalando o Helm - -Helm é um gerenciador de pacotes do Kubernetes que vamos utilizar neste tutorial. A instalação do Helm é simples, basta executar o comando curl no seu terminal: - -``` -curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash -``` - -Para mais informações sobre o Helm acesse o conteúdo da Seção [Helm](day_four/descomplicando_kubernetes.md#helm) ou acesse a [página oficial](https://helm.sh/). - -# Criação do Cluster - -> Referência: https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough - -## Criando Resource Group - -Inicie a criação do cluster criando um grupo de recursos informando o nome e a localização. No exemplo abaixo foi criado um resource group com o nome LIVE indicando a localização nos Estados Unidos. - -``` -az group create --name LIVE --location eastus -``` - -Comando executado deverá retornar um json que traz uma série de informações sobre o resource group criado, como o id, location, name, entre outros. - -## Criando Cluster AKS - -Para criar o cluster utilizando o AKS da Azure, basta rodar o comando abaixo: - -``` -az aks create --resource-group LIVE \ - --name LIVE-AKS \ - --node-count 2 \ - --enable-addons monitoring \ - --generate-ssh-keys -``` - -O comando ``az aks create`` precisa ser informado uma série de parâmetros. No ``resource-group`` é informado o nome do grupo já existente no cluster. O ``name`` é o nome do cluster que será criado. Para o parâmetro ``node-count`` é necessário passar a quantidade de nós que serão criados para o cluster, neste exemplo foi utilizado apenas dois. No parâmetro ``enable-addons`` é interessante ressaltar que ao ativá-lo, será possível visualizar e monitorar o cluster na plataforma Azure. Por fim, é informado o ``generate-ssh-keys`` para termos acesso. - -Vai levar um tempinho até finalizar, então basta aguardar até finalizar a instalação. Quando finalizado, irá retornar um JSON contendo diversas informações do cluster. - -> **ATENÇÃO!!!**: Quando foi realizada esta etapa acompanhando a live, ocorreu um erro bem específico quando foi tentado criar com três nodes. O comando retornou uma mensagem "BadRequestError" na qual dizia que existe uma "cota", um limite de núcleos por região. Então acabei preferindo diminuir a quantidade de nodes. Porém depois descobri que poderia só ter trocado de região. - -# Configuração do Cluster - -> Referência: https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough#connect-to-the-cluster - -## Instalando as dependências - -Agora que você tem o seu cluster criado e rodando bonitinho, já podemos iniciar a configuração. O primeiro passo é instalar o ``kubectl`` para gerenciar o cluster com Kubernetes. Para instalar basta rodar o comando abaixo: - -``` -sudo az aks install-cli -``` - -## Gerenciando a conexão com o Cluster - -Como o cluster está rodando na nuvem, precisamos buscar as credenciais deste cluster para gerenciar de forma remota. Para isso, basta rodar o comando ``az aks get-credentials``, informando o nome do resource group através do parâmetro ``--resource-group`` e o nome do seu cluster através do parâmetro ``--name``. Exemplo do comando: - -``` -az aks get-credentials --resource-group LIVE --name LIVE-AKS -``` - -Este comando irá adicionar as credenciais do cluster criado no seu arquivo de configuração na sua máquina. - -## Listando todos os nodes - -Para verificar se toda a configuração foi realizada com sucesso, podemos listar os nodes criados no nosso cluster. Para isso, basta acessar seu terminal e executar o comando abaixo: - -``` -kubectl get nodes -``` - -Este comando irá retornar as informações dos nodes criados no cluster, contendo o nome de cada node, o status, o tempo em que o node está de pé, entre outros dados interessantes. - -# Habilitando acesso externo - -> Referência: https://docs.microsoft.com/en-us/azure/aks/ingress-tls - -## Criando o ingress controller - -O **ingress controller** é uma forma para que você possa disponibilizar os serviços externamente, podendo criar rules e paths para que o usuário acesse o cluster externamente. - -### Criando namespace - -Primeiro passo para criar nosso ingress é criar um namespace. Para isso, basta executar o comando abaixo no seu terminal: - -``` -kubectl create namespace ingress-basic -``` - -### Instalando o nginx-ingress - -Com o comando abaixo será possível adicionar o repositório do ingress-nginx no helm para que depois possamos instalar o ingress controller do nginx. - -``` -helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx -``` - -Após executar o comando você receberá uma mensagem informando que o repositório foi adicionado, mas caso você já tenha este repositório no seu ambiente, receberá outra mensagem informando que já existe esta configuração. - -Agora para instalar o nginx-ingress basta rodar o comando abaixo no seu terminal: - -``` -helm install nginx-ingress ingress-nginx/ingress-nginx \ - --namespace ingress-basic \ - --set controller.replicaCount=2 \ - --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \ - --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \ - --set controller.admissionWebhooks.patch.nodeSelector."beta\.kubernetes\.io/os"=linux -``` - -Neste comando, estamos instalando o repositório nginx-ingress que foi adicionado no helm anteriormente. Para realizar a instalação do mesmo, é necessário informar o namespace do ingress já criado, a quantidade de réplicas de controller e informar qual sistema operacional estará rodando no controller, default backend e no admission Webhooks. - -A saída no terminal da instalação do nginx-ingress no helm irá informar diversas informações sobre a sua instalação. - -### Visualizando o nginx externamente - -Com tudo instalado podemos agora visualizar os detalhes dos nossos pods e services a fim de buscar mais informações, basta apenas informar o nome do namespace que criamos. Para visualizar o nosso nginx de forma externa precisamos buscar o IP deste serviço, para isso, podemos utilizar o kubectl para visualizar os dados dos serviços que estão rodando no namespace que criamos. - -``` -kubectl get svc -n ingress-basic -``` - -O comando ``kubectl get`` nos retorna uma lista dos pods ou serviços que estão rodando no nosso cluster, para visualizar apenas os serviços, nós utilizamos a sigla "svc" ou "service". Agora para especificar de qual namespace os services devem ser retornados, devemos passar o parâmetro ``-n`` contendo logo após o nome do namespace, no exemplo utilizamos o ingress-basic que criamos anteriormente. - -A saida deste comando irá informar o nome dos serviços, o tipo de cada serviço, o IP externo e a porta que o serviço está rodando. Tendo a informação do IP externo do nosso nginx, podemos copiar e colar no navegador para visualizar o serviço rodando. Como não temos nada rodando dentro deste serviço, vamos visualizar apenas uma mensagem "404 Not Found". \ No newline at end of file diff --git a/pt/extras/exame_tips.md b/pt/extras/exame_tips.md deleted file mode 100644 index 8eae7152..00000000 --- a/pt/extras/exame_tips.md +++ /dev/null @@ -1,96 +0,0 @@ -# Dicas CKA/CKAD - - * Estar bem familiarizado com todos objetos dentro do k8s (pod, deploy, replicaSet, jobs, pv, pvc, statefulSet ...) - - * Dominar o kubectl: - * explain - ex: ``kubecetl explain deployment --recursive`` - * create - ex: ``kubectl create deployment nginx --image nginx -o yaml`` - * dry-run - ex: ``kubectl create deployment nginx --image nginx -o yaml --dry-run=client`` - * json-path - ex: ``kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'`` - - * Básico no VIM: - * Copiar - * Editar - * Substituir - * Deletar - - * Dominar um pouco de shell para manipular saídas: - * ">" - * ">>" - * ``awk '{print $}'`` - * ``grep`` - - * Gerência de tempo: - * Não gaste todo seu tempo em uma única questão, se não resolver em 2x tentativas passe para próxima questão e após ver/fazer as outras questões volte nela. - - * Peso das perguntas: - * Ficar atento com o peso das perguntas pois vão ter perguntar fáceis valendo muito e perguntas extremamente complicadas valendo pouco. - - * Conhecer um pouco do ``SystemD`` e ``Journalctl``: - * ``systemctl stop|restart|stop|status`` - * ``journalctl -xe`` - - * Básico de ETCD para backup e restore: - * https://github.com/badtuxx/DescomplicandoKubernetes/tree/main/Extras/Manutencao-Cluster-Etcd - - * Experiência em Linux ajuda também nas de troubleshooting: - * Ver logs - * Procurar arquivos - * tmux/screen - - - * Fazer alias ajuda a ganhar tempo: - * ``alias k=kubectl`` - * ``alias kn=kubectl get no`` - * ``alias kp=kubectl get po`` - -# ETCD - -Para a prova do CKA é bem relevante saber como o ETCD funciona. - -O assunto do ETCD está relacionado aos 11% do Cluster Maintenance. - -Porém, pode ser que você seja obrigado a salvar esse **snapshot** em um diretório específico. Exemplo: ``/tmp/``. - -Com isso, o comando ficaria assim: - -``` -ETCDCTL_API=3 etcdctl \ ---cacert /var/lib/minikube/certs/etcd/ca.crt \ ---key /var/lib/minikube/certs/etcd/server.key \ ---cert /var/lib/minikube/certs/etcd/server.crt \ ---endpoints [127.0.0.1:2379] \ -snapshot save /tmp/snapshot.db -``` - -Para fazer o restore usando o arquivo de backup /tmp/snapshot.db podemos executar os seguintes comandos: - -``` -ETCDCTL_API=3 etcdctl \ ---cacert /var/lib/minikube/certs/etcd/ca.crt \ ---key /var/lib/minikube/certs/etcd/server.key \ ---cert /var/lib/minikube/certs/etcd/server.crt \ ---endpoints 127.0.0.1:2379 \ -snapshot restore /tmp/snapshot.db - -sudo mv /var/lib/etcd/member /var/lib/etcd/member.old -sudo mv /var/lib/etcd/default.etcd/member /var/lib/etcd/ -``` - -# Referências - -A seguir estão alguns links com dicas e questões de estudo para a certificação: - -* https://docs.linuxfoundation.org/tc-docs/certification/faq-cka-ckad -* https://docs.linuxfoundation.org/tc-docs/certification/tips-cka-and-ckad -* https://www.cncf.io/certification/cka/ -* https://www.cncf.io/certification/ckad/ -* https://blog.nativecloud.dev/what-changes-with-certified-kubernetes-administrator-in-september-2020/ -* https://dev.to/aurelievache/tips-about-certified-kubernetes-application-developers-ckad-exam-287g -* https://www.linkedin.com/pulse/kubernetes-certification-cka-ckad-exam-tips-gineesh-madapparambath/?articleId=6662722107232911361 -* https://github.com/dgkanatsios/CKAD-exercises -* https://dev.to/liptanbiswas/ckad-practice-questions-4mpn -* https://github.com/twajr/ckad-prep-notes?utm_sq=gi8psj8vrn -* https://medium.com/faun/be-fast-with-kubectl-1-18-ckad-cka-31be00acc443 -* https://medium.com/faun/how-to-pass-certified-kubernetes-administrator-cka-exam-on-first-attempt-36c0ceb4c9e -* https://medium.com/@yitaek/getting-kubernetes-certified-the-mostly-free-way-41c8b68c8ed4 diff --git a/pt/extras/pod_security_policy.md b/pt/extras/pod_security_policy.md deleted file mode 100644 index d04f28d5..00000000 --- a/pt/extras/pod_security_policy.md +++ /dev/null @@ -1,153 +0,0 @@ -# Pod Security Policy - -**Pod Security Policy** é um recurso *cluster-level* que controla aspectos de segurança na especificação de um POD. A finalidade do PodSecurityPolicy é definir uma série de condições de segurança que devem ser seguidas para que um pod possa ser aceito pelo *admission controller*. - -Com ele é possível controlar os seguintes aspectos: - -* Execução de contêineres privilegiados; -* Uso de *host namespaces*; -* Uso de *host networking* e portas; -* Uso de tipos de volumes; -* Uso de *host filesystem*; -* Permitir *driver FlexVolume*; -* Alocar um FSGroup ao volume mapeado no pod; -* Limitar a "*read only*" o uso de *root file system*; -* Os IDs de usuário e grupo do contêiner; -* Restringir a escalação de privilégios de **root**; -* *Linux capabilities*; -* Utilizar o SELinux nos contêineres; -* Permitir a montagem de Proc para contêiner; -* Perfil do AppArmor utilizado nos contêineres; -* Perfil do seccomp utilizado nos contêineres; -* Perfil do sysctl utilizado nos contêineres. - -# Habilitando o PodSecurityPolicy - -Ele é tratado como um recurso adicional por isso não vem habilitado por padrão, para ativá-lo é necessário realizar uma configuração no ``kube-apiserver`` com o seguinte comando: - -``` -kube-apiserver --enable-admission-plugins=PodSecurityPolicy -``` - -Listando os plugins ativos: - -``` -kube-apiserver -h | grep enable-admission-plugins -``` - -Agora com o PodSecurityPolicy ativo vamos criar nossa primeira regra para vermos como ele funciona na pratica. - -# LAB - -Primeiro vamos criar dois simples pods do ``nginx`` para fazermos os testes, um sendo privilegiado e outro não. - -``` -kubectl run nginx-privi --image=nginx --privileged - -kubectl run nginx --image=nginx -``` - -Ambos criados com sucesso, com o status **Running** e sem apresentar nenhum tipo de erro. Já podemos deletá-los. - -``` -kubectl delete pod nginx nginx-privi -``` - -Vamos criar nossa primeira *policy*. Para fazer isso, utilize o seguinte comando: - -``` -kubectl create -f- < 80/TCP 2m -appsvc2 ClusterIP 10.97.250.131 80/TCP 2m -kubernetes ClusterIP 10.96.0.1 443/TCP 11d -``` - -Vamos listar os Endpoints dos services: - -``` -kubectl get ep - -NAME ENDPOINTS AGE -appsvc1 10.44.0.11:80,10.44.0.12:80 4m -appsvc2 10.32.0.4:80,10.44.0.13:80 4m -kubernetes 10.142.0.5:6443 11d -``` - -Agora vamos acessar os sites e ver se tudo deu certo com as variáveis de ambiente que configuramos nos Deployments. - -``` -curl 10.44.0.11 - -... -

Hello GIROPOPS!

- -

This is being served from a docker
-container running Nginx.

-``` - -``` -curl 10.32.0.4 -h1 id="toc_0">Hello STRIGUS! - -

This is being served from a docker
-container running Nginx.

-``` - -Vamos criar um deployment para o backend: - -``` -vim default-backend.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: default-backend -spec: - replicas: 2 - selector: - matchLabels: - app: default-backend - template: - metadata: - labels: - app: default-backend - spec: - terminationGracePeriodSeconds: 60 - containers: - - name: default-backend - image: gcr.io/google_containers/defaultbackend:1.0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - scheme: HTTP - initialDelaySeconds: 30 - timeoutSeconds: 5 - ports: - - containerPort: 8080 - resources: - limits: - cpu: 10m - memory: 20Mi - requests: - cpu: 10m - memory: 20Mi -``` - -Atenção para os seguintes parâmetros no arquivo anterior: - -* **terminationGracePeriodSeconds** => Tempo em segundos que ele irá aguardar o pod ser finalizado com o sinal SIGTERM, antes de realizar a finalização forçada com o sinal de SIGKILL. -* **livenessProbe** => Verifica se o pod continua em execução, caso não esteja, o ``kubelet`` irá remover o contêiner e iniciará outro em seu lugar. -* **readnessProbe** => Verifica se o container está pronto para receber requisições vindas do service. -* **initialDelaySeconds** => Diz ao ``kubelet`` quantos segundos ele deverá aguardar para realizar a execução da primeira checagem da livenessProbe -* **timeoutSeconds** => Tempo em segundos que será considerado o timeout da execução da probe, o valor padrão é 1. -* **periodSeconds** => Determina de quanto em quanto tempo será realizada a verificação do livenessProbe. - -Crie o namespace ``ingress``: - -``` -kubectl create namespace ingress - -namespace/ingress created -``` - -Crie o deployment do backend no namespace ``ingress``: - -``` -kubectl create -f default-backend.yaml -n ingress - -deployment.apps/default-backend created -``` - -Crie um arquivo para definir um service para o backend: - -``` -vim default-backend-service.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: default-backend -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 8080 - selector: - app: default-backend -``` - -Crie o service para o backend no namespace ``ingress``: - -``` -kubectl create -f default-backend-service.yaml -n ingress - -service/default-backend created -``` - -Visualize novamente os deployments no namespace ``default``: - -``` -kubectl get deployments. - -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -app1 2 2 2 2 29m -app2 2 2 2 2 28m -``` - -Visualize o deployment no namespace ``ingress``: - -``` -kubectl get deployments. -n ingress - -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -default-backend 2 2 2 2 27s -``` - -Visualize novamente os services no namespace ``default``: - -``` -kubectl get service - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -appsvc1 ClusterIP 10.98.174.69 80/TCP 28m -appsvc2 ClusterIP 10.96.193.198 80/TCP 28m -kubernetes ClusterIP 10.96.0.1 443/TCP 11d -``` - -Visualize o service no namespace ``ingress``: - -``` -kubectl get service -n ingress - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -default-backend ClusterIP 10.99.233.157 80/TCP 38s -``` - -Visualize o endpoint no namespace ``ingress``: - -``` -kubectl get ep -n ingress - -NAME ENDPOINTS AGE -default-backend 10.32.0.14:8080,10.40.0.4:8080 2m -``` - -Agora crie o um arquivo para definir um ``configMap`` a ser utilizado pela nossa aplicação: - -``` -vim nginx-ingress-controller-config-map.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: nginx-ingress-controller-conf - labels: - app: nginx-ingress-lb -data: - enable-vts-status: 'true' -``` - -Crie o configMap no namespace ``ingress``: - -``` -kubectl create -f nginx-ingress-controller-config-map.yaml -n ingress - -configmap/nginx-ingress-controller-conf created -``` - -Visualize o configMap no namespace ``ingress``: - -``` -kubectl get configmaps -n ingress - -NAME DATA AGE -nginx-ingress-controller-conf 1 20s -``` - -Visualize os detalhes do configMap recém criado no namespace ``ingress``: - -``` -kubectl describe configmaps nginx-ingress-controller-conf -n ingress - -Name: nginx-ingress-controller-conf -Namespace: ingress -Labels: app=nginx-ingress-lb -Annotations: -Data -==== -enable-vts-status: ----- -true -Events: -``` - -Vamos criar os arquivos para definir as permissões para o nosso deployment: - -``` -vim nginx-ingress-controller-service-account.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: nginx - namespace: ingress -``` - -``` -vim nginx-ingress-controller-clusterrole.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: nginx-role -rules: -- apiGroups: - - "" - - "extensions" - resources: - - configmaps - - secrets - - endpoints - - ingresses - - nodes - - pods - verbs: - - list - - watch -- apiGroups: - - "" - resources: - - services - verbs: - - list - - watch - - get - - update -- apiGroups: - - "extensions" - resources: - - ingresses - verbs: - - get -- apiGroups: - - "" - resources: - - events - verbs: - - create -- apiGroups: - - "extensions" - resources: - - ingresses/status - verbs: - - update -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - create -``` - -``` -vim nginx-ingress-controller-clusterrolebinding.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: nginx-role - namespace: ingress -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: nginx-role -subjects: -- kind: ServiceAccount - name: nginx - namespace: ingress -``` - -Aplique as permissões no namespace ``ingress`` com os seguintes comandos: - -``` -kubectl create -f nginx-ingress-controller-service-account.yaml -n ingress - -serviceaccount/nginx created -``` - -``` -kubectl create -f nginx-ingress-controller-clusterrole.yaml -n ingress - -clusterrole.rbac.authorization.k8s.io/nginx-role created -``` - -``` -kubectl create -f nginx-ingress-controller-clusterrolebinding.yaml -n ingress - -clusterrolebinding.rbac.authorization.k8s.io/nginx-role created -``` - -Visualize os serviceAccount e roles recém criados no namespace ``ingress`` com os seguintes comandos: - -``` -kubectl get serviceaccounts -n ingress -``` - -``` -kubectl get clusterrole -n ingress -``` - -``` -kubectl get clusterrolebindings -n ingress -``` - -Agora crie um arquivo para definir outro deployment: - -``` -vim nginx-ingress-controller-deployment.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-ingress-controller -spec: - replicas: 1 - selector: - matchLabels: - app: nginx-ingress-lb - revisionHistoryLimit: 3 - template: - metadata: - labels: - app: nginx-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - serviceAccount: nginx - containers: - - name: nginx-ingress-controller - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.9.0 - imagePullPolicy: Always - readinessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - livenessProbe: - httpGet: - path: /healthz - port: 10254 - scheme: HTTP - initialDelaySeconds: 10 - timeoutSeconds: 5 - args: - - /nginx-ingress-controller - - --default-backend-service=ingress/default-backend - - --configmap=ingress/nginx-ingress-controller-conf - - --v=2 - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - ports: - - containerPort: 80 - - containerPort: 18080 -``` - -Crie o deployment no namespace ``ingress``: - -``` -kubectl create -f nginx-ingress-controller-deployment.yaml -n ingress - -deployment.apps/nginx-ingress-controller created -``` - -Visualize o deployment recém criado no namespace ``ingress``: - -``` -kubectl get deployments -n ingress - -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -default-backend 2 2 2 2 53m -nginx-ingress-controller 1 1 1 1 23s -``` - -Visualize todos os pods: - -``` -kubectl get pods --all-namespaces - -NAMESPACE NAME READY STATUS RESTARTS AGE -default app1-6b65555ff9-s7dh4 1/1 Running 0 1h -default app1-6b65555ff9-z6wj6 1/1 Running 0 1h -default app2-d956f58df-dp79f 1/1 Running 0 1h -default app2-d956f58df-fsjtf 1/1 Running 0 1h -ingress default-backend-5cb55f8865-2wp5m 1/1 Running 0 54m -ingress default-backend-5cb55f8865-9jgr4 1/1 Running 0 54m -ingress nginx-ingress-controller-65fbdc747b-mlb9k 1/1 Running 0 1m -``` - -Agora crie um arquivo para definir o ingress que redirecionará para o backend: - -``` -vim nginx-ingress.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: nginx-ingress -spec: - rules: - - host: ec2-54-198-119-88.compute-1.amazonaws.com # Mude para o seu endereço dns - http: - paths: - - backend: - service: - name: nginx-ingress - port: - number: 18080 - path: /nginx_status - pathType: Prefix -``` - -Agora crie um arquivo para definir o ingress que redirecionará para os serviços das aplicações que criamos no início desta seção: - -``` -vim app-ingress.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - name: app-ingress -spec: - rules: - - host: ec2-54-198-119-88.compute-1.amazonaws.com # Mude para o seu endereço dns - http: - paths: - - backend: - service: - name: appsvc1 - port: - number: 80 - path: /app1 - pathType: Prefix - - backend: - service: - name: appsvc2 - port: - number: 80 - path: /app2 - pathType: Prefix -``` - -Crie os ingresses no namespace ``ingress`` e ``default`` com os seguintes comandos, respectivamente: - -``` -kubectl create -f nginx-ingress.yaml -n ingress - -ingress.networking.k8s.io/nginx-ingress created -``` - -``` -kubectl create -f app-ingress.yaml - -ingress.networking.k8s.io/app-ingress created -``` - -Visualize os ingresses recém criados: - -``` -kubectl get ingresses -n ingress - -NAME HOSTS ADDRESS PORTS AGE -nginx-ingress ec2-54-159-116-229.compute-1.amazonaws.com 80 35s -``` - -``` -kubectl get ingresses - -NAME HOSTS ADDRESS PORTS AGE -app-ingress ec2-54-159-116-229.compute-1.amazonaws.com 80 16s -``` - -Visualize os detalhes do ingress que redireciona para o backend no namespace ``ingress``: - -``` -kubectl describe ingresses.extensions nginx-ingress -n ingress - -Name: nginx-ingress -Namespace: ingress -Address: -Default backend: default-http-backend:80 () -Rules: - Host Path Backends - ---- ---- -------- - ec2-54-159-116-229.compute-1.amazonaws.com - /nginx_status nginx-ingress:18080 () -Annotations: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal CREATE 50s nginx-ingress-controller Ingress ingress/nginx-ingress -``` - -Visualize os detalhes do ingress que redireciona para a aplicação no namespace ``default``: - -``` -kubectl describe ingresses.extensions app-ingress - -Name: app-ingress -Namespace: default -Address: -Default backend: default-http-backend:80 () -Rules: - Host Path Backends - ---- ---- -------- - ec2-54-159-116-229.compute-1.amazonaws.com - /app1 appsvc1:80 () - /app2 appsvc2:80 () -Annotations: - nginx.ingress.kubernetes.io/rewrite-target: / -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal CREATE 1m nginx-ingress-controller Ingress default/app-ingress -``` - -Crie um arquivo para definir um service do tipo nodePort: - -``` -vim nginx-ingress-controller-service.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: nginx-ingress -spec: - type: NodePort - ports: - - port: 80 - nodePort: 30000 - name: http - - port: 18080 - nodePort: 32000 - name: http-mgmt - selector: - app: nginx-ingress-lb -``` - -Agora crie o service do tipo nodePort: - -``` -kubectl create -f nginx-ingress-controller-service.yaml -n=ingress - -service/nginx-ingress created -``` - -Pronto! Agora você já pode acessar suas apps pela URL que você configurou. Abra o navegador e adicione os seguintes endereços: - -``` -http://SEU-ENDEREÇO:30000/app1 - -http://SEU-ENDEREÇO:30000/app2 - -http://SEU-ENDEREÇO:32000/nginx_status -``` - -Ou ainda via curl: - -``` -curl http://SEU-ENDEREÇO:30000/app1 - -curl http://SEU-ENDEREÇO:30000/app2 - -curl http://SEU-ENDEREÇO:32000/nginx_status -``` - ---- - -# RASCUNHO - -Caso você queira fazer a instalação utilizando o repositório do Jeferson, ao invés de criar todos os arquivos, abaixo os comandos necessários para realizar o deploy: - -Criando o Cluster: - -``` -curl -fsSL https://get.docker.com | bash -vim /etc/modules-load.d/k8s.conf -sudo apt-get update && sudo apt-get install -y apt-transport-https -curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - -sudo echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list -sudo apt-get update -sudo apt-get install -y kubelet kubeadm kubectl -sudo kubeadm config images pull -sudo kubeadm init -mkdir -p $HOME/.kube -kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" -cat /etc/modules-load.d/k8s.conf -sudo modprobe br_netfilter ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack_ipv4 ip_vs -kubectl get nodes -``` - -Realizando o clone do repositório: - -``` -git clone https://github.com/badtuxx/ingress.git -``` - -Iniciando o deploy de nossa app e também do Nginx Ingress. - -``` -cd ingress/ -kubectl create -f app-deployment.yaml -kubectl create -f app-service.yaml -kubectl get pods -kubectl get ep -kubectl create namespace ingress -kubectl create -f default-backend-deployment.yaml -n ingress -kubectl create -f default-backend-service.yaml -n ingress -kubectl get deployments. -n ingress -kubectl get service -kubectl get service -n ingress -kubectl create -f nginx-ingress-controller-config-map.yaml -n ingress -kubectl create -f nginx-ingress-controller-roles.yaml -n ingress -kubectl create -f nginx-ingress-controller-deployment.yaml -n ingress -kubectl create -f nginx-ingress-controller-service.yaml -n=ingress -kubectl get pods -kubectl get pods -n ingress -kubectl create -f nginx-ingress.yaml -n ingress -kubectl create -f app-ingress.yaml -kubectl get pods -n ingress -kubectl get pods -kubectl get services -kubectl get services -n ingress -kubectl get ingress -kubectl get deploy -kubectl get deploy -n ingress -``` - -Pronto! Agora você já pode acessar suas apps pela URL que você configurou. Abra o navegador e adicione os seguintes endereços: - -``` -http://SEU-ENDEREÇO:30000/app1 - -http://SEU-ENDEREÇO:30000/app2 - -http://SEU-ENDEREÇO:32000/nginx_status -``` - -Ou ainda via curl: - -``` -curl http://SEU-ENDEREÇO:30000/app1 - -curl http://SEU-ENDEREÇO:30000/app2 - -curl http://SEU-ENDEREÇO:32000/nginx_status -``` \ No newline at end of file diff --git a/pt/old/day_four/descomplicando_kubernetes.md b/pt/old/day_four/descomplicando_kubernetes.md deleted file mode 100755 index 2dad6ec1..00000000 --- a/pt/old/day_four/descomplicando_kubernetes.md +++ /dev/null @@ -1,2118 +0,0 @@ -# Descomplicando Kubernetes dia 4 - -## Sumário - -- [Descomplicando Kubernetes dia 4](#descomplicando-kubernetes-dia-4) - - [Sumário](#sumário) -- [Volumes](#volumes) - - [Empty-Dir](#empty-dir) - - [Persistent Volume](#persistent-volume) -- [Cron Jobs](#cron-jobs) -- [Secrets](#secrets) -- [ConfigMaps](#configmaps) -- [InitContainers](#initcontainers) -- [Criando um usuário no Kubernetes](#criando-um-usuário-no-kubernetes) -- [RBAC](#rbac) - - [Role e ClusterRole](#role-e-clusterrole) - - [RoleBinding e ClusterRoleBinding](#rolebinding-e-clusterrolebinding) -- [Helm](#helm) - - [Instalando o Helm 3](#instalando-o-helm-3) - - [Comandos Básicos do Helm 3](#comandos-básicos-do-helm-3) - -# Volumes - -## Empty-Dir - -Um volume do tipo **EmptyDir** é criado sempre que um Pod é atribuído a um nó existente. Esse volume é criado inicialmente vazio, e todos os contêineres do Pod podem ler e gravar arquivos no volume. - -Esse volume não é um volume com persistência de dados. Sempre que o Pod é removido de um nó, os dados no ``EmptyDir`` são excluídos permanentemente. É importante ressaltar que os dados não são excluídos em casos de falhas nos contêineres. - -Vamos criar um Pod para testar esse volume: - -``` -vim pod-emptydir.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busybox - namespace: default -spec: - containers: - - image: busybox - name: busy - command: - - sleep - - "3600" - volumeMounts: - - mountPath: /giropops - name: giropops-dir - volumes: - - name: giropops-dir - emptyDir: {} -``` - -Crie o volume a partir do manifesto. - -``` -kubectl create -f pod-emptydir.yaml - -pod/busybox created -``` - -Visualize os pods: - -``` -kubectl get pod - -NAME READY STATUS RESTARTS AGE -busybox 1/1 Running 0 12s -``` - -Pronto! Já subimos nosso pod. - -Vamos listar o nome do contêiner que está dentro do pod ``busybox``: - -``` -kubectl get pods busybox -n default -o jsonpath='{.spec.containers[*].name}*' - -busy -``` - -Agora vamos adicionar um arquivo dentro do path ``/giropops`` diretamente no Pod criado: - -``` -kubectl exec -ti busybox -c busy -- touch /giropops/funciona -``` - -Agora vamos listar esse diretório: - -``` -kubectl exec -ti busybox -c busy -- ls -l /giropops/ - -total 0 --rw-r--r-- 1 root root 0 Jul 7 17:37 funciona -``` - -Como podemos observar nosso arquivo foi criado corretamente. Vamos verificar se esse arquivo também foi criado no volume gerenciado pelo ``kubelet``. Para isso precisamos descobrir em qual nó está alocado o Pod. - -``` -kubectl get pod -o wide - -NAME READY STATUS RESTARTS AGE IP NODE -busybox 1/1 Running 0 1m 10.40.0.6 elliot-02 -``` - -Vamos acessar o shell do contêiner ``busy``, que está dentro do pod ``busybox``: - -``` -kubectl exec -ti busybox -c busy sh -``` - -Liste o conteúdo do diretório ``giropops``. - -``` -ls giropops -``` - -Agora vamos sair do Pod e procurar o nosso volume dentro do nó ``elliot-02``. Para isso acesse-o node via SSH e, em seguida, execute o comando: - -``` -find /var/lib/kubelet/pods/ -iname giropops-dir - -/var/lib/kubelet/pods/7d33810f-8215-11e8-b889-42010a8a0002/volumes/kubernetes.io~empty-dir/giropops-dir -``` - -Vamos listar esse ``Path``: - -``` -ls /var/lib/kubelet/pods/7d33810f-8215-11e8-b889-42010a8a0002/volumes/kubernetes.io~empty-dir/giropops-dir -funciona -``` - -O arquivo que criamos dentro do contêiner está listado. - -De volta ao nó ``elliot-01``, vamos para remover o Pod e listar novamente o diretório. - -``` -kubectl delete -f pod-emptydir.yaml - -pod "busybox" deleted -``` - -Volte a acessar o nó ``elliot-02`` e veja se o volume ainda existe: - -``` -ls /var/lib/kubelet/pods/7d...kubernetes.io~empty-dir/giropops-dir - -No such file or directory -``` - -Opa, recebemos a mensagem de que o diretório não pode ser encontrado, exatamente o que esperamos correto? Porque o volume do tipo **EmptyDir** não mantém os dados persistentes. - -## Persistent Volume - -O subsistema **PersistentVolume** fornece uma API para usuários e administradores que resume detalhes de como o armazenamento é fornecido e consumido pelos Pods. Para o melhor controle desse sistema foi introduzido dois recursos de API: ``PersistentVolume`` e ``PersistentVolumeClaim``. - -Um **PersistentVolume** (PV) é um recurso no cluster, assim como um nó. Mas nesse caso é um recurso de armazenamento. O PV é uma parte do armazenamento no cluster que foi provisionado por um administrador. Os PVs tem um ciclo de vida independente de qualquer pod associado a ele. Essa API permite armazenamentos do tipo: NFS, ISCSI ou armazenamento de um provedor de nuvem específico. - -Um **PersistentVolumeClaim** (PVC) é semelhante a um Pod. Os Pods consomem recursos de um nó e os PVCs consomem recursos dos PVs. - -Mas o que é um PVC? Nada mais é do que uma solicitação de armazenamento criada por um usuário. - -Vamos criar um ``PersistentVolume`` do tipo ``NFS``, para isso vamos instalar os pacotes necessários para criar um NFS Server no GNU/Linux. - -Vamos instalar os pacotes no node ``elliot-01``. - -No Debian/Ubuntu: - -``` -sudo apt-get install -y nfs-kernel-server -``` - -No CentOS/RedHat tanto no servidor quanto nos nodes o pacote será o mesmo: - -``` -sudo yum install -y nfs-utils -``` - -Agora vamos instalar o pacote ``nfs-common`` nos demais nodes da família Debian. - -``` -sudo apt-get install -y nfs-common -``` - -Agora vamos montar um diretório no node ``elliot-01`` e dar as permissões necessárias para testar tudo isso que estamos falando: - -``` -sudo mkdir /opt/dados -sudo chmod 1777 /opt/dados/ -``` - -Ainda no node ``elliot-01``, vamos adicionar esse diretório no NFS Server e fazer a ativação do mesmo. - -``` -sudo vim /etc/exports -``` - -Adicione a seguinte linha: - -``` -/opt/dados *(rw,sync,no_root_squash,subtree_check) -``` - -Aplique a configuração do NFS no node ``elliot-01``. - -``` -sudo exportfs -a -``` - -Vamos fazer o restart do serviço do NFS no node ``elliot-01``. - -No Debian/Ubuntu: - -``` -sudo systemctl restart nfs-kernel-server -``` - -No CentOS/RedHat: - -``` -sudo systemctl restart nfs -``` - -Ainda no node ``elliot-01``, vamos criar um arquivo nesse diretório para nosso teste. - -``` -sudo touch /opt/dados/FUNCIONA -``` - -Ainda no node ``elliot-01``, vamos criar o manifesto ``yaml`` do nosso ``PersistentVolume``. Lembre-se de alterar o IP address do campo server para o IP address do node ``elliot-01``. - -``` -sudo vim primeiro-pv.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: PersistentVolume -metadata: - name: primeiro-pv -spec: - capacity: - storage: 1Gi - accessModes: - - ReadWriteMany - persistentVolumeReclaimPolicy: Retain - storageClassName: nfs - nfs: - path: /opt/dados - server: 10.138.0.2 - readOnly: false -``` - -Agora vamos criar nosso ``PersistentVolume``: - -``` -kubectl create -f primeiro-pv.yaml - -persistentvolume/primeiro-pv created -``` - -Visualizando os PVs: - -``` -kubectl get pv - -NAME CAPACITY ACCESS MODES RECLAIM POLICY ... AGE -primeiro-pv 1Gi RWX Retain ... 22s -``` - -Visualizando mais detalhes do PV recém criado: - -``` -kubectl describe pv primeiro-pv - -Name: primeiro-pv -Labels: -Annotations: -Finalizers: [kubernetes.io/pv-protection] -StorageClass: -Status: Available -Claim: -Reclaim Policy: Retain -Access Modes: RWX -Capacity: 1Gi -Node Affinity: -Message: -Source: - Type: NFS (an NFS mount that lasts the lifetime of a pod) - Server: 10.138.0.2 - Path: /opt/dados - ReadOnly: false -Events: -``` - -Agora precisamos criar nosso ``PersitentVolumeClaim``, assim os Pods conseguem solicitar leitura e escrita ao nosso ``PersistentVolume``. - -Crie o seguinte arquivo: - -``` -vim primeiro-pvc.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: primeiro-pvc -spec: - accessModes: - - ReadWriteMany - resources: - requests: - storage: 800Mi - storageClassName: nfs -``` - -Crie o ``PersitentVolumeClaim`` a partir do manifesto. - -``` -kubectl create -f primeiro-pvc.yaml - -persistentvolumeclaim/primeiro-pvc created -``` - -Vamos listar nosso ``PersistentVolume``: - -``` -kubectl get pv - -NAME CAPACITY ACCESS MOD ... CLAIM ... AGE -primeiro-pv 1Gi RWX ... default/primeiro-pvc ... 8m -``` - -Vamos listar nosso ``PersistentVolumeClaim``: - -``` -kubectl get pvc - -NAME STATUS VOLUME CAPACITY ACCESS MODES ... AGE -primeiro-pvc Bound primeiro-pv 1Gi RWX ... 3m -``` - -Agora que já temos um ``PersistentVolume`` e um ``PersistentVolumeClaim`` vamos criar um deployment que irá consumir esse volume: - -``` -vim nfs-pv.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: nginx - name: nginx - namespace: default -spec: - progressDeadlineSeconds: 600 - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - run: nginx - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - run: nginx - spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx - volumeMounts: - - name: nfs-pv - mountPath: /giropops - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumes: - - name: nfs-pv - persistentVolumeClaim: - claimName: primeiro-pvc - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 -``` - -Crie o deployment a partir do manifesto. - -``` -kubectl create -f nfs-pv.yaml - -deployment.apps/nginx created -``` - -Visualize os detalhes do deployment. - -``` -kubectl describe deployment nginx - -Name: nginx -Namespace: default -CreationTimestamp: Wed, 7 Jul 2018 22:01:49 +0000 -Labels: run=nginx -Annotations: deployment.kubernetes.io/revision=1 -Selector: run=nginx -Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable -StrategyType: RollingUpdate -MinReadySeconds: 0 -RollingUpdateStrategy: 1 max unavailable, 1 max surge -Pod Template: - Labels: run=nginx - Containers: - nginx: - Image: nginx - Port: - Host Port: - Environment: - Mounts: - /giropops from nfs-pv (rw) - Volumes: - nfs-pv: - Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) - ClaimName: primeiro-pvc - ReadOnly: false -Conditions: - Type Status Reason - ---- ------ ------ - Available True MinimumReplicasAvailable - Progressing True NewReplicaSetAvailable -OldReplicaSets: -NewReplicaSet: nginx-b4bd77674 (1/1 replicas created) -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal ScalingReplicaSet 7s deployment-controller Scaled up replica set nginx-b4bd77674 to 1 -``` - -Como podemos observar detalhando nosso pod, ele foi criado com o Volume NFS utilizando o ``ClaimName`` com o valor ``primeiro-pvc``. - -Vamos detalhar nosso pod para verificar se está tudo certinho. - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE ... NODE -nginx-b4b... 1/1 Running 0 28s elliot-02 -``` - -``` -kubectl describe pod nginx-b4bd77674-gwc9k - -Name: nginx-b4bd77674-gwc9k -Namespace: default -Priority: 0 -PriorityClassName: -Node: elliot-02/10.138.0.3 -... - Mounts: - /giropops from nfs-pv (rw) - /var/run/secrets/kubernetes.io/serviceaccount from default-token-np77m (ro) -Conditions: - Type Status - Initialized True - Ready True - ContainersReady True - PodScheduled True -Volumes: - nfs-pv: - Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) - ClaimName: primeiro-pvc - ReadOnly: false - default-token-np77m: - Type: Secret (a volume populated by a Secret) - SecretName: default-token-np77m - Optional: false -... -``` - -Tudo certo, não? O pod realmente montou o volume ``/giropops`` utilizando o volume ``nfs``. - -Agora vamos listar os arquivos dentro do path no contêiner utilizando nosso exemplo que no caso está localizado no nó `elliot-02`: - -``` -kubectl exec -ti nginx-b4bd77674-gwc9k -- ls /giropops/ - -FUNCIONA -``` - -Podemos ver o arquivos que lá no começo está listado no diretório. - -Agora vamos criar outro arquivo utilizando o próprio contêiner com o comando ``kubectl exec`` e o parâmetro ``-- touch``. - -``` -kubectl exec -ti nginx-b4bd77674-gwc9k -- touch /giropops/STRIGUS - -kubectl exec -ti nginx-b4bd77674-gwc9k -- ls -la /giropops/ - -total 4 -drwxr-xr-x. 2 root root 4096 Jul 7 23:13 . -drwxr-xr-x. 1 root root 44 Jul 7 22:53 .. --rw-r--r--. 1 root root 0 Jul 7 22:07 FUNCIONA --rw-r--r--. 1 root root 0 Jul 7 23:13 STRIGUS -``` - -Listando dentro do contêiner podemos observar que o arquivo foi criado, mas e dentro do nosso NFS Server? Vamos listar o diretório do NSF Server no ``elliot-01``. - -``` -ls -la /opt/dados/ - --rw-r--r-- 1 root root 0 Jul 7 22:07 FUNCIONA --rw-r--r-- 1 root root 0 Jul 7 23:13 STRIGUS -``` - -Viram? Nosso NFS server está funcionando corretamente, agora vamos apagar o deployment para ver o que acontece com o volume. - -``` -kubectl get deployment - -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -nginx 1 1 1 1 28m -``` - -Remova o deployment: - -``` -kubectl delete deployment nginx - -deployment.extensions "nginx" deleted -``` - -Agora vamos listar o diretório no NFS Server. - -``` -ls -la /opt/dados/ - --rw-r--r-- 1 root root 0 Jul 7 22:07 FUNCIONA --rw-r--r-- 1 root root 0 Jul 7 23:13 STRIGUS -``` - -Como era de se esperar os arquivos continuam lá e não foram deletados com a exclusão do Deployment, essa é uma das várias formas de se manter arquivos persistentes para os Pods consumirem. - -# Cron Jobs - -Um serviço **CronJob** nada mais é do que uma linha de um arquivo crontab o mesmo arquivo de uma tabela ``cron``. Ele agenda e executa tarefas periodicamente em um determinado cronograma. - -Mas para que podemos usar os **Cron Jobs****? As "Cron" são úteis para criar tarefas periódicas e recorrentes, como executar backups ou enviar e-mails. - -Vamos criar um exemplo para ver como funciona, bora criar nosso manifesto: - -``` -vim primeiro-cron.yaml -``` - -Informe o seguinte conteúdo. - -```yaml -apiVersion: batch/v1 -kind: CronJob -metadata: - name: giropops-cron -spec: - schedule: "*/1 * * * *" - jobTemplate: - spec: - template: - spec: - containers: - - name: giropops-cron - image: busybox - args: - - /bin/sh - - -c - - date; echo Bem Vindo ao Descomplicando Kubernetes - LinuxTips VAIIII ;sleep 30 - restartPolicy: OnFailure -``` - -Nosso exemplo de ``CronJobs`` anterior imprime a hora atual e uma mensagem de de saudação a cada minuto. - -Vamos criar o ``CronJob`` a partir do manifesto. - -``` -kubectl create -f primeiro-cron.yaml - -cronjob.batch/giropops-cron created -``` - -Agora vamos listar e detalhar melhor nosso ``Cronjob``. - -``` -kubectl get cronjobs - -NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE -giropops-cron */1 * * * * False 1 13s 2m -``` - -Vamos visualizar os detalhes do ``Cronjob`` ``giropops-cron``. - -``` -kubectl describe cronjobs.batch giropops-cron - -Name: giropops-cron -Namespace: default -Labels: -Annotations: -Schedule: */1 * * * * -Concurrency Policy: Allow -Suspend: False -Starting Deadline Seconds: -Selector: -Parallelism: -Completions: -Pod Template: - Labels: - Containers: - giropops-cron: - Image: busybox - Port: - Host Port: - Args: - /bin/sh - -c - date; echo LinuxTips VAIIII ;sleep 30 - Environment: - Mounts: - Volumes: -Last Schedule Time: Wed, 22 Aug 2018 22:33:00 +0000 -Active Jobs: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal SuccessfulCreate 1m cronjob-controller Created job giropops-cron-1534977120 - Normal SawCompletedJob 1m cronjob-controller Saw completed job: giropops-cron-1534977120 - Normal SuccessfulCreate 41s cronjob-controller Created job giropops-cron-1534977180 - Normal SawCompletedJob 1s cronjob-controller Saw completed job: giropops-cron-1534977180 - Normal SuccessfulDelete 1s cronjob-controller Deleted job giropops-cron-1534977000 -``` - -Olha que bacana, se observar no ``Events`` do cluster o ``cron`` já está agendando e executando as tarefas. - -Agora vamos ver esse ``cron`` funcionando através do comando ``kubectl get`` junto do parâmetro ``--watch`` para verificar a saída das tarefas, preste atenção que a tarefa vai ser criada em cerca de um minuto após a criação do ``CronJob``. - -``` -kubectl get jobs --watch - -NAME DESIRED SUCCESSFUL AGE -giropops-cron-1534979640 1 1 2m -giropops-cron-1534979700 1 1 1m -``` - -Vamos visualizar o CronJob: - -``` -kubectl get cronjob giropops-cron - -NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE -giropops-cron */1 * * * * False 1 26s 48m -``` - -Como podemos observar que nosso ``cron`` está funcionando corretamente. Para visualizar a saída dos comandos executados pela tarefa vamos utilizar o comando ``logs`` do ``kubectl``. - -Para isso vamos listar os pods em execução e, em seguida, pegar os logs do mesmo. - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -giropops-cron-1534979940-vcwdg 1/1 Running 0 25s -``` - -Vamos visualizar os logs: - -``` -kubectl logs giropops-cron-1534979940-vcwdg - -Wed Aug 22 23:19:06 UTC 2018 -LinuxTips VAIIII -``` - -O ``cron`` está executando corretamente as tarefas de imprimir a data e a frase que criamos no manifesto. - -Se executarmos um ``kubectl get pods`` poderemos ver os Pods criados e utilizados para executar as tarefas a todo minuto. - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -giropops-cron-1534980360-cc9ng 0/1 Completed 0 2m -giropops-cron-1534980420-6czgg 0/1 Completed 0 1m -giropops-cron-1534980480-4bwcc 1/1 Running 0 4s -``` - ---- - -> **Atenção!!!** Por padrão, o Kubernetes mantém o histórico dos últimos 3 ``cron`` executados, concluídos ou com falhas. -Fonte: https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#jobs-history-limits - ---- - -Agora vamos deletar nosso CronJob: - -``` -kubectl delete cronjob giropops-cron - -cronjob.batch "giropops-cron" deleted -``` - -# Secrets - -Objetos do tipo **Secret** são normalmente utilizados para armazenar informações confidenciais, como por exemplo tokens e chaves SSH. Deixar senhas e informações confidenciais em arquivo texto não é um bom comportamento visto do olhar de segurança. Colocar essas informações em um objeto ``Secret`` permite que o administrador tenha mais controle sobre eles reduzindo assim o risco de exposição acidental. - -Vamos criar nosso primeiro objeto ``Secret`` utilizando o arquivo ``secret.txt`` que vamos criar logo a seguir. - -``` -echo -n "giropops strigus girus" > secret.txt -``` - -Agora que já temos nosso arquivo ``secret.txt`` com o conteúdo ``descomplicando-k8s`` vamos criar nosso objeto ``Secret``. - -``` -kubectl create secret generic my-secret --from-file=secret.txt - -secret/my-secret created -``` - -Vamos ver os detalhes desse objeto para ver o que realmente aconteceu. - -``` -kubectl describe secret my-secret - -Name: my-secret -Namespace: default -Labels: -Annotations: - -Type: Opaque - -Data -==== -secret.txt: 18 bytes -``` - -Observe que não é possível ver o conteúdo do arquivo utilizando o ``describe``, isso é para proteger a chave de ser exposta acidentalmente. - -Para verificar o conteúdo de um ``Secret`` precisamos decodificar o arquivo gerado, para fazer isso temos que verificar o manifesto do do mesmo. - -``` -kubectl get secret - -NAME TYPE DATA AGE -my-secret Opaque 1 13m -``` - -``` -kubectl get secret my-secret -o yaml - -apiVersion: v1 -data: - secret.txt: Z2lyb3BvcHMgc3RyaWd1cyBnaXJ1cw== -kind: Secret -metadata: - creationTimestamp: 2018-08-26T17:10:14Z - name: my-secret - namespace: default - resourceVersion: "3296864" - selfLink: /api/v1/namespaces/default/secrets/my-secret - uid: e61d124a-a952-11e8-8723-42010a8a0002 -type: Opaque -``` - -Agora que já temos a chave codificada basta decodificar usando ``Base64``. - -``` -echo 'Z2lyb3BvcHMgc3RyaWd1cyBnaXJ1cw==' | base64 --decode - -giropops strigus girus -``` - -Tudo certo com nosso ``Secret``, agora vamos utilizar ele dentro de um Pod, para isso vamos precisar referenciar o ``Secret`` dentro do Pod utilizando volumes, vamos criar nosso manifesto. - -``` -vim pod-secret.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: test-secret - namespace: default -spec: - containers: - - image: busybox - name: busy - command: - - sleep - - "3600" - volumeMounts: - - mountPath: /tmp/giropops - name: my-volume-secret - volumes: - - name: my-volume-secret - secret: - secretName: my-secret -``` - -Nesse manifesto vamos utilizar o volume ``my-volume-secret`` para montar dentro do contêiner a Secret ``my-secret`` no diretório ``/tmp/giropos``. - -``` -kubectl create -f pod-secret.yaml - -pod/test-secret created -``` - -Vamos verificar se o ``Secret`` foi criado corretamente: - -``` -kubectl exec -ti test-secret -- ls /tmp/giropops - -secret.txt -``` - -``` -kubectl exec -ti test-secret -- cat /tmp/giropops/secret.txt - -giropops strigus girus -``` - -Sucesso! Esse é um dos modos de colocar informações ou senha dentro de nossos Pods, mas existe um jeito ainda mais bacana utilizando os Secrets como variável de ambiente. - -Vamos dar uma olhada nesse cara, primeiro vamos criar um novo objeto ``Secret`` usando chave literal com chave e valor. - -``` -kubectl create secret generic my-literal-secret --from-literal user=linuxtips --from-literal password=catota - -secret/my-literal-secret created -``` - -Vamos ver os detalhes do objeto ``Secret`` ``my-literal-secret``: - -``` -kubectl describe secret my-literal-secret - -Name: my-literal-secret -Namespace: default -Labels: -Annotations: - -Type: Opaque - -Data -==== -password: 6 bytes -user: 9 bytes -``` - -Acabamos de criar um objeto ``Secret`` com duas chaves, um ``user`` e outra ``password``, agora vamos referenciar essa chave dentro do nosso Pod utilizando variável de ambiente, para isso vamos criar nosso novo manifesto. - -``` -vim pod-secret-env.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: teste-secret-env - namespace: default -spec: - containers: - - image: busybox - name: busy-secret-env - command: - - sleep - - "3600" - env: - - name: MEU_USERNAME - valueFrom: - secretKeyRef: - name: my-literal-secret - key: user - - name: MEU_PASSWORD - valueFrom: - secretKeyRef: - name: my-literal-secret - key: password -``` - -Vamos criar nosso pod. - -``` -kubectl create -f pod-secret-env.yaml - -pod/teste-secret-env created -``` - -Agora vamos listar as variáveis de ambiente dentro do contêiner para verificar se nosso Secret realmente foi criado. - -``` -kubectl exec teste-secret-env -c busy-secret-env -it -- printenv - -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -HOSTNAME=teste-secret-env -TERM=xterm -MEU_USERNAME=linuxtips -MEU_PASSWORD=catota -KUBERNETES_PORT_443_TCP_PROTO=tcp -KUBERNETES_PORT_443_TCP_PORT=443 -KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1 -KUBERNETES_SERVICE_HOST=10.96.0.1 -KUBERNETES_SERVICE_PORT=443 -KUBERNETES_SERVICE_PORT_HTTPS=443 -KUBERNETES_PORT=tcp://10.96.0.1:443 -KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443 -HOME=/root -``` - -Viram? Agora podemos utilizar essa chave dentro do contêiner como variável de ambiente, caso alguma aplicação dentro do contêiner precise se conectar ao um banco de dados por exemplo utilizando usuário e senha, basta criar um ``secret`` com essas informações e referenciar dentro de um Pod depois é só consumir dentro do Pod como variável de ambiente ou um arquivo texto criando volumes. - -# ConfigMaps - -Os Objetos do tipo **ConfigMaps** são utilizados para separar arquivos de configuração do conteúdo da imagem de um contêiner, assim podemos adicionar e alterar arquivos de configuração dentro dos Pods sem buildar uma nova imagem de contêiner. - -Para nosso exemplo vamos utilizar um ``ConfigMaps`` configurado com dois arquivos e um valor literal. - -Vamos criar um diretório chamado ``frutas`` e nele vamos adicionar frutas e suas características. - -``` -mkdir frutas - -echo -n amarela > frutas/banana - -echo -n vermelho > frutas/morango - -echo -n verde > frutas/limao - -echo -n "verde e vermelha" > frutas/melancia - -echo -n kiwi > predileta -``` - -Crie o ``Configmap``. - -``` -kubectl create configmap cores-frutas --from-literal=uva=roxa --from-file=predileta --from-file=frutas/ -``` - -Visualize o Configmap. - -``` -kubectl get configmap -``` - -Vamos criar um pod para usar o Configmap: - -``` -vim pod-configmap.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busybox-configmap - namespace: default -spec: - containers: - - image: busybox - name: busy-configmap - command: - - sleep - - "3600" - env: - - name: frutas - valueFrom: - configMapKeyRef: - name: cores-frutas - key: predileta -``` - -Crie o pod a partir do manifesto. - -``` -kubectl create -f pod-configmap.yaml -``` - -Após a criação, execute o comando ``set`` dentro do contêiner, para listar as variáveis de ambiente e conferir se foi criada a variável de acordo com a ``key=predileta`` que definimos em nosso arquivo yaml. - -Repare no final da saída do comando ``set`` a env ``frutas='kiwi'``. - -``` -kubectl exec -ti busybox-configmap -- sh -/ # set -... -frutas='kiwi' -``` - -Vamos criar um pod utilizando utilizando mais de uma variável: - -``` -vim pod-configmap-env.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busybox-configmap-env - namespace: default -spec: - containers: - - image: busybox - name: busy-configmap - command: - - sleep - - "3600" - envFrom: - - configMapRef: - name: cores-frutas -``` - -Crie o pod a partir do manifesto: - -``` -kubectl create -f pod-configmap-env.yaml -``` - -Vamos entrar no contêiner e executar o comando ``set`` novamente para listar as variáveis, repare que foi criada todas as variáveis. - -``` -kubectl exec -ti busybox-configmap-env -- sh - -/ # set -... -banana='amarela' -limao='verde' -melancia='verde e vermelha' -morango='vermelho' -predileta='kiwi' -uva='roxa' -``` - -Agora vamos criar um pod para usar outro Configmap, só que dessa vez utilizando volume: - -``` -vim pod-configmap-file.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busybox-configmap-file - namespace: default -spec: - containers: - - image: busybox - name: busy-configmap - command: - - sleep - - "3600" - volumeMounts: - - name: meu-configmap-vol - mountPath: /etc/frutas - volumes: - - name: meu-configmap-vol - configMap: - name: cores-frutas -``` - -Crie o pod a partir do manifesto. - -``` -kubectl create -f pod-configmap-file.yaml -``` - -Após a criação do pod, vamos conferir o nosso configmap como arquivos. - -``` -kubectl exec -ti busybox-configmap-file -- sh -/ # ls -lh /etc/frutas/ -total 0 -lrwxrwxrwx 1 root root 13 Sep 23 04:56 banana -> ..data/banana -lrwxrwxrwx 1 root root 12 Sep 23 04:56 limao -> ..data/limao -lrwxrwxrwx 1 root root 15 Sep 23 04:56 melancia -> ..data/melancia -lrwxrwxrwx 1 root root 14 Sep 23 04:56 morango -> ..data/morango -lrwxrwxrwx 1 root root 16 Sep 23 04:56 predileta -> ..data/predileta -lrwxrwxrwx 1 root root 10 Sep 23 04:56 uva -> ..data/uva -``` - -# InitContainers - -O objeto do tipo **InitContainers** são um ou mais contêineres que são executados antes do contêiner de um aplicativo em um Pod. Os contêineres de inicialização podem conter utilitários ou scripts de configuração não presentes em uma imagem de aplicativo. - -- Os contêineres de inicialização sempre são executados até a conclusão. -- Cada contêiner init deve ser concluído com sucesso antes que o próximo comece. - -Se o contêiner init de um Pod falhar, o Kubernetes reiniciará repetidamente o Pod até que o contêiner init tenha êxito. No entanto, se o Pod tiver o ``restartPolicy`` como ``Never``, o Kubernetes não reiniciará o Pod, e o contêiner principal não irá ser executado. - -Crie o Pod a partir do manifesto: - -``` -vim nginx-initcontainer.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: init-demo -spec: - containers: - - name: nginx - image: nginx - ports: - - containerPort: 80 - volumeMounts: - - name: workdir - mountPath: /usr/share/nginx/html - initContainers: - - name: install - image: busybox - command: ['wget','-O','/work-dir/index.html','http://linuxtips.io'] - volumeMounts: - - name: workdir - mountPath: "/work-dir" - dnsPolicy: Default - volumes: - - name: workdir - emptyDir: {} -``` - -Crie o pod a partir do manifesto. - -``` -kubectl create -f nginx-initcontainer.yaml - -pod/init-demo created -``` - -Visualize o conteúdo de um arquivo dentro de um contêiner do Pod. - -``` -kubectl exec -ti init-demo -- cat /usr/share/nginx/html/index.html -``` - -Vamos ver os detalhes do Pod: - -``` -kubectl describe pod init-demo - -Name: init-demo -Namespace: default -Priority: 0 -PriorityClassName: -Node: k8s3/172.31.28.13 -Start Time: Sun, 11 Nov 2018 13:10:02 +0000 -Labels: -Annotations: -Status: Running -IP: 10.44.0.13 -Init Containers: - install: - Container ID: docker://d86ec7ce801819a2073b96098055407dec5564a678c2548dd445a613314bac8e - Image: busybox - Image ID: docker-pullable://busybox@sha256:2a03a6059f21e150ae84b0973863609494aad70f0a80eaeb64bddd8d92465812 - Port: - Host Port: - Command: - wget - -O - /work-dir/index.html - http://kubernetes.io - State: Terminated - Reason: Completed - Exit Code: 0 - Started: Sun, 11 Nov 2018 13:10:03 +0000 - Finished: Sun, 11 Nov 2018 13:10:03 +0000 - Ready: True - Restart Count: 0 - Environment: - Mounts: - /var/run/secrets/kubernetes.io/serviceaccount from default-token-x5g8c (ro) - /work-dir from workdir (rw) -Containers: - nginx: - Container ID: docker://1ec37249f98ececdfb5f80c910142c5e6edbc9373e34cd194fbd3955725da334 - Image: nginx - Image ID: docker-pullable://nginx@sha256:d59a1aa7866258751a261bae525a1842c7ff0662d4f34a355d5f36826abc0341 - Port: 80/TCP - Host Port: 0/TCP - State: Running - Started: Sun, 11 Nov 2018 13:10:04 +0000 - Ready: True - Restart Count: 0 - Environment: - Mounts: - /usr/share/nginx/html from workdir (rw) - /var/run/secrets/kubernetes.io/serviceaccount from default-token-x5g8c (ro) -Conditions: - Type Status - Initialized True - Ready True - ContainersReady True - PodScheduled True -Volumes: - workdir: - Type: EmptyDir (a temporary directory that shares a pod's lifetime) - Medium: - default-token-x5g8c: - Type: Secret (a volume populated by a Secret) - SecretName: default-token-x5g8c - Optional: false -QoS Class: BestEffort -Node-Selectors: -Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s - node.kubernetes.io/unreachable:NoExecute for 300s -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Scheduled 3m1s default-scheduler Successfully assigned default/init-demo to k8s3 - Normal Pulling 3m kubelet, k8s3 pulling image "busybox" - Normal Pulled 3m kubelet, k8s3 Successfully pulled image "busybox" - Normal Created 3m kubelet, k8s3 Created container - Normal Started 3m kubelet, k8s3 Started container - Normal Pulling 2m59s kubelet, k8s3 pulling image "nginx" - Normal Pulled 2m59s kubelet, k8s3 Successfully pulled image "nginx" - Normal Created 2m59s kubelet, k8s3 Created container - Normal Started 2m59s kubelet, k8s3 Started container -``` - -Coletando os logs do contêiner init: - -``` -kubectl logs init-demo -c install - -Connecting to linuxtips.io (23.236.62.147:80) -Connecting to www.linuxtips.io (35.247.254.172:443) -wget: note: TLS certificate validation not implemented -saving to '/work-dir/index.html' -index.html 100% |********************************| 765k 0:00:00 ETA -'/work-dir/index.html' saved -``` - -E por último vamos remover o Pod a partir do manifesto: - -``` -kubectl delete -f nginx-initcontainer.yaml - -pod/init-demo deleted -``` - -# Criando um usuário no Kubernetes - -Para criar um usuário no Kubernetes, vamos precisar gerar um CSR (*Certificate Signing Request*) para o usuário. O usuário que vamos utilizar como exemplo é o ``linuxtips``. - -Comando para gerar o CSR: - -``` -openssl req -new -newkey rsa:4096 -nodes -keyout linuxtips.key -out linuxtips.csr -subj "/CN=linuxtips" -``` - -Agora vamos fazer o request do CSR no cluster: - -``` -cat < linuxtips.crt -``` - -Será necessário para a configuração do ``kubeconfig`` o arquivo referente a CA do cluster, para obtê-lá vamos extrai-lá do ``kubeconf`` atual que estamos utilizando: - -``` -kubectl config view -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' --raw | base64 --decode - > ca.crt -``` - -Feito isso vamos montar nosso ``kubeconfig`` para o novo usuário: - -Vamos pegar as informações de IP cluster: - -``` -kubectl config set-cluster $(kubectl config view -o jsonpath='{.clusters[0].name}') --server=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}') --certificate-authority=ca.crt --kubeconfig=linuxtips-config --embed-certs -``` - -Agora setando as confs de ``user`` e ``key``: - -``` -kubectl config set-credentials linuxtips --client-certificate=linuxtips.crt --client-key=linuxtips.key --embed-certs --kubeconfig=linuxtips-config -``` - -Agora vamos definir o ``context linuxtips`` e, em seguida, vamos utilizá-lo: - -``` -kubectl config set-context linuxtips --cluster=$(kubectl config view -o jsonpath='{.clusters[0].name}') --user=linuxtips --kubeconfig=linuxtips-config -``` - -``` -kubectl config use-context linuxtips --kubeconfig=linuxtips-config -``` - -Vamos ver um teste: - -``` -kubectl version --kubeconfig=linuxtips-config -``` - -Pronto! Agora só associar um ``role`` com as permissões desejadas para o usuário. - -# RBAC - -O controle de acesso baseado em funções (*Role-based Access Control* - RBAC) é um método para fazer o controle de acesso aos recursos do Kubernetes com base nas funções dos administradores individuais em sua organização. - -A autorização RBAC usa o ``rbac.authorization.k8s.io`` para conduzir as decisões de autorização, permitindo que você configure políticas dinamicamente por meio da API Kubernetes. - -## Role e ClusterRole - -Um RBAC ``Role`` ou ``ClusterRole`` contém regras que representam um conjunto de permissões. As permissões são puramente aditivas (não há regras de "negação"). - -- Uma ``Role`` sempre define permissões em um determinado namespace, ao criar uma função, você deve especificar o namespace ao qual ela pertence. -- O ``ClusterRole``, por outro lado, é um recurso sem namespaces. - -Você pode usar um ``ClusterRole`` para: - -* Definir permissões em recursos com namespace e ser concedido dentro de namespaces individuais; -* Definir permissões em recursos com namespaces e ser concedido em todos os namespaces; -* Definir permissões em recursos com escopo de cluster. - -Se você quiser definir uma função em um namespace, use uma ``Role``, caso queria definir uma função em todo o cluster, use um ``ClusterRole``. :) - -## RoleBinding e ClusterRoleBinding - -Uma ``RoleBinding`` concede as permissões definidas em uma função a um usuário ou conjunto de usuários. Ele contém uma lista de assuntos (usuários, grupos ou contas de serviço) e uma referência à função que está sendo concedida. Um ``RoleBinding`` concede permissões dentro de um namespace específico, enquanto um ``ClusterRoleBinding`` concede esse acesso a todo o cluster. - -Um RoleBinding pode fazer referência a qualquer papel no mesmo namespace. Como alternativa, um RoleBinding pode fazer referência a um ClusterRole e vincular esse ClusterRole ao namespace do RoleBinding. Se você deseja vincular um ClusterRole a todos os namespaces em seu cluster, use um ClusterRoleBinding. - -Com o ``ClusterRoleBinding`` você pode associar uma conta de serviço a uma determinada ClusterRole. - -Primeiro vamos exibir as ClusterRoles: - -``` -kubectl get clusterrole - -NAME CREATED AT -admin 2020-09-20T04:35:27Z -calico-kube-controllers 2020-09-20T04:35:34Z -calico-node 2020-09-20T04:35:34Z -cluster-admin 2020-09-20T04:35:27Z -edit 2020-09-20T04:35:27Z -kubeadm:get-nodes 2020-09-20T04:35:30Z -system:aggregate-to-admin 2020-09-20T04:35:28Z -system:aggregate-to-edit 2020-09-20T04:35:28Z -system:aggregate-to-view 2020-09-20T04:35:28Z -system:auth-delegator 2020-09-20T04:35:28Z -system:basic-user 2020-09-20T04:35:27Z -system:certificates.k8s.io:certificatesigningrequests:nodeclient 2020-09-20T04:35:28Z -system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 2020-09-20T04:35:28Z -system:certificates.k8s.io:kube-apiserver-client-approver 2020-09-20T04:35:28Z -system:certificates.k8s.io:kube-apiserver-client-kubelet-approver 2020-09-20T04:35:28Z -system:certificates.k8s.io:kubelet-serving-approver 2020-09-20T04:35:28Z -system:certificates.k8s.io:legacy-unknown-approver 2020-09-20T04:35:28Z -system:controller:attachdetach-controller 2020-09-20T04:35:28Z -system:controller:certificate-controller 2020-09-20T04:35:28Z -system:controller:clusterrole-aggregation-controller 2020-09-20T04:35:28Z -system:controller:cronjob-controller 2020-09-20T04:35:28Z -system:controller:daemon-set-controller 2020-09-20T04:35:28Z -system:controller:deployment-controller 2020-09-20T04:35:28Z -system:controller:disruption-controller 2020-09-20T04:35:28Z -system:controller:endpoint-controller 2020-09-20T04:35:28Z -system:controller:endpointslice-controller 2020-09-20T04:35:28Z -system:controller:endpointslicemirroring-controller 2020-09-20T04:35:28Z -system:controller:expand-controller 2020-09-20T04:35:28Z -system:controller:generic-garbage-collector 2020-09-20T04:35:28Z -system:controller:horizontal-pod-autoscaler 2020-09-20T04:35:28Z -system:controller:job-controller 2020-09-20T04:35:28Z -system:controller:namespace-controller 2020-09-20T04:35:28Z -system:controller:node-controller 2020-09-20T04:35:28Z -system:controller:persistent-volume-binder 2020-09-20T04:35:28Z -system:controller:pod-garbage-collector 2020-09-20T04:35:28Z -system:controller:pv-protection-controller 2020-09-20T04:35:28Z -system:controller:pvc-protection-controller 2020-09-20T04:35:28Z -system:controller:replicaset-controller 2020-09-20T04:35:28Z -system:controller:replication-controller 2020-09-20T04:35:28Z -system:controller:resourcequota-controller 2020-09-20T04:35:28Z -system:controller:route-controller 2020-09-20T04:35:28Z -system:controller:service-account-controller 2020-09-20T04:35:28Z -system:controller:service-controller 2020-09-20T04:35:28Z -system:controller:statefulset-controller 2020-09-20T04:35:28Z -system:controller:ttl-controller 2020-09-20T04:35:28Z -system:coredns 2020-09-20T04:35:30Z -system:discovery 2020-09-20T04:35:27Z -system:heapster 2020-09-20T04:35:28Z -system:kube-aggregator 2020-09-20T04:35:28Z -system:kube-controller-manager 2020-09-20T04:35:28Z -system:kube-dns 2020-09-20T04:35:28Z -system:kube-scheduler 2020-09-20T04:35:28Z -system:kubelet-api-admin 2020-09-20T04:35:28Z -system:node 2020-09-20T04:35:28Z -system:node-bootstrapper 2020-09-20T04:35:28Z -system:node-problem-detector 2020-09-20T04:35:28Z -system:node-proxier 2020-09-20T04:35:28Z -system:persistent-volume-provisioner 2020-09-20T04:35:28Z -system:public-info-viewer 2020-09-20T04:35:27Z -system:volume-scheduler 2020-09-20T04:35:28Z -view 2020-09-20T04:35:28Z -``` - -Lembra que falamos anteriormente que para associar uma ``ClusterRole``, precisamos criar uma ``ClusterRoleBinding``? - -Para ver a função de cada uma delas, você pode executar o ``describe``, como fizemos para o **cluster-admin**, repare em ``Resources`` que tem o ``*.*``, ou seja, a ``ServiceAccount`` que pertence a este grupo, pode fazer tudo dentro do cluster. - -``` -kubectl describe clusterrole cluster-admin - -Name: cluster-admin -Labels: kubernetes.io/bootstrapping=rbac-defaults -Annotations: rbac.authorization.kubernetes.io/autoupdate: true -PolicyRule: - Resources Non-Resource URLs Resource Names Verbs - --------- ----------------- -------------- ----- - *.* [] [] [*] - [*] [] [*] -``` - -Vamos criar uma ``ServiceAccount`` na unha para ser administrador do nosso cluster: - -``` -kubectl create serviceaccount jeferson -``` - -Conferindo se a ``ServiceAccount`` foi criada: - -``` -kubectl get serviceaccounts - -NAME SECRETS AGE -default 1 10d -jeferson 1 10s -``` - -Visualizando detalhes da ``ServiceAccount``: - -``` -kubectl describe serviceaccounts jeferson - -Name: jeferson -Namespace: default -Labels: -Annotations: -Image pull secrets: -Mountable secrets: jeferson-token-h8dz6 -Tokens: jeferson-token-h8dz6 -Events: -``` - -Crie uma ``ClusterRoleBinding`` e associe a ``ServiceAccount`` **jeferson** e com a função ``ClusterRole`` **cluster-admin**: - -``` -kubectl create clusterrolebinding toskeria --serviceaccount=default:jeferson --clusterrole=cluster-admin -``` - -Exibindo a ``ClusterRoleBinding`` que acabamos de criar: - -``` -kubectl get clusterrolebindings.rbac.authorization.k8s.io toskeria - -NAME ROLE AGE -toskeria ClusterRole/cluster-admin 118m -``` - -Vamos mandar um ``describe`` do ``ClusterRoleBinding`` **toskeira**. - -``` -kubectl describe clusterrolebindings.rbac.authorization.k8s.io toskeria - -Name: toskeria -Labels: -Annotations: -Role: - Kind: ClusterRole - Name: cluster-admin -Subjects: - Kind Name Namespace - ---- ---- --------- - ServiceAccount jeferson default -``` - -Agora iremos criar um ``ServiceAccount`` **admin-user** a partir do manifesto ``admin-user.yaml``. - -Crie o arquivo: - -``` -vim admin-user.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: admin-user - namespace: kube-system -``` - -Crie a ``ServiceAccount`` partir do manifesto. - -``` -kubectl create -f admin-user.yaml -``` - -Checando se a ``ServiceAccount`` foi criada: - -``` -kubectl get serviceaccounts --namespace=kube-system admin-user - -NAME SECRETS AGE -admin-user 1 10s -``` - -Agora iremos associar o **admin-user** ao **cluster-admin** também a partir do manifesto ``admin-cluster-role-binding.yaml``. - -Crie o arquivo: - -``` -vim admin-cluster-role-binding.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -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: kube-system -``` - -Crie o ``ClusterRoleBinding`` partir do manifesto. - -``` -kubectl create -f admin-cluster-role-binding.yaml - -clusterrolebinding.rbac.authorization.k8s.io/admin-user created -``` - -Cheque se o ``ClusterRoleBinding`` foi criado: - -``` -kubectl get clusterrolebindings.rbac.authorization.k8s.io admin-user - -NAME ROLE AGE -admin-user ClusterRole/cluster-admin 21m -``` - -Pronto! Agora o usuário **admin-user** foi associado ao ``ClusterRoleBinding`` **admin-user** com a função **cluster-admin**. - -Lembrando que toda vez que nos referirmos ao ``ServiceAccount``, estamos referindo à uma conta de usuário. - -# Helm - -O **Helm** é o gerenciador de pacotes do Kubernetes. Os pacotes gerenciados pelo Helm, são chamados de **charts**, que basicamente são formados por um conjunto de manifestos Kubernetes no formato YAML e alguns templates que ajudam a manter variáveis dinâmicas de acordo com o ambiente. O Helm ajuda você a definir, instalar e atualizar até o aplicativo Kubernetes mais complexo. - -Os Helm charts são fáceis de criar, versionar, compartilhar e publicar. - -O Helm é um projeto graduado no CNCF e é mantido pela comunidade, assim como o Kubernetes. - -Para obter mais informações sobre o Helm, acesse os seguintes links: - -* https://helm.sh -* https://helm.sh/docs/intro/quickstart -* https://www.youtube.com/watch?v=Zzwq9FmZdsU&t=2s -* https://helm.sh/docs/topics/architecture - ---- - -> **Atenção!!!** É bom utilizar o Helm3 ao invés de Helm2.> -> Fonte: https://helm.sh/docs/topics/v2_v3_migration - ---- - -## Instalando o Helm 3 - -Execute o seguinte comando para instalar o Helm3 no node ``elliot-01``: - -``` -curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash - -``` - -Visualize a versão do Helm: - -``` -helm version -``` - -## Comandos Básicos do Helm 3 - -Vamos adicionar os repositórios oficiais de Helm charts estáveis do Prometheus e do Grafana: - -``` -helm repo add prometheus-community https://prometheus-community.github.io/helm-charts -helm repo add grafana https://grafana.github.io/helm-charts -``` - -Vamos listar os repositórios Helm adicionados: - -``` -helm repo list - -NAME URL -prometheus-community https://prometheus-community.github.io/helm-charts -grafana https://grafana.github.io/helm-charts -``` - ---- - -> **Atenção!!!** Para remover um repositório Helm, execute o comando: `helm repo remove NOME_REPOSITORIO`. - ---- - -Vamos obter a lista atualizada de Helm charts disponíveis para instalação utilizando todos os repositórios Helm adicionados. Seria o mesmo que executar o comando ``apt-get update``. - -``` -helm repo update -``` - -Por enquanto só temos um repositório adicionado. Se tivéssemos adicionados mais, esse comando nos ajudaria muito. - -Agora vamos listar quais os charts estão disponíveis para ser instalados: - -``` -helm search repo -``` - -Temos ainda a opção de listar os charts disponíveis a partir do Helm Hub (tipo o Docker Hub): - -``` -helm search hub -``` - ---- - -> **Atenção!!!** O comando ``helm search repo`` pode ser utilizado para listar os charts em todos os repositórios adicionados. - ---- - -Vamos instalar o Prometheus utilizando o Helm. Mas antes vamos visualizar qual a versão do chart disponível para instalação: - -``` -helm search repo prometheus-community - -NAME CHART VERSION APP VERSION DESCRIPTION -prometheus-community/alertmanager 0.12.2 v0.22.1 The Alertmanager handles alerts sent by client ... -prometheus-community/kube-prometheus-stack 18.1.0 0.50.0 kube-prometheus-stack collects Kubernetes manif... -prometheus-community/kube-state-metrics 3.5.2 2.2.0 Install kube-state-metrics to generate and expo... -prometheus-community/prometheus 14.8.0 2.26.0 Prometheus is a monitoring system and time seri... -prometheus-community/prometheus-adapter 2.17.0 v0.9.0 A Helm chart for k8s prometheus adapter -prometheus-community/prometheus-blackbox-exporter 5.1.0 0.19.0 Prometheus Blackbox Exporter -... -``` - -* A coluna **NAME** mostra o nome do repositório e o chart. -* A coluna **CHART VERSION** mostra apenas a versão mais recente do chart disponível para instalação. -* A coluna **APP VERSION** mostra apenas a versão mais recente da aplicação a ser instalada pelo chart. Mas nem todo o time de desenvolvimento mantém a versão da aplicação atualizada no campo *APP VERSION*. Eles fazem isso para evitar gerar uma nova versão do chart só porque a imagem Docker da aplicação mudou, sem haver mudanças na estrutura do chart. Dependendo de como o chart é desenvolvido, a versão da imagem Docker da aplicação é alterada apenas no manifesto ``values.yaml`` que cita qual a imagem Docker que será instalada pelo chart. - ---- - -> **Atenção!!!** O comando ``helm search repo prometheus -l`` exibe todas as versões do chart ``prometheus`` disponíveis para instalação. - ---- - -Agora sim, vamos finalmente instalar o Prometheus no namespace ``default``: - -``` -helm install meu-prometheus --version=14.8.0 prometheus-community/prometheus - -NAME: meu-prometheus -LAST DEPLOYED: Tue Sep 28 09:01:26 2021 -NAMESPACE: default -STATUS: deployed -REVISION: 1 -TEST SUITE: None -NOTES: -The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster: -meu-prometheus-server.default.svc.cluster.local - - -Get the Prometheus server URL by running these commands in the same shell: - export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=server" -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace default port-forward $POD_NAME 9090 - - -The Prometheus alertmanager can be accessed via port 80 on the following DNS name from within your cluster: -meu-prometheus-alertmanager.default.svc.cluster.local - - -Get the Alertmanager URL by running these commands in the same shell: - export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=alertmanager" -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace default port-forward $POD_NAME 9093 -################################################################################# -###### WARNING: Pod Security Policy has been moved to a global property. ##### -###### use .Values.podSecurityPolicy.enabled with pod-based ##### -###### annotations ##### -###### (e.g. .Values.nodeExporter.podSecurityPolicy.annotations) ##### -################################################################################# - - -The Prometheus PushGateway can be accessed via port 9091 on the following DNS name from within your cluster: -meu-prometheus-pushgateway.default.svc.cluster.local - - -Get the PushGateway URL by running these commands in the same shell: - export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=pushgateway" -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace default port-forward $POD_NAME 9091 - -For more information on running Prometheus, visit: -https://prometheus.io/ -``` - ---- - -> **Atenção!!!** Se a opção ``-n NOME_NAMESPACE`` for utilizada, a aplicação será instalada no namespace específico. No Helm 3 você pode utilizar a opção ``--create-namespace`` para criar um namespace durante a instalação de uma aplicação. - ---- - -Liste as aplicações instaladas com o Helm no namespace ``default``: - -``` -helm list - -NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -meu-prometheus default 1 2021-09-28 09:01:26.462915708 -0300 -03 deployed prometheus-14.8.0 2.26.0 -``` - -Simples como voar, não é mesmo? - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -meu-prometheus-alertmanager-f97fbdd7d-rd6xh 2/2 Running 0 2m15s -meu-prometheus-kube-state-metrics-6d75d55d9d-965bv 1/1 Running 0 2m15s -meu-prometheus-node-exporter-4xlvc 1/1 Running 0 2m15s -meu-prometheus-node-exporter-b4n54 1/1 Running 0 2m15s -meu-prometheus-pushgateway-54cc45bc49-r45dl 1/1 Running 0 2m15s -meu-prometheus-server-677777d9dc-kp2hk 2/2 Running 0 2m15s -``` - -Top da Balada! Veja os detalhes do pod ``meu-prometheus-server``: - -``` -kubectl describe pod meu-prometheus-server-677777d9dc-kp2hk - -Name: meu-prometheus-server-677777d9dc-kp2hk -Namespace: default -Priority: 0 -Node: kind-multinodes-worker/172.18.0.4 -Start Time: Tue, 28 Sep 2021 09:01:36 -0300 -Labels: app=prometheus - chart=prometheus-14.8.0 - component=server - heritage=Helm - pod-template-hash=677777d9dc - release=meu-prometheus -Annotations: -Status: Running -IP: 10.244.1.5 -IPs: - IP: 10.244.1.5 -Controlled By: ReplicaSet/meu-prometheus-server-677777d9dc -Containers: - prometheus-server-configmap-reload: - Container ID: containerd://aba926df8ffa30ef9c485ef83eb86acc71dd86d4a63230ef88a55b550d6d12bd - Image: jimmidyson/configmap-reload:v0.5.0 - Image ID: docker.io/jimmidyson/configmap-reload@sha256:904d08e9f701d3d8178cb61651dbe8edc5d08dd5895b56bdcac9e5805ea82b52 - Port: - Host Port: - Args: - --volume-dir=/etc/config - --webhook-url=http://127.0.0.1:9090/-/reload - State: Running - Started: Tue, 28 Sep 2021 09:01:50 -0300 - Ready: True - Restart Count: 0 - Environment: - Mounts: - /etc/config from config-volume (ro) - /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-sgnt5 (ro) - prometheus-server: - Container ID: containerd://e34e6d9203ae10ed44e4d52bb137ca630b2a269ae2897df338786b3c94738976 - Image: quay.io/prometheus/prometheus:v2.26.0 - Image ID: quay.io/prometheus/prometheus@sha256:38d40a760569b1c5aec4a36e8a7f11e86299e9191b9233672a5d41296d8fa74e - Port: 9090/TCP - Host Port: 0/TCP - Args: - --storage.tsdb.retention.time=15d - --config.file=/etc/config/prometheus.yml - --storage.tsdb.path=/data - --web.console.libraries=/etc/prometheus/console_libraries - --web.console.templates=/etc/prometheus/consoles - --web.enable-lifecycle - State: Running - Started: Tue, 28 Sep 2021 09:02:42 -0300 - Ready: True - Restart Count: 0 - Liveness: http-get http://:9090/-/healthy delay=30s timeout=10s period=15s #success=1 #failure=3 - Readiness: http-get http://:9090/-/ready delay=30s timeout=4s period=5s #success=1 #failure=3 - Environment: - Mounts: - /data from storage-volume (rw) - /etc/config from config-volume (rw) - /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-sgnt5 (ro) -Conditions: - Type Status - Initialized True - Ready True - ContainersReady True - PodScheduled True -Volumes: - config-volume: - Type: ConfigMap (a volume populated by a ConfigMap) - Name: meu-prometheus-server - Optional: false - storage-volume: - Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) - ClaimName: meu-prometheus-server - ReadOnly: false - kube-api-access-sgnt5: - Type: Projected (a volume that contains injected data from multiple sources) - TokenExpirationSeconds: 3607 - ConfigMapName: kube-root-ca.crt - ConfigMapOptional: - DownwardAPI: true -QoS Class: BestEffort -Node-Selectors: -Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s - node.kubernetes.io/unreachable:NoExecute op=Exists for 300s -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Scheduled 4m17s default-scheduler Successfully assigned default/meu-prometheus-server-677777d9dc-kp2hk to kind-multinodes-worker - Normal Pulling 4m17s kubelet Pulling image "jimmidyson/configmap-reload:v0.5.0" - Normal Pulled 4m3s kubelet Successfully pulled image "jimmidyson/configmap-reload:v0.5.0" in 13.523406715s - Normal Created 4m3s kubelet Created container prometheus-server-configmap-reload - Normal Started 4m3s kubelet Started container prometheus-server-configmap-reload - Normal Pulling 4m3s kubelet Pulling image "quay.io/prometheus/prometheus:v2.26.0" - Normal Pulled 3m12s kubelet Successfully pulled image "quay.io/prometheus/prometheus:v2.26.0" in 51.09900272s - Normal Created 3m11s kubelet Created container prometheus-server - Normal Started 3m11s kubelet Started container prometheus-server -``` - -Podemos ver nas linhas ``Liveness`` e ``Readness`` que o Prometheus está sendo executado na porta 9090/TCP. - ---- - -> **Atenção!!!** Para quem está utilizando o kubectl e o helm instalado na máquina local, pode criar um redirecionamento entre a porta 9090/TCP do pod e a porta 9091/TCP da sua máquina: - -``` -kubectl port-forward meu-prometheus-server-5bc59849fd-b29q4 --namespace default 9091:9090 -``` - -Agora acesse o navegador no endereço http://localhost:9091. Mágico não é mesmo? - -O comando ``kubectl port-forward`` cria um redirecionamento do tráfego 9091/TCP da sua máquina para a porta 9090 do pod que está no seu cluster. Saiba mais em: - -https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/#forward-a-local-port-to-a-port-on-the-pod - ---- - -Vamos visualizar os deployments: - -``` -kubectl get deployment - -NAME READY UP-TO-DATE AVAILABLE AGE -meu-prometheus-alertmanager 1/1 1 1 5m47s -meu-prometheus-kube-state-metrics 1/1 1 1 5m47s -meu-prometheus-pushgateway 1/1 1 1 5m47s -meu-prometheus-server 1/1 1 1 5m47s -``` - -Percebeu? Foi o Helm quem criou os deployments ao instalar a aplicação ``meu-prometheus``. - -Visualize os replicaSet: - -``` -kubectl get replicaset - -NAME DESIRED CURRENT READY AGE -meu-prometheus-alertmanager-f97fbdd7d 1 1 1 6m9s -meu-prometheus-kube-state-metrics-6d75d55d9d 1 1 1 6m9s -meu-prometheus-pushgateway-54cc45bc49 1 1 1 6m9s -meu-prometheus-server-677777d9dc 1 1 1 6m9s -``` - -Visualize o services: - -``` -kubectl get services - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 7m2s -meu-prometheus-alertmanager ClusterIP 10.98.31.191 80/TCP 6m24s -meu-prometheus-kube-state-metrics ClusterIP 10.96.213.170 8080/TCP 6m24s -meu-prometheus-node-exporter ClusterIP None 9100/TCP 6m24s -meu-prometheus-pushgateway ClusterIP 10.101.233.209 9091/TCP 6m24s -meu-prometheus-server ClusterIP 10.110.25.250 80/TCP 6m24s -``` - -O Helm também criou esses objetos no cluster ao instalar a aplicação ``meu-prometheus``. - -Vamos instalar o Grafana usando o Helm. Mas antes vamos visualizar qual a versão do chart mais recente: - -``` -helm search repo grafana - -NAME CHART VERSION APP VERSION DESCRIPTION -grafana/grafana 6.16.10 8.1.5 The leading tool for querying and visualizing t... -grafana/enterprise-logs 1.2.0 v1.1.0 Grafana Enterprise Logs -grafana/enterprise-metrics 1.5.3 v1.5.0 Grafana Enterprise Metrics -grafana/fluent-bit 2.3.0 v2.1.0 Uses fluent-bit Loki go plugin for gathering lo... -grafana/loki 2.6.0 v2.3.0 Loki: like Prometheus, but for logs. -grafana/loki-canary 0.4.0 2.3.0 Helm chart for Grafana Loki Canary -grafana/loki-distributed 0.37.3 2.3.0 Helm chart for Grafana Loki in microservices mode -grafana/loki-stack 2.4.1 v2.1.0 Loki: like Prometheus, but for logs. -grafana/promtail 3.8.1 2.3.0 Promtail is an agent which ships the contents o... -grafana/tempo 0.7.7 1.1.0 Grafana Tempo Single Binary Mode -grafana/tempo-distributed 0.9.15 1.1.0 Grafana Tempo in MicroService mode -grafana/tempo-vulture 0.1.0 0.7.0 Grafana Tempo Vulture - A tool to monitor Tempo... -``` - -Agora sim, vamos instalar a aplicação ``meu-grafana``: - -``` -helm install meu-grafana --version=6.16.10 grafana/grafana - -NAME: meu-grafana -LAST DEPLOYED: Tue Sep 28 09:09:48 2021 -NAMESPACE: default -STATUS: deployed -REVISION: 1 -NOTES: -1. Get your 'admin' user password by running: - - kubectl get secret --namespace default meu-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo - -2. The Grafana server can be accessed via port 80 on the following DNS name from within your cluster: - - meu-grafana.default.svc.cluster.local - - Get the Grafana URL to visit by running these commands in the same shell: - - export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=meu-grafana" -o jsonpath="{.items[0].metadata.name}") - kubectl --namespace default port-forward $POD_NAME 3000 - -3. Login with the password from step 1 and the username: admin -################################################################################# -###### WARNING: Persistence is disabled!!! You will lose your data when ##### -###### the Grafana pod is terminated. ##### -################################################################################# -``` - -Observe que logo após a instalação do Grafana, tal como ocorreu com o Prometheus, são exibidas algumas instruções sobre como acessar a aplicação. - -Essas instruções podem ser visualizadas a qualquer momento usando os comandos: - -``` -helm status meu-grafana -helm status meu-prometheus -``` - -Vamos listar as aplicações instaladas pelo Helm em todos os namespaces: - -``` -helm list --all - -NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -meu-grafana default 1 2021-09-28 09:09:48.800781373 -0300 -03 deployed grafana-6.16.10 8.1.5 -meu-prometheus default 1 2021-09-28 09:01:26.462915708 -0300 -03 deployed prometheus-14.8.0 2.26.0 -``` - -Observe que a coluna **REVISION** mostra a revisão para cada aplicação instalada. - -Vamos remover a aplicação ``meu-prometheus``: - -``` -helm uninstall meu-prometheus --keep-history -``` - -Liste os pods: - -``` -kubectl get pods -A -``` - -O Prometheus foi removido, certo? - -Vamos listar novamente as aplicações instaladas pelo Helm em todos os namespaces: - -``` -helm list --all - -NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -meu-grafana default 1 2021-09-28 09:09:48.800781373 -0300 -03 deployed grafana-6.16.10 8.1.5 -meu-prometheus default 1 2021-09-28 09:01:26.462915708 -0300 -03 uninstalled prometheus-14.8.0 2.26.0 -``` - -Observe que o status da aplicação **meu-prometheus** é **uninstalled**. - -Agora vamos fazer o rollback da remoção da aplicação ``meu-prometheus``, informando a **revision 1**: - -``` -helm rollback meu-prometheus 1 - -Rollback was a success! Happy Helming! -``` - -Liste as aplicações instaladas pelo Helm em todos os namespaces: - -``` -helm list --all - -NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -meu-grafana default 1 2021-09-28 09:09:48.800781373 -0300 -03 deployed grafana-6.16.10 8.1.5 -meu-prometheus default 2 2021-09-28 09:11:57.567890297 -0300 -03 deployed prometheus-14.8.0 2.26.0 -``` - -Olha o Prometheus de volta! A **revision** do Prometheus foi incrementada para **2**. - -A revision sempre é incrementada a cada alteração no deploy de uma aplicação. Essa mesma estratégia de rollback pode ser aplicada quando estiver fazendo uma atualização de uma aplicação. - -Vamos visualizar o histórico de mudanças da aplicação ``meu-prometheus``: - -``` -helm history meu-prometheus - -REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION -1 Tue Sep 28 09:01:26 2021 uninstalled prometheus-14.8.0 2.26.0 Uninstallation complete -2 Tue Sep 28 09:11:57 2021 deployed prometheus-14.8.0 2.26.0 Rollback to 1 -``` - -Se a aplicação for removida sem a opção `--keep-history`, o histórico será perdido e não será possível fazer rollback. - -Para testar isso, remova as aplicações ``meu-prometheus`` e ``meu-grafana`` com os seguintes comandos: - -``` -helm uninstall meu-grafana -helm uninstall meu-prometheus -``` - -Liste as aplicações instaladas em todos os namespaces: - -``` -helm list --all -``` diff --git a/pt/old/day_one/descomplicando_kubernetes.md b/pt/old/day_one/descomplicando_kubernetes.md deleted file mode 100644 index 325d0e18..00000000 --- a/pt/old/day_one/descomplicando_kubernetes.md +++ /dev/null @@ -1,1791 +0,0 @@ -# Descomplicando Kubernetes dia 1 - -## Sumário - -- [Descomplicando Kubernetes dia 1](#descomplicando-kubernetes-dia-1) - - [Sumário](#sumário) -- [O quê preciso saber antes de começar?](#o-quê-preciso-saber-antes-de-começar) - - [Qual distro GNU/Linux devo usar?](#qual-distro-gnulinux-devo-usar) - - [Alguns sites que devemos visitar](#alguns-sites-que-devemos-visitar) - - [E o k8s?](#e-o-k8s) - - [Arquitetura do k8s](#arquitetura-do-k8s) - - [Portas que devemos nos preocupar](#portas-que-devemos-nos-preocupar) - - [Tá, mas qual tipo de aplicação eu devo rodar sobre o k8s?](#tá-mas-qual-tipo-de-aplicação-eu-devo-rodar-sobre-o-k8s) - - [Conceitos-chave do k8s](#conceitos-chave-do-k8s) -- [Aviso sobre os comandos](#aviso-sobre-os-comandos) -- [Kubectl](#kubectl) - - [Instalação do Kubectl no GNU/Linux](#instalação-do-kubectl-no-gnulinux) - - [Instalação do Kubectl no MacOS](#instalação-do-kubectl-no-macos) - - [Instalação do Kubectl no Windows](#instalação-do-kubectl-no-windows) - - [kubectl: alias e autocomplete](#kubectl-alias-e-autocomplete) -- [Minikube](#minikube) - - [Requisitos básicos](#requisitos-básicos) - - [Instalação do Minikube no GNU/Linux](#instalação-do-minikube-no-gnulinux) - - [Instalação do Minikube no MacOS](#instalação-do-minikube-no-macos) - - [Instalação do Minikube no Microsoft Windows](#instalação-do-minikube-no-microsoft-windows) - - [Iniciando, parando e excluindo o Minikube](#iniciando-parando-e-excluindo-o-minikube) - - [Certo, e como eu sei que está tudo funcionando como deveria?](#certo-e-como-eu-sei-que-está-tudo-funcionando-como-deveria) - - [Descobrindo o endereço do Minikube](#descobrindo-o-endereço-do-minikube) - - [Acessando a máquina do Minikube via SSH](#acessando-a-máquina-do-minikube-via-ssh) - - [Dashboard](#dashboard) - - [Logs](#logs) -- [Microk8s](#microk8s) - - [Requisitos básicos](#requisitos-básicos-1) - - [Instalação do MicroK8s no GNU/Linux](#instalação-do-microk8s-no-gnulinux) - - [Versões que suportam Snap](#versões-que-suportam-snap) - - [Instalação no Windows](#instalação-no-windows) - - [Instalando o Chocolatey](#instalando-o-chocolatey) - - [Instalando o Multipass](#instalando-o-multipass) - - [Utilizando Microk8s com Multipass](#utilizando-microk8s-com-multipass) - - [Instalando o Microk8s no MacOS](#instalando-o-microk8s-no-macos) - - [Instalando o Brew](#instalando-o-brew) - - [Instalando o Microk8s via Brew](#instalando-o-microk8s-via-brew) -- [Kind](#kind) - - [Instalação no GNU/Linux](#instalação-no-gnulinux) - - [Instalação no MacOS](#instalação-no-macos) - - [Instalação no Windows](#instalação-no-windows-1) - - [Instalação no Windows via Chocolatey](#instalação-no-windows-via-chocolatey) - - [Criando um cluster com o Kind](#criando-um-cluster-com-o-kind) - - [Criando um cluster com múltiplos nós locais com o Kind](#criando-um-cluster-com-múltiplos-nós-locais-com-o-kind) -- [k3s](#k3s) -- [Instalação do cluster Kubernetes em três nós](#instalação-do-cluster-kubernetes-em-três-nós) - - [Requisitos básicos](#requisitos-básicos-2) - - [Configuração de módulos de kernel](#configuração-de-módulos-de-kernel) - - [Atualização da distribuição](#atualização-da-distribuição) - - [Instalação do Docker e do Kubernetes](#instalação-do-docker-e-do-kubernetes) - - [Inicialização do cluster](#inicialização-do-cluster) - - [Configuração do arquivo de contextos do kubectl](#configuração-do-arquivo-de-contextos-do-kubectl) - - [Inserindo os nós workers no cluster](#inserindo-os-nós-workers-no-cluster) - - [Múltiplas Interfaces](#múltiplas-interfaces) - - [Instalação do pod network](#instalação-do-pod-network) - - [Verificando a instalação](#verificando-a-instalação) -- [Primeiros passos no k8s](#primeiros-passos-no-k8s) - - [Exibindo informações detalhadas sobre os nós](#exibindo-informações-detalhadas-sobre-os-nós) - - [Exibindo novamente token para entrar no cluster](#exibindo-novamente-token-para-entrar-no-cluster) - - [Ativando o autocomplete](#ativando-o-autocomplete) - - [Verificando os namespaces e pods](#verificando-os-namespaces-e-pods) - - [Executando nosso primeiro pod no k8s](#executando-nosso-primeiro-pod-no-k8s) - - [Verificar os últimos eventos do cluster](#verificar-os-últimos-eventos-do-cluster) - - [Efetuar o dump de um objeto em formato YAML](#efetuar-o-dump-de-um-objeto-em-formato-yaml) - - [Socorro, são muitas opções!](#socorro-são-muitas-opções) - - [Expondo o pod](#expondo-o-pod) - - [Limpando tudo e indo para casa](#limpando-tudo-e-indo-para-casa) - - - -## O quê preciso saber antes de começar? - -Durante essa sessão vamos saber tudo o que precisamos antes de começar a sair criando o nosso cluster ou então nossos deployments. - - -### Qual distro GNU/Linux devo usar? - -Devido ao fato de algumas ferramentas importantes, como o ``systemd`` e ``journald``, terem se tornado padrão na maioria das principais distribuições disponíveis hoje, você não deve encontrar problemas para seguir o treinamento, caso você opte por uma delas, como Ubuntu, Debian, CentOS e afins. - -### Alguns sites que devemos visitar - -Abaixo temos os sites oficiais do projeto do Kubernetes: - -- [https://kubernetes.io](https://kubernetes.io) - -- [https://github.com/kubernetes/kubernetes/](https://github.com/kubernetes/kubernetes/) - -- [https://github.com/kubernetes/kubernetes/issues](https://github.com/kubernetes/kubernetes/issues) - - -Abaixo temos as páginas oficiais das certificações do Kubernetes (CKA, CKAD e CKS): - -- [https://www.cncf.io/certification/cka/](https://www.cncf.io/certification/cka/) - -- [https://www.cncf.io/certification/ckad/](https://www.cncf.io/certification/ckad/) - -- [https://www.cncf.io/certification/cks/](https://www.cncf.io/certification/cks/) - - -Outro site importante de conhecer e estudar, é o site dos 12 fatores, muito importante para o desenvolvimento de aplicações que tem como objetivo serem executadas em cluster Kubernetes: - -- [https://12factor.net/pt_br/](https://12factor.net/pt_br/) - - - -## O que é o Kubernetes? - -**Versão resumida:** - -O projeto Kubernetes foi desenvolvido pela Google, em meados de 2014, para atuar como um orquestrador de contêineres para a empresa. O Kubernetes (k8s), cujo termo em Grego significa "timoneiro", é um projeto *open source* que conta com *design* e desenvolvimento baseados no projeto Borg, que também é da Google [1](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/). Alguns outros produtos disponíveis no mercado, tais como o Apache Mesos e o Cloud Foundry, também surgiram a partir do projeto Borg. - -Como Kubernetes é uma palavra difícil de se pronunciar - e de se escrever - a comunidade simplesmente o apelidou de **k8s**, seguindo o padrão [i18n](http://www.i18nguy.com/origini18n.html) (a letra "k" seguida por oito letras e o "s" no final), pronunciando-se simplesmente "kates". - -**Versão longa:** - -Praticamente todo software desenvolvido na Google é executado em contêiner [2](https://www.enterpriseai.news/2014/05/28/google-runs-software-containers/). A Google já gerencia contêineres em larga escala há mais de uma década, quando não se falava tanto sobre isso. Para atender a demanda interna, alguns desenvolvedores do Google construíram três sistemas diferentes de gerenciamento de contêineres: **Borg**, **Omega** e **Kubernetes**. Cada sistema teve o desenvolvimento bastante influenciado pelo antecessor, embora fosse desenvolvido por diferentes razões. - -O primeiro sistema de gerenciamento de contêineres desenvolvido no Google foi o Borg, construído para gerenciar serviços de longa duração e jobs em lote, que anteriormente eram tratados por dois sistemas: **Babysitter** e **Global Work Queue**. O último influenciou fortemente a arquitetura do Borg, mas estava focado em execução de jobs em lote. O Borg continua sendo o principal sistema de gerenciamento de contêineres dentro do Google por causa de sua escala, variedade de recursos e robustez extrema. - -O segundo sistema foi o Omega, descendente do Borg. Ele foi impulsionado pelo desejo de melhorar a engenharia de software do ecossistema Borg. Esse sistema aplicou muitos dos padrões que tiveram sucesso no Borg, mas foi construído do zero para ter a arquitetura mais consistente. Muitas das inovações do Omega foram posteriormente incorporadas ao Borg. - -O terceiro sistema foi o Kubernetes. Concebido e desenvolvido em um mundo onde desenvolvedores externos estavam se interessando em contêineres e o Google desenvolveu um negócio em amplo crescimento atualmente, que é a venda de infraestrutura de nuvem pública. - -O Kubernetes é de código aberto - em contraste com o Borg e o Omega que foram desenvolvidos como sistemas puramente internos do Google. O Kubernetes foi desenvolvido com um foco mais forte na experiência de desenvolvedores que escrevem aplicativos que são executados em um cluster: seu principal objetivo é facilitar a implantação e o gerenciamento de sistemas distribuídos, enquanto se beneficia do melhor uso de recursos de memória e processamento que os contêineres possibilitam. - -Estas informações foram extraídas e adaptadas deste [artigo](https://static.googleusercontent.com/media/research.google.com/pt-BR//pubs/archive/44843.pdf), que descreve as lições aprendidas com o desenvolvimento e operação desses sistemas. - -### Arquitetura do k8s - -Assim como os demais orquestradores disponíveis, o k8s também segue um modelo *control plane/workers*, constituindo assim um *cluster*, onde para seu funcionamento é recomendado no mínimo três nós: o nó *control-plane*, responsável (por padrão) pelo gerenciamento do *cluster*, e os demais como *workers*, executores das aplicações que queremos executar sobre esse *cluster*. - -É possível criar um cluster Kubernetes rodando em apenas um nó, porém é recomendado somente para fins de estudos e nunca executado em ambiente produtivo. - -Caso você queira utilizar o Kubernetes em sua máquina local, em seu desktop, existem diversas soluções que irão criar um cluster Kubernetes, utilizando máquinas virtuais ou o Docker, por exemplo. - -Com isso você poderá ter um cluster Kubernetes com diversos nós, porém todos eles rodando em sua máquina local, em seu desktop. - -Alguns exemplos são: - -* [Kind](https://kind.sigs.k8s.io/docs/user/quick-start): Uma ferramenta para execução de contêineres Docker que simulam o funcionamento de um cluster Kubernetes. É utilizado para fins didáticos, de desenvolvimento e testes. O **Kind não deve ser utilizado para produção**; - -* [Minikube](https://github.com/kubernetes/minikube): ferramenta para implementar um *cluster* Kubernetes localmente com apenas um nó. Muito utilizado para fins didáticos, de desenvolvimento e testes. O **Minikube não deve ser utilizado para produção**; - -* [MicroK8S](https://microk8s.io): Desenvolvido pela [Canonical](https://canonical.com), mesma empresa que desenvolve o [Ubuntu](https://ubuntu.com). Pode ser utilizado em diversas distribuições e **pode ser utilizado em ambientes de produção**, em especial para *Edge Computing* e IoT (*Internet of things*); - -* [k3s](https://k3s.io): Desenvolvido pela [Rancher Labs](https://rancher.com), é um concorrente direto do MicroK8s, podendo ser executado inclusive em Raspberry Pi. - -* [k0s](https://k0sproject.io): Desenvolvido pela [Mirantis](https://www.mirantis.com), mesma empresa que adquiriu a parte enterprise do [Docker](https://www.docker.com). É uma distribuição do Kubernetes com todos os recursos necessários para funcionar em um único binário, que proporciona uma simplicidade na instalação e manutenção do cluster. A pronúncia é correta é kay-zero-ess e tem por objetivo reduzir o esforço técnico e desgaste na instalação de um cluster Kubernetes, por isso o seu nome faz alusão a *Zero Friction*. **O k0s pode ser utilizado em ambientes de produção** - -A figura a seguir mostra a arquitetura interna de componentes do k8s. - -| ![Arquitetura Kubernetes](../../images/kubernetes_architecture.png) | -|:---------------------------------------------------------------------------------------------:| -| *Arquitetura Kubernetes [Ref: phoenixnap.com KB article](https://phoenixnap.com/kb/understanding-kubernetes-architecture-diagrams)* | - - -* **API Server**: É um dos principais componentes do k8s. Este componente fornece uma API que utiliza JSON sobre HTTP para comunicação, onde para isto é utilizado principalmente o utilitário ``kubectl``, por parte dos administradores, para a comunicação com os demais nós, como mostrado no gráfico. Estas comunicações entre componentes são estabelecidas através de requisições [REST](https://restfulapi.net); - -* **etcd**: O etcd é um *datastore* chave-valor distribuído que o k8s utiliza para armazenar as especificações, status e configurações do *cluster*. Todos os dados armazenados dentro do etcd são manipulados apenas através da API. Por questões de segurança, o etcd é por padrão executado apenas em nós classificados como *control plane* no *cluster* k8s, mas também podem ser executados em *clusters* externos, específicos para o etcd, por exemplo; - -* **Scheduler**: O *scheduler* é responsável por selecionar o nó que irá hospedar um determinado *pod* (a menor unidade de um *cluster* k8s - não se preocupe sobre isso por enquanto, nós falaremos mais sobre isso mais tarde) para ser executado. Esta seleção é feita baseando-se na quantidade de recursos disponíveis em cada nó, como também no estado de cada um dos nós do *cluster*, garantindo assim que os recursos sejam bem distribuídos. Além disso, a seleção dos nós, na qual um ou mais pods serão executados, também pode levar em consideração políticas definidas pelo usuário, tais como afinidade, localização dos dados a serem lidos pelas aplicações, etc; - -* **Controller Manager**: É o *controller manager* quem garante que o *cluster* esteja no último estado definido no etcd. Por exemplo: se no etcd um *deploy* está configurado para possuir dez réplicas de um *pod*, é o *controller manager* quem irá verificar se o estado atual do *cluster* corresponde a este estado e, em caso negativo, procurará conciliar ambos; - -* **Kubelet**: O *kubelet* pode ser visto como o agente do k8s que é executado nos nós workers. Em cada nó worker deverá existir um agente Kubelet em execução. O Kubelet é responsável por de fato gerenciar os *pods*, que foram direcionados pelo *controller* do *cluster*, dentro dos nós, de forma que para isto o Kubelet pode iniciar, parar e manter os contêineres e os pods em funcionamento de acordo com o instruído pelo controlador do cluster; - -* **Kube-proxy**: Age como um *proxy* e um *load balancer*. Este componente é responsável por efetuar roteamento de requisições para os *pods* corretos, como também por cuidar da parte de rede do nó; - -* **Container Runtime**: O *container runtime* é o ambiente de execução de contêineres necessário para o funcionamento do k8s. Desde a versão v1.24 o k8s requer que você utilize um container runtime compativel com o CRI (Container Runtime Interface) que foi apresentado em 2016 como um interface capaz de criar um padrão de comunicação entre o container runtime e k8s. Versões anteriores à v1.24 ofereciam integração direta com o Docker Engine usando um componente chamado dockershim porém essa integração direta não está mais disponível. A documentação oficial do kubernetes (v1.24) apresenta alguns ambientes de execução e suas respectivas configurações como o [containerd](https://kubernetes.io/docs/setup/production-environment/container-runtimes/#containerd) um projeto avaliado com o nível graduado pela CNCF (Cloud Native Computing Foundation) e o [CRI-0](https://kubernetes.io/docs/setup/production-environment/container-runtimes/#cri-o) projeto incubado pela CNCF. - -> Projetos graduados e incubados pela CNCF são considerados estáveis ​​e utilizados com sucesso em produção. - -### Portas que devemos nos preocupar - -**CONTROL PLANE** - -Protocol|Direction|Port Range|Purpose|Used By ---------|---------|----------|-------|------- -TCP|Inbound|6443*|Kubernetes API server|All -TCP|Inbound|2379-2380|etcd server client API|kube-apiserver, etcd -TCP|Inbound|10250|Kubelet API|Self, Control plane -TCP|Inbound|10251|kube-scheduler|Self -TCP|Inbound|10252|kube-controller-manager|Self - -* Toda porta marcada por * é customizável, você precisa se certificar que a porta alterada também esteja aberta. - -**WORKERS** - -Protocol|Direction|Port Range|Purpose|Used By ---------|---------|----------|-------|------- -TCP|Inbound|10250|Kubelet API|Self, Control plane -TCP|Inbound|30000-32767|NodePort|Services All - -Caso você opte pelo [Weave](https://weave.works) como *pod network*, devem ser liberadas também as portas 6783 (TCP) e 6783/6784 (UDP). - -### Tá, mas qual tipo de aplicação eu devo rodar sobre o k8s? - -O melhor *app* para executar em contêiner, principalmente no k8s, são aplicações que seguem o [The Twelve-Factor App](https://12factor.net/pt_br/). - -### Conceitos-chave do k8s - -É importante saber que a forma como o k8s gerencia os contêineres é ligeiramente diferente de outros orquestradores, como o Docker Swarm, sobretudo devido ao fato de que ele não trata os contêineres diretamente, mas sim através de *pods*. Vamos conhecer alguns dos principais conceitos que envolvem o k8s a seguir: - -- **Pod**: É o menor objeto do k8s. Como dito anteriormente, o k8s não trabalha com os contêineres diretamente, mas organiza-os dentro de *pods*, que são abstrações que dividem os mesmos recursos, como endereços, volumes, ciclos de CPU e memória. Um pod pode possuir vários contêineres; - -- **Deployment**: É um dos principais *controllers* utilizados. O *Deployment*, em conjunto com o *ReplicaSet*, garante que determinado número de réplicas de um pod esteja em execução nos nós workers do cluster. Além disso, o Deployment também é responsável por gerenciar o ciclo de vida das aplicações, onde características associadas a aplicação, tais como imagem, porta, volumes e variáveis de ambiente, podem ser especificados em arquivos do tipo *yaml* ou *json* para posteriormente serem passados como parâmetro para o ``kubectl`` executar o deployment. Esta ação pode ser executada tanto para criação quanto para atualização e remoção do deployment; - -- **ReplicaSets**: É um objeto responsável por garantir a quantidade de pods em execução no nó; - -- **Services**: É uma forma de você expor a comunicação através de um *ClusterIP*, *NodePort* ou *LoadBalancer* para distribuir as requisições entre os diversos Pods daquele Deployment. Funciona como um balanceador de carga. - -- **Controller**: É o objeto responsável por interagir com o *API Server* e orquestrar algum outro objeto. Um exemplo de objeto desta classe é o *Deployments*; - -- **Jobs e CronJobs**: são objetos responsáveis pelo gerenciamento de jobs isolados ou recorrentes. - - -## Importante! - -### Aviso sobre os comandos - -> **Atenção!!!** Antes de cada comando é apresentado o tipo prompt. Exemplos: - -``` -$ comando1 -``` - -``` -# comando2 -``` - -> O prompt que inicia com o caractere "$", indica que o comando deve ser executado com um usuário comum do sistema operacional. -> -> O prompt que inicia com o caractere "#", indica que o comando deve ser executado com o usuário **root**. -> -> Você não deve copiar/colar o prompt, apenas o comando. :-) - - - - -## Instalando e customizando o Kubectl - -### Instalação do Kubectl no GNU/Linux - -Vamos instalar o ``kubectl`` com os seguintes comandos. - -``` -curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl - -chmod +x ./kubectl - -sudo mv ./kubectl /usr/local/bin/kubectl - -kubectl version --client -``` - -### Instalação do Kubectl no MacOS - -O ``kubectl`` pode ser instalado no MacOS utilizando tanto o [Homebrew](https://brew.sh), quanto o método tradicional. Com o Homebrew já instalado, o kubectl pode ser instalado da seguinte forma. - -``` -sudo brew install kubectl - -kubectl version --client -``` - -Ou: - -``` -sudo brew install kubectl-cli - -kubectl version --client -``` - -Já com o método tradicional, a instalação pode ser realizada com os seguintes comandos. - -``` -curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl" - -chmod +x ./kubectl - -sudo mv ./kubectl /usr/local/bin/kubectl - -kubectl version --client -``` - -### Instalação do Kubectl no Windows - -A instalação do ``kubectl`` pode ser realizada efetuando o download [neste link](https://dl.k8s.io/release/v1.24.3/bin/windows/amd64/kubectl.exe). - -Outras informações sobre como instalar o kubectl no Windows podem ser encontradas [nesta página](https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/). - - -### Customizando o kubectl - -#### Auto-complete - -Execute o seguinte comando para configurar o alias e autocomplete para o ``kubectl``. - -No Bash: - -```bash -source <(kubectl completion bash) # configura o autocomplete na sua sessão atual (antes, certifique-se de ter instalado o pacote bash-completion). - -echo "source <(kubectl completion bash)" >> ~/.bashrc # add autocomplete permanentemente ao seu shell. -``` - -No ZSH: - -```bash -source <(kubectl completion zsh) - -echo "[[ $commands[kubectl] ]] && source <(kubectl completion zsh)" -``` - -#### Criando um alias para o kubectl - -Crie o alias ``k`` para ``kubectl``: - -``` -alias k=kubectl - -complete -F __start_kubectl k -``` - -## Criando um cluster Kubernetes - -### Criando o cluster em sua máquina local - -Vamos mostrar algumas opções, caso você queira começar a brincar com o Kubernetes utilizando somente a sua máquina local, o seu desktop. - -Lembre-se, você não é obrigado a testar/utilizar todas as opções abaixo, mas seria muito bom caso você testasse. :D - -#### Minikube - -##### Requisitos básicos - -É importante frisar que o Minikube deve ser instalado localmente, e não em um *cloud provider*. Por isso, as especificações de *hardware* a seguir são referentes à máquina local. - -* Processamento: 1 core; -* Memória: 2 GB; -* HD: 20 GB. - -##### Instalação do Minikube no GNU/Linux - -Antes de mais nada, verifique se a sua máquina suporta virtualização. No GNU/Linux, isto pode ser realizado com o seguinte comando: - -``` -grep -E --color 'vmx|svm' /proc/cpuinfo -``` - -Caso a saída do comando não seja vazia, o resultado é positivo. - -Há a possibilidade de não utilizar um *hypervisor* para a instalação do Minikube, executando-o ao invés disso sobre o próprio host. Iremos utilizar o Oracle VirtualBox como *hypervisor*, que pode ser encontrado [aqui](https://www.virtualbox.org). - -Efetue o download e a instalação do ``Minikube`` utilizando os seguintes comandos. - -``` -curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 - -chmod +x ./minikube - -sudo mv ./minikube /usr/local/bin/minikube - -minikube version -``` - -##### Instalação do Minikube no MacOS - -No MacOS, o comando para verificar se o processador suporta virtualização é: - -``` -sysctl -a | grep -E --color 'machdep.cpu.features|VMX' -``` - -Se você visualizar `VMX` na saída, o resultado é positivo. - -Efetue a instalação do Minikube com um dos dois métodos a seguir, podendo optar-se pelo Homebrew ou pelo método tradicional. - -``` -sudo brew install minikube - -minikube version -``` - -Ou: - -``` -curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 - -chmod +x ./minikube - -sudo mv ./minikube /usr/local/bin/minikube - -minikube version -``` - -##### Instalação do Minikube no Microsoft Windows - -No Microsoft Windows, você deve executar o comando `systeminfo` no prompt de comando ou no terminal. Caso o retorno deste comando seja semelhante com o descrito a seguir, então a virtualização é suportada. - -``` -Hyper-V Requirements: VM Monitor Mode Extensions: Yes - Virtualization Enabled In Firmware: Yes - Second Level Address Translation: Yes - Data Execution Prevention Available: Yes -``` - -Caso a linha a seguir também esteja presente, não é necessária a instalação de um *hypervisor* como o Oracle VirtualBox: - -``` -Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed.: A hypervisor has been detected. Features required for Hyper-V will not be displayed. -``` - -Faça o download e a instalação de um *hypervisor* (preferencialmente o [Oracle VirtualBox](https://www.virtualbox.org)), caso no passo anterior não tenha sido acusada a presença de um. Finalmente, efetue o download do instalador do Minikube [aqui](https://github.com/kubernetes/minikube/releases/latest) e execute-o. - - -##### Iniciando, parando e excluindo o Minikube - -Quando operando em conjunto com um *hypervisor*, o Minikube cria uma máquina virtual, onde dentro dela estarão todos os componentes do k8s para execução. - -É possível selecionar qual *hypervisor* iremos utilizar por padrão, através no comando abaixo: - -``` -minikube config set driver -``` - -Você deve substituir pelo seu hypervisor, por exemplo o KVM2, QEMU, Virtualbox ou o Hyperkit. - - -Caso não queria configurar um hypervisor padrão, você pode digitar o comando ``minikube start --driver=hyperkit`` toda vez que criar um novo ambiente. - - -##### Certo, e como eu sei que está tudo funcionando como deveria? - -Uma vez iniciado, você deve ter uma saída na tela similar à seguinte: - -``` -minikube start - -😄 minikube v1.26.0 on Debian bookworm/sid -✨ Using the qemu2 (experimental) driver based on user configuration -👍 Starting control plane node minikube in cluster minikube -🔥 Creating qemu2 VM (CPUs=2, Memory=6000MB, Disk=20000MB) ... -🐳 Preparing Kubernetes v1.24.1 on Docker 20.10.16 ... - ▪ Generating certificates and keys ... - ▪ Booting up control plane ... - ▪ Configuring RBAC rules ... -🔎 Verifying Kubernetes components... - ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5 -🌟 Enabled addons: default-storageclass, storage-provisioner -🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default - -``` - -Você pode então listar os nós que fazem parte do seu *cluster* k8s com o seguinte comando: - -``` -kubectl get nodes -``` - -A saída será similar ao conteúdo a seguir: - -``` -kubectl get nodes -NAME STATUS ROLES AGE VERSION -minikube Ready control-plane 26s v1.24.1 -``` - -Para criar um cluster com mais de um nó, você pode utilizar o comando abaixo, apenas modificando os valores para o desejado: - -``` -minikube start --nodes 2 -p multinode-cluster - -😄 minikube v1.26.0 on Debian bookworm/sid -✨ Automatically selected the docker driver. Other choices: kvm2, virtualbox, ssh, none, qemu2 (experimental) -📌 Using Docker driver with root privileges -👍 Starting control plane node minikube in cluster minikube -🚜 Pulling base image ... -💾 Downloading Kubernetes v1.24.1 preload ... - > preloaded-images-k8s-v18-v1...: 405.83 MiB / 405.83 MiB 100.00% 66.78 Mi - > gcr.io/k8s-minikube/kicbase: 385.99 MiB / 386.00 MiB 100.00% 23.63 MiB p - > gcr.io/k8s-minikube/kicbase: 0 B [_________________________] ?% ? p/s 11s -🔥 Creating docker container (CPUs=2, Memory=8000MB) ... -🐳 Preparing Kubernetes v1.24.1 on Docker 20.10.17 ... - ▪ Generating certificates and keys ... - ▪ Booting up control plane ... - ▪ Configuring RBAC rules ... -🔗 Configuring CNI (Container Networking Interface) ... -🔎 Verifying Kubernetes components... - ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5 -🌟 Enabled addons: storage-provisioner, default-storageclass - -👍 Starting worker node minikube-m02 in cluster minikube -🚜 Pulling base image ... -🔥 Creating docker container (CPUs=2, Memory=8000MB) ... -🌐 Found network options: - ▪ NO_PROXY=192.168.11.11 -🐳 Preparing Kubernetes v1.24.1 on Docker 20.10.17 ... - ▪ env NO_PROXY=192.168.11.11 -🔎 Verifying Kubernetes components... -🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default - -``` - -Para visualizar os nós do seu novo cluster Kubernetes, digite: - -``` -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -minikube Ready control-plane 66s v1.24.1 -minikube-m02 Ready 48s v1.24.1 -``` - -Inicialmente, a intenção do Minikube é executar o k8s em apenas um nó, porém a partir da versão 1.10.1 e possível usar a função de multi-node. - -Caso os comandos anteriores tenham sido executados sem erro, a instalação do Minikube terá sido realizada com sucesso. - -##### Ver detalhes sobre o cluster - -``` -minikube status -``` - -##### Descobrindo o endereço do Minikube - -Como dito anteriormente, o Minikube irá criar uma máquina virtual, assim como o ambiente para a execução do k8s localmente. Ele também irá configurar o ``kubectl`` para comunicar-se com o Minikube. Para saber qual é o endereço IP dessa máquina virtual, pode-se executar: - -``` -minikube ip -``` - -O endereço apresentado é que deve ser utilizado para comunicação com o k8s. - -##### Acessando a máquina do Minikube via SSH - -Para acessar a máquina virtual criada pelo Minikube, pode-se executar: - -``` -minikube ssh -``` - -##### Dashboard - -O Minikube vem com um *dashboard* *web* interessante para que o usuário iniciante observe como funcionam os *workloads* sobre o k8s. Para habilitá-lo, o usuário pode digitar: - -``` -minikube dashboard -``` - -##### Logs - -Os *logs* do Minikube podem ser acessados através do seguinte comando. - -``` -minikube logs -``` - -##### Remover o cluster - -``` -minikube delete -``` - -Caso queira remover o cluster e todos os arquivos referente a ele, utilize o parametro *--purge*, conforme abaixo: - -``` -minikube delete --purge -``` - -#### Kind - -O Kind (*Kubernetes in Docker*) é outra alternativa para executar o Kubernetes num ambiente local para testes e aprendizado, mas não é recomendado para uso em produção. - -##### Instalação no GNU/Linux - -Para fazer a instalação no GNU/Linux, execute os seguintes comandos. - -``` -curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-linux-amd64 - -chmod +x ./kind - -sudo mv ./kind /usr/local/bin/kind -``` - -##### Instalação no MacOS - -Para fazer a instalação no MacOS, execute o seguinte comando. - -``` -sudo brew install kind -``` - -ou - -``` -Para Intel Macs -[ $(uname -m) = x86_64 ]&& curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-darwin-amd64 -Para M1 / ARM Macs -[ $(uname -m) = arm64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.16.0/kind-darwin-arm64 - -chmod +x ./kind -mv ./kind /usr/bin/kind -``` - -##### Instalação no Windows - -Para fazer a instalação no Windows, execute os seguintes comandos. - -``` -curl.exe -Lo kind-windows-amd64.exe https://kind.sigs.k8s.io/dl/v0.14.0/kind-windows-amd64 - -Move-Item .\kind-windows-amd64.exe c:\kind.exe -``` - -###### Instalação no Windows via [Chocolatey](https://chocolatey.org/install) - -Execute o seguinte comando para instalar o Kind no Windows usando o Chocolatey. - -``` -choco install kind -``` - -##### Criando um cluster com o Kind - -Após realizar a instalação do Kind, vamos iniciar o nosso cluster. - -``` -kind create cluster - -Creating cluster "kind" ... - ✓ Ensuring node image (kindest/node:v1.25.2) 🖼 - ✓ Preparing nodes 📦 - ✓ Writing configuration 📜 - ✓ Starting control-plane 🕹️ - ✓ Installing CNI 🔌 - ✓ Installing StorageClass 💾 -Set kubectl context to "kind-kind" -You can now use your cluster with: - -kubectl cluster-info --context kind-kind - -Not sure what to do next? 😅 Check out https://kind.sigs.k8s.io/docs/user/quick-start/ - -``` - -É possível criar mais de um cluster e personalizar o seu nome. - -``` -kind create cluster --name giropops - -Creating cluster "giropops" ... - ✓ Ensuring node image (kindest/node:v1.25.2) 🖼 - ✓ Preparing nodes 📦 - ✓ Writing configuration 📜 - ✓ Starting control-plane 🕹️ - ✓ Installing CNI 🔌 - ✓ Installing StorageClass 💾 -Set kubectl context to "kind-giropops" -You can now use your cluster with: - -kubectl cluster-info --context kind-giropops - -Thanks for using kind! 😊 -``` - -Para visualizar os seus clusters utilizando o kind, execute o comando a seguir. - -``` -kind get clusters - -kind -giropops -``` - -Liste os nodes do cluster. - -``` -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -giropops-control-plane Ready control-plane 74s v1.25.2 - -``` - -##### Criando um cluster com múltiplos nós locais com o Kind - -É possível para essa aula incluir múltiplos nós na estrutura do Kind, que foi mencionado anteriormente. - -Execute o comando a seguir para selecionar e remover todos os clusters locais criados no Kind. - -``` -kind delete clusters $(kind get clusters) - -Deleted clusters: ["giropops" "kind"] -``` - -Crie um arquivo de configuração para definir quantos e o tipo de nós no cluster que você deseja. No exemplo a seguir, será criado o arquivo de configuração ``kind-3nodes.yaml`` para especificar um cluster com 1 nó control-plane (que executará o control plane) e 2 workers. - -``` -cat << EOF > $HOME/kind-3nodes.yaml -kind: Cluster -apiVersion: kind.x-k8s.io/v1alpha4 -nodes: - - role: control-plane - - role: worker - - role: worker -EOF -``` - -Agora vamos criar um cluster chamado ``kind-multinodes`` utilizando as especificações definidas no arquivo ``kind-3nodes.yaml``. - -``` -kind create cluster --name kind-multinodes --config $HOME/kind-3nodes.yaml - -Creating cluster "kind-multinodes" ... - ✓ Ensuring node image (kindest/node:v1.25.2) 🖼 - ✓ Preparing nodes 📦 📦 📦 - ✓ Writing configuration 📜 - ✓ Starting control-plane 🕹️ - ✓ Installing CNI 🔌 - ✓ Installing StorageClass 💾 - ✓ Joining worker nodes 🚜 -Set kubectl context to "kind-kind-multinodes" -You can now use your cluster with: - -kubectl cluster-info --context kind-kind-multinodes - -Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂 -``` - -Valide a criação do cluster com o comando a seguir. - -``` -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -kind-multinodes-control-plane Ready control-plane 52s v1.25.2 -kind-multinodes-worker Ready 32s v1.25.2 -kind-multinodes-worker2 Ready 32s v1.25.2 -``` - -Mais informações sobre o Kind estão disponíveis em: https://kind.sigs.k8s.io - - -### Instalação do cluster Kubernetes em três nós - -#### Requisitos básicos - -Como já dito anteriormente, o Minikube é ótimo para desenvolvedores, estudos e testes, mas não tem como propósito a execução em ambiente de produção. Dito isso, a instalação de um *cluster* k8s para o treinamento irá requerer pelo menos três máquinas, físicas ou virtuais, cada qual com no mínimo a seguinte configuração: - -- Distribuição: Debian, Ubuntu, CentOS, Red Hat, Fedora, SuSE; - -- Processamento: 2 *cores*; - -- Memória: 2GB. - -#### Configuração de módulos e parametrização de kernel - -O k8s requer que certos módulos do kernel GNU/Linux estejam carregados para seu pleno funcionamento, e que esses módulos sejam carregados no momento da inicialização do computador. Para tanto, crie o arquivo ``/etc/modules-load.d/k8s.conf`` com o seguinte conteúdo em todos os seus nós. - -```bash -vim /etc/modules-load.d/k8s.conf -``` - -``` -br_netfilter -ip_vs -ip_vs_rr -ip_vs_sh -ip_vs_wrr -nf_conntrack_ipv4 -overlay -``` - -Vamos habilitar o repasse de pacotes e fazer com que o *iptables* gerencie os pacotes que estão trafegando pelas *brigdes*. Para isso vamos utilizar *systcl* para parametrizar o kernel. - -```bash -vim /etc/sysctl.d/k8s.conf -``` - -``` -net.bridge.bridge-nf-call-ip6tables = 1 -net.bridge.bridge-nf-call-iptables = 1 -net.ipv4.ip_forward = 1 -``` - -Para ler as novas configurações: - -```bash -sysctl --system -``` - -#### Atualização da distribuição - -Em distribuições Debian e baseadas, como o Ubuntu, execute os comandos a seguir, em cada um de seus nós, para executar atualização do sistema. - -``` -sudo apt update - -sudo apt upgrade -y -``` - -Em distribuições Red Hat e baseadas, use o seguinte comando. - -``` -sudo yum upgrade -y -``` - -#### O Container Runtime - -Para que seja possível executar os containers nos nós é necessário ter um *container runtime* instalado em cada um dos nós. - -O *container runtime* ou o *container engine* é o responsável por executar os containers nos nós. Quando você está utilizando containers em sua máquina, por exemplo, você está fazendo uso de algum *container runtime*. - -O *container runtime* é o responsável por gerenciar as imagens e volumes, é ele o responsável por garantir que os os recursos que os containers estão utilizando está devidamente isolados, a vida do container e muito mais. - -Hoje temos diversas opções para se utilizar como *container runtime*, que até pouco tempo atrás tinhamos somente o Docker para esse papel. - -Hoje o Docker não é mais suportado pelo Kubernetes, pois o Docker é muito mais do que apenas um *container runtime*. - -O Docker Swarm, por exemplo, vem por padrão quando você instala o Docker, ou seja, não faz sentido ter o Docker inteiro sendo que o Kubernetes somente utiliza um pedaço pequeno do Docker. - -O Kubernetes suporta diversos *container runtime*, desde que alinhados com o *Open Container Interface*, o OCI. - -*Container runtimes* suportados pelo Kubernetes: - -- containerd -- CRI-O -- Docker Engine -- Mirantis Container Runtime - - -##### Instalando e configurando o containerd - -Para instalar o *containerd* nos nós, utilize o instalador de pacotes padrão de sua distribuição. Para esse exemplo estou utilizando um Ubuntu Server, então irei utilizar o *apt*. - -Para que isso seja possível vamos adicionar o repositório do Docker. Mas nós não iremos instalar o Docker, iremos somente realizar a instalação do Containerd. - - -```bash -# Adicionando a chave do repositório -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - - -sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" -sudo apt update - -# Instalando o containerd -sudo apt install -y containerd.io -``` - -Agora vamos criar diretório que irá conter as configurações do *containerd*. - -```bash -mkdir -p /etc/containerd -``` - -Agora já podemos criar a configuração básica para o nosso *containerd*, lembrando que é super importante ler a documentação do *containerd* para que você possa conhecer todas as opções para o seu ambiente. - -```bash -containerd config default > /etc/containerd/config.toml -``` - -Agora vamos reiniciar o serviço para que as novas configurações entrem em vigor. - -```bash -# Habilitando o serviço -systemctl enable containerd - -# Reiniciando o serviço -systemctl restart containerd -``` - -##### Instalando o kubeadm - -O próximo passo é efetuar a adição dos repositórios do k8s e efetuar a instalação do ``kubeadm``. - -Em distribuições Debian e baseadas, isso pode ser realizado com os comandos a seguir. - -``` -sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2 - -curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - - -sudo echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list - -sudo apt-get update - -sudo apt-get install -y kubelet kubeadm kubectl -``` - -É necessário desativar a memória swap em todos os nós com o comando a seguir. - -```bash -sudo swapoff -a -``` - -Além de comentar a linha referente à mesma no arquivo ```/etc/fstab```. - -```bash -sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab -``` - -Após esses procedimentos, é interessante a reinicialização de todos os nós do *cluster*. - - -##### Inicialização do cluster - -Antes de inicializarmos o *cluster*, vamos efetuar o *download* das imagens que serão utilizadas, executando o comando a seguir no nó que será o *control-plane*. -Vamos passar o parametro *--cri-socket* para especificar o caminho do arquivo de socket do nosso *container runtime*, nesse caso o *containerd* - -``` -sudo kubeadm config images pull --cri-socket /run/containerd/containerd.sock -``` - -Execute o comando a seguir também apenas no nó *control-plane* para a inicialização do cluster. - -Estamos passando alguns importantes parametros: - -- _--control-plane-endpoint_ -> Ip do seu node que será utilizado no cluster. Importante caso você tenha mais de uma interface ou endereço. - -- _--cri-socket_ -> O arquivo de socket do nosso container runtime. - -- _--upload-certs_ -> Faz o upload do certificado do *control plane* para o kubeadm-certs secret. - - -``` -sudo kubeadm init --upload-certs --control-plane-endpoint=ADICIONE_O_IP_DO_NODE_AQUI --cri-socket /run/containerd/containerd.sock -``` - -Opcionalmente, você também pode passar o cidr com a opção _--pod-network-cidr_. O comando obedecerá a seguinte sintaxe: - -``` -sudo kubeadm init --upload-certs --control-plane-endpoint=ADICIONE_O_IP_DO_NODE_AQUI --cri-socket /run/containerd/containerd.sock --pod-network-cidr 192.168.99.0/24 -``` - -A saída do comando será algo similar ao mostrado a seguir. - -``` -[init] Using Kubernetes version: v1.24.3 -[preflight] Running pre-flight checks -[preflight] Pulling images required for setting up a Kubernetes cluster -[preflight] This might take a minute or two, depending on the speed of your internet connection -[preflight] You can also perform this action in beforehand using 'kubeadm config images pull' -[certs] Using certificateDir folder "/etc/kubernetes/pki" -[certs] Generating "ca" certificate and key -[certs] Generating "apiserver" certificate and key -[certs] apiserver serving cert is signed for DNS names [172.31.19.147 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 172.31.19.147] -[certs] Generating "apiserver-kubelet-client" certificate and key -[certs] Generating "front-proxy-ca" certificate and key -[certs] Generating "front-proxy-client" certificate and key -[certs] Generating "etcd/ca" certificate and key -[certs] Generating "etcd/server" certificate and key -[certs] etcd/server serving cert is signed for DNS names [172.31.19.147 localhost] and IPs [172.31.19.147 127.0.0.1 ::1] -[certs] Generating "etcd/peer" certificate and key -[certs] etcd/peer serving cert is signed for DNS names [172.31.19.147 localhost] and IPs [172.31.19.147 127.0.0.1 ::1] -[certs] Generating "etcd/healthcheck-client" certificate and key -[certs] Generating "apiserver-etcd-client" certificate and key -[certs] Generating "sa" key and public key -[kubeconfig] Using kubeconfig folder "/etc/kubernetes" -[kubeconfig] Writing "admin.conf" kubeconfig file -[kubeconfig] Writing "kubelet.conf" kubeconfig file -[kubeconfig] Writing "controller-manager.conf" kubeconfig file -[kubeconfig] Writing "scheduler.conf" kubeconfig file -[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" -[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" -[kubelet-start] Starting the kubelet -[control-plane] Using manifest folder "/etc/kubernetes/manifests" -[control-plane] Creating static Pod manifest for "kube-apiserver" -[control-plane] Creating static Pod manifest for "kube-controller-manager" -[control-plane] Creating static Pod manifest for "kube-scheduler" -[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" -[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s -[apiclient] All control plane components are healthy after 8.505808 seconds -[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace -[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster -[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace -[upload-certs] Using certificate key: -55befb249a01aca7be98b3e7209628f4c4f04c6a05c250c4bb084af722452c36 -[mark-control-plane] Marking the node 172.31.19.147 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers] -[mark-control-plane] Marking the node 172.31.19.147 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule node-role.kubernetes.io/control-plane:NoSchedule] -[bootstrap-token] Using token: q1m5ci.5p2mtgby0s4ek4vr -[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles -[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes -[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials -[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token -[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster -[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace -[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key -[addons] Applied essential addon: CoreDNS -[addons] Applied essential addon: kube-proxy - -Your Kubernetes control-plane has initialized successfully! - -To start using your cluster, you need to run the following as a regular user: - - mkdir -p $HOME/.kube - sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config - sudo chown $(id -u):$(id -g) $HOME/.kube/config - -Alternatively, if you are the root user, you can run: - - export KUBECONFIG=/etc/kubernetes/admin.conf - -You should now deploy a pod network to the cluster. -Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: - https://kubernetes.io/docs/concepts/cluster-administration/addons/ - -You can now join any number of the control-plane node running the following command on each as root: - - kubeadm join 172.31.19.147:6443 --token q1m5ci.5p2mtgby0s4ek4vr \ - --discovery-token-ca-cert-hash sha256:45f6437514981d97631bd5d48822c670ec4a548c9768043fca6e5eda0133b934 \ - --control-plane --certificate-key 55befb249a01aca7be98b3e7209628f4c4f04c6a05c250c4bb084af722452c36 - -Please note that the certificate-key gives access to cluster sensitive data, keep it secret! -As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use -"kubeadm init phase upload-certs --upload-certs" to reload certs afterward. - -Then you can join any number of worker nodes by running the following on each as root: - -kubeadm join 172.31.19.147:6443 --token q1m5ci.5p2mtgby0s4ek4vr \ - --discovery-token-ca-cert-hash sha256:45f6437514981d97631bd5d48822c670ec4a548c9768043fca6e5eda0133b934 -``` - -Caso o servidor possua mais de uma interface de rede, você pode verificar se o IP interno do nó do seu cluster corresponde ao IP da interface esperada com o seguinte comando: - -``` -kubectl describe node elliot-1 | grep InternalIP -``` - -A saída será algo similar a seguir: - -``` -InternalIP: 172.31.19.147 -``` - -Caso o IP não corresponda ao da interface de rede escolhida, você pode ir até o arquivo localizado em _/etc/systemd/system/kubelet.service.d/10-kubeadm.conf_ com o editor da sua preferência, procure por _KUBELET_CONFIG_ARGS_ e adicione no final a instrução --node-ip=. O trecho alterado será semelhante a esse: - -``` -Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml --node-ip=192.168.99.2" -``` - -Salve o arquivo e execute os comandos abaixo para reiniciar a configuração e consequentemente o kubelet. - -``` -sudo systemctl daemon-reload -sudo systemctl restart kubelet -``` - -#### Configuração do arquivo de contextos do kubectl - -Como dito anteriormente e de forma similar ao Docker Swarm, o próprio kubeadm já mostrará os comandos necessários para a configuração do ``kubectl``, para que assim possa ser estabelecida comunicação com o cluster k8s. Para tanto, execute os seguintes comandos. - -``` -mkdir -p $HOME/.kube - -cp -i /etc/kubernetes/admin.conf $HOME/.kube/config - -sudo chown $(id -u):$(id -g) $HOME/.kube/config -``` - -#### Inserindo os nós workers no cluster - -Para inserir os nós *workers* ou mais *control plane* no *cluster*, basta executar a linha que começa com ``kubeadm join`` que vimos na saída do comando de inicialização do cluster. - -``` -You can now join any number of the control-plane node running the following command on each as root: - - kubeadm join 172.31.19.147:6443 --token q1m5ci.5p2mtgby0s4ek4vr \ - --discovery-token-ca-cert-hash sha256:45f6437514981d97631bd5d48822c670ec4a548c9768043fca6e5eda0133b934 \ - --control-plane --certificate-key 55befb249a01aca7be98b3e7209628f4c4f04c6a05c250c4bb084af722452c36 - -Please note that the certificate-key gives access to cluster sensitive data, keep it secret! -As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use -"kubeadm init phase upload-certs --upload-certs" to reload certs afterward. - -Then you can join any number of worker nodes by running the following on each as root: - -kubeadm join 172.31.19.147:6443 --token q1m5ci.5p2mtgby0s4ek4vr \ - --discovery-token-ca-cert-hash sha256:45f6437514981d97631bd5d48822c670ec4a548c9768043fca6e5eda0133b934 -``` - -Conforme notamos na saída acima temos dois comandos, um para que possamos adicionar mais nós como *control plane* ou então para adicionar nós como *worker*. - -Apenas copie e cole o comando nos nós que você deseja adicionar ao cluster. Nessa linha de comando do *kubeadm join* já estamos passando o IP e porta do nosso primeiro nó *control plane* e as informações sobre o certificado, informações necessárias para que seja possível a entrada do nó no cluster. - - -Lembre-se, o comando abaixo deve ser executado nos nós que irão compor o cluster, no exemplo vamos adicionar mais dois nós como *workers* - -```bash -kubeadm join 172.31.19.147:6443 --token q1m5ci.5p2mtgby0s4ek4vr --discovery-token-ca-cert-hash sha256:45f6437514981d97631bd5d48822c670ec4a548c9768043fca6e5eda0133b934 - -[preflight] Running pre-flight checks -[preflight] Reading configuration from the cluster... -[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' -[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" -[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" -[kubelet-start] Starting the kubelet -[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... - -This node has joined the cluster: -* Certificate signing request was sent to apiserver and a response was received. -* The Kubelet was informed of the new secure connection details. - -Run 'kubectl get nodes' on the control-plane to see this node join the cluster. -``` - -Agora no nó *control plane* verifique os nós que já fazem parte do cluster através do comando *kubectl* - -```bash -kubectl get nodes -NAME STATUS ROLES AGE VERSION -ip-172-31-19-147 NotReady control-plane 68s v1.24.3 -ip-172-31-24-77 NotReady 29s v1.24.3 -ip-172-31-25-32 NotReady 31s v1.24.3 -``` - -Perceba que os nós ainda não estão *Ready*, pois ainda não instalamos o *pod network* para resolver a comunicação entre pods em diferentes nós. - -#### A rede do Kubernetes - -Entender como funciona a rede no Kubernetes é super importante para que você consiga entender não somente o comportamento do próprio Kubernetes, como também para o entendimento de como as suas aplicações se comportam e interagem. -Primeira coisa que devemos entender é que o Kubernetes não resolve como funciona a comunicação de pods em nós diferentes, para que isso seja resolvido é necessário utilizar o que chamamos de *pod networking*. - -Ou seja, o k8s por padrão não fornece uma solução de *networking* *out-of-the-box*. - -Para resolver esse problema foi criado o *Container Network Interface*, o **CNI**. -O *CNI* nada mais é do que uma especificação e um conjunto de bibliotecas para a criação de soluções de *pod networking*, ou seja, plugins para resolver o problema de comunicação entre os pods. - -Temos diversas solução de *pod networking* como *add-on*, cada qual com funcionalidades diferentes, tais como: [Flannel](https://github.com/coreos/flannel), [Calico](http://docs.projectcalico.org/), [Romana](http://romana.io), [Weave-net](https://www.weave.works/products/weave-net/), entre outros. - -É importante saber as caracteristicas de cada solução e como elas resolvem a comunicação entre os pods. - -Por exemplo, temos soluções que utilizam *eBPF* como é o caso do *Cilium*, ou ainda soluções que atuam na camada 3 ou na camada 7 do modelo de referencia OSI. - -Dito isso, a melhor coisa é você ler os detalhes de cada solução e entender qual a melhor antende suas necessidades. - -Eu gosto muito da **Weave-net** e será ela que iremos abordar durante o treinamento, na dúvida de qual usar, vá de **Weave-net**! :) - - -Para instalar o *Weave-net* execute o seguinte comando no nó *control plane*. - -``` -kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" -``` - -Para verificar se o *pod network* foi criado com sucesso, execute o seguinte comando. - -``` -kubectl get pods -n kube-system -``` - -O resultado deve ser semelhante ao mostrado a seguir. - -``` -NAMESPACE NAME READY STATUS RESTARTS AGE -kube-system coredns-6d4b75cb6d-vjtw5 1/1 Running 0 2m4s -kube-system coredns-6d4b75cb6d-xd89l 1/1 Running 0 2m4s -kube-system etcd-ip-172-31-19-147 1/1 Running 0 2m19s -kube-system kube-apiserver-ip-172-31-19-147 1/1 Running 0 2m18s -kube-system kube-controller-manager-ip-172-31-19-147 1/1 Running 0 2m18s -kube-system kube-proxy-djvp4 1/1 Running 0 103s -kube-system kube-proxy-f2f57 1/1 Running 0 2m5s -kube-system kube-proxy-tshff 1/1 Running 0 105s -kube-system kube-scheduler-ip-172-31-19-147 1/1 Running 0 2m18s -kube-system weave-net-4qfbb 2/2 Running 1 (22s ago) 28s -kube-system weave-net-htlrp 2/2 Running 1 (22s ago) 28s -kube-system weave-net-nltmv 2/2 Running 1 (21s ago) 28s - -``` - -Pode-se observar que há três contêineres do Weave-net em execução, um em cada nó do cluster, provendo a *pod networking* para o nosso *cluster*. - -#### Verificando a instalação - -Para verificar se a instalação está funcionando, e se os nós estão se comunicando, você pode executar o comando ``kubectl get nodes`` no nó control-plane, que deve lhe retornar algo como o conteúdo a seguir. - - -```bash -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -ip-172-31-19-147 Ready control-plane 2m20s v1.24.3 -ip-172-31-24-77 Ready 101s v1.24.3 -ip-172-31-25-32 Ready 103s v1.24.3 - -``` - -### Primeiros passos no k8s - -#### Exibindo informações detalhadas sobre os nós - -``` -kubectl describe node [nome_do_no] -``` - -Exemplo: - -``` -kubectl describe node ip-172-31-19-147 - -Name: ip-172-31-19-147 -Roles: control-plane -Labels: beta.kubernetes.io/arch=amd64 - beta.kubernetes.io/os=linux - kubernetes.io/arch=amd64 - kubernetes.io/hostname=ip-172-31-19-147 - kubernetes.io/os=linux - node-role.kubernetes.io/control-plane= - node.kubernetes.io/exclude-from-external-load-balancers= -Annotations: kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock - node.alpha.kubernetes.io/ttl: 0 - volumes.kubernetes.io/controller-managed-attach-detach: true -CreationTimestamp: Sun, 07 Aug 2022 07:05:52 +0000 -Taints: node-role.kubernetes.io/control-plane:NoSchedule - node-role.kubernetes.io/master:NoSchedule -Unschedulable: false -Lease: - HolderIdentity: ip-172-31-19-147 - AcquireTime: - RenewTime: Sun, 07 Aug 2022 08:10:33 +0000 -Conditions: - Type Status LastHeartbeatTime LastTransitionTime Reason Message - ---- ------ ----------------- ------------------ ------ ------- - NetworkUnavailable False Sun, 07 Aug 2022 07:07:56 +0000 Sun, 07 Aug 2022 07:07:56 +0000 WeaveIsUp Weave pod has set this - MemoryPressure False Sun, 07 Aug 2022 08:09:15 +0000 Sun, 07 Aug 2022 07:05:49 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available - DiskPressure False Sun, 07 Aug 2022 08:09:15 +0000 Sun, 07 Aug 2022 07:05:49 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure - PIDPressure False Sun, 07 Aug 2022 08:09:15 +0000 Sun, 07 Aug 2022 07:05:49 +0000 KubeletHasSufficientPID kubelet has sufficient PID available - Ready True Sun, 07 Aug 2022 08:09:15 +0000 Sun, 07 Aug 2022 07:07:58 +0000 KubeletReady kubelet is posting ready status. AppArmor enabled -Addresses: - InternalIP: 172.31.19.147 - Hostname: ip-172-31-19-147 -Capacity: - cpu: 2 - ephemeral-storage: 7950756Ki - hugepages-2Mi: 0 - memory: 4016852Ki - pods: 110 -Allocatable: - cpu: 2 - ephemeral-storage: 7327416718 - hugepages-2Mi: 0 - memory: 3914452Ki - pods: 110 -System Info: - Machine ID: 23fb437f79c4489ab1e351f42b69a52c - System UUID: ec2e1b61-092b-df48-4c41-f51d2f5e84d7 - Boot ID: 1e1ce6a2-3cf0-4961-be37-1f15ba5cd232 - Kernel Version: 5.13.0-1029-aws - OS Image: Ubuntu 20.04.4 LTS - Operating System: linux - Architecture: amd64 - Container Runtime Version: containerd://1.6.6 - Kubelet Version: v1.24.3 - Kube-Proxy Version: v1.24.3 -PodCIDR: 10.244.0.0/24 -PodCIDRs: 10.244.0.0/24 -Non-terminated Pods: (8 in total) -.... -``` - -##### Exibindo novamente token para adicionar um novo nó no cluster - -Para visualizar novamente o *token* para inserção de novos nós, execute o seguinte comando. - -``` -sudo kubeadm token create --print-join-command -``` - -##### Ativando o autocomplete - -Em distribuições Debian e baseadas, certifique-se que o pacote ``bash-completion`` esteja instalado. Instale-o com o comando a seguir. - -``` -sudo apt install -y bash-completion -``` - -Em sistemas Red Hat e baseados, execute: - -``` -sudo yum install -y bash-completion -``` - -Feito isso, execute o seguinte comando. - -``` -kubectl completion bash > /etc/bash_completion.d/kubectl -``` - -Efetue *logoff* e *login* para carregar o *autocomplete*. Caso não deseje, execute: - -``` -source <(kubectl completion bash) -``` - -##### Verificando os namespaces e pods - -O k8s organiza tudo dentro de *namespaces*. Por meio deles, podem ser realizadas limitações de segurança e de recursos dentro do *cluster*, tais como *pods*, *replication controllers* e diversos outros. Para visualizar os *namespaces* disponíveis no *cluster*, digite: - -``` -kubectl get namespaces - -NAME STATUS AGE -default Active 8d -kube-node-lease Active 8d -kube-public Active 8d -kube-system Active 8d -``` - -Vamos listar os *pods* do *namespace* **kube-system** utilizando o comando a seguir. - -``` -kubectl get pod -n kube-system - -NAME READY STATUS RESTARTS AGE -coredns-6d4b75cb6d-vjtw5 1/1 Running 0 106m -coredns-6d4b75cb6d-xd89l 1/1 Running 0 106m -etcd-ip-172-31-19-147 1/1 Running 0 106m -kube-apiserver-ip-172-31-19-147 1/1 Running 0 106m -kube-controller-manager-ip-172-31-19-147 1/1 Running 0 106m -kube-proxy-djvp4 1/1 Running 0 106m -kube-proxy-f2f57 1/1 Running 0 106m -kube-proxy-tshff 1/1 Running 0 106m -kube-scheduler-ip-172-31-19-147 1/1 Running 0 106m -weave-net-4qfbb 2/2 Running 1 (104m ago) 105m -weave-net-htlrp 2/2 Running 1 (104m ago) 105m -weave-net-nltmv 2/2 Running 1 (104m ago) 105m -``` - -Será que há algum *pod* escondido em algum *namespace*? É possível listar todos os *pods* de todos os *namespaces* com o comando a seguir. - -``` -kubectl get pods --all-namespaces -``` - -Há a possibilidade ainda, de utilizar o comando com a opção ```-o wide```, que disponibiliza maiores informações sobre o recurso, inclusive em qual nó o *pod* está sendo executado. Exemplo: - -``` -kubectl get pods --all-namespaces -o wide - -NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -kube-system coredns-6d4b75cb6d-vjtw5 1/1 Running 0 105m 10.32.0.3 ip-172-31-19-147 -kube-system coredns-6d4b75cb6d-xd89l 1/1 Running 0 105m 10.32.0.2 ip-172-31-19-147 -kube-system etcd-ip-172-31-19-147 1/1 Running 0 105m 172.31.19.147 ip-172-31-19-147 -kube-system kube-apiserver-ip-172-31-19-147 1/1 Running 0 105m 172.31.19.147 ip-172-31-19-147 -kube-system kube-controller-manager-ip-172-31-19-147 1/1 Running 0 105m 172.31.19.147 ip-172-31-19-147 -kube-system kube-proxy-djvp4 1/1 Running 0 105m 172.31.24.77 ip-172-31-24-77 -kube-system kube-proxy-f2f57 1/1 Running 0 105m 172.31.19.147 ip-172-31-19-147 -kube-system kube-proxy-tshff 1/1 Running 0 105m 172.31.25.32 ip-172-31-25-32 -kube-system kube-scheduler-ip-172-31-19-147 1/1 Running 0 105m 172.31.19.147 ip-172-31-19-147 -kube-system weave-net-4qfbb 2/2 Running 1 (103m ago) 103m 172.31.19.147 ip-172-31-19-147 -kube-system weave-net-htlrp 2/2 Running 1 (103m ago) 103m 172.31.25.32 ip-172-31-25-32 -kube-system weave-net-nltmv 2/2 Running 1 (103m ago) 103m 172.31.24.77 ip-172-31-24-77 -``` - -##### Executando nosso primeiro pod no k8s - -Iremos iniciar o nosso primeiro *pod* no k8s. Para isso, executaremos o comando a seguir. - -``` -kubectl run nginx --image nginx - -pod/nginx created -``` - -Listando os *pods* com ``kubectl get pods``, obteremos a seguinte saída. - -``` -NAME READY STATUS RESTARTS AGE -nginx 1/1 Running 0 66s -``` - -Vamos olhar agora a descrição desse objeto dentro do *cluster*. - -``` -kubectl describe pod nginx - -Name: nginx -Namespace: default -Priority: 0 -Node: ip-172-31-25-32/172.31.25.32 -Start Time: Sun, 07 Aug 2022 08:53:24 +0000 -Labels: run=nginx -Annotations: -Status: Running -IP: 10.40.0.1 -IPs: - IP: 10.40.0.1 -Containers: - nginx: - Container ID: containerd://d7ae9933e65477eed7ff04a107fb3a3adb6a634bc713282421bbdf0e1c30bf7b - Image: nginx - Image ID: docker.io/library/nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 - Port: - Host Port: - State: Running - Started: Sun, 07 Aug 2022 08:53:30 +0000 - Ready: True - Restart Count: 0 - Environment: - Mounts: - /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-tmjgq (ro) -Conditions: - Type Status - Initialized True - Ready True - ContainersReady True - PodScheduled True -Volumes: - kube-api-access-tmjgq: - Type: Projected (a volume that contains injected data from multiple sources) - TokenExpirationSeconds: 3607 - ConfigMapName: kube-root-ca.crt - ConfigMapOptional: - DownwardAPI: true -QoS Class: BestEffort -Node-Selectors: -Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s - node.kubernetes.io/unreachable:NoExecute op=Exists for 300s -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Scheduled 16s default-scheduler Successfully assigned default/nginx to ip-172-31-25-32 - Normal Pulling 16s kubelet Pulling image "nginx" - Normal Pulled 10s kubelet Successfully pulled image "nginx" in 5.387864178s - Normal Created 10s kubelet Created container nginx - Normal Started 10s kubelet Started container nginx - -``` - -##### Verificar os últimos eventos do cluster - -Você pode verificar quais são os últimos eventos do *cluster* com o comando ``kubectl get events``. Serão mostrados eventos como: o *download* de imagens do Docker Hub (ou de outro *registry* configurado), a criação/remoção de *pods*, etc. - -A saída a seguir mostra o resultado da criação do nosso contêiner com Nginx. - -``` -kubectl get events - -LAST SEEN TYPE REASON OBJECT MESSAGE -44s Normal Scheduled pod/nginx Successfully assigned default/nginx to ip-172-31-25-32 -44s Normal Pulling pod/nginx Pulling image "nginx" -38s Normal Pulled pod/nginx Successfully pulled image "nginx" in 5.387864178s -38s Normal Created pod/nginx Created container nginx -38s Normal Started pod/nginx Started container nginx - -``` - -No resultado do comando anterior é possível observar que a execução do nginx ocorreu no *namespace* default e que a imagem **nginx** não existia no repositório local e, sendo assim, teve de ser feito download da imagem. - - -##### Efetuar o dump de um objeto em formato YAML - -Assim como quando se está trabalhando com *stacks* no Docker Swarm, normalmente recursos no k8s são declarados em arquivos **YAML** ou **JSON** e depois manipulados através do ``kubectl``. - -Para nos poupar o trabalho de escrever o arquivo inteiro, pode-se utilizar como *template* o *dump* de um objeto já existente no k8s, como mostrado a seguir. - -``` -kubectl get pod nginx -o yaml > meu-primeiro.yaml -``` - -Será criado um novo arquivo chamado ``meu-primeiro.yaml``, resultante do redirecionamento da saída do comando ``kubectl get pod nginx -o yaml``. - -Abrindo o arquivo com ``vim meu-primeiro.yaml`` (você pode utilizar o editor que você preferir), teremos o seguinte conteúdo. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - creationTimestamp: "2022-08-07T08:53:24Z" - labels: - run: nginx - name: nginx - namespace: default - resourceVersion: "9598" - uid: d0928186-bf6d-459b-aca6-9b0d84b40e9c -spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - volumeMounts: - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: kube-api-access-tmjgq - readOnly: true - dnsPolicy: ClusterFirst - enableServiceLinks: true - nodeName: ip-172-31-25-32 - preemptionPolicy: PreemptLowerPriority - priority: 0 - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - tolerations: - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 300 - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 300 - volumes: - - name: kube-api-access-tmjgq - projected: - defaultMode: 420 - sources: - - serviceAccountToken: - expirationSeconds: 3607 - path: token - - configMap: - items: - - key: ca.crt - path: ca.crt - name: kube-root-ca.crt - - downwardAPI: - items: - - fieldRef: - apiVersion: v1 - fieldPath: metadata.namespace - path: namespace -status: - conditions: - - lastProbeTime: null - lastTransitionTime: "2022-08-07T08:53:24Z" - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: "2022-08-07T08:53:30Z" - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: "2022-08-07T08:53:30Z" - status: "True" - type: ContainersReady - - lastProbeTime: null - lastTransitionTime: "2022-08-07T08:53:24Z" - status: "True" - type: PodScheduled - containerStatuses: - - containerID: containerd://d7ae9933e65477eed7ff04a107fb3a3adb6a634bc713282421bbdf0e1c30bf7b - image: docker.io/library/nginx:latest - imageID: docker.io/library/nginx@sha256:ecc068890de55a75f1a32cc8063e79f90f0b043d70c5fcf28f1713395a4b3d49 - lastState: {} - name: nginx - ready: true - restartCount: 0 - started: true - state: - running: - startedAt: "2022-08-07T08:53:30Z" - hostIP: 172.31.25.32 - phase: Running - podIP: 10.40.0.1 - podIPs: - - ip: 10.40.0.1 - qosClass: BestEffort - startTime: "2022-08-07T08:53:24Z" -``` - -Observando o arquivo anterior, notamos que este reflete o **estado** do *pod*. Nós desejamos utilizar tal arquivo apenas como um modelo, e sendo assim, podemos apagar as entradas que armazenam dados de estado desse *pod*, como *status* e todas as demais configurações que são específicas dele. O arquivo final ficará com o conteúdo semelhante a este: - -```yaml - apiVersion: v1 - kind: Pod - metadata: - labels: - run: nginx - name: nginx - spec: - containers: - - image: nginx - name: nginx - resources: {} - dnsPolicy: ClusterFirst - restartPolicy: Always - status: {} -``` - -Vamos agora remover o nosso *pod* com o seguinte comando. - -``` -kubectl delete pod nginx -``` - -A saída deve ser algo como: - -``` -pod "nginx" deleted -``` - -Vamos recriá-lo, agora a partir do nosso arquivo YAML. - -``` -kubectl create -f meu-primeiro.yaml - -pod/nginx created -``` - -Observe que não foi necessário informar ao ``kubectl`` qual tipo de recurso seria criado, pois isso já está contido dentro do arquivo. - -Listando os *pods* disponíveis com o seguinte comando. - -``` -kubectl get pods -``` - -Deve-se obter uma saída similar à esta: - -``` -NAME READY STATUS RESTARTS AGE -nginx 1/1 Running 0 109s -``` - -Uma outra forma de criar um arquivo de *template* é através da opção ``--dry-run`` do ``kubectl``, com o funcionamento ligeiramente diferente dependendo do tipo de recurso que será criado. Exemplos: - -Para a criação do template de um *pod*: - -``` -kubectl run meu-nginx --image nginx --dry-run=client -o yaml > pod-template.yaml -``` - -Para a criação do *template* de um *deployment*: - -``` -kubectl create deployment meu-nginx --image=nginx --dry-run=client -o yaml > deployment-template.yaml -``` - -A vantagem deste método é que não há a necessidade de limpar o arquivo, além de serem apresentadas apenas as opções necessárias do recurso. - -#### Socorro, são muitas opções! - -Calma, nós sabemos. Mas o ``kubectl`` pode lhe auxiliar um pouco em relação a isso. Ele contém a opção ``explain``, que você pode utilizar caso precise de ajuda com alguma opção em específico dos arquivos de recurso. A seguir alguns exemplos de sintaxe. - -``` -kubectl explain [recurso] - -kubectl explain [recurso.caminho.para.spec] - -kubectl explain [recurso.caminho.para.spec] --recursive -``` - -Exemplos: - -``` -kubectl explain deployment - -kubectl explain pod --recursive - -kubectl explain deployment.spec.template.spec -``` - -#### Expondo o pod e criando um Service - -Dispositivos fora do *cluster*, por padrão, não conseguem acessar os *pods* criados, como é comum em outros sistemas de contêineres. Para expor um *pod*, execute o comando a seguir. - -``` -kubectl expose pod nginx -``` - -Será apresentada a seguinte mensagem de erro: - -``` -error: couldn't find port via --port flag or introspection -See 'kubectl expose -h' for help and examples -``` - -O erro ocorre devido ao fato do k8s não saber qual é a porta de destino do contêiner que deve ser exposta (no caso, a 80/TCP). Para configurá-la, vamos primeiramente remover o nosso *pod* antigo: - -``` -kubectl delete -f meu-primeiro.yaml -``` - -Abra agora o arquivo ``meu-primeiro.yaml`` e adicione o bloco a seguir. - -```yaml -... -spec: - containers: - - image: nginx - imagePullPolicy: Always - ports: - - containerPort: 80 - name: nginx - resources: {} -... -``` - -> **Atenção!!!** Arquivos YAML utilizam para sua tabulação dois espaços e não *tab*. - -Feita a modificação no arquivo, salve-o e crie novamente o *pod* com o comando a seguir. - -``` -kubectl create -f meu-primeiro.yaml - -pod/nginx created -``` - -Liste o pod. - -``` -kubectl get pod nginx - -NAME READY STATUS RESTARTS AGE -nginx 1/1 Running 0 32s -``` - -O comando a seguir cria um objeto do k8s chamado de *Service*, que é utilizado justamente para expor *pods* para acesso externo. - -``` -kubectl expose pod nginx -``` - -Podemos listar todos os *services* com o comando a seguir. - -``` -kubectl get services - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 8d -nginx ClusterIP 10.105.41.192 80/TCP 2m30s -``` - -Como é possível observar, há dois *services* no nosso *cluster*: o primeiro é para uso do próprio k8s, enquanto o segundo foi o quê acabamos de criar. Utilizando o ``curl`` contra o endereço IP mostrado na coluna *CLUSTER-IP*, deve nos ser apresentada a tela principal do Nginx. - -``` -curl 10.105.41.192 - - - - -Welcome to nginx! - - - -

Welcome to nginx!

-

If you see this page, the nginx web server is successfully installed and -working. Further configuration is required.

- -

For online documentation and support please refer to -nginx.org.
-Commercial support is available at -nginx.com.

- -

Thank you for using nginx.

- - -``` - -Este *pod* está disponível para acesso a partir de qualquer nó do *cluster*. - - -#### Limpando tudo e indo para casa - -Para mostrar todos os recursos recém criados, pode-se utilizar uma das seguintes opções a seguir. - -``` -kubectl get all - -kubectl get pod,service - -kubectl get pod,svc -``` - -Note que o k8s nos disponibiliza algumas abreviações de seus recursos. Com o tempo você irá se familiar com elas. Para apagar os recursos criados, você pode executar os seguintes comandos. - -``` -kubectl delete -f meu-primeiro.yaml - -kubectl delete service nginx -``` - -Liste novamente os recursos para ver se os mesmos ainda estão presentes. diff --git a/pt/old/day_one/extras-day1.md b/pt/old/day_one/extras-day1.md deleted file mode 100644 index c49bf3eb..00000000 --- a/pt/old/day_one/extras-day1.md +++ /dev/null @@ -1,42 +0,0 @@ -### Múltiplas Interfaces - -Caso algum dos nós que será utilizado tenha mais de uma interface de rede, verifique se ele consegue alcançar o `service` do `Kubernetes` através da rota padrão. - -Para verificar, será necessário pegar o IP interno do `service` Kubernetes através do comando ``kubectl get services kubernetes``. Após obter o IP, basta ir no nó que será ingressado no cluster e rodar o comando ``curl -k https://SERVICE`` alterando o `SERVICE` para o IP do `service`. Exemplo: ``curl -k https://10.96.0.1``. - -Caso a saída seja algo parecido com o exemplo a seguir, a conexão está acontecendo normalmente. - -```json -{ - "kind": "Status", - "apiVersion": "v1", - "metadata": { - - }, - "status": "Failure", - "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"", - "reason": "Forbidden", - "details": { - - }, - "code": 403 -} -``` - -Caso a saída não seja parecido com o exemplo, será necessário adicionar uma rota com o seguinte comando. - -```shell -ip route add REDE_DO_SERVICE/16 dev INTERFACE -``` - -Substitua a `REDE_DO SERVICE` com a rede do `service` (geralmente é um IP finalizando com 0). - -Exemplo: Se o IP for `10.96.0.1` a rede é `10.96.0.0`) e a `INTERFACE` com a interface do nó que tem acesso ao `control-plane` do cluster. - -Exemplo de comando para adicionar uma rota: - -``` -sudo ip route add 10.96.0.0/16 dev eth1 -``` - -Adicione a rota nas configurações de rede para que seja criada durante o boot. \ No newline at end of file diff --git a/pt/old/day_six/descomplicando_kubernetes.md b/pt/old/day_six/descomplicando_kubernetes.md deleted file mode 100644 index 2c589bec..00000000 --- a/pt/old/day_six/descomplicando_kubernetes.md +++ /dev/null @@ -1,566 +0,0 @@ - -# Descomplicando Kubernetes Day 6 - -## Sumário - -- [Security Context](#security-context) - - [Utilizando o security Context](#utilizando-o-security-context) - - [Capabilities](#capabilities) -- [Manutenção do Cluster ETCD](#manutenção-do-cluster-etcd) - - [O que preciso saber antes de começar?](#o-que-preciso-saber-antes-de-começar) - - [O que é o ETCD?](#o-que-é-o-etcd) - - [ETCD no Kubernetes](#etcd-no-kubernetes) - - [Certificados ETCD](#certificados-etcd) - - [Interagindo com o ETCD](#interagindo-com-o-etcd) - - [Backup do ETCD no Kubernetes](#backup-do-etcd-no-kubernetes) -- [Dicas para os exames](#dicas-para-os-exames) - -# Security Context - -**Security Context** são um conjunto de configurações onde definimos privilégios e acessos a um pod. Essas configurações incluem: - -* Definir o usuário e grupo do contêiner; -* Se o contêiner será um contêiner privilegiado; -* Linux Capabilities; -* Se o contêiner pode escalar privilégios; -* Utilizar SELinux/APPArmor. - -## Utilizando o security Context - -Para utilizar essa configuração precisamos incluir o bloco ``securityCotext`` no manifesto do pod. - -Primeiro vamos definir um usuário e grupo para nosso contêiner através das *flags* ``runAsUser`` e ``runAsGroup``. O usuário e grupo devem ser informados por ``UID``. Exemplo: ``1000``. - -Crie um arquivo ```busy-security-user.yaml```: - -``` -vim busy-security-user.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busy-security-user -spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - containers: - - name: sec-busy - image: busybox - command: [ "sh", "-c", "sleep 1h" ] -``` - -No exemplo anterior utilizamos o user/group ID ``1000`` para o contêiner. - -Crie o pod: - -``` -kubectl create -f busy-security-user.yaml - -pod/busy-security-user created -``` - -Vamos executar o comando a seguir para verificar com o ``id`` nosso usuário e grupo. - -``` -kubectl exec busy-security-user -- id - -uid=1000 gid=1000 -``` - -As configurações de ``securityContext`` definidas no contêiner são aplicadas somente a ele, já se são definidas no bloco ``securityContext`` fora de ``containers`` será aplicada para todos contêineres no manifesto. - -Crie um arquivo ```busy-security-uid.yaml```: - -``` -vim busy-security-uid.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busy-security-uid -spec: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - containers: - - name: sec-busy - image: busybox - securityContext: - runAsUser: 2000 - runAsGroup: 2000 - command: [ "sh", "-c", "sleep 1h" ] -``` - -Crie o pod: - -``` -kubectl create -f busy-security-uid.yaml - -pod/busy-security-uid created -``` - -Verifique novamente o ``id`` nosso usuário e grupo. - -``` -kubectl exec busy-security-uid -- id - -uid=2000 gid=1000 -``` - -As configurações declaradas em contêineres sempre serão prioritárias e irão sobrescrever as demais. - -## Capabilities - -Nos sistemas UNIX existem basicamente duas categorias de processos: **processos privilegiados** que são executados como o ``UID 0`` (``root`` ou superusuario) e os **não privilegiados** que possuem o ``UID`` **diferente** de ``0``. - -Os processos privilegiados dão *bypass* em todas as verificações do kernel. Já os processos não-privilegiados passam por algumas checagens como ``UID``, ``GID`` e ``ACLS``. - -Começando no kernel 2.2, o GNU/Linux dividiu as formas tradicionais de privilégios associados ao superusuários em unidades diferentes, agora conhecidas como ``capabilities``, que podem ser habilitadas e desabilitadas independentemente umas das outras. Essas capacidades são atribuídas por thread. - -Um pouco mais sobre capabilities está disponível na página: http://man7.org/linux/man-pages/man7/capabilities.7.html - -Para demonstrar, vamos fazer um teste tentando alterar a hora de um contêiner. - -Crie um arquivo ```busy-security-cap.yaml```: - -``` -vim busy-security-cap.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busy-security-cap -spec: - containers: - - name: sec-busy - image: busybox - command: [ "sh", "-c", "sleep 1h" ] -``` - -Crie o pod: - -``` -kubectl create -f busy-security-cap.yaml - -pod/busy-security-cap created -``` - -Verifique a hora do contêiner: - -``` -kubectl exec busy-security-cap -- date -s "18:00:00" - -date: can't set date: Operation not permitted -``` - -Adicionando a capabilitie ``SYS_TIME`` no contêiner: - -``` -vim busy-security-cap.yaml -``` - -Altere o arquivo com o conteúdo a seguir: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: busy-security-cap -spec: - containers: - - name: sec-busy - image: busybox - securityContext: - capabilities: - add: ["SYS_TIME"] - command: [ "sh", "-c", "sleep 1h" ] -``` - -Delete o pod e recrie novamente: - -``` -kubectl delete -f busy-security-cap.yaml - -pod "busy-security-cap" deleted - -kubectl create -f busy-security-cap.yaml - -pod/busy-security-cap created -``` - -Verifique novamente a hora do contêiner: - -``` -kubectl exec busy-security-cap -- date -s "18:00:00" - -Sat May 16 18:00:00 UTC 2020 -``` - - -# Manutenção do Cluster ETCD - -## O que preciso saber antes de começar? - -ETCD é um dos componentes fundamentais que fazem o Kubernetes funcionar. - -## O que é o ETCD? - -Basicamente, o ETCD é um database de armazenamento de chave-valor de alta disponibilidade. - -Em um banco de dados relacional, nós temos colunas e dentro das colunas nós temos o tipo de informação que está sendo armazenada; - -| ![Banco de dados relacional](../../images/relational-database-chart.jpg) | -|:---------------------------------------------------------------------------------------------:| -| *Banco de dados relacional [Ref: hswstatic.com](https://cdn.hswstatic.com/gif/relational-database-chart.jpg)* | - -Em um banco de dados de chave-valor, quando consultamos e obtemos a chave, é retornado o valor atribuido à aquela chave. - -| ![Banco de dados chave valor](../../images/KeyValue.png) | -|:---------------------------------------------------------------------------------------------:| -| *Banco de dados chave-valor [Ref: Wikimedia.org](https://upload.wikimedia.org/wikipedia/commons/5/5b/KeyValue.PNG)* | - -Quando consultamos a chave ``k1``, o resultado retornado é o valor: ``AAA,BBB,CCC`` - -Quando consultamos a chave ``k5``, o resultado retornado é o valor: ``3,ZZZ,5623`` - -## ETCD no Kubernetes - -No kubernetes, o ETCD é responsável por registrar todo tipo de informação do cluster, tais como: ``nodes``, ``roles``, ``pods``, ``configs``, ``accounts``, ``secrets``, etc. - -Quando o cluster é iniciado pelo ***kubeadm***, um pod do ``etcd`` é criado no node ``master``. - -Toda informação que é apresentada ao usuário quando executado o comando ``kubect get`` são informações armazenadas no ETCD. - -Vejamos se o *pod etcd* foi criado com sucesso com o seguinte comando. - -``` -kubectl get pods -n kube-system - -NAME READY STATUS RESTARTS AGE -coredns-66bff467f8-pfm2c 1/1 Running 0 8d -coredns-66bff467f8-s8pk4 1/1 Running 0 8d -etcd-docker-01 1/1 Running 0 8d -kube-apiserver-docker-01 1/1 Running 0 8d -kube-controller-manager-docker-01 1/1 Running 0 8d -kube-proxy-mdcgf 1/1 Running 0 8d -kube-proxy-q9cvf 1/1 Running 0 8d -kube-proxy-vf8mq 1/1 Running 0 8d -kube-scheduler-docker-01 1/1 Running 0 8d -weave-net-7dhpf 2/2 Running 0 8d -weave-net-fvttp 2/2 Running 0 8d -weave-net-xl7km 2/2 Running 0 8d -``` - -## Certificados ETCD - -O ETCD, como os demais serviços do Kubernetes, utilizam certificados PKI para autenticação sobre TLS, essas chaves são declaradas no manifesto de configuração em: - -``` -kubectl describe pod etcd-docker-01 -n kube-system -``` - -Parâmetros: - -``` ---cert-file ---key-file ---trusted-ca-file -``` - -Essas chaves vão ser utilizadas pelos demais componentes do cluster como, por exemplo, o **API Server** possam conectar e fazerem alterações. - -``` -kubectl describe pod kube-apiserver -n kube-system -``` - -Parâmetros: - -``` ---etcd-cafile ---etcd-certfile ---etcd-keyfile -``` - -Então, para toda e qualquer interação com o ETCD vamos precisar utilizar esses certificados para nos autenticar. - -## Interagindo com o ETCD - -Para interagir com o ETCD vamos precisar o ``etcdctl`` ou utilizar o próprio contêiner do etcd com o comando ```kubectl exec``` - -Referência: https://github.com/etcd-io/etcd/tree/master/etcdctl - -Baixando a ultima versão do etcd: - -GNU/Linux: - -``` -ETCD_VER=v3.4.7 - -GOOGLE_URL=https://storage.googleapis.com/etcd - -GITHUB_URL=https://github.com/etcd-io/etcd/releases/download - -DOWNLOAD_URL=${GOOGLE_URL} - -rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz - -rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test - -curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz - -tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1 - -rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz - -/tmp/etcd-download-test/etcd --version - -/tmp/etcd-download-test/etcdctl version -``` - -Referência: https://github.com/etcd-io/etcd/releases - -Como vimos anteriormente, vamos precisar utilizar os certificados para nos autenticar. Vamos fornecer os dados nos seguintes parâmetros no comando: - -``` ---cacert ---key ---cert -``` - -Além disso vamos precisar do endpoint, caso esteja no contêiner do ETCD seu endpoint será ``127.0.0.1:2379``. - -A sua URL para o endpoint vai estar na flag ```--advertise-client-urls``` nas configurações do ETCD. - -ETCDCTL: - -``` -ETCDCTL_API=3 etcdctl \ ---cacert /var/lib/minikube/certs/etcd/ca.crt \ ---key /var/lib/minikube/certs/etcd/server.key \ ---cert /var/lib/minikube/certs/etcd/server.crt \ ---endpoints $ADVERTISE_URL \ -get / --prefix --keys-only -``` - -O comando ``kubectl exec`` ficará similar ao mostrado a seguir. - -``` -kubectl exec -it etcd-minikube -n kube-system \ --- etcdctl --endpoints=https://127.0.0.1:2379 \ ---cacert=/var/lib/minikube/certs/etcd/ca.crt \ ---key=/var/lib/minikube/certs/etcd/server.key \ ---cert=/var/lib/minikube/certs/etcd/server.crt get / --prefix --keys-only -``` - -Output: - -``` -/registry/apiregistration.k8s.io/apiservices/v1. - -/registry/apiregistration.k8s.io/apiservices/v1.admissionregistration.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.apiextensions.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.apps - -/registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.autoscaling - -/registry/apiregistration.k8s.io/apiservices/v1.batch - -/registry/apiregistration.k8s.io/apiservices/v1.coordination.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.scheduling.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io - -/registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io -``` - -Aqui temos uma parte do conteúdo da  resposta do get no ``/`` do ETCD, onde listamos todas as chaves do etcd. - -Em um exemplo um pouco mais prático, vamos listar apenas as chaves dos pods no namespace ``default``. O parâmetro para que o output contenha apenas as chaves é ```--keys-only```. - -``` -kubectl exec -it etcd-minikube -n kube-system \ --- etcdctl --endpoints=https://127.0.0.1:2379 \ ---cacert=/var/lib/minikube/certs/etcd/ca.crt \ ---key=/var/lib/minikube/certs/etcd/server.key \ ---cert=/var/lib/minikube/certs/etcd/server.crt get /registry/pods/default \ ---prefix=true --keys-only -``` - -Output: - -``` -/registry/pods/default/nginx -``` - -Agora vamos ver os valores contidos na chave ``/registry/pods/default/nginx``, onde estão as configurações do pod. Vamos remover o parâmetro ```--keys-only``` para que possamos ver os valores da chave. - -``` -kubectl exec -it etcd-minikube -n kube-system \ --- etcdctl --endpoints=https://127.0.0.1:2379 \ ---cacert=/var/lib/minikube/certs/etcd/ca.crt \ ---key=/var/lib/minikube/certs/etcd/server.key \ ---cert=/var/lib/minikube/certs/etcd/server.crt get /registry/pods/default/nginx \ ---prefix=true -``` - -Output: - -``` -k8s - -v1Pod - -nginxdefault"*$a748750e-7582-4db5-ab63-0fab1d0c91542Z - -runnginxz -kubectlUpdatev����FieldsV1:� -�{"f:metadata":{"f:labels":{".":{},"f:run":{}}},"f:spec":{"f:containers":{"k:{\"name\":\"nginx\"}":{".":{},"f:image":{},"f:imagePullPolicy":{},"f:name":{},"f:resources":{},"f:terminationMessagePath":{},"f:terminationMessagePolicy":{}}},"f:dnsPolicy":{},"f:enableServiceLinks":{},"f:restartPolicy":{},"f:schedulerName":{},"f:securityContext":{},"f:terminationGracePeriodSeconds":{}}}�� -kubeletUpdatev����FieldsV1:� -�{"f:status":{"f:conditions":{"k:{\"type\":\"ContainersReady\"}":{".":{},"f:lastProbeTime":{},"f:lastTransitionTime":{},"f:status":{},"f:type":{}},"k:{\"type\":\"Initialized\"}":{".":{},"f:lastProbeTime":{},"f:lastTransitionTime":{},"f:status":{},"f:type":{}},"k:{\"type\":\"Ready\"}":{".":{},"f:lastProbeTime":{},"f:lastTransitionTime":{},"f:status":{},"f:type":{}}},"f:containerStatuses":{},"f:hostIP":{},"f:phase":{},"f:podIP":{},"f:podIPs":{".":{},"k:{\"ip\":\"172.17.0.5\"}":{".":{},"f:ip":{}}},"f:startTime":{}}}� -1 -default-token-657qb2 -default-token-657qb�� -nginxnginx*BJJ -default-token-657qb-/var/run/secrets/kubernetes.io/serviceaccount"2j/dev/termination-logrAlways����FileAlways 2 - -ClusterFirstBdefaultJdefaultminikubeX`hr���default-scheduler�6 -node.kubernetes.io/not-readyExists" NoExecute(��8 -node.kubernetes.io/unreachableExists" NoExecute(����� -Running# - -InitializedTru����*2 -ReadyTru����*2' -ContainersReadyTru����*2$ - -PodScheduledTru����*2"* - 192.168.64.22 -172.17.0.����B� -nginx - - -���� (2 - nginx:latest:_docker-pullable://nginx@sha256:86ae264c3f4acb99b2dee4d0098c40cb8c46dcf9e1148f05d3a51c4df6758c12BIdocker://4f42eaab397e862432c01d66d44b6e2d395ffae5e5dd16cfb83d906b3fc5022bHJ -BestEffortZb - - -172.17.0.5" -``` - -Isso foi um pouco de como podemos interagir diretamente com o ETCD. - -## Backup do ETCD no Kubernetes - -Como sabemos, o ETCD é responsável por armazenar todo tipo de informação sobre o estado do nosso cluster. - -Para realizarmos o backup (snapshot) do ETCD, precisamos utilizar alguns comandos *built-in* que já vem com o próprio ETCD. - -Esse snapshot, contém todos os dados do estado do cluster. - -Para realizar o snapshot do ETCD sem a autenticação **TLS habilitado**, precisamos executar o seguinte comando. - -``` -ETCDCTL_API=3 etcdctl \ ---endpoints $ENDPOINT \ -snapshot save snapshot.db -``` - -Visualizando o status. - -``` -ETCDCTL_API=3 etcdctl \ ---write-out=table \ -snapshot status snapshot.db -``` - -Output: - -``` -+----------+----------+------------+------------+ -| HASH | REVISION | TOTAL KEYS | TOTAL SIZE | -+----------+----------+------------+------------+ -| fe01cf57 | 10 | 7 | 2.1 MB | -+----------+----------+------------+------------+ -``` - -Existem algumas diferenças ao realizar o snapshot do ETCD com o **TLS habilitado** que são obrigatórias: - -Além do ``--endpoits``, precisamos adicionar as chaves e certificados referentes ao TLS que são: - -* ``--cacert`` - verifica os certificados dos servidores que estão com TLS habilitados; -* ``--cert`` - identifica o cliente usando o certificado TLS; -* ``--endpoints=[127.0.0.1:2379]`` - novamente, esse é o valor padrão de onde o ETCD está rodando no nó master com a porta padrão do ETCD, 2379 - TCP; -* ``--key`` - identifica o cliente usando a chave TLS; - -Logo, o comando ficará assim: - -``` -ETCDCTL_API=3 etcdctl \ ---cacert /var/lib/minikube/certs/etcd/ca.crt \ ---key /var/lib/minikube/certs/etcd/server.key \ ---cert /var/lib/minikube/certs/etcd/server.crt \ ---endpoints [127.0.0.1:2379] \ -snapshot save snapshot.db -``` - -# Dicas para os exames - -Para a prova do CKA é bem relevante saber como o ETCD funciona. - -O assunto do ETCD está relacionado aos 11% do Cluster Maintenance. - -Porém, pode ser que você seja obrigado a salvar esse **snapshot** em um diretório específico. Exemplo: ``/tmp/``. - -Com isso, o comando ficaria assim: - -``` -ETCDCTL_API=3 etcdctl \ ---cacert /var/lib/minikube/certs/etcd/ca.crt \ ---key /var/lib/minikube/certs/etcd/server.key \ ---cert /var/lib/minikube/certs/etcd/server.crt \ ---endpoints [127.0.0.1:2379] \ -snapshot save /tmp/snapshot.db -``` - -Para fazer o restore usando o arquivo de backup /tmp/snapshot.db podemos executar os seguintes comandos: - -``` -ETCDCTL_API=3 etcdctl \ ---cacert /var/lib/minikube/certs/etcd/ca.crt \ ---key /var/lib/minikube/certs/etcd/server.key \ ---cert /var/lib/minikube/certs/etcd/server.crt \ ---endpoints 127.0.0.1:2379 \ -snapshot restore /tmp/snapshot.db - -sudo mv /var/lib/etcd/member /var/lib/etcd/member.old -sudo mv /var/lib/etcd/default.etcd/member /var/lib/etcd/ -``` diff --git a/pt/old/day_three/descomplicando_kubernetes.md b/pt/old/day_three/descomplicando_kubernetes.md deleted file mode 100644 index cea0150a..00000000 --- a/pt/old/day_three/descomplicando_kubernetes.md +++ /dev/null @@ -1,1540 +0,0 @@ -# Descomplicando Kubernetes dia 3 - -## Sumário - -- [Descomplicando Kubernetes dia 3](#descomplicando-kubernetes-dia-3) - - [Sumário](#sumário) -- [Deployments](#deployments) - - [Filtrando por Labels](#filtrando-por-labels) - - [Node Selector](#node-selector) - - [Kubectl Edit](#kubectl-edit) -- [ReplicaSet](#replicaset) -- [DaemonSet](#daemonset) -- [Rollouts e Rollbacks](#rollouts-e-rollbacks) - -# Deployments - -O **Deployment** é um recurso com a responsabilidade de instruir o Kubernetes a criar, atualizar e monitorar a saúde das instâncias de suas aplicações. - -Um Deployment é o responsável por gerenciar o seu **ReplicaSet** (que iremos falar logo menos), ou seja, o Deployment é quem vai determinar a configuração de sua aplicação e como ela será implementada. O Deployment é o **controller** que irá cuidar, por exemplo, uma instância de sua aplicação por algum motivo for interrompida. O **Deployment controller** irá identificar o problema com a instância e irá criar uma nova em seu lugar. - -Quando você utiliza o ``kubectl create deployment``, você está realizando o deploy de um objeto chamado **Deployment**. Como outros objetos, o Deployment também pode ser criado através de um arquivo [YAML](https://en.wikipedia.org/wiki/YAML) ou de um [JSON](https://www.json.org/json-en.html), conhecidos por **manifestos**. - -Se você deseja alterar alguma configuração de seus objetos, como o pod, você pode utilizar o ``kubectl apply``, através de um manifesto, ou ainda através do ``kubectl edit``. Normalmente, quando você faz uma alteração em seu Deployment, é criado uma nova versão do ReplicaSet, esse se tornando o ativo e fazendo com que seu antecessor seja desativado. As versões anteriores dos ReplicaSets são mantidas, possibilitando o _rollback_ em caso de falhas. - -As **labels** são importantes para o gerenciamento do cluster, pois com elas é possível buscar ou selecionar recursos em seu cluster, fazendo com que você consiga organizar em pequenas categorias, facilitando assim a sua busca e organizando seus pods e seus recursos do cluster. As labels não são recursos do API server, elas são armazenadas no metadata em formato chave-valor. - -Antes nos tínhamos somente o RC, _Replication Controller_, que era um controle sobre o número de réplicas que determinado pod estava executando, o problema é que todo esse gerenciamento era feito do lado do *client*. Para solucionar esse problema, foi adicionado o objeto Deployment, que permite a atualização pelo lado do *server*. **Deployments** geram **ReplicaSets**, que oferecerem melhores opções do que o **ReplicationController**, e por esse motivo está sendo substituído. - -Podemos criar nossos deployments a partir do template: - -``` -kubectl create deployment --dry-run=client -o yaml --image=nginx nginx-template > primeiro-deployment-template.yaml -kubectl create -f primeiro-deployment-template.yaml -``` - -Vamos criar os nossos primeiros Deployments: -``` -vim primeiro-deployment.yaml -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: nginx - app: giropops - name: primeiro-deployment - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - run: nginx - template: - metadata: - labels: - run: nginx - dc: UK - spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx2 - ports: - - containerPort: 80 - protocol: TCP - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 -``` - -Vamos criar o deployment a partir do manifesto: - -``` -kubectl create -f primeiro-deployment.yaml - -deployment.extensions/primeiro-deployment created -``` - -Crie um segundo deployment: - -``` -vim segundo-deployment.yaml -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: nginx - name: segundo-deployment - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - run: nginx - template: - metadata: - labels: - run: nginx - dc: Netherlands - spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx2 - ports: - - containerPort: 80 - protocol: TCP - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 -``` - -Vamos criar o deployment a partir do manifesto: - -``` -kubectl create -f segundo-deployment.yaml - -deployment.extensions/segundo-deployment created -``` - -Visualizando os deployments: - -``` -kubectl get deployment - -NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE -primeiro-deployment 1 1 1 1 6m -segundo-deployment 1 1 1 1 1m -``` - -Visualizando os pods: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -primeiro-deployment-68c9dbf8b8-kjqpt 1/1 Running 0 19s -segundo-deployment-59db86c584-cf9pp 1/1 Running 0 15s -``` - -Visualizando os detalhes do ``pod`` criado a partir do **primeiro deployment**: - -``` -kubectl describe pod primeiro-deployment-68c9dbf8b8-kjqpt - -Name: primeiro-deployment-68c9dbf8b8-kjqpt -Namespace: default -Priority: 0 -PriorityClassName: -Node: elliot-02/10.138.0.3 -Start Time: Sat, 04 Aug 2018 00:45:29 +0000 -Labels: dc=UK - pod-template-hash=2475869464 - run=nginx -Annotations: -Status: Running -IP: 10.46.0.1 -Controlled By: ReplicaSet/primeiro-deployment-68c9dbf8b8 -Containers: - nginx2: - Container ID: docker://963ec997a0aa4aa3cecabdb3c59f67d80e7010c51eac23735524899f7f2dd4f9 - Image: nginx - Image ID: docker-pullable://nginx@sha256:d85914d547a6c92faa39ce7058bd7529baacab7e0cd4255442b04577c4d1f424 - Port: 80/TCP - Host Port: 0/TCP - State: Running - Started: Sat, 04 Aug 2018 00:45:36 +0000 - Ready: True - Restart Count: 0 - Environment: - Mounts: - /var/run/secrets/kubernetes.io/serviceaccount from default-token-np77m (ro) -Conditions: - Type Status - Initialized True - Ready True - ContainersReady True - PodScheduled True -Volumes: - default-token-np77m: - Type: Secret (a volume populated by a Secret) - SecretName: default-token-np77m - Optional: false -QoS Class: BestEffort -Node-Selectors: -Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s - node.kubernetes.io/unreachable:NoExecute for 300s -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Scheduled 51s default-scheduler Successfully assigned default/primeiro-deployment-68c9dbf8b8-kjqpt to elliot-02 - Normal Pulling 50s kubelet, elliot-02 pulling image "nginx" - Normal Pulled 44s kubelet, elliot-02 Successfully pulled image "nginx" - Normal Created 44s kubelet, elliot-02 Created container - Normal Started 44s kubelet, elliot-02 Started container -``` - -Visualizando os detalhes do ``pod`` criado a partir do **segundo deployment**: - -``` -kubectl describe pod segundo-deployment-59db86c584-cf9pp - -Name: segundo-deployment-59db86c584-cf9pp -Namespace: default -Priority: 0 -PriorityClassName: -Node: elliot-02/10.138.0.3 -Start Time: Sat, 04 Aug 2018 00:45:49 +0000 -Labels: dc=Netherlands - pod-template-hash=1586427140 - run=nginx -Annotations: -Status: Running -IP: 10.46.0.2 -Controlled By: ReplicaSet/segundo-deployment-59db86c584 -Containers: - nginx2: - Container ID: docker://a9e6b5463341e62eff9e45c8c0aace14195f35e41be088ca386949500a1f2bb0 - Image: nginx - Image ID: docker-pullable://nginx@sha256:d85914d547a6c92faa39ce7058bd7529baacab7e0cd4255442b04577c4d1f424 - Port: 80/TCP - Host Port: 0/TCP - State: Running - Started: Sat, 04 Aug 2018 00:45:51 +0000 - Ready: True - Restart Count: 0 - Environment: - Mounts: - /var/run/secrets/kubernetes.io/serviceaccount from default-token-np77m (ro) -Conditions: - Type Status - Initialized True - Ready True - ContainersReady True - PodScheduled True -Volumes: - default-token-np77m: - Type: Secret (a volume populated by a Secret) - SecretName: default-token-np77m - Optional: false -QoS Class: BestEffort -Node-Selectors: -Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s - node.kubernetes.io/unreachable:NoExecute for 300s -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal Scheduled 2m default-scheduler Successfully assigned default/segundo-deployment-59db86c584-cf9pp to elliot-02 - Normal Pulling 2m kubelet, elliot-02 pulling image "nginx" - Normal Pulled 2m kubelet, elliot-02 Successfully pulled image "nginx" - Normal Created 2m kubelet, elliot-02 Created container - Normal Started 2m kubelet, elliot-02 Started container -``` - -Visualizando os detalhes do **primeiro deployment**: - -``` -kubectl describe deployment primeiro-deployment - -Name: primeiro-deployment -Namespace: default -CreationTimestamp: Sat, 04 Aug 2018 00:45:29 +0000 -Labels: app=giropops - run=nginx -Annotations: deployment.kubernetes.io/revision=1 -Selector: run=nginx -Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable -StrategyType: RollingUpdate -MinReadySeconds: 0 -RollingUpdateStrategy: 1 max unavailable, 1 max surge -Pod Template: - Labels: dc=UK - run=nginx - Containers: - nginx2: - Image: nginx - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Conditions: - Type Status Reason - ---- ------ ------ - Available True MinimumReplicasAvailable - Progressing True NewReplicaSetAvailable -OldReplicaSets: -NewReplicaSet: primeiro-deployment-68c9dbf8b8 (1/1 replicas created) -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set primeiro-deployment-68c9dbf8b8 to 1 -``` - -Visualizando os detalhes do **segundo deployment**: - -``` -kubectl describe deployment segundo-deployment - -Name: segundo-deployment -Namespace: default -CreationTimestamp: Sat, 04 Aug 2018 00:45:49 +0000 -Labels: run=nginx -Annotations: deployment.kubernetes.io/revision=1 -Selector: run=nginx -Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable -StrategyType: RollingUpdate -MinReadySeconds: 0 -RollingUpdateStrategy: 1 max unavailable, 1 max surge -Pod Template: - Labels: dc=Netherlands - run=nginx - Containers: - nginx2: - Image: nginx - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Conditions: - Type Status Reason - ---- ------ ------ - Available True MinimumReplicasAvailable - Progressing True NewReplicaSetAvailable -OldReplicaSets: -NewReplicaSet: segundo-deployment-59db86c584 (1/1 replicas created) -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set segundo-deployment-59db86c584 to 1 -``` - -## Filtrando por Labels - -Quando criamos nossos Deployments adicionamos as seguintes labels: - -```yaml - labels: - run: nginx - dc: UK ---- - labels: - run: nginx - dc: Netherlands -``` - -As Labels são utilizadas para a organização do cluster, vamos listar nossos pods procurando pelas Labels. - -Primeiro vamos realizar uma pesquisa utilizando as labels ``dc=UK`` e ``dc=Netherlands``: - -Pesquisando pela label ``UK``: - -``` -kubectl get pods -l dc=UK - -NAME READY STATUS RESTARTS AGE -primeiro-deployment-68c9dbf8b8-kjqpt 1/1 Running 0 3m -``` - -Pesquisando pela label ``Netherlands``: - -``` -kubectl get pods -l dc=Netherlands - -NAME READY STATUS RESTARTS AGE -segundo-deployment-59db86c584-cf9pp 1/1 Running 0 4m -``` - -Caso queira uma saída mais personalizada podemos listar da seguinte forma, veja: - -``` -kubectl get pod -L dc - -NAME READY STATUS RESTARTS AGE DC -primeiro-deployment-68c9... 1/1 Running 0 5m UK -segundo-deployment-59db ... 1/1 Running 0 5m Netherlands -``` - -## Node Selector - -O **Node Selector** é uma forma de classificar nossos nodes como por exemplo nosso node ``elliot-02`` que possui disco **SSD** e está localizado no DataCenter ``UK``, e o node ``elliot-03`` que possui disco **HDD** e está localizado no DataCenter ``Netherlands``. - -Agora que temos essas informações vamos criar essas labels em nossos nodes, para utilizar o ``nodeSelector``. - -Criando a label ``disk`` com o valor ``SSD`` no worker 1: - -``` -kubectl label node elliot-02 disk=SSD - -node/elliot-02 labeled -``` - -Criando a label ``dc`` com o valor ``UK`` no worker 1: - -``` -kubectl label node elliot-02 dc=UK - -node/elliot-02 labeled -``` - -Criando a label ``dc`` com o valor ``Netherlands`` no worker 2: - -``` -kubectl label node elliot-03 dc=Netherlands - -node/elliot-03 labeled -``` - -Criando a label ``disk`` com o valor ``hdd`` no worker 2: - -``` -kubectl label nodes elliot-03 disk=hdd - -node/elliot-03 labeled -``` - -Opa! Acabamos declarando o ``disk=hdd`` em letra minúscula, como arrumamos isso? Subscrevendo a label como no comando a seguir. - -``` -kubectl label nodes elliot-03 disk=HDD --overwrite - -node/elliot-03 labeled -``` - -Para saber as labels configuradas em cada node basta executar o seguinte comando: - -No worker 1: - -``` -kubectl label nodes elliot-02 --list - -dc=UK -disk=SSD -kubernetes.io/hostname=elliot-02 -beta.kubernetes.io/arch=amd64 -beta.kubernetes.io/os=linux -``` - -No worker 2: - -``` -kubectl label nodes elliot-03 --list - -beta.kubernetes.io/os=linux -dc=Netherlands -disk=HDD -kubernetes.io/hostname=elliot-03 -beta.kubernetes.io/arch=amd64 -``` - -Agora, basta realizar o deploy novamente, porém antes vamos adicionar duas novas opções ao YAML e vamos ver a mágica acontecer. O nosso pod irá ser criado no node ``elliot-02``, onde possui a label ``disk=SSD``. - -Crie o arquivo ``terceiro-deployment.yaml``: - -``` -vim terceiro-deployment.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: nginx - name: terceiro-deployment - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - run: nginx - template: - metadata: - creationTimestamp: null - labels: - run: nginx - dc: Netherlands - spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx2 - ports: - - containerPort: 80 - protocol: TCP - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 - nodeSelector: - disk: SSD -``` - -Crie o deployment a partir do manifesto: - -``` -kubectl create -f terceiro-deployment.yaml - -deployment.extensions/terceiro-deployment created -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE IP NODE -primeiro-deployment-56d9... 1/1 Running 0 14m 172.17.0.4 elliot-03 -segundo-deployment-869f... 1/1 Running 0 14m 172.17.0.5 elliot-03 -terceiro-deployment-59cd... 1/1 Running 0 22s 172.17.0.6 elliot-02 -``` - -Removendo a label ``dc`` de um node worker: - -``` -kubectl label nodes elliot-02 dc- -``` - -Removendo uma determinada label de todos os nodes: - -``` -kubectl label nodes --all dc- -``` - -Agora imagine as infinitas possibilidades que isso poderá lhe proporcionar… Já estou pensando em várias, como por exemplo se é produção ou não, se consome muita CPU ou muita RAM, se precisa estar em determinado rack e por aí vai. 😃 - -Simples como voar, não? - -## Kubectl Edit - -Agora vamos fazer o seguinte, vamos utilizar o comando ``kubectl edit`` para editar nosso primeiro deployment, digamos que a "quente" com o pod ainda em execução. - -``` -kubectl edit deployment primeiro-deployment -``` - -Abriu um editor, correto? Vamos alterar a label ``DC``. Vamos imaginar que esse Deployment agora rodará no ``DC`` de ``Netherlands``. Precisamos adicionar a ``Label`` e o ``nodeSelector``. - -O conteúdo deve ser o seguinte: - -```yaml -spec: - replicas: 1 - selector: - matchLabels: - run: nginx - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - creationTimestamp: null - labels: - dc: Netherlands - app: giropops - run: nginx -spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx2 - ports: - - containerPort: 80 - protocol: TCP - resources: {} - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - nodeSelector: - dc: Netherlands -... - -deployment.extensions/primeiro-deployment edited -``` - -Como podemos ver mudamos o valor da label ``dc`` e também modificamos o ``nodeSelector``, onde ele agora subirá no node que tiver a label ``dc`` com o valor ``Netherlands``, fácil! 😀 - -Veja se o resultado foi conforme esperado: - -``` -kubectl get pods -l dc=Netherlands -o wide - -NAME READY STATUS RESTARTS AGE ..NODE -primeiro-deployment-7.. 1/1 Running 0 3m elliot-03 -segundo-deployment-5.. 1/1 Running 0 49m elliot-02 -terceiro-deployment-5.. 1/1 Running 0 14m elliot-02 -``` - -Com certeza, esse pod foi criado no node ``elliot-03``, pois havíamos dito que ele possuía essa label anteriormente. - -# ReplicaSet - -O **ReplicaSet** garante a quantidade solicitada de pods e os recursos necessários para um Deployment. Uma vez que o Deployment é criado, é o ReplicaSet que controla a quantidade de pods em execução, caso algum pod seja finalizado, ele que irá detectar e solicitar que outro pod seja executado em seu lugar, garantindo assim a quantidade de réplicas solicitadas. - -Vamos criar nosso primeiro ReplicaSet: - -``` -vim primeiro-replicaset.yaml -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: apps/v1 -kind: ReplicaSet -metadata: - name: replica-set-primeiro -spec: - replicas: 3 - selector: - matchLabels: - system: Giropops - template: - metadata: - labels: - system: Giropops - spec: - containers: - - name: nginx - image: nginx:1.7.9 - ports: - - containerPort: 80 -``` - -Crie o ReplicaSet a partir do manifesto: - -``` -kubectl create -f primeiro-replicaset.yaml - -replicaset.extensions/replica-set-primeiro created -``` - -Visualizando o ReplicaSet: - -``` -kubectl get replicaset - -NAME DESIRED CURRENT READY AGE -replica-set-primeiro 3 3 1 2s -``` - -Podemos observar os pods em execução: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -replica-set-primeiro-6drmt 1/1 Running 0 12s -replica-set-primeiro-7j59w 1/1 Running 0 12s -replica-set-primeiro-mg8q9 1/1 Running 0 12s -``` - -Temos exatamente 3 pods do ``nginx`` rodando simultaneamente. - -Podemos obter mais informações do nosso ReplicaSet utilizando o comando ``describe``. - -``` -kubectl describe rs replica-set-primeiro - -Name: replica-set-primeiro -Namespace: default -Selector: system=Giropops -Labels: system=Giropops -Annotations: -Replicas: 3 current / 3 desired -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed -Pod Template: - Labels: system=Giropops - Containers: - nginx: - Image: nginx:1.7.9 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal SuccessfulCreate 31s replicaset-controller Created pod: replica-set-primeiro-mg8q9 - Normal SuccessfulCreate 31s replicaset-controller Created pod: replica-set-primeiro-6drmt - Normal SuccessfulCreate 31s replicaset-controller Created pod: replica-set-primeiro-7j59w -``` - -Assim podemos ver todos os pods associados ao ReplicaSet, e se excluirmos um desses Pods, o que será que acontece? Vamos testar: - -``` -kubectl delete pod replica-set-primeiro-6drmt - -pod "replica-set-primeiro-6drmt" deleted -``` - -Agora vamos verificar novamente os Pods em execução: - -``` -kubectl get pods -l system=Giropops - -NAME READY STATUS RESTARTS AGE -replica-set-primeiro-7j59w 1/1 Running 0 1m -replica-set-primeiro-mg8q9 1/1 Running 0 1m -replica-set-primeiro-s5dz2 1/1 Running 0 15s -``` - -Percebeu que ele recriou outro Pod? O **ReplicaSet** faz com que sempre tenha 3 pods disponíveis. - -Vamos alterar para 4 réplicas e recriar o ReplicaSet, para isso vamos utilizar o ``kubectl edit`` visto anteriormente, assim podemos alterar o ReplicaSet já em execução. - -``` -kubectl edit rs replica-set-primeiro -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: apps/v1 -kind: ReplicaSet -metadata: - creationTimestamp: 2018-07-05T04:32:42Z - generation: 2 - labels: - system: Giropops - name: replica-set-primeiro - namespace: default - resourceVersion: "471758" - selfLink: /apis/extensions/v1beta1/namespaces/default/replicasets/replica-set-primeiro - uid: 753290c1-800c-11e8-b889-42010a8a0002 -spec: - replicas: 4 - selector: - matchLabels: - system: Giropops - template: - metadata: - creationTimestamp: null - labels: - system: Giropops -... - -replicaset.extensions/replica-set-primeiro edited -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -l system=Giropops - -NAME READY STATUS RESTARTS AGE -replica-set-primeiro-7j59w 1/1 Running 0 2m -replica-set-primeiro-96hj7 1/1 Running 0 10s -replica-set-primeiro-mg8q9 1/1 Running 0 2m -replica-set-primeiro-s5dz2 1/1 Running 0 1m -``` - -Veja que ele não cria um deployment para esse replicaset: - -``` -kubectl get deployment.apps -``` - -Perceba que não é listado um deployment relacionado ao ``replica-set-primeiro``. - -Agora vamos editar um dos pods e modificar a versão da imagem do Nginx que estamos utilizando no exemplo. Vamos alterar de ``image: nginx:1.7.9_`` para ``image: nginx:1.15.0`` utilizando o ``kubectl edit``. Editando o pod: - -``` -kubectl edit pod replica-set-primeiro-7j59w -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: replica-set-primeiro -... - spec: - containers: - - name: nginx - image: nginx:1.15.0 - ports: - - containerPort: 80 -... - -pod/replica-set-primeiro-7j59w edited -``` - -Agora vamos observar novamente os pods, como estão? - -``` -kubectl get pods -l system=Giropops - -NAME READY STATUS RESTARTS AGE -replica-set-primeiro-7j59w 1/1 Running 1 8m -replica-set-primeiro-96hj7 1/1 Running 0 6m -replica-set-primeiro-mg8q9 1/1 Running 0 8m -replica-set-primeiro-s5dz2 1/1 Running 0 7m -``` - -Aparentemente nada aconteceu concordam? Vamos detalhar melhor esse pod que acabamos de alterar: - -``` -kubectl describe pod replica-set-primeiro-7j59w - -Name: replica-set-primeiro-7j59w -Namespace: default -Priority: 0 -PriorityClassName: -Node: elliot-02/10.138.0.3 -Start Time: Sat, 04 Aug 2018 01:47:56 +0000 -Labels: system=Giropops -Annotations: -Status: Running -IP: 10.46.0.2 -Controlled By: ReplicaSet/replica-set-primeiro -Containers: - nginx: - Container ID: docker://6991b627cf4d6daca039ab9d6336929c0de1fc279c55a451cf9c7304e1c46504 - Image: nginx:1.15.0 -... -Successfully assigned default/replica-set-primeiro-7j59w to elliot-02 - Normal Pulled 9m kubelet, elliot-02 Container image "nginx:1.7.9" already present on machine - Normal Killing 1m kubelet, elliot-02 Killing container with id docker://nginx:Container spec hash changed (3238050430 vs 811632170).. Container will be killed and recreated. - Normal Pulling 1m kubelet, elliot-02 pulling image "nginx:1.15.0" - Normal Created 1m (x2 over 9m) kubelet, elliot-02 Created container - Normal Started 1m (x2 over 9m) kubelet, elliot-02 Started container - Normal Pulled 1m kubelet, elliot-02 Successfully pulled image "nginx:1.15.0" -``` - -Como podemos observar ele alterou a imagem do nginx do **1.7.9** para **1.15.0**, como o replicaset não tem um deployment ele apenas destruiu o contêiner sem destruir o pod, então a configuração passada manualmente é uma configuração válida, mas caso o pod seja removido o ReplicaSet vai recriá-lo com as configurações originais. - -Vamos apagar o pod e ver se realmente acontece isso: - -``` -kubectl delete pod replica-set-primeiro-7j59w - -pod "replica-set-primeiro-7j59w" delete -``` - -Visualizando os pods: - -``` -kubectl get pods -l system=Giropops - -NAME READY STATUS RESTARTS AGE -replica-set-primeiro-96hj7 1/1 Running 0 12m -replica-set-primeiro-mg8q9 1/1 Running 0 14m -replica-set-primeiro-s5dz2 1/1 Running 0 13m -replica-set-primeiro-xzfvg 1/1 Running 0 5s -``` - -Visualizando os detalhes do pods: - -``` -kubectl describe pod replica-set-primeiro-xzfvg - -Name: replica-set-primeiro-xzfvg -Namespace: default -Priority: 0 -PriorityClassName: -Node: elliot-02/10.138.0.3 -Start Time: Sat, 04 Aug 2018 02:02:35 +0000 -Labels: system=Giropops -Annotations: -Status: Running -IP: 10.46.0.2 -Controlled By: ReplicaSet/replica-set-primeiro -Containers: - nginx: - Container ID: docker://e8b88065640ba3ea346c93bb368ae6b7fb7b1d9507a948d891ca632df0dfc071 - Image: nginx:1.7.9 -... -``` - -Olha só, o novo pod foi criado com a imagem configurada no replicaset. - -Agora vamos apagar nosso ReplicaSet: - -``` -kubectl get rs - -NAME DESIRED CURRENT READY AGE -replica-set-primeiro 4 4 4 25m -``` - -``` -kubectl delete rs replica-set-primeiro - -replicaset.apps "replica-set-primeiro" deleted -``` - -# DaemonSet - -**DaemonSet** é basicamente a mesma coisa do que o ReplicaSet, com a diferença que quando você utiliza o DaemonSet você não especifica o número de réplicas, ele subirá um pod por node em seu cluster. - -É sempre interessante quando criar usar e abusar das labels, assim você conseguirá ter melhor flexibilidade na distribuição mais adequada de sua aplicação. - -Ele é bem interessante para serviços que necessitem rodar em todos os nodes do cluster, como por exemplo, coletores de logs e agentes de monitoração. - -Vamos criar o nosso primeiro DaemonSet: - -``` -vim primeiro-daemonset.yaml -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: daemon-set-primeiro -spec: - selector: - matchLabels: - system: Strigus - template: - metadata: - labels: - system: Strigus - spec: - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule - containers: - - name: nginx - image: nginx:1.7.9 - ports: - - containerPort: 80 -``` - -Caso não queria utilizar a diretiva 'tolerations', podemos também utilizar a remoção do taint nas masters como a seguir: - -``` -kubectl taint nodes --all node-role.kubernetes.io/master- - -node/elliot-01 untainted -taint "node-role.kubernetes.io/master:" not found -taint "node-role.kubernetes.io/master:" not found -``` - -Agora podemos criar nosso DaemonSet: - -``` -kubectl create -f primeiro-daemonset.yaml - -daemonset.extensions/daemon-set-primeiro created -``` - -Vamos listar nossos DaemonSet: - -``` -kubectl get daemonset - -NAME DESIRED CURRENT READY UP-TO-DATE ... AGE -daemon-set-primeiro 3 3 3 3 30s -``` - -Visualizando os detalhes do DaemonSet: - -``` -kubectl describe ds daemon-set-primeiro - -Name: daemon-set-primeiro -Selector: system=Strigus -Node-Selector: -Labels: system=Strigus -Annotations: -Desired Number of Nodes Scheduled: 3 -Current Number of Nodes Scheduled: 3 -Number of Nodes Scheduled with Up-to-date Pods: 3 -Number of Nodes Scheduled with Available Pods: 3 -Number of Nodes Misscheduled: 0 -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed -Pod Template: - Labels: system=Strigus - Containers: - nginx: - Image: nginx:1.7.9 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal SuccessfulCreate 41s daemonset-controller Created pod: daemon-set-primeiro-jl6f5 - Normal SuccessfulCreate 412 daemonset-controller Created pod: daemon-set-primeiro-jh2sp - Normal SuccessfulCreate 412 daemonset-controller Created pod: daemon-set-primeiro-t9rv9 -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE .. NODE -daemon-set-primeiro.. 1/1 Running 0 1m elliot-01 -daemon-set-primeiro.. 1/1 Running 0 1m elliot-02 -daemon-set-primeiro.. 1/1 Running 0 1m elliot-03 -``` - -Como podemos observar temos um pod por nó rodando nosso ``daemon-set-primeiro``. - -Vamos alterar a imagem desse pod diretamente no DaemonSet, usando o comando ``kubectl set``: - -``` -kubectl set image ds daemon-set-primeiro nginx=nginx:1.15.0 - -daemonset.extensions/daemon-set-primeiro image updated -``` - -Vamos confirmar se a imagem foi realmente alterada: - -``` -kubectl describe ds daemon-set-primeiro - -Name: daemon-set-primeiro -Selector: system=Strigus -Node-Selector: -Labels: system=Strigus -Annotations: -Desired Number of Nodes Scheduled: 3 -Current Number of Nodes Scheduled: 3 -Number of Nodes Scheduled with Up-to-date Pods: 0 -Number of Nodes Scheduled with Available Pods: 3 -Number of Nodes Misscheduled: 0 -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed -Pod Template: - Labels: system=Strigus - Containers: - nginx: - Image: nginx:1.15.0 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal SuccessfulCreate 2m daemonset-controller Created pod: daemon-set-primeiro-jl6f5 - Normal SuccessfulCreate 2m daemonset-controller Created pod: daemon-set-primeiro-jh2sp - Normal SuccessfulCreate 2m daemonset-controller Created pod: daemon-set-primeiro-t9rv9 -``` - -Agora vamos verificar se as imagens dos pods estão atualizadas: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -daemon-set-primeiro-jh2sp 1/1 Running 0 2m -daemon-set-primeiro-jl6f5 1/1 Running 0 2m -daemon-set-primeiro-t9rv9 1/1 Running 0 2m -``` - -Como podemos observar não tivemos nenhum restart nos pods. - -Vamos verificar a imagem executando em um dos pods: - -``` -kubectl describe pod daemon-set-primeiro-jh2sp | grep -i image: - -Image: nginx:1.7.9 -``` - -Exatamente, Não conseguimos alterar informações do DaemonSet em execução. - -E se o pod for deletado? - -``` -kubectl delete pod daemon-set-primeiro-jh2sp - -pod "daemon-set-primeiro-jh2sp" deleted -``` - -Visualizando os pods: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -daemon-set-primeiro-hp4qc 1/1 Running 0 3s -daemon-set-primeiro-jl6f5 1/1 Running 0 10m -daemon-set-primeiro-t9rv9 1/1 Running 0 10m -``` - -Vamos listar o novo Pod que foi criado, após deletarmos o Pod antigo: - -``` -kubectl describe pod daemon-set-primeiro-hp4qc | grep -i image: - - Image: nginx:1.15.0 -``` - -Agora um Pod que já estava em execução: - -``` -kubectl describe pod daemon-set-primeiro-jl6f5 | grep -i image: - - Image: nginx:1.7.9 -``` - -Como podemos observar, para atualizar todos os pods do DaemonSet precisamos recriá-lo ou destruir todos os pods relacionado a ele, mas isso não é muito ruim? Sim, é bem ruim. Para melhorar nossas vidas temos a opção ``RollingUpdate`` que vamos ver no próximo capítulo. - -# Rollouts e Rollbacks - -Agora vamos imaginar que essa nossa última edição utilizando o comando ``kubectl set`` no DaemonSet não foi correta e precisamos voltar a configuração anterior, onde a versão da imagem era outra, como faremos? - -É muito simples, para isso existe o _Rollout_. Com ele você pode verificar quais foram as modificações que aconteceram em seu Deployment ou DaemonSet, como se fosse um versionamento. Vejaaaa! (Com a voz do Nelson Rubens) - -``` -kubectl rollout history ds daemon-set-primeiro - -daemonsets "daemon-set-primeiro" -REVISION CHANGE-CAUSE -1 -2 -``` - -Ele irá mostrar duas linhas, a primeira que é a original, com a imagem do ``nginx:1.7.9`` e a segunda já com a imagem ``nginx:1.15.0``. As informações não estão muito detalhadas concordam? - -Veja como verificar os detalhes de cada uma dessas entradas, que são chamadas de **revision**. - -Visualizando a revision 1: - -``` -kubectl rollout history ds daemon-set-primeiro --revision=1 - -daemonsets "daemon-set-primeiro" with revision #1 -Pod Template: - Labels: system=DaemonOne - Containers: - nginx: - Image: nginx:1.7.9 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -``` - -Visualizando a revision 2: - -``` -kubectl rollout history ds daemon-set-primeiro --revision=2 - -daemonsets "daemon-set-primeiro" with revision #2 -Pod Template: - Labels: system=DaemonOne - Containers: - nginx: - Image: nginx:1.15.0 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -``` - -Para voltar para a ``revision`` desejada, basta fazer o seguinte: - -``` -kubectl rollout undo ds daemon-set-primeiro --to-revision=1 - -daemonset.extensions/daemon-set-primeiro rolled back -``` - -Perceba que trocamos o ``history`` por ``undo`` e o ``revision`` por ``to-revision``, assim faremos o **rollback** em nosso DaemonSet, e voltamos a versão da imagem que desejamos. 😃 - ---- - ->**Atenção!!!** Por padrão, o DaemonSet guarda apenas as 10 últimas revisions. Para alterar a quantidade máxima de revisions no nosso Daemonset, execute o seguinte comando. -Fonte: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#clean-up-policy - ---- - -``` -kubectl edit daemonsets.apps daemon-set-primeiro -``` - -Altere a quantidade no parâmetro ``revisionHistoryLimit``: - -```yaml - revisionHistoryLimit: 10 -``` - ---- - -Voltando à nossa linha de raciocínio, para acompanhar o rollout, execute o seguinte comando: - -``` -kubectl rollout status ds daemon-set-primeiro -``` - -Vamos confirmar se já estamos executando a nova imagem e um dos nosso pods: - -``` -kubectl describe pod daemon-set-primeiro-hp4qc | grep -i image: - -Image: nginx:1.15.0 -``` - -Não funcionou, por quê? Porque teremos que matar o Pod para ele ser recriado com as novas configuração. - -Vamos afinar esse nosso DaemonSet, vamos adicionar o ``RollingUpdate`` e esse cara vai atualizar automaticamente os Pods quando houver alguma alteração. - -Vamos lá, primeiro vamos remover o ``DaemonSet``, adicionar duas novas informações em nosso manifesto yaml e, em seguida, criar outro DaemonSet em seu lugar: - -``` -kubectl delete -f primeiro-daemonset.yaml - -daemonset.extensions "daemon-set-primeiro" deleted -``` - -Edite o arquivo ``primeiro-daemonset.yaml``. - -``` -vim primeiro-daemonset.yaml -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: daemon-set-primeiro -spec: - selector: - matchLabels: - system: Strigus - template: - metadata: - labels: - system: Strigus - spec: - containers: - - name: nginx - image: nginx:1.7.9 - ports: - - containerPort: 80 - updateStrategy: - type: RollingUpdate -``` - -Crie o DaemonSet: - -``` -kubectl create -f primeiro-daemonset.yaml - -daemonset.extensions/daemon-set-primeiro created -``` - -Sucesso, vamos verificar se nosso DaemonSet foi inicializado certinho. - -``` -kubectl get daemonset - -NAME DESIRED CURRENT READY ... AGE -daemon-set-primeiro 3 3 3 ... 5m -``` - -Visualizando os detalhes do DaemonSet: - -``` -kubectl describe ds daemon-set-primeiro - -Name: daemon-set-primeiro -Selector: system=DaemonOne -Node-Selector: -Labels: system=DaemonOne -Annotations: -Desired Number of Nodes Scheduled: 3 -Current Number of Nodes Scheduled: 3 -Number of Nodes Scheduled with Up-to-date Pods: 3 -Number of Nodes Scheduled with Available Pods: 3 -Number of Nodes Misscheduled: 0 -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed -Pod Template: - Labels: system=DaemonOne - Containers: - nginx: - Image: nginx:1.7.9 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal SuccessfulCreate 5m daemonset-controller Created pod: daemon-set-primeiro-52k8k - Normal SuccessfulCreate 5m daemonset-controller Created pod: daemon-set-primeiro-6sln2 - Normal SuccessfulCreate 5m daemonset-controller Created pod: daemon-set-primeiro-9v2w9 - daemonset-controller Created pod: daemon-set-primeiro-9dktj -``` - -Vamos verificar nossa recém adicionada configuração de ``RollingUpdate``: - -``` -kubectl get ds daemon-set-primeiro -o yaml | grep -A 2 Strategy - - updateStrategy: - rollingUpdate: - maxUnavailable: 1 -``` - -Agora com nosso DaemonSet já configurado, vamos alterar aquela mesma imagem do ``nginx`` e ver o que acontece de fato: - -``` -kubectl set image ds daemon-set-primeiro nginx=nginx:1.15.0 - -daemonset.extensions/daemon-set-primeiro image updated -``` - -Vamos listar o DaemonSet e os Pods para ter certeza de que nada se quebrou: - -``` -kubectl get daemonset - -NAME DESIRED CURRENT READY ... AGE -daemon-set-primeiro 3 3 3 ... 6m -``` - -Visualizando os pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE NODE -daemon-set-primeiro-7m... 1/1 Running 0 10s elliot-02 -daemon-set-primeiro-j7... 1/1 Running 0 10s elliot-03 -daemon-set-primeiro-v5... 1/1 Running 0 10s elliot-01 -``` - -Como podemos observar nosso DaemonSet se manteve o mesmo, porém os Pods foram recriados, vamos detalhar o DaemonSet para visualizar as alterações realizadas. - -``` -kubectl describe ds daemon-set-primeiro - -Name: daemon-set-primeiro -Selector: system=DaemonOne -Node-Selector: -Labels: system=DaemonOne -Annotations: -Desired Number of Nodes Scheduled: 3 -Current Number of Nodes Scheduled: 3 -Number of Nodes Scheduled with Up-to-date Pods: 3 -Number of Nodes Scheduled with Available Pods: 3 -Number of Nodes Misscheduled: 0 -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed -Pod Template: - Labels: system=DaemonOne - Containers: - nginx: - Image: nginx:1.15.0 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -Events: - Type Reason Age From Message - ---- ------ ---- ---- ------- - Normal SuccessfulCreate 8m daemonset-controller Created pod: daemon-set-primeiro-52k8k - Normal SuccessfulCreate 8m daemonset-controller Created pod: daemon-set-primeiro-6sln2 - Normal SuccessfulCreate 8m daemonset-controller Created pod: daemon-set-primeiro-9v2w9 - Normal SuccessfulDelete 10m daemonset-controller Deleted pod: daemon-set-primeiro-6sln2 - Normal SuccessfulCreate 1m daemonset-controller Created pod: daemon-set-primeiro-j788v - Normal SuccessfulDelete 10m daemonset-controller Deleted pod: daemon-set-primeiro-52k8k - Normal SuccessfulCreate 1m daemonset-controller Created pod: daemon-set-primeiro-7mpwr - Normal SuccessfulDelete 10m daemonset-controller Deleted pod: daemon-set-primeiro-9v2w9 - Normal SuccessfulCreate 1m daemonset-controller Created pod: daemon-set-primeiro-v5m47 -``` - -Olha que Bacana! Se observamos o campo **Events** podemos ver que o ``RollingUpdate`` matou os pods antigos e recriou com a nova imagem que alteramos utilizando o ``kubectl set``. - -Podemos também verificar em um dos Pods se essa alteração realmente aconteceu. - -``` -kubectl describe pod daemon-set-primeiro-j788v | grep -i image: - -Image: nginx:1.15.0 -``` - -Viram? Muito sensacional esse negócio de ``RollingUpdate``. - -Vamos verificar nosso histórico de modificações: - -``` -kubectl rollout history ds daemon-set-primeiro - -daemonsets "daemon-set-primeiro" -REVISION CHANGE-CAUSE -1 -2 -``` - -Sim, temos duas alterações. Vamos detalhar para saber qual é qual. - -Visualizando a revision 1: - -``` -kubectl rollout history ds daemon-set-primeiro --revision=1 - -daemonsets "daemon-set-primeiro" with revision #1 -Pod Template: - Labels: system=DaemonOne - Containers: - nginx: - Image: nginx:1.7.9 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -``` - -Visualizando a revision 2: - -``` -kubectl rollout history ds daemon-set-primeiro --revision=2 - -daemonsets "daemon-set-primeiro" with revision #2 -Pod Template: - Labels: system=DaemonOne - Containers: - nginx: - Image: nginx:1.15.0 - Port: 80/TCP - Host Port: 0/TCP - Environment: - Mounts: - Volumes: -``` - -Agora vamos realizar o rollback do nosso DaemonSet para a revision 1: - -``` -kubectl rollout undo ds daemon-set-primeiro --to-revision=1 - -daemonset.extensions/daemon-set-primeiro rolled back - kubectl rollout undo ds daem kubectl rollout undo ds daem - ``` - -Visualizando os pods: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -daemon-set-primeiro-c2jjk 1/1 Running 0 19s -daemon-set-primeiro-hrn48 1/1 Running 0 19s -daemon-set-primeiro-t6mr9 1/1 Running 0 19s -``` - -Visualizando os detalhes dos pods: - -``` -kubectl describe pod daemon-set-primeiro-c2jjk | grep -i image: - -Image: nginx:1.7.9 -``` - -Sensacional não? - -Deu ruim? - -Basta retornar para a outra configuração: - -``` -kubectl rollout undo ds daemon-set-primeiro --to-revision=2 - -daemonset.extensions/daemon-set-primeiro rolled back -``` - -Visualizando o status do rollout: - -``` -kubectl rollout status ds daemon-set-primeiro - -daemon set "daemon-set-primeiro" successfully rolled out -``` - -Visualizando os pods: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -daemon-set-primeiro-jzck9 1/1 Running 0 32s -daemon-set-primeiro-td7h5 1/1 Running 0 29s -daemon-set-primeiro-v5c86 1/1 Running 0 40s -``` - -Visualizando os detalhes dos pods: - -``` -kubectl describe pod daemon-set-primeiro-jzck9 | grep -i image: - -Image: nginx:1.15.0 -``` - -Agora vamos deletar nosso DaemonSet: - -``` -kubectl delete ds daemon-set-primeiro - -daemonset.extensions "daemon-set-primeiro" deleted -``` diff --git a/pt/old/day_two/descomplicando_kubernetes.md b/pt/old/day_two/descomplicando_kubernetes.md deleted file mode 100644 index 235516d1..00000000 --- a/pt/old/day_two/descomplicando_kubernetes.md +++ /dev/null @@ -1,1484 +0,0 @@ -# Descomplicando Kubernetes dia 2 - -## Sumário - -- [Descomplicando Kubernetes dia 2](#descomplicando-kubernetes-dia-2) - - [Sumário](#sumário) -- [Componentes do K8s](#componentes-do-k8s) -- [Principais Comandos](#principais-comandos) -- [Container Network Interface](#container-network-interface) -- [Services](#services) - - [Criando um service ClusterIP](#criando-um-service-clusterip) - - [Criando um service NodePort](#criando-um-service-nodeport) - - [Criando um service LoadBalancer](#criando-um-service-loadbalancer) - - [EndPoint](#endpoint) -- [Limitando Recursos](#limitando-recursos) -- [Namespaces](#namespaces) -- [Kubectl taint](#kubectl-taint) -- [Colocando o nó em modo de manutenção](#colocando-o-nó-em-modo-de-manutenção) - -# Componentes do K8s - -**O k8s tem os seguintes componentes principais:** - -* Master node -* Worker node -* Services -* Controllers -* Pods -* Namespaces e quotas -* Network e policies -* Storage - -**[kube-apiserver](https://kubernetes.io/docs/concepts/overview/components/#kube-apiserver)** é a central de operações do cluster k8s. Todas as chamadas, internas ou externas são tratadas por ele. Ele é o único que conecta no ETCD. - -**[kube-scheduller](https://kubernetes.io/docs/concepts/overview/components/#kube-apiserver)** usa um algoritmo para verificar em qual node o pod deverá ser hospedado. Ele verifica os recursos disponíveis do node para verificar qual o melhor node para receber aquele pod. - -No **[ETCD](https://kubernetes.io/docs/concepts/overview/components/#etcd)** são armazenados o estado do cluster, rede e outras informações persistentes. - -**[kube-controller-manager](https://kubernetes.io/docs/concepts/overview/components/#cloud-controller-manager)** é o controle principal que interage com o ``kube-apiserver`` para determinar o seu estado. Se o estado não bate, o manager irá contactar o controller necessário para checar seu estado desejado. Tem diversos controllers em uso como: os endpoints, namespace e replication. - -O **[kubelet](https://kubernetes.io/docs/concepts/overview/components/#kubelet)** interage com o Docker instalado no node e garante que os contêineres que precisavam estar em execução realmente estão. - -O **[kube-proxy](https://kubernetes.io/docs/concepts/overview/components/#kube-proxy)** é o responsável por gerenciar a rede para os contêineres, é o responsável por expor portas dos mesmos. - -**[Supervisord](http://supervisord.org/)** é o responsável por monitorar e restabelecer, se necessário, o ``kubelet`` e o Docker. Por esse motivo, quando existe algum problema em relação ao kubelet, como por exemplo o uso do driver ``cgroup`` diferente do que está rodando no Docker, você perceberá que ele ficará tentando subir o kubelet frequentemente. - -**[Pod](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/)** é a menor unidade que você irá tratar no k8s. Você poderá ter mais de um contêiner por Pod, porém vale lembrar que eles dividirão os mesmos recursos, como por exemplo IP. Uma das boas razões para se ter mais de um contêiner em um Pod é o fato de você ter os logs consolidados. - -O Pod, por poder possuir diversos contêineres, muitas das vezes se assemelha a uma VM, onde você poderia ter diversos serviços rodando compartilhando o mesmo IP e demais recursos. - -**[Services](https://kubernetes.io/docs/concepts/services-networking/service/)** é uma forma de você expor a comunicação através de um **NodePort** ou **LoadBalancer** para distribuir as requisições entre diversos Pods daquele Deployment. Funciona como um balanceador de carga. - -# Principais Comandos - -A figura a seguir mostra a estrutura dos principais comandos do ``kubectl``. - -| ![Principais Comandos](../../images/kubernetes_commands.png) | -|:---------------------------------------------------------------------------------------------:| -| *Principais comandos [Ref: uploaddeimagens.com.br](https://uploaddeimagens.com.br/images/002/667/919/full/Kubernetes-Comandos.png)* | - -# Container Network Interface - -Para prover a rede para os contêineres, o k8s utiliza a especificação do **CNI**, Container Network Interface. - -CNI é uma especificação que reúne algumas bibliotecas para o desenvolvimento de plugins para configuração e gerenciamento de redes para os contêineres. Ele provê uma interface comum entre as diversas soluções de rede para o k8s. Você encontra diversos plugins para AWS, GCP, Cloud Foundry entre outros. - -Mais informações em: [https://github.com/containernetworking/cni](https://github.com/containernetworking/cni) - -Enquanto o CNI define a rede dos pods, ele não te ajuda na comunicação entre os pods de diferentes nodes. - -As características básicas da rede do k8s são: - -* Todos os pods conseguem se comunicar entre eles em diferentes nodes; -* Todos os nodes podem se comunicar com todos os pods; -* Não utilizar NAT. - -Todos os IPs dos pods e nodes são roteados sem a utilização de [NAT](https://en.wikipedia.org/wiki/Network_address_translation). Isso é solucionado com a utilização de algum software que te ajudará na criação de uma rede Overlay. Seguem alguns: - -* [Weave](https://www.weave.works/docs/net/latest/kube-addon/) -* [Flannel](https://github.com/coreos/flannel/blob/master/Documentation/kubernetes.md) -* [Canal](https://github.com/tigera/canal/tree/master/k8s-install) -* [Calico](https://docs.projectcalico.org/latest/introduction/) -* [Romana](http://romana.io/) -* [Nuage](https://github.com/nuagenetworks/nuage-kubernetes/blob/v5.1.1-1/docs/kubernetes-1-installation.rst) -* [Contiv](http://contiv.github.io/) - -Mais informações em: [https://kubernetes.io/docs/concepts/cluster-administration/addons/](https://kubernetes.io/docs/concepts/cluster-administration/addons/) - -# Services - -## Criando um service ClusterIP - -Vamos criar um pod a partir de um pod template utilizando os seguintes comandos: - -``` -kubectl run nginx --image nginx --dry-run=client -o yaml > pod-template.yaml -kubectl create -f pod-template.yaml -pod/nginx created -``` - -Expondo o pod do Nginx. - -``` -kubectl expose pod nginx --port=80 - -service/nginx exposed -``` - -Obtendo informações do service. - -``` -kubectl get svc - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 25m -nginx ClusterIP 10.104.209.243 80/TCP 7m15s -``` - -Execute o seguinte comando para visualizar mais detalhes do service ``nginx``. - -``` -kubectl describe service nginx - -Name: nginx -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: ClusterIP -IP: 10.104.209.243 -Port: 80/TCP -TargetPort: 80/TCP -Endpoints: 10.46.0.0:80 -Session Affinity: None -Events: -``` - -Acessando o Ningx. Altere o IP do cluster no comando a seguir de acordo com o seu ambiente. - -``` -curl 10.104.209.243 - -... -Welcome to nginx! -... -``` - -Acesse o log do Nginx. - -``` -kubectl logs -f nginx - -10.40.0.0 - - [10/May/2020:17:31:56 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" -``` - -Remova o serviço criado anteriormente. - -``` -kubectl delete svc nginx - -service "nginx" deleted -``` - -Agora vamos criar nosso service ``ClusterIP``, porém vamos criar um arquivo yaml com suas definições: - -``` -vim primeiro-service-clusterip.yaml -``` - -Informe o seguinte conteúdo: - -```yaml -apiVersion: v1 -kind: Service -metadata: - labels: - run: nginx - name: nginx-clusterip - namespace: default -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - run: nginx - type: ClusterIP -``` - -Criando o service: - -``` -kubectl create -f primeiro-service-clusterip.yaml - -service/nginx-clusterip created -``` - -Obtendo informações do service: - -``` -kubectl get services - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 28m -nginx-clusterip ClusterIP 10.109.70.243 80/TCP 71s -``` - -Visualizando os detalhes do service: - -``` -kubectl describe service nginx-clusterip - -Name: nginx-clusterip -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: ClusterIP -IP: 10.109.70.243 -Port: 80/TCP -TargetPort: 80/TCP -Endpoints: 10.46.0.1:80 -Session Affinity: None -Events: -``` - -Removendo o service: - -``` -kubectl delete -f primeiro-service-clusterip.yaml - -service "nginx-clusterip" deleted -``` - -Agora vamos mudar um detalhe em nosso manifesto, vamos brincar com o nosso ``sessionAffinity``: - -> **Nota:** Se você quiser ter certeza de que as conexões de um cliente específico sejam passadas para o mesmo pod todas as vezes, você pode selecionar a afinidade da sessão (*session affinity*) com base nos endereços IP do cliente, definindo ``service.spec.sessionAffinity`` como ``ClientIP`` (o padrão é ``None``). Você também pode definir o tempo de permanência máximo da sessão definindo ``service.spec.sessionAffinityConfig.clientIP.timeoutSeconds`` adequadamente (o valor padrão é 10800 segundos, o que resulta em 3 horas). - -``` -vim primeiro-service-clusterip.yaml -``` - -O conteúdo deve ser o seguinte: - -```yaml -apiVersion: v1 -kind: Service -metadata: - labels: - run: nginx - name: nginx-clusterip - namespace: default -spec: - ports: - - port: 80 - protocol: TCP - targetPort: 80 - selector: - run: nginx - sessionAffinity: ClientIP - type: ClusterIP -``` - -Criando o service novamente: - -``` -kubectl create -f primeiro-service-clusterip.yaml - -service/nginx-clusterip created -``` - -Obtendo informações do service: - -``` -kubectl get services - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 29m -nginx-clusterip ClusterIP 10.96.44.114 80/TCP 7s -``` - -Visualizando os detalhes do service: - -``` -kubectl describe service nginx - -Name: nginx-clusterip -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: ClusterIP -IP: 10.96.44.114 -Port: 80/TCP -TargetPort: 80/TCP -Endpoints: 10.46.0.1:80 -Session Affinity: ClientIP -Events: -``` - -Com isso, agora temos como manter a sessão, ou seja, ele irá manter a conexão com o mesmo pod, respeitando o IP de origem do cliente. - -Caso precise, é possível alterar o valor do timeout para o ``sessionAffinity`` (O valor padrão é de 10800 segundos, ou seja 3 horas), apenas adicionando a configuração abaixo. - -``` - sessionAffinityConfig: - clientIP: - timeoutSeconds: 10 -``` - -Agora podemos remover o service: - -``` -kubectl delete -f primeiro-service-clusterip.yaml - -service "nginx-clusterip" deleted -``` - -## Criando um service NodePort - -Execute o comando a seguir para exportar o pod usando o service NodePort. Lembrando que o range de portas internas é entre 30000/TCP a 32767/TCP. - -``` -kubectl expose pods nginx --type=NodePort --port=80 - -service/nginx exposed -``` - -Obtendo informações do service: - -``` -kubectl get svc - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 29m -nginx NodePort 10.101.42.230 80:31858/TCP 5s -``` - -Removendo o service: - -``` -kubectl delete svc nginx - -service "nginx" deleted -``` - -Agora vamos criar um service NodePort, porém vamos criar um manifesto yaml com suas definições. - -``` -vim primeiro-service-nodeport.yaml -``` - -O conteúdo deve ser o seguinte. - -```yaml -apiVersion: v1 -kind: Service -metadata: - labels: - run: nginx - name: nginx-nodeport - namespace: default -spec: - externalTrafficPolicy: Cluster - ports: - - nodePort: 31111 - port: 80 - protocol: TCP - targetPort: 80 - selector: - run: nginx - sessionAffinity: None - type: NodePort -``` - -Criando o service: - -``` -kubectl create -f primeiro-service-nodeport.yaml - -service/nginx-nodeport created -``` - -Obtendo informações do service: - -``` -kubectl get services - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 30m -nginx-nodeport NodePort 10.102.91.81 80:31111/TCP 7s -``` - -Visualizando os detalhes do service: - -``` -kubectl describe service nginx - -Name: nginx-nodeport -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: NodePort -IP: 10.102.91.81 -Port: 80/TCP -TargetPort: 80/TCP -NodePort: 31111/TCP -Endpoints: 10.46.0.1:80 -Session Affinity: None -External Traffic Policy: Cluster -Events: -``` - -Removendo o service: - -``` -kubectl delete -f primeiro-service-nodeport.yaml - -service "nginx-nodeport" deleted -``` - -## Criando um service LoadBalancer - -Execute o comando a seguir para exportar o pod usando o service LoadBalancer. - -``` -kubectl expose pod nginx --type=LoadBalancer --port=80 - -service/nginx exposed -``` - -Obtendo informações do service: - -``` -kubectl get svc - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 32m -nginx LoadBalancer 10.110.198.89 80:30728/TCP 4s -``` - -Removendo o service: - -``` -kubectl delete svc nginx - -service "nginx" deleted -``` - -Agora vamos criar service LoadBalancer, porém vamos criar um yaml com suas definições. - -``` -vim primeiro-service-loadbalancer.yaml -``` - -O conteúdo deve ser o seguinte. - -```yaml -apiVersion: v1 -kind: Service -metadata: - labels: - run: nginx - name: nginx-loadbalancer - namespace: default -spec: - externalTrafficPolicy: Cluster - ports: - - nodePort: 31222 - port: 80 - protocol: TCP - targetPort: 80 - selector: - run: nginx - sessionAffinity: None - type: LoadBalancer -``` - -Criando o service: - -``` -kubectl create -f primeiro-service-loadbalancer.yaml - -service/nginx-loadbalancer created -``` - -Obtendo informações do service: - -``` -kubectl get services - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 33m -nginx-loadbalancer LoadBalancer 10.96.67.165 80:31222/TCP 4s -``` - -Visualizando informações do service: - -``` -kubectl describe service nginx - -Name: nginx-loadbalancer -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: LoadBalancer -IP: 10.96.67.165 -Port: 80/TCP -TargetPort: 80/TCP -NodePort: 31222/TCP -Endpoints: 10.46.0.1:80 -Session Affinity: None -External Traffic Policy: Cluster -Events: -``` - -Removendo o service: - -``` -kubectl delete -f primeiro-service-loadbalancer.yaml - -service "nginx-loadbalancer" deleted -``` - -## EndPoint - -Sempre que criamos um service, automaticamente é criado um endpoint. O endpoint nada mais é do que o IP do pod que o service irá utilizar, por exemplo, quando criamos um service do tipo ClusterIP temos o seu IP, correto? - -Agora, quando batemos nesse IP ele redireciona a conexão para o **Pod** através desse IP, o **EndPoint**. - -Para listar os EndPoints criados, execute o comando: - -``` -kubectl get endpoints - -NAME ENDPOINTS AGE -kubernetes 10.142.0.5:6443 4d -``` - -Vamos verificar esse endpoint com mais detalhes. - -``` -kubectl describe endpoints kubernetes - -Name: kubernetes -Namespace: default -Labels: -Annotations: -Subsets: - Addresses: 172.31.17.67 - NotReadyAddresses: - Ports: - Name Port Protocol - ---- ---- -------- - https 6443 TCP - -Events: -``` - -Vamos fazer um exemplo, para isso, vamos realizar a criação de um deployment, aumentar o número de réplicas para 3 e na sequência um service para que possamos ver com mais detalhes os endpoints que serão criados. - -``` -kubectl create deployment nginx --image=nginx - -deployment.apps/nginx created -``` - -Observando os deployments: - -``` -kubectl get deployments.apps - -NAME READY UP-TO-DATE AVAILABLE AGE -nginx 1/1 1 1 5s -``` - -Escalando o deployment nginx para 3 réplicas: - -``` -kubectl scale deployment nginx --replicas=3 - -deployment.apps/nginx scaled -``` - -Observando os deployments: - -``` -kubectl get deployments.apps - -NAME READY UP-TO-DATE AVAILABLE AGE -nginx 3/3 3 3 1m5s -``` - -Expondo o deployment nginx: - -``` -kubectl expose deployment nginx --port=80 - -service/nginx exposed -``` - -Visualizando o service: - -``` -kubectl get svc - -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubernetes ClusterIP 10.96.0.1 443/TCP 40m -nginx ClusterIP 10.98.153.22 80/TCP 6s -``` - -Acessando o ``nginx``: - -``` -curl 10.98.153.22 - -... -

Welcome to nginx!

-... -``` - -Visualizando os endpoints: - -``` -kubectl get endpoints - -NAME ENDPOINTS AGE -kubernetes 172.31.17.67:6443 44m -nginx 10.32.0.2:80,10.32.0.3:80,10.46.0.2:80 3m31s -``` - -Visualizando os detalhes do endpoint ``nginx``: - -``` -kubectl describe endpoints nginx - -Name: nginx -Namespace: default -Labels: app=nginx -Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2020-05-10T17:47:05Z -Subsets: - Addresses: 10.32.0.2,10.32.0.3,10.46.0.2 - NotReadyAddresses: - Ports: - Name Port Protocol - ---- ---- -------- - 80 TCP - -Events: -``` - -Visualizando o endpoint no formato YAML. - -``` -kubectl get endpoints -o yaml - -apiVersion: v1 -items: -- apiVersion: v1 - kind: Endpoints - metadata: - creationTimestamp: "2020-05-10T17:06:12Z" - managedFields: - - apiVersion: v1 - fieldsType: FieldsV1 - fieldsV1: - f:subsets: {} - manager: kube-apiserver - operation: Update - time: "2020-05-10T17:06:12Z" - name: kubernetes - namespace: default - resourceVersion: "163" - selfLink: /api/v1/namespaces/default/endpoints/kubernetes - uid: 39f1e237-f9cc-4553-a32d-95402ff52f6c -... - - ip: 10.46.0.2 - nodeName: elliot-03 - targetRef: - kind: Pod - name: nginx-f89759699-dmt4t - namespace: default - resourceVersion: "6805" - uid: 6a9c4639-78ee-44c6-8eb1-4fd90d308189 - ports: - - port: 80 - protocol: TCP -kind: List -metadata: - resourceVersion: "" - selfLink: "" -``` - -Removendo o deployment ``nginx``: - -``` -kubectl delete deployment nginx - -deployment.apps "nginx" deleted -``` - -Removendo o service: - -``` -kubectl delete service nginx - -service "nginx" deleted -``` - -# Limitando Recursos - -Quando criamos um Pod podemos especificar a quantidade de CPU e Memória (RAM) que pode ser consumida em cada contêiner. Quando algum contêiner contém a configuração de limite de recursos o Scheduler fica responsável por alocar esse contêiner no melhor nó possível de acordo com os recursos disponíveis. - -Podemos configurar dois tipos de recursos, CPU que é especificada em **unidades de núcleos** e Memória que é especificada em **unidades de bytes**. - -Vamos criar nosso primeiro Deployment com limite de recursos, para isso vamos subir a imagem de um ``nginx`` e copiar o ``yaml`` do deployment com o seguinte comando. - -``` -kubectl create deployment nginx --image=nginx - -deployment.apps/nginx created -``` - -Escalando o deployment para 3 réplicas: - -``` -kubectl scale deployment nginx --replicas=3 - -deployment.apps/nginx scaled -``` - -Obtendo a lista de deployments: - -``` -kubectl get deployments - -NAME READY UP-TO-DATE AVAILABLE AGE -nginx 3/3 3 3 24s -``` - -Crie o seguinte arquivo: - -``` -vim deployment-limitado.yaml -``` - -O conteúdo deve ser o seguinte. - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: nginx - name: nginx - namespace: default -spec: - progressDeadlineSeconds: 600 - replicas: 3 - revisionHistoryLimit: 10 - selector: - matchLabels: - app: nginx - strategy: - rollingUpdate: - maxSurge: 25% - maxUnavailable: 25% - type: RollingUpdate - template: - metadata: - creationTimestamp: null - labels: - app: nginx - spec: - containers: - - image: nginx - imagePullPolicy: Always - name: nginx - # Adicione as seguintes linhas - resources: - limits: - memory: "256Mi" - cpu: "200m" - requests: - memory: "128Mi" - cpu: "50m" - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 -``` - -> **Atenção!!!** **1 core de CPU** corresponde a ``1000m`` (1000 milicore). Ao especificar ``200m``, estamos querendo reservar 20% de 1 core da CPU. Se fosse informado o valor ``0.2`` teria o mesmo efeito, ou seja, seria reservado 20% de 1 core da CPU. - -Vamos remover o deployment do ``nginx``: - -``` -kubectl delete deployments.apps nginx -``` - -Agora vamos criar nosso deployment e verificar os recursos. - -``` -kubectl create -f deployment-limitado.yaml - -deployment.apps/nginx created -``` - -Vamos acessar um contêiner e testar a configuração: - -``` -kubectl get pod - -NAME READY STATUS RESTARTS AGE -nginx 1/1 Running 0 12m -nginx-f89759699-77v8b 1/1 Running 0 117s -nginx-f89759699-ffbgh 1/1 Running 0 117s -nginx-f89759699-vzvlt 1/1 Running 0 2m2s -``` - -Acessando o shell de um pod: - -``` -kubectl exec -ti nginx-f89759699-77v8b -- /bin/bash -``` - -Agora no contêiner, instale e execute o ``stress`` para simular a carga em nossos recursos, no caso CPU e memória. - -Instalando o comando stress: - -``` -apt-get update && apt-get install -y stress -``` - -Executando o ``stress``: - -``` -stress --vm 1 --vm-bytes 128M --cpu 1 - -stress: info: [221] dispatching hogs: 1 cpu, 0 io, 1 vm, 0 hdd -``` -Aqui estamos _stressando_ o contêiner, utilizando 128M de RAM e um core de CPU. Brinque de acordo com os limites que você estabeleceu. - -Quando ultrapassar o limite configurado, você receberá um erro como mostrado ao executar o seguinte comando, pois ele não conseguirá alocar os recursos de memória: - -``` -stress --vm 1 --vm-bytes 512M --cpu 1 - -stress: info: [230] dispatching hogs: 1 cpu, 0 io, 1 vm, 0 hdd -stress: FAIL: [230] (415) <-- worker 232 got signal 9 -stress: WARN: [230] (417) now reaping child worker processes -stress: FAIL: [230] (451) failed run completed in 0s -``` - -Para acompanhar a quantidade de recurso que o pod está utilizando, podemos utilizar o ``kubectl top``. Lembre-se de executar esse comando no node e não no contêiner. :) - -``` -kubectl top pod --namespace=default nginx-f89759699-77v8b - -NAME CPU(cores) MEMORY(bytes) -nginx-85f7fb6b45-b6dsk 201m 226Mi -``` - -# Namespaces - -No kubernetes temos um cara chamado de Namespaces como já vimos anteriormente. - -Mas o que é um Namespace? Nada mais é do que um cluster virtual dentro do próprio cluster físico do Kubernetes. Namespaces são uma maneira de dividir recursos de um cluster entre vários ambientes, equipes ou projetos. - -Vamos criar nosso primeiro namespaces: - -``` -kubectl create namespace primeiro-namespace - -namespace/primeiro-namespace created -``` - -Vamos listar todos os namespaces do kubernetes: - -``` -kubectl get namespaces - -NAME STATUS AGE -default Active 55m -kube-node-lease Active 56m -kube-public Active 56m -kube-system Active 56m -primeiro-namespace Active 5s -``` - -Pegando mais informações do nosso namespace: - -``` -kubectl describe namespace primeiro-namespace - -Name: primeiro-namespace -Labels: -Annotations: -Status: Active - -No resource quota. - -No LimitRange resource. -``` - -Como podemos ver, nosso namespace ainda está sem configurações, então iremos utilizar o ``LimitRange`` para adicionar limites de recursos. - -Vamos criar o manifesto do ``LimitRange``: - -``` -vim limitando-recursos.yaml -``` - -O conteúdo deve ser o seguinte. - -```yaml -apiVersion: v1 -kind: LimitRange -metadata: - name: limitando-recursos -spec: - limits: - - default: - cpu: 1 - memory: 100Mi - defaultRequest: - cpu: 0.5 - memory: 80Mi - type: Container -``` - -Agora vamos adicionar esse ``LimitRange`` ao Namespace: - -``` -kubectl create -f limitando-recursos.yaml -n primeiro-namespace - -limitrange/limitando-recursos created -``` - -Listando o ``LimitRange``: - -``` -kubectl get limitranges - -No resources found in default namespace. -``` - -Opa! Não encontramos não é mesmo? Mas claro, esquecemos de passar nosso namespace na hora de listar: - -``` -kubectl get limitrange -n primeiro-namespace - -NAME CREATED AT -limitando-recursos 2020-05-10T18:02:51Z -``` - -Ou: - -``` -kubectl get limitrange --all-namespaces - -NAMESPACE NAME CREATED AT -primeiro-namespace limitando-recursos 2020-05-10T18:02:51Z -``` - -Vamos dar um describe no ``LimitRange``: - -``` -kubectl describe limitrange -n primeiro-namespace - -Name: limitando-recursos -Namespace: primeiro-namespace -Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio ----- -------- --- --- --------------- ------------- ----------------------- -Container cpu - - 500m 1 - -Container memory - - 80Mi 100Mi - -``` - -Como podemos observar, adicionamos limites de memória e cpu para cada contêiner que subir nesse ``Namespace``, se algum contêiner for criado dentro do ``Namespace`` sem as configurações de ``Limitrange``, o contêiner irá herdar as configurações de limites de recursos do Namespace. - -Vamos criar um pod para verificar se o limite se aplicará: - -``` -vim pod-limitrange.yaml -``` - -O conteúdo deve ser o seguinte. - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: limit-pod -spec: - containers: - - name: meu-container - image: nginx -``` - -Agora vamos criar um pod fora do namespace default e outro dentro do namespace limitado (primeiro-namespace), e vamos observar os limites de recursos de cada contêiner e como foram aplicados: - -Criando o pod no namespace ``default``: - -``` -kubectl create -f pod-limitrange.yaml - -pod/limit-pod created -``` - -Criando o pod no namespace ``primeiro-namespace``: - -``` -kubectl create -f pod-limitrange.yaml -n primeiro-namespace - -pod/limit-pod created -``` - -Vamos listar esses pods e na sequência ver mais detalhes : - -``` -kubectl get pods --all-namespaces - -NAMESPACE NAME READY STATUS RESTARTS AGE -default limit-pod 1/1 Running 0 10s -primeiro-namespace limit-pod 1/1 Running 0 5s -``` - -Vamos ver mais detalhes do pod no namespace ``default``. - -``` -kubectl describe pod limit-pod - -Name: limit-pod -Namespace: default -Priority: 0 -Node: elliot-02/172.31.19.123 -Start Time: Sun, 10 May 2020 18:03:52 +0000 -Labels: -Annotations: -Status: Running -IP: 10.32.0.4 -IPs: - IP: 10.32.0.4 -Containers: - meu-container: - Container ID: docker://19850dc935ffa41b1754cb58ab60ec5bb3616bbbe6a958abe1b2575bd26ee73d - Image: nginx -... -``` - -Vamos ver mais detalhes do pod no namespace ``primeiro-namespace``. - -``` -kubectl describe pod limit-pod -n primeiro-namespace - -Name: limit-pod -Namespace: primeiro-namespace -Priority: 0 -Node: elliot-03/172.31.24.60 -Start Time: Sun, 10 May 2020 18:03:57 +0000 -Labels: -Annotations: kubernetes.io/limit-ranger: - LimitRanger plugin set: cpu, memory request for container meu-container; cpu, memory limit for container meu-container -Status: Running -IP: 10.46.0.3 -IPs: - IP: 10.46.0.3 -Containers: - meu-container: - Container ID: docker://ad3760837d71955df47263a2031d4238da2e94002ce4a0631475d301faf1ddef - Image: nginx -... - Limits: - cpu: 1 - memory: 100Mi - Requests: - cpu: 500m - memory: 80Mi -``` - -Como podemos ver o **Pod** no namespace ``primeiro-namespace`` está com limit de recursos configurados. - -# Kubectl taint - -O **Taint** nada mais é do que adicionar propriedades ao nó do cluster para impedir que os pods sejam alocados em nós inapropriados. - -Por exemplo, todo nó ``master`` do cluster é marcado para não receber pods que não sejam de gerenciamento do cluster. - -O nó ``master`` está marcado com o taint ``NoSchedule``, assim o scheduler do Kubernetes não aloca pods no nó master, e procura outros nós no cluster sem essa marca. - -Visualizando os nodes do cluster: - -``` -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -elliot-01 Ready master 7d14h v1.18.2 -elliot-02 Ready 7d14h v1.18.2 -elliot-03 Ready 7d14h v1.18.2 -``` - -Visualizando as labels Taints do node ``master``: - -``` -kubectl describe node elliot-01 | grep -i taint - -Taints: node-role.kubernetes.io/master:NoSchedule -``` - -**Vamos testar algumas coisas e permitir que o nó master rode outros pods.** - -Primeiro vamos rodar 3 réplicas de ``nginx``: - -``` -kubectl create deployment nginx --image=nginx - -deployment.apps/nginx created -``` - -Visualizando os deployments: - -``` -kubectl get deployments.apps - -NAME READY UP-TO-DATE AVAILABLE AGE -nginx 1/1 1 1 5s -``` - -Escalando o deployment do nginx para 3 réplicas: - -``` -kubectl scale deployment nginx --replicas=3 - -deployment.apps/nginx scaled -``` - -Visualizando novamente os deployments: - -``` -kubectl get deployments.apps - -NAME READY UP-TO-DATE AVAILABLE AGE -nginx 3/3 3 3 1m5s -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -limit-pod 1/1 Running 0 3m44s 10.32.0.4 elliot-02 -nginx 1/1 Running 0 25m 10.46.0.1 elliot-03 -nginx-85f7fb6b45-9bzwc 1/1 Running 0 6m7s 10.32.0.3 elliot-02 -nginx-85f7fb6b45-cbmtr 1/1 Running 0 6m7s 10.46.0.2 elliot-03 -nginx-85f7fb6b45-rprz5 1/1 Running 0 6m7s 10.32.0.2 elliot-02 -``` - -Vamos adicionar a marca ``NoSchedule`` aos nós worker também para ver como eles se comportam. - -Node worker 1: - -``` -kubectl taint node elliot-02 key1=value1:NoSchedule - -node/elliot-02 tainted -``` - -Node worker 2: - -``` -kubectl taint node elliot-03 key1=value1:NoSchedule - -node/elliot-03 tainted -``` - -Visualizando a label Taint no node worker 1: - -``` -kubectl describe node elliot-02 | grep -i taint - -Taints: key1=value1:NoSchedule -``` - -Visualizando a label Taint no node worker 2: - -``` -kubectl describe node elliot-03 | grep -i taint - -Taints: key1=value1:NoSchedule -``` - -Agora vamos aumentar a quantidade de réplicas: - -``` -kubectl scale deployment nginx --replicas=5 - -deployment.apps/nginx scaled -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -limit-pod 1/1 Running 0 5m23s 10.32.0.4 elliot-02 -nginx 1/1 Running 0 27m 10.46.0.1 elliot-03 -nginx-85f7fb6b45-9bzwc 1/1 Running 0 7m46s 10.32.0.3 elliot-02 -nginx-85f7fb6b45-cbmtr 1/1 Running 0 7m46s 10.46.0.2 elliot-03 -nginx-85f7fb6b45-qnhtl 0/1 Pending 0 18s -nginx-85f7fb6b45-qsvpp 0/1 Pending 0 18s -nginx-85f7fb6b45-rprz5 1/1 Running 0 7m46s 10.32.0.2 elliot-02 -``` - -Como podemos ver, as nova réplicas ficaram órfãs esperando aparecer um nó com as prioridades adequadas para o Scheduler. - -Vamos remover esse Taint dos nossos nós worker: - -Removendo o taint do worker 1: - -``` -kubectl taint node elliot-02 key1:NoSchedule- - -node/elliot-02 untainted -``` - -Removendo o taint do worker 2: - -``` -kubectl taint node elliot-03 key1:NoSchedule- - -node/elliot-03 untainted -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -limit-pod 1/1 Running 0 6m17s 10.32.0.4 elliot-02 -nginx 1/1 Running 0 27m 10.46.0.1 elliot-03 -nginx-85f7fb6b45-9bzwc 1/1 Running 0 8m40s 10.32.0.3 elliot-02 -nginx-85f7fb6b45-cbmtr 1/1 Running 0 8m40s 10.46.0.2 elliot-03 -nginx-85f7fb6b45-qnhtl 1/1 Running 0 72s 10.46.0.5 elliot-03 -nginx-85f7fb6b45-qsvpp 1/1 Running 0 72s 10.46.0.4 elliot-03 -nginx-85f7fb6b45-rprz5 1/1 Running 0 8m40s 10.32.0.2 elliot-02 -``` - -Existem vários tipos de marcas que podemos usar para classificar os nós, vamos testar uma outra chamada ``NoExecute``, que impede o Scheduler de agendar Pods nesses nós. - -Adicionando a marca ``NoExecute`` no worker 1: - -``` -kubectl taint node elliot-02 key1=value1:NoExecute - -node/elliot-02 tainted -``` - -Adicionando a marca ``NoExecute`` no worker 2: - -``` -kubectl taint node elliot-03 key1=value1:NoExecute - -node/elliot-03 tainted -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -nginx-85f7fb6b45-87sq5 0/1 Pending 0 20s -nginx-85f7fb6b45-8q99g 0/1 Pending 0 20s -nginx-85f7fb6b45-drmzz 0/1 Pending 0 20s -nginx-85f7fb6b45-hb4dp 0/1 Pending 0 20s -nginx-85f7fb6b45-l6zln 0/1 Pending 0 20s -``` - -Como podemos ver todos os Pods estão órfãs. Porque o nó ``master`` tem a marca taint ``NoScheduler`` default do kubernetes e os nós worker tem a marca ``NoExecute``. - -Vamos diminuir a quantidade de réplicas para ver o que acontece. - -Reduzindo a quantidade de réplicas no worker 1: - -``` -kubectl scale deployment nginx --replicas=1 - -deployment.apps/nginx scaled -``` - -Reduzindo a quantidade de réplicas no worker 2: - -``` -kubectl get pods - -nginx-85f7fb6b45-drmzz 0/1 Pending 0 43s -``` - -Vamos remover o taint ``NoExecute`` do nós workers. - -Removendo o taint no worker 1: - -``` -kubectl taint node elliot-02 key1:NoExecute- - -node/elliot-02 untainted -``` - -Removendo o taint no worker 2: - -``` -kubectl taint node elliot-03 key1:NoExecute- - -node/elliot-03 untainted -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods - -NAME READY STATUS RESTARTS AGE -nginx-85f7fb6b45-drmzz 1/1 Running 0 76s -``` - -Agora temos um nó operando normalmente. - -Mas e se nossos workers ficarem indisponíveis, podemos rodar Pods no nó master? - -Claro que podemos, vamos configurar nosso nó master para que o Scheduler consiga agenda Pods nele. - -``` -kubectl taint nodes --all node-role.kubernetes.io/master- - -node/elliot-01 untainted -``` - -Visualizando a marca taint no nó master. - -``` -kubectl describe node elliot-01 | grep -i taint - -Taints: -``` - -Agora vamos aumentar a quantidade de réplicas do nosso pod ``nginx``. - -``` -kubectl scale deployment nginx --replicas=4 - -deployment.apps/nginx scaled -``` - -Visualizando os detalhes dos pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -nginx-85f7fb6b45-2c6dm 1/1 Running 0 9s 10.32.0.2 elliot-02 -nginx-85f7fb6b45-4jzcn 1/1 Running 0 9s 10.32.0.3 elliot-02 -nginx-85f7fb6b45-drmzz 1/1 Running 0 114s 10.46.0.1 elliot-03 -nginx-85f7fb6b45-rstvq 1/1 Running 0 9s 10.46.0.2 elliot-03 -``` - -Vamos adicionar o Taint ``NoExecute`` nos nós worker para ver o que acontece. - -Adicionando o taint no worker 1: - -``` -kubectl taint node elliot-02 key1=value1:NoExecute - -node/elliot-02 tainted -``` - -Adicionando o taint no worker 2: - -``` -kubectl taint node elliot-03 key1=value1:NoExecute - -node/elliot-03 tainted -``` - -Visualizando os detalhes do pods: - -``` -kubectl get pods -o wide - -NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES -nginx-85f7fb6b45-49knz 1/1 Running 0 14s 10.40.0.5 elliot-01 -nginx-85f7fb6b45-4cm9x 1/1 Running 0 14s 10.40.0.4 elliot-01 -nginx-85f7fb6b45-kppnd 1/1 Running 0 14s 10.40.0.6 elliot-01 -nginx-85f7fb6b45-rjlmj 1/1 Running 0 14s 10.40.0.3 elliot-01 -``` - -Removendo o deployment ``nginx``: - -``` -kubectl delete deployment nginx - -deployment.extensions "nginx" deleted -``` - -O Scheduler alocou tudo no nó ``master``, como podemos ver o Taint pode ser usado para ajustar configurações de qual Pod deve ser alocado em qual nó. - -Vamos permitir que nosso Scheduler aloque e execute os Pods em todos os nós: - -Removendo o taint ``NoSchedule`` em todos os nós do cluster: - -``` -kubectl taint node --all key1:NoSchedule- - -node/elliot-01 untainted -node/elliot-02 untainted -node/elliot-03 untainted -``` - -Removendo o taint ``NoExecute`` em todos os nós do cluster: - -``` -kubectl taint node --all key1:NoExecute- - -node/kube-worker1 untainted -node/kube-worker2 untainted -error: taint "key1:NoExecute" not found -``` - -Visualizando os taints dos nodes: - -``` -kubectl describe node elliot-01 | grep -i taint - -Taints: -``` - -# Colocando o nó em modo de manutenção - -Para colocar o nó em manutenção iremos utilizar o ``cordon``. - -``` -kubectl cordon elliot-02 - -node/elliot-02 cordoned -``` - -Visualizando o node em manutenção. - -``` -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -elliot-01 Ready master 7d14h v1.18.2 -elliot-02 Ready,SchedulingDisabled 7d14h v1.18.2 -elliot-03 Ready 7d14h v1.18.2 -``` - -Repare que o nó ``elliot-02`` ficou com o status ``Ready,SchedulingDisabled``, agora você pode fazer a manutenção no seu node tranquilamente. Para retirar nó de modo de manutenção, iremos utilizar o ``uncordon``. - -``` -kubectl uncordon elliot-02 - -node/elliot-02 uncordoned -``` - -Visualizando novamente os nós. - -``` -kubectl get nodes - -NAME STATUS ROLES AGE VERSION -elliot-01 Ready master 7d14h v1.18.2 -elliot-02 Ready 7d14h v1.18.2 -elliot-03 Ready 7d14h v1.18.2 -``` - -Pronto, agora seu nó não está mais em modo de manutenção.