Creating different configurations for deploy?

phoenix

#1

Are arbitrary configurations allowed? Can I create “staging”, “pre_staging”, “best_release” and so on? Any configuration of my choice.

I’ve created one called “staging” by:
– passing the variable MIX_ENV=staging to systemd service
– creating 2 additional config files: staging.exs and staging.secret.exs included in it.

And I’ve deployed it on a different server with the domain name “staging.my_domain.com”. However, it didn’t work.

Does Phoenix support such configurations? Does it support only 3 ones: prod, dev and test?

Do I have to use “prod” even on staging? + Env. variables


#2

What you have done is the way to go when working with different environments, yes.

So what exactly do you mean by “did not work”?

Can you show us some error messages, code, etc?


#3

Does Phoenix support them? Where is it specified in the documentation? Will it load an appropriate config file, say, “my_new_environment.exs” if my current environment is my_new_environment?


#4

They are part of mix not Phoenix. Phoenix does not even know in which env it was built.

As I said earlier please provide details about what is not working as you expect it.


edit

To clarify:

Mix is the build tool and the configuration is executed and generated during its run time. It gets injected into the applications BEAM-environment and can’t be changed without recompiling the application.

Mix reads from the file config/config.exs, and nothing else. It is convention though, to have import_config "#{Mix.env}.exs" as the last line, to load additional configuration that is specific to the targetted MIX_ENV. In the same manor the config/prod.secret.exs is read from config/prod.exs usually: import_config "prod.secret.exs".

There is not implicit magic happening to determine which config to read. You have to write the code for yourself, and you make your and other people life easier by following the conventions I briefly explained in the last paragraph.


#5

I just realise this… MIX_ENV is only relevant when you run your application through mix. So if you have built a release/package/binary on another computer whith MIX_ENV=dev, then the binary will have all the dev stuff included and not further look at the environment variable.

Setting MIX_ENV in the systemd unit will only work when you run mix as target. This is not the idiomatic way to go though.

You should MIX_ENV=staging mix how_you_build_your_stuff_previously and then push the resulting binary. It will have the staging related configuration.


#6

In my view you’re conflating build environments with deployment environments. test vs dev vs prod is a matter of build environment, where as staging vs production is a deployment environment.

The purpose of a staging environment is to validate the artifact that you want to deploy to production. This means that you want as identical of an artifact as possible to be deployed to staging and production. Consequently I think that you should always build for MIX_ENV=prod whether in staging or production. Different environment values can set via environment variables. Ideally you’re using releases and in such cases you can deploy literally the same .tar.gz file to both staging and production.


#7

How to set the environment in this case then?


#8

In the exact same post you are citing, I explained how one should do it:

But I have to admit, @benwilson512 is totally right by saying that prod, dev, test, and doc is usually enough and you should use prod on staging as well and read runtime dependant configuration by other means (environment variables, files, KV stores, etc).


#9

I’m using edeliver and distilery for deploying, how can I use mix instead?


#10

For me - not as I’ll need to show an additional debug information in “staging” on an html page. Namely:

<%= if Mix.env() == :staging do %>
  <%= render_debug_info %>
<% end %>

If I go with what I’ve been suggested above, I’ll have to create an env variable “CURRENT_ENV” on a server which won’t be wise.


#11

distillery is responsible for that. You should be able to find the necessary information in the [documentation], but after skimming it, it should be easy as I told earlier: MIX_ENV=staging mix whatever_you_did_before


#12

Don’t do this. This introduces a runtime dependency to mix, which usually is not available, since it is a build tool.

You could have something in your config like this:

config :my_app, Debug,
  show_additional_info: Mix.env in [:staging, :dev]

Then your snippet could look like this:

<%= if Application.get_env(:my_app, Debug)[:show_additional_info] do %>
  <%= render_debug_info %>
<% end %>

And instead of calling Application.get_env(:my_app, Debug)[:show_additional_info], you could introduce a helper function in MyAppWeb.HTML.Helpers and extend MyAppWeb.view/0 to import it in every view…


#13

How is it going to work if I run my app via systemd, not via mix? In my case on staging it’s still getting detected as production.


#14

You build your app via mix: MIX_ENV=staging mix whatever_you_do_tobuild_and_release_your_app.

You get a tarball out of this, which is permanently imbued with the staging environment.


#15

I build it with

mix edeliver build release

you mean that I should call it as MIX_ENV=staging mix edeliver build release?


#16

exactly

But as I said earlier, you you should do it via config, not via build environments


#17

In order to be able to use it in the config, I must pass MIX_ENV=staging to mix edeliver build release. What do you mean by “you should do it via config”?


#18

Similar to what I have drafted in Creating different configurations for deploy? you should do it in the config, but actually in a way that does not actually depend on the MIX_ENV.

Perhaps make it dependant on the value of an environment variable or the abscense thereof?