Why despite "drush" being installed via `composer global install` during image build, I cannot find the tool from within a running PHP script?

Viewed 510

I am developing a PHP web application inside of a Docker container. Using volumes: inside of my docker-compose.yml file, I have specified a local directory so that any files generated are dumped and persist after the container is destroyed.

volumes:
  - ./docroot:/var/www/html

Inside my Dockerfile, I RUN a command that installs a command line management tool:

RUN curl -sS https://getcomposer.org/installer | php && \
    mv composer.phar /usr/local/bin/composer && \
    ln -s /root/.composer/vendor/bin/drush /usr/local/bin/drush

RUN composer global require drush/drush:8.3.3 && \
    composer global update

When the container comes up, I can use docker-compose exec -it <container> bash to get inside the container, and everything works fine. drush is in my path, and I can use it globally throughout the container to manage the app.

Now here is the strange part. Part of my application is that I have to run that command from a PHP script inside the container to help automatically manage some of the build process.

Using php, I run exec('drush dbupdate', $output, $retval); $retval returns a exit status of 127, or command not found and $output is empty. If I switch up the exec to use the full path I get an exit status 126.

If I go back into the container, I can run that command just fine. Note all other cli commands work as expected with exec (ls, whoami, etc but which drush returns exist status 1)

What am I missing? Why can I use it with no problems manually, but PHP exec() can't find it? passthru(), shell_exec(), and others have the same behavior.

1 Answers

composer global install will not install the command "globally" for all users, but "globally" as in "for all projects".

Generally, these packages are installed in the home directory for the user executing the command (e.g. ~/.composer), and if they are available in your path is because ~/.composer/vendor/bin is added to the session path.

But when you run composer global require (while building the image) or when you "log in" to the running container (using exec [...] bash) the user involved is root. But when your PHP script runs, it's being executed by another user (presumably www-data). And for that user, ~/.composer does not contain anything.

Maybe do not install drush using composer, but rather download the PHAR file directly or something like that while you are building the image, and put it in /usr/local/bin.

If you are using Drupal >= 8, the recommended way of installing Drush is not as a "global" dependency, but as "project" dependency, so that the appropriate drush version is installed. This comes straight from the docs:

It is recommended that Drupal 8 sites be built using Composer, with Drush listed as a dependency. That project already includes Drush in its composer.json. If your Composer project doesn't yet depend on Drush, run composer require drush/drush to add it. After this step, you may call Drush via vendor/bin/drush

Related