{"id":21058145,"url":"https://github.com/devkyt/k8s-cookbook","last_synced_at":"2025-04-30T09:49:55.994Z","repository":{"id":234931916,"uuid":"776752352","full_name":"devkyt/k8s-cookbook","owner":"devkyt","description":"How to do the do on Kubernetes","archived":false,"fork":false,"pushed_at":"2024-04-21T13:57:01.000Z","size":6634,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-30T15:03:57.602Z","etag":null,"topics":["devops","infrastructure","kubernetes"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devkyt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-03-24T11:50:48.000Z","updated_at":"2024-04-23T15:28:20.000Z","dependencies_parsed_at":"2024-04-21T16:42:17.473Z","dependency_job_id":"173f6c2c-cfb4-4361-b85c-a4f83f3e20ed","html_url":"https://github.com/devkyt/k8s-cookbook","commit_stats":null,"previous_names":["devkyt/k8s-cookbook"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkyt%2Fk8s-cookbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkyt%2Fk8s-cookbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkyt%2Fk8s-cookbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devkyt%2Fk8s-cookbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devkyt","download_url":"https://codeload.github.com/devkyt/k8s-cookbook/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251679183,"owners_count":21626468,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["devops","infrastructure","kubernetes"],"created_at":"2024-11-19T17:06:29.517Z","updated_at":"2025-04-30T09:49:55.938Z","avatar_url":"https://github.com/devkyt.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- \u003cstyle\u003e\n.hover_img a span { position: absolute; display: none; z-index: 99; }\n.hover_img a:hover span { display: block; left: 25%; }\n\n.hover_gif a span { position: absolute; display: none; z-index: 99; }\n.hover_gif a:hover span { display: block; left: 5%; }\n\u003c/style\u003e --\u003e\n\n\u003cp\u003e\n  \u003cimg src=\"img/kuber-black.png#gh-dark-mode-only\" alt=\"image\" height=\"100\" style=\"margin-bottom: 15px\"/\u003e\n  \u003cimg src=\"img/kuber-white.png#gh-light-mode-only\" alt=\"image\" height=\"100\" style=\"margin-bottom: 15px\"/\u003e\n\u003c/p\u003e\n\n\n# Annotation \u003c!-- omit in toc --\u003e\nLet me be honest from the start, this repo is a collection of Kubernetes recipes and quick solutions to issues which I face daily in my job. \nYou don't find here any explanations how things work under the hood. If you need one of those better read some book, watch the video\nor refer to the official documentation. Fortunately, nowdays we have a real lot info about Kuber so whenever you want to\nyou always have an opportunity to go [deeper](./img/mike.png).\n\u003c!-- \u003cspan class=\"hover_img\"\u003e\n  \u003ca href=\"#\"\u003e\n    deeper.\n    \u003cspan\u003e\n      \u003cimg src=\"img/mike.png\" alt=\"mike\" height=\"100\"/\u003e\n    \u003c/span\u003e\n  \u003c/a\u003e\n\u003c/span\u003e --\u003e\n\n\nBut if you are trying to figure out how to do something in no time or just decide to get your hands dirty, you are welcome. Hope, \nyou will find what you seek in here. From my side, I commit to update this repo with new info and new recipes during my career. \n\n\n[Have fun!](./img/party.gif)\n\u003c!-- \u003cspan class=\"hover_gif\"\u003e\n  \u003ca href=\"#\"\u003e\n    Have fun!\n    \u003cspan\u003e\n      \u003cimg src=\"img/party.gif\" alt=\"party\" height=\"100\"/\u003e\n    \u003c/span\u003e\n  \u003c/a\u003e\n\u003c/span\u003e --\u003e\n\n\n\n## Table of Contents \u003c!-- omit in toc --\u003e\n- [Notes](#notes)\n- [Basic Commands](#basic-commands)\n  - [Switch to another access context](#switch-to-another-access-context)\n  - [List available pods](#list-available-pods)\n  - [Get pod logs](#get-pod-logs)\n  - [Delete pod](#delete-pod)\n  - [Map localhost port to app port](#map-localhost-port-to-app-port)\n  - [Copy data between pod and localhost](#copy-data-between-pod-and-localhost)\n  - [Execute shell command in the pod container](#execute-shell-command-in-the-pod-container)\n  - [List all available types of Kubernetes resources](#list-all-available-type-of-kubernetes-resources)\n  - [Get documentation for resource](#get-documentation-for-resource)\n  - [List all resources of a specific type that exist in a cluster](#list-all-resources-of-specific-type-that-exist-in-a-cluster)\n  - [Describe Kubernetes resource](#describe-kubernetes-resource)\n  - [Get manifest for Kubernetes resource](#get-manifest-for-kubernetes-resource)\n  - [Change resource definition](#change-resource-definition)\n  - [Scale Deployment/StatefulSet](#scale-deploymentstatefulset)\n  - [Get all available endpoints](#get-all-available-endpoints)\n- [Nodes](#nodes)\n  - [Get node IP address](#get-node-ip-address)\n  - [Add label to node](#add-label-to-node)\n  - [Remove label from node](#remove-label-from-node)\n  - [Add taints to node](#add-taints-to-node)\n  - [Remove taints from node](#remove-taints-from-node)\n  - [Get node's available resources](#get-nodes-available-resources)\n  - [Get node's conditions](#get-nodes-conditions)\n  - [Get node's system info](#get-nodes-system-info)\n- [Pods](#pods)\n  - [Create pod](#create-pod)\n  - [Get pod IP address](#get-pod-ip-address)\n  - [Delete all pods with specific status](#delete-all-pods-with-specific-status)\n  - [Count all pods in the cluster](#count-all-pods-in-the-cluster)\n  - [Schedule pod on specific node](#schedule-pod-on-specific-node)\n  - [Run pod on the same node as another pod](#run-pod-on-the-same-node-as-another-pod)\n  - [Force pod to ignore node taints](#force-pod-to-ignore-node-taints)\n  - [Pass pod metadata to container as environment variables](#pass-pod-metadata-to-container-as-environment-variables)\n  - [Pas container resource info to container as environment variables](#pas-container-resource-info-to-container-as-environment-variables)\n- [Volumes](#volumes)\n  - [Use ephemeral volume](#use-ephemeral-volume)\n  - [Mount pod metadata as volume](#mount-pod-metadata-as-volume)\n  - [Mount container resource info as volume](#mount-container-resource-info-as-volume)\n  - [Attach persistent volume to pod](#attach-persistent-volume-to-pod)\n- [ConfigMaps \\\u0026 Secrets](#configmaps--secrets)\n  - [Create ConfigMap](#create-configmap)\n  - [Mount ConfigMap as volume](#mount-configmap-as-volume)\n  - [Pass data from ConfigMap as environment](#pass-data-from-configmap-as-environment)\n  - [Make ConfigMap immutable](#make-configmap-immutable)\n- [Expose application to network traffic](#expose-application-to-network-traffic)\n  - [Create ClusterIP service](#create-clusterip-service)\n  - [Create NodePort service](#create-nodeport-service)\n  - [Create headless service](#create-headless-service)\n- [Jobs](#jobs)\n  - [Run some job once](#run-some-job-once)\n  - [Get logs of a job](#get-logs-of-a-job)\n  - [Run job regularly](#run-job-regularly)\n- [RBAC](#rbac)\n  - [Create Role](#create-role)\n  - [Get existing ServiceAccounts](#get-existing-serviceaccounts)\n  - [Create ServiceAccount](#create-serviceaccount)\n  - [Bind ServiceAccount to Role](#bind-serviceaccount-to-role)\n  - [Combine few ClusterRoles in one](#combine-few-clusterroles-in-one)\n  - [Check if service acc has permission to do some action](#check-if-service-acc-has-permission-to-do-some-action)\n- [Security](#security)\n  - [Prevent container to run with root user](#prevent-container-to-run-with-root-user)\n  - [Reduce container capabilities](#reduce-container-capabilities)\n  - [Make container root filesystem immutable](#make-container-root-filesystem-immutable)\n- [Network Traffic Rules](#network-traffic-rules)\n  - [Forbid all ingress traffic to an app](#forbid-all-ingress-traffic-to-an-app)\n  - [Restrict ingress traffic to the app](#restrict-ingress-traffic-to-the-app)\n  - [Deny all egress traffic from the app (except to kube-system for dns resolution)](#deny-all-egress-traffic-from-the-app-except-to-kube-system-for-dns-resolution)\n  - [Allow egress traffic only inside a cluster](#allow-egress-traffic-only-inside-a-cluster)\n  - [Forbid egress traffic to specific IP's](#forbid-egress-traffic-to-specific-ips)\n- [Resources \\\u0026 Quotas](#resources--quotas)\n  - [Configure default memory usage per container in the namespace](#configure-default-memory-usage-per-container-in-the-namespace)\n  - [Configure limit for the requested storage](#configure-limit-for-the-requested-storage)\n  - [Configure resource limits for the whole namespace](#configure-resource-limits-for-whole-namespace)\n  - [Configure how many objects of certain type can be created](#configure-how-many-objects-of-certains-type-can-be-created)\n- [Workflows](#workflows)\n- [Helm](#helm)\n- [Learning Resources](#learning-resources)\n  - [Books](#books)\n  - [Articles](#articles)\n    - [Resource Usage](#resource-usage)\n    - [Scheduling](#scheduling)\n    - [App expose](#app-expose)\n    - [Aviability](#aviability)\n    - [Pods](#pods-1)\n    - [Containers](#containers)\n    - [Security](#security-1)\n  - [Videos](#videos)\n  - [Repos](#repos)\n\n## Notes\n- Almost all ```kubectl``` commands listed below can be used without namespace flag ```-n```. In this case they will be executed in the default namespace.\n- To deploy resource from YAML manifest use ```kubectl apply -f path/to/manifest``` command.\n- Obviously, this repo can't cover everything but as I said I'll try to keep it up to life. So more materials will be added in the future.\n- Feel free to write me if you face some issues with examples or if you just disagree about something.\n\n\n## Basic Commands\n### Switch to another access context\nGet available access contexts:\n```sh\nkubectl config get-contexts\n```\n\nSwitch to another context:\n```sh\nkubectl config use-context \u003ccontext-name\u003e\n\n# example\nkubectl config use-context docker-desktop\n```\n\n### List available pods\nAll pods:\n```sh\nkubectl get pods -A\n```\n\nPods in specific namespace:\n```sh\nkubectl get pods \nkubectl get pods -n \u003cnamespace\u003e\n\n# example\nkubectl get pods -n events\n```\n\nPods matching a selector:\n```sh\nkubectl get pods -l \u003ckey\u003e=\u003cvalue\u003e \n\n# example\nkubectl get pods -l app=rabbitmq\n```\n\nPods with additional info:\n```sh\nkubectl get pods -o wide\n```\n\n### Get pod logs\nBy pods name:\n```sh\nkubectl logs \u003cpod-name\u003e\n\n# example\nkubectl logs rabbitmq-0\n```\n\nUsing selector:\n```sh\nkubectl logs -l \u003ckey\u003e=\u003cvalue\u003e\n\n# example\nkubectl logs -l app=rabbitmq\n```\n\n### Delete pod \nDelete gently by name:\n```sh\nkubectl delete pod \u003cpod-name\u003e\n\n# example\nkubectl delete pod event-collector-b7bc87c75-sw2gk\n```\n\nDelete gently by selector (all pods matching selector will be deleted): \n```sh\nkubectl delete pod -l \u003ckey\u003e=\u003cvalue\u003e\n\n# example\nkubectl delete pod -l app=event-collector\n```\n\nDelete immediatly:\n```sh\nkubectl delete pod \u003cpod-name\u003e --grace-period=0 --force\n\n# example\nkubectl delete pod event-collector-b7bc87c75-sw2gk --grace-period=0 --force\n```\n\n### Map localhost port to app port\nConnect directly to pod's port:\n```sh\nkubectl port-forward \u003cpod-name\u003e \u003clocalhost-port\u003e:\u003cremote-port\u003e\n\n# example\nkubectl port-forward event-collector-b7bc87c75-sw2gk 8000:5672\n```\n\nConnect via Service:\n```sh\nkubectl port-forward service/\u003cservice-name\u003e \u003clocalhost-port\u003e:\u003cservice-port\u003e\n\n# example\nkubectl port-forward service/event-collector 8000:5672\nkubectl port-forward service/event-collector 8000:metrics\n```\n\nConnect via Deployment:\n```sh\nkubectl port-forward deployment/\u003cdeployment-name\u003e \u003clocalhost-port\u003e:\u003cremote-port\u003e\n\n# example\nkubectl port-forward deployment/event-collector 8000:5672\n```\n\n### Copy data between pod and localhost \nCopy from localhost to pod:\n```sh\nkubectl cp /local/path \u003cnamespace\u003e/\u003cpod\u003e:/remote/path  \nkubectl cp /local/path \u003cnamespace\u003e/\u003cpod\u003e:/remote/path  -c \u003ccontainer-name\u003e\n\n# example\nkubectl cp config.json default/web/:app/src/\n```\n\nCopy from pod to localhost:\n```sh\nkubectl cp \u003cnamespace\u003e/\u003cpod\u003e:remote/path /local/path\n\n# example\nkubectl cp default/web:app/assets/css/  ./css/\n```\n\n### Execute shell command in the pod container\nSingle command:\n```sh\nkubectl exec \u003cpod\u003e  -- \u003ccommand\u003e\n\n# example\nkubectl exec -it busybox -- ls -a\n```\n\nGet into the container's shell:\n```sh\nkubectl exec -it \u003cpod\u003e -- sh\nkubectl exec -it \u003cpod\u003e -c \u003ccontainer\u003e -- sh\n\n# example\nkubectl exec -it busybox -- sh\nkubectl exec -it web -c nginx -- sh\n```\n\n### List all available types of Kubernetes resources\n```sh\nkubectl api-resources\n```\n\n### Get documentation for resource \nFor resources in common:\n```sh\nkubectl explain \u003cresource\u003e\n\n# example\nkubectl explain service\n```\n\nExplain specific field in resource definition:\n```sh\nkubectl explain \u003cresource\u003e.\u003cfield\u003e.\u003cnested-field\u003e\n\n# example\nkubectl explain service.spec.ports\n```\n\n### List all resources of specific type that exist in a cluster\n```sh\nkubect get \u003cresource-type\u003e -n \u003cnamespace\u003e\n\n# example\nkubectl get services \nkubectl get services -n eventes\n```\n\n### Describe Kubernetes resource\n```sh\nkubect decribe \u003cresource-type\u003e \u003cresource-name\u003e -n \u003cnamespace\u003e\n\n# example\nkubectl describe service kube-dns -n kube-system\n```\n\n### Get manifest for Kubernetes resource\nIn YAML:\n```sh\nkubectl get \u003cresource-type\u003e \u003cresource-name\u003e -n \u003cnamespace\u003e -o yaml\n\n# example\nkubectl get service kube-dns -n kube-system -o yaml\n```\n\nIn JSON:\n```sh\nkubectl get \u003cresource-type\u003e \u003cresource-name\u003e -n \u003cnamespace\u003e -o json\n\n# example\nkubectl get service kube-dns -n kube-system -o json\n```\n\n### Change resource definition \n```sh\nkubectl patch \u003cresource-type\u003e \u003cresource-name\u003e -p \u003cnew-data\u003e'{\"spec\":{\"containers\":[{\"name\":\"kubernetes-serve-hostname\",\"image\":\"new image\"}]}}'\n\n# example \nkubectl patch pod api-proxy -p '{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginx:stable-alpine\"}]}}'\n```\n\n### Scale Deployment/StatefulSet \n```sh\nkubectl scale \u003cdeploy/sts\u003e/\u003cresource-name\u003e --replicas=\u003cnumber\u003e\n\n# example\nkubectl scale deploy/event-service --replicas=0\nkubectl scale sts/datanode --replicas=4\n```\n\n\n### Get all available endpoints\n```sh\nkubectl get endpoints -A\n```\n\n\n## Nodes\n### Get node IP address\n```sh\nkubectl get node \u003cnode-name\u003e -o jsonpath=\"{.status.addresses[?(@.type == 'ExternalIP')].address}\"\nkubectl get node \u003cnode-name\u003e -o jsonpath=\"{.status.addresses[?(@.type == 'InternalIP')].address}\"\n```\n\n### Add label to node\n```sh\nkubectl label nodes \u003cnode-name\u003e \u003clabel\u003e=\u003cvalue\u003e\n```\n\n### Remove label from node\nFrom single node:\n```sh\nkubectl label nodes \u003cnode-name\u003e \u003clabel\u003e- \n```\n\nFrom all nodes:\n```sh\nkubectl label nodes --all \u003clabel\u003e-\n```\n\n### Add taints to node\n```sh\nkubectl taint nodes \u003cnode-name\u003e key=value:NoSchedule\n```\n\n### Remove taints from node\n```sh\nkubectl taint nodes \u003cnode-name\u003e key=value:NoSchedule-\n```\n\n### Get node's available resources\n```sh\nkubectl describe nodes \u003cnode-name\u003e | grep -i \"Capacity:\\|Allocatable:\" -A 6\n\n# example\nkubectl describe nodes gke-staging-de795cfc-mtfr | grep -i \"Capacity:\\|Allocatable:\" -A 6\n```\n\n### Get node's conditions\n```sh\nkubectl describe nodes \u003cnode-name\u003e | grep -i \"Conditions:\" -A 15\n\n# example\nkubectl describe nodes gke-staging-reports-de795cfc-mtfr | grep -i \"Conditions:\" -A 15\n```\n\n### Get node's system info\n```sh\nkubectl describe nodes \u003cnode-name\u003e | grep -i \"System Info:\" -A 10\n\n# example\nkubectl describe nodes gke-staging-reports-de795cfc-mtfr | grep -i \"System Info:\" -A 10\n```\n\n## Pods\n### Create pod \nUsing CLI:\n```sh\nkubectl run --image=\u003cimage\u003e \u003cpod-name\u003e --labels=\"key1=value1,key2=value2\" -- \u003ccommand-to-execute\u003e\n\n# example\nkubectl run --image=busybox:latest busybox --labels=\"env=prod,app=busy\" -- sleep 3600\n```\n\nFrom YAML:\n```yaml\napiVersion: v1 \nkind: Pod \nmetadata:\n  name: busybox\n  labels:\n    env: prod\n    app: busy\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    args:\n    - /bin/sh\n    - -c\n    - sleep 3600\n  restartPolicy: Never\n``` \n\n### Get pod IP address\n```sh\nkubectl get pod \u003cpod-name\u003e -o jsonpath=\"{.status.podIP}\"\n\n# example\nkubectl get pods busybox -o jsonpath=\"{.status.podIP}\"\n```\n\n### Delete all pods with specific status\n```sh\nkubectl delete pods --field-selector status.phase=\u003cstatus:Pending,Failed,Unknown,Running,Succeeded\u003e\n\n# exmaple\nkubectl delete pods --field-selector status.phase=Failed\n```\n\n### Count all pods in the cluster\n```sh\nkubectl get pods --field-selector=status.phase!=Succeeded,status.phase!=Failed --output json | jq -j '.items | length'\n```\n\n### Schedule pod on specific node\nVia nodeSelector:\n```yaml\nspec:\n  nodeSelector:\n    nodeLabel: value\n```\n\nVia nodeAffinity:\n```yaml\nspec:\n  affinity:\n    nodeAffinity:\n      requiredDuringSchedulingIgnoredDuringExecution: #hard requirement\n        nodeSelectorTerms: \n        - matchExpressions: \n          - key: NumberOfCores\n            operator: Gt\n            values: [ \"3\" ]\n      preferredDuringSchedulingIgnoredDuringExecution: #soft requirement \n      - weight: 1\n        preference:\n          matchField:\n          - key: metadata.name\n            operator: In\n            values: [ \"temporary-node\" ]\n```\n\n### Run pod on the same node as another pod\n```yaml\nspec:\n  affinity:\n    podeAffinity:\n      requiredDuringSchedulingIgnoredDuringExecution:\n        labelSelector:\n        - matchExpression:\n          - key: destination\n            operator: In\n            values: [ \"data\", \"ml\" ]\n```\n\n### Force pod to ignore node taints\n```yaml\nspec:\n  tolerations:\n  - key: \"key\"\n    operator: \"Exists\"\n    effect: \"NoSchedule\"\n---\nspec:\n  tolerations:\n  - key: \"key\"\n    operator: \"Equal\"\n    value: \"value\"\n    effect: \"NoSchedule\"\n```\n\n### Pass pod metadata to container as environment variables\n```yaml\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    env:\n    - name: NODE_NAME\n      valueFrom:\n        fieldRef:\n          fieldPath: spec.nodeName\n    - name: NAMESPACE\n      valueFrom:\n        fieldRef:\n          fieldPath: metadata.namespace\n    - name: IP\n      valueFrom:\n        fieldRef: \n          fieldpath: status.podIP     \n```\n\n### Pas container resource info to container as environment variables\n```yaml\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    env:\n    - name: MEMORY_LIMIT\n      valueFrom:\n        resourceFieldRef:\n          containerName: busybox\n          resource: limits.memory  \n    - name: CPU_REQUEST\n      valueFrom:\n        resourceFieldRef:\n          containerName: busybox\n          resource: requests.cpu    \n```\n\n\n## Volumes\n### Use ephemeral volume\n```yaml\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    volumeMounts:\n    - mountPath: /app/cache\n      name: local\n  volumes:\n  - name: local\n    emptyDir:\n      sizeLimit: 1Gi\n```\n\n### Mount pod metadata as volume\n```yaml\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    args: |\n      cat labels\n      cat annotations\n    volumeMounts:\n    - name: pod-meta\n  volumes:\n  - name: pod-meta\n    downardAPI:\n      items:\n      - path: labels\n        fieldRef:\n          fieldPath: metadata.labels\n      - path: annotations\n        fieldRef:\n          fieldPath: metadata.annotations\n```\n\n### Mount container resource info as volume\n```yaml\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    args: |\n      cat limits\n      cat requests\n    volumeMounts: container-info\n  volumes:\n  - name: container-info:\n    downardAPI:\n      items:\n        - path: limits\n          resourceFieldRef: \n            containerName: busybos\n            resource: limits\n        - path: requests\n          resourceFieldRef: \n            containerName: busybos\n            resource: requests\n```\n\n### Attach persistent volume to pod\nGet available storage classes:\n```sh\nkubectl get storageclass\n```\n\nCreate Persisten Volume Claim:\n```yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: random-log\nspec:\n  accessModes:\n    - ReadWriteOnce\n  storageClassName: standard\n  resources:\n    requests:\n      storage: 50Gi\n```\n\nAttach Persisten Volume Claim as a volume:\n```yaml\napiVersion: v1 \nkind: Pod \nmetadata:\n  name: busybox\n  labels:\n    env: prod\n    app: busy\nspec:\n  containers:\n  - name: busybox\n    image: busybox:latest\n    args:\n    - /bin/sh\n    - -c\n    - sleep 3600\n    volumeMounts:\n    - name: log-volume\n      mountPath: \"/logs\"\n  restartPolicy: Never\n  volumes:\n  - name: log-volume \n    persistentVolumeClaim:\n      claimName: random-log\n```\n\n## ConfigMaps \u0026 Secrets\n\n### Create ConfigMap \nUsing CLI and manual entered data:\n```sh\nkubectl create configmap \u003cconfigmap-name\u003e --from-literal=key1=value1 --from-literal=key2=value2\n\n# example\nkubectl create configmap db-config --from-literal=service=postgres --from-literal=port=5432\n```\n\nUsing CLI and the whole content of a file as a value for a key:\n```sh\nkubectl create configmap \u003cconfigmap-name\u003e --from-file=key1=/path/to/some --from-file=key2=/path/to/another\n\n# example\nkubectl create configmap monitoring-config --from-file=metrics=/user/config.xml \n```\n\nUsing ClI and key=value pairs in file as a source data:\n```sh\nkubectl create configmap \u003cconfigmap-name\u003e --from-file=path/to/some\n\n# exmaple\nkubectl create configmap db-config --from-file=db/props\n```\n\nFrom YAML:\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: db-config\ndata:\n  service: \"postgres\"\n  port: \"5432\"\n  migration.properties: |\n    user=mike\n    source.env=dev\n    target.env=staging\n```\n\n### Mount ConfigMap as volume\nAdd all the data from a ConfigMap to a volume:\n```yaml\nspec:\n  containers:\n    - name: busybox\n      image: busybox:latest\n      command: [ \"/bin/sh\", \"-c\", \"ls /etc/config/\" ]\n      volumeMounts:\n      - name: config\n        mountPath: /etc/config\n  volumes:\n    - name: config\n      configMap:\n        name: config-map-name\n```\n\nAdd data by key and make it available on specific path:\n```yaml\nspec:\n  containers:\n    - name: busybox\n      image: busybox:latest\n      command: [ \"/bin/sh\",\"-c\",\"cat /etc/config/keys\" ]\n      volumeMounts:\n      - name: config\n        mountPath: /etc/config\n  volumes:\n    - name: config\n      configMap:\n        name: config-map-name\n        items:\n        - key: key\n          path: keys\n```\n\n### Pass data from ConfigMap as environment\nSpecify a key from ConfigMap which value will be used as env variable:\n```yaml\nspec:\n  containers:\n    - name: busybox\n      image: busybox:latest\n      command: [ \"/bin/sh\", \"-c\", \"env\" ]\n      env:\n        - name: ENV_FROM_CONFIGMAP\n          valueFrom:\n            configMapKeyRef:\n              name: config-map-name\n              key: some-key\n```\n\nRead all ConfigMap's key-value pairs as env variables:\n```yaml\nspec:\n  containers:\n    - name: busybox\n      image: busybox:latest\n      command: [ \"/bin/sh\", \"-c\", \"env\" ]\n      envFrom:\n      - configMapRef:\n          name: config-map-name\n```\n\n### Make ConfigMap immutable\nObviously you can't change configmap after creation:\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: hero-config\ndata:\n  user: Invincible\n  strength: 500\nimmutable: true\n```\n\n## Expose application to network traffic \n\n### Create ClusterIP service\nUsing CLI\n```sh\nkubectl expose pod \u003cpod-name\u003e --port=\u003csvc-port-number\u003e --taget-port=\u003ctarget-port-number\u003e --name=\u003csvc-name\u003e\nkubectl expose deployment \u003cdeploy-name\u003e --port=\u003csvc-port-number\u003e --taget-port=\u003ctarget-port-number\u003e --name=\u003csvc-name\u003e\n\n# example\nkubectl expose pod nginx --port=80 --taget-port=80 --name=api-proxy\nkubectl expose deployment api-proxy --port=80 --taget-port=80 --name=api-proxy\n```\n\nFrom YAML:\n```yaml\napiVersion: v1\nkind: Service\nmetadata:  \n  name: api-proxy\nspec:\n  selector:    \n    app: nginx\n  type: ClusterIP\n  ports:  \n  - name: http\n    port: 80\n    targetPort: 80\n    protocol: TCP\n```\n\n### Create NodePort service \n```yaml\napiVersion: v1\nkind: Service\nmetadata:  \n  name: api-proxy\nspec:\n  selector:    \n    app: nginx\n  type: NodePort\n  ports:  \n  - name: http\n    port: 80\n    targetPort: 80\n    nodePort: 30036\n    protocol: TCP\n```\n\n### Create headless service \n```yaml\napiVersion: v1\nkind: Service\nmetadata:  \n  name: kafka\nspec:\n  selector:    \n    app: kafka\n  type: ClusterIP\n  clusterIP: None\n  ports:  \n  - name: http\n    port: 9092\n    targetPort: 9092\n    protocol: TCP\n```\n\n## Jobs\n### Run some job once\n```yaml\napiVersion: batch/v1\nkind: Job\nmetadata:\n  name: migrate-job\nspec:\n  template:\n    spec:\n      containers:\n      - name: migration\n        image: eu.gcr.io/org/backend:stable\n        command: [\"bash\", \"-c\", \"python manage.py migrate --fake-initial\"]\n        env:\n          - name: DATABASE_URL\n            valueFrom:\n              secretKeyRef:\n                key: DATABASE_URL\n                name: backend-env\n      restartPolicy: Never\n  backoffLimit: 2\n```\n\n### Get logs of a job\n```sh\nkubectl logs \u003cjob-pod-name\u003e\nkubectl logs jobs/\u003cjob-name\u003e\n\n# example\nkubectl logs migrate-job-7f6cc7cdc8-rqldg\nkubectl logs jobs/migrate-job\n```\n\n### Run job regularly\n```yaml\napiVersion: batch/v1\nkind: CronJob\nmetadata:\n  name: duck\nspec:\n  schedule: \"*/30 * * * *\"\n  jobTemplate:\n    spec:\n      template:\n        spec:\n          containers:\n          - name: duck-says\n            image: busybox:stable\n            imagePullPolicy: IfNotPresent\n            command:\n            - /bin/sh\n            - -c\n            - echo \"Kuber quack-quack-quack\"\n          restartPolicy: OnFailure\n```\n\n## RBAC\n\n### Create Role \nCreate role which control resource access within one namespace:\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: spy\n  namespace: default\nrules:\n- apiGroups: [\"\"]\n  resources: [\"secrets\"]\n  verbs: [\"get\", \"watch\", \"list\"]\n```\n\nCreate role which control resource access within whole cluster:\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: spy\nrules:\n- apiGroups: [\"\"]\n  resources: [\"secrets\"]\n  verbs: [\"get\", \"watch\", \"list\"]\n```\n\n### Get existing ServiceAccounts\n```sh\nkubectl get serviceaccounts -n \u003cnamespace\u003e\n\n# example\nkubectl get serviceaccounts -n events\n```\n\n### Create ServiceAccount \nUsing CLI:\n```sh\nkubectl create serviceaccount \u003cservice_acc_name\u003e -n \u003cnamespace\u003e\n\n# example \nkubectl create serviceaccount spy\nkubectl create serviceaccount spy -n events \n```\n\nFrom YAML:\n```yaml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: spy\n  namespace: default\n```\n\n### Bind ServiceAccount to Role \nCreate binding for the role in specific namespace:\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: secret-reader\n  namespace: default\nsubjects:\n- kind: ServiceAccount\n  name: spy\n  apiGroup: rbac.authorization.k8s.io\nroleRef:\n  kind: Role\n  name: spy\n  apiGroup: rbac.authorization.k8s.io\n```\n\nCreate binding for the cluster-wide role:\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  name: secret-reader\nsubjects:\n- kind: ServiceAccount\n  name: spy\n  apiGroup: rbac.authorization.k8s.io\nroleRef:\n  kind: Role\n  name: spy\n  apiGroup: rbac.authorization.k8s.io\n```\n\n**Notes**: Role Binding can reference a Cluster Role as well. If it so all permissions from Cluster Role work only for resources in namespace of Role Binding\n\n### Combine few ClusterRoles in one\nYou can combine few Cluster Roles into the one. To do this add a labels for Cluster Roles which permissions you want to aggregate and then create new role with aggreagtionRule option. Just likes this:\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: admin\naggregationRule:\n  clusterRoleSelectors:\n  - matchLabels:\n      aggregate-to-admin: \"true\"\nrules: [] # rules list must be empty. It will be filled from Cluster Roles that match the label\n```\n\n### Check if service acc has permission to do some action\n```sh\nkubectl auth can-i \u003cverb\u003e \u003cresource\u003e --as=system:serviceaccount:\u003cnamespace\u003e:\u003cservice_acc_name\u003e\n\n# example\nkubectl auth can-i create pod --as=system:serviceaccount:default:watchdog\n```\n\n## Security\n### Prevent container to run with root user\nEnsure that container doesn't start up with root user in charge:\n```yaml\nkind: Pod\nmetadata:\n  name: web \nspec:\n  securityContext: \n    runAsNonRoot: true \n  containers: \n  - name: web\n    image: nginx:stable-alpine\n```\n\nExplicitly define which user and group to use in the container:\n```yaml\nkind: Pod\nmetadata:\n  name: web \nspec:\n  securityContext: \n    runAsUser: 1000 \n    runAsGroup: 2000\n  containers: \n  - name: web\n    image: nginx:stable-alpine\n```\n\n**Note**: you can define ```securityContext``` both at the pod level and at the container level. In the first case it will be applied\nto all containers in the pod if they don't have their own ```securityContext```.\n\n### Reduce container capabilities \n```yaml\nkind: Pod\nmetadata:\n  name: web \nspec:\n  containers: \n  - name: web\n    image: nginx:stable-alpine\n    securityContext:\n      capabilities:\n        drop: [ 'ALL' ]\n        add: ['NET_BIND_SERVICE']\n```\n\n### Make container root filesystem immutable \n```yaml\nkind: Pod\nmetadata:\n  name: backend \nspec:\n  containers: \n  - name: web\n    image: eu.gcr.io/org/backend:stable\n    securityContext:\n      readOnlyRootFilesystem: true\n```\n\n## Network Traffic Rules \n### Forbid all ingress traffic to an app\n```yaml\nkind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  name: web-deny-all\nspec:\n  podSelector:\n    matchLabels:\n      app: web\n  ingress: []\n```\n\n### Restrict ingress traffic to the app\n```yaml\nkind: NetworkPolicy\napiVersion: networking.k8s.io/v1\nmetadata:\n  name: db-allow\nspec:\n  podSelector:\n    matchLabels: # to pods\n      app: gameshop \n      id: db\n  ingress:\n  - from:\n      - podSelector:\n          matchLabels: # from pods\n            app: gameshop\n            id: backend\n\n```\n\n\n### Deny all egress traffic from the app (except to kube-system for dns resolution)\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: deny-egress\nspec:\n  podSelector:\n    matchLabels:\n      app: db\n  policyTypes:\n  - Egress\n  egress:\n  - to:\n    - namespaceSelector:\n        matchLabels:\n          kubernetes.io/metadata.name: kube-system\n      podSelector:\n        matchLabels:\n          k8s-app: kube-dns\n    ports:\n      - port: 53\n        protocol: UDP\n      - port: 53\n        protocol: TCP\n```\n\n### Allow egress traffic only inside a cluster\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: egress-within-cluster\nspec:\n  policyTypes:\n  - Egress\n  podSelector:\n    matchLabels:\n      app: events\n  egress: []\n```\n\n### Forbid egress traffic to specific IP's\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: test-network-policy\n  namespace: default\nspec:\n  podSelector:\n    matchLabels:\n      role: db\n  policyTypes:\n  - Egress\n  egress:\n  - to:\n    - ipBlock:\n        cidr: 0.0.0.0/0\n        except:\n          - 172.17.0.0/16\n          - 172.23.42.0/24\n\n```\n\n## Resources \u0026 Quotas\n\n### Configure default memory usage per container in the namespace\nDefine just default values:\n```yaml\napiVersion: v1\nkind: LimitRange\nmetadata:\n  name: memory-limit\n  namespace: namespace\nspec:\n  limits:\n  - type: Container\n    default:\n      memory: 512Mi\n    defaultRequest:\n      memory: 256Mi \n```\n\nDefine default, min and max values:\n```yaml\napiVersion: v1\nkind: LimitRange\nmetadata:\n  name: memory-limit\n  namespace: namespace\nspec:\n  limits:\n  - type: Container\n    default:\n      memory: 512Mi\n    defaultRequest:\n      memory: 256Mi\n    min:\n      memory: 100Mi\n    max:\n      memory: 1028Mi\n```\n\n### Configure limit for the requested storage\n```yaml\napiVersion: v1\nkind: LimitRange\nmetadata:\n  name: storage-limit\n  namespace: namespace\nspec:\n  limits:\n  - type: PersistentVolumeClaim\n    max:\n      storage: 20Gi\n    min:\n      storage: 10Gi\n```\n\n### Configure resource limits for whole namespace\n```yaml\napiVersion: v1\nkind: ResourceQuota\nmetadata:\n  name: namespace-resource-limit\n  namespace: namespace\nspec:\n  hard:\n    requests.cpu: \"10\"\n    requests.memory: 10Gi\n    limits.cpu: \"20\"\n    limits.memory: 20Gi\n```\n\n### Configure how many objects of certains type can be created\nVia CLI:\n```sh\nkubectl create quota \u003cquota-name\u003e --hard=pods=300,limits.memory=300Gi --namespace=\u003cnamespace\u003e\n```\n\nIn YAML:\n```yaml\napiVersion: v1\nkind: ResourceQuota\nmetadata:\n  name: namespace-objects-quota\n  namespace: namespace\nspec:\n  hard:\n    pods: 100\n    services: 10\n    secrets: 10\n    configmaps: 10\n    persistentvolumeclaims: 20\n    services.nodeports: 0\n    services.loadbalancers: 0\n    count/roles.rbac.authorization.k8s.io: 10\n```\n\n## Workflows\nIn progress...\n\n## Helm \nIn progress...\n\u003c!-- ### Install Helm Chart to Cluster \nFrom repo:\n```sh\n```\n\nFrom local machine:\n```sh\n```\n\n### Upgrade existing Helm Chart \n### Validate Chart  \n\n### Reusable templates  --\u003e\n\n## Learning Resources \n\n### Books\n1. [Kubernetes Patterns by Bilgin Ibryam and Roland Huss](https://amzn.eu/d/0dqK7xD)\n2. [Kubernetes Operators by Jason Dobies and Joshua Wood](https://amzn.eu/d/4JkmoeT)\n\n### Articles\n#### Resource Usage\n1. [What Everyone Should Know About Kubernetes Memory Limits](https://home.robusta.dev/blog/kubernetes-memory-limit) \n2. [For the Love of God, Stop Using CPU Limits on Kubernetes](https://home.robusta.dev/blog/stop-using-cpu-limits) \n   \n#### Scheduling\n1. [Advanced Kubernetes pod to node scheduling](https://www.cncf.io/blog/2021/07/27/advanced-kubernetes-pod-to-node-scheduling/)\n   \n#### App expose\n1. [Kubernetes NodePort vs LoadBalancer vs Ingress](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)\n\n#### Aviability\n1. [Keep your Kubernetes cluster balanced](https://itnext.io/keep-you-kubernetes-cluster-balanced-the-secret-to-high-availability-17edf60d9cb7)\n\n#### Pods\n1. [What are Kubernetes Pods Anyway?](https://www.ianlewis.org/en/what-are-kubernetes-pods-anyway)\n\n#### Containers\n1. [The Almighty Pause Container](https://www.ianlewis.org/en/almighty-pause-container)\n\n\n#### Security\n1. [10 Kubernetes Security Context settings you should understand](https://snyk.io/blog/10-kubernetes-security-context-settings-you-should-understand)\n\n### Videos\n1. [Building a Container from sratch in Go](https://youtu.be/Utf-A4rODH8?si=6jIt3xnWNlu7c7XN)\n2. [Role Based Access Control in Kubernetes](https://youtu.be/CnHTCTP8d48?si=8h68TXDmKT0ykWhd)\n3. [Init Container Examples: Learn Kubernetes Pod Spec Features](https://youtu.be/Ezz03l2JDmE?si=ZfdkameL_qhranwf)\n4. [10 Ways to Shoot Yourself in the Foot with Kubernetes](https://youtu.be/QKI-JRs2RIE?si=p0yDqPHz_Lgs4uPb)\n\n### Repos\n1. [Kubernetes Network Policy Recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes)\n  \n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevkyt%2Fk8s-cookbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevkyt%2Fk8s-cookbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevkyt%2Fk8s-cookbook/lists"}