Please help me understand the difference between 'image' and 'build' within docker compose
image means docker compose will run a container based on that image
build means docker compose will first build an image based on the Dockerfile found in the path associated with build (and then run a container based on that image).
PR 2458 was eventually merged to allow both (and use image as the image name when building, if it exists).
therobyouknow mentions in the comments:
dockerfile: as a sub-statement beneath build: can be used to specify the filename/path of the Dockerfile.
version: '3'
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
build: expects dockerfile path as an argument, it will build an image first and then use the image to create a container.
image: expects existing image name as argument , it will launch container using this image.
Example:docker-compose.yaml
version: '3'
services:
service1:
build: .
ports:
- "5000:5000"
service2:
image: "redis:alpine"
service1 will build an image first based on Dockerfile of current path and run container based on this image.
service2 will download "redis:alpine" image from docker hub and run container on downloaded image.
Related
I am trying to build the two services with the same image, but two different Dockerfile. However Docker will always use only one Dockerfile for both, even though two have been defined:
version: '3.4'
services:
serviceA:
image: myimage
build:
dockerfile: ./Dockerfile
context: ${project.basedir}/${project.artifactId}-docker/target
depends_on:
- serviceB
serviceB:
image: myimage
build:
dockerfile: ./Dockerfile-cloud
context: ${project.basedir}/${project.artifactId}-docker/target
Even though I also say dependsOn, running
docker-compose up -f docker-compose.yml
it only used the Dockerfile-cloud for both.
I guess your problem is that you tag your image as myimage (using latest by default). So docker will build a first version of myimage with Dockerfile, then it'll build another version of myimage with Dockerfile-cloud, and in the end it will only use the latest version. This is why it will use Dockerfile-cloud for both. To fix it remove image: myimage or do something like:
serviceA:
image: myimage:serviceA
...
serviceB:
image: myimage:serviceB
Since you're building the two containers' images from different Dockerfiles, they can't really be the same image; they'll have different content and metadata.
Compose is capable of assigning unique names for the various things it generates. Unless you need to do something like docker-compose push built images to a registry, you can generally just omit the image: line. The two containers will use separate images built from their own Dockerfiles, and the Compose-assigned names will avoid the ambiguity you're running into here.
version: '3.8'
services:
serviceA:
# no image:
# short form of build: with default dockerfile: and no args:
build: ${project.basedir}/${project.artifactId}-docker/target
depends_on:
- serviceB
serviceB:
# no image:
build:
context: ${project.basedir}/${project.artifactId}-docker/target
dockerfile: ./Dockerfile-cloud
What I am trying to do is if an image is not present on private docker repository then build that image from source code with docker-compose.
E.g.
version: '3.4'
webapp:
image: private_ecr_repo.amazonecr.com/webapp:latest
build:
context: "."
So when the image doesn't exists on private_ecr_repo, I'm looking to build it from local source.
PS: I have looked at docker-compose build --pull docker-compose up --no-build but they do not have the behaviour I am looking for .
From the documentation, when image attribute is used with build context in docker-compose file, the image attribute value denotes tags of built images. When build context is not mentioned, the image attribute acts as a reference to pull the docker image from.
You can't conditionally set things in the docker-compose file but what you could do is use compose profiles
version: '3.4'
services:
webapp:
image: private_ecr_repo.amazonecr.com/webapp:latest
profiles:
- build
webappbuild:
build:
context: "."
profiles:
- pull
Then you could do docker-compose --profile pull up or docker-compose --profiles build up
I ended up using overriding configuration feature of docker compose and defaulted to ecr images
I.e.
docker-compose.yml
version: '3.4'
webapp:
image: private_ecr_repo.amazonecr.com/webapp:latest
and when I wanted to build local images, I'd specify multiple docker-compose files
docker-compose.local.yml
version: '3.4'
webapp:
build:
context: "."
with command docker-compose -f docker-compose.yml -f docker-compose.local.yml
The second file adds build context and causes docker-compose to build locally
Newbie here. I created an empty solution, added WebApplication1 and WebApplication2. I then added docker support (Docker for Windows, Windows Containers). Compose file looks like this:
version: '3.4'
services:
webapplication1:
image: compositeapp
build:
context: .\WebApplication1
dockerfile: Dockerfile
webapplication2:
image: compositeapp
build:
context: .\WebApplication2
dockerfile: Dockerfile
So both containers are in a single image. Webapplication1 dockerfile has ENV LICENSE=abc123 and webapplication2 dockerfile has ENV LICENSE=abc456.
After building and starting the containers, I used exec -it powershell to remote into the 2 containers and did get-item env:license. Both containers returned 456.
As a newbie, I was expecting one machine to return abc123 and the other abc456. I just made up the environment name as being license, but what does one do if they need a per container environment variable?
I guess the issue you notice provides from the fact you specified the same image name for both services, which implies that they will have the same ENV variable as defined in the latest-compiled Dockerfile.
Could you try this instead?
version: '3.4'
services:
webapplication1:
image: compositeapp1
build:
context: .\WebApplication1
dockerfile: Dockerfile
webapplication2:
image: compositeapp2
build:
context: .\WebApplication2
dockerfile: Dockerfile
Anyway, even if this is working, I assume your two Dockerfile are almost the same (?), in which case I would rather suggest to use a single Dockerfile and a single image tag, but customize the environment of both services by using some environment section in your docker-compose.yml (or some env_file section, along with some external .env files...).
For example, you may want to write something like this:
version: '3.4'
services:
webapplication1:
image: compositeapp
build:
context: .\WebApplication
dockerfile: Dockerfile
environment:
- LICENSE=abc123
webapplication2:
image: compositeapp
environment:
- LICENSE=abc456
(not forgetting to remove the ENV LICENSE=... line from the Dockerfile)
I have a setup that I am migrating to docker-compose from a set of shell scripts. The container I want to build uses a parent container that is created by a custom dockerfile. But I can't see how to get docker-compose to (re)build the requisite parent container.
There are three files as per:
/code/containers/parent/DockerFile
FROM centos:7
RUN... (rest of file to create common stuff used by multiple child images)
/code/containers/child-one/Dockerfile
FROM parent
RUN...
/code/docker-compose.yml
version: '3.3'
services:
my-service:
image: child-one
build:
dockerfile: containers/child-one/Dockerfile
context: .
As expected it will fail with:
Service 'my-service' failed to build: repository parent not found: does not exist or no pull access
Can't find any solution to this other than manually running docker to build the parent image first.
Any ideas much appreciated.
edit: base on VonCs idea:
version: '3.3'
services:
parent-notservice;
image: parent
build:
dockerfile: containers/parent/Dockerfile
context: .
my-service:
image: child-one
depends_on:
parent
build:
dockerfile: containers/child-one/Dockerfile
context: .
However I had to use depends_on, which was a hack, I am worried about effects of the parent starting (when child is run). This is not my intent.
As of January 2021, there is another way to do this by using the profiles key. Support for this key was added in Docker Compose 1.28.0.
version: '3.9'
services:
parent-notservice:
build:
dockerfile: containers/parent/Dockerfile
context: .
profiles:
- donotstart
my-service:
image: parent-notservice
another-service:
build:
context: .
dockerfile: ./containers/service/Dockerfile
my-service will be based directly on parent-notservice. Then you can add whatever ports and volumes are needed for that container in the docker-compose.yml file.
another-service will be built from the Dockerfile which could also be based on parent-notservice using the FROM command. Other packages can then be installed on that container that are not part of the parent.
FROM parent-notservice
RUN...
And the best part is that when you use docker-compose up the parent-notservice will not start.
Further documentation on the profiles key can be found here: https://docs.docker.com/compose/profiles/
"parent" would exist in your local docker registry if your build was setting the name "parent" (docker build -t parent)
With a docker-compose file, you need to build parent/DockerFile first, with an image: parent under your build directive.
However, you should only build service you intent to run, which is not the case for "parent": parent should be built before docker-compose is involved.
The proper solution is to have a wrapper script which would:
docker build -t parent ...
then call docker-compose
No more depends_on hack between imaginary services (there is no "service" for parent: nothing runs there).
Following the tutorial of docker compose. Let's say you have a Dockerfile for your app and docker-compose.yml for its services.
Dockerfile
FROM ruby:2.3.3
...
COPY . /myapp
docker-compose.yml
version: '3'
services:
db:
image: postgres
web:
build: .
image: dre-hh/myapp
volumes:
- .:/myapp
depends_on:
- db
While developing you would like to build the app from the local filesystem with docker-compose. Then later you could upload the app docker image to docker hub.
Do you need separted overridable configurations if you want to choose between building from local system or from docker hub? Or is it possible
somehow else as one can specify both build and image options on the yaml file?
When using build: with image:, the image name is simply to let you choose which name that docker-compose will tag the image as.
To push images, you should use a different config / build workflow, as lvonet mentioned