buildah icon indicating copy to clipboard operation
buildah copied to clipboard

[feature request] support setting build-time environment variables

Open chmeliik opened this issue 10 months ago • 13 comments

As developers of a CI system that uses buildah for building (https://konflux-ci.dev/), we have a need to dynamically set environment variables at build time (for the RUN instructions in a Containerfile).[^1]

We didn't find any great way to achieve that at present. The options we considered:

  • --build-arg
    • Requires the ARGs to be defined up-front in the Containerfile (or requires modifying the Container dynamically to inject them)
    • ARGs have a lower precedence than ENV. The Containerfile or the parent image may already be setting the variable via ENV => we're not able to override it
  • --env
    • Sets the environment variable in the image config, which we want to avoid. We want to set the environment variables only at build time
  • Inject a .env shell script into the build using --volume. Dynamically modify the RUN instructions in the Containerfile to source this shell script before doing the rest of the command(s)
    • This is the option we currently use, despite the problems
    • Modifying the RUN instructions is error-prone. We don't even support all the possible forms (e.g. exec form and heredoc form - related issue)
    • Some users are uncomfortable with having their Containerfile dynamically modified

It would be awesome if we could set build-time environment variables more easily. Some options that could work:

  • Buildah currently supports the env array from the engine table in containers.conf. Would it be reasonable to support env from the containers table as well and use these for the RUN environment?
    • Or, would it be reasonable for the [engine.env] variables to propagate to RUN instructions?
  • A new --build-env CLI option for buildah build that would set environment variables for RUN instructions but wouldn't set them on the resulting image config.

[^1]: For example, we set GOMODCACHE to a pre-populated cache directory that we mount into the build using --volume. We do a similar thing for Python builds - pointing pip to a directory instead of an index server using PIP_FIND_LINKS.

chmeliik avatar Feb 12 '25 13:02 chmeliik

One hack which can be done is dump all the env into a file in contextdir and use RUN --mount=type=bind,src=myfile.sh,target=myfile.sh,Z source myfile.sh <do other operation>

@chmeliik Any thoughts ?

flouthoc avatar Feb 13 '25 16:02 flouthoc

One hack which can be done is dump all the env into a file in contextdir and use RUN --mount=type=bind,src=myfile.sh,target=myfile.sh,Z source myfile.sh <do other operation>

@chmeliik Any thoughts ?

That's pretty much what we currently do

Inject a .env shell script into the build using --volume. Dynamically modify the RUN instructions ...

With the downsides mentioned in the issue description.

For more context: we don't own the Containerfiles we build. A user supplies the Containerfile, and we'd like the ability to set build-time environment variables without having to modify their Containerfile.

chmeliik avatar Feb 13 '25 16:02 chmeliik

--env Sets the environment variable in the image config, which we want to avoid. We want to set the environment variables only at build time

Yeah, though one could also edit the generated config to remove them after today.

A new --build-env CLI option for buildah build that would set environment variables for RUN instructions but wouldn't set them on the resulting image config.

Makes sense to me, although

Some users are uncomfortable with having their Containerfile dynamically modified

Right that's the thing, today cachi2 basically breaks the ability to replicate what happens in a pipeline with podman build, and if e.g. we also supported an ARG CACHI2_WHATEVER that the container owner would take responsibility to handle, that would seem like a clean option too.

cgwalters avatar Feb 26 '25 19:02 cgwalters

Yeah, though one could also edit the generated config to remove them after today.

We'd also need to take care not to unset environment variables that a user explicitly sets in their Containerfile, let's say

FROM registry.fedoraproject.org/fedora-minimal:41

ENV GOMODCACHE=/tmp/gomodcache

We would end up running something like buildah build --env GOMODCACHE=/cachi2/output/deps/gomod -f Containerfile. It seems that the ENV in the Containerfile takes precedence in this case, which is probably good. It breaks the cachi2 integration, but that might be fine. The Containerfile owner can fix that by moving the ENV below all the relevant RUN instructions (that might feel weird though). We would just have to make sure not to unset variables if their value is different from what we thought we were setting.

But it is a bit of unpleasant added complexity.

if e.g. we also supported an ARG CACHI2_WHATEVER that the container owner would take responsibility to handle, that would seem like a clean option too.

The existence of a --build-env option would make this unnecessary in my opinion. But if adding it is not acceptable, this could be an OK-ish fallback

chmeliik avatar Feb 27 '25 09:02 chmeliik

the ENV in the Containerfile takes precedence

This reminds me - the potential --build-env variables would need to take precedence over --env/ENV

chmeliik avatar Feb 27 '25 09:02 chmeliik

The Containerfile owner can fix that by moving the ENV below all the relevant RUN instructions

That said shouldn't basically every build be done via multi-stage? For everything except dnf installs that covers this problem I'd say as the ENV should only be transient to the builder phase. I think we could make cachi2/dnf work in a multi-stage flow too, but it would be supremely ugly like

FROM ubi as builder
ENV cachi2=blah # or whatever
RUN dnf download foo bar baz

FROM ubi
RUN --mount=from=builder,target=/builder dnf -y install /builder/*.rpm

cgwalters avatar Feb 27 '25 16:02 cgwalters

That said shouldn't basically every build be done via multi-stage? For everything except dnf installs that covers this problem

I think most Python apps also wouldn't be built multi-stage (could be, but people aren't used to it).

But I don't really care how our users build their Containers, I'm looking for an easy solution that would cover the most use cases

chmeliik avatar Feb 27 '25 16:02 chmeliik

As described, this would intentionally not leave a trace in the built image's config, meaning it could not be accounted for by the cache evaluation logic.

nalind avatar Feb 28 '25 16:02 nalind

As described, this would intentionally not leave a trace in the built image's config, meaning it could not be accounted for by the cache evaluation logic.

Ah, so it would have to imply --no-cache (or require that the user also specify --no-cache explicitly). That would work for us

chmeliik avatar Feb 28 '25 17:02 chmeliik

A friendly reminder that this issue had no activity for 30 days.

github-actions[bot] avatar Mar 31 '25 00:03 github-actions[bot]

Would this be a reasonable feature to have, or do the caching concerns disqualify it?

chmeliik avatar Apr 01 '25 09:04 chmeliik

A friendly reminder that this issue had no activity for 30 days.

github-actions[bot] avatar May 02 '25 00:05 github-actions[bot]

We would still be interested in having this

chmeliik avatar May 02 '25 08:05 chmeliik