{"id":5214,"date":"2023-10-21T19:25:27","date_gmt":"2023-10-21T17:25:27","guid":{"rendered":"http:\/\/miro.borodziuk.eu\/?p=5214"},"modified":"2024-02-24T19:52:27","modified_gmt":"2024-02-24T18:52:27","slug":"kubernetes-services-network-and-api","status":"publish","type":"post","link":"http:\/\/miro.borodziuk.eu\/index.php\/2023\/10\/21\/kubernetes-services-network-and-api\/","title":{"rendered":"Running and Deploying Kubernetes Applications"},"content":{"rendered":"<div class=\"transcript--cue-container--wu3UY\">\n<p class=\"transcript--underline-cue--3osdw\" tabindex=\"-1\" role=\"button\" data-purpose=\"transcript-cue\"><span class=\"\" data-purpose=\"cue-text\">All the services need to be in a running state. With Kubernetes, our ultimate aim is to deploy our application in the form of containers on a set of machines that are configured as worker nodes in a cluster. Kubernetes does not deploy containers directly on the worker nodes. The containers are encapsulated into a Kubernetes object known as pods. A pod is a single instance of an application. A pod is the smallest object that you can create in Kubernetes.<\/span><\/p>\n<\/div>\n<p><!--more--><\/p>\n<p><span style=\"color: #3366ff;\">What is a Pod?<\/span><\/p>\n<ul>\n<li>A Pod is an abstraction of a server\n<ul>\n<li>It can run multiple containers within a single NameSpace, exposed by a single IP address<\/li>\n<\/ul>\n<\/li>\n<li>The Pod is the minimal entity that can be managed by Kubernetes<\/li>\n<li>From a container perspective, a Pod is an entity that runs typically one or more containers by using container images<\/li>\n<li>Typically, Pods are only started through a Deployment, because &#8220;naked&#8221; Pods are not rescheduled in case of a node failure<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Naked Pod Disadvantages<\/span><\/p>\n<ul>\n<li>Naked Pods are not rescheduled in case of failure<\/li>\n<li>Rolling updates don&#8217;t apply to naked Pods; you can only bring it down and bring it up again with the new settings<\/li>\n<li>Naked Pods cannot be scaled<\/li>\n<li>Naked Pods cannot be replaced automatically<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Using Deployments<\/span><\/p>\n<ul>\n<li>The Deployment is the standard way for running containers in Kubernetes<\/li>\n<li>Deployments are responsible for starting Pods in a scalable way<\/li>\n<li>The Deployment resource uses a ReplicaSet to manage scalability<\/li>\n<li>Also, the Deployment offers the RollingUpdate feature to allow for zero-downtime application updates<\/li>\n<li>To start a Deployment the imperative way, use<code> kubectl create deploy<\/code> &#8230;<\/li>\n<\/ul>\n<p><span style=\"color: #3366ff;\">Kubernetes Tools<\/span><\/p>\n<ul>\n<li>Before starting the installation, you&#8217;ll have to install the Kubernetes tools<\/li>\n<li>These include the following:\n<ul>\n<li><code>kubeadm<\/code>: used to install and manage a Kubernetes cluster<\/li>\n<li><code>kubelet<\/code>: the core Kubernetes service that starts all Pods<\/li>\n<li><code> kubectl<\/code>: the interface that allows you to run and manage applications in Kubernetes<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-size: 14pt; color: #3366ff;\"><strong>kubectl<\/strong><\/span><\/p>\n<pre class=\"lang:default decode:true \">$ kubectl run nginx --image nginx\r\n<\/pre>\n<p>This command deploys a Docker container by creating a pod, so it first creates a pod automatically and deploys an instance of the NGINX Docker image, but where does it get the application image from? For that, you need to specify the image name using the dash dash image parameter. The application image, in this case, the NGINX image, is downloaded from the Docker Hub repository. You could configure Kubernetes to pull the image from the public Docker Hub or a private repository within the organization.<\/p>\n<p><span class=\"\" data-purpose=\"cue-text\">Now that we have a pod created, how do we see the list of pods available?<\/span><\/p>\n<pre class=\"lang:default decode:true\">$ kubectl get pods<\/pre>\n<p><span class=\"\" data-purpose=\"cue-text\">The<code> kubectl get pods<\/code> command helps us see the list of pods in our cluster. In this case,we see the pod is in a container creating state and soon changes to a running statewhen it is actually running.<\/span><\/p>\n<div class=\"transcript--cue-container--wu3UY\"><\/div>\n<div class=\"transcript--cue-container--wu3UY\">\n<p class=\"transcript--underline-cue--3osdw\" tabindex=\"-1\" role=\"button\" data-purpose=\"transcript-cue\"><span class=\"\" data-purpose=\"cue-text\">To see detailed information about the pod, run:<\/span><\/p>\n<pre class=\"lang:default decode:true \">$ kubectl describe pod myapp-pod<\/pre>\n<p><span class=\"\" data-purpose=\"cue-text\">This will tell you information <\/span><span class=\"transcript--highlight-cue--1bEgq\" data-purpose=\"cue-text\">about the pod when it was created, <\/span><span class=\"\" data-purpose=\"cue-text\">what labels are assigned to it, what docker containers are part of it and the events associated with that pod.<\/span><\/p>\n<\/div>\n<p>Examples<\/p>\n<pre class=\"lang:default decode:true \">[root@k8s ~]# kubectl run testpod --image=nginx\r\npod\/testpod created\r\n\r\n[root@k8s ~]# kubectl get pods\r\nNAME READY STATUS RESTARTS AGE\r\ntestpod 0\/1 Pending 0 8s\r\n\r\n[root@k8s ~]# kubectl create deploy -h\r\n\r\n[root@k8s ~]# kubectl create deployment firstnginx --image=nginx --replicas=3\r\ndeployment.apps\/firstnginx created\r\n\r\n[root@k8s ~]# kubectl get all\r\nNAME READY STATUS RESTARTS AGE\r\npod\/firstnginx-d8679d567-249g9 0\/1 Pending 0 20s\r\npod\/firstnginx-d8679d567-66c4s 0\/1 Pending 0 20s\r\npod\/firstnginx-d8679d567-72qbd 0\/1 Pending 0 20s\r\npod\/testpod 0\/1 Pending 0 7m47s\r\n\r\nNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\r\nservice\/kubernetes ClusterIP 10.96.0.1 &lt;none&gt; 443\/TCP 5h\r\n\r\nNAME READY UP-TO-DATE AVAILABLE AGE\r\ndeployment.apps\/firstnginx 0\/3 3 0 20s\r\n\r\nNAME DESIRED CURRENT READY AGE\r\nreplicaset.apps\/firstnginx-d8679d567 3 3 0 20s<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Understanding DaemonSets<\/span><\/p>\n<ul>\n<li>A DaemonSet is a resource that starts one application instance on each cluster node<\/li>\n<li>It is commonly used to start agents like the kube-proxy that need to be running on all cluster nodes<\/li>\n<li>It can also be used for user workloads<\/li>\n<li>lf the DaemonSet needs to run on control-plane nodes, a toleration must be configured to allow the node to run regardless of the control-plane taints<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true\">[root@k8s ~]# kubectl get ds\r\nNo resources found in default namespace.\r\n\r\n[root@k8s ~]# kubectl get ds -A\r\nNAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE\r\nkube-system kube-proxy 1 1 1 1 1 kubernetes.io\/os=linux 5h4m\r\n\r\n[root@k8s ~]# kubectl get ds -n kube-system kube-proxy\r\nNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE\r\nkube-proxy 1 1 1 1 1 kubernetes.io\/os=linux 5h9m\r\n\r\n[root@k8s ~]# kubectl get ds -n kube-system kube-proxy -o yaml\r\napiVersion: apps\/v1\r\nkind: DaemonSet\r\nmetadata:\r\nannotations:\r\ndeprecated.daemonset.template.generation: \"1\"\r\ncreationTimestamp: \"2024-01-31T15:03:27Z\"\r\ngeneration: 1\r\nlabels:\r\nk8s-app: kube-proxy\r\nname: kube-proxy\r\nnamespace: kube-system\r\nresourceVersion: \"4832\"\r\nuid: 2c4a7965-c3a4-42f9-8ce0-caa49b6d41c5\r\nspec:\r\nrevisionHistoryLimit: 10\r\nselector:\r\nmatchLabels:\r\nk8s-app: kube-proxy\r\ntemplate:\r\nmetadata:\r\ncreationTimestamp: null\r\nlabels:\r\nk8s-app: kube-proxy\r\nspec:\r\ncontainers:\r\n- command:\r\n- \/usr\/local\/bin\/kube-proxy\r\n- --config=\/var\/lib\/kube-proxy\/config.conf\r\n- --hostname-override=$(NODE_NAME)\r\nenv:\r\n- name: NODE_NAME\r\nvalueFrom:\r\nfieldRef:\r\napiVersion: v1\r\nfieldPath: spec.nodeName\r\nimage: registry.k8s.io\/kube-proxy:v1.28.3\r\nimagePullPolicy: IfNotPresent\r\nname: kube-proxy\r\nresources: {}\r\nsecurityContext:\r\nprivileged: true\r\nterminationMessagePath: \/dev\/termination-log\r\nterminationMessagePolicy: File\r\nvolumeMounts:\r\n- mountPath: \/var\/lib\/kube-proxy\r\nname: kube-proxy\r\n- mountPath: \/run\/xtables.lock\r\nname: xtables-lock\r\n- mountPath: \/lib\/modules\r\nname: lib-modules\r\nreadOnly: true\r\ndnsPolicy: ClusterFirst\r\nhostNetwork: true\r\nnodeSelector:\r\nkubernetes.io\/os: linux\r\npriorityClassName: system-node-critical\r\nrestartPolicy: Always\r\nschedulerName: default-scheduler\r\nsecurityContext: {}\r\nserviceAccount: kube-proxy\r\nserviceAccountName: kube-proxy\r\nterminationGracePeriodSeconds: 30\r\ntolerations:\r\n- operator: Exists\r\nvolumes:\r\n- configMap:\r\ndefaultMode: 420\r\nname: kube-proxy\r\nname: kube-proxy\r\n- hostPath:\r\npath: \/run\/xtables.lock\r\ntype: FileOrCreate\r\nname: xtables-lock\r\n- hostPath:\r\npath: \/lib\/modules\r\ntype: \"\"\r\nname: lib-modules\r\nupdateStrategy:\r\nrollingUpdate:\r\nmaxSurge: 0\r\nmaxUnavailable: 1\r\ntype: RollingUpdate\r\nstatus:\r\ncurrentNumberScheduled: 1\r\ndesiredNumberScheduled: 1\r\nnumberAvailable: 1\r\nnumberMisscheduled: 0\r\nnumberReady: 1\r\nobservedGeneration: 1\r\nupdatedNumberScheduled: 1<\/pre>\n<p>Lets create a DaemmonSet as it is written at<\/p>\n<p><code>https:\/\/kubernetes.io\/docs\/concepts\/workloads\/controllers\/daemonset\/<\/code><\/p>\n<p>copy yaml from<\/p>\n<p><code>https:\/\/raw.githubusercontent.com\/kubernetes\/website\/main\/content\/en\/examples\/controllers\/daemonset.yaml<\/code><\/p>\n<pre class=\"lang:default decode:true\">[root@k8s ~]# vi daemondemo.yaml\r\n[root@k8s ~]# cat daemondemo.yaml\r\napiVersion: apps\/v1\r\nkind: DaemonSet\r\nmetadata:\r\n  name: fluentd-elasticsearch\r\n  namespace: kube-system\r\n  labels:\r\n    k8s-app: fluentd-logging\r\nspec:\r\n  selector:\r\n    matchLabels:\r\n      name: fluentd-elasticsearch\r\n  template:\r\n    metadata:\r\n      labels:\r\n        name: fluentd-elasticsearch\r\n    spec:\r\n      tolerations:\r\n      # these tolerations are to have the daemonset runnable on control plane nodes\r\n      # remove them if your control plane nodes should not run pods\r\n      - key: node-role.kubernetes.io\/control-plane\r\n        operator: Exists\r\n        effect: NoSchedule\r\n      - key: node-role.kubernetes.io\/master\r\n        operator: Exists\r\n        effect: NoSchedule\r\n      containers:\r\n      - name: fluentd-elasticsearch\r\n        image: quay.io\/fluentd_elasticsearch\/fluentd:v2.5.2\r\n        resources:\r\n          limits:\r\n            memory: 200Mi\r\n          requests:\r\n            cpu: 100m\r\n            memory: 200Mi\r\n        volumeMounts:\r\n        - name: varlog\r\n          mountPath: \/var\/log\r\n      # it may be desirable to set a high priority class to ensure that a DaemonSet Pod\r\n      # preempts running Pods\r\n      # priorityClassName: important\r\n      terminationGracePeriodSeconds: 30\r\n      volumes:\r\n      - name: varlog\r\n        hostPath:\r\n          path: \/var\/log\r\n[root@k8s ~]# kubectl create deploy mydaemon --image=nginx --dry-run=client -o yaml &gt; mydaemon.yaml\r\n[root@k8s ~]# vim mydaemon.yaml\r\n<\/pre>\n<p>After edit the kind and remove replicas and sttrategy spec mydaemon.yaml file looks like:<\/p>\n<pre class=\"lang:default decode:true \">[root@k8s ~]# cat mydaemon.yaml\r\napiVersion: apps\/v1\r\nkind: Daemonset\r\nmetadata:\r\n  creationTimestamp: null\r\n  labels:\r\n    app: mydaemon\r\n  name: mydaemon\r\nspec:\r\n  selector:\r\n    matchLabels:\r\n      app: mydaemon\r\n  template:\r\n    metadata:\r\n      creationTimestamp: null\r\n      labels:\r\n        app: mydaemon\r\n    spec:\r\n      containers:\r\n      - image: nginx\r\n        name: nginx\r\n        resources: {}\r\nstatus: {}\r\n<\/pre>\n<p>Now lets create daemonset:<\/p>\n<pre class=\"lang:default decode:true \">[root@k8s ~]# kubectl apply -f mydaemon.yaml\r\ndaemonset.apps\/mydaemon created\r\n\r\n[root@k8s ~]# kubectl get ds\r\nNAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE\r\nmydaemon   0         0         0       0            0           &lt;none&gt;          62s\r\n\r\n[root@k8s ~]# kubectl get pods -o wide\r\nNAME                         READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES\r\nfirstnginx-d8679d567-249g9   0\/1     Pending   0          35m   &lt;none&gt;   &lt;none&gt;   &lt;none&gt;           &lt;none&gt;\r\nfirstnginx-d8679d567-66c4s   0\/1     Pending   0          35m   &lt;none&gt;   &lt;none&gt;   &lt;none&gt;           &lt;none&gt;\r\nfirstnginx-d8679d567-72qbd   0\/1     Pending   0          35m   &lt;none&gt;   &lt;none&gt;   &lt;none&gt;           &lt;none&gt;\r\ntestpod                      0\/1     Pending   0          43m   &lt;none&gt;   &lt;none&gt;   &lt;none&gt;           &lt;none&gt;\r\n<\/pre>\n<p>We have no daemonset running because we use minikube which has no worker node.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Stateful and Stateless Applications<\/span><\/p>\n<ul>\n<li>A stateless application is an application that doesn&#8217;t store any session data<\/li>\n<li>Redirecting traffic in a stateless application is easy, the traffic can just be directed to another Pod instance<\/li>\n<li>A stateful application saves session data to persistent storage<\/li>\n<li>Databases are an example of stateful applications<\/li>\n<li>Even if stateful applications can be started by a Deployment, it&#8217;s better to start it in a StatefulSet<\/li>\n<\/ul>\n<p><span style=\"color: #3366ff;\">StatefulSet<\/span><\/p>\n<p>A StatefulSet offers features that are needed by stateful applications<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>It provides guarantees about ordering and uniqueness of Pods<\/li>\n<li>It maintains a sticky identifier for each of the Pods it creates<\/li>\n<li>Pods in a StatefulSet are not interchangeable: each Pod has a persistent identifier that it maintains while being rescheduled<\/li>\n<li>The unique Pod identifiers make it easier to match existing volumes to replaced Pods<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"color: #3366ff;\">StatefulSet Considerations<\/span><\/p>\n<ul>\n<li>Storage must be automatically provisioned by a persistent volume provisioner. Pre-provisioning is challenging, as volumes need to be dynamically added when new Pods are scheduled<\/li>\n<li>When a StatefulSet is deleted, associated volumes will not be deleted<\/li>\n<li>A headless Service resource must be created in order to manage the network identity of Pods<\/li>\n<li>Pods are not guaranteed to be stopped while deleting a StatefulSet, and it is recommended to scale down to zero Pods before deleting the StatefulSet<\/li>\n<\/ul>\n<p>Let&#8217;s\u00a0 look at the below yaml file:<\/p>\n<pre class=\"lang:default decode:true\">[root@k8s cka]# cat statefuldemo.yaml\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: nginx\r\n  labels:\r\n    app: nginx\r\nspec:\r\n  ports:\r\n  - port: 80\r\n    name: web\r\n  clusterIP: None\r\n  selector:\r\n    app: nginx\r\n---\r\napiVersion: apps\/v1\r\nkind: StatefulSet\r\nmetadata:\r\n  name: web\r\nspec:\r\n  selector:\r\n    matchLabels:\r\n      app: nginx\r\n  serviceName: \"nginx\"\r\n  replicas: 3\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: nginx\r\n    spec:\r\n      terminationGracePeriodSeconds: 10\r\n      containers:\r\n      - name: nginx\r\n        image: k8s.gcr.io\/nginx-slim:0.8\r\n        ports:\r\n        - containerPort: 80\r\n          name: web\r\n        volumeMounts:\r\n        - name: www\r\n          mountPath: \/usr\/share\/nginx\/html\r\n  volumeClaimTemplates:\r\n  - metadata:\r\n      name: www\r\n    spec:\r\n      accessModes: [ \"ReadWriteMany\" ]\r\n      resources:\r\n        requests:\r\n          storage: 1Gi\r\n<\/pre>\n<p>StatefullSets requires headless service so <code>clusterIP<\/code> is set to <code>none<\/code> in the above yaml file. Let&#8217;s run it and see what it is doing:<\/p>\n<pre class=\"lang:default decode:true \">[root@k8s cka]# kubectl apply -f statefuldemo.yaml\r\nservice\/nginx created\r\nstatefulset.apps\/web created\r\n\r\n[root@k8s cka]# kubectl get statefulset\r\nNAME   READY   AGE\r\nweb    0\/3     16s\r\n\r\n[root@k8s cka]# kubectl get pods\r\nNAME                         READY   STATUS    RESTARTS   AGE\r\nfirstnginx-d8679d567-249g9   0\/1     Pending   0          12h\r\nfirstnginx-d8679d567-66c4s   0\/1     Pending   0          12h\r\nfirstnginx-d8679d567-72qbd   0\/1     Pending   0          12h\r\ntestpod                      0\/1     Pending   0          12h\r\nweb-0                        0\/1     Pending   0          25s\r\n\r\n[root@k8s cka]# kubectl get pvc\r\nNAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE\r\nwww-web-0   Pending                                      standard       40s\r\n<\/pre>\n<p>The name of pods (<code>web-0<\/code>) which has been generated doesn&#8217;t contain the random id but there are nice names. Because of the availability here of the storage class the StatefulSets has been able to automatically allocate storage for very single instance in the StatefulSet.<\/p>\n<p><span style=\"color: #3366ff;\">Running Individual Pods<\/span><\/p>\n<ul>\n<li>Running individual Pods has disadvantages:<\/li>\n<li>No workload protection<\/li>\n<li>No load balancing<\/li>\n<li>No zero-downtime application update<\/li>\n<li>Use individual Pods only for testing, troubleshooting, and analyzing<\/li>\n<li>In all other cases, use Deployment, DaemonSet, or StatefulSet<\/li>\n<\/ul>\n<p>Here is how we can run an idividual pod:<\/p>\n<pre class=\"lang:default decode:true\">[root@k8s cka]# kubectl run -h \r\n[root@k8s cka]# kubectl run sleepy --image=busybox -- sleep 3600 \r\npod\/sleepy created\r\n\r\n[root@k8s cka]# kubectl get pods\r\nNAME                         READY   STATUS    RESTARTS   AGE\r\nfirstnginx-d8679d567-249g9   0\/1     Pending   0          14h\r\nfirstnginx-d8679d567-66c4s   0\/1     Pending   0          14h\r\nfirstnginx-d8679d567-72qbd   0\/1     Pending   0          14h\r\nsleepy                       0\/1     Pending   0          3m14s\r\ntestpod                      0\/1     Pending   0          14h\r\nweb-0                        0\/1     Pending   0          133m\r\n<\/pre>\n<p><code>--\u00a0<\/code> [dash dash space] is the easy way to pass a command (<code>sleep 3600<\/code>) that sholud be started by a pod.<\/p>\n<p>What can you do if you want to initialize something before the main application is started ? You can run an init container.<\/p>\n<p><span style=\"color: #3366ff;\">Using !nit Containers<\/span><\/p>\n<ul>\n<li>If preparation is required before running the main container, use an init container<\/li>\n<li>Init containers run to completion, and once completed the main container can be started<\/li>\n<li>Use init containers in any case where preliminary setup is required<\/li>\n<\/ul>\n<p>Consider such an init container temmplate:<\/p>\n<pre class=\"lang:default decode:true\">[root@k8s cka]# cat initme.yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  name: init-demo\r\nspec:\r\n  containers:\r\n  - name: nginx\r\n    image: nginx\r\n    ports:\r\n    - containerPort: 80\r\n  # These containers are run during pod initialization\r\n  initContainers:\r\n  - name: install\r\n    image: busybox\r\n    command:\r\n    - sleep\r\n    - \"30\"\r\n\r\n[root@k8s cka]# kubectl apply -f initme.yaml\r\npod\/init-demo created\r\n\r\n[root@k8s cka]# kubectl get pods\r\nNAME                         READY   STATUS    RESTARTS   AGE\r\nfirstnginx-d8679d567-249g9   0\/1     Pending   0          15h\r\nfirstnginx-d8679d567-66c4s   0\/1     Pending   0          15h\r\nfirstnginx-d8679d567-72qbd   0\/1     Pending   0          15h\r\ninit-demo                    0\/1     Pending   0          20s\r\nsleepy                       0\/1     Pending   0          47m\r\ntestpod                      0\/1     Pending   0          15h\r\nweb-0                        0\/1     Pending   0          177m\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Scaling Applications<\/span><\/p>\n<ul>\n<li>kubectl scale is used to manually scale Deployment, ReplicaSet, or StatefulSet\n<ul>\n<li><code>kubectl scale deployment myapp --replicas=3 <\/code><\/li>\n<\/ul>\n<\/li>\n<li>Alternatively, HorizontalPodAutoscaler can be used<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true \">[root@k8s cka]# kubectl scale -h\r\n\r\n[root@k8s cka]# kubectl scale --replicas=4 deployment\/firstnginx\r\ndeployment.apps\/firstnginx scaled\r\n\r\n[root@k8s cka]# kubectl get deploy\r\nNAME         READY   UP-TO-DATE   AVAILABLE   AGE\r\nfirstnginx   0\/4     4            0           17h\r\n\r\n[root@k8s cni]# kubectl get all --selector app=firstnginx\r\nNAME                             READY   STATUS    RESTARTS   AGE\r\npod\/firstnginx-d8679d567-249g9   1\/1     Running   0          24h\r\npod\/firstnginx-d8679d567-66c4s   1\/1     Running   0          24h\r\npod\/firstnginx-d8679d567-72qbd   1\/1     Running   0          24h\r\npod\/firstnginx-d8679d567-rhhlz   1\/1     Running   0          7h54m\r\n\r\nNAME                         READY   UP-TO-DATE   AVAILABLE   AGE\r\ndeployment.apps\/firstnginx   4\/4     4            4           24h\r\n\r\nNAME                                   DESIRED   CURRENT   READY   AGE\r\nreplicaset.apps\/firstnginx-d8679d567   4         4         4       24h\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Multi-container Pods<\/span><\/p>\n<ul>\n<li>As a Pod should be created for each specific task, running single-container Pods is the standard<\/li>\n<li>In some cases, an additional container is needed to modify or present data generated by the main container<\/li>\n<li>Specific use cases are defined:\n<ul>\n<li>Sidecar: provides additional functionality to the main container<\/li>\n<li>Ambassador: is used as a proxy to connect containers externally<\/li>\n<li>Adapter: is used to standardize or normalize main container output<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"color: #3366ff;\">Multi-container Storage<\/span><\/p>\n<ul>\n<li>In a multi-container Pod, Pod Volumes are often used as shared storage<\/li>\n<li>The Pod Volume may use PersistentVolumeClaim (PVC) to refer to a PersistentVolume, but may also directly refer to the required storage<\/li>\n<li>By using shared storage, the main container can write to it, and the helper Pod will pick up information written to the shared storage<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true\">[root@k8s cka]# cat sidecarlog.yaml\r\napiVersion: v1\r\nkind: Pod\r\nmetadata:\r\n  name: two-containers\r\nspec:\r\n\r\n  volumes:\r\n  - name: shared-data\r\n    emptyDir: {}\r\n\r\n  containers:\r\n\r\n  - name: nginx-container\r\n    image: nginx\r\n    volumeMounts:\r\n    - name: shared-data\r\n      mountPath: \/usr\/share\/nginx\/html\r\n\r\n  - name: busybox-container\r\n    image: busybox\r\n    volumeMounts:\r\n    - name: shared-data\r\n      mountPath: \/messages\r\n    command: [\"\/bin\/sh\"]\r\n    args: [\"-c\", \"echo hello from the cluster &gt; \/messages\/index.html &amp;&amp; sleep 600\" ]\r\n\r\n[root@k8s cka]# kubectl apply -f sidecarlog.yaml\r\npod\/two-containers created\r\n\r\n[root@k8s cni]# kubectl exec -it two-containers -c nginx-container -- cat \/usr\/share\/nginx\/html\/index.html\r\nhello from the cluster\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Lab: Running a DaemonSet<\/span><\/p>\n<ul>\n<li>Create a DaemonSet with the name nginxdaemon.<\/li>\n<li>Ensure it runs an Nginx Pod on every worker node.<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true \">[root@k8s cni]# kubectl create deployment deploydaemon --image=nginx --dry-run=client -o yaml &gt; deploydaemon.yaml\r\n[root@k8s cni]# vim deploydaemon.yaml<\/pre>\n<p>Edit <code>deploydaemon.yaml<\/code>. Change kind and delete replicas and strategy lines.<\/p>\n<pre class=\"lang:default decode:true \">[root@k8s cni]# kubectl apply -f deploydaemon.yaml\r\ndaemonset.apps\/deploydaemon created\r\n\r\n[root@k8s cni]# kubectl get all --selector app=deploydaemon\r\nNAME                     READY   STATUS    RESTARTS   AGE\r\npod\/deploydaemon-zzllp   1\/1     Running   0          28s\r\n\r\nNAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE\r\ndaemonset.apps\/deploydaemon   1         1         1       1            1           &lt;none&gt;          28s\r\n<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>All the services need to be in a running state. With Kubernetes, our ultimate aim is to deploy our application in the form of containers on a set of machines that are configured as worker nodes in a cluster. Kubernetes does not deploy containers directly on the worker nodes. The containers are encapsulated into a &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/miro.borodziuk.eu\/index.php\/2023\/10\/21\/kubernetes-services-network-and-api\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Running and Deploying Kubernetes Applications&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[99],"tags":[],"_links":{"self":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/5214"}],"collection":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/comments?post=5214"}],"version-history":[{"count":35,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/5214\/revisions"}],"predecessor-version":[{"id":5217,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/5214\/revisions\/5217"}],"wp:attachment":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media?parent=5214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/categories?post=5214"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/tags?post=5214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}