Kubernetes API
Let’s see how to play K8s in MacOs using MniKube. Some of the topics are very basic such as How to create a namespace and pod in it. Shelling to the pod and after delete pod and the namespace. However, this is written to address the concepts such as configMap, secrets, resource sharing and Helm charts.
- Minikube
- Create namespace and pod
- Interacting with pod
- Delete resources
- ConfigMaps
- Secrets
- Security Context
- Resource Sharing
- Service Account
- Helm
- Chart
Minikube
Find the latest support Minikube supported Kubernetes version from here, and you can start the Minikube as follows
minikube start --cpus=2 --memory=4000 --kubernetes-version=v1.23.3
you can find component status:
kubectl get componentstatus
Display the nodes
kubectl get nodes
Find the cluster information:
kubectl cluster-info
The above command will create a default
namespace.
kubectl get namespaces
Login to the docker instance of Minikube
minikube ssh
You can get the IP address of the docker instance using minikube ip
.
Create namespace and pod
To create a new namespace:
kubectl create namespace <namespace>
To list the namespaces available.
kubectl get namespaces
Create POD
kubectl run <pod-name> --image=nginx:2.3.5 --restart=Never --port=80 --namespace=<namespace>
Or simply kubectl run ghost --image=ghost:0.9 -n testns
.
List all the pods in the namespace.
kubectl get pod -n <namespace>
for example kubectl get pods -n testns
:
To update the pod image.
kubectl set image pod <pod-name> mypod=nginx --namespace=<namespace>
The above command will use the latest version of the nginx
.
Check the latest status of the pod:
kubectl get pod -n <namespace>
Interacting with pod
Shelling to the pod
kubectl exec <pod-name> -it --namespace=<namespace> -- /bin/sh
Accessing pod logs:
kubectl logs <pod-name> -n <namespace>
You can create the pod from a yaml file.
Before going further delete the existing pod in the testns
namespace:
kubectl delete pod ghost -n testns
Create pod.yaml
using the following command:
kubectl run ghost --image=ghost:0.9 -n testns -o yaml --dry-run=client > pod.yaml
The above command will create the pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: ghost
name: ghost
namespace: testns
spec:
containers:
- image: ghost:0.9
name: ghost
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
Now deploy from the above pod.yaml
kubectl apply -f pod.yaml
If you list using kubectl get pods -n testns
, you will find the ghost pod.
Delete resources
Delete the pod
kubectl delete pod <pod-name> --namespace=<namespace>
delete the namespace
kubectl delete namespace <namespace>
For example, kubectl delete ns testns
.
Verify resources are delete
kubectl get pod, namespace
To delete Minikube
minikube stop
minikube delete --all
ConfigMaps
ConfigMaps decouple the configuration values needed at runtime from the definition of a Pod.
-
Create a
config.txt
file with the key-value pairs for each line to have one key-value pair. -
create configmap, for example,
db-config
map:kubectl create configmap db-config --from-env-file=config.txt
-
verify the config files are created
kubectl get configmaps
Or YAML
kubectl get configmap db-config -o yaml
-
Now generate the YAML file for your pod with dry run
kubectl run backend --image=nginx --restart=Never -o yaml --dry-run > pod.yaml
-
Add the configMap to that
spec: containers: - image: nginx name: backend envFrom: - configMapRef: name: db-config
-
now create the pod
kubectl create -f pod.yaml
-
Shell into the pod and verify
kubectl exec backend -it -- /bin/sh
Check within the pod bash
env | grep <key pattern>
Secrets
The way to maintain secret information, data should be base64 encoded. Secrets are only in memory and not written to the disk.
- generate the
db-credentials
kubectl create secret generic db-credentials --from-literal=db-password=<password>
- verify
kubectl get secrets
- check the YAML representation
kubectl get secret db-credentials -o yaml
-
Dry run to pod.xml
kubectl run backend --image=nginx --restart=Never -o yaml --dry-run > pod.yaml
-
update the pod.xml with
db-credentials
:spec: containers: - image: nginx name: backend env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-credentials key: db-password
-
Now, you can create a pod from the pod.xml file
kubectl create -f pod.yaml
-
Verify by shelling to the pod
kubectl exec backend -it -- /bin/sh
and
env | grep DB_PASSWORD
Security Context
Define access control to a pod or container. Default there is no pod or container security context available.
-
create a pod with a volume
kubectl run secured --image=nginx --restart=Never -o yaml --dry-run > sec.yaml
-
Edit the sec.yaml to have
spec: securityContext: fsGroup: 3000 containers: - image: nginx name: secured volumeMounts: - name: data-vol mountPath: /data/app resources: {} volumes: - name: data-vol emptyDir: {}
-
create a pod from the above sec.yaml
kubectl create -f sec.yaml
-
verify by login to the pod bash
kubectl exec -it secured -- /bin/sh
change the directory and create a file, then list the files and see the security group
cd /data/app touch test.txt ls -l
Resource Sharing
Resource quotation is bound to the namespace.
-
First, create a namespace
-
Create a YAML file with the resource definition
apiVersion: v1 kind: ResourceQuota metadata: name: app spec: hard: pods: "2" requests.cpu: "2" requests.memory: 500m
-
create a quota for the namespace
kubectl create -f <resource-quota>.yaml --namespace=<namespace>
-
Describe the quota for the namespace
kubectl describe quota --namespace=<namespace>
-
Create pod.xml in the above namespace with dry run
kubectl run <pod-name> --image=nginx --restart=Never -o yaml --dry-run > pod.yaml
-
under the resource section in the pod.xml
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: testpod name: testpod spec: containers: - image: nginx name: testpod resources: requests: memory: "200m" cpu: "400m" dnsPolicy: ClusterFirst restartPolicy: Never status: {}
If you change the
memory: "1G"
, you will get an error something similar to:error from server (Forbidden): error when creating "pod.yaml": pods "testpod" is forbidden: exceeded quota: app, requested: requests.memory=1G,...
And pod creation will be failed.
-
create a pod in the namespace
kubectl create -f pod.yaml --namespace=<namespace>
Service Account
Pod use a service account to communicate with the cluster API. There is a default service account always.
-
create a service account
kubectl create sa <sa-name>
This will create a secret for the service account automatically.
-
inspect the service account
kubectl get serviceaccount <sa-name> -o yaml
-
You can find the secret created
kubectl get secrets
You will get something similar to
<sa-name>-token-rg4b8
-
Assigning to the pod
kubectl run <pod-name> --image=nginx --restart=Never --serviceaccount=<sa-name>
-
To verify, get into the pod
kubectl exec -it backend -- /bin/sh
The same token is available at
cat /var/run/secrets/kubernetes.io/serviceaccount/token
Helm
This is the cluster administration tool for Kubernetes. Charts are source codes for infrastructure as code with the great help of dependency management, which can be packaged, named and under the version management. Charts define a composition of related Kubernetes resources and values that make up a deployment solution.
Install Helm on Mac:
brew install helm
you can verify the installation by running the following command:
helm env
You can find Helm artifact hub for chart repostiories.
search for postgresql
in the hub:
helm search hub postgresql
For example, narrow the charts and install
helm search hub redis | grep --color bitnami
the result will be
https://artifacthub.io/packages/helm/bitnami/redis 16.5.2 6.2.6 Redis(TM) is an open source, advanced key-value...
https://artifacthub.io/packages/helm/bitnami-ak... 16.5.2 6.2.6 Redis(TM) is an open source, advanced key-value...
https://artifacthub.io/packages/helm/bitnami-ak... 7.3.2 6.2.6 Redis(TM) is an open source, scalable, distribu...
https://artifacthub.io/packages/helm/bitnami/re... 7.3.2 6.2.6 Redis(TM) is an open source, scalable, distribu...
you can add Binami as respository
helm repo add bitnami https://charts.bitnami.com/bitnami
List the repos to verify
helm repo list
The advantage is that you can directly search the repository.
helm search repo bitnami/redis
You will get the following.
For additional information:
helm show chart bitnami/redis
read readme:
helm show readme bitnami/redis
context values:
helm show values bitnami/redis
Create a namespace
kubectl create namespace redis
before installing, create a Redis values YAML file:
replica:
replicaCount: 2
volumePermissions:
enabled: true
securityContext:
enabled: true
fsGroup: 1001
runAsUser: 1001
Install the chart
helm install test-redis bitnami/redis --version 16.5.2 --namespace redis --values redis-values.yaml
list the installation:
helm ls -n redis
To find the secrets are deployed to the namespace where the chart is deployed.
kubectl get secrets --all-namespaces | grep sh.helm
to read the secret:
kubectl --namespace redis describe secret sh.helm.release.v1.test-redis.v1
You can use watch
command (install on macOS using brew install watch
) to find out what was deployed:
watch kubectl get statefulsets,pods,services -n redis
Create persistent volume as specified in the pv.yaml:
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-volume1
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "./data1"
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-volume2
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "./data2"
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-volume3
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "./data3"
Run the following command to create the above-specified volumes:
kubectl apply -f pv.yaml
ensure Redis has permission to write to these volumes
mkdir ./data1 ./data2 ./data3 --mode=777
To get your password run:
export REDIS_PASSWORD=$(kubectl get secret --namespace redis test-redis -o jsonpath="{.data.redis-password}" | base64 --decode)
kubectl port-forward --namespace redis svc/test-redis-master 6379:6379 > /dev/null &
Create a Redis client to access the above-created Redis server
kubectl run --namespace redis redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:6.2.6-debian-10-r146 --command -- sleep infinity
if you check, you can verify Redis client has been created
use the following command to connect to the Redis client:
kubectl exec --tty -i redis-client --namespace redis -- bash
Inside the client, connect to the
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h test-redis-master
And type the PING. The output should be PONG
.
Uninstall Redis
helm delete test-redis -n redis
delete redis client
kubectl delete pod redis-client -n redis
delete redis namespace
kubectl delete namespace redis
Chart
Helm use Go templating API.
Create your chart.
helm create my-chart
to list the skeleton:
tree my-chart
Resource definition is in the template directory:
cat my-chart/templates/deployment.yaml | grep -color 'kind:' -n -B1 -A5
Injected container image for deployment
cat my-chart/templates/deployment.yaml | grep --color 'image:' -n -C3
for the above container image is injected to the { { .Values.image.repository } }
from the values.yaml
as shown in the below:
cat my-chart/values.yaml | grep --color 'repository' -n -C3
Let’s try dry run:
helm install my-app ./my-chart --dry-run --debug | grep --color 'image: "' -n -C3
You can override the default.
helm install my-app ./my-chart --dry-run --debug --set image.pullPolicy=Always | grep --color 'image: "' -n -C3
after the dry run investigate, as shown in the above screenshot, install the version change
helm install my-app ./my-chart --set image.pullPolicy=Always
helm list
kubectl get deployments,service