Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Spiral's avatar

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.

0 likes
31 replies
krisi_gjika's avatar

when you run printenv do the env names match what you would expect on a .env file?

Spiral's avatar

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

Spiral's avatar

@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"
krisi_gjika's avatar

@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

Spiral's avatar

@krisi_gjika

  1. Are you asking about Laravel .env that i have just copied from .env.example to .env in Dockerfile
  2. 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> 
    
    
Spiral's avatar

@krisi_gjika

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's avatar

@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 
Spiral's avatar

@krisi_gjika I'm confused if everything is working into the exec pod then why the connection is not built

Snapey's avatar

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?

Spiral's avatar

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

Spiral's avatar

@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!

Spiral's avatar

If something is confusing you. I will explain to you again

Snapey's avatar

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?

Spiral's avatar

@Snapey

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

krisi_gjika's avatar

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

1 like
Spiral's avatar

@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's avatar

@krisi_gjika Okay, let me create a web route and attach controller, and i will add this log into controller. Thank you

Spiral's avatar

@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

Spiral's avatar

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

krisi_gjika's avatar

@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?

1 like
Spiral's avatar

@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?

Snapey's avatar

@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

Spiral's avatar

@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

Snapey's avatar

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

Spiral's avatar

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.

1 like

Please or to participate in this conversation.