Come installare un sito Wordpress su Google Cloud Run

Salvo Pappalardo
Devmy

--

Al Google Cloud Next 2019 è stato presentato (in Beta) un nuovo interessante servizio chiamato Cloud Run.

Cloud Run permette di avviare container stateless invocabili da richieste HTTP in maniera completamente managed, ovvero senza preoccuparsi del provisioning di macchine, clusters, certificati TLS (https) o dell’autoscaling e soprattutto pagando solo per l’effettivo tempo di esecuzione della richiesta, rendendolo quindi una soluzione totalmente serverless.
Cloud Run si affianca ad altre soluzioni serverless già consolidate come App Engine e Cloud Functions (vedi qui una comparativa) ma a differenza di queste ultime è possibile eseguire il deploy di applicazioni scritte in qualsiasi linguaggio: questo perché quello che sarà pubblicato su Cloud Run sarà sostanzialmente una container image (che rispetti però un contratto ben preciso).

Come viene calcolato il costo ?

Nella pagina ufficiale del pricing di Cloud Run è illustrata la modalità di billing, qui rappresentata da un immagine esplicativa:

Diversamente dalla maggior parte dei servizi serverless Cloud Run riesce a gestire multiple richieste simultanee (80 come default): il billable time comincia all'inizio della prima richiesta e finisce al termine dell’ultima (vedi immagine sopra).
Verrà calcolato un costo solo per la CPU e la memoria allocata durante il periodo di funzionamento del container (arrotondato ai più vicini 100 ms) e per il traffico inviato al client (egress traffic).
Subito dopo il “tassametro” si spegne e la nostra applicazione non consuma risorse (fino alla successiva richiesta il costo di hosting sarà quindi zero).
E’ già attivo inoltre un “free tier” (che si resetta mensilmente) per cui si pagheranno solo i consumi oltre la quota gratuita.

In Acadevmy siamo molto interessati alle soluzioni serverless e in questo e successivi articoli proveremo a presentare degli esempi completi di deploy su Cloud Run.

Cominciamo dunque da un applicazione “abbastanza” famosa nel mondo web: l’immancabile blog Wordpress!

Lista delle attività

Per raggiungere il nostro obiettivo eseguiremo i seguenti steps:

  1. Setup dell’environment GCP
  2. Creazione di un istanza MySQL
  3. Creazione di un database e un utente per Wordpress
  4. Creazione di una container image custom per Wordpress
  5. Build e Deploy della container image su Cloud Run
  6. Installazione di Wordpress

Il repository completo del progetto è disponibile su GitHub a questo indirizzo:

Per chi ha già familiarità con il deploy di container è possibile scaricare il repo e lanciare solo i comandi creazione del database e di build&deploy.

Setup dell’environment GCP

Per configurare l’ambiente GCP seguiamo la guida ufficiale Google per il setup base:

I passaggi affrontati nella guida sono sostanzialmente:

  • Accedere al proprio account GCP e selezionare/creare un nuovo progetto.
  • Abilitare la fatturazione e le API di Google Cloud Run.
  • Installare la CLI gcloud (inclusi i components beta).
  • Impostare la region di default.
  • Opzionale: installare Docker per il build delle immagini in locale.

NOTA BENE: attualmente Cloud Run supporta solo la region us-central1 quindi impostiamo come region e zone della nostra configurazione:

gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-a

Se tutto è stato configurato a dovere lanciando il comando:

gcloud config list

Dovremmo ottenere un risultato simile al seguente:

[compute]
region = us-central1
zone = us-central1-a
[core]
account = salvo@acadevmy.it
disable_usage_reporting = True
project = cr-test-wordpress

Creazione di un istanza MySQL

Wordpress usa un database MySQL per salvare tutti i dati del sito.
Per la creazione di un istanza MySQL di seconda generazione su GCP potete fare riferimento al seguente articolo:

Tuttavia i comandi necessari dovrebbero essere i seguenti:

# creazione istanza database
#gcloud sql instances create [INSTANCE_NAME] --tier=[MACHINE_TYPE] -#-region=[REGION]
# creiamo un istanza minimale (micro)
gcloud sql instances create mysql --tier=db-f1-micro --region=us-central1

Sarà necessario attendere qualche minuto affinché l’istanza venga resa disponibile per l’utilizzo e potrebbe capitare anche di ricevere il seguente errore:

ERROR: (gcloud.sql.instances.create) Operation https://www.googleapis.com/sql/v1beta4/projects/cr-test-wordpress/operations/a0a22c4e-2222-1111-yyyy-xxxx is taking longer than expected. You can continue waiting for the operation by running `gcloud beta sql operations wait --project cr-test-wordpress a0a22c4e-2222-1111-yyyy-xxxx`

Come suggerito dal messaggio basterà monitorare il progress delle operazioni lanciando il comando suggerito.
Alla fine delle operazioni di creazione dovremmo ottenere un messaggio simile al seguente:

NAME                                  TYPE    START                          END                            ERROR  STATUS
a0a22c4e-2222-1111-yyyy-xxxx CREATE 2019-06-12T09:05:11.593+00:00 2019-06-12T09:12:04.976+00:00 - DONE

Ora possiamo impostare la password per l’utente root del database con il seguente comando:

# settiamo la pass per root
gcloud sql users set-password root --host % --instance mysql --password [PASSWORD]

Ottimo! A questo punto possiamo aggiungere uno schema ed un user dedicati a Wordpress.

Creazione di un database e un utente per Wordpress

Per creare un database e un utente per Wordpress sono necessari i seguenti comandi:

# creazione database wordpress
gcloud sql databases create wordpress --instance=mysql --charset=utf8 --collation=utf8_general_ci
# creazione user wordpress
gcloud sql users create wordpress \
--host=% --instance=mysql --password=[PASSWORD]

Sostituendo [PASSWORD] dove necessario.
Dopo la creazione di istanza, database e utente è possibile verificare che tutto sia andato a buon fine aprendo una sessione di Google Cloud Shell e lanciando:

gcloud sql connect mysql --user=wordpress --quiet

Immettendo la password scelta al prompt dovremmo accedere al database appena creato.
IMPORTANTE: creando l’utente dalla CLIgcloud quest’ultimo avrà tutti i privilegi database tranne FILE e SUPER.
Per restringere i privilegi per l’user possiamo agire dal clientmysql con i classici comandiGRANT e REVOKE.

Creazione di una container image custom per Wordpress

Andiamo adesso a creare una container image custom che ci permetta di eseguire il deploy di Wordpress su Cloud Run.
Per farlo, partiremo dall'immagine ufficiale presente su Docker Hub https://hub.docker.com/_/wordpress/.

Dobbiamo adattarla giusto un po’ al fine di:

  1. Rispettare il runtime contract di Cloud Run relativamente alla porta in ascolto.
  2. Collegarci con il db MySQL creato precedentemente tramite Cloud Sql Proxy.
  3. Impostare le credenziali di accesso per il db MySQL sul file di configurazione di Wordpress wp-config.php
  4. Forzare l’uso di HTTPS agendo sempre su wp-config.php

Diamo uno sguardo al nostro Dockerfile:

Per soddisfare il punto 1 è necessario che la nostra applicazione abbia un web server in ascolto su 0.0.0.0 porta 8080 (ovvero la porta contenuta nella variabile d’ambiente PORT).
Tra i tags disponibili scegliamo quindi un-apache come ad esempio il 5.2.1-php7.3-apache.

Di default l’immagine Apache ascolta però sulla porta 80, quindi effettuiamo un trova&sostituisci con il comandosed(Dockerfile riga 6) per sostituire la porta 80 con PORT sui files di configurazione di Apacheports.conf e su 000-default.conf che rappresenta il Virtual Host di default.

Colleghiamoci adesso con il db MySQL, come indicato al punto 2:
Per collegarci ad una istanza database su GCP è necessario utilizzare Cloud SQL Proxy (vedi anche https://cloud.google.com/sql/docs/mysql/sql-proxy ).

Cloud SQL Proxy permette di collegarsi in modo sicuro ad un istanza MySQL senza dover mettere in whitelist indirizzi o configurare SSL su MySQL.

Installiamo quindi il binario fornito da Google (Dockerfile riga 10–13) e adattiamo l’entrypoint dell’immagine affinché avvi il bin cloud_sql_proxy(Dockerfile riga 16 e 18).

E’ inoltre necessario:

  1. Andare su IAM e aggiungere il ruolo CloudSQL Client al service account di Cloud Run (l’account che finisce con@serverless-robot-prod.iam.gserviceaccount.com ).
  2. Attivare le API Cloud SQL Admin visitando https://console.developers.google.com/apis/library/sqladmin.googleapis.com?project=[PROJECT_ID] e cliccare su ENABLE (vedi foto allegata di seguito)

A questo punto cloud_sql_proxysarà autorizzato a comunicare con le istanze database, sarà necessario solo passargli il nome dell’istanza nella forma <progetto-gcp>:<region>:<nome-istanza>, cosa che faremo in fase di deploy grazie ad una variabile d’ambiente chiamataCLOUDSQL_ISTANCE.
Di seguito il nostro custom entrypoint che effettua questa operazione.

Rimangono adesso solo i punti 3 e 4 che riguardano la configurazione del file wp-config.

Per prima cosa impostiamo le credenziali di accesso al database tramite variabili di ambiente (usiamo la funzione PHP getenv):

define( 'DB_NAME', getenv('DB_NAME')  );
/** MySQL database username */
define( 'DB_USER', getenv('DB_USER') );
/** MySQL database password */
define( 'DB_PASSWORD', getenv('DB_PASSWORD') );
/** MySQL hostname */
define( 'DB_HOST', getenv('DB_HOST') );

Valorizzeremo le variabili di ambiente durante la fase di deploy.
Sarebbe necessario passare questi dati sensibili tramite secrets ma non sono (attualmente) supportati nativamente da Cloud Run: per semplicità ci limitiamo a passarli in chiaro ma per deploy in produzione è assolutamente consigliato l’uso di uno dei possibili workaround disponibili qui https://www.sethvargo.com/secrets-in-serverless/.

L’altra cosa necessaria è forzare l’uso di HTTPS per l’area admin (e quindi per la fase di installazione di WP) come spiegato qui https://wordpress.org/support/article/administration-over-ssl/#using-a-reverse-proxy.

if (
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false
) {
define('FORCE_SSL_ADMIN', true);
$_SERVER['HTTPS'] = 'on';
}

Questo perché al termine del deploy, Cloud Run fornisce in automatico un url HTTPS *.run.appper la nostra applicazione, tramite il suo load balancer (è anche possibile usare un proprio dominio seguendo la procedura descritta qui https://cloud.google.com/run/docs/mapping-custom-domains ).
Grazie all’header X-Forwarded-Proto possiamo individuare che il nostro dominio è in https e forzare la costante necessaria per Wordpress.

Adesso che il nostro Dockerfile è finalmente completo, procediamo con il build della container image definitiva e con il deploy su Cloud Run.

Build e Deploy della container image su Cloud Run

Grazie a Cloud Build è possibile effettuare una build veloce del nostro Dockerfile e contestualmente un push dell’immagine generata su Cloud Registry.

Dalla directory contenente il Dockerfile digitiamo:

gcloud builds submit --tag gcr.io/[PROJECT-ID]/wp:v1

dove [PROJECT-ID] è l’id del nostro progetto GCP ricavabile con

gcloud config get-value project

Subito dopo l’avvio del comando ci verrà chiesto se desideriamo attivare l’API [cloudbuild.googleapis.com], rispondiamo di si e a quel punto gcloud avvierà il processo di build:

e al termine farà automaticamente il push sul Container Registry con nome:tag wp:v1 .

Adesso che la nostra custom container image Wordpress è presente sul Registry possiamo finalmente eseguire il deploy con il comando:

gcloud beta run deploy wp --image gcr.io/[PROJECT-ID]/wp:v1 \
--add-cloudsql-instances <instance-name> \
--update-env-vars DB_HOST='127.0.0.1',DB_NAME=<dbname>,DB_USER=<dbuser>,DB_PASSWORD=<dbpass>,CLOUDSQL_INSTANCE='<project.id>:<region>:<instance-name>'

Dove:

  • --image indica il percorso del Registry dal quale recuperare la container image (la cui build è stata fatta con il comando precedente).
  • --add-cloudsql-instances <instance-name> come indicato in questo articolo, autorizza il nostro servizio ad accedere all'istanza.
  • --update-env-vars setta delle variabili d’ambiente (nella forma NOME=valore) per il nostro servizio.
    Importante notare che l’host del db sarà 127.0.0.1 dato che abbiamo installato e avviato cloud_sql_proxynella nostra container image.

il comando finale dovrebbe essere simile al seguente:

gcloud beta run deploy wp --image gcr.io/cr-test-wordpress/wp:v1 \
--add-cloudsql-instances mysql \
--update-env-vars DB_HOST='127.0.0.1',DB_NAME=wordpress,DB_USER=wordpress,DB_PASSWORD=wordpress,CLOUDSQL_INSTANCE='cr-test-wordpress:us-central1:mysql'

Lanciamo dunque il comando di deploy e rispondiamoYalla richiesta di attivare l’API [run.googleapis.com] e anche alla richiesta di unauthenticated invocations (ovvero vogliamo che il nostro servizio sia accessibile pubblicamente).

Se tutte le fasi andranno a buon fine verrà restituito l’indirizzo https del nostro sito Wordpress.

Installazione di Wordpress

A questo punto non ci resta che lanciare l’installazione di Wordpress visitando l’indirizzo https ottenuto:

e al completamento cominciare ad usare il nostro nuovo blog.

Temi e plugins

Per estendere il blog con plugins e temi custom si dovrà semplicemente aggiungere al Dockerfile il loro sorgente nei percorsi citati dalla documentazione dell’immagine docker Wordpress originale:

Themes go in a subdirectory in /var/www/html/wp-content/themes/
Plugins go in a subdirectory in /var/www/html/wp-content/plugins/

Installare temi e plugins dall'area admin di Wordpress renderebbe questi ultimi disponibili solo fino a quando il servizio resterà nello stato “warm” e comunque non oltre il deploy di una nuova revision.
Viceversa una volta aggiunti alla container image saranno disponibili anche se il servizio dovesse passare nello stato “cold” ovvero uno stato in cui il servizio è “addormentato” in attesa di essere “risvegliato” da una richiesta che farà scaricare nuovamente l’immagine ed avviare un container che servirà la richiesta.

Nel pannello di controllo del servizio saranno disponibili tutte le metriche riassuntive delle richieste ricevute, oltre alla latenza e alla CPU / Memoria utilizzati.
Sarà anche presente la lista delle revisioni precedenti (una per ogni nuovo deploy) e il tab logs che ci porterà alla lista dei logs delle richieste ricevute dal servizio, gestite attraverso il prodotto integrato Stackdriver.

Conclusioni

Google Clod Run, pur essendo in fase beta, è sicuramente un servizio molto interessante, supera brillantemente alcuni dei limiti delle soluzioni serverless finora sul mercato e rende l’hosting di servizi stateless assolutamente cost-effective.

Segui Acadevmy - Software Factory & Learning su Medium, Twitter e Facebook per contattarci o tenerti aggiornato sul mondo dello sviluppo Frontend e DevOps.

--

--