PostgreSQL: Get Started
PostgreSQL is a very popular open-source relational database management system (RDBMS), known for its extensibility and feature-rich capabilities, making it suitable for mission-critical applications. Not to mention its active PostgreSQL community.
In the upcoming posts, I will start a series of PostgreSQL studies to:
- Explore PostgreSQL main features, installation, and basic administration tasks.
- Deploy a PostgreSQL cluster onto K8S with PostgreSQL Operator, validate backup and rolling upgrades.
- Create a simple Flash microservice application to connect to the PostgreSQL cluster and validate failover.
- Integrate the whole deployment into a CICD pipeline for automation.
- Create AWS RDS PostgreSQL, with S3 Block storage as a replica.
By the end of the series, we should be able to have a comprehensive understanding of PostgreSQL from a DevOps perspective.
PostgreSQL Basic
To begin, we will:
- Install PostgreSQL as a docker container on a local Ubuntu machine to get it up and running.
# ubuntu install docker root@ubt-server:~# curl -fsSL https://get.docker.com -o get-docker.sh root@ubt-server:~# sh get-docker.sh root@ubt-server:~# docker --version root@ubt-server:~# systemctl enable docker # install PostgreSQL 15.0 root@ubt-server:~# docker run --name zack-postgres -e POSTGRES_PASSWORD=password -d postgres:15.0 root@ubt-server:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b4fc638dfde3 postgres:15.0 "docker-entrypoint.sā¦" 7 seconds ago Up 6 seconds 5432/tcp zack-postgres
- Run a simple PostgreSQL database with Docker Compose
# create docker-compose.yaml and run postgres and adminer from docker-compose
root@ubt-server:~# vim docker-compose.yaml
version: '3.1'
services:
db:
image: postgres:15.0
restart: always
environment:
POSTGRES_PASSWORD: password
ports:
- 5000:5432
adminer:
image: adminer
restart: always
ports:
- 8080:8080
# run docker compose
root@ubt-server:~# docker compose up
- Validate from the Adminer web console localhost:8080 with the password set in the environment variables
- Persist data to mount the PostgreSQL container volume, validate data table after start/stop container. PostgreSQL stores its data by default under /var/lib/postgresql/data. Here, we create a /pgdata folder on the local machine to mount PostgreSQL's default volume.
# create local Persist data directory /pgdata
root@ubt-server:~# mkdir pgdata
# run PostgreSQL to mount local Persist data and Bind a different port
root@ubt-server:~# docker run -d -it --rm --name zack-postgres2 -e POSTGRES_PASSWORD=password -v ${PWD}/pgdata:/var/lib/postgresql/data -p 5000:5432 postgres:15.0
PostgreSQL Database directory appears to contain a database; Skipping initialization
2024-01-08 00:58:47.540 UTC [1] LOG: starting PostgreSQL 15.0 (Debian 15.0-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
2024-01-08 00:58:47.541 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
2024-01-08 00:58:47.541 UTC [1] LOG: listening on IPv6 address "::", port 5432
2024-01-08 00:58:47.542 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2024-01-08 00:58:47.545 UTC [28] LOG: database system was shut down at 2024-01-08 00:57:45 UTC
2024-01-08 00:58:47.547 UTC [1] LOG: database system is ready to accept connections
- Connect to DB container and validate
# enter the container
root@ubt-server:~# docker exec -it zack-postgres2 bash
# login to postgres
root@d7386c566872:/# psql -h localhost -U postgres
psql (15.0 (Debian 15.0-1.pgdg110+1))
Type "help" for help.
# create a table
postgres=# CREATE TABLE customers (firstname text,lastname text, customer_id serial);
CREATE TABLE
# add record
postgres=# INSERT INTO customers (firstname, lastname) VALUES ( 'Bob', 'Smith');
INSERT 0 1
# show table
postgres=# \dt
List of relations
Schema | Name | Type | Owner
--------+-----------+-------+----------
public | customers | table | postgres
(1 row)
# get records
postgres=# SELECT * FROM customers;
firstname | lastname | customer_id
-----------+----------+-------------
Bob | Smith | 1
(1 row)
# quit
postgres=# \q
# exit db container
root@d7386c566872:/# exit
exit
- Add persist data in Docker Compose and run PostgreSQL from compose
# add persist data folder in compose yaml
root@ubt-server:~# vim docker-compose.yaml
version: '3.1'
services:
db:
image: postgres:15.0
restart: always
environment:
POSTGRES_PASSWORD: admin123
ports:
- 5000:5432
volumes:
- ./pgdata:/var/lib/postgresql/data
adminer:
image: adminer
restart: always
ports:
- 8080:8080
root@ubt-server:~# docker compose up
- Validate the previous table and record from the Adminer console. Table and record still there because of the persistent data mount.
PostgreSQL Configuration
Before jumping into replication, it is more important to explore the PostgreSQL configuration files to have a better understanding of its important config, take the default conf files out of a running database and learn them. Then, mount these conf files into the container, telling PostgreSQL to use our own configuration files to perform our preferred way.
To achieve this, we need the db user "postgres" to have an ID of 999 with access to custom conf files.
root@ubt-server:~/pgdata# chown 999:999 config/postgresql.conf root@ubt-server:~/pgdata# chown 999:999 config/pg_hba.conf root@ubt-server:~/pgdata# chown 999:999 config/pg_ident.conf root@ubt-server:~/pgdata# ll *.conf -rw------- 1 lxd docker 4821 May 8 00:30 pg_hba.conf -rw------- 1 lxd docker 1636 May 8 00:30 pg_ident.conf -rw------- 1 lxd docker 88 May 8 00:30 postgresql.auto.conf -rw------- 1 lxd docker 29525 May 8 00:30 postgresql.conf root@ubt-server:~# mkdir config root@ubt-server:~# cd config/ root@ubt-server:~# cp *.conf /config root@ubt-server:~/pgdata# chown 999:999 config/postgresql.conf root@ubt-server:~/pgdata# chown 999:999 config/pg_hba.conf root@ubt-server:~/pgdata# chown 999:999 config/pg_ident.conf
The official PostgreSQL documentation explains those configuration files as below:
- pg_hba.conf:
This file stands for "PostgreSQL Host-Based Authentication." It controls client authentication based on the host and user information. It specifies which hosts are allowed to connect to the PostgreSQL server, which databases and users they can access, and what authentication methods they must use. It's a crucial security measure for controlling access to the PostgreSQL server.
- pg_ident.conf:
This file, "PostgreSQL Identification Mapping," allows defining mappings between external (e.g., operating system) and internal (PostgreSQL) user names.
- postgresql.conf: Main configuration file for PostgreSQL which contains global settings to tailor its behavior to specific requirements and environment.
Create custom config file
Now we can adjust the command by adding environment variables to run PostgreSQL from Docker and Docker Compose using our custom conf files.
root@ubt-server:~# vim docker-compose.yaml
version: '3.1'
services:
db:
container_name: postgres
image: postgres:15.0
# important: passing argument to postgres container to tell where conf file is located, to match the custom conf file we created before when DB initiated
command: "postgres -c config_file=/config/postgresql.conf"
environment:
POSTGRES_USER: "postgresadmin"
POSTGRES_PASSWORD: "admin123"
POSTGRES_DB: "postgresdb"
PGDATA: "/data"
volumes:
- ./pgdata:/data
- ./config:/config/
ports:
- 5000:5432
adminer:
image: adminer
restart: always
ports:
- 8080:8080
root@ubt-server:~# docker run -it --rm --name postgres -e POSTGRES_USER=postgresadmin -e POSTGRES_PASSWORD=admin123 -e POSTGRES_DB=postgresdb -e PGDATA="/data" -v ${PWD}/pgdata:/data -v ${PWD}/config:/config -p 5000:5432 postgres:15.0 -c 'config_file=/config/postgresql.conf'
PostgreSQL Database directory appears to contain a database; Skipping initialization
2024-01-10 10:40:44.685 UTC [1] LOG: starting PostgreSQL 15.0 (Debian 15.0-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
2024-01-10 10:40:44.685 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
2024-01-10 10:40:44.685 UTC [1] LOG: listening on IPv6 address "::", port 5432
2024-01-10 10:40:44.685 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2024-01-10 10:40:44.688 UTC [28] LOG: database system was shut down at 2024-01-10 10:30:42 UTC
2024-01-10 10:40:44.690 UTC [1] LOG: database system is ready to accept connections
root@ubt-server:~# docker compose up -d
WARN[0000] /root/docker-compose.yaml: `version` is obsolete
[+] Running 2/2
ā Container postgres Started 0.4s
ā Container root-adminer-1 Started
Conclusion
Now we can run a PostgreSQL container from Docker and Docker Compose with persistent data and custom configuration mounted into the container. In the next blog, we will discover primary and standby replication, WAL (write-ahead log) options.