Google Cloud Platform

Rolling your own private Ruby gem server on Google Cloud Platform

Great news, Rubyists! We recently released google-cloud-gemserver gem, making it possible to deploy a private gem server to Google Cloud Platform (GCP) with a single command:

  $ google-cloud-gemserver create --use-proj [MY_PROJECT_ID]

This is a big deal for organizations that build libraries with proprietary business logic or that mirror public libraries for internal use. In Ruby, these libraries are called gems, and until recently, there wasn't a good hosted solution for serving them. For Ruby in particular, many developers found themselves building their own custom solutions or relying on third parties such as Gemfury.

Running a gem server run on GCP has a lot of advantages. Specifically, the above command deploys the gem server to a Google App Engine Flex instance, which has 99.95% uptime (Google Container Engine support coming soon). App Engine can also autoscale the number of instances based on CPU utilization to minimize the amount of maintenance for the gem server. Having the gem server on GCP also allows you to use existing cloud infrastructure such as Stackdriver Logging, Cloud Storage and direct access to the underlying VM running the gem server for fine-grained control. The gem server can store an unlimited amount of public and private gems allowing an unlimited amount of users with the correct permissions to access it. This level of flexibility and customization makes GCP a highly productive environment to deploy apps to, and the gem server is no exception.

Using the gem server 

Let’s take a look at how to install and configure a private gem server.

To deploy your own private gem server to GCP:

  1. First install the gem:
    $ gem install google-cloud-gemserver
  2. Ensure you have Cloud SDK installed and a GCP project created with billing enabled. Also ensure that you're authenticated with it. For a full list of prerequisites, read this checklist. 
  3. Run the following command in your terminal: $ google-cloud-gemserver create --use-proj [MY_PROJECT_ID] where MY_PROJECT_ID is the GCP project ID the gem server will be deployed to. This deploys the gem server to App Engine and creates a default key used to push and fetch gems from the gem server. For brevity, the value of this key will later be referred to as “my-key” and its name will later be referred to as “my-key-name”.
Now, you can access the gem server at http://[MY_PROJECT_ID].appspot.com. Gems can easily be pushed to the gem server with a key that has write access to the gem server. The above command generated a default key, my-key, that can be used. You can push a gem by running:

  $ gem push --key my-key-name [PATH_TO_MY_GEM] --host \         
> http://[MY_PROJECT_ID].appspot.com/private/

Before you can download gems from the gem server, you need to create a key that has read access to the gem server. Conveniently, the “create” command above also generated a default key. Installing gems uses bundler, which needs to be configured such that it associates the gem server with my-key when downloading gems, otherwise the download would fail with a 401 Unauthorized Error. This is also done automatically for my-key when you use the “create” command. Now, make a small modification to your Gemfile:

  source “[GEMSERVER_URL]”
source “[GEMSERVER_URL]/private” do
  gem “MY_GEM”
end

Then, run “bundle install” and it fetches and installs the gem “MY_GEM” from the gem server!

Conclusion 

That is all it takes to spin up a personal, private gem server on GCP and access gems from it. Under the hood, it uses Google Cloud SQL to manage gem metadata, cached gems, authentication keys, etc., and Cloud Storage to maintain backups of the gems. The google-cloud-gemserver gem is built on top of an existing gem that runs a private gem server locally; it served as a base and was extended to work with GCP infrastructure. It's worth noting that the google-cloud-gemserver gem is open source and actively maintained. We're always looking to improve the gem and encourage contributions!