0

Project

I am building a docker-compose file for a simple devops stack. One of the tools is Helix Core by Perforce. I am trying to build an Ubuntu Dockerfile, that will install Helix Core and then run it. I have already written a bash script install.sh that when put like this

FROM ubuntu:20.04
COPY ./install.sh /install.sh
ENTRYPOINT["/bin/bash", "/install.sh"]

will work flawlessly.

Breaking Change

The problem is that I need the script to run as a setup step and not every time the container is started. So I tried the following:

FROM ubuntu:20.04
COPY ./install.sh /install.sh
RUN chmod +x /install.sh
SHELL ["/bin/bash", "-c"] 
RUN /install.sh
ENTRYPOINT [ "p4d" ]

Problem

Now firstly I do not get any descriptive output in the console. The only thing I get is the default building output.

...
=> CACHED [2/4] COPY ./install.sh /install.sh                                                                                                                                                                                                                                                         0.0s 
=> CACHED [3/4] RUN chmod +x /install.sh                                                                                                                                                                                                                                                              0.0s 
=> CACHED [4/4] RUN /install.sh                                                                                                                                                                                                                                                                       0.0s 
=> exporting to image
...

Secondly the script does not seem to execute or fails immediately. (It should take much longer than it does.) Here is the script, it does work in the first Dockerfile, just not in the second.

#!/bin/bash

service_name="${service_name:="master"}"
p4root="${p4root:="/opt/perforce/servers/$service_name"}"
unicode_mode="${unicode_mode:=0}"
case_sensitive="${case_sensitive:=0}"
p4port="${p4port:="1666"}"
super_user_login="${super_user_login:="super"}"

if [ -z "$super_user_password" ]
then
    echo "Install aborted!"
    echo "Please set 'super_user_password' via environment variable!"
    exit
fi

echo "Installing Helix Core..."

echo "Updating Ubuntu..."
apt-get update -y

echo "Installing utilities..."
apt-get install ca-certificates wget gpg curl -y

echo "Downloading public key..."
curl https://package.perforce.com/perforce.pubkey > perforce.pubkey

echo "Adding public key..."
gpg init
gpg -n --import --import-options import-show perforce.pubkey

rm perforce.pubkey

echo "Adding perforce packaging key to keyring..."
wget -qO - https://package.perforce.com/perforce.pubkey | apt-key add -

echo "Adding perforce repository to APT configuration..."
echo "deb http://package.perforce.com/apt/ubuntu focal release" > /etc/apt/sources.list.d/perforce.list

echo "Updating Ubuntu..."
apt-get update -y

echo "Installing..."
apt-get install helix-p4d -y

echo "Install complete! Writing config file..."

/opt/perforce/sbin/configure-helix-p4d.sh $service_name -n -p $p4port -r $p4root -u $super_user_login -P $super_user_password

p4 admin stop

Extra Information

The Dockerfile is being built with docker-compose, but I have already tried out docker build with no success.

My Thoughts

It is my understanding that the only relevant difference between RUN and ENTRYPOINT is, that RUN only executes one time in the lifecycle of a container (in the build phase), while ENTRYPOINT defines the executable that will be started together with the container every time it is started. So I assume the environment that script is called in is the same.

Any ideas to why this behavior occurs and how to fix it are appreciated.

Juhuja
  • 147
  • 5
  • 1
    Probably a good first thing to look at is [Why is docker build not showing any output from commands?](https://stackoverflow.com/questions/64804749/why-is-docker-build-not-showing-any-output-from-commands), which should help you get output from your script. Do you have specific evidence that the script is failing? (Note the `CACHED` line: if it hasn't changed, Docker won't re-run it on rebuild.) – David Maze May 04 '22 at 13:49
  • @DavidMaze Thanks for that. I have already had a look at that and assumed I had done something wrong, but I just looked at it again and saw it. Sadly this just causes more problems. My script can not access environment variables from RUN – Juhuja May 04 '22 at 13:55

1 Answers1

0

So thanks to @DavidMaze I took another look at something I overlooked before. You can get output from the build command using --progress (see: Why is docker build not showing any output from commands?) Problem 1 solved!

From there I found:

#6 [4/4] RUN /install.sh
#6 sha256:26be9fa6818fd9e3a0fb64e95a83b816de790902b1f54da1c123ff19888873ff
#6 0.344 Install aborted!
#6 0.344 Please set 'super_user_password' via environment variable!
#6 DONE 0.4s

Problem 2 identified!

Now... the actual problem is that: Environment variables and arguments are two different things. You want environment variables for the execution environment and arguments for the build environment. This webpage explained it to me.

My mistake was trying to use environment variables for the build environment.

Modified dockerfile:

FROM ubuntu:20.04
COPY ./install.sh /install.sh
SHELL ["/bin/bash", "-c"] 
RUN chmod +x /install.sh 
RUN ["/install.sh", "$super_user_password"]
ENTRYPOINT [ "p4d" ]

and I had to add this line to my script:

super_user_password="$1"

And finally... it works!

Juhuja
  • 147
  • 5
  • 1
    Build [`ARG`](https://docs.docker.com/engine/reference/builder/#arg)s will be visible to `RUN` commands, but not the main container process, as environment variables. Is that what you're after? (This invocation runs your script with literally the string `$super_user_password`.) – David Maze May 04 '22 at 14:50
  • @DavidMaze Yes this was my misunderstanding at the time. I thought environment variables where available to RUN commands, which they are not. Can you clarify why the script gets passed the string "$super_user_password" exactly? I assume it's because of the line `RUN ["/install.sh", "$super_user_password"]` that should be `RUN ["/install.sh", $super_user_password]`. I can not see how that behaves yet, as I now have other problems to deal with that are more on the perforce side of things. – Juhuja May 05 '22 at 07:34
  • Both `ARG` and `ENV` settings should be visible to `RUN` commands as environment variables. If you use JSON-array form `RUN ["command", "arg"]` no shell is invoked and the `arg` gets passed to the command as-is, with no environment variable substitution or other handling. – David Maze May 05 '22 at 15:27