Today I learned about symlinks and deleting protected files

  • Written on: Fr Dec 2020
  • Last update: Fr Dec 2020

Today I wanted to build my VueJS app inside a Docker container. The whole thing is then deployed with Capistrano and served with Nginx.

One thing I stubbled on was that I was trying to mount my app folder inside my container but there was one file, a config file, that wasn't imported in the container. That's problematic because my app needed that file. Then I thought, why does that file is not imported in the container? Then I remembered that file was a linked file. That means it was shared between releases in our server. Every time we release, Capistrano makes a symlink from that shared file to every release.

By searching on that side, I discovered that any files that are symlink cannot be mounted inside a Docker volume.

That made me think on how to handle that. My solution was to mount a config file that was not a symlink!

By doing that, I made a bash script that would copy my config file into a temporarily file, mount a volume for that file in my container, then remove that temporarily file.

SYMLINK_FILE=$(readlink $(pwd)/config/config.json)
UNLINKED_FILE=config-unlinked.json

## Copy the config file that is a symlink due to Capistrano release
## to a temporarly file
if test -f "$SYMLINK_FILE"; then
  cp $SYMLINK_FILE $UNLINKED_FILE
else
  cp config/config.json $UNLINKED_FILE
fi

## Run the build and mount a volume from the unlinked file to the container config
docker run -it --rm \
  -v $(pwd)/$UNLINKED_FILE:/app/config/config.json \
  -v app_node_modules:/app/node_modules \
  -v $(pwd):/app \
  --user $(id -u):$(id -g) \
  $(docker build --force-rm -q .)

## Remove the unlinked file since we don't need it anymore
rm $(pwd)/$UNLINKED_FILE

Deleting files as non root through Docker

On the same subject about Capistrano, I had an issue with releases files that weren't deleted because the files that my build created on deployment were created on root.

That's an issue because we don't have root access to our servers but a specific user. With that user, we cannot delete root files.

A trick I've found is to mount my Capistrano releases folder inside a Node container. Note that Node uses the root user by default.

docker run -it --rm -v $(pwd)/releases:/releases node:12.0 bash

By doing that, I'm accessing my Node container where I have a releasesfolder with all my releases. Then I just have to delete the releases I don't need anymore by doing :

rm -rf /releases/2020122020203

This will remove the release folder and because we mounted the container with our real releases folder, it will also remove that folder in our machine, even if we don't have root access!