Aug 19, 2021

8 min read

PHP Laravel Development with Kubernetes using DevSpace — Developer Edition

Image of a PHP stuffed elephant doll sitting on a laptop

Architecture

We will look at ways to deploy a Laravel based application into a Kubernetes cluster for development and production environments. We will develop our application while the application is running in Kubernetes as if we are developing locally. And we will be able to troubleshoot our application in real-time with ease.

  • PHP-FPM container, which processes all the PHP assets.
  • Nginx container, which serves static files and acts as a reverse proxy for the PHP assets.
  • MySQL container, as the database.
  • Redis container, as session and cache.

Introduction to DevSpace

Continuous Delivery is a challenge while developing on Kubernetes. Without using a special tool, you need to build and deploy every time code or assets change. DevSpace handles this seamlessly either by synchronizing files and hot reload of the container in question or automatically rebuilding and deploying the image(s) required. DevSpace allows you to develop in a Kubernetes cluster as if you are developing in your local machine.

Feature Highlights

  • Agile development on local and remote Kubernetes clusters. Execution of entire continuous development and deployment pipeline, and a single command to deploy all components of your application.
  • Declarative configuration kept in source code, in the devspace.yaml file. All of the development, deployment, and pre/post-deployment actions are defined in a single file.
  • Hot Reloading for faster feedback. Instead of building and re-deploying artifacts, DevSpace allows you to use high-performance and bi-directional file synchronization. This allows changes to trigger a hot-reload on the deployed container. All of these features are highly configurable.
  • Extensibility. You can extend the functionality of DevSpace via the plugin system. Hooks and commands are also built-in constructs; you can expand the functionality heavily used in CI/CD pipelines.
  • Easy clean Up. You can delete the resources created via `devspace purge` in a single simple step.
  • Client Only. DevSpace doesn’t require server/cluster side components. A single executable on a local machine is sufficient to develop, troubleshoot and deploy.

Requirements and Setting Up Development Environment

The following tools should be installed on your local development machine:

  • Kubectl, documentation here.
  • Helm, documentation here.
  • DevSpace, installation instructions here.

Developing with DevSpace

First, let’s start with the code. Clone the repository to your local development machine as follows. This code includes a vanilla Laravel installation, a Dockerfile, and a devspace.yaml prepopulated.

$ git clone git@github.com:loft-sh/devspace-php-laravel-nginx.git
$ cp .env.example .env
$ devspace run generate-key
$ devspace list vars
Variable              Value                                                
APP_DEBUG true
APP_IMAGE leventogut/php-laravel-nginx-devspace
APP_KEY xxxxxxxxxxxxxxxx
ASSET_VOLUME_NAME static-asset-volume
ASSET_VOLUME_SIZE 1Gi
DB_DATABASE laravel
DB_HOST mysql
DB_MYSQL_VERSION 8.0.23
DB_PASSWORD xxxxxxxxxxxxxxxx
DB_PORT 3306
DB_ROOT_PASSWORD xxxxxxxxxxxxxxxx
DB_USERNAME laravel
NGINX_CONFIG_HASH 740941
NGINX_IMAGE_VERSION 1.9
REDIS_PASSWORD xxxxxxxxxxxxxxxx
REDIS_VERSION 6.0.12

#Running devspace dev

DevSpace is context-aware; it follows your Kubernetes config to determine the Kubernetes cluster to deploy on. However, It is good practice to set the context and namespace to use with:

$ devspace use context docker-desktop[info] Your kube-context has been updated to 'docker-desktop' To revert this operation, run: devspace use context maple-staging [done] √ Successfully set kube-context to 'docker-desktop'$ devspace use namespace laravel[info] The default namespace of your current kube-context 'docker-desktop' has been updated to 'laravel' To revert this operation, run: devspace use namespace [done] √ Successfully set default namespace to 'laravel'
$ devspace dev
Route::get('ping', function () {
return "pong";
})

Port Forwarding and Reverse Port Forwarding

You can reach the application via port forwarding. These can be defined in the devspace.yaml file. In the current configuration, the Nginx container's port 80 is forwarded to local port 8080. The browser will be automatically opened after a successful deployment and start of the containers.

$ devspace list commandsName           Command                                                            Description
artisan devspace enter -c php -- php artisan Entry point for artisan commands.
composer devspace enter -c php -- composer Entry point for composer commands.
php devspace enter -c php -- php Entry point for PHP commands.
npm devspace enter -c php -- npm Entry point for NPM commands.
generate-key TMP_FILE=.devspace/app_key.tmp && docker run --rm -v $PWD:/ap... Generate APP_KEY.
mysql devspace enter -c mysql -- mysql -h'mysql' -P'3306' -u'larave... Enter to MySQL shell.
  • Changing MySQL user and password
  • Running npm run watch on the PHP container.
  • Reloading Nginx to re-read the configuration.

Deploying to Production

The devspace deploy command will deploy our application into the environment we define. DevSpace configuration allows us to modify and alter our parameters based on profiles. This flexibility brings numerous configuration options for development, staging, production environments. DevSpace configuration can hold all different parameters and configurations for each environment. Generally speaking, it is a good practice to create a production profile for deployment, which will remove troubleshooting aids and set parameters accordingly.

$ devspace deploy -p production

Troubleshooting with DevSpace

Troubleshooting and debugging are pretty straightforward with DevSpace. DevSpace provides aid for the following:

  • Logging
  • Entering into containers
  • Running commands inside the containers
  • Interactive mode

Entering to and Working with Containers

The devspace enter command allows you to open a shell to any of the running containers by providing the container name, so you don't have to deal with the copy/paste of long pod names.

$ devspace enter -c php[info] Using namespace 'default' [info] Using kube context 'docker-desktop' [info] Opening shell to pod:container app-0:php root@app-0:/var/www/html#
? Which pod do you want to open the terminal for?
[Use arrows to move, type to filter]
> redis-master-0:redis app-0:nginx
app-0:php
mysql-0:mysql
$ devspace run php ./vendor/bin/phpunit[info]   Using namespace 'default'
[info] Using kube context 'docker-desktop'
[info] Opening shell to pod:container app-0:php
PHPUnit 9.5.3 by Sebastian Bergmann and contributors.

.F 2 / 2 (100%)

Time: 00:00.122, Memory: 20.00 MB

There was 1 failure:

1) Tests\Feature\ExampleTest::testBasicTest
Expected status code 200 but received 302.
Failed asserting that 200 is identical to 302.

/var/www/html/vendor/laravel/framework/src/Illuminate/Testing/TestResponse.php:187
/var/www/html/tests/Feature/ExampleTest.php:19

FAILURES!
Tests: 2, Assertions: 2, Failures: 1.
$ devspace run artisan test[info]   Using namespace 'default'
[info] Using kube context 'docker-desktop'
[info] Opening shell to pod:container app-0:php

PASS Tests\Unit\ExampleTest
✓ basic test

FAIL Tests\Feature\ExampleTest
⨯ basic test

---

• Tests\Feature\ExampleTest > basic test
Expected status code 200 but received 302.
Failed asserting that 200 is identical to 302.

at tests/Feature/ExampleTest.php:19
15▕ public function testBasicTest()
16▕ {
17▕ $response = $this->get('/');
18▕
➜ 19▕ $response->assertStatus(200);
20▕ }
21▕ }
22▕


Tests: 1 failed, 1 passed
Time: 0.19s

Conclusion

We have seen DevSpace in action while developing, deploying, and troubleshooting. We have seen that once DevSpace is configured, it can encompass all deployment options within it. So it can be used for development and deployment to any environment. The ability to change profiles, add new commands, and execute any hooks is advantageous.

Further Reading