Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Dockerfile inheritance?

Tags:

docker

I have a Dockerfile which installs production & test dependencies. I want to have separate image for tests, so production image is smaller, without to much code duplication. Maybe there is something like FROM statement for referencing other Dockerfiles?

Dockerfile has following lines:

ADD requirements.txt ${PROJECT_DIR}/requirements.txt
RUN pip install --no-cache --process-dependency-links --trusted-host github.com -r requirements.txt
ADD requirements-test.txt ${PROJECT_DIR}/requirements-test.txt
RUN pip install --no-cache --process-dependency-links --trusted-host github.com -r requirements-test.txt

First two install depencencies for project, second two - install dependencies for testing (pytest, pylint, etc.).

I also have docker-compose that starts database, redis cache, etc. This is how I run service and run tests:

run:
    docker-compose -f docker-compose.yaml run
test:
    docker-compose -f docker-compose-dev.yaml run py.test tests/

Inside both docker-compose.yaml has this build config for my container:

build:
  context: .
  dockerfile: ./Dockerfile

So, I could reference different Dockerfiles from my docker-compose.yaml, but I don't want them to be complete copies that have only two lines difference.

like image 470
Bunyk Avatar asked Oct 08 '18 11:10

Bunyk


2 Answers

The recommend method is multistage builds:

https://docs.docker.com/develop/develop-images/multistage-build/

That is dont separate production from test docker files. Instead keep all the requirements in one file and build for the target stage you need.

An example Dockerfile:

FROM python:3.8.7-slim-buster AS production
ADD requirements.txt ${PROJECT_DIR}/requirements.txt
RUN pip install -r requirements.txt


FROM production AS test
ADD requirements-test.txt ${PROJECT_DIR}/requirements-test.txt
RUN pip install -r requirements-test.txt

and then for your production build target the correct stage:

docker build --target production -t org/service:latest .

Multistage build syntax was introduced in Docker Engine 17.05.

like image 194
bensentropy Avatar answered Sep 18 '22 19:09

bensentropy


FROM is the way to go here. Production and Development images should not differ too much, or at all, since the idea is to deploy what you have developed. In my experience it is easier to start with a production image and extend a development image from that, since development requires more software like debuggers, compilers, etc.

Due to the comment:

Within a dockerfile the FROM directive takes an image tag, so something like ubuntu:latest and than docker will first try to find that image locally and than try to pull it from a repo, if not.

In case you do not have a repo, you can create the base image locally by running:

docker build --tag vendor/production:0.0.1 .

what will compile the image. Than you can write:

FROM vendor/production:0.0.1

in your dev-dockerfile and compile this. I usually create a tiny bash script for all the compilation stuff.

like image 26
philipp Avatar answered Sep 21 '22 19:09

philipp