Setting up PostgreSQL Server in Docker Container on Ubuntu: A Step-by-Step Guide
Introduction
Setting up a PostgreSQL server within a Docker container may seem daunting, but it’s an efficient way to ensure your database environment is portable, consistent, and easily replicable. Welcome to our step-by-step guide designed for Ubuntu users, from novices to seasoned system administrators. Whether you’re looking to streamline your development process, deploy applications faster, or simply learn about containerization, you’re in the right place.
By following this guide, you’ll learn how to deploy a PostgreSQL server using Docker, configure it for secure remote access, and manage logs effectively. We’ll walk you through creating a dedicated user, thus minimizing risks and promoting good security practices right from the start.
Prerequisites
Before we dive in, ensure you have Docker and Docker Compose installed on your Ubuntu machine. If you’re unsure how to do that, check out the official Docker documentation for installation instructions.
Step 1: Define Your Docker-Compose Configuration
We will use docker-compose
to manage our PostgreSQL container. The configuration below defines the setup for our PostgreSQL server.
version: '3.8'
services:
postgres:
container_name: postgres_container
image: postgres:16
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-defaultpassword}
PGDATA: /var/lib/postgresql/data
volumes:
- ./data:/var/lib/postgresql/data
- ./logs:/var/log/postgresql
- ./postgresql.conf:/etc/postgresql/postgresql.conf
- ./pg_hba.conf:/etc/postgresql/pg_hba.conf
ports:
- "5432:5432"
restart: unless-stopped
command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf",
"-c", "hba_file=/etc/postgresql/pg_hba.conf",]
volumes:
data:
driver: local
logs:
driver: local
Explanation:
version
: Specifies the version of the Compose file format.container_name
: Assign a custom name for easier identification.image
: The PostgreSQL image version to use.environment
: Defines environment variables for the container.volumes
: Maps directories between the host and container for data persistence and log storage.ports
: Exposes PostgreSQL default port to the host.restart
: Ensures the container restarts unless manually stopped.command
: Instructs PostgreSQL to use our custom configuration file.
Save this as docker-compose.yml
in your project directory.
Explanation of the key configurations
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-defaultpassword}
PGDATA: /var/lib/postgresql/data
environment: Sets environment variables inside the container. POSTGRES_USER
and POSTGRES_PASSWORD
are credentials for the default PostgreSQL user. If not provided, they default to postgres
and defaultpassword
. PGDATA
sets the location where the PostgreSQL data files will reside inside the container.
volumes:
- ./data:/var/lib/postgresql/data
- ./logs:/var/log/postgresql
- ./postgresql.conf:/etc/postgresql/postgresql.conf
- ./pg_hba.conf:/etc/postgresql/pg_hba.conf
volumes: These lines mount directories from the host to the container. It creates a persistent storage for data (./data
), a place for logs (./logs
), and mounts custom configuration files (postgresql.conf
and pg_hba.conf
) from the host to the appropriate locations in the container.
command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]
command: Overrides the default command run by the container. It starts PostgreSQL with a specific configuration file.
tep 2: Configure PostgreSQL
Now let’s set up the postgresql.conf
and pg_hba.conf
files.
PostgreSQL Configuration (postgresql.conf
)
logging_collector = on
log_directory = '/var/log/postgresql'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_statement = 'ddl'
log_min_messages = 'info'
log_min_error_statement = 'info'
log_min_duration_statement = 0
log_line_prefix = '%m [%p]: [%l-1] user=%u,db=%d ' # Time, process ID, line number, username, and database name.
listen_addresses = '*'
This configuration enables logging and specifies the log directory and file format.
Client Authentication Configuration (pg_hba.conf
)
# TYPE DATABASE USER ADDRESS METHOD
host all all 0.0.0.0/0 md5
This file configures which hosts are allowed to connect, which databases they can access, and which authentication method is required.
The Intricacies of PostgreSQL Configuration
The postgresql.conf
file contains settings that control the behavior of the PostgreSQL server.
logging_collector = on
logging_collector: This enables the collection of log files, which are essential for diagnosing issues and auditing access.
log_directory = '/var/log/postgresql'
log_directory: Specifies the directory where log files will be stored. It is set to the directory we mounted in our Docker volume.
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_filename: Defines the naming pattern for log files, which includes the date and time, making it easier to navigate through historical data.
log_statement = 'ddl'
log_statement: Determines which SQL statements are logged. ddl
logs all data definition commands like CREATE, ALTER, and DROP.
log_min_messages = 'info'
log_min_messages: Sets the minimum level of messages to log. info
ensures we log all informational messages, which is useful for troubleshooting.
log_min_error_statement = 'info'
log_min_error_statement: Similar to log_min_messages
, but for error statements. It ensures that
all error information is captured in the logs.
log_min_duration_statement = 0
log_min_duration_statement: All SQL statements that run are logged along with their duration, set to 0
to log every statement regardless of duration.
log_line_prefix = '%m [%p]: [%l-1] user=%u,db=%d '
log_line_prefix: This is a format string that is output at the beginning of each log line, %m
for time, %p
for process ID, %l
for line number, %u
for user, and %d
for database.
listen_addresses = '*'
listen_addresses: Configures the server to listen on all available IP addresses, which is necessary for accepting connections from the internet.
Network Security with pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
host all all 0.0.0.0/0 md5
This line in the pg_hba.conf
file determines who can connect, to which database, from where, and which authentication method is used. md5
requires a password for connections.
Step 2: Creating and Managing PostgreSQL Roles and Permissions
Next, let’s establish a secure user role and its permissions. It’s a best practice to avoid using the superuser role for application connections because of the extensive privileges it carries. Instead, we create a specific role with more limited permissions for everyday use.
Creating a Database
To create a new database:
CREATE DATABASE bettertrack;
This command creates a new database named bettertrack
. The name should be meaningful to your environment or project.
Switching Databases
To switch to your new database, use the command:
\c bettertrack;
The \c
command followed by the database name changes the current database context to bettertrack
.
Creating a Role for the Environment
Now, create a role with login permissions and a password:
CREATE ROLE stage LOGIN PASSWORD 'strongpassword';
Here’s the breakdown:
- CREATE ROLE: This statement is used to create a new role in PostgreSQL.
- stage: This is the name of the role. Ideally, it should be relevant to the environment it’s meant for, like
stage
,dev
, orprod
. - LOGIN: This clause allows the role to log in, which is essential for a user that needs to connect to the database.
- PASSWORD: Specifies the password for the role. It’s crucial to use a strong, ideally generated, password here for security reasons.
Granting Permissions to the Role
Once the role is created, grant it the necessary permissions on the database:
GRANT CONNECT ON DATABASE bettertrack TO stage;
GRANT USAGE ON SCHEMA public TO stage;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO stage;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO stage;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO stage;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE ON SEQUENCES TO stage;
GRANT CREATE ON SCHEMA public TO stage;
Here is what each command accomplishes:
- GRANT CONNECT: Allows the
stage
role to connect to thebettertrack
database. - GRANT USAGE ON SCHEMA public: Permits the
stage
role to access thepublic
schema, which is the default schema for most operations. - GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES: Gives the
stage
role permission to read, create, modify, and delete records in all tables within thepublic
schema. - ALTER DEFAULT PRIVILEGES: Ensures that any future tables created within the
public
schema will automatically grant the specified privileges to thestage
role. - GRANT USAGE ON ALL SEQUENCES: Allows the
stage
role to use all sequences. Sequences are often used for generating unique identifiers for table rows. - GRANT CREATE ON SCHEMA public: Gives the
stage
role the ability to create new tables or other objects within thepublic
schema.
Connecting to the Database Using the New User
Finally, to test the connection to the bettertrack
database using the new stage
role:
psql -h localhost -U stage -d bettertrack -W
You will be prompted to enter the password for the stage
user. Ensure that this is done on a secure machine, as the password will grant access to the database.
Securing Your Setup
Security should be at the forefront when configuring any database accessible from the internet. Make sure to:
- Keep your PostgreSQL and Docker software up to date with security patches.
- Use strong, unique passwords for all database roles.
- Regularly review your
pg_hba.conf
file to ensure that only intended clients can connect. - Monitor your logs to detect unauthorized access attempts.
Practical Examples: Real-World Applications of PostgreSQL within Docker
Development and Testing Environments: Developers often require isolated environments to test new features or updates without affecting the main codebase. Docker containers with PostgreSQL can be spun up quickly, offering a consistent database environment that closely mirrors production. For instance, a developer working on a new application feature that requires database changes can use Docker to create a temporary, isolated test database to experiment without risking the stability of the production database.
In Summary: Deployment Workflow: PostgreSQL on Docker in Ubuntu
By now, you have not only set up PostgreSQL on Docker, but you have also learned the ins and outs of each configuration step. You’ve taken the extra step to secure your database connections and ensure that your logs keep you informed of the database’s health and access patterns.
Feel empowered to explore further configurations that align with your project needs, and remember, every step you take towards mastering containerization and database management is a stride towards a more robust and scalable architecture.
Keep exploring, keep learning, and may your data always be well-structured and your connections secure!