{"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\/es\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","title":{"rendered":"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/23b2db49941fa5bd5000358c8ffb991b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCada vez m\u00e1s, recibimos solicitudes de clientes como: \"Queremos algo como Amazon RDS, pero m\u00e1s barato\"; \"Queremos algo como RDS, pero en todas partes, en cualquier infraestructura\". Para implementar una soluci\u00f3n gestionada similar en Kubernetes, analizamos el estado actual de los operadores m\u00e1s populares para PostgreSQL (Stolon, operadores de Crunchy Data y Zalando) y tomamos nuestra decisi\u00f3n.<\/p>\n<p>Este art\u00edculo presenta nuestra experiencia desde un punto de vista te\u00f3rico (una revisi\u00f3n de soluciones) y pr\u00e1ctico (lo que se eligi\u00f3 y qu\u00e9 resultado se obtuvo). Pero primero, definamos qu\u00e9 requisitos se exigen para un posible reemplazo de RDS...<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>\u00bfQu\u00e9 es RDS?<\/h2>\n<p>\nCuando la gente habla de RDS, seg\u00fan nuestra experiencia, se refieren a un servicio gestionado (managed) de base de datos que:<\/p>\n<ol>\n<li>es f\u00e1cil de configurar;<\/li>\n<li>tiene la capacidad de trabajar con instant\u00e1neas y restaurarse a partir de ellas (preferentemente, con soporte para <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Point-in-time_recovery\">PITR<\/a><\/noindex>);<\/li>\n<li>permite crear topolog\u00edas master-slave;<\/li>\n<li>tiene una rica lista de extensiones;<\/li>\n<li>proporciona auditor\u00eda y gesti\u00f3n de usuarios\/accesos.<\/li>\n<\/ol>\n<p>\nEn t\u00e9rminos generales, los enfoques para implementar la tarea planteada pueden ser muy diversos, sin embargo, la opci\u00f3n con un Ansible condicional no nos resulta cercana. (Llegaron a una conclusi\u00f3n similar nuestros colegas de 2GIS como resultado de <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/509926\/\">su intento<\/a><\/noindex> de crear \"una herramienta para la r\u00e1pida implementaci\u00f3n de un cl\u00faster redundante basado en Postgres\".)<\/p>\n<p>Precisamente los operadores son el enfoque com\u00fan para solucionar tareas semejantes en el ecosistema de Kubernetes. Ya se ha hablado de ellos en cuanto a bases de datos ejecutadas dentro de Kubernetes, por el director t\u00e9cnico de \"Flanta\", <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/distol\/\" class=\"user_link\">distol<\/a><\/noindex>, en <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">en una de sus presentaciones<\/a><\/noindex>.<\/p>\n<p><i><strong>NB<\/strong><\/i><i>: Para crear r\u00e1pidamente operadores sencillos, recomendamos prestar atenci\u00f3n a nuestra herramienta de c\u00f3digo abierto <\/i><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/shell-operator\"><i>shell-operator<\/i><\/a><\/noindex><i>. Us\u00e1ndola, se puede hacer sin conocimientos de Go, de manera m\u00e1s familiar para los administradores de sistemas: en Bash, Python, etc.<\/i><\/p>\n<p>Existen varios operadores K8s populares para PostgreSQL:<\/p>\n<ul>\n<li>Stolon;<\/li>\n<li>Crunchy Data PostgreSQL Operator;<\/li>\n<li>Zalando Postgres Operator.<\/li>\n<\/ul>\n<p>\nMiremos m\u00e1s de cerca.<\/p>\n<h2>Selecci\u00f3n de un operador<\/h2>\n<p>\nAdem\u00e1s de las importantes capacidades que ya se mencionaron, nosotros, como ingenieros de infraestructura en Kubernetes, tambi\u00e9n esper\u00e1bamos de los operadores lo siguiente:<\/p>\n<ul>\n<li> despliegue desde Git y con <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/extend-kubernetes\/operator\/#deploying-operators\">Recursos Personalizados<\/a><\/noindex>;<\/li>\n<li> soporte para anti-afinidad de pods;<\/li>\n<li> instalaci\u00f3n de afinidad de nodos o selector de nodo;<\/li>\n<li> instalaci\u00f3n de tolerancias;<\/li>\n<li> existencia de capacidades de optimizaci\u00f3n;<\/li>\n<li> tecnolog\u00edas comprensibles e incluso comandos.<\/li>\n<\/ul>\n<p>\nSin entrar en detalles sobre cada uno de los puntos (pueden preguntar en los comentarios si quedan dudas sobre ellos despu\u00e9s de leer todo el art\u00edculo), se\u00f1alar\u00e9 en general que estos par\u00e1metros son necesarios para una descripci\u00f3n m\u00e1s precisa de la especializaci\u00f3n de los nodos del cl\u00faster, con el fin de encargarlos para aplicaciones espec\u00edficas. As\u00ed podemos lograr un equilibrio \u00f3ptimo en cuestiones de rendimiento y costo.<\/p>\n<p>Ahora, pasemos a los propios operadores de PostgreSQL.<\/p>\n<h3>1. Stolon<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\">Stolon<\/a><\/noindex> de la empresa italiana Sorint.lab en <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">el informe ya mencionado<\/a><\/noindex> fue considerado como un tipo de referencia entre los operadores para bases de datos. Es un proyecto bastante antiguo: su primera publicaci\u00f3n p\u00fablica fue en noviembre de 2015(!), y el repositorio de GitHub cuenta con casi 3000 estrellas y m\u00e1s de 40 colaboradores.<\/p>\n<p>Y de hecho, Stolon es un excelente ejemplo de una arquitectura bien pensada:<\/p>\n<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/a34625c130bfd29c5645cf2417042de2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPuedes conocer los detalles de este operador en el informe o <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\/blob\/master\/doc\/architecture.md\">la documentaci\u00f3n del proyecto<\/a><\/noindex>. En general, basta con decir que puede hacer todo lo descrito: failover, un proxy para acceso transparente de clientes, copias de seguridad... Adem\u00e1s, el proxy proporciona acceso a trav\u00e9s de un \u00fanico endpoint de servicio, a diferencia de otras dos soluciones que se describen a continuaci\u00f3n (ellas tienen dos servicios para acceder a la base).<\/p>\n<p>Sin embargo, Stolon <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\/issues\/463#issuecomment-379666733\">no tiene recursos personalizados<\/a><\/noindex>, lo que hace que no se pueda desplegar tan f\u00e1cil y r\u00e1pidamente \u2014 \"como pan caliente\" \u2014 crear instancias de bases de datos en Kubernetes. La gesti\u00f3n se realiza a trav\u00e9s de la utilidad <code>stolonctl<\/code>, el despliegue \u2014 a trav\u00e9s de Helm chart, y se definen variables de usuario en ConfigMap.<\/p>\n<p>Por un lado, resulta que el operador no es realmente un operador (ya que no utiliza CRD). Pero por otro lado, es un sistema flexible que permite configurar recursos en K8s de la manera que te resulte conveniente.<\/p>\n<p>Resumiendo, para nosotros no parec\u00eda \u00f3ptimo tener un chart separado para cada base de datos. Por lo tanto, comenzamos a buscar alternativas.<\/p>\n<h3>2. Crunchy Data PostgreSQL Operator<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/postgres-operator\">El operador de Crunchy Data<\/a><\/noindex>, una joven startup estadounidense, parec\u00eda una alternativa l\u00f3gica. Su historia p\u00fablica comienza con el primer lanzamiento en marzo de 2017, desde entonces el repositorio de GitHub ha recibido poco menos de 1300 estrellas y m\u00e1s de 50 colaboradores. La \u00faltima versi\u00f3n de septiembre fue probada para trabajar con Kubernetes 1.15-1.18, OpenShift 3.11+ y 4.4+, GKE y VMware Enterprise PKS 1.3+.<\/p>\n<p>La arquitectura del Crunchy Data PostgreSQL Operator tambi\u00e9n cumple con los requisitos declarados:<\/p>\n<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/343cd0494abae42fcf5b47c5bb4eb310.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLa gesti\u00f3n se realiza a trav\u00e9s de la utilidad <code>pgo<\/code>, sin embargo, es responsable de generar Recursos Personalizados para Kubernetes. Por lo tanto, como potenciales usuarios, el operador nos alegr\u00f3:<\/p>\n<ul>\n<li> hay gesti\u00f3n a trav\u00e9s de CRD;<\/li>\n<li> gesti\u00f3n conveniente de usuarios (tambi\u00e9n a trav\u00e9s de CRD);<\/li>\n<li> integraci\u00f3n con otros componentes <noindex><a rel=\"nofollow\" href=\"https:\/\/access.crunchydata.com\/documentation\/crunchy-postgres-containers\/4.3.1\/\">Crunchy Data Container Suite<\/a><\/noindex> \u2014 una colecci\u00f3n especializada de im\u00e1genes de contenedores para PostgreSQL y herramientas relacionadas (incluyendo pgBackRest, pgAudit, extensiones de contrib y m\u00e1s).<\/li>\n<\/ul>\n<p>\nSin embargo, los intentos de comenzar a usar el operador de Crunchy Data revelaron varios problemas:<\/p>\n<ul>\n<li>No hab\u00eda posibilidad de toleraciones \u2014 solo se preve\u00eda nodeSelector.<\/li>\n<li>Los pods creados eran parte de un Deployment, a pesar de que est\u00e1bamos implementando una aplicaci\u00f3n stateful. A diferencia de StatefulSet, los Deployments no pueden crear discos.<\/li>\n<\/ul>\n<p>\nLa \u00faltima desventaja lleva a momentos peculiares: en el entorno de prueba logramos lanzar 3 r\u00e9plicas con un solo disco <i>almacenamiento local<\/i>, lo que hizo que el operador informara que 3 r\u00e9plicas estaban funcionando (aunque no era as\u00ed).<\/p>\n<p>Otra caracter\u00edstica de este operador es su integraci\u00f3n lista con varios sistemas auxiliares. Por ejemplo, es f\u00e1cil instalar pgAdmin y pgBounce, y en <noindex><a rel=\"nofollow\" href=\"https:\/\/access.crunchydata.com\/documentation\/postgres-operator\/4.4.0\/installation\/other\/ansible\/installing-metrics\/\">la documentaci\u00f3n<\/a><\/noindex> se consideran Grafana y Prometheus preconfigurados. En el reciente <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/postgres-operator\/releases\/tag\/v4.5.0-beta.1\">lanzamiento 4.5.0-beta1<\/a><\/noindex> se destaca una mejor integraci\u00f3n con el proyecto <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/pgmonitor\">pgMonitor<\/a><\/noindex>, gracias a lo cual el operador ofrece una visualizaci\u00f3n clara de m\u00e9tricas de PgSQL 'listo para usar'.<\/p>\n<p>Sin embargo, la extra\u00f1a elecci\u00f3n de recursos generados por Kubernetes nos llev\u00f3 a la necesidad de encontrar otra soluci\u00f3n.<\/p>\n<h3>3. Zalando Postgres Operator<\/h3>\n<p>\nConocemos los productos de Zalando desde hace tiempo: tenemos experiencia con Zalenium y, por supuesto, hemos probado <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/patroni\">Patroni<\/a><\/noindex> \u2014 su popular soluci\u00f3n HA para PostgreSQL. Acerca del enfoque de la empresa para crear <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\">Postgres Operator<\/a><\/noindex> habl\u00f3 uno de sus autores \u2014 Alexey Klyukin \u2014 en la transmisi\u00f3n <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/479438\/\">Postgres-Martes \u21165<\/a><\/noindex>, y nos gust\u00f3.<\/p>\n<p>Esta es la soluci\u00f3n m\u00e1s joven de las analizadas en el art\u00edculo: la primera versi\u00f3n se lanz\u00f3 en agosto de 2018. Sin embargo, a pesar de la peque\u00f1a cantidad de lanzamientos formales, el proyecto ha recorrido un largo camino, ya superando en popularidad a la soluci\u00f3n de Crunchy Data con m\u00e1s de 1300 estrellas en GitHub y el mayor n\u00famero de contribuyentes (m\u00e1s de 70).<\/p>\n<p>\u2018Bajo el cap\u00f3\u2019 de este operador se utilizan soluciones probadas por el tiempo:<\/p>\n<ul>\n<li> Patroni y <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/spilo\">Spilo<\/a><\/noindex> para la gesti\u00f3n,<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">WAL-E<\/a><\/noindex> \u2014 para copias de seguridad,<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgbouncer\/pgbouncer\">PgBouncer<\/a><\/noindex> \u2014 como un pool de conexiones.<\/li>\n<\/ul>\n<p>\nAs\u00ed es como se presenta la arquitectura del operador de Zalando:<\/p>\n<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/c66f10c1a818592ecaacd2db4ce5ace5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEl operador se gestiona completamente a trav\u00e9s de Custom Resources, creando autom\u00e1ticamente un StatefulSet a partir de contenedores que luego se pueden personalizar a\u00f1adiendo diversos sidecars al pod. Todo esto es una ventaja significativa en comparaci\u00f3n con el operador de Crunchy Data.<\/p>\n<p>Dado que elegimos la soluci\u00f3n de Zalando entre las 3 opciones consideradas, a continuaci\u00f3n se presentar\u00e1 una descripci\u00f3n de sus capacidades junto con ejemplos de uso.<\/p>\n<h2>Pr\u00e1ctica con el Postgres Operator de Zalando<\/h2>\n<p>\nEl despliegue del operador es muy sencillo: basta con descargar la versi\u00f3n actual desde GitHub y aplicar los archivos YAML de la carpeta. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/tree\/master\/manifests\">manifests<\/a><\/noindex>. Como alternativa, tambi\u00e9n se puede utilizar <noindex><a rel=\"nofollow\" href=\"https:\/\/operatorhub.io\/operator\/postgres-operator\">OperatorHub<\/a><\/noindex>.<\/p>\n<p>Despu\u00e9s de la instalaci\u00f3n, es importante preocuparse por la configuraci\u00f3n <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/reference\/operator_parameters.md#aws-or-gcp-interaction\">de los almacenes para logs y copias de seguridad.<\/a><\/noindex>. Se realiza a trav\u00e9s de ConfigMap <code>postgres-operator<\/code> en el espacio de nombres donde se instal\u00f3 el operador. Una vez que los almacenes est\u00e1n configurados, se puede desplegar el primer cl\u00faster de PostgreSQL.<\/p>\n<p>Por ejemplo, nuestro despliegue est\u00e1ndar se ve de la siguiente manera:<\/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>\nEste manifiesto despliega un cl\u00faster de 3 instancias con un sidecar en forma de <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wrouesnel\/postgres_exporter\">postgres_exporter<\/a><\/noindex>, desde el cual recopilamos m\u00e9tricas de la aplicaci\u00f3n. Como pueden ver, todo es muy simple, y si se desea, se puede crear literalmente un n\u00famero ilimitado de cl\u00fasteres.<\/p>\n<p>Tambi\u00e9n vale la pena prestar atenci\u00f3n a <b>la interfaz web para administraci\u00f3n<\/b> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/operator-ui.md\">postgres-operator-ui<\/a><\/noindex>. Se proporciona junto con el operador y permite crear y eliminar cl\u00fasteres, as\u00ed como gestionar las copias de seguridad que realiza el operador.<\/p>\n<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/2e9ae033a9817d101c843ce061aafdb5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Lista de cl\u00fasteres de PostgreSQL<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/74a65f7f301da14a0cb7bea6d5ef84ec.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Gesti\u00f3n de copias de seguridad<\/i><\/p>\n<p>Otra caracter\u00edstica interesante es el soporte para <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/user.md#teams-api-roles\">Teams API<\/a><\/noindex>. Este mecanismo crea autom\u00e1ticamente <b>roles en PostgreSQL<\/b>, bas\u00e1ndose en la lista de nombres de usuarios recibida. Despu\u00e9s de esto, la API permite devolver la lista de usuarios para quienes se crean roles autom\u00e1ticamente.<\/p>\n<h3>Problemas y sus soluciones<\/h3>\n<p>\nSin embargo, el uso del operador pronto revel\u00f3 varias desventajas significativas:<\/p>\n<ol>\n<li> falta de soporte para nodeSelector.<\/li>\n<li> imposibilidad de desactivar las copias de seguridad;<\/li>\n<li> al utilizar la funci\u00f3n de creaci\u00f3n de bases no aparecen privilegios por defecto;<\/li>\n<li> peri\u00f3dicamente falta documentaci\u00f3n o esta se encuentra desactualizada.<\/li>\n<\/ol>\n<p>\nAfortunadamente, muchos de estos problemas pueden resolverse. Comencemos por el final: problemas con <strong>documentaci\u00f3n<\/strong>. <\/p>\n<p>Es probable que te enfrentes a que no siempre est\u00e1 claro c\u00f3mo definir la copia de seguridad y c\u00f3mo conectar el bucket de respaldo a la interfaz de usuario de Operator. Esto se menciona de manera superficial en la documentaci\u00f3n, y la descripci\u00f3n real se encuentra en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/481\">PR<\/a><\/noindex>:<\/p>\n<ol>\n<li>hay que crear un secreto;<\/li>\n<li>para pas\u00e1rselo al operador como un par\u00e1metro <code>pod_environment_secret_name<\/code> en la CRD con la configuraci\u00f3n del operador o en ConfigMap (dependiendo de c\u00f3mo decidieras instalar el operador).<\/li>\n<\/ol>\n<p>\nSin embargo, como result\u00f3 ser, en este momento es imposible. Es por eso que hemos reunido <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/postgres-operator\">nuestra versi\u00f3n del operador<\/a><\/noindex> con algunos desarrollos adicionales de terceros. M\u00e1s detalles sobre ello \u2014 ver abajo.<\/p>\n<p>Si se le pasan al operador par\u00e1metros para la copia de seguridad, concretamente \u2014 <code>wal_s3_bucket<\/code> y las claves de acceso en AWS S3, entonces \u00e9l <strong>realizar\u00e1 copias de seguridad de todo<\/strong>: no solo las bases en producci\u00f3n, sino tambi\u00e9n las de staging. Eso no nos satisfizo.<\/p>\n<p>En la descripci\u00f3n de los par\u00e1metros para Spilo, que es la envoltura b\u00e1sica de Docker para PgSQL al usar el operador, se descubri\u00f3: se puede pasar el par\u00e1metro <code>WAL_S3_BUCKET<\/code> vac\u00edo, desactivando as\u00ed las copias de seguridad. Adem\u00e1s, para nuestra gran alegr\u00eda, tambi\u00e9n se encontr\u00f3 un <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/908\">PR listo<\/a><\/noindex>, que de inmediato aceptamos en nuestro fork. Ahora solo es necesario agregar <code>enableWALArchiving: false<\/code> al recurso del cl\u00faster de PostgreSQL.<\/p>\n<p>S\u00ed, hab\u00eda la opci\u00f3n de hacerlo de otra manera, ejecutando 2 operadores: uno para staging (sin copias de seguridad) y el otro \u2014 para producci\u00f3n. Pero as\u00ed pudimos manejarlo con uno solo.<\/p>\n<p>Est\u00e1 bien, aprendimos a dar acceso a las bases para S3 y las copias de seguridad empezaron a llegar al almacenamiento. \u00bfC\u00f3mo hacer que las p\u00e1ginas de copias de seguridad funcionen en la interfaz de usuario de Operator?<\/p>\n<p><img decoding=\"async\" alt=\"Breve rese\u00f1a de operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia\" src=\"\/wp-content\/uploads\/2020\/09\/46169b53707b0bbb686798c655022f40.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEn la interfaz de usuario de Operator ser\u00e1 necesario agregar 3 variables:<\/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>\nDespu\u00e9s de esto, la gesti\u00f3n de copias de seguridad estar\u00e1 disponible, lo que en nuestro caso simplificar\u00e1 el trabajo con staging, permitiendo entregar all\u00ed instant\u00e1neas de producci\u00f3n sin scripts adicionales.<\/p>\n<p>Como otra ventaja se mencion\u00f3 el trabajo con la API de Teams y amplias posibilidades para crear bases y roles mediante el operador. Sin embargo, los roles creados <strong>no ten\u00edan derechos por defecto<\/strong>. En consecuencia, un usuario con derechos de lectura no pod\u00eda leer nuevas tablas.<\/p>\n<p>\u00bfPor qu\u00e9 es as\u00ed? A pesar de que en el c\u00f3digo <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/pkg\/cluster\/database.go#L42\">hay<\/a><\/noindex> son necesarios <code>GRANT<\/code>, no se aplican siempre. Hay 2 m\u00e9todos: <code>syncPreparedDatabases<\/code> y <code>syncDatabases<\/code>. Hay <code>syncPreparedDatabases<\/code> \u2014 a pesar de que en la secci\u00f3n <code>preparedDatabases<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/manifests\/complete-postgres-manifest.yaml#L26\">hay<\/a><\/noindex> hay una condici\u00f3n <code>defaultRoles<\/code> y <code>defaultUsers<\/code> para la creaci\u00f3n de roles, \u2014 los permisos por defecto no se aplican. Estamos en proceso de preparar un parche para que estos permisos se apliquen autom\u00e1ticamente.<\/p>\n<p>Y el \u00faltimo punto en las mejoras relevantes para nosotros es <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/975\">parche<\/a><\/noindex>, que a\u00f1ade Node Affinity al StatefulSet creado. Nuestros clientes a menudo prefieren reducir costos utilizando instancias spot, y no deber\u00edamos alojar servicios de base de datos en ellas. Este problema se podr\u00eda resolver tambi\u00e9n mediante tolerancias, pero la presencia de Node Affinity aporta una mayor certeza.<\/p>\n<h3>\u00bfQu\u00e9 se ha logrado?<\/h3>\n<p>\nComo resultado de la soluci\u00f3n a los problemas mencionados, hemos bifurcado el Postgres Operator de Zalando en <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/postgres-operator\">nuestro repositorio<\/a><\/noindex>, donde se compila con parches tan \u00fatiles. Y para mayor comodidad, hemos recopilado <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/flant\/postgres-operator\">imagen de Docker<\/a><\/noindex>.<\/p>\n<p>La lista de PR aceptados en la bifurcaci\u00f3n:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/1066\">la construcci\u00f3n de una imagen ligera y segura para el operador en Docker<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/908\">la desactivaci\u00f3n de copias de seguridad<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/1121\">la actualizaci\u00f3n de versiones de recursos para las versiones actuales de k8s<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/975\">la implementaci\u00f3n de Node Affinity<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\nSer\u00eda genial si la comunidad apoyara estos PR para que ingresen upstream con la pr\u00f3xima versi\u00f3n del operador (1.6).<\/p>\n<h2>\u00a1Bonus! Historia de \u00e9xito con la migraci\u00f3n de producci\u00f3n<\/h2>\n<p>\nSi usas Patroni, puedes migrar producci\u00f3n viva al operador con un tiempo de inactividad m\u00ednimo.<\/p>\n<p>Spilo permite crear cl\u00fasteres en standby a trav\u00e9s de almacenamiento S3 con <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">Wal-E<\/a><\/noindex>, cuando el registro binario de PgSQL se guarda primero en S3 y luego se descarga por la r\u00e9plica. Pero, \u00bfqu\u00e9 hacer si tienes <i>no<\/i> Wal-E en una infraestructura antigua? La soluci\u00f3n a este problema ya <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/true_engineering\/blog\/437318\/\">ha sido propuesta<\/a><\/noindex> en Habr.<\/p>\n<p>La replicaci\u00f3n l\u00f3gica de PostgreSQL viene al rescate. Sin embargo, no entraremos en detalles sobre c\u00f3mo crear publicaciones y suscripciones, porque\u2026 nuestro plan fracas\u00f3.<\/p>\n<p>El hecho es que hab\u00eda varias tablas con alta carga en la base de datos con millones de filas, que adem\u00e1s, estaban siendo constantemente actualizadas y eliminadas. <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/12\/sql-createsubscription\">Una simple suscripci\u00f3n<\/a><\/noindex> con <code>copy_data<\/code>, cuando una nueva r\u00e9plica copia todo el contenido del maestro, simplemente no pod\u00eda mantenerse al d\u00eda con el maestro. La copia del contenido funcion\u00f3 durante una semana, pero no alcanz\u00f3 al maestro. Al final, resolver el problema fue posible gracias a <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/avitotech\/recovery-use-cases-for-logical-replication-in-postgresql-10-a1e6bab03072\">Windows<\/a><\/noindex> compa\u00f1eros de Avito: se puede transferir datos utilizando <code>pg_dump<\/code>. Voy a describir nuestra (ligeramente modificada) variante de este algoritmo.<\/p>\n<p>La idea es crear una suscripci\u00f3n inactiva vinculada a un slot de replicaci\u00f3n espec\u00edfico y luego corregir el n\u00famero de transacci\u00f3n. Hubo r\u00e9plicas disponibles para el trabajo de producci\u00f3n. Esto es importante porque la r\u00e9plica ayudar\u00e1 a crear un volcado consistente y continuar recibiendo cambios del maestro.<\/p>\n<p>En los siguientes comandos que describen el proceso de migraci\u00f3n, se utilizar\u00e1n las siguientes designaciones para los hosts:<\/p>\n<ol>\n<li><i>master<\/i> \u2014 servidor de origen;<\/li>\n<li><i>replica1<\/i> \u2014 r\u00e9plica en flujo en la antigua producci\u00f3n;<\/li>\n<li><i>replica2<\/i> \u2014 nueva r\u00e9plica l\u00f3gica.<\/li>\n<\/ol>\n<p><\/p>\n<h3>Plan de migraci\u00f3n<\/h3>\n<p>\n1. Crearemos en el maestro una suscripci\u00f3n para todas las tablas en el esquema <code>public<\/code> de la base de datos. <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. Crearemos un slot de replicaci\u00f3n en el maestro:<\/p>\n<pre><code class=\"bash\">psql -h master -c \"select pg_create_logical_replication_slot('repl', 'pgoutput');\"\n<\/code><\/pre>\n<p>\n3. Detendremos la replicaci\u00f3n en la antigua r\u00e9plica:<\/p>\n<pre><code class=\"bash\">psql -h replica1 -c \"select pg_wal_replay_pause();\"\n<\/code><\/pre>\n<p>\n4. Obtendremos el n\u00famero de transacci\u00f3n desde el maestro:<\/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. Haremos un volcado desde la antigua r\u00e9plica. Haremos esto en varios hilos, lo que ayudar\u00e1 a acelerar el proceso:<\/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. Cargaremos el volcado en el nuevo servidor:<\/p>\n<pre><code class=\"bash\">pg_restore -h replica2 -F d -j 8 -d dbname dump\/\n<\/code><\/pre>\n<p>\n7. Despu\u00e9s de cargar el volcado, se puede iniciar la replicaci\u00f3n en la r\u00e9plica en flujo:<\/p>\n<pre><code class=\"bash\">psql -h replica1 -c \"select pg_wal_replay_resume();\"\n<\/code><\/pre>\n<p>\n7. Creamos la suscripci\u00f3n en la nueva r\u00e9plica l\u00f3gica:<\/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. Obtendremos <code>oid<\/code> la suscripci\u00f3n:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c \"select oid, * from pg_subscription;\"\n<\/code><\/pre>\n<p>\n9. Supongamos que se obtuvo <code>oid=1000<\/code>. Aplicaremos el n\u00famero de transacci\u00f3n a la suscripci\u00f3n:<\/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. Iniciaremos la replicaci\u00f3n:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c \"alter subscription oldprod enable;\"\n<\/code><\/pre>\n<p>\n11. Comprobaremos el estado de la suscripci\u00f3n, la replicaci\u00f3n deber\u00eda estar funcionando:<\/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. Despu\u00e9s de que la replicaci\u00f3n est\u00e9 en marcha y las bases est\u00e9n sincronizadas, se puede realizar el cambio.<\/p>\n<p>13. Despu\u00e9s de deshabilitar la replicaci\u00f3n, ser\u00e1 necesario corregir las secuencias. Esto est\u00e1 bien descrito <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Fixing_Sequences\">en el art\u00edculo de wiki.postgresql.org.<\/a><\/noindex>.<\/p>\n<p>Gracias a este plan, el cambio se realiz\u00f3 con m\u00ednimas demoras.<\/p>\n<h2>Conclusi\u00f3n<\/h2>\n<p>\nLos operadores de Kubernetes permiten simplificar diversas acciones, reduci\u00e9ndolas a la creaci\u00f3n de recursos de K8s. Sin embargo, tras lograr una asombrosa automatizaci\u00f3n mediante su uso, es importante recordar que puede acarrear una serie de matices inesperados, as\u00ed que elige tus operadores sabiamente.<\/p>\n<p>Tras considerar los tres operadores de Kubernetes m\u00e1s populares para PostgreSQL, decidimos optar por el proyecto de Zalando. Tuvimos que enfrentar ciertas dificultades, pero el resultado realmente nos satisfizo, por lo que planeamos expandir esta experiencia a otras instalaciones de PgSQL. Si tienes experiencia con soluciones similares, estaremos encantados de ver los detalles en los comentarios.<\/p>\n<h2>P.D.<\/h2>\n<p>\nTambi\u00e9n puedes leer en nuestro blog:<\/p>\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">Bases de datos y Kubernetes (rese\u00f1a y video de la presentaci\u00f3n)<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/479438\/\">Martes de Postgres N\u00ba 5: PostgreSQL y Kubernetes. CI\/CD. Automatizaci\u00f3n de pruebas<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/480722\/\">Una historia con el operador Redis en K8s y un mini-resumen de las herramientas para analizar datos de esta base de datos<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<p>Fuente: <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.2 - 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\/es\/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.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\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\/es\/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\udd47 Breve rese\u00f1a de los operadores de PostgreSQL para Kubernetes, nuestra selecci\u00f3n y experiencia | ProHoster","description":"Cada vez m\u00e1s por parte de los clientes.","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/95322","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=95322"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/95322\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media\/95323"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=95322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=95322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=95322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}