Migration de base de données avec Cloud Seed.

EZEKIAS BOKOVE
5 min readNov 21, 2022

--

Database migration with Cloud Seed

Pour commencer, nous allons d’abord explorer Cloud Seed.

Cloud Seed is an open-source collaboration between Google Cloud and GitLab to accelerate cloud adoption and app-modernization.

Cloud Seed makes it ridiculously simple to provision and consume Google Cloud services within the GitLab web UI.

DevFest Nantes

Dans cet article, on verra comment utiliser Cloud Seed pour concevoir des pipelines de migrations de base de données sur Cloud SQL. À la base, Cloud Seed nous permet d’effectuer un certain nombre de choses tel que :

  • Déployer des applications Web basées sur des conteneurs sur Cloud Run
  • Créer des instances de Cloud SQL pour PostgreSQL, MySQL, SQL Server, …

L’objectif de cet article, est de tirer parti des avantages de Cloud Seed pour effectuer d’autres actions comme la migration de base de données.

Let’s go …

- Configuration de l’environnement

Dans le dashboard du projet GitLab, sélectionnez Infrastructure > Google Cloud > Configuration. Après cela, vous serez amené à vous connecter avec votre compte Google Cloud.

Une fois que c’est fait, nous allons utiliser Cloud Seed pour créer un service account qui va nous permettre d’accéder à certains services Google Cloud tels que : Cloud Run, Cloud SQL for Postgres, Cloud Storage, …

Personnellement, je pense que le fait d’avoir un service account qui dispose d’une panoplie de rôles n’est pas trop bon pour la sécurité.

Lors de la création du service account nous allons choisir la branche ou le tag qui sera lié à ce dernier.

Créer un service account depuis GitLab

Maintenant, nous allons configurer la région dans laquelle nous allons exécuter notre charge de travail.

Setting up a GCP region on GitLab

Pour finir, nous allons créer une instance Cloud SQL pour Postgres.

Aller dans Infrastructure > Google Cloud > Databases.

Une fois que c’est bon, nous allons configurer le fichier .gitlab-ci.yml pour l’intégration continue.

# File: .gitlab-ci.yml
stages:
- database-migration

database-migration:
stage: database-migration
image: registry.gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library/google-cloud-sdk-for-gitlab:main
script:
- chmod +x cloud-migration.sh
- ./cloud-migration.sh
environment:
name: migration/$CI_COMMIT_REF_NAME
action: stop

Dans le fichier .gitlab-ci.yml , nous allons exécuter le fichier cloud-migration.sh que voici 👇.

## cloud-migration.sh
## utils

error_and_exit() {
local MESSAGE="${1}"
local HINT="${2}"
echo ""
echo "🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥"
echo ""
echo "Error \`cloud-run.sh\`"
echo "===================="
echo ""
echo "Message"
echo "-------"
echo "$MESSAGE"
echo ""
echo "Hint"
echo "----"
echo "$HINT"
echo ""
echo "/end"
echo ""
exit 1
}

## required environment variables

if [[ -z "$GCP_PROJECT_ID" ]]; then
error_and_exit "\$GCP_PROJECT_ID is not set" "Did you setup a service account?"
fi

if [[ -z "$GCP_SERVICE_ACCOUNT" ]]; then
error_and_exit "\$GCP_SERVICE_ACCOUNT is not set" "Did you setup a service account?"
fi

if [[ -z "$GCP_SERVICE_ACCOUNT_KEY" ]]; then
error_and_exit "\$GCP_SERVICE_ACCOUNT_KEY is not set" "Did you setup a service account?"
fi

if [[ -z "$CI_PROJECT_ID" ]]; then
error_and_exit "\$CI_PROJECT_ID is not set"
fi

if [[ -z "$CI_COMMIT_REF_SLUG" ]]; then
error_and_exit "\$CI_COMMIT_REF_SLUG is not set"
fi

## private variables

SERVICE_NAME="gitlab-$CI_PROJECT_ID-$CI_COMMIT_REF_SLUG"
__GCP_SERVICE_ACCOUNT_KEY_PRIVATE_KEY_DATA_FILE_NAME=local-service-account-key-private-key-data.txt
__GCP_SERVICE_ACCOUNT_KEY_FILE_NAME=local-service-account-key-file.json

## cleanup tmp files

rm --force $__GCP_SERVICE_ACCOUNT_KEY_PRIVATE_KEY_DATA_FILE_NAME
rm --force $__GCP_SERVICE_ACCOUNT_KEY_FILE_NAME

## extract service account key file

case "$GCP_SERVICE_ACCOUNT_KEY" in
*privateKeyData*)
echo "🟩🟩 '.privateKeyData' found"
echo "$GCP_SERVICE_ACCOUNT_KEY" | jq --raw-output '.privateKeyData' >$__GCP_SERVICE_ACCOUNT_KEY_PRIVATE_KEY_DATA_FILE_NAME
base64 --decode $__GCP_SERVICE_ACCOUNT_KEY_PRIVATE_KEY_DATA_FILE_NAME >$__GCP_SERVICE_ACCOUNT_KEY_FILE_NAME
;;
*private_key_data*)
echo "🟩🟩 '.private_key_data' found"
echo "$GCP_SERVICE_ACCOUNT_KEY" | jq --raw-output '.private_key_data' >$__GCP_SERVICE_ACCOUNT_KEY_FILE_NAME
;;
*)
error_and_exit "Failed to extract service account key file" "Did you setup a service account?"
;;
esac

## gcloud auth and configure

gcloud auth activate-service-account --key-file $__GCP_SERVICE_ACCOUNT_KEY_FILE_NAME || error_and_exit "Failed to activate service account"
gcloud config set project $GCP_PROJECT_ID || error_and_exit "Failed to set GCP project"

## gcloud command for migration

gcloud builds submit . --config=cloudbuild.yaml || error_and_exit "Failed to Database Migration "

Avec cloud-migration.sh nous allons établir la connexion avec Google Cloud et faire appel à Cloud Build afin d’exécuter le fichier cloudbuild.yaml pour effectuer notre migration.

# File:  cloudbuild.yaml
steps:
# build the container image
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/students/${_IMAGE_NAME}', '.' ]

# push the container image
- name: 'gcr.io/cloud-builders/docker'
args: [ 'push', 'us-central1-docker.pkg.dev/$PROJECT_ID/students/${_IMAGE_NAME}']

- name: "gcr.io/google-appengine/exec-wrapper"
entrypoint: 'bash'
args: ["-c",
"/buildstep/execute.sh -i us-central1-docker.pkg.dev/$PROJECT_ID/students/${_IMAGE_NAME} -s $$CONNECTION_NAME -e DATABASE_URL=$$DATABASE_URL -- alembic upgrade head"]
secretEnv: ['DATABASE_URL', 'CONNECTION_NAME']
options:
logging: CLOUD_LOGGING_ONLY

substitutions:
_IMAGE_NAME: "img-students-api"

availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/DATABASE_URL/versions/latest
env: 'DATABASE_URL'
- versionName: projects/$PROJECT_ID/secrets/CONNECTION_NAME/versions/latest
env: 'CONNECTION_NAME'

Dans le fichier cloudbuild.yaml , il y a deux variables d’environnement à savoir DATABASE_URL et CONNECTION_NAME que nous allons stocker dans Secret Manager pour des raisons de sécurité.

DATABASE_URL=postgresql://username:password@localhost/databasename?host=/cloudsql/project-id:region:instance-id

CONNECTION_NAME=project-id:region:instance-id

Pour enregistrer une variable dans Secret Manager, sélectionnez Securitysuivi de Secret Manager dans le menu en haut à gauche de Google Cloud. Cliquez ensuite sur CREATE SECRET et mettez le nom de la variable et la valeur du secret. Laissez le reste des paramètres par défaut et créer votre secret.

NB: Utiliser les vraies variables.

- Service account

Nous allons apporter des modifications au service account qui a été créé plus haut parce qu’il dispose de certains rôles dont nous n’avons pas besoin. Pour cela, il faut sélectionner IAM & Admin suivi de IAM dans le menu en haut à gauche. Une fois que vous êtes dans IAM, chercher le service account sous la forme gitlab-xxxxxxxxxxxxxxxxxxxxxx et modifier ces rôles comme suit 👇.

Pour effectuer notre migration, le service account de Cloud Build aura besoin des rôles suivant : Cloud Build Service Account, Cloud SQL Client, Secret Manager Secret Accessor et Service Account User .

- Artifact Registry

Pour finir, nous allons créer un repo Docker pour stocker nos images Docker.

Create repo docker in Artifact Registry

C’est le moment de lancer notre pipeline pour la migration de données🤞.

Mission accomplie, la migration a été effectuer avec succès.

Le code est disponible ici 👇 .

Merci pour la lecture, j’espère que vous avez aimé. À la prochaine.👋

--

--

EZEKIAS BOKOVE

GDE & Champion Innovators for Google Cloud. Serverless & DevOps enthusiast. I like to learn from others, to share my knowledge with other people.