{"id":20575361,"url":"https://github.com/c123r/kubernetes-hands-on","last_synced_at":"2026-06-20T12:31:32.120Z","repository":{"id":159933041,"uuid":"195357248","full_name":"C123R/kubernetes-hands-on","owner":"C123R","description":"This set of hands-on lab covers fundamentals of Kubernetes.","archived":false,"fork":false,"pushed_at":"2019-08-01T13:54:42.000Z","size":254,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-11T12:47:04.049Z","etag":null,"topics":["basics","hands-on","kubernetes","starting-point","training"],"latest_commit_sha":null,"homepage":"","language":"Smarty","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/C123R.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-05T07:07:32.000Z","updated_at":"2022-06-29T13:22:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"f2964268-1f46-41dd-90b1-c354d055b739","html_url":"https://github.com/C123R/kubernetes-hands-on","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/C123R/kubernetes-hands-on","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C123R%2Fkubernetes-hands-on","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C123R%2Fkubernetes-hands-on/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C123R%2Fkubernetes-hands-on/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C123R%2Fkubernetes-hands-on/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/C123R","download_url":"https://codeload.github.com/C123R/kubernetes-hands-on/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/C123R%2Fkubernetes-hands-on/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34570533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["basics","hands-on","kubernetes","starting-point","training"],"created_at":"2024-11-16T05:38:59.423Z","updated_at":"2026-06-20T12:31:32.100Z","avatar_url":"https://github.com/C123R.png","language":"Smarty","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kubernetes-hands-on\n\nThis set of hands-on covers fundamentals of Kubernetes.\n\nIt will take you through all required basics to get started with Kubernetes. By the end of this hands-on, you should able to deploy demo application.\n\n1. [**Kubectl** - Kubernetes Command line tool](##kubectl)\n1. [**Pod** - Basic building block](#pod)\n1. [**ReplicaSet**](#ReplicaSet)\n1. [**Deployment**](#Deployment)\n1. [**Service**](#Service)\n1. [**Configuration Management**](#Configuration)\n1. [**Volume**](#Volume)\n1. [**HELM** - Kubernetes Package Manager](#Helm)\n\n## kubectl\n\n`kubectl` is a Kubernetes CLI client. You will use it to create, delete and inspect various Kubernetes objects.\n\n### **Installation**\n\n#### For MacOS\n\n```sh\nbrew install kubernetes-cli\n```\n\nOthers can follow instructions from [here](https://kubernetes.io/docs/tasks/tools/install-kubectl/).\n\nTry this:\n\n```sh  \nkubectl version\n\n# Print the client and server versions for the current context\n```\n\n#### Kubernetes Config\n\nThere is a kubeconfig file behind every working kubectl command. Default location for kubeconfig is: `$HOME/.kube/config`.\n\nYou can specify other kubeconfig files by setting the `KUBECONFIG` environment variable or by setting the `--kubeconfig` flag.\n\n`kubectl` follows below preference for the kubeconfig:\n\n- --kubeconfig flag, if specified  \n- KUBECONFIG environment variable, if specified\n- $HOME/.kube/config file\n\n```yaml\napiVersion: v1\nclusters:\n- cluster:\n    certificate-authority-data: \u003cCA-DATA\u003e\n    server: https://\u003cAPISERVER-HOST\u003e:\u003cAPISERVER-PORT\u003e\n  name: \u003cCLUSTER-NAME\u003e\ncontexts:\n- context:\n    cluster: \u003cCLUSTER-NAME\u003e\n    user: \u003cUSER\u003e\n  name: \u003cUSER\u003e@\u003cCLUSTER-NAME\u003e\nkind: Config\nusers:\n- name: \u003cUSER\u003e\n  user:\n    client-certificate-data: \u003cCLIENT-CRT-DATA\u003e\n    client-key-data: \u003cCLIENT-KEY-DATA\u003e\n    token: \u003cBEARER TOKEN\u003e\n```\n\nYou can use [sample](https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/kubeconfig/sample-kubeconfig.yaml) kubeconfig for playing around with `kubectl config` command.\n\n\n\n```sh\ncurl https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/kubeconfig/sample-kubeconfig.yaml \u003e ~/.kube/config\n```\n\n### **Useful kubectl commands - You need to know**\n\n- **Managing Config/Context/Cluster**\n\n    ```sh\n    kubectl config view\n    kubectl config use-context\n    kubectl config get-contexts\n    ```\n\n    ```sh\n    kubectl cluster-info\n    ```\n\n- **Viewing Kubernetes Resources**\n\n    The most basic command for viewing Kubernetes objects via kubectl is **get**.  \n\n    `kubectl get \u003cresource-name\u003e \u003cobject-name\u003e`\n\n    For example:\n\n    ```sh\n    kubectl get pods nginx\n    ```\n\n    If you need more detailed information about a particular object, you can use **describe**.\n\n    `kubectl describe \u003cresource-name\u003e \u003cobject-name\u003e`\n\n    For example:\n\n    ```sh\n    kubectl describe pods nginx\n    ```\n\n    You can use different output format `-o,--output=''` in kubectl.\n\n    ```sh\n    kubectl describe pods nginx -o yaml\n    ```\n\n- **Creating, Updating, and Destroying Kubernetes Resources**\n\n    `kubectl apply` is the the recommended way of managing Kubernetes applications.  \n    For example:\n\n     ```sh\n    kubectl apply -f examples/pods/pod.yaml\n\n    # Here you dont need to specify resource type, as its part of the yaml.\n    ```\n\n    You can still make changes to this `examples/pods/pod.yaml` and apply it again to update the object, or you can use `edit` command to make changes interactively.\n\n    `kubectl edit \u003cresource-name\u003e \u003cobj-name\u003e`\n\n    For example:\n\n    ```sh\n    kubectl edit pod nginx\n    ```\n\n    (Imperative way)\n    You could use `create` to make a namespace,secret,deployment etc. For instance:\n\n    ```sh\n    kubectl create production\n    # create namespace\n\n    kubectl create deployment nginx --image=nginx\n    # start a single instance of nginx\n    ```\n\n    When you want to delete an object, you can simply run:\n\n    `kubectl delete \u003cresource-name\u003e \u003cobj-name\u003e`\n\n    and if object was created using apply:\n\n    For example:\n\n    ```sh\n    kubectl delete -f examples/pods/pod.yaml\n    ```\n\n- **Troubleshoot and Debugging Commands**\n\n    To get the logs for a container in a pod\n\n    `kubectl logs \u003cresource-name\u003e \u003cobj-name\u003e`\n\n    For example:\n\n    ```sh\n    kubectl logs nginx\n    ```\n\n    You can also execute command into container\n\n    `kubectl exec -it \u003cpod-name\u003e -- bash`\n\n    For example:\n\n    ```sh\n    kubectl exec -it nginx -- bash\n    kubectl exec -it nginx -- date\n    ```\n\n    There is way to create a proxy between localhost and Kubernetes API Server.\n\n     ```sh\n    kubectl proxy\n    ```\n\n    So you can practically access all kubernetes internal services from localhost now. For instance, you can access Kubernetes Dashboard:\n\n    http://localhost:8001/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy\n\n    **Important:** Exposing kubernetes dashboard is not recommended, even if you are doing it make sure you have authentication - to avoid security issues like what [Tesla](https://blog.heptio.com/on-securing-the-kubernetes-dashboard-16b09b1b7aca) had.\n\n\n\n## **Basic Kubernetes Objects**\n\n### **Namespace**\n\n```sh\nkubectl get namespaces\n\nkubectl create namespace $(whoami)\n```\n\n### **POD**\n\nA Pod is the basic building block of K8s Objects.\n\n```yaml\napiVersion: v1  \nkind: Pod           # type of k8s object\nmetadata:\n  name: nginx\n  labels:\n    env: demo\n# spec consists of the core information about pod\nspec:\n  containers:\n  - name: nginx\n    image: nginx\n  ports:\n    - name: http\n      containerPort: 80\n```\n\nLets create a pod running nginx container:\n\n```sh\nkubectl apply -f https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/examples/pods/pod.yaml -n $(whoami)\n```\n\n```sh\nkubectl get pods --watch\n\nkubectl get pods -n $(whoami)\nNAME    READY   STATUS    RESTARTS   AGE\nnginx   1/1     Running   0          31s\n```\n\nYou can get the complete pod manifest with output option -o yaml\n\n```sh\nkubectl get pods -n $(whoami) -o yaml\n```\n\nNow view the details:\n\n```sh\nkubectl describe pod nginx -n $(whoami)\n```\n\nTo check the logs:\n\n```sh\nkubectl logs nginx -n $(whoami)\n```\n\nNow you can access nginx pod with `port-forward`:\n\n```sh\nkubectl port-forward nginx 8080:80 -n $(whoami)\n```\n\nLets read nginx.conf file from our nginx container:\n\n```sh\nkubectl exec -it nginx -n $(whoami) -- cat /etc/nginx/nginx.conf\n```\n\n**But as you know, Pod is a smallest deployable unit and not a single container**, you can run multiple containers in one POD, which will share the network namespace(IP and Port space etc.) and volumes.\n\nFor example:\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nginx-mc\n  labels:\n    env: test\nspec:\n  containers:\n  - name: nginx             #1 Container running nginx\n    image: nginx\n    ports:\n    - name: http\n      containerPort: 80\n    volumeMounts:\n    - name: content\n      mountPath: /usr/share/nginx/html\n\n  - name: content-writer    #2 Container updating nginx default html page.\n    image: debian\n    volumeMounts:\n    - name: content\n      mountPath: /html\n    command: [\"/bin/sh\", \"-c\"]\n    args:\n      - while true; do\n            echo \"\u003ch1\u003eCurrent time:$(date +%T)\u003c/h1\u003e\" \u003e /html/index.html;\n          sleep 1;\n        done\n\n  volumes:                  # Volume which will be shared\n  - name: content\n    emptyDir: {}            # If POD gets removed, this data will be lost...but its safe if container is crashing\n```\n\nTry this:\n\n```sh\nkubectl apply -f https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/examples/pods/multiContainerPod.yaml -n $(whoami)\n\nkubectl port-forward nginx-mc -n $(whoami) 8080:80\n```\n\n## **Service**\n\n**Kubernetes service** - a virtual IP with a group of POD's IP as endpoints, it acts as a virtual load balancer whose IP stays same while backend POD's IP may keep changing.\n\nSimplest way to create service for a kubernetes resources is using `kubectl expose`.\n\n```sh\nkubectl expose pod nginx -n $(whoami)\n\nkubectl get svc -n $(whoami) -o yaml\n```\n\nAs you can see under the hood, it does a POST request to the API server with service defination to create a new instance.\n\n```yaml\napiVersion: v1\nkind: Service\nmetadata:\n  name: nginx-service\nspec:\n  selector:         # The set of Pods targeted by a Service is usually determined by a selector\n    env: demo\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 80\n```\n\n```sh\nkubectl apply -f https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/examples/services/services.yaml -n $(whoami)\n```\n\nFor third party endpoints we can use [Services without Selectors](https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors).\n\n### **ReplicaSet**\n\nOne of the main reason bare pods cant be deployed directly on Production environment as it could die for many reasons like Node failure, ran out of resources etc. So we cant keep track on number of running PODs.\n\n**ReplicaSet/ReplicaController** is one level above the Pod that ensures a certain number of PODs are always running.\n\n```yaml\napiVersion: apps/v1\nkind: ReplicaSet\nmetadata:\n  name: frontend\nspec:\n  replicas: 3                               # Number of PODs\n  selector:                                 # Pod Label Selector\n    matchLabels:\n      env: demo\n  template:                                 # Pod Template\n    metadata:\n      labels:\n        env: demo\n    spec:\n      containers:\n      - name: nginx\n        image: nginx\n        ports:\n        - name: http\n          containerPort: 80\n```\n\n```sh\nkubectl create -f https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/examples/replicaSet/replicaSet.yaml  -n $(whoami)\n```\n\n```sh\nkubectl get rs -n $(whoami)\n```\n\nThe difference between a replica set and a replication controller - replica set supports **set-based selector** requirements whereas a replication controller only supports **equality-based selector** requirements.\n\n**ReplicaSet:**\n\n```yaml\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      tier: frontend\n```\n\n**ReplicaController:**\n\n```yaml\nspec:\n  replicas: 1  \n  selector:\n    name: frontend\n````\n\n### **Deployment**\n\n**Deployment** is one level above the ReplicaSet/Replication Controller which keeps the set of identical pods running as well as upgrade them in a controlled way.\n\n**Deployment is now the recommended way to set up replication in Kubernetes.**\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx-deployment\n  labels:\n    app: nginx\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      labels:\n        app: nginx\n    spec:\n      containers:\n      - name: nginx\n        image: nginx:1.7.9\n        ports:\n        - containerPort: 80\n```\n\nCreate a deployment:\n\n```sh\nkubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml -n $(whoami)\n````\n\nGet the deployments:\n\n```sh\nkubectl get deployments -n $(whoami)\n\nkubectl get rs -n $(whoami)\n\nkubectl get pods --show-labels -n $(whoami)\n```\n\n**Note:** `pod-template-hash` is generated by hashing PodTemplate to ensure that child ReplicaSets of a Deployment do not overlap.\n\nDeployments give us the ability to track the rollout of changes  and roll them back if necessary.\n\nTo Track the rollout status you can use:\n\n```sh\nkubectl rollout status deployment nginx-deployment -n $(whoami)\n```\n\nNow lets say, we have to upgrade the **nginx** version:\n\n```sh\nkubectl set image deployment/nginx-deployment nginx=nginx:1.9 -n $(whoami)\n```\n\nOr you can edit the deployment object directly:\n\n```sh\nkubectl edit deployment nginx-deployment -n $(whoami)\n```\n\nYou can see the history of rollout:\n\n```sh\nkubectl rollout history -n zocperei deployment nginx-deployment\ndeployment.extensions/nginx-deployment\nREVISION  CHANGE-CAUSE\n1         \u003cnone\u003e\n2         \u003cnone\u003e\n```\n\nCHANGE-CAUSE is empty as we have to record the changes, it can be done using --record flag.\n\n**Rollback:**\n\nPractically you can rollback to previous version of nginx version, just by changing the image. But you can also undo the rollout easily:\n\n```sh\nkubectl rollout undo deployment.v1.apps/nginx-deployment -n $(whoami)\n\n# or you can use specific version from history\n```\n\n**Scaling:**\n\nScaling replicas is as easy as:\n\n```sh\nkubectl scale deployment nginx-deployment --replicas=5 -n $(whoami)\n```\n\n### **Configuration**\n\nThe 3rd factor (Configuration) of the [Twelve-Factor App Methodology](https://12factor.net/config) states:\n\n**Configuration that varies between deployments should be stored in the environment.**\n\n- **ConfigMap**\n\n    ConfigMaps(one of K8s API Resource) bind configuration files, command-line arguments, environment variables, port numbers, and other configuration artifacts to your Pods' containers and system components at runtime.\n\n    `kubectl create configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run] [options]`\n\n    For example:\n\n- Create ConfigMaps from literal values:\n\n    ```sh\n    kubectl create configmap special-config --from-literal=SPECIAL_LEVEL=very --from-literal=SPECIAL_TYPE=charm -n $(whoami)\n    ```\n\n    Lets create a pod which will consume this config:\n\n    ```sh\n    kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-env-var-valueFrom.yaml -n $(whoami)\n    ```\n\n    ```yaml\n    apiVersion: v1\n    kind: Pod\n    metadata:\n    name: dapi-test-pod\n    spec:\n    containers:\n        - name: test-container\n        image: k8s.gcr.io/busybox\n        command: [ \"/bin/sh\", \"-c\", \"echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)\" ]\n        env:\n            - name: SPECIAL_LEVEL_KEY\n            valueFrom:\n                configMapKeyRef:\n                name: special-config\n                key: SPECIAL_LEVEL\n            - name: SPECIAL_TYPE_KEY\n            valueFrom:\n                configMapKeyRef:\n                name: special-config\n                key: SPECIAL_LEVEL\n    restartPolicy: Never  \n    ```\n\n- Create ConfigMaps from env file:\n\n    ```sh\n    cat \u003c\u003c EOF \u003e /tmp/config.env\n    SPECIAL_LEVEL=verrrry\n    SPECIAL_TYPE=charmmm\n    EOF\n    ```\n\n    ```sh\n    kubectl create configmap special-config --from-env-file=/tmp/config.env -n $(whoami)\n    ```\n\n- Or we can directly create configmap object using kubectl:\n\n    ```yaml\n    apiVersion: v1\n    kind: ConfigMap\n    metadata:\n        name: special-config\n    data:\n        SPECIAL_LEVEL: very\n        SPECIAL_TYPE: charm\n    ```\n\n    ```sh\n    kubectl create -f https://raw.githubusercontent.com/C123R/kubernetes-hands-on/master/configmap/config-map.yaml -n $(whoami)\n    ```\n\n    We can create a volume in POD to store this confimap:\n\n    ```yaml\n    apiVersion: v1\n    kind: Pod\n    metadata:\n    name: dapi-test-pod\n    spec:\n        containers:\n            - name: test-container\n            image: k8s.gcr.io/busybox\n            command: [ \"/bin/sh\", \"-c\", \"ls /etc/config/\" ]\n            volumeMounts:\n            - name: config-volume\n                mountPath: /etc/config\n        volumes:\n            - name: config-volume\n            configMap:\n                name: special-config\n        restartPolicy: Never\n    ```\n\n    ```sh\n    kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume.yaml -n $(whoami)\n\n    kubectl logs dapi-test-pod -n $(whoami)\n    SPECIAL_LEVEL\n    SPECIAL_TYPE\n    ```\n\n    With Specific path in the Volume\n\n    ```yaml\n    volumes:\n    - name: config-volume\n      configMap:\n        name: special-config\n        items:\n        - key: SPECIAL_LEVEL\n          path: keys\n    ```\n\n    This can be access from path `cat /etc/config/keys`\n\n    **Caution**: If there are some files in the /etc/config/ directory, they will be deleted.\n\n- **Secret**\n\nKubernetes secret objects let you store and manage sensitive information, such as passwords, OAuth tokens, and ssh keys.\n\nYou can use `kubectl create secret` to create new secret in your cluster:  \n\n` kubectl create secret [flags] [options]`\n\nLets create our first secret using --form-env-file option\n\n```sh\nkubectl create secret generic my-secret --from-env-file=/tmp/config.env -n $(whoami)\n\nkubectl get secrets my-secret -o yaml -n $(whoami)\n```\n\nHow to use secret in PODs:\n\n```yaml\napiVersion: v1\nkind: Pod\nmetadata:\n  name: secret-env-pod\nspec:\n  containers:\n  - name: mycontainer\n    image: redis\n    env:\n      - name: SECRET_USERNAME\n        valueFrom:\n          secretKeyRef:\n            name: mysecret\n            key: username\n      - name: SECRET_PASSWORD\n        valueFrom:\n          secretKeyRef:\n            name: mysecret\n            key: password\n  restartPolicy: Never\n```\n\n### **Volume**\n\nA Kubernetes volume is essentially a directory accessible to all containers running in a pod.  \n\n- `node-local` types such as emptyDir\n- `file-sharing` types such as nfs\n- `cloud provider-specific` types like azureDisk, awsElasticBlockStore, or gcePersistentDisk\n- special-purpose types like `secret`, `configmap`\n\n**[-\u003e List of Kubernetes supported volume types \u003c-](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes)**\n\n![K8sVolume](img/volume-mount.png)\n\n#### emptyDir:\n\n```yaml\nspec:\n  containers:\n  - name: nginx\n    image: nginx\n    ports:\n    - name: http\n      containerPort: 80\n    volumeMounts:\n    - name: content\n      mountPath: /usr/share/nginx/html\n  - name: content-writer\n    image: debian\n    volumeMounts:\n    - name: content\n      mountPath: /html\n    command: [\"/bin/sh\", \"-c\"]\n    args:\n      - while true; do\n            echo \"\u003ch1\u003eCurrent time:$(date +%T)\u003c/h1\u003e\" \u003e /html/index.html;\n          sleep 1;\n        done\n  volumes:\n  - name: content\n    emptyDir: {}\n```\n\n#### configmap or secret:\n\n```yaml\nspec:\n  containers:\n    - name: test-container\n      image: k8s.gcr.io/busybox\n      command: [ \"/bin/sh\", \"-c\", \"ls /etc/config/\" ]\n      volumeMounts:\n      - name: config-volume\n        mountPath: /etc/config\n  volumes:\n    - name: config-volume\n      configMap:\n        # Provide the name of the ConfigMap containing the files you want\n        # to add to the container\n        name: special-config\n```\n\n#### PersistentVolume and PersistentVolumeClaim\n\nA `PersistentVolume` (PV) is a piece of storage in the cluster that has been provisioned by an administrator or dynamically provisioned using Storage Classes.\n\nA `PersistentVolumeClaim` (PVC) is a request for storage by a user. It is similar to a pod. Pods consume node resources and PVCs consume PV resources. 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).\n\nPVs are resources in the cluster. PVCs are requests for those resources and also act as claim checks to the resource.\n\n- **Static PV**: Cluster admin create PVs and then using kubernetes API resources can claim it.\n- **Dyanmic PV**: When none of the static PVs the administrator created matches a user’s PersistentVolumeClaim, the cluster may try to dynamically provision a volume specially for the PVC.\n\nSo for instance, if we want to create Dynamic PVC in Azure, we can simply create PVC as mentioned below:\n\n```sh\nkubectl get sc\n```\nCreating PVC resource using Storage class:\n\n```yaml\ncat \u003c\u003cEOF | kubectl apply -f -\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: azure-managed-disk\nspec:\n  accessModes:\n  - ReadWriteOnce\n  storageClassName: managed-premium\n  resources:\n    requests:\n      storage: 5Gi\nEOF\n```\n\n```sh\nkubectl get pvc\n```\n\nClaim as a Volume in POD\n\n```yaml\ncat \u003c\u003cEOF | kubectl apply -f -\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nginx\nspec:\n  containers:\n    - name: nginx\n      image: nginx\n      volumeMounts:\n      - mountPath: \"/var/www/html\"\n        name: nginx\n  volumes:\n    - name: nginx\n      persistentVolumeClaim:\n        claimName: azure-managed-disk\nEOF\n```\n```sh\nkubectl describe pods nginx\n```\n\n`ReadWriteOnce`: The volume can be mounted as read-write by a single node.  \n`ReadOnlyMany`: The volume can be mounted read-only by many nodes.  \n`ReadWriteMany`: The volume can be mounted as read-write by many nodes.  \n\n\n\n\n\n## Demo Application\n\nLets deploy our first demo application([k8s-click-counter](https://github.com/C123R/k8s-click-counter#k8s-click-counter)) using above discussed objects - Deployment + Services.\n\n## Helm\n\nSee the dedicated [README](HELM.MD)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc123r%2Fkubernetes-hands-on","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc123r%2Fkubernetes-hands-on","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc123r%2Fkubernetes-hands-on/lists"}