camptocamp/docker-qgis-server

QNetworkDiskCache::prepare() unable to open temporary file

Closed this issue · 6 comments

Testing the image in a Kubernetes setup, we mount /cache als cache / tmp dir.

Using
QGIS_SERVER_CACHE_DIRECTORY=/cache
as env variable for QGIS server

And I see qgisserver writing all familiar files and dir's to that dir.

But I keep getting:
QNetworkDiskCache::prepare() unable to open temporary file
messages in the log

Anybody has a hint on how to fix this?

Sibyx commented

I am experiencing similar problems. Have you found any solution, @rduivenvoorde? I'm also facing difficulties due to the read-only filesystem usage. Consequently, sed is unable to create temporary files in the /etc/apache2/sites-enabled/ directory.

Sibyx commented

Hi @rduivenvoorde,

Here is my updated Dockerfile, along with related files, which is functioning within the Kubernetes cluster. The following adjustments had to be made:

  • The image was updated to run under a non-root user.
  • All temporary files were identified and mounted as tmpfs.
  • All pertinent environment variables were located to configure PID file creation, etc.
  • HEALTHCHECK
  • Entry-point is now customized shell script (mine included some extra logic outside of this issue)

I must confess, I haven't encountered your exact error message ("QNetworkDiskCache::prepare() unable to open temporary file"). However, I suspect it may stem from the mounting of the /tmp directory as tmpfs. Please review my updated files below, as well as the final Dockerfile. Admittedly, it's a bit of a hack, but it should suffice in resolving your issue.

Files

Dockerfile

FROM camptocamp/qgis-server

RUN echo "Mutex posixsem" >> /etc/apache2/apache2.conf
RUN sed -i -e 's/<VirtualHost \*:80>/<VirtualHost *:8080>/' /etc/apache2/sites-enabled/000-default.conf
RUN sed -i -e 's/Listen 80$/Listen 8080/' /etc/apache2/ports.conf
RUN rm -rf /etc/apache2/conf-enabled/other-vhosts-access-log.conf

# Permissions
RUN useradd --user-group --system -u 1500 --create-home --no-log-init qgis-server
RUN usermod -aG www-data qgis-server
RUN chown -R qgis-server:www-data ${APACHE_CONFDIR} ${APACHE_RUN_DIR} ${APACHE_LOCK_DIR} ${APACHE_LOG_DIR} /var/lib/apache2/fcgid /var/log /var/www/.qgis3 /var/www/plugins /usr/bin/fc-cache /etc/qgisserver
RUN chmod -R g+rw  ${APACHE_CONFDIR} ${APACHE_RUN_DIR} ${APACHE_LOCK_DIR} ${APACHE_LOG_DIR} /var/lib/apache2/fcgid /var/log /var/www/.qgis3 /var/www/plugins /usr/bin/fc-cache /etc/qgisserver
RUN chgrp -R qgis-server ${APACHE_LOG_DIR} /var/lib/apache2/fcgid

USER 1500
WORKDIR /etc/qgisserver

# Entry point will create SQL structures
COPY setup setup

USER 0
RUN chown -R qgis-server:www-data setup
RUN chmod +x setup/entrypoint.sh
RUN chmod +x setup

# /usr/local/bin/start-server
RUN rm -rf /usr/local/bin/start-server
RUN mv setup/start-server /usr/local/bin/start-server

# /etc/apache2/mods-enabled/fcgid.conf
RUN rm -rf /etc/apache2/mods-enabled/fcgid.conf
RUN mv setup/fcgid.conf /etc/apache2/mods-enabled/fcgid.conf

RUN chmod +x /usr/local/bin/start-server

USER 1500
CMD ["setup/entrypoint.sh"]

HEALTHCHECK CMD curl --fail http://localhost:8080/index.json || exit 1

EXPOSE 8080

setup/entrypoint.sh

#!/bin/sh
exec /usr/local/bin/start-server

setup/fcgid.conf

All temporary files must be inside the /tmp or under mounted tmpfs because of the read-only nature of the image inside the Kubernetes.

<IfModule mod_fcgid.c>
	FcgidConnectTimeout 20
	FcgidIPCDir /tmp/mod_fcgid
	FcgidProcessTableFile /tmp/fcgid_shm

	<IfModule mod_mime.c>
		AddHandler fcgid-script .fcgi
	</IfModule>
</IfModule>

setup/start-server

I had to remove the original fallback to port 8080 from 80 if the program is not running under root user. It was implemented using a sed command which was creating temporary files in funky locations.

#!/bin/bash -e

# Be able to install fonts without creating a new image
if [ -e /etc/qgisserver/fonts/ ]; then
    fc-cache --really-force --system-only
fi

# save the environment to be able to restore it in the FCGI daemon (used
# in /usr/local/bin/qgis_mapsev_wrapper) for the startup code.
${GET_ENV} ${FILTER_ENV} | sed -e 's/^\([^=]*\)=.*/PassEnv \1/' > /tmp/pass-env

# Save the list of variables to be passed along with the FCGI requests (used in
# /etc/apache2/conf-enabled/qgis.conf).
${GET_ENV} ${FILTER_ENV} | sed -e 's/.\+/export "\0"/' > /tmp/init-env

trap 'echo "caught a SIGTERM"; kill -TERM $PID2; wait $PID2; kill -TERM $PID1; wait $PID1' TERM
trap '' WINCH

rm -f $APACHE_RUN_DIR/apache2.pid

exec apache2 -DFOREGROUND

Environment variables

Variable Example content
QGIS_SERVER_CACHE_DIRECTORY /cache
QGIS_SERVER_LOG_STDERR 1
APACHE_RUN_DIR /tmp
APACHE_PID_FILE /tmp/apache2.pid

Mounting

Container path Description
/cache Cache location (the path should be according to the QGIS_SERVER_CACHE_DIRECTORY variable)
/tmp Temporary data (mount as tmpfs)

Execution

docker run -p 8080:8080 --read-only -v ./volumes/cache:/cache --tmpfs /tmp --env APACHE_RUN_DIR=/tmp --env APACHE_PID_FILE=/tmp/apache2.pid --env QGIS_SERVER_CACHE_DIRECTORY=/cache --name pamis-qgis-server pamis-qgis-server

If you have any questions, feel free to write me or create a comment :)

Sibyx commented

@sbrunner I am not sure if I have resolved issue in the right way. If you are alright with the changes in the comment above I can offer a PR.

I didn't succeed to seeing the issue, on which query, do you have an issue?
Do you have something like an external layer in the project?

Sibyx commented

The whole problem was to execute the image with the --read-only docker flag which is sometimes required for the k8s deployments. Also the container currently runs as root user which is also not cool in some k8s scenarios. If you want to switch to non-root user you need to do some little enhancements in scripts such as start-server because the sed commands creates temporary files which could not be created in read-only file systems.

I started to create the pull request #648 I think that it should work, thanks for your investigations @Sibyx :-)