|
| 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) |