In this topic, you will take your next step in studying Dockerfile instructions. You will learn two instructions that allow you to copy files from a host or another source to the image. You will also learn about the differences between these two instructions. After this, you will see two instructions that you can use to set variables for different purposes.
COPY instruction
When working with Docker, you have to copy files to an image quite often. The COPY instruction fulfills this exact role. Let's study it by looking at an example. First, let's find out the Ubuntu working directory when we launch a container. To do this, let's use a simple Dockerfile you are already familiar with.
FROM ubuntu:22.04
LABEL author=HyperUser
ENTRYPOINT ["pwd"]Running a container based on the Dockerfile above will print the working directory. If the image is ubuntu:v1, the output of running the container is:
$ docker run --name hs-ubuntu-1 ubuntu:v1
/So, the working directory is /. This is also the root directory. Now, let's create a simple demo.txt file and add it to the image. Then modify the Dockerfile into:
FROM ubuntu:22.04
LABEL author=HyperUser
# COPY source destination
COPY demo.txt /
ENTRYPOINT ["ls"]Here, the COPY instruction copies the specified file from the host/source working directory to the image/destination root directory.
You can also specify all of the content in your working directory to be copied to the image. In that case, the instruction will be COPY . /.
The ENTRYPOINT instruction will execute the ls command. If everything is correct, you will find the demo.txt file in the output. Let's check it:
$ docker run --name hs-ubuntu-2 ubuntu:v2
bin
boot
demo.txt
dev
etc
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
varThis instruction also supports the --chown flag. This flag can change the file owner available for Linux. To see how it works, let's first modify the Dockerfile and check the current demo.txt owner.
FROM ubuntu:22.04
LABEL author=HyperUser
Copy demo.txt /
ENTRYPOINT ["ls", "-l", "demo.txt"]For this Dockerfile, running the container will give the following result:
-rw-r--r-- 1 root root 0 Nov 16 10:54 demo.txt If you replace the third instruction of the Dockerfile above with COPY --chown=bin demo.txt /, the result will be:
-rw-r--r-- 1 bin bin 0 Nov 16 10:54 demo.txtIn addition to this, you can specify different users and groups explicitly using their names or IDs.
COPY --chown=0:1 demo.txt /
OR
COPY --chown=root:bin demo.txt /Let's move on to another docker instruction. The ADD instruction is similar to COPY but has some features that make it the better option in certain scenarios.
ADD instruction
Though the ADD instruction is similar to COPY it comes with two additional features:
The source can be a remote URL including git repositories.
The source can also be a
tararchive ofidentity,gzip,bzip2, orxzcompression formats.
ADD instruction operates just as the previous instruction, so it also supports the --chown flag. In case the file is a supported archive format, Docker will automatically unpack it. You can easily check this.
Assuming you have a demo.txt file, archive it using the tar -czf demo.txt.tar.gz demo.txt command. Modify the last Dockerfile from the previous section by replacing COPY demo.txt / with ADD demo.txt.tar.gz / instruction. If everything goes well, the ls command will print the content of the root directory. There you will find the demo.txt file.
What about the remote files or git repositories? You must specify the URL for files that are not present in your physical storage drive. For this purpose, Docker provides the --checksum flag to ensure data from the remote repository isn't corrupted.
Docker also allows you to work with environment variables. Let's look at the ENV instruction in action.
ENV instruction
If you're familiar with environment variables on Linux, the ENV instruction will be easier to grasp. Docker lets you declare environment variables to use inside images. The command format is ENV <key>=<value> where both key and value can be set with or without double quotes.
Let's take the Dockerfile from the previous snippet and modify it.
FROM ubuntu:22.04
LABEL author=HyperUser
ENV HOST_FILE=demo.txt
ENV IMAGE_DESTINATION="/tmp"
COPY $HOST_FILE $IMAGE_DESTINATION
ENTRYPOINT ["ls", "/tmp"]It performs the same operation – copies from the host to the image's /tmp directory. But this time, paths are set with environment variables. When you run a container using mentioned Dockerfile, the output will be demo.txt.
You can also set environment variables when running the container and access them while the container is running. For that purpose, Docker has --env or -e flags. To check this feature you need a new Dockerfile.
FROM ubuntu:22.04
LABEL author=HyperUser
ENTRYPOINT ["/bin/bash"]While running a container in interactive mode, you can access its value like this:
$ docker run -e ENV=my_env -it --name hs-ubuntu-v1 ubuntu:v1
root@f35edcae09a3:/# echo $ENV
my_envNow, let's move on to ARG instruction and explore its similarities as well as differences with the ENV instruction.
ARG instruction
The ARG instruction has a similar role to the ENV instruction. But it has one key difference. Though you declare it in a Dockerfile, Docker assigns the value during image build time. To see this in action, let's update the Dockerfile used to define ENV variables from the previous section.
ARG VERSION
FROM ubuntu:$VERSION
LABEL author=HyperUser
ENV HOST_FILE=demo.txt
ENV IMAGE_DESTINATION="/tmp"
COPY $HOST_FILE $IMAGE_DESTINATION
ENTRYPOINT ["ls", "/tmp"]Build the image by specifying the Ubuntu version with the ARG instruction.
$ docker build --build-arg VERSION=22.04 -t ubuntu:v1 .
Sending build context to Docker daemon 13.82kB
Step 1/7 : ARG VERSION
Step 2/7 : FROM ubuntu:$VERSION
22.04: Pulling from library/ubuntu
e96e057aae67: Pull complete
Digest: sha256:4b1d0c4a2d2aaf63b37111f34eb9fa89fa1bf53dd6e4ca954d47caebca4005c2
Status: Downloaded newer image for ubuntu:22.04
---> a8780b506fa4If you look at the output of the building process in step two, you'll see that Docker pulls version 22.04 as expected.
Note, that these variables can also have a default value. You can assign a value to the ARG variable inside the Dockerfile. They will be overridden if you pass the value when building the image.
Conclusion
You have dealt with another group of Docker instructions. You now know how to copy files from different sources into an image and set owners for them. Another important knowledge you gained in this topic is the two types of instructions you can use to work with variables. You explored how to declare variables and assign values during image build time or when running a container. If you think you're ready, let's practice what you have learned.