Javier García
Javier García

Reputation: 1114

docker-compose overrides directories in the container

Context

I set up a PHP application recently to work in a docker container connected to a database in a different container.

In production, we're using a single container environment since it just connects to the database which is hosted somewhere else. Nonetheless, we decided to use two containers and docker-compose locally for the sake of easing the development workflow.

Problem

The issue we've encountered is that the first time we build and run the application via docker-compose up --build Composer's vendor directory isn't available in the container, even though we had a specific RUN composer install line in the Dockerfile. We would have to execute the composer install from within the container once it was running.

Solution found

After a lot of googling around, we figured that we had two possible solutions:

  1. change the default command of our Docker image to the following:
bash -c "composer install && /usr/sbin/apache2ctl -D FOREGROUND"
  1. Or simply override the container's default command to the above via docker-compose's command.

The difference is that if we overrid the command via docker-compose, when deploying the application to our server, it would run seamlessly, as it should, but when changing the default command in the Dockerfile it would suffer a 1 minute-ish downtime everytime we deployed.

This helped during this process:

  1. Running composer install within a Dockerfile

Some (maybe wrong) conclusions

My conclusion was that that minute of downtime was due to the container having to install all the dependencies via composer before running the Apache server, vs simply running the server.

Furthermore, another conclusion I drew from all the poking around was that the reason why the docker-compose up --build wouldn't install the composer dependencies was because we had a volume specified in the docker-compose.yml which overrid the directories in the container.

These helped:

  1. https://stackoverflow.com/a/38817651/4700998

  2. https://stackoverflow.com/a/48589910/4700998

Actual question

I was hoping for somebody to shed some light into all this since I don't really understand what's going on fully – why running docker-compose would not install the PHP dependencies, but including the composer install in the default command would and why adding the composer install to the docker-compose.yml is better. Furthermore, how do volumes come into all this, and is it the real reason for all the hassle.

Our current docker file looks like this:

FROM php:7.1.27-apache-stretch

ENV DEBIAN_FRONTEND=noninteractive

# install some stuff, PHP, Apache, etc.

WORKDIR /srv/app
COPY . .

RUN composer install

RUN service apache2 restart

EXPOSE 80

CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

And our current docker-compose.yml like this:

version: '3'
services:
  database:
    image: mysql:5.7
    container_name: container-cool-name
    command: mysqld --user=root --sql_mode=""
    ports:
      - "3306:3306"
    volumes:
      - ./db_backup.sql:/tmp/db_backup.sql
      - ./.docker/import.sh:/tmp/import.sh
    environment:
      MYSQL_DATABASE: my_db
      MYSQL_USER: my_user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: test

  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: image-name
    command: bash -c "composer install && /usr/sbin/apache2ctl -D FOREGROUND"
    ports:
      - 8080:80
    volumes:
      - .:/srv/app
    links:
      - database:db
    depends_on:
      - database
    environment:
      DB_HOST: db
      DB_PORT: 3306
      DB_DATABASE: my_db
      DB_USER: my_user
      DB_PASSWORD: password

Upvotes: 2

Views: 3375

Answers (1)

alx
alx

Reputation: 2357

Your first composer install within Dockerfile works fine, and your resulting image has vendor/ etc.

But later you create a container from that image, and that container is executed with whole directory being replaced by a host dir mount:

volumes:
      - .:/srv/app

So, your docker image has both your files and installed vendor files, but then you replace project directory with one on your host which does not have vendor files, and final result looks like the building was never done.

My advice would be:

  • don't add second command build to the Dockerfile
  • mount individual folders in your container, i.e. not .:/srv/app, but ./src:/srv/app/src, etc.
  • or, map whole folder, but copy vendor files from image/container to your host
  • or use some 3rd party utility to solve exactly this problem, e.g. http://docker-sync.io or many others

Upvotes: 4

Related Questions