Docker, copy files in production and use volume in development - docker

I'm new to using docker for development but wanted to try it in my latest project and have ran into a couple of questions.
I have a scenario where I want to link the current project directory as a volume to a running docker container in development mode, so that file changes can be done locally without restarting the container each time. To do this, I have the following comand:
docker run --name app_instance -p 3100:80 -v $(pwd):/app appimage
In contrast, in production I want to copy files from the current project directory.
E.G in the docker file have ADD . /app (With a .dockerignore file to ignore certain folders). Also, I would like to mount a volume for persistent storage. For this scenario, I have the following command :
docker run --name app_instance -p 80:80 -v ./filestore:/app/filestore appimage
My problem is that with only one dockerfile, for the development command a volume will be mounted at /app and also files copied with ADD . /app. I haven't tested what happens in this scenario, but I am assuming it is incorrect to have both for the same destination.
My question is, what is the best practice to handle such a situation?
Solutions I have thought of:
Mount project folder to different path than /app during development and ignore the /app directory created in the container by the dockerfile
Have two docker files, one that copies the current project and one that does not.

My problem is that with only one dockerfile, for the development command a volume will be mounted at /app and also files copied with ADD . /app. I haven't tested what happens in this scenario, but I am assuming it is incorrect to have both for the same destination.
For this scenario, it will do as follows:
a) Add your code in host server to app folder in container when docker build.
b) Mount your local app to the folder in the container when docker run, here will always your latest develop code.
But it will override the contents which you added in dockerfile, so this could meet your requirements. You should try it, no need for any complex solution.

Related

I want to write a docker file where my container can load db file from a directory and past it to application directory and on exit wrtie it back

I am working with Golang application that saves the information inside sqlite file and that resideds inside the data/sqlite.db same directory as docker file. My docker file is something like this
p.s: guys it's my very first docker file please be kind to me :(
FROM golang:1.16.4
ENV GIN_MODE=release
ENV PORT=8081
ADD . /go/src/multisig-svc
WORKDIR /go/src/multisig-svc
RUN go mod download
RUN go build -o bin/multisig-svc cmd/main.go
EXPOSE $PORT
ENTRYPOINT ./bin/multisig-svc
I deployed this application to the Google cloud plateform but somehow the container gets restarted there and after that my db is vanished. So i researched and try to use volumes.
I build the container using this command docker build -t svc . and then run it with docker run -p 8080:8081 -v data:/var/dump -it svc but i can not see the data folder is getting copied to /var/dump directory. My basic idea is , Whenever the container start it loads the db file from dump and then past it to data directory so application can use it and when it exits it copy it back to dump directory. I don't know if i am on right track any help would really be appreciated.
#Edit
The issue is when no request arrives for 15 minutes GPC shut down the container and start it when there comes a request again. Now the issue is to somehow fetch the db file from dump directory update it and write it back to the dump dir when container goes down for future use.
For a local run and if you are running on a VM, you need to specify the absolute path of the directory you want to mount as a bind mount into your directory. In this case something like that should work
docker run -p 8080:8081 -v $(pwd)/data:/var/dump -it svc
When you don't specify the absolute path, the volume you're mounting to your running container is a named volume manage by the docker daemon. And it is not located in a path related to your current working directory. You can find more information about how work docker volumes here https://docs.docker.com/storage/volumes/
However there are multiple environment on GCP (app engine, kubernetes, VMs), so depending on your environment you may need to adapt this solution.

Developing in docker-compose. Getting the container to recognise code changes

I have a docker-container with a Python3 environment and various libraries installed.
I'm trying to develop a simple Python program against this environment.
So what I have is a volume with my source code outside the container which is ADDed and set as WORKDIR in the Dockerfile.
I'm then shelling into the container and trying to run the program on the command-line.
When I hit an error, I want to simply change the source in my editor which is outside the container, and run again.
However, when I do this, the executing code in the container doesn't seem to be taking any notice of the changes I made.
If I do
docker-compose up --build
and rebuild the container then it does.
Obviously this is very slow.
Surely it should be possible for the container to see changes to the code I'm working on without being rebuilt? If so, how do I make this happen?
Using ADD bakes files into a container image, so as you've noticed, updating files in a running application requires an entire container rebuild and restart. To get around this, you can mount a directory on your host machine over the path you've copied into your container using ADD.
To do this with Docker, you can use -v or --volume. Using Docker Compose, you can list the directory to be mounted under volumes:. For example, if you had the following in your build file:
# Copy app code into the container working directory
ADD /my/app/code /usr/app/src
You can then mount your live code over the baked-in files at container start time (note that directory paths must be absolute - you can use $PWD for this):
$ docker run -v /my/live/app/code:/usr/app/src python:latest
$ docker run -v "$PWD"/app/code:/usr/app/src python:latest
The docker-compose.yml equivalent is as follows:
my-service:
image: python:latest
volumes:
- /my/live/app/code:/usr/app/src
- ./relative/paths:/work/too
There's more about bind mounts in the documentation.

How to keep changes inside a container on the host after a docker build?

I have a docker-compose dev stack. When I run, docker-compose up --build, the container will be built and it will execute
Dockerfile:
RUN composer install --quiet
That command will write a bunch of files inside the ./vendor/ directory, which is then only available inside the container, as expected. The also existing vendor/ on the host is not touched and, hence, out of date.
Since I use that container for development and want my changes to be available, I mount the current directory inside the container as a volume:
docker-compose.yml:
my-app:
volumes:
- ./:/var/www/myapp/
This loads an outdated vendor directory into my container; forcing me to rerun composer install either on the host or inside the container in order to have the up to date version.
I wonder how I could manage my docker-compose stack differently, so that the changes during the docker build on the current folder are also persisted on the host directory and I don't have to run the command twice.
I do want to keep the vendor folder mounted, as some vendors are my own and I like being able to modifiy them in my current project. So only mounting the folders I need to run my application would not be the best solution.
I am looking for a way to tell docker-compose: Write all the stuff inside the container back to the host before adding the volume.
You can run a short side container after docker-compose build:
docker run --rm -v /vendor:/target my-app cp -a vendor/. /target/.
The cp could also be something more efficient like an rsync. Then after that container exits, you do your docker-compose up which mounts /vendor from the host.
Write all the stuff inside the container back to the host before adding the volume.
There isn't any way to do this directly, but there are a few options to do it as a second command.
as already suggested you can run a container and copy or rsync the files
use docker cp to copy the files out of a container (without using a volume)
use a tool like dobi (disclaimer: dobi is my own project) to automate these tasks. You can use one image to update vendor, and another image to run the application. That way updates are done on the host, but can be built into the final image. dobi takes care of skipping unnecessary operations when the artifact is still fresh (based on modified time of files or resources), so you never run unnecessary operations.

Is there a way to replicate pwd in a volume mount for docker in a boot2docker context?

So currently I can do: docker -v .:/usr/src/app or even specify it in my docker-compose.yml:
web:
volumes:
- .:/usr/src/app
But when I attempt to define this in my Dockerfile:
VOLUME .:/usr/src/app
It doesn't mount anything.
Now I understand the complexities in that I'm using OSX and so I have to virtualize the environment to run Docker via boot2docker, and that boot2docker solves the copy issue by mounting /User to the linux machine running Docker.
The documentation wants me to be explicit, but since my explicitness would require me to name my user (in this case /User/krainboltgreene/code/krainboltgreene/blankrails) it seems non-idiomatic, as that obviously doesn't work on other people's environments.
What's the solution for this? I mean, I can technically get this all working without (as noted above the CLI and compose works fine), but it means not being able to do project specific provisioning (bower install, npm install, vulcanize, etc).
You can't specify a host directory for a volume inside a Dockerfile, because of the portability reasons you mention (not everyone will have the same directories and there are security issues regarding mounting sensitive files).
If you instead do:
VOLUME /usr/src/app
Docker will automatically set up a volume at run-time for the folder, which will be mapped to a directory under /var/lib/docker/volumes.
If you want to be able to quickly make changes during development, I would suggest using COPY in the Dockerfile, but mounting local changes over the top with a volume at run-time. This has the disadvantage that if you volume mount a folder, all the contents of that directory in the container will be hidden (rather than merged).
The docker run -v .:/usr/src/app ... command as well as the docker-compose definitions are executing during runtime. Whereas the Dockerfile instructions are executed during build time.
By the way the instruction in your Dockerfile is syntactically incorrect. It should be VOLUME /usr/src/app instead.
That VOLUME keyword only defines that later during runtime this location will be stored on a volume. So all files that you add by further Dockerfile instructions or manual commits to that location are ignored and not added to the resulting image.
Now during runtime when you did not specify a volume it Docker will generate a volume for you which is empty by default.
To have your docker-compose setup working for other colleagues you could simply make the docker-compose configuration file being part of your blankrails project folder. Everybody then runs docker-compose from within that directory and your provided configuration will work.
EDIT:
I do not know exactly what you mean with project specific provisioning. But if your aim is to provide default contents for the defined volume you could do something like the following:
Add all required project files during the Dockerfile build to a /bootstrap folder on the image.
Instead of executing your app directly use a start shell script for CMD.
In that start script you can check whether the volume mounted to /usr/src/app is empty or not. When it is empty copy all the /bootstrap contents into it.
Afterwards start your app from within that script in foreground.
With that approach you can easily provide a default file set for mounted volumes. And when you re-use that volume e.g. after a container restart the container just works with the files that are on the volume without touching them again during startup. So modified files will be persisted.

Assetss from wwwroot cannot be found on Docker Image

I have got Linux VM Docker Image up and running but I have encountered one difficulity.
All assetss that were in my wwwroot folder cannot be found
Failed to load resource: the server responded with a status of 404 (Not Found)
I have included
"webroot": "wwwroot"
In project.json file but that doesn't fix the problem. One more thing is thaht running from VS 2015 (on ISS Express) everything works - is there something that I should include in Dockerfile as well?.
EDIT:
I added VOLUME to docker file but that did not help:
FROM microsoft/aspnet
COPY . /app
WORKDIR /app
RUN ["kpm", "restore"]
VOLUME ["/wwwroot"]
EXPOSE 5004
ENTRYPOINT ["k", "kestrel"]
are you working through the example here: asp ? I don't know much about asp, but, I think you are pretty close. First, I don't think you need to modify the Dockerfile. You can always mount a volume, the VOLUME keyword just declares it as necessary. But, you do need to modify your project.json file like you have shown, with one difference:
"webroot": "/webroot"
I am assuming that the name is "webroot" and the directory to look in (for the project) is "/webroot". Then, build it, like the example shows:
docker build -t myapp .
So, when you run this do:
docker run -t -v $(pwd)/webroot:/webroot -d -p 80:5004 myapp
What this docker run command does is takes your webroot directory from the current directory ($pwd) and mounts it in the container and calls that mount /webroot. In other words, you container must reference /webroot (not webroot, that would be relative to WORKDIR I think).
I think the bottom line is there are two things going on here. The first one is 'building' the image, the second one is running it. When you run it you provide the volume that you want mounted. As long as you application repects the project.json file's "webroot" value as the place to look for the web pages then this will work.

Resources