Docker-compose.yml file that builds a base image, then children based on it?

15,815

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.

Share:
15,815

Related videos on Youtube

Will Parzybok
Author by

Will Parzybok

Updated on June 04, 2022

Comments

  • Will Parzybok
    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
    Ayushya over 6 years
    Have I misunderstood the question?
  • Will Parzybok
    Will Parzybok over 6 years
    Somewhat, 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 their FROMstatement. 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
    vedarthk over 6 years
    @ayushya your compose file will use base-image directory are context to build the image and tag it as api_img. What @WillParzybok want is to build base image whenever he is bringing up any service in the compose file.
  • Ayushya
    Ayushya over 6 years
    @vedarthk My fault, I was building api and don't know how I gave context of base image.
  • Will Parzybok
    Will Parzybok over 6 years
    Would 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
    Ayushya over 6 years
    @WillParzybok That seems a better idea and suitable to your purpose.
  • Grimmy
    Grimmy over 6 years
    That'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
    Mišo over 4 years
    Yes, 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
    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 and up on the other.
  • zsteinkamp
    zsteinkamp over 4 years
    You 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.