Mounting volumes with docker-compose - docker-compose

I'm looking into how to mount volumes with docker-compose for data persistence but I'm having trouble understanding all the examples I read.
https://www.linux.com/learn/docker-volumes-and-networks-compose
version: '2'
services:
mysql:
image: mysql
container_name: mysql
volumes:
- mysql:/var/lib/mysql
...
volumes:
mysql:
Ok so this defines a volume named mysql at the bottom and it references this volume in
- mysql:/var/lib/mysql
How will the mysql image know to look in this volume named mysql? Is it just designed to look in all the volumes it has to store data or something?
Then in other examples I see the following:
services:
nginx:
image: nginx
depends_on:
- ghost
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
ports:
- "80:80"
networks:
- proxy
This example doesn't need to define a volume, why is that?

your MySQL data will be stored in the named volume mysql which is created by:
volumes:
mysql:
You can list the docker volumes using docker volume ls and the 'path' will be something like: /var/lib/docker/volumes/mysql/date. When you cd in this folder you will see the same data as the data which is in your mysql container on path: /var/lib/mysql. If you exec inside your container you will see the same data.
How does it know how to use this path?
Well check the Dockerfile of mysql. Here is:
VOLUME /var/lib/mysql
In short: all the data of your mysql is stored in /var/lib/mysql inside your container and mounted to your named docker volume mysql on your host, which path is something like /var/lib/docker/volumes/mysql/data/.
The next part is mounting ./default.conf (on your host, relative path) on the path /etc/nginx/conf.d/default.conf inside your nginx container.
Nginx and ghost don't need a named volume in this case because they don't need to keep specific data. When you create your environment you will add data using Ghost (write blogs), but the data itself will be stored in the mysql database. Not in the Ghost container.
Remark (if your second example has nothing to do with the mysql example): the default image of ghost is working with the sqlite3 db which is inside the same container (=! microservice for each container so this is fine to develop, not in production). But if you would use this setup you need to create a named volume for your sqlite which is in the same container as ghost. Take a look to the dockerfile of ghost.
If you want to use mysql you probably need to mount a config file to your ghost container to tell the container: use mysql, you will not need a named docker volume for ghost then, because data won't be stored in the ghost container but in the mysql container.
To keep your last example persistent without using mysql with a named volume you have to add a volume for the sqlite db which is inside the ghost container for this path: /var/lib/ghost/content. Check the Dockerfile again to see this path.
This blog post explains how to setup ghost with mysql in docker-compose

Related

unable to persist postgresql data using named volume in docker-compose

I am using docker-compose to spin up a spring api with a postgres database . I am new to docker and I am trying to persist my database using a named volume I created with
docker volume create employeedata
I add this volume inside my docker-compose.yml but the db does not persist if I stop or remove my containers .
version: '3.8'
services:
app:
container_name: springboot-postgresql
image: springboot-postgresql
build: ./
ports:
- "8080:8080"
depends_on:
- postgresqldb
postgresqldb:
image: postgres
ports:
- "5432:5432"
volumes:
- employeedata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=postgres
- POSTGRES_DB=employeedb
volumes:
employeedata:
I tried doing docker inspect employeedata and got the result below
It seems fishy to me that the docker-compose version is 2 and not 3 plus I don't understand how the mountpoint is related to the volume path I specify in my docker-compose.yml above
I would appreciate your help
docker compose created all objects in a project namespace. This namespace is usually the folder name of the docker-compose.yml file but you can set it by passing --project-name to (all) your calls to docker compose.
As docker does not have first class namespaces, the project name is simply used as a prefix for all objects defined in the compose file, so in this case, assuming your project was in a folder called "project" then compose would have created project_app as the container and project_employeedata as the volume.
To override this, you specify an explict container-name as you have done. But you really shouldn't as it means that any two deployments of compose files with this name will now conflict.
And to override it for volumes - tell docker compose that the volume is externally created and provide the external name. Otherwise compose will try to use the namespaced name.
volumes:
employeedata:
external: true
name: employeedata
Again, letting compose manage the volume name is probably the better option. Simply ensure the directory hosting the compose file has a unique name that is suitable - or ensure a suitable unique name is passed via --project-name, and then manage the volume using whatever_employeedata.
nb. Docker compose does not remove compose managed volumes unless -v / --volumes is passed to docker compose down so your data will persist here.
/var/lib/docker/volumes is simply the (default) location that docker will manage volumes.
The 2.0 refers to the version of compose, not the version in your compose.yml file.

Is it possible to "combine" naming volumes and defining the path between containers? (docker compose)

Is it possible to "combine" naming volumes and defining the path between containers? (docker compose)
I got a docker compose file with multiple services which need to share volumes. At the same time I want to specify the path of these volumes for backup purposes and to control on which drive the data resides.
Currently I am using an .env file combined with the docker-compose file to solve this as follows.
File .env:
VOLUME_SHARED=/home/docker_user/data_service
File docker-compose.yml
version: '3.8'
services:
service1:
image: service1
volumes:
- ${VOLUME_SHARED}:/data
service2:
image: service2
volumes:
- ${VOLUME_SHARED}:/data
I know there are named volumes, but I couldnt find a way to define their path. Is there a way to locate all the information within the docker-compose file?
So to make it clear, is something like the following possible?
File docker-compose.yml
version: '3.8'
services:
service1:
image: service1
volumes:
- shared_data:/data
service2:
image: service2
volumes:
- shared_data:/data
volumes:
shared_data=/home/docker_user/data_service
There is no such feature neither in compose file reference nor in docker volume create command manual. Thus you can't define storage location when you create a volume.
You can either change location for all docker files (see this post) or use bind mounts (as you do now).
There is also a hack which can do what you want but I don't recommend it. On Linux you can replace an existing volume with a soft link pointing somewhere else.
# move the volume to a new location
mv /var/lib/docker/volumes/postgres_volume/ /root
# replace it with a soft link
ln -sv /root/postgres_volume/ /var/lib/docker/volumes/postgres_volume

Using a docker volume with postgresql to verify it is saving on the hosts filesystem

I am trying to get docker volumes working.
I have defined a volume in my Dockerfile as follows:
version: "3"
services:
redis:
image: redis:alpine
ports:
- "6379:6379"
db:
image: postgres:9.4
#container_name: db
volumes:
- "db-data:/var/lib/postgresql/data"
volumes:
db-data:
Now my question is, when I do a docker-compose up I don't see my data persisted on my local laptop (or server).
I just want to test/verify that my data is saving to the host's filesystem, so if I start/stop docker when it restarts it reads from the database file on the host.
That construct saves data in a named volume; if you look under /var/lib/docker/volumes as root you should be able to see it there (though mucking around in /var/lib/docker generally isn't advisable; and I believe this is one of the things where Docker Compose will change the name to try to make it unique).
If you want the data to be saved in a host directory, change the volume declaration to explicitly have a relative or absolute path. You won't need the explicit volume declaration, and for this you can remove the volumes block entirely. That would leave you with a docker-compose.yml that looks like:
version: "3"
services:
db:
image: postgres:9.4
volumes:
- "./db-data:/var/lib/postgresql/data"

Permission denied when running `mkdir` inside of a Docker container

I am using Docker Compose to run several containers, including one with a Postgres image. I am attempting to add a volume to that container to persist my data across container builds. However, I am receiving an error when it tries to create a directory for this volume within the container.
I run:
docker-compose build
then
docker-compose up
And I receive the following error:
ERROR: for cxbenchmark_db_1 Cannot start service db: oci runtime error: container_linux.go:265: starting container process caused "process_linux.go:368: container init caused \"rootfs_linux.go:57: mounting \\"/var/lib/docker/volumes/69845a017b4465e9122852a75ca194db473df95fa218658b8a60fb56eba9be9e/_data\\" to rootfs \\"/var/lib/docker/overlay2/627956d63fb0480448079577a83b0b54f83866fdf31136b7c669541c3f672355/merged\\" at \\"/var/lib/docker/overlay2/627956d63fb0480448079577a83b0b54f83866fdf31136b7c669541c3f672355/merged/var/lib/postgresql/data\\" caused \\"mkdir /var/lib/docker/overlay2/627956d63fb0480448079577a83b0b54f83866fdf31136b7c669541c3f672355/merged/var/lib/postgresql/data: permission denied\\"\""
My full docker-compose.yml looks like this (note the service called db where the volume is defined):
version: '3'
services:
nginx:
image: nginx:latest
ports:
- 80:8000
volumes:
- ./src:/src
- ./config/nginx:/etc/nginx/conf.d
- ./src/static:/static
depends_on:
- web
web:
build: .
command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn cx_benchmark.wsgi -b 0.0.0.0:8000"
depends_on:
- db
volumes:
- ./src:/src
- ./src/static:/static
expose:
- 8000
db:
image: postgres:latest
volumes:
- /private/var/lib/postgresql:/var/lib/postgresql
ports:
- 5432:5432
Any ideas for how to solve?
The error you are seeing is not a problem (necessarily) with the explicit volume bind mount in your compose file, but rather with the VOLUME declaration in the main postgres official Docker image Dockerfile:
VOLUME /var/lib/postgresql/data
Since you haven't provided a mount-point for this directory (but rather the parent), the docker engine is creating a local volume and then trying to mount that volume into your already bind-mounted location and getting a permissions error.
For clarity, here is the volume the docker engine created for you:
/var/lib/docker/volumes/69845a017b4465e9122852a75ca194db473df95fa218658b8a60fb56eba9be9e/_data
And here is the directory location at which it is trying to bind mount that dir; on top of your bind mount from /private/var/lib/postgresql:
mkdir /var/lib/docker/overlay2/627956d63fb0480448079577a83b0b54f83866fdf31136b7c669541c3f672355/merged/var/lib/postgresql/data: permission denied
Now, I think the reason this is failing is that you may have turned on user namespaces in your Docker engine ("userns-remap" flag/setting) such that the container doesn't have permissions to create a directory in that root-owned location on your host. Barring that, the only other option is that the postgres container is starting as a non-root user, but I don't see anything in your compose file or the official Dockerfile for the latest release that uses the USER directive.
As an aside, since you are ending up with double-volumes because your bind mount doesn't match the VOLUME specifier in the postgres Dockerfile, you could change your compose file to mount to /var/lib/postgresql/data and get around that extra volume being created. Especially if you expect your DB data to end up in /private/var/lib/postgresql, as it may be surprising to find it isn't there, but rather in the /var/lib/docker/volumes/.. location.

ansible docker postgres volume

i am doing some postgres deployment with docker, ansible and terraform in aws
things are going relatively well, i start the instance with terraform, provision the instance with docker using ansible, start my postgres container with ansible also, and attach a ebs volume to my instance, which i intend to use as the main data storage.
but i am confused as to how to attach the volume to the docker (not to the instance as i am able to do that using terraform)
i imagine it is possible using ansible or modifiying the dockerfile, but the documentation of the "volume" which seems to be the answer is not that clear to me.
so if i had an ansible playbook like this:
name: Start postgis
docker_container:
name: postgis
image: "{{ ecr_url }}"
network_mode: bridge
exposed_ports:
5432
published_ports:
5432:5432
state: started
how would i specify the ebs volume to be used for the data storage of Postgres?
resource "aws_volume_attachment" "ebs-volume-postgis-attach" {
device_name = "/dev/xvdh"
volume_id = "${aws_ebs_volume.ebs-volume-postgis.id}"
instance_id = "${aws_instance.postgis.id}"
}
that was the code used to attach the ebs volume, in case someone is interested
please ask any kind of info that you need, all help is deeply apreciated
Here is a checklist:
Attach EBS volume (disk) to EC2 instance (e.g. /dev/xvdh)
Make partition (optional) (e.g. /dev/xvdh1)
Make filesystem on the partition/disk
Mount filesystem inside your EC2 instance (e.g. /opt/ebs_data)
Start Docker-container with volume (e.g. /opt/ebs_data:/var/lib/postgresql/data)
In Ansible's docker_container module, volumes is a list, so:
- docker_container:
name: postgis
image: "{{ ecr_url }}"
network_mode: bridge
exposed_ports:
- 5432
published_ports:
- 5432:5432
state: started
volumes:
- /opt/ebs_data:/var/lib/postgresql/data