Get PHP Composer to Run On Docker Container [A How To Guide]

Author profile picture

@ifominIgor Fomin

Full stack web developer, tech lead, project manager

I have a php docker container, that runs my app, and I need to start using Composer to install a php package. What is the best way to approach it?
Source files can be found here:

1. Not the best approach, but the most straightforward one: not to use "php:7.2-fpm" image, but to build a custom image with both php and composer.

Technically this works, I get composer installed in my php image, and whenever I need to update or install dependencies I simply execute calls in my custom php container.
Problems:
  • need to use composer in several different containers - results in custom images for each container, where composer is needed
  • if I run docker in swarm mode and scale container to more than 1 copy - results in each container executing "composer install"

2. A much better approach: use a dedicated composer docker image, map my project inside, and execute composer commands.

Create docker-compose.yml file in "docker" folder:
version: "3.7"

services:

  web:
    image: nginx:1.17
    ports:
      - 80:80
    volumes:
      - /var/www/docker-study.loc/recipe-05/php:/var/www/myapp
      - /var/www/docker-study.loc/recipe-05/docker/site.conf:/etc/nginx/conf.d/site.conf
    depends_on:
      - php

  php:
    image: php:7.2-fpm
    volumes:
      - /var/www/docker-study.loc/recipe-05/php:/var/www/myapp
      - /var/www/docker-study.loc/recipe-05/docker/php.ini:/usr/local/etc/php/php.ini
    depends_on:
      - redis

  redis:
    image: redis:latest
    ports:
      - 6379:6379
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis-data:/data

  composer:
    image: composer:1.9
    command: ["composer", "install"]
    volumes:
      - /var/www/docker-study.loc/recipe-05/php:/app

volumes:
  redis-data:
Here I do several things:
  • /var/www/docker-study.loc/recipe-05/php:/app - composer image by default executes commands from /app folder, that's why I map project like this
  • I map /var/www/docker-study.loc/recipe-05/php to both, php container and composer container, this way composer container can execute "composer install", and php container will have the updated code
  • "depends_on" - prevents container to start before other container, on which it depends

3. Create composer.json in "php" folder:

{
    "require": {
        "predis/predis": "^1.1"
    }
}

4. Create index.php in "php" folder:

<?php

require __DIR__ . '/vendor/autoload.php';

$client = new Predis\Client([
    'scheme' => 'tcp',
    'host'   => 'redis',
    'port'   => 6379,
]);
$client->set('foo', 'works!');
$value = $client->get('foo');

echo $value;

?>
The goal here is to use composer library - "predis/predis" (just as an example). This library needs to get installed once "composer" container gets started.
I can go to /var/www/docker-study.loc/recipe-05/docker/ and execute:
docker-compose up -d
Now go to myapp.loc/ and see "works!"

5. Final Thoughts.

When composer container started, it executed "composer install" command and then exited. I can confirm this by running: "docker container ls -a" - this will show that container "docker_composer_1" has exited.
If I do - "docker logs docker_composer_1" - I can see information on what happened when container started, and how "composer install" process went.
What if I change composer.json file, and need to install additional library?
docker-compose restart composer
This will start this container again, execute install and exit.
What if I need to run "composer update" instead of "composer install"?
I can change "install" -> "update" in docker-compose.yml, and run "docker-compose restart composer"

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!