简体   繁体   中英

sharing values among files Dockerfile, docker-compose.yml, python.py, and shell

How do I share a value among the stack of technologies docker , docker-compose , Python , and POSIX shell for a single project?

For example, I would like to set the value PORT once. It would be nice if PORT was set within one file and other files would reference that value.

However, in my foo project the value PORT must be set among several files, each of which is a parsed by different a technology:


File foo.py

#!/usr/bin/env python
PORT = 80

File Dockerfile

# foo
ENV PORT=80
EXPOSE ${PORT}

File docker-compose.yml

version: '2'
services:
  web:
    image: docker.corp.com/foo
  expose:
    - '80'

File run.sh

#!/usr/bin/env sh
PORT=80


It is preferable to git commit the files "as is", eg no "on the fly" code generators.

It seems like the easiest solution would be setting PORT in your local environment.

Then:

  • Your python code can read the value from os.environ .

  • You can provide the value to your container in docker-compose by including:

     environment: PORT: ${PORT}
  • If you need to start a container outside of docker-compose , you can pass it on the docker run command line:

     docker run -e PORT=$PORT...
  • And of course your run.sh script can just reference $PORT directly.

There are a couple of things like filesystem paths and TCP port numbers where Docker allows picking a value when the container is run, and that value doesn't have to be the same as what's inside the image. For the example you give of a TCP port, it's usually easier to just pick some number and not try to make it configurable at the Docker layer.

# Dockerfile
# Don't bother setting ENV PORT
EXPOSE 80
# docker-compose.yml
services:
  web:
    image: docker.corp.com/foo
  # expose: is already in the Dockerfile, but you probably need
  ports:
    - '8000:80'
      #     ^^ where this matches the image

You also don't need to set values at every level. If you EXPOSE a port in your Dockerfile you don't need to also expose: the same port in docker-compose.yml ; if you set an ENV in the Dockerfile you don't need to set it in shell scripts that run inside the container.

In your script itself, you'll probably be running it both inside Docker and also outside Docker for day-to-day development, so it's useful to make details like the port number, database connectivity, ... configurable there.

# foo.py
PORT = int(os.environ.get('PORT', '80'))

The general approach I take to this in my day job is to make the defaults in the script match what a developer needs – "high" ports like 8000, the database is running on localhost – but in the Docker deployment reconfigure it for the different environment.

For things that aren't related to Docker settings like port numbers, there's a more general answer to the specific question you asked. Say you have some other environment variable

# The URL the service is ultimately reachable at, taking
# things like load balancers into account
EXTERNAL_URL = os.environ.get('EXTERNAL_URL', '')
#!/bin/sh
echo "Your service will be reachable at $EXTERNAL_URL"
exec ./myscript.py

These variables aren't resolved until the script is ultimately run, so if you set it once in docker-compose.yml everyone else will be able to read it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM