Mapping Docker Volumes in a Cluster/Docker-Swarm - docker

I am running Docker Swarm with 3-Masters and 3-Worker nodes.
On this Swarm, I have an Elastic search container which reads data from multiple log files and then writes the data into a directory. Later it reads data from this directory and shows me the logs on a UI.
Now the problem is that I am running only 1 instance of this Elastic Search Container and say for some reason it goes down then docker swarm start this on another machine. Since I have 6 machines I have created the particular directory on all the machines, but whenever I start the docker stack the ES container starts and starts reading/writing directory on the machine where it is running.
Is there a way that we can
Force docker swarm to run a container on a particular machine
or
Map volume to shared/network drive

Both are available.
Force docker swarm to run a container on a particular machine
Add --constraint flag when executing docker service create. Some introduction.
Map volume to shared/network drive
Use docker volume with a driver that supports writing files to an external storage system like NFS or Amazon S3. More introduction.

Related

How to persist docker Images through multiple dind containers? [duplicate]

Is is possible to share a single docker volume to multiple docker containers with /var/lib/docker destination?
A minimal reproducible example would be like below:
$ docker volume create --name lib
$ docker run --privileged -v lib:/var/lib/docker --name c1 -d docker:dind
$ docker run --privileged -v lib:/var/lib/docker --name c2 -d docker:dind
I want to work with docker inside c1 and c2 containers simultaneously. But if you wait a moment, you'll see it's not possible and the second container (c2) stops. I've checked the error logs:
$ docker logs -f c2
.
.
.
failed to start containerd: timeout waiting for containerd to start
And, I can not make multiple volumes; Because the storage is limited and the size of images are heavy.
UPDATE:
Maybe I'm facing with XY Problem! Actually I want to have my images shared. I want all of my Docker Images inside my host machine, go into all DinD containers ALSO the containers should be able to create a new Docker Image and this new image should be accessible from other containers at the same time.
On the title of the question, yes, multiple containers can mount the same volume. However, your containers are each docker engines, and the second engine is failing to start because there's already a running docker engine on the /var/lib/docker directory. This isn't a volume mounting issue so much as a docker engine design challenge.
Given your requirements, a container image database from the host engine, shared with various DinD instances, while not sharing the docker engine of the host itself (via a docker.sock or mTLS), I don't believe there's a good answer. You're left with two options:
Run your own local registry server. This is keep the layers from being sent outside your network, and could even be on the same host. However, the layers will be copied for each engine, and you'll need to manage GC policies on that registry. This gives you the desired isolation without the desired deduplication of image layers.
Share the docker.sock between the host and trusted containers. The containers would then have direct access to the host engine, effectively root on the host (unless you have setup the engine as rootless), so only do this in environments where you trust it. This would give you the layer deduplication, but none of the isolation.
The reason it's difficult is docker is designed to manage it's own copy of /var/lib/docker, so all the state can be tracked in memory and periodically pushed out as json metadata files on disk to handle restarts. Mutexes are within the one process, and it doesn't need to worry about multiple writers modifying layers, or a reader running while a writer is still creating a layer.
Take a look at this Document:
https://docs.docker.com/storage/bind-mounts/

How to mount a single volume to multiple /var/lib/docker simultaneously?

Is is possible to share a single docker volume to multiple docker containers with /var/lib/docker destination?
A minimal reproducible example would be like below:
$ docker volume create --name lib
$ docker run --privileged -v lib:/var/lib/docker --name c1 -d docker:dind
$ docker run --privileged -v lib:/var/lib/docker --name c2 -d docker:dind
I want to work with docker inside c1 and c2 containers simultaneously. But if you wait a moment, you'll see it's not possible and the second container (c2) stops. I've checked the error logs:
$ docker logs -f c2
.
.
.
failed to start containerd: timeout waiting for containerd to start
And, I can not make multiple volumes; Because the storage is limited and the size of images are heavy.
UPDATE:
Maybe I'm facing with XY Problem! Actually I want to have my images shared. I want all of my Docker Images inside my host machine, go into all DinD containers ALSO the containers should be able to create a new Docker Image and this new image should be accessible from other containers at the same time.
On the title of the question, yes, multiple containers can mount the same volume. However, your containers are each docker engines, and the second engine is failing to start because there's already a running docker engine on the /var/lib/docker directory. This isn't a volume mounting issue so much as a docker engine design challenge.
Given your requirements, a container image database from the host engine, shared with various DinD instances, while not sharing the docker engine of the host itself (via a docker.sock or mTLS), I don't believe there's a good answer. You're left with two options:
Run your own local registry server. This is keep the layers from being sent outside your network, and could even be on the same host. However, the layers will be copied for each engine, and you'll need to manage GC policies on that registry. This gives you the desired isolation without the desired deduplication of image layers.
Share the docker.sock between the host and trusted containers. The containers would then have direct access to the host engine, effectively root on the host (unless you have setup the engine as rootless), so only do this in environments where you trust it. This would give you the layer deduplication, but none of the isolation.
The reason it's difficult is docker is designed to manage it's own copy of /var/lib/docker, so all the state can be tracked in memory and periodically pushed out as json metadata files on disk to handle restarts. Mutexes are within the one process, and it doesn't need to worry about multiple writers modifying layers, or a reader running while a writer is still creating a layer.
Take a look at this Document:
https://docs.docker.com/storage/bind-mounts/

Is there a Better way to run a command or shell on Docker swarm

Lets say I want to edit a config file for an NGINX Docker service that is replicated across 3 nodes.
Currently I list the services using docker service ls.
Then get the details to find a node running a container for that service using docker serivce ps servicename.
Then ssh to a node where one of the containers is running.
Finally, docker exec -it containername bash. Then I edit the config file.
Two questions:
Is there a better way to do this rather than ssh to a node running a container? Maybe there is a swarm or service command to do so?
If I were to edit that config file on one container would that change be replicated to the other 2 containers in the swarm?
The purpose of this exercise would be to edit configuration without shutting down a service.
You should not be exec'ing into containers to change their configuration, and so docker has not created an easy way to do this within Swarm Mode. You could use classic swarm to avoid the need to ssh into the other host, but I still don't recommend this.
The correct way to do this is to migrate your configuration file into a docker config entry. Version your config name. Then when you want to update it, you create a new version with the desired changes, and do a rolling update of your service to use that new configuration.
Unless the config is mounted from an external source like NFS, changes to one config in one container will not apply to other containers running on other nodes. If that config is stored locally inside your container as part of it's internal copy-on-write filesystem, then no changes from one container will be visible in any other container.

Share docker images between hosts with NFS

I'building a mesosphere infrastructure on AWS instances with 3 master servers (running zookeeper, mesos-master, marathon and haproxy) and N slaves (running mesos-slave and docker).
If I run the same container on different slaves marathon downloads on each slave the same image. I would like to share one single nfs export (say on master1) and mount it on every slave in order to have a unique storage for the images.
Im using Ubuntu on the EC2 instances, so the storage driver used by default is device-mapper. I set up the slaves to mount /var/lib/docker/devicemapper and /var/lib/docker/graph but it ends up with this error: "stale NFS file handle"
What I would like to understand is:
There is a way to do it using a different storage driver?
In any case is the docker daemon doing some look on the files in this directory?
Is my approach wrong or possible leading into "cconcurrency access issues?
Instead of using NFS to expose the backing file system, I think it would be easier to set up docker-registry (with a volume on the master1, so the data is persisted there) and on the other nodes pull images via docker protocol by e.g. docker pull master1:5000/image:latest

How to build stateful docker services architecture with CoreOS's fleet?

CoreOS used with fleet enables one to build services running some docker applications.
But is there any way to run docker services which require its state to be kept between restarts, to be persistent? For instance, databases or services that must store some files to be shared later on.
Because as far as I know, the service can be launched on core-1 machine (for example), and on restart will be launched on another one randomly. So the docker volume can be lost.
The simplest way to maintain a database service is to always schedule the fleet unit to the same machine. You can do this by adding an [X-Fleet] section to the fleet unit file and either assigning the unit to a particular X-ConditionMachineID, or X-ConditionMachineMetadata. See the coreos documentation.
You can then persist data outside your docker containers by mounting a volume from the host machine. The recommended way of doing this is to wrap this data in a separate data container via docker:
docker run --name mongodb-volume -v /home/core/mongodb-data:/data/db busybox
docker run -p 27017 --volumes-from mongodb-volume mongodb:latest
Since /home/core/mongodb-data on a particular machine will store persistent mongodb state and the unit will always be scheduled to that same machine, this will solve your problem.
You can consider to run some distributed filesystem over CoreOS cluster. This way whatever machine your database service container ends on, it will always be able to use database, mounted from DFS.

Resources