1

I need to run the same python code, but with different initiation arguments with docker. So under the main directory I've setup a folder called docker that contains different folders, each having same docker file but with the different arguments setup. Below is are examples of test_1 and test_2, where test_x is changed between the different folders, as well as test_1 becomes test_2 and so on:

Dockerfile found under docker/test_1 folder

FROM python:3.7
RUN mkdir /app/test_1
WORKDIR /app/test_1
COPY ./env/requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY ../ .
CMD ["python", "main.py","-t","test_1"]

Dockerfile found under docker/test_2 folder

FROM python:3.7
RUN mkdir /app/test_2
WORKDIR /app/test_2
COPY ./env/requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY ../ .
CMD ["python", "main.py","-t","test_2"]

Under the main directory I've setup a docker compose file that initiates the different containers (all running the same code) and that share a txt file in shared_folder:

services:
  test_1:
    container_name: test_1
    build: ./docker/test_1
    volumes:
      - output:/app/shared_folder
    restart: unless-stopped

  test_2:
    container_name: test_2
    build: ./docker/test_2
    volumes:
      - output:/app/shared_folder
    restart: unless-stopped

So my question here with docker, is this the right way to go about it, when setting up multiple py executions of the same code with different parameter? or is there another recommended approach. Do want to mention, they need to share the file in shared_folder, that's a requirement and all the instances have read/write access to the same file in the shared_folder (this is a must have).

Raginald Avto
  • 25
  • 1
  • 6
  • How exactly do `test_1` and `test_2` differ? Can you [edit] the post and add the containerfile for `test_2`? It might be possible to use the same containerfile, only changing some environment varialbes or the `command` in the compose file. – Turing85 Apr 30 '22 at 22:25
  • Hey thank you for the suggestion, i've added test_2 – Raginald Avto Apr 30 '22 at 22:28
  • yeah that's my question, is there a better approach to my crude implementation that achieves this different instances propagation. – Raginald Avto Apr 30 '22 at 22:28
  • Is this even working `COPY ../ .`? At first sight, I would say: [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) it, and create a single _Dockerfile_ using an `ARG folder` and pass that value in the build of the docker-compose.yml. – β.εηοιτ.βε Apr 30 '22 at 22:34
  • 1
    Okay, please take this with a grain of salt, I am not 100% sure if this will work, but... you could remove the `CMD` form the containerfile and then add `command: ["python", "main.py","-t","test_1"]` for `test_1` and `command: ["python", "main.py","-t","test_2"]` for `test_2`. This should allow you to use one and the same containerfile for both containers. If this works, we could also get rid of the `test_1` folder in `app` and standardize it to just `/app`. – Turing85 Apr 30 '22 at 22:34
  • hey @β.εηοιτ.βε, yeah i'm trying to avoid doing this implementation by asking a question on best practice here, I'll check out that arg folder if there is a way to use it, any links are appreciated – Raginald Avto Apr 30 '22 at 22:36
  • @Turing85yeah i think from what i've read this is not best practice, because if one blows up, so do the rest (having them in the same Dockerfile) and it is recommended to use compose... – Raginald Avto Apr 30 '22 at 22:37
  • 2
    @RaginaldAvto what do you mean by "*blows up*"? The containerfile is not the container. The containerfile is used to build an image. A container is an instantiation of an image. Two containers, started from the same image, are independent. – Turing85 Apr 30 '22 at 22:38
  • @Turing85 yeah i mean if there is an error in one, all the python instances will need to restart, since adding them in the same DockerFile from what i understand, they share the same container I think... I'm far from an expert obviously, but referencing this https://stackoverflow.com/questions/53920742/how-to-run-multiple-python-scripts-and-an-executable-files-using-docker – Raginald Avto Apr 30 '22 at 22:42
  • @RaginaldAvto you are mixing **images** and **containers** which are two really different things in docker https://stackoverflow.com/questions/23735149/what-is-the-difference-between-a-docker-image-and-a-container – β.εηοιτ.βε Apr 30 '22 at 22:47
  • @RaginaldAvto that question has other issues. They are using multiple `CMD`s in the same containerfile. The [containerfile specification](https://www.mankier.com/5/Containerfile) clearly states that: "*the last `CMD` takes effect.*". I suggested to override the command in the docker-compose file. If you provide me with a git repo, I could try to refactor it and open an PR/MR. – Turing85 Apr 30 '22 at 22:47
  • @β.εηοιτ.βε thank you for that link, yeah i was mixing up when i was referring to images and containers... that post helps clarify it – Raginald Avto May 01 '22 at 07:53

3 Answers3

0

First delete CMD ["python", "main.py","-t","test_2"] in Dockerfile and instead add entrypoint in docker-compose.yaml would be a better way to build the image for the code are all the same. if you have more container to start, it will save you a lot of time.

About the question you asked if the shared_folder you want to share is a read-only file, it is OK, if not, for instance, log files you want to put in it from instance out to the host, you should be careful about the log file name, should not be the same in the two containers.

  • Hye thank you for that helpful comment, i updated my question to clearly mention that all the different instances have read/write privileges in the `shared_folder` . – Raginald Avto May 01 '22 at 05:39
  • and yeah the log file name should be the same, they need to write into the same log file if possible, otherwise i'll need to read on all of them, to be able to update the one tied to a particular instance, which is also possible but not ideal – Raginald Avto May 01 '22 at 05:48
0

I would definitely DRY it, use a single Dockefile and use an ARG to build them.

Here is what you could do:

In docker/Dockerfile:

FROM python:3.7

ARG FOLDER

## We need to duplicate the value of the ARG in an ENV
## because the arguments are only visible through the build
## so, it won't be accessible to our command
ENV FOLDER=$FOLDER

RUN mkdir -p /app/$FOLDER
WORKDIR /app/$FOLDER
COPY ./$FOLDER/env/requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .

CMD ["sh", "-c", "python main.py -t $FOLDER"]

And in your docker-compose.yml define those build arguments:

version: "3.9"
services:
  test1:
    container_name: test_1
    build:
      context: ./docker
      args:
        FOLDER: test1
    volumes:
      - output:/app/shared_folder
    restart: unless-stopped

  test2:
    container_name: test_2
    build:
      context: ./docker
      args:
        FOLDER: test2
    volumes:
      - output:/app/shared_folder
    restart: unless-stopped
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
0

It is very easy to override the Dockerfile CMD with a docker run command-line argument or Compose command:. So, I would build only one image, and I would give it a useful default CMD.

FROM python:3.7
WORKDIR /app
COPY ./env/requirements.txt ./
RUN pip install -r requirements.txt
COPY ./ ./
CMD ["./main.py"]

(Make sure your script is executable – maybe run chmod +x main.py on the host – and begins with a "shebang" line #!/usr/bin/env python3, so you don't have to explicitly name the interpreter.)

Now in your docker-compose.yml file, have both services build: the same image. You'll technically get two images out in the docker images output but they will have the same image ID and the second image build will run extremely quickly (it will come entirely from the layer cache). Use Compose command: to override the entire CMD as required.

version: '3.8'
services:
  test_1:
    build: .
    command: ./main.py -t test_1
    volumes:
      - output:/app/shared_folder
    restart: unless-stopped

  test_2:
    build: .
    command: ./main.py -t test_2
    volumes:
      - output:/app/shared_folder
    restart: unless-stopped

You could also manually run this outside of Compose if you just wanted to validate things, with the same approach

docker build -t myapp .
docker run --rm myapp \
  ./main.py --help

With this approach you do not need to rebuild the image for each different command you want to run or wrangle with the syntactic complexities of docker run --entrypoint.

David Maze
  • 130,717
  • 29
  • 175
  • 215