-
Notifications
You must be signed in to change notification settings - Fork 18.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allows environment variables to be lazily expanded on container run #31525
Conversation
daemon/oci_windows.go
Outdated
toPrepend += "cmd /S /C " | ||
cmdLine := "'" + strings.Join(s.Process.Args, " ") + "'" | ||
s.Process.Args = make([]string, 0) | ||
s.Process.Args = append(s.Process.Args, "powershell", "-Command", toPrepend, "cmd", "/s", "/c", cmdLine) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do all windows containers have powershell?
Also, append([]string{}, ...)
, or just skip the append.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both nanoserver and server core have powershell, yes. I'll make the change and amend
6966d37
to
dcdd77b
Compare
78ae9a9
to
a884653
Compare
Context: On Windows, environment variables can be either volatile (scoped to a process and its children, like on Linux), or persisted (stored in registry, shared accross sessions, even sometimes accross users). The current ENV dockerfile command does not consider that a particular variable can have a living value stored in the container registry simply because persisted variables does not exist on *nix platforms. This is a problem, very well illustrated by a simple file: ``` FROM microsoft/nanoserver ADD .\\bin c:\\myapp ENV PATH ${PATH};c:\\myapp RUN echo %PATH% ``` In this example, the builder does not consider that PATH can have a living value in the stored base image and overrides its value with `;c:\\myapp`. this breaks basically the whole Windows The way I solved this, is by introducing a flag to the ENV command telling the variable should be expanded at runtime: ``` ENV --lazy-expand PATH ${PATH};c:\\myapp ``` The lazy-expandiness of a variable is stored in the image configuration, and when running a container for an image with such parameters, the processStart info is modified to expand these variables in powershell before invoking the previously defined processStart. Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
a884653
to
c1a8a69
Compare
cc @jhowardmsft whats your opinion of this vs #29048? |
The assertion that powershell is always present is a false one - it will be optional in future base images, so it shouldn't be mandated with that knowledge. I circumvented that in #29048 through cmd for extracting vars - see the big block comment (although I realise mine was a getter - this is a setter). Otherwise, purely from a quick glance at the code (not tested at all), it does pretty much the same thing, but in a significantly more complex manner. From an end-user perspective, I believe what (in 29048) is I have strong concerns about the prepending of the arguments https://github.com/docker/docker/pull/31525/files#diff-010226ebaaeeb61428008a57958bcf75R44 through Powershell, then hard-coding Before going with either this or 20948, I think there's some design choices still to be made. Personally I still prefer the |
@jhowardmsft Would it be possible to keep this behavior but avoid overriding command for starting a container? |
If we could pass an option to hcs asking it to expand env variables, it would be really helpful (because I do aggree that prepending the powershell script is really messy) |
Short answer no. Longer answer: There's no way from outside a Windows container to get the environment for a process from the registry (and optionally the shell). (Well there is, but it's incredibly complex, would require mounting the registry hives, parsing it offline, and doing shell processing offline. Somehow....). So let's realistically rule that out as impractical. The only way to get the effective environment from a container is by starting a process in it. Hence what both this PR and the GETENV PR do to solve it.
For the reasons above, I don't really think so. Summary: I'm still of the believe the |
I would be in favor of a solution that avoids modifying the image format. Assigning this to the declaration stage of the environment variable seems a little awkward when we could just change how it is referenced and interpreted. It might make more sense to do something like this:
(Alternatively, Combined with an escaped path in the definition above, it will ensure that the behavior is restricted to the statement it affects, rather than other, unrelated statements. In general, we should differentiate features that affect the current build from those that modify the resulting image format. I also find this quite odd because an environment variable typically is expanded at the time that is referenced. For the definition of the env var, the expansion is done at the definition point, making the behavior contextually clear, but well-controlled. Deferring this behavior to add lazy expansion introduces an interpreter that might never exit. Even in this example, the definition is a recursion, and has the potential to never terminate. |
I assume this could be done without extra fields to image because lazy expand only makes sense if a value has Considering that the actual problem here is that the image format currently does not have a place that defines Looking to the future, builder should be a DAG of filesystem modifications(either moving files or running commands on them) and to create images a filesystem should be associated with image metadata. Currently, builder implementation doesn't make a clear distinction and causes bugs(wrong reference counting, ebusy, side effects to daemon state), performance issues(slow commit, container creation for metadata changes) and blocks innovation on composition features(concurrency, better cache). |
IIRC, what is very costly when running a container on windows is to setup the container and its network - not actually running the process. |
In linux we run |
@tonistiigi Where does that binary come from? How is it guaranteed to be in every container image (including the MS distributed base ones)? How would it be signed. How would it do stdio handle handoff on Windows when HCS is tracking the original process for exit and "fork/exec" (not that there is such a thing in reality in the Win32 API set) I really don't think this is a good idea that would work on Windows. |
@jhowardmsft In the case of linux, the |
Right, but that still doesn't solve the problem above... Just introduces yet another unnecessary overhead |
With that we would get he opportunity to extract env vars at each "run" with a low overhead (don't have to create the container / assign it a network twice). That seems really nice to me to reconciliate env vars states |
👉 |
@simonferquel this one needs to be rebased |
Let's close this one for now; if we still want this, this probably has to be reimplemented for buildkit |
Context:
On Windows, environment variables can be either volatile (scoped to a
process and its children, like on Linux), or persisted (stored in
registry, shared accross sessions, even sometimes accross users).
The current ENV dockerfile command does not consider that a particular
variable can have a living value stored in the container registry simply
because persisted variables does not exist on *nix platforms.
This is a problem, very well illustrated by a simple file:
In this example, the builder does not consider that PATH can have a
living value in the stored base image and overrides its value with
;c:\\myapp
. this breaks basically the whole WindowsThe way I solved this, is by introducing a flag to the ENV command
telling the variable should be expanded at runtime:
The lazy-expandiness of a variable is stored in the image configuration,
and when running a container for an image with such parameters, the
processStart info is modified to expand these variables in powershell
before invoking the previously defined processStart.
Signed-off-by: Simon Ferquel simon.ferquel@docker.com