1

I'm provisioning docker Centos image with Packer and using bash scripts instead of Dockerfile to configure image (this seems to be the Packer way). What I can't seem to figure out is how to update PATH variable so that my custom binaries can be executed like this:

docker run -i -t <container> my_binary

I have tried putting .sh file in /etc/profile.d/ folder and also writing directly to /etc/environment but none of that seems to take effect.

I'm suspecting it has something to do with what shell Docker uses when executing commands in a disposable container. I thought it was Bourne Shell but as mentioned earlier neither /etc/profile.d/ nor /etc/environment approach worked.

UPDATE:

As I understand now, it is not possible to change environment variables in a running container due to reasons explained in @tgogos answer. However I don't believe this is an issue in my case since after Packer is done provisioning the image, it commits it and uploads to Docker Hub. More accurate example would be as follows:

$ docker run -itd --name test centos:6
$ docker exec -it test /bin/bash
[root@006a9c3195b6 /]# echo 'echo SUCCESS' > /root/test.sh  
[root@006a9c3195b6 /]# chmod +x /root/test.sh
[root@006a9c3195b6 /]# echo 'export PATH=/root:$PATH' > /etc/profile.d/my_settings.sh
[root@006a9c3195b6 /]# echo 'PATH=/root:$PATH' > /etc/environment
[root@006a9c3195b6 /]# exit
$ docker commit test test-image:1
$ docker exec -it test-image:1 test.sh

Expecting to see SUCCESS printed but getting

OCI runtime exec failed: exec failed: container_linux.go:296: starting container process caused "exec: \"test.sh\": executable file not found in $PATH": unknown

UPDATE 2

I have updated PATH in ~/.bashrc which lets me execute following:

$ docker run -it test-image:1 /bin/bash
[root@8f821c7b9b82 /]# test.sh 
SUCCESS

However running docker run -it test-image:1 test.sh still results in

docker: Error response from daemon: OCI runtime create failed: container_linux.go:296: ...

I can confirm that my image CMD is set to "/bin/bash". So can someone explain why running docker run -it test-image:1 test.sh doesn't source ~/.bashrc?

IvanR
  • 533
  • 4
  • 23

2 Answers2

0

/etc/profile is only read by bash when invoked by a login shell.

For more information about which files are read by bash on startup see this article.

EDIT: If you change the last line in your example to: docker exec -it test bash -lc test.sh it works as you expect.

Rickard von Essen
  • 4,110
  • 2
  • 23
  • 27
  • Thanks for your reply. I have tried setting PATH in `/etc/profile` and `/etc/bash.bashrc` (which according to the article you shared are the first places Bash looks for) and that had no effect. It makes me doubt whether commands executed as `docker run -it my_binary` run in a bash shell at all. – IvanR Mar 08 '18 at 12:52
  • Also worth to note is that you don't have a she bang in `test.sh` and thus it is invoked by `sh` and not bash. – Rickard von Essen Mar 08 '18 at 15:24
  • Good observation but not an issue since it never comes to actually executing `test.sh` since it doesn't know where to find it. – IvanR Mar 08 '18 at 15:54
  • Since you never invokes bash. – Rickard von Essen Mar 08 '18 at 16:13
  • so "where" (i.e. in what environment) is `test.sh` being executed when invoked as `docker run -it test-image:1 test.sh` ? I thought it runs in `/bin/bash` because that is what CMD is set too. But having re-read Dockerfile documentation I'm not sure that is the case. – IvanR Mar 08 '18 at 16:26
0

A few good points are mentioned at:

where @BMitch mentions:

Destroy your container and start a new one up with the new environment variable using docker run -e .... It's identical to changing an environment variable on a running process, you stop it and restart with a new value passed in.

and in the comments section, he adds:

Docker doesn't provide a way to modify an environment variable in a running container because the OS doesn't provide a way to modify an environment variable in a running process. You need to destroy and recreate.

update: (see the comments section)

You can use

docker commit --change "ENV PATH=your_new_path_here" test test-image:1
tgogos
  • 23,218
  • 20
  • 96
  • 128
  • Thanks a lot or your reply! It has clarified some things for me. Unfortunately, one of them was that my "Minimal, Complete, and Verifiable example" was too minimal and not complete enough. In particular, after provisioning is done via Packer, resulting container is exported to Docker Hub. Later, when other users attempt to use it and run the `my_binary` is when they get the issue of that binary not being on the PATH. I have updated mcve and would really appreciate if you could check **UPDATED 2** section of my answer and see if you know solution for that scenario. – IvanR Mar 08 '18 at 14:36
  • Sorry, I read second post you share in more detail (Docker - Updating Environment Variables of a Container) and it seems to be similar to my scenario. My understanding is that I should be able to preserve filesystem changes made during provisioning step for them to be available later, **What I'm missing is what those changes have to be exactly**. – IvanR Mar 08 '18 at 14:43
  • I see the `PATH` container variable is being saved at `/var/lib/docker/containers/b03d22......./config.v2.json` and this is why a [github user](https://github.com/moby/moby/issues/8838#issuecomment-117284347) proposes to stop docker daemon, update the file and restart. I don't think this is a good solution. I am afraid that you have to `docker run` a new container with the value you want (from the begining) because `PATH` can't be changed in retrospect... – tgogos Mar 08 '18 at 15:21
  • github issue you linked to is still talking about modifying running container. In my case I want to make sure that environment variable changes persist after container is committed to an image. – IvanR Mar 08 '18 at 15:44
  • I updated my answer based on your request about `docker commit`. I tried to use something like: `/root:$PATH` but it takes the PATH variable of my host. – tgogos Mar 08 '18 at 16:07
  • I saw that I can do something like this but I would really like to avoid it and instead be able to modify PATH from inside the container. Reason for that being that I want to keep all changes inside the provisioning script, but in order to use your suggested approach with `commit --change` I would have to modify Packer template. – IvanR Mar 08 '18 at 16:15
  • After spending some more time studying my options, it appears that your suggestion to use `--change` flag is the best in my case. Unfortunately, I was unable to make it work (see details https://stackoverflow.com/questions/49235330/how-to-update-docker-container-path-using-commit-change-flag). Have you used it before? Perhaps you came across similar issue as described in my other question? – IvanR Mar 12 '18 at 13:09