monorepo-kubernetes-continuous-delivery
monorepo-kubernetes-continuous-delivery copied to clipboard
Example of Continuous delivery with Kubernetes and Monorepo
Example of Continuous Delivery with Kubernetes and Monorepo
Features
- Google Cloud Platform support - create new test cluster on each commit for test runs
- Docker for Mac support - deploy, run and test everything locally
- Integration tests made easy
- Pushback logic - easy to implement commit bots
TLDR show me the code
.circleci/ci.sh has all functions for cluster creation, putting it down, etc.
Suggested workflow
Once PR is made CI would create new Kuberentes cluster, deploy all apps, run all integration, optionally push back changes back to the branch, destroy test environment
Once PR is merged - deploy all new apps to production cluster. Google Container Builder is used for image building
Local development/deployment
-
./run.sh build [FILTER]
- build, whereFILTER
is an optional podname -
./run.sh test [FILTER]
- build and test, whereFILTER
is an optional podname -
./run.sh switch [ENV]
- switch environment, whereENV
isprod
or empty for local env -
./run.sh expose [EXPOSE]
- expose pod from kubernetes to local machine, where EXPOSE ispodname
ORpodname:podport
orpodname1:podport1 podname2:podport2 ...
Setup
Starting point is .circleci/config.yml. It's CircleCI config, but it's used only as an example and you can achieve exactly the same with Travis or self hosted solutions like Jenkins. Properties:
-
PROJECT
- Google Cloud Platform project to use -
PROD_CLUSTER
- Production cluster name -
NAMESPACE
- Google Container Registry namespace to use (gcr.io, eu.gcr.io, etc.) -
COMPUTE_ZONE
- Google Cloud Platform zone to use for new cluster creation -
ISOLATION
- Eithercluster
ornamespace
. First creates new cluster for each CI session, but it takes around 3m to start and kill the cluster.namespace
isolation takes seconds to start and kill, but as it uses production cluster it may impact other apps there
git commands are needed if you would like to have pushback logic (described latter)
Google Cloud Platform setup
Service account key with project access has to be presented as base64 string in GC_SERVICE_KEY
environment variable. You may find how to do it here https://circleci.com/docs/1.0/google-auth/. Also service account has to have Kubernetes Engine Admin
role. You can add it on IAM page - https://console.cloud.google.com/iam-admin/iam/project. Find your service account (most probably [NUMBER][email protected]
) and add Kubernetes Engine Admin
role there. This role is required for new Kubernetes service account creation which is needed for accessing Kubernetes API from inside the pod
Production cluster setup
You can do it in Google Cloud Platform UI or simply via command like
gcloud container clusters create [NAME] \
--cluster-version 1.8.5-gke.0 \
--disk-size 100 \
--machine-type g1-small \
--num-nodes 3
Local cluster
Install latest Docker for Mac with Kubernetes support then:
-
ENV=local PROJECT=test ACTION=build FILTER='' bash .circleci/ci.sh
- rebuild all Docker images and redeploy all services and apps into local cluster -
ENV=local PROJECT=test ACTION=test FILTER='' bash .circleci/ci.sh
- rebuild all and then run all integrations in local cluster context
If you want to build/test only one app then set filter like FILTER=front
. Those command are hard to remember, so Makefile with those aliases is provided. Simply run make build
or make test
or use your favorite other build tool.
You can access pods on your local cluster using kubectl port-forward
Directory structure
-
apps
- folder for your pods, more info in apps. Example app apps/front -
jobs
- folder for your jobs, more info in jobs. Example job jobs/init-kafka-data -
services
- folder for your statefulsets, more info in services. Example service services/2-kafka
Integrations
For tests you may create [integration-name].integration
files which are essentially Dockerfiles. Once all apps and services got deployed to test environment then all integrations will run, meaning you can run any kind of integration tests against your cluster there
Pushback integrations
Traditionally CI were treated as read only workflow, but it opens new possibilities if you allow your CI to push changes as well.
Take an example of code format - your CI knows exactly how code should look like regarding spaces, semicolons, etc. and yet once it found that something is not right it just fails the build and that's it. But now many linters (tslint, eslint, etc.) has --fix
flag which allows to fix those errors, and that exactly what pushback logic it meant for.
Example with prettier, just create prettier.integration
with content like:
FROM node
WORKDIR /srv
RUN npm install prettier --global --silent
CMD prettier --write "*.js"
All integration has it's current folder mapped into /srv
and any changes made there would be commited back to your branch. It works rather well for pull requests