-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
18b2fd2
commit 0fda1a3
Showing
12 changed files
with
270 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
FROM python:3.9-alpine | ||
|
||
# Set the working directory | ||
WORKDIR /app | ||
|
||
# Copy the Python files into the container | ||
COPY main.py k8s_client.py ./ | ||
|
||
# Install additional dependencies from requirements.txt | ||
COPY requirements.txt . | ||
RUN pip install --no-cache-dir -r requirements.txt | ||
|
||
# Set the command to run the Python script | ||
CMD ["python", "main.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,70 @@ | ||
# leader-election | ||
# Leader Election with Kubernetes ConfigMap | ||
|
||
This project demonstrates a leader election algorithm using a ConfigMap in Kubernetes. The algorithm ensures that only one pod becomes the leader and performs specific tasks while other pods wait for their turn. | ||
|
||
## Prerequisites | ||
|
||
- Kubernetes cluster | ||
- `kubectl` command-line tool | ||
- Python 3.6 or later | ||
|
||
## Setup | ||
|
||
*1.* Clone the repository: | ||
```bash | ||
git clone <repository_url> | ||
``` | ||
*2.* Navigate to the project directory: | ||
```bash | ||
cd leader-election-k8s-configmap | ||
``` | ||
|
||
*3.* Install the required Python packages: | ||
|
||
```bash | ||
pip install -r requirements.txt | ||
``` | ||
|
||
## Usage | ||
Make sure you have a running Kubernetes cluster and the kubectl command-line tool properly configured to access the cluster. | ||
|
||
Deploy the leader election application: | ||
|
||
```bash | ||
kubectl apply -f deployment.yaml | ||
``` | ||
Monitor the logs of the pod to observe the leader election process: | ||
|
||
```bash | ||
kubectl logs -f <pod_name> | ||
``` | ||
Replace <pod_name> with the name of the pod running the leader election application. | ||
|
||
Modify the ConfigMap named leader-election to trigger a change in leadership: | ||
|
||
```bash | ||
kubectl edit configmap leader-election | ||
``` | ||
This will open the ConfigMap in your default text editor. Modify the leader field to change the leader. Save and close the file. | ||
|
||
Note: Ensure that the ConfigMap leader-election exists in the same namespace as the application. | ||
|
||
Observe the logs of the leader election application to see the leader change and pod restarts. | ||
|
||
## Cleanup | ||
To clean up the deployed resources, run the following command: | ||
|
||
```bash | ||
kubectl delete -f deployment.yaml | ||
``` | ||
This will delete the Deployment, and Kubernetes will automatically remove the associated pods. | ||
|
||
## Troubleshooting | ||
If the leader election process or pod restarts are not working as expected, you can check the following: | ||
|
||
Verify that the MY_POD_NAME and MY_POD_NAMESPACE environment variables are properly set in the pod. | ||
Check the logs of the pod for any error messages or issues. | ||
Ensure that the ConfigMap leader-election exists in the same namespace as the application. | ||
If you encounter any issues or have questions, please feel free to reach out for assistance. | ||
|
||
Happy leader election in Kubernetes! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
apiVersion: v1 | ||
kind: ConfigMap | ||
metadata: | ||
name: leader-election | ||
data: | ||
leader: "" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: my-deployment | ||
labels: | ||
app: my-app | ||
spec: | ||
replicas: 4 | ||
selector: | ||
matchLabels: | ||
app: my-app | ||
template: | ||
metadata: | ||
labels: | ||
app: my-app | ||
namespace: $(MY_POD_NAMESPACE) | ||
spec: | ||
serviceAccountName: pod-deleter | ||
containers: | ||
- name: my-container | ||
image: leader-election:0.0.1 | ||
command: ["python", "main.py"] | ||
env: | ||
- name: MY_POD_NAME | ||
valueFrom: | ||
fieldRef: | ||
fieldPath: metadata.name | ||
- name: MY_POD_NAMESPACE | ||
valueFrom: | ||
fieldRef: | ||
fieldPath: metadata.namespace | ||
resources: | ||
limits: | ||
cpu: 200m | ||
memory: 500Mi | ||
requests: | ||
cpu: 100m | ||
memory: 200Mi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from kubernetes import client, config, watch | ||
import os | ||
|
||
class K8sClient: | ||
def __init__(self): | ||
# Load the kube config | ||
config.load_incluster_config() | ||
self.v1 = client.CoreV1Api() | ||
|
||
def get_leader(self): | ||
try: | ||
# Get the 'leader-election' ConfigMap from the MY_POD_NAMESPACE namespace | ||
pod_namespace = os.getenv('MY_POD_NAMESPACE') | ||
|
||
config_map = self.v1.read_namespaced_config_map("leader-election", pod_namespace) | ||
# Return the 'leader' data from the ConfigMap | ||
return config_map.data["leader"] | ||
except client.exceptions.ApiException as e: | ||
# If the ConfigMap doesn't exist or 'leader' key doesn't exist, return None | ||
if e.status == 404: | ||
return None | ||
else: | ||
raise | ||
|
||
def set_leader(self): | ||
# Get the current pod name from the environment variable | ||
pod_name = os.getenv('MY_POD_NAME') | ||
|
||
# Update the 'leader' value in the 'leader-election' ConfigMap | ||
pod_namespace = os.getenv('MY_POD_NAMESPACE') | ||
try: | ||
# Get the existing ConfigMap | ||
config_map = self.v1.read_namespaced_config_map("leader-election", pod_namespace) | ||
# Update the 'leader' key with the current pod name | ||
config_map.data["leader"] = pod_name | ||
# Update the ConfigMap | ||
self.v1.replace_namespaced_config_map("leader-election", pod_namespace, config_map) | ||
print(f"Updated leader to '{pod_name}' in the ConfigMap.") | ||
except client.exceptions.ApiException as e: | ||
print(f"Failed to update leader in ConfigMap: {e}") | ||
|
||
def watch_configmap(self): | ||
# Create a watch object | ||
w = watch.Watch() | ||
|
||
# Start watching the 'leader-election' ConfigMap in the 'default' namespace | ||
pod_namespace = os.getenv('MY_POD_NAMESPACE') | ||
for event in w.stream(self.v1.list_namespaced_config_map, pod_namespace): | ||
# If the 'leader-election' ConfigMap is modified | ||
if event['object'].metadata.name == "leader-election" and event['type'] == 'MODIFIED': | ||
print("ConfigMap 'leader-election' has been modified") | ||
# Print the new data | ||
print(f"New data: {event['object'].data}") | ||
# Stop watching after a change is detected | ||
w.stop() | ||
|
||
def restart_pod(self): | ||
# Get the pod name from the environment variable set in the Deployment | ||
pod_name = os.getenv("MY_POD_NAME") | ||
|
||
# Delete the current pod | ||
try: | ||
pod_namespace = os.getenv('MY_POD_NAMESPACE') | ||
self.v1.delete_namespaced_pod(pod_name, pod_namespace) | ||
print(f"Pod {pod_name} deleted successfully. A new one will be recreated automatically.") | ||
except client.exceptions.ApiException as e: | ||
print(f"Failed to delete pod {pod_name}: {e}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import os | ||
import time | ||
from k8s_client import K8sClient | ||
|
||
|
||
|
||
def main(): | ||
k8s = K8sClient() | ||
pod_name = os.getenv('MY_POD_NAME') | ||
while True: | ||
leader = k8s.get_leader() | ||
if leader is None or leader == pod_name: | ||
# If there is no leader, or if this pod is the leader, | ||
# Watch for changes in the ConfigMap | ||
k8s.watch_configmap() | ||
k8s.restart_pod() | ||
time.sleep(5) | ||
else: | ||
# If this pod is not the leader, try to become the leader | ||
k8s.set_leader() | ||
time.sleep(5) | ||
|
||
if __name__ == '__main__': | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
kubernetes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
kind: Role | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
metadata: | ||
namespace: default | ||
name: configmap-writer | ||
rules: | ||
- apiGroups: [""] | ||
resources: ["configmaps"] | ||
verbs: ["get", "update", "delete"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
kind: Role | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
metadata: | ||
namespace: default | ||
name: configmap-reader | ||
rules: | ||
- apiGroups: [""] | ||
resources: ["configmaps"] | ||
verbs: ["get", "watch", "list"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
kind: RoleBinding | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
metadata: | ||
name: configmap-writer-binding | ||
namespace: default | ||
subjects: | ||
- kind: ServiceAccount | ||
name: default | ||
namespace: default | ||
roleRef: | ||
kind: Role | ||
name: configmap-writer | ||
apiGroup: rbac.authorization.k8s.io |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
kind: RoleBinding | ||
apiVersion: rbac.authorization.k8s.io/v1 | ||
metadata: | ||
name: configmap-reader-binding | ||
namespace: default | ||
subjects: | ||
- kind: ServiceAccount | ||
name: default | ||
namespace: default | ||
roleRef: | ||
kind: Role | ||
name: configmap-reader | ||
apiGroup: rbac.authorization.k8s.io |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
apiVersion: v1 | ||
kind: ServiceAccount | ||
metadata: | ||
name: pod-deleter | ||
namespace: default |