I have a Docker container that I've created simply by installing Docker on Ubuntu and doing:
sudo docker run -i -t ubuntu /bin/bash
I immediately started installing Java and some other tools, spent some time with it, and stopped the container by
exit
Then I wanted to add a volume and realised that this is not as straightforward as I thought it would be. If I use sudo docker -v /somedir run ... then I end up with a fresh new container, so I'd have to install Java and do what I've already done before just to arrive at a container with a mounted volume.
All the documentation about mounting a folder from the host seems to imply that mounting a volume is something that can be done when creating a container. So the only option I have to avoid reconfiguring a new container from scratch is to commit the existing container to a repository and use that as the basis of a new one whilst mounting the volume.
Is this indeed the only way to add a volume to an existing container?
You can commit your existing container (that is create a new image from container’s changes) and then run it with your new mounts.
Example:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a8f89adeead ubuntu:14.04 "/bin/bash" About a minute ago Exited (0) About a minute ago agitated_newton
$ docker commit 5a8f89adeead newimagename
$ docker run -ti -v "$PWD/somedir":/somedir newimagename /bin/bash
If it's all OK, stop your old container, and use this new one.
You can also commit a container using its name, for example:
docker commit agitated_newton newimagename
That's it :)
We don't have any way to add volume in running container, but to achieve this objective you may use the below commands:
Copy files/folders between a container and the local filesystem:
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
For reference see:
https://docs.docker.com/engine/reference/commandline/cp/
I've successfully mount /home/<user-name> folder of my host to the /mnt folder of the existing (not running) container. You can do it in the following way:
Open configuration file corresponding to the stopped container, which can be found at /var/lib/docker/containers/99d...1fb/config.v2.json (may be config.json for older versions of docker).
Find MountPoints section, which was empty in my case: "MountPoints":{}. Next replace the contents with something like this (you can copy proper contents from another container with proper settings):
"MountPoints":{"/mnt":{"Source":"/home/<user-name>","Destination":"/mnt","RW":true,"Name":"","Driver":"","Type":"bind","Propagation":"rprivate","Spec":{"Type":"bind","Source":"/home/<user-name>","Target":"/mnt"},"SkipMountpointCreation":false}}
or the same (formatted):
"MountPoints": {
"/mnt": {
"Source": "/home/<user-name>",
"Destination": "/mnt",
"RW": true,
"Name": "",
"Driver": "",
"Type": "bind",
"Propagation": "rprivate",
"Spec": {
"Type": "bind",
"Source": "/home/<user-name>",
"Target": "/mnt"
},
"SkipMountpointCreation": false
}
}
Restart the docker service: service docker restart
This works for me with Ubuntu 18.04.1 and Docker 18.09.0
Jérôme Petazzoni has a pretty interesting blog post on how to Attach a volume to a container while it is running. This isn't something that's built into Docker out of the box, but possible to accomplish.
As he also points out
This will not work on filesystems which are not based on block devices.
It will only work if /proc/mounts correctly lists the block device node (which, as we saw above, is not necessarily true).
Also, I only tested this on my local environment; I didn’t even try on a cloud instance or anything like that
YMMV
Unfortunately the switch option to mount a volume is only found in the run command.
docker run --help
-v, --volume list Bind mount a volume (default [])
There is a way you can work around this though so you won't have to reinstall the applications you've already set up on your container.
Export your container
docker container export -o ./myimage.docker mycontainer
Import as an image
docker import ./myimage.docker myimage
Then docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
A note for using Docker Windows containers after I had to look for this problem for a long time!
Condiditions:
Windows 10
Docker Desktop (latest version)
using Docker Windows Container for image microsoft/mssql-server-windows-developer
Problem:
I wanted to mount a host dictionary into my windows container.
Solution as partially discripted here:
create docker container
docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows-developer
go to command shell in container
docker exec -it <CONTAINERID> cmd.exe
create DIR
mkdir DirForMount
stop container
docker container stop <CONTAINERID>
commit container
docker commit <CONTAINERID> <NEWIMAGENAME>
delete old container
docker container rm <CONTAINERID>
create new container with new image and volume mounting
docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y -v C:\DirToMount:C:\DirForMount <NEWIMAGENAME>
After this i solved this problem on docker windows containers.
My answer will be little different. You can stop your container, add the volume and restart it. How to do it, follow the steps.
docker volume create ubuntu-volume
docker stop <container-name>
sudo docker run -i -t --mount source=ubuntu-volume,target=<target-path-in-container> ubuntu /bin/bash
You can stop and remove the container, append the existing volume in a startup script, and restart from the image. If the already existing existing partitions do keep the data, you shouldn't experience any loss of information. This should also work the same way with Dockerfile and Docker composer.
eg (solr image).
(initial script)
#!/bin/sh
docker pull solr:8.5
docker stop my_solr
docker rm solr:8.5
docker create \
--name my_solr \
-v "/XXXX/docker/solr/solrdata":/var/solr \
-p 8983:8983 \
--restart unless-stopped \
--user 1000:1000 \
-e SOLR_HEAP=1g \
--log-opt max-size=10m \
--log-opt max-file=3 \
solr:8.5
docker cp /home/XXXX/docker/solr/XXXXXXXX.jar my_solr:/opt/solr/contrib/dataimporthandler-extras/lib
docker start my_solr
file with the second volume
#!/bin/sh
docker pull solr:8.5
docker stop my_solr
docker rm solr:8.5
docker create \
--name my_solr \
-v "/XXXX/docker/solr/solrdata":/var/solr \
-v "/XXXX/backups/solr_snapshot_folder":/var/solr_snapshots \
-p 8983:8983 \
--restart unless-stopped \
--user 1000:1000 \
-e SOLR_HEAP=1g \
--log-opt max-size=10m \
--log-opt max-file=3 \
solr:8.5
docker cp /home/XXXX/docker/solr/XXXXXXXX.jar my_solr:/opt/solr/contrib/dataimporthandler-extras/lib
docker start my_solr
Use symlink to the already mounted drive:
ln -s Source_path targer_path_which_is_already_mounted_on_the_running_docker
The best way is to copy all the files and folders inside a directory on your local file system by: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
SRC_PATH is on container
DEST_PATH is on localhost
Then do docker-compose down attach a volume to the same DEST_PATH and run Docker containers by using docker-compose up -d
Add volume by following in docker-compose.yml
volumes:
- DEST_PATH:SRC_PATH
I need create a docker container for several projects tha use Mysql 8.0 with PHP 7.3
I like create it, because I need modify mysql startup configuration
For this I create
Dockerfile
FROM mysql:8.0
COPY mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf
ENV MYSQL_ROOT_PASSWORD="123456"
mysqld_charset.cnf
[mysqld]
default-authentication-plugin = mysql_native_password
collation-server = utf8mb4_general_ci
character-set-server = utf8mb4
License and readme files.
Execute
$ docker build --no-cache -t mysql8_legacy_password .
Sending build context to Docker daemon 14.85kB
Step 1/3 : FROM mysql:8.0
---> 62a9f311b99c
Step 2/3 : COPY mysqld_charset.cnf /etc/mysql/conf.d/mysqld_charset.cnf
---> 0e21143ae822
Step 3/3 : ENV MYSQL_ROOT_PASSWORD="123456"
---> Running in a8d350dbd651
Removing intermediate container a8d350dbd651
---> 7dd66b27be00
Successfully built 7dd66b27be00
Successfully tagged mysql8_legacy_password:latest
$ docker run --name mysql8_legacy_password -it mysql:8.0
error: database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD
The issue is in the run command.
docker run --name mysql8_legacy_password -it mysql:8.0
You are trying to start a container from mysql:8.0 image in which no env has been setup.
The last argument of the docker run command should be the image name. Since you have tagged your image as mysql8_legacy_password, this should work:
docker run --name container_name -it mysql8_legacy_password
docker run
I want to build a new MySQL image based on the official MySQL docker container image. I want to reduce the number of parameters I need to add when running the image. (eg. -e MYSQL_USER, -e MYSQL_DATABASE and even -e MYSQL_ROOT_PASSWORD='rootsecret')
that already includes my settings for the global variables and my Create Database SQL file in the docker-entrypoint-initdb.d folder.
How do I add all my settings and create a new image to simply docker run mysql:config1 docker run mysql:config2 and so on?
You could build your own mysql docker image using a docker file, configure username, password and everything else you might need, build that image, upload it to the docker hub and then when you launch a new docker container you just use the previously built container.
An example of a Docker file to build an ubuntu image with a mysql server inside would be something like bellow (save it to a file called Dockerfile):
FROM ubuntu:latest
RUN apt-get update \
&& apt-get install -y apt-utils \
&& { \
echo debconf debconf/frontend select Noninteractive; \
echo mysql-community-server mysql-community-server/data-dir \
select ''; \
echo mysql-community-server mysql-community-server/root-pass \
password 'Desired-Password'; \
echo mysql-community-server mysql-community-server/re-root-pass \
password 'Desired-Password'; \
echo mysql-community-server mysql-community-server/remove-test-db \
select true; \
} | debconf-set-selections \
&& apt-get install -y mysql-server mysql-client
Then build your mysql docker container like this (you have to be in the folder where the Docker file was/is saved):
docker build my-ubuntu-mysql-docker
Then you have to push it to the docker hub and then you can use it to start a new docker container like this:
docker run -d -p 2222:22 -p 3306:3306 --name my-ubuntu-mysql-docker ...
Where 2222 is local ssh port mapped to ssh port 22 of the docker container and 3306 is local mysql port mapped to the mysql port of the docker container.
I hope this helps!
The following has to be written into the Dockerfile:
FROM mysql:latest
LABEL Name=mylabel Version=0.0.1
COPY path/to/sh/sql/sql.gz/files /docker-entrypoint-initdb.d
ENV MYSQL_ROOT_PASSWORD='rootpassword'
As stated in the documentation on the official docker website:
When a container is started for the first time, a new database with
the specified name will be created and initialized with the provided
configuration variables. Furthermore, it will execute files with
extensions .sh, .sql and .sql.gz that are found in
/docker-entrypoint-initdb.d. Files will be executed in alphabetical
order.
What you you would want to do is to modify Mysql's image entry point
and please note that you do not need to pass all the parameters, most of them are optional
I am trying another way to build a rails application into a docker image.
The structure of my services:
redis -- from official docker hub registry
fluentd -- from official docker hub registry
mysql -- from official docker hub registry
sidekiq -- build myself(maybe there isn't a official image for this)
web -- build myself
I created two Dockerfiles like:
Dockerfile.sidekiq
Dockerfile.web
Dockerfile.sidekiq
FROM ruby:2.2.2
ENV APP_HOME /myapp
RUN mkdir $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile $APP_HOME/Gemfile
ADD Gemfile.lock $APP_HOME/Gemfile.lock
ADD config/sidekiq.yml $APP_HOME/config/sidekiq.yml
ADD init_sidekiq.sh $APP_HOME/
RUN export LANG=C.UTF-8 && bundle install
ADD . $APP_HOME
CMD ["sh", "init_sidekiq.sh"]
init_sidekiq.sh
#!/bin/sh
bundle exec sidekiq -C config/sidekiq.yml
Dockerfile.web
FROM rails:4.2.1
ENV APP_HOME /myapp
RUN mkdir $APP_HOME
WORKDIR $APP_HOME
ADD Gemfile $APP_HOME/Gemfile
ADD Gemfile.lock $APP_HOME/Gemfile.lock
ADD init_web.sh $APP_HOME/
RUN export LANG=C.UTF-8 && bundle install
ADD . $APP_HOME
CMD ["sh", "init_web.sh"]
init_web.sh
#!/bin/sh
bundle exec rake db:create db:migrate
bundle exec rails server -b 0.0.0.0
Use them I built two images:
myapp_web
myapp_sidekiq
Then run these containers:
$ docker run --name redis -d redis
$ docker run --name fluentd -d -p 24224:24224 fluent/fluentd
$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=my_password -d mysql
Make env.list
RAILS_ENV=production
DATABASE_URL=mysql2://root:my_password#172.17.0.4/myapp?checkout_timeout=20000
Go on run these containers:
$ docker run --name web -d -p 3000:3000 --link mysql:mysql --env-file ./env.list myapp_web
$ docker run --name sidekiq -d --link mysql:mysql --env-file ./env.list myapp_sidekiq
The result:
redis -- success
fluentd -- success
mysql -- success
web -- success
sidekiq -- failure
The sidekiq log:
$ docker logs sidekiq
Unknown database 'myapp'
/usr/local/bundle/gems/activerecord-4.2.1/lib/active_record/connection_adapters/mysql2_adapter.rb:23:in `rescue in mysql2_connection'
I used the same method both web and sidekiq to connect mysql. I believe that in the mysql container there exists a myapp database. But why it can't find it?
Is it a wrong way to make them been two containers? How to run sidekiq correctly?
I think the problem there is how are you connecting to redis? The message appears to come from sidekiq and somehow it can't connect to your redis server. (and I think trying to connect to some bogus db server/database)
So I think you need to link your sidekiq container to both your db container and also your redis container.
docker run --name sidekiq -d --link mysql:mysql --link redis:redis --env-file ./env.list myapp_sidekiq
Also, would be nice if you can share your env.list
Tried copying a directory and it doesn't seem to work.
Start a MySQL container.
docker cp mysql:/var/lib/mysql .
cd mysql
ls
NOTHING.
Here's the script to try it yourself.
extra info.
On Ubuntu 14.04
jc#dev:~/work/jenkins/copy-sql/mysql$ docker -v
Docker version 1.2.0, build fa7b24f
In the Dockerfile for the image your container comes from, there is the VOLUME instruction which tells Docker to leave the /var/lib/mysql directory out of the container filesystem.
The docker cp can only access the container filesystem and thus won't see the files in mounted volumes.
If you need to backup your mysql data, I suggest you follow the instructions from the Docker userguide in section Backup, restore, or migrate data volumes. You might also find the discordianfish/docker-backup docker image useful for that task.
Here's a little example to illustrate your case.
given a simple Dockerfile with just a VOLUME instruction
$ cat Dockerfile
FROM base
VOLUME /data
build an image named test
$ docker build --force-rm -t test .
run a container named container_1 which will create two files, one being on the mounted volume
$ docker run -d --name container_1 test bash -c 'echo foo > /data/foo.txt; echo bar > /tmp/bar.txt; while true; do sleep 1; done'
make sure the container is running
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e97aa18ac83 test:latest "bash -c 'echo foo > 3 seconds ago Up 2 seconds container_1
use the docker cp command to cp file /tmp/bar.txt and check its content
$ docker cp container_1:/tmp/bar.txt .
$ cat bar.txt
bar
try the same with the file which is in the mounted volume (won't work)
$ docker cp container_1:/data/foo.txt .
2014/09/27 00:03:43 Error response from daemon: Could not find the file /data/foo.txt in container container_1
now run a second container to print out the content of that file
$ docker run --rm --volumes-from container_1 base cat /data/foo.txt
foo
It looks like you're trying to pass the name of your container to the docker cp command. The docs say it takes a container id. Try grepping for "CONTAINER ID" in your script instead.
EDIT:
Since changing your script to grep for the Container ID didn't help, you should start by trying this manually (outside of your script).
The docker cp command works. The reason it's not working for you is either:
a permission thing
you're not formatting the command correctly, or
the directory doesn't exist in your container.
With a running container id of XXXX, try this (using your container id):
sudo docker cp XXXX:/var/lib/mysql .
If this doesn't work, and you don't get an error, I'd maybe suggest that that directory doesn't exist in your container.
EDIT2:
As I said, it's one of the 3 things above.
I get this when I run your script:
2014/09/26 16:10:18 lchown mysql: operation not permitted
Changing the last line of your script to prefix with sudo now gives no errors, but no directory either.
Run the container interactively:
docker run -t -i mysql /bin/bash
Once inside the container:
cd /var/lib/mysql
ls
...no files.
So your script is working fine. The directory is just empty (basically #3 above).
For reference, the mysql Dockerfile is here.