Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go? Bash! Meet the Shell-operator

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

flant

August 20, 2020
Tweet

More Decks by flant

Other Decks in Programming

Transcript

  1. Go? Bash! Meet the Shell-operator
    Go? Bash! Meet the Shell-operator
    Andrey Klimentyev & Dmitry Stolyarov

    View Slide

  2. Go? Bash! Meet the Shell-operator
    Kubernetes
    API Basics

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  48. Go? Bash! Meet the Shell-operator
    shell-operator

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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 "$@"

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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
    }

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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: { … }

    View Slide

  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: { … }

    View Slide

  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: { … }

    View Slide

  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: { … }

    View Slide

  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
    - ...

    View Slide

  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: { … }

    View Slide

  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: { … }

    View Slide

  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: { … }

    View Slide

  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: { … }

    View Slide

  102. Go? Bash! Meet the Shell-operator
    function __main__() {
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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

    View Slide

  120. Go? Bash! Meet the Shell-operator
    kubernetes

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  155. Go? Bash! Meet the Shell-operator
    apiVersion: example.com/v1alpha1
    kind: MysqlDatabase
    metadata:
    name: foo
    namespace: bar

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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: []

    View Slide

  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: "* * * * *"

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  174. Go? Bash! Meet the Shell-operator

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  201. Go? Bash! Meet the Shell-operator
    #!
    shell-operator

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  217. Go? Bash! Meet the Shell-operator
    #!
    +
    shell-operator
    addon-operator
    =
    #!
    hooks
    +
    events
    +
    helm
    =
    #!
    hooks
    +
    events

    View Slide

  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

    View Slide