{"id":95322,"date":"2020-09-28T07:42:39","date_gmt":"2020-09-28T05:42:39","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt"},"modified":"2020-09-28T07:42:39","modified_gmt":"2020-09-28T05:42:39","slug":"kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","title":{"rendered":"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/23b2db49941fa5bd5000358c8ffb991b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSempre pi\u00f9 spesso riceviamo richieste dai clienti: \u00abVogliamo qualcosa come Amazon RDS, ma pi\u00f9 economico\u00bb; \u00abVogliamo qualcosa come RDS, ma ovunque, in qualsiasi infrastruttura\u00bb. Per realizzare una soluzione managed simile su Kubernetes, abbiamo esaminato lo stato attuale dei principali operatori per PostgreSQL (Stolon, operatori di Crunchy Data e Zalando) e abbiamo fatto la nostra scelta.<\/p>\n<p>Questo articolo rappresenta la nostra esperienza acquisita sia dal punto di vista teorico (panoramica delle soluzioni) che pratico (cosa \u00e8 stato scelto e cosa ne \u00e8 venuto fuori). Ma prima di tutto, definiamo quali sono le esigenze richieste per una potenziale sostituzione di RDS...<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Cos'\u00e8 RDS<\/h2>\n<p>\nQuando le persone parlano di RDS, per la nostra esperienza, si riferiscono a un servizio di database gestito (managed) che:<\/p>\n<ol>\n<li>\u00e8 facilmente configurabile;<\/li>\n<li>ha la possibilit\u00e0 di lavorare con snapshot e di ripristinarli (preferibilmente con supporto per <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Point-in-time_recovery\">PITR<\/a><\/noindex>);<\/li>\n<li>consente di creare topologie master-slave;<\/li>\n<li>ha un'ampia lista di estensioni;<\/li>\n<li>fornisce audit e gestione degli utenti\/accessi.<\/li>\n<\/ol>\n<p>\nParlando in generale, gli approcci per affrontare la questione possono essere molto diversi, tuttavia la strada con il presunto Ansible non ci si addice. (Nello stesso modo sono giunti a una conclusione simile anche i colleghi di 2GIS a seguito della loro <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/509926\/\">tentativo<\/a><\/noindex> di creare uno \u00abstrumento per il rapido dispiegamento di un cluster ad alta disponibilit\u00e0 basato su Postgres\u00bb.)<\/p>\n<p>Gli operatori sono l'approccio convenzionale per affrontare tali questioni nell'ecosistema Kubernetes. Abbiamo gi\u00e0 parlato di questo in relazione ai database eseguiti all'interno di Kubernetes, il CTO di \u00abFlanta\u00bb <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/distol\/\" class=\"user_link\">distol<\/a><\/noindex>, in <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">in una delle sue relazioni<\/a><\/noindex>.<\/p>\n<p><i><strong>NB<\/strong><\/i><i>: Per creare rapidamente operatori semplici, ti consigliamo di dare un'occhiata alla nostra utilit\u00e0 Open Source <\/i><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/shell-operator\"><i>shell-operator<\/i><\/a><\/noindex><i>. Utilizzando essa, puoi farlo senza conoscere Go, attraverso modi pi\u00f9 familiari per i sistemi, come Bash, Python, ecc.<\/i><\/p>\n<p>Per PostgreSQL esistono diversi popolari operatori K8s:<\/p>\n<ul>\n<li>Stolon;<\/li>\n<li>Crunchy Data PostgreSQL Operator;<\/li>\n<li>Zalando Postgres Operator.<\/li>\n<\/ul>\n<p>\nEsaminiamoli pi\u00f9 da vicino.<\/p>\n<h2>Scelta dell'operatore<\/h2>\n<p>\nOltre alle importanti funzionalit\u00e0 gi\u00e0 menzionate, noi \u2013 come ingegneri di gestione dell'infrastruttura in Kubernetes \u2013 ci aspettavamo anche dai nostri operatori quanto segue:<\/p>\n<ul>\n<li> deploy da Git e con <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/extend-kubernetes\/operator\/#deploying-operators\">Custom Resources<\/a><\/noindex>;<\/li>\n<li> supporto per pod anti-affinity;<\/li>\n<li> installazione di node affinity o node selector;<\/li>\n<li> installazione di tolerations;<\/li>\n<li> disponibilit\u00e0 di opzioni di tuning;<\/li>\n<li> tecnologie comprensibili e anche comandi.<\/li>\n<\/ul>\n<p>\nSenza entrare nei dettagli su ciascun punto (chiedi nei commenti se hai domande dopo aver letto l'intero articolo), vorrei sottolineare in generale che questi parametri sono necessari per una descrizione pi\u00f9 dettagliata della specializzazione dei nodi del cluster, in modo da poterli ordinare per applicazioni specifiche. In questo modo possiamo raggiungere un equilibrio ottimale tra prestazioni e costi.<\/p>\n<p>Ora passiamo agli operatori PostgreSQL.<\/p>\n<h3>1. Stolon<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\">Stolon<\/a><\/noindex> dall'azienda italiana Sorint.lab in <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">gi\u00e0 citato nella relazione<\/a><\/noindex> \u00e8 stato considerato un certo standard tra gli operatori per DBMS. Questo \u00e8 un progetto piuttosto vecchio: la sua prima versione pubblica risale a novembre 2015 (!), e il repository su GitHub pu\u00f2 vantare quasi 3000 stelle e oltre 40 collaboratori.<\/p>\n<p>E in effetti, Stolon \u00e8 un ottimo esempio di architettura ben progettata:<\/p>\n<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/a34625c130bfd29c5645cf2417042de2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPuoi approfondire il funzionamento di questo operatore nella relazione o <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\/blob\/master\/doc\/architecture.md\">documentazione del progetto<\/a><\/noindex>. In generale, basta dire che \u00e8 in grado di fare tutto ci\u00f2 che \u00e8 descritto: failover, proxy per accesso trasparente ai client, backup... Inoltre, i proxy forniscono accesso tramite un unico endpoint di servizio - a differenza delle due altre soluzioni esaminate pi\u00f9 avanti (che hanno due servizi per accedere al database).<\/p>\n<p>Tuttavia, Stolon <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\/issues\/463#issuecomment-379666733\">non ha Custom Resources<\/a><\/noindex>, il che rende impossibile implementarlo in modo che si possano creare istanze di DBMS in Kubernetes in modo semplice e veloce - \"come panini caldi\". La gestione avviene tramite l'utilit\u00e0 <code>stolonctl<\/code>, mentre il deploy avviene tramite un chart Helm e le definizioni utente sono impostate in ConfigMap.<\/p>\n<p>Da un lato, sembra che l'operatore non sia proprio un operatore (dopotutto non utilizza CRD). D'altra parte, \u00e8 un sistema flessibile che consente di configurare le risorse in K8s come preferisci.<\/p>\n<p>In sintesi, non ci \u00e8 sembrato ottimale avere un chart separato per ogni DB. Pertanto, abbiamo cominciato a cercare alternative.<\/p>\n<h3>2. Crunchy Data PostgreSQL Operator<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/postgres-operator\">L'operatore di Crunchy Data<\/a><\/noindex>, una giovane startup americana, sembrava un'alternativa logica. La sua storia pubblica inizia con il primo rilascio nel marzo 2017, da allora il repository su GitHub ha ricevuto poco meno di 1300 stelle e oltre 50 collaboratori. L'ultimo rilascio di settembre \u00e8 stato testato per funzionare con Kubernetes 1.15\u20141.18, OpenShift 3.11+ e 4.4+, GKE e VMware Enterprise PKS 1.3+.<\/p>\n<p>L'architettura del Crunchy Data PostgreSQL Operator soddisfa anche i requisiti dichiarati:<\/p>\n<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/343cd0494abae42fcf5b47c5bb4eb310.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa gestione avviene tramite l'utilit\u00e0 <code>pgo<\/code>, tuttavia essa a sua volta genera Custom Resources per Kubernetes. Pertanto, come potenziali utenti, l'operatore ci ha soddisfatto:<\/p>\n<ul>\n<li> c'\u00e8 gestione tramite CRD;<\/li>\n<li> comoda gestione degli utenti (anch'essa tramite CRD);<\/li>\n<li> integrazione con altri componenti <noindex><a rel=\"nofollow\" href=\"https:\/\/access.crunchydata.com\/documentation\/crunchy-postgres-containers\/4.3.1\/\">Crunchy Data Container Suite<\/a><\/noindex> \u2014 una collezione specializzata di immagini di container per PostgreSQL e utilit\u00e0 per lavorarci (incluso pgBackRest, pgAudit, estensioni da contrib, ecc.).<\/li>\n<\/ul>\n<p>\nTuttavia, i tentativi di iniziare a utilizzare l'operatore di Crunchy Data hanno rivelato alcuni problemi:<\/p>\n<ul>\n<li>Non c'era la possibilit\u00e0 di tolerations \u2014 era previsto solo nodeSelector.<\/li>\n<li>I pod creati facevano parte di un Deployment, nonostante stessimo deployando un'applicazione stateful. A differenza di StatefulSet, i Deployment non possono creare dischi.<\/li>\n<\/ul>\n<p>\nQuesto ultimo difetto porta a momenti divertenti: nell'ambiente di test siamo riusciti a far partire 3 repliche con un solo disco <i>storage locale<\/i>, con il risultato che l'operatore riportava che 3 repliche stavano funzionando (anche se non era cos\u00ec).<\/p>\n<p>Un'altra caratteristica di questo operatore \u00e8 la sua integrazione pronta con vari sistemi ausiliari. Ad esempio, \u00e8 facile installare pgAdmin e pgBounce, e in <noindex><a rel=\"nofollow\" href=\"https:\/\/access.crunchydata.com\/documentation\/postgres-operator\/4.4.0\/installation\/other\/ansible\/installing-metrics\/\">documentazione<\/a><\/noindex> sono considerate Grafana e Prometheus preconfigurate. Nel recente <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/postgres-operator\/releases\/tag\/v4.5.0-beta.1\">rilascio 4.5.0-beta1<\/a><\/noindex> si segnala un miglioramento dell'integrazione con il progetto <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/pgmonitor\">pgMonitor<\/a><\/noindex>, il che consente all'operatore di offrire una visualizzazione chiara delle metriche PgSQL \u00about of the box\u00bb.<\/p>\n<p>Tuttavia, la strana scelta di risorse Kubernetes generate ci ha portato alla necessit\u00e0 di trovare un'altra soluzione.<\/p>\n<h3>3. Zalando Postgres Operator<\/h3>\n<p>\nI prodotti Zalando ci sono noti da tempo: abbiamo esperienza nell'utilizzo di Zalenium e, naturalmente, abbiamo provato <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/patroni\">Patroni<\/a><\/noindex> \u2014 la loro soluzione HA popolare per PostgreSQL. Uno degli autori, Alexey Klukin, ha parlato dell'approccio dell'azienda nella creazione <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\">del Postgres Operator<\/a><\/noindex> nella diretta del <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/479438\/\">Postgres Tuesday #5<\/a><\/noindex>, e ci \u00e8 piaciuto.<\/p>\n<p>Questa \u00e8 la soluzione pi\u00f9 recente tra quelle considerate nell'articolo: il primo rilascio \u00e8 avvenuto nell'agosto 2018. Tuttavia, nonostante il numero ridotto di rilasci formali, il progetto ha fatto molta strada, superando gi\u00e0 la soluzione di Crunchy Data con oltre 1300 stelle su GitHub e il numero massimo di contributori (oltre 70).<\/p>\n<p>Sotto il cofano, questo operatore utilizza soluzioni collaudate nel tempo:<\/p>\n<ul>\n<li> Patroni e <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/spilo\">Spilo<\/a><\/noindex> per la gestione,<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">WAL-E<\/a><\/noindex> \u2014 per i backup,<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgbouncer\/pgbouncer\">PgBouncer<\/a><\/noindex> \u2014 come pool di connessioni.<\/li>\n<\/ul>\n<p>\nEcco come \u00e8 rappresentata l'architettura dell'operatore di Zalando:<\/p>\n<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/c66f10c1a818592ecaacd2db4ce5ace5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nL'operatore \u00e8 completamente gestito tramite Custom Resources, crea automaticamente un StatefulSet da contenitori che poi possono essere personalizzati aggiungendo vari sidecar nei pod. Tutto ci\u00f2 rappresenta un notevole vantaggio rispetto all'operatore di Crunchy Data.<\/p>\n<p>Poich\u00e9 abbiamo scelto la soluzione di Zalando tra 3 opzioni considerate, la descrizione delle sue funzionalit\u00e0 verr\u00e0 presentata di seguito, insieme alla pratica di applicazione.<\/p>\n<h2>Pratica con Postgres Operator di Zalando<\/h2>\n<p>\nIl deploy dell'operatore avviene in modo molto semplice: \u00e8 sufficiente scaricare l'ultima versione da GitHub e applicare i file YAML dalla directory. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/tree\/master\/manifests\">manifests<\/a><\/noindex>In alternativa, \u00e8 possibile anche utilizzare <noindex><a rel=\"nofollow\" href=\"https:\/\/operatorhub.io\/operator\/postgres-operator\">OperatorHub<\/a><\/noindex>.<\/p>\n<p>Dopo l'installazione, \u00e8 opportuno preoccuparsi della configurazione <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/reference\/operator_parameters.md#aws-or-gcp-interaction\">di archiviazione per i log e i backup<\/a><\/noindex>. Si effettua tramite ConfigMap <code>postgres-operator<\/code> nello spazio dei nomi in cui hai installato l'operatore. Una volta configurati gli archivi, puoi avviare il primo cluster PostgreSQL.<\/p>\n<p>Ad esempio, il deploy standard appare come segue:<\/p>\n<pre><code class=\"plaintext\">apiVersion: acid.zalan.do\/v1\nkind: postgresql\nmetadata:\n name: staging-db\nspec:\n numberOfInstances: 3\n patroni:\n   synchronous_mode: true\n postgresql:\n   version: \"12\"\n resources:\n   limits:\n     cpu: 100m\n     memory: 1Gi\n   requests:\n     cpu: 100m\n     memory: 1Gi\n sidecars:\n - env:\n   - name: DATA_SOURCE_URI\n     value: 127.0.0.1:5432\n   - name: DATA_SOURCE_PASS\n     valueFrom:\n       secretKeyRef:\n         key: password\n         name: postgres.staging-db.credentials\n   - name: DATA_SOURCE_USER\n     value: postgres\n   image: wrouesnel\/postgres_exporter\n   name: prometheus-exporter\n   resources:\n     limits:\n       cpu: 500m\n       memory: 100Mi\n     requests:\n       cpu: 100m\n       memory: 100Mi\n teamId: staging\n volume:\n   size: 2Gi\n<\/code><\/pre>\n<p>\nQuesto manifesto deploya un cluster di 3 istanze con un sidecar in forma di <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wrouesnel\/postgres_exporter\">postgres_exporter<\/a><\/noindex>, dal quale raccogliamo le metriche dell'applicazione. Come puoi vedere, \u00e8 tutto molto semplice e, se lo desideri, puoi creare un numero praticamente illimitato di cluster.<\/p>\n<p>Vale la pena prestare attenzione anche alla <b>interfaccia web per la gestione<\/b> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/operator-ui.md\">postgres-operator-ui<\/a><\/noindex>. Viene fornita insieme all'operatore e consente di creare ed eliminare cluster, cos\u00ec come di gestire i backup effettuati dall'operatore.<\/p>\n<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/2e9ae033a9817d101c843ce061aafdb5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Elenco dei cluster PostgreSQL<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/74a65f7f301da14a0cb7bea6d5ef84ec.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Gestione dei backup<\/i><\/p>\n<p>Un'altra caratteristica interessante \u00e8 il supporto per <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/user.md#teams-api-roles\">Teams API<\/a><\/noindex>. Questo meccanismo crea automaticamente <b>ruoli in PostgreSQL<\/b>, basandosi sull'elenco ricevuto di nomi degli utenti. Successivamente, l'API consente di restituire l'elenco degli utenti per i quali vengono creati automaticamente i ruoli.<\/p>\n<h3>Problemi e loro soluzione<\/h3>\n<p>\nTuttavia, l'uso dell'operatore ha presto rivelato alcuni significativi svantaggi:<\/p>\n<ol>\n<li> mancanza di supporto per nodeSelector;<\/li>\n<li> impossibilit\u00e0 di disattivare i backup;<\/li>\n<li> quando si utilizza la funzione di creazione delle basi non compaiono privilegi di default;<\/li>\n<li> periodicamente manca la documentazione o questa \u00e8 obsoleta.<\/li>\n<\/ol>\n<p>\nFortunatamente, molti di essi possono essere risolti. Iniziamo dalla fine: problemi con <strong>documentazione<\/strong>. <\/p>\n<p>Probabilmente vi imbatterete nel fatto che non \u00e8 sempre chiaro come specificare il backup e come collegare il bucket di backup all'Operator UI. Questo viene citato brevemente nella documentazione, ma la descrizione reale si trova in <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/481\">PR<\/a><\/noindex>:<\/p>\n<ol>\n<li>\u00e8 necessario creare un segreto;<\/li>\n<li>passarlo all'operatore nel parametro <code>pod_environment_secret_name<\/code> nel CRD con le impostazioni dell'operatore o nel ConfigMap (dipende da come avete deciso di installare l'operatore).<\/li>\n<\/ol>\n<p>\nTuttavia, come si \u00e8 rivelato, attualmente non \u00e8 possibile. Ecco perch\u00e9 abbiamo raccolto <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/postgres-operator\">la nostra versione dell'operatore<\/a><\/noindex> con alcune funzionalit\u00e0 aggiuntive di terze parti. Maggiori dettagli su di essa \u2014 vedi sotto.<\/p>\n<p>Se si passano all'operatore parametri per il backup, in particolare \u2014 <code>wal_s3_bucket<\/code> e le chiavi di accesso in AWS S3, allora lui <strong>effettuer\u00e0 il backup di tutto<\/strong>: non solo le basi in produzione, ma anche quelle di staging. Questo non ci ha soddisfatti.<\/p>\n<p>Nella descrizione dei parametri per Spilo, che \u00e8 il wrapper Docker di base per PgSQL utilizzando l'operatore, \u00e8 emerso: \u00e8 possibile passare il parametro <code>WAL_S3_BUCKET<\/code> vuoto, disattivando cos\u00ec i backup. Inoltre, con grande gioia \u00e8 stato trovato anche un <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/908\">PR pronto<\/a><\/noindex>, che abbiamo immediatamente accettato nel nostro fork. Ora \u00e8 sufficiente aggiungere <code>enableWALArchiving: false<\/code> alle risorse del cluster PostgreSQL.<\/p>\n<p>S\u00ec, era possibile farlo diversamente, avviando 2 operatori: uno per staging (senza backup) e l'altro per produzione. Ma cos\u00ec siamo riusciti a farne a meno di uno.<\/p>\n<p>Ok, abbiamo imparato a fornire accesso alle basi per S3 e i backup hanno iniziato a essere memorizzati. Come far funzionare le pagine dei backup nell'Operator UI?<\/p>\n<p><img decoding=\"async\" alt=\"Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza\" src=\"\/wp-content\/uploads\/2020\/09\/46169b53707b0bbb686798c655022f40.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNell'Operator UI sar\u00e0 necessario aggiungere 3 variabili:<\/p>\n<ul>\n<li> <code>SPILO_S3_BACKUP_BUCKET<\/code><\/li>\n<li> <code>AWS_ACCESS_KEY_ID<\/code><\/li>\n<li> <code>AWS_SECRET_ACCESS_KEY<\/code><\/li>\n<\/ul>\n<p>\nDopo di che la gestione dei backup diventer\u00e0 disponibile, il che nel nostro caso semplificher\u00e0 il lavoro con lo staging, consentendo di portare l\u00ec tagli dalla produzione senza script aggiuntivi.<\/p>\n<p>Come ulteriore vantaggio, \u00e8 stata menzionata la gestione con l'API Teams e le ampie possibilit\u00e0 per la creazione di basi e ruoli tramite l'operatore. Tuttavia, i ruoli creati <strong>non avevano diritti di default<\/strong>. Di conseguenza, un utente con diritti di lettura non poteva leggere nuove tabelle.<\/p>\n<p>Perch\u00e9 \u00e8 cos\u00ec? Nonostante nel codice ci siano <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/pkg\/cluster\/database.go#L42\">c'\u00e8<\/a><\/noindex> necessari <code>GRANT<\/code>, non vengono applicati sempre. Ci sono 2 metodi: <code>syncPreparedDatabases<\/code> e <code>syncDatabases<\/code>. In <code>syncPreparedDatabases<\/code> \u2014 nonostante che nella sezione <code>preparedDatabases<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/manifests\/complete-postgres-manifest.yaml#L26\">c'\u00e8<\/a><\/noindex> ci sia una condizione <code>defaultRoles<\/code> e <code>defaultUsers<\/code> per la creazione di ruoli, i permessi predefiniti non vengono applicati. Siamo nel processo di preparazione di una patch affinch\u00e9 questi diritti vengano applicati automaticamente.<\/p>\n<p>E l'ultimo punto nelle modifiche per noi rilevanti \u00e8 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/975\">patch<\/a><\/noindex>, che aggiunge Node Affinity nel StatefulSet creato. I nostri clienti spesso preferiscono ridurre i costi utilizzando istanze spot, e su di esse chiaramente non si dovrebbero collocare servizi DB. Questo problema potrebbe essere risolto anche tramite tolerations, ma la presenza di Node Affinity offre maggiore sicurezza.<\/p>\n<h3>Cosa \u00e8 emerso?<\/h3>\n<p>\nA seguito della risoluzione dei problemi elencati, abbiamo forkato il Postgres Operator di Zalando nel <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/postgres-operator\">nostro repository<\/a><\/noindex>, dove viene compilato con patch cos\u00ec utili. E per maggior comodit\u00e0 abbiamo raccolto anche <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/flant\/postgres-operator\">Docker image<\/a><\/noindex>.<\/p>\n<p>Elenco delle PR accettate nel fork:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/1066\">costruzione di un'immagine Docker sicura e leggera per l'operatore<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/908\">disabilitazione dei backup<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/1121\">aggiornamento delle versioni delle risorse per le versioni attuali di k8s<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/975\">implementazione di Node Affinity<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\nSarebbe fantastico se la comunit\u00e0 supportasse queste PR affinch\u00e9 possano entrare nell'upstream con la prossima versione dell'operatore (1.6).<\/p>\n<h2>Bonus! Storia di successo con la migrazione della produzione<\/h2>\n<p>\nSe utilizzi Patroni, puoi migrare una produzione live con un minimo di downtime.<\/p>\n<p>Spilo consente la creazione di cluster standby tramite archiviazione S3 con <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">Wal-E<\/a><\/noindex>, quando il log binario PgSQL viene prima salvato in S3 e poi estratto dal replica. Ma cosa fare se hai <i>non<\/i> Wal-E utilizzato nella tua vecchia infrastruttura? La soluzione a questo problema \u00e8 gi\u00e0 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/true_engineering\/blog\/437318\/\">stata proposta<\/a><\/noindex> su Habr.<\/p>\n<p>La replica logica di PostgreSQL viene in soccorso. Tuttavia, non ci addentreremo nei dettagli su come creare pubblicazioni e sottoscrizioni, perch\u00e9... il nostro piano ha subito un fallimento.<\/p>\n<p>Il fatto \u00e8 che nel DB c'erano alcune tabelle sovraccariche con milioni di righe, che, inoltre, venivano continuamente riempite e svuotate. <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/12\/sql-createsubscription\">Una semplice sottoscrizione<\/a><\/noindex> con <code>copy_data<\/code>, in cui il nuovo replica copia tutto il contenuto dal master, semplicemente non riusciva a stare dietro al master. La copia del contenuto ha funzionato per una settimana, ma non ha mai raggiunto il master. Alla fine, per risolvere il problema ci hanno aiutato <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/avitotech\/recovery-use-cases-for-logical-replication-in-postgresql-10-a1e6bab03072\">su Habr.<\/a><\/noindex> colleghi di Avito: \u00e8 possibile trasferire i dati utilizzando <code>pg_dump<\/code>. Descriver\u00f2 la nostra versione (leggermente modificata) di questo algoritmo.<\/p>\n<p>L'idea \u00e8 quella di poter creare una sottoscrizione disattivata, legata a uno specifico slot di replica, e poi correggere il numero della transazione. Erano disponibili repliche per il lavoro di produzione. Questo \u00e8 importante perch\u00e9 la replica aiuter\u00e0 a creare un dump coerente e a continuare a ricevere modifiche dal master.<\/p>\n<p>Nelle successive istruzioni che descrivono il processo di migrazione, verranno utilizzate le seguenti designazioni per gli host:<\/p>\n<ol>\n<li><i>master<\/i> \u2014 server sorgente;<\/li>\n<li><i>replica1<\/i> \u2014 replica in streaming sulla vecchia produzione;<\/li>\n<li><i>replica2<\/i> \u2014 nuova replica logica.<\/li>\n<\/ol>\n<p><\/p>\n<h3>Piano di migrazione<\/h3>\n<p>\n1. Creiamo sul master una sottoscrizione per tutte le tabelle nello schema <code>pubblico<\/code> del database <code>dbname<\/code>:<\/p>\n<pre><code class=\"bash\">psql -h master -d dbname -c \"CREATE PUBLICATION dbname FOR ALL TABLES;\"\n<\/code><\/pre>\n<p>\n2. Creiamo uno slot di replica sul master:<\/p>\n<pre><code class=\"bash\">psql -h master -c \"select pg_create_logical_replication_slot('repl', 'pgoutput');\"\n<\/code><\/pre>\n<p>\n3. Fermeremo la replica sulla vecchia replica:<\/p>\n<pre><code class=\"bash\">psql -h replica1 -c \"select pg_wal_replay_pause();\"\n<\/code><\/pre>\n<p>\n4. Otteniamo il numero della transazione dal master:<\/p>\n<pre><code class=\"bash\">psql -h master -c \"select replay_lsn from pg_stat_replication where client_addr = 'replica1';\"\n<\/code><\/pre>\n<p>\n5. Eseguiremo un dump dalla vecchia replica. Lo faremo in pi\u00f9 thread, il che aiuter\u00e0 ad accelerare il processo:<\/p>\n<pre><code class=\"bash\">pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump\/ dbname\n<\/code><\/pre>\n<p>\n6. Caricheremo il dump sul nuovo server:<\/p>\n<pre><code class=\"bash\">pg_restore -h replica2 -F d -j 8 -d dbname dump\/\n<\/code><\/pre>\n<p>\n7. Dopo aver caricato il dump, possiamo avviare la replica sulla replica in streaming:<\/p>\n<pre><code class=\"bash\">psql -h replica1 -c \"select pg_wal_replay_resume();\"\n<\/code><\/pre>\n<p>\n7. Creiamo una sottoscrizione sulla nuova replica logica:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -c \"create subscription oldprod connection 'host=replica1 port=5432 user=postgres password=secret dbname=dbname' publication dbname with (enabled = false, create_slot = false, copy_data = false, slot_name='repl');\"\n<\/code><\/pre>\n<p>\n8. Otteniamo <code>oid<\/code> della sottoscrizione:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c \"select oid, * from pg_subscription;\"\n<\/code><\/pre>\n<p>\n9. Supponiamo di aver ottenuto <code>oid=1000<\/code>. Applicheremo il numero della transazione alla sottoscrizione:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c \"select pg_replication_origin_advance('pg_1000', 'AA\/AAAAAAAA');\"\n<\/code><\/pre>\n<p>\n10. Avviamo la replica:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c \"alter subscription oldprod enable;\"\n<\/code><\/pre>\n<p>\n11. Controlliamo lo stato della sottoscrizione; la replica dovrebbe funzionare:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c \"select * from pg_replication_origin_status;\"\npsql -h master -d dbname -c \"select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;\"\n<\/code><\/pre>\n<p>\n12. Dopo che la replica \u00e8 stata avviata e i database sono stati sincronizzati, si pu\u00f2 effettuare il switch.<\/p>\n<p>13. Dopo aver disabilitato la replica, \u00e8 necessario correggere le sequenze. Questo \u00e8 ben descritto <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Fixing_Sequences\">nell'articolo su wiki.postgresql.org<\/a><\/noindex>.<\/p>\n<p>Grazie a questo piano, il passaggio \u00e8 avvenuto con minime attese.<\/p>\n<h2>Conclusione<\/h2>\n<p>\nI operator di Kubernetes semplificano diverse operazioni, riducendole alla creazione di risorse K8s. Tuttavia, una volta raggiunta una straordinaria automazione con il loro aiuto, \u00e8 importante ricordare che possono portare anche una serie di sfide inaspettate, quindi scegliete gli operatori con saggezza.<\/p>\n<p>Esaminando i tre operatori Kubernetes pi\u00f9 popolari per PostgreSQL, abbiamo deciso di optare per il progetto di Zalando. Con questo abbiamo dovuto affrontare alcune difficolt\u00e0, ma il risultato \u00e8 stato davvero soddisfacente, tanto che prevediamo di estendere questa esperienza ad alcune altre installazioni PgSQL. Se avete esperienza con soluzioni simili, saremo felici di vedere i dettagli nei commenti!<\/p>\n<h2>P.S.<\/h2>\n<p>\nLeggi anche nel nostro blog:<\/p>\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">Database e Kubernetes (panoramica e video relazione)<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/479438\/\">Postgres-Marted\u00ec n. 5: PostgreSQL e Kubernetes. CI\/CD. Automazione dei test.<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/480722\/\">Una storia con l'operatore Redis in K8s e una mini-guida agli strumenti per l'analisi dei dati di questo DB.<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/520616\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b: \u00ab\u0425\u043e\u0442\u0438\u043c \u043a\u0430\u043a Amazon RDS, \u043d\u043e \u0434\u0435\u0448\u0435\u0432\u043b\u0435\u00bb; \u00ab\u0425\u043e\u0442\u0438\u043c \u043a\u0430\u043a RDS, \u043d\u043e \u0432\u0435\u0437\u0434\u0435, \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435\u00bb. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 managed-\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 Kubernetes, \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f PostgreSQL (Stolon, \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043e\u0442 Crunchy Data \u0438 Zalando) \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0432\u044b\u0431\u043e\u0440. \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u043c\u0438 \u043e\u043f\u044b\u0442 \u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":95323,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-95322","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 PostgreSQL \u0434\u043b\u044f Kubernetes, \u043d\u0430\u0448 \u0432\u044b\u0431\u043e\u0440 \u0438 \u043e\u043f\u044b\u0442 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-09-28T05:42:39+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-09-28T05:42:39+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Una panoramica degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza | ProHoster","description":"Sempre pi\u00f9 frequentemente dai clienti.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 PostgreSQL \u0434\u043b\u044f Kubernetes, \u043d\u0430\u0448 \u0432\u044b\u0431\u043e\u0440 \u0438 \u043e\u043f\u044b\u0442 | ProHoster","og:description":"\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-09-28T05:42:39+00:00","article:modified_time":"2020-09-28T05:42:39+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"95322","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 11:08:22","updated":"2022-09-30 21:12:08","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/95322","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=95322"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/95322\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/95323"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=95322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=95322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=95322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}