Sometimes I don't have access to app let's say in my Database Pool singleton and I need a way to detect the environment while instantiating pools and other resources etc, retrieve development or production configs.
I tried to lookup process object and process.env but couldn't find much.
Wondering if there's another way to detect the environment, I came across passing variables when running app.js but it's not possible in the production environment, so any other suggestions please.
or as a last resort, I'll add a variable to process.env object in a cautious manner.
Related
I am building a relatively complex distributed Node system. Let's say there are two processes (node apps), A and B. They are defined in separate projects.
In addition, there are a couple of custom made node modules, being used in both A and B. Let's call them M and N. In addition, M is using N.
How should I correctly handle environment vars?
I guess I should define .env for both main processes (A and B), handle all ENV vars from there and simply pass the needed env vars from there, down to M and N. This way, M and N (and other internal modules) will receive their own ENV vars passed as parameters on creation.
Is this approach correct?
Having modules getting direct access to process.env is not a good idea, and modules having their own .env file is an even worse idea.
.env files should not be added to source control (ie git) because they change with the environment (dev, prod, pre-prod) and sometimes contains sensitive information (like AWS secret keys). So that would require you to paste a .env file each time you install your node_modules making your deployment process more complex.
The .env file loaded inside your module could merge in unexpected ways with the .env of your root app (remember there is only one process.env).
Imagine a case where your module would need to behave differently in two parts of your application. How would you override the data loaded via the .env file only in one place?
So in my opinion, your guess is correct: don't put .env in node_modules.
// This is better...
nModule.someMethod(process.env.PARAM1, process.env.PARAM2);
// ...than this
process.env.PARAM1 = '';
process.env.PARAM2 = '';
nModule.someMethod();
I feel strongly that environment variables are reserved for, well, the environment. This to me implies a few things:
Inside the code, these variables should be global, i.e., accessed only via process.env.
They are not passed down to other modules. Certainly it's a good idea to make dependencies customizable with parameters you can pass to the functions they export. But the environment should not be used for that.
How you load values into process.env is really a question of how you start your programs A and B. I personally prefer systemd services for that which have excellent support for defining the runtime environment. The dotenv package seems more like a crutch, but it's fine from the program's perspective.
Your approach sounds correct and it should work. When you define .env file and use dotenv package, you will be able to access all the variables inside .env in your code. That means that custom made node modules will also be able to access it, and you don't have to pass them anything (you can access them directly with process.env.NAME_OF_ENVIRONMENT_VARIABLE).
SUMERIZE: Create .env file in both A and B, use dotenv package, and then you can access environment variables directly inside the code with process.env.NAME_OF_ENVIRONMENT_VARIABLE (in custom node modules also). You can create constructor (for custom modules) in modules A and B, and just pass process.env.ENV_WHATEVER as a parameters. That is even better approach since your custom module's logic will be independent from the rest of the app (it will depend only on the input).
NOTE: Don't commit your .env to Git since .env usually have some confidential information. The best practice is to create a .gitignore file and add .env in it.
RECOMMENDATION You can keep all your .env files in one centralized place for better management. You can check some password management tools like https://www.dashlane.com/ or https://www.lastpass.com/.
You mentioned complex distributed system. Distribution can also be associated with a hub / centralized key/variable management system. I'm assuming there are many env variables that are shared across your multiple apps.
Isn't it a plus if you create a centralized node that contain all your required variables and protected them with authentication?
All nodes (regardless of app) to maintain only a single password string in order to authenticated with the centralized node, and load all required variables from a single .env file.
Alternatively you can use a system like vault
I am looking to bind a PCF (Pivotal Cloud Foundry) Service to allow us to set certain api endpoints used by our UI within PCF environment. I want to use the values in this service to overwrite the values in the root directory file, 'config.json'. Are there any examples out there that accomplish this sort of thing?
The primary way to tackle this is to have your application do this parsing. Most (all?) programming languages give you the ability to load environment variables and to parse JSON. Using these capabilities, what you'd want to do is to read the VCAP_SERVICES environment variable and parse the JSON. This is where the platform will insert the information from your bound services. From there you, you have the configuration information so you can configure your app using the values from your bound service.
Manual Ex:
var vcap_services = JSON.parse(process.env.VCAP_SERVICES)
or you can use a library. There's a handy Node.js library called cfenv. You can read more about both of these options in the docs.
https://docs.cloudfoundry.org/buildpacks/node/node-service-bindings.html
If you cannot read the configuration inside of your application, perhaps there's a timing problem and you need the information before your app starts, you can use the platform's pre-runtime hooks.
https://docs.cloudfoundry.org/devguide/deploy-apps/deploy-app.html#profile
The runtime hooks allow your application to include a file called .profile which will execute before your application. The .profile file is a simple bash script which can do anything needed to ready your application to be run. The only catch is that this needs to happen very quickly because it must complete before your application is able to start up and your application has a finite amount of time to start (usually 60s).
In your case, you could use jq to parse you values and insert them info your config file, perhaps using sed to overwrite a template value. Another option would be to run a small Node.js script, since your app is using Node.js it should be available on the path when this script runs, to read the environment variables and generate your config file.
Hope that helps!
Context:
As my Node.js project grows larger, the need for configuration increases. This project is the first project where I have switched from a 'legacy configuration file' (say, a config.js or config.json) to a dotenv (.env) file to configure the product.
However, the sheer amount of environment variables used raises a question. These environment variables are all related to OS and networking configuration, so it seems justified to configure the application with the dotenv technique.
Question:
Say there is one environment variable already set; that would mess up the configuration. A practical example of this would be when you upload a project to some of the bigger (cloud) hosts: the PORT environment variable of the machine is set, and may therefore override a default value (see example below), or a value that you might expect. For a system administrator, these errors would be hard to debug.
const PORT = process.env.PORT || 3000
How does one deal with these pitfalls?
Current situation:
I am currently using [name of product]_[name of variable] as template for my environment variables. It feels like a hack (remember private members in JS?) and there is most likely a better solution available.
The second option I have in mind is to be very explicit in the .env files by settings all variables used in the product. However, reliability seems to be a weak spot here: if someone were to remove one setting, the entire "defense mechanism" is gone and the product is vulnerable to these bugs again.
I'm working on a mongoDB backed expressjs app. I've used the express generator to create it.
I would really like to work on a development database through MongoLab, and then deploy to Heroku (which would also be backed by a MongoLab database).
What are the best practices for splitting these two up so when I start the app in development mode it uses the development mongo instance, and when I deploy to heroku in production mode it will use the production DB?
Thanks!
Heroku's 12Factor architecture document does a great job of explaining both the best practices of config management, and the rationale behind them:
http://12factor.net/config
The tldr is, "pull in config from environment variables and use explicit configuration instead of named environments like 'development' or 'production.'"
Heroku will provide all the environment variables you need for connecting to your mongolab db, so all you have to sort out is providing those same variables to your app locally. One common solution is the .env file:
https://devcenter.heroku.com/articles/heroku-local#copy-heroku-config-vars-to-your-local-env-file
This is essentially a file that you don't check in, which provides a list of key-value pairs for your local environment variables. It can be run through Heroku Local or, more generally, via tools like node-foreman or docker-compose.
disclosure: I'm the Node.js platform owner at Heroku
Is there something like node’s process.env to access environment variables? I want to know in my Foxx code whether it's running in development, test, staging, or production.
Alternatively, is there any way to determine if my Foxx app is running in development-mode?
Yes, we have thought about a getenv wrapper several times, I guess now its time to implement it. It may be in time for 2.5.1, we'll see ;-)
The foxx self debug awareness can be achieved via: applicationContext.isDevelopment
As noted above, arangodb now contains the process.env functionality similar to nodejs.