Background
A php application in running in a Docker container. With docker-compose, this container is ran in a configuration together with a postgres database container and a lot of other containers.
Attempting to run my phpunit tests in phpstorm, I have created a Docker Remote Interpreter test configuration which runs the PHP application container.
Problem
The container complains that it can not connect to the database, which of course is not started because it's configured in the docker-compose.yml and not started up along with the single container used by PhpStorm.
Attempts to solve
A PHP Remote Debug can use a deployment, so I tried to create a Docker Deployment configuration which uses the docker-compose.yml (therefore starting all containers) and is launched before the PHPUnit launch, but I cannot select this deployment.
Starting the Docker Compose containers except the one from the PHP app and have it connect to it. This proves difficult, because they are on different networks, so the php app container still complains about not finding the database. I cannot configure which network the container uses in PhpStorm.
tl;dr
My PhpStorm project is a PHP application. This application can run in a Docker container which serves through nginx. I can run my PHPUnit tests in the container with a run configuration, but it also needs other containers which are not started up automatically.
Question
How can I use PHPStorm to run PHPUnit tests in a PHP application container together with the containers it depends on (already described in a docker-compose.yml)?
The answer is too long. I hope this 5 minutes video by Jetbrains TV helps you.
https://www.youtube.com/watch?v=I7aGWO6K3Ho
In short you need:
Configure Docker instance in PHPStorm
Configure new PHP Interpreter from Docker container
Configure PHPUnit to use your new interpreter
Related
I am currently trying to set up a development environment with Docker. The goal is have a single Docker Compose file to start all necessary containers and develop and test code within the containers.
I now ran into a problem with my environment variables not being available when running tests using PhpStorm's built-in Docker support. All my tests are succeeding when running docker compose exec api-internal-php vendor/bin/phpunit but not when running my tests in PhpStorm. To clarify: In both cases I am executing my tests in the running container. The reason for my tests failing is that the environment variables I defined in my Docker Compose file, and that are necessary for connecting to my database, are not available when running PHPUnit in PhpStorm. My Docker image is based on php:8.2-fpm-alpine.
My system configuration (up-to-date at the time of writing):
macOS 13.1
Docker Desktop 4.15.0
PhpStorm 2022.3.1
Of course I ensured that I am actually running the tests using Docker. I am using a Docker network and connect to the database by using the service's name. I can confirm that the scope of my environment variables is the issue, because when replacing the environment variables in my code by their actual value, the tests are succeeding even in PhpStorm. That also means that the test is able to connect to the database using the service's name and the Docker network.
I installed Xdebug in my image and debugging is working fine. By adding a breakpoint at the beginning of my test I can confirm that my variables are missing in the $_ENV array.
I tried different things and was searching for a solution for hours but did not succeed yet. I tried adding an fpm config file with my environment variables like this post suggested, which did not help. Otherwise, I did not find any question with the exact same problem.
Relevant excerpt of my Docker Compose file:
api-internal-php:
build:
context: .
dockerfile: dockerfiles/php.dockerfile
args:
APP_ENV: dev
SYMFONY_DIRECTORY: backend-api-internal
restart: unless-stopped
volumes:
- ./backend-api-internal:/var/www/html:ro
- ./backend-api-internal/var:/var/www/html/var
- ./backend-api-internal/vendor:/var/www/html/vendor
- ./backend-api-internal/.phpunit.result.cache:/var/www/html/.phpunit.result.cache
environment:
DB_ANSWERS_URL: mysqli://root:local#mariadb/
DB_DEV_NAME: dev_env_db
DB_TEST_NAME: test_env_db
depends_on:
- mariadb
- model
One interesting side note: My application/working directory in the container is (obviously) /var/www/html. Somehow, PhpStorm uses /opt/project as the path mapping. As I said, when replacing the environment variables in the code by their actual value, the tests run just fine, so I do not think that this is the problem.
So as it turned out, the Docker integration in PhpStorm works quite well if you know how to use it. The mistake I made was to first set up the CLI Interpreter as "Docker" instead of "Docker Compose" and then, when switching to "Docker Compose", not picking the correct "Lifecycle" option.
So first of all, to execute tests in your Docker container, go to the "PHP > CLI Interpreter" setting, click on the three dots and create a new one. Select "From Docker, ..." and then make sure to select "Docker Compose" if your setup is based on a Docker Compose configuration YAML file. There you can select your configuration file and the service. You do not need to set anything under "Environment Variables".
Hit "OK" and then, lastly, to execute tests in a running container, change the "Lifecycle" setting to "Connect to existing container". Under the hood, this will use the docker compose exec command instead of docker compose run.
Thanks to #Foobar for the solution!
We are developing a webapplication, which runs in three containers (MySQL database, Nginx webserver, PHP FPM).
Docker-Compose is used to manage the containers.
The current goal is to bring automated tests that makes use of Selenium into the pipeline of gitlab.
Within the gitlab-ci config I would launch the three containers using docker-compose and run our tests.
This however feels a bit complicated.
Is there a better, more clean way to set up testing?
I have an AngularJS/PHP7/MySQL application and I want improve its architecture. Actually, it currently runs in separate docker containers.
One container for both the front end and back end created with Angular JS and PHP respectively.
One container for the database
I want to improve this setup and achieve something like this:
One container with NGINX : port 80, 443
One container with node and my AngularJS front : port 4200
One container apache (or php fpm ?) with my backend PHP : port 81
One container with MySQL : port 3306
And more broadly, is it a good thing to separate front and back ? For scaling problems later? And what kind of tools, I will use for these scaling problems? Docker Swarm, Kubernetes?
I don't know if it's a good approach. Could you help me to choose the right path for this application ? (Sorry for my English, I'm not native). Thanks!
I think you need to start looking into Docker Compose Basics first rather than trying to straightly dive into the deployment. This will help you to understand how to deploy multi container applications and the basic idea behind it. As per your scenario docker-compose allows you to define your NGINX container, Angular JS container (your front end), PHP (your back end) and your MySQL DB container, the ports which they are running on and also define overlay networks which you can separate container wise. Please see below resources, in the 3rd link you can also visit a Docker Compose file which has defined exactly the same configurations as your current setup, just refer it after you get hang out of the basics.
Docker Compose Official Documentation
How to use Docker Compose
Sample Docker Compose File
When it comes into Docker Swarm and Kubernetes those are container orchestration platforms. Both of these allow you to run containers in clusters which means you can replicate the number of containers running each service (service here means one of your containers, i.e NGINX Container) to make them highly available. Imagine one of your NGINX containers fails and you have defined to run 3 NGINX containers on your Docker Swarm or Kubernetes cluster and your users won't be affected though one of your NGINX container is down as there are two more other containers running. There are some differences between Docker Swarm and Kubernetes and its up to you to decide on what tool to use after you get these basics right. If you are starting out with docker-compose going into Docker-Swarm will be bit easy.
Difference between Docker Swarm and Kubernetes
Also I have added an answer explaining the use of Docker Swarm on to scenario like yours, read it so you can get an idea on how to deploy your app with Docker Swarm.
My Answer on Docker Swarm Use case
I'm trying to build a couple of Docker images for different PHP-based web apps, and for now I've been deploying them to Elastic Beanstalk using the Sample Application provided by AWS as a template. This application contains two Docker container definitions: one for PHP itself, and the other for Nginx (to act as a reverse-proxy).
However, it seems a little odd to me that the source code for my PHP application is effectively deployed outside of the Docker image. As you can see from the Github sample project linked above, there's a folder called php-app which contains all the PHP source files, but these aren't part of the container definitions. The two containers are just the stock images from Dockerhub. So in order to deploy this, it's not sufficient to merely upload the Dockerrun.aws.json file by itself; you need to ZIP this file together with the PHP source files in order for things to run. As I see it, it can (roughly) be represented by this visual tree:
*
|
|\
| - PHP Docker Container
|\
| - Linked Nginx Container
\
- Volume that Beanstalk auto-magically creates alongside these containers
Since the model here involves using two Docker images, plus a volume/file system independent of those Docker images, I'm not sure how that works. In my head I keep thinking that it would be better/easier to roll my PHP source files and PHP into one common Docker container, instead of doing whatever magic that Beanstalk is doing to tie everything together.
And I know that Elastic Beanstalk is really only acting as a facade for ECS in this case, where Task definitions and the like are being created. I have very limited knowledge of ECS but I'd like to keep my options open, in case I wanted to manually create an ECS task (using Fargate, for instance), instead of relying on Beanstalk to do it for me. And I'm worried that Beanstalk is doing something magical with that volume that would make things difficult to manually write a Task definition, if I wanted to go down that route.
What is the best practice for packaging PHP applications in a Docker environment, when the reverse proxy (be it Nginx or Apache or whatever) is in a separate container? Can anyone provide a better explanation (or correct any misunderstandings) of how this works? And how would I do the equivalent of what Beanstalk is doing here, in ECS, for a PHP application?
You have several options to build it.
The easiest is to have one service ecs with two container foreach web app (one container for php app and one container for nginx).
The only exposed port in each service is nginx 80 port with ecs dynamic port.
Each exposed service should have an alb that redirect trafic to nginx port.
In this case nginx is not used as loadbalancer, only for front web server.
Edit:
Your DockerFile for php app should be like that:
...
# Add Project files.
COPY . /home/usr/src
...
And for dev mode your docker-compose:
version: '3.0'
services:
php:
build:.
depends_on:
...
environment:
...
ports:
...
tty: true
working_dir: /home/usr/src
volumes:
- .:/home/usr/src
Then in local use docker-compose and live edit your files in container.
And in production mode file was copied in container at build time.
Is it more clear?
I am trying to understand the general process that goes into deploying a PHP web app through Docker. I have a web app developed in LAMP.
So far I understood that firs of all I have to download and install Docker itself. Afterwards I have to install the Docker Composer. Then using the Composer I have to create a container that will contain the image of my server (Apache).
And this is where I get confused. Do I have to then create a container for my database and another one for the application itself (the directory containing the code) or do I have one container for the server the database and the app?
I dont need a detailed explanation, just the general idea behind the process then I can figure out the rest on my own
Thank you to anyone who can provide any help.
There can be many ways but the simple way is to install docker on some linux machine , write a docker file that installs and configures all the necessay components such as apache , php , mysql etc , and then grab your application code either inside the container or attach it as external volume from the host.
After writing dockerfile , you can build the docker image by using the docker build command , and after the image is build you can use it locally or push to dockerhub , or push it to your private docker registery if you want.
The other option is if you just want to test , you can pull an already existing image from dockerhub that contains the LAMP stack and you then just need to do docker run on the image attaching your php application as external volume.
Ofcourse , to access the application on port 80 or 443 outside docker you have to expose those ports either in docker file , or at docker run command time.
For a test environment , you can run all the services in just one container.
For larger Deployements you can consider a container orchestration service such as DockerSwarm or Kubernetes . You can also try DC/OS from MesoSphere , by grabbing a vagrant file from thier github repo that will setup the DC/OS on a single machine for you. Then you can just spin up as many services as you want on Mesos. They provide out of the box support for service installation , container management and scaling.
The best practices recommends to have one Docker container per process/service (one container for Apache + PHP, another container for MySQL and so on) but it's just a guideline and it doesn't mean that you cannot have only one container with everything you need inside it.
If you decide to go with only one container to run all the services, you'll be fine just using Docker (Engine). You can still use Docker Compose in this case but there's no real need for it.
Docker Compose is more helpful when you have to run multiple containers. With just one command you can get all your containers up and running. Also here you can use only Docker Engine but you'll need to run each container manually.