Cloud SQL for PostgreSQL
Oppsett av instanser med terraformâ
SKIP har laget to terraform-moduler (cloud_sql og cloud_sql_config) for Ă„ gjĂžre det enkelt Ă„ sette opp nye Cloud SQL-instanser i GCP.
Dokumentasjon for hvordan modulene brukes finnes pÄ wiki-siden til terraform-modules Spesielt guiden for hvordan bruke terraform-modules repoet er relevant.
cloud_sql modulenâ
For mer utfyllende dokumentasjon se cloud_sql wiki
module "cloudsql_test" {
source = "git@github.com:kartverket/terraform-modules.git/?ref=cloud_sql/v0.10.0"
env = "sandbox"
instance_name = "foo-db"
project_id = "skip-sandbox-37c2"
}
Du kan koble deg til pÄ denne mÄten:
- JIT deg til cloudsql.admin
- Last ned cloudsql-proxy
gcloud auth application-default login
./cloud-sql-proxy --private-ip <connection-name> --auto-iam-authn
-- connection name finner du pÄ sql instansen i GCPpsql -d admin -h localhost -U admin
eller fra applikasjon
Du mÄ vÊre pÄ Kartverkets nettverk for Ä fÄ tilgang, selv med cloud sql proxy. Man kan ikke koble til fra egen klient uten proxy. Du trenger ikke Ä bruke SSL sertifikater nÄr du kobler til via proxy.
cloud_sql_config modulen og konfigurering av brukereâ
For mer utfyllende dokumentasjon se cloud_sql_config wiki
Denne modulen er laget for konfigurasjon av postgres instanser. Vi har laget denne for Ă„ gjĂžre konfigurering av databaser enklest mulig for dere,
og for Ä unngÄ "click-ops".
Det er noen ting dere bĂžr tenke over fĂžr dere tar denne i bruk:
- Den burde bare brukes pÄ en ny instans. à importere eksisterende databaser, brukere og skjemaer er noe vi frarÄder
- Feil bruk av denne modulen kan slette brukere, secrets og hele databasen inkludert all data. Sjekk alltid PLAN fĂžr du applyer.
- VÊr sikker pÄ at migreringene dine er kompatible med modulen mtp. privileges
Eksempel config:
module "cloudsql_config" {
source = "git@github.com:kartverket/terraform-modules.git/?ref=cloud_sql_config/v0.7.0"
gcp_instance_name = module.cloudsql_test.cloud_sql_instance_name
gcp_project_id = module.cloudsql_test.gcp_project_id
env = "prod"
databases = {
"backstage" = {
name = "backstage"
owner = "backstage"
extensions = ["pgcrypto", "postgis"]
prevent_destroy = true
# Denne variabelen mÄ IKKE endres uten at dere er klare til Ä migrere state manuelt.
schemas = [
{
name = "backstage"
migration_user = {
name = "backstage_migrater" # migration_user blir eier av skjemaet som opprettes
}
application_user = {
name = "backstage_app" # application user fÄr CRUD privilegier
}
misc_users = [
{
name = "readonly"
privileges = ["SELECT"]
}
]
},
{
name = "opencost"
unified_user = true
migration_user = {
name = "opencost_migrater" # ignoreres, fordi vi har unified_user = true, men den mÄ settes likevel
}
application_user = {
name = "opencost_app"
privileges = ["SELECT", "UPDATE"] # ignoreres, app user blir owner av skjemaet fordi unified_user er true
}
misc_users = [
{
name = "readonly"
privileges = ["SELECT"]
}
]
}
]
}
}
}
For hver bruker sÄ vil modulen generere opp et klient sertifikat og en privatnÞkkel, disse legges i GSM. Den private nÞkkelen legges i to formater; PEM og PK8. Vi har erfart at JDBC ikke liker PEM, sÄ i dette tilfellet sÄ bÞr du bruke PK8 nÞkkelen istedenfor.
Bruke instansen fra SKIPâ
NÄr du skal bruke instansen fra SKIP sÄ mÄ du gjÞre noen fÄ modifikasjoner til applikasjonsmanifestet ditt.
Det fÞrste du mÄ gjÞre er Ä hente ut secrets.
Terraform modulen vil generere opp og legge inn alle secrets du trenger for Ă„ koble til databasen i Google Secret Manager i prosjektet du har valgt.
Kjenner du ikke til GSM og ExternalSecrets anbefaler vi Ă„ lese Hente hemmeligheter fra hemmelighetshvelv fĂžrst.
For Ä hente ut disse sÄ mÄ du lage to ExternalSecret
, en for sertifikater og en for passord/brukernavn, her er et eksempel:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: my-app-db-client-password # Denne brukes for Ă„ hente ut password fra json secreten i gsm.
namespace: my-app-namespace
spec:
refreshInterval: 1h
secretStoreRef:
name: gsm
kind: SecretStore
target:
name: my-app-db-user-password # Navnet pÄ Kubernetes Secret som opprettes
creationPolicy: Owner
data:
- remoteRef:
conversionStrategy: Default
decodingStrategy: None
key: cloudsql-myinstance-myuser # Navnet pÄ GSM secret
metadataPolicy: None
property: password
secretKey: password
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-certs
spec:
secretStoreRef:
kind: SecretStore
name: gsm
data:
- secretKey: server.crt
remoteRef:
key: cloudsql-<instansnavn>-ca-certificate
- secretKey: client.crt
remoteRef:
key: cloudsql-<instansnavn>-<bruker>-client-certificate
### client.key i PEM, fungerer for de fleste
- secretKey: client.key
remoteRef:
key: cloudsql-<instansnavn>-<bruker>-client-key
### VISST DU TRENGER PK8 (JDBC kan kreve dette) - Bare ta med ĂN key, ikke begge
- secretKey: client.pk8
remoteRef:
decodingStrategy: Base64 # MĂ„ vĂŠre med for pk8
key: cloudsql-<instansnavn>-<bruker>-client-key-pk8
NĂ„ har du hentet alle hemmelighetene du trenger, og kan bruke disse i skiperator manifestet ditt:
apiVersion: skiperator.kartverket.no/v1alpha1
kind: Application
metadata:
name: minapp
spec:
image: ghcr.io/kartverket/minapp
port: 8080
replicas: 2
accessPolicy:
outbound:
external:
- host: <instansnavn>-db-<env> # Velg selv hva du vil kalle denne, sÄ lenge den er unik
ip: 10.x.x.x # Privat IP-adresse til databasen, den finner du i GCP
ports:
- name: sql
port: 5432
protocol: TCP
env: ## DISSE env VERDIENE ER EKSEMPLER, OG MĂ
JUSTERES FOR HVER APPLIKASJON
- name: POSTGRES_DB
value: minapp
- name: POSTGRES_USER
value: minappbrukernavn
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
key: db_password
name: minapp-hemmligheter
- name: PGSSLCA
value: /app/db-certs/server.crt
- name: PGSSLKEY
value: /app/db-certs/client.key
- name: PGSSLCERT
value: /app/db-certs/client.crt
filesFrom:
- mountPath: /app/db-certs
secret: database-certs
Skiperator vil nÄ:
- lage en
NetworkPolicy
som gir applikasjonen tilgang til databasen - 'mounte' sertifikatene inn i filsystemet til poden, slik applikasjonen kan bruke de til Ă„ koble til databasen
- laste inn passord hemmeligheten som en env variabel inn i poden, slik applikasjonen kan koble til databasen
Bruke CloudSQL fra Java applikasjonerâ
Skal du bruke CloudSQL fra Java applikasjoner mÄ du lage til ExternalSecrets og konfigurere skiperator som ovenfor,
men bruk pk8 nĂžkkel istedenfor vanlig pem nĂžkkel.
Det skal vĂŠre nok Ă„ konfigurere en connection string som ser noe slik ut postgresql://<privat-ip>:5432/<database-navn>?sslmode=require&sslrootcert=/app/db-certs/server.crt&sslcert=/app/db-certs/client.crt&sslkey=/app/db-certs/client.pk8
Alternativt kan man ogsÄ bruke en Cloud Sql Auth Proxy connector, men da vil man fÄ litt dÄrligere ytelse. Bruker man en connector sÄ slipper man Ä bruke certs, men man mÄ Äpne for port 3307 mot databasen i access policies i skiperator manifestet.
Monitorering og alarmeringâ
Fungerer bare dersom dere bruker hĂžyere versjon enn 0.9.1 av cloud_sql modulen.
Vi har laget et dashboard, sammen med DBAene, for monitorering av CloudSQL databasene, som kan finne her. I tillegg sÄ finnes ogsÄ Googles standard dashboard og metrikker som man kan finne inne pÄ CloudSQL ressursen i GCP consolen.
For alarmering sĂ„ brukes grafana-alerts repoet som for alle andre type alerts. Her har vi utviklet en cloud_sql_alerts modul som gir dere et sett med standard alarmer. Metrikker vi baserer oss pĂ„ blir hentet ut ved hjelp av sql_exporter, disse metrikkene er hentet ut pĂ„ grunnlag av SQL-spĂžrringer som DBAene har predefinert. Ănskes det andre metrikker sĂ„ ta kontakt med dem.
Det er ogsÄ tilgjengelig et sett med standardmetrikker fra Google gjennom grafana, for Ä bruke disse sÄ gÄ inn i explore view i grafana.
Velg Google Cloud Monitoring
som datasource, og velg prosjektet ditt og Cloudsql som service. Se pÄ cloud_sql_alerts
modulen dersom du Ăžnsker Ă„ se hvordan de kan brukes i en alert.
Backup og katastrofehĂ„ndteringâ
Backupâ
CloudSQL er en google managed lÞsning av postgres, og det betyr ogsÄ at det har et innebygd backup system, og hÄndteres i gcp console.
Dette systemet tar automatisk backup av databasen din, og lagrer disse i 7 dager som standard. Hvis du har behov for Ă„ bevare backups lengre enn dette kan det konfigureres med en variabel til terraform-modulen, ref: input_retained_backups
Backupen er inkrementel og man har Point-in-time
recovery tilgjengelig.
Vi anbefaler at du leser gjennom Google sin dokumentasjon for Ä forstÄ hvordan backup fungerer i CloudSQL.
KatastrofehĂ„ndteringâ
Google Cloud SQL har innebygd failover, og det betyr at dersom primÊrinstansen din gÄr ned, sÄ vil en av de tilgjengelige replicaene ta over.
Dette mÄ konfigureres i terraform, ved bruk av availability_type
variabelen, default pÄ denne er ZONAL
som betyr at du ikke fÄr en secondary instans.
I produksjon er det anbefalt Ä ha en secondary instans, og da mÄ availability_type
settes til REGIONAL
i terraform.
Les mer her: Google sin dokumentasjon
Viktig Ă„ huske pĂ„â
Max connectionsâ
I enkelte situasjoner kan hele CloudSQL-instansen bli utilgjengelig, og man vil motta fĂžlgende feilmelding:
HTTPError 409: Operation failed because another operation was already in progress. Try your request after the current operation is complete.
Basert pÄ erfaring skyldes dette som regel at det er Äpnet for mange samtidige connections mot databasen.
For eksempel, dersom max_connections
-variabelen i Terraform-modulen er satt til 100
, og man har to applikasjoner som hver bruker 30
connections og kjĂžrer med to replikas, vil det totalt bli 120
connections â i tillegg til noen system-connections (typisk 2â3).
I slike tilfeller kan instansen bli utilgjengelig: man kan verken restarte den eller gjĂžre konfigurasjonsendringer.
LĂžsning:
Skaler ned alle applikasjoner (sett replicas
til 0
), og vent opptil én time. NÄr connections er frigjort, kan man justere max_connections
-verdien.
Anbefaling:
Implementer connection pooling i applikasjonene. Hver enkelt connection Þker belastningen pÄ databaseinstansen, og unÞdvendig hÞyt antall tilkoblinger er bÄde ineffektivt og kostbart.
Legg ogsÄ til denne alarmmodulen i grafana-alerts, da fÄr dere alarmer nÄr connections nÊrmer seg maks.