In this tutorial you'll learn how to create more than one container and communicate between them. This requires Docker compose which is a great way for local developing and testing your projects.
This tutorial is based on the previous tutorial about debugging multiple projects, but you don't need to check that first in order to follow this one.
You can find the sample project on github
In Visual Studio, create a solution with two PHP projects (
*.phpproj). You can do it by first creating one project.
The first project will present the data to the user. Let's call it PHPWebProject. Then to the same solution we will add a second project called PHPWebService which be actually doing the work.
Now when you have to projects, go to File menu and click Save All. You will be asked to save the solution file, go one folder level up, so you do not save it the the project and name it 'MultiplePHPProjectsOnDocker'.
Dockerfile in the both projects.
In the PHPWebProject and copy the following content:
FROM php:8.0-cli ENV APP_DIR /var/www/html RUN mkdir -p $APP_DIR WORKDIR $APP_DIR EXPOSE 80 VOLUME $APP_DIR # Xdebug RUN pecl install xdebug && docker-php-ext-enable xdebug; # append to end of php.ini the xdebug section RUN echo "xdebug.client_host=host.docker.internal" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \ && echo "xdebug.mode=debug" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \ && echo "xdebug.client_port=9003" >> "$PHP_INI_DIR/conf.d/xdebug.ini" CMD ["php", "-S", "0.0.0.0:80", "-t", "."]
There is plenty of tutorial on the internet explaining exactly what any of that means, but in short this will create a container with php 8.0 and installs and configures Xdebug.
The last line executes php build-in web server which will be listening on port
80. In the real world scenario you would rather use
nginx ( https://blog.devsense.com/2019/php-nginx-docker ) or
Apache server for that. But just for a simplicity we will go the easy route in the tutorial.
Then open the project properties of the PHPWebProject. Right click on the PHPWebProject node in the Solution Explorer and open Server tab.
Change Server to
Custom and fill in project URL
In the PHPWebService project create this
FROM php:8.0-cli ENV APP_DIR /var/www/html RUN mkdir -p $APP_DIR WORKDIR $APP_DIR EXPOSE 80 VOLUME $APP_DIR # Xdebug RUN pecl install xdebug && docker-php-ext-enable xdebug; # append to end of php.ini the xdebug section RUN echo "xdebug.client_host=host.docker.internal" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \ && echo "xdebug.mode=debug" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \ && echo "xdebug.client_port=9003" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \ && echo "xdebug.start_with_request=yes" >> "$PHP_INI_DIR/conf.d/xdebug.ini" \ && echo "xdebug.idekey=10F3DA6B" >> "$PHP_INI_DIR/conf.d/xdebug.ini"; CMD ["php", "-S", "0.0.0.0:80", "-t", "."]
It's almost identical to the previous one, but we've added
xdebug.start_with_request=yes option which instructs Xdebug to try to initiate the debug session on each request and
xdebug.idekey=10F3DA6B identifies which project should handle the Xdebug requests coming from this container.
Open the PHPWebService project properties and on the Server tab fill the project URL, e.g.
http://phpwebservice. In this case it doesn't really matter since we will not be calling this service directly from our development computer. What matters here is
IDE_KEY option. Make sure
10F3DA6B is set there.
Managing multiple containers requires container orchestration and requires an orchestrator such as Docker Compose, Kubernetes, or Service Fabric. So once we have
Dockerfile in the both projects, we will create a solution file
docker-compose.yml to use Docker compose.
Right click on the solution node in the Solution Explorer and select Add, New Item... (make sure to click on the solution node, not the project node).
docker-compose.yml and hit ENTER
Once the file is created in the Solution, copy the following content:
version: "3.9" services: phpweb: build: context: ./PHPWebProject dockerfile: Dockerfile networks: - internal volumes: - ./PHPWebProject/:/var/www/html ports: - 8080:80 phpservice: build: context: ./PHPWebService dockerfile: Dockerfile networks: - internal volumes: - ./PHPWebService/:/var/www/html volumes: phpweb: phpservice: networks: internal: driver: bridge
We include both projects as services, first PHPWebProject as
phpweb and PHPWebService as
phpweb we will need to map port
80 to local port
8080 so we can access it from host machine. We also defined a network so
phpweb can access
Since we want to access PHPWebService from PHPWebProject copy the following code to the
index.php of PHPWebProject
<?php $ch = curl_init("http://phpservice/"); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($ch); curl_close($ch); echo $response; ?>
As you can see we are able to access PHPWebService with
phpservice name defined in the
docker-compose.yml. This will work since docker compose sets up the host names in its own network, so that
phpservice is visible to other services as a hostname.
To know we actually got the response from the PHPWebService, copy the following code to
<?php echo "Hello World from WebService on Docker";
Open a terminal by pressing Ctrl + ` or go to
View | Terminal and run
docker compose up.
We can see the containers have been built and they are both running and serving requests with php built-in web server.
You can see more details about the containers at Containers tool window. Open
View | Other Windows | Containers
We want both projects to start when F5 is pressed. In the solution Properties (right click on Solution node in the Solution Explorer and choose Properties), select Startup Project tab, choose Multiple startup projects and select Action for both projects to Start.
We do not want to launch browser for the PHPWebService project. Open PHPWebService properties (right on PHPWebService node in the Solution Explorer, choose Properties). As Start Action select Don't open a page. Wait for a request from and external application.
Let's add breakpoints to both projects and press F5.
First the debugger will break in the PHPWebProject.
Then press F5 again and it will break in PHPWebService.
Pressing F5 one more time will finish the requests and you can see the output in the browser.
The important thing to note is we can further develop this solution without needing to build the containers again since the files in the projects are shared with the containers. Make changes and they will immediately take effect.
Congratulations! You are running multi-container PHP app with Docker Compose.