Docker-compose.yml file that builds a base image, then children based on it?
Solution 1
As per the documentation the build
option of a service takes a directory as an argument which contains the famous Dockerfile
. There is no way to build a base image and then the actual image of the service.
Docker is a environment in which your application runs. When you are creating a base image, it should have things which are not going to change often. Then you need to build baseiamge once and upload to your repository and use FROM baseimage:latest
in the Dockerfile.
For example, if you are building a python application you can create it from python and install requirements:
FROM python:3.6
COPY requirements.txt .
RUN pip install -r requirements.txt
here, python:3.6
is the base image which is not going to change often and thus you need not build it every time you are running docker compose commands.
Solution 2
Yes, kind of. Use it like this:
version: '2'
services:
wls-admin:
container_name: wls-admin
image: weblogic-domain
build:
context: wls-admin
args:
- ADMIN_PORT=${WLS_ADMIN_PORT}
- CLUSTER_NAME=${WLS_CLUSTER_NAME}
- PRODUCTION_MODE=dev
networks:
- wls-network
image
clause here makes docker-compose build
generate docker image named weblogic-domain
for this service. This image can be re-used by other services' Dockerfiles, even in the same build process.
Solution 3
Instead of running docker-compose, you can implement a script, witch builds image with specific tag docker build ... -t your_tag
, then runs docker-compose. In children dockerfiles you can use FROM your_tag
.
Solution 4
Just a minor addition to Kanedias' answer. If you choose to follow his approach (which was my choice), you can avoid instantiating a container for the base image with the --scale
flag from the docker-compose up
command:
docker-compose up --scale wls-admin=0
From the up
command documentation:
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.
One important thing to note is that the scale
setting in the docker-compose.yml was removed in v3, so there is actually nothing to override in v3.
Solution 5
From the shellscript that makes the images, we can see that you have different dockerfiles in different directories. You can use that to create a docker-compose.yml file. The build settings are used to tell docker that how should it build the image.
You can use those dockerfiles in your compose file in this manner:
version: '3'
services:
api_cntr:
image: api_img
build:
context: ./api
container_name:api_cntr
ports:
- 5000:5000
Here, I have assumed that your docker-compose.yml
file is placed in a folder which also contains a directory called base-image
. And base-image
has a dockerfile
which is used to build the image.
This can be structure of one of your service. In similar manner, you can create other services also. And while usig docker-compose
you will not need to specify a network for each, because all services declared within a docker-compose.yml
file are part of an isolated network.
Related videos on Youtube
Will Parzybok
Updated on June 04, 2022Comments
-
Will Parzybok almost 2 years
For clarification, when I say base image, I mean the parent image that has all the common configurations, so that the children based on it don't need to download the dependencies individually.
From my understanding, docker-compose.yml files are the run-time configurations, while Dockerfiles are the build-time configurations. However, there is a
build
option using docker-compose, and I was wondering how I could use this to build a base image.As of right now, I use a shellscript that runs other shellscripts. One builds all my images, from a base image that it also creates. The other runs them as containers with the necessary configurations. However, the base image is never ran as a container.
Currently, the shellscript I hope to change into a docker-compose file, looks like so:
echo "Creating docker network net1" docker network create net1 echo "Running api as a container with port 5000 exposed on net1" docker run --name api_cntr --net net1 -d -p 5000:5000 api_img echo "Running redis service with port 6379 exposed on net1" docker run --name message_service --net net1 -p 6379:6379 -d redis echo "Running celery worker on net1" docker run --name celery_worker1 --net net1 -d celery_worker_img echo "Running flower HUD on net1 with port 5555 exposed" docker run --name flower_hud --net net1 -d -p 5555:5555 flower_hud_img
The shellscript that makes the images, is as follows:
echo "Building Base Image" docker build -t base ../base-image echo "Building api image from Dockerfile" docker build -t api_img ../api echo "Building celery worker image" docker build -t celery_worker_img ../celery-worker echo "Building celery worker HUD" docker build -t flower_hud_img ../flower-hud
My questions comes down to one thing, can I create this Base image without ever running it in a container with docker-compose. (All the Dockerfiles start with
FROM base:latest
other than the base itself). I'm looking to make it as easy as possible for other people, so that they only have to run a single command.EDIT: I am using version 3, and acording to the docs,
build:
is ignored, and docker-compose only accepts pre-built images. -
Ayushya over 6 yearsHave I misunderstood the question?
-
Will Parzybok over 6 yearsSomewhat, and that is probably my fault for poor wording. The base-image directory contains a Dockerfile that creates an image called
base
. All the other containers, have their own directory with their own Dockerfile that references this base in theirFROM
statement. In other words, the base itself is never ran as a container, and is instead a pre-built base for all the other images. -
vedarthk over 6 years@ayushya your compose file will use
base-image
directory are context to build the image and tag it asapi_img
. What @WillParzybok want is to build base image whenever he is bringing up any service in the compose file. -
Ayushya over 6 years@vedarthk My fault, I was building api and don't know how I gave context of base image.
-
Will Parzybok over 6 yearsWould it then be best to build the base image first, then in a separate command do the docker-compose up, and have a shellscript run both of these if I am going for the one-command-does-all?
-
Ayushya over 6 years@WillParzybok That seems a better idea and suitable to your purpose.
-
Grimmy over 6 yearsThat's what I do. Jenkins builds my base images and puts it in a private image repo. If you tag them properly with version number you always have control. It's a fairly straight forward process to deal with.
-
Mišo over 4 yearsYes, but the
docker-compose up
will try to run the container from it and I would like to avoid it because it's only the base image for the other services. -
Kanedias over 4 years@Mišo yes, docker-compose doesn't support this as of now. The current solution, apparently, is to use multiple yaml files, where you do
build
on first andup
on the other. -
zsteinkamp over 4 yearsYou could set the CMD in the base Dockerfile to just be "echo". This way, your base image does start but it quickly exits. Not ideal, but it works.