Laravel ENV variable collision in a Kubernetes cluster

7/30/2018

I came to a very specific case by using Laravel framework as a part of a kubernetes cluster. These are the facts, which have to be known:

  • I've created a Docker container for caching called redis
  • I've created a Docker container for application called application
  • These two work together in a Kubernetes cluster

Kubernetes is setting ENV variables in each Docker container. Commonly, one is called {container-name}_PORT. Therefore, Kubernetes has created the ENV variable REDIS_PORT in my application container, which is set to something like that: tcp://{redis-container-ip}:{redis-container-port}.

Laravel sets this ENV variable too, but use it as a standalone port variable like 6379. However, in this specific case, Redis does not work in Laravel, because of overwritten REDIS_PORT variable. The framework try to fetch redis on this example host string inside Kubernetes: tcp://redis:tcp://10.7.240.204:6379. Laravel logic behind: {scheme}://{REDIS_HOST}:{REDIS_PORT}. You can see, REDIS_PORT is filled with tcp://10.7.240.204:6379.

What is preferable to solve the issue?

In my opinion, Kubernetes uses the ENV variable for {container-name}_PORT in a wrong way, but I do understand the internal logic behind Kubernetes ENV variables.

At the moment, I have changed my config/database.php configuration in Laravel, but this causes a review of changelogs on every update.

Some of other details can be read here: https://github.com/laravel/framework/issues/24999

-- floflock
docker
kubernetes
laravel
php
redis

1 Answer

8/6/2018

@Florian's reply to himself on github:

My solution was to change the config in config/database.php like that:

'redis' => [

    'client' => 'predis',

    'default' => [
        'scheme' => 'tcp',
        'host' => env('REDIS_SERVICE_HOST', env('REDIS_HOST','127.0.0.1')),
        'port' => env('REDIS_SERVICE_PORT', env('REDIS_PORT',6379)),
        'password' => env('REDIS_PASSWORD', null),
        'database' => 0,
    ],

],

Now, the config checks first, if the REDIS_SERVICE_HOST and REDIS_SERVICE_PORT are present as ENV variable. This is the case, if you have a container in a docker/kubernetes cluster which is called REDIS.

Advantage of this solution is, that REDIS_SERVICE_HOST returns the IP address of the container, not a hostname. Therefore, there is no dns resolution anymore for this internal connections.

-- VKR
Source: StackOverflow