when you run printenv do the env names match what you would expect on a .env file?
Troubleshooting Laravel Environment Variables on Kubernetes
Hello,
I'm currently facing an issue with running Laravel on Kubernetes, particularly with environment variables.
Here's the situation: I've successfully deployed Laravel on Kubernetes, but I'm encountering difficulties with environment variables. I've stored the Laravel environment variables in a Kubernetes Secret, and when I inspect the container and run printenv, I can see that the RDS credentials are correctly populated from the Secret. However, when I attempt to access any API endpoint, I encounter the following error:
Illuminate\Database\QueryException: SQLSTATE[HY000] [2002] Connection refused (Connection: mysql, SQL: select count(*) as aggregate from 'users' where 'email' = [email protected]) in file /var/www/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 829
I've heard that Laravel on Kubernetes is capable of retrieving environment variables directly from PHP rather than from the .env file. Do I need to enable this feature, and if so, how? Additionally, I'm trying to avoid using a .env file to avoid the need to create a separate Docker image for each environment.
Could you please provide guidance on how to set up Laravel environment variables effectively on Kubernetes? Thank you.
Yes, I can see all variables with dynamic values when I run printenv into the pod in exec mode that i have added in configmap.yml and secret.yml file
@krisi_gjika Thank you for replying to me..
I have also tried with AppServiceProvider like this but did not work
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class EnvironmentConfigServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
$this->app->singleton('mysql_credentials', function () {
// Fetch MySQL credentials dynamically from your provider
$host = config('database.connections.mysql.host');
$port = config('database.connections.mysql.port');
$database = config('database.connections.mysql.database');
$username = config('database.connections.mysql.username');
$password = config('database.connections.mysql.password');
return [
'host' => $host,
'port' => $port,
'database' => $database,
'username' => $username,
'password' => $password,
];
});
}
/**
* Bootstrap services.
*/
public function boot(): void
{
//
}
}
Why I tried that because after exec mode into Pod i can see all values of my RDS credential that i have set in secret.yml file
ubuntu@ip-xxxxxxxxxxx:/ecom-prod$ kubectl exec -it pod/ecom-xxxxxxxx-kb62z -n ecom-eks -- bash
root@ecom-kb62z:/var/www# php artisan tinker
Psy Shell v0.12.0 (PHP 8.1.27 — cli) by Justin Hileman
> config('database.connections.mysql.username');
= "root"
> config('database.connections.mysql.password');
= "xxxxx"
> config('database.connections.mysql.database');
= "xxxxxxxx"
> config('database.connections.mysql.host');
= "ecomc7.xxxxxxxx.us-east-1.rds.amazonaws.com"
> config('database.connections.mysql.port');
= "3306"
@Spiral so the env is loaded correctly? are you sure than that the error is not on your network? can your RDS be accessed from your server?
Is your DB_CONNECTION=mysql or something else? Try and run a query on tinker and see
- Are you asking about Laravel
.envthat i have just copied from.env.exampleto.envinDockerfile - I can access RDS from my server with the RDS endpoint(as a host), username and password and also there is a database and tables
ubuntu@ip-xxxxxxxxxxx:/ecom-prod$ mysql -h ecom-db-identifier.xxxxxxxx.us-east-1.rds.amazonaws.com -u root -p Enter password: xxxxx Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 113 Server version: 8.0.35 Source distribution Copyright (c) 2000, 2024, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | ecom | | sys | +--------------------+ 5 rows in set (0.29 sec) mysql> use ecom Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables; +------------------------+ | Tables_in_ecom | +------------------------+ | activity_log | | comments | | failed_jobs | | migrations | | password_reset_tokens | | permissions | | personal_access_tokens | | policies | | users | +------------------------+ 28 rows in set (0.28 sec) mysql>
root@ecom-kb62z:/var/www# php artisan tinker
Psy Shell v0.12.0 (PHP 8.1.27 — cli) by Justin Hileman
> config('database.default');
= "mysql"
> config('database.connections.mysql');
= [
"driver" => "mysql",
"url" => null,
"host" => "ecom-identifier.xxxxxx.us-east-1.rds.amazonaws.com",
"port" => "3306",
"database" => "ecom",
"username" => "root",
"password" => "xxxxxx",
"unix_socket" => "",
"charset" => "utf8mb4",
"collation" => "utf8mb4_unicode_ci",
"prefix" => "",
"prefix_indexes" => true,
"strict" => true,
"engine" => null,
"options" => [],
]
@Spiral within tinker: App\Models\User::find(1); does the connection work?
@krisi_gjika yes, I did check now, and that is working also
root@ecom-deployment-xxxxxxx-kb62z:/var/www# php artisan tinker
Psy Shell v0.12.0 (PHP 8.1.27 — cli) by Justin Hileman
> App\Models\User::find(1);
= App\Models\User {#5534
id: 1,
name: "Test User",
email: "[email protected]",
#email_verified_at: "2024-03-12 15:52:14",
#password: "y$.bHDGgvm4zY.ucub4L.avOcERJzaS72sC0GZna6cAhy2/3xI1Cr/e",
image: null,
#remember_token: "SnA9FiQFl8",
created_at: "2024-03-12 15:52:14",
updated_at: "2024-03-12 15:52:14",
}
also, I did check to run the command into the exec mode of a pod
like
php artisan db:seed
that is also work
root@ecom-deployment-xxxxx-kb62z:/var/www# php artisan db:seed
INFO Seeding database.
Database\Seeders\PermissionsSeeder ................................................................................................. RUNNING
Database\Seeders\PermissionsSeeder ............................................................................................... 6 ms DONE
Database\Seeders\RolesSeeder ....................................................................................................... RUNNING
Database\Seeders\RolesSeeder ..................................................................................................... 6 ms DONE
Database\Seeders\RolePermissionsSeeder ............................................................................................. RUNNING
Database\Seeders\RolePermissionsSeeder ......................................................................................... 104 ms DONE
@krisi_gjika I'm confused if everything is working into the exec pod then why the connection is not built
are you trying to cache config at all?
I would have thought doing anything in a service provider might be too late in the bootstrap?
@Snapey Thank you for replying to me.
I did not understand what you said. The provider approach I have just tried did not work other than that about cache clear, I have also tried but got no result.
@krisi_gjika @snapey what could be any other approach that can solve my issue?
I'm encountering environment-related issues with my Laravel application. If I use the Laravel .env file, I'm concerned about how to manage RDS credentials within the pods. Currently, I'm utilizing configmaps and secrets to handle this, and I can confirm that the values are being retrieved. However, despite this, the database connection is not being established. Are there any alternative approaches that could resolve this issue?
Thank you in advance!
@snapey @krisi_gjika can you please check, I'm unable to solve this issue for the last day
If something is confusing you. I will explain to you again
could it be permissions related? You can access the database with Tinker but it seems your app cannot. Your app may be running under a different user account to you when you use the command line.?
Does the user that your webserver runs as have rights to read from the Kubernetes secrets?
Both I have created in the same user account. If I login to RDS with the terminal and I have given the same credentials in secrets that I have attached in deployments and after apply deployment I can see also required credentials with printenv command
@Spiral maybe log the connection information \DB::connection(config('database.default'))->getConfig() from your controller? In case your webserver is reading different envs from your cli user.
@krisi_gjika Yes it could be an issue but I don't know what I have to do. However, I have attached secrets with the deployment that I have created and also I can see everything related to database credentials in the POD after exec.
when I give a hardcoded value in the .env then it works well.
connection information \DB::connection(config('database.default'))->getConfig()
root@ecom-deployment-6dbffcbb98-4f845:/var/www# php artisan tinker
Psy Shell v0.12.0 (PHP 8.1.27 — cli) by Justin Hileman
> \DB::connection(config('database.default'))->getConfig();
= [
"driver" => "mysql",
"host" => "ecom-db-identifier.xxxxx.us-east-1.rds.amazonaws.com",
"port" => "3306",
"database" => "ecomdb",
"username" => "root",
"password" => "xxxxxx",
"unix_socket" => "",
"charset" => "utf8mb4",
"collation" => "utf8mb4_unicode_ci",
"prefix" => "",
"prefix_indexes" => true,
"strict" => true,
"engine" => null,
"options" => [],
"name" => "mysql",
]
@Spiral I said to log it from your controller, not from tinker
@krisi_gjika Okay, let me create a web route and attach controller, and i will add this log into controller. Thank you
@krisi_gjika Hi, I did check after added \DB::connection(config('database.default'))->getConfig() into the controller and get this result in the browser
{"driver":"mysql","host":"127.0.0.1","port":"3306","database":"forge","username":"forge","password":"","unix_socket":"","charset":"utf8mb4","collation":"utf8mb4_unicode_ci","prefix":"","prefix_indexes":true,"strict":true,"engine":null,"options":[],"name":"mysql"}
@krisi_gjika It means when I try to hit anything then it's going to localhost from my live server
taking from default config/database.php It's very weird. Howevery from tinker into the pod there coming correct. OMG
@krisi_gjika how can I handle the environment for Kubernetes deployment if I don't use secret.
how can i could be enable to use laravel .env for deployment and pods into the container.
i will be very thankful to you.
@Spiral ok so the issue is on the webserver. what webserver do you use? also do a config clear from your server and hit that route again. does the config update?
@krisi_gjika I have deployed this project on Amazon EKS (Elastic Kubernetes Service) with EC2 instances
will I need to use any web server like Nginx?
@krisi_gjika did you get any solution from which I can solve my issue
@Spiral your webserver is likely using www-root but you can prove this by logging something in that test controller you created and then look at the log file and see who owns it.
delete the log file before you start so that you are sure it was created by the web server.
I don't see what web server has to do with 'deployment' user
@Snapey I followed your advice and logged something in the test controller. Upon checking the log file generated by the web server.
I can confirm that the logs are indeed appearing there. This indicates that the web server is using the www-root user. I appreciate your help in identifying this aspect of the issue.
If you have any further insights or suggestions on how to resolve the main issue with environment variables, I would greatly appreciate it.
you can in this screenshot https://imgur.com/F8NNaUe
@Spiral screenshot is irrelevant. You need to do an ls on the folder from the command prompt if you want to see who owns the file. Then once you know that, make sure that the user can access the secrets.
Hi @krisi_gjika and @snapey
I wanted to express my heartfelt gratitude for your invaluable assistance. Your dedication to helping others truly makes a difference.
I'm pleased to inform you that the issue has been successfully resolved. It turned out that the problem stemmed from the handling of the Laravel .env file in the Dockerfile. By removing the command that copied .env.example to .env, we eliminated the conflict between Kubernetes secrets and the Laravel environment. Now, we rely solely on Kubernetes configmap and secrets
Once again, thank you both for your exceptional support.
@Spiral did you have the default DB_*='' in your .env?
@krisi_gjika No I had commented all MySQL credentials. The main issue with the .env file
Please or to participate in this conversation.