2

I need to define the array of exposed ports for a given service from an environment variable.

If I define the ports array as below, it works without problems:

services:
  open-connect:
    ports: ["80:80","90:90"]

or

services:
  open-connect:
    ports: ['80:80','90:90']

However, if I define it in a .env file

EXPOSED_PORTS="'80:80','90:90'"

or

EXPOSED_PORTS='"80:80","90:90"'

services:
  open-connect:
    ports: [$EXPOSED_PORTS]

It gives me the error:

$ docker-compose up -d --build
ERROR: The Compose file './docker-compose.override.yml' is invalid because:
services.open-connect.ports contains an invalid type, it should be a number, or an object

It only works if the environment variable contains a single port mapping:

EXPOSED_PORTS="80:80"

How can I make this array of exposed ports configurable from an environment variable?

Update

The suggested similar question docker-compose variable substitution / interpolation with list, map, or array value is a bit old (2018) and doesn't provide a solution supported by docker-compose on its own; instead, it requires to use an external command to physically alter the docker-compose file with the array value.

1

1 Answer 1

2

It is little bit tricky but closer solution to what you want to do.

You may inject ports as second docker-compose file passed from STDIN.

Let's say that we have docker-compose.yml:

version: '3'

services:
  web:
    image: 'test:v0.1'

and variable PORTS:

$ export PORTS='"1:1","2:2"'
$ echo $PORTS
"1:1","2:2"

Let's check config with STDIN injection:

printf "version: '3'\nservices:\n  web:\n    ports: [${PORTS}]\n" | docker-compose -f /dev/stdin -f docker-compose.yml config

output:

services:
  web:
    image: test:v0.1
    ports:
    - 1:1/tcp
    - 2:2/tcp
version: '3.0'

As you can see we injected

version: '3'
services:
  web:
    ports: ["1:1","2:2"]

part from command line


Also multiple ports may be simply set via "80-90:80-90" syntax (all 10 ports will be forwarded).

Sign up to request clarification or add additional context in comments.

6 Comments

Nice. Notice that if you want to run this porgramatically, you could change the prinf for an echo,
There are many ways to solve the issue of specifying multiple ports - The question is about how to format an array on a single line
env is able to store only string values. Yaml doesn't have a built-in functionality to cast values into different types. Most focused and straightforward answer: It is impossible
YAML explicitly defines how to serialize sequences and key-value series as string values.
YAML explicitly defines how to serialize sequences → since link is broken I'm not sure what you are trying to point, but I think you are talking about [name , hr, avg ] example. Again, it is not possible to interpret '[a, b, c]' string as a list. And since we try to get a value from env it will be a string, and it is not matter if this value looks like list. Anyway, maybe I'm wrong and don't know something. Feel free to add your answer, isn't that is why SOF exists?
The link is fine, it's your browser that isn't capable of linking to text in a page - the relevant part is what you say with the [ a, b, c ] format - and it doesn't (shouldn't) matter if YAML can cast anything because variable substitution should occur before YAML is interpreted. The whole YAML file is a string after all... it makes no sense to do substitutions after it is interpreted so I'd argue that if that is what is happening, that is a bug in Compose that needs to be addressed. Or, since YAML was chosen, Compose needs to be updated to actually handle expected syntax.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.