This is a foolish little program meant to help learn Kubernetes. The basic idea is that you deploy 4 services into a Kubernetes cluster:
ping
pong
ding
dong
Each service is actually just this program acting according to the environment
variable PPDD_MODE
- which should be set to one of the values above.
Each service calls another service with a message. The message includes the calling service's name and miscellaneous information to facilitate debugging and learning.
sequenceDiagram
participant Ping
participant Pong
participant Ding
participant Dong
Ping->>Pong: ping
Pong->>Ping: pong
Ping->>Ding: ping
Ding->>Ping: ding
Ding->>Dong: ding
Dong->>Ping: dong
The basic idea is that ping
periodically calls out to pong
and ding
.
The dong
service is opaque to ping
- it is activated by ding
.
Again, I said this is kind of stupid. It's meant to be just complicated enough to try some things out like upgrading individual services. I intend to extend it to play around with service mesh, gRPC, observability tools, etc.
The program accepts parameters via various environment variables.
PPDD_MODE
: required, sets the type of serviceHTTP_PORT
: (optional8080
) but useful to set if testing in a non-Kubernetes environmentNAMESPACE
: (optionaldefault
) Kubernetes namespace (set tolocalhost
if testing locally)PING_SVC
: (optionalping
)PING_PORT
: (optional8080
)PONG_SVC
: (optionalpong
)PONG_PORT
: (optional8080
)
Inside a cluster, the services will find each other via:
{PING_SVC}.{NAMESPACE}.svc.cluster.local
If NAMESPACE == localhost
then we assume you are just running the binaries
locally in different processes so the services will find each other via:
localhost:{PING_PORT}
The program exports the following endpoints.
GET /
: display the mode and various information about the servicePOST /
: send a JSON encoded message to the serviceGET /health
: JSON encoded health checkPOST /shutdown
: cleanly shutdown the service
The endpoint PUT /
accepts JSON encoded messages in the following format:
{
"Msg": "<string>"
}
Where <string>
is one of; ping
, pong
, ding
, or dong
.
# Start the program in a mode of your choice
PPDD_MODE=dong HTTP_PORT=8989 go run .
# In another terminal, run commands
curl localhost:8989/health
# {"Status":"OK"}
curl localhost:8989/
# Hello from: 127.0.0.1:8989:
# mode: dong
# operating system: darwin
# ...
curl -v -X POST localhost:8989/ \
-H 'Content-Type: application/json' \
-d '{"Msg": "ding"}'
curl -X POST localhost:8989/shutdown
# Shutting down
# Terminal 1
PPDD_MODE=dong \
HTTP_PORT=8083 \
NAMESPACE=localhost \
PING_PORT=8080 \
PONG_PORT=8081 \
DING_PORT=8082 \
DONG_PORT=8083 \
go run .
# Terminal 2
PPDD_MODE=ding \
HTTP_PORT=8082 \
NAMESPACE=localhost \
PING_PORT=8080 \
PONG_PORT=8081 \
DING_PORT=8082 \
DONG_PORT=8083 \
go run .
# Terminal 3
PPDD_MODE=pong \
HTTP_PORT=8081 \
NAMESPACE=localhost \
PING_PORT=8080 \
PONG_PORT=8081 \
DING_PORT=8082 \
DONG_PORT=8083 \
go run .
# Terminal 4
PPDD_MODE=ping \
HTTP_PORT=8080 \
NAMESPACE=localhost \
PING_PORT=8080 \
PONG_PORT=8081 \
DING_PORT=8082 \
DONG_PORT=8083 \
go run .
To run the tests locally and check coverage.
go test -v -cover -coverprofile=c.out .
go tool cover -html=c.out
There is a sample YAML file that uses the following K8s features:
- ConfigMap
- Secret
- Service
- Deployment
The secret is used to access GitHub's private container registry. You should follow the instructions on GitHub to create a Personal Access Token (PAT) with read access to the registry. Then create the K8s secret as below:
kubectl create secret docker-registry ghcr.io \
--docker-server=https://ghcr.io/v1/ \
--docker-username=michaelerickson \
[email protected] \
--docker-password=ghp_Wxxx
This will be references in a Pod as:
Use the secret in a Pod:
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: private-image:latest
imagePullSecrets:
- name: ghcr.io # <--- match name of secret you created above ---
Set the cluster up via helm or the base K8s files:
Helm
cd helm
# Install everything into the `ppdd` namespace, creating it if necessary
# Test first
helm install ppdd ./helm/ppdd --namespace=ppdd --create-namespace --dry-run
helm install ppdd ./helm/ppdd --namespace=ppdd --create-namespace
helm list
Base K8s files.
kubectl apply -f ppdd.yml
# Delete things later via:
kubectl delete -f ppdd.yml
# Debug the network by running a container with various networking diagnostic
# tools on it
kubectl run -it dnsutils --image gcr.io/kubernetes-e2e-test-images/dnsutils:1.3
nslookup pong
# Server: 10.43.0.10
# Address: 10.43.0.10#53
#
# Name: pong.default.svc.cluster.local
# Address: 10.43.147.93
wget http://pong.default.svc.cluster.local:8080/
# Connecting to pong.default.svc.cluster.local:8080 (10.43.147.93:8080)
# index.html 100% |**************************| 1165 0:00:00 ETA
cat index.html
# Hello from: 10.42.0.98:8080:
# mode: pong
# operating system: linux
# ...
# Remove the debug pod
exit # return to local terminal (ctl-d also works)
kubectl delete pods/dnsutils