Table of contents
Foreword
Today, I struggled with linking my composer vendor
folder from my container to my host. I was setting up a simple Lumen container for my microservice. Its Dockerfile looked like this:
FROM php:7.3-fpm-alpine
RUN docker-php-ext-install pdo_mysql
WORKDIR /var/www/html/
# Install composer
RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer
COPY . .
RUN composer install
It is simple. It pulls a PHP 7.3 image, installs the pdo_mysql
extension, copies my project files to the working directory, and runs a composer install.
Problem
It looked properly working at first until I realized that my Intelephense VS Code plugin started throwing a bunch of Undefined type
errors everywhere. I thought it was just a false positive before restarting my VS Code. I discovered that the culprit was an empty vendor
folder in my workspace. Weird!
Personally, it was a frustrating experience. Especially to me who just recently picked up Docker. I did some research and stumbled upon a Stackoverflow answer which talks about a similar issue I am having. It is about a developer not having his node_modules
showing up on his host machine. I appropriated the proposed solutions in the thread for my vendor
folder!
Solution
As stated in one of the answers, a solution can be to create a cache directory in your Dockerfile along with a couple of tricks. Like so:
FROM php:7.3-fpm-alpine
RUN apk add rsync
RUN docker-php-ext-install pdo_mysql
# Set up cache directory
RUN mkdir /var/www/cache
WORKDIR /var/www/cache
# Install composer
RUN mkdir tests
COPY composer.* ./
RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer
RUN composer install
# Move to actual working directory
WORKDIR /var/www/html
Aside from what we have known so far, we are adding rsync
on our container. We will be using this for our entry-point.sh
script later. We are just setting up a cache directory where we move our composer-related files there and do the composer install. After that, we move to our actual working directory!
The real MVP behind this solution is the entry-point.sh
file. Like so:
#!/bin/sh
# copy from the image backup location to the volume mount
echo "Synchronizing vendor files..." rsync -a --stats /var/www/cache/vendor/* /var/www/html/vendor/ echo "Synchronized vendor files"
# run PHP server
exec php -S lumen:8000 -t public # port 8000 here will be overwritten by config
It is invoked in my docker-compose.yml
. It synchronizes the contents of our cache directory to our actual vendor folder. I used rsync
because using plain old cp
can be unnecessary overhead; considering this entry-point.sh
script is ran every time this container is ran. Then, as usual, execute your remaining commands as needed.
Additionally, my docker-compose.yml
looks like this if you are curious:
version: "3.5"
services:
lumen:
build: .
ports: - "${APP_PORT:-8000}:8000"
volumes: - .:/var/www/html
command: /var/www/html/entry-point.sh
Final Thoughts
My vendor
folder now has its proper and expected contents. It even syncs up properly whenever I do add new composer dependencies in the container! Cool beans.