I've been attempting to containerize my php wev app (built on laravel) but I've run into a few issues
first I've found that the container exits after executing a command so I moved the building script to a different container (migrations and composer install)
I made a script called init.sh that contains the build instructions but whenever I run them from the command in docker-compose.yml I get no such file or directory.
this is my dockerfile
FROM nimmis/apache-php7
COPY apache_default /etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite
RUN service apache2 restart
this is my docker-compose.ym
version: "3"
volumes:
db-data:
external: false
services:
db:
image: mysql/mysql-server
env_file: .env
volumes:
- db-data:/var/lib/mysql-server
migrations:
build: .
env_file: .env
volumes:
- .:/var/www/html/books
depends_on:
- app
command:
# - /var/www/html/books/artisan migrate
# - chmod 777 /var/www/html/init.sh
- /var/www/html/books/init.sh
# - /var/www/html/init.sh
environment:
- ALLOW_OVERRIDE=true
app:
build: .
env_file: .env
volumes:
- .:/var/www/html/books
ports:
- "8081:80"
depends_on:
- db
environment:
- ALLOW_OVERRIDE=true
the commented parts a different attempts to run the script correctly.
I'm trying to run it on windows 10 using docker toolbox
What am I doing wrong? and is this the correct approach?
The RUN directive will execute something in the container when the container is building, not when the container is executing.
To that end, your Dockerfile should look something more like this:
FROM nimmis/apache-php7
COPY apache_default /etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite
ENTRYPOINT ["bash", "/path/to/init.sh"]
CMD ["apache2", "-DFOREGROUND", "-k", "start"]
The Entrypoint directive will run right before the CMD directive, irrespective if you pass a command into the container at boot.
So, you'll want to make init.sh execute the command the container passes to it:
#!/bin/bash
# init.sh
# todo: whatever init.sh does...
# Execute the CMD passed to the container:
exec "$#"
So I figured out what was wrong ... it was a permissions issue.
when I set the permissions to be executable it worked fine ...
so now all I had to do was adjust my dockerfile to be
FROM nimmis/apache-php7
COPY . /var/www/html/books
COPY start.sh /
RUN chmod +x /start.sh
COPY apache_default /etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite
RUN service apache2 restart
Instead of this
volumes:
- .:/var/www/html/books
use
volumes:
- folder_containg_sh:/var/www/html/books #relative path to script
in docker-compose file
Related
I'm working on a project in Laravel and using Docker. I don't know why I suddenly get this error message from PhpStorm.
I ran sudo chmod 777 -R my-project-name but I keep getting the error message.
How can I fix that?
The error message:
Docker file:
FROM php:8.1-fpm-alpine
RUN docker-php-ext-install pdo pdo_mysql
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
WORKDIR /app
COPY . .
RUN composer install
CMD php artisan serve --host=0.0.0.0
docker-compose.yml file:
version: '3.8'
services:
backend:
build:
context: .
dockerfile: Dockerfile
ports:
- 8000:8000
volumes:
- .:/app
depends_on:
- db
db:
image: mysql:5.7.22
restart: unless-stopped
ports:
- 33066:3306
environment:
MYSQL_DATABASE: admin
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
volumes:
- ./mysql:/var/lib/mysql
When you run docker-compose
It will creat a project with ower is root or name for docker set. You will see lock icon in the folder. Current, you are only a visitor. But you always change files that you are not owner. How can do it?
When start you can run.
sudo chmod 777 -R my-project-name
But it is not good. Because everyone can change your file without permission.
Solution:
check permission your file:
getfacl [relate_path_your_file]/TestController.php or ls -l [relate_path_your_file]/TestController.php
[enter image description here][1]
[1]: https://i.stack.imgur.com/9T85A.png
Add your account to group of this project
sudo adduser {USER-NAME-HERE} {GROUP-NAME-HERE}
Add write permission for group user
sudo chmod g+w [relate_path_your_file]/TestController.php
Right now your group user can edit file, include you
If you want to change others file, redo step 3 with path your file.
If not work, reopen phpStom
My goal is to get php dependencies in one stage of a docker file then copy those dependencies to the next stage (the vendor/ dir). However, once a volume is specified in docker-compose.yml that overrides the COPY statement as if it never happened.
docker-compose.yml
version: "3"
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
volumes:
- .:/var/www/html
docker/app/Dockerfile
FROM composer AS php_builder
COPY . /app
RUN composer install --no-dev
FROM php:7.1-fpm
COPY --from=php_builder /app/vendor /var/www/html/vendor
The result of building and running this is a /var/www/html directory that doesn't have the vendor/ directory as I'd expect.
My guess is that this is because the volume specified in the docker-compose.yml service definition actually happens after the COPY --from statement which seems to be logical. But how do I get around this? I'd still like to use a volume here instead of an ADD or COPY command.
You can combine bind mounts & volume to make your aim, a minimal example for your reference:
docker-compose.yaml:
version: "3"
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
volumes:
- my_folder:/var/www/html/vendor
- .:/var/www/html
volumes:
my_folder:
docker/app/Dockerfile:
FROM composer AS php_builder
COPY . /app
#RUN composer install --no-dev
RUN mkdir -p vendor && echo "I'm dependency!" > vendor/dependencies.txt
FROM php:7.1-fpm
COPY --from=php_builder /app/vendor /var/www/html/vendor
Results:
shubuntu1#shubuntu1:~/test$ ls
docker docker-compose.yaml index.php
shubuntu1#shubuntu1:~/test$ docker-compose up -d
Creating network "test_default" with the default driver
Creating test_app_1 ... done
shubuntu1#shubuntu1:~/test$ docker exec -it test_app_1 /bin/bash
root#bf59d8684581:/var/www/html# ls
docker docker-compose.yaml index.php vendor
root#bf59d8684581:/var/www/html# cat vendor/dependencies.txt
I'm dependency!
From above execution, you can see the dependencies.txt which generated in the first stage of Dockerfile still could be seen in the container, volume just manage the data by docker itself, while bind mounts give you chance to manage data for yourself.
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:
change the default command of our Docker image to the following:
bash -c "composer install && /usr/sbin/apache2ctl -D FOREGROUND"
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:
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:
https://stackoverflow.com/a/38817651/4700998
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
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
I'm working on a docker project and I want to run a php file which will configure the database for the project.
My Docker file :
FROM php:7.2-apache
LABEL maintainer="admin#ksoftlabs.com"
COPY site/ /var/www/html
RUN chmod -R 777 /var/www/html
RUN docker-php-ext-install mysqli
COPY 000-default.conf /etc/apache2/sites- available/000-default.conf
EXPOSE 80
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
My docker-compose.yml
version: '3.1'
services:
db:
image: mysql
command:
--default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: group_db
server:
image : apache
ports:
- "80:80"
I want to run the install.php which will be in /var/www/html/ directory. How can I do that?
Edit : I want to run this file automatically after the container is up
Would running it earlier work?
After RUN docker-php-ext-install mysqli, put RUN php /path/to/your/file.php?
I need to install cURL compiled with OpenSSL and zlib via Dockerfile for Debian image with apache and php 5.6. I tried many approaches but due to the fact that I don't have string understanding in Linux a failed. I use docker-compose to up my container. docker-compose.yaml looks like:
version: '2'
services:
web:
build: .
command: php -S 0.0.0.0:80 -t /var/www/html/
ports:
- "80:80"
depends_on:
- db
volumes:
- $PWD/www/project:/var/www/html
container_name: "project-web-server"
db:
image: mysql:latest
ports:
- "192.168.99.100:3306:3306"
container_name: "project-db"
environment:
MYSQL_DATABASE: dbname
MYSQL_USER: dbuser
MYSQL_PASSWORD: dbpass
MYSQL_ROOT_PASSWORD: dbpass
As a build script I use Dockerfile:
FROM php:5-fpm
RUN apt-get update && apt-get install -y \
apt-utils \
curl libcurl3 libcurl3-dev php5-curl php5-mcrypt
RUN docker-php-ext-install -j$(nproc) curl
'docker-php-ext-install' is a helper script from the base image https://hub.docker.com/_/php/
The problem is that after $ docker build --rm . which is successful a don't get an image with cURL+SSL+zlib. After $ docker-compose up I have a working container with Apache+MySQL and can run my project but libraries I need are not there.
Could you explain how to add these extensions to my apache in container properly? I even tried to create my own Dockerfile and build apache+php+needed libs there, but had no result.
Your Dockerfile is not complete. You have not done a COPY (or similar) to transfer your source code to execute from the host into the container. The point of a Dockerfile is to setup an environment together with your source code which finishes by launching a process (typically a server).
COPY code-from-some-location into-location-in-container
CMD path-to-your-server
... as per the URL you reference a more complete Dockerfile would appear like this
FROM php:5.6-cli
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
CMD [ "php", "./your-script.php" ]
notice the COPY which recursively copies all files/dirs (typically the location of your source code, etc like data and/or config files) in your $PWD where you execute the command onto the specified location internal to the container In unix a period as in . indicates the current directory so above command
COPY . /usr/src/myapp
will copy all files and directories in current directory from the host computer (the one you are using when typing in the docker build command) into the container directory called /usr/src/myapp
the WORKDIR acts to change directories into your container's dir supplied
finally the CMD launches the server which hums along once your launch the container