My earlier post generated a healthy amount of comments and inquiry for overcoming the ephemeral nature of file storage that exists in most Platform As a Service technologies, which includes Cloud Foundry and BlueMix. Briefly, BlueMix applications are typically given an ephemeral file system and isolated from read/write access to any persistent disk. The Cloud Foundry community recommends that applications avoid writing to the local file system. [Reference] Some reasons for this include:
Local file system storage is short-lived. When apps crash, stop or are restarted, resources can be reclaimed by the platform.
Instances of the same app do not share a local file system. Each app runs in its own container. If you scale up instances, both instances will not have access to the same file system.
This creates an interesting quandry. Ghost.js rocks! BlueMix can rapidly deploy, host and scale up a Ghost.js instance, which is awesome! But, BlueMix uses an ephemeral file storage and most bloggers will not tolerate being constrained to using images defined by URI only nor being constantly hassled with having to go upload local image files to some other place. [As an interesting aside: Ghost.js provides a configuration option named filestorage to eliminate the local file upload scenario entirely and be more compatible with PaaS environments]
Enter Cloudant. Let’s exploit BlueMix’s composeable service model to quickly attach a Cloudant CouchDB instance to our deployed Ghost.js app. A couple of BlueMix UI clicks and a quick Cloudant account create should be the elixir to our ills 🙂 I considered MongoDB’s GridFS capability as well, but settled on Cloudant because of its stellar dashboard management and responsive performance as a proven commercial solution. After 5 mins of clicking – well, that also includes one quick email and an instant message, the next chore was to empower Ghost.js to leverage this storage resource. I copied the localfilesystem module and created a new one called cloudant.js. I dutifully tweaked the save and exists functions to interact with Cloudant using the simple, but solid, Nano Node.js package. This resulted in a user experience where I can upload local files into my BlueMix Ghost.js deployment, while having Ghost.js be smart enough to subsequently go and create a representative Cloudant document and attachment which it will then exploit as a linked image resource. Sweet! Ghost.js now always uses URI defined image sources and the user experience remains intact for uploading local files without additional end-user hassle.
If this has piqued your interest, give it a try. You’ll love the results. Here’s how …
Unzip the download (e.g. unzip Ghost-0.4.2.zip) and change to the base directory (e.g. ghost-0.6.4)
Clone a copy of this git repository and copy the content within the files folder into the root of your ghost installation directory. You will replace two (2) new files (package.json and core/server/storage/index.js), deleteone (1) file (npm-shrinkwrap.json), add four (4) new files (config.js, manifest.yml, manifest.cfg and core/server/storage/cloudant.js) and modify one (1) file (core/server/api/upload.js) to the default Ghost.js installation to enable its use.
Open the core/server/api/upload.js and edit line #44
Reason: While the local files are temporarily stored on the local filesystem, our new CloudantFileStore actually tells Ghost a url that is an HTTP URL which we’ve generated on-the-fly via a binary attachment into Cloudant. Unlinking is unnecessary and these tmp files will be destroyed during app future app re-staging/restart as a victim of the ephemeral storage paradigm.
Update the name, host and services entries within the manifest.yml to match your deployment environment. The service entries for both the MySQL and Cloudant Service instance names are totally up to you.
Using the BlueMix Web UI, login to BlueMix, and create two (2) back-end database service instances (MySQL and Cloudant) that matches your manifest.yml entries. IMPORTANT: When creating the Cloudant Service Instance, the url field should be in the format of <your_cloudant_username>.cloudant.com . Your database can be named anything and your username/password will be whatever was used when setting up your Cloudant account. Be sure to alter your image store database permissions so that reader access is granted to everyone. This is easily done by clicking on the DB within the Cloudant dashboard, then clicking on the Docs dropdown button and choosing permissions. Click the Reader checkbox for the Everybody Else category. A database will automatically be located or created with the format <app_name>-ghost-images for use by Ghost.js during application startup. Permissions are automatically set for Everyone on the database to have read access.
Navigate to the root of the Ghost.js installation directory. Using the cloud foundry v6 cli, login to BlueMix and deploy Ghost.js.
#Step 0: cf login -a
<b>$ cf login -a https://api.ng.bluemix.net</b>
# Step 1: CF_STAGING_TIMEOUT=4 CF_STARTUP_TIMEOUT=4 cf push -s cflinuxfs2
# CF_STAGING_TIME : Max wait time for app instance startup, in minutes
# CF_STARTUP_TIMEOUT : Max wait time for app instance startup, in minutes
# -s : Establishes the stack to use as Trusty Ubuntu 14.04<br /># ENV variables are suggested to accommodate longer staging and startup times.
<b>$ CF_STAGING_TIMEOUT=4 CF_STARTUP_TIMEOUT=4 cf push -s cflinuxfs2</b>
If all goes well, you should have a running Ghost.js blogging platform. Browse and setup your user. Then visit: <your_app_name>.mybluemix.net/ghost/ .
There are two (2) ways to embed an image and there are at least two places where images are used within Ghost.js.
Place #1: Settings. You can click on the upload image buttons for a blog cover and blog logo. You will see a little chain-link icon in the bottom left. That toggles the UI from being a file upload to a direct url link to the image. Feel free to give both ways a try, but the Cloudant tweak affects only the local file upload flow. After uploading an image and saving, you can verify if the tweak is working by using the browsers “inspect element” context menu. This should show an image that has a source using a cloudant url pointing to your account. In theory, this should never go away if the account remains in good standing and you never delete the database or document.
Place #2: Content. You can embed an image using the markdown syntax ![alt text](url to image). If you simply type ![an inspiring image of earth] … you will see a familiar image uploader dialog in the preview that can be clicked. Same options hold true, direct web url or local file upload. Same technique to verify if its using Cloudant.
My name is John and I am a user experience here at IBM. I actually work on the newer reporting solutions working their way through Rational right now…anyhow, I am in need of a fresh online portfolio and I have been wanting to try Ghost. I would also like to get everything up and running on Bluemix, if at all possible. I found you cool example and explanation of how you got it up and running and it looks like a feasible solution.
Unfortunately, I am not a dev per se and the whole Bluemix/web application deployment via cloud services thing is something I am just getting my head wrapped around…and this experiment with Bluemix strikes me as an ideal means to get my iron hot.
That said, everything seems rather clear to me. I have successfully deployed simple “Hey World” apps on BlueMix in the past. My issue here concerns some confusion over Cloudant and which account to use. I have a unique Cloudant account (the most basic, free version). I cannot figure out how to use this unique account to create my Cloudant service when using BlueMix…am I missing something or do you recommend I simply use the account that is auto-generated when I attempt to create a new service instance using Bluemix.
Also, are there any plans to make an auto deploy version of Ghost (similar to that found on OpenShift) for Bluemix? This would strike me as a awesome move in the “coolness” direction as Ghost seems to have quite a bit of momentum as a simple, fast blogging platform and many hosts seem to be struggling to get up to speed, for various reasons.
It may help if I clarify that I cannot find any means–when creating my Cloudant service–to change the URI to match myCloudantusernamecloudantcom. The app field, which I presume is the URI field you mention, is not editable.
While I wrote the article to leverage the built-in generated Cloudant account provided by the Bluemix service, there is no hard requirement to point to that. Take a look at: https://github.com/ibmjstart/bluemix-ghost-js/blob/master/files/core/server/storage/cloudant.js#L24-35 . These lines within the cloudant.js file (and used with Step 3) are what define the url to use with Cloudant. I’m dynamically reading the environment variable to grab the Bluemix service details … but you could comment/delete these lines and provide your own details in the form of a JSON string. Something like:
Using route johnyux.mybluemix.net
Uploading app files from: C:UsersIBM_ADMINDocumentsGitHubjohnyux.mybluemix.
Uploading 818K, 220 files
Binding service ClearDB MySQL Database-di to app johnyux in org firstname.lastname@example.org
m / space dev as email@example.com…
Binding service Cloudant NoSQL DB-8c to app johnyux in org firstname.lastname@example.org / s
pace dev as email@example.com…
Checkout my comment here. Specifically, I discovered a bug in my approach for using the manifest.yml as a config data source. I suspect that your app_url isn’t being populated correctly which causes a startup failure and an error during startup of a missing manifest.yml file relevant lines of code. Try
If you’re curious about why this happens: I think that CloudFoundry includes the manifest.yml file as an “ignoreable” file during pushes since in theory it is only supposed to be used to tell CF how to deploy and not tell the app how to run. It was a flaw in my thinking to use it.
I feared for long hours setting this up, but amazingly it took about 15 minutes.. thank you for that
Just one comment i had to remove ‘https://’ + from line 144 in your cloudant.js file .. as the service was already prepending this, so uploading images gave me http://http://xxx.cloudant.com
after removing this http:// is nicely worked
@Guy – Awesome! Glad that it worked smoothly and more importantly – quickly. I’ve updated the git repo files to remove the prefixed ‘https://’ string for the benefit of others. Appreciate the feedback.
Great job! I got my first blue mix up and running! But I got some erros;
Error: Cannot find module ‘intl’
Error: Cannot find module ‘intl-messageformat’
So added this 2 lines;
to package.json file. Now it works!
Awesome! Glad you were able to get it deployed with minimal trouble. Thanks for the heads up. I’ve located the package.json commit that caused this here (https://github.com/TryGhost/Ghost/commit/d89abaa15edf5990887e1c6341ca547fc13c97d8#diff-b9cfc7f2cdf78a7f4b91a753d10865a2) . In general, this will be an ongoing challenge to our repo since we’re maintaining a fork of the TryGhost project’s package.json. Feel free to send us a PR on our repo for updates to the package.json which include your mentioned changes and I’ll merge it in. Otherwise, I’ll try to make the tweak later this week. Thanks again for the feedback 🙂
With IBM Cloud App ID’s Cloud Directory feature, you can create a user registry, and add sign-up and email/password sign-in to your mobile or web app. Cloud Directory comes with a pre-built sign-in widget that you can use, or if you prefer to use your own branding, you can replace it with your own custom UI. This blog will show you how to use Cloud Directory APIs and add your own custom sign-in screen to an Android application. You can find the Android Cloud Land App on GitHub.