Kubernetes Custom Resource Definitions (CRDs)


Делаю: 22.04.2020


https://github.com/burrsutter/9stepsawesome/blob/master/11_crds.adoc


https://github.com/burrsutter/9stepsawesome/tree/master/pizzas


$ cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: pizzas.mykubernetes.burrsutter.com
  labels:
    app: pizzamaker
    mylabel: stuff
spec:
  group: mykubernetes.burrsutter.com
  scope: Namespaced
  version: v1beta2
  names:
    kind: Pizza
    listKind: PizzaList
    plural: pizzas
    singular: pizza
    shortNames:
    - pz
  validation:
    openAPIV3Schema:
      type: object
      properties:
        spec:
          type: object
          properties:
            toppings:
              type: array
            sauce:
              type: string
EOF


$ kubectl get crds
NAME                                 CREATED AT
pizzas.mykubernetes.burrsutter.com   2020-04-21T20:50:35Z


$ kubectl create namespace pizzahat
$ kubectl config set-context --current --namespace=pizzahat
$ cat <<EOF | kubectl apply -f -
apiVersion: mykubernetes.burrsutter.com/v1beta2
kind: Pizza
metadata:
  name: burrcheese
spec:
  toppings:
  - mozzarella
  sauce: regular
EOF


$ kubectl get pizzas
NAME         AGE
burrcheese   47s


$ kubectl describe pizza burrcheese

$ kubectl api-resources | grep burr
pizzas                            pz           mykubernetes.burrsutter.com    true         Pizza


Make more Pizzas

$ cat <<EOF | kubectl apply -f -
apiVersion: mykubernetes.burrsutter.com/v1beta2
kind: Pizza
metadata:
  name: burrmeats
spec:
  toppings:
  - mozzarella
  - pepperoni
  - sausage
  - bacon
  sauce: extra
EOF
$ cat <<EOF | kubectl apply -f -
apiVersion: mykubernetes.burrsutter.com/v1beta2
kind: Pizza
metadata:
  name: burrveggie2
spec:
  toppings:
  - mozzarella
  - black olives
  sauce: extra
EOF
$ kubectl get pizzas --all-namespaces

$ kubectl get pizzas --all-namespaces
NAMESPACE   NAME          AGE
pizzahat    burrcheese    5m16s
pizzahat    burrmeats     5s
pizzahat    burrveggie2   10s


$ kubectl delete pizzas --all


Controllers

$ kubectl create namespace metacontroller

$ kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/metacontroller/master/manifests/metacontroller-rbac.yaml

$ kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/metacontroller/master/manifests/metacontroller.yaml

$ kubectl config set-context --current --namespace=metacontroller

$ kubectl get pods
NAME               READY   STATUS    RESTARTS   AGE
metacontroller-0   1/1     Running   0          2m26s
$ cat <<EOF | kubectl apply -f -
apiVersion: metacontroller.k8s.io/v1alpha1
kind: CompositeController
metadata:
  name: pizza-controller
spec:
  generateSelector: true
  parentResource:
    apiVersion: mykubernetes.burrsutter.com/v1beta2
    resource: pizzas
  childResources:
  - apiVersion: v1
    resource: pods
    updateStrategy:
      method: Recreate
  hooks:
    sync:
      webhook:
        url: http://pizza-controller.pizzahat:8080/sync
EOF
$ touch ~/tmp/sync.py
$ cat > ~/tmp/sync.py << EOF
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import json
import logging

class Controller(BaseHTTPRequestHandler):
  def sync(self, parent, children):

    # Compute status based on observed state.
    desired_status = {
       "pods": 1
    }

    # Collect the specifications
    name = parent["metadata"]["name"]
    sauce = parent.get("spec", {}).get("sauce")
    toppings = parent.get("spec",{}).get("toppings")
    print("\n\nsauce: %s" % sauce)
    print("toppings: %s" % toppings)
    for topping in toppings:
      print(topping)

    stuff = ' ' + sauce + ' ' + ' '.join(toppings) + ' of ' + name

    print stuff

    # Generate the desired child object(s)

    desired_pods = [
      {
        "apiVersion": "v1",
        "kind": "Pod",
        "metadata": {
          "name": name
        },
        "spec": {
          "restartPolicy": "OnFailure",
          "containers": [
            {
              "name": "pizza",
              "image": "busybox",
              "command": ["echo", "requested pizza: %s" % stuff]
            }
          ]
        }
      }
    ]

    return {"status": desired_status, "children": desired_pods}

  def do_POST(self):
    # Serve the sync() function as a JSON webhook.

    observed = json.loads(self.rfile.read(int(self.headers.getheader("content-length"))))
    desired = self.sync(observed["parent"], observed["children"])

    self.send_response(200)
    self.send_header("Content-type", "application/json")
    self.end_headers()
    self.wfile.write(json.dumps(desired))

HTTPServer(("", 8080), Controller).serve_forever()
EOF
$ kubectl -n pizzahat create configmap pizza-controller --from-file=/home/marley/tmp/sync.py

$ kubectl -n pizzahat apply -f webhook-py.yaml
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pizza-controller
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pizza-controller
  template:
    metadata:
      labels:
        app: pizza-controller
    spec:
      containers:
      - name: controller
        image: python:2.7
        command: ["python", "/hooks/sync.py"]
        volumeMounts:
        - name: hooks
          mountPath: /hooks
      volumes:
      - name: hooks
        configMap:
          name: pizza-controller
---
apiVersion: v1
kind: Service
metadata:
  name: pizza-controller
spec:
  selector:
    app: pizza-controller
  ports:
  - port: 8080
EOF

Deploy some Pizzas

$ cat <<EOF | kubectl -n pizzahat  apply -f -
apiVersion: mykubernetes.burrsutter.com/v1beta2
kind: Pizza
metadata:
  name: burrcheese
spec:
  toppings:
  - mozzarella
  sauce: regular
EOF
$ cat <<EOF | kubectl -n pizzahat  apply -f -
apiVersion: mykubernetes.burrsutter.com/v1beta2
kind: Pizza
metadata:
  name: burrmeats
spec:
  toppings:
  - mozzarella
  - pepperoni
  - sausage
  - bacon
  sauce: extra
EOF
$ cat <<EOF | kubectl -n pizzahat  apply -f -
apiVersion: mykubernetes.burrsutter.com/v1beta2
kind: Pizza
metadata:
  name: burrveggie2
spec:
  toppings:
  - mozzarella
  - black olives
  sauce: extra
EOF

Ничего не заработало! pizza-controller не запустился!

$ kubectl logs burrveggie -n pizzahat
$ kubectl delete pizza burrveggie
$ kubectl delete namespace pizzahat


Kafka via OperatorHub

http://operatorhub.io/

$ kubectl create namespace franz

$ kubectl config set-context --current --namespace=franz

$ curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/0.12.0/install.sh | bash -s 0.12.0

$ kubectl create -f https://operatorhub.io/install/strimzi-kafka-operator.yaml

$ kubectl get csv -n operators

$ kubectl get crds | grep kafka

$ watch kubectl get pods


$ kubectl apply -f https://raw.githubusercontent.com/burrsutter/9stepsawesome/master/kubefiles/kafka-strimzi-minikube.yml


$ kubectl get kafkas
NAME           DESIRED KAFKA REPLICAS   DESIRED ZK REPLICAS
burr-cluster   3                        3


$ kubectl get pods
NAME                                           READY   STATUS    RESTARTS   AGE
burr-cluster-entity-operator-84b7bfc5c-8vjc4   2/2     Running   0          3m10s
burr-cluster-kafka-0                           2/2     Running   0          3m43s
burr-cluster-kafka-1                           2/2     Running   0          3m43s
burr-cluster-kafka-2                           2/2     Running   0          3m43s
burr-cluster-zookeeper-0                       2/2     Running   0          4m38s
burr-cluster-zookeeper-1                       2/2     Running   0          4m38s
burr-cluster-zookeeper-2                       2/2     Running   0          4m38s


Clean up

$ kubectl delete kafka burr-cluster
$ kubectl delete namespace franz