Three layered sources
environment: wins, and the Dockerfile value is only the floor
dockerfile: ENV PORT=8080 env_file: PORT=9090 environment: PORT=3000
Work out which value the container actually gets. Prefix each line with its source: run, environment, env_file, dockerfile or shell.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Test. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
environment: wins, and the Dockerfile value is only the floor
dockerfile: ENV PORT=8080 env_file: PORT=9090 environment: PORT=3000
Reaches nothing, and the Dockerfile default is what the container gets
shell: API_KEY=fromshell dockerfile: ENV API_KEY=default
These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Containers do not inherit the shell's environment. Compose reads it only for interpolating the compose file.
Instead:Pass it explicitly with a bare key: environment: [API_KEY].
environment: is more specific, so it always wins. The env_file value is simply ignored.
Instead:Remove it from whichever place should not own it, so there is one source to check.
It is baked into the image metadata and readable with docker history by anybody who can pull the image.
Instead:Pass it at run time, and use a build secret mount if it is needed during the build.
That is the one people lose the most time to, because the same command works in a terminal and the container gets nothing.
-e on the command line, then environment: in the compose file, then env_file:, then the Dockerfile's ENV. Each is more specific than the one below it, which means a shared env_file cannot override a per-service value, and that is usually discovered by somebody trying exactly that.
Compose reads your environment only to fill in ${ } while parsing the compose file. To pass a variable from your shell into the container you have to say so, with a bare key and no value: environment: [API_KEY]. That is the only route.
It populates ${ } in the compose file, from the project directory. It is not env_file:, it does not reach the container, and the same name can sit in both with different values and nothing will point that out.
It is the value when nothing else supplies one, and it is baked into the image metadata, so anybody who can pull the image can read it with docker history. A credential in an ENV is a published credential.
Not because the resolution is ambiguous, it is not, but because whoever changes the losing one will believe they have changed the behaviour. One place per variable is worth more than knowing the order.
Anything you did not paste, including whether a variable exists at all. It resolves the sources you describe, in your browser.