The general design pattern is one container = one running service - see the initial comment at https://docs.docker.com/config/containers/multi-service_container/
Now, after spending about a year developing a multi-service application relying heavily on docker this is what works for me:
Avoid creating files inside the container unless it is your storage engine - in which case use volumes (recommended by Docker and also common sense) - we use Elasticsearch for that.
If I need multiple custom configurations I am trying to either load it from somewhere (DB, Environment) or I mount the configuration as a volume like
-v config.yml:/usr/src/app/config.yml
In general, we have one service = one repository, but sometimes you have to copy all the dependencies in order to just create one script. So we have one repository where these scripts are aggregated and I change the CMD with an environment variable like this:
CMD cd /usr/src/app && python -u $RUN_SCRIPT
It can be probably improved with a combination of ENTRYPOINT and CMD as described here http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/
Then we use various docker-compose.yml
files for getting the setup we need.
For some operations (like DB setup) we either run one container like
docker run --network ournetwork init-profiling
or I can run a command inside that container
docker run -it --network ournetwork init-profiling bash
# run_command.sh
^D
We spent some time minimizing the footprint of containers, they can quickly get bloated. For example, we use a common base image for our python containers. Also, things like pip freeze
do make sense only if you use a separate virtual environment for each repository/container.
We do not use swarm/kubernetes for now, so I cannot add any additional guidelines for that.