Laravel ENV variable collision in a Kubernetes cluster - php

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

#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.

Related

How to use Redis with auth::attempt in Laravel?

I'm working on a Laravel project and I want to use Redis to store session data for improved performance. I have set up Redis correctly and it's working fine with basic functionality. However, I'm having trouble getting the auth::attempt function to work with Redis.
Here's my current auth::attempt code:
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// User authentication successful
} else {
// User authentication failed
}
This works fine with the default session driver in Laravel, but I want to use Redis for better performance. I have tried changing the SESSION_DRIVER variable in my .env file to 'redis' and set the Redis connection in config/database.php, but I'm still getting an authentication error.
I'm not sure what I'm missing. Can anyone help me understand how to use Redis with auth::attempt in Laravel? Thanks in advance!
When using Redis for session storage in Laravel, you need to ensure that your Redis server is running and that your Laravel application is configured to use Redis as the session driver.
To set Redis as your session driver, you can change the value of the SESSION_DRIVER variable in your .env file to redis. You can also configure the Redis connection in the config/database.php file. Here's an example configuration:
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'table' => 'sessions',
'expire_on_close' => false,
],
Once you've configured Redis as your session driver, you can use the Auth::attempt method as usual. However, if you're still encountering authentication errors, there are a few things you can try:
Make sure your Redis server is running and accessible from your
Laravel application.
Check your Redis configuration in the config/database.php file to
ensure that it's set up correctly.
Clear your Laravel application's cache using the php artisan
cache:clear command.
Check your Redis server's logs for any errors or issues that might
be causing the authentication failures.

HTTP request from a Laravel app on one Apache virtual host to a Lumen app on sibling virtual hosts: MySQL Access denied for user 'root'#'localhost' [duplicate]

I am developing an API service that another site I've developed will be using. So locally when building and testing, obviously I want both local copies of the site to work. However, it seems to mix up the environment variables.
For example:
Site A has APP_URL=http://a.local
Site B has APP_URL=http://b.local
I send a GET Request (using Guzzle) from Site A code to http://b.local/test
The /test endpoing in Site B simply dumps out dump(env('APP_URL'))
Result retrieved by Site A is "http://a.local"
Expected result: "http://b.local"
So the code in Site B is running with environment variables loaded from Site A. This is an issue as Site B cannot access the correct database, it's trying to use the Site A's database.
Is this an issue with my local setup (Win10 + WAMP), PHP settings, Laravel settings?
I also encountered this issue, and it is mentioned here. The resolution for it is to run php artisan config:cache in both projects to cache configuration from .env files or patch the code from here.
are you using artisan commands to run both projects with different ports ?
php artisan serve --port=8000
php artisan serve --port=8010
You can set Environment variables in either the vhost config OR in an .htaccess file:
SetEnv APP_URL http://b.local
Apart from #Daniel Protopopov answer above there is also another way, that is also works when both Site A and Site B are Lumen.
In short just rename your DB_DATABASE variable on each side to a different name. Then change the respective variable names in the respective config/<configfilename>.php files.
So that on Site A you would have SITE_A_DB_DATABASE in .env and matching 'database' => env('API_A_DB_DATABASE', 'forge'), line in config/database.php.
Then your Site B SITE_B_DB_DATABASE will not be overwritten due to variable names are different.
The same solution applies for any .env variables which names match.
Because the command php artisan config:cache doesn't work here (closure needed in routes file config file)
LogicException : Your configuration files are not serializable.
I add phpdotenv with composer :
composer require vlucas/phpdotenv
And at the begginning of the file "/bootstrap/app.php" (after "new Illuminate\Foundation\Application"), I add :
$app->detectEnvironment(function () {
$dotenv = Dotenv\Dotenv::create(__DIR__ . '/../', '.env');
$dotenv->overload();
});
Maybe an alternative
If you are calling a Lumen 8 API from within a Laravel 6 application using GuzzleHttp and the Laravel env is being inherited to Lumen, creating config file worked for me.
In bootstrap/app.php comment below lines to prevent loading current env values from Laravel
// (new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
// dirname(__DIR__)
// ))->bootstrap();
In bootstrap/app.php add below line after $app has been created.
$app->configure('database');
Create config/database.php in lumen root folder. Return all env values needed for Lumen api in an array in the config file.
<?php
return [
'timezone' => 'UTC',
'default' => 'pdbmysql',
'connections' => [
'pdbmysql' => [
'driver' => 'mysql',
'host' => 'localhost',
'port' => '3306',
'database' => 'db2',
'username' => 'root',
'password' => 'root',
],
],
];

WAMP Laravel - Sending API requests from one local site to another mixes up environment variables

I am developing an API service that another site I've developed will be using. So locally when building and testing, obviously I want both local copies of the site to work. However, it seems to mix up the environment variables.
For example:
Site A has APP_URL=http://a.local
Site B has APP_URL=http://b.local
I send a GET Request (using Guzzle) from Site A code to http://b.local/test
The /test endpoing in Site B simply dumps out dump(env('APP_URL'))
Result retrieved by Site A is "http://a.local"
Expected result: "http://b.local"
So the code in Site B is running with environment variables loaded from Site A. This is an issue as Site B cannot access the correct database, it's trying to use the Site A's database.
Is this an issue with my local setup (Win10 + WAMP), PHP settings, Laravel settings?
I also encountered this issue, and it is mentioned here. The resolution for it is to run php artisan config:cache in both projects to cache configuration from .env files or patch the code from here.
are you using artisan commands to run both projects with different ports ?
php artisan serve --port=8000
php artisan serve --port=8010
You can set Environment variables in either the vhost config OR in an .htaccess file:
SetEnv APP_URL http://b.local
Apart from #Daniel Protopopov answer above there is also another way, that is also works when both Site A and Site B are Lumen.
In short just rename your DB_DATABASE variable on each side to a different name. Then change the respective variable names in the respective config/<configfilename>.php files.
So that on Site A you would have SITE_A_DB_DATABASE in .env and matching 'database' => env('API_A_DB_DATABASE', 'forge'), line in config/database.php.
Then your Site B SITE_B_DB_DATABASE will not be overwritten due to variable names are different.
The same solution applies for any .env variables which names match.
Because the command php artisan config:cache doesn't work here (closure needed in routes file config file)
LogicException : Your configuration files are not serializable.
I add phpdotenv with composer :
composer require vlucas/phpdotenv
And at the begginning of the file "/bootstrap/app.php" (after "new Illuminate\Foundation\Application"), I add :
$app->detectEnvironment(function () {
$dotenv = Dotenv\Dotenv::create(__DIR__ . '/../', '.env');
$dotenv->overload();
});
Maybe an alternative
If you are calling a Lumen 8 API from within a Laravel 6 application using GuzzleHttp and the Laravel env is being inherited to Lumen, creating config file worked for me.
In bootstrap/app.php comment below lines to prevent loading current env values from Laravel
// (new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
// dirname(__DIR__)
// ))->bootstrap();
In bootstrap/app.php add below line after $app has been created.
$app->configure('database');
Create config/database.php in lumen root folder. Return all env values needed for Lumen api in an array in the config file.
<?php
return [
'timezone' => 'UTC',
'default' => 'pdbmysql',
'connections' => [
'pdbmysql' => [
'driver' => 'mysql',
'host' => 'localhost',
'port' => '3306',
'database' => 'db2',
'username' => 'root',
'password' => 'root',
],
],
];

Non-static method Redis::get() cannot be called statically in laravel 5.4?

i am working on Redis to store data Everything is working fine in my local system. i have successfully installed redis also in laravel with this command composer require predis/predis also and Redis setup of window also installed. Now when i store data in Redis like this:-
Redis::set('first',"My first Test"); // put data in Redis key
echo Redis ::get('first'); // get data
Above code is working fine in my local system. when i try to use this code in live server it is showing the below error:-
Please help me to resolve this issue. We are using amazon-ec2 server Thanks in advance :)
I had the same issue. But I believe its related to php 7 rather than Larevel 5.4 because I'm using Laravel 5.1 and I still have the problem.
I came across 2 solutions
Use use Illuminate\Support\Facades\Redis; instead of use Redis; if you want to call the Redis methods statically.
Change to dynamic calling
$redis = new Redis();
$redis->set('boo','Have beer and relax!')
$redis->get('boo');
Just remove or comment out extension=php_redis.dll from your php.ini
Laravel and server Redis conflicts with name "Redis"
This will work
In Laravel database config you can define a client for your Redis handler.
As you have installed predis, your Redis database configuration should look like this
'redis' => [
'client' => 'predis',
'cluster' => false,
'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
PhpRedis extension and Laravel alias for Redis Facades are same which is creating the issue. In case you want to use the PhpRedis extension you need to change the alias keyword defined in app.php and client in the database config.

Configuring Laravel 4 with AWS Elasticache Memcached

I have Amazon Elasticache Memcached node (just one)
I have a webserver in the same region.
Cache subnet group VPC ID is the same as EC2 instance's, the permissions are set properly from AWS perspective.
In laravel in config/cache.php
'driver' => 'memcached',
and
'memcached' => array(
array('host' => 'xxxxx.xxxx.xxx.xxxx.cache.amazonaws.com', 'port' => 11211, 'weight' => 100),
),
However, Cache::has('key') and Cache::add('key'); do not work.
Do I need a special package for Laravel to work with AWS Elasticache? I only have one node and do not need auto-discovery.
Thanks
P.S. Is there way to get a log for AWS Elasticache? or laravel? logs directory is empty
You should be able to use the elasticache-laravel package, available here: https://github.com/atyagi/elasticache-laravel
Or conversely, check out this post: http://blog.hapnic.com/2013/09/11/Laravel-4-and-ElastiCache/
For your PS: Elasticache logs can be accessed this way:
http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/ManagingEvents.html
Your Laravel logs should be in app/storage/logs - if there's nothing in there, check the permissions of the storage directory and make sure it's writeable by the web server. Barring that, check the default error log location for your web server (such as /var/log/httpd/error_log), as defined by your server configuration.

Categories