Notas Mentales de Un SysAdmin

blog sobre tecnologías para sysadmin y devops

postgresql

Chuleta de PSQL

Aunque te hayas pegado a menudo con una base de datos postgresql, normalmente, se tocan de uvas a peras. Es difícil acordarse de todo, y por ello, hoy os dejo mi chuleta personal cuando no me acuerdo de algo.

Ficheros de configuración

/var/lib/postgresql/11/main'		# use data in another directory
/etc/postgresql/11/main/postgresql.conf' #default conf file
/etc/postgresql/11/main/pg_hba.conf'	# host-based authentication file

Conectarse desde cliente psql

Para hacer login en la BD postgres, utilizaremos la siguiente sintaxis:

psql -h [HOST] -U [user] [BD]

Ejemplo:

psql -h localhost -U user_name db_name

Visualizar ROLES

\du

Resultado:

                                Lista de roles
  Nombre de rol  |                   Atributos                    | Miembro de
-----------------+------------------------------------------------+------------
 postgres        | Superusuario, Crear rol, Crear BD, Replicación | {}
 xxxxxxxxx       | Superusuario                                   | {}
 yyyyyyyyyyy     |                                                | {}

Crear un GRUPO

CREATE ROLE nombre [ [ WITH ] opción [ ... ] ]

Donde opción puede ser:

  SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| CREATEUSER | NOCREATEUSER
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| CONNECTION LIMIT límite_conexiones
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'contraseña'
| VALID UNTIL 'fecha_hora'
| IN ROLE nombre_de_rol [, ...]
| IN GROUP nombre_de_rol [, ...]
| ROLE nombre_de_rol [, ...]
| ADMIN nombre_de_rol [, ...]
| USER nombre_de_rol [, ...]
| SYSID uid

Ejemplo:

CREATE GROUP dev WITH LOGIN NOCREATEDB NOSUPERUSER NOCREATEROLE;

Dar permisos de conexión sobre una BD

GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
    ON DATABASE database_name [, ...]
    TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]

Para más info de GRANT sobre postgres, visitar:
Postgres GRANT

Ejemplo:

GRANT CONNECT ON DATABASE tellmegen TO dev;

Mostrar todos los SCHEMA disponibles

select schema_name from information_schema.schemata;

Resultado:

    schema_name
--------------------
 isisaudit
 isiscommand
 isissecurity
 isissessionlogger
 pg_toast
 pg_temp_1
 pg_toast_temp_1
 pg_catalog
 information_schema
 public

Dar permisos de SELECT, INSERT… sobre SCHEMA

GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
    [,...] | ALL [ PRIVILEGES ] }
    ON { [ TABLE ] table_name [, ...]
         | ALL TABLES IN SCHEMA schema_name [, ...] }
    TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]

Ejemplo:1

GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO dev;

Crear usuario y agregarlo a grupo

Utilizaremos la misma sintaxis que para crear un grupo. Ejemplo:

CREATE ROLE user_name WITH LOGIN NOCREATEDB NOSUPERUSER NOCREATEROLE CONNECTION LIMIT 1 PASSWORD 'password' IN GROUP dev;

Es interesante establecer CONNECTION LIMIT 1, para evitar suplantación de identidad del usuario

Cambiar de grupo al usuario

Eliminar usuario del grupo:

REVOKE user_name FROM group_name;

Modificar el fichero de conexión pg_hba.conf

Para permitir el acceso del usuario, hay que modificar el fichero pg_hba.conf. Esta configuración no funciona para usuarios, así que para permitir el acceso, habrá que añadir a cada usuario de manera individual.

/var/lib/pgsql/9.3/data/pg_hba.conf

o o para postgres11:

/etc/postgresql/11/main/pg_hba.conf

La sintaxis del fichero debe de llevar alguna de las siguientes formas:

# local      DATABASE  USER  METHOD  [OPTIONS]
# host       DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
# hostssl    DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
# hostnossl  DATABASE  USER  ADDRESS  METHOD  [OPTIONS]

Ejemplo para login local:

local database_name user_name peer

Ejemplo para login remoto / pgadmin:

host database_name user_name ip/32 trust

Reiniciar siempre el servicio de postgres para aplicar cambios:

service postgresql-9.3.service restart

Problema resuelto!

Snapshots periódicos de un PVC en GCP con Google SDK + Bash + CronJob

Pues ahí va la historia de este script:

Resulta que queremos mover una base de datos, la típica postgresql, de una maquina virtual a un pod de kubernetes. Hay muchos factores a tener en cuenta: Si se va a hacer subida de versión, como importar una copia de la base de datos, persistencia de discos… Aunque el que más me preocupaba era el disaster recovery.

Con una VM era sencillo. Script sacado de un blog de google y adaptado al entorno GCP, cambiando el almacenamiento local por un bucket de Storage. Pero claro, la mayoría de imágenes de postgresql vienen sobre alpine, que viene con las funcionalidades más que justas para que su consumo sea mínimo.

Se me ocurrieron un par de soluciones para abordar el problema:

  • Instalar cron en el archivo Dockerfile de la imagen. Importar también los scripts actuales de la VM a dicha imágen. En definitiva, emular la VM en el entorno GKE.
  • Levantar una imagen google/cloud-sdk, copiar un script .sh que trabajara con snapshots de Kubernetes y ejecutarlo desde un CronJob.

Al final, la que me pareció más adecuada fue la segunda. Y es que hace poco, intentando implementar ELK, descubrí «nuevos» tipos de carga de trabajo más allá de los deployments: Los CronJobs.

Un CronJob es un tipo de carga de trabajo que permite ejecutar trabajos en una programación basada en el tiempo. Estos trabajos automatizados se ejecutan como tareas Cron en un sistema Linux o UNIX.

Este tipo de carga de trabajo, junto a la potencia del SDK de Google, que permite trabajar con cuentas de servicio de permisos limitados, hacen posible que este script funcione. Eh aquí mis archivos «mágicos»:

Dockerfile

FROM google/cloud-sdk:latest

RUN mkdir /scripts

COPY ./[service-account-key].json /scripts
COPY ./snapshot_creation.sh /scripts

RUN chmod +x /scripts/snapshot_creation.sh

CMD tail -f /dev/null

Para poder utilizar GKE de forma desatendida, es necesario utilizar una cuenta de servicio. Os dejó aquí un enlace de como activar y empezar a usar una cuenta de servicio con GCP.

Script en Bash

#VAR definition
account_service_email="[account-service-email]"
account_service_json_dir="/scripts/.[service-account-key].json"
cluster_name="[cluster-name]"
cluster_zone="[cluster-zone]"
date=$(date +%Y%m%d-%H%M)
gcp_project_name="[gcp-project-name]"
pvc_name="pvc-[id]"
snapshot_name=$date-prod-psql-snapshot
snapshot_namespace="[kubernetes-namespace]"


#Create YAML
printf "apiVersion: snapshot.storage.k8s.io/v1beta1 \n" > snapshot.yaml
printf "kind: VolumeSnapshot \n" >> snapshot.yaml
printf "metadata: \n" >> snapshot.yaml
printf "  name: $snapshot_name \n" >> snapshot.yaml
printf "  namespace: $snapshot_namespace \n" >> snapshot.yaml
printf "spec: \n" >> snapshot.yaml
printf "  source: \n" >> snapshot.yaml
printf "    persistentVolumeClaimName: $pvc_name" >> snapshot.yaml

#Create snapshot
gcloud auth activate-service-account $account_service_email --key-file=$account_service_json_dir --project=$gcp_project_name
gcloud container clusters get-credentials $cluster_name --zone $cluster_zone --project $gcp_project_name
kubectl create -f snapshot.yaml --save-config

#Remove old versions
snapshot_count=`kubectl get volumesnapshot | grep prod-psql-snapshot | wc -l`
digest_array=(`kubectl get volumesnapshot | grep prod-psql-snapshot | awk '{print $1}'`)

if [ $snapshot_count -gt 14 ]
then
  oldest_snapshot=`echo ${digest_array[0]}`
  kubectl delete volumesnapshot $oldest_snapshot
fi

Lo que hago con este script es generar el YAML de un VolumeSnapshot, me autentico con la cuenta de servicio y creo ese snapshot. Para dejarlo todo limpio, cuento el número de copias al finalizar, y si pasan de 14, borro las últimas. Para más info acerca de como trabajar con los VolumeSnapshots en GCP, podéis consultarlo aquí.

CronJob

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: snapshot
spec:
  schedule: "01 0 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: backup
              image: gcr.io/[project-name]/[image_name]
              args:
                - /bin/sh
                - -c
                - sh /scripts/snapshot_creation.sh
          restartPolicy: Never

Y ya estaría! Problema resuelto!

Scroll hacia arriba