Run one-off tasks and database migrations in Cloud Foundry 2016

Within Cloud Foundry 2016, with Diego support enabled and the latest cf CLI you can now run one-off tasks natively in your Cloud Foundry.

For Ruby on Rails applications this means you can run database migrations or seed the database from your local computer very easily.

Conceptually you would run either:

cf ssh <appname>
cf ssh <appname> --command 'rake db:seed'

The --command or -c flag allows a command string to be executed. If you miss it then you will get a bash prompt and can run arbitrary commands inside one of the running containers.

Except, that doesn’t work as expected. I’ve pasted in the errors I got at the end of the post to help Google match the error to the solution.

Targeting Pivotal Web Services which is running the latest Cloud Foundry (release v230, API 2.48.0) I found that I had to run the following:

cf ssh <appname> \
  -c 'cd app; HOME=$(pwd) source ~/app/.profile.d/*.sh; rake db:seed'

Or if I was going to work inside a container:

cf ssh <appname>

Then setup the environment:

cd app; HOME=$(pwd) source ~/app/.profile.d/*.sh

Hopefully someone can explain why this is necessary; or even better – automatically source the ~/app/.profile.d/*.sh file(s) automatically in future.

From Eric Malm

In the [email protected] mailing list Eric Malm suggested another workaround:

https://lists.cloudfoundry.org/archives/list/[email protected]/message/DKORQNOPVRQ5CJTL5QEHP3JW2MXGZP45/

This issue also came up in the #buildpacks channel in the CF Slack the other day. Until we solve this permanently, a cleaner and more complete workaround seems to be to run

/tmp/lifecycle/launcher "app" "$SHELL" ""

once you start your interactive session. Running the command through the launcher binary will set up HOME and TMPDIR as it does for the app’s start command, inject per-instance values into VCAP_APPLICATION, and source the buildpack-provided setup files in /home/vcap/app/.profile.d/*.sh.

This technique should also work for running non-interactive commands via cf ssh: instead of cf ssh APP_NAME -c '<command>', try running

cf ssh APP_NAME -c '/tmp/lifecycle/launcher "app" "<command>" ""'

As far as getting a permanent fix for this environmental setup issue in SSH commands, I’ve scheduled a new attempt at this in the Diego backlog at https://www.pivotaltracker.com/story/show/113237191, and we intend to get to it soon in a way that doesn’t accidentally break Windows apps.

Symptoms

I discovered this issue when trying to innocently use cf ssh <appname> but bundle wasn’t available and ruby -v gave the wrong version:

# cf ssh <appname>
$ cd app
$ bundle
bash: bundle: command not found
$ ./bin/bundle
/usr/lib/ruby/1.9.1/rubygems.rb:308:in `bin_path': can't find gem bundler (>= 0) (Gem::GemNotFoundException)
from ./bin/bundle:3:in `<main>'
$ ruby -v
ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-linux]

Hopefully this post helps other people who are excited to use cf ssh as I am!

Spread the word

twitter icon facebook icon linkedin icon