Zenko can be deployed on a managed-Kubernetes cluster on Google Cloud (GKE) using the Helm charts distributed in its repository. There are many other ways to run Zenko on a Kubernetes cluster, including our favorite Kubernetes distribution MetalK8s. The Helm charts are designed to isolate how Zenko is deployed from where it is deployed: any Kubernetes cluster will be good to get started. In some ways, it helps developers like Zenko itself tries to give developers the freedom to choose the best cloud storage system, abstracting the complex choices like supporting multiple APIs or aggregate metadata. GKE is an easy way to quickly setup a cloud-agnostic storage platform.
The first step is to start a new cluster on Kubernetes following the instructions on Google Cloud documentation. For better performance, you’ll need a cluster with 3 nodes, 2vCPU and 7.5GB RAM each. Once the cluster is running, connect to it and install Helm.
Create Role For Tiller
Google Kubernetes Engine requires Role Based Access Control to be setup. The first step is to create a serviceaccount for tiller:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-cluster-1-default-pool-9ad69bcf-4g2n Ready <none> 1m v1.8.10-gke.0
gke-cluster-1-default-pool-9ad69bcf-frj5 Ready <none> 1m v1.8.10-gke.0
gke-cluster-1-default-pool-9ad69bcf-rsbt Ready <none> 1m v1.8.10-gke.0
Install Helm on Kubernetes Cluster
Helm is not available by default on GKE and needs to be installed.
Clone Zenko’s repo and go into the charts directory:
$ git clone https://github.com/scality/Zenko.git
$ cd ./Zenko/charts
Once you have the repo cloned you can retrieve all dependencies:
$ helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
"incubator" has been added to your repositories
$ helm dependency build zenko/
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "incubator" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 8 charts
Downloading prometheus from repo https://kubernetes-charts.storage.googleapis.com/
Downloading mongodb-replicaset from repo https://kubernetes-charts.storage.googleapis.com/
Downloading redis from repo https://kubernetes-charts.storage.googleapis.com/
Downloading kafka from repo http://storage.googleapis.com/kubernetes-charts-incubator
Downloading zookeeper from repo http://storage.googleapis.com/kubernetes-charts-incubator
Deleting outdated charts
With your dependencies built, you can run the following shell command to deploy a three-nodes Zenko stack with Orbit enabled.
Scality’s Release Engineering team has completed the integration of all Zenko-related repositories in its GitWaterFlow delivery model, like all other Scality’s products. The GitWaterFlow model was introduced years ago at Scality to increase release quality and increase development speed.
You may have noticed that Cloudserver and Backbeat repositories now default to a branch called development/8.0. The repositories also contain new directories called eve and pull requests contain comments from the bot Bert-E. What’s going on? That’s the GitWaterFlow process in action. To understand it, we need a little history …
At the start, the small-scale team of Scality engineers working to develop the RING product employed CVS and later Subversion in an ad-hoc fashion, and collaboration happened ‘on the spot’. The engineering team pushed features and bug fixes into a shared trunk branch. This branch was slated to become the next ‘major’ release of the product, though overeager integration of partially-delivered features often resulted in the branch being in a non-shippable state.
The process to port bug fixes to relevant branches (‘back-porting’) was fully manual. When the change rate of the codebase reached a certain level, this turned out to be a bottleneck in the development process. As with all manual processes, this also was prone to introduce accidental bugs or regressions. Creation of backport commits on various version branches also destroyed relationships between semantically equivalent changesets, which could only be recovered through information kept in commit messages or the ticketing system, again relying on humans doing the right thing.
Introducing the GitWaterFlow model
Fig. 1. Forward-porting patches on multiple development branches
That approach had too many flaws and didn’t scale. The Release Engineering team investigated options to radically change the approach, easing the workflow for developers as well as ensuring correctness of meta-information. The results were announced at the end of 2016 and kept improving since then.
GitWaterFlow (GWF) is a combination of a branching model and its associated tooling, featuring a transactional view on multi-branch changesets supported by none of the tools and models previously described. GWF tends to ban “backporting” in favor of “(forward) porting”. The term “porting” is employed to describe the act of developing a changeset on an old — yet active — version branch and subsequently merging it on newer ones. It is considered better than “backporting” for multiple reasons. “Porting” also makes merge automation trivial. In fact, changes that are merged in an old version branch, whether fixes or improvements, must also land in newer ones, otherwise there is a risk of regression. A bot can use this assumption to prepare and then execute the merge on newer branches, thus offloading the developer.
Development Branches
GWF comes with a versioning scheme that is inspired by semantic versioning (semver). Basically, version numbers are in the form major.minor.patch. patch is incremented only when backward compatible bug fixes are being added, minor is incremented when backward-compatible features are added, and major is incremented with major backward incompatible changes.
In GWF, every living minor version has a corresponding development/major.minor branch, each of which must be included in newer ones. In fig. 1 a development/1.0 is included into development/1.1, which in turn is included in development 2.0. Consequently, a GWF-compliant repository has a waterfall-like representation, hence the name “GitWaterFlow”.
As GWF is based on ‘porting’, feature branches do not necessarily start from the latest development branch. In fact, prior to start coding a developer must determine the oldest development/* branch his code should land upon (refer to fig.1.a). Once ready to merge, the developer creates a pull request that targets the development branch from which he started. A gating and merging bot will ensure that the feature branch will be merged not only on the destination but also on all the subsequent development branches.
Transactional Multi-Branch Changes
The fact that every pull request can concurrently target more than one mainline branch can dramatically affect the approach that developers take in addressing issues. For instance, it is not uncommon that conflicts exist between the feature branch targeting version n, and version n+1. In our setup, this class of conflicts must be detected and fixed prior to merging the pull request. The code that resolves such conflicts is considered part of the change, in fact, and must be reviewed at the same time. Also, it is a requirement that a pull request be merged only once it has passed the tests on all targeted versions.
In short, the changes brought to the software on multiple branches is a single entity and should be developed, reviewed, tested, and merged as such.
Only The Bot Can Merge
Bert-E is the gatekeeping and merging bot Scality developed in-house to automate GWF, its purpose being to help developers merge their feature branches on multiple development branches. The tool is written in Python and designed to function as a stateless idempotent bot. It is triggered via Bitbucket/GitHub webhooks after each pull request change occurrence (creation, commit, peer approval, comment, etc.).
Bert-E helps the developer prepare his pull request for merging. It interacts directly with the developer through GitHub’s (or Bitbucket) comment system via the pull-request timeline, pushing contextualized messages on the current status and next expected actions. In Scality’s case, Bert-E ensures that the pull request has at least two approvals from peers before it merges the contribution. In the future, Bert-E will also check that the JIRA fixVersion field is correct for the target branches to help product managers keep track of progress. Bert-E usually replies in less than 50 seconds, thus creating a trial-and-error process with a fast feedback loop that is ideal in onboarding newcomers to the ticketing process.
Integration Branches
In parallel with the previously described process, Bert-E begins trying to merge on the subsequent development branches by creating integration branches named w/major.minor/feature/foo, after both the originating feature branch and the target development branch (refer to fig.1.b). Every time Bert-E is triggered, it checks to ensure that the w/* branches are ahead of both the feature branch and the corresponding development branches (updating them following the same process when this is not the case).
Every change on a w/* branch triggers a build/test session. When the pull request fulfills all the requirements previously described, and when the builds are green on all the w/* branches, Bert-E fast-forwards all the development branches to point to the corresponding w/* branches in an atomic transaction, as depicted in fig.1.c.
Note that if another pull request is merged in the interim, Bert-E will not be able to push and must re-update its w/* branches and repeat the build/test process.
Better ‘Definition of DONE’ and Smoother Developer Process
In use at Scality for over two years, we can testify that the main GWF benefit is its atomic multi-branch merge property. In this context, ‘DONE’ means merged and fully tested on all target branches, and there is no additional backporting phase wherein it is discovered that the backport is more complex than the fix itself. Target branch conflicts are detected early and are dealt with prior to merging.
Peer reviews/approvals aside, the development process is smoother and allows the developer to push his changeset to completion without depending on third parties to merge. Changeset ownership reverts back to the author and does not vary across time. Thus, the developer is responsible for it up until the merge.
Also, the metadata in the git repository is much clearer, and now a simple git branch –contains <commit> will indicate within which branch a change has been merged. Due to gatekeeping, the development branches are always in a shippable state, which has greatly improved Scality’s accuracy in predicting delivery dates. Hand-in-hand with that, the amount of overall engineering work in progress has been reduced due to the GWF deployment, and as a direct result Scality is shipping faster.
Bert-E and Eve are open source
Source code and documentation for Bert-E and Eve are available on Bitbucket. If you have questions, please ask them on Zenko forum.
[…] a tool that makes it easy to run Kubernetes locally. Minikube runs a single-node Kubernetes cluster inside a VM on your laptop for users looking to try out Kubernetes or develop with it day-to-day.
Once Minikube, kubectl, and helm are installed, start Minikube with Kubernetes version 1.9 or newer, and preferably at least 4GB of RAM. Then enable the Minikube ingress addon for communication.
Once Minikube started, run the helm initialization.
$ helm init --wait
With K8s now running, clone Zenko repository and go into the Helm charts directory to retrieve all dependencies:
$ git clone https://github.com/scality/Zenko.git
$ cd ./Zenko/charts
$ helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
"incubator" has been added to your repositories
$ helm dependency build zenko/
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "incubator" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 8 charts
Downloading prometheus from repo https://kubernetes-charts.storage.googleapis.com/
Downloading mongodb-replicaset from repo https://kubernetes-charts.storage.googleapis.com/
Downloading redis from repo https://kubernetes-charts.storage.googleapis.com/
Downloading kafka from repo http://storage.googleapis.com/kubernetes-charts-incubator
Downloading zookeeper from repo http://storage.googleapis.com/kubernetes-charts-incubator
Deleting outdated charts
With your dependencies built, you can run the following shell command to deploy a single node Zenko stack with Orbit enabled.
To view the K8s dashboard type the following and will launch the dashboard in your default browser:
$ minikube dashboard
The endpoint can now be accessed via the K8s cluster ip (run minikube ip to display the cluster ip). Now you have a running Zenko instance in a mini-kubernetes cluster. To connect your instance to Orbit, find the instance ID
{"name":"S3","time":1529101607249,"req_id":"9089628bad40b9a255fd","level":"info","message":"this deployment's Instance ID is 6075357a-b08d-419e-9af8-cc9f391ca8e2","hostname":"zenko-cloudserver-front-f74d8c48c-dt6fc","pid":23}
The Instance ID in this case is 6075357a-b08d-419e-9af8-cc9f391ca8e2. Login into Orbit and register this instance. To test your minikube deployment, assign a hostname to the clusters ingress IP address to make things easier, then using s3cmd test
By default, minikube only exposes SSL port 443, so you’ll want to ask your client/app to use SSL. However, since minikube uses a self-signed certificate, you may get security error. You can either configure minikube to use a trusted certificate, or simply ignore the certificate.
When configuring storage locations in Zenko Orbit, you need to enter some combination of access key, secret key, and account name. All this information varies by cloud provider and it can be annoyingly complicated to find all that information. This cheatsheet will help you configure access to AWS, Azure and Google for Zenko Orbit.
This document assumes you know how to log into the AWS, Azure and Google cloud portals and that you know how to create a storage location in Zenko Orbit.
AWS
Location name = any descriptive name; “aws-location” “aws-demo” etc.
You may or may not have IAM roles set up in your account. If not, press the Continue to Security Credentials button
Press the “+” sign next to “Access keys (access key ID and secret access key)”
Prease the Create New Access Key Button
Window will appear with your Access and Secret Key (screenshot below)
Copy/paste your Secret Key somewhere safe.
Target Bucket Name = name of existing Bucket in Amazon S3
Azure
Location name = any descriptive name; “azure-location” “azure-demo” etc.
Azure Storage Endpoint = the “Blob Storage Endpoint” located on the top right of the Overview tab for your storage account (screenshot below).
Azure Account Name = the name of your Azure storage account located on the top of the Azure Portal (screenshot below – “scalitydemo” is Azure Account Name).
Azure Access Key = the “key1 / Key” visible when you select Access Key in the Azure Portal.
Target Bucket Name = name of existing Container in Azure
Google
Location name = any descriptive name; “gcs-location” “gcs-demo” etc.
GCP Access Key and Secret Key = navigate to GCP Console / Storage / Settings / Interoperability Tab (see screenshot below
Target Bucket Name = name of existing Bucket in Google Cloud Storage
Target Helper Bucket Name for Multi-part Uploads = name of existing Bucket in Google Cloud Storage
(Google Cloud Storage handles MPU in such a way that Zenko requires a second bucket for temporary staging purposes)
Wrapping up a great week at the OpenStack Summit in Vancouver where Zenko sponsored of the Superuser Awards. We had the honor to hand the trophy to the Ontario Institute for Cancer Research (OICR), a group of scientists that uses OpenStack to build the Cancer Genome Collaboratory: a cloud that enables research on the world’s largest and most comprehensive cancer genome dataset.
We like to see technology used to really improve the world by solving very difficult problems. The Superuser Award couldn’t be better placed, in the hands of small teams with highly constrained resources providing inspiration, amusement and wonder thanks to open source.
We hear inspiring stories from open source users all the time and that’s why we loved being with OpenStack: we’d love to see Zenko’s multi-cloud and replication capabilities added to the toolboxes of developers fixing the hard problems of the world.
Outside of the keynotes, the Zenko team spent time in Vancouver going to sessions, meeting the press and getting to know the ever changing OpenStack community. For me, this was the 13th OpenStack Summit (my first was in Boston, 2011). Years after, I found a strong group of people highly motivated to put OpenStack at the center of the infrastructure world. The announcements of the Kata Containers project and the spin-off of Zuul as its own project outside of OpenStack-infra team mark a pivotal moment for the Foundation. The comments we’ve heard on the Marketplace seemed all positive which seems to confirm the maturity of a community that has navigated across the hype cycle.