
Maîtriser ses réseaux et ses équipements grâce à la gestion des adresses IP (IPAM)
Ces derniers temps, j'ai remarqué que de plus en plus de clients rencontrent des difficultés réseau, notamment en peering, à cause de collisions de plages d'adresses IP. Le besoin de planifier et de gérer les adresses IP à l'échelle de l'organisation devient évident.
Une feuille de calcul partagée peut suffire pour suivre vos adresses IP, mais des outils logiciels dédiés existent aussi. Cet article montre comment exécuter Netbox, un outil open source populaire de gestion des adresses IP (IPAM), en mode cloud-native sur Google Cloud Platform (GCP).
L'architecture traditionnelle
Historiquement, Netbox tourne sur une ou plusieurs machines virtuelles, derrière un serveur web. Une image Docker maintenue par la communauté existe, mais les seules instructions fournies reposent sur docker compose. Cette architecture ressemble pourtant à beaucoup d'applications développées ou exploitées en entreprise — un excellent cas d'école pour illustrer une migration vers le cloud public.

Source : Netbox — installation standard de Netbox
Une conception cloud-native
J'ai voulu comprendre le fonctionnement de l'image Docker, ses dépendances et ses paramètres de configuration, pour la déployer sur GCP en n'utilisant que des services managés. Cet exemple illustre les approches move and improve ou rip and replace lors d'une migration vers le cloud public.

Installation Netbox revue sur GCP avec des services managés
Composants applicatifs
- Application Netbox (application Python utilisant le framework Django)
- Base de données PostgreSQL (Cloud SQL)
- Redis (Cloud Memorystore)
Choix de conception
- Base de données et cache managés (Cloud SQL, Cloud Memorystore)
- IP privées uniquement pour les bases de données et le cache (Private Service Access)
- DNS privé pour les noms d'hôtes des bases (Cloud DNS)
- Secrets stockés dans le gestionnaire de secrets (Secret Manager)
- Runtime de conteneurs serverless (Cloud Run, Artifact Registry)
- Load balancer global avec TLS (HTTP(S) Load Balancing, Managed Certificate)
- Pare-feu WAF (Cloud Armor)
Beaucoup d'organisations peinent à connecter services managés et applications serverless via des adresses IP privées. Cet exemple illustre comment réserver des plages privées dans son réseau VPC, puis les attribuer aux services managés pour créer un pont de connectivité.
Cloud DNS sert à établir des noms d'hôtes privés que les applications utilisent pour se connecter aux bases de données. Cela offre davantage de souplesse à l'avenir si vous changez de base ou devez basculer en cas de panne : il suffit de mettre à jour les enregistrements DNS et les applications continuent de pointer vers le même domaine. En théorie, j'aurais pu utiliser le DNS forwarding et tout connecter à mon domaine public, mais en interne ce n'est pas nécessaire — j'ai donc utilisé example.com.
La VM bastion (ou jump host) n'était pas indispensable, mais j'en ai créé une pour tester les connexions au fur et à mesure de la mise en place. Normalement, un bastion est déployé dans un managed instance group (MIG) de taille 1, sans adresse IP externe.
Application web sécurisée et load-balancée

Pour bien illustrer comment l'ensemble s'articule, j'ai utilisé un domaine personnel et enregistré un A record pointant vers l'adresse IP statique attribuée au Global Load Balancer ; un certificat managé a été provisionné automatiquement.

Pour renforcer la sécurité, j'ai appliqué une politique Cloud Armor (pare-feu WAF) au load balancer et restreint les plages d'IP (voir ci-dessous).
Code d'implémentation
Le code ci-dessous reprend, étape par étape, les commandes utilisées pour tout configurer : réseau, variables d'environnement et secrets, bases de données, artifact registry et images Docker, Cloud Run, load balancing et pare-feu WAF.
#!/usr/bin/env bash
###################################################################### REFERENCES# - https://docs.netbox.dev/en/stable/installation/3-netbox/# - https://github.com/netbox-community/netbox-docker/wiki/# - https://hub.docker.com/r/netboxcommunity/netbox# - https://cloud.google.com/sql/docs/postgres/configure-private-ip# - https://cloud.google.com/sql/docs/postgres/create-instance# - https://cloud.google.com/sql/docs/postgres/create-manage-databases#gcloud# - https://cloud.google.com/sql/docs/postgres/create-manage-users#gcloud# - https://cloud.google.com/memorystore/docs/redis/create-manage-instances#creating_a_redis_instance_with_a_specific_ip_address_range# - https://cloud.google.com/artifact-registry/docs/docker/store-docker-container-images# - https://cloud.google.com/artifact-registry/docs/docker/pushing-and-pulling# - https://cloud.google.com/dns/docs/zones#create-private-zone# - https://cloud.google.com/dns/docs/records# - https://cloud.google.com/secret-manager/docs/configuring-secret-manager# - https://cloud.google.com/secret-manager/docs/create-secret# - https://cloud.google.com/run/docs/configuring/secrets#command-line# - https://cloud.google.com/run/docs/configuring/connecting-vpc#gcloud#####################################################################
export PROJECT_ID=$(gcloud config get-value project)export PROJECT_USER=$(gcloud config get-value core/account) # set current userexport PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")export IDNS=${PROJECT_ID}.svc.id.goog # workflow identity domain
export GCP_REGION="us-central1" # CHANGEME (OPT)export GCP_ZONE="us-central1-a" # CHANGEME (OPT)export NETWORK_NAME="default"
# enable apisgcloud services enable compute.googleapis.com \ servicenetworking.googleapis.com \ vpcaccess.googleapis.com \ secretmanager.googleapis.com \ sqladmin.googleapis.com \ redis.googleapis.com \ artifactregistry.googleapis.com \ dns.googleapis.com \ cloudbuild.googleapis.com \ storage.googleapis.com\ run.googleapis.com
# configure gcloud sdkgcloud config set compute/region $GCP_REGIONgcloud config set compute/zone $GCP_ZONE
############################################################## NETWORKING#############################################################export NETBOX_NETWORK_NAME="netbox"export NETBOX_RESERVED_RANGE_NAME="google-managed-services-netbox"export SUBNET_BASTION_NAME="bastion"export SUBNET_BASTION_RANGE="10.250.0.0/29"export CONNECTOR_NAME="serverless-connector"export CONNECTOR_RANGE="10.200.0.0/28"export DNS_ZONE="private-zone"export DNS_SUFFIX="example.com" # CHANGEME (OPT)export DNS_LABELS="dept=networking" # CHANGEME (OPT)
# create network (custom-mode)gcloud compute networks create $NETBOX_NETWORK_NAME \ --subnet-mode=custom
# create bastion subnetgcloud compute networks subnets create $SUBNET_BASTION_NAME \ --region=$GCP_REGION \ --network=$NETBOX_NETWORK_NAME \ --range=$SUBNET_BASTION_RANGE
# allocate private rangegcloud compute addresses create $NETBOX_RESERVED_RANGE_NAME \ --global \ --purpose=VPC_PEERING \ --addresses=10.100.0.0 \ --prefix-length=16 \ --network=projects/$PROJECT_ID/global/networks/$NETBOX_NETWORK_NAME
# create peering for managed servicesgcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=$NETBOX_RESERVED_RANGE_NAME \ --network=$NETBOX_NETWORK_NAME
# create serverless vpc connector (for peering serverless to VPC)gcloud compute networks vpc-access connectors create $CONNECTOR_NAME \ --network $NETBOX_NETWORK_NAME \ --region $GCP_REGION \ --range $CONNECTOR_RANGE
# create private zonegcloud dns managed-zones create $DNS_ZONE \ --description="internal zone" \ --dns-name=$DNS_SUFFIX \ --networks=$NETBOX_NETWORK_NAME \ --labels=$DNS_LABELS \ --visibility=private
# firewall allow sshgcloud compute firewall-rules create fw-allow-ssh \ --network=$NETBOX_NETWORK_NAME \ --action=allow \ --direction=ingress \ --target-tags=allow-ssh \ --rules=tcp:22
############################################################## NETBOX (ENV/SECRETS)#############################################################export SECRET_ID="netbox-secrets"export SECRET_VERSION=1export SECRET_FILE=".env-local"export ENV_FILE="netbox.env"# individualexport SECRET_DB_PASS="db_password"export SECRET_REDIS_PASS="redis_password"export SECRET_REDIS_CACHE_PASS="redis_cache_password"export SECRET_SU_PASS="superuser_password"export SECRET_EMAIL_PASS="email_password"export SECRET_SECRET_KEY="secret_key"
# fetch secret values from local .env filesource $SECRET_FILE
# save file with injected valuescat > $ENV_FILE << EOF# requiredALLOWED_HOSTS="*"DB_HOST=$POSTGRES_INSTANCE.$DNS_SUFFIXDB_PORT=$POSTGRES_PORTDB_NAME=netboxDB_USER=netboxREDIS_CACHE_DATABASE=1REDIS_CACHE_HOST=$REDIS_INSTANCE.$DNS_SUFFIXREDIS_CACHE_INSECURE_SKIP_TLS_VERIFY=falseREDIS_CACHE_SSL=falseREDIS_DATABASE=0REDIS_HOST=$REDIS_INSTANCE.$DNS_SUFFIXREDIS_INSECURE_SKIP_TLS_VERIFY=falseREDIS_SSL=falseEOF
# add config to envsource $ENV_FILE
# create secret for all varsgcloud secrets create $SECRET_ID --replication-policy="automatic"gcloud secrets versions add $SECRET_ID --data-file=${PWD}/$SECRET_FILE # version 1
# create env secretsecho -n $DB_PASSWORD | gcloud secrets create $SECRET_DB_PASS \ --replication-policy="automatic" \ --data-file=-# redis auth string after creation# redis_cache auth string after creationecho -n $SUPERUSER_PASSWORD | gcloud secrets create $SECRET_SU_PASS \ --replication-policy="automatic" \ --data-file=-echo -n $EMAIL_PASSWORD | gcloud secrets create $SECRET_EMAIL_PASS \ --replication-policy="automatic" \ --data-file=-echo -n $SECRET_KEY | gcloud secrets create $SECRET_SECRET_KEY \ --replication-policy="automatic" \ --data-file=-
############################################################## DATABASE (POSTGRES)#############################################################export POSTGRES_INSTANCE="netbox-db"export POSTGRES_VERSION="POSTGRES_14"export POSTGRES_TIER="db-f1-micro"export POSTGRES_PORT=5432
gcloud beta sql instances create $POSTGRES_INSTANCE \ --database-version=$POSTGRES_VERSION \ --tier=$POSTGRES_TIER \ --network=projects/$PROJECT_ID/global/networks/$NETBOX_NETWORK_NAME \ --no-assign-ip \ --allocated-ip-range-name=$NETBOX_RESERVED_RANGE_NAME \ --region=$GCP_REGION
# get internal IPexport POSTGRES_HOST=$(gcloud beta sql instances describe $POSTGRES_INSTANCE --format="value(ipAddresses.ipAddress)")
# add to private-zone DNSgcloud dns record-sets transaction start --zone=$DNS_ZONEgcloud dns record-sets transaction add $POSTGRES_HOST \ --name="$POSTGRES_INSTANCE.$DNS_SUFFIX" --ttl="3600" --type="A" --zone=$DNS_ZONEgcloud dns record-sets transaction execute --zone=$DNS_ZONE
# lock down postgres (admin) user [manually input at prompt]gcloud sql users set-password postgres \ --instance=$POSTGRES_INSTANCE \ --prompt-for-password
# create netbox usergcloud sql users create $DB_USER \ --instance=$POSTGRES_INSTANCE \ --password=$DB_PASSWORD
# create databasegcloud sql databases create $DB_NAME \ --instance=$POSTGRES_INSTANCE
############################################################## CACHE (REDIS)#############################################################export REDIS_INSTANCE="netbox-cache"export REDIS_VERSION="redis_6_x"
gcloud redis instances create $REDIS_INSTANCE \ --size=1 \ --tier=STANDARD \ --region=$GCP_REGION \ --network=$NETBOX_NETWORK_NAME \ --reserved-ip-range=$NETBOX_RESERVED_RANGE_NAME \ --connect-mode=PRIVATE_SERVICE_ACCESS \ --redis-version=$REDIS_VERSION \ --enable-auth
# get internal IPexport REDIS_HOST=$(gcloud redis instances describe $REDIS_INSTANCE --region $GCP_REGION --format="value(host)")export REDIS_PORT=$(gcloud redis instances describe $REDIS_INSTANCE --region $GCP_REGION --format="value(port)")
# get auth stringexport REDIS_PASSWORD=$(gcloud beta redis instances get-auth-string $REDIS_INSTANCE --region $GCP_REGION --format="value(authString)")
# add to private-zone DNSgcloud dns record-sets transaction start --zone=$DNS_ZONEgcloud dns record-sets transaction add $REDIS_HOST \ --name="$REDIS_INSTANCE.$DNS_SUFFIX" --ttl="3600" --type="A" --zone=$DNS_ZONEgcloud dns record-sets transaction execute --zone=$DNS_ZONE
# add secrets to secret managerecho -n $REDIS_PASSWORD | gcloud secrets create $SECRET_REDIS_PASS \ --replication-policy="automatic" \ --data-file=-echo -n $REDIS_PASSWORD | gcloud secrets create $SECRET_REDIS_CACHE_PASS \ --replication-policy="automatic" \ --data-file=-
############################################################## COMPUTE (TEST BASTION)# - NOTE: if real bastion, create in managed instance group size=1# - NOTE: if real bastion, no external IP and use IAP tunnel only#############################################################export BASTION_NAME="bastion-1"
# create compute instance to test from proxy-only network to ILBgcloud compute instances create $BASTION_NAME \ --machine-type e2-micro \ --zone $GCP_ZONE \ --network $NETBOX_NETWORK_NAME \ --subnet $SUBNET_BASTION_NAME \ --tags allow-ssh
# install netcatgcloud compute ssh $BASTION_NAME --zone $GCP_ZONE -- sudo apt-get updategcloud compute ssh $BASTION_NAME --zone $GCP_ZONE -- sudo apt-get -y install netcat
# test internal DNS for database (IP may vary)gcloud compute ssh $BASTION_NAME --zone $GCP_ZONE -- nc -zv $POSTGRES_INSTANCE.$DNS_SUFFIX $POSTGRES_PORT# Connection to netbox-db.example.com (10.100.0.5) 5432 port [tcp/postgresql] succeeded!
# test internal DNS for cache (IP may vary)gcloud compute ssh $BASTION_NAME --zone $GCP_ZONE -- nc -zv $REDIS_INSTANCE.$DNS_SUFFIX $REDIS_PORT# Connection to netbox-cache.example.com (10.100.1.4) 6379 port [tcp/redis] succeeded!
############################################################## ARTIFACT REGISTRY# - WARNING: arm architecture on Mac will produce non-runnable image# run pull / tag / push commands from your temp bastion#############################################################export REPO_NAME="netbox-repo"export NETBOX_IMAGE="netboxcommunity/netbox:v3.4-beta1-2.3.0"export IMAGE_NAME="netbox"export TAG_NAME="v3.4-beta1-2.3.0"export IMAGE_PATH=$GCP_REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/$IMAGE_NAME:$TAG_NAME
gcloud artifacts repositories create $REPO_NAME \ --repository-format=docker \ --location=$GCP_REGION \ --description="Docker repository"
# configure authgcloud auth configure-docker ${GCP_REGION}-docker.pkg.dev
# fetch latest community netbox imagedocker pull $NETBOX_IMAGE
# tag image for artifact registrydocker tag $NETBOX_IMAGE \ $IMAGE_PATH
# push image to artifact registrydocker push $IMAGE_PATH
############################################################## NETBOX (CLOUD RUN)#############################################################export SERVICE_NAME="netbox"export SECRET_PATH="env/$SECRET_FILE" # as config in docker-compose.yamlexport SA_EMAIL="[email protected]"
# add compute service account access to secrets# - NOTE: best practice to create separate service account to run each workloadgcloud secrets add-iam-policy-binding $SECRET_ID \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"# individualgcloud secrets add-iam-policy-binding $SECRET_DB_PASS \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"gcloud secrets add-iam-policy-binding $SECRET_REDIS_PASS \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"gcloud secrets add-iam-policy-binding $SECRET_REDIS_CACHE_PASS \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"gcloud secrets add-iam-policy-binding $SECRET_SU_PASS \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"gcloud secrets add-iam-policy-binding $SECRET_EMAIL_PASS \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"gcloud secrets add-iam-policy-binding $SECRET_SECRET_KEY \ --member="serviceAccount:$SA_EMAIL" \ --role="roles/secretmanager.secretAccessor"
# deploy cloud run service (default port 8080) config from envgcloud run deploy $SERVICE_NAME \ --platform managed \ --no-cpu-throttling \ --allow-unauthenticated \ --vpc-connector $CONNECTOR_NAME \ --ingress=internal-and-cloud-load-balancing \ --region $GCP_REGION \ --image $IMAGE_PATH \ --set-env-vars "ALLOWED_HOSTS=$ALLOWED_HOSTS" \ --set-env-vars "DB_HOST=$POSTGRES_INSTANCE.$DNS_SUFFIX" \ --set-env-vars "DB_PORT=$POSTGRES_PORT" \ --set-env-vars "DB_NAME=$DB_NAME" \ --set-env-vars "DB_USER=$DB_USER" \ --set-env-vars "REDIS_HOST=$REDIS_INSTANCE.$DNS_SUFFIX" \ --set-env-vars "REDIS_PORT=$REDIS_PORT" \ --set-env-vars "REDIS_DATABASE=$REDIS_DATABASE" \ --set-env-vars "REDIS_CACHE_HOST=$REDIS_INSTANCE.$DNS_SUFFIX" \ --set-env-vars "REDIS_CACHE_PORT=$REDIS_PORT" \ --set-env-vars "REDIS_CACHE_DATABASE=$REDIS_CACHE_DATABASE" \ --update-secrets=DB_PASSWORD=$SECRET_DB_PASS:$SECRET_VERSION \ --update-secrets=REDIS_PASSWORD=$SECRET_REDIS_PASS:$SECRET_VERSION \ --update-secrets=REDIS_CACHE_PASSWORD=$SECRET_REDIS_CACHE_PASS:$SECRET_VERSION \ --update-secrets=SUPERUSER_PASSWORD=$SECRET_SU_PASS:$SECRET_VERSION \ --update-secrets=EMAIL_PASSWORD=$SECRET_EMAIL_PASS:$SECRET_VERSION \ --update-secrets=SECRET_KEY=$SECRET_SECRET_KEY:$SECRET_VERSION \ --set-env-vars "DB_WAIT_DEBUG=1"
########################################################### Load Balancer##########################################################export APP_NAME=$SERVICE_NAMEexport TLD="msparr.com" # OVERRIDE PRIOR - CHANGE ME TO DESIRED DOMAINexport DOMAIN="$SERVICE_NAME.$TLD" # netbox.msparr.comexport EXT_IP_NAME="public-ip"export BACKEND_SERVICE_NAME="$APP_NAME-service"export SERVERLESS_NEG_NAME="$APP_NAME-neg"
# create static IP addressgcloud compute addresses create --global $EXT_IP_NAME
# wait 10 seconds and then set varexport EXT_IP=$(gcloud compute addresses describe $EXT_IP_NAME --global --format="value(address)")echo "Remember to add DNS 'A' record [$DOMAIN] for IP [$EXT_IP]"
# create serverless NEGgcloud compute network-endpoint-groups create $SERVERLESS_NEG_NAME \ --region=$GCP_REGION \ --network-endpoint-type=serverless \ --cloud-run-service=$SERVICE_NAME
# create backend servicegcloud compute backend-services create $BACKEND_SERVICE_NAME \ --load-balancing-scheme=EXTERNAL \ --global
# add serverless NEG to backend servicegcloud compute backend-services add-backend $BACKEND_SERVICE_NAME \ --network-endpoint-group=$SERVERLESS_NEG_NAME \ --network-endpoint-group-region=$GCP_REGION \ --global
# create URL mapgcloud compute url-maps create $APP_NAME-url-map \ --default-service $BACKEND_SERVICE_NAME
# create managed SSL certgcloud beta compute ssl-certificates create $APP_NAME-cert \ --domains $DOMAIN
# create target HTTPS proxygcloud compute target-https-proxies create $APP_NAME-https-proxy \ --ssl-certificates=$APP_NAME-cert \ --url-map=$APP_NAME-url-map
gcloud compute forwarding-rules create $APP_NAME-fwd-rule \ --target-https-proxy=$APP_NAME-https-proxy \ --global \ --ports=443 \ --address=$EXT_IP_NAME
# verify app is running (wait 10-15 minutes until cert provisions)curl -k "https://$DOMAIN" # Unauthorized request
########################################################### [OPTIONAL] Restrict Traffic with Cloud Armor security policy# - https://cloud.google.com/armor/docs/configure-security-policies#gcloud##########################################################export INTERNAL_POLICY_NAME="internal-users-policy"export ALLOWED_CIDR="192.168.0.0/24" # CHANGE ME TO DESIRED IP RANGE
# create policiesgcloud compute security-policies create $INTERNAL_POLICY_NAME \ --description "policy for internal test users"
# update default rulesgcloud compute security-policies rules update 2147483647 \ --security-policy $INTERNAL_POLICY_NAME \ --action "deny-502"
# restrict traffic to desired IP rangesgcloud compute security-policies rules create 1000 \ --security-policy $INTERNAL_POLICY_NAME \ --description "allow traffic from $ALLOWED_CIDR" \ --src-ip-ranges "$ALLOWED_CIDR" \ --action "allow"
# attach policy to backend service (one at a time)gcloud compute backend-services update $BACKEND_SERVICE_NAME \ --security-policy $INTERNAL_POLICY_NAME \ --globalComplexité supplémentaire et points à considérer
J'ai justement choisi Netbox pour illustrer la modernisation et le déploiement d'applications en mode cloud-native en raison de sa complexité technique. L'application embarque un système de fichiers, des sessions, des workers et même un traitement quotidien de nettoyage via cron.

Extrait de Docker Compose pour l'application Netbox (notez netbox-worker et netbox-housekeeping)
L'extrait du fichier docker-compose.yaml ci-dessus illustre une fonctionnalité de YAML appelée anchors, qui n'est pas spécifique à docker-compose.

Vous pouvez ainsi dupliquer des configurations de manière concise, puis surcharger les commandes pour exécuter différents scripts au runtime.
Recréer les workers sur Cloud Run
Pour reproduire ce type de fonctionnement sur Cloud Run, il existe les options --cmd et --args. Il suffit de dupliquer les commandes utilisées pour déployer l'application principale, de changer le nom, puis de surcharger le CMD pour exécuter un autre script d'entrée comme ci-dessous :
gcloud run deploy $WORKER_NAME \ --platform managed \ --allow-unauthenticated \ --vpc-connector $CONNECTOR_NAME \ --ingress=internal-and-cloud-load-balancing \ --region $GCP_REGION \ --image $IMAGE_PATH \ --set-env-vars "ALLOWED_HOSTS=$ALLOWED_HOSTS" \
...
--cmd "/opt/netbox/venv/bin/python" \ --args "/opt/netbox/netbox/manage.py" \ --args "rqworker"Tâche quotidienne de housekeeping avec Cloud Run et Cloud Scheduler
La tâche quotidienne de housekeeping s'exécute en créant un service dupliqué sur Cloud Run, puis en planifiant ce job quotidien pour qu'il invoque le service via Cloud Scheduler.
gcloud run deploy $HOUSEKEEPING_NAME \ --platform managed \ --allow-unauthenticated \ --vpc-connector $CONNECTOR_NAME \ --ingress=internal-and-cloud-load-balancing \ --region $GCP_REGION \ --image $IMAGE_PATH \ --set-env-vars "ALLOWED_HOSTS=$ALLOWED_HOSTS" \
...
--cmd "/opt/netbox/housekeeping.sh"Une fois le service de housekeeping déployé, on active l'API Cloud Scheduler :
gcloud services enable cloudscheduler.googleapis.comOn crée ensuite un compte de service, on lui accorde les droits d'invocation, puis on crée la tâche planifiée :
# fetch the service URLexport SVC_URL=$(gcloud run services describe $HOUSEKEEPING_NAME \ --platform managed --region $GCP_REGION --format="value(status.url)")
########################################################## create cloud scheduler job#########################################################export SA_NAME="cloud-scheduler-runner"export SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
# create service accountgcloud iam service-accounts create $SA_NAME \ --display-name "${SA_NAME}"
# add sa binding to cloud run appgcloud run services add-iam-policy-binding $HOUSEKEEPING_NAME \ --platform managed \ --region $GCP_REGION \ --member=serviceAccount:$SA_EMAIL \ --role=roles/run.invoker
# create the job to invoke service every day at 2:30 AMgcloud scheduler jobs create http housekeeping-job --schedule "30 2 * * *" \ --http-method=GET \ --uri=$SVC_URL \ --oidc-service-account-email=$SA_EMAIL \ --oidc-token-audience=$SVC_URLSystèmes de fichiers
Mon objectif était de prouver qu'on peut découper une application complexe comme Netbox et la déployer dans le cloud avec Cloud Run et d'autres services managés. Ce n'est sans doute pas la solution idéale pour cette application en particulier, mais c'est faisable.
Si vous devez exploiter le système de fichiers, les plateformes serverless restent aujourd'hui limitées ; mieux vaut alors privilégier Kubernetes Engine, voire une simple VM Compute Engine. Vous pouvez exécuter une VM en tant que conteneur — c'est très pratique — et y attacher disques et volumes selon les besoins.
Une astuce pour disposer d'un système de fichiers simple sur Cloud Run consiste cependant à s'appuyer sur Secret Manager, comme dans l'exemple ci-dessous.
# create secret for all varsgcloud secrets create $SECRET_ID --replication-policy="automatic"gcloud secrets versions add $SECRET_ID --data-file=${PWD}/$SECRET_FILE
# mount file path in cloud rungcloud run deploy $SERVICE --image $IMAGE_URL \ --update-secrets="/env/netbox.env"=$SECRET_ID:$SECRET_VERSIONBonne pratique : des comptes de service distincts
Même si les exemples partagés ne montrent un compte de service séparé que pour le module Cloud Scheduler, la bonne pratique consiste à créer un compte de service distinct pour chaque service ainsi que pour le bastion (VM), et à n'attribuer que les rôles IAM minimaux nécessaires. C'est le principe du moindre privilège.
Pour le service Cloud Run, mieux vaut créer un compte de service dédié netbox-runner, puis ne lui accorder que les rôles indispensables, par exemple :
- Cloud SQL Client
- Redis Viewer
- Secret Accessor
- Artifact Registry Reader
- Service Account User
- Storage Object Viewer
J'espère que cet exemple montre comment moderniser des applications existantes et tirer parti des services managés du cloud public. Si votre seul objectif est de faire tourner Netbox, les extraits de code ci-dessus feront l'affaire — mais un déploiement sur VM ou sur K8s reste une option à considérer.
Vous pourriez également convertir cet exemple fonctionnel en Terraform à l'aide de solutions tierces comme Terraformer, ou via les outils d'export en masse de GCP, qui font de la rétro-ingénierie sur votre infrastructure existante pour générer du code Terraform.
Si votre organisation rencontre les mêmes difficultés de collisions d'IP au moment de configurer ses réseaux, il est peut-être temps d'adopter une démarche IPAM, soit avec une feuille de calcul partagée, soit avec un outil reconnu comme Netbox.
Bon clouding !