Skip to content
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

Documentation seems wrong, and error message is unhelpful #506

Closed
nhumrich opened this issue Jul 26, 2021 · 21 comments · Fixed by #519
Closed

Documentation seems wrong, and error message is unhelpful #506

nhumrich opened this issue Jul 26, 2021 · 21 comments · Fixed by #519

Comments

@nhumrich
Copy link

nhumrich commented Jul 26, 2021

Hello, I started up an image of rabbitmq, and on the readme it says that you can set the username and password with environment variables:

https://github.com/docker-library/docs/tree/master/rabbitmq#setting-default-user-and-password

But when I do that, I get an error:

error: RABBITMQ_DEFAULT_PASS is set but deprecated
error: RABBITMQ_DEFAULT_USER is set but deprecated
error: deprecated environment variables detected

Please use a configuration file instead; visit https://www.rabbitmq.com/configure.html to learn more

But the url in the error is just a general page for rabbitmq, and doesn't tell me at all how to configure rabbitmq for docker using environment variables. What are the new environment variables?

@wglambert
Copy link

Looks like the documentation needs to be updated for #467
I'll get a PR up shortly 👍

@yosifkit
Copy link
Member

Already open: docker-library/docs#1996

@tianon
Copy link
Member

tianon commented Jul 26, 2021

But the url in the error is just a general page for rabbitmq, and doesn't tell me at all how to configure rabbitmq for docker using environment variables. What are the new environment variables?

The TLDR of the change in #467 is that in 3.9+, there are no environment variables. You should use a configuration file provided either via custom image, bind mount, Docker/Kubernetes config object, etc instead.

@cetra3
Copy link

cetra3 commented Jul 27, 2021

This looks like a breaking change to the docker image but doesn't bump a major semver as I'm assuming this image is tracking the rabbitmq release version. Initial discussion for removing the script is here: #422

For anyone else hitting this issue, you can tag to 3.8 instead of latest / 3 while you migrate to a new way of doing things.

It would have been nice if before making this change that:

  • The readme on docker hub clearly indicates that the env vars were about to be deprecated
  • There is an easy upgrade path for users who are using these env vars (i.e, those using secrets)

@reggermont
Copy link

reggermont commented Jul 27, 2021

This looks like a breaking change to the docker image but doesn't bump a major semver as I'm assuming this image is tracking the rabbitmq release version. Initial discussion for removing the script is here: #422

For anyone else hitting this issue, you can tag to 3.8 instead of latest / 3 while you migrate to a new way of doing things.

It would have been nice if before making this change that:

  • The readme on docker hub clearly indicates that the env vars were about to be deprecated
  • There is an easy upgrade path for users who are using these env vars (i.e, those using secrets)

Totally agree. Deprecated also means "Support will be removed in the future", not "Support is already removed, thx bye"

@sithmein
Copy link

May I ask why this change was made in the first place? Pretty much every Docker image I know can be configured with environment variables (at least the basic settings). And using env variable for configuring containers is the standard approach for containerized applications. Reverting back to configuration files seems like a step back and make using the image considerably more complicated. Building an own image is additional work and requires a place to store it and using bind mounts is not always possible (e.g. if you start a sidecar container from within another container). Personally I believe this change is a huge mistake.

@michaelklishin
Copy link
Contributor

michaelklishin commented Jul 27, 2021

@sithmein it may be the standard approach that works well for some applications. In the context of RabbitMQ,
environment variables are inferior to rabbitmq.conf in many ways:

  • No typing is enforced, env variables are just strings
  • No standard validations can be applied early enough
  • Many end up storing secrets there
  • When troubleshooting, communicating your configuration involves sharing configuration file(s) and half-a-dozen environment variables
  • RabbitMQ and CLI tools can support the same environment variables, causing obscure conflicts that no one can reproduce outside of environments that use a specific image

rabbitmq.conf does not have the first two problems. advanced.config offers value encryption.

RABBITMQ_ERLANG_COOKIE is used by both earlier versions of this image and RabbitMQ CLI tools,
creating obscure shared secret mismatches that wasted a lot of time for a lot of people in the last few years

Heavy environment variable use in this image has proven to be counterproductive time and time again. It was pretty
directly responsible for time-consuming issues that no one
in the broader RabbitMQ community runs into.

Just mount a configuration file (in fact, you can mount a directory of them) and avoid a whole range of "container snowflake" issues. Go with the ecosystem flow, inventing your own means of configuration is entirely uncalled for in this
specific image.

@michaelklishin
Copy link
Contributor

michaelklishin commented Jul 27, 2021

In addition, specific combinations of environment variables produced configuration files that were incorrect. This was not
a one-time issue, as issues in this repository — often used for questions — demonstrate.

When you use rabbitmq.conf you always can set anything that the RabbitMQ version you use supports. When inventing
your own means of configuration you are always catching up.

This list of issues with heavy environment variable abuse is long enough for me. Env variables were never designed to be a
primary way of configuring reasonably complex stateful distributed systems.

@sithmein
Copy link

The thing is we cannot mount a configuration file into the container because the RabbitMQ container itself is started from another container. And bind mount always refer to the host file system which we don't have access to.

What's the difference between providing a configuration file directly or letting the container read environment variables and create a configuration file on the fly? This is what many other official images we are using do.

Anyway, for us it's fine to stick with the 3.8 image.

@michaelklishin
Copy link
Contributor

michaelklishin commented Jul 28, 2021

What's the difference between providing a configuration file directly or letting the container read environment variables and
create a configuration file on the fly

The difference is that if the user provides a file, this image can avoid maintaining an entire complex layer of shell script code.
As mentioned before, there are all kinds of image-specific issues that all come down to the
fact that the entrypoint tried to be smart and effectively invented its own configuration mechanism on top of
env variables and shell script. Such "configuration system" is

  • unique to this image. No other RabbitMQ user, including those who use the K8S Operator for RabbitMQ in a recommended way, would use it
  • prone to errors that can generate an incorrect config or a config that is technically correct but does not do what you expect
  • constantly behind latest available RabbitMQ settings. There is no way this soup of env variables can provide access to 100% of configurable settings in practice, even for TLS listener options alone

We have a few years worth of evidence of these issues. Just go through the issues in this repo or rabbitmq-users group archives.

I find it hard to believe that there is no suitable way to get a configuration file into an image. It can be downloaded from
a URL, mounted, "pasted" from a secret/object, et cetera. If there really is no way, can you share a bit more context
about your environment? I guess your only option is to reinvent the environment variable/shell script soup in your
own image built on top of this one, and maintain it for as long as you need it.

RabbitMQ 3.8 will be out of general support in Jan 2022. Sticking to it for the
long term over newer releases is a losing proposition.

@michaelklishin
Copy link
Contributor

One scenario where we see environment variables seem to be actively with the 3.8 versions of this image is
service containers on GitHub, GitLab and so on. Those containers cannot easily mount files.
They need a dedicated user and perhaps virtual hosts but typically not any RabbitMQ configuration per se.

A small feature in RabbitMQ itself that would simplify initial setup for service containers would be introducing a load_definitions counterpart that uses a remote URL instead of a local file. That would instantly take care of users/virtual host/permission setup, or maybe even topologies if needed: rabbitmq/rabbitmq-server#3249

Assuming that an HTTP API call against the management plugin-enabled container is possible on GItLab and such,
I don't see why it would not be possible to import a basic definition file with users/virtual hosts/permissions without any additional features. Then simply use that user
in your suites, creating new users over remote guest access has been the recommended way for many years.

@marcwittke

This comment has been minimized.

@nhumrich
Copy link
Author

nhumrich commented Aug 2, 2021

find it hard to believe that there is no suitable way to get a configuration file into an image. It can be downloaded from
a URL, mounted, "pasted" from a secret/object, et cetera.

I think the biggest problem with this change is that you haven't updated the documentation at all to help those who don't understand docker as well. Literally none of these options are present in the documentation. The documentation says "get the config file there", with no path on how. For those coming from 3.8, there is essentially no upgrade path, without making them spend hours on learning docker/rabbit deeper.

I think a section in the documentation that shows an example of a config file, and a couple examples of how to get it to the right place, would go a long way.
For example, you say the config file can be downloaded from a URL, I have no idea how to do that, its not listed in the documentation at all, but that would probably solve my problems and a lot of people on this thread. If you reply in this thread with how, I would be willing to make the actual change to the documentation.

@eriksw
Copy link

eriksw commented Aug 2, 2021

RabbitMQ 3.8 will be out of general support in Jan 2022. Sticking to it for the
long term over newer releases is a losing proposition.

Then give us a reasonable way to configure it in environments where mounting a configuration file is not possible.

Assuming that an HTTP API call against the management plugin-enabled container is possible on GItLab and such...

This is not possible in ECS. I would have to run a sidecar container just to serve the config file to rabbitmq.

@tianon
Copy link
Member

tianon commented Aug 2, 2021

For users who want to rely on the old behavior, what I would recommend is taking the old shell script that's currently in 3.8, and building your own 3.9 image that includes it -- most of it should still work (and you can remove the deprecation warning too). By doing so, you'll be taking over continuing maintenance of that (frankly fragile) script, and can keep that behavior as long as you want. If you want a simpler solution, writing a script that only supports the subset of variables you actually use would be pretty trivial (echo "foo.bar.baz = $FOO_BAR_BAZ" >> /etc/rabbitmq/rabbitmq.conf).

@michaelklishin
Copy link
Contributor

Then give us a reasonable way to configure it in environments where mounting a configuration file

@eriksw why are you so hell bent on using environment variables? We have explained how they are objectively inferior to a validated, type-safe[r] configuration format that the entire RabbitMQ ecosystem already uses.

This is not possible in ECS. I would have to run a sidecar container just to serve the config file to rabbitmq

Sounds like a reasonable solution to me. Less effort than maintaining the environment variable soup for the maintainers of this image
or anyone who builds on top of it.

@nhumrich
Copy link
Author

nhumrich commented Aug 9, 2021

why are you so hell bent on using environment variables? We have explained how they are objectively inferior to a validated, type-safe[r] configuration format that the entire RabbitMQ ecosystem already uses.

Because environment variables are how the entire docker ecosystem works. Fits the bill for 12-factor apps. And in almost all cases, the only configuration people want on this container is username/password. Surely, you dont need a full config file or type-safety, for those simple things.

@marcwittke
Copy link

Because environment variables are how the entire docker ecosystem works

... the whole SaaS ecosystem works ... +1 for citing the 12 factor app spec.

Honestly, by killing this feature you are doing something fundamentally wrong, when it comes to a containerized environment. Blaming your own struggle to maintain it is no justification for killing a feature that is fundamental from devops point of view. Sure, you are right with all those workarounds, but if you think these should become first class citizen, you are failing to understand what smooth devops is about.

@stormmuller
Copy link

Is there not a sensible middle ground here? Docker has a way of mounting in config files.

Maybe all sensitive/frequently changing configurations could be set using environment variables. And the rest could exist in the config file?

Also considering that the config file has type safety and validation in place. Could the env vars not just be injected into the file before validation?

@marcwittke
Copy link

marcwittke commented Aug 11, 2021

That's what the .net configuration basically does. A json configuration file like this

"ConnectionStrings": {
    "Default": "Server=localhost;Database=MyDevDb;User=sa;Password=s3cret"
  }

can just be overridden by setting an environment variable

SET ConnectionStrings:Default="Server=prod.sql.domain.com; ... "

or

export ConnectionStrings__Default="Server=prod.sql.domain.com; ... " (posix systems)

If you fail passing the type check after reading those config sources the error will be the same, no matter whether you provided the bad value via config file or env variable.

@marcwittke
Copy link

❤️ 👍 for rabbitmq/rabbitmq-server#3299

thanks guys, this is the sweet spot between simple use cases via env variables and advanced use cases via config (and various blends between)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.