I am building a Django application with docker.
I would like to know for Django or general development work using docker, what files are typically included in the .dockerignore.
I am thinking of the following for now:
.git
*.pyc
You may have noticed that if you put a Dockerfile in your home, and launch a docker build you will see a message uploading context, this means docker creates a .tar with all the files in your home and in all the subdirectories, and uploads this tar to the docker daemon.
If you have some huge files, this may take a long time.
So to avoid this you may
1) create a specific directory, where you put your Dockerfile, and all what is needed for your build
2) tell docker to ignore some files during the build
So you may put in the .dockerignore all the files not needed for your build
This what I typically put in .dockerignore for dockerized Django apps
**/*.pyc
**/*.pyo
**/*.mo
.gitignore
.git/
**/__pycache__/
Dockerfile
db.sqlite3
**/*.md
Related
I have a question about the .dockerignore workflow which I wasn't really able to understand while browsing through the documentation and different internet topics.
Have the following folder structure:
home
|
|- folder_1
|- folder_2
Inside my dockerfile I want to copy the contents of home directory, so I use
COPY ./ /home
Inside .dockerignore I have:
*
!folder_1
!folder_3
I am referring to a non-existent folder - folder_3, which is supposed to be copied, right?
I ran it and it looks like there's no problem with that, thus .dockerignore somehow manages this situation.
If I tried to do the same thing without using .dockerignore, targeting a non-existent directory I would get an error.
If anybody can please clear this workflow, or if a duplicate, please attach some information so I can educate myself.
Thanks in advance!
First of all, .dockerignore works like .gitignore. Inside these files you set the rules on the basis of which files should be added, and which should not.
In your scenario you COPY the whole home directory which consists of folder_1 and folder_2. Your .dockerignore file sets the following rules:
* # ignore all files/directories
!folder_1 # do not ignore folder_1
!folder_3 # do not ignore folder_3
Regardless of whether there is a folder_1 or folder_3 in your local home directory or not, it won't show you any errors, because it just tries to find particular files/directories that are inside .dockerignore. If it finds this file/directory, it applies the rules. If it doesn't find this file/directory, it doesn't do anything with it.
Hope that's a little bit more clear now.
You'll occasionally see reference to a Docker build context. The build has two steps:
The docker build client application creates a tar file of its directory parameter, and sends it in an HTTP request to the Docker daemon.
The Docker daemon unpacks the tar file, finds the Dockerfile in it, and runs it using the file content it was given.
.dockerignore only affects the first step: it keeps docker build from sending the Docker daemon particular files. The .dockerignore file doesn't require there to be a folder_3 directory, it just says that if there is one it shouldn't be excluded. The second step on the Docker daemon side doesn't use .dockerignore at all, and when you COPY . /somewhere it copies the entire build context; that is, whatever was sent in the API request.
There are a couple of practical consequences of this workflow. If you have a very large local directory it can take time to send it to the Docker daemon, and the Docker daemon keeps a duplicate copy of it during the build, so it's often worthwhile to .dockerignore your .git directory and a build tree. This setup is also how docker build works with a Docker daemon on a different system or in a VM, and it's why if you try to COPY a file by name that doesn't exist (COPY folder_3 somewhere) you get an error message referencing a Docker-internal path.
In a Dockerfile I want to copy a file relative to my local home inside the images's home.
So I have tried many variations of:
COPY "~/.m2/settings.xml" "$HOME/.m2/settings2.xml"
But I get errors like
COPY failed: stat /var/lib/docker/tmp/docker-builder635958043/~/.m2/settings.xml: no such file or directory
How can I copy a file relative to my local home inside the image?
The source for the COPY command is the build context. The build context is included in the last argument to the docker build command, often a . which means the current directory. This location is sent to the docker engine before running any steps of the Dockerfile, using a tar file, in the default/classic builder. Therefore, to keep builds running fast, you want to keep this directory small by not sending over the entire hard drive contents. This is even more important when building locally since you could potentially start sending files recursively if you were to include docker's temporary directory in the folders being sent.
All this means you should move any files you want to include in the COPY source parameter to be inside the build context, typically the same location as your Dockerfile.
I built a .jar file that accesses an .xml file
I add this jar file to docker via a Dockerfile
But how do I add this xml file to the docker image?
According to the Dockerfile best practices, the COPY command is preferred on the ADD command:
Although ADD and COPY are functionally similar, generally speaking, COPY is preferred.
recommended reading for your task:
The "ADD or COPY" section in the Dockerfile best practices.
Docker Tip #2: The Difference between COPY and ADD in a Dockerfile
ADD test-harness.xml test-harness.xml
This basically adds the .xml file to the Docker image and makes it accessible to the jar file which was added in a similar way.
In a Dockerfile, I have
COPY . .
I want to exclude an entire directory, in my case, node_modules directory.
Something like this:
COPY [all but **/node_modules/**] .
Is this possible with Docker?
Create file .dockerignore in your docker build context directory (so in this case, most likely a directory that is a parent to node_modules) with one line in it:
**/node_modules
although you probably just want:
node_modules
Info about dockerignore: https://docs.docker.com/engine/reference/builder/#dockerignore-file
For those who can't use a .dockerignore file (e.g. if you need the file in one COPY but not another):
Yes, but you need multiple COPY instructions. Specifically, you need a COPY for each letter in the filename you wish to exclude.
COPY [^n]* # All files that don't start with 'n'
COPY n[^o]* # All files that start with 'n', but not 'no'
COPY no[^d]* # All files that start with 'no', but not 'nod'
Continuing until you have the full file name, or just the prefix you're reasonably sure won't have any other files.
FOR A ONE LINER SOLUTION, type the following in Command prompt or Terminal at project root.
echo node_modules >> .dockerignore
This command appends "node_modules" in the .dockerignore file. If the .dockerignore does not exist already, it will create a new one. Replace node_modules with the folder you want to exclude.
Warning:
If you are new to Docker ecosystem and/or you already have the .dockerignore file in your project, please take a backup before proceeding.
BONUS: (as pointed out by Joey Baruch)
(To CREATE/OVERWRITE the .dockerignore file via PowerShell, which can be handled by Docker):
>> echo node_modules | Out-File -Encoding UTF8 .dockerignore
Excluding node_modules from current directory
node_modules
Excluding node_modules in any immediate subdirectories
*/node_modules
Here is the official docs
For those using gcloud build:
gcloud build ignores .dockerignore and looks instead for .gcloudignore
Use:
cp .dockerignore .gcloudignore
Source
Adding .dockerignore works for me.
One additional point Those who are trying this solution on Windows , windows will not let you create .dockerignore file (as it doesn't by default allows creating file starting with .)
To create such file starting with . on Windows, include an ending dot also, like : .dockerignore. and hit enter ( provided you have enabled view extension options from folder options )
I used a multi stage build approach since I needed one stage to have access to the file but not another stage so .dockerignore wouldn't work:
FROM ruby AS builder
COPY app/ app/
# Do stuff with app
# remove the stuff you don't want
RUN rm -Rf app/assets
FROM ruby AS publish
# In my real version I needed the absolute path to builder WORKDIR.
# Since I'm copying from the builder stage, app/assets won't exist
# and neither will it be part of the publish image.
COPY --from=builder app app
in my dockerfile I have these two lines:
ADD /ansible/inventory /etc/ansible/hosts
ADD /ansible/. /ansiblerepo
The first line works, as I can run the container and see my hosts file has been populated with all the ips from my inventory file.
The second line doesn't appear to be working though. I'm just trying to copy all the files/subdirectories of ansible and copy them over to the ansiblerepo directory inside the new container.
There are no errors while building the image, but again ansiblerepo is just an empty directory and nothing has copied over to it. I assume I'm just missing a back slash or something.
Docker ADD and COPY commands work relative to the build directly, and only for files in that directory that weren't excluded with a .dockerignore file. The reason for this is that builds actually run on the docker host, which may be a remote machine. The first step of a docker build . is to package up all the files in the directory (in this case .) and send them to the host to run your build. Any absolute paths you provide are interpreted as relative to the build directory and anything you reference that wasn't sent to the server will be interpreted as a missing file.
The solution is to copy /ansible to your build directory (typically the same folder as your Dockerfile).
Make sure that in your ".dockerignore" file, it does not excluded everything. usually, dockerignore file has these lines
*
!obj\Docker\publish\*
!obj\Docker\empty\
this means that everything is ignored except publish and empty folders.
Removing trailing /. from source directory should fix the ADD command.
On a related note, Docker Best Practices suggest using COPY over ADD if you don't need the URL download feature.