I have two custom images. One is for developing websites using next.js and the other is to develop APIs.
My company/site image is like:
FROM node:lts-bullseye-slim
# the rest of it
And my company/api image is like:
ARG VARIANT="6.0-bullseye-slim"
FROM mcr.microsoft.com/vscode/devcontainers/dotnet:${VARIANT}
# the rest of it
The problem is that, the COPY commands works when I use company/api as my FROM image, but fails when I use company/site.
In other words, this works:
FROM company/api
COPY . .
RUN /buildScript.sh
But for the same directory, the same context, the same everything, this fails:
FROM compnay/site
COPY . .
RUN /buildScript.sh
In other words, COPY copies no file to the image. Everything is the same. There is no .dockerignore file. The same directory, the same context, the same syntax docker build -t company/api-or-site .
The only thing that causes this fail, is changing the base image.
What can cause this error? How can I debug this?
After spending days on this, I finally realized what the problem was.
When you create a custom image using a Dockerfile, if you use the WORKDIR command, then that would be the . in your future COPY commands.
Consider the following image:
FROM node:lts-bullseye-slim
# Your specific commands
WORKDIR /project
Let's say you build this image and tag it company/node.
Now if you want to use it as the base image for another image, and COPY . . files, then those files would be copied to the /project directory.
FROM company/node
COPY . . # here, the second dot means the relative path inside the company/node image
Related
I'm a newbie to docker, sorry if my question is too basic. I saw dockerfile like this:
FROM diamol/maven AS builder
WORKDIR /usr/src/iotd
COPY pom.xml .
RUN mvn -B dependency:go-offline
COPY . .
RUN mvn package
FROM diamol/openjdk
WORKDIR /app
COPY --from=builder /usr/src/iotd/target/iotd-service-0.1.0.jar .
EXPOSE 80
ENTRYPOINT ["java", "-jar", "/app/iotd-service-0.1.0.jar"]
I'm confused about COPY . . instruction, what does the first period and second period COPY . . mean?
Also, if I want to copy all files of the current working directory from my host machine into the image, then how can I modify COPY . . so that the first period means currenty directory of my machine?
In the Dockerfile COPY directive, the last argument is the path inside the container, relative to the current WORKDIR. All of the preceding arguments are paths inside the build context, the host directory passed as an argument to docker build.
I want to copy all files of the current working directory from my host machine into the image, then how can I modify COPY . . ...?
You probably don't need to. So long as you docker build . naming the current directory . as the last argument, that's exactly what COPY . . does. That instruction means to copy . – the entirety of the build context, from the original host system – to . – the current directory, inside the image.
WORKDIR /usr/src/iotd # `COPY anything .` will put it here inside the image
COPY pom.xml . # Copy a single file into that WORKDIR
COPY . . # Copy the entire build context into the WORKDIR
I've mentioned "build context" a couple of times. That is the directory argument to docker build
docker build \
-t myname/some-image: tag \
. # <--- the build context directory
or that you specify in a docker-compose.yml file
version: '3.8'
services:
one:
build: ./one # <-- this directory
two:
build:
context: ./two # <-- this directory
except that the files mentioned in a .dockerignore file are removed first.
In the question title you also ask
does dockerfile's instruction execute in order?
They do. The newer BuildKit backend has some capability to execute build stages not necessarily in the order they're written, but it ensures that you get the same results as if all of the COPY and RUN instructions from a previous stage had run before a COPY --from=... in a later stage happens.
From my perspective, one of the best ways to know all the details for COPY and WORKDIR docker commands is to go through following official documentation.
You can either search for COPY and WORKDIR keywords on the home page at below first link or please refer to last two links and find all the details including examples.
https://docs.docker.com/engine/reference/builder/
https://docs.docker.com/engine/reference/builder/#copy
https://docs.docker.com/engine/reference/builder/#workdir
I'm building a multistage docker image where we have a base image that will be extended to build the actual final image. However I can't seem to copy files that are coming from the parent image into the child.
Base image
FROM debian:10.9-slim AS base
# PHP Version
ONBUILD ARG PHP_VERSION
ONBUILD ENV PHP_VERSION=${PHP_VERSION:-7.4}
# More stuff.
...
# Copy PHP settings into the image
COPY ./php/pool.d/*.conf /build-php/pool.d/
COPY ./php/conf.d/*.ini /build-php/conf.d/
# Onbuild copy the settings to the correct PHP version
ONBUILD COPY /build-php/pool.d/*.conf /etc/php/${PHP_VERSION}/fpm/pool.d/
ONBUILD COPY /build-php/conf.d/*.ini /etc/php/${PHP_VERSION}/fpm/conf.d/
ONBUILD COPY /build-php/conf.d/*.ini /etc/php/${PHP_VERSION}/cli/conf.d/
Specific image
ARG PHP_VERSION=8.0
FROM abcdef.amazonaws.com/php-base:v1.14.0 AS base
When building the secondary image I get the following error
$ docker build -t php8.0:base .
...
=> ERROR [7/1] COPY /build-php/pool.d/*.conf /etc/php/8.0/fpm/pool.d/ 0.0s
------
> [7/1] COPY /build-php/pool.d/*.conf /etc/php/8.0/fpm/pool.d/:
------
lstat /var/lib/docker/tmp/buildkit-mount474178567/build-php/pool.d: no such file or directory
I checked the parent image and the files are copied fine into /build-php. Also when building the child image (with the onbuild copy disabled) the files are present at /build-php. I don't understand why the onbuild copy can't find the files.
COPY always copies files from the host system (more specifically from the Docker build context); if it's run ONBUILD then it forces the derived image's build context (source tree) to have a specific layout.
In this setup, the files are already in the base image (in /build-php) and so you need to RUN cp /build-php/... /etc/php/... to move the files within the image.
Using ONBUILD, in general, can make it hard to reason about what steps are happening when, and can lead to confusing side effects. Rather than having one base image, which eventually will install and configure some version of PHP, the setup might be easier if you have a fully-configured base image for each version of the interpreter you use.
# For simplicity, use the Docker Hub base image
# (There can be good reasons to build your own)
ARG PHP_VERSION=7.4
FROM php:${PHP_VERSION}
ARG PHP_VERSION
# Copy PHP settings into the image
COPY ./php/pool.d/*.conf /etc/php/${PHP_VERSION}/fpm/pool.d/
COPY ./php/conf.d/*.ini /etc/php/${PHP_VERSION}/fpm/conf.d/
COPY ./php/conf.d/*.ini /etc/php/${PHP_VERSION}/cli/conf.d/
docker build \
--build-arg PHP_VERSION=8.0 \
-t abcdef.amazonaws.com/php-80-base:v1.14.0 \
.
I want to extend the existing redis:6.0-alpine image from docker-hub and want to add my configuration file in the container.
For that I've created this dockerfile
FROM redis:6.0-alpine
WORKDIR .
COPY redis.master.conf ./config/redis.conf
but when building a container from this image, there is nothing copyed at the specified location.
Setup:
wsl2 (ubuntu 18.04 distro)
windows 10
docker-for-windows (v20.10.2)
Some help ?
Just tested myself, and it's copied without issues.
Where are you trying to look for the file? Notice the entry directory of this image is not /, it's /data, hence your file is on /data/etc/redis.conf
This is because WORKDIR is set to . in your dockerfile, which means current working directory. If you look at the official dockerfile of redis:6.0-alpine, the WORKDIR is set to /data.
Hence according to your dockerfile, you are copying the redis.master.conf file to ./ which means /data. Please check your file at /data/etc/redis.conf. I tried this at my end and can confirm this behavior.
If you want to copy it at /etc/redis.conf then remove ./ before /etc.
I am confused about whether . means that it's a shortened abbreviation of the current directory of the image or if it's the current working directory on the local machine. Or is it the same meaning of . in most console commands like essentially selecting all in the current directory.
COPY somecode.java .
#copy the rest of the code
COPY . .
The . also seems to mean find the docker file in the current directory.
docker build -t image-tag .
The . simply means "current working directory"
docker build
In the context of the docker build command, you are using it to signal that the build context for docker build is the current working directory. Like so:
docker build -t mytag:0.1 .
Let's say that you have this structure:
/home/me/myapp/
├── Dockerfile
├── theapp.py
And you invoke the docker build command from /home/me/myapp - you will pass the current working directory as the build context. This means that docker will see the following filestructure when building:
/
├── Dockerfile
├── theapp.py
Dockerfile
In the context of a Dockerfile, it means that same. Both inside and outside the image.
Take this COPY instruction for example:
COPY . /app
Here the . means the current working directory, where the docker build command is executed. This will be relative the to build context that is passed to the docker build command.
For this COPY instruction:
COPY theapp.py .
It means, take the file theapp.py and copy it to the working directory of the docker image that is being built. This directory can be set at build time with the WORKDIR instruction, so that:
WORKDIR /app
COPY theapp.py .
Would leave you with the file /app/theapp.py inside the resulting docker image.
Finally, this COPY instruction:
COPY . .
Means take everything from the working directory where the docker build command is issued, relative to the build context that is passed to it. And copy it to the current working directory of the docker image.
I saw 3 . characters on your question, so let me expand one by one.
The first, as you imagine, the . character means the current directory.
In your Dockerfile
COPY . .
The second dot represented the current location on your virtual machine. Whenever you run cd command in the Dockerfile. That may be easy to understand.
The first dot more unintelligible a little. The first dot character represented the current location on your host machine. The location you input after docker build command like that:"docker build [options] <location>".
Docker build command
The dot character means the current directory whenever you call your docker build command. For example:
[~]$ docker build .
The dot character represented for default home directory of this user on your real machine.
It depends on the context. In your COPY somecode.java . it's the image. In COPY . . it's both. The first dot is in the local machine and the second dot is the image.
In the docker build command, it tells Docker to take files for the newly built image from the working directory on your local machine.
As others said, it's basically just means "current working directory". But when building a Docker image, there are two of those. One in your local machine where you're building the image. The second one is the file system that's built in the image.
.(dot) means current working directory.
I have a Dockerfile that creates the build image I want to use here: ~/build/Dockerfile then I use a standard image to deploy
The image built from ~/build/Dockerfile is not Published anywhere, I know I can simply copy paste the one Dockerfile into the other, however it would be better if I could simply reference it so..
Is it possible to somehow reference the Dockerfile itself when deploying?
like so:
FROM [insert something that creates an image using ~/build/Dockerfile] as build-env
... build operations ....
FROM some-image
COPY --from=build-env /built .
ENTRYPOINT [blah]
This won't work but is there some other way to accomplish this?
No you can't do it because you have to provide an image to FROM.
Change the COPY line to
COPY --from=step1 /built .
And write a script to build your image:
cd path1
docker build -t step1 .
cd path2
docker build -t final_image .
(if you don't want to hard code step1 in the Dockerfile, replace it with a var and call with ARG)
Generally things in Docker space like the docker run command and the FROM directive will use a local image if it exists; it doesn't need to be pushed to a repository. That means you can build your first image and refer to it in the later Dockerfile by name. (There's no way to refer to the other Dockerfile per se.)
Newer versions of Docker have an extended form of the Dockerfile COPY command which
accepts a flag --from=<name|index>.... In case a build stage with a specified name can’t be found an image with the same name is attempted to be used instead.
So if you ahead of time run
docker build -t build-env ~/build
then the exact syntax you show in your proposed Dockerfile will work
FROM some-image
COPY --from=build-env /built .
and it doesn't matter that the intermediate build image isn't actually pushed anywhere.