I recently moved from Wamp (wampserver) to Docker (Windows host). While using wamp, I was able to have multiple projects like in following file structure
- wamp64
- www/
- project1/
- project2/
- ....
On the wamp's Apache, I had defined a couple of virtual hosts, and all of the projects, used wamp's database, each one each own schema.
So it was quite common within the day to switch context when necessary from project1
, to project2
to project3
etc..
by visiting either url like http://localhost/projectX
or the corresponding virtual host.
This does not seem so straight forward on Docker, as I have seen so far. My first approach was to have a distinct Docker set up on each project
- www/
- project1/
- dockerfile & docker-compose
- project2/
- dockerfile & docker-compose
- projectX/
- dockerfile & docker-compose
- data // this is where mysql data lie
I think that this does not seem too efficient, compared to what I was used to using wamp, since every time I want to change context I have to use docker-compose stop
the project I am currently working and docker-compose up
to the project I want to switch to and vice versa.
I tried another approach, to run all projects in a single apache-php container (the entire www folder)
- www/
dockerfile & docker-compose
- project1/
- project2/
which would let me have all projects available at once, but with this approach, I face two serious issues.
My docker-compose file in the first approach looks like this
version: '3'
services:
project1:
build:
context: . // contents of specific project directory
dockerfile: .docker/Dockerfile
image: project1
ports:
– 80:80
volumes:
– .:/app/project1
links:
– mysql
mysql:
image: mysql:5.7
ports:
– 13306:3306
environment:
MYSQL_DATABASE: docker
MYSQL_USER: docker
MYSQL_PASSWORD: docker
MYSQL_ROOT_PASSWORD: docker
volumes:
- ../data:var/lib/mysql
while my docker-compose file in the second approach looks like this
version: '3'
services:
web-project:
build:
context: . // contents of www directory
dockerfile: .docker/Dockerfile
image: web-project
ports:
– 80:80
volumes:
– /project1:/app/project1
– /project2:/app/project2
– /projectX:/app/projectX
links:
– mysql
mysql:
image: mysql:5.7
ports:
– 13306:3306
volumes:
- /data:var/lib/mysql
ref for mysql data persist Docker-Compose persistent data MySQL
I think the best solution for you would be to run each project in it's own container. Since containers are (should be) lightweight and easy to bring up and down, the overhead of doing this should be minimal.
The difference in what I will show versus first approach is that the docker-compose file is going to orchestrate your containers for you. As a result it should allow all of your containers (projects) to communicate with your database at the same time. (Given your projects do not overwrite each-other constantly, and cause deadlock)
Folder Structure:
- www/
docker-compose.yml
- project1/
Dockerfile
- project2/
Dockerfile
Docker Compose
version: '3'
services:
project1:
build:
context: /project1 #automatically finds Dockerfile
container_name: project1
ports:
– 8081:80
volumes:
– .:/app/project
links:
– mysql
project2:
build:
context: /project2 #automatically finds Dockerfile
container_name: project2
ports:
– 8082:80
volumes:
– .:/app/project
links:
– mysql
...
mysql:
image: mysql:5.7
ports:
– 13306:3306
volumes:
- /data:var/lib/mysql
Then when you run docker-compose up
it will bring up two project containers and a database containers within the same network. Note that each project is run on it's own port. So you will need to remember which port is linked to which container.
Create a top level folder and put this Dockerfile in it
FROM webdevops/php-apache-dev:7.2
# Add microsoft SQL support to PHP
# add microsoft packages to apt sources
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/debian/9/prod.list > /etc/apt/sources.list.d/mssql-release.list
# install needed system packages as well as a few nice to have utils
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get -y upgrade && \
ACCEPT_EULA=Y apt-get -y install msodbcsql17 unixodbc-dev less joe iputils-ping traceroute telnet && \
apt-get purge -y --auto-remove && \
rm -rf /var/lib/apt/lists/*
# install sqlsrv php extensions
RUN pecl install sqlsrv pdo_sqlsrv
# load the pdo extension
RUN echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/30-pdo_sqlsrv.ini
# load the mssql extension
RUN echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20-sqlsrv.ini
# our docroot
WORKDIR /app
In the top level folder run the following command:
docker build -t myphpdev:latest . -f Dockerfile
Now in the same top level folder create a docker-compose.yml and put the following in it:
version: '3'
services:
web_debug:
image: myphpdev:latest
ports:
- 1080:80
volumes:
- .:/app
environment:
- PHP_XDEBUG_ENABLED=1
- PHP_DATE_TIMEZONE="America/Los_Angeles"
- PHP_MEMORY_LIMIT="512M"
- PHP_MAX_EXECUTION_TIME="600"
- PHP_MAX_INPUT_TIME="60"
- PHP_POST_MAX_SIZE="512M"
- PHP_UPLOAD_MAX_FILESIZE="512M"
- PHP_ERROR_REPORTING="E_ALL & ~E_DEPRECATED & ~E_STRICT"
- PHP_DISPLAY_ERRORS="1"
- PHP_DISPLAY_STARTUP_ERRORS="1"
- PHP_DEBUGGER="xdebug"
- XDEBUG_CONFIG=remote_host=host.docker.internal
mysql:
image: mysql:5.7
ports:
- 13306:3306
volumes:
- ./data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=password
# if you get errors about invalid or needing to use absolute paths
# you may need to down your stack then run the next line then up the stack
# SET COMPOSE_CONVERT_WINDOWS_PATHS=1
In that same top level folder create a folder named data for your database persistence and one for each one of you sites. Each site will be available at http://localhost:1080/site_folder
adjust / add any PHP_ env vars as needed the image will update the php.ini based on the env vars when it comes up.
When running this way each site will have to be setup with relative links instead of absolute and they will all be sharing the same db instance.
The least resource intensive config is for each site to share the same db instance and have each site with its own db on the instance. You could also use table prefixing if for some reason all the site had to use the same db name.
If you don't mind the extra resource usage you could copy the mysql block making sure you have a unique port number and data folder for each and bring up a totally separate db server for each site.
Mounting the host inside the container will allow you edit the contents of the site folders from the host side as well as debug with xdebug in real-time without having to rebuild your docker environment every time you want to iterate or context switch.
You can also setup virtual hosts by adding some Apache configs if you don’t want to use relative links in your sites by mounting a config into /opt/docker/etc/httpd/vhost.common.d/
Check out the docs for the image referenced in Dockerfile. They have tons of variations in terms of php version web server and base os as well as dev vs production setups. I have included a link to their docs below.
WebDevOps ApachePHP Docker Docs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With