DevOps

Implantar um cluster aks via crossplane provider Azure

Neste artigo vamos apresentar o Crossplane, e para nossa demonstração iremos prover um cluster Kubernetes (K8S) na Azure (AKS), caso queira ver como provisionar algum outro recurso em outro provedor de nuvem (AWS, GCP, OCI…) deixe nos comentários que podemos fazer um artigo abordando o assunto.

Crossplane é um framework que permite o controle e deploy de recursos na nuvem sem a necessidade de escrever código como acontece com o Pulumi por exemplo, e como ele roda via K8S ele usa o gerenciador de estado para orquestrar e sincronizar os recursos implantados dos que estão em produção. Para integração completa com os principais provedores do mercado o crossplane conta com um marketplace suportado pela upbound e comunidade, em nosso exemplo usaremos providers da comunidade.

Atualização: Na parte de credenciais, indicamos inicialmente as roles Directory.ReadWrite.All e Application.ReadWrite.All. Em vez disso, mudamos para as seguintes: Directory.Read.All e Application.ReadWrite.OwnedBy. Desta forma, o SP criado tem os acessos reduzidos, aumentando a segurança da nossa app e, mesmo assim, não impossibilitando a criação de um AKS. Caso tenha usado outras permissões, comente abaixo.

Pré-Requisitos

  • Minikube ou Docker Desktop ou Rancher Desktop
  • kubectl
  • Helm
  • Azure CLI
  • Assinatura Ativa ou conta gratuita junto a Azure

Explicando estrutura do projeto

Nosso projeto está estruturado de forma a criar um tipo de recurso por arquivo, deixamos genérico o suficiente para que trocando apenas os valores presentes em azure.vars.sh seja o suficiente para fazer deploy de um cluster AKS, porém é altamente recomendado que leia e entenda o que cada um deles faz, caso queira consultar este projeto ele se encontra no github.

Explicando o arquivo azure.vars.sh

#!/bin/sh

export CIL_LOCATION="East US"
export CIL_PROVIDER_NAME="codeinloop-provider-azure"
export CIL_PROVIDER_CONFIG_NAME="codeinloop-provider-config-azure"
export CIL_RESOURCE_GROUP_NAME="codeinloop-crossplane"
export CIL_VNET_NAME="codeinloop-vnet"
export CIL_VNET_SUBNET_NAME="codeinloop-subnet"
export CIL_AKS_NAME="codeinloop-crossplane"
export CIL_SECRET_NAME="codeinloop-creds"
export CIL_CROSSPLANE_NS="crossplane-system"
export CIL_K8S_VERSION="1.29.2"
export CIL_AKS_FLAVOR="Standard_B2s"
export CIL_AKS_NODE=1
export CIL_AKS_DNS_PREFIX="codeinloop-crossplane"
export CIL_SECRETS_VALUE=$(base64 -w 0 < creds.json)
Bash
  • CIL_LOCATION = Refere-se a região aonde seus recursos serão deployados, neste site no nosso exemplo usaremos East US
  • CIL_PROVIDER_NAME = Nome dado para o Provider Azure
  • CIL_PROVIDER_CONFIG_NAME = Nome dado para o Provider de Configuração
  • CIL_RESOURCE_GROUP_NAME = Nome usado como Resource Group na Azure
  • CIL_VNET_NAME = Nome do Virtual Network
  • CIL_VNET_SUBNET_NAME = Nome da Subnet do Virtual Network
  • CIL_AKS_NAME = Nome do AKS
  • CIL_SECRET_NAME = Nome da secret que armazenará as credenciais da Azure
  • CIL_CROSSPLANE_NS = Namespace usada para fazer deploy do Crossplane
  • CIL_K8S_VERSION = Versão do Kubernetes, consulte as versões disponiveis na Azure aqui
  • CIL_AKS_FLAVOR = Configuração de Memória Ram, HD e CPU da máquina virtual usada pelo cluster, consulte este link para ver outras opções
  • CIL_AKS_NODE = Quantidade de máquinas que vão compor o cluster AKS
  • CIL_AKS_DNS_PREFIX = Prefixo do domínio fornecido pela Azure
  • CIL_SECRETS_VALUE = Credenciais geradas pela CLI do azure e salvas no creds.json

Ajuste este arquivo de acordo com seu cenário.

Instalação e login no Azure CLI

Neste guia vamos abordar a instalação do CLI via pacote Deb para sistemas operacionais como Ubuntu e Debian, para os demais recomendamos este link. Uma vez com o terminal aberto, rode:

sudo apt update
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
Bash

Caso tenha erro ao fazer a instalação verifique a versão do Python, até o momento em que escrevemos o artigo o CLI precisava da versão 3.9.x do python, use o ASDF para mudar a versão do Python.

Após instalado devemos autenticar o CLI.

az login --use-device-code
Bash

Uma vez logado, podemos ir para os próximos passos.

Instalando o Crossplane no MiniKube via helm

Com o MiniKube instalado e sem nenhuma configuração especial, a instalação do crossplane é bem simples e basta ter o helm instalado. Com ele instalado vamos aos seguintes comandos:

helm repo add crossplane https://charts.crossplane.io/stable;
helm repo update

. ./azure-vars.sh; helm upgrade --install crossplane crossplane/crossplane \
--namespace ${CIL_CROSSPLANE_NS} \
--create-namespace 

curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh" | sh
Bash

Na última linha também mostramos como instalar o CLI, que não vamos usar nesse artigo porém recomendamos o uso. Para ver se deu tudo certo com a instalação basta ver os pods na namespace recém criada:

. ./azure-vars.sh; kubectl get pods -n  ${CIL_CROSSPLANE_NS}
Bash

Criando Service Aplication com credenciais de acesso na Azure

Uma vez autenticado, podemos criar o nosso SP. Use a variável CIL_AZURE_SUBSCRIPTION_ID para inserir o ID da sua subscrição, veja este link para saber como obter este ID.

Na variável CIL_AZURE_SP_NAME coloque o nome usado durante a criação da aplicação.


export CIL_AZURE_SUBSCRIPTION_ID="be5a7d8a-7907-415a-b62e"
export CIL_AZURE_SP_NAME="codeinloop-df-rbac"

az ad sp create-for-rbac --sdk-auth \
--role Owner \
--scopes="/subscriptions/${CIL_AZURE_SUBSCRIPTION_ID}" -n ${CIL_AZURE_SP_NAME} > "creds.json"
az ad sp create-for-rbac --role Owner --scopes="/subscriptions/${CIL_AZURE_SUBSCRIPTION_ID}" --sdk-auth -n ${CIL_AZURE_SP_NAME} > "creds.json"

if which jq > /dev/null 2>&1; then
  AZURE_CLIENT_ID=$(jq -r ".clientId" < "./creds.json")
else
  AZURE_CLIENT_ID=$(cat creds.json | grep clientId | cut -c 16-51)
fi

RW_ALL_APPS=1cda74f2-2616-4834-b122-5cb1b07f8a59
RW_DIR_DATA=5778995a-e1bf-45b8-affa-663a9f3f4d04
AAD_GRAPH_API=00000002-0000-0000-c000-000000000000
az ad app permission add --id "${AZURE_CLIENT_ID}" --api ${AAD_GRAPH_API} --api-permissions ${RW_ALL_APPS}=Role ${RW_DIR_DATA}=Role

#Necessario ter acesso de Administrador da conta para rodar o comando abaixo.
az ad app permission admin-consent --id "${AZURE_CLIENT_ID}"
Bash

Vale destacar que para este comando funcionar é preciso que tenha acesso de admin para poder autorizar, caso contrário o último comando terá que ser executado via CLI ou tela pelo Administrador da conta Azure.

Provendo recursos para criação do AKS via Crossplane

Para a comunicação entre seu kubernetes e as apis da Azure é necessário instalar um provider do Crossplane. Para nosso exemplo estamos usando este, sua instalação é demonstrada no arquivo azure-provider.yaml. Além disso configuramos o provider de configuração no mesmo arquivo, nele devemos definir qual o nome da nossa secret, este que conterá as credenciais da nossa SP com acesso de criação de recursos.

apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
 name: ${CIL_PROVIDER_NAME}
spec:
 package: "xpkg.upbound.io/crossplane-contrib/provider-azure:v0.20.1"
---
apiVersion: azure.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
 name: ${CIL_PROVIDER_CONFIG_NAME}
spec:
 credentials:
   source: Secret
   secretRef:
     namespace: ${CIL_CROSSPLANE_NS}
     name: ${CIL_SECRET_NAME}
     key: creds
YAML

Após a instalação do provider temos acesso às apis, que neste caso estão separadas por 24 grupos e delas usamos apenas 3, são elas:

Resource Group

Usamos o Resource Group como forma lógica de separar os recursos e com base no nosso provider ele é criado com essa estrutura:

apiVersion: azure.crossplane.io/v1alpha3
kind: ResourceGroup
metadata:
  name: ${CIL_RESOURCE_GROUP_NAME}
spec:
  location: ${CIL_LOCATION}
  providerConfigRef:
    name: ${CIL_PROVIDER_CONFIG_NAME}
YAML

Azure network

Precisamos de uma rede para ingressar nossas máquinas e fazemos isso com o arquivo azure-network.yaml, nele criamos tanto o virtual network quanto a subnet.

apiVersion: network.azure.crossplane.io/v1alpha3
kind: VirtualNetwork
metadata:
  name: ${CIL_VNET_NAME}
spec:
  location: ${CIL_LOCATION}
  properties:
    addressSpace:
      addressPrefixes:
        - 10.3.0.0/16
  providerConfigRef:
    name: ${CIL_PROVIDER_CONFIG_NAME}
  resourceGroupNameRef:
    name: ${CIL_RESOURCE_GROUP_NAME}
---
apiVersion: network.azure.crossplane.io/v1alpha3
kind: Subnet
metadata:
  name: ${CIL_VNET_SUBNET_NAME}
spec:
  properties:
    addressPrefix: 10.3.0.0/24
  providerConfigRef:
    name: ${CIL_PROVIDER_CONFIG_NAME}
  resourceGroupNameRef:
    name: ${CIL_RESOURCE_GROUP_NAME}
  virtualNetworkNameRef:
    name: ${CIL_VNET_NAME}
YAML

AKS Gerenciado

Por último porém não menos importante, vamos definir o arquivo de configuração do AKS é nele que vamos definir o tamanho da máquina, prefixo da dns e afins.

apiVersion: compute.azure.crossplane.io/v1alpha3
kind: AKSCluster
metadata:
  name: ${CIL_AKS_NAME}
  name: ${CIL_AKS_NAME}
spec:
  dnsNamePrefix: ${CIL_AKS_DNS_PREFIX}
  location: ${CIL_LOCATION}
  nodeCount: ${CIL_AKS_NODE}
  nodeVMSize: ${CIL_AKS_FLAVOR}
  version: ${CIL_K8S_VERSION}
  disableRBAC: false
  providerConfigRef:
    name: ${CIL_PROVIDER_CONFIG_NAME}
  resourceGroupNameRef:
    name: ${CIL_RESOURCE_GROUP_NAME}
  vnetSubnetIDRef:
    name: ${CIL_VNET_SUBNET_NAME}
  writeConnectionSecretToRef:
    name: ${CIL_AKS_NAME}
    namespace: ${CIL_CROSSPLANE_NS}
YAML

Vale lembrar que no marketplace você consegue encontrar todos os parâmetros disponíveis na última versão, caso este tutorial em algum momento fique desatualizado a documentação é recomendada, coloque nos comentários também para que possamos atualizar.

Executando tudo

Como já preparamos um repositório com todo o código, uma vez clonados e alterados os valores, podemos simplesmente rodar esses comandos para criar os recursos descritos acima:

. ./azure-vars.sh; envsubst < azure-secret.yaml | kubectl apply -f -
cat ./azure-provider.yaml | envsubst | kubectl apply -f -
cat ./azure-resourcegroup.yaml | envsubst | kubectl apply -f -
cat ./azure-network.yaml | envsubst | kubectl apply -f -
cat ./azure-aks.yaml | envsubst | kubectl apply -f -
Bash

Rode um por um a fim de validar erros durante a execução. Se tudo der certo no final você terá um cluster com um nó na Azure pronto para uso.

Durante a execução de cada linha você poderá ver a situação dela, por exemplo na imagem abaixo está o resultado do comando kubectl get akscluster:

Nesta imagem temos o nome, se ele já foi criado, sua situação de sincronia entre o Crossplane e a Microsoft Azure, sua endpoint (se possuir), localização e tempo de vida. Em caso de erro ao obter a descrição do recurso, podemos contar com log da execução e desta forma validar algum tipo de erro, abaixo colocamos os dois comandos de exemplo:

kubectl get akscluster
kubectl describe akscluster codeinloop-crossplane
Bash

Como resultado do último comando teremos uma imagem similar a de baixo:

Remoção do AKS via Crossplane

Conforme dito mais acima um dos pontos positivos do Crossplane é a forma que ele usa o Kubernetes para garantir a integridade de estado, isso é, se você deletar os recursos diretamente pelo site da Azure, o kubernetes que estiver vinculado a essa conta validará a ausência do recurso e fará a recriação. É por isso que a melhor forma para remoção de recurso é pelo Crossplane, para manter a sincronia. Com isso vamos fazer o delete na ordem inversa a de criação.

. ./azure-vars.sh; cat ./azure-resourcegroup.yaml | envsubst | kubectl delete -f -
cat ./azure-provider.yaml | envsubst | kubectl delete -f -
. ./azure-vars.sh; envsubst < azure-secret.yaml | kubectl delete -f -
Bash

Execute os dois últimos comandos se desejar remover o provider e credenciais da Azure do seu Crossplane, caso queira apenas desprover os recursos pode pular os dois últimos comandos.

Conclusão

Já conhecia o Crossplane? Usa qual ferramenta para criar infraestrutura nos provedores de cloud? Deixa aqui nos comentários, em caso de dúvida ou sugestão não deixe de comentar.

2 Comentários

  1. Maravilha de artigo. Estamos em um processo implantação do Crossplane no Azure e o artigo caiu como uma luva. Seria muito legal poder ler mais sobre essa stack.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.