-
Notifications
You must be signed in to change notification settings - Fork 197
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Environment variable support for configuration #1049
Comments
Hmm, as in an environment variable setting the location of the config file, or specific config entries being populated by env variables? If the latter, there may be a way to do that already via yaml's weird builtins |
The second. I think kodah might have mentioned something relevant? |
Yeah if we can make it clean and simple then coolcool. Having a separate If we don't find a nice clean yaml way to do this and still want to support it: Rather than e.g. what we did for the secret cloak key env var, if we do end up supporting this we can just skip the config file altogether and have ora just load the |
That would be ideal for most things. However, I do see one issue where this becomes a bit difficult, which is the list/dict variables, like the This would mean users would only have make a ConfigMap for the things they want to override, like the above variables. I realize that this may also complicate things, but I think this may be a cleaner solution given you'd otherwise have to deal with how to load lists/maps from environment variables. |
Sounds like you could do this externally with templating/scripting? |
A real-world example: our integration test suite can modify the config programmatically from Python, then dump it as JSON for consumption by Oragono (since valid JSON is valid YAML). |
I would like to avoid overriding the entrypoint of the oragono container, and there's not really a way to automatically template or script configs without adding all the necessary components into the Docker container. |
Anyway the Currently, it is not obvious how to launch the project with docker-compose. |
I'm a fan of twelve-factor apps -- I think configuration is the only facet of that where Ora really falls down. Using something like https://github.com/caarlos0/env it could be fairly straight-forward to add some extra tags to the config struct and some parsing logic. I'm not sure how it should interact with the yaml config if it exists - the easiest way is probably to just have a flag to switch entirely between them. Then the docker entrypoint can default to using that flag and the compose file can include the necessary vars. If there were strong objections to doing that then it could be done in the existing entrypoint script which already does some config munging to set the oper password. I feel like that would get very messy very quickly, but it'd be nicer than end-users trying to do their own versions and having to override the entrypoint and keep it up-to-date. (I'd much rather get rid of that shell script entirely rather than make it more important, so we can avoid having a shell and all its accoutrements in the container). |
This looks like a templating problem to me, tbh Just my 2c |
I'll think more about this; I'm not really up to date on best practices with Docker at all. In particular, I don't understand the tradeoffs between putting things "inside" and "outside" the container. The My main concern is that environment variables don't seem like they can be as expressive as YAML, or at least not without sacrificing cleanliness and visibility. If I squint, I can see a solution where we have environment variables like |
Oh, by the way, any thoughts on the narrow issue of moving |
Environmental variables allow for small/incremental changes, and are natively supported by container orchestrators like kubernetes. You can maintain plain text config files outside of that, and you can write some tooling to automate that, but the more you go that way the more you're going against the grain and losing benefits. e.g. you can get ora running right now by doing
whereas with a config file it's:
Running multiple instances with small differences (e.g. different hostnames) is obviously a lot easier with env vars, as is keeping track of state (I can see exactly what env vars each container is running with, whereas I can only see the current state of the config file and hope the instances have been rehashed since it last changed). Finally, upgrading feels a lot nicer with env vars (the base image defines some new defaults, I override them if I want) vs config files (I have to manually merge the new config fields, or start from a new default config, or bury my head in the sand and ignore them; if the config file has incompatible changes I need to manage the editing and the upgrading of the containers in sync, etc).
Yes, for sure. I wouldn't try and configure, say, haproxy using env vars, but I think Ora's config is not actually that complex? If you flatten all the namespacing I think there's only a few bits that wouldn't fit straight into a KEY=value or KEY="value1 value2 value3" structure. I'm having a hard time deciding how messy that would make the current config code without actually giving it a try...
The entrypoint is just the executable that's started when the container starts. Ideally for a go app it'd just be the statically compiled binary, and the image would have almost nothing else in it. In practice, we have a small script as the entrypoint that (if needed) installs a default config, generates a random oper password, creates self-signed certs, then launches oragono itself. If we didn't want Ora itself to worry about environment variables, this script could potentially edit the config if there are env vars present, but that brings its own world of mess (and would probably be better done in python not shell script, which then drags python into the image as well...)
I'm personally ambivalent. I'd usually put it at the root for my projects, but it's no skin off my nose if it's elsewhere and pointed at by the README (as it is now for Ora). Some software has example compose files inline in the docs or on the website, it's not a hard and fast rule that it should exist in the root of the repo. (Thank you for attending my TED talk on environment variables.) |
Thanks for this very detailed analysis, I learned a lot :-) This side-by-side comparison (for changing the server name) seems to be eliding details that would be necessary for actual productionization. You wouldn't actually have important configuration data floating around on a command line somewhere, you'd have it in some kind of versioned file (I think this is the
I don't think this accurately reflects real-world issues with upgrading Oragono. In particular:
Anyway, as long as I can get it to work in a reasonably clean way with |
Oper blocks (which came up earlier as part of hashbang's use case) are a good example of something that doesn't fit neatly into this framework --- hence Ryan's interest in "include" directives or the equivalent. |
@csmith: just wanted to get your opinion on the proposal ( |
I don't think this is a good idea. Usually you'd see e.g. comma separated values; or perhaps JSON; or they're left out of env var support. |
All valid JSON is valid YAML, so that seems fine, no? |
I'd like more feedback on above proposal if this is going to make it into 2.4 :-) |
TL;DR: Sounds great! 👍 Sorry for not replying earlier. I was completely swamped with work at the time and then, well, forgot about it :)
Yes, fair point, it's slightly more complex, but it still basically comes down to something like "configure things via a standard key/value method" vs "figure out whatever particular config format this app is using, where it needs to be placed on the file system, etc". Honestly I'm probably being a bit quixotic here - if you're setting up oragono it's likely something you care about and don't mind spend time configuring -- and the config format is actually quite nice -- as opposed to, say, a random dependency-of-a-dependency that requires you to configure it in XML and you really can't be bothered with that kind of nonsense.
Again, fair points. I was speaking in mostly hypotheticals and you've taken good care to avoid the problems there.
As a minor point, I'd much prefer if they could be styled like Using YAML values seems fine to me. I believe most of the simple options will "just work" because plain strings/numbers/bools are all valid YAML? e.g. If you do want to put the more complicated stuff in environment variables it's not actually that inelegant if it's yaml on both ends (which is true for docker-compose and k8s). You can do something like: environment:
ORAGONO_OPERS: |
chris:
class: "server-admin"
whois-line: "etc"
slingamn:
class: "etc"
ORAGONO_SOMETHING_ELSE: "..." (Where the Obviously that's pushing what's sensible and personally I'd probably be reaching for the proper config at that point, but it works and isn't hideous.
I think it's fine to have the option. The stuff on the more complex-end of the spectrum like oper blocks won't be everyone's cup of tea, but strings/bools/ints/etc will just work, and lists using the JSON-esque syntax of |
Thanks!
The motivation for the other syntax was that it would be easier to parse --- in particular, you could split on |
Ah, yeah, I wasn't sure if you were planning to iterate the env vars and map them onto the config struct, or iterate the config struct and look for matching env vars. Alternatively what about dropping dashes entirely, then |
Ah, good point about I'm looking for a solution where no special casing is required at all, and the config handling code can process environment variables based only on the preexisting struct tags and the I think this would work for me: |
thank. ❤️
cc @daurnimator
The text was updated successfully, but these errors were encountered: