Kubernetes
Install and Deploy
- install kubectl
- install minikube
Commands:
minikube start
minikube status
kubectl get node
kubectl get pods
kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.4
kubectl expose deployment hello-minikube --type=NodePort --port=8080
minikube service hello-minikube --url
curl http://192.168.49.2:31223
kubectl delete deployments.apps hello-minikube
minikube pause
minikube unpause
minikube stop
Namespaces
- for organization and resource separation
kubectl --namespace=mystuff
orkubectl -n=mystuff
kubectl --all-namespaces
Default namespaces for new clusters:
$ kubectl get ns
NAME STATUS AGE
default Active 13m # k8s resources are crated here by default
kube-node-lease Active 13m # storage for node lease information
kube-public Active 13m # world-readable
kube-system Active 13m # infrastructure pods
Commands:
kubectl get all --all-namespaces # all objects in all ns
kubectl get pods -n default # all pods in default ns
kubectl api-resources | grep -iE 'namespace|KIND' # get res name: Namespace
kubectl explain Namespace | head -n 2 # get its version
# create app-ns.yml
kubectl create -f app-ns.yml
kubectl create ns dev
kubectl get ns
kubectl describe ns dev
kubectl get ns default -o yaml
# create nginx-app.yml
kubectl create -f nginx-app.yml
kubectl get pods -n default nginx-app # not found
kubectl get pods -n app nginx-app # found
kubectl delete ns dev # delete everything in a ns incl.
kubectl delete pods -n app --all # keep namespace, delete all pods
kubectl delete all -n app --all # delete all
Pods
- declarative way: uses yaml files, like nginx-app.yml above
- imperative way: uses
kubectl
- a pod contains containers. Usually one. If a pod has more than one containers, they are always executed on a single worker, never span to multiple workers.
Examples:
kubectl create -f nginx.yml
kubectl get pods -o wide
kubectl describe pod nginx # shows the node
docker ps # get status on the node
kubectl exec -it nginx -c nginx -- /bin/bash
kubectl port-forward nginx 8000:80
multi-container Pods use-cases
- sidecar container: enhances primary app, e.g. logging. Both are closely related.
- ambassador container: a container represents a primary container for outside e.g. proxy
- adapter container: to adapt/normalize traffic for other apps inside
Examples:
# create create-sidecar.yml
kubectl create -f create-sidecar.yml
kubectl get pods -o wide
$ kubectl exec -it sidecar-pod -c sidecar -- /bin/bash
[root@sidecar-pod /]# curl http://localhost/date.txt
Sun Feb 21 08:53:05 UTC 2021
Sun Feb 21 08:53:15 UTC 2021
Sun Feb 21 08:53:25 UTC 2021
Sun Feb 21 08:53:35 UTC 2021
Sun Feb 21 08:53:45 UTC 2021
Sun Feb 21 08:53:55 UTC 2021
Sun Feb 21 08:54:05 UTC 2021
Sun Feb 21 08:54:15 UTC 2021
Sun Feb 21 08:54:25 UTC 2021
Sun Feb 21 08:54:35 UTC 2021
Sun Feb 21 08:54:45 UTC 2021
[root@sidecar-pod /]#
kubectl logs sidecar-pod sidecar # show logs
kubectl delete pod nginx
Jobs
completitions=m # stop after `m`
parallelism=n # `n` jobs are started
Examples:
kubectl explain Job
# create k8s/pod-simple-job.yml
kubectl create -f k8s/pod-simple-job.yml
kubectl get pods # each execution will add one more pod
kubectl get jobs
kubectl delete job pod-simple-job
.spec.activeDeadlineSeconds
to set an execution deadline no matter how many pods are created.
Init containers
- run in the same pod as main container
- to complete a task before the regular container is started
- if a pod restarts, all init containers are executed again
Example:
$ cat pod-init-container.yml
...
$ k create -f pod-init-container.yml
$ k get pods
NAME READY STATUS RESTARTS AGE
init-container-example-1 0/1 Init:0/1 0 58s
Rolling Updates
- A
Replica Set
manages pods. ADeployment
manages aReplica Set
. - property:
minReadySeconds
how long the pod should be ready before it is treated as available. Until it is available, the rollout will not continue. maxSurge
- max number of pods that can be created over the desired number ofReplicaSet
before updatingmaxUnavailable
- max number of pods that can be unavailable during rollout
Examples:
k create deployment nginx-deploy --image=nginx --dry-run=client -o yaml > nginx-deploy.yml
# adapt nginx-deploy.yml
k create -f nginx-deploy.yml
k get deployments
k get rs # replica set
# rolling deployment example
k create -f rolling-nginx.yml
k get pods
k get deployments
k get event --field-selector involvedObject.name=rolling-nginx-74cf96d8bb-bn9jq # filter for pecific pod
k rollout history deployment rolling-nginx # show rollout history (no record)
k delete deployments.apps rolling-nginx
k create -f rolling-nginx.yml --record # add change cause to history
k set image deployment rolling-nginx nginx=nginx:1.15 --record # changes will be recorded
kubectl set image deployment rolling-nginx nginx=nginx:1.15 --record
k rollout status deployment rolling-nginx # status of deployment
# pause and resume deployment
$ k set image deployment rolling-nginx nginx=nginx:1.16 --record
$ k rollout pause deployment rolling-nginx
$ k rollout status deployment rolling-nginx
Waiting for deployment "rolling-nginx" rollout to finish: 2 out of 4 new replicas have been updated...
$ k get pods -l app=rolling-nginx
NAME READY STATUS RESTARTS AGE
rolling-nginx-74cf96d8bb-4pbs2 1/1 Running 0 88s
rolling-nginx-74cf96d8bb-8t2gf 1/1 Running 0 90s
rolling-nginx-74cf96d8bb-jklcv 1/1 Running 0 90s
rolling-nginx-765c4fc67d-dfqgs 0/1 ContainerCreating 0 20s
rolling-nginx-765c4fc67d-nm5sr 0/1 ContainerCreating 0 20s
$ kubectl rollout resume deployment rolling-nginx
# rollback
$ k rollout undo deployment rolling-nginx --to-revision=2
Labels
- key: value pairs for categorization.
- Annotations are labels that won’t need to be queried against.
Selectors:
tier = frontend
tier != frontend
tier != frontend, game = super-shooter-2
environment in (production, qa)
tier notin (frontend, backend)
partition # all pods that have partition label - no mater what value
env in (prod, qa), tier notin (fe, be), partition # joining
kubectl examples:
# Assign labels while creating new objects
k create deployment label-nginx-example --image=nginx --dry-run=client -o yaml > label-nginx-example.yml
# edit the file
k create -f label-nginx-example.yml
k get deployments --show-labels
k get pods --show-labels
# Assign new label to existing pod runtime as patch
k patch deployment label-nginx-example --patch "$(cat update-label.yml)"
k describe deployment label-nginx-example
k get pods --show-labels
# Assign a new label to existing deployments using kubectl
k create -f nginx-deploy.yml
k get deployments.apps --show-labels
k label deployment nginx-deploy tier=backend
k get deployments.apps --show-labels # `tier` added for nginx-deploy
# List resource objects
k get pods --selector 'app=prod'
k get pods --selector 'app=dev'
k get deployment --selector "app in (prod, dev)"
# Removing labels
k label deployment nginx-deploy type-
k get deployments.apps --show-labels
Replication Controller and Replica Sets
- A replication controller is a k8s resource that ensures that its pods are always running.
- It ensures that exact number of pods always matches its label selector.
- If a Node is out of resources for creating new pods, it will automatically create new one on another available cluster node.
Examples:
# create replication-controller.yml
kubectl api-resources | grep -iE 'KIND|replication'
kubectl explain ReplicationController | head -n2 # find out version
kubectl create -f replication-controller.yml
kubectl get pods # three new pods
kubectl get rc # status and list of available rc
k delete pod myapp-rc-mgztn
k get pods # one is new
k get pods -o wide
k describe rc myapp-rc
# changing the pod template will affect only newly created pods
k edit rc myapp-rc # reduce replicas to 2
k get pods # one is terminating
k get rc # display status
k scale rc myapp-rc --replicas=6 # horizontal scaling
k delete rc myapp-rc --cascade=false # to keep its pods running
ReplicaSets
- ReplicaSet deprecates ReplicationController. It has more expressive pod selectors. It can match pods lacking a certain selector or just having a key regardless of the value.
- Pods aren’t owned by RC/RS and can be moved between them if necessary.
Examples:
k api-resources | grep -iE 'KIND|replica'
k explain ReplicaSet | head -n 2
k apply -f replica-set.yml # to manage orphaned pods `app=myapp`
k get rs
k describe rs myapp-replicaset
k delete rs myapp-replicaset
k apply -f replica-set2.yml
kubectl scale rs myapp-replicaset --replicas=6
k delete rs myapp-replicaset
Kubernetes Services
- A Kubernetes Service provides a single, constant (pod are ephemeral) entry point to a group of pods providing the same service.
- The kube-proxy agent on the nodes watches the k8s API for new services and endpoints.
DaemonSets
- A DaemonSet ensures that a Pod is running across a set of nodes.
- Deploy system daemons like log collectors and monitoring agents.
Examples:
kubectl api-resources | grep -iE 'KIND|daemonse'
kubectl explain DaemonSet | head -n 2
k create -f fluentd-daemonset.yml
k get ds # inspect daemonsets
k get pods -o wide
# deploy on specific nodes only (label `sdd: true`)
k create -f nginx-daemonset.yml
k get ds # desired = 0
k get nodes --show-labels
k label nodes minikube ssd=true
k get ds # desired = 1
k label nodes minikube ssd- # remove label
k get ds
k delete ds nginx-fast-storage fluentd # use --cascade to keep pods
Scheduling Jobs
kubectl api-resources | grep -iE 'KIND|cron'
kubectl explain cronjob.spec
kubectl explain cronjob.spec.schedule # alternative
# create pod-cronjob.yml
k create -f pod-cronjob.yml
k get cronjobs.batch # list avail. jobs
k get jobs --watch # monitor status
k get pods # show completed pods
k delete cronjobs.batch pod-cronjob
Volumes
- pods have isolated FS.
- Storage volumes aren’t top level resources like pods, but are defined a s components of the pod.
- Aren’t standalone kubernetes objects and cannot be created or deleted on their own.
- Volumes live with a Pod across a container life cycle.
Types of volumes (Volume Type: Storage Provider):
- emptyDir: Localhost. Simplest volume type. Will be ereased, when the Pod is removed.
- hostPath: Localhost
- glusterfs: GlusterFS cluster
- downwardAPI: Kubernets Pod Information
- nfs: NFS server
- awsElasticBlockStore: AWS Elastic Block Store
- gcePersistentDsik: Google Compute Engine persistent disk
- azureDisk: Azure disk storage
- projected: Kubernetes resources; currently: secret, downwardAPI and configMap
- secret: K8s secret resource
- vSphereVolume: vSphere VMDK volume
- gitRepo: git repository (volume content will be deleted when Pod is removed)
Once you define volumes in volumes
section, you can start using them in the volumeMounts
section.
Examples:
k create -f shared-volume-emptyDir.yml
k get pods shared-volume-emptydir
k get pod shared-volume-emptydir -o json
k exec -it shared-volume-emptydir -c alpine1 -- touch /alpine1/someFile.txt
k exec -it shared-volume-emptydir -c alpine2 -- ls -l /alpine2
To create the dir in memory using tmpfs:
volumes:
- name: data
- emptydir:
medium: Memory
This gives instead:
$ k exec -it shared-volume-memory -c alpine2 -- df -h /alpine2
Filesystem Size Used Available Use% Mounted on
tmpfs 1.4G 0 1.4G 0% /alpine2
Instead of original:
$ k exec -it shared-volume-memory -c alpine2 -- df -h /alpine2
/dev/mapper/rhel-root
10.3G 7.9G 1.8G 81% /alpine2
hostPath
is the first type of persistent storage. Its contents are stored on a node’s FS. It is not a good idea to use hostPath
for regular poth, because it makes the app sensitive to pod scheduling. Examples:
k create -f shared-volume-hostpath.yml
k get pods shared-volume-hostpath -o wide # get the node IP
k exec -it shared-volume-hostpath -c alpine1 -- touch /alpine1/someFile.txt
[root@nodeIP]# ls -l /tmp/data/
total 0
-rw-r--r-- 1 root root 0 Jan 7 15:26 someFile.txt
NFS
First make sure that nfs-utils
package is installed on k8s minions. Check /etc/exports
and make sure it can be mounted using nfs -t nfs server:share mountpoint
. Examples:
kubectl create -f shared-volume-nfs.yml
kubectl get pods shared-volume-nfs -o wide # wait for Running
state
kubectl describe pod # check mounting status
K8s actually mounts server:share
into /var/lib/kubelet/pods/<id>/volumes/kubernetes.io-nfs/nfs
and then mounts it into the container as the destination /<mount-point>
.
Persistent Volumes
Capacity:
- K (kilobyte: 1000 bytes)
- Ki (kibibyte: 1024 bytes)
Volume mode is either Filesystem
(default) or Block
.
Access Modes:
- RWO - ReadWriteOnce - a single node can mount for RW
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
Storage is mounted to nodes, so even with RWO, multiple pods on the same node can mount the volume and write to it.
Reclaim Policy determines, what happens when a persistent volume claim is deleted:
- Retain: volume will need to be reclaimed manualy
- Delete: associated storage asset, such as AWS EBS, AzureDisk, OpenStack Cinder volume etc. is deleted.
- Recycle: delete content only. Allows the volume to be claimed again.
ATM Only NFS and HostPath
support recycling. AWS EBS, GCE PD, Azure Disk and Cinder volumes support deletion.
Example:
k api-resources | grep -iE 'KIND|persistent'
k explain PersistentVolume | head -n 2
k create - f persistent-volume.yml
# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-share-pv 1Gi ROX,RWX Recycle Available 18s
PersistentVolumes
don’t belong to any namespace. They are cluster-level resources like nodes.
PersistentVolumeClaim
Claiming a PersistentVolume
is completely separate process from creating a pod.
Example:
k explain PersistentVolumeClaim | head -n 2
[root@controller ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-share-pvc Bound nfs-share-pv 1Gi ROX,RWX
[root@controller ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-share-pv 1Gi ROX,RWX Recycle Bound default/nfs-share-pvc 7m26s
[root@controller ~]# kubectl describe pvc nfs-share-pvc
Name: nfs-share-pvc
Namespace: default
StorageClass:
Status: Bound
Volume: nfs-share-pv
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 1Gi
Access Modes: ROX,RWX
VolumeMode: Filesystem
Mounted By: <none>
Events: <none>
PV is now yours to use. Nobody else can claim it until you release it.
Using a PersistentVolumeClaim in a Pod
# kubectl create -f nfs-share-pod.yml
# kubectl get pods pod-nfs-share # make sure pod is Running
# kubectl exec -it pod-nfs-share -- df -h /var/www
Filesystem Size Used Avail Use% Mounted on
192.168.43.48:/nfs_share 14G 8.6G 4.1G 68% /var/www
Recycle Persistent Volumes:
k delete pod pod-nfs-share
k delete pvc nfs-share-pvc
[root@controller ~]# kubectl get pv # Status - Released
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-share-pv 1Gi ROX,RWX Recycle Released default/nfs-share-pvc 80m
If we would have used Retain
ReclaimPolicy
then we would have to manually clean up the data in order to bind the PersistentVolume
again.
Local Persistent Volumes with StorageClass
k create -f storage-class.yml
k get sc # check status
k create -f local-pv-sc.yml
k get pv
k describe pv local-pv
k create -f local-pvc.yml
k get pvc # STATUS = Pending
k describe pvc local-storage-claim
k create -f local-pv-pod.yml
k get pods local-pod # make sure it is `Running`
k get pvc # STATUS=Bound
k get pv # STATUS=Bound
ConfigMaps
- Env-specfic data is provided to the application by the env it is deployed into.
- ConfigMap defines application related data.
Examples:
kubectl create configmap my-config
--from-file=foo.json # single file
--from-file=bar=foo.json # single file stored under custom key
--from-file=config-opts/ # dir
--from-literal=foo=bar # literal value
kubectl create cm nginx-cm --from-file nginx-custom-config.conf
k get cm
k create -f nginx-cm.yml
k exec -it nginx-cm -- cat /etc/nginx/conf.d/default.conf
# create CM using CLI args
k create cm myconfig --from-literal=color=red
k get cm
k create -f test-cm-pod.yml
k exec -it test-pod -- env | grep COLOR
Kubernetes Secrets
- Indented to store small amount (1 MB for a secret) of sensitive data.
- A secret is base64 encoded, so we cannot treat it as secure.
- K8s ensures that Secrets are passed only to the nodes that are running Pods that need the respective secrets.
Examples:
k create secret generic test-secret --from-literal=user=deepak --from-literal=password=test1234
k get secrets test-secret -o yaml
echo dGVzdDEyMzQ= | base64 --decode
k create -f secret-busybox.yml
k exec -it secret-busybox -- /bin/sh
# cat data/password
# cat data/user
Defining secrets from a file:
k create secret generic secret-tls --from=file=server.crt --from-file=server.key
k describe secret secret-tls
k create -f secret-ls-pod.yml
k get pods secret-tls-pod
k exec -it secret-ls-pod -- /bin/sh
# ls -l /tls
Stateful sets
- Available from k8s 1.5 as a bond between the Pod and the Persistent Volume.
- Pods names consist of name-I where I is zero based index.
- Replaced Pods get the same name and hostname as the Pod that has been replaced.
- Limitations:
- storage for a given Pod must be provisioned by a PersistentVolume Provisioner
- deleting and/or scaling will not delete associated volumes.
- Headless Service is required to be responsible for the network identity of the Pods. You’re responsible for creating this Service.
- No guarantee on termination of pods on deletion. To achieve ordered and graceful termination of the pods, scale the StatefulSet down to 0 prior deletion.
- When using Rolling Updates with the default Pod Management Policy (OrderedReady), it’s possible to get into a broken state that requires manual intervention to repair.
Examples:
[root@controller ~]# exportfs -v
/share1 (sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
k create -f nfs-pv-share1.yml -f nfs-pv-share2.yml -f nfs-pv-share3.yml
k api-resources | grep -iE 'KIND|stateful'
k explain StatefulSet | head -n 2
k create -f nfs-stateful.yml
k get statefulsets # READY = 0/3
k get pvc # STATUS = Bound
k get pv
k get pods # no fancy names
k get pv # all claimed
k get pods -o wide
k exec -it nginx-statefulset-2 -c nginx-statefulset -- touch /var/www/pod3-file
[root@controller ~]# ls -l /share3/
total 0
-rw-r--r-- 1 root root 0 Jan 9 16:44 pod3-file
k delete pod nginx-statefulset-2
k get pods -o wide # new pod is being created with same IP and nodename
kubectl exec -it nginx-statefulset-2 -c nginx-statefulset -- ls -l /var/www/ # `pod3-file` is there
K8s API Server
- In k8s all communication between control plane and external clients (e.g. kubectl) are translated into REST API calls handled by the API server. The API server is the only component that talks directly with distributed storage etcd.
- API server responsibilities is to provide k8s API and to proxy cluster components (e.g. dashboard), stream logs, service ports or serve kubectl exec sessions.
- Master: etcd <-> API Server (Control Manager + Scheduler)
- Worker: kubelet, native app
- The API server is stateless and designed to scale horizontally. For HA it is recommended to have 3+ instances.
Examples:
k get pods -n kube-system
K8s HTTP Request flow: client (kubectl) + Service Account -> authentification -> authorization -> admission control -> etcd.
After the request is authenticated and authorized, it goes to the admission control modules. K8s comes with predefined admission controllers, but you can define custom ones as well.
Service Account + Roles
k apply -f service-account.yml -f cluster-role.yml -f cluster-role-binding.yml
k get pods --all-namespaces
k describe pod -n kube-system kube-apiserver-minikube
# forbidden - returned by authorization plugin
k --as=system:serviceaccount:default:read-only-user get pods --all-namespaces
k --as=system:serviceaccount:default:read-only-user describe pod -n kube-apiserver-minikube
# inquiry
k auth can-i get pods --all-namespaces # yes
k --as=system:serviceaccount:default:read-only-user auth can-i get pods --all-namespaces
k delete serviceaccount read-only-user
k delete clusterrole read-only-user-cluster-role
HTTP Interface of the API Server:
- POST: k create -f
- PUT: k apply -f
- GET: k get; k describe
- PATCH: k set image deployment/kuberserve nginx=nginx1.9.1
- DELETE: k delete
API resources and versions:
k api-resources
k api-versions
k explain pod # for any resource kind
K8s API via CLI:
k get --raw / # get all API resources
k get --raw /api/v1/namespaces | jq
k get --raw /api/v1/namespaces/default | jq
# access using curl
k proxy --port=9000
curl http://127.0.0.1:9000/apis | less
curl http://127.0.0.1:9000/apis/apps/v1/namespaces/default/deployments
Container’s Security Context
- Each pod gets its own IP and port space. Each pod has its own process tree, its own IPC namespace, allowing only processes in the same pod to communicate through IPC.
- Here we learn to allow pods to access resources of the node they’re running on.
Example:
k create -f pod-with-host-network.yml
k get pods
k exec pod-with-host-network -- ifconfig
# Allow pods to bind a port in the node's default namespace
# using `ports.hostPort`
# (only one instance of the pod can be schedules to each node)
k create -f nginx-lab.yml
curl 127.0.0.1:9000 # XXX doesn't work (because of minikube?)
# Using node's PID and IPC namespaces
k create -f pod-with-host-pid-and-ipc.yml
k exec pod-with-host-pid-and-ipc -- ps aux # includes container process
Configure container’s security context
# run with given user
$ k run pod-with-defaults --image alpine --restart Never -- /bin/sleep 99999
$ k exec pod-with-defaults -- id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
$ k create -f pod-as-user-guest.yml
$ k exec pod-as-user-guest -- id
uid=65534(nobody) gid=65534(nobody)
# run as non-root
k create -f pod-run-as-non-root.yml
k get po pod-run-as-non-root # STATUS=CreateContainerConfigError
k describe pods pod-run-as-non-root # Error: container has runAsNonRoot and image will run as root
# run in privileged mode (to get full access to node's kernel)
k create -f pod-privileged.yml
k exec -it pod-with-defaults -- ls /dev # 16
k exec -it pod-privileged -- ls /dev # 241
Individual Capabilities
# add individual capabilities to a container
k exec -it pod-with-defaults -- date +%T -s "12:00:00" # date: can't set date: Operation not permitted
k create -f pod-add-settime-capability.yml
k exec -it pod-add-settime-capability -- date +%T -s "12:00:00"; date
# drop individual capabilities from a container
k create -f pod-drop-chown-capability.yml
k exec pod-drop-chown-capability -- chown guest /tmp # operation not permitted
# ro FS
k create -f pod-with-readonly-filesystem.yml
k exec -it pod-with-readonly-filesystem -- touch /new-file # exit 1 - Read-only file system
k exec -it pod-with-readonly-filesystem -- touch /volume/newfile # works
k exec -it pod-with-readonly-filesystem -- ls -la /volume/newfile
Authentication
- Client certificates (most common) using X509 CA.
--client-ca-file=file_path
server option. - Static tokens: ``-token-auth-file=
. Tokens persist indefinitely and the API server needs to be restarted to update the tokens. Username and password are passed in the request header:
Authentication: Basic base64(user:password)` - Bootstrap tokens: are dynamically managed and stored as secrets in
kube-system
.--enable-bootstrap-token-auth
option for the CLI server. - Service account tokens:
--service-acount-key-file
- Authentication proxy:
--requestheader-{username-headers,group-headers,extra-headers-prefix}
arguments. - Webhook tokens:
authorization-webhook-config-file=
kubectl
uses certificates stores in ~/.kube/config
or /etc/kubernetes/admin.conf
.
Example using client certificates:
[root@controller ~]# kubectl config view | grep server
server: https://192.168.43.48:6443
[root@controller ~]# curl https://192.168.43.48:6443
curl: (60) SSL certificate problem: unable to get local issuer certificate
[root@controller ~]# export client=$(grep client-cert /etc/kubernetes/admin.conf | cut -d " " -f 6)
[root@controller ~]# export key=$(grep client-key-data /etc/kubernetes/admin.conf | cut -d " " -f 6)
[root@controller ~]# export auth=$(grep certificate-authority-data /etc/kubernetes/admin.conf | cut -d " " -f 6)
[root@controller ~]# echo $client | base64 -d - > client.pem
[root@controller ~]# echo $key | base64 -d - > client-key.pem
[root@controller ~]# echo $auth | base64 -d - > ca.pem
[root@controller ~]# curl --cert client.pem --key client-key.pem --cacert ca.pem https://192.168.43.48:6443 # works
Authorization
- Node. Enabled by default.
- ABAC: requests are validating policies against the attributes of the request.
--authorization-policy-file=
and--authorization-mode=ABAC
options. - RBAC. To enable start the API server with
--authorization-mode=RBAC
. - Webhooks (uses remote API server to check for permissions). Option
--authorization-webhook-config-file=
.
RBAC
kubeconfig:
- users: username and authentication mechanism
- clusters: all data necessary to connect to the cluster
- contexts: association between users and clusters
Create user example:
# create linux user
useradd -G nogroup user1
passwd user1
# create certs
openssl genrsa -out user1.key 4096
openssl req -new -key user1.key -out user1.csr -subj "/CN=user1/O=dev" # cert. signing request
# openssl x509 -req -in user1.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out user1.crt -days 365
openssl x509 -req -in user1.csr -CA ~/.minikube/ca.crt -CAkey ~/.minikube/ca.key -CAcreateserial -out user1.crt -days 365
# create namespace (optional)
k create namespace dev
# update k8s config with user credentials
k config view
k config set-credentials user1 --client-certificate=user1.crt --client-key=user1.key
k config view
# create security context for new user
k config set-context user1-context --cluster=kubernetes --namespace=dev --user=user1 # and set default namespace
k config get-contexts
k --context=user1-context get pods # XXX failed (minikube?)
Define new role with “modify” permission:
kubectl api-resources | grep -iE 'role|KIND'
k explain Role | head -n 2
k create -f dev-role.yml
k create -f user1-rolebind.yml
k --context=user1-context get pods # XXX failed (minikube?)
k -n dev describe role dev
k create deployment devnginx --image=nginx --context=user1-context
k get pods # not there
k get pods -n dev # but here
# testing
k auth can-i create pods --context=user1-context # yes
k auth can-i create service --context=user1-context # no
# Define role with "view-only" permission
k create namespace view-only
k create -f view-only-role.yml
k create -f view-only-rolebinding.yml
k config set-context viewonly-context --cluster=kubernetes --namespace=view-only --user=user1
k config get-contexts
k --context=viewonly-context get pods
k -n view-only describe role view-only
k create deployment testnginx --image=nginx --context=viewonly-context # FORBIDDEN
k auth can-i create pods --context=viewonly-context # no
k auth can-i get pods --context=viewonly-context # yes
k auth can-i get service --context=viewonly-context # no
Deleting Context, Role, RoleBinding:
k config delete-context user1-context
k config delete-context viewonly-context
k delete role dev -n dev
k delete rolebinding dev-role-binding -n dev
Limit Resources
- Resource quota is applied on the namespace.
- Resource limit is applied on the containers.
- If creating or updating a resource violates a quota contraint -> HTTP 403.
- Is quota enabled in a namespace for compute resources (cpu, mem), users must specify requests or limits for those value, otherwise quota system may reject pod creation.
Resource quota types
Compute resources:
- limits.cpu: sum of CPU limits cannot exceed this value
- limits.memory: sum of memory limits cannot exceed this value
- requests.cpu: dtto for requests
- requests.memory: dtto for requests
Storage resource quota:
- requests.storage: total amount of requested storage across all persistent volume claims
- persistentvolumeclaims: maximum number of persistent volume claims allowed in the namespace
- .storageclass.storage.k8s.io/requests.storage: total amount of requested storage across all persistent volume claims associated wit the storage class name
- .storageclass.storage.k8s.io/persistentvolumeclaims: maximum number of persistent volume claims allowed in the namespace that are associated with the storage class name
- requests.ephemeral-storage: total amount of requested ephemeral storage across all pods in the namespace claims
- limits.ephemeral-storage: total amount of limits for empeheral storage across all pods in the namespace claims.
Object count quota:
- count/. for resources from non-core groups
- count/ for resources from the core group
Some of these:
count/persistentvolumeclaims
count/services
count/secrets
count/configmaps
count/replicationcontrollers
count/deployments.apps
count/replicasets.apps
count/statefulsets.apps
count/jobs.batch
count/cronjobs.batch
Example:
k create namespace quota-example
k apply -f ns-quota-limit.yml
k describe ns quota-example
k create -f pod-nginx-lab-1.yml
k -n quota-example scale deployment/example --replicas=5
k -n quota-example get events
k -n quota-example get pods # ready
k describe ns quota-example # show current
k delete deployments -n quota-example example
k delete ns quota-example
# count quota for pods
k create ns pods-quota-ns
k apply -f pod-quota-limit.yml
k get resourcequota -n pods-quota-ns # REQUEST pods: 0/2
k describe ns pods-quota-ns
k create -f nginx-example.yml
k get pods -n pods-quota-ns # READY 1/1
k -n pods-quota-ns scale deployment/nginx-1 --replicas=5
k get pods -n pods-quota-ns # 2
k -n pods-quota-ns get events # FailedCreate ...
k describe ns pods-quota-ns # 2/2
Limit Range
If a LimitRange object exists in a namespace, then any container created without the resource requests or limits configured will inherit these values from the limit range.
Example:
k create -f assign-limit-range.yml
k get limits -n pods-quota-ns # define-limit created $NOW
k describe ns pods-quota-ns
k describe limits -n pods-quota-ns define-limit # only the limits
k delete deployments.apps -n pods-quota-ns nginx-1
k get pods -n pods-quota-ns # 0
k apply -f nginx-example.yml
k describe pods -n pods-quota-ns nginx-1 # requests/limits inherited
k delete limitrange -n pods-quota-ns define-limit
Limiting resources
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.limits.hugepages-
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
spec.containers[].resources.requests.hugepages-
CPU:
- CPU unit is 1 core for cloud providers and 1 hyperthread for bare metal Intel processors
- .5 is half a core, or 500 m (mili-cores).
- Smallest addressable unit is 1m.
Memory:
- K/M/G/T/P/E suffix - 1000**N
- Ki/Mi/Gi/Ti/Pi/Ei - 1024**N
Example:
k create ns cpu-limit
k get ns
k create -f pod-resource-limit.yml
k get pods -n cpu-limit -o wide
k get pods -o wide
k describe pods frontend
k delete pods -n cpu-limit frontend
If no CPU limit is specified and there is no LimitRange
object, the countainer will use all the available CPU resources on the node it is running.
Expose containers to external networks
kubectl port forwarding
kubectl port-forward nginx 8888:80
curl localhost:8888
kubectl expose
k create deployment nginx-lab-1 --image=nginx --replicas=3 --dry-run=client -o yaml > nginx-lab-1.yml
k create -f nginx-lab-1.yml
k get pods | grep nginx-lab-1
k expose deployment nginx-lab-1 --type=NodePort --port=80
k get services
# ...
# nginx-lab-1 NodePort 10.108.128.242 <none> 80:31060/TCP 3s
k describe svc nginx-lab-1 # to get more info about the service
Ingress
- provide an externally visible URL to the service
- load balance traffic
- terminates SSL
- provide name-based virtual hosting
Only creating an Ingress resource has no efect. You need to select and deploy one to your cluster (many implementations, e.g. nginx or HAProxy).
minikube version
kubectl get nodes
minikube addons enable ingress
k get pods -n kube-system # ingress-nginx-*
Configure Ingress using Host
k create deployment nginx --image=nginx
k scale deployment nginx --replicas=3
k get deployments
k expose deployment nginx --type=NodePort --port=80
k get service
minikube service nginx --url # or `ip a`
# add this to /etc/hosts as host.example.com
k create -f nginx-ingress-rule.yml
k get ingress
k get ing nginx-ingress -o yam
curl http://host.example.com
Configure Ingress using Path
k create deployment web2 --image=nginx
k scale deployment web2 --replicas=3
k expose deployment web2 --type=NodePort --port=80
k get svc # +web2
minikube service web2 --url
# vi nginx-ingress-rule.yml
k apply -f nginx-ingress-rule.yml
k get ing nginx-ingress -o yaml
curl http://host.example.com/v2