Docker - Using Composer inside PHP container - php

I want to be able to use composer install inside my php-fpm container. My current setup:
docker-compose.yml
version: '2'
services:
web:
image: nginx
ports:
- "80:80"
volumes:
- ./public:/var/www/html
- ./vhost.conf:/etc/nginx/conf.d/vhost.conf
fpm:
image: php:fpm
volumes:
- ./public:/var/www/html
expose:
- 9000
composer:
restart: 'no'
image: composer/composer
command: install --working-dir=/var/www/html
volumes_from:
- fpm
But obviously my command: install is happening in the composer container and doesnt have the required php extensions to complete the install.
And composer install inside php-fpm container says composer is not installed
Somehow google doesn't have an answer for this from what I have seen.

You just need to install composer inside your fpm container.
Something like
FROM php:5.6-fpm
...
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& php -r "unlink('composer-setup.php');"

A more sexy way yo add composer into your image :
# Install Composer
ADD https://getcomposer.org/installer /tmp/composer-setup.php
RUN php /tmp/composer-setup.php --install-dir /usr/local/bin/ --filename composer \
&& rm /tmp/composer-setup.php
Note that composer can be useful for development images (eg: For Continuous Integration or tests). A production image should not have composer inside... Only the generated vendors :)

Actually what I would suggest would be a separate lightweight php-cli container just to run composer (and other commands). It doesn't have to run a "persistent" way. If interested have a look how I did my image for running php tasks like composer or phpunit.
docker run -ti --rm -v /path/to/your/project:/app kmwrona/ci-stack /usr/bin/composer install --quiet
docker run -ti --rm -v /path/to/your/project:/app kmwrona/ci-stack /usr/bin/composer dump-autoload --optimize
docker run -ti -a STDOUT -v /path/to/your/project:/app kmwrona/ci-stack /usr/bin/phpunit --log-junit /app/junit.xml --testdox-html /app/unit-tests-html-report.html

Related

failed to solve: executor failed running [/bin/sh -c composer install]: exit code: 1

Trying to run composer install during docker compose build from inside the php container, but it errors out at the end acting like the composer.json file isn't there. However if I comment out the last line in the Dockerfile (ie. RUN composer install), then do something like, docker exec -it <container name> bash, manually run composer install from inside the container where /var/www/html/composer.json does in fact exist it works.
Dockerfile
FROM php:7.4-apache
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN docker-php-ext-install pdo_mysql mysqli
RUN a2enmod rewrite
WORKDIR /var/www/html
## install and run composer so that this test is self contained
RUN apt-get update
RUN apt-get install -y git
RUN composer install
Produces the following
=> ERROR [stage-0 8/8] RUN composer install 0.5s
------
> [stage-0 8/8] RUN composer install:
#0 0.437 Do not run Composer as root/super user! See https://getcomposer.org/root for details
#0 0.446 Composer could not find a composer.json file in /var/www/html
#0 0.446 To initialize a project, please create a composer.json file. See https://getcomposer.org/basic-usage
------
failed to solve: executor failed running [/bin/sh -c composer install]: exit code: 1
In case it's important this is the docker-compose.yml file
version: "3.9"
services:
php:
build: ./docker/php
volumes:
- ./src:/var/www/html
ports:
- 8080:80
restart: unless-stopped
mysql:
image: mariadb
volumes:
- ./docker/sql:/docker-entrypoint-initdb.d/
ports:
- 3306:3306
environment:
MARIADB_ROOT_PASSWORD: xxx
MARIADB_DATABASE: xxx
MARIADB_USER: xxx
MARIADB_PASSWORD: xxx
restart: unless-stopped
You're already pretty close with your container build directives, it's just that I'd say you only need the composer.json during the build and you actually need to have the vendor folder in the service container afterwards.
It's bascially two commands:
First update the build instructions:
<<'DOCKERFILE' tee Dockerfile >/dev/null && git add Dockerfile && git commit -m 'add composer install to build'
ARG ver=7.4
FROM php:$ver-cli
COPY --from=composer /usr/bin/composer /usr/bin/composer
COPY composer.json composer.json
RUN set -ex ; \
apt-get update ; \
apt-get install -y git zip ; \
composer -n validate --strict ; \
composer -n install --no-scripts --ignore-platform-reqs --no-dev
ARG ver=7.4
FROM php:$ver-apache
RUN set -ex ; \
docker-php-ext-install pdo_mysql mysqli ; \
a2enmod rewrite
COPY --from=0 vendor vendor
DOCKERFILE
Then build the container (this time with the composer.json file):
git archive --format tar HEAD Dockerfile composer.json | docker build --no-cache --rm --force-rm --tag my:build -
You'll see it run through. And given the composer.json file actually exists for the build context, then validates within the build container and you don't have any networking issues this should do it. You have not shared your build context properties, so this is the bare minimum for composer in docker (Dockerfile + composer.json).
Mind the PHP version in use, you find it parameterized so that the version can be controlled. Time to step away from PHP 7.4 which is going EOL soon. Docker Compose supports build parameters so you can do that in different working trees.
And here the takeaway: If you want more files from context, add them to the context and remember that when you need to copy from the context into the container again, there must be no --from option, that is only to copy from other containers (either intermediate stages or from the container repository). You can control all that with the Dockerfile as you had it already and additionally shown again above.

Using RUN in Dockerfile to install Laravel inside a php image is not working

I am trying to install Laravel inside a php container using this line on my Dockerfile:
RUN composer create-project laravel/laravel=8.* . --prefer-dist
My goal is to install it on my container directory /var/www/html. My first assumption is that by using . , the command ran on the current working directory, which is /var/www/html itself. And actually, it works when I go inside the container and run the command there. But, when building using the Dockerfile, seems that it doesn't install anything anywhere. On the contrary, the message I got on the terminal looked like the command ran successfully:
=> [stage-0 6/6] RUN composer create-project laravel/laravel=8.* . --prefer-dist
Currently my docker-compose.yaml looked like this:
version: '3.8'
services:
# PHP + Apache Service
php-apache:
build:
context: ./php-apache
working_dir: /var/www/html
ports:
- 80:80
volumes:
- ./src/:/var/www/html
- ./php-apache/apache2.conf:/etc/apache2/apache2.conf
- ./php-apache/000-default.conf:/etc/apache2/sites-available/000-default.conf
depends_on:
mysql:
condition: service_healthy
# other services and volumes...
Also my Dockerfile:
FROM php:8.1-apache
# Mysql driver on php
RUN docker-php-ext-install pdo pdo_mysql mysqli
# Composer
RUN apt-get update && apt-get install -y git zip
COPY --from=composer:2.2.2 /usr/bin/composer /usr/bin/composer
# Node.js
RUN apt-get update && apt-get install -y nodejs npm
# Laravel
RUN composer create-project laravel/laravel=8.* . --prefer-dist
I already set the working_dir to /var/www/html. Why is that the case here?
You could use the entry point script to run scripts after the container has started.
Create a bash script in the same location where you have Dockerfile.
start-container.sh
#!/usr/bin/env bash
#This will try to install laravel in /var/www/html/new-laravel if folder does not exists
composer create-project laravel/laravel=8.* /var/www/html/new-laravel --prefer-dist
#If your container gets exited, then consider restarting apache, here is an #example
#service php7.4-fpm start && nginx -g "daemon off;"
Remember to make the bash script executable, run the command before you run docker-compose build
chmod u+x start-container.sh
Then in your Dockerfile towards the end add:
ENTRYPOINT ["start-container"]
Then:
docker-compose stop && docker-compose build && docker-compose up -d

composer install not working php-alpine docker

I am using php FPM alpine container with nginx alpine container for my laravel application.
Here is my Dockerfile,
FROM php:7.4-fpm-alpine
WORKDIR /usr/src/app
# install composer
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php composer-setup.php --install-dir=/usr/local/bin --filename=composer
RUN php -r "unlink('composer-setup.php');"
# copy files
COPY ./ /usr/src/app/
# install packages
ENV COMPOSER_ALLOW_SUPERUSER 1
RUN composer install
Here is my docker-compose file,
version: "3.7"
services:
web:
image: nginx:1.19-alpine
ports:
- 80:80
volumes:
- ../api:/usr/src/app
- ./site.conf:/etc/nginx/conf.d/site.conf
depends_on:
- api
api:
build: ../api
volumes:
- ../api:/usr/src/app
When I run docker-compose up --build the container build process works as you can see in the attached screenshot but the vendor directory was never created by the composer!?
Is it a known issue while using PHP FPM Alpine containers?
Also, when I access into the container using this command
docker exec -it docker_api_1 /bin/ash
and run composer install manually then everything works. Any suggestions are appreciated.
This is the error message when i visit the site. It can't find the composer autoload.php file,

GitLab CI/CD - vendor directory on nginx container

I try write CI/CD for symfony, but i have problem with vendor directory. App is copied right, but i don't have vendor. I tried various ways but nothing works. Locally, as instead of variables with the image name, I will give the image name, it all works fine.
My .gitlab-ci.yml
image: tiangolo/docker-with-compose
services:
- docker:dind
variables:
DOCKER_DRIVER: overlay2
IMAGE_TAG: $CI_REGISTRY_IMAGE/demo:$CI_COMMIT_REF_NAME
IMAGE_PHP_PROD: $CI_REGISTRY_IMAGE/demo:$CI_COMMIT_SHA
IMAGE_NGINX_PROD: $CI_REGISTRY_IMAGE/demo-nginx:latest
VERSION: $CI_COMMIT_SHA
stages:
- build
- deploy
before_script:
- apk add --no-cache python3 python3-dev py3-pip libffi-dev openssl-dev gcc libc-dev make
- docker login -u $CI_USER -p $CI_PASSWORD registry.gitlab.com
# build:
# stage: build
# script:
# - docker build --pull -t $IMAGE_TAG deploy
# - docker push $IMAGE_TAG
production images:
stage: build
script:
- docker build . -f deploy/php/Dockerfile -t $IMAGE_PHP_PROD
- docker push $IMAGE_PHP_PROD
- docker build . -f deploy/Dockerfile-nginx-prod -t $IMAGE_NGINX_PROD
- docker push $IMAGE_NGINX_PROD
pull:
stage: deploy
tags:
- prod
script:
- docker pull $IMAGE_PHP_PROD
- docker pull $IMAGE_NGINX_PROD
production:
stage: deploy
tags:
- deploy
before_script:
script:
- docker-compose -f deploy/docker-compose.yml up -d
docker-compose.yml
version: '3'
services:
nginx:
container_name: sf_nginx
image: $IMAGE_NGINX_PROD
restart: on-failure
ports:
- '81:80'
depends_on:
- php
php:
container_name: sf_php
image: $IMAGE_PHP_PROD
restart: on-failure
user: 1000:1000
Dockerfile for php
FROM php:7.4-fpm
RUN docker-php-ext-install pdo_mysql
RUN pecl install apcu
RUN apt-get update && \
apt-get install -y \
libzip-dev
RUN docker-php-ext-install zip
RUN docker-php-ext-enable apcu
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php composer-setup.php --filename=composer \
&& php -r "unlink('composer-setup.php');" \
&& mv composer /usr/local/bin/composer
WORKDIR /usr/src/app
COPY --chown=1000:1000 ./ /usr/src/app
RUN PATH=$PATH:/usr/src/apps/vendor/bin:bin
Dockerfile for nginx
FROM nginx
ADD ./ /usr/src/app
ADD ./deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
In php container exist vendor directory. Docker-compose run, but my app not working:
Am I wrong or you are just installing composer without executing it?
After && mv composer /usr/local/bin/composer you should put && composer install --no-interaction!

Why is my volume not copying over to its docker container?

I am trying to run a webserver container with nginx and a php-fpm server running a Laravel application. The directory houses a frontend and backend directory so my paths are not off in the configuration files.
I setup a docker-compose.yml file
version: '2'
services:
webserver:
build:
context: ./
dockerfile: webserver.docker
volumes:
- /home/colesam/Documents/code/todo/backend:/var/www
ports:
- "8080:80"
links:
- backend
backend:
build:
context: ./
dockerfile: backend.docker
volumes:
- ./home/colesam/Documents/code/todo/backend:/var/www
And php-fpm Dockerfile (backend.docker)
FROM php:7.2-fpm
RUN apt-get update -y && apt-get install -y libmcrypt-dev openssl
RUN pecl install mcrypt-1.0.2
RUN docker-php-ext-enable mcrypt
RUN docker-php-ext-install pdo mbstring
RUN apt-get install -y apt-transport-https
RUN apt-get install -y curl
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN chown -R www-data:www-data /var/www
VOLUME ["/var/www"]
RUN ls -al /var/www
WORKDIR /var/www
RUN composer install
And the nginx webserver Dockerfile (webserver.docker)
FROM nginx:1.10
ADD ./vhost.conf /etc/nginx/conf.d/default.conf
WORKDIR /var/www
For some reason when I run docker-compose up -d --build I always fail at this step of the build process:
Step 13/13 : RUN composer install
---> Running in 65bb97f03004
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Composer could not find a composer.json file in /var/www
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
ERROR: Service 'backend' failed to build: The command '/bin/sh -c composer install' returned a non-zero code: 1
From the last line of the output it looks like it failed because /var/www/was empty and didn't have the files copied over like composer.json. I looked around a lot and this stackoverflow issue seemed to be the most related to what was happening but I think I'm already following everything the accepted answer suggests.
Do I need to include a COPY or ADD command even though I'm mounting the folder through a volume?
The build phase does not see any mounted volumes. The only thing that is available to "build" are the things defined in the backend.docker and in the compose section of build:
build:
context: ./
dockerfile: backend.docker
Do I need to include a COPY or ADD command even though I'm mounting the folder through a volume?
Yes, modify your backend.docker similar to this
...
WORKDIR /var/www
ADD composer.json .
RUN composer install

Categories