patternbashlaravelMinor
Laravel Docker-Compose
Viewed 0 times
dockercomposelaravel
Problem
I've created a repo for some Docker containers that work together with docker-compose to make a very easy and quick installation for Laravel including nginx, mariadb, and redis. Laravel is known for having one somewhat annoying step to get it started, which is that the
However, docker containers that use shared volumes between the container and host tend to have permission issues because of discrepancies between uids and guids differing between the container and the host.
This is a Mac-only project until I get these basic issues solved. The repository can be found here.
I would greatly appreciate solutions for how to have the PHP process user in the PHP container have write permissions on those directories in the shared volume.
This install script (called by typing
install
```
#!/bin/bash
echo "installing and building docker containers..."
docker-compose up -d
echo "installing laravel/installer via composer..."
rm -rf code
if [[ $(composer global show) != laravel/installer ]]
then
composer global require "laravel/installer"
fi
echo "installing laravel..."
laravel new code
echo "changing working directory to code..."
cd code
echo "setting permissions..."
chmod -R 777 storage bootstrap/cache
docker exec ${PWD##*/}_php_1 chgrp -R www-data /code
docker exec ${PWD##*/}_php_1 chmod -R 777 storage bootstrap/cache
echo "installing predis..."
composer require "predis/predis"
echo "installing correct database settings to laravel..."
sed -i '' "s/DB_HOST=127.0.0.1/DB_HOST=mariadb/" .env
sed -i '' "s/DB_DATABASE=homestead/DB_DATABASE=laravel/" .env
sed -i '' "s/DB_USERNAME=homestead/DB_USERNAME=laravel/" .env
sed -i '' "s/REDIS_HOST=127.0.0.1/REDIS_HOST=redis/" .env
sed -i '' "s/CACHE_DRIVER=file/CACHE_DRIVER=redis/" .env
sed -i '' "s/SESSIO
storage and bootstrap/cache directories have to be writable by the webserver/php process:chmod -R 777 storage bootstrap/cacheHowever, docker containers that use shared volumes between the container and host tend to have permission issues because of discrepancies between uids and guids differing between the container and the host.
This is a Mac-only project until I get these basic issues solved. The repository can be found here.
I would greatly appreciate solutions for how to have the PHP process user in the PHP container have write permissions on those directories in the shared volume.
This install script (called by typing
./install into the terminal) is what should be theoretically setting the permissions:install
```
#!/bin/bash
echo "installing and building docker containers..."
docker-compose up -d
echo "installing laravel/installer via composer..."
rm -rf code
if [[ $(composer global show) != laravel/installer ]]
then
composer global require "laravel/installer"
fi
echo "installing laravel..."
laravel new code
echo "changing working directory to code..."
cd code
echo "setting permissions..."
chmod -R 777 storage bootstrap/cache
docker exec ${PWD##*/}_php_1 chgrp -R www-data /code
docker exec ${PWD##*/}_php_1 chmod -R 777 storage bootstrap/cache
echo "installing predis..."
composer require "predis/predis"
echo "installing correct database settings to laravel..."
sed -i '' "s/DB_HOST=127.0.0.1/DB_HOST=mariadb/" .env
sed -i '' "s/DB_DATABASE=homestead/DB_DATABASE=laravel/" .env
sed -i '' "s/DB_USERNAME=homestead/DB_USERNAME=laravel/" .env
sed -i '' "s/REDIS_HOST=127.0.0.1/REDIS_HOST=redis/" .env
sed -i '' "s/CACHE_DRIVER=file/CACHE_DRIVER=redis/" .env
sed -i '' "s/SESSIO
Solution
If any of the commands fail, then the script ploughs blindly on afterwards. That's probably not what we want - and it's certainly not what we want if this command fails:
We can fix this by testing the exit status of the command, e.g. with
We can simplify this
If we read it as "either
Or we could write it in portable shell, allowing us to use plain
Here, we expand a variable unsafely:
We need quotes, i.e.
Even in a Docker container, I feel dirty about granting write permission to "other" users (i.e. the 002 bit).
As mentioned by Sᴀᴍ Onᴇᴌᴀ, the multiple
This is still a little tedious to write, so I have previously written a function to create a suitable
This command is pointless:
The only thing we do in this process after that is a simple
cd codeWe can fix this by testing the exit status of the command, e.g. with
||, but I recommend setting the -e flag of the shell to make failed commands exit the shell immediately. While we're at it, let's set -u so that misspelling a variable name is caught as an error:set -euWe can simplify this
if/then:if [[ $(composer global show) != *laravel/installer* ]]
then
composer global require "laravel/installer"
fiIf we read it as "either
laravel/installer is already required, else require it", that becomes[[ $(composer global show) == *laravel/installer* ]] ||
composer global require "laravel/installer"Or we could write it in portable shell, allowing us to use plain
/bin/sh rather than needing Bash:case "$(composer global show)" in
*laravel/installer*) ;; # no action needed
*) composer global require "laravel/installer" ;;
esacHere, we expand a variable unsafely:
docker exec ${PWD##*/}_php_1 chgrp -R www-data /code
docker exec ${PWD##*/}_php_1 chmod -R 777 storage bootstrap/cacheWe need quotes, i.e.
"${PWD##*/}_php_1". And we might want to consider running both commands together:docker exec "${PWD##*/}_php_1" \
sh -c 'chgrp -R www-data /code && chmod -R 777 storage bootstrap/cache'Even in a Docker container, I feel dirty about granting write permission to "other" users (i.e. the 002 bit).
As mentioned by Sᴀᴍ Onᴇᴌᴀ, the multiple
sed commands modifying one file can be combined. Also, if we use the keys to address the relevant lines, we can avoid repetition and be more robust about initial values:sed -i '' \
-e '/^DB_HOST=/s/=.*/=mariadb/' \
-e '/^DB_DATABASE=/s/=.*/=laravel/' \
-e '/^DB_USERNAME=/s/=.*/=laravel/' \
-e '/^REDIS_HOST=/s/=.*/=redis/' \
-e '/^CACHE_DRIVER=/s/=.*/=redis/' \
-e '/^SESSION_DRIVER=/s/=.*/=redis/' \
.envThis is still a little tedious to write, so I have previously written a function to create a suitable
sed script from a list of keys and values (which as written needs Bash for the ${//} substitution; we don't actually need that here because none of our values contain /, so we could get away with "$@" instead of "${@//\//\\/}"):change_values() {
printf '/^%s *=/s/=.*/= %s/\n' "${@//\//\\/}"
}sed -i '' \
-e "$(change_values \
DB_HOST mariadb \
DB_DATABASE laravel \
DB_USERNAME laravel \
REDIS_HOST redis \
CACHE_DRIVER redis \
SESSION_DRIVER redis \
)" \
.envThis command is pointless:
echo "returning working directory to previous state..."
cd ..The only thing we do in this process after that is a simple
echo, which is unaffected by the change of directory. We can simply remove these two lines.Code Snippets
if [[ $(composer global show) != *laravel/installer* ]]
then
composer global require "laravel/installer"
fi[[ $(composer global show) == *laravel/installer* ]] ||
composer global require "laravel/installer"case "$(composer global show)" in
*laravel/installer*) ;; # no action needed
*) composer global require "laravel/installer" ;;
esacdocker exec ${PWD##*/}_php_1 chgrp -R www-data /code
docker exec ${PWD##*/}_php_1 chmod -R 777 storage bootstrap/cachedocker exec "${PWD##*/}_php_1" \
sh -c 'chgrp -R www-data /code && chmod -R 777 storage bootstrap/cache'Context
StackExchange Code Review Q#139150, answer score: 2
Revisions (0)
No revisions yet.