Two services with same images should use different Dockerfiles - docker

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

Related

docker commit after docker compose

I'm running docker compose as follows:
docker-compose -f docker-compose.dev.yml up --build -d
the contents of docker-compose.dev.yml are:
version: '3'
services:
client:
container_name: client
build:
context: frontend
environment:
- CADDY_SUBDOMAIN=xxx
- PRIVATE_IP=xxx
restart: always
ports:
- "80:80"
- "443:443"
links:
- express
volumes:
- /home/ec2-user/.caddy:/root/.caddy
express:
container_name: express
build: express
environment:
- NODE_ENV=development
restart: always
Then I want to create images from these containers to use them in a testing server by pushing them to aws ECR and pulling on the test server, to avoid the time of creating the dockers all over again. Simply using docker commit did not worked.
what is the correct approach to creating images from outputs of docker compose?
thanks
You should basically never use docker commit. The standard approach is to describe how to build your images using a Dockerfile, and check that file into source control. You can push the built image to a registry like Docker Hub, and you can check out the original source code and rebuild the image.
The good news is that you basically have this setup already. Each of your Compose services has a build: block that has the data on how to build the image. So it's enough to
docker-compose build
and you'll get a separate Docker image for each component.
Often if you're doing this you'll also want to push the images to some Docker registry. In the Compose setup, you can specify an image: for each service as well. If you have both build: and image:, that specifies the image name to use for the built image (otherwise Compose will pick one based on the project name).
version: '3.8'
services:
client:
build:
context: frontend
image: registry.example.com/project/frontend
et: cetera
express:
build: express
image: registry.example.com/project/express
et: cetera
Then you can have Compose both build and push the images
docker-compose build
docker-compose push
One final technique that can be useful is to split the Compose setup into two files. The main docker-compose.yml file has the setup you'd need to run the set of containers, on any system, with access to the container registry. A separate docker-compose.override.yml file would support developer use where you have a copy of the source code as well. If you're using Compose for deployment, you only need to copy the main docker-compose.yml file to the target system.
# docker-compose.yml
version: '3.8'
services:
client:
image: registry.example.com/project/frontend
ports: [...]
environment: [...]
restart: always
# volumes: [...]
express:
image: registry.example.com/project/express
ports: [...]
environment: [...]
restart: always
# docker-compose.override.yml
version: '3.8'
services:
client:
build: frontend
# all other settings come from main docker-compose.yml
express:
build: express
# all other settings come from main docker-compose.yml

docker-compose - COMPOSE_PROJECT_NAME, DockerHub and "service name". How to use it?

I'm using docker-compose to built customised nginx and php images and then I'd like to push it to DockeHub.
I'm using COMPOSE_PROJECT_NAME in an .env file to set a prefix image name:
COMPOSE_PROJECT_NAME=myapp
and docker-compose.yml is something like:
version: '3'
services:
php-fpm:
build:
context: ./php-fpm
args:
.....
volumes:
.....
expose:
.....
nginx:
build:
context: ./nginx
args:
.....
volumes:
.....
port:
.....
Running docker-compose up -d the images name are:
myapp_nginx
myapp_php-fpm
the container name are:
myapp_nginx_1
myapp_php-fpm_1
Now, to push these images to DocekeHub I need to change image name adding the DockerHub "account" suffix:
myaccount/myapp_nginx
myaccount/myapp_php-fpm
to solve this problem, I added the "image" option to docker-compose.yml:
version: '3'
services:
php-fpm:
build:
context: ./php-fpm
args:
.....
volumes:
.....
expose:
.....
image: myaccount/${COMPOSE_PROJECT_NAME}_php-fpm
nginx:
build:
context: ./nginx
args:
.....
volumes:
.....
port:
.....
image: myaccount/${COMPOSE_PROJECT_NAME}_nginx
now, running docker-compose push the images are pushed to DockerHub.
Ok, my question are:
1) is there a way to insert DockerHub account name myaccout into COMPOSE_PROJECT_NAME variable? Something like: COMPOSE_PROJECT_NAME=myaccount/myapp to create automatically the image name like: myaccount/myapp_nginx and myaccount/myapp_php-fpm?
2) is there a variable to get "service name" the retrieve the name nginx or php-fpm?
For example, into the docker-compose.yml file, I could set: image: myaccount/${COMPOSE_PROJECT_NAME}_<service_name> then If I change the "service name" from nginx to nginx2 automatically the image will be myaccount/myapp_nginx2
3) is there a way to rename the images produced with docker-compose only to permit the push?
Thank you
You'd typically use fixed image names in this context. A published image name shouldn't be dependent on details of the specific Compose file that launched it.
version: '3'
services:
nginx:
build: ./nginx
image: myaccount/nginx # no project name
Imagine you're planning to run this same setup on a different system. It has Docker and Compose installed, but none of your application source code. You should be able to copy the docker-compose.yml file there, delete the build: line, and run the same thing. It doesn't matter if the directory is named project or other, and it doesn't matter if the Compose setup actually names the service proxy instead of nginx; you'd use the same image: to refer to it.
# COMPOSE_PROJECT_NAME=other
version: '3'
services:
proxy:
image: myaccount/nginx # same image as above
If you're unhappy with the names Compose produces, you can manually docker tag and docker push the images outside of Compose. You'll also need to do this if you want an image to have multiple tags (both a date stamp and latest for example) or if for whatever reason you need to push it to multiple repositories (both Docker Hub and Amazon ECR).

Are docker environment variables shared between containers?

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)

build contains unsupported option: 'ports'

Trying to use docker-compose for the first time, but not having much luck. I have the following setup:
docker-compose version 1.8.0, build f3628c7
/home/GabeThermComposer contains the docker-compose.yml
/home/GabeThermComposer/GabeThermApache contains Dockerfile
/home/GabeThermComposer/GabeThermPHPMyAdmin contains Dockerfile
/home/GabeThermComposer/GabeThermDB contains Dockerfile and nest-init.sql
When I create docker images using the Dockerfile in each subdir, it all works without issues. I was hoping with the docker-compose.yml to do all the seperate building of images at once.
The docker-compose.yml looks like this:
version: '2'
services:
GabeThermDB:
build:
context: ./GabeThermDB
dockerfile: Dockerfile
GabeThermApache:
build:
context: ./GabeThermApache
dockerfile: Dockerfile
ports:
- "80:80"
GabeThermPHPMyAdmin:
build:
context: ./GabeThermPHPMyAdmin
dockerfile: Dockerfile
ports:
- "8080:80"
When trying to run "docker-compose up", I get the following error:
ERROR: The Compose file './docker-compose.yml' is invalid because:
services.GabeThermPHPMyAdmin.build contains unsupported option: 'ports'
services.GabeThermApache.build contains unsupported option: 'ports'
I have no clue on what is wrong with this. I think I did exactly as other examples have shown. Btw, I do know that the "context:" and "dockerfile:" is overdone, but since I'm new, I wanted to be sure to what files I'm pointing in case I forget it automatically dives into the subdir and runs the Dockerfile.
Any help is appreciated.
You have to move the ports out of the build block.
version: '2'
services:
GabeThermDB:
build:
context: ./GabeThermDB
dockerfile: Dockerfile
GabeThermApache:
build:
context: ./GabeThermApache
dockerfile: Dockerfile
ports:
- "80:80"
GabeThermPHPMyAdmin:
build:
context: ./GabeThermPHPMyAdmin
dockerfile: Dockerfile
ports:
- "8080:80"

Difference between 'image' and 'build' within docker compose

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.

Resources