Azure Database for MySQL – Criando seu MySQL gerenciado no Azure

Fala galera!

Neste post veremos como é tranquilo provisionar uma instancia de banco de dados MySQL no Azure. Em breve devo fazer um post falando especificamente sobre o MySQL, neste caso iremos tratar apenas de como subir um novo cluster simples.

Acesse o o portal do Azure e busque por MySQL no campo de busca no canto superior central:

Como vocês podem ver, temos o Azure Database for MySQL severs e o flexible servers, já já vocês entenderão a diferença dos dois.

Clique em Create:

Agora podemos ver duas opções: Flexible server e WordPress + MySQL Flexible server. A primeira é o padrão e a indicada pelo Azure, a segunda é especifica para um provisionamento de um WordPress, desta forma ele provisiona a aplicação do WordPress no APP Service e já sobe uma instancia com o banco de dados no MySQL.

Podemos ver também que há uma mensagem onde o MySQL – Single Server esta sendo descontinuado e a Microsoft desaconselha utilizar este modelo, inclusive aconselha quem esteja o utilizando a migrar para o Flexible server, conforme esta documentação.

Clique em Create no Flexible server:

Na tela abaixo começaremos a configurar nosso cluster MySQL, escolha a Subscription e o Resource group. Depois coloque um nome que seja único para o cluster.

No campo MySQL version teremos a disposição as versões 5.7 e 8.0, sugiro sempre escolher a 8.0 que é a mais recente, a 5.7 esta em seu End Of Life, fora que a versão 8 tem muitas features interessantes.

No campo Workload type o Azure já te entrega algumas opções de pré configuração, setando um sizing adequado ao tipo de atividade ao qual seu ambiente irá rodar, isso já adianta a vida de quem tem duvidas de qual sizing aplicar. Ao lado direito você consegue conferir as configurações de Compute Size, Storage, IOPs, Backup e Bandwith\Rede tudo isso já com o custo estimado do ambiente:

Caso você não queira trabalhar com essas sugestões, basta clicar em Compute + storage e configurar todos estes items dentro de suas necessidades:

Como é possível vermos acima temos 3 tipos de computação:

Burstable: opção mais barata de sizing entrega uma computação mais voltada para ambientes não produtivos como desenvolvimento e testes\qa;

General Purpose: este tipo entrega uma computação equilibrada entre vCPUs e memória RAM que atende o dia a dia da maioria das aplicações;

Business Critical: aqui temos sizings focados em processamento massivo de dados, entregando tamanhos grandes de instancias focados em aplicações que demandam muita CPU, memória RAM e máxima performance no acesso aos discos (iops).

A escolha do tamanho de maquina é o maior fator que pesará sobre o custo final, depois dela vem o Storage size juntamente com o número de operações de entrada e saída (iops). O custo de storage é de R$0,63 por GB enquanto a configuração de IOPS pode variar, se você escolher Auto scale IOPS será cobrado por uso em milhões de chamadas ou também é possível trabalhar com Pre-provisioned IOPS que é um valor máximo de operações de IO que a instancia poderá fazer entre leitura e escrita (recomendado), o custo por IOPs é de R$0,63 por IOPS.

As demais configurações são:

Storage Auto-Growth: crescimento automático do tamanho de storage disponível para o sgbd;

High Availability: nesta opção o Azure provisiona mais uma instancia para que haja uma contingência de ambiente e ai temos duas opções, colocar na mesma zona de disponibilidade ou em uma outra zona para termos redundância de sites;

Backup: aqui temos o tempo de retenção do backup da instancia que será executado automaticamente pelo serviço bem como se queremos torna-lo redundante não só na mesma avalability zone ou em outra para termos uma segurança a mais em caso de um disaster recovery.

Abaixo podemos ver uma configuração econômica para testes, configure e clique em Save:

Abaixo voltamos para a primeira tela após escolher o sizing de nosso ambiente, podemos ver aqui também a opção de habilitarmos a alta disponibilidade do ambiente (HA) e também as configurações de autenticação, sendo estas:

MySQL auth only: aqui configuramos um usuário principal para a instancia, ele será o principal usuário a principio;

Microsoft Entra auth only: nesta configuração ativamos o Entra (Antigo Active Directory) que é o serviço de gestão de usuários da Microsoft;

MySQL and Microsoft Entra auth: aqui utilizaremos ambas as opções acima.

Para o nosso case vamos usar apenas o MySQL authentication, coloque um usuário e senha forte, depois clique em Next: Networking:

Na área de Networking veremos que podemos liberar o acesso publico que através do Firewall e via Private Endpoint ou apenas via Private access que depende de uma integração com a VNet. Para ambientes produtivos aconselho sempre trabalhar com Private Access por ser mais seguro, camadas de armazenamento de dados devem estar sempre restritas a aplicação que precisa acessa-las.

Para o nosso lab iremos utilizar o tipo de conectividade como Public access e também deixar marcado o check box de Public access para que possamos nos conectar nessa instancia de forma rápida.

Na parte de Firewall rules veremos um sinal de + um pouco abaixo, sugerindo a inclusão do nosso ip externo e para abrir para qualquer ip também, inclua ambos e clique depois em Next: security:

Aqui temos a configuração de criptografia em repouso (ou at rest), que é a criptografia em disco, onde nossos dados serão armazenados de forma segura a partir de uma chave de criptografia e autenticação segura, não ativaremos criptografia para este lab mas considere o fazer para ambientes produtivos. Clique em Review + create:

Após verificar o resumo sobre sua instancia, clique em Create:

Depois de alguns minutos você terá sua instancia provisionada, clique no recurso para acessa-lo:

Este é o painel do Azure Database for MySQL flexible server, posteriormente farei outro post detalhando as opções, mas agora, vamos pegar o server name e o usuário para que possamos acessar nossa instancia:

Estou utilizando o Jetbrains DataGrip, mas poderíamos estar utilizando o MySQL Workbench também, basta colocar o server name no campo Host e o usuário e senha e clicar em conectar:

Execute os SELECTs abaixo para que possamos ver as tabelas do sistema, o hostname e os processos em execução:

Para saber mais sobre o MySQL flexible servers consulte a documentação: https://learn.microsoft.com/en-us/azure/mysql/flexible-server/overview

É isso galera! Viram como é tranquilo criar uma instancia MySQL no Azure? Espero que tenham curtido. No próximo post veremos como criar uma instancia PostgreSQL gerenciada no Azure. Fiquem ligados!

[Série][AKS] Provisionando Bancos de Dados no Azure Kubernetes Service – Vitess

Fala minha gente! Espero que estejam todos bem!

Voltando com a série onde utilizamos nosso AKS para provisionar e escalar bancos de dados em containers falaremos desta vez de um dos bancos distribuídos que mais escalam horizontalmente: Vitess!

O Vitess é um projeto graduado da CNCF que entrega um cluster banco de dados MySQL distribuído por meio de uma camada de replicação que permite que você replique dados entre diversas instancias de MySQL, transformando o próprio MySQL em storage distribuído para seus dados. Além disso o Vitess tem a capacidade de utilizar Shardings que é a divisão de dados de uma determinada tabela ou conjunto de tabelas entre clusters diferentes com o intuito de isolar dados focados em uma determinada região do mundo, aumento a performance de escrita e leitura.

Para quem quiser conhecer mais a fundo como o Vitess funciona e sua arquitetura eu apresento aqui nesta palestra que fiz para o KCD Brasil de 2022:

Vamos começar, para isso precisamos criar uma pasta e baixar os arquivos que utilizaremos em nosso lab:

mkdir vitess
cd vitess
git clone https://github.com/vitessio/vitess
cd vitess/examples/operator

Vamos criar nosso namespace para encapsular os recursos que iremos provisionar:

kubectl create namespace vitess

Agora vamos criar o Operator para depois provisionarmos nosso cluster:

kubectl apply -f operator.yaml -n vitess

Agora vamos provisionar nosso cluster Vitess, para isso precisamos primeiro criar a configuração que será utilizada pelos nós do Cluster, crie um arquivo chamado vitess-cluster-config.yaml com o conteúdo:

apiVersion: v1
kind: Secret
metadata:
  name: vitess-cluster-config
type: Opaque
stringData:
  users.json: |
    {
      "user": [{
        "UserData": "user",
        "Password": ""
      }]
    }
  init_db.sql: |
    # This file is executed immediately after mysql_install_db,
    # to initialize a fresh data directory.

    ###############################################################################
    # Equivalent of mysql_secure_installation
    ###############################################################################
    # We need to ensure that super_read_only is disabled so that we can execute
    # these commands. Note that disabling it does NOT disable read_only.
    # We save the current value so that we only re-enable it at the end if it was
    # enabled before.
    SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF');
    SET GLOBAL super_read_only='OFF';

    # Changes during the init db should not make it to the binlog.
    # They could potentially create errant transactions on replicas.
    SET sql_log_bin = 0;
    # Remove anonymous users.
    DELETE FROM mysql.user WHERE User = '';

    # Disable remote root access (only allow UNIX socket).
    DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost';

    # Remove test database.
    DROP DATABASE IF EXISTS test;

    ###############################################################################
    # Vitess defaults
    ###############################################################################

    # Vitess-internal database.
    CREATE DATABASE IF NOT EXISTS _vt;
    # Note that definitions of local_metadata and shard_metadata should be the same
    # as in production which is defined in go/vt/mysqlctl/metadata_tables.go.
    CREATE TABLE IF NOT EXISTS _vt.local_metadata (
      name VARCHAR(255) NOT NULL,
      value VARCHAR(255) NOT NULL,
      db_name VARBINARY(255) NOT NULL,
      PRIMARY KEY (db_name, name)
      ) ENGINE=InnoDB;
    CREATE TABLE IF NOT EXISTS _vt.shard_metadata (
      name VARCHAR(255) NOT NULL,
      value MEDIUMBLOB NOT NULL,
      db_name VARBINARY(255) NOT NULL,
      PRIMARY KEY (db_name, name)
      ) ENGINE=InnoDB;

    # Admin user with all privileges.
    CREATE USER 'vt_dba'@'localhost';
    GRANT ALL ON *.* TO 'vt_dba'@'localhost';
    GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost';

    # User for app traffic, with global read-write access.
    CREATE USER 'vt_app'@'localhost';
    GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE,
      REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES,
      LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW,
      SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER
      ON *.* TO 'vt_app'@'localhost';

    # User for app debug traffic, with global read access.
    CREATE USER 'vt_appdebug'@'localhost';
    GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost';

    # User for administrative operations that need to be executed as non-SUPER.
    # Same permissions as vt_app here.
    CREATE USER 'vt_allprivs'@'localhost';
    GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE,
      REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES,
      LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW,
      SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER
      ON *.* TO 'vt_allprivs'@'localhost';

    # User for slave replication connections.
    # TODO: Should we set a password on this since it allows remote connections?
    CREATE USER 'vt_repl'@'%';
    GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%';

    # User for Vitess filtered replication (binlog player).
    # Same permissions as vt_app.
    CREATE USER 'vt_filtered'@'localhost';
    GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE,
      REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES,
      LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW,
      SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER
      ON *.* TO 'vt_filtered'@'localhost';

    FLUSH PRIVILEGES;

    RESET SLAVE ALL;
    RESET MASTER;

    # custom sql is used to add custom scripts like creating users/passwords. We use it in our tests
    # {{custom_sql}}

    # We need to set super_read_only back to what it was before
    SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'ON');
  rbac.yaml: |
    rules:
    - resource: "*"
      actions:
        - "get"
        - "create"
        - "put"
        - "ping"
      subjects: ["*"]
      clusters: ["*"]
    - resource: "Shard"
      actions:
        - "emergency_failover_shard"
        - "planned_failover_shard"
      subjects: ["*"]
      clusters: ["*"]

Agora vamos criar o arquivo que vai provisionar o cluster propriamente dito, chame-o de vitess-cluster.yaml e insira:

apiVersion: planetscale.com/v2
kind: VitessCluster
metadata:
  name: vitess
  namespace: vitess
spec:
  images:
    vtctld: vitess/lite:latest
    vtadmin: vitess/vtadmin:latest
    vtgate: vitess/lite:latest
    vttablet: vitess/lite:latest
    vtbackup: vitess/lite:latest
    vtorc: vitess/lite:latest
    mysqld:
      mysql80Compatible: vitess/lite:latest
    mysqldExporter: prom/mysqld-exporter:v0.11.0
  cells:
  - name: zone1
    gateway:
      authentication:
        static:
          secret:
            name: vitess-cluster-config
            key: users.json
      replicas: 1
      resources:
        requests:
          cpu: 100m
          memory: 256Mi
        limits:
          memory: 256Mi
  vitessDashboard:
    cells:
    - zone1
    extraFlags:
      security_policy: read-only
    replicas: 1
    resources:
      limits:
        memory: 128Mi
      requests:
        cpu: 100m
        memory: 128Mi
  vtadmin:
    rbac:
      name: vitess-cluster-config
      key: rbac.yaml
    cells:
      - zone1
    apiAddresses:
      - http://localhost:14001
    replicas: 1
    readOnly: false
    apiResources:
      limits:
        memory: 128Mi
      requests:
        cpu: 100m
        memory: 128Mi
    webResources:
      limits:
        memory: 128Mi
      requests:
        cpu: 100m
        memory: 128Mi

  keyspaces:
  - name: commerce
    durabilityPolicy: none
    turndownPolicy: Immediate
    vitessOrchestrator:
      resources:
        limits:
          memory: 128Mi
        requests:
          cpu: 100m
          memory: 128Mi
      extraFlags:
        recovery-period-block-duration: 5s
    partitionings:
    - equal:
        parts: 1
        shardTemplate:
          databaseInitScriptSecret:
            name: vitess-cluster-config
            key: init_db.sql
          tabletPools:
          - cell: zone1
            type: replica
            replicas: 3
            vttablet:
              extraFlags:
                db_charset: utf8mb4
              resources:
                limits:
                  memory: 256Mi
                requests:
                  cpu: 100m
                  memory: 256Mi
            mysqld:
              resources:
                limits:
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 512Mi
            dataVolumeClaimTemplate:
              accessModes: ["ReadWriteOnce"]
              resources:
                requests:
                  storage: 10Gi
  updateStrategy:
    type: Immediate

Agora basta executar ambos:

kubectl create -f vitess-cluster-config.yaml -n vitess
kubectl create -f vitess-cluster.yaml -n vitess

Vamos ver agora como ficou toda nossa estrutura e componentes:

kubectl get all -n vitess
kubectl get pvc -n vitess
kubectl get pv -n vitess

 Após provisionamento dos recursos vamos agora instalar algumas coisas necessárias para operar neste banco de dados, começando pelo mysql-client:

brew install mysql-client

Agora vamos instalar o Vitess localmente para que possamos ter o client vtctlclient disponível para importamos os dados em nossos bancos de dados:

brew install vitess

Para podermos acessar no cluster vamos precisar fazer alguns Port Forwards, altere o arquivo pf.sh deixando assim:

#!/bin/sh

kubectl -n vitess port-forward --address localhost "$(kubectl -n vitess get service --selector="planetscale.com/component=vtctld" -o name | head -n1)" 15000 15999 & process_id1=$!
kubectl -n vitess port-forward --address localhost "$(kubectl -n vitess get service --selector="planetscale.com/component=vtgate,!planetscale.com/cell" -o name | head -n1)" 15306:3306 & process_id2=$!
kubectl -n vitess port-forward --address localhost "$(kubectl -n vitess get service --selector="planetscale.com/component=vtadmin" -o name | head -n1)" 14000:15000 14001:15001 & process_id3=$!
sleep 2
echo "You may point your browser to http://localhost:15000, use the following aliases as shortcuts:"
echo 'alias vtctlclient="vtctlclient --server=localhost:15999 --logtostderr"'
echo 'alias vtctldclient="vtctldclient --server=localhost:15999 --logtostderr"'
echo 'alias mysql="mysql -h 127.0.0.1 -P 15306 -u user"'
echo "Hit Ctrl-C to stop the port forwards"
wait $process_id1
wait $process_id2
wait $process_id3

Feito isso execute:

./pf.sh &
alias vtctlclient="vtctlclient --server=localhost:15999"
alias mysql="mysql -h 127.0.0.1 -P 15306 -u user"

No comando acima também criamos dois alias para comandos que vamos executar para acessar o cluster Vitess, sendo assim, vamos executar alguns scripts no Vitess, o primeiro cria o Schema\Banco de Dados Commerce, o segundo cria o VSchema:

vtctlclient ApplySchema -- --sql="$(cat create_commerce_schema.sql)" commerce
vtctlclient ApplyVSchema -- --vschema="$(cat vschema_commerce_initial.json)" commerce

Agora vamos logar em nosso cluster Vitess com o comando mysql, depois vamos executar:

mysql
show databases;
use commerce;
show tables;

É isso gente! Devo fazer outro post falando sobre Sharding exclusivamente para o Vitess, onde iremos estender este lab para mostrar o quão escalável ele é!

Até a próxima!

[Série][AKS] Provisionando Bancos de Dados no Azure Kubernetes Service – MongoDB

Fala meu povo!

Depois de alguns dias de descanso dos posts por aqui, estamos de volta!

Dessa vez veremos como provisionar um cluster de MongoDB no nosso querido e amado AKS!

Do ultimo post que fizemos até este tive problemas na minha subscription do MSDN que tem um limite de gastos e precisei alterar a subscription e por consequencia tive que recriar o cluster de AKS, segue as especificações deste novo cluster:

Agora que temos nosso cluster no ar, vamos baixar as credenciais para utiliza-lo:

az aks get-credentials --resource-group aks-database-labs --name aks-database-labs

Agora vamos verificar se existem 3 nodes assim como o cluster anterior:

kubectl get nodes

Uma vez que nosso cluster esta ok vamos começar a provisionar nosso cluster mongodb. Primeira coisa será isolar nossos recursos em um namespace dedicado:

kubectl create namespace mongodb

Para este lab utilizaremos o Operator do MongoDB Community Edition, versão indicada para testes e ambientes não produtivos, para ambientes produtivos indico a utilização do MongoDB Enterprise para, além de ter todas as features, também ter um suporte especializado do fornecedor. Para baixar os arquivos necessários, execute o git clone:

git clone https://github.com/mongodb/mongodb-kubernetes-operator.git

Uma vez com os arquivos em maquina, vamos agora alterar o arquivo cluster_role_binding.yaml para inserir no namespace para criação do ServiceAccount e ClusterRole que serão utilizados pelo Operator:

vim deploy/clusterwide/cluster_role_binding.yaml

O arquivo deve ficar desta forma:

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: mongodb-kubernetes-operator
subjects:
- kind: ServiceAccount
  namespace: mongodb
  name: mongodb-kubernetes-operator
roleRef:
  kind: ClusterRole
  name: mongodb-kubernetes-operator
  apiGroup: rbac.authorization.k8s.io

Agora vamos começar a provisionar nosso Operator, para isso vamos executar alguns yamls que irão criar as rbacs e acessos necessários para o nosso cluster:

kubectl apply -f deploy/clusterwide
kubectl apply -k config/rbac --namespace mongodb

Agora vamos registrar uma nova API em nosso AKS, essa API irá conter todos os componentes necessários para seguirmos com a criação do nosso operator e cluster replica-set:

kubectl apply -f config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml
kubectl get crd/mongodbcommunity.mongodbcommunity.mongodb.com

Agora vamos validar a criação das nossas RBACs executando:

kubectl apply -k config/rbac/ --namespace mongodb
kubectl get role mongodb-kubernetes-operator --namespace mongodb
kubectl get rolebinding mongodb-kubernetes-operator --namespace mongodb
kubectl get serviceaccount mongodb-kubernetes-operator --namespace mongodb

Agora vamos criar nosso Operator efetivamente executando o seguinte yaml:

kubectl create -f config/manager/manager.yaml --namespace mongodb
kubectl get pods --namespace mongodb

Uma vez que nosso Operator esteja rodando com sucesso, vamos agora criar um ReplicaSet que irá provisionar nosso cluster de MongoDB Community, para isso crie um arquivo chamado mongodb.yaml com o conteúdo abaixo:

---
apiVersion: mongodbcommunity.mongodb.com/v1
kind: MongoDBCommunity
metadata:
  name: mongodb
spec:
  members: 3
  type: ReplicaSet
  version: "4.2.6"
  security:
    authentication:
      modes: ["SCRAM"]
  users:
    - name: akslabuser
      db: admin
      passwordSecretRef: # a reference to the secret that will be used to generate the user's password
        name: akslabuserpassword
      roles:
        - name: clusterAdmin
          db: admin
        - name: userAdminAnyDatabase
          db: admin
      scramCredentialsSecretName: my-scram
  additionalMongodConfig:
    storage.wiredTiger.engineConfig.journalCompressor: zlib

---
apiVersion: v1
kind: Secret
metadata:
  name: akslabuserpassword
type: Opaque
stringData:
  password: P@ssW0rdC0mpl3x

Agora crie o Replica Set:

kubectl create -f mongodb.yaml -n mongodb
kubectl get pods -n mongodb

Varios componentes foram criados junto neste provisionamento em background, vamos ver como ficou toda nossa estrutura? Execute:

kubectl get all -n mongodb
kubectl get pvc -n mongodb
kubectl get pv -n mongodb

Agora temos nosso cluster MongoDB executando em nosso AKS, se precisarmos adicionar algum Arbiter para ajudar na eleição de novos primarys e auxiliar na gestão do cluster basta incluir no arquivo de provisionamento do Replica Set:

Execute o comando para alterar o Replica Set:

kubectl apply -f mongodb.yaml -n mongodb

Para saber as strings de conexão e informações para logar no cluster execute o seguinte comando:

kubectl get secret mongodb-admin-akslabuser -n mongodb -o json | jq -r '.data | with_entries(.value |= @base64d)'

Para validar se o seu cluster esta funcionando apropriadamente vamos entrar em algum dos pods, logar no MongoDB e executar o comando rs.status() para verificar o cluster:

kubectl -n mongodb exec --stdin --tty mongodb-0 -- /bin/bash

Uma vez dentro do Pod mongodb-0 execute:

mongo "mongodb+srv://akslabuser:P%40ssW0rdC0mpl3x@mongodb-svc.mongodb.svc.cluster.local/admin?replicaSet=mongodb&ssl=false"

E agora para verificar o Status do nosso Replica Set, basta executar:

rs.status()

Caso vocês queiram se aprofundar mais neste lab e em outros componentes desta estrutura é só consultar o projeto no Github:

https://github.com/mongodb/mongodb-kubernetes-operator

Gente, por hoje é só, lembrando que este é um lab, caso queira executar o MongoDB em ambiente produtivo e em K8s indico seguir com a versão Enterprise.

Até o próximo Post!

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure – Criando Módulo Terraform para Azure Cache for Redis

Fala meu povo e minha pova!

Mais uma manhã com conteúdo top! Continuando nossa série de posts de mão na massa, de construção de pipelines DevOps para entrega de infraestrutura de banco de dados no Azure, neste post veremos como criar uma instancia de banco de dados Redis gerenciado! O Redis é um banco de dados NoSQL, chave-valor que tem o intuito de armazenar dados em cache, ou seja, em memória Ram, o que o torna extremamente mais performático que um banco de dados relacional, principalmente para leitura.

O Redis é uma tecnologia que utilizamos para retirar carga de leitura estática dos bancos de dados relacionais e até alguns NoSQL que ficam no backend das nossas aplicações, os tipos de sistemas que mais se beneficiam desta tecnologia são: Login, configurações estáticas, armazenamento de estado, entre outros.

Vamos iniciar nosso módulo, para quem ainda não viu os posts anteriores sobre o projeto e a criação dos repositórios git, aconselho ver os seguintes posts:

Crie o repositório pipeline_iac_azure_cache_redis e dentro dele crie os seguintes arquivos:

1 – Vamos criar o arquivo rg.tf que será responsável por provisionar nosso resource group:

resource "azurerm_resource_group""rg"{  
name     = var.rg  
location = var.regiao
}

2 – Agora crie o arquivo variables.tf aonde iremos declarar nossas variáveis dinâmicas que serão utilizadas posteriormente para criar os recursos de bancos de dados e o próprio resource group:

variable "rg" {
    description = "Resource Group que será criado|utilizado na criação dos recursos de banco de dados"
}

variable "regiao" {
    description = "Região ao qual os recursos serão criados"
}

variable "ambiente" {
    type = map
    default = {
        d = "dev",
        h = "hml",
        p = "prd"
    }
}

variable "env" {
    default = "d"

    validation {
        condition = contains(["d","h","p"],var.env)
        error_message = "Argument 'env' must be either 'd' (dev), 'h' (hml) or 'p' (prd)"
    }
}

variable "nome_sistema" {
    description = "Nome do sistema ao qual os recursos serão destinados"
}

variable "tamanho_servidor" {
    description = "Especifica o tipo de perfil do servidor de cache Redis que será criado. Valores possíveis: Basic, Standard e Premium"
    default = {
        d = "Basic",
        h = "Standard",
        p = "Premium"
    }
}

variable "capacidade_servidor" {
    description = "Tamanho do servidor cache Redis. Valores validos baseado na variavel tamanho_servidor: C (Basic/Standard) are 0, 1, 2, 3, 4, 5, 6, and for P (Premium) family are 1, 2, 3, 4, 5."
    default = 1
}

variable "versao_redis" {
    description = "Versão do Redis que será utilizado, por padrão será a mais recente disponivel neste momento: 6"
    default = "6"
}

3 – Depois disso vamos criar o arquivo locals.tf onde algumas variáveis serão trabalhadas com base em tomadas de decisão, principalmente focada no ambiente produtivo, aonde precisamos ter ambientes mais robustos e redundantes:

locals {
    ambiente                = lookup(var.ambiente,var.env)
    server_sku_name         = lookup(var.tamanho_servidor,var.env)
    server_family           = local.server_sku_name == "Premium" ? "P" : "C"
    
    tags = {
        env         = var.env
        ambiente    = local.ambiente
        sistema     = var.nome_sistema
    }
}

4 – Agora vamos criar nossos recursos de cache de bancos de dados, crie um arquivo redis.tf aonde iremos criar um servidor de Redis:

resource "azurerm_redis_cache" "redis_cache_db" {
  name                = "rediscachedb-${var.nome_sistema}-${local.ambiente}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  redis_version       = var.versao_redis  
  capacity            = var.capacidade_servidor
  family              = local.server_family
  sku_name            = local.server_sku_name
  enable_non_ssl_port = false
  minimum_tls_version = "1.2"

  redis_configuration {
  }

  tags = merge(local.tags)
}

Alguns pontos importantes que podemos verificar acima são: configurações de tls habilitadas para garantir a criptografia de dados que estão trafegando do Redis para aplicação e vice-versa (Podemos ver isso na imagem abaixo) e o campo redis_configuration, neste campo podemos configurar o Redis internamente setando configurações especificas desta tecnologia. Para mais informações sobre essas configurações, olhar: https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-configure#default-redis-server-configuration

5 – Quase acabando, vamos criar um arquivo output.tf para sabermos qual é o ID e hostname do banco de dados que estamos provisionando:

output "azure_cache_redis_id" {
    value = azurerm_redis_cache.redis_cache_db.id
}

output "azure_cache_redis_hostname" {
    value = azurerm_redis_cache.redis_cache_db.hostname
}

6 – Por fim, vamos declarar os valores das nossas variáveis no arquivo terraform.tfvars:

rg              = "TerraformAzurCacheRedis"
regiao          = "eastus"
env             = "p"
nome_sistema    = "login"

Uma vez criado todos os componentes do nosso módulo Terraform, vamos agora executa-lo para verificar se esta tudo funcionando como esperado:

terraform init
terraform validate
terraform plan
terraform apply --auto-approve

Podemos seguir agora para destruição desses recursos que não utilizaremos agora, executando:

terraform destroy

Vamos agora subir nossos códigos para o Github:

git add .
git commit -m "Modulo Terraform Azure Cache for Redis"
git push

É isso gente! Terminamos de criar nossos módulo Terraform para provisionamento de nossas infras de banco de dados, nos próximos capítulos iremos construir nossas pipelines de provisionamento dessas infraestruturas de forma totalmente automatizada!

Fiquem ligades! Até a próxima!

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure – Criando Módulo Terraform para Azure Database for MySQL

Fala meu poves!

De volta com essa série maravilinda para mais um episódio de criação de módulo Terraform para entregar um banco de dados MySQL desta vez, vocês verão que a estrutura é muito parecida com o módulo de PostgreSQL, mudando apenas algumas coisas relativas a própria engine do MySQL.

Para quem ainda não viu os posts anteriores sobre o projeto e a criação dos repositórios git, aconselho ver os seguintes posts:

Crie o repositório pipeline_iac_azure_db_mysql e dentro dele crie os seguintes arquivos:

1 – Vamos criar o arquivo rg.tf que será responsável por provisionar nosso resource group:

resource "azurerm_resource_group" "rg" {
  name     = var.rg
  location = var.regiao
}

2 – Agora crie o arquivo variables.tf aonde iremos declarar nossas variáveis dinâmicas que serão utilizadas posteriormente para criar os recursos de bancos de dados e o próprio resource group:

variable "rg" {
    description = "Resource Group que será criado|utilizado na criação dos recursos de banco de dados"
}

variable "regiao" {
    description = "Região ao qual os recursos serão criados"
}

variable "ambiente" {
    type = map
    default = {
        d = "dev",
        h = "hml",
        p = "prd"
    }
}

variable "env" {
    default = "d"

    validation {
        condition = contains(["d","h","p"],var.env)
        error_message = "Argument 'env' must be either 'd' (dev), 'h' (hml) or 'p' (prd)"
    }
}

variable "nome_sistema" {
    description = "Nome do sistema ao qual os recursos serão destinados"
}

variable "storage_account_tier" {
    description = "Tipo de Storage Account que pode ser Standard ou Premium. Por padrão será Standard"
    default = "Standard"
}

variable "storage_account_repl_type" {
    description = "Tipo de Replicação de Storage Account que pode ser LRS, GRS, RAGRS, ZRS, GZRS and RAGZRS. Por padrão será LRS"
    default = "LRS"
}

variable "admin_user_login" {
    description = "Usuario para logar no servidor e banco de dados"
    default = "admindb"
}

variable "admin_user_passwd" {
    description = "Senha do usuario para logar no servidor e banco de dados"
    sensitive = true
}

variable "db_collation" {
    description = "Collation do banco de dados."
    default = "utf8_unicode_ci"
}

variable "db_charset" {
    description = "Conjunto de caracteres do banco de dados. Por padrão será UTF8"
    default = "utf8"
}

variable "db_storage_max_size_mb" {
    description = "Tamanho máximo do banco de dados em Megabytes. Por padrão 5120MB"
    default = 5120
}

variable "db_storage_auto_grow" {
    description = "Habilita crescimento automatico de storage."
    default = false
}

variable "tamanho_servidor" {
    description = "Especifica o tipo de perfil do servidor de banco de dados que será criado. https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/mysql_server"
    default = {
        d = "B_Gen4_1",
        h = "B_Gen5_2",
        p = "GP_Gen5_8"
    }
}

variable "versao_mysql" {
    description = "Versão do MySQL que será utilizado, por padrão será a mais recente disponivel neste momento: 8.0"
    default = "8.0"
}

variable "dias_retencao_backup" {
    description = "Quantidade de dias que o backup ficará disponível para ser restaurado. Por padrão 7 dias"
    default = 7
}

variable "reundancia_regiao_backup" {
    description = "Ativa a redundancia de backup para outras região para casos de DR."
    default = false
}

3 – Depois disso vamos criar o arquivo locals.tf onde algumas variáveis serão trabalhadas com base em tomadas de decisão, principalmente focada no ambiente produtivo, aonde precisamos ter ambientes mais robustos e redundantes:

locals {
    ambiente                = lookup(var.ambiente,var.env)
    server_sku_name         = lookup(var.tamanho_servidor,var.env)
    reundancia_regiao_backup = var.env == "p" ? true : var.reundancia_regiao_backup
    db_storage_auto_grow    = var.env == "p" ? true : var.db_storage_auto_grow

    tags = {
        env         = var.env
        ambiente    = local.ambiente
        sistema     = var.nome_sistema
    }
}

4 – Agora vamos criar nossos recursos de bancos de dados, crie um arquivo mysql.tf aonde iremos criar um servidor de banco de dados MySQL e um banco de dados dentro deste servidor:

resource "azurerm_mysql_server" "mysql_server" {
  name                = "mysqlserver-${var.nome_sistema}-${local.ambiente}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  sku_name = local.server_sku_name

  storage_mb                   = var.db_storage_max_size_mb
  backup_retention_days        = var.dias_retencao_backup
  geo_redundant_backup_enabled = local.reundancia_regiao_backup
  auto_grow_enabled            = local.db_storage_auto_grow

  administrator_login          = var.admin_user_login
  administrator_login_password = var.admin_user_passwd
  version                      = var.versao_mysql
  ssl_enforcement_enabled      = true

  tags = merge(local.tags)
}

resource "azurerm_mysql_database" "mysql_database" {
  name                = "mysqldb-${var.nome_sistema}-${local.ambiente}"
  resource_group_name = azurerm_resource_group.rg.name
  server_name         = azurerm_mysql_server.mysql_server.name
  charset             = var.db_charset
  collation           = var.db_collation
}

5 – Quase acabando, vamos criar um arquivo output.tf para sabermos qual é o ID do banco de dados que estamos provisionando:

output "azure_db_mysql_id" {
    value = azurerm_mysql_database.mysql_database.id
}

6 – Por fim, vamos declarar os valores das nossas variáveis no arquivo terraform.tfvars:

rg              = "TerraformAzureMySQLdb"
regiao          = "eastus"
env             = "p"
nome_sistema    = "pagamentos"
admin_user_passwd = "P@ssW0dComPl3x"

Uma vez criado todos os componentes do nosso módulo Terraform, vamos agora executa-lo para verificar se esta tudo funcionando como esperado:

terraform init
terraform validate
terraform plan
terraform apply --auto-approve

Vamos ver como estão nossos recursos na console do Azure:

Como podemos ver na tela acima, versão do MySQL esta conforme declaramos e o sizing do servidor foi baseado na variavel env o qual escolhemos um ambiente produtivo, logo, com um sizing maior dentre outras melhorias, isso pode ser confirmado nas tags também.

Agora podemos excluir todos os recursos executando:

terraform destroy

Vamos agora mandar todo esse código para o Github? Só executar:

git add .
git commit -m "Modulo Terraform Azure Database for MySQL"
git push

É isso galera! Mais um módulo pronto, no próximo post faremos nosso ultimo módulo Terraform e depois partiremos para a construção das pipelines! Então fiquem ligades galera!

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure – Criando Módulo Terraform para Azure Database for PostgreSQL

Fala meu povo!

Mais um capitulo da nossa saga de criar módulos Terraform para no futuro construirmos nossa pipeline de entrega de bancos de dados no Azure DevOps. Desta vez vamos construir um módulo Terraform que entrega um banco de dados Azure Database for PostgreSQL. Vamos lá!

Para quem ainda não viu os posts anteriores sobre o projeto e a criação dos repositórios git, aconselho ver os seguintes posts:

Crie o repositório pipeline_iac_azure_db_postgresql e dentro dele crie os seguintes arquivos:

1 – Vamos criar o arquivo rg.tf que será responsável por provisionar nosso resource group:

resource "azurerm_resource_group" "rg" {
  name     = var.rg
  location = var.regiao
}

2 – Agora crie o arquivo variables.tf aonde iremos declarar nossas variáveis dinâmicas que serão utilizadas posteriormente para criar os recursos de bancos de dados e o próprio resource group:

variable "rg" {
    description = "Resource Group que será criado|utilizado na criação dos recursos de banco de dados"
}

variable "regiao" {
    description = "Região ao qual os recursos serão criados"
}

variable "ambiente" {
    type = map
    default = {
        d = "dev",
        h = "hml",
        p = "prd"
    }
}

variable "env" {
    default = "d"

    validation {
        condition = contains(["d","h","p"],var.env)
        error_message = "Argument 'env' must be either 'd' (dev), 'h' (hml) or 'p' (prd)"
    }
}

variable "nome_sistema" {
    description = "Nome do sistema ao qual os recursos serão destinados"
}

variable "storage_account_tier" {
    description = "Tipo de Storage Account que pode ser Standard ou Premium. Por padrão será Standard"
    default = "Standard"
}

variable "storage_account_repl_type" {
    description = "Tipo de Replicação de Storage Account que pode ser LRS, GRS, RAGRS, ZRS, GZRS and RAGZRS. Por padrão será LRS"
    default = "LRS"
}

variable "admin_user_login" {
    description = "Usuario para logar no servidor e banco de dados"
    default = "admindb"
}

variable "admin_user_passwd" {
    description = "Senha do usuario para logar no servidor e banco de dados"
    sensitive = true
}

variable "db_collation" {
    description = "Collation do banco de dados."
    default = "English_United States.1252"
}

variable "db_charset" {
    description = "Conjunto de caracteres do banco de dados. Por padrão será UTF8"
    default = "UTF8"
}

variable "db_storage_max_size_mb" {
    description = "Tamanho máximo do banco de dados em Megabytes. Por padrão 5120MB"
    default = 5120
}

variable "db_storage_auto_grow" {
    description = "Habilita crescimento automatico de storage."
    default = false
}

variable "tamanho_servidor" {
    description = "Especifica o tipo de perfil do servidor de banco de dados que será criado. https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_server"
    default = {
        d = "B_Gen4_1",
        h = "B_Gen5_2",
        p = "GP_Gen5_8"
    }
}

variable "versao_postgresql" {
    description = "Versão do PostgreSQL que será utilizado, por padrão será a mais recente disponivel neste momento: 11"
    default = "11"
}

variable "dias_retencao_backup" {
    description = "Quantidade de dias que o backup ficará disponível para ser restaurado. Por padrão 7 dias"
    default = 7
}

variable "reundancia_regiao_backup" {
    description = "Ativa a redundancia de backup para outras região para casos de DR."
    default = false
}

3 – Depois disso vamos criar o arquivo locals.tf onde algumas variáveis serão trabalhadas com base em tomadas de decisão, principalmente focada no ambiente produtivo, aonde precisamos ter ambientes mais robustos e redundantes:

locals {
    ambiente                = lookup(var.ambiente,var.env)
    server_sku_name         = lookup(var.tamanho_servidor,var.env)
    reundancia_regiao_backup = var.env == "p" ? true : var.reundancia_regiao_backup
    db_storage_auto_grow    = var.env == "p" ? true : var.db_storage_auto_grow

    tags = {
        env         = var.env
        ambiente    = local.ambiente
        sistema     = var.nome_sistema
    }
}

4 – Agora vamos criar nossos recursos de bancos de dados, crie um arquivo postgresql.tf aonde iremos criar um servidor de banco de dados PostgreSQL e um banco de dados dentro deste servidor:

resource "azurerm_postgresql_server" "pgsql_server" {
  name                = "postgresql-${var.nome_sistema}-${local.ambiente}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  sku_name = local.server_sku_name

  storage_mb                   = var.db_storage_max_size_mb
  backup_retention_days        = var.dias_retencao_backup
  geo_redundant_backup_enabled = local.reundancia_regiao_backup
  auto_grow_enabled            = local.db_storage_auto_grow

  administrator_login          = var.admin_user_login
  administrator_login_password = var.admin_user_passwd
  version                      = var.versao_postgresql
  ssl_enforcement_enabled      = true

  tags = merge(local.tags)
}

resource "azurerm_postgresql_database" "pgsql_database" {
  name                = "pgsqldb-${var.nome_sistema}-${local.ambiente}"
  resource_group_name = azurerm_resource_group.rg.name
  server_name         = azurerm_postgresql_server.pgsql_server.name
  charset             = var.db_charset
  collation           = var.db_collation
}

5 – Quase acabando, vamos criar um arquivo output.tf para sabermos qual é o ID do banco de dados que estamos provisionando:

output "azure_db_pgsql_id" {
    value = azurerm_postgresql_database.pgsql_database.id
}

6 – Por fim, vamos declarar os valores das nossas variáveis no arquivo terraform.tfvars:

rg              = "TerraformAzurePostgreSQLdb"
regiao          = "eastus"
env             = "p"
nome_sistema    = "pagamentos"
admin_user_passwd = "P@ssW0dComPl3x"

Uma vez criado todos os componentes do nosso módulo Terraform, vamos agora executa-lo para verificar se esta tudo funcionando como esperado:

terraform init
terraform validate
terraform plan
terraform apply --auto-approve

Vamos ver como estão nossos recursos na console do Azure:

Como podemos ver na tela acima, versão do PostgreSQL esta conforme declaramos e o sizing do servidor foi baseado na variavel env o qual escolhemos um ambiente produtivo, logo, com um sizing maior dentre outras melhorias, isso pode ser confirmado nas tags também.

Para excluir todos esses recursos uma vez que não vamos utiliza-los agora, basta executar:

terraform destroy

E é isso por hoje gente, agradeço novamente pela atenção de vocês e no próximo post iremos construir um módulo MySQL! Não perca! Até a próxima.

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure – Criando Módulo Terraform para CosmosDB (MongoDB)

Fala minha gente! Espero que estejam todos bem!

Neste post iremos construir um módulo Terraform que será utilizado posteriormente em nossa pipeline no Azure DevOps, desta vez construiremos um IaC para provisionar um banco de dados CosmosDB!

Vamos iniciar criando os arquivos de provider.tf:

terraform {

  backend "local" {
  }
 
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "3.48.0"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = "16d873b7-07e2-482d-a0d7-d652b5d72e4a"
}

E rg.tf para criar nosso Resource Group aonde ficará nossos recursos do CosmosDB:

resource "azurerm_resource_group" "rg" {
  name     = var.rg
  location = var.regiao
}

Agora vamos criar um arquivo com nossas variáveis chamado variables.tf:

variable "subscription_id" {
    description = "Passar sua subscription do Azure aonde os recursos serão gerados"
}

variable "rg" {
    description = "Resource Group que será criado|utilizado na criação dos recursos de banco de dados"
}

variable "regiao" {
    description = "Região ao qual os recursos serão criados"
}

variable "ambiente" {
    type = map
    default = {
        d = "dev",
        h = "hml",
        p = "prd"
    }
}

variable "env" {
    default = "d"

    validation {
        condition = contains(["d","h","p"],var.env)
        error_message = "Argument 'env' must be either 'd' (dev), 'h' (hml) or 'p' (prd)"
    }
}

variable "nome_sistema" {
    description = "Nome do sistema ao qual os recursos serão destinados"
}

variable "tempo_expiracao_registro" {
    description = "TTL - Time To Live, tempo de expiração do dado na collection do CosmosDB. Default 7 Dias."
    default = 604800 
}

variable "shard_key" {
    description = "Nome da coluna para chave de particionamento|sharding"
}

variable "throughput" {
    description = "Capacidade de RU/s que a collection terá. Por padrão será o minimo de 400."
    default = 400
}

variable "keys" {
    description = "Colunas para determinar a chave de particionamento da tabela. Por default será a coluna _id"
    type        = list(string)
    default     = ["_id"] 
}

Agora com base nas variáveis criadas acima vamos criar nossos locals que tem por base algumas variáveis passadas, criaremos o arquivo locals.tf com o conteúdo:

locals {
    ambiente                = lookup(var.ambiente,var.env)
    default_ttl_seconds    = var.env == "p" && var.tempo_expiracao_registro > 604800 ? var.tempo_expiracao_registro : 86400 #1 dia

    tags = {
        env         = var.env
        ambiente    = local.ambiente
    }
}

Depois de criarmos nossa base do módulo vamos criar os recursos que é o nosso banco de dados CosmosDB. Para quem não esta familiarizado, o CosmosDB é um banco de dados NoSQL multi engine serverless onde podemos criar bancos de dados de varios tipos como NoSQL com Documentos + Linguagem SQL, PostgreSQL gerenciado, Cassandra (Wide-Column oriented), Tabela, Gremlin (Grafos) e por fim MongoDB que entrega document-json. Abaixo temos todas essas ofertas na console do Azure:

Este módulo que estamos criando tem o intuito de entregar um banco de dados CosmosDB com engine\api MongoDB, justamente para termos uma opção voltada a documentos entre os bancos que estamos provisionando em nossas pipelines, sendo assim, criaremos um arquivo cosmosdb_mongodb.tf com o conteúdo:

resource "azurerm_cosmosdb_account" "cosmosdbmongoacc" {
  name                = "${var.nome_sistema}-cosmosdb-account-${local.ambiente}"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  offer_type          = "Standard"
  kind                = "MongoDB"

  capabilities {
    name = "EnableAggregationPipeline"
  }

  capabilities {
    name = "mongoEnableDocLevelTTL"
  }

  capabilities {
    name = "MongoDBv3.4"
  }

  capabilities {
    name = "EnableMongo"
  }

  consistency_policy {
    consistency_level       = "BoundedStaleness"
    max_interval_in_seconds = 300
    max_staleness_prefix    = 100000
  }

  geo_location {
    location          = azurerm_resource_group.rg.location
    failover_priority = 1
  }

  tags                = merge(local.tags)

}

resource "azurerm_cosmosdb_mongo_database" "mongodb_database" {
  name                = "cosmosdb-mongo-${var.nome_sistema}-${local.ambiente}"
  resource_group_name = azurerm_resource_group.rg.name
  account_name        = azurerm_cosmosdb_account.cosmosdbmongoacc.name
}

resource "azurerm_cosmosdb_mongo_collection" "mongodb_collection" {
  name                = "cosmosdb-${var.nome_sistema}-${local.ambiente}"
  resource_group_name = azurerm_cosmosdb_account.cosmosdbmongoacc.resource_group_name
  account_name        = azurerm_cosmosdb_account.cosmosdbmongoacc.name
  database_name       = azurerm_cosmosdb_mongo_database.mongodb_database.name

  default_ttl_seconds = local.default_ttl_seconds
  shard_key           = var.shard_key
  throughput          = var.throughput

  index {
    keys   = var.keys
    unique = true
  }
}

Vamos então imprimir na saída da criação dos recursos os ids de criação do banco de dados e da collection, criando o arquivo output.tf:

output "cosmodb_database_id" {
    value = azurerm_cosmosdb_mongo_database.mongodb_database.id
}

output "cosmodb_collection_id" {
    value = azurerm_cosmosdb_mongo_collection.mongodb_collection.id
}

Agora por fim, iremos declarar os valores das nossas variáveis para não precisarmos digita-las durante a execução do módulo, crie o arquivo terraform.tfvars com o conteúdo a seguir:

subscription_id = "sua_subscription_id_aqui"
rg              = "TerraformAzureCosmosDBMongoDB"
regiao          = "eastus"
nome_sistema    = "webapp"
env             = "p"
shard_key       = "uniqueKey"
throughput      = 1000

Assim ficou a estrutura do nosso módulo terraform:

Vamos agora executar nosso módulo para verificar se todos os recursos serão executados com êxito, lembrando que você precisará executar o login no azure via cli para conseguir rodar o terraform:

az login #logue na Azure com sua conta
terraform init
terraform validate
terraform plan
terraform apply --auto-approve

Por fim temos nossos recursos criados e podemos ver no console do Azure:

Para nos conectarmos na nossa instancia de banco de dados mongodb precisamos ir em Settings (Configurações) no menu do lado esquerdo da tela e clicar em Connection String, então teremos as seguintes informações:

No meu caso que utilizo JetBrains DataGrip posso utilizar a URL de conexão a base destacada na imagem acima, basta escolher o Datasource Mongodb e configurar para passar apenas a URL de autenticação e clicar em Test Connection e depois em OK:

Pronto, mais um banco de dados provisionado com sucesso no Azure! Agora podemos destruir essa infraestrutura que não precisa ficar disponível neste momento, para isso basta executar:

terraform destroy

Agora vamos subir nosso código para o Github para ficar guardadinho lá esperando a pipeline que faremos posteriormente:

git add .
git commit -m "Modulo Terraform Azure CosmosDB"
git push

É isso por hoje gente, obrigado por me acompanhar nesta série maravilhosa onde estamos desenvolvendo nossa infraestrutura como código!

No próximo post iremos construir mais um banco de dados! Fiquem ligades!

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure – Criando Módulo Terraform para Azure SQL Database

Opaaaa!

Estamos de volta para colocar a mão no código! Vamos iniciar o desenvolvimento da infraestrutura como código do Azure SQL Database para posteriormente o mesmo ser adicionado à pipeline que iremos criar no Azure DevOps. Vamos lá.

Para instalar o Terraform verifique o link a seguir:

https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli

Depois de instalar o Terraform vamos instalar o Visual Studio Code, pelo link:

https://code.visualstudio.com/download

Abra o VS Code e clique no icone de Extensões do lado esquerdo e escreva no campo de busca superior Terraform, clique no icone que tiver Hashicorp Terraform e selo da Hashicorp em baixo, depois disso clique em Instalar (Install):

Agora vamos abrir as pasta aonde estão nossos repositórios: Clique na parte superior em Arquivos (File), Abrir Pasta (Open Folder…) e encontre a pasta onde estão seus repositórios e clique em Abrir (Open):

Agora vamos iniciar o desenvolvimento, crie os seguintes arquivos dentro da estrutura de pasta da pipeline de iac do azure sql database:

Abra o arquivo provider.tf e insira código a seguir:

terraform {

  backend "local" {
  }
 
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "3.48.0"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = "seu_subscription_id"
}

Precisamos declarar as variáveis que serão utilizados nos recursos abaixo, edite o arquivo varibles.tf:

variable "rg" {
    description = "Resource Group que será criado|utilizado na criação dos recursos de banco de dados"
}

variable "regiao" {
    description = "Região ao qual os recursos serão criados"
}

variable "ambiente" {
    type = map
    default = {
        d = "dev",
        h = "hml",
        p = "prd"
    }
}

variable "env" {
    default = "d"

    validation {
        condition = contains(["d","h","p"],var.env)
        error_message = "Argument 'env' must be either 'd' (dev), 'h' (hml) or 'p' (prd)"
    }
}

variable "nome_sistema" {
    description = "Nome do sistema ao qual os recursos serão destinados"
}

variable "storage_account_tier" {
    description = "Tipo de Storage Account que pode ser Standard ou Premium. Por padrão será Standard"
    default = "Standard"
}

variable "storage_account_repl_type" {
    description = "Tipo de Replicação de Storage Account que pode ser LRS, GRS, RAGRS, ZRS, GZRS and RAGZRS. Por padrão será LRS"
    default = "LRS"
}

variable "admin_user_login" {
    description = "Usuario para logar no servidor e banco de dados"
    default = "admindb"
}

variable "admin_user_passwd" {
    description = "Senha do usuario para logar no servidor e banco de dados"
    sensitive = true
}

variable "db_collation" {
    description = "Collation do banco de dados."
    default = "SQL_Latin1_General_CP1_CI_AS"
}

variable "db_max_size" {
    description = "Tamanho máximo do banco de dados. Por padrão 10GB"
    default = 10
}

variable "db_sku_name" {
    description = "Especifica o tipo de perfil de banco de dados que será criado. As opções são: GP_S_Gen5_2,HS_Gen4_1,BC_Gen5_2, ElasticPool, Basic,S0, P2 ,DW100c, DS100. Por padrão será Basic. https://azure.microsoft.com/en-us/pricing/details/azure-sql-database/single/"
    default = "Basic"
}

Vamos criar mais algumas regras onde, para o caso de o ambiente ser produtivo onde vamos forçar a utilização de features que nos permitam ter redundância e performance como storage premium e replica de leitura (ainda não disponível para esta versão do provider, no futuro atualizaremos o post.). Para criar as condições basta comparar o resultado de uma variável com um valor seguido do ? onde a primeira parte é em caso verdadeiro utilizar o valor setado e os : aplica-se uma condição se-não em caso retorno falso da primeira expressão setar este valor, ficando da seguinte forma: condição ? (então) verdadeiro : (se-não) falso. Abra o arquivo locals.tf e cole o texto:

locals {
    ambiente                = lookup(var.ambiente,var.env)
    storage_account_tier    = var.env == "p" ? "Premium" : var.env
    read_replica_count      = var.env == "p" ? 1 : 0
    zone_redundant          = var.env == "p" ? true : false

    tags = {
        env         = var.env
        ambiente    = local.ambiente
    }
}

Após o provider vamos criar o Resource Group que irá comportar nossos recursos, abra o arquivo rg.tf:

resource "azurerm_resource_group" "rg" {
  name     = var.rg
  location = var.regiao
}

Agora vamos abrir o arquivo azuresqldb.tf agora e começar a desenvolver a criação do resource de banco de dados:

resource "azurerm_storage_account" "storage_account" {
  name                     = "sc${var.nome_sistema}${local.ambiente}"
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = azurerm_resource_group.rg.location
  account_tier             = local.storage_account_tier
  account_replication_type = var.storage_account_repl_type
}

resource "azurerm_sql_server" "mssql_server" {
  name                         = "sqlserver-${var.nome_sistema}-${local.ambiente}"
  resource_group_name          = azurerm_resource_group.rg.name
  location                     = azurerm_resource_group.rg.location
  version                      = "12.0"
  administrator_login          = var.admin_user_login
  administrator_login_password = var.admin_user_passwd

  tags                          = local.tags
}

resource "azurerm_sql_database" "mssql_db" {
    name                    = "sqldb-${var.nome_sistema}-${local.ambiente}"
    resource_group_name     = azurerm_resource_group.rg.name
    location                = azurerm_resource_group.rg.location
    server_name             = azurerm_sql_server.mssql_server.name
    collation               = var.db_collation


    tags                    = merge(local.tags)

}

Para saber qual é o ID do banco de dados gerado vamos criar um output no arquivo output.tf:

output "azure_db_sql_id" {
    value = azurerm_sql_database.mssql_db.id
}

Por fim, para não precisar digitar as variáveis obrigatórias no momento do plan e apply, vamos declarar as variáveis e valores das mesmas no arquivo terraform.tfvars:

rg              = "TerraformAzureSQLdb"
regiao          = "eastus"
env             = "p"
nome_sistema    = "contabilidade"
admin_user_passwd = "P@ssW0dComPl3x"

Após popular todos nossos arquivos vamos agora executar nosso Terraform para verificar se tudo esta sendo criado de forma esperada antes de criarmos a pipeline.

Para iniciar vamos executar:

terraform init

Este comando irá baixar o provider do Azure, o azurerm.

Depois disso vamos validar a sintaxe do código declarado:

terraform validate

Como podemos ver ele mostra um aviso dizendo que o recurso que cria o server que irá alocar o banco de dados esta deprecado e que na versão 4.0 será descontinuado, isso também esta explicito na documentação do recurso, logo após o warning podemos ver que a validação foi um sucesso, vamos seguir com o plan:

terraform plan

Veremos todos os recursos que serão criados e as configurações determinadas nos arquivos azuresqldb.tf. Vamos agora criar efetivamente com o apply:

terraform apply --auto-approve

Recursos criados, vamos conferir no console:

Agora vou liberar o acesso ao server a partir do meu ip, basta clicar no recurso do azure sql server, depois clicar em Network, terá um campo para adicionar o seu ip externo para ser liberado, clique no + e depois em salvar:

Com isso já podemos configurar nossa conexão e esta tudo funcionado conforme o exemplo abaixo:

Como tudo funcionou bem podemos agora destruir nossa infraestrutura pois o objetivo era montar o módulo de criação do nosso azure sql database. Para destruir a infraestrutura basta executar:

terraform destroy

Escreva “yes” para confirmar a destruição dos recursos:

Por fim vamos subir as alterações para o Github, executando:

git add .
git commit -m "Modulo Terraform Azure SQL Database"
git push

No próximo post vamos desenvolver mais um módulo terraform, fiquem ligados!

Até a próxima pessoal!

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure – Criando repositório no Git

Vamos por a mão na massa em nosso projeto de construção de algumas pipelines no Azure DevOps para entregar instancias de bancos de dados em diversas tecnologias no Azure.

Para começar, vamos criar os repositórios das tecnologias no Github, para isso, caso não tenha conta, crie uma, caso já tenha faça login:

Todos os projetos estarão disponíveis no meu profile: https://github.com/williamloliveira

Acesse seu profile:

Clique em repositórios e depois em Novo:

Na tela seguinte preencha os campos da seguinte forma:

  • Nome do Repositório: pipeline_iac_azure_sql_db
  • Descrição: Repositório onde estarão os códigos responsáveis pela pipeline e criação da infraestrutura como código de criação de um banco de dados no Azure SQL Databases.
  • Maque o repositório como público.
  • Maque para adicionar um arquivo README para que possamos documentar algumas coisas posteriormente neste repositório
  • Adicione um arquivo .gitignore do tipo Terraform para que possamos ignorar alguns arquivos que serão criados no repositório durante nossos testes
  • Por fim clique em Criar Repositório

Faça o mesmo para as demais tecnologias, sendo os nomes dos repositórios:

  • pipeline_iac_azure_cache_redis
  • pipeline_iac_azure_db_mysql
  • pipeline_iac_azure_db_postgresql
  • pipeline_iac_azure_cosmosdb

Por fim teremos todos os nossos repositórios devidamente criados:

Agora vamos configurar os repositórios em nossa maquina, para isso precisamos ter o Git instalado, se você utiliza Linux ou Mac provavelmente já o tem rodando, para o caso de rodar Windows, segue o link de instalação: https://git-scm.com/download/win

Após instalar o Git, execute o comando para saber se esta tudo ok:

git -v

Com o git ok, vamos clonar nossos repositórios para dentro de nossa maquina com os seguintes comandos:

git clone https://github.com/williamloliveira/pipeline_iac_azure_cosmosdb.git
git clone https://github.com/williamloliveira/pipeline_iac_azure_db_postgresql.git
git clone https://github.com/williamloliveira/pipeline_iac_azure_db_mysql.git
git clone https://github.com/williamloliveira/pipeline_iac_azure_cache_redis.git
git clone https://github.com/williamloliveira/pipeline_iac_azure_sql_db.git

Se entrarmos em uma das pastas e listarmos nossos arquivos veremos que teremos o arquivo README.md, .gitignore e a pasta .git:

Bom, já temos a estrutura para seguirmos com o desenvolvimento, no próximo capitulo começaremos a desenvolver nossos módulos Terraform para provisionar nossa infraestrutura.

Não perca! Até a próxima!

[Série][DBRE] Pipeline de IaC para provisionamento de bancos de dados no Azure

Fala galera!

Mais uma série iniciando aqui no blog! Dessa vez vamos iniciar o desenvolvimento de um projeto onde iremos construir um pipeline de provisionamento de bancos de dados no Azure utilizando Visual Studio Code, Github, Azure DevOps e Terraform!

A ideia aqui é demonstrar principalmente para DBA’s, Desenvolvedores e SysAdmins tradicionais como funciona um fluxo de entrega de infraestrutura de banco de dados em cloud publica, mais especificamente no Azure.

Uma outra motivação é demonstrar um pouco mais sobre processos aonde um DBRE pode atuar no dia a dia, uma vez que deixa de ser um DBA tradicional para atuar mais próximo dos desenvolvedores e sysadmins. Parte do trabalho do DBRE é retirar o Toil (trabalho manual\repetitivo) tanto da sua área como das demais, aumentando a eficiência da área de banco de dados e conseguindo mais tempo para trabalhar em entregas de valor para a organização.

Abaixo temos o fluxo de entrega de infraestrutura de banco de dados no Azure:

1 – Iniciaremos desenvolvendo o código da infraestrutura no VS Code;

2 – Vamo criar um repositório do Github e commitar o mesmo de forma a termos nosso código disponível e versionado;

3 – Depois criaremos uma pipeline que irá verificar quando houver um novo commit em nosso repositório e irá iniciar a pipeline para criação da infraestrutura;

4 – Aqui o terraform será executado iniciando o provisionamento da infra de banco de dados;

5 – Por fim teremos um banco de dados provisionado em algum desses serviços: Azure Database For MySQL, Azure Database for PostgreSQL, Azure CosmosDB, Azure Cache for Redis e Azure SQL Database.

Para este projeto iremos desenvolver um módulo Terraform e uma pipeline para cada tipo de banco de dados, logo, será bastante trabalho mas iremos fazer em dozes homeopáticas para ficar bem prático e diminuir a curva de aprendizado.

Então fique ligado para os próximos posts dessa série maravilinda!

Até mais!