Include --mix-env value to the release/upgrade name #87

Closed
gaynetdinov opened this Issue May 18, 2016 · 16 comments

Comments

Projects
None yet
2 participants
@gaynetdinov
Contributor

gaynetdinov commented May 18, 2016

Hello.

Currently if I build a release/upgrade with --mix-env=staging and --mix-env=prod there is no way to distinguish these two releases.

Say, I built a release with --mix-env=staging, then somebody ran mix edeliver build release --mix-env=prod, given that master branch hasn't changed since a release for staging was built, the new release for prod will override staging release and there is no way to determine for which mix environment this release was built. This situation already happened to me, when I deployed a release to production, which was built for staging mix environment.

Is it possible to include a --mix-env value to a release/upgrade name?

Thanks!

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 18, 2016

Contributor

Hi. If only the configuration is different for the different environments, I would recommend to not include the config into the release, but link it and install different configurations on staging and production hosts. This enables you to test and deploy exactly the same release on/to different environments and always use the correct config.
But in the case that also the release content would be different, we could add the ability to append the mix env to the release version to the auto versioning feature, e.g like AUTO_VERSION=...+mix-env.

Contributor

bharendt commented May 18, 2016

Hi. If only the configuration is different for the different environments, I would recommend to not include the config into the release, but link it and install different configurations on staging and production hosts. This enables you to test and deploy exactly the same release on/to different environments and always use the correct config.
But in the case that also the release content would be different, we could add the ability to append the mix env to the release version to the auto versioning feature, e.g like AUTO_VERSION=...+mix-env.

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor

I tried to use approach with sys.config, but I couldn't make it work.

As I understood, I need to specify file location in the .deliver/config and then create such file on my target host(staging/production/qa), put necessary configuration there and during deployment it should somehow magically fetch config parameters from this file.

Wiki page says that .deliver/config should look like this:

# .deliver/config
APP=my_app
LINK_SYS_CONFIG=/etc/my_app.config

but shouldn't it look like this?

# .deliver/config
APP="my_app"
LINK_SYS_CONFIG="/etc/my_app.config"

Does it make a difference?

Also, would this technique work with custom env variables? I have custom QA deployment environment.

And I really don't get how does it work. As I understand mix edeliver deploy release to qa just copies chosen release to a target host and unpacks it. Then I run mix edeliver restart qa to (re)start release. On which step the magic about getting necessary config parameters from file located in LINK_SYS_CONFIG kicks in?

These two sentences do not make sense to me:

The sys.config file is usually generated during compile time from the $APP/config/config.exs merged with the $APP/config/production.exs and is replaced by the link. The generated sys.config can be used as template for the custom configs used as link destination on each host.

Should LINK_SYS_CONFIG point to some specific path or file can be located anywhere?

Sorry, I'm really confused. Can you please help me?

Contributor

gaynetdinov commented May 25, 2016

I tried to use approach with sys.config, but I couldn't make it work.

As I understood, I need to specify file location in the .deliver/config and then create such file on my target host(staging/production/qa), put necessary configuration there and during deployment it should somehow magically fetch config parameters from this file.

Wiki page says that .deliver/config should look like this:

# .deliver/config
APP=my_app
LINK_SYS_CONFIG=/etc/my_app.config

but shouldn't it look like this?

# .deliver/config
APP="my_app"
LINK_SYS_CONFIG="/etc/my_app.config"

Does it make a difference?

Also, would this technique work with custom env variables? I have custom QA deployment environment.

And I really don't get how does it work. As I understand mix edeliver deploy release to qa just copies chosen release to a target host and unpacks it. Then I run mix edeliver restart qa to (re)start release. On which step the magic about getting necessary config parameters from file located in LINK_SYS_CONFIG kicks in?

These two sentences do not make sense to me:

The sys.config file is usually generated during compile time from the $APP/config/config.exs merged with the $APP/config/production.exs and is replaced by the link. The generated sys.config can be used as template for the custom configs used as link destination on each host.

Should LINK_SYS_CONFIG point to some specific path or file can be located anywhere?

Sorry, I'm really confused. Can you please help me?

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

Usually the the sys.config - which contains the configurations for all applications running in the release - is included in the release tar which is copied and extracted on the deploy hosts. The same applies also for the vm.args containing the erlang vm configuration for the release. They are usually located at $DELIVER_TO/$APP/releases/<version>/sys.config or .../vm.args respectively.

This does not make sense if you need different configurations for different deploy hosts, otherwise you would need to generate and deploy different releases.

When using LINK_SYS_CONFIG while building the release with edeliver, your config is not included into the release but just a link pointing to a sys.config file on your deploy hosts, which then can have different content on different deploy hosts.

Because the sys.config contains erlang terms and is generated from the config/config.exs and the config/<env>.exs file for elixir projects, you might want to use the generated sys.config as template
instead of creating a config from scratch. E.g. you can copy the generated config from $BUILD_HOST:$BUILD_AT/rel/$APP/releases/<version>/sys.config to my-production-host-01:/etc/sys.config and my-production-host-02:/etc/sys.config and just change some values and then build and deploy the release while LINK_SYS_CONFIG is set to /etc/sys.config.

Then the same release on my-production-host-01 would use a different config for the applications (and/or erlang vm) as the release on my-production-host-02, but you are able to deploy exactly the same release. This also allows to test exactly the same the release e.g. on a staging host before deploying it to production hosts or some other environment.

Contributor

bharendt commented May 25, 2016

Usually the the sys.config - which contains the configurations for all applications running in the release - is included in the release tar which is copied and extracted on the deploy hosts. The same applies also for the vm.args containing the erlang vm configuration for the release. They are usually located at $DELIVER_TO/$APP/releases/<version>/sys.config or .../vm.args respectively.

This does not make sense if you need different configurations for different deploy hosts, otherwise you would need to generate and deploy different releases.

When using LINK_SYS_CONFIG while building the release with edeliver, your config is not included into the release but just a link pointing to a sys.config file on your deploy hosts, which then can have different content on different deploy hosts.

Because the sys.config contains erlang terms and is generated from the config/config.exs and the config/<env>.exs file for elixir projects, you might want to use the generated sys.config as template
instead of creating a config from scratch. E.g. you can copy the generated config from $BUILD_HOST:$BUILD_AT/rel/$APP/releases/<version>/sys.config to my-production-host-01:/etc/sys.config and my-production-host-02:/etc/sys.config and just change some values and then build and deploy the release while LINK_SYS_CONFIG is set to /etc/sys.config.

Then the same release on my-production-host-01 would use a different config for the applications (and/or erlang vm) as the release on my-production-host-02, but you are able to deploy exactly the same release. This also allows to test exactly the same the release e.g. on a staging host before deploying it to production hosts or some other environment.

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor

Thanks for the great explanation!

So using this approach you cannot change any of your config parameters(even those which are common for all environments) for staging/production. To change those params you would need to go to staging/production host and change config there manually, which is not very convenient from my point of view.

Do I understand correctly that if I put LINK_SYS_CONFIG to the .deliver/config, ls -la inside releases/<version> should display sys.config as a symlink which points to file which I specified? I'm asking because I still can't get it working. I added LINK_SYS_CONFIG to the config and after deployment I still see generated sys.config instead of sys.config which I have on target host. How can I debug it?

Contributor

gaynetdinov commented May 25, 2016

Thanks for the great explanation!

So using this approach you cannot change any of your config parameters(even those which are common for all environments) for staging/production. To change those params you would need to go to staging/production host and change config there manually, which is not very convenient from my point of view.

Do I understand correctly that if I put LINK_SYS_CONFIG to the .deliver/config, ls -la inside releases/<version> should display sys.config as a symlink which points to file which I specified? I'm asking because I still can't get it working. I added LINK_SYS_CONFIG to the config and after deployment I still see generated sys.config instead of sys.config which I have on target host. How can I debug it?

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor

Maybe adding --mix-env value to a release name might be an option for those, who want to build release per environment. How hard would it be to add such feature?

Contributor

gaynetdinov commented May 25, 2016

Maybe adding --mix-env value to a release name might be an option for those, who want to build release per environment. How hard would it be to add such feature?

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

Actually I addded it already, just have to push it:

Contributor

bharendt commented May 25, 2016

Actually I addded it already, just have to push it:

bharendt added a commit that referenced this issue May 25, 2016

Allow to append `MIX_ENV` as metadata to version
when using auto-versioning option `mix-env`. See #87.
@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

But I still think building different releases for different environments is quite dangerous in case of a release would be deployed to a wrong environment. And also because it would not be possible to test exactly the same release which would be deployed to production e.g. on a testing / staging environment.

Contributor

bharendt commented May 25, 2016

But I still think building different releases for different environments is quite dangerous in case of a release would be deployed to a wrong environment. And also because it would not be possible to test exactly the same release which would be deployed to production e.g. on a testing / staging environment.

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

If only some few values of the sys.config are different on different deploy hosts / environments, you can also embed the sys.config into the release which is generated from the config/config.exs and config/<env>.exs and override just some values by providing an additional config on the deploy hosts. This can be done by adding an additional -config /etc/additional.config line to the vm.args.

Since you cannot provide a custom vm.args file to exrm, you would need to link that vm.args file then instead of the sys.config using the LINK_VM_ARGS env in your .deliver/config.

Contributor

bharendt commented May 25, 2016

If only some few values of the sys.config are different on different deploy hosts / environments, you can also embed the sys.config into the release which is generated from the config/config.exs and config/<env>.exs and override just some values by providing an additional config on the deploy hosts. This can be done by adding an additional -config /etc/additional.config line to the vm.args.

Since you cannot provide a custom vm.args file to exrm, you would need to link that vm.args file then instead of the sys.config using the LINK_VM_ARGS env in your .deliver/config.

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor

Oh, that sounds exactly what I need, thank you, I'll try to use vm.args linking.

Contributor

gaynetdinov commented May 25, 2016

Oh, that sounds exactly what I need, thank you, I'll try to use vm.args linking.

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor
additional configs added to a linked vm.args are lost after a hot code upgrade. these configs must be reloaded after a hot code upgrade

It means that after an upgrade, Application.get_env(:my_app, :my_additional_config) will return nil? How would I reload my additional config?

Contributor

gaynetdinov commented May 25, 2016

additional configs added to a linked vm.args are lost after a hot code upgrade. these configs must be reloaded after a hot code upgrade

It means that after an upgrade, Application.get_env(:my_app, :my_additional_config) will return nil? How would I reload my additional config?

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor

https://github.com/boldpoker/edeliver/blob/master/lib/exrm/plugins/link_vm_args.ex#L8

Does env: :prod mean that linking would work only on prod mix environment?

Contributor

gaynetdinov commented May 25, 2016

https://github.com/boldpoker/edeliver/blob/master/lib/exrm/plugins/link_vm_args.ex#L8

Does env: :prod mean that linking would work only on prod mix environment?

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

Yes, but I think it makes sense to remove that restriction. I think it was added to avoid linking in :dev env, but this can also be easily avoided by just not setting the LINK_VM_ARGS env then, so I will remove that:

Contributor

bharendt commented May 25, 2016

Yes, but I think it makes sense to remove that restriction. I think it was added to avoid linking in :dev env, but this can also be easily avoided by just not setting the LINK_VM_ARGS env then, so I will remove that:

bharendt added a commit that referenced this issue May 25, 2016

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

Not sure whether this is fixed already at the latest otp version, but when using additional configs you might need to load them again during the hot code upgrade e.g. by an upgrade instruction like that:

 % relup
 {apply,{'Elixir.MyModule',load_additional_config,[<<"/etc/additional.config">>, my_app]}},
  # MyModule
  def load_additional_config(file_name, application) do
    case :file.consult(file_name) do
      {:ok, [content = [{_,_}|_]]} ->
        case List.keyfind(content, application, 0) do
          {application, configs = [_|_]} ->
            for {key, value} <- configs do
              Application.put_env(application, key, value)
              Logger.info "Loaded new value for app config '#{inspect key}' of #{inspect application} application."
            end
            :ok
          _ -> Logger.error "No additional configuration for app #{inspect application} found in file #{inspect file_name}."
        end
      _ -> throw "Failed to load additional config #{inspect file_name}"
    end
  end
Contributor

bharendt commented May 25, 2016

Not sure whether this is fixed already at the latest otp version, but when using additional configs you might need to load them again during the hot code upgrade e.g. by an upgrade instruction like that:

 % relup
 {apply,{'Elixir.MyModule',load_additional_config,[<<"/etc/additional.config">>, my_app]}},
  # MyModule
  def load_additional_config(file_name, application) do
    case :file.consult(file_name) do
      {:ok, [content = [{_,_}|_]]} ->
        case List.keyfind(content, application, 0) do
          {application, configs = [_|_]} ->
            for {key, value} <- configs do
              Application.put_env(application, key, value)
              Logger.info "Loaded new value for app config '#{inspect key}' of #{inspect application} application."
            end
            :ok
          _ -> Logger.error "No additional configuration for app #{inspect application} found in file #{inspect file_name}."
        end
      _ -> throw "Failed to load additional config #{inspect file_name}"
    end
  end
@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 25, 2016

Contributor

Now after deployment I can see that vm.args is actually a symlink which points to my version of vm.args with -config option to load additional config. The problem is that my additional config is not loaded. If I run ./bin/my_app remote_console and ran Application.get_env(:my_app, :my_additional_config) it returns nil.

I checked that after changing sys.config and restarting a release, new changes from sys.config are applied. But any changes in my additional config file are not applied after release restart. It seems like vm.args is ignored at all, because I can even remove this file and then restart the release without any problem, run remote_console, etc. Of course I cannot start a release without sys.config.

Contributor

gaynetdinov commented May 25, 2016

Now after deployment I can see that vm.args is actually a symlink which points to my version of vm.args with -config option to load additional config. The problem is that my additional config is not loaded. If I run ./bin/my_app remote_console and ran Application.get_env(:my_app, :my_additional_config) it returns nil.

I checked that after changing sys.config and restarting a release, new changes from sys.config are applied. But any changes in my additional config file are not applied after release restart. It seems like vm.args is ignored at all, because I can even remove this file and then restart the release without any problem, run remote_console, etc. Of course I cannot start a release without sys.config.

@bharendt

This comment has been minimized.

Show comment
Hide comment
@bharendt

bharendt May 25, 2016

Contributor

This might be an exrm issue. Does your exrm version create a running-config folder when you start the release? It might help to delete it (it will then be recreated, but I think with the content of the linked files) or to delete the files in it and link the vm.args there too.

Contributor

bharendt commented May 25, 2016

This might be an exrm issue. Does your exrm version create a running-config folder when you start the release? It might help to delete it (it will then be recreated, but I think with the content of the linked files) or to delete the files in it and link the vm.args there too.

@gaynetdinov

This comment has been minimized.

Show comment
Hide comment
@gaynetdinov

gaynetdinov May 26, 2016

Contributor

It worked when I deleted running-config folder and restarted a release.
But once I deployed a new release, running-config didn't get updated with new vm.args.
So maybe indeed it is exrm feature then :(

And upgrade uses vm.args from running-config, so it replaces vm.args which is symlink with version from running-config.

Contributor

gaynetdinov commented May 26, 2016

It worked when I deleted running-config folder and restarted a release.
But once I deployed a new release, running-config didn't get updated with new vm.args.
So maybe indeed it is exrm feature then :(

And upgrade uses vm.args from running-config, so it replaces vm.args which is symlink with version from running-config.

@bharendt bharendt closed this Aug 11, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment