shlink: Unable to set `readOnlyRootFilesystem` in Kubernetes deployment

Shlink version

3.7.2-non-root

PHP version

3.7.2-non-root

How do you serve Shlink

RoadRunner Docker image

Database engine

PostgreSQL

Database version

16.1

Current behavior

I am trying to set a Kubernetes security context on shlink however it doesn’t work and falis with the following error.

            securityContext:
              allowPrivilegeEscalation: false
              readOnlyRootFilesystem: true
              capabilities: { drop: ["ALL"] }
│   ERR  In FileNotWritableException.php line 45:                                                                                                                                         │
│   ERR                                                                                                                                                                                   │
│   ERR    [ProxyManager\Exception\FileNotWritableException]                                                                                                                              │
│   ERR    Cannot rename "/tmp/ShlinkProxy__PM__GeoIp2DatabaseReaderGenerated1cc76100a                                                                                                    │
│   ERR    9790b1d2nlMain" to "/etc/shlink/data/proxies/ShlinkProxy__PM__GeoIp2Databas                                                                                                    │
│   ERR    eReaderGenerated1cc76100a9790b1d241b38c9b0c3801c.php": rename(/tmp/ShlinkPr                                                                                                    │
│   ERR    oxy__PM__GeoIp2DatabaseReaderGenerated1cc76100a9790b1d2nlMain,/etc/shlink/d                                                                                                    │
│   ERR    ata/proxies/ShlinkProxy__PM__GeoIp2DatabaseReaderGenerated1cc76100a9790b1d2                                                                                                    │
│   ERR    41b38c9b0c3801c.php): Read-only file system

Expected behavior

The application should not need r/w access to the root filesystem

How to reproduce

Deploy shlink in Kubernetes and set the security context as I mentioned above.

About this issue

  • Original URL
  • State: closed
  • Created 6 months ago
  • Comments: 15 (10 by maintainers)

Most upvoted comments

Looks like there is also a problem here… The cache directory “data/cache” is not writable in /etc/shlink/vendor/mezzio/mezzio-fastroute/src/FastRouteRouter.php:558

This is not needed when running Shlink with RoadRunner or openswoole. I’ll change it as part of the other modifications.

I’m pretty confident that, as a workaround, you should be good to go by mounting empty dirs to /etc/shlink/data/proxies and /etc/shlink/data/locks.

Nah, scratch that. The GeoLite db downloading needs to write directly in /etc/shlink/data 🤦🏼

I’m pretty confident that, as a workaround, you should be good to go by mounting empty dirs to /etc/shlink/data/proxies and /etc/shlink/data/locks.

If it still fails, you may need to mount /tmp as well.

In the meantime I’ll continue investigating if it’s possible to ship Shlink with an empty /etc/shlink/data.

I tried mounting /etc/shlink/data to a emptyDir but had the error mentioned here, as you mentioned it looks like it is clobbering that directory of all existing files.

I have already verified it is possible to move migrations somewhere else, so that everything inside the data dir is stuff generated at runtime.

I also need to check if it can be shipped as an empty dir, ensuring subdirs are created as required. At the moment, a few of those subdirs need to exist for everything to work, so mounting an empty dir would still fail even without taking migrations into consideration.

If they could stay in /tmp that would be great since I can mount an emptyDir to that location.

I’m afraid that’s not possible (at least without an unreasonable amount of changes). Shlink needs to write a number of temporary/static files at runtime (GeoLite db file, entity proxies, service proxies, filesystem locks, configuration cache files, etc).

However, all files are (or should) be written inside /etc/shlink/data/???, so you should be able to mount /etc/shlink/data instead of /tmp, if that’s an option.

Of course, that leaves the fact that there seems to be something writing in /tmp for some reason, which I need to address.

Hmmm. Looks like some proxies are written to tmp first and then moved to Shlink’s folder.

I’ll check if this can be configured.