Fala galera! Espero que estejam todos bem!
Dando continuidade a nossa séria de provisionamento de bancos de dados no Azure Kubernetes Service vamos ter uma sequencia de bancos de dados considerados como distribuídos, ou seja, que assim como Redis que vimos no ultimo post, conseguem escalar horizontalmente tanto em escrita como leitura, mas com a diferença de que eles entregam uma capacidade relacional diferente dos bancos de dados NoSQL como o próprio Redis, Cassandra, MongoDB e outros.
Neste capitulo veremos o famigerado BarataDB ou comumente conhecido por: CockroachDB (rsrs).
O CockroachDB é um banco de dados distribuído, de escalabilidade horizontal, que possiu uma engine NoSQL key-valued store (assim como o Redis) mas que também implementa uma camada de conexão PostgreSQL onde, apesar de possuir um core NoSQL, se comporta como um banco de dados relacional, contendo tabelas, relacionamentos e ACID.
Vamos iniciar o provisionamento do nosso cluster de banco de dados iniciando pela criação de um CRD ou Custom Resource Definition que é uma forma de estendermos as capacidades da API padrão do Kubernetes fazendo com que ela se comporte de forma especifica para a criação de um determinado recurso não nativo do K8s. Para criar o CRD basta executar:
kubectl apply -f https://raw.githubusercontent.com/cockroachdb/cockroach-operator/v2.10.0/install/crds.yaml

Agora, pela primeira vez, vamos criar um Operator que é o componente mais importante quando falamos em gerenciar clusters de bancos de dados no Kubernetes. O Operator é o recurso que gerencia o estado das instancias de bancos de dados, chaveando automaticamente os recursos em caso de falhas, rebalanciando carga, entre outras capacidades de gerenciamento.
Para baixar o yaml nativo do fornecedor basta executar:
curl -O https://raw.githubusercontent.com/cockroachdb/cockroach-operator/v2.10.0/install/operator.yaml
Vamos explorar este arquivo, o primeiro recurso a ser criado será um namespace de nome cockroach-operator-system:
apiVersion: v1
kind: Namespace
metadata:
labels:
control-plane: cockroach-operator
name: cockroach-operator-system
Depois temos a criação de um ServiceAccount que será utilizado para autenticação exclusiva dos Pods referentes ao cluster CockroachDB na API do K8s:
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: cockroach-operator
name: cockroach-operator-sa
namespace: cockroach-operator-system
Após isso temos a criação de RBAC’s ou Role-based Access Control onde serão declarados regras de acesso dos recursos referentes ao cluster Cockroach para dentro do K8s:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: cockroach-operator-role
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- get
- patch
- update
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- get
- patch
- update
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resources:
- statefulsets/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- apps
resources:
- statefulsets/scale
verbs:
- get
- update
- watch
- apiGroups:
- apps
resources:
- statefulsets/status
verbs:
- get
- patch
- update
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- batch
resources:
- jobs/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
- jobs/status
verbs:
- get
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- create
- delete
- get
- list
- patch
- watch
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/status
verbs:
- get
- patch
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps/status
verbs:
- get
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- list
- update
- apiGroups:
- ""
resources:
- pods
verbs:
- delete
- deletecollection
- get
- list
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
- apiGroups:
- ""
resources:
- pods/log
verbs:
- get
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- list
- watch
- apiGroups:
- ""
resources:
- services
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- services/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- services/status
verbs:
- get
- patch
- update
- apiGroups:
- crdb.cockroachlabs.com
resources:
- crdbclusters
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- crdb.cockroachlabs.com
resources:
- crdbclusters/finalizers
verbs:
- update
- apiGroups:
- crdb.cockroachlabs.com
resources:
- crdbclusters/status
verbs:
- get
- patch
- update
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses/status
verbs:
- get
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- policy
resources:
- poddisruptionbudgets/finalizers
verbs:
- get
- list
- watch
- apiGroups:
- policy
resources:
- poddisruptionbudgets/status
verbs:
- get
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
verbs:
- create
- get
- list
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
- roles
verbs:
- create
- get
- list
- watch
- apiGroups:
- security.openshift.io
resources:
- securitycontextconstraints
verbs:
- use
Criado o Cluster Role (RBAC) temos o vinculo deste com o Service Account criado anteriormente:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cockroach-operator-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cockroach-operator-role
subjects:
- kind: ServiceAccount
name: cockroach-operator-sa
namespace: cockroach-operator-system
Agora vamos criar o Service para expor a porta do Operator:
apiVersion: v1
kind: Service
metadata:
labels:
control-plane: cockroach-operator
name: cockroach-operator-webhook-service
namespace: cockroach-operator-system
spec:
ports:
- port: 443
targetPort: 9443
selector:
app: cockroach-operator
Agora temos a criação do Deployment que irá provisionar o Pod contendo o sistema de gerenciamento do cluster CockroachDB considerado o Operator em si:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: cockroach-operator
name: cockroach-operator-manager
namespace: cockroach-operator-system
spec:
replicas: 1
selector:
matchLabels:
app: cockroach-operator
template:
metadata:
labels:
app: cockroach-operator
spec:
containers:
- args:
- -zap-log-level
- info
env:
- name: RELATED_IMAGE_COCKROACH_v20_1_4
value: cockroachdb/cockroach:v20.1.4
- name: RELATED_IMAGE_COCKROACH_v20_1_5
value: cockroachdb/cockroach:v20.1.5
- name: RELATED_IMAGE_COCKROACH_v20_1_8
value: cockroachdb/cockroach:v20.1.8
- name: RELATED_IMAGE_COCKROACH_v20_1_11
value: cockroachdb/cockroach:v20.1.11
- name: RELATED_IMAGE_COCKROACH_v20_1_12
value: cockroachdb/cockroach:v20.1.12
- name: RELATED_IMAGE_COCKROACH_v20_1_13
value: cockroachdb/cockroach:v20.1.13
- name: RELATED_IMAGE_COCKROACH_v20_1_15
value: cockroachdb/cockroach:v20.1.15
- name: RELATED_IMAGE_COCKROACH_v20_1_16
value: cockroachdb/cockroach:v20.1.16
- name: RELATED_IMAGE_COCKROACH_v20_1_17
value: cockroachdb/cockroach:v20.1.17
- name: RELATED_IMAGE_COCKROACH_v20_2_0
value: cockroachdb/cockroach:v20.2.0
- name: RELATED_IMAGE_COCKROACH_v20_2_1
value: cockroachdb/cockroach:v20.2.1
- name: RELATED_IMAGE_COCKROACH_v20_2_2
value: cockroachdb/cockroach:v20.2.2
- name: RELATED_IMAGE_COCKROACH_v20_2_3
value: cockroachdb/cockroach:v20.2.3
- name: RELATED_IMAGE_COCKROACH_v20_2_4
value: cockroachdb/cockroach:v20.2.4
- name: RELATED_IMAGE_COCKROACH_v20_2_5
value: cockroachdb/cockroach:v20.2.5
- name: RELATED_IMAGE_COCKROACH_v20_2_6
value: cockroachdb/cockroach:v20.2.6
- name: RELATED_IMAGE_COCKROACH_v20_2_8
value: cockroachdb/cockroach:v20.2.8
- name: RELATED_IMAGE_COCKROACH_v20_2_9
value: cockroachdb/cockroach:v20.2.9
- name: RELATED_IMAGE_COCKROACH_v20_2_10
value: cockroachdb/cockroach:v20.2.10
- name: RELATED_IMAGE_COCKROACH_v20_2_11
value: cockroachdb/cockroach:v20.2.11
- name: RELATED_IMAGE_COCKROACH_v20_2_12
value: cockroachdb/cockroach:v20.2.12
- name: RELATED_IMAGE_COCKROACH_v20_2_13
value: cockroachdb/cockroach:v20.2.13
- name: RELATED_IMAGE_COCKROACH_v20_2_14
value: cockroachdb/cockroach:v20.2.14
- name: RELATED_IMAGE_COCKROACH_v20_2_15
value: cockroachdb/cockroach:v20.2.15
- name: RELATED_IMAGE_COCKROACH_v20_2_16
value: cockroachdb/cockroach:v20.2.16
- name: RELATED_IMAGE_COCKROACH_v20_2_17
value: cockroachdb/cockroach:v20.2.17
- name: RELATED_IMAGE_COCKROACH_v20_2_18
value: cockroachdb/cockroach:v20.2.18
- name: RELATED_IMAGE_COCKROACH_v20_2_19
value: cockroachdb/cockroach:v20.2.19
- name: RELATED_IMAGE_COCKROACH_v21_1_0
value: cockroachdb/cockroach:v21.1.0
- name: RELATED_IMAGE_COCKROACH_v21_1_1
value: cockroachdb/cockroach:v21.1.1
- name: RELATED_IMAGE_COCKROACH_v21_1_2
value: cockroachdb/cockroach:v21.1.2
- name: RELATED_IMAGE_COCKROACH_v21_1_3
value: cockroachdb/cockroach:v21.1.3
- name: RELATED_IMAGE_COCKROACH_v21_1_4
value: cockroachdb/cockroach:v21.1.4
- name: RELATED_IMAGE_COCKROACH_v21_1_5
value: cockroachdb/cockroach:v21.1.5
- name: RELATED_IMAGE_COCKROACH_v21_1_6
value: cockroachdb/cockroach:v21.1.6
- name: RELATED_IMAGE_COCKROACH_v21_1_7
value: cockroachdb/cockroach:v21.1.7
- name: RELATED_IMAGE_COCKROACH_v21_1_9
value: cockroachdb/cockroach:v21.1.9
- name: RELATED_IMAGE_COCKROACH_v21_1_10
value: cockroachdb/cockroach:v21.1.10
- name: RELATED_IMAGE_COCKROACH_v21_1_11
value: cockroachdb/cockroach:v21.1.11
- name: RELATED_IMAGE_COCKROACH_v21_1_12
value: cockroachdb/cockroach:v21.1.12
- name: RELATED_IMAGE_COCKROACH_v21_1_13
value: cockroachdb/cockroach:v21.1.13
- name: RELATED_IMAGE_COCKROACH_v21_1_14
value: cockroachdb/cockroach:v21.1.14
- name: RELATED_IMAGE_COCKROACH_v21_1_15
value: cockroachdb/cockroach:v21.1.15
- name: RELATED_IMAGE_COCKROACH_v21_1_16
value: cockroachdb/cockroach:v21.1.16
- name: RELATED_IMAGE_COCKROACH_v21_1_17
value: cockroachdb/cockroach:v21.1.17
- name: RELATED_IMAGE_COCKROACH_v21_1_18
value: cockroachdb/cockroach:v21.1.18
- name: RELATED_IMAGE_COCKROACH_v21_1_19
value: cockroachdb/cockroach:v21.1.19
- name: RELATED_IMAGE_COCKROACH_v21_1_20
value: cockroachdb/cockroach:v21.1.20
- name: RELATED_IMAGE_COCKROACH_v21_1_21
value: cockroachdb/cockroach:v21.1.21
- name: RELATED_IMAGE_COCKROACH_v21_2_0
value: cockroachdb/cockroach:v21.2.0
- name: RELATED_IMAGE_COCKROACH_v21_2_1
value: cockroachdb/cockroach:v21.2.1
- name: RELATED_IMAGE_COCKROACH_v21_2_2
value: cockroachdb/cockroach:v21.2.2
- name: RELATED_IMAGE_COCKROACH_v21_2_3
value: cockroachdb/cockroach:v21.2.3
- name: RELATED_IMAGE_COCKROACH_v21_2_4
value: cockroachdb/cockroach:v21.2.4
- name: RELATED_IMAGE_COCKROACH_v21_2_5
value: cockroachdb/cockroach:v21.2.5
- name: RELATED_IMAGE_COCKROACH_v21_2_7
value: cockroachdb/cockroach:v21.2.7
- name: RELATED_IMAGE_COCKROACH_v21_2_8
value: cockroachdb/cockroach:v21.2.8
- name: RELATED_IMAGE_COCKROACH_v21_2_9
value: cockroachdb/cockroach:v21.2.9
- name: RELATED_IMAGE_COCKROACH_v21_2_10
value: cockroachdb/cockroach:v21.2.10
- name: RELATED_IMAGE_COCKROACH_v21_2_11
value: cockroachdb/cockroach:v21.2.11
- name: RELATED_IMAGE_COCKROACH_v21_2_12
value: cockroachdb/cockroach:v21.2.12
- name: RELATED_IMAGE_COCKROACH_v21_2_13
value: cockroachdb/cockroach:v21.2.13
- name: RELATED_IMAGE_COCKROACH_v21_2_14
value: cockroachdb/cockroach:v21.2.14
- name: RELATED_IMAGE_COCKROACH_v21_2_15
value: cockroachdb/cockroach:v21.2.15
- name: RELATED_IMAGE_COCKROACH_v21_2_16
value: cockroachdb/cockroach:v21.2.16
- name: RELATED_IMAGE_COCKROACH_v21_2_17
value: cockroachdb/cockroach:v21.2.17
- name: RELATED_IMAGE_COCKROACH_v22_1_0
value: cockroachdb/cockroach:v22.1.0
- name: RELATED_IMAGE_COCKROACH_v22_1_1
value: cockroachdb/cockroach:v22.1.1
- name: RELATED_IMAGE_COCKROACH_v22_1_2
value: cockroachdb/cockroach:v22.1.2
- name: RELATED_IMAGE_COCKROACH_v22_1_3
value: cockroachdb/cockroach:v22.1.3
- name: RELATED_IMAGE_COCKROACH_v22_1_4
value: cockroachdb/cockroach:v22.1.4
- name: RELATED_IMAGE_COCKROACH_v22_1_5
value: cockroachdb/cockroach:v22.1.5
- name: RELATED_IMAGE_COCKROACH_v22_1_7
value: cockroachdb/cockroach:v22.1.7
- name: RELATED_IMAGE_COCKROACH_v22_1_8
value: cockroachdb/cockroach:v22.1.8
- name: RELATED_IMAGE_COCKROACH_v22_1_10
value: cockroachdb/cockroach:v22.1.10
- name: RELATED_IMAGE_COCKROACH_v22_1_11
value: cockroachdb/cockroach:v22.1.11
- name: RELATED_IMAGE_COCKROACH_v22_1_12
value: cockroachdb/cockroach:v22.1.12
- name: RELATED_IMAGE_COCKROACH_v22_1_13
value: cockroachdb/cockroach:v22.1.13
- name: RELATED_IMAGE_COCKROACH_v22_2_0
value: cockroachdb/cockroach:v22.2.0
- name: RELATED_IMAGE_COCKROACH_v22_2_1
value: cockroachdb/cockroach:v22.2.1
- name: RELATED_IMAGE_COCKROACH_v22_2_2
value: cockroachdb/cockroach:v22.2.2
- name: OPERATOR_NAME
value: cockroachdb
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: cockroachdb/cockroach-operator:v2.10.0
imagePullPolicy: IfNotPresent
name: cockroach-operator
resources:
requests:
cpu: 10m
memory: 32Mi
serviceAccountName: cockroach-operator-sa
E por fim temos a criação dos endpoints de comunicação do cluster considerados como Webhooks, utilizados na hora de provisionarmos do cluster e para a gestão do mesmo pós ser criado:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: null
name: cockroach-operator-mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: cockroach-operator-webhook-service
namespace: cockroach-operator-system
path: /mutate-crdb-cockroachlabs-com-v1alpha1-crdbcluster
failurePolicy: Fail
name: mcrdbcluster.kb.io
rules:
- apiGroups:
- crdb.cockroachlabs.com
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- crdbclusters
sideEffects: None
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
creationTimestamp: null
name: cockroach-operator-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
service:
name: cockroach-operator-webhook-service
namespace: cockroach-operator-system
path: /validate-crdb-cockroachlabs-com-v1alpha1-crdbcluster
failurePolicy: Fail
name: vcrdbcluster.kb.io
rules:
- apiGroups:
- crdb.cockroachlabs.com
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- crdbclusters
sideEffects: None
Para criar o Operator basta executar o comando:
kubectl create -f operator.yaml

Como podemos ver acima todos os recursos descritos foram criados a partir de um único arquivo separados por —.
Agora para facilitar a criação dos demais recursos iremos setar o context de nossa sessão com o Kubernetes para utilizar sempre o namespace criado:
kubectl config set-context --current --namespace=cockroach-operator-system

Desta forma não precisamos mais daqui pra frente passar nos comandos kubectl a sintaxe -n ou –namespace para acessar os recursos referentes ao namespace do Cockroach.
Vamos agora criar efetivamente nosso cluster de banco de dados criando o arquivo cockroachdb-cluster.yaml com o conteúdo:
apiVersion: crdb.cockroachlabs.com/v1alpha1
kind: CrdbCluster
metadata:
name: cockroachdb
spec:
dataStore:
pvc:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "100Gi"
volumeMode: Filesystem
resources:
requests:
cpu: 2000m
memory: 8Gi
limits:
cpu: 2
memory: 8Gi
tlsEnabled: true
image:
name: cockroachdb/cockroach:v22.2.2
nodes: 3
additionalLabels:
crdb: is-cool
Como podemos ver acima temos dois componentes a serem destacados:
- apiVersion: aqui estamos usando a API criada pelo Webhook no provisionamento do Operator com o endereço crdb.cockroachlabs.com/v1alpha1;
- kind: no tipo de recurso a ser criado é dedicado para o Operator provisionado, não usando um recurso conhecido do K8s, isso se da graças aos componentes criados anteriormente.
Para criar o cluster basta executarmos:
kubectl create -f cockroachdb-cluster.yaml

Para verificar todos os componentes criados, vamos executar os comandos:
kubectl get all -o wide
kubectl get pvc -o wide
kubectl get pv -o wide

Temos diversos recursos criados, com destaque para os Nodes escolhidos que fazem referencia ao nodepool2 que criamos e que possuem recurso o suficiente para provisionarmos os recursos solicitados (2 vCPUs e 8 GB de RAM), para o deployment do Operator e o StatefulSet do cluster CDB e por fim como não escolhemos um StorageClass o Default foi definido, se formos no Azure poderemos identifica-los conforme imagem abaixo:



Logo, o padrão para o AKS sempre será alocar um storage de bloco Azure Standard SSD com LRS.
Agora vamos criar o client para que possamos entrar e executar comandos no CockroachDB:
kubectl create \
-f https://raw.githubusercontent.com/cockroachdb/cockroach-operator/v2.10.0/examples/client-secure-operator.yaml

Uma vez provisionado, vamos entrar no cluster CockroachDB utilizando o service cockroachdb-public e vamos executar algumas queries para verificar se esta tudo funcionando:
kubectl exec -it cockroachdb-client-secure -- ./cockroach sql --certs-dir=/cockroach/cockroach-certs --host=cockroachdb-public
CREATE DATABASE dbExemplo;
USE dbExemplo;
CREATE TABLE tbCadastro(id int primary key, nome varchar(100), dtnasc date);
INSERT INTO dbExemplo.tbCadastro(id, nome, dtnasc) VALUES (1,'Paula','1978-04-12'),(2,'Carlos','1994-05-01');
SELECT * FROM dbExemplo.tbCadastro;
CREATE TABLE tbEndereco(id int primary key, idCadastro int not null REFERENCES tbCadastro (id) ON DELETE CASCADE, endereco varchar(1000), numero varchar(15));
INSERT INTO dbExemplo.tbEndereco(id, idCadastro, endereco, numero) VALUES (1,1,'Rua Exemplo', '432'), (2,2,'Rua Exemplo', '654');
SELECT c.nome, c.dtnasc, e.endereco, e.numero FROM dbexemplo.tbcadastro as c INNER JOIN dbexemplo.tbendereco as e ON c.id = e.idcadastro;



Como podemos ver nos comandos executados acima, temos todo o suporte total a linguagem SQL onde criamos um banco de dados, duas tabelas populadas com dados e com relacionamento via Chave Estrangeira (FK).
Vamos dar uma olhada agora no dashboard de gerenciamento do CockroachDB que eu particularmente acho um dos mais bonitos e completos dos bancos de dados que já administrei. Primeiro vamos criar um usuario para acessar o daashboard e depois vamos fazer um port foward para que possamos acessar da nossa maquina:
#ainda dentro da instancia
CREATE USER monitoring WITH PASSWORD 'C0ckr04chDB';
GRANT admin TO monitoring;
\q
kubectl port-forward service/cockroachdb-public 8080

Abra uma nova aba no seu navegador e digite: https://localhost:8080. Uma tela de login vai abrir, coloque o usuario e senha que criamos no banco de dados e o dashboard abrirá:

Aqui podemos ver nosso banco de dados e as tabelas que criamos:

No futuro farei um post mostrando apenas o CockroachDB e como o mesmo funciona, hoje conseguimos atingir nosso objetivo provisionando um novo cluster de banco de dados no nosso querido AKS!
Para excluir nosso laboratório basta executar:
kubectl delete -f cockroachdb-cluster.yaml
kubectl delete -f operator.yaml

No próximo post falaremos de mais um banco de dados com escalabilidade horizontal. Fique ligado. Muito obrigado pela atenção. Até a próxima!