Environment variable not recognised when deploying to Elastic Beanstalk - php

I'm trying to deploy my Laravel application to Elastic Beanstalk in development mode. To make the application run in development mode rather than production, I've done the following in my /bootstrap/start.php file:
$env = $app->detectEnvironment(function() {
return $_ENV['ENV_NAME'];
});
To actually create the environment variable, I've created a .config file in the following path: /.ebextensions/00environmentVariables.config with these contents:
option_settings:
- namespace: aws:elasticbeanstalk:application:environment
option_name: ENV_NAME
value: development
- option_name: DB_HOST
value: [redacted]
- option_name: DB_PORT
value: [redacted]
- option_name: DB_NAME
value: [redacted]
- option_name: DB_USER
value: [redacted]
- option_name: DB_PASS
value: [redacted]
When I run eb start from the command line, it spins up an EC2 instance and attempts to provision it, at which point it tells me it fails. and to check the logs. In the logs, I can see these entries:
PHP Notice: Undefined index: ENV_NAME in
/var/app/ondeck/bootstrap/start.php on line 28
Notice: Undefined index: ENV_NAME in /var/app/ondeck/bootstrap/start.php on line 28
So for some reason, the ENV_NAME environment variable doesn't exist, even though I've specified it in 00environmentVariables.config. What's even weirder, is that I can see the environment variable does exist under the software configuration settings of the EB environment:
To summarize:
I know my .config files are being parsed from looking at the logs
For some reason my Laravel application still doesn't think that ENV_NAME eixsts
ENV_NAME eixsts both in the .config file and in my Elastic Beanstalk settings for this environment
EDIT
Alright so I worked out that the environment variables do work correctly when serving the application over the Apache HTTP server, but the environment variables don't exist when running the PHP CLI.
In the above logs, it's complaining about ENV_NAME not existing when running a /usr/bin/composer.phar install.
So, for some reason, my environment variables don't exist within the PHP CLI but they do work normally when serving over Apache.
FURTHER EDIT
So I SSH'd into the EC2 instance that's hosting my Laravel application on Elastic Beanstalk, and I can see the proper environment variables when I use the ``printenv command`:
ENV_NAME=development
However, if I do a die(var_dump($_SERVER)); and run the PHP CLI, I don't see the environment variables that I've defined. Same story with $_ENV and getenv().
Why can't I access my environment variables within the PHP CLI, when I can access them when Apache processes my PHP scripts?
YET ANOTHER EDIT
I made a test.php file with one line: die(var_dump($_ENV));.
When I run this using php test.php I successfully get my custom environment variables coming out, so this seems like a composer only problem, not a PHP CLI problem.

I use a YAML script which sets the environment variables for the root user from the existing variables set for ec2-user. Add this to your .ebextensions folder with the .config extension.
From there you can run PHP cli and it will see the correct environment variables
commands:
create_post_dir:
command: "mkdir /opt/elasticbeanstalk/hooks/appdeploy/post"
ignoreErrors: true
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/job_after_deploy.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
source /opt/elasticbeanstalk/support/envvars
# Run PHP scripts here. #
From XuDing's answer to this question and this answer

I created a job that creates .env file every 5 minutes.
Add the following to your .ebextensions
"/opt/elasticbeanstalk/hooks/appdeploy/post/91_set_create_app_env_file_job.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
echo "Removing any existing CRON jobs..."
crontab -r
APP_ENV=/var/app/current/.env
EB_ENVVARS=/opt/elasticbeanstalk/support/envvars
CONSTANTS=/var/app/current/.constants
CRON_CMD="grep -oE '[^ ]+$' $EB_ENVVARS > $APP_ENV; cat $CONSTANTS >> $APP_ENV"
echo "Creating .env file...."
eval $CRON_CMD
echo "Scheduling .env file updater job to run every 5 minutes..."
(crontab -l 2>/dev/null; echo "*/5 * * * * $CRON_CMD")| crontab -
Reason I did it this way is that you may want to update your environment variables via the AWS UI Console.
This is the best solution in my opinion.

Related

Supervisor env var not working with Symfony Messenger

I'm trying to use multiple consumers with the same Redis transport using the Symfony Messenger component.
As mentioned in the Symfony guide, we can have problems if we use the same values for stream/group/messenger, cause the same message can be handled by multiple consumers.
So I have updated my supervisor config as follow:
environment=MESSENGER_CONSUMER_NAME=%(program_name)s_%(process_num)02d
Then, I have updated my messenger.yaml file as follow:
redis:
dsn: '%env(MESSENGER_TRANSPORT_REDIS)%'
options:
consumer: '%env(MESSENGER_CONSUMER_NAME)%'
I have reloaded the supervisor:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start messenger-consume:*
but I still get the error:
[2021-12-25T18:33:08.954217+01:00] console.CRITICAL: Error thrown while running command "messenger-dispatcher --count=100". Message: "Environment variable not found: "MESSENGER_CONSUMER_NAME"." {"exception":"[object] (Symfony\\Component\\DependencyInjection\\Exception\\EnvNotFoundException(code: 0): Environment variable not found: \"MESSENGER_CONSUMER_NAME\". at /var/www/vendor/symfony/dependency-injection/EnvVarProcessor.php:172)","command":"messenger-dispatcher --count=100","message":"Environment variable not found: \"MESSENGER_CONSUMER_NAME\"."} []
I follow the guidelines but there is something missing somewhere ... but where?
Why does my app not read env var?
If I call my consumer:
MESSENGER_CONSUMER_NAME=myconsumer ./bin/console messenger:consume redis
it works as expected; it does not work only with supervisor vars.
Thanks in advance
UPDATE
This is the complete section config of my supervisor file:
[program:consumer-redis]
command=php /var/www/bin/console messenger:consume redis --limit=5 --time-limit=3600
user=root
numprocs=6
startsecs=0
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d
environment=MESSENGER_CONSUMER_NAME=%(program_name)s_%(process_num)02d
Today I had a similar issue, but you need to explain a little more if my answer match with your problem if not please replay me to delete my answer.
So the problem is, when you run the command:
php /var/www/bin/console messenger:consume redis
Symfony asumes the APP_ENV from 2 parts, if you are using a web server, the variable is taken from the apache or nginx or php/apache.conf file configuration, but in command line if you server has no configured the variable APP_ENV, symfony is going to check the .env file and then .env.local or .env.local.php, so, if that variable doesn't exists, Symfony is not going to take any files like .env.prod.local or .env.prod because is missing that variable. If you are using
I found the answer thanks to this article.
Your configuration is all good. You simply need to add an environment variable with a default value, so that Symfony doesn't generate errors :
# .env.local
MESSENGER_CONSUMER_NAME=0
This env variable will be overwritten in processes ran by supervisor. To test it, I simply log $_ENV['MESSENGER_CONSUMER_NAME'] in a function. Here's what I get when I call it :
Not using Messenger (synchronously) : 0
Using Messenger : either messenger-consume_00 or messenger-consume_01. (In my config I have numprocs=2)
I fixed this problem by adding the following at the top of my config/packages/messenger.yaml file:
parameters:
env(MESSENGER_CONSUMER_NAME): '00'

APP_SERVER env var not found when deploying with EasyDeploy

I have this error when the deploy script tries to install the assets:
(Setup PHP 7.2, Symfony 4.4)
[Symfony\Component\Process\Exception\ProcessFailedException]
The command "ssh -A root#vps.net -p 21 '(export APP_ENV=prod; cd /var/www-deploy/site.com/releases/20191129224025
&& php /var/www-deploy/site.com/releases/20191129224025/bin/console assets:install /var/www-deploy/site.com/releases/20191129224025/public --symlink --no-debug --env=prod)'" failed.
Exit Code: 1(General error)
Working directory: /Users/coil/Sites/site.com
Output:
================
Error Output:
================
In EnvVarProcessor.php line 162:
Environment variable not found: "APP_SERVER".
I have put the .env file in the shared files, so it's copied when the release directory is created, this file is in the directory.
public function configure(): DefaultConfiguration
{
return $this->getConfigBuilder()
// ...
->sharedFilesAndDirs(['.env'])
// ...
}
I also tried to put the env vars in the .bashrc file of the user who deploys:
printenv | grep -i app
APP_DEBUG=0
APP_SECRET=whatever
APP_ENV=prod
APP_SERVER=prod
So, I don't understand, why the environment variables are still not found. And why they are not taken from the .env file.
If I interrupt the deployment and if I manually run the same command on the server it works well. Thanks.
[Edit 2019-11-30] I think I understand know, when running the command, there is an export of the APP_ENV that is done. And, if the application detects this env variable it will just skip the .env file. So, I need to avoid setting this env var, or I must set all instead of this one only.
[Edit 2021-02-13] I have fixed the bin/console file and removed the "hack". Instead of testing the APP_ENV var I test the APP_SECRET one which is not set by EasyDebug:
if (!isset($_SERVER['APP_SECRET'])) {
(new Dotenv())->load(__DIR__.'/../.env');
}
Old solution:
It now works with the following modififications, in src/Configuration/DefaultConfiguration.php:
} elseif (4 === $symfonyMajorVersion || (3 === $symfonyMajorVersion && 4 >= $symfonyMinorVersion)) {
$this->_symfonyEnvironmentEnvVarName = 'APP_ENV';
I have passed an unkown env var to Symfony:
$this->_symfonyEnvironmentEnvVarName = 'APP_FAKE_ENV';
So the .env file is not ignored any-more. I think there is a missing option to set or not this environment var based on the setup of the application. I'll try to do a PR to the bundle.
So, as the bundle is not modified yet, I have modified the private property, in order to make the command use my .env files instead of environment variables:
/**
* #see https://stackoverflow.com/q/1762135/633864
*/
private function forceEnvironmentEnvVarName(DefaultConfiguration $configuration): DefaultConfiguration
{
$myClassReflection = new ReflectionClass(get_class($configuration));
$symfonyEnvironmentEnvVarName = $myClassReflection->getProperty('_symfonyEnvironmentEnvVarName');
$symfonyEnvironmentEnvVarName->setAccessible(true);
$symfonyEnvironmentEnvVarName->setValue($configuration, 'FAKE_APP_ENV');
$symfonyEnvironmentEnvVarName->setAccessible(false);
return $configuration;
}

"-1" file created in app root directory when running php artisan

I am running Laravel on Homestead, and whenever I run any php artisan XXX command, the file named -1 is created in the root directory of the app.
Contents of the file are similar to these ones:
Log opened at 2017-12-22 13:54:00
I: Connecting to configured address/port: 10.0.2.2:9000.
E: Time-out connecting to client. :-(
Log closed at 2017-12-22 13:54:00
I am 99% sure it is related some changes I made in my failed attempts to make XDebug breakpoints work with artisan commands. I have exported some shell variables, as recommended in this answer, but when I run export -p I don't see any of them.
Did anyone have a similar issue? What setting can be causing such behavior?
Following the suggestion of LazyOne, I found the answer:
It seems that paths in .ini file have to be absolute. So instead of:
xdebug.remote_log=~/code/xdebug.log
I had to set it to:
xdebug.remote_log=/home/vagrant/code/xdebug.log
and now it works as supposed to.

AWS Elastic Beanstalk Deployment Order

I'm deploying code to a single-instance web server AWS EB environment that will provision/update my connected RDS database. I've got an .ebextensions file that calls deployment code:
---
container_commands:
01deploydb:
command: /var/www/html/php/cli/deploy-db.php
leader_only: true
On the same deployment, I dropped the deploy-db.php file back one directory into /cli/. On deployment, I get ERROR: [Instance: i-*****] Command failed on instance. Return code: 127 Output: /bin/sh: /var/www/html/php/cli/deploy-db.php: No such file or directory.
container_command 01deploydb in .ebextensions/01_db.config failed. For more detail, check /var/log/eb-activity.log using console or EB CLI.
If I deploy a version that does not include the command, then deploy a second update including the command, there is no error. However, adding the command and the file it calls at the same time produces the error. A similar sequence occurred earlier with a different command/file.
My question is: is there a documented order/sequence for how AWS updates the environment? I would have expected that my new version would have fully deployed (and the .php file installed) before container_commands are called.
The commands: section runs before the project files are put in place. This is where you can install server packages for example.
The container_commands: section runs in a staging directory before the files are put in its final destination. Here you can modify your files if you need to. Current path is this staging directory so you can run it like this (I might get the app directory wrong, maybe it should be php/cli/deploy-db.php)
container_commands:
01deploydb:
command: cli/deploy-db.php
leader_only: true
Reference for above: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html
You can also run a post deploy scripts. This is not very well documented (at least it wasn't). You can do something like this (it won't be leader only though, but you could put a file in this directory through a container_commands:):
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/99_deploy.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
/var/www/html/php/cli/deploy-db.php

Cant access environment variables in php

Im having issues accessing OS environment variables in php
I have apache/php installed on a centos 6.3 image
in httpd.conf mod mod_env.so is loaded
in php.ini I have set variables_order = "EGPCS"
restarted httpd (many times)
in shell if I type "env" I get
DB_PORT_28017_TCP_PROTO=tcp
HOSTNAME=c6188a8bd77f
DB_NAME=/rockmongo/db
DB_PORT_27017_TCP=tcp://172.17.0.36:27017
TERM=xterm
DB_PORT_28017_TCP_PORT=28017
DB_PORT=tcp://172.17.0.36:27017
DB_PORT_27017_TCP_PORT=27017
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/etc/php.d
DB_PORT_27017_TCP_PROTO=tcp
DB_PORT_28017_TCP_ADDR=172.17.0.36
DB_PORT_28017_TCP=tcp://172.17.0.36:28017
SHLVL=1
HOME=/
DB_PORT_27017_TCP_ADDR=172.17.0.36
container=lxc
_=/usr/bin/env
OLDPWD=/etc
which has the variables im after, however if I execute print_r($_ENV); in php I get
Array ( [TERM] => xterm [PATH] => /sbin:/usr/sbin:/bin:/usr/bin [PWD] => / [LANG] => C [SHLVL] => 2 [_] => /usr/sbin/httpd )
have also looked in $_SERVER & $GLOBALS.
Interestingly if I execute php -i in shell I see the env variables set correctly in _ENV
I should note im running this in a docker container, however I dont believe it is a issue as variables display correctly in #env & #php -i. I think I have a issue with my httpd/php config
Anyone have advice for this?
thanks
I ended up having a few options
if docker container needs to run multiple services, setting env vars to /etc/environment will make them available for all users. I added the following line to my Dockerfile CMD
CMD ["env | grep _ >> /etc/environment"]
if docker container runs a single service, its best to set the entry point to the desired application, env vars will automatically be passed to application user. this is my Dockerfile CDM & ENTRYPOINT to run apache
ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-D", "FOREGROUND"]
Dagon is correct.
Unless you logged in as your web server User (apache?) you may not see the same environment variables. You can see them easily with a phpinfo test file though:
<?php
phpinfo();
?>
Or you can set your own with a .htaccess file:
SetEnv HTTP_MY_VARIABLE "my value";
From dwitz: You can also make the environment variables available system wide with this:
env | grep _ >> /etc/environment
Sorry can't comment yet... So had to create an answer.
Recently i wrote a library to get values from environment variables and parse to the PHP data types. This library can be used to parse environment variables to PHP data types (like the casting to integer, float, null, boolean), parse the complex data structures like a JSON string and more with the contribution of the commnunity.
The library is available here: https://github.com/jpcercal/environment
As you say, the environment are already loaded. Then, to get the values from environment variable (independently of the environment CLI, Apache, Nginx, PHP Built-in Server and more) to do it:
<?php
// ...
require "vendor/autoload.php";
// ...
var_dump(Cekurte\Environment\Environment::get("YOUR_ENV_VARIABLE_NAME"));
Enjoy it.

Categories