Esecuzione di Django nell'ambiente Cloud Run

Il deployment di applicazioni stateful in Cloud Run come Django comporta l'integrazione di servizi per interagire tra loro per formare un progetto coerente.

Questo tutorial presuppone che tu conosca lo sviluppo web di Django. Se non hai mai utilizzato lo sviluppo Django, ti consigliamo di scrivere la tua prima app Django prima di continuare.

Questo tutorial illustra in modo specifico Django, ma puoi utilizzare questo processo di deployment con altri framework basati su Django, come Wagtail e Django CMS.

Questo tutorial utilizza Django 4, che richiede almeno Python 3.8.

Obiettivi

In questo tutorial, imparerai a:

  • Crea e connetti un database Cloud SQL.
  • Creare e utilizzare i valori segreti di Secret Manager.
  • Esegui il deployment di un'app Django in Cloud Run.

  • Ospitare file statici su Cloud Storage.

  • Utilizzare Cloud Build per automatizzare il deployment.

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud potrebbero essere idonei per una prova gratuita.

Prima di iniziare

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. Assicurati di disporre di autorizzazioni sufficienti per l'account utilizzato per questo tutorial.

prepara l'ambiente

Clonare un'app di esempio

Il codice per l'app Django di esempio si trova nel repository GoogleCloudPlatform/python-docs-samples su GitHub.

  1. Puoi scaricare l'esempio come file ZIP ed estrarlo oppure clonare il repository sulla tua macchina locale:

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
    
  2. Vai alla directory che contiene il codice di esempio:

    Linux/macOS

    cd python-docs-samples/run/django
    

    Windows

    cd python-docs-samples\run\django
    

Conferma la configurazione Python

Questo tutorial si basa su Python per eseguire l'applicazione di esempio sulla tua macchina. Il codice campione richiede anche l'installazione di dipendenze

Per ulteriori dettagli, consulta la guida all'ambiente di sviluppo di Python.

  1. Verifica che il tuo Python sia almeno la versione 3.7.

     python -V
    

    Dovresti vedere Python 3.7.3 o un valore superiore.

  2. Crea un ambiente virtuale Python e installa le dipendenze:

    Linux/macOS

    python -m venv venv
    source venv/bin/activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

    Windows

    python -m venv env
    venv\scripts\activate
    pip install --upgrade pip
    pip install -r requirements.txt
    

Scarica il proxy Cloud SQL Auth per connetterti a Cloud SQL dalla tua macchina locale

Una volta eseguito il deployment, l'applicazione utilizza il proxy Cloud SQL Auth integrato nell'ambiente Cloud Run per comunicare con la tua istanza Cloud SQL. Tuttavia, per testare la tua app localmente, devi installare e utilizzare una copia locale del proxy nel tuo ambiente di sviluppo. Per maggiori dettagli, consulta la guida al proxy Cloud SQL Auth.

Il proxy Cloud SQL Auth utilizza l'API Cloud SQL per interagire con la tua istanza SQL. A questo scopo, è necessaria l'autenticazione dell'applicazione tramite gcloud.

  1. Autentica e acquisisci le credenziali per l'API:

    gcloud auth application-default login
    
  2. Scarica e installa il proxy Cloud SQL Auth sulla tua macchina locale.

    Linux a 64 bit

    1. Scarica il proxy Cloud SQL Auth:
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
    2. Rendi il eseguibile del proxy Cloud SQL Auth eseguibile:
      chmod +x cloud_sql_proxy

    Linux a 32 bit

    1. Scarica il proxy Cloud SQL Auth:
      wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
    2. Se il comando wget non viene trovato, esegui sudo apt-get install wget e ripeti il comando di download.
    3. Rendi il eseguibile del proxy Cloud SQL Auth eseguibile:
      chmod +x cloud_sql_proxy

    macOS a 64 bit

    1. Scarica il proxy Cloud SQL Auth:
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
    2. Rendi il eseguibile del proxy Cloud SQL Auth eseguibile:
      chmod +x cloud_sql_proxy

    macOS a 32 bit

    1. Scarica il proxy Cloud SQL Auth:
      curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
    2. Rendi il eseguibile del proxy Cloud SQL Auth eseguibile:
      chmod +x cloud_sql_proxy

    Mac M1

    1. Scarica il proxy Cloud SQL Auth:
        curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.arm64
        
    2. Rendi il eseguibile del proxy Cloud SQL Auth eseguibile:
        chmod +x cloud_sql_proxy
        

    Windows a 64 bit

    Fai clic con il pulsante destro del mouse su https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe e seleziona Salva link con nome per scaricare il proxy Cloud SQL Auth. Rinomina il file come cloud_sql_proxy.exe.

    Windows a 32 bit

    Fai clic con il pulsante destro del mouse su https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe e seleziona Salva link con nome per scaricare il proxy Cloud SQL Auth. Rinomina il file come cloud_sql_proxy.exe.

    Immagine Docker proxy Cloud SQL Auth

    Per convenienza, diverse immagini container che contengono il proxy di autenticazione Cloud SQL sono disponibili su GitHub nel repository proxy di Cloud SQL Auth. Puoi estrarre l'immagine più recente sulla tua macchina locale utilizzando Docker con il seguente comando:
    docker pull gcr.io/cloudsql-docker/gce-proxy:1.30.1
    

    Altro sistema operativo

    Per altri sistemi operativi non inclusi, puoi compilare il proxy di autenticazione Cloud SQL dall'origine.

    Puoi scegliere di spostare il download in un punto comune, ad esempio una posizione in PATH o nella tua directory home. Se scegli di farlo, quando avvii il proxy di autenticazione Cloud SQL più avanti nel tutorial, ricorda di fare riferimento alla località scelta quando utilizzi i comandi cloud_sql_proxy.

Crea servizi di supporto

Questo tutorial utilizza diversi servizi Google Cloud per fornire il database, l'archiviazione multimediale e l'archiviazione segreta che supportano il progetto Django di cui è stato eseguito il deployment. Il deployment di questi servizi si svolge in un'area geografica specifica. Per ottimizzare l'efficienza tra i servizi, devi eseguire il deployment di tutti i servizi nella stessa area geografica. Per ulteriori informazioni sull'area geografica più vicina a te, consulta Prodotti disponibili per area geografica.

Questo tutorial utilizza i meccanismi integrati di hosting di asset statici in Cloud Run.

Configurare un'istanza Cloud SQL per PostgreSQL

Django supporta ufficialmente più database relazionali, ma offre il maggiore supporto per PostgreSQL. PostgreSQL è supportato da Cloud SQL, quindi questo tutorial sceglie di utilizzare questo tipo di database.

La sezione seguente descrive la creazione di un'istanza, un database e un utente di database PostgreSQL per l'app.

  1. Crea l'istanza PostgreSQL:

    Console

    1. In Cloud Console, vai alla pagina Istanze Cloud SQL.

      Vai alla pagina Istanze Cloud SQL

    2. Fai clic su Crea istanza.

    3. Fai clic su PostgreSQL.

    4. Nel campo ID istanza, inserisci INSTANCE_NAME.

    5. Inserisci una password per l'utente postgres.

    6. Mantieni i valori predefiniti per gli altri campi.

    7. Fai clic su Crea.

    Sono necessari alcuni minuti per creare l'istanza e prima che sia pronta per l'utilizzo.

    gcloud

    • Crea l'istanza PostgreSQL:

      gcloud sql instances create INSTANCE_NAME \
          --project PROJECT_ID \
          --database-version POSTGRES_13 \
          --tier db-f1-micro \
          --region REGION
      

    Sostituisci quanto segue:

    Sono necessari alcuni minuti per creare l'istanza e prima che sia pronta per l'utilizzo.

  2. All'interno dell'istanza creata, crea un database:

    Console

    1. Nella pagina dell'istanza, vai alla scheda Database.
    2. Fai clic su Crea database.
    3. Nella finestra di dialogo Nome database, inserisci DATABASE_NAME.
    4. Fai clic su Crea.

    gcloud

    • Crea il database all'interno dell'istanza creata di recente:

      gcloud sql databases create DATABASE_NAME \
          --instance INSTANCE_NAME
      

      Sostituisci DATABASE_NAME con un nome per il database all'interno dell'istanza.

  3. Crea un utente del database:

    Console

    1. Nella pagina dell'istanza, vai alla scheda Utenti.
    2. Fai clic su Add User Account (Aggiungi account utente).
    3. Nella finestra di dialogo Aggiungi un account utente all'istanza in "Autenticazione integrata":
    4. Inserisci il nome utente DATABASE_USERNAME.
    5. Inserisci la password DATABASE_PASSWORD
    6. Fai clic su Aggiungi.

    gcloud

    • Crea l'utente all'interno dell'istanza creata di recente:

      gcloud sql users create DATABASE_USERNAME \
          --instance INSTANCE_NAME \
          --password DATABASE_PASSWORD
      

      Sostituisci PASSWORD con una password sicura.

Configurare un bucket Cloud Storage

Puoi archiviare risorse statiche incluse di Django e i contenuti multimediali caricati dagli utenti nella memoria di oggetti ad alta disponibilità utilizzando Cloud Storage. Il pacchetto django-storages[google] gestisce l'interazione di Django con questo backend di archiviazione.

Console

  1. In the Google Cloud console, go to the Cloud Storage Buckets page.

    Go to Buckets page

  2. Click Create bucket.
  3. On the Create a bucket page, enter your bucket information. To go to the next step, click Continue.
    • For Name your bucket, enter a name that meets the bucket naming requirements.
    • For Location, select the following: MEDIA_BUCKET
    • For Choose a default storage class for your data, select the following: Standard.
    • For Choose how to control access to objects, select an Access control option.
    • For Advanced settings (optional), specify an encryption method, a retention policy, or bucket labels.
  4. Click Create.

gcloud

Lo strumento a riga di comando gsutil è stato installato durante l'installazione dell'interfaccia a riga di comando gcloud.

  • Crea un bucket Cloud Storage:

    gsutil mb -l REGION gs://PROJECT_ID_MEDIA_BUCKET
    

    Sostituisci MEDIA_BUCKET con un suffisso per il bucket multimediale. In combinazione con l'ID progetto, crea un nome univoco per il bucket.

Archivia valori di secret in Secret Manager

Ora che i servizi di supporto sono configurati, Django ha bisogno di informazioni su questi servizi. Anziché inserire questi valori direttamente nel codice sorgente di Django, questo tutorial utilizza Secret Manager per archiviare queste informazioni in modo sicuro.

Cloud Run e Cloud Build interagiscono con i secret utilizzando i rispettivi account di servizio. Gli account di servizio sono identificati da un indirizzo email che contiene il numero di progetto.

Crea file di ambiente Django come secret di Secret Manager

Archivia le impostazioni necessarie per avviare Django in un file env protetto. L'app di esempio utilizza l'API Secret Manager per recuperare il valore secret e il pacchetto django-environ per caricare i valori nell'ambiente Django. Il secret è configurato per essere accessibile da Cloud Run e Cloud Build.

  1. Crea un file denominato .env, definendo la stringa di connessione al database, il nome del bucket multimediale e un nuovo valore SECRET_KEY:

    echo DATABASE_URL=postgres://DATABASE_USERNAME:DATABASE_PASSWORD@//cloudsql/PROJECT_ID:REGION:INSTANCE_NAME/DATABASE_NAME > .env
    echo GS_BUCKET_NAME=PROJECT_ID_MEDIA_BUCKET >> .env
    echo SECRET_KEY=$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n1) >> .env
    
  2. Archivia il secret in Secret Manager:

    Console

    1. In Cloud Console, vai alla pagina di Secret Manager.

      Vai alla pagina Secret Manager

    2. Fai clic su Crea secret.

    3. Nel campo Nome, inserisci django_settings.

    4. Nella finestra di dialogo Valore segreto, incolla il contenuto del file .env.

    5. Fai clic su Crea secret.

    6. In Dettagli per django_settings, prendi nota del numero del progetto:

      projects/PROJECTNUM/secrets/django_settings
      
    7. Elimina il file locale per evitare sostituzioni di impostazioni locali.

    gcloud

    1. Crea un nuovo secret, django_settings, con il valore del file .env:

      gcloud secrets create django_settings --data-file .env
      
    2. Per confermare la creazione del secret, controlla:

      gcloud secrets describe django_settings
      
      gcloud secrets versions access latest --secret django_settings
      
    3. Recupera il valore del numero di progetto (PROJECTNUM):

      export PROJECTNUM=$(gcloud projects describe PROJECT_ID --format='value(projectNumber)')
      
    4. Elimina il file locale per evitare sostituzioni delle impostazioni locali:

      rm .env
      
  3. Configura l'accesso al secret:

    Console

    1. Fai clic sulla scheda Autorizzazioni.
    2. Fai clic su Aggiungi.
    3. Nel campo Nuovi membri, inserisci PROJECTNUM-compute@developer.gserviceaccount.com, quindi premi Enter.
    4. Nel campo Nuovi membri, inserisci PROJECTNUM@cloudbuild.gserviceaccount.com, quindi premi Enter.
    5. Nel menu a discesa Ruolo, seleziona Accesso segreto Secret Manager.
    6. Fai clic su Salva.

    gcloud

    1. Concedi l'accesso al secret all'account di servizio Cloud Run:

      gcloud secrets add-iam-policy-binding django_settings \
          --member serviceAccount:PROJECTNUM-compute@developer.gserviceaccount.com \
          --role roles/secretmanager.secretAccessor
      
    2. Concedi l'accesso al secret all'account di servizio Cloud Build:

      gcloud secrets add-iam-policy-binding django_settings \
          --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
          --role roles/secretmanager.secretAccessor
      

      Nell'output, verifica che bindings elenchi i due account di servizio come membri.

Crea il secret per la password amministratore di Django

Normalmente l'utente amministratore di Django viene creato eseguendo il comando di gestione interattiva createsuperuser.

Questo tutorial utilizza una migrazione dei dati per creare l'utente amministratore, recuperando la password amministratore da Secret Manager.

Console

  1. In Cloud Console, vai alla pagina di Secret Manager.
  2. Fai clic su Crea secret.

  3. Nel campo Nome, inserisci superuser_password.

  4. Nel campo Valore segreto, inserisci una password univoca e casuale.

  5. Fai clic su Crea secret.

  6. In Dettagli per superuser_password, prendi nota del numero del progetto (projects/PROJECTNUM/secrets/superuser_password).

  7. Fai clic sulla scheda Autorizzazioni.

  8. Fai clic su Aggiungi.

  9. Nel campo Nuovi membri, inserisci PROJECTNUM@cloudbuild.gserviceaccount.com, quindi premi Enter.

  10. Nel menu a discesa Ruolo, seleziona Accesso segreto Secret Manager.

  11. Fai clic su Salva

gcloud

  1. Crea un nuovo secret, superuser_password, da una password generata in modo casuale:

    echo -n "$(cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 30 | head -n1)" | gcloud secrets create superuser_password --data-file -
    
  2. Concedi l'accesso al secret a Cloud Build:

    gcloud secrets add-iam-policy-binding superuser_password \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/secretmanager.secretAccessor
    

    Nell'output, conferma che bindings elenca solo Cloud Build come membro.

Concedi a Cloud Build l'accesso a Cloud SQL

Affinché Cloud Build applichi le migrazioni del database, devi concedere le autorizzazioni a Cloud Build per accedere a Cloud SQL.

Console

  1. In Cloud Console, vai alla pagina Gestione di identità e accessi.

    Vai alla pagina Gestione di identità e accessi

  2. Per modificare la voce relativa a PROJECTNUM@cloudbuild.gserviceaccount.com, fai clic su Modifica.

  3. Fai clic su Aggiungi un altro ruolo.

  4. Nella finestra di dialogo Seleziona un ruolo, seleziona Client Cloud SQL.

  5. Fai clic su Salva

gcloud

  1. Concedi a Cloud Build l'accesso a Cloud SQL:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/cloudsql.client
    

Esecuzione dell'applicazione nel computer locale

Dopo aver configurato i servizi di supporto, ora puoi eseguire l'app sul tuo computer. Questa configurazione consente lo sviluppo locale e l'applicazione di migrazioni dei database. Tieni presente che le migrazioni dei database vengono applicate anche in Cloud Build, ma devi avere questa configurazione locale per makemigrations.

  1. In un terminale separato, avvia il proxy di autenticazione Cloud SQL:

    Linux/macOS

    ./cloud_sql_proxy -instances="PROJECT_ID:REGION:INSTANCE_NAME"=tcp:5432
    

    Windows

    cloud_sql_proxy.exe -instances="PROJECT_ID:REGION:INSTANCE_NAME"=tcp:5432
    

    Questo passaggio stabilisce una connessione dal computer locale alla tua istanza Cloud SQL a scopo di test locale. Mantieni il proxy Cloud SQL Auth in esecuzione per tutto il tempo per testare l'app localmente. L'esecuzione di questo processo in un terminale separato ti consente di continuare a lavorare durante l'esecuzione del processo.

  2. In un nuovo terminale, imposta l'ID progetto localmente (utilizzato dall'API Secret Manager):

    Linux/macOS

      export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    

    Windows

      set GOOGLE_CLOUD_PROJECT=PROJECT_ID
    
  3. Imposta una variabile di ambiente per indicare che utilizzi il proxy Cloud SQL Auth (questo valore è riconosciuto nel codice):

    Linux/macOS

      export USE_CLOUD_SQL_AUTH_PROXY=true
    

    Windows

      set USE_CLOUD_SQL_AUTH_PROXY=true
    
  4. Esegui le migrazioni Django per configurare i modelli e gli asset:

    python manage.py makemigrations
    python manage.py makemigrations polls
    python manage.py migrate
    python manage.py collectstatic
    
  5. Avvia il server web di Django:

    python manage.py runserver
    
  6. Nel browser, vai alla pagina http://localhost:8000.

    Nella pagina viene visualizzato il seguente testo: "Hello world. Sei nell'indice dei sondaggi." Il server web di Django in esecuzione sul computer fornisce le pagine di esempio dell'app.

  7. Premi Ctrl/Cmd+C per arrestare il server web locale.

Esegui il deployment dell'app su Cloud Run

Con la configurazione dei servizi di supporto, ora puoi eseguire il deployment del servizio Cloud Run.

  1. Utilizzando il cloudmigrate.yaml fornito, usa Cloud Build per creare l'immagine, eseguire le migrazioni del database e compilare gli asset statici:

    gcloud builds submit --config cloudmigrate.yaml \
        --substitutions _INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION
    

    Il completamento della prima build richiede alcuni minuti.

  2. Quando la build ha esito positivo, esegui il deployment del servizio Cloud Run per la prima volta, impostando l'area geografica del servizio, l'immagine di base e l'istanza Cloud SQL connessa:

    gcloud run deploy polls-service \
        --platform managed \
        --region REGION \
        --image gcr.io/PROJECT_ID/polls-service \
        --add-cloudsql-instances PROJECT_ID:REGION:INSTANCE_NAME \
        --allow-unauthenticated
    

    Dovresti vedere un output che mostra il deployment riuscito, con un URL del servizio:

    Service [polls-service] revision [polls-service-00001-tug] has been deployed
    and is serving 100 percent of traffic at https://polls-service-<hash>-uc.a.run.app
    
  3. Ora che l'URL del servizio è noto, aggiorna il servizio per impostare questo valore come variabile di ambiente:

    SERVICE_URL=$(gcloud run services describe polls-service --platform managed \
        --region REGION --format "value(status.url)")
    
    gcloud run services update polls-service \
        --platform managed \
        --region REGION \
        --set-env-vars CLOUDRUN_SERVICE_URL=$SERVICE_URL
    
  4. Per vedere il servizio di cui hai eseguito il deployment, vai all'URL del servizio.

  5. Per accedere all'amministratore Django, aggiungi /admin all'URL, quindi accedi con il nome utente admin e la password impostata in precedenza.

Aggiornamento dell'applicazione

Sebbene i passaggi iniziali di provisioning e deployment siano stati complessi, l'aggiornamento è un processo più semplice:

  1. Esegui lo script di creazione e migrazione di Cloud Build:

    gcloud builds submit --config cloudmigrate.yaml \
        --substitutions _INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION
    
  2. Esegui il deployment del servizio specificando solo l'area geografica e l'immagine:

    gcloud run deploy polls-service \
        --platform managed \
        --region REGION \
        --image gcr.io/PROJECT_ID/polls-service
    

Configurazione per la produzione in corso...

Ora hai un deployment Django funzionante, ma ci sono ulteriori passaggi che puoi seguire per assicurarti che la tua applicazione sia pronta per la produzione.

Disattiva debug

Verifica che la variabile DEBUG in mysite/settings.py sia impostata su False. In questo modo, non sarà possibile mostrare all'utente pagine di errore dettagliate contenenti informazioni sulle configurazioni.

Limita i privilegi utente del database

Tutti gli utenti creati tramite Cloud SQL hanno i privilegi associati al ruolo cloudsqlsuperuser: CREATEROLE, CREATEDB e LOGIN.

Per impedire che l'utente del database Django abbia queste autorizzazioni, crea manualmente l'utente in PostgreSQL. Dovrai avere installato il terminale interattivo di psql oppure utilizzare Cloud Shell su cui è preinstallato questo strumento.

Console

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  2. In Cloud Shell, utilizza il terminale integrato per connetterti all'istanza INSTANCE_NAME:

    gcloud sql connect INSTANCE_NAME --user postgres
    
  3. Inserisci la password utente postgres.

    Ora stai utilizzando psql. Dovresti vedere il messaggio postgres=>.

  4. Creare un utente:

    CREATE USER DATABASE_USERNAME WITH PASSWORD 'DATABASE_PASSWORD';
    

    Sostituisci PASSWORD con una password univoca e casuale.

  5. Concedi tutti i diritti sul nuovo database al nuovo utente:

    GRANT ALL PRIVILEGES ON DATABASE DATABASE_NAME TO DATABASE_USERNAME;
    
  6. Esci da: psql

    \q
    

gcloud

  1. Avvia una connessione all'istanza SQL:

    gcloud sql connect INSTANCE_NAME --user postgres
    

    Sostituisci INSTANCE_NAME con l'istanza Cloud SQL creata.

  2. Inserisci la password utente postgres.

    Ora stai utilizzando psql. Dovresti vedere il messaggio postgres=>.

  3. Creare un utente:

    CREATE USER DATABASE_USERNAME WITH PASSWORD 'DATABASE_PASSWORD';
    
  4. Concedi tutti i diritti sul nuovo database al nuovo utente:

    GRANT ALL PRIVILEGES ON DATABASE DATABASE_NAME TO DATABASE_USERNAME;
    
  5. Esci da: psql

    \q
    

Impostazione delle autorizzazioni minime

Per impostazione predefinita, questo servizio viene eseguito con l'account di servizio Compute predefinito. Tuttavia, in alcuni casi, l'utilizzo dell'account di servizio predefinito può fornire troppe autorizzazioni. Se vuoi essere più restrittivo, devi creare il tuo account di servizio e assegnare solo le autorizzazioni richieste dal tuo servizio. Le autorizzazioni richieste possono variare a seconda del servizio, a seconda delle risorse utilizzate da un determinato servizio.

I ruoli minimi del progetto richiesti da questo servizio sono i seguenti:

  • Invoker di Cloud Run
  • Client Cloud SQL
  • Amministratore spazio di archiviazione, nel bucket multimediale
  • Secret Manager Accessor, nel secret delle impostazioni di Django. L'accesso al secret di amministratore di Django non è richiesto dal servizio stesso.

Per creare un account di servizio con le autorizzazioni richieste e assegnarlo al servizio, esegui il comando seguente:

  1. Nell'interfaccia a riga di comando gcloud, crea un account di servizio con i ruoli richiesti:

    gcloud iam service-accounts create polls-service-account
    SERVICE_ACCOUNT=polls-service-account@PROJECT_ID.iam.gserviceaccount.com
    
    # Cloud Run Invoker
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/run.invoker
    
    # Cloud SQL Client
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/cloudsql.client
    
    # Storage Admin, on the media bucket
    gsutil iam ch \
        serviceAccount:${SERVICE_ACCOUNT}:roles/storage.objectAdmin \
        gs://MEDIA_BUCKET
    
    # Secret Accessor, on the Django settings secret.
    gcloud secrets add-iam-policy-binding django_settings \
        --member serviceAccount:${SERVICE_ACCOUNT} \
        --role roles/secretmanager.secretAccessor
    
  2. Esegui il deployment del servizio, associandolo al nuovo account di servizio:

    gcloud run services update polls-service \
        --platform managed \
        --region REGION \
        --service-account ${SERVICE_ACCOUNT}
    

Comprendere il codice

Applicazione di esempio

L'app di esempio Django è stata creata usando gli strumenti standard Django. I seguenti comandi creano il progetto e l'app Sondaggi:

django-admin startproject mysite
python manage.py startapp polls

Le visualizzazioni di base, i modelli e le configurazioni dei percorsi sono stati copiati da Scrittura della prima app Django (Parte 1 e Parte 2).

Secret di Secret Manager

Il file settings.py contiene il codice che utilizza l'API Secret Manager Python per recuperare l'ultima versione del secret denominato e eseguirne il pull nell'ambiente (utilizzando django-environ):

# SECURITY WARNING: don't run with debug turned on in production!
# Change this to "False" when you are ready for production
env = environ.Env(DEBUG=(bool, True))
env_file = os.path.join(BASE_DIR, ".env")

# Attempt to load the Project ID into the environment, safely failing on error.
try:
    _, os.environ["GOOGLE_CLOUD_PROJECT"] = google.auth.default()
except google.auth.exceptions.DefaultCredentialsError:
    pass

if os.path.isfile(env_file):
    # Use a local secret file, if provided

    env.read_env(env_file)
# ...
elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
    # Pull secrets from Secret Manager
    project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")

    client = secretmanager.SecretManagerServiceClient()
    settings_name = os.environ.get("SETTINGS_NAME", "django_settings")
    name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
    payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")

    env.read_env(io.StringIO(payload))
else:
    raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")

Il secret viene utilizzato per archiviare più valori del secret per ridurre il numero di diversi secret da configurare. Anche se superuser_password potrebbe essere stato creato direttamente dalla riga di comando, è stato utilizzato il metodo basato su file. Se generato dalla riga di comando, è stata curata l'utilizzo di head -c per determinare la lunghezza della stringa generata in modo casuale utilizzata, assicurandosi al tempo stesso che non fosse presente un carattere di nuova riga alla fine del file, il che avrebbe causato problemi al momento dell'inserimento della password nell'amministratore di Django.

Configurazioni CSRF

Django ha una protezione integrata contro Cross Site Request Forgery (CSRF). A partire da Django 4.0, le modifiche al funzionamento indicano che è importante comunicare a Django cos'è l'URL ospitato, in modo da offrire le migliori protezioni per gli utenti che inviano i dati.

Tu fornisci l'URL dell'app come variabile di ambiente nel file settings.py. Si tratta del valore utilizzato da Django per le impostazioni pertinenti.

# SECURITY WARNING: It's recommended that you use this when
# running in production. The URL will be known once you first deploy
# to Cloud Run. This code takes the URL and converts it to both these settings formats.
CLOUDRUN_SERVICE_URL = env("CLOUDRUN_SERVICE_URL", default=None)
if CLOUDRUN_SERVICE_URL:
    ALLOWED_HOSTS = [urlparse(CLOUDRUN_SERVICE_URL).netloc]
    CSRF_TRUSTED_ORIGINS = [CLOUDRUN_SERVICE_URL]
    SECURE_SSL_REDIRECT = True
    SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
else:
    ALLOWED_HOSTS = ["*"]

Sostituzioni secret locali

Se nel file system locale viene trovato un file .env, viene utilizzato al posto del valore di Secret Manager. La creazione di un file .env a livello locale può essere utile per i test locali (ad es., sviluppo locale rispetto a un database SQLite o altre impostazioni locali).

Connessione al database

Il file settings.py contiene la configurazione per il database SQL. Se configuri USE_CLOUD_SQL_AUTH_PROXY, l'impostazione DATABASES viene modificata per dedurre l'uso del proxy di autenticazione Cloud SQL.

# Use django-environ to parse the connection string
DATABASES = {"default": env.db()}

# If the flag as been set, configure to use proxy
if os.getenv("USE_CLOUD_SQL_AUTH_PROXY", None):
    DATABASES["default"]["HOST"] = "127.0.0.1"
    DATABASES["default"]["PORT"] = 5432

Statico archiviato su cloud

Il file settings.py utilizza inoltre django-storages per integrare il bucket multimediale di Cloud Storage direttamente nel progetto:

# Define static storage via django-storages[google]
GS_BUCKET_NAME = env("GS_BUCKET_NAME")
STATIC_URL = "/static/"
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
STATICFILES_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
GS_DEFAULT_ACL = "publicRead"

Automazione con Cloud Build

Il file cloudmigrate.yaml esegue non solo i passaggi tipici della creazione dell'immagine, ovvero la creazione dell'immagine container e il push a Container Registry, ma anche i comandi Django migrate e collectstatic. Questi richiedono l'accesso al database, che viene eseguito utilizzando app-engine-exec-wrapper, un helper per il proxy Cloud SQL Auth:

steps:
  - id: "build image"
    name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}", "."]

  - id: "push image"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"]

  - id: "apply migrations"
    name: "gcr.io/google-appengine/exec-wrapper"
    args:
      [
        "-i",
        "gcr.io/$PROJECT_ID/${_SERVICE_NAME}",
        "-s",
        "${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}",
        "-e",
        "SETTINGS_NAME=${_SECRET_SETTINGS_NAME}",
        "--",
        "python",
        "manage.py",
        "migrate",
      ]

  - id: "collect static"
    name: "gcr.io/google-appengine/exec-wrapper"
    args:
      [
        "-i",
        "gcr.io/$PROJECT_ID/${_SERVICE_NAME}",
        "-s",
        "${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}",
        "-e",
        "SETTINGS_NAME=${_SECRET_SETTINGS_NAME}",
        "--",
        "python",
        "manage.py",
        "collectstatic",
        "--verbosity",
        "2",
        "--no-input",
      ]

substitutions:
  _INSTANCE_NAME: django-instance
  _REGION: us-central1
  _SERVICE_NAME: polls-service
  _SECRET_SETTINGS_NAME: django_settings

images:
  - "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"

In questa configurazione vengono utilizzate le variabili di sostituzione. Se modifichi direttamente i valori nel file, il flag --substitutions può essere eliminato al momento della migrazione.

In questa configurazione vengono applicate solo le migrazioni esistenti. Le migrazioni devono essere create localmente utilizzando il metodo proxy di Cloud SQL Auth definito in "Running the local local". Questo modello può essere esteso per eseguire altri comandi manage.py, come richiesto.

Per estendere la configurazione di Cloud Build in modo da includere il deployment in una sola configurazione senza dover eseguire due comandi, consulta la sezione Deployment continuo da git tramite Cloud Build. Questo richiede modifiche IAM, come descritto.

Creazione di super user con migrazioni di dati

Il comando di gestione di Django createsuperuser può essere eseguito solo in modo interattivo, ovvero quando l'utente può inserire informazioni in risposta a richieste. Anche se puoi utilizzare questo comando con Cloud SQL Proxy ed eseguire i comandi all'interno di una configurazione Docker locale, puoi creare il superutente come migrazione dei dati:

import os

from django.contrib.auth.models import User
from django.db import migrations
from django.db.backends.postgresql.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps

import google.auth
from google.cloud import secretmanager

def createsuperuser(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
    """
    Dynamically create an admin user as part of a migration
    Password is pulled from Secret Manger (previously created as part of tutorial)
    """
    if os.getenv("TRAMPOLINE_CI", None):
        # We are in CI, so just create a placeholder user for unit testing.
        admin_password = "test"
    else:
        client = secretmanager.SecretManagerServiceClient()

        # Get project value for identifying current context
        _, project = google.auth.default()

        # Retrieve the previously stored admin password
        PASSWORD_NAME = os.environ.get("PASSWORD_NAME", "superuser_password")
        name = f"projects/{project}/secrets/{PASSWORD_NAME}/versions/latest"
        admin_password = client.access_secret_version(name=name).payload.data.decode(
            "UTF-8"
        )

    # Create a new user using acquired password, stripping any accidentally stored newline characters
    User.objects.create_superuser("admin", password=admin_password.strip())

class Migration(migrations.Migration):

    initial = True
    dependencies = []
    operations = [migrations.RunPython(createsuperuser)]

Esegui la pulizia

Per evitare che al tuo Account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Elimina il progetto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Passaggi successivi