So I accidentally made a Cloud SDK.
I was actually trying to make a game from the beginning, and as part of that I wanted the game to have a global high-score list.
But that meant I needed to have some way for players (if they choose to) to authenticate themselves, so that the list at least have the right name for a score. So some kind of server-side logic was needed.
I was using Pharo 8 to create the game, and it felt like a good idea to write the server parts in Pharo as well. The normal way to deploy a server-side application to a cloud provider is to first make a Docker container for it. There are a couple of good instruction here and here, for Pharo.
But building Docker images normally means that I would need to use a shell and run some commands, manipulating files and uploading them using custom CLI commands for the given cloud provider. It didn't feel very Smalltalk-y. I'd rather stay inside the Image and do everything without having to juggle files and additional software installations and all that.
It was a bit tricky, but it worked. The result is this project; https://github.com/psvensson/cloudsdk-st which contains an application to (hopefully) make the process more streamlined. It is an alpha release, and have the following constraints;
1. It only works for Google Cloud (at the moment)
2. It can only deploy Pharo Smalltalk applications to Google Cloud Run (fully managed cloud functions).
The workflow is as follows;
Add a key for a Google Cloud service account.If you already have a google account (gmail, you know), you can access and enable Google Cloud by going to the console here; https://console.cloud.google.com/
A service account is an identity that can access certain parts (or everything) of your Google Cloud account on behalf of you. This is in essence what the application needs to do - to impersonate you and to send commands to your Google Cloud project as if it were you, to build and deploy Docker containers.
You can find instructions on how to use service accounts and how to create and download private keys for them here; https://cloud.google.com/iam/docs/creating-managing-service-account-keys . I also have some instructions on this in the project README.
This is what a downloaded service account JSON key looks like;
And the first thing you need to do after that is to click 'New Account' which lets you either paste the text contents of the key into the application directly, or select a file containing the key.
Here is an example where I have four different keys installed, where each key can connect to a different project of yours. It is not uncommon to create on project for 'staging' and another for 'deployment'.
Create a Template
Now we need to decide what to deploy. The right part of the application contain a list of Application Templates. A template consists of three parts;
1. An editable base Dockerfile, which you need not change if you're OK with running Pharo 7
2. An editable load script, which is the Smalltalk code to be executed to start your service. For almost all purposes, you will have to have a (Zinc) web server listening on port 8080 and your own custom code to handle requests. This is also the default for the template from the beginning.
3. A list of external dependencies. You can search for and add Smalltalk packages by clicking 'Add Dependency'
You can write some text to search for packages to add as dependencies and also select to search for only Pharo or Smalltalk tags (or none). Currently the search is only done on Github but Smalltalkhub support is planned in the near future.
When the Template is used to create a container, the list of dependencies will be translated into Smalltalk code loading the dependencies using metacello, so the packages will be available to you loading script.
To actually deploy this template to a Cloud Run cloud function you must first enable a couple of things in your project.
- Granting access for Google Cloud build to deploy to Google Cloud Run, by setting 'Cloud Run Admin' to enabled here; (https://console.cloud.google.com/cloud-build/settings).
- Enabling the Cloud resource manager API, here; (https://console.developers.google.com/apis/api/cloudresourcemanager.googleapis.com/overview)
- Enabling the Cloud Run API, here; (https://console.developers.google.com/apis/api/run.googleapis.com/overview)
Creating and deploying containerAfter that you can click 'Create Container' (which in retrospect should really be called deploy, I now realize :) ), which will do the following;
1. Package the Dockerfile and load file strings as 'files' inside an in-memory zip archive
2. Send the zip file to the Google Cloud Build system
3. Telling the Cloud Build system to create a Docker container of the contents of the file
4. Deploy the newly created Docker container to a Cloud Run function with the same name.
This process takes 1 - 2 minutes normally.
You can watch the build taking place by going here after you have started it; https://console.cloud.google.com/cloud-build/builds
When (and if) everything is done, you will have a new Cloud Run cloud function popping up here; https://console.cloud.google.com/run
You can also see the the results in the application. the 'Containers' button lists and give details about all Google Cloud Build containers that is build for your project.
The 'Build results' button lists and gives details of the build process(es);
Finally the 'Deployments' button shows active and running Cloud Run cloud functions.
But 'running' is a bit of a misnomer actually, as cloud functions only runs when called. If not called for a while, the container spins down, so you only pay for the times the function is actually accessed. But mostly it is free as the first 2 million calls are free for every month, so it is a comfortable way to start testing while also being live in the clouds, so to speak.
And the game? It looks a bit like this and I hope to blog about it sometime soon as well, when I've rested a bit. It's currently a true rogue-like (as in; like rogue, actually, not just anything random with permadeath slapped on). I will have to make it real-time, rather than runt-based, in the spirit of mangband to accommodate multi-user adventures, though