En este artículo veremos como crear un bucket en GCP con fuentes de datos que se van a utilizar para crear un flujo en con google BigQuery, todo utilizando terraform.
Para está POC se requiere una cuenta de Google Cloud, si no tienes una puedes crearla y te regalan 300 USD de crédito. https://cloud.google.com/
Esté tutorial puede llegar a generar un costo mínimo por lo cual se requiere tener especial cuidado en destruir los artefactos creados.
Ya con una cuenta en google es necesario tener un proyecto y una cuenta de servicio para que pueda ser usada por terraform. https://cloud.google.com/compute/docs/access/service-accounts?hl=es-419
Bien, por ahora no usaremos un backend bucket para guardar nuestro tf state pero bien se podría incluir.
Entonces la estructura de nuestro proyecto quedaría como se muestra en el diagrama:
- Crear un bucket y cargarle un archivo .csv
- Crear la definición de BigQuery
- Crear una tabla con los datos de nuestro archivo .csv
- Crear una vista basada en la tabla anterior con un filtro (SQL Query)
- Crear una vista con información de BigQuery public dataset https://cloud.google.com/bigquery/public-data
Nuestro proyecto de terraform lo puedes ver acá: https://github.com/xRegner/GCP-Terraform-Dataset
.
├── README.md
├── bucket-sample-gcp-xtian
│ ├── bucket.tf
│ ├── output.tf
│ └── variables.tf
└── datasets-sample-gcp-xtian
├── data
│ └── sheet-t.csv
├── main.tf
├── teradata-307123-aea8bdd5e41f.json
├── terraform.tfvars
└── variables.tf
Básicamente en una carpeta vamos a poner a manera de modulo la creación de nuestro bucket con el archivo .csv que se encuentra dentro de la carpeta datasets-sample-gcp-xtian > data > sheet-t.csv
Una vez que nuestro bucket fue creado y aprovisionado con el archivo vamos a sacar la ruta privada de ese csv para que nuestro dataset pueda ir a buscar la info, esto se puede ver el archivo output.tf
output "bucketurl" { value = google_storage_bucket.my_bucket_xtian_pro.url } output "file_name" { value = google_storage_bucket_object.topsecret_info.name }
La carpeta datasets-sample-gcp-xtian contiene el main.tf que va a crear todos los componentes y se describe a continuación:
provider "google" { credentials = file("aquí debes poner la ruta de tu cuenta de servicio en .json ") project = var.project_id region = var.region zone = var.zone } # Aquí importamos el módulo y le pasamos las variables del nombre de nuestro bucket module "bucket_info" { source = "../bucket-sample-gcp-xtian" bucket_name = var.bucket_name } # en esta sección definimos nuestro BigQuery resource "google_bigquery_dataset" "bigqry_rhdw" { dataset_id = "teradatadts" friendly_name = "test-dtaset" description = "Nuestro super dataset de tipo tabla" location = "US" default_table_expiration_ms = 3600000 labels = { env = "default" } } # En esta sección estamos creando un schema vacío de datos y nuestra tabla se llama tabla1 resource "google_bigquery_table" "default" { dataset_id = google_bigquery_dataset.bigqry_rhdw.dataset_id table_id = "Tabla1" deletion_protection = false time_partitioning { type = "DAY" } labels = { env = "default" } schema = <<EOF [ { "name": "permalink", "type": "STRING", "mode": "NULLABLE", "description": "The Permalink" }, { "name": "state", "type": "STRING", "mode": "NULLABLE", "description": "State where the head office is located" } ] EOF } #Aquí creamos la tabla que se llena desde el archivo que depositamos en el bucket resource "google_bigquery_table" "sheet" { dataset_id = google_bigquery_dataset.bigqry_fidw.dataset_id table_id = "secret-data" deletion_protection = false schema = <<EOF [ { "name": "id", "type": "STRING", "mode": "NULLABLE", "description": "el id de los paises" }, { "name": "Country", "type": "STRING", "mode": "NULLABLE", "description": "algunos paises de ejemplo" }, { "name": "Quote", "type": "INTEGER", "mode": "NULLABLE", "description": "monto de venta" } ] EOF external_data_configuration { autodetect = true source_format = "CSV" source_uris = [ "${module.bucket_info.bucketurl}/${module.bucket_info.file_name}", ] } } # Aquí creamos la view de la tabla anteriormente creada resource "google_bigquery_table" "public" { deletion_protection = false dataset_id = google_bigquery_dataset.bigqry_rhdw.dataset_id table_id = "view-pro" view { query = "SELECT * FROM `teradata-307123.teradatadts.secret-data` WHERE Country = 'Mexico'" use_legacy_sql = false } depends_on = [ google_bigquery_table.sheet, ] } # Finalmente creamos una vista a partir de los datos públicos que tiene google resource "google_bigquery_table" "publicdataset" { deletion_protection = false dataset_id = google_bigquery_dataset.bigqry_rhdw.dataset_id table_id = "view-pro-public" view { query = "SELECT EXTRACT(YEAR FROM creation_date) AS Year, EXTRACT(MONTH FROM creation_date) AS Month, COUNT(*) AS Number_of_Questions, ROUND(100 * SUM(IF (answer_count > 0, 1, 0)) / COUNT(*), 1) AS Percent_Questions_with_Answers FROM `bigquery-public-data.stackoverflow.posts_questions` GROUP BY Year, Month HAVING Year > 2009 AND Year < 2016 ORDER BY Year" use_legacy_sql = false } depends_on = [ google_bigquery_dataset.bigqry_fidw, ] } output "uris" { value = google_bigquery_table.sheet.external_data_configuration[0].source_uris }
Los siguientes pasos son simplemente hacer:
#Dentro de la carpeta que contiene el archivo main: terraform init terraform plan terraform apply -auto-approve
Y eso es todo.
Conclusión:
Con terraform podemos armar un flujo de datos inicial definiendo así un estado deseado de trabajo y a la vez construir una estructura que puede ser consumida por herramientas de visualización como Data studio, Tableau, Microstrategy etc, esta es una simple POC pero definitivamente puede ser la base de un proyecto complejo de aprovisionamiento de datos + infraestructura como código.
Espero te sirva esta información.
Christian Regner