9 ms·
the twelve-factor app is a set of recommendations from 2011 that are based less on engineering principles and more on the capabilities of Heroku and containeriz
by zemo 3y ago
the twelve-factor app is a set of recommendations from 2011 that are based less on engineering principles and more on the capabilities of Heroku and containerized infrastructure in 2011. For example:
> Another approach to config is the use of config files which are not checked into revision control, such as config/database.yml in Rails. This is a huge improvement over using constants which are checked into the code repo, but still has weaknesses: it’s easy to mistakenly check in a config file to the repo; there is a tendency for config files to be scattered about in different places and different formats, making it hard to see and manage all the config in one place. Further, these formats tend to be language- or framework-specific.
> The twelve-factor app stores config in environment variables (often shortened to env vars or env).
yeah the reason they argue for this is that the people that wrote this worked on Heroku, and the way that Heroku worked is you populated the environment variables from some fields in a web app. If you want your config history tracked in version control, or you do gitops, or you have k8s configmaps, or you want to have your configuration files on a mounted volume ... those things are all broadly fine; they keep the configuration state separate from the app deploy state. This document really confuses the forest with the trees and recommends things based less on actual engineering principles and more on the product capabilities of the corporation that produced it. It is an actively harmful set of guidelines.
- phendrenad2 3y agoHistory repeats itself. Netlify tried this with the MACH Alliance.
- morelisp 3y agoThe 12 factor app that stored config in env vars found it trivial to migrate to ConfigMaps. The LOB apps today that expect complex ConfigMap layouts (at worst case, directly from the k8s API) are going to be hell to migrate to whatever comes after k8s.
- throw1234651234 3y agoThe whole .env file holding all your configs thing is a disaster. People forget to update the template, it has to be passed around, etc. Configure your secrets in Azure Key Vault (AWS Secrets Manager, GCP-something-I-forget) or whatever the non-cloud Vault software is called. Devs only set client_id, client_secret, and env defaulted to dev. On startup, the app fetches configs for the secret store. The needed secrets are in source control. If the needed secret is missing from the secret store, there is a clear error on startup. You are welcome, I just saved you weeks of onboarding, confusion, and devs passing around .envs on Slack.
- campbel 3y agoI agree, sops / ejson / gitcrypt or something else that encrypts a file in vcs, then use your cloud or shared secret vault to disperse the decryption key.
- danwee 3y ago> You are welcome, I just saved you weeks of onboarding, confusion, and devs passing around .envs on Slack. Don't get it. At one company I worked, .env files for the DEV environment were open (the file itself was stored on Vault, so only engineers had access to it), and one could only access DEV resources via VPN. So, starting a service using the DEV .env file was rather easy an uncomplicated.
- throw1234651234 3y agoHere is the problem with that. A dev pushes a change that requires a change to the env file. Another dev pulls down the code, but doesn't change the env file. Everything breaks. At really bad companies, DevOps sets env vars from somewhere other than that file passed around by devs - another failure point. My proposal: 1. Key Vault | HashiCorp Vault | whatever is the source of truth for secrets. 2. When a developer adds a key, they add it to Key Vault and update code to use it. 3. On app startup, code checks the dev's local for 2 env vars ONLY, which allow access to key vault. 4. The app then tries to pull in all the env vars it needs by secret name. 5. If any are missing, it fails. This keeps devs from having to pass around .env files outside of source control. Btw, Azure (and all other cloud) builds can be configured to pull env vars directly from Key Vault, so there's that benefit too.
- parasti 3y ago"5. If any are missing, it fails." That's literally all you need to solve the scenario you described with .env files.
- meowtimemania 3y agoThe difference is any time the .env config is updated, all engineers have to update their .env file. So with .env file: - developer adds to .env - pushes code - all developers see failures in dev env due to missing env var - all developers search slack/email to figure out what went wrong - all developers update their .env file and things are working again ————- In gp’s comment ———- - one person works on feature that introduces new config - failure happens in their local environment - they update config backend and push code - all other developers get updates with no changes needed
- jbotdev 3y agoIt is true that this is somewhat influenced by how Heroku works, but ConfigMaps and GitOps do not meet the same security and usability requirements as Heroku config/env vars. If you want secure config storage on Kubernetes, you end up using Secrets, which ends up being key-value like env vars anyway. If you want similar security with Git you need a layer of encryption, which breaks diffs and requires additional tooling. This all leads back to why high-level deployment tools like Heroku were created.
- campbel 3y ago> If you want secure config storage on Kubernetes, you end up using Secrets, which ends up being key-value like env vars anyway. You can load the secret file directly into the app, no need to load it as env vars or keep it strictly as key-value pairs. > If you want similar security with Git you need a layer of encryption, which breaks diffs and requires additional tooling. This all leads back to why high-level deployment tools like Heroku were created. You can use tools like ejson[1] or sops[2] to get encrypted files checked into Git that have key level granularity on diffs. There is definitely a place for higher level abstractions than Kubernetes. Mostly it gives operators a standard platform to build from when teams outgrow the PaaS sandbox. [1] https://github.com/Shopify/ejson https://github.com/Shopify/ejson [2] https://github.com/getsops/sops https://github.com/getsops/sops
- Spivak 3y ago> You can load the secret file directly into the app Now you're getting away from the spirit of 12factor and hard-coupling them again. The intent is for the app to consume the secrets but have no knowledge or care where they came from. Edit: misread as "load the secrets directly into the app." Yeah, this is just env vars but different.
- yjftsjthsd-h 3y agoI'm not really kubernetes expert, but don't they come from /my-secrets and the application doesn't need to care how that got mounted?
- xwdv 3y agoIf it is truly harmful, it shouldn’t be sitting at the top of Hackernews. Let’s flag it.
- zemo 3y agoI... don't think the "flag" functionality is intended to communicate "this is bad advice".
- xwdv 3y agoIt is “harmful” advice, not bad. Regardless, why should it sit on the front page of hackernews?
- v2223943777435 3y agoi got a ton of value out of reading the comments though
- wutwutwat 3y agoHeroku didn’t invent ENV variables nor did it dream up the idea of using them for app config. This has been in use long before Heroku existed. I’ll give Heroku credit for making it common knowledge and spreading the use of these concepts, though.
- zemo 3y agoyeah I never suggested that heroku invented environment variables, and the idea that environment variables weren't common knowledge before heroku came along is ... let's say at best revisionist.
- wutwutwat 3y agoTrue. If you remember the world before 12 factor you know that even if motivated by self serving incentives, Heroku making this mainstream has been an overall win for the entire industry and we are generally better and more secure for them having done so. We are still benefitting from all of this today, and Heroku who championed it is making death rattles.
- hirako2000 3y agoWhile valid points in many contexts, I've seen many other contexts where following this principle/pattern a/ yields none of its benefits b/ results in very significant business impact. Here is some obvious case observed many times. A small and very fast pace team builds a server application having limited to no external dependencies. No db even. Just a server doing stuff. It does have some config yes, many many key/value pairs even, a config file ended up with a dozen properties just to control Req per sec limits and such. Now just to deploy the thing, since of course env defined configurations is where things belong in best practice, the dev team setup a process to peer review those env values and despite all of that, fail to get the app running. Human errors happen but since more mistakes and release delays were caused by misconfiguration than any other reasons, the keen and bright enginnering team all agreed it would be better to have a config repo. One genius in the group argued that having a config service would be even neater than have the app read from a git repo! The whole got so hyped and of course spend the whole next sprint building and testing that. Brilliant, it worked! Except that of course outages happened, of course. Outages happen. Bringing down all environments one by one, hence blocking pretty much everyone. Everything went down because hey, since we made that effort which took for longer than we thought to build a config service and have our app reads from it, one of the dev minds thought it was a genius idea to have the app reload the config every 5 mins at runtime so that if a configuration change was made, no need to even restart anything. Of course error handling wasn't robust and well tested since the boss reminded the team we've got to ship a product by the end of the quarter and solving the universe can maybe wait 5 or 10 years after the IPO. Team resorted to simply track the config in the repo. Kept the runtime reload of the config and things worked just fine. Things can be done right and impacts could have been avoided. The example may seem like a twisted case since these were all configurations, not environment specific values. But I've just seen so many occurences of env variables being separated from the application repo costing so much and distracting contributors for no benefit that I have grown very cautious of it.
- donatj 3y agoThe invention of dotenv files just makes me chuckle and seems to completely miss the point of not putting them in a config file.
- bunderbunder 3y agodotenv files are great as a piece of developer ergonomics. And that's fine. I use them for that purpose all the time. I would not willingly consent to using them to manage environment variables in production. But I would also not willingly consent to doing it the way that's best for production during development. I think that's fine. 12-factor is a set of guidelines about what you do in production. There's a whole universe of things that are smart ideas for development and bad ideas for production. Leaving debug symbols in your binaries, leaving ports for connecting a debugger open on your containers, etc.
- zmmmmm 3y agoIt's interesting to me that your philosophy does sharply contradict with another popular notion which is that there is great benefit in unifying production and development environments. Curious what your take on that is.
- Aeolun 3y agoLoading environment variables from a .env file if it exists is no different between development and production. You just set the variables at startup in prod, and in the file on development (probably mostly because you want to change them all the time).
- stackskipton 3y agoOps person here. .env files at best should be injected into Developer environment by IDE/Editor. Many IDE/editors have this feature along with Docker. If that's not an option (Thanks JetBrains/Visual Studio), second thing is something like Python-dotenv where library loads .env file at startup, injects them into environment variables and rest of the code is configured to use environment variables. This behavior could even be environment variable controlled and should not error if no .env file is present.
- rbanffy 3y ago"Store config in the environment" does not necessarily mean configs are in environment variables - it only means configuration comes from the hosting environment, not the application itself - you are not adding a "settings.json" file to your machine before starting the app. This way, the same source deployed in, i.e. your AKS cluster in Azure EU north will take the configuration you set for that cluster while the one you run out of an Docker Swarm of RPi Zero's in an Ikea photo frame (I have one cluster like that, called Gibson), will take the configuration from that cluster.
- Kwpolska 3y agoThe page https://12factor.net/config https://12factor.net/config disagrees with you: > The twelve-factor app stores config in environment variables (often shortened to env vars or env).
- rbanffy 3y agoI would assume that is the interpretation back in 2011. While the mechanism changed, the principle still holds.
- lucideer 3y ago> or you have k8s configmaps [...] those things are all broadly fine; they keep the configuration state separate from the app deploy state Why are they fine? This seems to be an argument grounded in "it's a newer norm therefore it's better" but I don't see the justification. I've never used Heroku but ConfigMaps are a bane to manage. Even as a general programming principle within application code, colocality is a well-known, long-discussed topic around improving maintainability. If you're not using monorepos, that's currently not a reasonable option with current orchestration conventions. Even if you are using monorepos, you're highly likely to either get into writing & automating DSLs to feed into your configmaps or do weird things like using Jinja to do file includes in your mounts. That's all before you run into the etcd 1MB size limit & realise that actually this whole system is a hack. TL;DR newer ain't intrinsically better
- throwaway4good 3y agoAs far as I can tell this is the standard way of doing things also in a kubernetes setup: The application gets its configuration from the environment variables. Then in the case of a kubernetes setup. The application is wrapped inside a mechanism that gets the configuration from some where else.
- ljm 3y agoNobody calls it '12 factor' anymore but we still adhere to a generic set of principles as a result (since 12-factor predated docker and kubernetes in the mainstream). - Logs as a stream: yep, just write your logs to STDOUT instead of a file. Let the orchestrator deal with reading and storing it. - Configuration in the environment. Apps tend to pull config from different sources depending on the deploy - maybe a .env locally and a secret store in production. - Port binding - your app listens on a port and you put nginx or whatever in front of it and set up a reverse proxy. K8S services and ingress do that. I think the biggest criticism you can lay down on 12 Factor these days is that it's not actually written very well and assumes you know exactly what it is talking about.
- talent_deprived 3y ago> Port binding - your app listens on a port and you put nginx or whatever in front of it Apache for my personal projects, in front of the docker containers.
- morelisp 3y agoIt's written very well but the audience is server application programmers in 2011, not someone who has written a dozen services yet never seen a log rotator, "production mode", or an AF_UNIX socket in their whole career.
- rbanffy 3y ago> - Logs as a stream: yep, just write your logs to STDOUT instead of a file. Let the orchestrator deal with reading and storing it. This is one that always feels odd to me: what happened to rsyslogd?
- craigmcnamara 3y agoNot the responsibility of the container. The host deals with those details.
- rbanffy 3y agoStill, I haven't seen it in quite some time.