At VIBBIO we have adopted a devops mindset to everything we do. An essential part of such a mindset is to ๐ข the ๐ฉ to production. In order to do so safely and with even more control we have added a new tool to our toolbox: feature toggles.
The lovely people at Finn.no have developed an Open Source server for administering and using feature toggles. The project is called Unleash and is their company, but it is also gaining traction in a lot of other Norwegian companies as well. One thing we especially like about Unleash is that it’s a relatively simple solution which is fast to setup and get going. You do not need Zookeeper clusters or Big Data storage rigs to get this up and running ๐๐พ.
VIBBIO runs it’s services on Google Cloud and it’s Kubernetes Engine. Naturally we wanted to run unleash on the same infrastructure. The project has a docker sample which shows how to spin up a server using docker compose.
YAML YAML YAML YAML YAML YAML YAML
โ ๏ธ Before you proceed, if you have allergies towards yaml or experience stress when exposed to excessive amounts of yaml you are best advised to stop reading right now โ
In order to get Unleash ready we need two things:
- Postgres database
- Unleash server
Luckily the nice folks who wrote Unleash has a docker sample which provides a good starting point for getting it setup on Kubernetes Engine.
๐ Volumes, ๐ Claims & ๐ Configuration
You do want your data to be persistent and not disappear when the app gets recreated. In order to get this working you must setup a persistent volume and a persistent volume claim (more information on this are in the Google Cloude doucumentation)
kind: PersistentVolume
apiVersion: v1
metadata:
name: unleash-db-volume
labels:
type: local
app: unleash
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
hostPath:
path: "/var/lib/postgresql/data"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: unleash-db-claim
labels:
app: unleash
spec:
storageClassName: manual
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
Database configuration can be done by using a config map. You probably should use Kubernetes secrets for the credentials, but for this sample we just add it here.
apiVersion: v1
kind: ConfigMap
metadata:
name: unleash-db-config
labels:
app: unleash-db
data:
POSTGRES_DB: db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: somepassword
Data exposure ๐ผ
In order for the application to use your database, you must set it up as a services
apiVersion: v1
kind: Service
metadata:
name: unleash-db
labels:
app: unleash-db
spec:
type: NodePort
ports:
- port: 5432
selector:
app: unleash-db
Finally, the deployment descriptor
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: unleash
spec:
replicas: 1
template:
metadata:
labels:
app: unleash
spec:
volumes:
- name: unleash-storage
persistentVolumeClaim:
claimName: unleash-claim
containers:
- name: unleash
image: postgres:10.4
imagePullPolicy: "IfNotPresent"
ports:
- containerPort: 5432
envFrom:
- configMapRef:
name: unleash-config
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: unleash-storage
Once you’ve added all this config, you should query the cluster to see if it worked. You should expect something along the lines of this. However the numbers and IPs will be different for each system.
$ kubectl get \
pods,services,persistentvolumes,persistentvolumeclaims,deployments\
--selector=app=unleash-db
NAME READY STATUS RESTARTS AGE
po/unleash-db-56d4cdf6f6-h7wk8 1/1 Running 0 24d
NAM TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/unleash-db NodePort 10.7.255.41 <none> 5432:31643/TCP 24d
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
pv/unleash-db-volume 5Gi RWX Retain Bound default/unleash-db-claim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc/unleash-db-claim Bound unleash-db-volume 5Gi RWX manual 24d
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/unleash-db 1 1 1 1 24d
๐ ๐ You made it! It just took about 2 meters of yaml-configuration to get the storage setup. Now, for the server!
๐ Now, the server
First off, lets describe how to deploy the unleash-server Docker image.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: unleash-server
labels:
app: unleash-server
spec:
replicas: 1
template:
metadata:
labels:
app: unleash-server
spec:
containers:
- name: unleash-server
image: us.gcr.io/vibbioexpress/unleash-server:latest
imagePullPolicy: Always
ports:
- containerPort: 4242
env:
- name: NODE_ENV
value: 'production'
- name: DATABASE_URL
value: postgres://postgres:unleash@unleash-db.default/postgres
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
In order to expose it, we need to create a service.
apiVersion: v1
kind: Service
metadata:
name: unleash-server-service
annotations:
service.alpha.kubernetes.io/app-protocols: '{"http-port":"HTTP"}'
labels:
app: unleash-server
spec:
type: NodePort
selector:
app: unleash-server
ports:
- name: http-port
port: 80
targetPort: 4242
So far so good, but it would be beneficial for humans to be able to use the administration UI too. We will create an ingress for this and this one relies on a static IP in Google Cloud (see the documentation on how to do this)
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: unleash-server-ingress
labels:
app: unleash-server
annotations:
kubernetes.io/ingress.global-static-ip-name: unleash-server-ip
spec:
tls:
- secretName: ssl-secret
backend:
serviceName: unleash-server-service
servicePort: 80
Once all this is fired up, you should be able to visit your configured IP and see the administration UI ๐ ๐
Summarizing
In retrospect getting Unleash on Kubernetes Engine was quite simple. It just took some configuring and that was it.
NOTE! This write up is not recommended settings for a production environment. You should use secrets for credentials. In addition you should secure Unleash according to the documentation.