Kubernetes at a glance
WARN! Kubernetes is NOT for you!
Extracted from @[https://pythonspeed.com/articles/dont-need-kubernetes/]
  """...
  BºMicroservices are an organizational scaling technique: when you have  º
  Bº500 developers working on one live website, it makes sense to pay the º
  Bºcost of a large-scale distributed system if it means the developer    º
  Bºteams can work independently. So you give each team of 5 developers a º
  Bºsingle microservice, and that team pretends the rest of the           º
  Bºmicroservices are external services they can’t trust.                 º

  RºIf you’re a team of 5 and you have 20 microservices, and you          º
  Rºdon’t have a very compelling need for a distributed system,           º
  Rºyou’re doing it wrong. Instead of 5 people per service like the big   º
  Rºcompany has, you have 0.25 people per service.                        º
  """

- Extracted from Local Persistent Volume documentation:
  """  Because of these constraints, Rºit’s best to exclude nodes with º
  Rºlocal volumes from automatic upgrades or repairsº, and in fact some 
    cloud providers explicitly mention this as a best practice. """

  Basically most of the benefits of k8s are lost for apps managing
  storage at App level. This is the case with most modern DDBBs and stream
  architectures (PostgreSQL, MySQL, kafka, p2p-alike Ethereum, ....).

- As a reference Google, original creator of K8s, launches 
Bº2 billion containers per week!!!º in its infrastructures.
  This is not excatly a normal IT load.

- See also:
@[https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing]
   1.- "The network is reliable"
   2.- "Latency is zero"
   3.- "Bandwidth is infinite"
   4.- "The network is secure"
   5.- "Topology doesn't change"
   6.- "There is one administrator"
   7.- "Transport cost is zero"
   8.- "The network is homogeneous"
WARN! Kubernetes is for you!
- You plan to have a running infrastructure for years,
  and you know in advance that you will need to automate
  lot of RESTfull deployments in an standard way.
- You want to bet for a technology that is well known
  by software industry, so you can hire people that already
  are familiar with it.
- Distributed systems are complex are is better to skip,
  but you can not avoid them. Then k8s is the most familiar
  approach.
- Your company has different isolated teams with random knowledge
  and skills, from finances, to science, to marketing, .....
    They all want a common base and future-resistent virtual 
  computing infrastructure.
    They all want to share computer resources, and balance 
  computation when needed, as well as reuse DevOps knowledge 
  for databases, web servers, networking, ...
- Some k8s operator automate all the life-cycle of software
  management for a given database, CMS, ... You want to profit
  from such existing operator and the knowledge and experience
  of the operator developers.
External Links
- About Desired State management   @[https://www.youtube.com/watch?v=PH-2FfFD2PU]

- Online training:
@[https://www.katacoda.com/courses/kubernetes/playground]
@[https://labs.play-with-k8s.com/]

- @[https://kubernetes.io/]
- @[https://kubectl.docs.kubernetes.io/]   ← Book
- @[https://kubernetes.io/docs/reference/] (Generated from source)
- @[https://kubernetes.io/docs/reference/glossary/]
- @[https://kubernetes.io/docs/reference/tools/]

- Most voted questions k8s on serverfault:
@[https://serverfault.com/questions/tagged/kubernetes?sort=votes]
- Most voted questions k8s on stackoverflow:
@[https://stackoverflow.com/questions/tagged/kubernetes?sort=votes]
- Real app Examples:
@[https://github.com/kubernetes/examples]

ºk8s Issues:º
- @[https://kubernetes.io/docs/reference/issues-security/issues/]
- @[https://kubernetes.io/docs/reference/issues-security/security/]

ºk8s Enhancements/Backlogº
- @[https://github.com/kubernetes/enhancements]


ºSIG-Appsº
- @[https://github.com/kubernetes/community/blob/master/sig-apps/README.md]
  Special Interest Group for deploying and operating apps in Kubernetes.
  - They meet each week to demo and discuss tools and projects.
   """ Covers deploying and operating applications in Kubernetes. We focus
    on the developer and devops experience of running applications in
    Kubernetes. We discuss how to define and run apps in Kubernetes, demo
    relevant tools and projects, and discuss areas of friction that can lead
    to suggesting improvements or feature requests """


- Yaml Tips: 
@[https://www.redhat.com/sysadmin/yaml-tips]





Summary
ref:@[https://kubernetes.io/docs/concepts/overview/components/]
    @[https://kubernetes.io/docs/reference/#config-reference]

- k8s orchestates pools of CPUs, storage and networks

Kubernetes Cluster Components:
│ºetcdº:                      │    ºMasterº:                         
│- High availability key/value│    (Or cluster of masters)           
│ddbb used to save the cluster│     - manages the cluster.           
│metadata, service registrat. │     - keeps tracks of:               
│and discovery                │       - desired state.               
└─────────────────────────────┘       ─ application scalation        
                                      - rolling updates              
                                    - Raft consensus used in         
                                      multimaster mode               
                                      (requires 1,3,5,... masters    
                                     @[https://raft.github.io/])     
                                     └────────┬─────────────────┘    
                                              │                      
        ┌───────────────┬────────────┬────────┴────────────────┬──────────┬─────────────────────────────┐
ºkube─apiserver:º       │ºkube─controller─managerº             │ºkube-schedulerº               ºcloud─controller─managerº
 ─ (REST) Wrapper around│ ─Oº:EMBEDS K8S CORE CONTROL LOOPS!!!º│ ─ Assigns workloads to nodes  ─ k8s 1.6Rºalpha featureº
   k8s objects          │ ─ºhandles a number of controllers:º  │ ─ tracks host-resource ussage ─ runs controllers
 - Listen for management│   ─ regulating the state of  cluster │ ─ tracks total resources        interacting with underlying
   tools (kubectl,      │   ─ perform routine tasks            │   available per server and      cloud provider
   dashboard,...)       │     ─ ensures number of replicas for │   resources allocated to      ─ affected controllers
                        │       a service,                     │   existing workloads assigned   ─ Node Controller
                        │     ─ ...                            │   to each server                ─ Route Controller
                        │                                      │ ─ Manages availability,         ─ Service Controller
                        │                                      │   performance and capacity      ─ Volume ControllerCluster
                        │                                      │
                ºfederation-apiserveRº                   ºfederation-controller-managerº
                - API server for federated               - embeds the core control loops shipped
                  clusters                                 with Kubernetes federation.




   │ºnodeº (Pool):
   │- (VM) computer serving as
   │  a worker machine where pods
   │  are scheduled for execution.   takes a set of PodSpecs and ensures
   │- Contains k8s services:         thate described containers are
   │  - Kubelet agent        ←------ running and healthy.
   │  - Container runtime Iface
   │    (Docker or rkt)
   │- Get External IPs of all nodes:
   │$º$ kubectl get nodes -o jsonpath=\                                º
   │$º  '{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'º
   │ 
   └────────┬─────────────────┘    
            │                      
   ┌────────┴──────────────────┬─────────────────────────────┐
ºkubelet agentº      ºContainer Runtimeº            ºkube-proxyº
                                                     - Gº"SDN enabler"º
                                                     - simple or round-robin TCP/UDP
                                                       stream forwarding across set
                                                       of back-ends.
                                                     - Listen for new Service/Service.EndPoint
                                                       events from ºMasterº to update
                                                       Service Virtual IPs to 
                                                       real EndPoint IPs with the help of
                                                       proxy-ports, iptables,....

K8S
CLUSTER  1 ←···→ N Namespace  1 ←─┬─→  N Deployment       1 ←·····┐
───────            =========             ==========
─ etcd            "Virtual        │      "Application"            ·
─ Master           cluster"       │                               ·
─ Node Pool       Can be assigned │      · Load balancing         ·
                  max Memory/CPU  │        with(out) session      ·
                  Quotas          │        affinity               ·
                                  │      · Persistence storage    ·
                                  │      · Scheduing of pods into ·
                                  │        node pool              ·
                                  │      · Rolling deployments    ·
                                  │      · Ex:                    ·
                                  │        1 DDBB pod             ·
                                  │      + 2 Front End pods       ·
                                  │      + 1 ESB Pod              ·
                                  │                               ·
                                  └── N "Other" Controllers       ·
                                       (ReplicaSet, ...)          ·                                                 ·
                                                                  ·
 ┌································································┘
 │
 └→ N Pods    1 ←················→ 1+ Container
      ====                            =========
   · Minimum Unit of Exec/Sched.      · executable ("Docker") image
   · At creation time resource        .ºLifecycle Hooksº
     limits for CPU/memory are          - PostStart Hook
     defined (min and max-opt)          - PreStop   Hook
   · Ussually Pod 1←→1 Container
     (rarely 2 when such              type Container struct {
      containers are closely             Name string
      related to make Pod work)          Image string
   ·RºPods are ephemeral.º               Command []string
      Deploy Controller+                 Args []string
      Pods is high available.            WorkingDir string
                                         Ports []ContainerPort
   · Define shared resources            EnvFrom []EnvFromSource
     for its container/s:                Env []EnvVar
     o Volumes: (Shared Storage)         Resources ResourceRequirements
     o Networking: (Sharedºuniqueº       VolumeMounts []VolumeMount
          ºcluster IPº)                  VolumeDevices []VolumeDevice
     o Metadata: (Container image        LivenessProbe *Probe   ←······· kubelet exec the probes
         version, ports to use,...)      ReadinessProbe *Probe           - ExecAction
                                         Lifecycle *Lifecycle            - TCPSocketAction
   · Represent a "logical host"          TerminationMessagePath string   - HTTPGetAction
                                         TerminationMessagePolicy TerminationMessagePolicy
   · A Pod is tied to the Node where     ImagePullPolicy PullPolicy
     it has been scheduler to run,       SecurityContext *SecurityContext
     and remains there until             Stdin bool
     termination.                     }
   · In case of failure, controllers
     can be scheduled to run on other · containers in a Pod are
     available Nodes in the cluster.    co-located and co-scheduled
                                        on the same cluster node.
   · Controllers takes charge of
     scalling /"healing" pods.


REF: @[https://kubernetes.io/docs/Architecture/architecture_map.html?query=service+registration+discovery]
                                                ┌───────────┐
   ─ Describes the resources available ─┐       │Node Status│
     ─ CPU                              │       ├───────────┤
     ─ memory                           │       │Addresses  ←─(HostName, ExternalIP, InternalIP)
     ─ max.number of pods supported     └───────→Capacity   │                        ^^^^^^^^^^
    ┌───────────────────────────────────────────→Condition  │                        Typically visible
    status ofºallºRunning nodes.                │Info       ← General info. like     within cluster
    Node               Description              └───────────┘ kernel/k8s/docker ver,
    -----------------  -------------------------------------  OS name,...
    OutOfDisk          True → insufficient free space on the
                              node for adding new pods
    Ready              True → node is healthy and ready to accept pods
                       if not True after ºpod─eviction─timeoutº
                       (5 minutes by default)
                       an argument is passed to the kube-controller-manager
                       and all Pods
    MemoryPressure     True → pressure exists on the node memory
    PIDPressure        True → pressure exists on the processes
    DiskPressure       True → pressure exists on the disk size
    NetworkUnavailable True → node network not correctly configured


Network REF:@[https://kubernetes.io/docs/concepts/architecture/cloud-controller/] NETWORK SCHEMA WITHOUT CLOUD-CONTROLLER | NETWORK SCHEMAºWITHº CLOUD-CONTROLLER: o Cloud connector _ _ | o Cloud connector _ _ ___| | ___ _ _ __| | | ___| | ___ _ _ __| | kube─controller─managero──→ / __| |/ _ \| | | |/ _` | | cloud-controller─managero──→ / __| |/ _ \| | | |/ _` | ^ | (__| | (_) | |_| | (_| | | ^ | (__| | (_) | |_| | (_| | │ \___|_|\___/ \__,_|\__,_| | kube─controller─manager │ \___|_|\___/ \__,_|\__,_| │ ^ | ^ │ │ │ | │ │ │ │ | └─────────────────┤ v │ node | │ etcd ←───→ kube─apiserver ←──┬─┐ ┌─o────────┐ | v node │ └──→kubelet ←───┐ | etcd ←───────→ kube─apiserver ←──┬─┐ ┌──────────┐ ^ │ │ │ │ | │ └─→kubelet ←───┐ │ │ │ │ │ | ^ │ │ │ │ v │ │ │ │ | │ │ │ │ │ kube─scheduler └────→kube─proxy│ │ | v │ │ │ │ └──────────┘ │ | kube─scheduler └───→kube─proxy│ │ │ | └──────────┘ │ │ ┌────────┐ │ └─→Image ←───────────────────────────────────────────────┘ │Registry│ └────────┘
Object Management REF: - @[https://kubernetes.io/docs/tasks/tools/install-kubectl/] - @[https://kubernetes.io/docs/concepts/overview/object-management-kubectl/overview/] - @[https://kubernetes.io/docs/reference/kubectl/cheatsheet/] º┌──────────┐º ┌───────────┐ º│k8s object│º ┌─→│metadata │ º├──────────┤º │ ├───────────┤ º│kind │º one of the GºResource typesº│ │name │← maps to /api/v1/pods/name *│metadata │←─────────────────────────────┘ │UID │← Distinguish between historical º│spec │← desired stateº │namespace │ occurrences of similar object º│state │← present stateº │labels │ º└──────────┘º │annotations│ └───────────┘ metadata is organized around the concept of an application. k8s does NOT enforce a formal notion of application. Apps are described thorugh metadata in a loose definition. etcd kubernetes (/openapi/v2) cli management: (serialized ←────── objects ←────────────────→ API ←───→ ºkubectlº'action' Gº'resource'º API resource - Represent API resources Server *1 ^^^^^^ states) (persistent entities ºget º: list resources in a cluster) ºdescribeº: show details (and events for pods) - The can describe: ºlogs º: print container - apps running on nodes logs - resources available to ºexec º: exec command on a given app container - policies around apps ºapply º: creates and updates resources (restart, upgrades, ...) ... common kubectl flags: --all-namespaces -o wide --include-uninitialized --sort-by=.metadata.name --sort-by='.status.containerStatuses[0].restartCount' --selector=app=cassandra *1: @[https://kubernetes.io/docs/conceptsverview/kubernetes-api/]
Resource Types GºRESOURCE TYPES SUMMARYº clusters │podtemplates │statefulsets (cs)componentstatuses │(rs)replicasets │(pvc)persistentvolumeclaims (cm)configmaps │(rc)replicationcontrollers │(pv) persistentvolumes (ds)daemonsets │(quota)resourcequotas │(po) pods (deploy)deployments │cronjob │(psp)podsecuritypolicies (ep)endpoints │jobs │secrets (ev)event │(limits)limitranges │(sa)serviceaccount (hpa)horizon...oscalers │(ns)namespaces │(svc)services (ing)ingresses │networkpolicies │storageclasses │(no)nodes │thirdpartyresources GºRESOURCE TYPES EXTENDEDº @[https://github.com/kubernetes/kubernetes/blob/master/pkg/apis/core/types.go] 001 Volume 021 FlexPersistentVolumeSource 041 DownwardAPIProjection 002 VolumeSource 022 FlexVolumeSource 042 AzureFileVolumeSource 003 PersistentVolumeSource 023 AWSElasticBlockStoreVolumeSource 043 AzureFilePersistentVolumeSource 004 PersistentVolumeClaimVolumeSource 024 GitRepoVolumeSource 044 VsphereVirtualDiskVolumeSource 005 PersistentVolume 025 SecretVolumeSource 045 PhotonPersistentDiskVolumeSource 006 PersistentVolumeSpec 026 SecretProjection 046 PortworxVolumeSource 007 VolumeNodeAffinity 027 NFSVolumeSource 047 AzureDiskVolumeSource 008 PersistentVolumeStatus 028 QuobyteVolumeSource 048 ScaleIOVolumeSource 009 PersistentVolumeList 029 GlusterfsVolumeSource 049 ScaleIOPersistentVolumeSource 010 PersistentVolumeClaim 030 GlusterfsPersistentVolumeSource 050 StorageOSVolumeSource 011 PersistentVolumeClaimList 031 RBDVolumeSource 051 StorageOSPersistentVolumeSource 012 PersistentVolumeClaimSpec 032 RBDPersistentVolumeSource 052 ConfigMapVolumeSource 013 PersistentVolumeClaimCondition 033 CinderVolumeSource 053 ConfigMapProjection 014 PersistentVolumeClaimStatus 034 CinderPersistentVolumeSource 054 ServiceAccountTokenProjection 015 HostPathVolumeSource 035 CephFSVolumeSource 055 ProjectedVolumeSource 016 EmptyDirVolumeSource 036 SecretReference 056 VolumeProjection 017 GCEPersistentDiskVolumeSource 037 CephFSPersistentVolumeSource 057 KeyToPath 018 ISCSIVolumeSource 038 FlockerVolumeSource 058 LocalVolumeSource 019 ISCSIPersistentVolumeSource 039 DownwardAPIVolumeSource 059 CSIPersistentVolumeSource 020 FCVolumeSource 040 DownwardAPIVolumeFile 060 CSIVolumeSource 061 ContainerPort 081 Handler 101 PreferredSchedulingTerm 062 VolumeMount 082 Lifecycle 102 Taint 063 VolumeDevice 083 ContainerStateWaiting 103 Toleration 064 EnvVar 084 ContainerStateRunning 104 PodReadinessGate 065 EnvVarSource 085 ContainerStateTerminated 105 PodSpec 066 ObjectFieldSelector 086 ContainerState 106 HostAlias 067 ResourceFieldSelector 087 ContainerStatus 107 Sysctl 068 ConfigMapKeySelector 088 PodCondition 108 PodSecurityContext 069 SecretKeySelector 089 PodList 109 PodDNSConfig 070 EnvFromSource 090 NodeSelector 110 PodDNSConfigOption 071 ConfigMapEnvSource 091 NodeSelectorTerm 111 PodStatus 072 SecretEnvSource 092 NodeSelectorRequirement 112 PodStatusResult 073 HTTPHeader 093 TopologySelectorTerm 113 Pod 074 HTTPGetAction 094 TopologySelectorLabelRequirement 114 PodTemplateSpec 075 TCPSocketAction 095 Affinity 115 PodTemplate 076 ExecAction 096 PodAffinity 116 PodTemplateList 077 Probe 097 PodAntiAffinity 117 ReplicationControllerSpec 078 Capabilities 098 WeightedPodAffinityTerm 118 ReplicationControllerStatus 079 ResourceRequirements 099 PodAffinityTerm 119 ReplicationControllerCondition 080 Container 100 NodeAffinity 120 ReplicationController 121 ReplicationControllerList 141 DaemonEndpoint 161 Preconditions 181 ResourceQuotaSpec 122 ServiceList 142 NodeDaemonEndpoints 162 PodLogOptions 182 ScopeSelector 123 SessionAffinityConfig 143 NodeSystemInfo 163 PodAttachOptions 183 ScopedResourceSelerRequirement 124 ClientIPConfig 144 NodeConfigStatus 164 PodExecOptions 184 ResourceQuotaStatus 125 ServiceStatus 145 NodeStatus 165 PodPortForwardOptions 185 ResourceQuota 126 LoadBalancerStatus 146 AttachedVolume 166 PodProxyOptions 186 ResourceQuotaList 127 LoadBalancerIngress 147 AvoidPods 167 NodeProxyOptions 187 Secret 128 ServiceSpec 148 PreferAvoidPodsEntry 168 ServiceProxyOptions 188 SecretList 129 ServicePort 149 PodSignature 169 ObjectReference 189 ConfigMap 130 Service 150 ContainerImage 170 LocalObjectReference 190 ConfigMapList 131 ServiceAccount 151 NodeCondition 171 TypedLocalObjectReference 191 ComponentCondition 132 ServiceAccountList 152 NodeAddress 172 SerializedReference 192 ComponentStatus 133 Endpoints 153 NodeResources 173 EventSource 193 ComponentStatusList 134 EndpointSubset 154 Node 174 Event 194 SecurityContext 135 EndpointAddress 155 NodeList 175 EventSeries 195 SELinuxOptions 136 EndpointPort 156 NamespaceSpec 176 EventList 196 WindowsSecurityContextOptions 137 EndpointsList 157 NamespaceStatus 177 LimitRangeItem 197 RangeAllocation 138 NodeSpec 158 Namespace 178 LimitRangeSpec 139 NodeConfigSource 159 NamespaceList 179 LimitRange 140 ConfigMapNodeConfigSource 160 Binding 180 LimitRangeList
k8s (def.)TCP Ports REF @[https://kubernetes.io/docs/tasks/tools/install-kubeadm/] ┌───────┬───────┐ │Master │Worker │ │node(s)│node(s)│ ┌──────────────────────────────────────┼───────┼───────┤ │Port Range │ Purpose │ X │ │ ├──────────────────────────────────────┼───────┼───────┤ │6443* │ Kubernetes API server │ X │ │ ├──────────────────────────────────────┼───────┼───────┤ │2379─2380 │ etcd server client API │ X │ │ ├──────────────────────────────────────┼───────┼───────┤ │10250 │ Kubelet API │ X │ X │ ├──────────────────────────────────────┼───────┼───────┤ │10251 │ kube─scheduler │ X │ │ ├──────────────────────────────────────┼───────┼───────┤ │10252 │ kube─controller─manager│ X │ │ ├──────────────────────────────────────┼───────┼───────┤ │10255 │ Read─only Kubelet API │ X │ X │ ├──────────────────────────────────────┼───────┼───────┤ │ 30000─32767 │ NodePort Services │ │ X │ └──────────────────────────────────────┴───────┴───────┘
Application Troubleshooting
REF: @[https://learnk8s.io/]

- @[https://kubernetes.io/docs/tasks/debug-application-cluster/debug-application/]

$º$ kubectl get pods º
    └─────┬────────┘
QºQ: Is there any pending Pod?º
  └─────────┬────────────────┘
  ┌─────────┘
  ├ YES → $º$ kubectl describe º←QºQ: Is the cluster full?º
  │       $º     pod $pod_name º   └────────┬────────────┘
  │           ┌─────────────────────────────┘
  │           ├ NO  →QºQ: Are you hitting ResourceQuotaLimits?º
  │           │        └────────────────────┬────────────────┘
  │           │       ┌─────────────────────┘
  │           │       ├ NO  →QºQ: Are you mounting a PENDINGº
  │           │       │      Qº   PersistentVolumeClaim?º
  │           │       │        └───────────┬────────────────┘
  │           │       │       ┌────────────┘
  │           │       │       ├ NO  →$º$ kubectl get pods º←QºQ: Is the Pod assignedº
  │           │       │       │      $º    -o wide        º Qº   to the Node?º
  │           │       │       │                               └────┬───────────────┘
  │           │       │       │      ┌─────────────────────────────┘
  │           │       │       │      ├ YES →RºThere is an issue with the Kubeletº
  │           │       │       │      │
  │           │       │       │      └ NO  →RºThere is an issue with the Schedulerº
  │           │       │       │
  │           │       │       └ YES →BºFix the PersistentVolumeClaimº
  │           │       │
  │           │       └ YES →BºRelax Quota Limitsº
  │           │
  │           └ YES →BºProvision a bigger clusterº
  │
  └ NO  →QºQ: Are the Pods Running?º
           └──────┬───────────────┘
  ┌───────────────┘
  ├ NO  → $º$ kubectl logs $pod_name º←QºQ: Can you see the logsº
  │        ↑                           Qº   for the App?º
  │        │                             └─────────┬───────────┘
  │        │  ┌────────────────────────────────────┘
  │        │  ├ Yes →BºFix the issue in the Appº
  │        │  └ NO  →QºQ: Did the container died too Quickly?º
  │        │           └──────┬─────────────────────────────┘
  │        │      ┌───────────┘
  │        │      ├ NO  → $º$ kubectl describe º←QºQ: Is the Pod in statusº
  │        │      │       $º    pod $pod_name  º Qº   ImagePullBackOff?  º
  │        │      │                                └──┬──────────────────┘
  │        │      │  ┌────────────────────────────────┘
  │        │      │  ├ NO  →QºQ: Is the Pode Status CrashLoopBackOff?º
  │        │      │  │        └─────────┬─────────────────────────┘
  │        │      │  │ ┌────────────────┘
  │        │      │  │ ├ NO →QºQ: Is the Pod status RunContainerError?º
  │        │      │  │ │       └─────────┬───────────────────────────┘
  │        │      │  │ │ ┌───────────────┘
  │        │      │  │ │ ├ NO  →BºConsult StackOverflowº
  │        │      │  │ │ │
  │        │      │  │ │ └ YES →BºThe issue is likely to be withº
  │        │      │  │ │        Bºmounting volumesº
  │        │      │  │ │
  │        │      │  │ └ YES →QºQ: Did you inspect the logs and fixedº
  │        │      │  │        Qº   the crashes?º
  │        │      │  │          └─────────┬─────────────────────────┘
  │        │      │  │    ┌───────────────┘
  │        │      │  │    ├ NO  →BºFix the app crahsesº
  │        │      │  │    │
  │        │      │  │    └ YES →QºQ: Did you forget the 'CMD' instructionº
  │        │      │  │           Qº   in the Dockerfile?                  º
  │        │      │  │             └──────────┬──────────────────────────┘
  │        │      │  │       ┌────────────────┘
  │        │      │  │       ├ YES →BºFix the Dockerfileº
  │        │      │  │       │
  │        │      │  │       └ NO  →QºQ: Is the Pod restarting frequently?º
  │        │      │  │              Qº   Cycling between Running and      º
  │        │      │  │              Qº   CrashLoopBackoff?º
  │        │      │  │                └──────────┬────────────────────────┘
  │        │      │  │        ┌──────────────────┘
  │        │      │  │        ├ YES →BºFix the liveness probeº
  │        │      │  │        │
  │        │      │  │        └ NO  →RºUnknown Stateº
  │        │      │  │
  │        │      │  └ YES →QºQ: Is the name of the image correct?º
  │        │      │           └────┬─────────────────────────────┘
  │        │      │   ┌────────────┘
  │        │      │   ├ NO  →BºFix the image nameº
  │        │      │   │
  │        │      │   └ YES →QºQ: Is the image tag valid?º
  │        │      │          Qº   Does it exists?º
  │        │      │            └──┬──────────────────────┘
  │        │      │   ┌───────────┘
  │        │      │   ├ NO  →BºFix the tagº
  │        │      │   │
  │        │      │   └ YES →QºQ: Are you pulling images from aº
  │        │      │          Qº   private registry?º
  │        │      │            └─────────┬────────────────────┘
  │        │      │    ┌─────────────────┘
  │        │      │    ├ NO  →BºThe Issue could be with CRI|Kubeletº
  │        │      │    │
  │        │      │    └ YES →BºConfigure pulling images from aº
  │        │      │           Bºprivate registryº
  │        │      │
  │        │      └ YES → $º$ kubectl logs $pod_name --previous º
  │        │                  └────────────┬──────────────────┘
  │        └───────────────────────────────┘
  └ YES →QºQ: Are ther Pods READY?º
           └──┬──────────────────┘
  ┌───────────┘
  ├ NO  → $º$ kubectl describe º←QºQ: Is the Readiness probeº
  │       $º    pod $pod_name  º Qº   failing?º
  │                                └──┬────────────────────┘
  │           ┌───────────────────────┘
  │           ├ YES →BºFix the Readiness Probeº
  │           │
  │           └ NO  →RºUnknown Stateº
  │
  └ YES → $º$ kubectl port-forward      \ º ←QºQ: Can you access the app?º
          $º    $pod_name  8080:$pod_port º    └──────────┬─────────────┘
  ┌───────────────────────────────────────────────────────┘
  ├ NO  →QºQ: Is the port exposed by container correctº
  │      Qº   and listening on 0.0.0.0?º
  │        └────────────────────┬────────────────────┘
  │       ┌─────────────────────┘
  │       ├ NO  →BºFix the app. It should listen onº
  │       │      Bº0.0.0.0.º
  │       │      BºUpdate the containerPortº
  │       │
  │       └ YES →RºUnknown Stateº
  ↓
  YES
  ↓
Bº***************************º
Bº*POD ARE RUNNING CORRECTLY*º
Bº***************************º
   └──────────┬────────────┘
              ↓
$º$ kubectl describe   \  º ←QºQ: Can you see a listº
$º  service $SERVICE_NAME º  Qº    of endpoints?º
                               └──────┬────────────┘
  ┌───────────────────────────────────┘
  ├ NO  →QºQ: Is the Selector matching the rightº
  │      Qº   Pod label?º
  │        └──┬────────────────────────────────┘
  │     ┌─────┘
  │     ├ NO  → Fix the Service selector. It has
  │     │       to match the Pod labels
  │     │
  │     └ YES →QºQ: Does the Pod have an IP address assigned?º
  │              └──┬───────────────────────────────────────┘
  │           ┌─────┘
  │           ├ NO  → There is an issue with
  │           │       the Controller Manager
  │           │
  │           └ YES → There is an issue with the Kubelet
  │
  └ YES →$º$ kubectl port-forward    \ º←QºQ: Can you visit the app?º
         $º    service/$SERVICE_NAME \ º   └──┬────────────────────┘
         $º    8080:$SERVICE_PORT      º      │
                                              │
  ┌───────────────────────────────────────────┘
  ├ NO  →QºQ: Is the targetPort on the Service º
  │      Qº   matching the containerPort in theº
  │      Qº   Pod?º
  │        └──┬────────────────────────────────┘
  │     ┌─────┘
  │     ├ NO  →BºFix the Service targetPort andº
  │     │      Bºthe containerPodº
  │     │
  │     └ YES →BºThe issue could be with Kube Proxyº
  ↓
 YES
  ↓
Bº******************************º
Bº*SERVICE IS RUNNING CORRECTLY*º
Bº******************************º
  ↓
$º$ kubectl describe    \ º←QºQ: Can you see a list of Backends?º
$º  ingress $INGRESS_NAME º   └──┬─────────────────────────────┘
  ┌──────────────────────────────┘
  ├ NO  →QºQ: Are the serviceName and servicePortº
  │      Qº   mathcing the service?º
  │        └──┬─────────────────────────────────┘
  │       ┌───┘
  │       ├ NO  →BºFix the ingress serviceName and servicePortº
  │       │
  │       └ YES →BºThe issue is specific to the Ingress Controllerº
  │              BºConsult the docs for your Ingressº
  ↓
 YES
  ↓
Bº**********************************º
Bº*THE INGRESS IS RUNNING CORRECTLY*º
Bº**********************************º
Bº(The app should be working now!!!)º
  │
  ↓                         ┌ NO  →RºThe issue is likely to be with the   º
                            │      RºInfrastructure and how the cluster isº
QºQ:  Can you visit app º→ ─┤      Rºexposedº
Qº    from the Internet?º   │
                            │       Bº*****º
                            └ YES → Bº*END*º
                                    Bº*****º
Kubectl
- @[https://kubernetes.io/docs/reference/kubectl/jsonpath/]
  @[https://kubernetes.io/docs/reference/kubectl/overview/]
  @[https://kubernetes.io/docs/reference/kubectl/kubectl/]
  @[https://kubernetes.io/docs/reference/kubectl/kubectl-cmds/]
  @[https://kubernetes.io/docs/reference/kubectl/conventions/]
  @[https://kubernetes.io/docs/reference/kubectl/docker-cli-to-kubectl/]

$ KUBE_EDITOR="vim"
$ source ˂(kubectl completion bash)  # kubectl autocomple
$ source ˂(kubectl completion zsh)
# use multiple kubeconfig files
$ KUBECONFIG=~/.kube/config:~/.kube/kubconfig2 \
kubectl config view # Show Merged kubeconfig settings.

$ kubectl config current-context
$ kubectl config use-context my-cluster-name

$ kubectl run nginx --image=nginx
$ kubectl explain pods,svc

$ kubectl edit svc/my-service-1  # ← Edit resource

ºkubectl Field Selectorsº
- filter k8s objects based on the value of one or more object fields.
- the possible field depends on each object type/kind but
  all resource-types support 'metadata.name' and 'metadata.namespace'
  Ex:
  $ kubectl get pods --field-selector       metadata.name==my-service,spec.restartPolicy=Always
  $ kubectl get pods --field-selector  metadata.namespace!=default,status.phase==Running
Building Blocks
NameSpaces
Namespace
@[https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/]
@[https://kubernetes.io/docs/tasks/administer-cluster/namespaces/]
- Provide a scope for names
- Namespaces are intended for use in environments with many users spread
  across multiple teams, or projects. For clusters with a few to tens of users,
  you should not need to create or think about namespaces at all. Start
  using namespaces when you need the features they provide.
- use labels, not namespaces, to distinguish resources within the same namespace
- Services are created with DNS entry
  "service-name"."namespace".svc.cluster.local

$ kubectlºget namespacesº
NAME          STATUS    AGE
default       Active    1d
kube-system   Active    1d

$ kubectlºcreate namespaceºmy-namespace // ← create namespace:

$ kubectlº--namespace=my-namespaceº \ ← set NS for request
    run nginx --image=nginx
$ kubectlºconfig set-contextº\           ← permanently save the NS
    $(kubectl ºconfig current-contextº) \ ← shell syntax sugar: Exec command and take output
    --namespace=MyFavouriteNS                                   as input for next command
$ kubectl config view | \
    grep namespace: # Validate
Secrets
@[https://kubernetes.io/docs/concepts/configuration/secret/]

@[https://github.com/kubernetes/community/blob/master/contributors/design-proposals/auth/secrets.md]
See also: 
 @[https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/]

- (Handling passwords, OAuth tokens, ssh keys, ... in k8s)

- Users (and system) create secrets
- At runtime Pods reference the secrets in three ways:
  - as files in a mounted volume
  - as ENVIRONMENT variables.
- Also used by kubelet when pulling images for the pod

ºBuilt-in Secretsº
- Service Accounts automatically create and attach secrets with API Credentials
- Kubernetes automatically creates secrets which contain credentials for
  accessing the API and it automatically modifies your pods to use this type
  of secret.

ºCreating User Secretsº
│       ALTERNATIVE 1                           │ ALTERNATIVE 2                                    │ALTERNATIVE 3
│ ºSTEP 1º: Create un-encrypted secrets locally:│ºSTEP 1:ºCreate Secret with data                  │ºSTEP 1º: Create Secret with stringData
│   $ echo -n 'admin'        ˃ ./username.txt   │   cat ˂˂ EOF ˃ secret.yaml                       │apiVersion: v1
│   $ echo -n '1f2d1e2e67df' ˃ ./password.txt   │   apiVersion: v1                                 │kind:ºSecretº
│              ^^^^^^^^^^^^                     │   kind:ºSecretº                                  │metadata:
│              special chars. must be           │   metadata:                                      │  name: mysecret
│              '\' escaped.                     │     name: mysecret                               │type: Opaque
│                                               │   type: Opaque                                   │stringData:
│                                               │   data:                                          │  config.yaml: |-
│                                               │     username: $(echo -n 'admin'        | base64) │    apiUrl: "https://my.api.com/api/v1"
│                                               │     password: $(echo -n '1f2d1e2e67df' | base64) │    username: admin
│                                               │   EOF                                            │    password: 1f2d1e2e67df
│                                               │                                                  │
│ ºSTEP 2:º Package into a Secret k8s object    │ºSTEP 2:º Apply                                   │ºSTEP 2:ºApply
│   $ kubectlºcreate secretº\                   │  $ kubectl apply -f ./secret.yaml                │  $ kubectl apply -f ./secret.yaml
│     genericGºdb-user-passº \                  │                                                  │
│     --from-file=./username.txt \              │                                                  │
│     --from-file=./password.txt                │                                                  │

│ºSTEP 3:º Check that Secret object has been ┌────────────────────────────────────────────
│  properly created.                         │ ºUsing the Secrets in a Podº
│  $ kubectl get secrets                     │                                   Control secret path with items:         Consume as ENV.VARS
│  → NAME           TYPE    DATA  AGE        │ apiVersion: v1                  │ apiVersion: v1                        | apiVersion: v1
│  → db-user-pass   Opaque  2     51s        │ kind:ºPodº                      │ kind:ºPodº                            | kind: Pod
│                                            │ metadata:                       │ metadata:                             | metadata:
│  $ kubectl describe secrets/db-user-pass   │   name: mypod                   │   name: mypod                         |   name: secret-env-pod
│  → Name:          Gºdb-user-passº          │ spec:                           │ spec:                                 | spec:
│  → Namespace:       default                │   containers:                   │   containers:                         |  containers:
│  → Labels:          ˂none˃                 │   ─ name: mypod                 │   - name: mypod                       |  - name: mycontainer
│  → Annotations:     ˂none˃                 │     image: redis                │     image: redis                      |   image: redis
│  →                                         │     volumeMounts:               │     volumeMounts:                     |   env:
│  → Type:            Opaque                 │     ─ name:ºfoOº                │     - name:ºfooº                      |    - name: SECRET_USERNAME
│  →                                         │       mountPath: "/etc/foo"     │       mountPath: "/etc/foo"           |     valueFrom:
│  → Data                                    │       readOnly:ºtrueº           │       readOnly: true                  |      secretKeyRef:
│  → ====                                    │   volumes:                      │   volumes:                            |       name: Gºdb─user─passº
│  →ºpassword.txt:º   12 bytes               │   ─ name:ºfoOº                  │   - name:ºfooº                        |       key: username
│  →ºusername.txt:º   5 bytes                │     secret:                     │     secret:                           |    - name: SECRET_PASSWORD
                                             │       secretName:Gºdb─user─passº│       secretName:Gºdb─user─passº      |     valueFrom:
                                             │       defaultMode: 256          │       items:                          |      secretKeyRef:
                                             │                     ^           │       - key: username                 |       name: Gºdb─user─passº
                                             │                     |           │         path: my-group/my-username    |       key: password
                                                                   |                           ^^^^^^^^^^^^^^^^^^^^
                                                            JSON does NOT support     · username will be seen in container as:
                                                            octal notation.             /etc/foo/my-group/my-username
                                                                     256 = 0400       · password secret is not projected


Ex 2:
SECRET CREATION                                      | SECRET USSAGE
$ kubectl create secret generic \                    | apiVersion: v1
Gºssh-key-secretº \                                  | kind: Pod
  --from-file=ssh-privatekey=/path/to/.ssh/id_rsa \  | metadata:
  --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub |   name: secret-test-pod
                                                     |   labels:
                                                     |     name: secret-test
                                                     | spec:
                                                     |   volumes:
                                                     |   - name: secret-volume
                                                     |     secret:
                                                     |       secretName:Gºssh-key-secretº
                                                     |   containers:
                                                     |   - name: ssh-test-container
                                                     |     image: mySshImage
                                                     |     volumeMounts:
                                                     |     - name: secret-volume
                                                     |       readOnly: true
                                                     |       mountPath: "/etc/secret-volume"
                                                     |                  ^^^^^^^^^^^^^^^^^^^^
                                                     |          secret files available visible like:
                                                     |          /etc/secret-volume/ssh-publickey
                                                     |          /etc/secret-volume/ssh-privatekey


FEATURE STATE: Kubernetes v1.13 beta
You can enable encryption at rest for secret data, so that the secrets are not stored in the clear into etcd .
(Pod)ConfigMap
@[https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/]

ConfigMaps: decouple configuration artifacts from image content

ºCreate a ConfigMapº


$ kubectl create configmap \
   'map-name' \
   'data-source'   ← data-source: directories, files or literal values
                                  translates to the key-value pair in the ConfigMap where
                                  key   = file_name or key               provided on the cli
                                  value = file_contents or literal_value provided on the cli

You can use kubectl describe or kubectl get to retrieve information about a ConfigMap.

ConfigMapºfrom config-fileº:
┌───────────────────────────── ┌──────────────────────────────────────
│ºSTEP 0:º Input to config map │ºSTEP 1:º create ConfigMap object
│ ...configure─pod─container/  │ $ kubectl create configmap \
│    └─ configmap/             │   game-config
│       ├─ºgame.propertiesº    │   --from-file=configmap/
│       └─º  ui.propertiesº    │               ^^^^^^^^^^
│                              │               combines the contents of
│                              │               all files in the directory

┌───────────────────────────────────────────────────────────────────────────────────────────────────────────
│ºSTEP 2:º check STEP 1
│$ kubectlºget configmapsºgame-config -o yaml                     │$ kubectlºdescribe configmapsºgame-config
│→ apiVersion: v1                                                 │→
│→ kind: ConfigMap                                                │→ Name:           game-config
│→ metadata:                                                      │→ Namespace:      default
│→   creationTimestamp: 2016-02-18T18:52:05Z                      │→ Labels:         
│→   name: game-config                                            │→ Annotations:    
│→   namespace: default                                           │→
│→   resourceVersion: "516"                                       │→ Data
│→   selfLink: /api/v1/namespaces/default/configmaps/game-config  │→ ====
│→   uid: b4952dc3-d670-11e5-8cd0-68f728db1985                    │→ºgame.properties:º 158 bytes
│→ data:                                                          │→ºui.properties:  º  83 bytes
│→  ºgame.properties:º|
│→     enemies=aliens
│→     lives=3                                  ┌───────────────────────────────────
│→     enemies.cheat=true                       │ºSTEP 3:ºUse in Pod container*
│→     enemies.cheat.level=noGoodRotten         │ apiVersion: v1
│→     secret.code.passphrase=UUDDLRLRBABAS     │ kind: Pod
│→     secret.code.allowed=true                 │ metadata:
│→     secret.code.lives=30                     │   name: dapi-test-pod
│→  ºui.properties:º|                           │ spec:
│→     color.good=purple                        │  containers:
│→     color.bad=yellow                         │   - name: test-container
│→     allow.textmode=true                      │     ...
│→     how.nice.to.look=fairlyNice              │     env:
                                                │     º- name: ENEMIES_CHEAT     º
                                                │     º  valueFrom:              º
                                                │     º    configMapKeyRef:      º
                                                │     º      name: game-config   º
                                                │     º      key: enemies.cheat  º


ConfigMapºfrom env-fileº:
│ºSTEP 0:º Input to config map       │ºSTEP 1:º create ConfigMap object
│ ...configure─pod─container/        │ $ kubectl create configmap \
│    └─ configmap/                   │   game-config-env-file \
│       └─ºgame-env-file.propertiesº │   --from-env-file=game-env-file.properties
│          ^^^^^^^^^^^^^^^^^^^^^^^^
│          game-env-file.properties
│          enemies=aliens            │ ºSTEP 2:º Check STEP 1
│          lives=3                   │ $ kubectl get configmap game-config-env-file -o yaml
│          allowed="true"            │ → apiVersion: v1
                                     │ → kind: ConfigMap
                                     │ → metadata:
                                     │ →   creationTimestamp: 2017-12-27T18:36:28Z
                                     │ →   name: game-config-env-file
                                     │ →   namespace: default
                                     │ →   resourceVersion: "809965"
                                     │ →   selfLink: /api/v1/namespaces/default/configmaps/game-config-env-file
                                     │ →   uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
                                     │ → data:
                                     │ →   allowed: '"true"'
                                     │ →   enemies: aliens
                                     │ →   lives: "3"

NOTE: kubectl create configmap ... --from-file=Bº'my-key-name'º='path-to-file'
      will create the data under:
      → ....
      → data:
      → Bºmy-key-name:º
      →     key1: value1
      →     ...

ºConfigMaps from literal valuesº
º STEP 1º                                     | º STEP 2º
$ kubectl create configmap special-config \   | → ...
   --from-literal=special.how=very \          | → data:
   --from-literal=special.type=charm          | →   special.how: very
                                              | →   special.type: charm

  restartPolicy: Never

Containers
Init Containers
@[https://kubernetes.io/docs/concepts/workloads/pods/init-containers/]

- one or more specialized Containers that run before app Containers
-ºcan contain utilities or setup scripts not present in an app imageº
- exactly equal to regular Containers, except:
  - They always run to completion.
    k8s will restart it repeatedly until succeeds
    (unless restartPolicy == Never)
  - Each one must complete successfully before the next one is started.
  - status is returned in .status.initContainerStatuses
                                  ^^^^^^^^^^^^^^^^^^^^^
                       vs .status.containerStatuses
  - readiness probes do not apply

Note: Init Containers can also be given access to Secrets that app Containers
      are not able to access.

- Ex: Wait for 'myService' and then for 'mydb'.
  │ apiVersion: v1                  │apiVersion: v1        │apiVersion: v1
  │ kind:ºPodº                      │kind:ºServiceº        │kind:ºServiceº
  │ metadata:                       │metadata:             │metadata:
  │   name: myapp─pod               │  name:Gºmyserviceº   │  name:Bºmydbº
  │   labels:                       │spec:                 │spec:
  │     app: myapp                  │  ports:              │  ports:
  │ spec:                           │  ─ protocol: TCP     │  ─ protocol: TCP
  │   containers:                   │    port: 80          │    port: 80
  │   ─ name: myapp─container       │    targetPort: 9376  │    targetPort: 9377
  │     image: busybox:1.28         └────────────────────  └─────────────────────
  │     command: ['sh', '─c', 'echo The app is running! ⅋⅋ sleep 3600']
  │  ºinitContainers:º
  │   ─ name:Oºinit─myserviceº
  │     image: busybox:1.28
  │     command: ['sh', '─c', 'until nslookup Gºmyserviceº; sleep 2; done;']
  │   ─ name:Oºinit─mydbº
  │     image: busybox:1.28
  │     command: ['sh', '─c', 'until nslookup Bºmydbº     ; sleep 2; done;']

  Inspect init Containers like:
  $ kubectl logs myapp-pod -c Oºinit-myserviceº
  $ kubectl logs myapp-pod -c Oºinit-mydb     º

RºWARN:º
- Use activeDeadlineSeconds on the Pod and livenessProbe on the Container
  to prevent Init Containers from failing forever.

- Debugging Init Containers:
@[https://kubernetes.io/docs/tasks/debug-application-cluster/debug-init-containers/]
Containers Limits
@[https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/]

- See also design proposal:
@[https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/resource-qos.md]

A Container:
-   ºcan exceedº its resourceºrequestºif the Node has memory available,
- isºnot allowedºto use more than its resource ºlimitº.

- spec.containers[].resources.limits.cpu              ← can NOT exceed resource limit → it will be scheduled
- spec.containers[].resources.limits.memory                                             for termination
- spec.containers[].resources.requests.cpu            ← can     exceed resource request
- spec.containers[].resources.requests.memory
- spec.containers[].resources.limits.ephemeral-storage     k8s 1.8+
- spec.containers[].resources.requests.ephemeral-storage   k8s 1.8+

Note: resource quota feature can be configured to limit the total amount of resources
      that can be consumed. In conjunction namespaces, it can prevent one team from
      hogging all the resources.

ContaineRºComputeºResource types:
- CPU    : units of cores
           - total amount of CPU time that a container can use every 100ms.
             (minimum resolution can be setup to 1ms)
           - 1 cpu is equivalent to: 1 (AWS vCPU|GCP Core|Azure vCore,IBM vCPU,Hyperthread bare-metal )
           - 0.1 cpu == 100m
- memory : units of bytes:
           - Ex: 128974848, 129e6, 129M, 123Mi
- Local ephemeral storage(k8s 1.8+):
           - No QoS can be applied.
           - Ex: 128974848, 129e6, 129M, 123Mi

When using Docker:
 greater of this number or 2 is used as the value of the --cpu-shares flag in the docker run command.


ºExtended resourcesº
- fully-qualified resource names outside the kubernetes.io domain.

Ussage:
- STEP 1: cluster operator must advertise an Extended Resource.
- STEP 2: users must request the Extended Resource in Pods.
(See official doc for more info)

It is planned to add new resource types, including a node disk space resource, and a framework for adding custom resource types.
Pods
Life Cicle
 DEFINITION                                               END
  defined   → scheduled in node → run → alt1: run until their container(s) exit
                                        alt2: pod removed (for any other reason)
                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                  depending on policy and exit code,
                                                  may be removed after exiting, or
                                                  may be retained in order to enable
                                                  access containers logs.

@[https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/]
Pod.PodStatus.phase := Pending|Running|Succeeded|Failed

Pod Preset @[https://kubernetes.io/docs/concepts/workloads/pods/podpreset/] - objects used to inject information into pods at creation time like secrets, volumes, volume mounts, and environment variables. - label selectors are used to specify Pods affected. ºDisable Pod Preset for a Specific Podº Add next annotation to the Pod Spec: - podpreset.admission.kubernetes.io/exclude: "true".
Pod QoS @[https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/] Pod.spec.qosClass := Guaranteed Assigned to pod when: - All Pod-Containers have a defined cpu/mem. limit. - All Pod-Containers have same cpu/mem.limit and same cpu/mem.request Burstable Assigned to pod when: - criteria for QoS class Guaranteed isºNOTºmet. - 1+ Pod-Containers have memory or CPU request. BestEffort Assigned to pod when: - Pod-Containers do NOT have any memory/CPU request/limit Ex. Pod YAML Definition: apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: gcr.io/google_containers/test-webserver name: test-container volumeMounts: - mountPath: /cache ← where to mount name:Bºcache-volumeº ← volume (name) to mount - mountPath: /test-pd name:Gºtest-volumeº volumes: - name:Bºcache-volumeº emptyDir: {} - name:Gºtest-volumeº hostPath: # directory location on host path: /data # this field is optional type: Directory Managing running pods
$ kubectl get pod shell-demo # ← ensure pod is running $ kubectlºlogsºmy-pod (-c my-container) (-f) # ← Get logs ^^ "tail" $ kubectlºattachºmy-pod -i $ kubectlºport-forwardºmy-pod 5000:6000 ^ ^ local pod machine port $ kubectlºrunº-i \ # ← Exec. shell for image --tty busybox \ # (launch new temporal pod) --image=busybox \ -- sh $ kubectlºexecºmy-pod \ # ← Get a shell inside already-running Pod (-c my-container) # ← Required if Pod has 2+ containers -it # ← Allocate terminal. -- /bin/bash $ kubectlºexecºmy-pod \ # ← Execute non-interatively inside already-running Pod (-c my-container) # ← Required if Pod has 2+ containers env # ← env execution will dump all ENV.VARs inside container $ kubectlºtopºpod POD_NAME --containers
SecurityContext
@[https://kubernetes.io/docs/tasks/configure-pod-container/security-context/]
@[https://github.com/kubernetes/community/blob/master/contributors/design-proposals/auth/security_context.md]
Pod.spec.securityContext Ex:
Ex:
apiVersion: v1                            Exec a terminal into a running container adnd execute:
kind: Pod                                 $ id
metadata:                                ºuid=1000 gid=3000 groups=2000º
  name: security-context-demo                 ^^^^     ^^^^
spec:                                         uid/gid 0/0 if not specified
 ºsecurityContext:  º
 º  runAsUser: 1000 º
 º  runAsGroup: 3000º
 º  fsGroup: 2000º ← owned/writable by this GID when supported by volume
  volumes:
  - name: sec-ctx-vol   ← Volumes will be relabeled with provided seLinuxOptions values
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    ...
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
   ºsecurityContext:º
   º  allowPrivilegeEscalation: falseº
   º  capabilities:º
   º    add: ["NET_ADMIN", "SYS_TIME"]º ← Provides a subset of 'root' capabilities:
                                        @[https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h]
    º seLinuxOptions:º
    º   level: "s0:c123,c456"º


SecurityContext holds security configuration that will be applied to a container.
Some fields are present in both SecurityContext and PodSecurityContext.  When both
are set, the values in SecurityContext take precedence.
typeºSecurityContextºstruct {
    // The capabilities to add/drop when running containers.
    // Defaults to the default set of capabilities granted by the container runtime.
    // +optional
    Capabilities *Capabilities
    // Run container in privileged mode.
    // Processes in privileged containers are essentially equivalent to root on the host.
    // Defaults to false.
    // +optional
    Privileged *bool
    // The SELinux context to be applied to the container.
    // If unspecified, the container runtime will allocate a random SELinux context for each
    // container.  May also be set in PodSecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence.
    // +optional
    SELinuxOptions *SELinuxOptions
    // Windows security options.
    // +optional
    WindowsOptions *WindowsSecurityContextOptions
    // The UID to run the entrypoint of the container process.
    // Defaults to user specified in image metadata if unspecified.
    // May also be set in PodSecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence.
    // +optional
    RunAsUser *int64
    // The GID to run the entrypoint of the container process.
    // Uses runtime default if unset.
    // May also be set in PodSecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence.
    // +optional
    RunAsGroup *int64
    // Indicates that the container must run as a non-root user.
    // If true, the Kubelet will validate the image at runtime to ensure that it
    // does not run as UID 0 (root) and fail to start the container if it does.
    // If unset or false, no such validation will be performed.
    // May also be set in PodSecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence.
    // +optional
    RunAsNonRoot *bool
    // The read-only root filesystem allows you to restrict the locations that an application can write
    // files to, ensuring the persistent data can only be written to mounts.
    // +optional
    ReadOnlyRootFilesystem *bool
    // AllowPrivilegeEscalation controls whether a process can gain more
    // privileges than its parent process. This bool directly controls if
    // the no_new_privs flag will be set on the container process.
    // +optional
    AllowPrivilegeEscalation *bool
    // ProcMount denotes the type of proc mount to use for the containers.
    // The default is DefaultProcMount which uses the container runtime defaults for
    // readonly paths and masked paths.
    // +optional
    ProcMount *ProcMountType
}
─────────────────────────────────────────────────────────────────────────────
// PodSecurityContext holds pod-level security attributes and common container settings
// Some fields are also present in container.securityContext.  Field values of
// container.securityContext take precedence over field values of PodSecurityContext.
typeºPodSecurityContextºstruct {
    // Use the host's network namespace.  If this option is set, the ports that will be
    // used must be specified.
    // Optional: Default to false
    // +k8s:conversion-gen=false
    // +optional
    HostNetwork bool
    // Use the host's pid namespace.
    // Optional: Default to false.
    // +k8s:conversion-gen=false
    // +optional
    HostPID bool
    // Use the host's ipc namespace.
    // Optional: Default to false.
    // +k8s:conversion-gen=false
    // +optional
    HostIPC bool
    // Share a single process namespace between all of the containers in a pod.
    // When this is set containers will be able to view and signal processes from other conts
    // in the same pod, and the first process in each container will not be assigned PID 1.
    // HostPID and ShareProcessNamespace cannot both be set.
    // Optional: Default to false.
    // This field is beta-level and may be disabled with the PodShareProcessNamespace feature.
    // +k8s:conversion-gen=false
    // +optional
    ShareProcessNamespace *bool
    // The SELinux context to be applied to all containers.
    // If unspecified, the container runtime will allocate a random SELinux context for each
    // container.  May also be set in SecurityContext.  If set in
    // both SecurityContext and PodSecurityContext, the value specified in SecurityContext
    // takes precedence for that container.
    // +optional
    SELinuxOptions *SELinuxOptions
    // Windows security options.
    // +optional
    WindowsOptions *WindowsSecurityContextOptions
    // The UID to run the entrypoint of the container process.
    // Defaults to user specified in image metadata if unspecified.
    // May also be set in SecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence
    // for that container.
    // +optional
    RunAsUser *int64
    // The GID to run the entrypoint of the container process.
    // Uses runtime default if unset.
    // May also be set in SecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence
    // for that container.
    // +optional
    RunAsGroup *int64
    // Indicates that the container must run as a non-root user.
    // If true, the Kubelet will validate the image at runtime to ensure that it
    // does not run as UID 0 (root) and fail to start the container if it does.
    // If unset or false, no such validation will be performed.
    // May also be set in SecurityContext.  If set in both SecurityContext and
    // PodSecurityContext, the value specified in SecurityContext takes precedence
    // for that container.
    // +optional
    RunAsNonRoot *bool
    // A list of groups applied to the first process run in each container, in addition
    // to the container's primary GID.  If unspecified, no groups will be added to
    // any container.
    // +optional
    SupplementalGroups []int64
    // A special supplemental group that applies to all containers in a pod.
    // Some volume types allow the Kubelet to change the ownership of that volume
    // to be owned by the pod:
    //
    // 1. The owning GID will be the FSGroup
    // 2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
    // 3. The permission bits are OR'd with rw-rw----
    //
    // If unset, the Kubelet will not modify the ownership and permissions of any volume.
    // +optional
    FSGroup *int64
    // Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
    // sysctls (by the container runtime) might fail to launch.
    // +optional
    Sysctls []Sysctl
}
ServiceAccount
@[https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/]
@[https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/]

- Processes in containers inside pods can also contact the apiserver.
  When they do, they are authenticated as a particular Service Account
- provides an identity for processes that run in a Pod.
- to access the API from inside a pod a mounted service account with
  a 1-hour-expiration-token is provided.
  (can be disabled with automountServiceAccountToken)
- User accounts are for humans. Service accounts are for processes running on pods.
- Service accounts are namespaced.
- cluster users can create service accounts for specific tasks (i.e. principle of least privilege).
- Allows to split auditing between humans and services.

- Three separate components cooperate to implement the automation around service accounts:
  - AºService account admission controllerº, part of the apiserver, thatsynchronously modify
    pods as they are created or updated:
    - sets the ServiceAccount to default when not specified by pod.
    - abort if ServiceAccount in the pod spec does NOT exists.
    - ImagePullSecrets of ServiceAccount are added to the pod if none is specified by pod.
    - Adds a volume to the pod which contains a token for API access.
      (service account token expires after 1 hour or on pod deletion)
    - Adds a volumeSource to each container of the pod mounted at
      */var/run/secrets/kubernetes.io/serviceaccount*
  - AºToken controllerº, running as as part of controller-manager. It acts asynchronously and
    - observes serviceAccount creation and creates a corresponding Secret to allow API access.
    - observes serviceAccount deletion and deletes all corresponding ServiceAccountToken Secrets.
    - observes secret addition, and ensures the referenced ServiceAccount exists, and adds a
      token to the secret if needed.
    - observes secret deletion and removes a reference from the corresponding ServiceAccount if needed.
    NOTE:
      controller-manageRº'--service-account-private-key-file'º indicates the priv.key signing tokens
     - kube-apiserver   º'--service-account-key-file'º         indicates the matching pub.key verifying signatures
    - A controller loop ensures a secret with an API token exists for each service account.

    To create additional API tokens for a service account:
    - create a new secret of type ServiceAccountToken like:
      (controller will update it with a generated token)
      {
        "kind":º"Secret"º,
        "type":º"kubernetes.io/service-account-token"º
        "apiVersion": "v1",
        "metadata": {
          "name": "mysecretname",
          "annotations": {
            "kubernetes.io/service-account.name" :
              "myserviceaccount"  ← reference to service account
          }
        },
      }
  - AºService account controller:º
    - manages ServiceAccount inside namespaces,
    - ensures a ServiceAccount named “default” exists in every active namespace.
      $ kubectl get serviceAccounts
      NAME      SECRETS    AGE
      default   1          1d   ← Exists for each namespace
      ...
    - Additional ServiceAccount's can be created like:
    -
    - $ kubectl apply -f - ˂˂EOF
    - apiVersion: v1
    - kind: ServiceAccount
    - metadata:
    -   name: build-robot
    - EOF
Liveness/Readiness Probes
@[https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/]
@[https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.14/#probe-v1-core]
.
- liveness probes  : used by kubelet to know when to restart a Container.
- readiness probes : used by kubelet to know whether a Container can accept new requests.
                     - A Pod is considered ready when all of its Containers are ready.
                     - The Pod is not restarted in this case but no new requests are
                       forwarded.
                     - Readiness probes continue to execute for the lifetime of the Pod
                       (not only at startup)

ºliveness COMMANDº            │ ºliveness HTTP requestº         │ ºTCP liveness probeº
                              │                                 │
apiVersion: v1                │ apiVersion: v1                  │ apiVersion: v1
kind:ºPodº                    │ kind:ºPodº                      │ kind:ºPodº
metadata:                     │ metadata:                       │ metadata:
  ...                         │   ...                           │   ...
spec:                         │ spec:                           │ spec:
 ºcontainers:º                │  ºcontainers:º                  │  ºcontainers:º
  - name: ...                 │   - name: ...                   │   - name: ...
    ...                       │     ...                         │    ºreadinessProbe:          º
   ºlivenessProbe:          º │    ºlivenessProbe:           º  │    º  tcpSocket:             º
   º  exec:                 º │    º  httpGet:               º  │    º    port: 8080           º
   º    command:            º │    º    path: /healthz       º  │    º  initialDelaySeconds: 5 º
   º    - cat               º │    º    port: 8080           º  │    º  periodSeconds: 10      º
   º    - /tmp/healthy      º │    º    httpHeaders:         º  │    ºlivenessProbe:           º
   º  initialDelaySeconds: 5º │    º    - name: Custom-HeadeRº  │    º  tcpSocket:             º
   º  periodSeconds: 5      º │    º      value: Awesome     º  │    º    port: 8080           º
                              │    º  initialDelaySeconds: 3 º  │    º  initialDelaySeconds: 15º
                              │    º  periodSeconds: 3       º  │    º  periodSeconds: 20      º
                                HTTP proxy ENV.VARS is ignored
                                in liveness probes (k8s v1.13+)

                                      ↑                                ↑
                                      │                                │
ºnamedºContainerPort can also   ──────┴────────────────────────────────┘
be used for HTTP and TCP probes
like:
 │ ports:
 │ - name: liveness-port
 │   containerPort: 8080
 │   hostPort: 8080
 │
 │ livenessProbe:
 │   httpGet:
 │     path: /healthz
 │     port: liveness-port

ºMonitor liveness test resultº
$ kubectl describe pod liveness-exec

Other optional parameters:
- timeoutSeconds  : secs after which the probe times out. (1 sec by default)
- successThreshold: Minimum consecutive successes for the probe to be
                    considered successful after having failed. (1 by default)
- failureThreshold: number of failures before "giving up": Pod will be marked Unready.(Def 3)

HTTP optional parameters:
- host  : for example 127.0.0.1 (defaults to pod IP)
- port  : Name or number(1-65535)
- scheme: HTTP or HTTPS(skiping cert.validation)
- path  :
- httpHeaders: Custom headers
Services
Service

Problem: Pods can be rescheduled to a different node in k8s pool,
         "at random", changing their internal cluster IP.
         How Pods can deterministically access some other Pod's
         services (TCP/UDP/Web service, ...)?

Solution: Use k8s Services

- A Services logically groups a set of Pods through a Label-selection,
  and for such logical group, it also established a ºnetwork policyº.
  to access them.

- Kubernetes-native applications: K8s offers a simple Endpoints API
- non-native        applications: K8s offers virtual-IP-based-2-Service bridge

-OºService Types:º
  - OºClusterIPº   : (default) internal-to-cluster virtual IP.
                     No IP exposed outside the cluster.

  - OºExternalNameº: Maps apps (Pods services) to an externally
                     visible DNS entry (ex: foo.example.com)

  ─ OºNodePortº    : Exposes an external NodeIP:NodePort to        ←───────┐  k8s ºIngressº can also be used
                     Pods providing the service.                           ├─ to expose HTTP/S services to 
                                                                           │  external clients.
  ─ OºLoadBalancerº: Exposes Service externally using a cloud provider's ←─┘  NodePort/LoadBalancer Services
                     load balancer. NodePort and ClusterIP services,          allows for TCP,UDP,PROXY and SCTP(k8s 1.2+)
                     to which the external load balancer routes, are          - Advanced load balancing 
                     automatically created.                                     (persistent sessions, dynamic weights)
                                                                                are RºNOTº yet supported by Ingress rules
                                                                              - On the other side ingress allows
                                                                                to expose services based on
                                                                                HTTP host (virtual hosting), paths/regex,...
                                                                                not available to NodePort/LoadBalancer 
                                                                                Services

 kube-proxy, installed on each node of the k8s pool, will get in charge of 
 forwarding correctly to the correct target.
 Note: kube-proxy is more reliable than DNS due to problems with TTLs,
       DNS caching on clients,...

   OºClusterIPº           │    OºNodePortº             │    OºExternalNameº
   Oº=========º           │    Oº========º             │    Oº============º
                          │                            │
                    ┌───┐ │ :3100┌────┐       :80┌───┐ │              ┌────┐:80───┐
              ┌─→:80│Pod│ │ ┌───→│node├───┐  ┌──→│Pod│ │           ┌─→│node├─→│Pod│
              │     └───┘ │ │    └────┘   │  │   └───┘ │           │  └────┘  └───┘
        :80┌───────────┐  │ Incomming  ┌──v───────┐    │     :80 ┌──────────┐
Internal──→│ºClusterIPº│  │ traffic    │ºNodePortº│    │     ┌─→:│  ºLoadº  │ ┌───┐
Traffic    └───────────┘  │ │          └──^───────┘    │     │   │ºBalancerº│ │Pod│
              │     ┌───┐ │ │    ┌────┐   │  │   ┌───┐ │     │   └──────────┘ └───┘
              └─→:80│Pod│ │ └───→│node├───┘  └──→│Pod│ │ Incomming │   ┌────┐  ↑:80
                    └───┘ │ :3100└────┘       :80└───┘ │   traffic └──→│node├──┘
                          │ ^                 ^        │               └────┘
                          │ Creates mapping between    │  configures an external
                          │ node port(3100) and        │  IP address in balancer.
                          │ Pod port (80)              │  Then connects requested
                          │                            │  pods to balancer


    apiVersion: v1
    kind:ºServiceº
    metadata:
      name: Redis_Master ← Must be a valid DNS label name
    spec:
┌→  ·  selector:          ← Targeted Pods defined in selector
|   ·    app: MyApp       ← Matching label.
|   ·  clusterIP: 1.1.1.1 ← Optional. set it to match any existing DNS entry or 
|   ·                       legacy systems with hardcoded IPs difficult to reconfigure
|   ·                       In k8s apps, clusterIP can be auto-assigned by k8s, 
|   ·                       App will use Environment Variables (injected into the Pod)
|   ·                       and/or DNS.
|   ·                       REDIS_MASTER_SERVICE_HOST=10.0.0.11
|   ·                       REDIS_MASTER_SERVICE_PORT=6379
|   ·                       REDIS_MASTER_PORT=tcp://10.0.0.11:6379
|   ·                       REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
|   ·                       REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
|   ·                       REDIS_MASTER_PORT_6379_TCP_PORT=6379
|   ·                       REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
|   ·                     RºWARNº: Service must be setup before Pod is started.
| 
| 
|   ·                       The DNS entry (if CoreDNS or other k8s-aware DNS server is setup) 
|   ·                       will be like:
|   ·                       redis_master.myNameSpace
|   ·                                   ^^^^^^^^^^^^
|   ·                                   Needed only for Pods in another Namespace.
|   ·  ports:             
|   ·  - name: http
|   ·    protocol: TCP     ← TCP*, UDP, HTTP, PROXY, SCTP(k8s 1.2+) º*1º
|   ·    port: 80          ← Request to port 80 will be forwarded to Port 9376
|   ·    targetPort: 9376    on "any" pod matching the selector.
|   ·  - name: https
|   ·    protocol: TCP
|   ·    port: 443
|   ·    targetPort: 9377
|   ·  sessionAffinity: "ClientIP" ← Optionally sessionAffinityConfig.clientIP.timeoutSeconds
|                                    can be set (defaults to 10800)
|
└ The selector can be empty if Service doesn't target internal pod. 
  This is the case when we want the Service to point to:
┌ - External tcp service (DDBB, ERP, ...)
| - Different Namespace or differente K8s cluster.
| - k8s migration is in progress.
| In this case the Endpoint object is not automatically created. Admins can point manually
| to an external end-point like:
|   
|   apiVersion: v1
|   kind:ºEndpointsº
|   metadata:
|     name: my-service   ← Must also be a valid DNS subdomain name.
└→  subsets:
      - addresses: 
        - ip: 10.0.0.10  ← External PostgreSQL @10.0.0.10:5432
      - ports: 
        - port: 5432


ºUser-space Proxy Mode:º
 (kube-proxy on each k8s node of k8s node-pool keeps listening for events from Master.ApiServer)
 master →     kube-proxy: Event  +Service.EndPoint 
 kube-proxy → kube-proxy: - Open Random Port 01 
                          - Setup round-robin from random-port 01 to *all existing*
                            Backend Pods matching the Service selector.
 kube-proxy → iptables  : Install iptables rule in kernel to capture traffice to
                          (virtual) clusterIP:port to Random Port 01
 ...
 app        → kernel    : request to clusterIP:port
 kernel     → iptables  : request to clusterIP:port
 iptables   → kube-proxy: request to random port
 kube-proxy → kube-proxy: Round-robin amongst all availables Pods.
                          (The kube-proxy keeps a list of live-Pods matching the Service.Selector)
                          (Using also SessionAffinity for better balancing) 
 kube-proxy → Pod N     : request

ºiptables Proxy Mode:º
 (kube-proxy on each k8s node of k8s node-pool keeps listening for events from Master.ApiServer)
 master →     kube-proxy: Event  +Service.EndPoint 
 kube-proxy → iptables  : Install iptables rule in kernel to capture traffice to
                          (virtual) clusterIP:port to some Pod i (and just one) from
                          all Pods matching the Service.selecotr
 ...
 app        → kernel    : request to clusterIP:port
 kernel     → iptables  : request to clusterIP:port
 iptables   → Pod i     : request 
              ^^^^^
            - If Pod is down request fails. 
            - readiness probes can be set to avoid forwarding to a faulty Pod.

ºIPVS proxy modeº
 PRE-SETUP: IPVS module must be available on the node.
 master     → kube-proxy: Event +Service.EndPoint
 kube-proxy → netlink   : Create IPVS rules (sync status periodically)
                          to all Pods in Selector (allowing for balancing)
 app        → kernel    : request to clusterIP:port
 kernel     → netlink   : request to clusterIP:port
 netlink    → Pod i     : request

 Note: netlink allows next balancing options: 
       · rr: round-robin
       · lc: least connection (smallest number of open connections)
       · dh: destination hashing
       · sh: source hashing
       · sed: shortest expected delay
       · nq: never queue



º*1º:@[https://kubernetes.io/docs/concepts/services-networking/service/#protocol-support]
                                              ºLoad Balancerºworks at ºlayer 4º.
                                               unaware of the actual apps.
 (Layer 7)                  ┌───┐    ┌───┐ ☜ ☞ Use OºIngress controllersº(Oºlayer 7º)
┌─────────────────────┐     │Pod│    │Pod│     for advanced rules based on inbound
│OºIngress controllerº│     └─^─┘    └─^─┘     URL, ...
│ ┌─────────────────┐ │     ┌─┴────────┴───┐ - Another common feature of Ingress
│ │ myapp.com/blog  │ │───→ │Blog service  │   isºSSL/TLS terminationºremoving
│ └─────────────────┘ │     └──────────────┘   TLS cert complexity from Apps
│ ┌─────────────────┐ │     ┌──────────────┐
│ │ myapp.com/store │ │────→│Store service │
│ └─────────────────┘ │     └─┬────────┬───┘
└───^─────────────────┘     ┌─v─┐    ┌─v─┐
    |                       │Pod│    │Pod│
  Incomming                 └───┘    └───┘
   Traffic

-ºService.spec.clusterIP can be used to force a given IPº

┌─────────────────┐
│SERVICE DISCOVERY│
├─────────────────┴─────────────────────────────────────────────────────────────────────────────────────────
│  ALT.1, using ENV.VARS                          │  ALT.2, using the k8s DNS add─on
│                                                 │  (strongly recommended).
├─────────────────────────────────────────────────┼──────────────────────────────────────────────────────────
│Ex: given service "redis─master" with            │  Updates dynamically the set of DNS records for services.
│  OºClusterIPº = 10.0.0.11:6379                  │  The entry will be similar to:  "my─service.my─namespace"
│  next ENV.VARs are created:                     │
│  REDIS_MASTER_SERVICE_HOST=10.0.0.11            │
│  REDIS_MASTER_SERVICE_PORT=6379                 │
│  REDIS_MASTER_PORT=tcp://10.0.0.11:6379         │
│  REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379│
│  REDIS_MASTER_PORT_6379_TCP_PROTO=tcp           │
│  REDIS_MASTER_PORT_6379_TCP_PORT=6379           │
│  REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11      │
└─────────────────────────────────────────────────┴──────────────────────────────────────────────────────────


ºQuick App(Deployment) service creationº
REF: @[https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/]
$ kubectl expose deployment/my-nginx

is equivalent to:

$ kubectl apply -f service.yaml
                   ^^^^^^^^^^^^
                   apiVersion: v1
                   kind: Service
                   metadata:
                     name: my-nginx
                     labels:
                       run: my-nginx
                   spec:
                     ports:
                     - port: 80
                       protocol: TCP
                     selector:
                       run: my-nginx

@[https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/]

Debug Services
@[https://kubernetes.io/docs/tasks/debug-application-cluster/debug-service/]

☞ (Much more) detailed info available at:
  ( about kube-proxy + iptables +... advanced config settings)
@[https://kubernetes.io/docs/concepts/services-networking/service/]
Ingress Rules
@[https://kubernetes.io/docs/concepts/services-networking/ingress/]
- Ingress objects (and its rules) allows to exposes HTTP/S based k8s services to
  the internal cluster.

Ussually a WebApp (HTTP/s) can be summarised as:
 Creating Pods      →   Creating Services         → Creating Ingress Rules
 running on             to access Pods from         to expose HTTP/S Services
 k8s pool-nodes         other Ports.                externally allowing to
 listening for          Services listen for         split requests based on host name,
 HTTP/s requests        Pod creation/destruction    HTTP path/subpaths, ...
                        events to adjust
                        the correct node/port
                        target
                  
PRE-SETUP:
Prerequisites

- an ingress controller must be in place.
  ingress-nginx, ingress-istio, etc...
RºWARNº: Different Ingress controllers operate slightly differently to expected specification.

BºIngress Resource Example:º
  apiVersion: networking.k8s.io/v1beta1
 ºkind: Ingressº
  metadata:
  · name: test-ingress
  · annotations:
  ·   nginx.ingress.kubernetes.io/rewrite-target: / ← Annotation used before IngressClass was added 
  ·                                                   to define the underlying controller implementation.
  ·                                                   .ingressClassName can replace it now.
  spec:
    tls:                               ← Optional but recomended. Only 443 port supported.
    · - hosts:             ← values must        apiVersion: v1
    ·     - secure.foo.com   match cert CNs     kind: Secret                   
    ·                                           metadata:                      
    ·   secretName: secretTLSPrivateKey ←·····→   name: secretTLSPrivateKey    
    ·                                             namespace: default           
    ·                                           data:                          
    ·                                             tls.crt: base64 encoded cert 
    ·                                             tls.key: base64 encoded key  
    ·                                           type: kubernetes.io/tls        

    rules:                             ← A backend with no rules could be use to expose a single service

    - host: reddis.bar.com             ← Optional. filter-out HTTP requests not addressing this host
      http:
        paths:                         ← For each path in paths list a 
                                         If more than on path in list matches the request, longest matchs "wins".
        - path: /reddis
          pathType: Prefix             ← ImplementationSpecific: delegate matching to IngressClass (nginx, istio, ...)
                                         Exact                 : Matches URL path exactly             (RºWARNº:case sensitive).
                                         Prefix                : Matching based on request URL prefix (RºWARNº:case sensitive)

          backend:                    
            serviceName: reddissrv     ← targeted k8s service
            servicePort: 80            ← Need if more than a Listening port is defined for Service

    - host: monit.bar.com              ← Optional. filter-out HTTP requests not addressing this host
      http:
        - path: /grafana
          pathType: Prefix
          backend:
            serviceName: grafanasrv    ← targeted k8s service
        - path: /prometheus
          pathType: Prefix
          backend:
            serviceName: prometheussrv ← targeted k8s service

    - http:                            ← No host specified. All traffice not matching reddis.bar.com/monit.bar.com
        - path: /                        will be forwarded here.
          pathType: Prefix
          backend:
            serviceName: httpdsrv    ← targeted k8s service


Labels
Labels
@[https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors/]
- Labels = key/value pairs attached to objects.
- labelsºdo not provide uniquenessº
  - we expect many objects to carry the same label(s)
- used to specify ºidentifying attributes of objectsº
 ºmeaningful and relevant to usersº, (vs k8s core system)
- Normally used to organize and to select subsets of objects.
- Label format:
  ("prefix"/)name
  name : [a-z0-9A-Z\-_.]{1,63}
  prefix : must be a DNS subdomain no longer than 253 chars

- Example labels:
  "release"    : "stable" # "canary" ...
  "environment": "dev" # "qa", "pre",  "production"
  "tier"       : "frontend" # "backend" "cache"
  "partition"  : "customerA", "partition" : "customerB"
  "track"      : "daily" # "weekly" "monthly" ...


ºRecommended Labelsº
@[https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/]
Key                           Description                      Example             Type
app.kubernetes.io/name        The name of the application      mysql               string
app.kubernetes.io/instance    A unique name identifying        wordpress-abcxzy    string
                              the instance of an application
app.kubernetes.io/version     current version of the app       5.7.21              string
app.kubernetes.io/component   component within the arch        database            string
app.kubernetes.io/part-of     name of higher level app         wordpress           string
app.kubernetes.io/managed-by  tool used to manage the          helm                string
                              operation of an application

Ex.1 use in an StatefulSet object:

apiVersion: apps/v1                           |apiVersion: apps/v1             |apiVersion: v1
kind: StatefulSet                             |kind: Deployment                |kind: Service
metadata:                                     |metadata:                       |metadata:
 labels:                                      | labels:                        | labels:
  app.kubernetes.io/name      : mysql         |  .../name      : wordpress     |  .../name      : wordpress
  app.kubernetes.io/instance  : wordpress-abc |  .../instance  : wordpress-abc |  .../instance  : wordpress-abcxzy
  app.kubernetes.io/version   : "5.7.21"      |  .../version   : "4.9.4"       |  .../version   : "4.9.4"
  app.kubernetes.io/component : database      |  .../component : server        |  .../component : server
 ºapp.kubernetes.io/part-of   :ºwordpressº    |  .../part-of   :ºwordpressº    |  .../part-of   : wordpressº
  app.kubernetes.io/managed-by: helm          |  .../managed-by: helm          |  .../managed-by: helm
                                              |...                             |...




-ºWell-Known Labels, Annotations and Taintsº
@[https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/]
    kubernetes.io/arch
    kubernetes.io/os
    beta.kubernetes.io/arch (deprecated)
    beta.kubernetes.io/os (deprecated)
    kubernetes.io/hostname
    beta.kubernetes.io/instance-type
    failure-domain.beta.kubernetes.io/region
    failure-domain.beta.kubernetes.io/zone
Label selectors
- core (object) grouping primitive.
- two types of selectors:
  - equality-based
    Ex. environment=production,tier!=frontend
                              ^
                            "AND" represented with ','

  - set-based
    - filter keys according to a set of values.
      (in, notin and exists )
    Ex.'ºkeyºequal to environment andºvalueºequal to production or qa'

    Ex.'environment in (production, qa)'

    Ex.'tier notin (frontend, backend)'
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        all resources with
            (key == "tier" AND
             values != frontend or backend )  AND
        all resources with
            (key != "tier")

    Ex:'partition'                    !partition
        ^^^^^^^^^                     ^^^^^^^^^
        all resources including       all resources without
        a label with key 'partition'  a label with key 'partition'

- LIST and WATCH operations may specify label selectors to filter the sets
  of objects returned using a query parameter.
  Ex.:
  $ kubectl get pods -l environment=production,tier=frontend             # equality-based
  $ kubectl get pods -l 'environment in (production),tier in (frontend)' # set-based
  $ kubectl get pods -l 'environment in (production, qa)'                # "OR" only set-based
  $ kubectl get pods -l 'environment,environment notin (frontend)'       # "NOTIN"
Storage
Volume

@[https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/volume-ownership-management.md]

    REF: https://www.youtube.com/watch?v=OulmwTYTauI

                             once underlying         "hardware" resource applying
                             storage has been        to the whole cluster
                             assigned to a pod       (ºlifespanº independent of pods)
  ┌──────────────────┐       PV is bound to PVC      ┌─↓───────────┐
  │ Pod              │       one-to-one relation┌···→│ Persistent  ·····plugin to
  │                  │     ┌───────────────────┐·    │ Volume(ºPVº)│    one of
  │┌───────────────┐ │ ┌··→│ Persistent *1     │·    └─────────────┘        ·       Underlying
  ││ºVolume Mountsº│ │ ·   │ Volume            │·                           ·          Storage
  ││ /foo          │ │ ·   │ Claim (ºPVCº)     │·                       ┌───↓────────────────┐
  │└───────────────┘ │ ·   │                   │·    ┌────────────┐     │-Local HD           │
  │    ┌──────────────┐·   │- 100Gi            │· ┌·→│ Storage    │     │-NFS: path,serverDNS│
  │    │ Volumes:     │·   │- Selector ·········┘ ·  │ Class(ºSCº)│     │-Amazon:EBS,EFS,... │
  │    │ -PVC ·········┘   │- StorageClassName····┘  └────────────┘     │-Azure:...          │
  │    │ ─claimName   ←┐   └───────────────────┘                        │-...                │
  │    └──────────────┘└─ Volumeºlifespamºis                            └────────────────────┘
  └──────────────────┘    that of the Pod.

├────────Created by users (Dev)───────────────────┤ ├──────Created by Admin (Ops)────────────┤

- many types supported, and a Pod can use any number of them simultaneously.
- a pod specifies what volumes to provide for the pod (spec.volumes) and where
  to mount those into each container(spec.containers.volumeMounts).

- Sometimes, it is useful to share one volume for multiple uses in a single
  pod. The volumeMounts.subPath property can be used to specify a sub-path inside
  the referenced volume instead of its root.

*1:Similar to how Pods can request specific levels of resources
   (CPU and Memory), Claims can request specific size and access modes
   (e.g., can be mounted once read/write or many times read-only)
☞ BºPV contains max size, PVC contains min sizeº
    wih PV max.size ˃ PVC min.size must be ˂ PV max.size
Networking Model
@[https://kubernetes.io/docs/concepts/cluster-administration/networking/]

Storage
Local Persistent Vol (1.12+) 
REF: @[https://kubernetes.io/blog/2019/04/04/kubernetes-1.14-local-persistent-volumes-ga/]
     Authors: Michelle Au (Google), Matt Schallert (Uber), Celina Ward (Uber)
       
- local persistent volume (k8s GA 1.14+) leverage local disks and it enables to use
  them with persistent volume claims (pvc).
- Local PV provide for consistent high performance guarantees of local directly-attached 
  storage. 
-Bºthis type of storage is suitable for applications which handles the dataº
 Bºreplication themself.  software defined storage or replicated databases º
 Bºlike kafka, Ethereum, "p2p", cassandra, ...)º.
   Apps that do not will better opt for standard (remote) PVs that transparently
   takes care of data replication.

- to use this as a persistent volume, we have some manual steps to do:
  - Pre-partition, format and mount disks to nodes

  - Create Persistent Volumes:
    - Alt 1: Manually
    - Alt 2: Let a DaemonSet handle the creation.

  - Create Storage Class
    (can be skipeed in newer k8s releases)
 
NOTE: 
Q: k8s "hostPath" already allows to use local disk as a storage for Pods.
   why SHOULD we use Local Persistent Volume instead? 
A: With Local PV, the Scheduler is aware of the Local PV, so on Pod
   re-start, execution will be assigned to the same worker node.
   With hostPath, k8s can re-schedule in a different node, loosing all
   previously stored data.

Note: Most other k8s  block and file storage plugins provide for remote storage
      where data  is persisted  independently of the node excuting the Pod.

- raw block device support is also provided.

- K8s is also able to format the block device on demand, avoiding manual formating.


- dynamic volume provisioning RºNOTº supported.
  (@[https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner]
   can be used to help manage the Local PV lifecycle - create,clean up,reuse -
   for individual disks),
   
BºUssage Steps:º

Bº└RE-SETUP Plannification:º
 - how many local disks would each node cluster have?
 - How would they be partitioned?
 (The local static provisioner provides guidance to help answer these questions).
 Hint: It’s best to be able to dedicate a full disk to each local volume (for IO isolation)
        and a full partition per-volume (for capacity isolation).
 
Bº└1.- Create StorageClass:º

      Qº kind: StorageClass                       º
      Qº apiVersion: storage.k8s.io/v1            º
      Qº metadata:                                º
      Qº   name: local-storage                    º
      Qº provisioner: kubernetes.io/no-provisionerº
      Qº volumeBindingMode: WaitForFirstConsumer  º  ← *1: enable Bºvolume topology-aware schedulingº
                            └────── *1 ────────┘           Consumer == "Pod requesting the volume"

Bº└2.-ºthe external static provisioner can be configured and run to  (TODO)
       create PVs for all the local disks on your nodes.
    $º$ kubectl get pv º
      NAME              CAPA  ACC. RECLAIM  STATUS    CLAIM STORAGECLASS  REASON AGE
                              MODE POLICY   
      local-pv-27c0f084 368Gi RWO  Delete   Available       local-storage         8s
      local-pv-3796b049 368Gi RWO  Delete   Available       local-storage         7s
      local-pv-3ddecaea 368Gi RWO  Delete   Available       local-storage         7s

Bº└3.- Start using PVs in workloads by:º
      - Alt 1: creating a PVC and Pod
      - Alt 2: creating a StatefulSet with volumeClaimTemplates
           Ex: 
    QºapiVersion: apps/v1                    º
    Qºkind: StatefulSet                      º
    Qºmetadata:                              º
    Qº  name: local-test                     º
    Qºspec:                                  º
    Qº  serviceName: "local-service"         º
    Qº  replicas: 3                          º
    Qº  selector:                            º
    Qº    matchLabels:                       º
    Qº      app: local-test                  º
    Qº  template:                            º
    Qº    metadata:                          º
    Qº      labels:                          º
    Qº        app: local-test                º
    Qº    spec:                              º
    Qº      containers:                      º
    Qº      - name: test-container           º
    Qº        image: k8s.gcr.io/busybox      º
    Qº        command:                       º
    Qº        - "/bin/sh"                    º
    Qº        args:                          º
    Qº        - "-c"                         º
    Qº        - "sleep 100000"               º
    Qº        volumeMounts:                  º
    Qº        - name: local-vol              º
    Qº          mountPath: /usr/test-pod     º
    Qº  volumeClaimTemplates:                º
    Qº  - metadata:                          º
    Qº      name: local-vol                  º
    Qº    spec:                              º
    Qº      accessModes: [ "ReadWriteOnce" ] º
    Qº      storageClassName: "local-storage"º
    Qº      resources:                       º
    Qº        requests:                      º
    Qº          storage: 368Gi               º

      Once the StatefulSet is up and running,
      the PVCs will be bound:
      
      $º$ kubectl get pvc º
        NAME                   STATUS VOLUME              CAPACITY ACC.. STORAGECLASS   AGE
        local-vol-local-test-0 Bound  local-pv-27c0f084   368Gi    RWO   local-storage  3m45s
        local-vol-local-test-1 Bound  local-pv-3ddecaea   368Gi    RWO   local-storage  3m40s
        local-vol-local-test-2 Bound  local-pv-3796b049   368Gi    RWO   local-storage  3m36s

Bº└4.- Automatic Clean Up Ex:º
    $º$ kubectl patch sts local-test \   º
    $º  -p '{"spec":{"replicas":2}}'     º
                      └────────────┘
                      Reduce Pod replicates 3→2 
                      Associated local-pv-... is not needed anymore.
                      The external static provisioner will clean up 
                      the disk and make the PV available for use again.

    $ºstatefulset.apps/local-test patchedº
      
    $º$ kubectl delete pvc local-vol-local-test-2º
      persistentvolumeclaim "local-vol-local-test-2" deleted

    $ kubectl get pv
    $º$ kubectl get pv º
      NAME              CAPA  ACC. RECLAIM  STATUS    CLAIM STORAGECLASS  REASON AGE
                              MODE POLICY   
      local-pv-27c0f084 368Gi RWO  Delete   Bound      ...-0 local-storage        11m
      local-pv-3796b049 368Gi RWO  Delete   Available        local-storage         7s
      local-pv-3ddecaea 368Gi RWO  Delete   Bound      ...-1 local-storage        19m
                                                       └─┬─┘
                                                       default/local-vol-local-test-0

                                                       default/local-vol-local-test-1

BºLIMITATIONS AND CAVEATSº:
  - It ties apps to a specific node, making it harder to schedule.
    Those apps Bºshould specify a high priorityº so that lower priority pods,
    can be preempted if necessary.
    Also if the tied-to node|local volume become inaccessible, then the pod
    also becomes inaccessible requiring manual intervention, external controllers
    or operators.
    If a node becomes unavailable (removed from the cluster or drained), pods using
    local volumes on that node are stuck in "Unknown" or "Pending" state depending
    on whether or not the node was removed gracefully.

    Recovering pods from these interim states means having to delete the PVC binding the pod 
    to its local volume and then delete the pod in order for it to be rescheduled
    (or wait until the node and disk are available again).
    "... We took this into account when building our operator for M3DB, which makes changes
      to the cluster topology when a pod is rescheduled such that the new one gracefully
      streams data from the remaining two peers..."

    Because of these constraints, Rºit’s best to exclude nodes with º
  Rºlocal volumes from automatic upgrades or repairsº, and in fact some 
    cloud providers explicitly mention this as a best practice.
    (Basically most of the benefits of k8s are lost for apps managing
     storage at App level. This is the case with most DDBBs and stream
     architectures).
Running storage services(GlusterFS,iSCSI,...) 
@[https://opensource.com/article/17/12/storage-services-kubernetes]
Rook.io
@[https://rook.io/]
Rook turns distributed storage systems into self-managing, 
self-scaling, self-healing storage services. It automates the tasks 
of a storage administrator: deployment, bootstrapping, configuration, 
provisioning, scaling, upgrading, migration, disaster recovery, 
monitoring, and resource management.

Rook uses the power of the Kubernetes platform to deliver its 
services via a Kubernetes Operator for each storage provider.


https://www.infoq.com/news/2019/08/rook-v1-release/

Rook, a storage orchestrator for Kubernetes, has released version 1.0 
for production-ready workloads that use file, block, and object 
storage in containers. Highlights of Rook 1.0 include support for 
storage providers through operators like Ceph Nautilus, EdgeFS, and 
NFS. For instance, when a pod requests an NFS file system, Rook can 
provision it without any manual intervention.

Rook was the first storage project accepted into the Cloud Native 
Computing Foundation (CNCF), and it helps storage administrators to 
automate everyday tasks like provisioning, configuration, disaster 
recovery, deployment, and upgrading storage providers. Rook turns a 
distributed file system into storage services that scale and heal 
automatically by leveraging the Kubernetes features with the operator 
pattern. When administrators use Rook with a storage provider like 
Ceph, they only have to worry about declaring the desired state of 
the cluster and the operator will be responsible for setting up and 
configuring the storage layer in the cluster.
Ceph
@[https://ceph.io/]
Noobaa
https://www.noobaa.io/try

NooBaa can collapse multiple storage silos into a single, scalable 
storage fabric, by its ability to virtualize any local storage, 
whether shared or dedicated, physical or virtual and include both 
private and public cloud storage, using the same S3 API and 
management tools. NooBaa also gives you full control over data 
placement, letting you place data based on security, strategy and 
cost considerations, in the granularity of an application.
 

- Easily scales locally on top of PVs or Ceph external clusters

- Workload Portability
  Easily mirror data to other cluster or native cloud storage

Controllers
ReplicaSet
@[https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/]
- Target: ensure "N" pod replicas are running simultaneously.
- Most of the times used indirectly by "Deployments" to orchestrate pod creation/deletion/updates.
 BºNOTE:º Job       controller prefered for pods that terminate on their own.
 BºNOTE:º DaemonSet controller prefered for pods providing a machine-level function.
                    (monitoring,logging, pods that need to be running before others pods starts).
                  OºDaemonSet pods  lifetime == machine lifetimeº
  |controllers/frontend.yaml
  |
  |apiVersion: apps/v1
  |kind:ºReplicaSetº
  |metadata:
  |  name: frontend
  |  labels:
  |    app: guestbook
  |    tier: frontend
  |spec:
  |  # modify replicas according to your case
  | ºreplicas: 3º  ← Default to 1
  |Oºselector:º
  |Oº  matchLabels:º
  |Oº    tier: frontendº
  |Oº  matchExpressions:º
  |Oº    - {key: tier, operator: In, values: [frontend]}º
  |  template:  ← ················· Pod template (nested pod schema, removing
  |    metadata:                                 apiVersion/kind properties -)
  |      labels:             ←····· Needed in pod-template (vs isolated pod)
  |        app: guestbook           .spec.template.metadata.labels must match
  |      Oºtier: frontendº          .spec.selector
  |    spec:
  |     ºrestartPolicy: Alwaysº←··· (default/only allowed value)
  |    Qºcontainers:º
  |      - name: php-redis
  |        image: gcr.io/google_samples/gb-frontend:v3
  |        resources: ←············ "Best Pattern". Indicate resources.
  |          requests:
  |            cpu: 100m
  |            memory: 100Mi
  |        env:
  |        - name: GET_HOSTS_FROM
  |          value: dns ←·········· replace 'dns' by 'env' if DNS is not configured
  |        ports:
  |        - containerPort: 80

$º$ kubectl create -f http://.../frontend.yaml º
  → replicaset.apps/frontend created
  
$º$ kubectl describe rs/frontend               º
  → Name:       frontend
  · Namespace:  default
  · Selector:   tier=frontend,tier in (frontend)
  · Labels:     app=guestbook
  ·         tier=frontend
  · Annotations:    ˂none˃
  · Replicas:  Bº3 current / 3 desiredº
  · Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
  · Pod Template:
  · OºLabels:     app=guestbookº
  · Oº            tier=frontendº
  ·   Containers:
  ·  Qºphp-redis:º
  ·     Image:      gcr.io/google_samples/gb-frontend:v3
  ·     Port:       80/TCP
  ·     Requests:
  ·       cpu:      100m
  ·       memory:   100Mi
  ·     Environment:
  ·       GET_HOSTS_FROM:   dns
  ·     Mounts:             ˂none˃
  ·   Volumes:              ˂none˃
  · Events:
  ·  FirstSeen  LastSeen Count  From       ···     Type     Reason            Message
  ·  ---------  -------- -----  ----               -------- ------            -------
  ·  1m         1m       1      {replicaset-cont } Normal   SuccessfulCreate  Created pod: frontend-qhloh
  ·  1m         1m       1      {replicaset-cont } Normal   SuccessfulCreate  Created pod: frontend-dnjpy
  ·  1m         1m       1      {replicaset-cont } Normal   SuccessfulCreate  Created pod: frontend-9si5l
  
  
$º$ kubectl get pods                       º
  → NAME             READY     STATUS    RESTARTS   AGE
  · frontend-9si5l   1/1       Running   0          1m
  · frontend-dnjpy   1/1       Running   0          1m
  · frontend-qhloh   1/1       Running   0          1m


Deployment(=="aplication") @[https://kubernetes.io/docs/concepts/workloads/controllers/deployment/] - Built "on top" of ReplicaSets adding lifecycle management (creation, updates,...). For example, if a Pod definition is changed, Deployments takes care of gradually moving from a running (old) ReplicaSet to a new (automatically created) ReplicaSet. Deployments also rollback to (old) ReplicaSet if new one is not stable. Old ReplicaSets are automatically removed once the updated one is detected to be stable. - Ussually a running applications maps to a Deployment (plus some network ingress rules, to make pod exposed services visibles "outside" k8s) - Ex. Deployment: | # for versions before 1.7.0 use apps/v1beta1 | apiVersion: apps/v1beta2 | kind: Deployment | metadata: | name: nginx-deployment | labels: | app: nginx | # namespace: production | spec: | replicas: 3 ← 3 replicated Pods | strategy: | - type : Recreate ← Recreate | RollingUpdate* | # Alt. strategy example | # strategy: | # rollingUpdate: | # maxSurge: 2 | # maxUnavailable: 0 | # type: RollingUpdate | selector: | matchLabels: | app: nginx | template: ← pod template | metadata: | labels: | app: nginx | spec: ← template pod spec | containers: change triggers new rollout | - name: nginx | image: nginx:1.7.9 | ports: | - containerPort: 80 | livenessProbe: | httpGet: | path: /heartbeat | port: 80 | scheme: HTTP $º$ kubectl create -f nginx-deployment.yaml º $º$ kubectl get deployments º → NAME DESIRED CURRENT ... · nginx-deployment 3 0 $º$ kubectl rollout status deployment/nginx-deployment º → Waiting for rollout to finish: 2 out of 3 new replicas · have been updated... · deployment "nginx-deployment" successfully rolled out $º$ kubectl get deployments º → NAME DESIRED CURRENT ... · nginx-deployment 3 3 ºTo see the ReplicaSet (rs) created by the deployment:º $ kubectl get rs NAME DESIRED ... nginx-deployment-...4211 3 └─────────┬────────────┘ Format: [deployment-name]-[pod-template-hash-value] $º$ kubectl get pods --show-labels º ← Display ALL labels automatically → NAME ... LABELS generated for ALL pods · nginx-..7ci7o ... app=nginx,..., · nginx-..kzszj ... app=nginx,..., · nginx-..qqcnn ... app=nginx,..., - Ex: Update nginx Pods from nginx:1.7.9 to nginx:1.9.1: $º$ kubectl set image deployment/nginx-deployment \ º $º nginx=nginx:1.9.1 º ºCheck the revisions of deployment:º $ kubectl rollout history deployment/nginx-deployment deployments "nginx-deployment" R CHANGE-CAUSE 1 kubectl create -f nginx-deployment.yaml ---record 2 kubectl set image deployment/nginx-deployment \ nginx=nginx:1.9.1 3 kubectl set image deployment/nginx-deployment \ nginx=nginx:1.91 $ kubectl rollout undo deployment/nginx-deployment \ --to-revision=2 ºScale Deployment:º $ kubectl scale deployment \ nginx-deployment --replicas=10 $ kubectl autoscale deployment nginx-deployment \ --min=10 --max=15 --cpu-percent=80
StatefulSet (v:1.9+)
@[https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/]
- naming convention, network names, and storage persist as replicas are
  rescheduled.
- underlying persistent storage remains even when the StatefulSet is deleted.
- Pods in StatefulSet are scheduled and run across any available node in an
  AKS cluster (vs DaemonSet pods, attached to a given node).

- Manages stateful apps:
  - Useful for apps requiring one+ of:
    {
    - Stable, unique network identifiers.
    - persistent storage across Pod (re)scheduling
    - Ordered, graceful deployment and scaling.
    - Ordered, graceful deletion and termination.
    - Ordered, automated rolling updates.
    }

  - Manages the deploy+scaling of Pods providing
      guarantees about ordering and uniqueness
  - Unlike Deployments, a StatefulSet maintains a sticky identity for each
    of their Pods. These pods are created from the same spec, but are not
    interchangeable: each has a persistent identifier that it maintains
    across any rescheduling
  - Pod Identity: StatefulSet Pods have a unique identity that is comprised
    of [ordinal, stable network identity, stable storage] that sticks even
    if Pods is rescheduled on another node.
    
    - Ordinal:Each Pod will be assigned an unique integer ordinal, from 0 up through N-1, where N = number of replicas - Stable Network Pod host-name = $(statefulset name)-$(ordinal) Ex. full DNS using Stateless service: Pod full DNS (web == StatefullSet.name) Oº← pod-host →º Bº← service ns →º Qº←clusterDoma→º Oºweb-{0..N-1}º.Bºnginx.default.svcº.Qºcluster.localº Oºweb-{0..N-1}º.Bºnginx.foo .svcº.Qºcluster.localº Oºweb-{0..N-1}º.Bºnginx.foo .svcº.Qºkube.local º *1: Cluster Domain defaults to cluster.local - Pod Name Label: When the controller creates a Pod, it adds a label statefulset.kubernetes.io/"pod-name" set to the name of the pod, allowing to attach a Service to an unique Pod ºLimitationsº - The storage for a given Pod must either be provisioned by a PersistentVolume Provisioner based on the requested storage class, or pre-provisioned by an admin. - Deleting and/or scaling a StatefulSet down will not delete the volumes associated with the StatefulSet in order to ensure data safety, which is generally more valuable than an automatic purge of all related StatefulSet resources. - StatefulSets currently require a Headless Service to be responsible for the network identity of the Pods. You are responsible for creating this Service. ºExample StatefulSetº The Bºheadless Service (named nginx)º, is used to control the network domain The OºStatefulSet(named web)º, has a Spec that indicates that 3 replicas of the nginx container will be launched in unique Pods. The GºvolumeClaimTemplatesº will provide stable storage using PersistentVolumes provisioned by a PersistentVolume Provisioner. apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: replicas: 3 # by default is 1 selector: matchLabels: Qºapp: nginx # has to match .spec.template.metadata.labelsº serviceName: "nginx" template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html ºvolumeClaimTemplatesº: # Kubernetes creates one PersistentVolume for each VolumeClaimTemplate - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] # each Pod will receive a single PersistentVolume # When a Pod is (re)scheduled onto a node, its volumeMounts mount # the PersistentVolumes associated with its PersistentVolume Claims. storageClassName: "my-storage-class" resources: requests: storage: 1Gi
    DONT'S - The StatefulSet should NOT specify a pod.Spec.TerminationGracePeriodSeconds of 0. Unsafe and ºstrongly discouragedº
    Deployment and Scaling Guarantees - Pods are deployed sequentially in order from {0..N-1}. - When Pods are deleted they are terminated in reverse order, from {N-1..0} - Before a scaling operation is applied to a Pod, all of its predecessors must be Running and Ready - Before a Pod is terminated, all of its successors must be completely shutdown -ºOrdering Policies guarantees can be relaxed via .spec.podManagementPolicy(K8s 1.7+)º
      - OrderedReady: Defaults, implements the behavior described above - Parallel Pod Management: launch/terminate all Pods in parallel, not waiting for Pods to become Running and Ready or completely terminated -
    -º.spec.updateStrategyº allows to configure and disable automated rolling updates for containers, labels, resource request/limits, and annotations for the Pods in a StatefulSet.
      - "OnDelete" implements the legacy (1.6 and prior) behavior. StatefulSet controller will not automatically update the Pods in a StatefulSet. Users must manually delete Pods to cause the controller to create new Pods that reflect modifications made to a StatefulSet’s .spec.template. - "RollingUpdate" (default 1.7+) implements automated, rolling update for Pods. The StatefulSet controller will delete and recreate each Pod proceeding in the same order as Pod termination (largest to smallest ordinal), updating each Pod one at a time waiting until an updated Pod is Running and Ready prior to updating its predecessor. Partitions { - RollingUpdate strategy can be partitioned, by specifying a .spec.updateStrategy.rollingUpdate.partition - If specified all Pods with an ordinal greater than or equal to the partition will be updated when the StatefulSet’s .spec.template is updated. All Pods with an ordinal that is less than the partition will not be updated, and, even if they are deleted, they will be recreated at the previous version. - If it is greater than its .spec.replicas, updates to its .spec.template will not be propagated to its Pods. - In most cases you will not need to use a partition, but they are useful if you want to stage an update, roll out a canary, or perform a phased roll out. }
    }
    Debug @[https://kubernetes.io/docs/tasks/debug-application-cluster/debug-stateful-set/]
DaemonSet
- ensures "N" Nodes run a Pod instance
- typical uses: cluster storage, log collection or monitoring
  - As nodes are added to the cluster, Pods are added to them. As nodes are
    removed from the cluster, those Pods are garbage collected. Deleting a
    DaemonSet will clean up the Pods it created.
  - Ex (simple case): one DaemonSet, covering all nodes, would be used
    for each type of daemon. A more complex setup might use multiple DaemonSets
    for a single type of daemon, but with different flags and/or different memory
    and cpu requests for different hardware types.

Ex.  DaemonSet for Bºfluentd-elasticsearchº:
$ cat daemonset.yaml
apiVersion: apps/v1
kind: ºDaemonSetº
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template: # Pod template
    # Pod Template must have RestartPolicy equal to Always (default if un-specified)
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: Bºk8s.gcr.io/fluentd-elasticsearch:1.20º
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

Garbage Collection 
@[https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/]
Jobs
@[https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/]

Running Automated Tasks with a CronJob
Parallel Processing using Expansions
Coarse Parallel Processing Using a Work Queue
Fine Parallel Processing Using a Work Queue

- One example of Job pattern would be a Job which starts a Pod which 
  runs a script that in turn starts a Spark master controller (see 
  spark example), runs a spark driver, and then cleans up.

- reliably run 1+ Pod/s to "N" completions
  - creates one+ pods and ensures that a specified number of them successfully terminate
  - Jobs are complementary to Deployment Controllers. A Deployment Controller
    manages pods which are not expected to terminate (e.g. web servers), and
    a Job manages pods that are expected to terminate (e.g. batch jobs).
  - As pods successfully complete, the job tracks the successful completions. When a specified number of successful completions is reached, the job itself is complete. Deleting a Job will cleanup the pods it created.
  - Pod Backoff failure policy: ifyou want to fail a Job after N retries set
      .spec.backoffLimit (defaults to 6).
  - Pods are not deleted on completion in order to allow view logs/output/errors for completed pods. They will show up with kubectl get pods º-aº.
    Neither the job object in order to allow viewing its status.
  -  Another way to terminate a Job is by setting an active deadline
    in .spec.activeDeadlineSeconds or .specs.template.specs.activeDeadlineSeconds

  }
  example. Compute  2000 digits of "pi"
$ cat job.yaml

apiVersion: batch/v1
kind: ºJobº
metadata:
  name: pi
spec:
  template: # Required (== Pod template - apiVersion - kind)
    spec:
      containers:
      - name: pi
        ºimage: perlº
        ºcommand: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]º
      OºrestartPolicy: Neverº # Only Never/OnFailure allowed
  backoffLimit: 4

# ºRun job using:º
# $ kubectl create -f ./job.yaml

# ºCheck job current status like:º
# $ kubectl describe jobs/pi
# output will be similar to:
# Name:             pi
# Namespace:        default
# Selector:         controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
# Labels:           controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
#                   job-name=pi
# Annotations:      ˂none˃
# Parallelism:      1
# Completions:      1
# Start Time:       Tue, 07 Jun 2016 10:56:16 +0200
# Pods Statuses:    0 Running / 1 Succeeded / 0 Failed
# Pod Template:
#   Labels:       controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495
#                 job-name=pi
#   Containers:
#    pi:
#     Image:      perl
#     Port:
#     Command:
#       perl
#       -Mbignum=bpi
#       -wle
#       print bpi(2000)
#     Environment:        ˂none˃
#     Mounts:             ˂none˃
#   Volumes:              ˂none˃
# Events:
#   FirstSeen LastSeen  Count From            SubobjectPath  Type    Reason            Message
#   --------- --------  ----- ----            -------------  ------- ------            -------
#   1m        1m        1     {job-controller}               Normal  SuccessfulCreate  Created pod: pi-dtn4q
#
# ºTo view completed pods of a job, use º
# $ kubectl get pods

# ºTo list all pods belonging to job in machine-readable-formº:
#
# $ pods=$(kubectl get pods --selector=ºjob-name=piº --output=ºjsonpath={.items..metadata.name}º)
# $ echo $pods
pi-aiw0a


# ºView the standard output of one of the pods:º
# $ kubectl logs $pods
# 3.1415926535897a....9

Parallel Jobs - Parallel Jobs with a fixed completion count (.spec.completions greater than zero). the job is complete when there is one successful pod for each value in the range 1 to .spec.completions. - Parallel Jobs with a work queue: do not specify .spec.completions: pods must coordinate with themselves or external service to determine what each should work on. each pod is independently capable of determining whether or not all its peers are done, thus the entire Job is done. - For Non-parallel job, leave both .spec.completions and .spec.parallelism unset. - Actual parallelism (number of pods running at any instant) may be more or less than requested parallelism, for a variety of reasons - (read official K8s docs for Job Patterns ussages) } Cron Jobs (1.8+) - written in Cron format (question mark (?) has the same meaning as an asterisk *) - Concurrency Policy - Allow (default): allows concurrently running jobs - Forbid: forbids concurrent runs, skipping next if previous still running - Replace: cancels currently running job and replaces with new one
CronJob - @[https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/] - Ex. cronjob: $ cat cronjob.yaml apiVersion: batch/v1beta1 kind: CronJob metadata: name: hello spec: schedule: Oº"*/1 º º º º"º jobTemplate: spec: template: spec: containers: Oº- name: hello º Oº image: busybox º Oº args: º Oº - /bin/sh º Oº - -c º Oº - date; echo 'Hi from K8s'º restartPolicy: OnFailure # Alternatively: $ kubectl run hello \ --schedule="*/1 º º º º" \ --restart=OnFailure \ --image=busybox \ -- /bin/sh -c "date; echo Hello from the Kubernetes cluster" # get status: $ kubectl get cronjob hello NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE hello */1 º º º º False 0 # Watch for the job to be created: $ kubectl get jobs --watch NAME DESIRED SUCCESSFUL AGE hello-4111706356 1 1 2s
Node Monitoring
Node Health
@[https://kubernetes.io/docs/tasks/debug-application-cluster/monitor-node-health/]

crictl: Debug node @[https://kubernetes.io/docs/tasks/debug-application-cluster/crictl/]
Monitoring the cluster
Auditing
@[https://kubernetes.io/docs/tasks/debug-application-cluster/audit/]
Events in Stackdriver
@[href=https://kubernetes.io/docs/tasks/debug-application-cluster/events-stackdriver/]
- Kubernetes events are objects that provide insight into what is 
  happening inside a cluster, such as what decisions were made by 
  scheduler or why some pods were evicted from the node.

- Since events are API objects, they are stored in the apiserver on 
  master. To avoid filling up master's disk, a retention policy is 
  enforced: events are removed one hour after the last occurrence. To 
  provide longer history and aggregation capabilities, a third party 
  solution should be installed to capture events.
  
- This article describes a solution that exports Kubernetes events to 
  Stackdriver Logging, where they can be processed and analyzed.
Metrics API+Pipeline
- Resource usage metrics, such as container CPU and memory usage, are 
  available in Kubernetes through the Metrics API. These metrics can be 
  either accessed directly by user, for example by using kubectl top 
  command, or used by a controller in the cluster, e.g. Horizontal Pod 
  Autoscaler, to make decisions.

@[https://kubernetes.io/docs/tasks/debug-application-cluster/resource-metrics-pipeline/]
@[https://github.com/kubernetes-incubator/metrics-server]

  Extracted from @[https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/]
  """...If running on Minikube, run the following command to enable the metrics-server:
  $º$ minikube addons enable metrics-server º
  
  ... to see whether the metrics-server is running, or another provider of the resource metrics
  API (metrics.k8s.io), run the following command:
  
  $º$ kubectl get apiservices               º
     output must include a reference to metrics.k8s.io.
     → ...
     → v1beta1.metrics.k8s.io
  """
Node Auditing
Auditing
@[https://kubernetes.io/docs/tasks/debug-application-cluster/audit/] 
- Kubernetes auditing provides a security-relevant chronological set of 
  records documenting the sequence of activities that have affected 
  system by individual users, administrators or other components of the 
  system. It allows cluster administrator to answer the following 
  questions:
  - what happened?
  - when did it happen?
  - who initiated it?
  - on what did it happen?
  - where was it observed?
  - from where was it initiated?
  - to where was it going?
K8s Extension Tools
HELM Charts
@[https://helm.sh/docs/intro/quickstart/]

ºPRE-SETUPº
 └ "kubectl" installed locally.

ºINITIAL-SETUPº
 └ Download from @[https://github.com/helm/helm/releases], use homebrew (MacOSX),...
   and add "helm" command to path.
 
 └ Initialize aºHelm Chart Repositoryº
 $º$ helm repo add stable \                           º
 $º  https://kubernetes-charts.storage.googleapis.com/º ← Official repo.

ºDAILY USEº

  $º$ helm get -h                              º
  $º$ helm search repo stable                  º ← list charts available for installation.
  $ºNAME                          CHART VERSION   APP VERSION DESCRIPTION                                       º
  $ºstable/acs-engine-autoscaler  2.2.2           2.1.1       DEPRECATED Scales worker nodes within agent pools º
  $ºstable/aerospike              0.2.8           v4.5.0.5    A Helm chart for Aerospike in Kubernetes          º
  $ºstable/airflow                4.1.0           1.10.4      Airflow is a platform to programmatically autho...º
  $º...                                                                                                         º
  
  $º$ helm repo update                         º  ← Make sure we get the latest list of charts
┌→$º$ helm install stable/mysql --generate-nameº  ← Install MySQL
│                  ^^^^^^
│                  Helm has several ways to find and install a chart,
│                  official stable charts is the easiests. 
│ $º$ helm show chart stable/mysql            º ← get an idea of the chart features
│ $º$ helm show all   stable/mysql            º ← get all information about chart
│
└ Whenever an install is done, a new local release is created
  cluster, allowing to install multiple times into the same cluster.
  Each local release can be independently managed and upgraded.
  To list local released:
  $º$ helm ls                                 º
  $ºNAME             VERSION   UPDATED                   STATUS    CHART       º
  $ºsmiling-penguin  1         Wed Sep 28 12:59:46 2016  DEPLOYED  mysql-0.1.0 º

  To uninstall a release:
  $º$ helm uninstall \                        º 
  $º$      smiling-penguin   --keep-history   º ←·························┐
  $ºRemoved smiling-penguin                   º                           |
  $º$ helm status smiling-penguin             º ← works only in using the --keep-history 
  $ºStatus: UNINSTALLED                       º   flag during uninstall.
  $...                                        º   It also allows to roolback a deleted 
                                                release using $º$ helm rollback ...º

TODO: @[https://helm.sh/docs/intro/using_helm/]


NOTE:@[https://www.infoworld.com/article/3541608/kubernetes-helm-gets-full-cncf-approval.html]

Kubeapps
- Application Dashboard for Kubernetes
@[https://kubeapps.com/]
  - Deploy Apps Internally:
    Browse Helm charts from public or your own private chart repositories
    and deploy them into your cluster.
  - Manage Apps:
    Upgrade, manage and delete the applications that are deployed in your 
    Kubernetes cluster.
  - Service Catalog:
    Browse and provision external services from the Service Catalog and 
    available Service Brokers.
Teresa
@[https://github.com/luizalabs/teresa]
- extremely simple platform as a service that runs on top 
  of Kubernetes. It uses a client-server model: the client sends high 
  level commands (create application, deploy, etc.) to the server, 
  which translates them to the Kubernetes API.
Gatekeeper policy controls
The Open Policy Agent project (OPA) provides a way to create policies 
across cloud-native application stacks, from ingress to service-mesh 
components to Kubernetes. Gatekeeper provides a Kubernetes-native way 
to enforce OPA policies on a cluster automatically, and to audit for 
any events or resources violating policy. All this is handled by a 
relatively new mechanism in Kubernetes, admission controller 
Webhooks, that fire on changes to resources. With Gatekeeper, OPA 
policies can be maintained as just another part of your Kubernetes 
cluster’s defined state, without needing constant babysitting. 
Gravity Portable clusters
"take a cluster as is and deploy it somewhere else"

- Gravity takes snapshots of Kubernetes clusters, their container 
  registries, and their running applications, called "application 
  bundles." The bundle, which is just a .tar file, can replicate the 
  cluster anywhere Kubernetes runs.

- Gravity also ensures that the target infrastructure can support the 
  same behavioral requirements as the source, and that the Kubernetes 
  runtime on the target is up to snuff. The enterprise version of 
  Gravity adds security features including role-based access controls 
  and the ability to synchronize security configurations across 
  multiple cluster deployments.

- latest major version, Gravity 7, can deploy a Gravity image into 
  an existing Kubernetes cluster, versus spinning up an all-new cluster 
  using the image. Gravity 7 can also deploy into clusters that 
  aren’t already running a Gravity-defined image. Plus, Gravity now 
  supports SELinux and integrates natively with the Teleport SSH 
  gateway.
Kaniko, Container Build
- Kaniko performs container builds inside a container environment,
Bºwithout relying on a container daemon (Docker Daemon)º.
- Kaniko extracts the file system from the base image, 
  executes the build commands in user space atop the extracted
  file system, taking a snapshot of the file system after each command.
-
Kubecost: Cost metrics running k8s

- monitor "the dollars" cost of running Kubernetes?

- Kubecost uses real-time Kubernetes metrics, and real-world cost 
  information derived from running clusters on the major cloud 
  providers, to provide a dashboard view of the monthly cost of each 
  cluster deployment. Costs for memory, CPU, GPU, and storage are all 
  broken out by Kubernetes component (container, pod, service, 
  deployment, etc.).

- Kubecost can also track the costs of “out of cluster” resources, 
  such as Amazon S3 buckets, although this is currently limited to AWS. 

- Kubecost is free to use if you only need to keep 15 days of logs. For 
  more advanced features, pricing starts at $199 per month for 
  monitoring 50 nodes.
KubeDB: Run production DBs
- operators exists for MySQL/PostgreSQL/Redis/... Rºbut there are plenty of gapsº.

BºKubeDB allows to create custom Kubernetes operators for managing databasesº
  - Running backups, cloning, monitoring, snapshotting, and declaratively
    creating databases are all part of the mix.
  Rºsupported features vary among databasesº. Ex:
    clustering is available for PostgreSQL but not MySQL.
Kube-monkey: Chaos testing
- stress test, breaking stuff at random. 
- It works by randomly killing pods in a cluster 
  that you specifically designate, and can be fine-tuned
  to operate within specific time windows.
Ingress Controller for AWS
- Allows to reuse AWS load balancing functionality.
- It uses AWS CloudFormation to ensure that cluster state 
  remains consistent.
Unordered notes
GPU and Kubernetes
@[https://www.infoq.com/news/2018/01/gpu-workflows-kubernetes]
@[https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/]
Skaffold
@[https://www.infoq.com/news/2018/03/skaffold-kubernetes/]

- Tool to facilitate Continuous Development by allowing Local Kubernetes Development.
  optimized “Source to Kubernetes” - Skaffold detects changes in 
  your source code and handles the pipeline to build, push, and deploy 
  your application automatically with policy-based image tagging and 
  highly optimized, fast local workflows.

- Skaffold handles the workflow for building, pushing and deploying the application,
   allowing to focus on what matters most: writing code. 

- Lightweight: client-side only.
- Works Everywhere: share your project with 'git clone' → 'skaffold run'.
- Support for profiles, local user config, environment variables, and flags
  to easily incorporate differences across environments.
- Feature Rich:  policy-based image tagging, resource port-forwarding and
  logging, file syncing, and much more.
- Optimized Development: Skaffold's inner loop is tight and highly optimized,
  providing instant feedback while developing.

PodDisruptionBudget
@[https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#how-disruption-budgets-work]
@[https://kubernetes.io/docs/tasks/run-application/configure-pdb/]

A PodDisruptionBudget object (PDB) can be defined for each deployment(application),
limiting the number of pods of a replicated application that
are down simultaneously from ºvoluntaryº disruptions.

Ex: A Deployment has:
  - .spec.replicas: 5  (5 pods desired at any given time)
  - The PDB is defined as:
    apiVersion: policy/v1beta1
    kind: PodDisruptionBudget
    metadata:
      name: zookeeper-pdb
    spec:
      maxUnavailable: 1  ←--   Eviction API will allow voluntary disruption of one,
      selector:                but not two pods, at a time trying to have 4 running
        matchLabels:           at all times
          app: zookeeper

Eviction API compatible tools/commands
like 'kubectl drain' must be used
(vs directly deleting pods/deployments)

cluster Administration
Bootstrap/Manage k8s clusters
Kubespray: Cluster Bootstrap
@[https://github.com/kubernetes-sigs/kubespray/blob/master/docs/comparisons.md]
- Kubespray is formed by a set of Ansible playbooks (optionally Vagrant) allowing 
  to create a new production-ready k8s cluster (mono/multi-master,
  single/distributed etcd, Flannel|Calico|Weave|... network...).
  Extra playbooks allows to add/remove new nodes to a running k8s cluster.
- It targets "mostly" any environment, from bare metal (RedHat, CoreOS, Ubuntu,...)
  to public clouds.
- Compared to "Kops", "Kops" is more tightly integrated and profits better from
  the unique features of the supported clouds (AWS,GCE, ...). "Kops" doesn't
  allow to deploy on standard linux distros running on bare-metal/VMs.
KOPS: Deploy on Cloud
@[https://github.com/kubernetes/kops/blob/master/README.md]
@[https://github.com/kubernetes/kops/blob/master/README.md]
- Kops cli-tool allows the automation of production-grade k8s cluster
  (creation/destruction, upgrade, maintenance).
- AWS is currently officially supported, with GCE in beta support,
  and VMware vSphere in alpha, and other platforms planned.
- It does NOT support standard linux distros on bare-metal/VMs.
  Kubespray is prefered in this case.
Kubeadm
Overview of kubeadm
kubeadm init
kubeadm join
kubeadm upgrade
kubeadm config
kubeadm reset
kubeadm token
kubeadm version
kubeadm alpha
Implementation details

Note: Kubespray offers a "simpler" front-end based on Ansible playbooks to Kubeadm.
Example Tasks:
- Upgrading kubeadm HA clusters from 1.9.x to 1.9.y
@[https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-ha/]
- Upgrading/downgrading kubeadm clusters between v1.8 to v1.9:
@[https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-9/]
- Upgrading kubeadm clusters from 1.7 to 1.8
@[https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-8/]
- Upgrading kubeadm clusters from v1.10 to v1.11:
@[https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-11/]
WKSctl GitOps install
- Tool for Kubernetes Cluster Management Using BºGitOpsº.
  WKSctl is an open-source project to install, bootstrap, and manage Kubernetes
 clusters, including add-ons, through SSH. WKS is a provider of the Cluster API
 (CAPI) using the GitOps approach. Kubernetes cluster configuration is defined
 in YAML, and WKSctl applies the updates after every push in Git, allowing users
 to have repeatable clusters on-demand.
- CAPI (@[https://cluster-api.sigs.k8s.io/]  k8s sub-project is focused on providing
  declarative APIs and tooling to simplify provisioning, upgrading, and operating
  multiple Kubernetes clusters.

Other Admin Tasks
TLS Cert Mng:
- Managing TLS Certs:
@[https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster/]
@[https://kubernetes.io/docs/tasks/tls/certificate-rotation/]
- kubelet TLS setup:
@[https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-authentication-authorization/]
@[https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/]
private registries
- using a private (image) registry:
@[https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry]
- Pull Image from a Private Registry:
@[https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/]
- imagePullSecrets:
@[https://kubernetes.io/docs/concepts/configuration/secret/]
- method to pass a secret that contains a Docker image registry password
  to the Kubelet so it can pull a private image on behalf of your Pod.
Manage Cluster DaemonSets
- Perform a Rollback on a DaemonSet:
@[https://kubernetes.io/docs/tasks/manage-daemon/rollback-daemon-set/]
- Perform a Rolling Update on a DaemonSet:
@[https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/]
Install Service Catalog
- Install Service Catalog using Helm:
@[https://kubernetes.io/docs/tasks/service-catalog/install-service-catalog-using-helm/]
- Install Service Catalog using SC:
@[https://kubernetes.io/docs/tasks/service-catalog/install-service-catalog-using-sc/]
Max Node Lattency
@[https://stackoverflow.com/questions/46891273/kubernetes-what-is-the-maximum-distance-latency-supported-between-kubernetes-no]
   """....There is no latency limitation between nodes in kubernetes cluster. They are configurable parameters. 
   └ For kubelet on worker node:
     --node-status-update-frequency duration Specifies how often kubelet posts node status to master.
                                             Note: be cautious when changing the constant, it must work
                                               with nodeMonitorGracePeriod in nodecontroller. (default 10s)
   └ For controller-manager on master node:
     --node-monitor-grace-period duration    Amount of time which we allow running Node to be unresponsive
                                             before marking it unhealthy. Must be N times more than kubelet's
                                             nodeStatusUpdateFrequency, where N means number of retries allowed
                                             for kubelet to post node status. (default 40s)
     --node-monitor-period duration          The period for syncing NodeStatus in NodeController. (default 5s)
     --node-startup-grace-period duration    Amount of time which we allow starting Node to be unresponsive before
                                             marking it unhealthy. (default 1m0s)
   """
Cluster Admin (Cont)
Admin Tasks
Config Ref()
@[https://kubernetes.io/docs/concepts/cluster-administration/cluster-administration-overview/]
@[https://kubernetes.io/docs/concepts/cluster-administration/certificates/]
@[https://kubernetes.io/docs/concepts/cluster-administration/cloud-providers/]
@[https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/]
@[https://kubernetes.io/docs/concepts/cluster-administration/networking/]
@[https://kubernetes.io/docs/concepts/cluster-administration/logging/]
@[https://kubernetes.io/docs/concepts/cluster-administration/kubelet-garbage-collection/]
@[https://kubernetes.io/docs/concepts/cluster-administration/proxies/]
@[https://kubernetes.io/docs/concepts/cluster-administration/controller-metrics/]
@[https://kubernetes.io/docs/concepts/cluster-administration/addons/]

Config. files (documented in the Reference section of the online documentation, under each binary:) kubelet kube-apiserver kube-controller-manager kube-scheduler.
Compute, Storage, and Networking Extensions
Network Plugins
Device Plugins
Service Catalog
kubecfg
k8s as code
@[https://github.com/ksonnet/kubecfg]
@[https://www.youtube.com/watch?v=zpgp3yCmXok] Writing less yaml

A tool for managing Kubernetes resources as code.

kubecfg allows you to express the patterns across your infrastructure and reuse
these powerful "templates" across many services, and then manage those templates
as files in version control. The more complex your infrastructure is, the more
you will gain from using kubecfg.

The idea is to describe as much as possible about your configuration as files
in version control (eg: git).
Cluster Federation
Cluster Federation
Run an App on 
Multiple Clusters
@[https://kubernetes.io/docs/concepts/cluster-administration/federation/]

ºFederation APIº:
 - @[https://kubernetes.io/docs/reference/federation/extensions/v1beta1/definitions/]
 - @[https://kubernetes.io/docs/reference/federation/extensions/v1beta1/operations/]
 - @[https://kubernetes.io/docs/reference/federation/v1/definitions/]
 - @[https://kubernetes.io/docs/reference/federation/v1/operations/]

ºExternal references:º
- @[https://kubernetes.io/docs/reference/command-line-tools-reference/federation-apiserver/]
- @[https://kubernetes.io/docs/reference/command-line-tools-reference/federation-controller-manager/]
- Cross-cluster Service Discovery using Federated Services
- Set up Cluster Federation with Kubefed
- Set up CoreDNS as DNS provider for Cluster Federation
- Set up placement policies in Federation
- Federated Cluster
- Federated ConfigMap
- Federated DaemonSet
- Federated Deployment
- Federated Events
- Federated Horizontal Pod Autoscalers (HPA)
- Federated Ingress
- Federated Jobs
- Federated Namespaces
- Federated ReplicaSets
- Federated Secrets
- Extend kubectl with plugins
- Manage HugePages

ºSecretsº
- Federated Secrets
kubefed: Controls cluster federation
@[https://kubernetes.io/docs/reference/setup-tools/kubefed/kubefed/]
@[https://kubernetes.io/docs/reference/setup-tools/kubefed/kubefed-options/]
@[https://kubernetes.io/docs/reference/setup-tools/kubefed/kubefed-init/]
@[https://kubernetes.io/docs/reference/setup-tools/kubefed/kubefed-join/]
@[https://kubernetes.io/docs/reference/setup-tools/kubefed/kubefed-unjoin/]
@[https://kubernetes.io/docs/reference/setup-tools/kubefed/kubefed-version/]
Federated Services
@[https://kubernetes.io/docs/tasks/federation/federation-service-discovery/]
Using the k8s API
Kubernetes API Overview
Accessing the API
Controlling Access to the Kubernetes API
Authenticating
Authenticating with Bootstrap Tokens
Using Admission Controllers
Dynamic Admission Control
Managing Service Accounts
Authorization Overview
Using RBAC Authorization
Using ABAC Authorization
Using Node Authorization
Webhook Mode
Understanding K8S Code
K8s Implementation Summary
- Julia Evans "A few things I've learned about Kubernetes"

- """... you can run the kubelet by itself! And if you have a kubelet, you
can add the API server and just run those two things by themselves! Okay,
awesome, now let’s add the scheduler!"""

- the “kubelet” is in charge of running containers on nodes
- If you tell the API server to run a container on a node, it will tell the kubelet to get it done (indirectly)
- The scheduler translates "run a container" to "run a container on node X"

ºetcd is Kubernetes’ brainº
- Every component in Kubernetes (API server, scheduler, kubelets, controller manager, ...) is stateless.
   All of the state is stored in the (key-value store) etcd database.
- Communication between components (often) happens via etcd.
-Oºbasically everything in Kubernetes works by watching etcd for stuff it has to do,º
 Oºdoing it, and then writing the new state back into etcd º

  Ex 1: Run a container on Machine "X":
   Wrong way: ask kubelet@Machine"X" to run the container.
   Right way: kubectl*1 →(API Server)→ etcd: "This pod should run on Machine X"
              kubelet@Machine"X"     → etcd: check work to do
              kubelet@Machine"X"     ← etcd: "This pod should run on Machine X"
              kubelet@Machine"X"     ← kubelet@Machine"X": Run pod

  Ex 2: Run a container anywhere on the k8s cluster
    kubectl*1 → (API Server) → etcd: "This pod should run somewhere"
    scheduler                → etcd: Something to run?
    scheduler                ← etcd: "This pod should run somewhere"
    scheduler                → kuberlet@Machine"Y":  Run pod

 *1 The kubectl is used from the command line.
    In the sequence diagram it can be replaced for any
    of the existing controllers (ReplicaSet, Deployment, DaemonSet, Job,...)

ºAPI server roles in cluster:º
API Server is responsible for:
1.- putting stuff into etcd

    kubectl    → API Server : put "stuff" in etcd
    API Server → API Server : check "stuff"
    alt 1:
       kubectl ← API Server : error: "stuff" is wrong
    alt 2:
       API Server → etcd    : set/update "stuff"

2.- Managing authentication:
    ("who is allowed to put what stuff into etcd")
    The normal way is through X509 client certs.


ºcontroller manager does a bunch of stuffº
Responsible for:
- Inspect etcd for pending to schedule pods.
- daemon-set-controllers will inspect etcd for
  pending daemonsets and will call the scheduler
  to run them on every machine with the given
  pod configuration.
- The "replica set controller" will inspect etcd for
  pending replicasets and will create 5 pods that
  the scheduler will then schedule.
- "deployment controller" ...

ºTroubleshooting:º
something isn’t working? figure out which controller is
responsible and look at its logs

ºCore K8s components run inside of k8sº
- Only 5 things needs to be running before k8s starts up:
  - the scheduler
  - the API server
  - etcd
  - kubelets on every node (to actually execute containers)
  - the controller manager (because to set up daemonsets you
                            need the controller manager)

  Any other core system (DNS, overlay network,... ) can
  be scheduled by k8s inside k8s
API Conventions
@[https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md]
Source Code Layout
Note: Main k8s are placed in kubernetes/pkg/
      (API, kubectl, kubelet, controller, ...)

- REF: A Tour of the Kubernetes Source Code Part One: From kubectl to API Server

ºExamining kubectl sourceº

Locating the implementation of kubectl commands in the Kubernetes source code

- kubectl entry point for all commands
  - Inside there is a name of a go directory that matches the kubectl command:
    Example:
    kubectl create/create.go

ºK8s loves the Cobra Command Frameworkº
- k8s commands are implemented using the Cobra command framework.
- Cobra provides lot of features for building command line interfaces
  amongst them, Cobra puts the command usage message and command
  descriptions adjacent to the code that runs the command.
  Ex.:
  | // NewCmdCreate returns new initialized instance of create sub command
  | func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
  |     o := NewCreateOptions(ioStreams)
  |
  |     cmd := ⅋cobra.Command{
  |         Use:                   "create -f FILENAME",
  |         DisableFlagsInUseLine: true,
  |         Short:                 i18n.T("Create a resource from a file or from stdin."),
  |         Long:                  createLong,
  |         Example:               createExample,
  |         Run: func(cmd *cobra.Command, args []string) {
  |             if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) {
  |                 defaultRunFunc := cmdutil.DefaultSubCommandRun(ioStreams.ErrOut)
  |                 defaultRunFunc(cmd, args)
  |                 return
  |             }
  |             cmdutil.CheckErr(o.Complete(f, cmd))
  |             cmdutil.CheckErr(o.ValidateArgs(cmd, args))
  |             cmdutil.CheckErr(o.RunCreate(f, cmd))
  |         },
  |     }
  |
  |     // bind flag structs
  |     o.RecordFlags.AddFlags(cmd)
  |
  |     usage := "to use to create the resource"
  |     cmdutil.AddFilenameOptionFlags(cmd, ⅋o.FilenameOptions, usage)
  |     ...
  |     o.PrintFlags.AddFlags(cmd)
  |
  |     // create subcommands
  |     cmd.AddCommand(NewCmdCreateNamespace(f, ioStreams))
  |     ...
  |     return cmd
  | }

ºBuilders and Visitors Abound in Kubernetesº
  Ex. code:
  | r := f.NewBuilder().
  |     Unstructured().
  |     Schema(schema).
  |     ContinueOnError().
  |     NamespaceParam(cmdNamespace).DefaultNamespace().
  |     FilenameParam(enforceNamespace, ⅋o.FilenameOptions).
  |     LabelSelectorParam(o.Selector).
  |     Flatten().
  |     Do()
  The functions Unstructured, Schema, ContinueOnError,...  Flatten
  all take in a pointer to a Builder struct, perform some form of
  modification on the Builder struct, and then return the pointer to
  the Builder struct for the next method in the chain to use when it
  performs its modifications defined at:
  https://github.com/kubernetes/cli-runtime/blob/master/pkg/genericclioptions/resource/builder.go:

  | ...
  | func (b ºBuilder) Schema(schema validation.Schema) ºBuilder {
  |     b.schema = schema
  |     return b
  | }
  | ...
  | func (b ºBuilder) ContinueOnError() ºBuilder {
  |     b.continueOnError = true
  |     return b
  | }

 The Do function finally returns a Result object that will be used to drive
the creation of our resource. It also creates a Visitor object that can be
used to traverse the list of resources that were associated with this
invocation of resource.NewBuilder. The Do function implementation is shown below.


  a new DecoratedVisitor is created and stored as part of the Result object
that is returned by the Builder Do function. The DecoratedVisitor has a Visit
function that will call the Visitor function that is passed into it.
  |// Visit implements Visitor
  |func (v DecoratedVisitor) Visit(fn VisitorFunc) error {
  |    return v.visitor.Visit(func(info *Info, err error) error {
  |        if err != nil {
  |            return err
  |        }
  |        for i := range v.decorators {
  |            if err := v.decorators[i](info, nil); err != nil {
  |                return err
  |            }
  |        }
  |        return fn(info, nil)
  |    })
  |}


  Create eventually will call the anonymous function that contains the
  createAndRefresh function that will lead to the code making a REST call
  to the API server.

  The createAndRefresh function invokes the Resource NewHelper
  function found in ...helper.go returning a new Helper object:
  | func NewHelper(client RESTClient, mapping ºmeta.RESTMapping) ºHelper {
  |     return ⅋Helper{
  |         Resource:        mapping.Resource,
  |         RESTClient:      client,
  |         Versioner:       mapping.MetadataAccessor,
  |         NamespaceScoped: mapping.Scope.Name() == meta.RESTScopeNameNamespace,
  |     }
  | }

  Finally the Create function iwill invoke a createResource function of the
  Helper Create function.
  The Helper createResource function, will performs the actual REST call to
  the API server to create the resource we defined in our YAML file.


ºCompiling and Running Kubernetesº
- we are going to use a special option that informs the Kubernetes build process

$ make WHAT='cmd/kubectl'  # ← compile only kubectl
Test it like:
On terminal 1 boot up local test hack cluster:
$ PATH=$PATH KUBERNETES_PROVIDER=local hack/local-up-cluster.sh
On terminal 2 execute the compiled kubectl:
$ cluster/kubectl.sh create -f nginx_replica_pod.yaml

ºCode Learning Toolsº
Tools and techniques that can really help accelerate your ability to learn the k8s src:
- Chrome Sourcegraph Plugin:
  provides several advanced IDE features that make it dramatically
  easier to understand Kubernetes Go code when browsing GitHub repositories.
  Ussage:
  - start by looking at an absolutely depressing snippet of code,
    with ton of functions.
  - Hover over each code function with Chrome browser + Sourcegraph extension
    installed:
    It will popup a description of the function, what is passed into it
    and what it returns.
  - It also provides advanced view with the ability to peek into the function
    being invoked.
- Properly formatted print statements:
  fmt.Println("\n createAndRefresh Info = %#v", info)
- Use of a go panic to get desperately needed stack traces:
  | func createAndRefresh(info *resource.Info) error {
  |     fmt.Println("\n createAndRefresh Info = %#v", info)
  |     ºpanic("Want Stack Trace")º
  |     obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
  |     if err != nil {
  |         return err
  |     }
  |     info.Refresh(obj, true)
  |     return nil
  | }
- GitHub Blame to travel back in time:
  "What was the person thinking when they committed those lines of code?"
  - GitHub browser interface has a blame option available as a button on the user interface:
      It returns a view of the code that has the commits responsible for each line of code
    in the source file. This allows you to go back in time and look at the commit that added
    a particular line of code and determine what the developer was trying to accomplish when
    that line of code was added.
Extending k8s API

- Custom Resources:
@[https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/]

- Extend API with CustomResourceDefinitions:
@[https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/]

- Versions of CustomResourceDefinitions:
@[https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning/]

- Migrate a ThirdPartyResource to CustomResourceDefinition:
@[https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/migrate-third-party-resource/]
- Aggregation Layer:
@[https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/]
  - Configure the Aggregation Layer:
  @[https://kubernetes.io/docs/tasks/access-kubernetes-api/configure-aggregation-layer/]
- Setup an Extension API Server:
@[https://kubernetes.io/docs/tasks/access-kubernetes-api/setup-extension-api-server/">
- Use HTTP Proxy to Access the k8s API:
@[https://kubernetes.io/docs/tasks/access-kubernetes-api/http-proxy-access-api/]
K8s Networking Explained
@[https://www.slideshare.net/CJCullen/kubernetes-networking-55835829]
Networking
SDNs
SDN intro: 
@[https://www.redhat.com/sysadmin/getting-started-sdn]
- provide sdns: allows admin teams to control network traffic in
      complex networking topologies through a centralized panel,
      rather than handling each network device, such as routers
      and switches, manually ("hierarchical" topology)

ºcontainer network interface (cni):º
- library definition and a set of tools to configure network
  interfaces in linux containers through many supported plugins.
- multiple plugins can run at the same time in a container
  that participates in a network driven by different plugins.
- networks use json configuration files and instantiated as
  new namespaces when the cni plugin is invoked.

- common cni plugins include:
  -ºcalicoº:
    - high scalability.
    @[https://docs.projectcalico.org/v3.7/getting-started/kubernetes/]
    @[https://kubernetes.io/docs/tasks/administer-cluster/network-policy-provider/calico-network-policy/]
  -ºciliumº:
    - provides network connectivity and load balancing
      between application workloads, such as application
      containers and processes, and ensures transparent security.
  -ºcontivº:
    - integrates containers, virtualization, and physical servers
      based on the container network using a single networking fabric.
  -ºcontrailº:
    - provides overlay networking for multi-cloud and
      hybrid cloud through network policy enforcement.
  -ºflannelº:
    - makes it easier for developers to configure a layer 3
      network fabric for kubernetes.
  -ºmultusº:
    - supports multiple network interfaces in a single pod on
      kubernetes for sriov, sriov-dpdk, ovs-dpdk, and vpp workloads.
  -ºopen vswitch (ovs)º:
    - production-grade cni platform with a standard management
      interface on openshift and openstack.
  -ºovn-kubernetesº:
    - enables virtual networks for multiple containers on different
      hosts using an overlay function.
  -ºromanaº:
    - makes cloud network functions less expensive to build,
      easier to operate, and better performing than traditional
      cloud networks.

- in addition to network namespaces, an sdn should increase security by
offering isolation between multiple namespaces with the multi-tenant plugin:
  packets from one namespace, by default, will not be visible to
  other namespaces, so containers from different namespaces cannot
  send packets to or receive packets from pods and services of a
  different namespace.
network policy providers
use cilium for networkpolicy
use kube-router for networkpolicy
romana for networkpolicy
weave net for networkpolicy
access clusters using the kubernetes api
access services running on clusters
advertise extended resources for a node
autoscale the dns service in a cluster
change the reclaim policy of a persistentvolume
change the default storageclass
cluster management
configure multiple schedulers
configure out of resource handling
configure quotas for api objects
control cpu management policies on the node
customizing dns service
debugging dns resolution
declare network policy
developing cloud controller manager
encrypting secret data at rest
guaranteed scheduling for critical add-on pods
ip masquerade agent user guide
kubernetes cloud controller manager
limit storage consumption
operating etcd clusters for kubernetes
reconfigure a node's kubelet in a live cluster
reserve compute resources for system daemons
safely drain a node while respecting application slos
securing a cluster
set kubelet parameters via a config file
set up high-availability kubernetes masters
static pods
storage object in use protection
using coredns for service discovery
using a kms provider for data encryption
using sysctls in a kubernetes cluster
service mesh
istio.io
linkerd