JetBrains Projector + Docksal integration for Remote development environments

JetBrains just announced the availability of Projector, which allows you to "project" Swing applications from a server to a client with the ability to connect through a web browser or a native client. This is extremely cool, and I nerded out on it for a solid 4 hours last evening to get a POC working with my Docksal projects.

My requirements were:

  • ...use PHPStorm for remote development, both through the browser as well as through the native Projector client
  • ...ensure that any global configuration made to PHPStorm stays preserved between system/IDE restarts
  • ...work with my Docksal projects
    • connect to a given project's database(s)
    • be able to use Xdebug

My immediate research pointed me to setting up everything through Docker, with the following environment:

  • A container (named ide-projector) that runs PHPStorm and Projector, provided by JetBrains' projector-docker project.
  • A shared network (named projector-network) with connections from:
    • ide-projector
    • Docksal project's cli and db services.

Standing up PHPStorm + Projector

Looking at JetBrains' projector-docker project, we see that all it takes to get the ide-projector container up and running is:

docker pull registry.jetbrains.team/p/prj/containers/projector-phpstorm
docker run --rm -p 8887:8887 --name ide-projector -it registry.jetbrains.team/p/prj/containers/projector-phpstorm

With that, you can access http://localhost:8887/ and be connected and working in PHPStorm.

However, there is a caveat where as soon as you recreate the container you will lose all customizations you've made to PHPStorm. To get this to really work for us we need this to persist between removal and creation of the container. For the sake of simplicity this is accomplished by mapping the directory where I store all of my projects to the ide-projector container's home directory, which is where PHPStorm in the container wants to put all of the global configuration.

So, instead of running the above, we would pull the image first and then run the container with a mounted directory:

docker pull registry.jetbrains.team/p/prj/containers/projector-phpstorm
docker run --rm -p 8887:8887 --name ide-projector -v ~/TestProjects:/home/projector-user -it registry.jetbrains.team/p/prj/containers/projector-phpstorm

Spinning up the container like that, and configuring the IDE a bit (I registered it with my JetBrains account and synchronized my settings), you end up with the following directory structure at ~/TestProjects:

lpeabody@pop-os:~/TestProjects$ ll
total 32
drwxrwxr-x  7 lpeabody lpeabody 4096 Mar 18 16:23 ./
drwxr-xr-x 38 lpeabody lpeabody 4096 Mar 18 16:51 ../
-rw-------  1 lpeabody lpeabody  337 Mar 19 00:16 .bash_history
drwxr-xr-x  3 lpeabody lpeabody 4096 Mar 18 16:17 .cache/
drwxr-xr-x  3 lpeabody lpeabody 4096 Mar 18 16:17 .config/
drwxr-xr-x  3 lpeabody lpeabody 4096 Mar 18 16:17 .java/
drwxr-xr-x  3 lpeabody lpeabody 4096 Mar 18 16:17 .local/

 

Integrate with Docksal

The next step was to create a project we can test this workflow with. I used Docksal's fin project create command to create a Drupal 9 project named projector_test_drupal in ~/TestProjects. Afterwards, you can navigate to http://localhost:8887 to connect to the IDE and then open up the project like you normally would any project in a JetBrains editor. Upon opening, you would see something similar to:

Image
Screenshot of PHPStorm working through the web browser.

Now, we need to ensure that ide-projector can communicate with our Docksal project, specifically it's cli and db services so we can use Xdebug and connect to the project database through the IDE.

First, create a new network named projector-network and connect the ide-projector container to it:

docker network create projector-network
docker network connect --alias ide-projector projector-network ide-projector

Note that we need to use --alias in our connect command in order to allow the project's cli service to connect back to ide-projector via host name.

At this point we need to also connect the project's cli and db services. While you could do this manually via docker network connect ... it would instead be better to do this through Docksal's configuration so you don't have to repeat connection steps in the future. To do this, edit the project's docksal-local.yml file (if it does not exist, create it from the project's example.docksal-local.yml file, and if that does not exist then just create the file anyway). My starting docksal-local.yml file looks like this:

version: "2.1"

services:
  cli:
    environment:
#      - XDEBUG_ENABLED=1
      - XDEBUG_CONFIG=idekey=PHPSTORM remote_host=192.168.64.1
      - PHP_IDE_CONFIG=serverName=${VIRTUAL_HOST}

We need to update the configuration such that:

  • The cli and db services can connect to the projector-network network.
  • Xdebug is configured to connect to the container the IDE is running in, in this case the ide-projector container which is accessible within the network via its host name ide-projector.

Given the above, our updated docksal-local.yml looks like this:

version: "2.1"

services:
  cli:
    networks:
      - projector
      - default
    environment:
#      - XDEBUG_ENABLED=1
      - XDEBUG_CONFIG=idekey=PHPSTORM remote_host=ide-projector
      - PHP_IDE_CONFIG=serverName=${VIRTUAL_HOST}
  db:
    networks:
      - projector
      - default

networks:
  projector:
    external: true
    name: projector-network

Once you've made those modifications you can run fin up to apply the new configuration. Also you should verify that your Drupal site is still accessible. For me this was checking that http://projector-test-drupal.docksal.site was still running and accessible.

Two notes on the updated configuration:

  • The remote_host value for Xdebug was set to ide-projector, the alias we gave to the ide-projector container when we attached it to the projector-network network. If we did not use an alias when attaching it to the network we would be forced to use the container's IP address, which is subject to change whereas the alias name is not.
  • The networks configuration for both cli and db services list default as well as projector, rather than just projector. Why? Docker Compose creates a default network for all services to share so the containers can talk to one and other. HOWEVER, as I discovered, it does not connect services that have explicit networking configurations. So, without listing default in addition to projector, the cli and db services would not be able to communicate with the rest of the project's services, which obviously would completely break your project environment.

Now, run fin up to apply the new settings. With the pertinent containers able to communicate, we can now configure PHPStorm to connect to the database as well as Xdebug.

Configure IDE to connect to the project database

Run fin status to get the container name of your project's database, which in my case is projector_test_drupal_db_1. Then, add a MySQL database connection in PHPStorm with configuration (assuming default Docksal project values for the database):

  • Name: @db
  • Host: projector_test_drupal_db_1
  • Port: 3306
  • User: user
  • Password: user

Click Test Connection to validate the connection, and click Apply or OK.

In the IDE's Database tab, you should now be able to expand schemas and see the default database is present and when expanded shows all of the expected Drupal tables.

Configure IDE to connect to Xdebug in cli service

To configure Xdebug all that needs doing is configuring a PHP Server and its path mappings. Add a new PHP Server and configure its path mappings with values (substitute your name/host and project directory if they differ):

  • Name: projector-test-drupal.docksal.site
  • Host: projector-test-drupal.docksal.site
  • Port: 80
  • Path mappings:
    • /home/projector-user/projector_test_drupal -> /var/www
    • /home/projector-user/projector_test_drupal/vendor/bin/drush -> /usr/local/bin/drush

And that's it. To test this, switch the XDEBUG_ENABLED flag in docksal-local.yml  from 0 to 1 (and make sure its uncommented if it was previously commented) and run fin up. Then, add a breakpoint somewhere in index.php and navigate to your project's site, in my case http://projector-test-drupal.docksal.site. Xdebug should activate and break at the breakpoint you just added in index.php!

Thoughts and future work

I have been super jealous of VSCode's ability to run a remote server because that allowed folks who like to use VSCode to spin up remote Linux development environments with lightning-fast Docker performance. I'm assuming the folks over at JetBrains were equally jealous of this capability and decided to make their own offering, which I am forever grateful for. I love PHPStorm and I don't really want to be forced to move away from it as development workflows gradually shift more to the cloud.

The above work demonstrated a very basic POC, and it has one major drawback: the IDE Terminal feature is basically useless since the editor is running in an isolated container. To make it really useful, in the case of Docksal (and most other dev environments I would imagine), you'd need to run PHPStorm + Projector directly on the host server rather than in a container. Doing so you'd be able to open up Terminal in the IDE and use fin commands to interact with the project like you normally would any Docksal project. A workaround to that is simply SSHing into the host server and interacting with the project in a shell outside of the editor.

So, you can expect a future update from me on how I get that working. More to come!