Setting an environment variable before initial push of application

2,121 views
Skip to first unread message

Mike Youngstrom

unread,
Aug 19, 2013, 6:35:51 PM8/19/13
to vcap...@cloudfoundry.org
It is great that the stagers now expose environment variables mapped to an application.

However, this seems to have exposed a bit of a chicken and egg problem with cf push.  Is it possible to set environment variables with cf before or during the initial push of a new application?  Perhaps similar to service bind and creation at cf push time?  Are there plans to add such functionality to cf?

Mike

mariash

unread,
Aug 20, 2013, 1:18:37 AM8/20/13
to vcap...@cloudfoundry.org
Mike, if you want to push with environment variables set you can use manifest file

http://docs.cloudfoundry.com/docs/using/deploying-apps/manifest.html

The other way is to push without start `cf push --no-start`, then `cf set-env` and then `cf start`. 

-Maria

Dr Nic Williams

unread,
Aug 20, 2013, 10:55:49 AM8/20/13
to vcap...@cloudfoundry.org
Mike, what might be an example of env variables that you'd only want to expose at compile/build time, but would be bad if they were also exposed at run time; and vice versa?

Nic


To unsubscribe from this group and stop receiving emails from it, send an email to vcap-dev+u...@cloudfoundry.org.



--
Dr Nic Williams
Stark & Wayne LLC - consultancy for Cloud Foundry users
twitter @drnic

James Bayer

unread,
Aug 20, 2013, 11:14:58 AM8/20/13
to vcap...@cloudfoundry.org
if this is an ongoing problem, you can use scripts in you app's .profiled to have control over env variables. i'm not sure if the .profiled scripts get called during staging. one thing we could consider is setting an env variable boolean so that the processes know whether it is "staging" time vs "runtime".  mark kropf is who you should ask about that with a GH issue if you want to explore that.
Thank you,

James Bayer

Mike Youngstrom

unread,
Aug 20, 2013, 12:44:06 PM8/20/13
to vcap...@cloudfoundry.org

Thanks for the suggestions guys.  My concern isn't that I don't want environment variables available at runtime.  My concern is that I might want to use environment variables to prompt some behavior in my build pack.  `cf` doesn't seem to provide a very user friendly way to set environment variables prior to build pack execution of a newly pushed app.  It provides a way to bind services in a user friendly way at push time but not set environment variables.

I think this issue will become larger as buildpacks start taking greater advantage of environment variables.  I believe I saw some discussion of the new Java build pack planning to use environment variables to hint the build pack to behave in certain ways.

That said Maria gave me an answer.  `cf --no-start` and/or the manifest should work for me for now.

Thanks,
Mike

Scott Frederick

unread,
Aug 20, 2013, 3:31:38 PM8/20/13
to vcap...@cloudfoundry.org
The new Java buildpack is definitely not relying on env vars to provide staging hints. Customizing the behavior of this buildpack requires forking the buildpack and modifying configuration files contained within the buildpack.

I have seen buildpacks that look at a configuration file (yaml, json, or properties files) pushed with the application to make staging decisions. If you believe that developers should have some control over how the software stack for their application is configured (which is not universally believed to be a good idea), then IMO a configuration file is a better way to go than relying on user-provided env vars, as a file is easier to version control and document.  

Scott 

Mike Youngstrom

unread,
Aug 20, 2013, 3:48:52 PM8/20/13
to vcap...@cloudfoundry.org
Thanks for the clarification Scott.  That makes sense.

Mike

James Bayer

unread,
Aug 21, 2013, 4:28:55 AM8/21/13
to vcap...@cloudfoundry.org

Mike, you can also set env variables in an app manifest.yml, that way the first time you cf push, those vars are available to your app buildpack without any separate commands.

Example:

---
applications:
- name: env-test
  memory: 256M
  instances: 1
  host: env-test
  domain: cfapps.io
  path: .
  env:
    foo: bar

Ben Hale

unread,
Aug 21, 2013, 8:04:42 AM8/21/13
to vcap...@cloudfoundry.org
The new Java buildpack is definitely not relying on env vars to provide staging hints. Customizing the behavior of this buildpack requires forking the buildpack and modifying configuration files contained within the buildpack.

Well, not user environment variables anyway.  I'm almost sure that what you were remembering, Mike, is that we wanted access to system environment variables such as $MEMORY_LIMIT, $VCAP_SERVICES, etc.  Those we are definitely using for staging hints.


I do think there's a requirement lurking around `cf` prompting for env vars though.  As an example, an application I'm working on requires a set of environment variables to work.  At the moment, my instructions specify that a user has to run seven commands to properly set them.  Now that I'm aware of the the manifest style, I could replace that with a note that the user has to edit the `manifest.yml` file to add/update with the user's specific values.  However, both of these solutions require the user to have actually read the documentation, something that most people won't do.  Instead, it might be nice to be able to say something like:

---
applications:
- name: gopivotal-cla
  memory: 1G
  instances: 1
  host: gopivotal-cla
  domain: cfapps.io
  path: target/github-cla-integration-1-SNAPSHOT.war
  env:
    ADMIN_EMAIL_DOMAINS: ${prompt: A comma delimited list of email address domains used to identify administrative users}
    DATABASE_URL: ${prompt: The URL for the application's database}
    ENCRYPTION_KEY: ${prompt: The key used to encrypt data in the database}
    GITHUB_CLIENT_ID: ${prompt: The Client ID assigned to your registered application}
    GITHUB_CLIENT_SECRET: ${prompt: The Client Secret assigned to your registered application}
  services:
    gopivotal-cla-elephantsql:
      label: elephantsql
      provider: elephantsql
      version: n/a
      plan: turtle
    gopivotal-cla-newrelic:
      label: newrelic
      provider: newrelic
      version: n/a
      plan: standard


While I suspect this isn't a feature that most applications will use (it probably makes sense to just code most values directly into the manifest and check them into source control), I do think it addresses requirements for people who want to create pre-packed applications that "just run" on Cloud Foundry without a whole lot of user knowledge.  @Mark, @James, any thoughts?


-Ben Hale
Cloud Foundry Java Experience

James Bayer

unread,
Aug 21, 2013, 11:08:31 AM8/21/13
to vcap...@cloudfoundry.org
Ben,

That certainly looks like an interesting approach. The way the manifests work now is that if you are missing name, host, or domain, or a set of other metadata values the user will be prompted, so this proposed prompt is a similar UX.

I've also been advocating to support processing of manifest.yml files on the server-side. This would enable a single HTTP interaction to create app metadata and push bits into the system non-interactively. Imagine the use case where a small set of javascript can post an app to your CF org if it has your OAuth token and space id. As long as we can provide a default value with the system is in a non-interactive mode, then I think this style could work.

Can you open a GH issue with the cf repository? I'm not sure if I've considered everything, but it seems like a good approach on first pass and the team closest to cf can probably help us analyze this more.


To unsubscribe from this group and stop receiving emails from it, send an email to vcap-dev+u...@cloudfoundry.org.

matthe...@gmail.com

unread,
Aug 21, 2013, 7:09:24 PM8/21/13
to vcap...@cloudfoundry.org
Hi Ben.  I'm probably hijacking the thread but I'm really curious how you're dealing with scenarios like late-binding (where services are bound to an application after it's been staged) and scaling operations that change the memory limits after the droplet has been created.  I believe both of those things can happen after the application has been pushed and staged.

For example, unless things have changed, the build pack doesn't execute after service binding or scaling but the values of VCAP_SERVICES and MEMORY_LIMIT can.

Thanks.

Scott Frederick

unread,
Aug 21, 2013, 8:44:20 PM8/21/13
to vcap...@cloudfoundry.org
If an app has been pushed and started, and then you bind or unbind services, change user-provided environment variables (e.g. 'cf set-env/unset-env'), or change the memory setting (e.g. 'cf scale --memory'), these changes will not take affect until the application has been restarted. 

The 'cf start' and 'cf restart' operations are generally smart enough to know whether an app can just be started from an existing droplet or needs to be re-staged and then started. Currently, binding or unbinding a service causes a re-stage on the next start/restart, changing user env vars and scaling memory does not cause a re-stage. 

Scott

Ben Hale

unread,
Aug 22, 2013, 6:40:13 AM8/22/13
to vcap...@cloudfoundry.org
If an app has been pushed and started, and then you bind or unbind services, change user-provided environment variables (e.g. 'cf set-env/unset-env'), or change the memory setting (e.g. 'cf scale --memory'), these changes will not take affect until the application has been restarted. 

The 'cf start' and 'cf restart' operations are generally smart enough to know whether an app can just be started from an existing droplet or needs to be re-staged and then started. Currently, binding or unbinding a service causes a re-stage on the next start/restart, changing user env vars and scaling memory does not cause a re-stage. 
 
Scott is correct that nearly everything we do with environment variables (with the exception of $PORT only I believe) requires a re-stage to notice any changes.  This is certainly not the way other buildpacks do things, but for the Java Buildpack, it was the only efficient way.  For example, if a New Relic service is bound, we go and download the New Relic JAR (so a user doesn't have package/configure it) and add its support to the command line that is executed.  If we chose to go down the path of not requiring the restart it would mean that the logic to detect, download, and configure the New Relic support would have to be moved to application start up and be run for every instance of the application (10's, 100's, 1000's of times potentially?).  Another example is the calculation that we do to automatically utilize all of the available memory.  This calculation isn't trivial (see how much code we wrote to do it) and certainly couldn't be done in bash.  That would mean that for Java applications we'd either need to start up a JVM to do the calculation (or bring in another runtime like Ruby) and then start up another JVM for the application each time the application was started, for every instance of the application even though we'd expect the results to be the same.

So while we realize that requiring re-staging each time an environment variable changes (even the system ones) isn't the best user-experience, we feel that it is better than moving all of our sophisticated logic out to the startup of each instance of an application.

Matthew Sykes

unread,
Aug 22, 2013, 7:02:23 AM8/22/13
to vcap...@cloudfoundry.org
So I completely understand why the work is being done during staging and I'm doing the same thing with the build pack I'm working on.  My concern was whether or not staging would be forced when service bindings or memory limits (both of which you rely on) change.

If I'm reading Scott's reply correctly, it sounds like service bindings are covered but the memory limit is not.  This seems reasonable and expected but it also implies that the memory calculation should probably be deferred to app instance start.


To unsubscribe from this group and stop receiving emails from it, send an email to vcap-dev+u...@cloudfoundry.org.



--
Matthew Sykes
matthe...@gmail.com

James Bayer

unread,
Aug 22, 2013, 11:16:26 AM8/22/13
to vcap...@cloudfoundry.org
the future ux plan-of-record:

changes to an app will effectively mark it as "dirty", which is an indicator to the system that the app should be staged the next time it is started/restarted.

changes that would mark an app as dirty include:
- updates to app code
- updates to app metadata such as memory
- add/remove/update env variables
- bind/unbind services

changes that do not mark an app as dirty:
- number of instances
- mapped/unmapping urls

if an app is already running while dirty changes happen via the cli, the cli will warn the user that the app should be restarted to ensure all changes take effect.

when an app is dirty gets started, the staging will happen automatically.

staging again is not required for dirty apps that are already running and are scaled up/down or have the urls mapped/unmapped.

in order to support these capabilities the cloud controller needs to implement additional app versioning capabilities. the routes may also have some additional work to update dynamically, but this is the current plan-of-record for the way it should work.
Thank you,

James Bayer

Ben Hale

unread,
Aug 23, 2013, 5:59:45 AM8/23/13
to vcap...@cloudfoundry.org
if an app is already running while dirty changes happen via the cli, the cli will warn the user that the app should be restarted to ensure all changes take effect.

when an app is dirty gets started, the staging will happen automatically.

staging again is not required for dirty apps that are already running and are scaled up/down or have the urls mapped/unmapped.

Just to verify my understanding, this means that some of the automatic re-staging that currently happens (e.g. when a service is bound) will no longer happen.  This is going to be removed in lieu of a UI warning that such a thing needs to be done.  Is this correct?  If so, I think there will be some grumbling about the change in behavior, but I think that making the behavior uniform and predictable is overwhelmingly good.
 
in order to support these capabilities the cloud controller needs to implement additional app versioning capabilities. the routes may also have some additional work to update dynamically, but this is the current plan-of-record for the way it should work.

A side-effect of `cf restart` causing a re-stage is some ambiguity about what is actually handed to the buildpack for the re-stage.  Have you thought about whether a buildpack should assume that it gets the "original" view of the application or should it assume that it might get the "current" (e.g. previously staged) view of the application and handle that defensively?

Mike Youngstrom

unread,
Aug 23, 2013, 12:00:23 PM8/23/13
to vcap...@cloudfoundry.org
Just to verify my understanding, this means that some of the automatic re-staging that currently happens (e.g. when a service is bound) will no longer happen.  This is going to be removed in lieu of a UI warning that such a thing needs to be done.  Is this correct?  If so, I think there will be some grumbling about the change in behavior, but I think that making the behavior uniform and predictable is overwhelmingly good.

 My understanding was that after performing a service bind or something else that would require a restage then the UI would prompt the user to restart the application for the change to take effect?

Mike

Ben Hale

unread,
Aug 23, 2013, 12:05:58 PM8/23/13
to vcap...@cloudfoundry.org
 My understanding was that after performing a service bind or something else that would require a restage then the UI would prompt the user to restart the application for the change to take effect?

I believe that the wording was "warn" rather than "prompt", but I don't view that as a wide difference.  They thing I'm asking about is when a user does the `cf restart` to cause the re-stage, what does the filesystem that the buildpack is given look like?  The user won't have re-pushed bits, so there's some ambiguity as to whether you'll get the "original" bits (exactly what the user pushed way back at the beginning) or the "current" bits (the contents of the droplet after the first staging).

James Bayer

unread,
Aug 23, 2013, 9:28:17 PM8/23/13
to vcap...@cloudfoundry.org
my understanding of how it currently works: when apps are built they always use the current 'app package', which is the source of the app in the cloud controller blob store and a full representation of what the client pushed to the server. the output droplets from previous staging requests are orphaned and never recycled into the buildpack staging again. the buildpack app cache for the app is persisted however, so things like previously downloaded gems for the same app guid are available when the app stages.


To unsubscribe from this group and stop receiving emails from it, send an email to vcap-dev+u...@cloudfoundry.org.

Ben Hale

unread,
Aug 27, 2013, 2:51:50 AM8/27/13
to vcap...@cloudfoundry.org
my understanding of how it currently works: when apps are built they always use the current 'app package', which is the source of the app in the cloud controller blob store and a full representation of what the client pushed to the server. the output droplets from previous staging requests are orphaned and never recycled into the buildpack staging again. the buildpack app cache for the app is persisted however, so things like previously downloaded gems for the same app guid are available when the app stages.

Perfect, thanks.
Reply all
Reply to author
Forward
0 new messages