Docker: docker-compose copy files from container to host - php

I want to copy all files during the installation process in docker-compose.yml file.
If I run:
$ git clone https://github.com/laravel/laravel.git laravel-app
$ cd laravel-app
$ docker run --rm -v $(pwd):/app composer install
It will copy all new files from container to host during the installation process in the docker container.
So I will see new vendor folder and composer.lock file in my laravel-app directory after installation.
But if I setup volume in docker-compose.yml:
version: '3'
services:
#PHP Service
app:
build:
context: .
dockerfile: Dockerfile
container_name: app
restart: unless-stopped
tty: true
environment:
SERVICE_NAME: app
SERVICE_TAGS: dev
working_dir: /var/www
volumes:
- ./:/var/www
- ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- app-network
And then setup installation process in Dockerfile:
FROM php:7.4.4-fpm
# Set working directory
WORKDIR /var/www
# Install dependencies
RUN apt-get update && apt-get install -y
# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Copy existing application directory contents
COPY . /var/www
# Install composer.json dependencies
RUN composer install # <<-- !this one!
It will not copy vendor folder and composer.lock file back to my host.
Hot to make it happen?

how about add composer docker image to your docker compose, and run command install
version: '3'
services:
#PHP Service
#your php image
# composer
composer:
image: composer/composer
volumes:
- ./:/var/www
command: install

You copy all build context into your image /var/www
You run composer install from the image, so vendor and composer.lock only exist in the image, not on your host
You bind mount your current directory(which has composer.json but not vendor and composer.lock) to /var/www, so it replaces the image /var/www
You know your issue, the fix depends on what you want to do exactly, tell me in a comment.
Tip: You should use Docker multi-stage builds to install Composer into your image. It's much cleaner than the curl
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY . /var/www/
RUN composer install --no-scripts --no-suggest --optimize-autoloader

Related

From which Dockerfile should composer install be called from

I need to call composer install and unsure from which Dockerfile to call it from - Dockerfile-apache or Dockerfile-php-fpm?
Should I install composer in Dockerfile-apache (and PHP CLI?) and run it from there?
Running composer install from Dockerfile-php-fpm gives me this: Composer could not find a composer.json file in /var/www/html
Docker-php-fpm
# Do we target a specific version? ie. 7.4.25?
FROM php:7.4-fpm
# Need to add zip and other extensions
RUN buildDeps=" \
libonig-dev \
libzip-dev \
libxml2-dev \
" \
&& apt-get -y update \
&& apt-get install -y $buildDeps zip libicu-dev \
&& docker-php-ext-configure intl \
&& docker-php-ext-install intl mbstring json mysqli opcache pdo pdo_mysql xml \
&& apt-get purge -y --auto-remove $buildDeps \
&& rm -r /var/lib/apt/lists/*
# Copying of base conf files
COPY docker/php-fpm/conf/php-fpm.conf /usr/local/etc
COPY docker/php-fpm/conf/php.ini-development /usr/local/etc/php/php.ini
COPY docker/php-fpm/conf/www.conf /usr/local/etc/php-fpm.d
# Install Composer.
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/ \
&& ln -s /usr/local/bin/composer.phar /usr/local/bin/composer
EXPOSE 9000
Docker-apache:
FROM httpd:2.4
# Copy config files
COPY docker/apache/conf/httpd.conf /usr/local/apache2/conf
COPY docker/apache/conf/httpd-vhosts.conf /usr/local/apache2/conf/extra
# Do something about log rotate?
# Create vhost directory
WORKDIR /var/www/html
#Set our application folder as an environment variable
ENV APP_HOME /var/www/html
#copy files
COPY bin ${APP_HOME}/bin
COPY config ${APP_HOME}/config
COPY plugins ${APP_HOME}/plugins
COPY src ${APP_HOME}/src
COPY webroot ${APP_HOME}/webroot
COPY .htaccess ${APP_HOME}
COPY index.php ${APP_HOME}
COPY composer.json ${APP_HOME}
COPY composer.lock ${APP_HOME}
Edit #1
docker-compose.yml
version: "3.2"
services:
php-fpm:
container_name: php-fpm
build:
context: .
dockerfile: Dockerfile-php-fpm
networks:
- backend
ports:
- "9000:9000"
apache:
container_name: httpd
build:
context: .
dockerfile: Dockerfile-apache
depends_on:
- php
networks:
- frontend
- backend
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
Edit #2
This docker-compose file enables the communication via a common volume. I just need to compile, build and copy the files in Apache at this point.
version: "3.9"
services:
php-fpm:
container_name: php-fpm
build:
context: .
dockerfile: Dockerfile-php-fpm
volumes:
- mydata:/var/www/html:rw
networks:
- backend
ports:
- "9000:9000"
apache:
container_name: httpd
build:
context: .
dockerfile: Dockerfile-apache
depends_on:
- php
volumes:
- mydata:/var/www/html:rw
networks:
- frontend
- backend
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
volumes:
mydata:
I would go with neither of the above; instead, run composer install locally and copy the resulting vendor directory as part of your application.
Fetching dependencies is fundamentally part of building an application, not part of running it, so Composer shouldn't even be installed on a production host or container. If you were writing a C application which needed to be compiled with gcc, you would run that as an earlier step, and then copy the binary into the container; composer install can be treated the same way.
So for instance, you might have a build script (to run manually, or in a CI server like Jenkins, Github Actions, Azure DevOps, etc) that went through the following steps:
Clone the repo from a git repository
Check out the latest tag
Run composer install
Run a script to minify the client-side JS
Run docker-composer, copying the source code, minified JS, and vendor directory
The software inside the Docker container therefore only needs to be able to run the application, not build it.

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,

Docker copy composer vendor from inside container

I've made a container which I am building through docker-compose, here is .yml:
gateway:
build: .
image: sng
container_name: sng
command: tail -F /dev/null
ports:
- "10091:10091"
volumes:
- vendor:/root/vendor
volumes:
vendor:
And Dockerfile is simply pulling the image and running composer install:
FROM php:7-fpm-alpine
EXPOSE 10091
WORKDIR /root
COPY . .
RUN apk add composer && composer install --no-progress
Is there a way for me to sync back the created vendor folder automatically back to the codebase without running a docker cp from the host machine?
Oh man, im so sorry!! I did what you want, is just mount a volume of vendor to the vendor folder.
volumes:
- path/to/local/vendor:vendor

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

Composer install with dockerfile

I'm pretty new with docker, I try to automatically execute composer install within my Dockerfile but it seems that I can't cd into my application while installing, what's wrong? Or maybe there is another better way to do that?
my docker-compose.yml
version: "3.1"
services:
app:
image: nginx:alpine
container_name: app
working_dir: /application
volumes:
- ./Projects/app:/application/app
- ./Docker/nginx/app.conf:/etc/nginx/conf.d/app.conf
ports:
- "8080:8080"
php-fpm-app:
build: Docker/php-fpm-app
container_name: php-fpm-app
working_dir: /application
volumes:
- ./Projects:/application
- ./Docker/php-fpm-app/php-ini-overrides.ini:/etc/php/7.2/fpm/conf.d/99-overrides.ini
my Dockerfile
FROM phpdockerio/php72-fpm:latest
WORKDIR "/application"
# Fix debconf warnings upon build
ARG DEBIAN_FRONTEND=noninteractive
RUN mkdir -p /var/www/.composer \
&& chown -R www-data:www-data /var/www/.composer
USER www-data
RUN cd /application/app; composer install
The output after I run this command:
docker-compose up -d
Step 6/6 : RUN cd /application/app; composer install
---> Running in ac53e653af46
/bin/sh: 1: cd: can't cd to /application/app
Composer could not find a composer.json file in /application
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
ERROR: Service 'php-fpm-app' failed to build: The command '/bin/sh -c cd /application/app; composer install' returned a non-zero code: 1
If I try to remove the last line from my Dockerfile, once it's up and running if I run this command:
docker-compose exec --user www-data php-fpm-app bash -c 'cd
/application/app && composer install'
It works, I don't understand why I can't do this with my Dockerfile.
===========================
Finally
I find a way to execute a script but I don't see the output, so if the script last for many secondes/minutes I won't know when it's done.
ADD ./setup.sh /setup.sh
RUN chmod +x /setup.sh
CMD ["sh", "/setup.sh"]
I decided to execute this script manually once all it's up and running
sh ./setup.sh
You should not run composer install in Dockerfile. It will fail because you have not created/synced volume from the local to container yet. Thus all files including composer.json is not placed under /var/www/html.
What you can do is to add 1 line (command) into your docker-compose.yaml file inside the service eg.
services:
api-php-fpm:
build: ./docker/php-fpm
command: sh -c "composer install"
This is because the volumes aren't mounted until the build is complete. Just use COPY to copy only the composer.json into the folder, and run the composer install as normal.
Referencing the Documentation for Dockerfiles you need to edit your Dockerfile.
it should be:
WORKDIR /application/app
RUN composer install
Does this fix your problem?

Categories