Since we know that etcd stores data and for having consistent data we
should not be allowing multiple things to modify data. This is where Api server
comes into picture.
The job of the api server is to mediate the communication between etcd
and other clients. The Api server is the only one who have access to the Etcd
server. When a client makes a call, he does that to Api server which in turn
connects to the etcd server to obtain data. Api server provides CRUD interface
for querying and modifying state over a RESTful API calls.
Besides Storing data,it also performs validation of those objects like
pod manifest etc. One another things that the API server does is to handle the
locking, so that call to change an objects from the API server are handled
correctly and never overridden by other clients in the event of concurrent
update.
Here are the steps as what happens inside the API Server,
Authentication
- Once the client request for creating a resource ( pod, Deployment )
comes to API , authentication is done to identify the client. Multiple
authentication plugins are configured in the Api server which will read
the request one after the another until one identifies the client sending
the request. Since the request are in Rest format which is HTTP request,
Api server will read the headers and identify the client by extracting the
user name , user id, group id etcAuthorization - Once the authentication is done, authorization comes into picture. More than one authorization plugins are configured to determine that the authenticated user can perform the action suggested in the request. For example, if a request for pod creation comes these plugins check if that user has the permission to create a pod, if so in what namespace etc
Admission Control Plugins - In the 3 stage
admission control plugins comes into picture. The Job of these is intercept the request
before the Api server persistent. It
intercepts the request and validates if anything is missing, values. For
example, let's say if we have a Namespace which has resource set and if we
are creating a pod in this namespace , these controls will set the limits for
the pod based on the namespace.
Etcd - The request is then stored in the etcd.
One important thing that we need to know is that Api server gets the
request from client and once all above steps are done it will save to the etcd
server. It will full-fill any requests like , if Api server receives a request
for pod creation it performs all the above steps and then store in the Etcd. It
will not create the pod or tell to any other component to create the pod.
One another important job that the Api server does is sending
notifications to the clients. For example , if a client request for creation of
the pod, the data is saved into the etcd and a notification is sent to the
interested parties. These interested parties can either create the pod or
perform some other action based on the notification sent by the APi server.
These interested parties can request for the changes from Api server that they
are interested in.
Clients or interested parties open a Http connection to the Api Server
and using this connection the client will receive notification ( like
modification , creation ) to the resources that are interested in or requested
for.
Kubectl is one of the client for Api server.Using the command “kubectl
get pods --watch”, we don’t need to poll for the list of pods in turn Api
server will send the details to the kubectl which is watching.
Exploring the Api Interface - Api is a library of functions and
procedures whose interfaces are exposed so that external applications can use
them. If we need to develop any scripts we need to have an understanding of the
functionality that is exposed by Kubernetes.
In many cases we will use the kubectl command to talk with the api server in performing the tasks. K8
Api is based on Rest implementation which means we can make a Rest call to the
api server using linux command line tools like curl or any other tool that can
make a rest call.
Api provides Url for endpoints and these endpoints provide access to
specific functionality. Let use the kubectl command to access Api. for this we
will run the “kubectl proxy” command from where we want to access the Api.
[root@manja17-I13330 ~]# kubectl proxy --port=8001 &
[1] 20120
[root@manja17-I13330 ~]# Starting to serve on
127.0.0.1:8001
The above command
starts a proxy to the Kubernetes API server.Now use the curl command to
access the Api as,
[root@manja17-I13330 ~]# curl http://localhost:8001/
{
"paths":
[
"/api",
"/api/v1",
"/apis",
"/apis/",
"/apis/admissionregistration.k8s.io",
"/apis/admissionregistration.k8s.io/v1beta1",
"/apis/apiextensions.k8s.io",
"/apis/apiextensions.k8s.io/v1beta1",
"/apis/apiregistration.k8s.io",
"/apis/apiregistration.k8s.io/v1",
"/apis/apiregistration.k8s.io/v1beta1",
"/apis/apps",
"/apis/apps/v1",
"/apis/apps/v1beta1",
"/apis/apps/v1beta2",
"/apis/authentication.k8s.io",
"/apis/authentication.k8s.io/v1",
"/apis/authentication.k8s.io/v1beta1",
"/apis/authorization.k8s.io",
"/apis/authorization.k8s.io/v1",
"/apis/authorization.k8s.io/v1beta1",
"/apis/autoscaling",
"/apis/autoscaling/v1",
"/apis/autoscaling/v2beta1",
"/apis/batch",
"/apis/batch/v1",
"/apis/batch/v1beta1",
"/apis/certificates.k8s.io",
"/apis/certificates.k8s.io/v1beta1",
"/apis/events.k8s.io",
"/apis/events.k8s.io/v1beta1",
"/apis/extensions",
"/apis/extensions/v1beta1",
"/apis/networking.k8s.io",
"/apis/networking.k8s.io/v1",
"/apis/policy",
"/apis/policy/v1beta1",
"/apis/rbac.authorization.k8s.io",
"/apis/rbac.authorization.k8s.io/v1",
"/apis/rbac.authorization.k8s.io/v1beta1",
"/apis/storage.k8s.io",
"/apis/storage.k8s.io/v1",
"/apis/storage.k8s.io/v1beta1",
"/healthz",
"/healthz/autoregister-completion",
"/healthz/etcd",
"/healthz/ping",
"/healthz/poststarthook/apiservice-openapi-controller",
"/healthz/poststarthook/apiservice-registration-controller",
"/healthz/poststarthook/apiservice-status-available-controller",
"/healthz/poststarthook/bootstrap-controller",
"/healthz/poststarthook/ca-registration",
"/healthz/poststarthook/generic-apiserver-start-informers",
"/healthz/poststarthook/kube-apiserver-autoregistration",
"/healthz/poststarthook/rbac/bootstrap-roles",
"/healthz/poststarthook/start-apiextensions-controllers",
"/healthz/poststarthook/start-apiextensions-informers",
"/healthz/poststarthook/start-kube-aggregator-informers",
"/healthz/poststarthook/start-kube-apiserver-informers",
"/logs",
"/metrics",
"/openapi/v2",
"/swagger-2.0.0.json",
"/swagger-2.0.0.pb-v1",
"/swagger-2.0.0.pb-v1.gz",
"/swagger.json",
"/swaggerapi",
"/version"
]
}
Each of the above line talks about the interface that is being exposed
by the kubernetes. Let's check for a specific interface,
[root@manja17-I13330 ~]# curl http://localhost:8001/api/v1
| less
{
"kind":
"APIResourceList",
"groupVersion": "v1",
"resources": [
{
"name": "bindings",
"singularName": "",
"namespaced": true,
"kind": "Binding",
"verbs": [
"create"
]
},
*******
If we can see that this is a APIResourceList kind which provides
various resource bindings. If we grep the above command more specifically we
can see,
[root@manja17-I13330 ~]# curl http://localhost:8001/api/v1
| grep name | grep -v namespaced
"name": "bindings",
"name": "componentstatuses",
"name": "configmaps",
"name": "endpoints",
"name": "events",
"name": "limitranges",
"name": "namespaces",
"name": "namespaces/finalize",
"name": "namespaces/status",
"name": "nodes",
"name": "nodes/proxy",
"name": "nodes/status",
"name": "persistentvolumeclaims",
"name": "persistentvolumeclaims/status",
"name": "persistentvolumes",
"name": "persistentvolumes/status",
"name": "pods",
"name": "pods/attach",
"name": "pods/binding",
"name": "pods/eviction",
"name": "pods/exec",
"name": "pods/log",
"name": "pods/portforward",
"name": "pods/proxy",
"name": "pods/status",
"name": "podtemplates",
"name": "replicationcontrollers",
"name": "replicationcontrollers/scale",
"name": "replicationcontrollers/status",
"name": "resourcequotas",
"name": "resourcequotas/status",
"name": "secrets",
"name": "serviceaccounts",
"name": "services",
"name": "services/proxy",
"name": "services/status",
This is the same that we will be using when defining a manifest file.
For example if we are creating a name space ,we define the manifest file as
[root@manja17-I13330 kubenetes-config]# cat
basic-namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name:
sample-testing
We can the first element that is being passed it the apiVersion: v1
which in turn uses these. This also talks about what operations that can be
performed using the namespaces. If you hit the api server with above command
and check for the namespace element, we see
{
"name": "namespaces",
"singularName": "",
"namespaced": false,
"kind": "Namespace",
"verbs": [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch"
],
"shortNames": [
"ns"
]
},
It gives all the operations that can be done on the namespaces. If you
want to find out all the available namespaces currently exist we can use,
[root@manja17-I13330 kubenetes-config]# curl
http://localhost:8001/api/v1/namespaces | grep name | grep -v
"selfLink"
"name": "default",
"name": "kube-public",
"name": "kube-system",
Using this “curl http://localhost:8001/api/v1/namespaces/default/pods” we can a list
of all pods running in the default namespace
Now if we need to find more details about a pod running in a namespace
we can use,
[root@manja17-I13330 kubenetes-config]# curl
http://localhost:8001/api/v1/namespaces/default/pods/my-nginx
{
"kind":
"Pod",
"apiVersion": "v1",
"metadata": {
"name":
"my-nginx",
"namespace": "default",
"selfLink":
"/api/v1/namespaces/default/pods/my-nginx",
"uid":
"e68afd34-8f0d-11e8-a791-020055e1ea1d",
"resourceVersion": "7837400",
"creationTimestamp": "2018-07-24T06:50:50Z",
"labels": {
"env":
"dev"
}
},
"spec": {
"volumes": [
{
"name": "default-token-fx8mm",
"secret": {
"secretName": "default-token-fx8mm",
"defaultMode": 420
}
}
],
"containers": [
{
"name":
"my-nginx",
"image": "nginx",
"ports": [
{
"containerPort": 80,
"protocol": "TCP"
}
],
"resources": {
},
"volumeMounts": [
{
"name": "default-token-fx8mm",
"readOnly": true,
"mountPath":
"/var/run/secrets/kubernetes.io/serviceaccount"
}
],
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"imagePullPolicy":
"Always"
}
],
"restartPolicy": "Always",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "default",
"serviceAccount": "default",
"nodeName": "manja17-i14021",
"securityContext": {
},
"schedulerName": "default-scheduler",
"tolerations": [
{
"key": "node.kubernetes.io/not-ready",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
},
{
"key": "node.kubernetes.io/unreachable",
"operator": "Exists",
"effect": "NoExecute",
"tolerationSeconds": 300
}
]
},
"status":
{
"phase": "Running",
"conditions": [
{
"type": "Initialized",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2018-07-24T06:49:26Z"
},
{
"type": "Ready",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2018-07-24T06:49:36Z"
},
{
"type": "PodScheduled",
"status": "True",
"lastProbeTime": null,
"lastTransitionTime": "2018-07-24T06:50:50Z"
}
],
"hostIP": "10.131.36.181",
"podIP": "10.38.0.3",
"startTime":
"2018-07-24T06:49:26Z",
"containerStatuses": [
{
"name": "my-nginx",
"state": {
"running": {
"startedAt": "2018-07-24T06:49:36Z"
}
},
"lastState": {
},
"ready": true,
"restartCount": 0,
"image": "docker.io/nginx:latest",
"imageID":
"docker-pullable://docker.io/nginx@sha256:4a5573037f358b6cdfa2f3e8a9c33a5cf11bcd1675ca72ca76fbe5bd77d0d682",
"containerID": "docker://ac58e1679ffb9c74063431ae280fce7d35fa55e99883ef70c235d5e32b427416"
}
],
"qosClass": "BestEffort"
}
}
No comments :
Post a Comment