Skip to content

Commit a376195

Browse files
committed
simplify database creation using POSTGRES_DB env var and init script
Use POSTGRES_DB env var to create demo1 (the primary app database) and a slim docker_postgres_init.sql to create demo2, demonstrating both approaches. Update README to match current docker-compose.yml, fix stale version references, and correct file paths.
1 parent a1efb06 commit a376195

3 files changed

Lines changed: 90 additions & 106 deletions

File tree

README.md

Lines changed: 88 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
Steps to try out the sample.
66

77
* checkout the code
8-
* run postgres and pgAdmin using `docker-compose up`
9-
* Using a browser go to `localhost:15432` and explore the pgAdmin console. There should be two
8+
* run postgres and pgAdmin using `docker compose up`
9+
* Using a browser go to `localhost:15433` and explore the pgAdmin console. There should be two
1010
databases `demo1` and `demo2`. pgAdmin will not ask for any passwords.
11-
* run the spring boot sample application with `./mvnw spring-boot:run` you will need Java 11 JDK
12-
installed for this command to work. If you are only interested in the postgres docker-compose
11+
* run the spring boot sample application with `./mvnw spring-boot:run` you will need Java 25 JDK
12+
installed for this command to work. If you are only interested in the postgres docker-compose
1313
configuration you can skip this step.
1414

1515
Check out my blog [adibsaikali.com](https://adibsaikali.com) for a nice directory of other samples
@@ -59,14 +59,12 @@ We will break down the [docker-compose.yml](docker-compose.yml) into parts and
5959
each part works.
6060

6161
```yaml
62-
version: '3.8'
63-
6462
volumes:
6563
postgres:
6664
pgadmin:
6765
```
6866
69-
The above section defines standard docker-compose file version number, and it also defines
67+
The above section defines
7068
two volumes. The postgres volume will be used by the container running postgres, this means
7169
that the state of the postgres database will survive restarts of the container. Similarly,
7270
the `pgadmin` volume will be used by the pgAdmin container to store its configuration
@@ -80,94 +78,93 @@ docker-compose derives the network name from the directory name containing the
8078

8179
# Setting up the PostgresSQL Container
8280

83-
The `docker-compose.yml` contains a service named `postgres` defined below.
81+
The `docker-compose.yml` contains a service named `postgres` defined below.
8482

8583
```yml
8684
services:
8785
postgres:
8886
container_name: demo_postgres
89-
image: "postgres:15"
87+
image: "postgres:18"
9088
environment:
9189
POSTGRES_USER: "postgres"
9290
POSTGRES_PASSWORD: "password"
91+
POSTGRES_DB: "demo1"
9392
PGDATA: "/data/postgres"
9493
volumes:
95-
- postgres:/data/postgres
96-
- ./docker_postgres_init.sql:/docker-entrypoint-initdb.d/docker_postgres_init.sql
94+
- postgres:/data/postgres
95+
- ./db/docker_postgres_init.sql:/docker-entrypoint-initdb.d/docker_postgres_init.sql
9796
ports:
98-
- "15432:5432"
97+
- "${PG_PORT:-15432}:5432"
9998
restart: unless-stopped
10099
```
101-
In order to make the environment reproducible and predictable we explicitly set
102-
the postgres container version to `postgres:15` which will always give us the most recent
103-
bug fix release of postgres 12. Setting the container tag to `postgres:latest` or
104-
`postgres` will lead to unpredictability since we will get whatever is the latest version of
105-
postgres at the time we run `docker-compose up`.
100+
In order to make the environment reproducible and predictable we explicitly set
101+
the postgres container version to `postgres:18` which will always give us the most recent
102+
bug fix release of postgres 18. Setting the container tag to `postgres:latest` or
103+
`postgres` will lead to unpredictability since we will get whatever is the latest version of
104+
postgres at the time we run `docker compose up`.
106105

107106
To configure the administrative user for the database we set the `POSTGRES_USER` and
108-
`POSTGRES_PASSWORD` environment variables.
107+
`POSTGRES_PASSWORD` environment variables.
109108

110-
Postgres database files are stored in `/data/postgres`.
109+
Postgres database files are stored in `/data/postgres`.
111110
This directory is mapped to postgres volume via the mapping `postgres:/data/postgres`.
112111

113-
When the postgres container starts it looks for a file called `docker_postgres_init.sql`
114-
which will be executed during start up to configure the database. For example, in this repo we
115-
create two databases `demo1` and `demo2` using the DDL below.
116-
117-
```SQL
118-
CREATE DATABASE demo1
119-
WITH
120-
OWNER = postgres
121-
ENCODING = 'UTF8'
122-
LC_COLLATE = 'en_US.utf8'
123-
LC_CTYPE = 'en_US.utf8'
124-
TABLESPACE = pg_default
125-
CONNECTION LIMIT = -1;
126-
127-
CREATE DATABASE demo2
128-
WITH
129-
OWNER = postgres
130-
ENCODING = 'UTF8'
131-
LC_COLLATE = 'en_US.utf8'
132-
LC_CTYPE = 'en_US.utf8'
133-
TABLESPACE = pg_default
134-
CONNECTION LIMIT = -1;
135-
```
112+
## Creating Databases
113+
114+
The postgres Docker image provides two ways to create databases on first startup. This
115+
repo demonstrates both approaches.
136116

137-
The postgres container looks for the initialization sql file at the path
138-
`/docker-entrypoint-initdb.d/docker_postgres_init.sql`. To keep things
139-
simple we store our ddl in a file called `docker_postgres_init.sql` and put it
140-
at the same level as the `docker-compose.yml` as shown by the example directory
141-
listing below.
117+
### Using the `POSTGRES_DB` Environment Variable
142118

119+
The simplest way to create a database is to set the `POSTGRES_DB` environment variable.
120+
The postgres container will automatically create a database with this name on first startup.
121+
In this repo we use it to create the `demo1` database which is the primary database used
122+
by the Spring Boot application.
123+
124+
```yaml
125+
environment:
126+
POSTGRES_DB: "demo1"
143127
```
144-
-rw-r--r-- 1 adib staff 1.0K 2 Aug 20:37 docker-compose.yml
145-
-rw-r--r-- 1 adib staff 300B 2 Aug 17:04 docker_pgadmin_servers.json
146-
-rw-r--r-- 1 adib staff 375B 2 Aug 16:35 docker_postgres_init.sql
128+
129+
### Using Initialization Scripts
130+
131+
For additional databases beyond the one created by `POSTGRES_DB`, the postgres container
132+
will execute any `*.sql`, `*.sql.gz`, or `*.sh` scripts found in
133+
`/docker-entrypoint-initdb.d/` during first startup.
134+
135+
In this repo we use a SQL init script `db/docker_postgres_init.sql` to create a second
136+
database called `demo2`:
137+
138+
```sql
139+
CREATE DATABASE demo2;
147140
```
148141

149-
The init sql file is mapped to the place where the postgres container expects it to
150-
be via the volume mapping below.
142+
The init script is mounted into the container via a volume mapping:
151143

152144
```yaml
153145
volumes:
154-
- ./docker_postgres_init.sql:/docker-entrypoint-initdb.d/docker_postgres_init.sql
146+
- ./db/docker_postgres_init.sql:/docker-entrypoint-initdb.d/docker_postgres_init.sql
155147
```
156148

157-
In order to make the postgres database running inside the docker container accessible to
158-
applications on the workstation we map the default postgres port `5432` to
149+
**Note:** Initialization scripts are only run when the container starts with an empty data
150+
directory. If you need to re-run them, remove the postgres volume first with `./pg clean`.
151+
152+
## Port Mapping
153+
154+
In order to make the postgres database running inside the docker container accessible to
155+
applications on the workstation we map the default postgres port `5432` to
159156
`15432` as shown by the docker-compose configuration below.
160157

161158
```yaml
162159
ports:
163-
- "15432:5432"
160+
- "${PG_PORT:-15432}:5432"
164161
```
165162

166-
When a developer checks out the git repo with the application source code in it we want
167-
them to be able to run `docker-compose up` and have that work, this is why we expose
163+
When a developer checks out the git repo with the application source code in it we want
164+
them to be able to run `docker compose up` and have that work, this is why we expose
168165
port `15432` since the workstation might already have postgres installed and listening
169166
on the default port `5432`. Our hope is that port `15432` is available on the developer's
170-
workstation.
167+
workstation. The port can be customized using the `PG_PORT` environment variable.
171168

172169
For example the spring boot application included in this repo can connect to the postgres
173170
database using the `application.yml` configuration below
@@ -201,28 +198,30 @@ To set up the pgAdmin container we use the following service in the `docker-comp
201198

202199
```yaml
203200
pgadmin:
204-
container_name: demo_pgadmin
205-
image: "dpage/pgadmin4:4.24"
206-
environment:
207-
PGADMIN_DEFAULT_EMAIL: admin@example.com
208-
PGADMIN_DEFAULT_PASSWORD: admin
209-
PGADMIN_CONFIG_SERVER_MODE: "False"
210-
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False"
211-
volumes:
212-
- pgadmin:/var/lib/pgadmin
213-
- ./docker_pgadmin_servers.json:/pgadmin4/servers.json
214-
ports:
215-
- "15433:80"
216-
entrypoint:
217-
- "/bin/sh"
218-
- "-c"
219-
- "/bin/echo 'postgres:5432:*:postgres:password' > /tmp/pgpassfile && chmod 600 /tmp/pgpassfile && /entrypoint.sh"
220-
restart: unless-stopped
201+
container_name: demo_pgadmin
202+
labels:
203+
org.springframework.boot.ignore: true
204+
image: "dpage/pgadmin4:9.13"
205+
environment:
206+
PGADMIN_DEFAULT_EMAIL: "admin@example.com"
207+
PGADMIN_DEFAULT_PASSWORD: "admin"
208+
PGADMIN_CONFIG_SERVER_MODE: "False"
209+
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False"
210+
volumes:
211+
- pgadmin:/var/lib/pgadmin
212+
- ./db/docker_pgadmin_servers.json:/pgadmin4/servers.json
213+
ports:
214+
- "${PGADMIN_PORT:-15433}:80"
215+
entrypoint:
216+
- "/bin/sh"
217+
- "-c"
218+
- "/bin/echo 'postgres:5432:*:postgres:password' > /tmp/pgpassfile && chmod 600 /tmp/pgpassfile && /entrypoint.sh"
219+
restart: unless-stopped
221220
```
222221

223-
In order to have a repeatable build we use a specific version of the pgAdmin container
224-
`dpage/pgadmin4:4.24`. David Page is the lead developer and maintainer of pgAdmin so
225-
`dpage/pgadmin4:4.24` is a good container image to use.
222+
In order to have a repeatable build we use a specific version of the pgAdmin container
223+
`dpage/pgadmin4:9.13`. David Page is the lead developer and maintainer of pgAdmin so
224+
`dpage/pgadmin4` is a good container image to use.
226225

227226
pgAdmin can run in one of two modes desktop mode or server mode. When running in
228227
desktop mode pgAdmin assumes that it can only be reached from a developer's workstation
@@ -239,8 +238,8 @@ username and password using the environment variables below.
239238
240239
```yaml
241240
environment:
242-
PGADMIN_DEFAULT_EMAIL: admin
243-
PGADMIN_DEFAULT_PASSWORD: admin
241+
PGADMIN_DEFAULT_EMAIL: "admin@example.com"
242+
PGADMIN_DEFAULT_PASSWORD: "admin"
244243
```
245244
246245
pgAdmin is a generic console it can connect to multiple postgres servers. Therefore, it stores
@@ -276,8 +275,8 @@ details that pgAdmin will import into its configuration the first time it starts
276275
```
277276

278277
The pgAdmin container looks for connections file at `pgadmin4/servers.json` therefore
279-
we store the configuration file at `docker_pgadmin_servers.json` and map it into
280-
the pgAdmin container using the mapping `./docker_pgadmin_servers.json:/pgadmin4/servers.json`
278+
we store the configuration file at `db/docker_pgadmin_servers.json` and map it into
279+
the pgAdmin container using the mapping `./db/docker_pgadmin_servers.json:/pgadmin4/servers.json`
281280

282281
In order for pgAdmin to store it's state across container restarts we map the location
283282
it stores state `/var/lib/pgadmin` to the docker volume `pgadmin` as shown in the yaml
@@ -286,7 +285,7 @@ below.
286285
```yaml
287286
volumes:
288287
- pgadmin:/var/lib/pgadmin
289-
- ./docker_pgadmin_servers.json:/pgadmin4/servers.json
288+
- ./db/docker_pgadmin_servers.json:/pgadmin4/servers.json
290289
```
291290

292291
pgAdmin provides no mechanism to set passwords for the connections in `servers.json` since
@@ -371,15 +370,15 @@ the `src/test/resources/application.yml` config file uses test containers url sh
371370
```yaml
372371
spring:
373372
datasource:
374-
url: "jdbc:tc:postgresql:12:///demo1?TC_TMPFS=/testtmpfs:rw"
373+
url: "jdbc:tc:postgresql:15:///demo1?TC_TMPFS=/testtmpfs:rw"
375374
username: postgres
376375
password: password
377376
```
378377

379-
Test containers has nice integration with Spring Boot and it uses the specially formatted jdbc
380-
url `jdbc:tc:postgresql:12:///demo1?TC_TMPFS=/testtmpfs:rw` to launch the postgres 12 container
381-
create database called demo1 and put the postgres data directory on a temporary in RAM
382-
file system for optimal performance of Postgres while the test is executing. The postgres database
378+
Test containers has nice integration with Spring Boot and it uses the specially formatted jdbc
379+
url `jdbc:tc:postgresql:15:///demo1?TC_TMPFS=/testtmpfs:rw` to launch a postgres container,
380+
create a database called demo1 and put the postgres data directory on a temporary in RAM
381+
file system for optimal performance of Postgres while the test is executing. The postgres database
383382
will only exist for the duration of the test case execution there is no point in storing its data
384383
on disk.
385384

db/docker_postgres_init.sql

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1 @@
1-
CREATE DATABASE demo1
2-
WITH
3-
OWNER = postgres
4-
ENCODING = 'UTF8'
5-
LC_COLLATE = 'en_US.utf8'
6-
LC_CTYPE = 'en_US.utf8'
7-
TABLESPACE = pg_default
8-
CONNECTION LIMIT = -1;
9-
10-
CREATE DATABASE demo2
11-
WITH
12-
OWNER = postgres
13-
ENCODING = 'UTF8'
14-
LC_COLLATE = 'en_US.utf8'
15-
LC_CTYPE = 'en_US.utf8'
16-
TABLESPACE = pg_default
17-
CONNECTION LIMIT = -1;
1+
CREATE DATABASE demo2;

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ services:
1212
environment:
1313
POSTGRES_USER: "postgres"
1414
POSTGRES_PASSWORD: "password"
15+
POSTGRES_DB: "demo1"
1516
PGDATA: "/data/postgres"
1617
volumes:
1718
- postgres:/data/postgres

0 commit comments

Comments
 (0)