Go? Bash! Meet the Shell-operator

93aef1d166a8a3536538eff713f80307?s=47 flant
August 20, 2020

Go? Bash! Meet the Shell-operator

Andrey Klimentyev and Dmitry Stolyarov from Flant (https://flant.com/) tell why and how our company has simplified the process of creating Kubernetes operators — thanks to shell-operator.

* Article: https://medium.com/flant-com/meet-the-shell-operator-kubecon-36c14ba2f8fe?source=friends_link&sk=a545f75ddb2e4787fd95da61f0bd241c
* Video: https://www.youtube.com/watch?v=we0s4ETUBLc

GitHub for:
* shell-operator: https://github.com/flant/shell-operator
* addon-operator: https://github.com/flant/addon-operator

93aef1d166a8a3536538eff713f80307?s=128

flant

August 20, 2020
Tweet

Transcript

  1. Go? Bash! Meet the Shell-operator Go? Bash! Meet the Shell-operator

    Andrey Klimentyev & Dmitry Stolyarov
  2. Go? Bash! Meet the Shell-operator Kubernetes API Basics

  3. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod GET

    backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml Simple HTTP API
  4. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod PUT

    backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET Simple HTTP API
  5. Go? Bash! Meet the Shell-operator okay backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod

    PUT backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET Simple HTTP API
  6. Go? Bash! Meet the Shell-operator NO! backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod

    PUT backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET Simple HTTP API
  7. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH

    backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml GET PUT Simple HTTP API
  8. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  9. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  10. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  11. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  12. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  13. Go? Bash! Meet the Shell-operator GET PUT backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml

    frontend-65d68fd554-twl85.yaml …. .yaml backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml Simple HTTP API
  14. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod GET

    PUT WATCH backend.yaml frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml Simple HTTP API
  15. Go? Bash! Meet the Shell-operator backend-689bc4d4d5-rv4rq.yaml Deployment ReplicaSet Pod backend.yaml

    frontend.yaml …. .yaml backend-689bc4d4d5.yaml backend-cf789746c.yaml frontend-66544df5ff.yaml frontend-7b5f97db64.yaml frontend-65d68fd554.yaml …. .yaml backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml frontend-66544df5ff-dtnhn.yaml frontend-65d68fd554-twl85.yaml …. .yaml External world type #1 type #2
  16. Go? Bash! Meet the Shell-operator User backend.yaml Deployment

  17. Go? Bash! Meet the Shell-operator User Deployment Controller backend.yaml Deployment

  18. Go? Bash! Meet the Shell-operator User Deployment Controller backend.yaml backend-689bc4d4d5.yaml

    Deployment ReplicaSet
  19. Go? Bash! Meet the Shell-operator Deployment Controller User backend.yaml backend-689bc4d4d5.yaml

    Deployment ReplicaSet ReplicaSet Controller
  20. Go? Bash! Meet the Shell-operator Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml

    backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod ReplicaSet Controller
  21. Go? Bash! Meet the Shell-operator ReplicaSet Controller Deployment Controller User

    Scheduler backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  22. Go? Bash! Meet the Shell-operator ReplicaSet Controller Deployment Controller User

    Scheduler node-x node-y backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  23. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet
  24. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet
  25. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet Docker Docker
  26. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet Docker Docker
  27. Go? Bash! Meet the Shell-operator ReplicaSet Controller Scheduler node-x node-y

    Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod Kubelet Kubelet Docker Docker
  28. Go? Bash! Meet the Shell-operator Kubelet Kubelet Docker Docker Scheduler

    node-x node-y Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod ReplicaSet Controller
  29. Go? Bash! Meet the Shell-operator Kubelet Kubelet Docker Docker Scheduler

    node-x node-y Deployment Controller User backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod ReplicaSet Controller
  30. Go? Bash! Meet the Shell-operator User Kubelet Kubelet Docker Docker

    ReplicaSet Controller Scheduler node-x node-y Deployment Controller backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  31. Go? Bash! Meet the Shell-operator User Kubelet Kubelet Docker Docker

    ReplicaSet Controller Scheduler node-x node-y Deployment Controller backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod
  32. Go? Bash! Meet the Shell-operator Kubelet Kubelet Docker Docker ReplicaSet

    Controller Scheduler node-x node-y Deployment Controller backend-689bc4d4d5-rv4rq.yaml backend-689bc4d4d5-qqbmn.yaml backend.yaml backend-689bc4d4d5.yaml Deployment ReplicaSet Pod User
  33. Go? Bash! Meet the Shell-operator default foo qux quux garply

    mysecret secret:yes secret:yes secret:yes kubernetes
  34. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    garply mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  35. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  36. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes secret:yes mysecret secret:yes
  37. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret secret:yes
  38. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret secret:yes
  39. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret
  40. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes mysecret
  41. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  42. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  43. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  44. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  45. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  46. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret secret:yes secret:yes mysecret secret:yes
  47. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  48. Go? Bash! Meet the Shell-operator shell-operator

  49. Go? Bash! Meet the Shell-operator kubernetes #! /hooks/ foo.sh bar.py

    baz.rb
  50. Go? Bash! Meet the Shell-operator kubernetes #! #! #! #!

  51. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #! #!
  52. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #! #!
  53. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #! #!
  54. Go? Bash! Meet the Shell-operator Configuration Hook is executed with

    --config arg. 1 Hook should output YAML with its configuration. 2 Normal execution Hook is executed with no args. 1 Hook receives binding context. 2 once, on startup many times, on events
  55. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { } function __main__() { } hook::run "$@"
  56. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { #THE LOGIC } hook::run "$@" cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF
  57. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { #THE LOGIC } hook::run "$@" #THE LOGIC
  58. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { #THE LOGIC } hook::run "$@"
  59. Go? Bash! Meet the Shell-operator default foo qux quux quuz

    garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes kubernetes
  60. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  61. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  62. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  63. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  64. Go? Bash! Meet the Shell-operator #!/bin/bash source /shell_lib.sh function __config__()

    { cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF } function __main__() { } hook::run "$@" cat << EOF configVersion: v1 # BINDING CONFIGURATION EOF Binding configuration
  65. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 # BINDING CONFIGURATION EOF Binding configuration
  66. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  67. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  68. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  69. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  70. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  71. Go? Bash! Meet the Shell-operator snapshots: src_secret: - object: apiVersion:

    v1 kind: Secret metadata: { … } data: { … } function __config__() { } cat << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding context Binding configuration
  72. Go? Bash! Meet the Shell-operator snapshots: src_secret: - object: apiVersion:

    v1 kind: Secret metadata: { … } data: { … } function __config__() { } cat << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding context Binding configuration
  73. Go? Bash! Meet the Shell-operator snapshots: src_secret: - object: apiVersion:

    v1 kind: Secret metadata: { … } data: { … } function __config__() { } cat << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding context Binding configuration
  74. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  75. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration
  76. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration
  77. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration
  78. Go? Bash! Meet the Shell-operator # kubectl get ns foo

    -o json | jq '{ > "name": .metadata.name, > "hasLabel": ( .metadata.labels // {} | contains({"secret": "yes"}) ) > }' { "name": "kube-system", "hasLabel": true }
  79. Go? Bash! Meet the Shell-operator - name: namespaces group: main

    apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding configuration Binding configuration
  80. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  81. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  82. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  83. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  84. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true object: apiVersion: v1 kind: Namespace metadata: { … } - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  85. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true object: apiVersion: v1 kind: Namespace metadata: { … } - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  86. Go? Bash! Meet the Shell-operator snapshots: namespaces: - filterResult: namespace:

    foo hasLabel: true object: apiVersion: v1 kind: Namespace metadata: { … } - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - ... - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { namespace: .metadata.name, hasLabel: ( .metadata.labels // {} | contains({"secret": "yes"}) ) } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  87. Go? Bash! Meet the Shell-operator kubernetes default foo qux quux

    quuz garply waldo fred mysecret mysecret mysecret secret:yes secret:yes mysecret secret:yes
  88. Go? Bash! Meet the Shell-operator - name: dst_secrets apiVersion: v1

    kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding configuration
  89. Go? Bash! Meet the Shell-operator - name: dst_secrets apiVersion: v1

    kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding configuration
  90. Go? Bash! Meet the Shell-operator - name: dst_secrets apiVersion: v1

    kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding configuration
  91. Go? Bash! Meet the Shell-operator snapshots: dst_secrets: - filterResult: namespace:

    foo resourceVersion: 123456 - name: dst_secrets apiVersion: v1 kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  92. Go? Bash! Meet the Shell-operator snapshots: dst_secrets: - filterResult: namespace:

    foo resourceVersion: 123456 - name: dst_secrets apiVersion: v1 kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .metadata.annotations.resourceVersion } group: main keepFullObjectsInMemory: false Binding context Binding configuration
  93. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  94. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  95. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  96. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  97. Go? Bash! Meet the Shell-operator Is in sync with ?

    do nothing yes kubectl create or replace no dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … } namespaces: - filterResult: namespace: foo hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ...
  98. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  99. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  100. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  101. Go? Bash! Meet the Shell-operator namespaces: - filterResult: namespace: foo

    hasLabel: true - filterResult: namespace: bar hasLabel: false - filterResult: namespace: baz hasLabel: false - filterResult: namespace: quz hasLabel: false - ... Does exist? kubectl delete yes do nothing no dst_secrets: - filterResult: namespace: foo resourceVersion: 123456 - filterResult: namespace: corge resourceVersion: 123456 - filterResult: namespace: xyzzy resourceVersion: 123456 src_secret: - object: apiVersion: v1 kind: Secret metadata: { … } spec: { … }
  102. Go? Bash! Meet the Shell-operator function __main__() { }

  103. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  104. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  105. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  106. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done }
  107. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi }
  108. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi }
  109. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi }
  110. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  111. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  112. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  113. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  114. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  115. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  116. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  117. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  118. Go? Bash! Meet the Shell-operator function delete_secret() { if context::jq

    -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi }
  119. Go? Bash! Meet the Shell-operator 35 lines in yaml configVersion:

    v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main - name: dst_secrets apiVersion: v1 kind: Secret labelSelector: matchLabels: managed-secret: "yes" jqFilter: | { "namespace": .metadata.namespace, "resourceVersion": .annotations."resourceVersion" } group: main keepFullObjectsInMemory: false - name: namespaces group: main apiVersion: v1 kind: Namespace jqFilter: | { name: .metadata.name, hasLabel: (.metadata.labels // {} | contains({"secret": "yes"})) } group: main keepFullObjectsInMemory: false 20 lines in bash #! + + shell-operator function __main__() { for i in $(seq 0 "$(context::jq -r '(.snapshots.namespaces | length) - 1')"); do ns_name="$(context::jq -r '.snapshots.namespaces['"$i"'].filterResult.name')" if context::jq -e '.snapshots.namespaces['"$i"'].filterResult.hasLabel'; then sync_secret "$ns_name" else delete_secret "$ns_name" fi done } function delete_secret() { if context::jq -e --arg ns "$1" 'select(.snapshots…namespace == $ns)' ; then kubectl -n "$1" delete secret "mysecret" fi } function sync_secret() { src_resource_version="$(…)" dst_secret_resource_version="$(…)" if [ "$src_resource_version" != "$dst_resource_version" ] ; then new_secret="$(context::jq -r '.snapshots.src_secret[0].object | …)" kubectl -n "$1" replace -f <(echo "$new_secret") || kubectl -n "$1" create -f <(echo "$new_secret") fi } kubernetes default foo qux quux quuz garply waldo fred mysecret mysecret mysecret mysecret secret:yes secret:yes secret:yes
  120. Go? Bash! Meet the Shell-operator kubernetes

  121. Go? Bash! Meet the Shell-operator kubernetes Config Map

  122. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password ENV
  123. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 volumeMounts: - mountPath: /etc/config name: config volumes: - name: config configMap: name: foo items: - key: config.yaml path: config.yaml Mount
  124. Go? Bash! Meet the Shell-operator Config Map kubernetes

  125. Go? Bash! Meet the Shell-operator kubernetes Config Map v.1

  126. Go? Bash! Meet the Shell-operator kubernetes Config Map v.1 v.1

    v.1 v.1
  127. Go? Bash! Meet the Shell-operator kubernetes Config Map v.2 v.1

    v.1 v.1
  128. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password
  129. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password
  130. Go? Bash! Meet the Shell-operator apiVersion: apps/v1 kind: Deployment metadata:

    name: foo spec: template: metadata: annotations: config/checksum: b4d6b660fffb798dcaca5b8a spec: containers: - name: bar image: registry.example.com/myapp:v1.0.0 env: - name: DB_USER valueFrom: configMapKeyRef: name: foo key: db_user - name: DB_PASSWORD valueFrom: configMapKeyRef: name: foo key: db_password
  131. Go? Bash! Meet the Shell-operator kubernetes Config Map

  132. Go? Bash! Meet the Shell-operator kubernetes Config Map b4d6b6

  133. Go? Bash! Meet the Shell-operator kubernetes Config Map b4d6b6 b4d6b6

    b4d6b6 b4d6b6
  134. Go? Bash! Meet the Shell-operator kubernetes Config Map b4d6b6 b4d6b6

    b4d6b6 b4d6b6
  135. Go? Bash! Meet the Shell-operator kubernetes Config Map b4d6b6 b4d6b6

    b4d6b6 b4d6b6
  136. Go? Bash! Meet the Shell-operator kubernetes Config Map b4d6b6 b4d6b6

    b4d6b6 b4d6b6
  137. Go? Bash! Meet the Shell-operator kubernetes #! Config Map b4d6b6

    b4d6b6 b4d6b6 b4d6b6
  138. Go? Bash! Meet the Shell-operator kubernetes #! Config Map b4d6b6

    b4d6b6 b4d6b6 b4d6b6
  139. Go? Bash! Meet the Shell-operator kubernetes #! Config Map b4d6b6

    b4d6b6 b4d6b6 b4d6b6
  140. Go? Bash! Meet the Shell-operator kubernetes #! Config Map b4d6b6

    b4d6b6 b4d6b6 b4d6b6
  141. Go? Bash! Meet the Shell-operator kubernetes #! Config Map b4d6b6

    b4d6b6 b4d6b6 b4d6b6
  142. Go? Bash! Meet the Shell-operator kubernetes #! Config Map b4d6b6

    b4d6b6 b4d6b6 b4d6b6
  143. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    b4d6b6 b4d6b6 b4d6b6
  144. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    b4d6b6 b4d6b6 b4d6b6
  145. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    b4d6b6 b4d6b6
  146. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 b4d6b6 b4d6b6
  147. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 b4d6b6 b4d6b6
  148. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 b4d6b6
  149. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 c0ee75 b4d6b6
  150. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 c0ee75
  151. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 c0ee75 c0ee75
  152. Go? Bash! Meet the Shell-operator kubernetes #! Config Map c0ee75

    c0ee75 c0ee75 c0ee75
  153. Go? Bash! Meet the Shell-operator backend.yaml Deployment backend-689bc4d4d5.yaml ReplicaSet backend-689bc4d4d5-rv4rq.yaml

    Pod backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml
  154. Go? Bash! Meet the Shell-operator backend.yaml Deployment backend-689bc4d4d5.yaml ReplicaSet backend-689bc4d4d5-rv4rq.yaml

    Pod backend-cf789746c-qqbmn.yaml backend-cf789746c-l9sfr.yaml a-users.yaml MysqlDatabase a-archive.yaml Custom Resource Definitions
  155. Go? Bash! Meet the Shell-operator apiVersion: example.com/v1alpha1 kind: MysqlDatabase metadata:

    name: foo namespace: bar
  156. Go? Bash! Meet the Shell-operator kubernetes foo bar baz qux

  157. Go? Bash! Meet the Shell-operator kubernetes foo main bar main

    baz main qux main another
  158. Go? Bash! Meet the Shell-operator kubernetes foo main bar main

    baz main qux main another #!
  159. Go? Bash! Meet the Shell-operator kubernetes foo main bar main

    baz main qux main another #! server
  160. Go? Bash! Meet the Shell-operator kubernetes server foo main bar

    main baz main qux main another #! foo.main bar.main baz.main baz.another qux.main
  161. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false
  162. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false
  163. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false
  164. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false executeHookOnEvent: []
  165. Go? Bash! Meet the Shell-operator configVersion: v1 kubernetes: - name:

    nodes apiVersion: v1 kind: Node jqFilter: | { name: .metadata.name, ip: ( .status.addresses[] | select(.type == "InternalIP") | .address ) } group: main keepFullObjectsInMemory: false executeHookOnEvent: [] schedule: - name: every_minute group: main crontab: "* * * * *"
  166. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  167. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  168. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  169. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  170. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  171. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  172. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  173. Go? Bash! Meet the Shell-operator function __main__() { for i

    in $(seq 0 "$(context::jq -r '(.snapshots.nodes | length) - 1')"); do node_name="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.name')" node_ip="$(context::jq -r '.snapshots.nodes['"$i"'].filterResult.ip')" packets_lost=0 if ping -c 1 $node_ip -t 1 ; then packets_lost=1 fi cat <<-END { "name": "node_packets_lost", "add": $packets_lost, "labels": { "node": $node_name, } } END >> $METRICS_PATH done }
  174. Go? Bash! Meet the Shell-operator

  175. Go? Bash! Meet the Shell-operator #!

  176. Go? Bash! Meet the Shell-operator #!

  177. Go? Bash! Meet the Shell-operator #! #!

  178. Go? Bash! Meet the Shell-operator #! #!

  179. Go? Bash! Meet the Shell-operator #! #! #!

  180. Go? Bash! Meet the Shell-operator #! #! #!

  181. Go? Bash! Meet the Shell-operator #! #! #! #! #!

    #!
  182. Go? Bash! Meet the Shell-operator #! #! #! #! #!

    #!
  183. Go? Bash! Meet the Shell-operator #!

  184. Go? Bash! Meet the Shell-operator #!

  185. Go? Bash! Meet the Shell-operator #! #! #!

  186. Go? Bash! Meet the Shell-operator #! #! #!

  187. Go? Bash! Meet the Shell-operator #! #! #!

  188. Go? Bash! Meet the Shell-operator #! #! #!

  189. Go? Bash! Meet the Shell-operator #! #! #!

  190. Go? Bash! Meet the Shell-operator #! #! #!

  191. Go? Bash! Meet the Shell-operator #! #! #!

  192. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  193. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  194. Go? Bash! Meet the Shell-operator #!

  195. Go? Bash! Meet the Shell-operator #! #! #! #! #!

    #!
  196. Go? Bash! Meet the Shell-operator #! #! #! #! #!

    #!
  197. Go? Bash! Meet the Shell-operator #! #! #! #! #!

    #!
  198. Go? Bash! Meet the Shell-operator #! #! #! #! #!

    #!
  199. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main EOF Binding configuration
  200. Go? Bash! Meet the Shell-operator function __config__() { } cat

    << EOF configVersion: v1 kubernetes: - name: src_secret apiVersion: v1 kind: Secret nameSelector: matchNames: - mysecret namespace: nameSelector: matchNames: ["default"] group: main queue: "some_name" EOF Binding configuration
  201. Go? Bash! Meet the Shell-operator #! shell-operator

  202. Go? Bash! Meet the Shell-operator #! + shell-operator addon-operator

  203. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #!
  204. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #!
  205. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #!
  206. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! #!

    #!
  207. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! External

    world #! #!
  208. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API #! External

    world #! #!
  209. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + #!

    External world #!
  210. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + #!

    chart External world #!
  211. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + #!

    chart External world #!
  212. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + values

    #! chart External world #!
  213. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + values

    #! chart External world #!
  214. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + values

    #! chart External world #!
  215. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + values

    #! chart External world #!
  216. Go? Bash! Meet the Shell-operator kubernetes Kubernetes API + values

    #! chart External world #!
  217. Go? Bash! Meet the Shell-operator #! + shell-operator addon-operator =

    #! hooks + events + helm = #! hooks + events
  218. Go? Bash! Meet the Shell-operator Thank you! Like? Try! And

    don’t forget to star on GitHub Dmitry Stolyarov CTO & Co-founder twitter.com/dmistol linkedin.com/in/distol Flant Running your production 24×7×365 medium.com/flant-com youtube.com/c/flant_com flant.com #! + shell-operator github.com/flant/shell-operator addon-operator github.com/flant/addon-operator Andrey Klimentyev Solutions Engineer