{"id":22941270,"url":"https://github.com/thejaxon/cka","last_synced_at":"2025-08-12T21:31:47.649Z","repository":{"id":130963037,"uuid":"291824544","full_name":"theJaxon/CKA","owner":"theJaxon","description":"Preparation for the Certified Kubernetes Administrator exam [CKA v1.29]","archived":false,"fork":false,"pushed_at":"2024-02-08T10:18:10.000Z","size":360,"stargazers_count":47,"open_issues_count":0,"forks_count":28,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-02-08T11:28:17.088Z","etag":null,"topics":["certified-kubernetes-administrator","cka","cncf","container-orchestration","kubernetes","linuxfoundation"],"latest_commit_sha":null,"homepage":"","language":null,"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/theJaxon.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}},"created_at":"2020-08-31T21:05:28.000Z","updated_at":"2024-02-08T10:15:47.000Z","dependencies_parsed_at":"2023-03-31T16:22:42.298Z","dependency_job_id":null,"html_url":"https://github.com/theJaxon/CKA","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theJaxon%2FCKA","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theJaxon%2FCKA/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theJaxon%2FCKA/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theJaxon%2FCKA/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theJaxon","download_url":"https://codeload.github.com/theJaxon/CKA/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229709197,"owners_count":18111384,"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":["certified-kubernetes-administrator","cka","cncf","container-orchestration","kubernetes","linuxfoundation"],"created_at":"2024-12-14T13:38:27.547Z","updated_at":"2024-12-14T13:38:28.048Z","avatar_url":"https://github.com/theJaxon.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# CKA\n![CKA](https://img.shields.io/badge/-CKA-0690FA?style=for-the-badge\u0026logo=kubernetes\u0026logoColor=white)\n![K8s](https://img.shields.io/badge/-kubernetes-326CE5?style=for-the-badge\u0026logo=kubernetes\u0026logoColor=white)\n\nAn environment made as a preparation for the Certified Kubernetes Administrator exam [CKA v1.29]\n\n---\n\n### :pencil: Objectives:\n\n\u003cdetails\u003e\n\u003csummary\u003e1- Cluster Architecture, Installation \u0026 Configuration 25%\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n1. Manage role based access control (RBAC)\n2. Use Kubeadm to install a basic cluster\n3. Manage a highly-available Kubernetes cluster\n4. Provision underlying infrastructure to deploy a Kubernetes cluster\n5. Perform a version upgrade on a Kubernetes cluster using Kubeadm\n6. Implement etcd backup and restore\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e2- Workloads \u0026 Scheduling 15%\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n1. Understand deployments and how to perform rolling update and rollbacks\n2. Use ConfigMaps and Secrets to configure applications\n3. Know how to scale applications\n4. Understand the primitives used to create robust, self-healing, application deployments [Probes]\n5. Understand how resource limits can affect Pod scheduling [resources for pods and quota for namespaces]\n6. Awareness of manifest management and common templating tools\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e3- Services \u0026 Networking 20%\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n1. Understand host networking configuration on the cluster nodes\n2. Understand connectivity between Pods\n3. Understand ClusterIP, NodePort, LoadBalancer service types and endpoints\n4. Know how to use Ingress controllers and Ingress resources\n5. Know how to configure and use CoreDNS\n6. Choose an appropriate container network interface plugin\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e4- Storage 10%\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n1. Understand storage classes, persistent volumes\n2. Understand volume mode, access modes and reclaim policies for volumes\n3. Understand persistent volume claims primitive\n4. Know how to configure applications with persistent storage\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e5- Troubleshooting 30%\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n1. Evaluate cluster and node logging\n2. Understand how to monitor applications\n3. Manage container stdout \u0026 stderr logs\n4. Troubleshoot application failure\n5. Troubleshoot cluster component failure\n6. Troubleshoot networking\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n---\n\n### Cluster components:\nKubernetes cluster consists of one or more master nodes + one or more worker nodes, the master node components are called `Control plane`.\n\n#### Control plane components:\n- **kube-api** server\n- **etcd** Key value store\n- **kube-scheduler** that allocates nodes for pods\n- **kube-controller-manager** and there are different types of controllers like `replication controller`, `endpoints controller`, `service account controller` and `Token controller`\n\n#### Worker nodes components:\n- **Kubelet** Ensures pods are running on the nodes\n- **kube-proxy** Maintains network rules on the nodes to keep `SVCs` working. \n\n---\n\n### [Important kubectl commands](https://blog.heptio.com/kubectl-explain-heptioprotip-ee883992a243):\n\n**--recursive** with `k explain`\n```\nk explain pod.spec.containers --recursive | less\n```\n\n```bash\nk \u003ccommand\u003e -v=\u003cnumber\u003e # For verbose output, useful for debugging\nk cluster-info \nk cluster-info dump\nk config -h\nk config view # View content of ~/.kube/config | /etc/kubernetes/admin.conf\n\nk get events # Displays events for the current ns \nk get events -n \u003cns\u003e\n# Filter out normal events so that warnings are better shown\nk get events --field-selector type!=Normal \n\n# Auto completion enable\nk completion -h \nvi ~/.bashrc\nalias k=kubectl\nsource \u003c(kubectl completion bash | sed 's/kubectl/k/g')\nexport do=\"--dry-run=client -o yaml\"\nsource ~/.bashrc\n\nvi ~/.vimrc\nset tabstop=2 shiftwidth=2 expandtab ai\n\n# if there's an issue with indentation https://stackoverflow.com/questions/426963/replace-tabs-with-spaces-in-vim\n:retab\n\nk explain deploy\n\n# Check all fields in a resource\nk explain \u003cresource\u003e --recursive # resource can be pod, deployment, ReplicaSet etc\n\nk explain deploy.spec.strategy\n\nk config -h\n\nk proxy # runs on port 8001 by default \n# use curl http://localhost:8801 -k to see a list of API groups\n\n# NOT kubectl but useful\njournalctl -u kubelet\njournalctl -u kube-apiserver\n\n# Dry run and validate\nk apply -f fileName.yml --validate --dry-run=client\n\nkubelet -h\n```\n\n---\n\n### :file_folder: Important Directories:\n```bash\n/etc/kubernetes/pki/ # Here all certs and keys are stored\n\n# ETCD certs \n/etc/kubernetes/pki/etcd\n\n/etc/cni\n\n/etc/kubernetes/manifests # Static pods definition files that are used for bootstraping kubernetes are located here\n  /etcd.yaml\n  /kube-apiserver.yaml\n  /kube-controller-manager.yaml\n  /kube-scheduler.yaml\n\n/etc/kubernetes/kubelet.conf # On Worker nodes \n\n$HOME/.kube/config # --kubeconfig file\n\n/var/lib/docker # [\"aufs\", \"containers\", \"image\", \"volumes\"]\n\n/var/lib/kubelet/config.yaml # kubelet config file that contains static pod path //usually /etc/kubernetes/manifests\n\n/var/log/pods # The output of kubectl log \u003cpod\u003e is coming from here with a different formatting\n\n/var/log/containers # docker logs are stored here \n\n/usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf\n```\n\n* API Serves on port `6443` by default\n\n![kubeconfig](https://github.com/theJaxon/CKA/blob/master/etc/kubeconfig.png)\n\n- A single kubeconfig file can have information related to multiple kubernetes clusters (different servers).\nThere are 3 core fields in the kubeconfig file:\n1. cluster field: includes details related to the URL of the cluster `server` and associated info.\n2. user field: contains info about [authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/) mechanisms for the user which can be either\n  1. user/password\n  2. certificates\n  3. tokens\n\n3. context field: groups information related to cluster, user and namespaces.\n\n* To remove any field from the kubeconfig use the unset command \n\n```bash\n# Remove context from kubeconfig \nk config unset contexts.\u003cname\u003e\n\n# Remove user from kubeconfig \nk config unset users.\u003cname\u003e\n```\n\n* While kubeconfig can be loaded from the known locations as `.kube` in home dir or $KUBECONFIG ENV var, sometimes you want to exactly know from where it gets loaded an here the -v is really helpful \n```bash\nk config view -v=10\n```\n\n#### Create a kubeconfig file: \n```bash\n# 1. Generate the base config file\nk config --kubeconfig=\u003cname\u003e set-cluster \u003ccluster-name\u003e --server=https://\u003caddress\u003e\n\n# 2. Add user details \nk config --kubeconfig=\u003cname\u003e set-credentials \u003cusername\u003e --username=\u003cusername\u003e --password=\u003cpwd\u003e\n\n# 3. set context in the kubeconfig file \nk config --kubeconfig=\u003cname\u003e set-context \u003cname\u003e --cluster=\u003ccluster-name\u003e --namespace=\u003cns\u003e --user=\u003cuser\u003e\n\n```\n---\n\n### Important Documentation page sections:\n- [Tasks](https://kubernetes.io/docs/tasks/)\n\n- [kubeadm check required ports](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#check-required-ports) \n\n- [Application Introspection and Debugging](https://kubernetes.io/docs/tasks/debug-application-cluster/debug-application-introspection/)\n\n---\n\n### :bulb: Imperative usage of kubectl command:\n```bash\n# View api-resources \nk api-resources -h\n\n# View only the namespaced api-resources\nk api-resources --namespaced=True\n\n# Add annotation to deployment\nk annotate deploy/\u003cname\u003e k=v\n\n# Create namespace \nk create ns \u003cname\u003e\n\n# Create deployment and set an env variable for it\nk create deploy \u003cname\u003e --image=\u003cname\u003e \nk set env deploy/\u003cname\u003e K=v\n\n# Create ConfigMap from env varibales and use it in a deployment\nk create cm \u003cname\u003e --from-literal=K=v --from-literal=K=v \nk set env deploy/\u003cname\u003e --from=cm/\u003cname\u003e\n\n# Those key value pairs can be stored in a .env file and also be used \nk create cm \u003cname\u003e --from-env-file=\u003cname\u003e.env\nk set env deploy/\u003cname\u003e --from=cm/\u003cname\u003e\n\n# Limit the values that will be used from a configMap using --keys option\nk set env deploy/\u003cname\u003e --from=cm/\u003cname\u003e --keys=\"key,key\" \n\n# Set resources for deployment \nk set resources -h \nk set resources deploy/\u003cname\u003e --requests=cpu=200m,memory=512Mi --limits=cpu=500m,memory=1Gi\n\n# Create HorizontalPodAutoscaler resource [HPA] for a deployment\nk autoscale deploy \u003cname\u003e --min=\u003cnumber\u003e --max=\u003cnumber\u003e --cpu-percent=\u003cnumber\u003e\nk get hpa\n\nk get all \n\n# Create a secret \nk create secret generic \u003cname\u003e --from-literal=K=v\n\n# Delete resource \nk delete \u003cresource\u003e --force --grace-period=0 \n\n# Get using labels, either --selector or -l followed by key value pairs\nk get po --selector | -l k=v # Can be done for multiple labels just separate using a comman k=v,k=v etc\n\n# Get pods with the same label across all namespaces [-A is short for --all-namespaces]\nk get po -l k=v -A\n\n# Run a pod \nk run \u003cname\u003e --image=\u003cname\u003e -o yaml --dry-run=client \u003e \u003cname\u003e.yml\nk apply -f \u003cname\u003e.yml\n\n# Define an env variable for a pod using --env\nk run \u003cname\u003e --image=\u003cname\u003e --env K=v --env K=v -o yaml --dry-run=client \n\n\n## Labelling\n# Label a node\nk label nodes \u003cnode-name\u003e k=v\n\n# Delete a lable from the node\nk label nodes \u003cnode-name\u003e k-\n\n## Rollout commands\nk rollout -h \nk rollout [history/pause/restart/resume/status/undo] deploy/\u003cname\u003e\n\n# View details of a specific revision\nk rollout history deploy/\u003cname\u003e --revision=\u003cnumber\u003e\n\n# Scale replicas of a deployment \nk scale deploy/\u003cname\u003e --replicas=\u003cnumber\u003e\n\n```\n\n---\n\n\u003cdetails\u003e\n\u003csummary\u003eCluster Maintenance\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n# Mark node as unusable \nk drain \u003cnode\u003e | k cordon \u003cnode\u003e\n\n# Remove the drain restriction\nk uncordon \u003cnode\u003e\n```\n\nCordon Vs drain:\n- Cordon doesn't terminate existing pods on the node but it prevents creation of any new pods on that node\n- Drain terminates those pods and they get allocated to a different node\n\nUpgrading a cluster:\n```bash\nkubeadm upgrade plan\nkubeadm upgrade apply\n```\n\nBackup resource configuration:\n1- Backup all resources \n```bash\nkubectl get all -Ao yaml \u003e all_resources.yml\n```\n\u003e :bell: Implement etcd backup and restore :bell:\n\n2- Use etcdctl to backup the etcd server\n```bash\nETCD_API=3 etcdctl snapshot save snapshot.db\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\n---\n\n#### User certificates:\nThere are 3 essential certs found in ~/.kube/config file (can also be viewed using `k config view`), those are:\n1. client-certificate-data # public key cert\n2. client-key-data # private key \n3. certificate-authority-data # CA public key cert\n\n#### Kubernetes user accounts [Authentication]:\n- There are no `user` objects in k8s.\n- User account is just an authorized cert + RBAC authorization\n\nThere are 5 steps involved in creating the user, the steps should result in 2 files being created, those are:\n1. private.key\n2. certificate.crt\n\nThose 2 can be used to talk to the `API-server`\n\n![add-user](https://github.com/theJaxon/CKA/blob/master/etc/add-user.png)\n\nSteps explained:\n```bash\n# 1. create a new private key \nopenssl genrsa -out \u003cname\u003e.key 2048\n\n# 2. Create a CSR and encode it \n# Search docs for authentication or User word\nopenssl req -new -key \u003cname\u003e.key -out \u003cname\u003e.csr -subj \"/CN=\u003cname\u003e\"\ncat \u003cname\u003e.csr | base64 | tr -d '\\n'\n\n# 3. Create k8s CSR object using the generated openssl csr\n# https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#create-certificatesigningrequest\nk apply -f csr.yml\nk get csr\n\n# 4. Approve k8s csr \nk certificate approve \u003cname\u003e\n\n# 5. Grab .crt content from the approved csr and decode it into a file\nk get csr \u003cname\u003e -o jsonpath='{.status.certificate}' | base64 -d \u003e \u003cname\u003e.crt\n```\n\nKubernetes CSR file sample:\n```yaml\napiVersion: certificates.k8s.io/v1\nkind: CertificateSigningRequest\nmetadata:\n  name: \u003cname\u003e\nspec:\n  groups:\n  - system:authenticated\n  request: # Place your \u003ccsr\u003e base64 encoded here\n  signerName: kubernetes.io/kube-apiserver-client\n  usages:\n  - client auth\n```\n\nThat's all .. now we can use our **`.crt`** and **`.key`** to talk to the API server\n\n![Authentication](https://github.com/theJaxon/CKA/blob/master/etc/Authentication.png)\n\nTo use them we create a new context \n```bash\n# 1. set the credentials\nk config set-credentials \u003cname\u003e --client-certificate=\u003cname\u003e.crt --client-key=\u003cname\u003e.key \n\n# 2. Verify that credentials were added \nk config view\n\n# 3. create and set context \nk config set-context \u003cuser\u003e --cluster=\u003cname\u003e --user=\u003cname\u003e\nk config get-contexts\n\n# 4. use context to verify \nk --context \u003cname\u003e get po\n```\n\n---\n\n### Authorization:\nAuthorization modules in K8s include:\n1. AlwaysAllow # For testing only \n2. AlwaysDeny # For testing only \n3. **RBAC**\n4. ABAC\n5. Node\n6. Webhook\n\n---\n\n### Talking to the server without proxy:\nWhile the easy approach is to just use `k proxy \u0026` and then curl request would work on port `8001`, there are other approaches like\n1. Using **Bearer Token** for authentication:\nBy default kubernetes creates a secret for each `service account` so for the default namespace a secret is created as `default-token-*`\n\nTo be able to make a curl request to the server grab the secret \n```\n# 1- Grab the Server URL\nk config view \n\n# 2- Copy the token\nk describe secret default-token-*\n\n# 3- use curl to access the server as follows\ncurl -k https://\u003cserver-address\u003e/api/v1 --header \"Authorization: Bearer \u003ctoken\u003e\"\n```\n\n---\n\n#### Using NetworkPolicies to restrict pod communication:\n* By default all the pods in the cluster can communicate with each others without restrictions.\n* Network Policy is used to modify this behavior\n\n#### How the spec is organized:\n\n![NetPol](https://github.com/theJaxon/CKA/blob/master/etc/NetPol.jpg)\n\n* Check the repo [Kubernetes Network Policy Recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes)\n\n```bash\n# View Network policies in the current ns \nk get netpol\n```\n\n#### Blocking all incoming traffic using blank Netpol:\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: deny-all-policy \nspec:\n  podSelector: {} # Select all pods \n  ingress: [] # No traffic is whitelisted\n```\n* From [Ahmet Balkan talk at Kubecon](https://www.youtube.com/watch?v=3gGpMmYeEO8)\n\n---\n\n#### JSON Path queries:\n```bash\n# First view the returned output from the command, you will narrow this output down\nkubectl get \u003cobject\u003e -o json \n\n# Filter the output\nkubectl get pods -o=jsonpath='{.items[0].spec.containers[0].image}'\n\n# You can query more than one item at a time\nkubectl get po -o=jsonpath='{.items[*].metadata.name}{.items[*].status.capacity.cpu}'\n\n# Prettifying the output using tabs or newlines\nkubectl get po -o=jsonpath='{.items[*].metadata.name}{\"\\n\"}{.items[*].status.capacity.cpu}'\n\n# Loops \n'{range .items[*]}\n  {.metadata.name}{\"\\t\"} {.status.capacity.cpu}{\"\\n\"}\n{end}\n'\n\n# FInal form\nkubectl get nodes -o=jsonpath='{range .items[*]} {.metadata.name} {\"\\t\"} {.status.capacity.cpu} {\"\\n\"} {end}'\n\n# Custom column iteration\nkubectl get nodes  -o=custom-columns=NODE:.metadata.name,CPU:.status.capacity.cpu\n\n```\n\n---\n### Referencing Values:\n#### From pod fields:\n\n\u003cdetails\u003e\n\u003csummary\u003emetadata\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n.name\n.namespace\n.uid\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003espec\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n.nodeName\n.serviceAccountName\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003estatus\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n.hostIP\n.podIP\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n---\n\n#### From container resources fields:\n\n\u003cdetails\u003e\n\u003csummary\u003erequests\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n.cpu\n.memory\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003elimits\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n.cpu\n.memory\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n### :diamonds: Storage: \n```\n.pod.spec.containers.volumeMounts\n  . readOny: True \n```\n\n---\n\n### :diamonds: 1- Cluster Architecture, Installation \u0026 Configuration 25%:\n#### :gem: 1- Manage role based access control (RBAC)\nAfter creating a user account and configuring keys and certs we then create ClusterRole (or a Role) and ClusterRoleBinding (or a RoleBinding)\n```bash\n# Create a Role \nk create role -h \nk create role \u003cns\u003e --verb=get,watch,create,update,patch,delete --resource=deploy,po,rs -n \u003cns\u003e -o yaml --dry-run=client \u003e ns-role.yml\n\n# Bind the user to the role \nk create rolebinding -h\nk create rolebinding \u003cusername-binding\u003e --role=\u003cns\u003e --user=\u003cusername\u003e -n \u003cns\u003e\n```\n\nTest the effect of the role by using --context:\n```\nk --context=\u003ccontext-name\u003e \u003cverb\u003e \u003cobject\u003e \u003cname\u003e\n```\n\n---\n\n#### :gem: 2- Use Kubeadm to install a basic cluster\n```bash\n# 1. initialize the cluster and the first control plane\nsudo kubeadm init\n\n# Initialize from a given config file \nkubeadm init --config=/\u003cpath\u003e/\u003cfile\u003e.cfg\n\n# 2. Install Pod Network Addon [Flannel, Calico, etc ..]\nk apply -f \u003cNetwork-addon\u003e.yml\n\n# 3. OPTIONAL For HA Cluster\n# Join more control plane nodes\nsudo kubeadm join \u003ccontrol-plane-host\u003e:\u003ccontrol-plane-port\u003e \\\n-- token \u003ctoken\u003e --discovery-token-ca-cert-hash sha256:\u003chash\u003e \\\n-- control-plane --certificate-key \u003ccertificate-decryption-key\u003e\n\n# 4. Join Worker Nodes \nsudo kubeadm join \u003ccontrol-plane-host\u003e:\u003ccontrol-plane-port\u003e \\\n--token \u003ctoken\u003e --discovery-token-ca-cert sha256:\u003chash\u003e\n```\n\n![kubeadm](https://github.com/theJaxon/CKA/blob/master/etc/Kubeadm.jpg)\n\n* Check [kubeadm deep dive](https://youtu.be/DhsFfNSIrQ4)\n\n#### :gem: 5- Perform a version upgrade on a Kubernetes cluster using Kubeadm\nRefer to [kubeadm upgrade docs](https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/)\n```bash\n# Master node\n# Drain the node \nk drain \u003cnode\u003e --ignore-daemonsets --delete-local-data\napt-get update \u0026\u0026 apt-get install -y kubeadm=1.19.x\nsudo kubeadm upgrade plan\nsudo kubeadm upgrade apply v1.19.x\n\n# Upgrade kubelet and kubectl \napt-get install -y kubelet=1.19.x kubectl=1.19.x\n\nsystemctl restart kubelet\n\n# Uncordon the node\nk uncordon \u003cnode\u003e\n\n# Worker node \nk drain \u003cnode\u003e --ignore-daemonsets --delete-local-data\n```\n\n#### :gem: 6- Implement etcd backup and restore\n```bash\netcdctl snapshot save \netcdctl snapshot status \u003clocation\u003e\netcdctl snapshot restore\n```\n\n```bash\nyum provides */etcd\nyum install -y etcd # This also installs etcdctl\netcdctl -h\nETCDCTL_API=3 etcdctl -h # View help menu of API V3 for etcd\nETCDCTL_API=3 etcdctl snapshot save -h\nps aux | grep etcd\n\n# From the help we figure the parameters needed as \n# --cacert --cert --key\nexport ETCDCTL_API=3\n\netcdctl \\\n--cacert=/etc/kubernetes/pki/etcd/ca.crt \\\n--cert /etc/kubernetes/pki/etcd/server.crt \\\n--key /etc/kubernetes/pki/etcd/server.key snapshot save \u003clocation\u003e\n```\n* Create a backup of ETCD database (API V3 is used), write the backup to `/var/exam/etcd-backup`\n\nSearch for **etcdctl snapshot save** in the documentation page which should result in [Operating etcd clusters for k8s](https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/)\n\n### :diamonds: Workloads \u0026 Scheduling:\n\n#### :gem:  1- Understand deployments and how to perform rolling update and rollbacks:\n\n```bash\nk create deploy/\u003cname\u003e --image=\u003cname\u003e --replicas=1\nk rollout status deploy/\u003cname\u003e\n\nk rollout history deploy/\u003cname\u003e\n\n# Manually annotate the current revision\nk annotate deploy/\u003cname\u003e kubernetes.io/change-cause=\"Initial deployment\"\n\n# Annotate the upcoming revision using the specified command \nk set image deploy/\u003cname\u003e name=\u003cimage\u003e --record\n\n# Rollback help\nk rollout undo -h\n\n# Rollback to the last revision \nk rollout undo deploy/\u003cname\u003e\n\n# Rollback to specific revision with the --to-revision flag\nk rollout undo deploy/\u003cname\u003e --to-revision=\u003cnumber\u003e\n\n\n```\n\n\u003cdetails\u003e\n\u003csummary\u003ek explain deploy.spec.strategy.rollingUpdate\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n.maxSurge # Max no of pods above the desired limit [For the new revision]\n.maxUnavailable # Max no of pods that can be absent from the old revision during the rollout\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n#### :gem: 2- Use ConfigMaps and Secrets to configure applications:\n\n- Create configMaps imperatively:\n```bash\n# cm from file\nk create cm \u003cname\u003e --from-file=\u003cfile-name\u003e.\u003cextension\u003e\n\n# cm from env file \nk create cm \u003cname\u003e --from-env-file=\u003cfile-name\u003e.env\n\n# cm from literals \nk create cm \u003cname\u003e --from-literal=K=v --from-literal=K=v\n```\n\n- Use configMaps as volumes:\n  1. Mount configMap item in a specific path\n  * The key is usally a name of a file and all you do is mount the specific file to a specific path.\n  ```bash\n  # Create a simple configMap\n  k create cm test-cm --from-literal=DISTRO=ubuntu --from-literal=CODENAME=focal\n\n  # Generate pod definition\n  k run busybox --image=busybox -o yaml --dry-run=client \u003e busybox.yml --command sleep 3600\n\n  # Modify the file to use only the DISTRO item from the configMap\n  spec:\n  volumes:\n  - name: test-v\n    configMap:\n      name: test-cm\n      items:\n      - key: DISTRO\n        path: distro.name\n  containers:\n  - command:\n    - sleep\n    - \"3600\"\n    image: busybox\n    name: busybox\n    volumeMounts:\n    - name: test-v\n      mountPath: /tmp\n  # Verify\n  k exec -it busybox -- cat /tmp/distro.name # shows ubuntu\n  ```\n\n  2. Mount the whole configMap to a specific path \n\n:mag: Search the docs for:\n```bash\n#Configmap volume\nalso can be reached via \nk explain pod.spec.volumes.configmap\n```\n\n#### :gem: 3- Know how to scale applications\n```bash\n# Scale a deployment \nk scale deploy/\u003cname\u003e --replicas=\u003cnumber\u003e\n\n# Conditionally scale using hpa \nk autoscale deploy/\u003cname\u003e --min=\u003cnumber\u003e --max=\u003cnumber\u003e --cpu-percent=\u003cnumber\u003e\n```\n\n---\n\n#### Static pods:\n* Static pods are directly attached to the kubelet daemon\n* The files used for static pods are placed using `staticPodPath` section of the kubelet file in the **kubelet config file**\n* static pod path can be found using:\n```bash\n#1- Search in kubelet config file\ncat /var/lib/kubelet/config.yaml\n\n#2- Use kube proxy \nk proxy \u0026\ncurl localhost:8001/api/v1/nodes/\u003cnode-name\u003e/proxy/configz\n```\n* The path for static pods is usually `/etc/kubernetes/manifests`\n\n---\n\n#### :gem: 5- Understand how resource limits can affect Pod scheduling:\nScheduling on specific nodes using labels and node name:\n```bash\nk label nodes \u003cname\u003e k=v\nk explain pod.spec.nodeSelector \ncontainers:\n  spec:\n    nodeSelector:\n      k=v\n\n# Using nodeName directly\nk explain pod.spec.nodeName\ncontainers:\n  spec:\n    nodeName: \u003cnode-name\u003e\n```\n\n```bash\nk explain pod.spec.affinity\n```\n\n* Affinity, antiAffinity and taints all impact scheduling and limit which pods can be scheduled to which nodes.\n* Affinity can be applied at 2 levels, at **Nodes** and at **Pods**\n* NodeAffinity sets affinity rules on nodes: specifies which nodes a pod can be scheduled on.\n* Inter-pod affinity sets affinity rules between pods\n* Taints and tolerations ensues that pods aren't scheduled on inapporpriate nodes\n* Taints and tolerations have no effect on daemonsets\n* Tains are ignored if the pod has a toleration\n\nThere are 3 types of taints `k explain node.spec.taints`\n1. NoSchedule: Prevents scheduling of new pods.\n2. PreferNoSchedule: doesn't schedule new pods unless there's no other option\n3. NoExecute: migrate all pods away from this node\n\n\n\n#### :gem: 6- Awareness of manifest management and common templating tools:\n**pod.spec**:\nThere are many fields under the `containers` in the spec, the most signifacnt ones are:\n1. **Scheduling**: This helps in selecting the node where the pod will be deployed to either directly through `nodeName` , `nodeSelector` which uses a lable or using `affinity` and `tolerations`\n\n2. **SecurityContext**: defines security attributes like `runAsUser`, `capabilites`\n```bash\nk explain pod.spec.containers.securityContext\n\n# There's also securityContext available at the spec level \nk explain pod.spec.securityContext\n```\n\n\u003cdetails\u003e\n\u003csummary\u003ek explain pod.spec\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n.securityContext.runAsUser\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003ek explain pod.spec.containers\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n.securityContext.capabilites\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n3. **Lifecycle** \n  . `restartPolicy`: defines action taken after the termination of a pod.\n  . `terminationGracePeriodSeconds`: fine-tune the periods after which processes running in the containers of a terminating pod are killed, The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal.\n  . `activeDeadlineSeconds` Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers\n\n\u003cdetails\u003e\n\u003csummary\u003ek explain pod.spec\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n.restartPolicy\n.terminationGracePeriodSeconds\n.activeDeadlineSeconds\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n4. **ServiceAccount**: Gives specific rights to pods using a specific `serviceAccountName`\n\n5. Hostname \u0026 Name resolution: \n`hostAliases`: List of hosts and IPs that gets added to `/etc/hosts` file.\n`dnsConfig`:  Specifies the DNS parameters of a pod and update `/etc/resolv.conf`\n`hostname`: Specifies the hostname of the Pod If not specified\n\n\u003cdetails\u003e\n\u003csummary\u003ek explain pod.spec\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n.dnsConfig\n.hostAliases\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\n---\n\n### :diamonds: Services \u0026 Networking:\n\n#### :gem: 4. Know how to use Ingress controllers and Ingress resources:\n```bash\n# 1. Create an Ingress controller \nk apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yaml\n\n# Get the ports on which the ingress controller listens \nk get svc -n ingress-nginx \n\n# Test HTTP and HTTPS \ncurl \u003cworker-ip\u003e:\u003cport-number\u003e\ncurl -k https://\u003cworker-ip\u003e:\u003cport-number\u003e\n\n```\n\n---\n\n### :diamonds: Troubleshooting:\n* Logs of the pods are stored in the node running the pod at **`/var/log/pods`**\n\n```bash\nk top nodes # metrics-server needs to be deployed\n```\n\n#### :gem: Evaluate cluster and node logging:\n\n```bash\n# View kubelet logs \njournalctl -u kubelet\n\n# View logs for core componentes \ncd /var/log/containers \ncat $(ls kube-proxy*) | tail -n 1\ncat $(ls coredns*) | tail -n 1\ncat $(ls kube-apiserver*) | tail -n 1\n\n# View kube-system ns pods\nk get po -n kube-system\n\nk logs \u003cname\u003e -n kube-system\n\nk describe po etcd-controller -n kube-system\n\n# Logs at node level \n\n```\n\n#### :gem: Manage container stdout \u0026 stderr logs:\n```bash\n# View logs from all containers with specific label in a specific ns \nk logs -l k=v --all-containers -n \u003cns\u003e \n\n```\n\n#### :gem: Multiple Schedulers:\n```bash\n# From documentation get the page about multi schedulers\n# https://kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/\nk apply -f my-scheduler.yml\nk edit clusterrole system:kube-scheduler\nresourceNames:\n- kube-scheduler\n- my-scheduler # Add this \n\n# When creating a pod just add\nk explain pod.spec.schedulerName\nschedulerName: \n```\n\n---\n\n### Practice Qs:\n1- Create a pod from the image nginx\n```bash\nk run nginx --image=nginx\n```\n\n2- Create a new Deployment with the below attributes using your own deployment definition file\nName: httpd-frontend; Replicas: 3; Image: httpd:2.4-alpine\n\n```bash\nk create deploy httpd-fronted --image=httpd:2.4-alpine --replicas=3\n```\n\n3- Deploy a pod named nginx-pod using the nginx:alpine image \"Use imperative commands only.\"\n```bash\nk run nginx-pod --image=nginx:alpine\n```\n\n4- Deploy a redis pod using the redis:alpine image with the labels set to tier=db.\n\nEither use imperative commands to create the pod with the labels. Or else use imperative commands to generate the pod definition file, then add the labels before creating the pod using the file.\n\n```bash\nk run redis --image=redis:alpine --labels=\"tier=db\"\n```\n\n5- Create a service redis-service to expose the redis application within the cluster on port 6379. Use imperative commands\n```bash\nk expose po redis --port=6379 --target-port=6379 --name=redis-service\n```\n\n6- Create a deployment named webapp using the image kodekloud/webapp-color with 3 replicas. Try to use imperative commands only. Do not create definition files.\n```bash\nk create deploy webapp --image=kodekloud/webapp-color --replicas=3\n```\n\n7- Create a new pod called custom-nginx using the nginx image and expose it on container port 8080\n```bash\nk run custom-nginx --image=nginx --port=8080 \n```\n\n8- Create a new namespace called dev-ns.\n```bash\nk create ns dev-ns\n```\n\n9- Create a new deployment called redis-deploy in the dev-ns namespace with the redis image. It should have 2 replicas.\n```bash\nk create deploy redis-deploy --image=redis --replicas=2 -n dev-ns\n```\n\n10- Create a pod called httpd using the image httpd:alpine in the default namespace. \nNext, create a service of type ClusterIP by the same name (httpd). The target port for the service should be 80.\n```bash\nk run httpd --image=httpd:alpine \nk expose po/httpd --port=80 --target-port=80\n```\n\n11- Create a taint on node01 with key of 'spray', value of 'mortein' and effect of 'NoSchedule'\n```bash\nk taint -h\nk taint nodes node01 spray=mortein:NoSchedule\n```\n\n12- Create another pod named 'bee' with the NGINX image, which has a toleration set to the taint Mortein\n Image name: nginx\nKey: spray\nValue: mortein\nEffect: NoSchedule\nStatus: Running \n\n```bash\nk explain pod.spec.tolerations\nk run bee --image=nginx -o yaml --dry-run=client \u003e nginx.yml \n# Add to the file \nspec:\n  tolerations:\n  - effect: NoSchedule\n    key: spray \n    value: mortein\n    operator: Equal\n```\n\n13- Remove the taint on master/controlplane, which currently has the taint effect of NoSchedule\n\n```\nk taint nodes controleplane node-role.kubernetes.io/master-\n```\n\n14- Apply a label color=blue to node node01\n\n```bash\nk label nodes node1 color=blue\n```\n\n15- Create a new deployment named blue with the nginx image and 6 replicas\n\n```bash\nk create deploy blue --image=nginx --replicas=6\n```\n\n16- Set Node Affinity to the deployment to place the pods on node01 only\nName: blue\nReplicas: 6\nImage: nginx\nNodeAffinity: requiredDuringSchedulingIgnoredDuringExecution\nKey: color\nvalues: blue \n\n```bash\nk explain pod.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms\nmatchExpressions # labels \n  key:\n  operator:\n  values:\n\nk create deploy blue --image=nginx --replicas=6 -o yaml --dry-run=client \u003e nginx.yml\n```\n\n17- Create a new deployment named red with the nginx image and 3 replicas, and ensure it gets placed on the master/controlplane node only.\n\nUse the label - node-role.kubernetes.io/master - set on the master/controlplane node.\n\nName: red\nReplicas: 3\nImage: nginx\nNodeAffinity: requiredDuringSchedulingIgnoredDuringExecution\nKey: node-role.kubernetes.io/master\nUse the right operator \n\n```\nk create deploy red --image=nginx --replicas=3 -o yaml --dry-run=client\n```\n\n18- Deploy a DaemonSet for FluentD Logging.\n\nUse the given specifications.\n\n    Name: elasticsearch\n    Namespace: kube-system\n    Image: k8s.gcr.io/fluentd-elasticsearch:1.20\n\n```bash\nk create deploy elasticsearch --image=k8s.gcr.io/fluentd-elasticsearch:1.20 -n kube-system -o yaml --dry-run=client \u003e elastic.yml\n# Modify and change the kind to DaemonSet, remove replicas and strategy\n```\n\n19- Create a static pod named static-busybox that uses the busybox image and the command sleep 1000\n```\ncd /etc/kubernetes/manifests\nk run static-busybox --image=busybox -o yaml --dry-run=client \u003e busybox.yml --command sleep 1000\n```\n\ndelete static pod named static-greenbox\n```bash\n# ssh into the node containing the pod definition file \nk get po -o wide # See which node the pod is on\nk get nodes -o wide # Get node ip\nssh ip-address\ncat /var/lib/kubelet/config.yml # Check the staticPodPath\ncd /static/pod/path\nrm file.yml \n```\n\n20- Create a new Secret named 'db-secret' with the data given(on the right).\n\nYou may follow any one of the methods discussed in lecture to create the secret.\n\nSecret Name: db-secret\nSecret 1: DB_Host=sql01\nSecret 2: DB_User=root\nSecret 3: DB_Password=password123 \n\n```\nk create secret generic db-secret --from-literal=DB_Host=sql01 --from-literal=DB_User=root --from-literal=DB_Password=password123\n```\n\n21- Configure webapp-pod to load environment variables from the newly created secret.\nDelete and recreate the pod if required.\n\nPod name: webapp-pod\nImage name: kodekloud/simple-webapp-mysql\nEnv From: Secret=db-secret \n\n```\nk create secret generic --from-literal=Secret=db-secret\nk get po webapp-pod -o yaml \u003e webapp-pod.yaml\nk set env po/webapp-pod --from=secret/db-secret \n```\n\n22- Create a multi-container pod with 2 containers.\nUse the spec given on the right.\n\nName: yellow\nContainer 1 Name: lemon\nContainer 1 Image: busybox\nContainer 2 Name: gold\nContainer 2 Image: redis\n\n```\nk run lemon --image=busybox --labels=\"name=yellow\" -o yaml --dry-run=client \u003e multi.yml \nvi multi.yml\n\n- name: gold\n  image: redis\n```\n\nEdit the pod to add a sidecar container to send logs to ElasticSearch. Mount the log volume to the sidecar container..\nOnly add a new container. Do not modify anything else. Use the spec on the right.\n\nName: app\nContainer Name: sidecar\nContainer Image: kodekloud/filebeat-configured\nVolume Mount: log-volume\nMount Path: /var/log/event-simulator/\nExisting Container Name: app\nExisting Container Image: kodekloud/event-simulator\n\n```\nk get po app -o yaml \u003e app.yml\nvi app.yml\ncontainers:\n- image: kodekloud/filebeat-configured\n  name: sidecar\n  volumeMounts:\n  - name: log-volume\n    mountPath: /var/log/event-simulator\n```\n\nCreate the necessary roles and role bindings required for the dev-user to create, list and delete pods in the default namespace.\n\nUse the given spec\n\nRole: developer\nRole Resources: pods\nRole Actions: list\nRole Actions: create\nRoleBinding: dev-user-binding\nRoleBinding: Bound to dev-user\n\n```bash\nk create role developer --resource=po --verb=list,create -n default -o yaml --dry-run=client \u003e developer.yml\nk apply -f developer.yml\n\nk create rolebinding dev-user-binding --role=developer --user=dev-user --namespace=default -o yaml --dry-run=client \u003e dev-user-binding.yml\nk apply -f dev-user-binding.yml\n```\n\nA new user michelle joined the team. She will be focusing on the nodes in the cluster. Create the required ClusterRoles and ClusterRoleBindings so she gets access to the nodes.\n\nGrant permission to list nodes \n```bash\nk create clusterrole michelle --verb=list --resource=node \nk create clusterrolebinding michelle --clusterrole=michelle --user=michelle\n```\n\nmichelle's responsibilities are growing and now she will be responsible for storage as well. \nCreate the required ClusterRoles and ClusterRoleBindings to allow her access to Storage.\n\nGet the API groups and resource names from command kubectl api-resources. Use the given spec.\n\nClusterRole: storage-admin\nResource: persistentvolumes\nResource: storageclasses\nClusterRoleBinding: michelle-storage-admin\nClusterRoleBinding Subject: michelle\nClusterRoleBinding Role: storage-admin \n```bash\nk create clusterrole storage-admin --resource=pv,sc --verb=create,list,delete -o yaml --dry-run=client \u003e storage-admin.yml\nk apply -f storage-admin.yml \n\nk create clusterrolebinding michelle-storage-admin --clusterrole=storage-admin --user=michelle -o yaml --dry-run=client \u003e michelle-storage-admin.yml\nk apply -f michelle-storage-admin.yml\n```\n\nCreate a network policy to allow traffic from the 'Internal' application only to the 'payroll-service' and 'db-service'\nUse the spec given on the right. You might want to enable ingress traffic to the pod to test your rules in the UI.\n\nPolicy Name: internal-policy\nPolicy Types: Egress\nEgress Allow: payroll\nPayroll Port: 8080\nEgress Allow: mysql\nMYSQL Port: 3306 \n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata:\n  name: internal-policy\n  namespace: default\nspec:\n  podSelector:\n    matchLabels:\n      name: internal\n  policyTypes:\n  - Egress\n  egress:\n  - to:\n      podSelector:\n        matchLabels:\n          name: mysql\n    ports:\n    - protocol: TCP\n      port: 3306 # MYSQL\n  - to:\n      podSelector:\n        matchLabels:\n          name: payroll\n    ports:\n    - protocol: TCP\n      port: 8080\n```\n\nConfigure a volume to store these logs at /var/log/webapp on the host\nUse the spec given on the right.\nName: webapp\nImage Name: kodekloud/event-simulator\nVolume HostPath: /var/log/webapp\nVolume Mount: /log \n\n```yaml\nvolumes:\n- name: webapp-v\n  hostPath:\n    path: /var/log/webapp\n\ncontainers:\n- name: webapp\n  image: kodekloud/event-simulator\n  volumeMounts:\n  - name: webapp-v\n    mountPath: /log\n```\n\nCreate a 'Persistent Volume' with the given specification.\n\nVolume Name: pv-log\nStorage: 100Mi\nAccess modes: ReadWriteMany\nHost Path: /pv/log \n\n```yml\nk explain pv # Follow the link and copy the NFS example \napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: pv-log\nspec:\n  capacity:\n    storage: 100Mi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteMany\n  hostPath:\n    path: /pv/log\n```\n\nLet us claim some of that storage for our application. Create a 'Persistent Volume Claim' with the given specification.\n\nVolume Name: claim-log-1\nStorage Request: 50Mi\nAccess modes: ReadWriteOnce\n```yaml\nk explain pvc # Follow the link and copy the sample\n\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: claim-log-1\nspec:\n  accessModes:\n    - ReadWriteOnce\n  volumeMode: Filesystem\n  resources:\n    requests:\n      storage: 50Mi\n```\n\nUpdate the webapp pod to use the persistent volume claim as its storage.\n\nReplace hostPath configured earlier with the newly created PersistentVolumeClaim\n\nName: webapp\nImage Name: kodekloud/event-simulator\nVolume: PersistentVolumeClaim=claim-log-1\nVolume Mount: /log \n\n```yaml\nvolumes:\n- name: pvc-v\n  persistentVolumeClaim:\n    claimName: claim-log-1\ncontainers:\n- name: webapp\n  image: kodekloud/event-simulator\n  volumeMounts:\n  - name: pvc-v\n    mountPath: /log\n```\n\nCreate a new pod called nginx with the image nginx:alpine. \nThe Pod should make use of the PVC local-pvc and mount the volume at the path `/var/www/html`.\n\nThe PV local-pv should in a bound state.\nPod created with the correct Image?\nPod uses PVC called local-pvc?\nlocal-pv bound?\nnginx pod running?\nVolume mounted at the correct path? \n\n```bash\n# Generate pod file \nk run nginx --image=nginx:alpine -o yaml --dry-run=client \u003e nginx.yml\n```\nModify the generated file:\n```yaml\nvolumes:\n- name: test \n  persistentVolumeClaim:\n    claimName: local-pvc\ncontainers:\n- name: nginx\n  image: nginx:alpine\n  volumeMounts:\n  - name: test \n    mountPath: /var/www/html\n\n```\n\nCreate a new Storage Class called delayed-volume-sc that makes use of the below specs:\n\nprovisioner: kubernetes.io/no-provisioner\nvolumeBindingMode: WaitForFirstConsumer\n\nStorage Class uses: kubernetes.io/no-provisioner ?\nStorage Class volumeBindingMode set to WaitForFirstConsumer ?\n\n```yaml\napiVersion: storage.k8s.io/v1\nkind: StorageClass\nmetadata:\n  name: delayed-volume-sc\nprovisioner: kubernetes.io/no-provisioner\nvolumeBindingMode: WaitForFirstConsumer\n```\n\nYou are requested to change the URLs at which the applications are made available. Make the video application available at /stream.\n\nIngress: ingress-wear-watch\nPath: /stream\nBackend Service: video-service\nBackend Service Port: 8080 \n\n```yaml\nk edit ingress -n app-space ingress-wear-watch\n\nspec:\n  rules:\n  - http:\n    paths:\n    - backend:\n      serviceName: video-service\n      servicePort: 8080\n    path: /stream\n```\n\nYou are requested to add a new path to your ingress to make the food delivery application available to your customers. Make the new application available at /eat.\n\nIngress: ingress-wear-watch\nPath: /eat\nBackend Service: food-service\nBackend Service Port: 8080 \n\n```yaml\nk edit ingress -n app-space ingress-wear-watch\n\nspec:\n  rules:\n    paths:\n    - path: /eat\n      backend:\n        serviceName: food-service\n        servicePort: 8080\n```\n\nYou are requested to make the new application available at /pay.\nIdentify and implement the best approach to making this application available on the ingress controller and test to make sure its working. Look into annotations: rewrite-target as well.\n\nIngress Created\nPath: /pay\nConfigure correct backend service\nConfigure correct backend port\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: pay-ingress\n  namespace: critical-space\n  annotations:\n    nginx.ingress.kubernetes.io/rewrite-target: /\nspec:\n  rules:\n  - http:\n      paths:\n      - path: /pay\n        pathType: ImplementationSpecific\n        backend:\n          service: # k get svc --all-namespaces\n            name: pay-service\n            port: 8282\n```\n\nPrint the names of all deployments in the admin2406 namespace in the following format:\nDEPLOYMENT CONTAINER_IMAGE READY_REPLICAS NAMESPACE\n\u003cdeployment name\u003e \u003ccontainer image used\u003e \u003cready replica count\u003e \u003cNamespace\u003e\n. The data should be sorted by the increasing order of the deployment name.\n\nExample:\nDEPLOYMENT CONTAINER_IMAGE READY_REPLICAS NAMESPACE\ndeploy0 nginx:alpine 1 admin2406\nWrite the result to the file /opt/admin2406_data.\n\nHint: Make use of -o custom-columns and --sort-by to print the data in the required format.\n\n```\nk get deploy -n admin2046 -o custom-columns='DEPLOYMENT:metadata.name,CONTAINER_IMAGE:spec.template.spec.containers[*].image.READY_REPLICAS:spec.replicas,NAMESPACE:metadata.namespace'\n```\n\nCreate a new deployment called nginx-deploy, with image nginx:1.16 and 1 replica. Next upgrade the deployment to version 1.17 using rolling update. Make sure that the version upgrade is recorded in the resource annotation.\n\nWeight: 12\n\n    Image: nginx:1.16\n    Task: Upgrade the version of the deployment to 1:17\n    Task: Record the changes for the image upgrade\n\n```bash\nk create deploy nginx-deploy --image=nginx:1.16 --replicas=1 $do \u003e nginx.yml\nk apply -f nginx.yml\n\nk set image deploy/nginx-deploy nginx=nginx:1.17 --record\nk rollout history deploy nginx-deploy\n```\n\nCreate a pod called secret-1401 in the admin1401 namespace using the busybox image. The container within the pod should be called secret-admin and should sleep for 4800 seconds.\n\n```yaml\nk run secret-1401 --image=busybox -n admin1401 --command sleep 4800 $do \u003e busybox.yml\n# Modify containers section \nname: secret-admin\n\n# Volume part\nvolumes:\n- name: dotfile-secret-v\n  secret:\n    secretName: dotfile-secret\n\nvolumeMounts:\n- name: dotfile-secret-v\n  mountPath: /etc/secret-volume\n  readOnly: True\n```\n\nThe container should mount a read-only secret volume called secret-volume at the path /etc/secret-volume. The secret being mounted has already been created for you and is called dotfile-secret.\n\n\nCreate a Pod called redis-storage with image: redis:alpine with a Volume of type emptyDir that lasts for the life of the Pod. Specs on the right.\n\nPod named 'redis-storage' created\nPod 'redis-storage' uses Volume type of emptyDir\nPod 'redis-storage' uses volumeMount with mountPath = /data/redis \n\n```yaml\nk run redis-storage --image=redis:alpine $do \u003e redis-storage.yml\nvi redis-storage.yml\n\nspec:\n  volumes:\n  - name: redis-storage-v\n    emptyDir: {}\n\n  containers:\n  - image: redis:alpine\n    name: redis-storage\n    volumeMounts:\n    - name: redis-storage-v\n      mountPath: /data/redis\n```\n\nCreate a new pod called super-user-pod with image busybox:1.28. Allow the pod to be able to set system_time\n\nThe container should sleep for 4800 seconds\n\nPod: super-user-pod\nContainer Image: busybox:1.28\nSYS_TIME capabilities for the conatiner?\n\n```yaml\nk run super-user-pod --image=busybox:1.28 $do \u003e super-user-pod.yml --command sleep 4800\nk explain pod.spec.containers.securityContext\nvi super-user-pod.yml\n\ncontainers:\n- command:\n  - sleep\n  - \"4800\"\n  image: busybox:1.28\n  name: super-user-pod\n  securityContext:\n    capabilities:\n      add:\n        - SYS_TIME\n```\n\nCreate a new deployment called nginx-deploy, with image nginx:1.16 and 1 replica. Record the version. Next upgrade the deployment to version 1.17 using rolling update. Make sure that the version upgrade is recorded in the resource annotation.\n\nDeployment : nginx-deploy. Image: nginx:1.16\nImage: nginx:1.16\nTask: Upgrade the version of the deployment to 1:17\nTask: Record the changes for the image upgrade \n\n```yaml\nk create deploy nginx-deploy --image=nginx:1.16 --replicas=1 $do \u003e nginx-16.yml\nk apply -f nginx-16.yml\nk annotate deploy/nginx-deploy kubernetes.io/change-cause=\"1.16\"\nk set image deploy/nginx-deploy nginx=nginx:1.17 --record\nk rollout history deploy/nginx-deploy\n```\n\nCreate a new user called john. Grant him access to the cluster. John should have permission to create, list, get, update and delete pods in the development namespace . The private key exists in the location: /root/CKA/john.key and csr at /root/CKA/john.csr\n\nImportant Note: As of kubernetes 1.19, the CertificateSigningRequest object expects a signerName.\n\nPlease refer documentation below to see the example usage:\nhttps://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/#create-certificate-request-kubernetes-object\n\nCSR: john-developer Status:Approved\nRole Name: developer, namespace: development, Resource: Pods\nAccess: User 'john' has appropriate permissions \n\nCreate an nginx pod called nginx-resolver using image nginx, expose it internally with a service called nginx-resolver-service. Test that you are able to look up the service and pod names from within the cluster. Use the image: busybox:1.28 for dns lookup. Record results in /root/CKA/nginx.svc and /root/CKA/nginx.pod\n\nPod: nginx-resolver created\nService DNS Resolution recorded correctly\nPod DNS resolution recorded correctly \n\n```bash\nk run nginx-resolver --image=nginx $do \u003e nginx.yml\nk apply -f nginx.yml\nk expose pod nginx-resolver --port=80 --target-port=80 --name=nginx-resolver-service\n```\n\nCreate a new service account with the name pvviewer. \nGrant this Service account access to list all PersistentVolumes in the cluster by creating an appropriate cluster role called pvviewer-role and ClusterRoleBinding called pvviewer-role-binding.\nNext, create a pod called pvviewer with the image: redis and serviceAccount: pvviewer in the default namespace\n\nServiceAccount: pvviewer\nClusterRole: pvviewer-role\nClusterRoleBinding: pvviewer-role-binding\nPod: pvviewer\nPod configured to use ServiceAccount pvviewer ? \n\n```bash\nk create sa pviewer\nk create clusterrole pviewer-role -h \nk create clusterrole pviewer-role --verb=list --resource=pv\nk create clusterrolebinding pviewer-role-binding --clusterrole=pviewer-role --serviceaccount=default:pviewer\nk run pviewer --image=redis --serviceaccount=pviewer $do \u003e pviewer.yml\nk apply -f pviewer.yml\n```\n\nList the InternalIP of all nodes of the cluster. Save the result to a file /root/CKA/node_ips\n\nAnswer should be in the format: InternalIP of master\u003cspace\u003eInternalIP of node1\u003cspace\u003eInternalIP of node2\u003cspace\u003eInternalIP of node3 (in a single line)\n```\nk get nodes -o jsonpath='{.items[*].status.addresses[*].address}' \u003e /root/CKA/node_ips\n```\n\nCreate a pod called multi-pod with two containers.\nContainer 1, name: alpha, image: nginx\nContainer 2: beta, image: busybox, command sleep 4800.\n\nEnvironment Variables:\ncontainer 1:\nname: alpha\n\nContainer 2:\nname: beta\n\nPod Name: multi-pod\nContainer 1: alpha\nContainer 2: beta\nContainer beta commands set correctly?\nContainer 1 Environment Value Set\nContainer 2 Environment Value Set\n\n```yaml\nk run multi-pod --image=busybox --env=name=beta $do \u003e multi-pod.yml --command sleep 4800\nvi multi-pod.yml\n\ncontainers:\n- name: alpha\n  image: nginx \n  env:\n  - name: name\n    value: alpha\n```\n\nCreate a Pod called non-root-pod , image: redis:alpine\nrunAsUser: 1000\nfsGroup: 2000\n\n```yaml\nk run non-root-pod --image=redis:alpine $do \u003e non-root-pod.yml\nvi non-root-pod.yml\n\nspec:\n  securityContext: \n    runAsUser: 1000\n    fsGroup: 2000\n  containers:\n  - image: redis:alpine\n    name: non-root-pod\n```\n\nWe have deployed a new pod called np-test-1 and a service called np-test-service.\nIncoming connections to this service are not working. Troubleshoot and fix it.\nCreate NetworkPolicy, by the name ingress-to-nptest that allows incoming connections to the service over port 80\n\nImportant: Don't delete any current objects deployed.\n\nImportant: Don't Alter Existing Objects!\nNetworkPolicy: Applied to All sources (Incoming traffic from all pods)?\nNetWorkPolicy: Correct Port?\nNetWorkPolicy: Applied to correct Pod? \n\nTaint the worker node node01 to be Unschedulable. \nOnce done, create a pod called dev-redis, image redis:alpine to ensure workloads are not scheduled to this worker node.\nFinally, create a new pod called prod-redis and image redis:alpine with toleration to be scheduled on node01.\n\nkey:env_type, value:production, operator: Equal and effect:NoSchedule\n\nKey = env_type\nValue = production\nEffect = NoSchedule\npod 'dev-redis' (no tolerations) is not scheduled on node01?\nCreate a pod 'prod-redis' to run on node01\n\n```yaml\nk taint node01 -h \nk taint node01 env_type=production:NoSchedule\nk run dev-redis --image=redis:alpine\nk run prod-redis --image=redis:alpine $do \u003e prod-redis.yml \nvi prod-redis.yml\nspec:\n  nodeName: node01\n  tolerations:\n  - key: env_type\n    value: production\n    operator: \"Equal\"\n    effect: \"NoSchedule\"\n```\n\nCreate a pod called hr-pod in hr namespace belonging to the production environment and frontend tier .\nimage: redis:alpine\nUse appropriate labels and create all the required objects if it does not exist in the system already.\n\nhr-pod labeled with environment production?\nhr-pod labeled with frontend tier? \n\n```\nk create ns hr\nk run hr-pod --image=redis:alpine -n hr -l tier=frontend,environment=production $do \u003e hr-pod.yml\n```\n\nCreate a cluster using [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) \n```bash\nkubeadm init \n# In case you're provided with a config file \nkubeadm init --config=\u003cname\u003e.conf\n\n# This will generate the join command that can be executed on the worker nodes\n# Install network add-on\n# https://v1-17.docs.kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network\nk apply -f \u003cnetwork-addon\u003e.yml\n\n# On worker nodes\nkubeadm join \n\n# Validate\nk get nodes\n```\n\nCreate a pod that runs the latest alpine image, it should be configured to sleep 3600 seconds and it should be created in the mynamespace namespace, ensure that the pod gets restarted automatically if it fails.\n\n```bash\n# 1- Create the Namespace\nk create ns mynamespace $do \u003e mynamespace.yml\nk apply -f mynamespace.yml\n\nk run alpine --image=alpine:latest --restart=OnFailure -n mynamespace $do \u003e alpine.yml --command sleep 3600\nk apply -f alpine.yml\n\n# Verify\n$ k get po -n mynamespace\nNAME     READY   STATUS    RESTARTS   AGE\nalpine   1/1     Running   0          31s\n```\n\nConfigure a pod that runs 2 containers. The first container should create the file `/data/runfile.txt`. The second container should only start once this file has been created and it should run sleep 10000 as its task.\n\n1- create a bash script that will check if the file exists and if it does then sleep command is executed\n```bash\nvi sleep-if-exists.sh\n#!/bin/bash\nif [ -f /data/runfile.txt ]\nthen\n  sleep \"10000\"\nfi\n```\n\n2- The bash script is stored in a configMap and will be used by the 2nd container \n```\nk create cm sleep-if-exists --from-file=sleep-if-exists.sh\n```\n\n```yml\nk run busybox --image=busybox $do \u003e multi-container.yml --command touch /data/runfile.txt \n\n# Create a configMap to hold our bash script\nvi multi-container.yml\n\napiVersion: v1\nkind: Pod\nmetadata:\n  labels:\n    run: busybox\n  name: busybox\nspec:\n  volumes:\n    # Shared volume that will be mounted in both containers\n  - name: shared-v\n    emptyDir: {}\n    # Bash script is stored in this CM and will be used by the 2nd container\n  - name: sleep-if-exists\n    configMap:\n      name: sleep-if-exists\n  initContainers:\n  - command:\n    - touch\n    - /data/runfile.txt\n    image: busybox\n    name: busybox\n    volumeMounts:\n    - name: shared-v\n      mountPath: /data\n  containers:\n  - name: sleep\n    image: busybox\n    volumeMounts:\n    - name: sleep-if-exists\n      mountPath: /tmp\n    - name: shared-v\n      mountPath: /data\n    command:\n    - \"/bin/sh\"\n    - \"/tmp/sleep-if-exists.sh\"\n```\n\nCreate a Persistent Volume that uses local host storage. This PV should be accessible from all namespaces. Run a pod with the name `pv-pod` that uses this persistent volume from the `myvol` namespace.\n\n```bash\nk create ns myvol $do \u003e myvol.yml\nk apply -f myvol.yml\nk explain pv # follow the link to the documentation and copy the example\nvim pv.yml\n```\npv.yml\n```yaml\napiVersion: v1\nkind: PersistentVolume\nmetadata:\n  name: mypv\nspec:\n  capacity:\n    storage: 5Gi\n  volumeMode: Filesystem\n  accessModes:\n    - ReadWriteOnce\n  hostPath:\n    path: /tmp\n```\n\n```bash\nk apply -f pv.yml\n# Create PVC \nk explain pvc # follow docs link\nvi pvc.yml\n```\n\n```yml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: mypvc\n  namespace: myvol\nspec:\n  accessModes:\n    - ReadWriteOnce\n  volumeMode: Filesystem\n  resources:\n    requests:\n      storage: 5Gi\n```\n\n```bash\nk apply -f pvc.yml\nk run pv-pod --image=busybox -n myvol $do \u003e pv-pod.yml --command sleep 3600\nvim pv-pod.yml\n```\n```yml\napiVersion: v1\nkind: Pod\nmetadata:\n  creationTimestamp: null\n  labels:\n    run: pv-pod\n  name: pv-pod\n  namespace: myvol\nspec:\n  volumes:\n  - name: devops-v\n    persistentVolumeClaim:\n      claimName: mypvc\n  containers:\n  - command:\n    - sleep\n    - \"3600\"\n    image: busybox\n    name: pv-pod\n    volumeMounts:\n    - name: devops-v\n      mountPath: /devops\n```\n```bash\nk apply -f pv-pod.yml\n```\n\nIn the run-once namespace, run a pod with the name xxazz-pod using the alpine image and the command sleep 3600. Create the namespace if needed, ensure that the task in the pod runs once and after running once the pod stops.\n\n```bash\nk create ns run-once $do \u003e run-once.yml\nk apply -f run-once.yml\nk create job xxazz-pod --image=alpine --namespace=run-once $do \u003e xxazz-pod.yml -- sleep 3600\nk apply -f xxazz-pod.yml\n```\n\nCreate deployment that runs nginx based on 1.14 version. After creating it enable recording and perform a rolling upgrade to upgrade to the latest nginx version.\nAfter successfully performing the upgrade undo the upgrade again.\n```bash\nk create deploy nginx --image=nginx:1.14 $do \u003e nginx.yml\nk apply -f nginx.yml\nk set image deploy nginx nginx=nginx:latest --record\nk rollout undo deployment nginx \n```\n\nFind all kubernetes objects in all namespaces that have the label k8s-app set tp the value kube-dns\n```bash\nk get all -A -l k8s-app=kube-dns\n```\n\nCreate a configMap that defines the variable myuser=mypassword.\nCreate a pod that runs alpine and uses this variable from the ConfigMap\n```bash\nk create cm myuser --from-literal=myuser=mypassword $do \u003e myuser.yml\nk apply -f myuser.yml\nk run alpine --image=alpine $do \u003e alpine.yml\nk apply -f alpine.yml\nk set env po/alpine --from=cm/myuser $do \u003e alpine.yml\nk delete po alpine --force --grace-period=0\nk apply -f alpine.yml\n```\n\nCreate a solution that runs multiple pods in parallel. The solution should start Nginx and ensure that it is started on every node in the cluster in a way that if a new node is added, an Nginx pod is automatically added to the node as well.\n```\nk create deploy nginx --image=nginx $do \u003e nginx.yml\nvi nginx.yml\n```\n```yml\napiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  labels:\n    app: nginx\n  name: nginx\nspec:\n  selector:\n    matchLabels:\n      app: nginx\n  template:\n    metadata:\n      creationTimestamp: null\n      labels:\n        app: nginx\n    spec:\n      # Allow scheduling on master node\n      tolerations:\n      - effect: NoSchedule\n        key: node-role.kubernetes.io/master\n        operator: \"Equal\"\n      containers:\n      - image: nginx\n        name: nginx\n```\n\nMark node worker2 as unavailable and ensure all pods are moved away from the local node and started again somewhere else \n```\nk drain kworker2.example.com --ignore-daemonsets --delete-local-data\n```\nAfter successfully executing this task make sure worker2 can be used again\n```\nk uncordon kworker2.example.com\n```\n\nPut worker2 in maintenance mode so that no new pods can be scheduled on it \n```\nk cordon kworker2.example.com\n```\n\nAfter successfully executing this task undo it \n```\nk uncordon kworker2.example.com\n```\n\nCreate a backup of the etcd database. Write the backup to /var/exam/etcd-backup\n```bash\nmkdir -p /var/exam/etcd-backup\nETCDCTL_API=3 etcdctl snapshot save \\ \n--cacert /etc/kubernetes/pki/etcd/ca.crt \\ \n--cert /etc/kubernetes/pki/etcd/server.crt \\ \n--key /etc/kubernetes/pki/etcd/server.key \n/var/exam/etcd-backup/etcd.db\n\n$ ETCDCTL_API=3 etcdctl snapshot status --write-out=\"table\" /var/exam/etcd-backup/etcd.db\n+----------+----------+------------+------------+\n|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |\n+----------+----------+------------+------------+\n| b59c7550 |  1497728 |       1449 |     5.8 MB |\n+----------+----------+------------+------------+\n```\n\nStart a pod that runs busybox image. use the name `busy33` for this pod. Expose this pod on a cluster IP address. Configure the pod and service such that DNS name resolution is possible, and use `nslookup` command to look up the names of both. write the output of DNS lookup command to /var/exam/dnsnames.txt\n```bash\n# DNS Doesn't work correctly on latest busybox so use image \u003c= 1.28\nk run busy33 --image=busybox:1.28 $do \u003e busy33.yml --command sleep 3600\nk apply -f busy33.yml\nk expose pod busy33 --port=53 --target-port=53 --type=ClusterIP\nk exec -it busy33 -- sh \n\n/ # nslookup busy33\nServer:    10.96.0.10\nAddress 1: 10.96.0.10\n\nName:      busy33\nAddress 1: 10.244.2.177 busy33\n```\n\nConfigure your node worker2 to auto start a pod that runs an Nginx webserver using the name auto-web\n```bash\nk run auto-web --image=nginx $do \u003e nginx.yml\nscp nginx.yml vagrant@kworker2.example.com:/etc/kubernetes/manifests/\n```\n\nFind the pod with the highest CPU load \n```\nk top pod --sort-by=cpu -A | head -n 2\n```\n\n---\n\n\n\n### Good to know:\n- Creating custom resource definitions [crd]\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthejaxon%2Fcka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthejaxon%2Fcka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthejaxon%2Fcka/lists"}