Customise k8s-sidecar 04/1404/1
authorxinhuili <lxinhui@vmware.com>
Wed, 14 Aug 2019 06:29:20 +0000 (14:29 +0800)
committerxinhuili <lxinhui@vmware.com>
Wed, 14 Aug 2019 06:29:20 +0000 (14:29 +0800)
This patch is to enable customization in k8s-sidecar.

Signed-off-by: XINHUI LI <lxinhui@vmware.com>
Change-Id: I8d856b00209e40bd5fb7a6e54ad99655768e6395

src/k8s-sidecar/.gitignore [new file with mode: 0644]
src/k8s-sidecar/Dockerfile [new file with mode: 0644]
src/k8s-sidecar/LICENSE [new file with mode: 0644]
src/k8s-sidecar/README.md [new file with mode: 0644]
src/k8s-sidecar/example.yaml [new file with mode: 0644]
src/k8s-sidecar/sidecar/sidecar.py [new file with mode: 0644]

diff --git a/src/k8s-sidecar/.gitignore b/src/k8s-sidecar/.gitignore
new file mode 100644 (file)
index 0000000..249963d
--- /dev/null
@@ -0,0 +1,2 @@
+*.iml
+.idea/
\ No newline at end of file
diff --git a/src/k8s-sidecar/Dockerfile b/src/k8s-sidecar/Dockerfile
new file mode 100644 (file)
index 0000000..76794d8
--- /dev/null
@@ -0,0 +1,6 @@
+FROM       python:3.6-slim-stretch
+RUN        pip install kubernetes==6.0.0
+COPY       sidecar/sidecar.py /app/
+ENV         PYTHONUNBUFFERED=1
+WORKDIR    /app/
+CMD [ "python", "-u", "/app/sidecar.py" ]
diff --git a/src/k8s-sidecar/LICENSE b/src/k8s-sidecar/LICENSE
new file mode 100644 (file)
index 0000000..51bcf2b
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Kiwigrid GmbH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/k8s-sidecar/README.md b/src/k8s-sidecar/README.md
new file mode 100644 (file)
index 0000000..dcb5202
--- /dev/null
@@ -0,0 +1,37 @@
+
+[![Docker Automated build](https://img.shields.io/docker/automated/kiwigrid/k8s-sidecar.svg)](https://hub.docker.com/r/kiwigrid/k8s-sidecar/)
+[![Docker Build Status](https://img.shields.io/docker/build/kiwigrid/k8s-sidecar.svg)](https://hub.docker.com/r/kiwigrid/k8s-sidecar/)
+
+# What?
+
+This is a docker container intended to run inside a kubernetes cluster to collect config maps with a specified label and store the included files in an local folder. The main target is to be run as a sidecar container to supply an application with information from the cluster. The contained python script is working with the Kubernetes API 1.10
+
+# Why?
+
+Currently (April 2018) there is no simple way to hand files in configmaps to a service and keep them updated during runtime.
+
+# How?
+
+Run the container created by this repo together you application in an single pod with a shared volume. Specify which label should be monitored and where the files should be stored.
+
+# Features
+
+- Extract files from config maps
+- Filter based on label
+- Update/Delete on change of configmap
+
+# Usage
+
+Example for a simple deployment can be found in `example.yaml`. Depending on the cluster setup you have to grant yourself admin rights first: `kubectl create clusterrolebinding cluster-admin-binding   --clusterrole cluster-admin   --user $(gcloud config get-value account)`
+
+## Configuration Environment Variables
+
+- `LABEL` 
+  - description: Label that should be used for filtering
+  - required: true
+  - type: string
+
+- `FOLDER`
+  - description: Folder where the files should be placed
+  - required: true
+  - type: string
diff --git a/src/k8s-sidecar/example.yaml b/src/k8s-sidecar/example.yaml
new file mode 100644 (file)
index 0000000..8f7b0f7
--- /dev/null
@@ -0,0 +1,75 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: sample-deployment
+  labels:
+    app: sample
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: sample
+  template:
+    metadata:
+        labels:
+          app: sample
+    spec:
+      serviceAccountName: sample-acc
+      containers:
+      - name: bash
+        image: bash:4.4.19
+        volumeMounts:
+        - name: shared-volume
+          mountPath: /tmp/
+        command: ["watch"]
+        args: ["ls", "/tmp/"]
+      - name: sidecar
+        image: kiwigrid/k8s-sidecar:latest
+        volumeMounts:
+        - name: shared-volume
+          mountPath: /tmp/
+        env:
+        - name: LABEL
+          value: "findme"
+        - name: FOLDER
+          value: /tmp/
+      volumes:
+      - name: shared-volume
+        emptyDir: {}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: sample-configmap
+  labels:
+    findme: "yea"
+data:
+  hello.world: |-
+     Hello World!
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: sample-role
+rules:
+- apiGroups: [""]
+  resources: ["configmaps"]
+  verbs: ["get", "watch", "list"]
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: sample-acc
+---
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: sample-rolebind
+roleRef:
+  kind: ClusterRole
+  name: cluster-admin
+  apiGroup: rbac.authorization.k8s.io
+subjects:
+- kind: ServiceAccount
+  name: sample-acc
+  namespace: default
diff --git a/src/k8s-sidecar/sidecar/sidecar.py b/src/k8s-sidecar/sidecar/sidecar.py
new file mode 100644 (file)
index 0000000..fcb186a
--- /dev/null
@@ -0,0 +1,58 @@
+from kubernetes import client, config, watch
+import os
+import sys
+
+
+def writeTextToFile(folder, filename, data):
+    with open(folder +"/"+ filename, 'w') as f:
+        f.write(data)
+        f.close()
+
+
+def removeFile(folder, filename):
+    completeFile = folder +"/"+filename
+    if os.path.isfile(completeFile):
+        os.remove(completeFile)
+    else:
+        print("Error: %s file not found" % completeFile)
+
+
+def watchForChanges(label, targetFolder):
+    v1 = client.CoreV1Api()
+    w = watch.Watch()
+    for event in w.stream(v1.list_config_map_for_all_namespaces):
+        if event['object'].metadata.labels is None:
+            continue
+        print("Working on configmap %s" % event['object'].metadata.name)
+        if label in event['object'].metadata.labels.keys():
+            print("Configmap with label found")
+            dataMap=event['object'].data
+            if dataMap is None:
+                print("Configmap does not have data.")
+                continue
+            eventType = event['type']
+            for filename in dataMap.keys():
+                print("File in configmap %s %s" % (filename, eventType))
+                if (eventType == "ADDED") or (eventType == "MODIFIED"):
+                    writeTextToFile(targetFolder, filename, dataMap[filename])
+                else:
+                    removeFile(targetFolder, filename)
+
+
+def main():
+    print("Starting config map collector")
+    label = os.getenv('LABEL')
+    if label is None:
+        print("Should have added LABEL as environment variable! Exit")
+        return -1
+    targetFolder = os.getenv('FOLDER')
+    if targetFolder is None:
+        print("Should have added FOLDER as environment variable! Exit")
+        return -1
+    config.load_incluster_config()
+    print("Config for cluster api loaded...")
+    watchForChanges(label, targetFolder)
+
+
+if __name__ == '__main__':
+    main()