55Steps 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
1010databases ` 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
1313configuration you can skip this step.
1414
1515Check 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
5959each part works.
6060
6161``` yaml
62- version : ' 3.8'
63-
6462volumes :
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
7068two volumes. The postgres volume will be used by the container running postgres, this means
7169that the state of the postgres database will survive restarts of the container. Similarly,
7270the ` 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
8684services:
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
107106To 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`.
111110This 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
153145volumes:
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
162159ports:
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
168165port `15432` since the workstation might already have postgres installed and listening
169166on 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
172169For example the spring boot application included in this repo can connect to the postgres
173170database 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
203200pgadmin:
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
227226pgAdmin can run in one of two modes desktop mode or server mode. When running in
228227desktop 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
241240environment :
242- PGADMIN_DEFAULT_EMAIL : admin
243- PGADMIN_DEFAULT_PASSWORD : admin
241+ PGADMIN_DEFAULT_EMAIL : " admin@example.com "
242+ PGADMIN_DEFAULT_PASSWORD : " admin"
244243` ` `
245244
246245pgAdmin 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
278277The 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
282281In order for pgAdmin to store it's state across container restarts we map the location
283282it stores state `/var/lib/pgadmin` to the docker volume `pgadmin` as shown in the yaml
@@ -286,7 +285,7 @@ below.
286285` ` ` yaml
287286volumes:
288287 - pgadmin:/var/lib/pgadmin
289- - ./docker_pgadmin_servers.json:/pgadmin4/servers.json
288+ - ./db/ docker_pgadmin_servers.json:/pgadmin4/servers.json
290289` ` `
291290
292291pgAdmin 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
372371spring:
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
383382will only exist for the duration of the test case execution there is no point in storing its data
384383on disk.
385384
0 commit comments