Shared, ephemeral read-only Docker volume - docker

I'm working on a Docker-based setup for a simple web-app running in Nginx+php-fpm. The common suggestion I've seen for storing the actual PHP code is to store it on the host and then mount it read-only in both the Nginx and PHP containers.
However, I want my setup to be self-contained so I can easily use it on Amazon ECS with Auto Scaling. In other words, I want to bundle the code somehow, rather than pulling it from the host.
So it seems what I want is a read-only volume that can be shared between two Docker containers and won't persist after those containers are destroyed. Is this possible? Or is there a better approach?

Docker images can contain volumes that are pre-populated with data. To achieve this, in the Dockerfile, first populate a the directory (for example using COPY or RUN) and then declare it as a volume. This allows you to build an image that contains your application code inside a volume:
FROM php:7-fpm
COPY ./app /var/www/html
VOLUME /var/www/html
Creating a new container from this image will create a new volume, initialize it with the data from the image's /var/www/html directory and mount it inside your new container at the same location.
Compare the documentation for more information:
The docker run command initializes the newly created volume with any data that exists at the specified location within the base image. For example, consider the following Dockerfile snippet:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
This Dockerfile results in an image that causes docker run, to create a new mount point at /myvol and copy the greeting file into the newly created volume.
This allows you to simply start your application image with docker run:
docker run -d --name app my_application_image
Then you can run your Nginx container and configure it to use the same volumes as your application container using the --volumes-from flag:
docker run -d --name web --link app:app --volumes-from app my_nginx_image
After this, you will have a Docker volume containing your application code that is mounted in both containers at /var/www/html.

Related

Docker NodeRed committed container does not maintain flows and modules

I'm working on a project using NodeRed deployed with docker and I would like to save the state of my deployment, including flows, settings and new added modules so that I can save the image and load it on another host replicating exactly the same NodeRed instance.
I created the container using:
docker run -itd --name my-nodered node-red
After implementing the flows and installing some custom modules, with the container running I used this command:
docker commit my-nodered my-project-nodered/my-nodered:version1
docker save my-project-nodered/my-nodered:version1 > tar-archive.tar.gz
And on another machine I'd imported the image using:
docker load < tar-archive.tar.gz
And run it using:
docker run -itd my-project-nodered/my-nodered:version1
And I obtain a vanilla NodeRed docker container with a default /data directory and just the files on the data directory maintained.
What am I missing? It could be possibile that my /data directory is overwrittenm as well as my settings.js file in the home directory? And in this case, which is the best practice to achieve my target?
Thank you a lot in advance
commit will not work, as you can see that there is volume defined in the Dockerfile.
# User configuration directory volume
VOLUME ["/data"]
That makes it impossible to create a derived image with any different content in that directory tree. (This is the same reason you can't create a mysql or postgresql image with prepopulated data.)
docker commit doesn't consider volumes at all, so you'll get an unchanged image with nothing preloaded in it.
You can see the offical documentation
Managing User Data
Once you have Node-RED running with Docker, we need to ensure any
added nodes or flows are not lost if the container is destroyed. This
user data can be persisted by mounting a data directory to a volume
outside the container. This can either be done using a bind mount or a
named data volume.
Node-RED uses the /data directory inside the container to store user
configuration data.
nodered-user-data-in-docker
one way is to restore the your config file on another machine, for example backup-config then
docker run -it -p 1880:1880 -v $PWD/backup-config/:/data --name mynodered nodered/node-red-docker
or if you want to full for some repo then you can try
docker run -it --rm -v "$PWD/$(wget https://raw.githubusercontent.com/openenergymonitor/oem_node-red/master/flows_emonpi.json)":/data/ nodered/node-red-docker

docker volume and VOLUME inside Dockerfile

I'm confused with what is different between creating docker volume create my-vol and VOLUME ["/var/www"].
My understanding is:
1) docker volume create my-vol creates a persistent volume on our machine and each container could be linked to my-vol.
2) VOLUME ["/var/www"] creates a volume inside its container.
And when I create another container, I could link my-vol as follows:
when running a container
$ docker run -d --name devtest --mount source=myvol2,target=/app nginx:latest
At that time, if I added VOLUME ["/var/www"] in my Dockerfile, all data of this docker file will be stored in both myvol2 and /var/www?
The Dockerfile VOLUME command says two things:
If the operator doesn't explicitly mount a volume on the specific container directory, create an anonymous one there anyways.
No Dockerfile step will ever be able to make further changes to that directory tree.
As an operator, you can mount a volume (either a named volume or a host directory) into a container with the docker run -v option. You can mount it over any directory in the container, regardless of whether or not there was a VOLUME declared for it in the Dockerfile.
(Since you can use docker run -v regardless of whether or not you declare a VOLUME, and it has confusing side effects, I would generally avoid declaring VOLUME in Dockerfiles.)
Just like in ordinary Linux, only one thing can be (usefully) mounted on any given directory. With the setup you describe, data will be stored in the myvol2 you create and mount, and it will be visible in /var/www in the container, but the data will only actually be stored in one place. If you deleted and recreated the container without the volume mount the data would not be there any more.
There are two types of persistent storage used in Docker,the first one is Docker Volumes and the second one is bind mounts. The differebce between them is that volumes are internal to Docker and stored in the Docker store (which is usually all under /var/lib/docker) and bind mounts use a physical location on your machine to store persistent data.
If you want to use a Docker Volume for nginx:
docker volume create nginx-vol
docker run -d --name devtest -v nginx-vol:/usr/share/nginx/html nginx
If you want to use a bind mount:
docker run -d --name devtest -v [path]:/usr/share/nginx/html nginx
[path] is the location in which you want to store the container's data.

Move docker bind-mount to volume

Actually, I run my containers like this, for example :
docker run -v /nexus-data:/nexus-data sonatype/nexus3
^
After reading the documentation, I discover volumes that are completely managed by docker. For some reasons, I want to change the way to run my containers, to do something like this :
docker run -v nexus-data:/nexus-data sonatype/nexus3
^
I want to transfer my existing bind-mount to volumes.
But I don't want to lose the data into /nexus-data folder, is there a possibility to transfer this folder, to the new volume, whitout restart everything ? Because I've also Jenkins and Sonar containers for example, I just want to change the way to have persistent data. The is a proper way to do this ?
You can try out following steps so that you will not loose your current nexus-data.
#>docker run -v nexus-data:/nexus-data sonatype/nexus3
#>docker copy /nexus-data/. <container-name-or-id>:/nexus-data/
#>docker stop <container-name-or-id>
#>docker start <container-name-or-id>
docker copy will copy data from your host-machine's /nexus-data folder to container's FS /nexus-data folder which is your mounted volume.
Let me know if you face any issue while performing following steps.
Here's another way to do this, that I just used successfully with a Heimdall container. It's outlined in the documentation for the sonatype/nexus3 image:
Stop the running container (e.g. named nexus3)
Create a docker volume called nexus-data, creating it with the following command: docker volume create nexus-data)
By default, Docker will store the volume's content at /var/lib/docker/volumes/nexus-data/_data/
Simply copy the directory where you previously had been using a bind mount to the aforementioned volume directory (you'll need super user privileges to do this, or for the user to be part of the docker group): cp -R /path/to/nexus-data/* /var/lib/docker/volumes/nexus-data/_data/
Restart the nexus3 container with $ docker run -v nexus-data:/nexus-data sonatype/nexus3 --name=nexus3
Your container will be back up and running, with the files persisted in the directory /path/to/nexus-data/ now mirrored in the docker volume. Check if functionality is the same, of course, and if so, you can delete the /path/to/nexus-data/ directory
Q.E.D.

Docker volume persistent

I have two questions about docker volume.
First : When I run my docker with a volume which it creates with docker volume create or with docker-compose, new files on the default directory are not appended to the volume. I give an example :
docker volume create testdock-logs
docker run -d -p 80:80 --name testdock --restart=on-failure -v testdock-logs:/var/www/logs testdock:latest -s
After that when I create a new file or directory on /var/www/logs and build my image testdocker, I don't find my new file on the volume.
What am I doing wrong?
Docker doesn't replace files in a volume with those in a modified image. Doing so would defeat the purpose of a volume, this is the one persistent location you have to store data that isn't reverted back to the image state when the container is recreated.
If you need the files from your image instead of the files in your volume, then reconsider whether you actually need a volume.

Sharing volume between Docker containers

I am using Docker to deploy some services and I want to share the Docker volumes between different containers.
Suppose I have a Docker container A which mounts a volume at /data. Here is its Dockerfile:
VOLUME /data
From my understanding, this will attach a volume to the container but it will not mount a host directory to the container. So the data inside this volume is still inside the container A.
I have another container B which provides an FTP service. It accesses the data under volume /public. Its Dockerfile is:
VOLUME /public
Now I want to link them together so that I can use B to manage A's data. From the Docker doc https://docs.docker.com/engine/userguide/containers/dockervolumes/ I shall use the --volumes-from flag to mount A's data volume to B. But this command will mount A's data to /data in B instead of /public, and in this case, the container B is not able to access the data. I didn't see any way to rename the mount point.
Any suggestions or best practices to handle this case?
The data-only container gives a good solution for this case. But if you want to use volumes-from and mount the data to different mount point, this question may be helpful!
How to map volume paths using Docker's --volumes-from?
You may find a lot of pointers mentioning data-only containers and --volumes-from. However, since docker 1.9, volumes have become first class citizens, they can have names, and have more flexibility:
It's now easy to achieve the behavior you want, here's an example :
Create a named data volume with name service-data:
docker volume create --name service-data
You can then create a container that mounts it in your /public folder by using the -v flag:
docker run -t -i -v service-data:/public debian:jessie /bin/bash
For testing purpose we create a small text file in our mapped folder:
cd public
echo 'hello' > 'hello.txt'
You may then attach your named volume to a second container, but this time under the data folder:
docker run -t -i -v service-data:/data debian:jessie /bin/bash
ls /data #-->shows "hello.txt"
Just remember, if both containers are using different images, be careful with ownership and permissions!

Resources