Coding exercises and notes from the book "Distributed Services with Go" by Travis Jeffrey, March 2021, ISBN: 9781680507607
Building basic elements: storage layer, defining data structures.
A simple JSON over HTTP commit log service.
Added the proglog go module.
go mod init github.com/evdzhurov/dist-services-with-go/proglog
Added proglog/internal/server/log.go
Added proglog/internal/server/http.go
Added proglog/cmd/server/main.go
Test the API
go run main.go
curl -X POST localhost:8080 -d \
'{"record": {"value": "TGV0J3MgR28gIzEK"}}'
curl -X POST localhost:8080 -d \
'{"record": {"value": "TGV0J3MgR28gIzIK"}}'
curl -X POST localhost:8080 -d \
'{"record": {"value": "TGV0J3MgR28gIzMK"}}'
curl -X GET localhost:8080 -d '{"offset": 0}'
curl -X GET localhost:8080 -d '{"offset": 1}'
curl -X GET localhost:8080 -d '{"offset": 2}'
Set up protocol buffers, generate data structures, set up automation.
Added proglog/api/v1/log.proto
Install latest protobuf compiler
Install the latest go plugin for protobuf compiler
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
Added proglog/Makefile
Build a commit log library as the core of the service for storing and retrieving data.
Added proglog/internal/log/store.go
Added proglog/internal/log/store_test.go
Added proglog/internal/log/index.go
Added proglog/internal/log/index_test.go
Added proglog/internal/log/segment.go
Added proglog/internal/log/segment_test.go
Added proglog/internal/log/log.go
Added proglog/internal/log/log_test.go
Make services work over a network.
Set up gRPC, define our server and client APIs, build client and server.
Install gRPC protobuf support
go install google.golang.org/grpc@v1.32.0
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.0.0
Updated the 'compile-proto' Makefile command to include gRPC
Added proglog/internal/server/server.go
Added proglog/api/v1/error.go
Added proglog/internal/server/server_test.go
Secure connections by authenticating with SSL/TLS and using access tokens.
Install CloudFlare CLIs:
go install github.com/cloudflare/cfssl/cmd/cfssl@v1.4.1
go install github.com/cloudflare/cfssl/cmd/cfssljson@v1.4.1
Added proglog/test/ca-csr.json
Added proglog/test/ca-config.json
Added proglog/test/server-csr.json
Update the proglog/Makefile
Added proglog/internal/config/files.go
Added proglog/internal/config/tls.go
Modify proglog/internal/server/server_test.go
Added proglog/test/client-csr.json
Modify proglog/Makefile
Modify proglog/internal/config/files.go
Modify proglog/internal/server/server_test.go
Install the ACL library Casbin
go get github.com/casbin/casbin@v1.9.1
Added proglog/internal/auth/authorizer.go
Modify proglog/Makefile
Run 'make gencert' to generate the new client certificates
Modify proglog/internal/server/server_test.go
Modify proglog/internal/config/files.go
Added proglog/test/model.conf and proglog/test/policy.csv
Modify proglog/internal/server/server_test.go
Modify proglog/internal/server/server.go
Modify proglog/internal/server/server_test.go
Make our service observable by adding logs, metrics and tracing.
Add OpenCensus (metrics, tracing) and Uber's Zap (logging) dependencies
go get go.uber.org/zap@v1.10.0
go get go.opencensus.io@v0.22.2
Modify proglog/internal/server/server.go
Modify proglog/internal/server/server_test.go
Run debug-enabled tests
cd internal/server
go test -v -debug=true
Make our service distributed, highly available, resilient and scalable.
Build discovery into our service and make server instances aware of each other.
Install Serf
go get github.com/hashicorp/serf@v0.8.5
Added proglog/internal/discovery/membership.go
Added proglog/internal/discovery/membership_test.go
Added proglog/internal/log/replicator.go
Added proglog/internal/agent/agent.go
Added proglog/internal/agent/agent_test.go
Add consensus to coordinate our servers and turn them into a cluster.
Install Raft
go get github.com/hashicorp/raft@v1.1.1
# use etcd's fork of Ben Johnson's Bolt key/value store,
# which includes fixes for Go 1.14+
go mod edit -replace github.com/hashicorp/raft-boltdb=\
github.com/travisjeffery/raft-boltdb@v1.0.0
Added proglog/internal/log/distributed.go
Modify proglog/internal/log/config.go
Modify proglog/internal/log/distributed.go
Modify proglog/api/v1/log.proto
Modify proglog/internal/log/distributed.go
Modify proglog/internal/log/distributed.go
Modify proglog/internal/discovery/membership.go
Modify proglog/internal/log/distributed.go
Many distributed services that use Raft multiplex Raft with other services like an RPC service.
Added proglog/internal/agent/agent.go
Modify proglog/internal/agent/agent_test.go
Add discovery in our gRPC clients so they can connect to the server with client-side load balancing.
Enable clients to:
Load-balancing strategies:
Modify proglog/api/v1/log.proto
Modify proglog/internal/log/distributed.go
Modify proglog/internal/log/distributed_test.go
Modify proglog/internal/server/server.go
Modify proglog/internal/agent/agent.go
Added proglog/internal/loadbalance/resolver.go
Added proglog/internal/loadbalance/resolver_test.go
In the gRPC architecture pickers perform request-routing logic.
Added proglog/internal/loadbalance/picker.go
Added proglog/internal/loadbalance/picker_test.go
Modify proglog/internal/agent/agent_test.go
Deploy our service and make it live.
Set up Kubernetes locally and run a cluster on your machine. Prepare to deploy on the Cloud.
Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)\
/bin/linux/amd64/kubectl"
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
Install Kind (Kubernetes in Docker) tool.
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.8.1/kind-$(uname)-amd64
chmod +x ./kind
mv ./kind /usr/local/bin/kind
Install Docker
Create a Kind cluster
kind create cluster
kubectl cluster-info
Added proglog/cmd/proglog/Dockerfile
Modify proglog/Makefile
Build the image and load it into our Kind cluster.
make build-docker
kind load docker-image github.com/evdzhurov/dist-services-with-go/proglog:0.0.1
Helm definitions:
Install Helm
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
Explore Helm by installing a chart for nginx
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-nginx bitnami/nginx
helm list
./test-helm-nginx.sh
helm uninstall my-nginx
Create a Helm chart for our service
mkdir deploy && cd deploy
helm create proglog
helm template proglog
rm proglog/templates/**/*.yaml proglog/templates/NOTES.txt
Kubernetes probes:
Modify proglog/internal/server/server.go
Modify proglog/deploy/proglog/templates/statefulset.yaml
Modify proglog/Dockerfile
Modify proglog/internal/log/config.go
Modify proglog/internal/log/distributed.go
Modify proglog/internal/log/distributed_test.go
Modify proglog/internal/agent/agent.go
Modify proglog/deploy/proglog/values.yaml
Install the chart:
helm install proglog deploy/proglog
Added proglog/cmd/getservers/main.go
Forward a pod port to a port on our machine
kubectl port-forward pod/proglog-0 8400
Run the getservers command
go run cmd/getservers/main.go
Create a Kubernetes cluster on Google Cloud's Kubernetes Engine and deploy our service to the Cloud.
Set the Google Cloud project
gcloud auth login
PROJECT_ID=$(gcloud projects list | tail -n 1 | cut -d' ' -f1)
gcloud config set project $PROJECT_ID
Push the image to GCR
gcloud auth configure-docker
docker tag github.com/evdzhurov/dist-services-with-go/proglog:0.0.1 gcr.io/$PROJECT_ID/proglog:0.0.1
docker push gcr.io/$PROJECT_ID/proglog:0.0.1
Configure kubectl
gcloud container clusters get-credentials proglog --zone europe-central2-a
Metacontroller is a Kubernetes add-on that makes it easy to write and deploy custom controllers with simple scripts.
Use Helm to install Metacontroller
cd deploy
helm create metacontroller
rm metacontroller/templates/*.yaml metacontroller/templates/NOTES.txt metacontroller/values.yaml
MC_URL=https://raw.githubusercontent.com/GoogleCloudPlatform/metacontroller/master/manifests
curl -L $MC_URL/metacontroller-rbac.yaml > metacontroller/templates/metacontroller-rbac.yaml
curl -L $MC_URL/metacontroller.yaml > metacontroller/templates/metacontroller.yaml
kubectl create namespace metacontroller
helm install metacontroller metacontroller
Added proglog/deploy/proglog/templates/service-per-pod.yaml
Added proglog/deploy/proglog/hooks/create-service-per-pod.jsonnet
Added proglog/deploy/proglog/hooks/delete-service-per-pod.jsonnet
Modify proglog/deploy/proglog/templates/statefulset.yaml
helm install proglog proglog --set image.repository=gcr.io/$PROJECT_ID/proglog --set service.lb=true
./test-getservers-cloud.sh