2

I am creating a web application using Java/Postgres/Docker/Gradle. My project is set up like this:

There is a db container and an application container. The app container just runs a plain jar file. The jar file is added using a volume from the host system. The container initially runs this jar and monitors it for changes. If it changes, it redeploys the jar allowing developers to see the changes on their local machines immediately. This is like deploying/updating a war file on Tomcat. The live application updates when you 'push a button'. No need to stop the app, rebuild and rerun: Just rebuild.

Using the Postgres image on Dockerhub, I want to do something similar: I want to 'push a button' in gradle which will update some file monitored by the DB container and have it redeploy.

I've hit a wall, unfortunately. My initial idea was to create a Dockerfile that extends the Postgres one. All it would do is run the Postgres service as usual and run a script looking for changes in some file and redeploying.

The following Dockerfile fails, unfortunately:

FROM postgres:9.4

WORKDIR /db
COPY monitor.py .
COPY run-pg-and-monitor.sh .

CMD ["run-pg-and-monitor.sh"]

The shell script has the following commands:

# Run monitor in the background
python3 monitor.py &

# Run postgres normally
postgres

Unfortunately, this doesn't fly with Postgres. I get the error:

db_1       | "root" execution of the PostgreSQL server is not permitted.
db_1       | The server must be started under an unprivileged user ID to prevent
db_1       | possible system security compromise.  See the documentation for
db_1       | more information on how to properly start the server.

If I were to set the command to:

CMD ["postgres"]

which is what the Postgres container originally did, the error goes away. Obviously, this doesn't run monitor.py which I need.

Oddly enough, running CMD without the square brackets also causes this issue.

CMD postgres

Running it from a shell environment also fails:

CMD ["sh", "-c", "postgres"]

Perhaps this has something to do with running it from a shell...

I know that postgres is supposed to be run from the postgres user and not root. What I find strange is if I set CMD to:

CMD ["whoami"]

I get:

db_1       | root

So, it was already running postgres as root with no problems.

A second idea I had was to just make a gradle task that:

1) Updates the jar which triggers a redeploy for the app container

2) Runs docker exec ... to update the running db container manually.

The only problem with this idea is that the job will obviously fail in the event that there is no app or db container running. I would have to add logic which checks to see if they are. This does not seem ideal.

Does anyone have any insights? Is there a solution that already exists I'm not aware of?

  • https://linux.die.net/man/1/su – Stephen Rauch Sep 02 '18 at 23:22
  • Don't know postgres, but there is likely an account that you need to run these under... If you enter a running container in your scenario that is working, you can check to see what account the postgres daemon in using, and then use `su` to do the same. – Stephen Rauch Sep 02 '18 at 23:24
  • I tried running with su. When I did that, it complained that the 'postgres' command was not found... – Andrew Cahill Sep 02 '18 at 23:33
  • Which user did you use for `su`? And you probably need to use a full path to `postgres`. Or maybe use `-p` to keep the environment/path. – Stephen Rauch Sep 02 '18 at 23:34
  • After attempting to run as postgres, it complained that a file could not be found. It's really very strange how this happens, too. It appears that the Postgres Dockerfile runs as root anyway. https://github.com/docker-library/postgres/blob/36294f464a4253017c4d9e04657d5469556f27f8/9.4/Dockerfile – Andrew Cahill Sep 02 '18 at 23:50
  • Default user in the container is root... – Stephen Rauch Sep 02 '18 at 23:51
  • And if you see the CMD section of the dockerfile, you, it says CMD ["postgres"] – Andrew Cahill Sep 03 '18 at 00:04
  • Since it is root, one might expect it to fail no matter what. But it doesn't. It does fail if you try to run it in a shell environment or don't use the square brackets. For instance: – Andrew Cahill Sep 03 '18 at 00:05
  • CMD postgres or CMD ["sh", "-c", "postgres"] – Andrew Cahill Sep 03 '18 at 00:06

1 Answers1

1

The reason for those oddities is that the postgres Dockerfile sets it's own docker-entrypoint.sh script as ENTRYPOINT for the image. So on container start docker-entrypoint.sh is executed and whatever is set as CMD is passed to the script as it's argument(s).

The entry script will do the required init steps for postgres, like dropping privileges, only if the first passed argument equals postgres (see here and here), before finally simply executing whatever was passed via CMD.

Overriding ENTRYPOINT instead of CMD, essentially wrapping docker-entrypoint.sh with your own script, should give you the desired behavior:

# Run monitor in the background
python3 monitor.py &

# Run postgres normally
docker-entrypoint.sh "$@"
Erik Dannenberg
  • 5,716
  • 2
  • 16
  • 21
  • Shoot, I clearly need to study up on the subtleties of Docker. Yeah, I knew I was missing something. Thanks for the info! – Andrew Cahill Sep 08 '18 at 18:46
  • I ended up just signaling the running db container from the host, but with this info, I might be able to do what I wanted to from the start. Thanks! – Andrew Cahill Sep 08 '18 at 18:47
  • Ok, ok. I think I get it. So, in shell/bash, "$@" is just the positional parameters from CMD (or whatever calls it). In this case, it's just ["postgres"]. That gets used by ENTRYPOINT which also does Postgres-ey incantations to start properly. Wasn't aware of what ENTRYPOINT did until now. – Andrew Cahill Sep 08 '18 at 18:58