Pointing php composer to a different directory for composer.json

I have a mediawiki running in a container, and and need to run php composer to install some extensions I need to use. The composer.json file is located in /var/www/html/. After building the image, and running docker-compose I get “Composer could not find a composer.json file in /app”. Can this be pointed to /var/www/html/ ?

I’m pretty sure I need to use the docker-compose becuase I need to update the composer.local.json from a external volume then run the composer-update.

Dockerfile:

FROM mediawiki:1.35

FROM composer:2.1.14 AS composer
COPY --from=composer /usr/bin/composer /usr/bin/composer

docker-compose.yml

version: '3'
services:
  mediawiki:
    image: mw:0.1
    container_name: mw
    restart: always
    ports:
      - 8080:80
    links:
      - database
    volumes:
      - ./volumes/mediawiki/images:/var/www/html/images
      - ./volumes/mediawiki/extensions:/var/www/html/extensions
      - ./volumes/mediawiki/LocalSettings.php:/var/www/html/LocalSettings.php
      - ./volumes/mediawiki/composer.local.json:/var/www/html/composer.local.json
    command: > 
      bash -c "composer update --no-dev --no-progress"

  database:
    image: mariadb
    container_name: db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: database
    volumes:
      - ./volumes/mariadb/config:/config
      - ./volumes/mariadb/db_backup:/backup
      - ./volumes/mariadb/mysql:/var/lib/mysql

Your built image should contain the vendor folder so it is updated during the build. Do not add composer as a command to mediawiki, because your mediawiki will not run after that even if the compose update works.

If you are still in the development stage, run composer with docker exec or create a container just for composer and mount the whole source folder to your mediawiki and also to the composer container.

Here is an old and reborn hobby project to show how I do it: GitHub - rimelek/redbobjects: Retired PHP database handling project from 2011 with some fixes for R.E. Login. NOT FOR PRODUCTION

I have a separate docker compose config for the composer and I alos have a composer.sh script.

If you look into the Dockerfile, you can see, I also installed composer inside the image, but I don’t actually use it. I just had two different solution and wanted to include both of them to see which will work, since I haven’t used any of them for some years.

If your composer.json is not

Is it composer.json or composer.local.json?

If you need to run something in a different folder, not from workdir, you can always use cd in a script to go there :slight_smile:
If you need to set only the path of the json file, you can use environment variables for that: Command-line interface / Commands - Composer
Maybe a symbolic link would work too.

Thanks for your detailed response. I have a few followup questions.

I’m not sure what you mean.

I tried something like this, and like my prior example, while it looks like the build works, the mw container won’t start. the daemon just gets caught in a loop.

FROM mediawiki:1.35

RUN apt-get update -y 
RUN apt-get upgrade -y
RUN apt-get install apt-utils -y
RUN apt-get install zip -y
RUN apt-get install unzip -y
RUN apt-get install haveged -y
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer self-update 2.1.14

How would you go about doing this? I know how to create another container running it, but I don’t know how to get the mw container to use it.

is that the

php -r "readfile('https://raw.githubusercontent.com/composer/getcomposer.org/${COMPOSER_INSTALLER_VERSION}/web/installer');" \ | php -- --install-dir=/usr/bin/ --filename=composer --version=${COMPOSER_VERSION}

you refer to? I tried something similar, see above, but I need to actually use composer, which causes a problem. You can see in the screen shot it just loops, looking for composer.json in the /app folder.

I could be wrong, but it seems like composer looking at ./app seems built in, would either of those suggestions change that behavior? See screenshot.

I don’t know how mediawiki organizes its folders, but usually you have a composer.json and composer creates a folder called “vendor” to download packages and configure the autoloader. In a production environment, it should be in the Docker image so you don’t need to run composer later at all. If you need a new package or a new version of a package, then you rebuild the image.

You just updated composer itself, not the packages. You must run composer update too and not self-update. I would not even use self-update in a Dockerfile. You can just download the version you need as I did in my project I linked above.

The question is where you can use it and where you should. You have multiple options. If you have questiones about my solution in the project I linked above (I had to rename the project because there was a typo in it, but I will fix my post), I can answer it but I don’t see new questions :slight_smile: just misunderstanding.

I realized you tried to use mutli-stage build but I guess you don’t know how that works. You can’t have multiple FROM instruction in a Dockerfile unless you use the first as a source of the second to copy some files to the next stage. mediawiki would work, but you actually run a composer image. Compose indeed has an “/app” folder. You don’t have mediawiki at all at this moment.

Check my solution again, because that works. I can help you with the details later.

I’ve managed to get this working on a regular server, not in a container. But it’s working with the container that’s confusing me. I have MW working just fine on it’s own, but the extension I’m trying to install instructions, and says to run php composer.phar update --no-dev.

I updated the Dockerfile to:

FROM mediawiki:1.35

RUN apt-get update -y && \
    apt-get upgrade -y && \
    php -r "readfile('https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer');" \
    | php -- --install-dir=/usr/bin/ --filename=composer --version=1.10.13 && \
    apt-get install zip -y && \
    apt-get install unzip -y    

and the docker-composer to:

# MediaWiki with MariaDB
version: '3'
services:
  mediawiki:
    image: mw:0.1
    container_name: mw
    restart: always
    ports:
      - 8080:80
    links:
      - database
    volumes:
      - ./volumes/mediawiki/images:/var/www/html/images
      - ./volumes/mediawiki/extensions:/var/www/html/extensions
      - ./volumes/mediawiki/LocalSettings.php:/var/www/html/LocalSettings.php
      - ./volumes/mediawiki/composer.local.json:/var/www/html/composer.local.json
    command: > 
      bash -c "composer update --no-dev --no-progress"

  database:
    image: mariadb
    container_name: db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER:  user
      MYSQL_PASSWORD: password
      MYSQL_DATABASE: dbname
    volumes:
      - ./volumes/mariadb/config:/config
      - ./volumes/mariadb/db_backup:/backup
      - ./volumes/mariadb/mysql:/var/lib/mysql

after building the image with sudo docker build -t mw:0.1 . it seems to work

but after running docker-compose with docker-compose up:

any way to run this command once and stop? rather than try over and over

I supposer the answer might be to map a volume to an external direcotry, but I don’t understand the dockerfile syntax for this

No, if you continue to do what I told you not to do :slight_smile: I quote again

In adition, you explicitly told Docker Compose to “always” restart. You have to decide whether you want to run composer or mediawiki.

Since I don’t have time, I thought, you would check the script I made: redbobjects/composer.sh at 5bdccf5c6f9df6bbaa20dc566dcb99ee8bd578b3 · rimelek/redbobjects · GitHub

and you can get an idea or ask about it. I try to create a very small demo in the next few days, which you can try, but until that the ways:

  1. Dockerfile
    • Copy your composer.json and your code into the image
    • Install Composer
    • Run composer update
    • After docker build, you have a working container. no need to run composer update again
  2. docker exec
    • Everything in the previous step
    • You also mount your code from the host into the container, including the vendor folder.
    • You use docker exec to run composer inside the container, but your code is mounted from the host, so you can change it and try again. You also mounted the vendor folder, so the composer in the container can update the code on your host. You can run command as root with the --user parameter even if the default user in the container is not root.
  3. Docker run and common volume
    • You do not need to install composer in the image
    • Run composer in a different container but mount the code into the composer container, and also mount the same vendor folder.
    • My script uses this approach, but also installs composer and makes the composer installation persistent by using volumes named after the required userid and composer version. I did this only because I could have used the official composer image is based on alpine Linux, and I didn’t want to have that difference, since I used debian based image for PHP. The best way to make sure composer works as you expect it is using the exact same image in a separate container for the composer.

Evything I described above could be harder with a mediawiki image. So you may need to change a little bit, but first, you have to try. What you NEVER should do is changing the command in the compose file, if you don’t know what it means for your service. “command” is not an optional, extra command which you can use to run something when the container starts like an event handler. It is the part of the final command which is responsible for starting the process inside the container. In this case, mediawiki.