[HN Gopher] The Twelve-Factor App (2011) ___________________________________________________________________ The Twelve-Factor App (2011) Author : edward Score : 317 points Date : 2023-10-12 14:19 UTC (6 hours ago) (HTM) web link (12factor.net) (TXT) w3m dump (12factor.net) | ris58h wrote: | You should add 2017 in the title. | wesleytodd wrote: | yeah I got confused seeing this on the top. in my head said | "what is this, 2012?". Am I wrong this existed way before 2017? | | edit: I am correct, it is much more old. | https://github.com/heroku/12factor/graphs/contributors | larsnystrom wrote: | First commit was 2011. | webmaven wrote: | The 12 factors go back even further, to Joel Spolsky's | "Joel Test" in 2000: | | https://www.joelonsoftware.com/2000/08/09/the-joel- | test-12-s... | richardwhiuk wrote: | That's a rather different set of 12 factors. | screamingninja wrote: | Previous discussion- | https://news.ycombinator.com/item?id=31198956 (102 comments) | didntcheck wrote: | Another interesting thread about how these practices have held | up or changed over the past decade: | | "Twelve-factor app anno 2022" | | Article: https://xenitab.github.io/blog/2022/02/23/12factor/ | | Discussion: https://news.ycombinator.com/item?id=31225921 | songshu wrote: | I love this generally but some of it has leaked out to the wrong | people and there are strong cargo cults around such things as one | codebase===one app. | notoverthere wrote: | Back in the early days of Docker, I did a whole bunch of work to | make WordPress behave as a Twelve-Factor App. | | It traditionally hasn't behaved as one - which sort of makes | sense, because WordPress grew-up in a world where long-lived | servers with writable and persistent local disk storage was | commonplace. | | I'm sure things have moved on since those days. This was back in | 2016. But it sure was a fun challenge! | DanielHB wrote: | I remember when I learned about making servers stateless by | storing session information in a database and just not writing | to disk and stuff. I was amazed at how much simpler it made | things and added the capacity to load-balance multiple nodes | without having to bother with session stickness. | | Of course it made things harder in other ways like having a | separate DB for sessions. | frankfrank13 wrote: | I like this in general, but the number of times I've had to delay | a release because some non/psuedo-technical person has pulled out | "12 factor" like a universal yellow card has been enough for me, | overall, to ignore it almost completely. I guess the same has | happened to me for "agile" honestly. I recognize the intent of | guidelines like these, but they seem to be much more useful to | people whose only "value" is to provide ivory tower technical | leadership. | Waterluvian wrote: | I've had issues like that before. The solution was to have a | clear, documented process, and point them to that. | | I've learned to take issues like that in good faith. Why are | they raising an issue? Is the existing process not clear? Is | there a deficiency in it? Is there a lack of reliability? If | reasonable concerns are found, the process can change (and the | documentation is to be updated). | ChrisMarshallNY wrote: | _> The solution was to have a clear, documented process, and | point them to that._ | | This has its own drawbacks. I worked for a company, in which | Process Was God, and Thou Shalt Do Only That Which God Has | Proclaimed Good. | | It worked most of the time, but made it very, very difficult | to introduce flexibility and orthogonal approaches. | | There's really no way to duplicate the results of | experienced, cohesive teams of high-functioning engineers, | with process. We can get similar results, in many ways, but | there's always a price to be paid. | | T. A. N. S. T. A. A. F. L. | willseth wrote: | Give an example. Like most things, it's context dependent and | there are grey areas, but I think most devs use 12 factor like | a north star. I wouldn't block a release due to some minor | deviation, but generally lacking alignment should be treated as | tech debt as a minimum. If a release regresses significantly in | one of the factors, I think it's fair to block or at least | force more detailed review to understand why the dev felt the | tradeoff was worth it for that release. | cduzz wrote: | There's the "Plumber Problem[1]" by John Siracusa where you | watch a story and see a problem in your specific domain that | leads you to mistrust the whole story. | | With the 12 factor nonsense, I see the guidance of "Dump | unformatted logs into stdout and make it someone else's | problem; they'll hadoop or splunk it and everyone wins." | There is no magic splunk that absolve you (the developer) of | generating useful data to logs, if you expect useful data out | of your logs. You can't reverse "cow -> burger -> sewage" and | shouldn't expect some magic hadoop to reverse entropy without | a ton of work. | | So -- I guess the 12 factor app dictum is fine for some | trivial "I rewrote twitter in 80 lines of erlang" app, but in | my opinion it is a "if we can land a man on the moon we can | land a man on the sun" misstatement of complexity in actually | getting things done in the real world. | | [1] https://hypercritical.co/2023/08/18/the-plumber-problem | morelisp wrote: | Spoken like someone who has never had to work on a Java | application with 22 custom log files, not including stdout, | stderr, and two separate syslogs. | | Yes, if you want useful data from logs you'll need to log | useful data, but this is a case where 12 factor is so | successful / dominant today I don't think you even know | what it's arguing against anymore. | cduzz wrote: | No, writing files is nearly as bad as writing to stdout | -- both imply someone else has to parse the output. | | If the logs matter -- write them to an API that retains | log structure by serializing it. | | If the logs don't matter, then they don't matter, but | typically the logs are used for all sorts of analytics | processes after the fact. | | Asking someone else to parse your data is rude. | nightpool wrote: | Again, "this is a case where 12 factor is so successful / | dominant today I don't think you even know what it's | arguing against anymore" | cduzz wrote: | The twelve factor app says: A twelve-factor app never | concerns itself with routing or storage of its output | stream. It should not attempt to write to or manage | logfiles. Instead, each running process writes its event | stream, unbuffered, to stdout. During local development, | the developer will view this stream in the foreground of | their terminal to observe the app's behavior. | | That guidance is deeply foolish; I have to assume the | rest of the guidance is just as silly for anything but a | toy application. | lexicality wrote: | Where does it say "unformatted"? All it says is that your | logs should be sent to stdout. | | You write your logs in whatever structure you want and | have something in the runtime environment (k8s, systemd, | file redirection in bash whatever) forward them to the | eventual storage location. I don't see the issue. | cduzz wrote: | So -- there's a file, that's created by some something in | a container emitting a string of bytes. A file must go | through a parsing and serialization phase to be useful to | a logging infrastructure. Just because you decorate the | contents of that file with { and } and other punctuation | doesn't make that file a string of json records, until | something's read and verified it. | | I'm supposed to just load it into memory hoping it's json | or avro or whatever? Nope, errors happen; there's a limit | to the number of bytes that can be sent from one place to | another before the kernel may interrupt it (you're | writing an application log and your runtime emits it's | own debugging message; they get intermingled because | they're both being written to a fifo). | | Maybe this is fine (usually it's fine) but eventually it | isn't fine. Use a logging library, categories your logs, | maybe start off with stdout but eventually put on some | big person pants and use a logging api and use the | stderr/stdout for high cardinality exceptions, not "all | my logs" | jameshart wrote: | 12 factor does not say 'don't use a logging library' | | Use a logging library. Configure it to output well formed | and categorized log messages to stdout. Let the runtime | environment take that stream of data from there. | lexicality wrote: | Just so I understand, you are saying that the entire | concept of the 12 factor app is bogus because it tells | you to write unformatted logs to stdout because anything | you write to stdout is by its very nature unformatted | because even if you're outputting formatted data | something else in your program might decide to | concurrently write into your stdout buffer while you're | writing a log line and that will corrupt your entire data | stream irreparably? | jameshart wrote: | What 12 factor is telling you to do is to _not build a | log file rotator into your application_. | | It is the least controversial and most broadly beneficial | of the 12 factors. | | Why do you think it's foolish? | cduzz wrote: | It says "send it to stdout and let someone else figure it | out." | | As that someone else, who often has bug reports like "why | aren't my log events all in one record in my thing? | Because you filled your stdout with newlines!" "Why did | my message vanish? It was important!" "because it's | malformed json because your runtime had an error; it's | over there instead of over here." | | Programming's a stack of details; all of which matter. | Log using a logging API where available; use | stdout/stderr for exception logging only, if at all | possible. If you want your logging to be useful, think | carefully about how and what you log. | jameshart wrote: | That's a total misreading of what 12 factor is about. | | All it means is to let someone else (other than the | program itself) figure out how to get the log messages | (whatever you decide they should be) from your process | (running wherever it is) to wherever you want to have | those logs for inspection. | | Do not hardcode into your application the assumption that | they are written to a file or sent to a port. | | In your application, write them to stdout. | | In local dev, stdout will probably go to an interactive | console. In a container running in a cloud hosted cluster | it will probably go to a networked log aggregator that | collects it all into an indexed time oriented data store | along with other logs from other running instances. | | Because you used stdout, that's easy to do. | | If you wrote them to a file whose name your application | manages and changes itself to manage log rotation... | either of those is _hard_ to do. | jeremyjh wrote: | The reason people pay outrageous prices for Splunk is you | can get some pretty decent burgers out of sewage if you | know what you are doing, and from personal experience the | results can be totally game-changing if you are stuck with | a mishmash of different log formats and have to support a | large distributed application. | Aurornis wrote: | > Give an example. | | I can give an example. The part about sticky sessions is good | generic advice for someone building generic web services, but | there are situations where sticky session-like functionality | or sharding-like behavior might be a better choice. Anyone | adhering literally to the 12-factor guide would get hung up | on trying to move that data to redis or memcached: | | > Some web systems rely on "sticky sessions" - that is, | caching user session data in memory of the app's process and | expecting future requests from the same visitor to be routed | to the same process. Sticky sessions are a violation of | twelve-factor and should never be used or relied upon. | Session state data is a good candidate for a datastore that | offers time-expiration, such as Memcached or Redis. | | The guide also has a strong preference for languages like | Ruby, Perl, and Python. There's even a quip about how | 12-factor prefers languages with a REPL, which in the wrong | hands becomes an argument against using Rust or other | languages. | | People who think the entire world is simple CRUD web apps | tend to think that guides like this are completely universal. | It's a good guide for people making common web apps, but it's | not a perfect methodology for every backend service. | brodouevencode wrote: | > People who think the entire world is simple CRUD web apps | tend to think that guides like this are completely | universal | | That's the very first point they make: | | > In the modern era, software is commonly delivered as a | service: called web apps, or software-as-a-service. The | twelve-factor app is a methodology for building software- | as-a-service apps that... | | Anything not web app/SaaS they express no opinion on. | willseth wrote: | I think it depends on how you interpret "rely". If your app | can gracefully recover to a reasonable state from a failure | to resume the expected session, then you could argue it's | not that reliant on it. Many systems use sticky sessions as | simply as an optimization, which is fine. | | You didn't actually give an complete example. When are | sticky sessions a better choice than persistence? | robertlagrant wrote: | > but they seem to be much more useful to people whose only | "value" is to provide ivory tower technical leadership. | | I've found it pretty useful in practice. I don't see why it's | much more useful to those people than it has been for me. | flakes wrote: | I call that weaponized dogmas. It's at least better than people | who insist on being DRY by writing an inscrutable generic | helper function which will only save 3 or 4 lines of code | duplication. | laurent_du wrote: | Nothing I hate more than a useless "helper" function that | wraps a built-in feature of the language and gets buried in a | "common lib" package that you need to inspect when you want | to understand what is going on, instead of just relying on | your knowledge of the language. Do we really need a function | to map a dictionary and a list of keys to the corresponding | values? | BossingAround wrote: | Oh my god I got a flashback to Groovy's missing method [0] | which caused us so many issues, and made our codebase so | unreadable. | | When you discover it for the first time, you think, "huh, | neat, why not use it". Before you know it, nobody can | reason about your code and if you leave, nobody wants to | maintain it (esp. if your test suite is not extensive). | | [0] https://groovy-lang.org/metaprogramming.html | booleandilemma wrote: | I'm a huge hater of these and I think they almost always | decrease readability of the code and slow down the | development and review process. | | I want to read and write the language I'm developing with, | not the helper methods of some overeager developer who | wanted to leave his mark on the codebase. | brodouevencode wrote: | The absolute counter to weaponized dogma is itself weaponized | dogma. There are times when implementing DRY, 12FA make sense | and times when it doesn't. Be careful with hard-lined | stances. | samtho wrote: | This is more a reflection of the organizational structure that | allows or tolerates such behavior rather than anything to do | with the 12 factor app methodology. I think most reasonable | people would agree that if you were able to incorporate most of | the list, you're doing alright. | Aurornis wrote: | > some non/psuedo-technical person has pulled out "12 factor" | like a universal yellow card has been enough for me, overall, | to ignore it almost completely. | | Ignoring it completely on principal is just as bad as the | people who treat it like mandatory dogma. | | I've also had over-eager junior engineers or wannabe architects | use the 12-factor article as mandatory requirements for any | launch. It takes a firm and unified explanation that these are | good goals to strive for, but in the real world we need to make | compromises for launch and choose which aspects to delay or | defer. | lopatin wrote: | Ignoring it completely is a viable strategy. A lot of 12 | factor sounds like common sense to people who regularly ship | stuff. For example, if I fail to put the config in the | environment, the risk that introduces will be immediately | obvious in the PR and someone would be able to raise that | concern, with real justification, not because it's declared | in a 12 factor manifesto. | i-use-nixos-btw wrote: | I think ignoring it completely is a viable strategy once | you've already gone through the stages - when your mind is | in the right place. | | I have moved on a long way from the days that 12 factor was | my bible, but those days completely redefined my way of | developing software. I'm not exaggerating here - it | completely shifted my approach. | | I guess it's similar to Scrum in that way - it isn't a | great end point, but if you're stuck in the old ways (i.e. | the methods used before it was even a thing) then it's at | least a good approach to sink your teeth into, try it out, | shape your approach, and move on from there. | | Basically, I'd rather see a replacement that improves on 12 | factor than throwing out the book entirely. | ascendantlogic wrote: | > A lot of 12 factor sounds like common sense to people who | regularly ship stuff. | | In 2023, yes. A lot of the 12 factor methodologies became | table stakes in the modern cloud era. Back when this was | written "cloud" was not nearly as ubiquitous as it is now, | although we were certainly headed in that direction. A lot | of the comments here are viewing this through a 2023 lens | and forgetting it was written in 2011. | darkwater wrote: | Well, if your app log directly to files on disk (extra bonus if | it doesn't respect any verbosity setting) or will only works if | secrets are hard coded in config files (even if this could be | work-arounded at deploy time probably), I for one will do all | that I can to avoid your app reaches production. | | Yeah, I work in ops^W platform. | brodouevencode wrote: | No amount of dogma should interfere with a deployment within | the scope of an MVP. Once it's out of MVP then anything not | addressed best practice-wise is tech debt. If your organization | had adopted 12FA as a set of best practices then those should | be met, but they should never interfere with a deployment. | | 12FA is not a single box that is to be checked. It can and in | most cases probably should be implemented over time as the | product matures, taking each point, point by point (and maybe | even breaking those up) and adding that into the product. If | you've done good engineering up front (abstractions and | interfaces where it makes sense, not hard coding everything) | this should not be an issue. | | inb4 YAGNI: this is just as abused as 12FA. | | EDIT: the biggest thing 12FA is missing are concrete examples | that junior engineers can reference. | jsight wrote: | TBH, most of the value in things like this is for consultants | who go into shops that really don't know better. | | Being able to point management at this can be really useful. | | For most of us here, it is 99% common sense. | bunderbunder wrote: | Indeed. | | Hard to believe that treating best practices as strict rules | would not turn out to be best practice, isn't it? | ireallywantthat wrote: | Nowadays, I see many articles titled "Beyond 12 factor Apps" | which proposes even more factors for App prominent among them | being one from IBM. What's your opinion on that? | | https://developer.ibm.com/articles/15-factor-applications/ | Moto7451 wrote: | This is a small but real trend. My experience at a company that | went deep into expanding beyond/removing some of the 12 Factors | is that it breaks portability of containerized software built | with those assumptions. There were a few times I needed to | install a vendor product or open source project that was built | to the 12 factors but spent a month or more just building a | shim to make it conform to our particular bend on it. I'm sure | there are good reasons to deviate but I wasn't particularly | impressed with our decisions and more importantly why we made | them. | aj_g wrote: | For sure an influential engineering codex. Feels almost strange | thinking about all the easy abstractions we have now for hosting, | like Render or Vercel or that this was written in 2012, when web | apps were much much more of a wild west in terms of | accepted/shared practices. | RugnirViking wrote: | I was kinda expecting this from the title to be some sort of | commentary on two factor authentication, like an app that needs | passport photo, face scan, drivers licence, sms text, google | authenticator, email link, password, fingerprint, all together to | log in just once. | patrickaljord wrote: | Your average centralized crypto exchange. | moffkalast wrote: | Sounds like roughly what the average stock or crypto exchange | requires before they let you trade haha. | rando_dfad wrote: | Thank KYC/AML for that. | | Money is not data, it is a complex social construct. Moving | money requires interacting with that social construct, i.e. | government regulations. | | Yes, crypto was supposed to get around that. No, government | didn't agree. | moffkalast wrote: | Well I'm glad they at least aren't collecting skin samples | yet. | revskill wrote: | Sorry, i put all secrets in my code. I don't need 12 factors at | all. | | It's super easy to deploy to multiple environments, because code | is single source of truth. | Aurornis wrote: | Secrets in code is bad practice because it puts the secrets in | source control and gives them to anyone with access to the | code. | | You separate out the secrets to keep them secret. | revskill wrote: | Next evolution of Git should automatically introspect the | code base for comment to leaving out all "secrets". | | My point is, make the code easy to clone in a runnable shape | wihtout any hacking on host system. | gdprrrr wrote: | You can configure GitLab to reject the push if you comitted | secrets, based on regex marching with common formats for | tokens. | pjs_ wrote: | Hell yeah brother. Move fast and break things philosophy | porsager wrote: | It's not a problem. Here you go: https://github.com/AGWA/git- | crypt | samus wrote: | This only works if secrets are frequently rotated and contain | enough entropy. Else, all secrets will eventually be | decrypted from leaked repositories and distribution | artifacts. | brodouevencode wrote: | What company do you work for? I'd like to cancel my | subscription. | | Seriously...bad idea. One repo leak or even one bad copy/paste | in StackOverflow and you're done. | ACV001 wrote: | Boring. This is already happening in any sane modern application. | seanhunter wrote: | It might be worth you reading | https://news.ycombinator.com/newsguidelines.html | | In particular: > Be kind. Don't be snarky. | Converse curiously; don't cross-examine. Edit out swipes. | > Please don't post shallow dismissals, especially of other | people's work. A good critical comment teaches us something. | gouggoug wrote: | > This is already happening in any sane modern application. | | Probably in part thanks to 12factor.net | sbjs wrote: | I genuinely feel like there's two camps of professionals: those | who know how to do something and do it extremely well; and those | who know how to describe something and break it down very well. | The former are the ones making the magic happen, like Fabrice | Bellard. The latter become very influential teachers like Bob | Martin. Both are needed (although the former more so), but the | latter usually get all the attention and credit. | webscalist wrote: | I prefer to have known configuration presets (groups) version | controlled. Documents known shared environments (db host, ... | etc) well. | vilunov wrote: | I feel like each of this points can be reasonably disputed. | | 1. One app - one repo. There is nothing fundamentally wrong with | multiple apps (as in separate pods/containers/processes) being | developed in a single repo, as long as they are tightly coupled | functionally, share the release cycle, but still need to be | deployed separately to get advantages of separate processes and | independent scaling. The first example that comes to mind is | separation of public api and worker processes, e.g. ruby's | sidekiq, python's celery or a generic kafka consumer. | | 2. > A twelve-factor app never relies on implicit existence of | system-wide packages. | | This is incredibly hard to achieve in practice if you're not | running something nix, and even then there are leaks of | dependencies on kernel syscall APIs. Every Rust app implicitly | depends on a glibc (except musl ones), which is present in major | Linux distros except slim ones such as Alpine. In fact, the whole | Docker crutch IMO is needed specifically to alleviate this | problem. | | 3. > The twelve-factor app stores config in environment variables | | It seems to me much more brittle, as it forces you to store | secrets in envs, which could be less secure, and to abandon | structured file configs, which may enjoy type safety, IDE | autocomplete and automatic parsing. With envs you are forced to | implement parses for non-trivial and non-string config vars | yourself. In fact, envs are often committed into repos as well in | form of dot-env files, so the point about commit-safety is moot | as well. | twic wrote: | > This is incredibly hard to achieve in practice if you're not | running something nix, and even then there are leaks of | dependencies on kernel syscall APIs. | | You're misinterpreting that guideline. The text says (my | emphasis): | | > Most programming languages offer a packaging system for | distributing support libraries, such as CPAN for Perl or | Rubygems for Ruby. Libraries installed through a packaging | system can be installed _system-wide_ (known as "site | packages") | | It's not saying not to depend on the operating system (of which | glibc is part), it's saying not to require particular language | package manager packages to be installed on the machine. | | Agreed that the other ones you mention are silly, though. | Especially the one about environment variables - that isn't | actually reasoned advice, it was just the authors writing down | what was most common in Ruby development at the time, on the | assumption that that must be the best thing to do. | vilunov wrote: | Well, glibc could be considered part of the operating system, | although this too is arguably not correct, because some | technologies go out of the way to not depend on anything | present in the system and be completely self-contained, e.g. | fully statically linked Go binary with no Cgo usage. | | Nevertheless, glibc is not the only system dependency which | is often used by apps, another such example is JVM of a | specific version, which is not tracked by any of the popular | JVM build tools and package managers; and OpenSSL, which is | too installed by the system package manager. | | Dockerfiles exists to fix this by defining all the necessary | installation steps as a sequence of instructions, but this is | far from a proper package manager. | aniforprez wrote: | In my experience, sourcing config from env variables seems | like the best thing to do because you can completely ignore | where the app is running in favor of injecting whatever you | want in any environment of your choosing and your app no | longer needs to care about that. The implication is that | business logic must not include the content of your config or | where it is sourced from. It must simply use the values in | the config. This way my apps could give less of a fart if I | run it as a container in kube, in nomad, in local on | localhost, in a devcontainer, in a directory with vars loaded | using direnv, in vercel/netlify and so on. This also allows | incredible flexibility in how that config is sourced as long | as you simply dump them into the env vars. Want to load | secrets from a .env file on local? Sure. Want to load secrets | from Vault on production? Run a simple script to load vault | secrets onto the env and run your app. | dalyons wrote: | yeah this is the actual point - it makes the code/app | totally portable & decoupled from config. I find it | significantly better than having to have the app code | choose different config based on interrogating facts about | its runtime (eg am i in prod? use this value. am i in test? | use this) | jjice wrote: | I heavily agree. I used to work on a LAMP stack where the | deployment was just dumping the code into an EC2 instance. | All is fine until there's a weird system dependency error | that isn't documented because the AMI being used has just | been hand built over the last three years. Have fun tracking | down that specific PHP system dependency when AL2 goes EOL. I | don't want to write code that doesn't have _documented_ | dependencies on system packages. Even just a Dockerfile | serves as solid documentation on what we're using. | damianh wrote: | "One app - one repo" | | Where did you see that being expressed? | vilunov wrote: | https://12factor.net/codebase | ulizzle wrote: | It says there that a codebase can contain multiple repos. | They don't mean a monorepo when they say codebase | vilunov wrote: | > A codebase is any single repo (in a centralized | revision control system like Subversion), or any set of | repos who share a root commit (in a decentralized | revision control system like Git). | | They do mean that a repo = a codebase. A remark about | "set of repos" is just a technicality of distributed | VCSs, meaning that each copy cloned from a single source | (or from other copies) is a single repo. | samus wrote: | I agree with your view of the first rule and would gladly store | multiple related apps in one repo. No rationale for why one | repo should only containing one app is given, therefore that | rule can be disregarded. | | Dynamic or managed languages can often ignore most of the | hassle with system packages. | brodouevencode wrote: | > 1. One app - one repo. | | There is a U-shaped utility to monorepos. Most projects fall in | the middle somewhere, largely ones managed by independent | engineering teams that have no centralized | platform/devops/whatever-we-are-calling-it-these-days team. | kagakuninja wrote: | They also say every server should be a separate process, which | is debatable. When using languages that lack real threads | (Ruby, Python, etc) you have no choice. | talent_deprived wrote: | > There is nothing fundamentally wrong with multiple apps (as | in separate pods/containers/processes) being developed in a | single repo, as long as they are tightly coupled functionally, | share the release cycle, but still need to be deployed | separately to get advantages of separate processes and | independent scaling. | | We disagree on fundamentals then and I think more of the world | agrees with me and with the 12 factors. | twic wrote: | The big thing missing from this document is justifications for | the rules. It's almost all just rules. Are the rules good? Hard | to say, and this document won't help you find out. | brodouevencode wrote: | If you click on the rule it links to a page that is what you're | asking for. For example: https://12factor.net/backing-services | samus wrote: | Not all the rules are explained on. For example, a detailed | reasoning why there should be only one app per repository is | not provided. It is only stated that it is not the 12factor | way. | twic wrote: | The page you link to does not contain a justification for the | rule. | moondev wrote: | Kubernetes basically forces you to deploy 12fa, using these | guidelines is a pretty good playbook for migrating an existing | application as well. | sergioisidoro wrote: | Twelve factor app: use environment for config | | Docker: Don't use environment for config, it's insecure | | I like and use many of the patterns of 12 factor, but indeed some | of these were written in the context of VPS, where environment is | stable, secure and more constant (unlike containers, where | environment might end up shipped in one of the layers). In the | age of containers, this particular point has been a bit of a | struggle for me. Docker secrets don't always play well, and you | need to do some gymnastics to make it work. | samus wrote: | The basic idea is still valid. You might just have to use a | more appropriate mechanism when using containers. For example, | the explanation of the Config factor explains that a config | file can also be used. | 3by7 wrote: | In retrospect, a better name for that section could have been | "Separate config from code" as it says in one of the first | paragraphs. | chrissoundz wrote: | How are environment variables insecure? | dharmab wrote: | Envvars have much weaker access controls than files; | basically anything in the same PID namespace can read your | envvars. Poke around in /proc/*/environ to see for yourself. | Files can use user permissions and MAC (AppArmor, SELinux, | etc) to secure them against unauthorized processes. | wutwutwat wrote: | If running in a containerized environment ENV is injected | only to the container, at container runtime. If you're | running your containers with a single process, you are | doing the exact access control you just outlined. At that | point what is the difference between a file on disk with | read permissions for the proc owner vs only the proc having | the ENV injected to its shell at runtime? I'd maybe even | say the ENV at runtime is _more_ secure than the chown'd | file on disk because the ENV injected variant is ephemeral | and when that container /proc dies, so does the ENV sitting | in its memory, whereas the other leaves a file on disk | potentially depending on where it was written to, | regardless of who can access it. Then there's the fact that | a lot more people than you think run containers as root so | all file access control goes out the window. | | From a security perspective it is always more secure to | have something only in memory of the running process than | it is to have a file on disk regardless of file permissions | dharmab wrote: | Containers don't enforce that isolation. Another process | can nsenter the container's PID namespace. You also have | issues if your container's PID1 creates subprocesses. | | File are not necessarily written to disk. e.g. the | Secrets CSI Driver loads secrets directly from a secrets | store as virtual files within ephemeral volumes. | jcrites wrote: | Could you elaborate? How are environment variables insecure? If | the secret will be present in the application throughout it's | lifetime, then what's a better alternative? | | Just because a secret is injected into the application as an | environment variable does not mean it's handled insecurely | elsewhere. For example, AWS ECS containers have built-in | support for fetching secrets from Secret Manager at startup and | passing them as environment variables: | https://docs.aws.amazon.com/AmazonECS/latest/developerguide/... | | This fetches the secret at the time the container starts up | (IIRC), and uses the IAM credentials of the running application | to fetch them from Secret Manager (so it must have permission | to the secret). | | The merit of using environment variables seems to depend | entirely on how they are, well, configured. With a mechanism | like this I don't see much disadvantage. (The main disadvantage | I see is that generic malware that attempts to dump environment | variables might capture them, but defending against that threat | is largely obfuscation, unless you aren't storing the secret at | all permanently in memory.) | dathinab wrote: | - any sub process has full unlimited access to env variables | | - env variables are prone to be dumped in various contexts | and might leak secrets to e.g. logs | | - env variables might leak, e.g. in context of docker build | stages etc. (but then using building a docker image to build | both the image and the software is often anyway not a good | idea) | | - env variables are often easily accessible by other | processes | | the method you mentioned of ad-hoc injecting a secret as env | by some form of security manager for containers avoid many | such problems | lazyant wrote: | > - env variables are often easily accessible by other | processes | | A process would need to have the same permission (same | user) or root to read /proc/$PID/environ no? or what | mechanism is there for a process to read another process | env vars (not children processes, that was already | mentioned)? unless of course, a process dumped them in some | world-readable file (like logs as mentioned) or some other | silly way | ezekg wrote: | Exactly. The operating system already offers security for | environment variables: use it. And you get the benefit of | increased security in other places by not sharing users | between applications. | yjftsjthsd-h wrote: | > env variables might leak, e.g. in context of docker build | stages etc. (but then using building a docker image to | build both the image and the software is often anyway not a | good idea) | | Since the rule describes runtime configuration, it | shouldn't be involved with the build process at all | sergioisidoro wrote: | My comment is specific to docker, although environment as a | broader sense can be discussed. | | I remember reading that it is possible to end up in | situations where your environments can end up in the layers | of the docker image. Also, you can read the secrets of a | container with inspect, and apparently linked containers | might be able to access other containers's secrets. | | I think it was this article: https://snyk.io/blog/keeping- | docker-secrets-secure/ | derefr wrote: | Presumably because /proc/$PID/environ exists and can be read | by the user that owns the process -- which means that any | attacker that can figure out how to spawn an arbitrary | subprocess running as the daemon user (a pretty common | vulnerability class!) can exfiltrate all your env-vars. | | It's similar to the reason that you're not supposed to supply | passwords on the command-line (/proc/$PID/cmdline exists), | but instead either read them from stdin, or do the big dance | of | | 1. creating a file that contains the password, is owned by | root, and is 0400; | | 2. having your daemon start off running as root for just long | enough to read the password into process memory; | | 3. then having your daemon drop privileges before doing any | work, so that someone exploiting the daemon _won 't_ have the | privilege as the "do the work" user to read the file with the | password in it. | dathinab wrote: | it's both true | | putting any form of secrets into a env var is deeply insecure | | using env is the most simple uniformly available way to have | configs | | through I would take it a step further, anything which must not | be leaked probably should not be in any config, weather env or | file or similar, it should be injected through other means if | viable | 0cf8612b2e1e wrote: | On the other hand, without platform support there are not a lot | of easy alternatives. It at least encourages separation of | config and code, keeping secrets out of vcs. | wutwutwat wrote: | One could argue that you should never consider any input as | "safe to consume", and if you write defensive app code, would | never consider the ENV to ever be secure or what you expect, | and would therefor sanitize that input before consuming. If | you're blindly trusting any input just because you're single | tenant, you're in for some hard to track down bugs and long | nights when those circumstances one day change due to random | business pivots. | jsight wrote: | Yeah, I've never been a fan of secrets in env vars for this | reason. It is shocking how frequent dumb debug consoles have | accidentally exposed env vars. You really don't want that to | accidentally expose your private keys. | | There's really nothing wrong with secrets mounted on the file | system via k8s. But, of course, all of this depends on your | deployment environment. | | Sometimes env vars are the least bad option, because secrets | really are always hard. | berkes wrote: | > dumb debug consoles have accidentally exposed env vars | | Huh? If the app can read the secret, then the app can... read | the secret. Maybe I'm misunderstanding what you call a "debug | console", but if this is anything running in the app, it can | ... read the secrets. Regardless of their source. | | Or, to put it differently: it matters nothing if your secrets | at rest are stored in a quantum-resistent-encrypted vault, | secrets.yml or ENV vars, if your logging, backtracing or | debug consoles dump them somewhere, you are compromised | regardless. | jsight wrote: | This is absolutely true, but it is far more common for | someone to accidentally leave open a display of env vars | than a display of files. | | I've got this problem to debug in prod, I know, I'll embed | the env vars in the source code of the error page. No big | deal and it might help me debug that! For a dev used to not | using secrets in env vars (for example, when testing | locally), this is an easy mistake. He may even use a third | party library that embeds features like this without | knowing it! Even things like the jmx console can be risky, | since access to that may not relate 1:1 with access to | secrets. | | I've never seen anyone make a similar mistake and | accidentally embed all_my_passwords.ini in their output. | | I must admit that some of what I've said above has become | outdated, since it is now a much more common practice to | embed passwords in env vars than it used to be. | zemo wrote: | 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. | morelisp wrote: | The 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 wrote: | The 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 wrote: | I 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 wrote: | > 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 wrote: | Here 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 wrote: | "5. If any are missing, it fails." | | That's literally all you need to solve the scenario you | described with .env files. | meowtimemania wrote: | The 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 | throw1234651234 wrote: | Exactly, thank you for phrasing it much better than I | did! | Rapzid wrote: | You can also just supply defaults that can be locally | overriden.. Benefit is they are reviewable in the same PR | that adds the code depending on them.. | nickzelei wrote: | I've resulted into a pretty similar setup. | | We use SOPS and the encrypted .env file is stored in VCS. The | key is stored in 1password with instructions on where to | stuff it on your machine. Then you just decrypt the .env file | and you're off to the races. | edwinbalani wrote: | For anyone new to SOPS like I was - | https://github.com/getsops/sops | victorNicollet wrote: | Hard agree. I think it's easy to get stuck on the mental | model that "the configuration value is the secret" (which | means the configuration itself needs special handling), and | the correct mental model should be "the configuration value | is the identifier of the secret", with another system (Azure | Key Vault, etc) being responsible for converting the secret- | identifier into the secret-value. | | My company open sourced the .NET library we use for this: | https://github.com/Lokad/Secrets | geraldwhen wrote: | The corporate VPN and proxy setups tend to fail or be slow. | This would add non-trivial startup time to any app, and | catastrophic startup time to integration tests. | jbotdev wrote: | It 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 wrote: | > 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 [2] | https://github.com/getsops/sops | Spivak wrote: | > 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 wrote: | I'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? | derefr wrote: | My trick for this with k8s Secrets, when there's some | sort of config file that absolutely must be consumed from | disk, is to | | 1. create a Secret that defines the file as a key | | 2. mount that Secret into the container | (.secret.secretName in the volume definition) under an | arbitrary conventional path, e.g. /secrets | | 3. define an env-var _that gives the full path to the | file_ ; where the fallback when this env-var _isn 't_ | defined is to find the file in the working directory with | a conventional filename. | | If your own code uses the file, it can read the path from | this env-var; while if the core of your container is some | opaque tool that doesn't know about the env-var but | _does_ take the file 's path on the command-line, then | you can wrap the tool in an entrypoint script that reads | the env-var and passes it as a command-line arg to the | tool. | | IMHO, this approach is flexible but principle-of-least- | surprise obeying for both development and production | deployment. | inferiorhuman wrote: | That sounds an awful lot like a .env file to me. | pojzon wrote: | yup thats exactly what .env is, and tbh that doesn't | change anything in the bigger picture | kelnos wrote: | > _Now you 're getting away from the spirit of 12factor_ | | The entire point here is that 12-factor isn't the be-all, | end-all, so this is irrelevant. | | > _The intent is for the app to consume the secrets but | have no knowledge or care where they came from._ | | This doesn't really make sense, and is an impossible | requirement. The app will always have to know where | configuration or secrets come from. Environment variables | is just one option of "knowing where they come from". | Choosing file storage is just as valid. | kagakuninja wrote: | I don't use kubernates. We have JVM servers running on | AWS. We load secrets from Secrets Manager. Configs are | mostly HOCON files stored in S3. The knowledge of where | to find them is configured via env vars. | | We use a custom setup in which the config values are | loaded from multiple sources actually, so we could put | everything into secrets manager, or load them all from | env vars or HOCON files. | | If we had to set every config value in ECS / lambda using | env vars, it would be a major pain in the ass, and error | prone. | pojzon wrote: | > We load secrets from Secrets Manager | | And how your apps authenticate to Secrets Manager ? Did | you ever call `env` on a pod that has IRSA configured ? | | This is just a middle step to do exactly the same thing | but instead of using envFromSecret you use envFromSM | maccard wrote: | Not OP but an IAM role with scoped access to secrets. | Better again, using secretsFrom in the task definition | which injects the secret as an environment variable for | you. | redeux wrote: | > somewhat influenced by how Heroku works | | The Twelve-Factor App is marketing content produced by the | former Founder & CTO of Heroku. It's a great piece of content | no doubt, but it should be viewed with that lens. | probotect0r wrote: | If it's marketing content then it's not doing a very good | job. I have known about the 12factor app principles for a | long time, and only found out today that it has ties to | Heroku. | xwdv wrote: | If it is truly harmful, it shouldn't be sitting at the top of | Hackernews. Let's flag it. | zemo wrote: | I... don't think the "flag" functionality is intended to | communicate "this is bad advice". | xwdv wrote: | It is "harmful" advice, not bad. Regardless, why should it | sit on the front page of hackernews? | zemo wrote: | it's really hard for me to express just how much content | hits the front page of HN that, if you follow it, will | make you worse at programming. | v2223943777435 wrote: | i got a ton of value out of reading the comments though | wutwutwat wrote: | Heroku 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 wrote: | yeah 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 wrote: | True. | | 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 wrote: | While 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. | ElevenLathe wrote: | The intent of this part of 12 Factor comes from the Bad | Old Days when devs didn't run their own stuff in | production. There was a dev team who could push code and | cut releases, and an ops team who would then deploy the | releases, and who was paged when things blew up. | | If you store the database hostname/credentials, as an | example, in the "code" (either literally in the app code, | or in a config.ini that lives in the repo and gets baked | into a release), then the ops people can't quickly | repoint the app at a hot-spare database during an | incident: they'll need to edit the repo, push it, cut a | new release, etc. If there is a long build step (as for a | C++ app, for example), then this isn't really tenable | during an outage. If this is in an environment variable, | their normal deployment scripts can make the change for | them. | | I agree that this is probably not necessary anymore if | your team is all wearing both hats (dev and ops), and its | just as quick to make an edit to the repo and cut/deploy | a new release as it would have been for the Ops team to | run their deployment script in the old days. | phendrenad2 wrote: | History repeats itself. Netlify tried this with the MACH | Alliance. | donatj wrote: | The invention of dotenv files just makes me chuckle and seems | to completely miss the point of not putting them in a config | file. | bunderbunder wrote: | dotenv 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. | scooble wrote: | I've read a bunch of tutorials promoting env vars to avoid | secrets being accidentally checked into git. Step 1 is | usually to create a .env file and add it to your gitignore. | rbanffy wrote: | "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 wrote: | The page https://12factor.net/config disagrees with you: | | > The twelve-factor app stores config in environment | variables (often shortened to env vars or env). | rbanffy wrote: | I would assume that is the interpretation back in 2011. | While the mechanism changed, the principle still holds. | lucideer wrote: | > _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 wrote: | As 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 wrote: | Nobody 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 wrote: | > 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 wrote: | It'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 wrote: | > - 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? | zoogeny wrote: | Seems good as a general heuristic but bad as a requirements | checklist. | lhnz wrote: | It's pretty bad that, more than a decade after this was released, | there are detractors for some of the guidelines but yet nobody is | able to point to a singular more modern set of principles. A lot | of our advice is now nuanced and spread out all over the | internet... | qwerty4343 wrote: | It's good to see it coming up again. I hope there will be a | platform among the new PAAS players that is 100% compatible with | the 12-factor app principles. | PaulKeeble wrote: | I have always disagreed most with the config advice. Config ends | up getting defined by a lot of different parties and quite often | by developers and its often best to ship the application with | reasonable defaults and then allow overrides from environment | specific files and then environment variables. This is the most | flexible for most server side applications because you often know | what a setup should be and its best source controlled but secrets | need to be injected at run time. Configuration needs to have | cascading levels to make life easiest in dev, test and production | without enormous setup time. | Kinrany wrote: | You can, and probably should, have reasonable defaults. | | Configuration should be version controlled, but separately from | source code because it describes deployments, not images used | for deployments. | willseth wrote: | Why not also express the defaults as config, or is that what | you meant? I don't think that runs afoul of 12 factor. | schneems wrote: | > Configuration needs to have cascading levels to make life | easiest in dev, test and production without enormous setup | time. | | The backdrop of when the 12factor app was written is that you | can toggle modes like that with RAILS_ENV=test (an environment | variable). | | One way I think of the config section is "does your config | strategy play well with containers?" Once you build an image | you have a static disk state that doesn't persist changes | unless you make a new image. If your config is file based | (only), then to toggle between test and production behavior you | would have to build a whole new image. | | By allowing config to change without the underlying disk, it | helps to isolate changes. Did the app break because something | in the deploy (image generation) broke? Or is it a bad config? | If you decouple image generation from configuration changes it | eliminates that question. | ahtihn wrote: | > Once you build an image you have a static disk state that | doesn't persist changes unless you make a new image. If your | config is file based (only), then to toggle between test and | production behavior you would have to build a whole new | image. | | You could mount a volume with the config file. The nice thing | is that this lets you change the config at runtime (assuming | the app watches for file changes). Env vars cannot be changed | at runtime. | CraigJPerry wrote: | So long as you are systemically protecting against someone | spinning up a QA instance against some Prod resource then it's | probably alright to ship most config with the app. You don't | want to allow a (entirely predictable) human error to cause | 100k auth denied retries against a prod job submission queue | from QA for example. Much config isn't about infra though, it's | often what kind of ResolverStrategy (made up but plausible | sounding name) bean do I want to wire in each env for example. | sethammons wrote: | > application with reasonable defaults | | defaults for dev or defaults for prod :) | | If you say dev, you will eventually break prod. And prod | defaults may not make _any_ sense for dev. | berkes wrote: | > And prod defaults may not make _any_ sense for dev | | They are actually rather dangerous even. You certainly don't | want your dev (or test CI) to reset the database if you are | accidentally connected to prod. Same for email-endpoints, | CDN, a message-bus, etc. | | I've had my share of near-heart-attacks where I send out 10k | emails or thousands of payments _on actual production | services_ because of a spagetti config loaders with stuff | that boils down to `if (getHostname() === "localhost") { | include("dev.json") } else { include("prod.json") }`. | | I'd prefer a hundred .envs and whatnots to avoid just one of | these scares. | porsager wrote: | Would be nice to have a simple term for all these absolutist | ideas about how to solve a Problem. I nominate the term "The Holy | Grail Jail". | | I've actually had great success doing the opposite to most of | these points. | dathinab wrote: | every time I read Twelve-Factor App I'm like who they set up | twelve factor authentication, that's crazy isn't 2FA enough | | then I remember that it's about something else | theusus wrote: | I hate things like these. They just make people architects and | SEs create forceful indirection that creates nothing but burden. | bdcravens wrote: | Perhaps in 2023, but in 2011, we were still at the edge of when | people would deploy by moving folders and individual files via | FTP, hard-coding credentials, and dropping in extracted zip | files as a method of dependency management. | | Of course even then added layers were often considered | "burden", but in general, we need some degree of order lest we | create an unmanageable mess of index.old.3 and files edited | directly on production. | adolph wrote: | _The 12 factor app guidelines are still relevant today since many | software teams are building distributed systems, which require | careful attention to detail as to how services are coupled, | configured, and deployed. The 12 factor app is a wonderful | starting point for best practices. In my experience though they | omit a few facets and leave room for antipatterns in certain | facets._ | | https://smallbatches.fm/5/transcript | | _[00:03:52] Joe Kuttner: But today the infrastructure that we | run on is disposable, right? It 's much more like livestock or | cattle where we can buy new ones when we need one at market and | we can dispose of, you know, something's not working. Right. We | get. Yeah. So it's a very, it's a very different model._ | | _[00:04:07] Joe Kuttner: And that was just emerging when the 12 | factor app was first launched. I think it did a great job of | helping bring people into that state of mind._ | | https://smallbatches.fm/20/transcript | nopurpose wrote: | I wish there was a generic control plane for generating and | shipping config to apps. Kinda what Envoy proxy has, but capable | of shipping arbitrary schema. | | Many complications of config management will go away then. Every | app instances knows just its ID, then everything else (region, | cluster, stage, current experiment, maintenance, anything else) | is discovered by "configd" service and config suitable for that | very instance is returned. Not unlike feature flags, but for | backend services. | | OPA (Open Policy Agent) comes close: it has data sources (so it | can fetch inventory from cloud providers, kubernetes, any other | internal system) and Rego language to program config generation, | but it doesn't have means to notify instances of config updates, | so they have to resort to polling. | wly_cdgr wrote: | "last updated 2017" if you look at the footer | RyeCombinator wrote: | Thought we are up to 15 now? | https://domenicoluciani.com/2021/10/30/15-factor-app.html | freedomben wrote: | Over the years I've had a lot of discussions around 12 factor | apps and encountered a lot of confusion. I find that the | 12-factor site is great, but mainly for people that already | understand _why_ those things are important. | | For people that don't already understand the _why_ behind the | rules, it took more in-depth explanation. For that purpose, I | made the video: "What are 12 Factor Apps and Why Should You | Care?"[1]. I know of a couple of companies that use that for new- | hire orientation for engineers/devops that have said it's been | really helpful. | | Regardless where you get the information, it's worth taking an | hour or two to learn about 12-factor apps. Most of these "rules" | are just things that take awareness and aren't immediately | obvious unless you've learned them all the hard way by making the | mistakes and feeling the pain. | | [1] https://youtu.be/REbM4BDeua0 | commandlinefan wrote: | It's like unit testing. The idea of writing code to test your | code was so blindingly obvious to me from the time I started | programming that I was shocked that it took so long for other | people to pick up on it, but the concept of "unit testing" | started to gain some traction around the late 90's and I was | relieved that somebody with some authority was advocating it. | | But the reason I didn't just do it myself before Kent Beck | published JUnit was because the code I worked on didn't lend | itself well to being controlled by other code. Global variables | everywhere, widely distributed state, dependence on external | systems and specific file system layouts and general disregard | for modularity made it impossible to run anything outside of | the context it was designed in. All of this was "bad design", | but it met deadlines, so everybody did it anyway. I was | _hoping_ that if unit testing gained some traction, programmers | would get away from monolithic design. | | After 25 years of observing unit tests for getters and setters | and then one big unit test that creates an in-memory database | because every function in the app needs a live database just to | run and then gets commented out because it fails, I've lost any | faith that unit testing will ever be more than a meaningless | checkmark that everybody fills out because it's a "best | practice" but nobody actually stops to think why. | berkes wrote: | I'd like to believe that "everybody" and "nobody" in your | story aren't as black-and-white. | | Many people see the value of unit testing. And see how TDD | actually shapes your code to be testable and (accidentally, | well, not really) therefore also cleaner and better | organized. | | I've always said, and will continue to do so: good, | maintainable code, is accidentally also very well testable | code. And vice-versa. And it's not a real accident, if you | think about it. | freedomben wrote: | I've seen similar as well. Aggressive scrum has also made | this much worse by laying all the incentives at "ship now and | let the poor sap later who has to work this figure it out. I | got my 'story points' and shipped so I won't be under the | metrics microscope." Having a general requirement of "each | code change should have tests in order to pass code review" | can definitely help, but it doesn't incentivize _good_ tests, | and IMHO the only thing worse than no tests are bad tests. | throwaway4good wrote: | Holds up well 12 years later. | lakomen wrote: | Not this again. Let the horse die already | commandlinefan wrote: | This horse or any other horse. I read this and I think "this is | good advice, we should follow it." You read it and you think | "this is good advice, we should follow it." And then we both | do, but our interpretations conflict completely so we end up | arguing about the true definition of "implicit existence of | system-wide packages". | robbywashere_ wrote: | Fun to compare this to with how insane deployments are now | featuring kubernetes manifests which only big brains can | understand | mplewis wrote: | What part of the Kubernetes manifest do you think makes | deployments insane? | xdennis wrote: | Not GP, but here's an example I've seen. Kubernetes files are | generated by Jsonnet. It is invoked from makefiles. Makefiles | are spread across different git modules. The scripts require | various Go binaries. Most are installed through a command, | some have to be installed manually. If the version is wrong, | mysterious errors happen. | | I once had a problem with the generated files so I deleted | the generated directory and regenerated everything. Turns out | you can't do that. The generated files are edited, and if you | generate from scratch you've wiped out the manual edits. | | Note that I'm not criticizing Kubernetes here. But when you | have a non-simple system with some missing aspects, some | people take the opportunity to make it even more complex. | pizzaknife wrote: | makefile cackles as it observes the exchange | dang wrote: | Related: | | _Ask HN: Is 12factor.net Still Relevant?_ - | https://news.ycombinator.com/item?id=36283702 - June 2023 (6 | comments) | | _12 Factor App Revisited_ - | https://news.ycombinator.com/item?id=33164407 - Oct 2022 (7 | comments) | | _Twelve-factor app anno 2022_ - | https://news.ycombinator.com/item?id=31225921 - May 2022 (35 | comments) | | _The Twelve-Factor App (2011)_ - | https://news.ycombinator.com/item?id=31198956 - April 2022 (102 | comments) | | _Twelve-factor app development on Google Cloud_ - | https://news.ycombinator.com/item?id=21415488 - Nov 2019 (63 | comments) | | _The Twelve-Factor App_ - | https://news.ycombinator.com/item?id=19947507 - May 2019 (3 | comments) | | _12 Factor CLI Apps_ - | https://news.ycombinator.com/item?id=18172689 - Oct 2018 (247 | comments) | | _12 factor app configuration vs. leaking environment variables | (2014)_ - https://news.ycombinator.com/item?id=15869436 - Dec | 2017 (2 comments) | | _Ask HN: Alternative to Heroku that doesn 't enforce 12-factor_ | - https://news.ycombinator.com/item?id=10628961 - Nov 2015 (1 | comment) | | _The Twelve-Factor App_ - | https://news.ycombinator.com/item?id=10288216 - Sept 2015 (3 | comments) | | _The Twelve-Factor App_ - | https://news.ycombinator.com/item?id=9492120 - May 2015 (2 | comments) | | _Twelve-Factor Applications with Consul_ - | https://news.ycombinator.com/item?id=7780249 - May 2014 (2 | comments) | | _The Twelve-Factor App_ - | https://news.ycombinator.com/item?id=7547687 - April 2014 (1 | comment) | | _Building Twelve Factor Apps on Heroku_ - | https://news.ycombinator.com/item?id=6219444 - Aug 2013 (1 | comment) | | _12 Factor model for architecting SaaS applications_ - | https://news.ycombinator.com/item?id=6060381 - July 2013 (1 | comment) | | _The Twelve-Factor App_ - | https://news.ycombinator.com/item?id=5979452 - July 2013 (1 | comment) | | _12factor: Methodology for Building Software-as-a-Service Apps_ | - https://news.ycombinator.com/item?id=4027026 - May 2012 (1 | comment) | | _Twelve Factors of Web Application Development_ - | https://news.ycombinator.com/item?id=3267187 - Nov 2011 (37 | comments) ___________________________________________________________________ (page generated 2023-10-12 21:00 UTC)