diff --git a/meta-operator/README.md b/meta-operator/README.md new file mode 100644 index 0000000..f09d477 --- /dev/null +++ b/meta-operator/README.md @@ -0,0 +1,2 @@ +kubectl create namespace meta-operator +kubectl apply -f application.yml -f keydb.yml diff --git a/meta-operator/application.yml b/meta-operator/application.yml new file mode 100644 index 0000000..a27a1fc --- /dev/null +++ b/meta-operator/application.yml @@ -0,0 +1,205 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusteroperators.codemowers.io +spec: + group: codemowers.io + names: + plural: clusteroperators + singular: clusteroperator + kind: ClusterOperator + shortNames: + - clusteroperator + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + resource: + type: object + properties: + group: + type: string + version: + type: string + plural: + type: string + secret: + type: object + properties: + name: + type: string + enabled: + type: boolean + structure: + type: array + items: + type: object + properties: + key: + type: string + value: + type: string + services: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + deployments: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + statefulsets: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + configmaps: + type: array + items: + type: object + x-kubernetes-preserve-unknown-fields: true + required: ["spec"] +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: meta-operator + namespace: meta-operator + labels: + app.kubernetes.io/name: meta-operator +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: meta-operator + template: + metadata: + labels: + app.kubernetes.io/name: meta-operator + spec: + serviceAccountName: meta-operator + containers: + - name: meta-operator + image: harbor.k-space.ee/k-space/meta-operator + securityContext: + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +--- +apiVersion: codemowers.io/v1alpha1 +kind: ClusterOperator +metadata: + name: meta +spec: + resource: + group: codemowers.io + version: v1alpha1 + plural: clusteroperators + secret: + enabled: false + deployments: + - apiVersion: apps/v1 + kind: Deployment + metadata: + name: foobar-operator + labels: + app.kubernetes.io/name: foobar-operator + spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: foobar-operator + template: + metadata: + labels: + app.kubernetes.io/name: foobar-operator + spec: + serviceAccountName: meta-operator + containers: + - name: meta-operator + image: harbor.k-space.ee/k-space/meta-operator + command: + - /meta-operator.py + - --target + - foobar + securityContext: + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: meta-operator +rules: +- apiGroups: + - "" + resources: + - secrets + - configmaps + - services + verbs: + - create + - get + - patch + - update + - delete + - list +- apiGroups: + - apps + resources: + - deployments + - statefulsets + verbs: + - create + - delete + - list + - update +- apiGroups: + - codemowers.io + resources: + - clusteroperators + - keydbs + verbs: + - get + - list + - watch +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: meta-operator + namespace: meta-operator +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: meta-operator +subjects: +- kind: ServiceAccount + name: meta-operator + namespace: meta-operator +roleRef: + kind: ClusterRole + name: meta-operator + apiGroup: rbac.authorization.k8s.io + diff --git a/meta-operator/keydb.yml b/meta-operator/keydb.yml new file mode 100644 index 0000000..4f24e57 --- /dev/null +++ b/meta-operator/keydb.yml @@ -0,0 +1,256 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: keydbs.codemowers.io +spec: + group: codemowers.io + names: + plural: keydbs + singular: keydb + kind: KeyDBCluster + shortNames: + - keydb + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + replicas: + type: integer + description: Replica count + required: ["spec"] +--- +apiVersion: codemowers.io/v1alpha1 +kind: ClusterOperator +metadata: + name: keydb +spec: + resource: + group: codemowers.io + version: v1alpha1 + plural: keydbs + secret: + enabled: true + name: foobar-secrets + structure: + - key: REDIS_PASSWORD + value: "%s" + - key: REDIS_URI + value: "redis://:%s@foobar" + configmaps: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: foobar-scripts + labels: + app.kubernetes.io/name: foobar + data: + entrypoint.sh: | + #!/bin/bash + set -euxo pipefail + host="$(hostname)" + port="6379" + replicas=() + for node in {0..2}; do + if [ "${host}" != "redis-${node}" ]; then + replicas+=("--replicaof redis-${node}.redis-headless ${port}") + fi + done + exec keydb-server /etc/keydb/redis.conf \ + --active-replica "yes" \ + --multi-master "yes" \ + --appendonly "no" \ + --bind "0.0.0.0" \ + --port "${port}" \ + --protected-mode "no" \ + --server-threads "2" \ + --masterauth "${REDIS_PASSWORD}" \ + --requirepass "${REDIS_PASSWORD}" \ + "${replicas[@]}" + ping_readiness_local.sh: |- + #!/bin/bash + set -e + [[ -n "${REDIS_PASSWORD}" ]] && export REDISCLI_AUTH="${REDIS_PASSWORD}" + response="$( + timeout -s 3 "${1}" \ + keydb-cli \ + -h localhost \ + -p 6379 \ + ping + )" + if [ "${response}" != "PONG" ]; then + echo "${response}" + exit 1 + fi + ping_liveness_local.sh: |- + #!/bin/bash + set -e + [[ -n "${REDIS_PASSWORD}" ]] && export REDISCLI_AUTH="${REDIS_PASSWORD}" + response="$( + timeout -s 3 "${1}" \ + keydb-cli \ + -h localhost \ + -p 6379 \ + ping + )" + if [ "${response}" != "PONG" ] && [[ ! "${response}" =~ ^.*LOADING.*$ ]]; then + echo "${response}" + exit 1 + fi + cleanup_tempfiles.sh: |- + #!/bin/bash + set -e + find /data/ -type f \( -name "temp-*.aof" -o -name "temp-*.rdb" \) -mmin +60 -delete + services: + - apiVersion: v1 + kind: Service + metadata: + name: foobar-headless + labels: + app.kubernetes.io/name: foobar + spec: + type: ClusterIP + clusterIP: None + ports: + - name: "server" + port: 6379 + protocol: TCP + targetPort: redis + selector: + app.kubernetes.io/name: foobar + - apiVersion: v1 + kind: Service + metadata: + name: foobar + labels: + app.kubernetes.io/name: foobar + annotations: + {} + spec: + type: ClusterIP + ports: + - name: "server" + port: 6379 + protocol: TCP + targetPort: redis + - name: "redis-exporter" + port: 9121 + protocol: TCP + targetPort: redis-exporter + selector: + app.kubernetes.io/name: foobar + sessionAffinity: ClientIP + statefulsets: + - apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: foobar + labels: + app.kubernetes.io/name: foobar + spec: + replicas: 3 + serviceName: foobar-headless + selector: + matchLabels: + app.kubernetes.io/name: foobar + template: + metadata: + annotations: + prometheus.io/port: "9121" + prometheus.io/scrape: "true" + labels: + app.kubernetes.io/name: foobar + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - 'foobar' + topologyKey: kubernetes.io/hostname + weight: 100 + containers: + - name: redis + image: eqalpha/keydb:x86_64_v6.3.1 + imagePullPolicy: Always + command: + - /scripts/entrypoint.sh + ports: + - name: redis + containerPort: 6379 + protocol: TCP + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + # One second longer than command timeout should prevent generation of zombie processes. + timeoutSeconds: 6 + successThreshold: 1 + failureThreshold: 5 + exec: + command: + - sh + - -c + - /scripts/ping_liveness_local.sh 5 + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + # One second longer than command timeout should prevent generation of zombie processes. + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 5 + exec: + command: + - sh + - -c + - /scripts/ping_readiness_local.sh 1 + startupProbe: + periodSeconds: 5 + # One second longer than command timeout should prevent generation of zombie processes. + timeoutSeconds: 2 + failureThreshold: 24 + exec: + command: + - sh + - -c + - /scripts/ping_readiness_local.sh 1 + resources: + {} + securityContext: + {} + volumeMounts: + - name: foobar-scripts + mountPath: /scripts + - name: foobar-data + mountPath: /data + envFrom: + - secretRef: + name: foobar-secrets + - name: redis-exporter + image: quay.io/oliver006/redis_exporter + ports: + - name: metrics + containerPort: 9121 + envFrom: + - secretRef: + name: foobar-secrets + securityContext: + {} + volumes: + - name: foobar-scripts + configMap: + name: foobar-scripts + defaultMode: 0755 + - name: foobar-data + emptyDir: {}