It's been 4 p.m. Sunday when I've started. I've been quite busy this week to properly understand and think about task, and now with a tiny bit of regret I acknowledge, that should've discussed couple of questions:
For this test I would love to omit Kubernetes cluster configutation in the cloud. I decided that cloud infrastructure should be out of scope of this service. And treat this as I would treat a project repo. Thus it should contain everything needed to develop application locally, and when it comes to cloud deploy, only contain application deployment scripts as if infrastructure is already in place.
Key requirements:
- The entire solution should be able to run on an fresh ubuntu VM.
- High-availability
- No changes to application logic
- Redis has to be password protected
- Should run on Ubuntu
So. First I decided to work on the application deployment. I decided to compile go code locally for simplicity (it will work on Ubuntu anyway), the better way would be to use docker to build the code. I quickly discovered that gin version is quite old and code would not run. First I though on changing the code, but then I decided not to touch it as infrastructure my main consern. Application itself is a stateless so I picked kubernetes_deployment to publish it. I've introduced replica count setting to control scaling and added LoadBalancer. I've studied through github issues and found version where route handling based on priority was introduces. Updated go.mod and switched to redis deployment. With redis I picked StatefulDeployment and created volume claims that locally reserve volumes on host path. In cloud those can be provisioned differently First I tried to set up Redis cluster, but due docker port mapping functionality I was not able to achieve any sensible result, cluster node could not get MEET command (after completing this test task I think that I've most likely mistaken somewhere). Then I tried to deploy a twemproxy with several Redis servers backed by replicas behind it. But twemproxy connection and sharding model assumes that clients are not using passwords to authenticate, which conflicted with requirements. By this point I've ran out of options and started working on Redis with Sentinel processes. That worked well.
Cluster mode amd twemproxy approach are an overkill for this test task as they also give an ability to scale horisontally, which is not required.
- Locally developers run docker.app with kubernetes support
- Developers have proper C++ compilers to compile Go (compilation can be done inside docker as well, but for some reason, I decided not to do that)
- Supported clouds? later I've dropped cloud support due to time restrictions.
src
- contains service codedeployment
- contains all needed to build (ikr) and deploy applicationdocker
- contains dockerfiles neededterraform
- contains all terraform configs_modules
counter
- go application deployemtnredis
- HA redis with sentinel deployment
local
- terraform scripts to deploy to local cluster (local, because it creates all resources, cloud deployment assumes that cloud infrastructure is already prepared)
build
- contains build artefacts (binaries), excluded from git
Makefile is a main entrypoint for developer
make buildbinaries
- will produce go binary of the counter app and store it in build
folder
make builddocker
- will call buildbinaries first then produce docker image tagged devops/counter
make refresh
- builds docker and restarts counter service. Used to quickly refresh code during local development
make deploy
- runs terrraform apply
in local
folder. Deploys all changes to kubernetes cluster aliased as minikube
Due to short amount of time I wasn't able to automate and debug dependency configuration on Ubuntu VM.
- First you need to install kubernetes server. I would suggest using
minikube
. Installation instructions are here https://minikube.sigs.k8s.io/docs/start/. - Install docker. https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository. IMPORTANT Check this section: https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
- Start minikube
minikube start
# If you are using single core VM then add arguments:
# --extra-config=kubeadm.ignore-preflight-errors=NumCPU --force --cpus=1
- Setup docker cli.
eval $(minikube docker-env)
- Clone this repo
git clone https://github.com/baitcode/devops-test-redis-ha.git
- Install Make and golang
sudo apt install -y make golang
- Install terraform (https://developer.hashicorp.com/terraform/downloads)
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform
-
Install kubectl. https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-using-native-package-management
-
Build docker and deploy
cd devops-test-redis-ha/
make deploy
- Expose port.
kubectl -n counter port-forward --address 0.0.0.0 services/counter 8080:8080
- VM configuration scripts
- Integration tests
- Test that nodes connect back to cluster after going online
- Build binaries with docker
- Easy way to configure kubectl context name aliases
- Cloud ready solution
- Finish developer flow section
Current solution was well tested using dockerapp If you have it installed then all you need for whole thing to work is create alias for docker-desktop context with name "minikube". From that point make deploy should work. Well dependencies have to be installed:
terraform and make