How can I get ash to load some environment variables on startup?
Just put them in /etc/profile
/etc/profile is only read for login shells; what about non-login shells, as frequently pop up when working with docker (which uses alpine>busybox>ash)?
A non-login shell will read a file if specified in the environment variable ENV
Great, how can I ensure ENV is set? It is itself an environment variable, and blank by default.
Essentially I’m looking for some overarching config file which ash is guaranteed to read. Preference for the version of ash used by busybox (BusyBox v1.28.4, if you want to be exact). Does such a thing exist? And yes, I know about the ENV directive in docker, which could be used to set $ENV when building a docker image; I'd still like to know if this is possible outside docker.
I have read this and this in an effort to understand.
As a side note, can anyone explain this odd behavior in alpine?
$docker run -it alpine
/ # echo $CHARSET #proof /etc/profile has not run
/ # echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/ # env -i sh -c 'echo $PATH'
/sbin:/usr/sbin:/bin:/usr/bin
/ # echo $ENV
/ #
What’s adding to the PATH compared to the default PATH set for a new shell, when we can show /etc/profile hasn’t? It’s not docker dickery either, the Dockerfile for alpine is deliberately minimal:
FROM scratch
ADD rootfs.tar.xz / #Automatically extracts, and I’m pretty sure that’s all
CMD ["/bin/sh"]
I only mention this because it looks like someone has found a way to persist an environment variable in a non-login shell without the use of $ENV.
I appreciate any information or context, however tangential.
Best Answer
When you run a docker container, you're running isolated from the calling environment. Variables aren't directly inherited.
We can see a "clean" environment, which we can see by creating a totally minimal container.
e.g. a
go
program:We can build this into a tiny container:
And if we run this:
These are variables created by the docker engine at runtime.
So when you
run .. /bin/sh
you're running a non-login shell that just inherits the environment docker creates. Since it's not a login shell,/etc/profile
isn't run./bin/sh
will, itself, create some default variables if they do not exist.So there are a number of ways you can do this. Off the top of my head, here's two ideas:
You can pass environment variables on the docker command line with
-e
.You could build your own image based on alpine with
ENV
commands:Basically, what you're seeing is the docker run time providing some variables,
/bin/sh
providing other variables, and isolation from the calling environment.