Database Volumes
By the end of this exercise, you should be able to:
- Provide a docker volume as a database backing to Postgres
- Make one Postgres container's database available to other Postgres containers
Launching Postgres
Download a postgres image, and look at its history to determine its default volume usage:
[centos@node-0 ~]$ docker image pull postgres:9-alpine [centos@node-0 ~]$ docker image inspect postgres:9-alpine ... "Volumes": { "/var/lib/postgresql/data": {} }, ...You should see a
Volumesblock like the above, indicating that those paths in the container filesystem will get volumes automatically mounted to them when a container is started based on this image.Set up a running instance of this postgres container:
[centos@node-0 ~]$ docker container run --name some-postgres \ -v db_backing:/var/lib/postgresql/data \ -d postgres:9-alpineNotice the explicit volume mount,
-v db_backing:/var/lib/postgresql/data; if we hadn't done this, a randomly named volume would have been mounted to the container's/var/lib/postgresql/data. Naming the volume explicitly is a best practice that will become useful when we start mounting this volume in multiple containers.
Writing to the Database
The
psqlcommand line interface to postgres comes packaged with the postgres image; spawn it as a child process in your postgres container interactively, to create a postgres terminal:[centos@node-0 ~]$ docker container exec \ -it some-postgres psql -U postgresCreate an arbitrary table in the database:
postgres=# CREATE TABLE CATICECREAM(COAT TEXT, ICECREAM TEXT); postgres=# INSERT INTO CATICECREAM VALUES('calico', 'strawberry'); postgres=# INSERT INTO CATICECREAM VALUES('tabby', 'lemon');Double check you created the table you expected, and then quit this container:
postgres=# SELECT * FROM CATICECREAM; coat | icecream --------+------------ calico | strawberry tabby | lemon (2 rows) postgres=# \qDelete the postgres container:
[centos@node-0 ~]$ docker container rm -f some-postgresCreate a new postgres container, mounting the
db_backingvolume just like last time:[centos@node-0 ~]$ docker container run \ --name some-postgres \ -v db_backing:/var/lib/postgresql/data \ -d postgres:9-alpineReconnect a
psqlinterface to your database, also like before:[centos@node-0 ~]$ docker container exec \ -it some-postgres psql -U postgresList the contents of the
CATICECREAMtable:postgres=# SELECT * FROM CATICECREAM;The contents of the database have survived the deletion and recreation of the database container; this would not have been true if the database was keeping its data in the writable container layer. As above, use
\qto quit from the postgres prompt.
Running Multiple Database Containers
Create another postgres runtime, mounting the same backing volume:
[centos@node-0 ~]$ docker container run \ --name another-postgres \ -v db_backing:/var/lib/postgresql/data \ -d postgres:9-alpineCreate another postgres interactive prompt, pointing at this new postgres container:
[centos@node-0 ~]$ docker container exec \ -it another-postgres psql -U postgresList the contents of the database one last time, again with
SELECT * FROM CATICECREAM;. The database is readable exactly as it is from the other running database runtime, from this new postgres container.Clean up by removing all your containers and deleting your postgres volume:
[centos@node-0 ~]$ docker container rm -f $(docker container ls -aq) [centos@node-0 ~]$ docker volume rm db_backing
Conclusion
Whenever data needs to live longer than the lifecycle of a container, it should be pushed out to a volume outside the container's filesystem; numerous popular databases are containerized using this pattern. In addition to making sure data survives container deletion, this pattern allows us to share data among multiple containers, so multiple database instances can access the same underlying data.