k8s 创建mysql pv k8s 创建pod api_k8s 创建mysql pv


所有demo都是用本地的minikube运行

Pods in Kubernetes

Pods在k8s中代表一系列共享一套环境的Container. 在k8s中 pods就是部署的最小单元,一个Pods里的东西肯定在一台机器上. 在一个Pods中跑的Application会共享一个IP以及网络名称,Hostname。 但需要记住的是,不同Pods中跑的Application是不共享IP地址以及其他信息的。

The Pod Manifest

我们通过Pod manifest来描述pod.Pod manifest.其实就是一个K8s Api对象的文本表达。 在K8s中我们很多使用都会使用声明式的配置(declarative configuration)来进行部署。

K8s的API server会接受并且处理Pod manifest并存储到Persistent storage(etcd)中。

当然,虽然我们可以直接部署Pods,但是在实际生产中更好的控制多个pod实例的方法是ReplicaSets.

Creating a Pod

命令式的创建一个pod很简单:


$ kubectl run kuard --generator=run-pod/v1  --image=gcr.io/kuar-demo/kuard-amd64:blue


然后通过下面命令得到Pods的status


$ kubectl get pods

NAME                          READY   STATUS    RESTARTS   AGE
kuard                         1/1     Running   1          2d6h


我们可以通过delete命令删除pods


$ kubectl delete pods/kuard

pod "kuard" deleted


Creating a Pod Manifest

一般使用YAML文件来写Pod manifests(更易读,写comments)

下面是一个kuard-pod.yaml的文件示例。。我们可以创建完这个文档后可以直接通过kubectl来创建pods


apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:blue
      name: kuard
      ports:
        - containerPort: 8080
          name: http
          protocol: TCP


然后创建Pods


$ kubectl apply -f kuard-pod.yaml

pod/kuard created


这个Pod manifest会被提交到K8s的api server上。然后k8s 系统就会调配资源让这个pod在集群中健康的机器上开始运行。

Listing Pods

获得所有pods的信息


$ kubectl get pods

NAME       READY     STATUS    RESTARTS   AGE
kuard      1/1       Running   0          44s


如果我们在部署完马上跑这个命令的话会显示如下情况,说明pod还没ready


NAME       READY     STATUS    RESTARTS   AGE
kuard      0/1       Pending   0          1s


Pending说明pods已经被提交但是还没有被k8s schedule。我们加入-o wide可以得到更多信息


$ kubectl get pods -o wide

NAME                          READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
kuard                         1/1     Running   0          5m53s   172.18.0.3   minikube   <none>           <none>
nginx-delp-7785f59c75-dqnpf   1/1     Running   1          2d21h   172.18.0.4   minikube   <none>           <none>


加入-o json或者-o yaml可以得到完整的文件


$ kubectl get pods -o yaml

apiVersion: v1
items:
- apiVersion: v1
  kind: Pod
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"kuard","namespace":"default"},"spec":{"containers":[{"image":"gcr.io/kuar-demo/kuard-amd64:blue","name":"kuard","ports":[{"containerPort":8080,"name":"http","protocol":"TCP"}]}]}}
    creationTimestamp: "2020-09-09T11:29:33Z"
    managedFields:
    - apiVersion: v1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:annotations:
            .: {}
            f:kubectl.kubernetes.io/last-applied-configuration: {}
        f:spec:
          f:containers:
            k:{"name":"kuard"}:
.........


Pod Details

可以通过describe 命令得到更详细的信息


$ kubectl describe pods kuard

Name:         kuard
Namespace:    default
Priority:     0
Node:         minikube/172.17.0.2
Start Time:   Wed, 09 Sep 2020 19:29:33 +0800
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"kuard","namespace":"default"},"spec":{"containers":[{"image":"gcr.io/...
Status:       Running
IP:           172.18.0.3
IPs:
  IP:  172.18.0.3
Containers:
  kuard:
    Container ID:   docker://1ee2a3aa1d2c38c40a7a66e8dbd95191b794eb1d76d70d1c09c59fefad2a9edd
    Image:          gcr.io/kuar-demo/kuard-amd64:blue
    Image ID:       docker-pullable://gcr.io/kuar-demo/kuard-amd64@sha256:1ecc9fb2c871302fdb57a25e0c076311b7b352b0a9246d442940ca8fb4efe229
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 09 Sep 2020 19:29:34 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-sw49t (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-sw49t:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-sw49t
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned default/kuard to minikube
  Normal  Pulled     7m56s      kubelet, minikube  Container image "gcr.io/kuar-demo/kuard-amd64:blue" already present on machine
  Normal  Created    7m56s      kubelet, minikube  Created container kuard
  Normal  Started    7m55s      kubelet, minikube  Started container kuard


在这份输出中,开头是pods的基础信息


Name:           kuard
Namespace:      default
Node:           node1/10.0.15.185
Start Time:     Sun, 02 Jul 2017 15:00:38 -0700
Labels:         <none>
Annotations:    <none>
Status:         Running
IP:             192.168.199.238
Controllers:    <none>


然后是pods中运行的container的信息


Containers:
  kuard:
    Container ID:  docker://055095…
    Image:         gcr.io/kuar-demo/kuard-amd64:blue
    Image ID:      docker-pullable://gcr.io/kuar-demo/kuard-amd64@sha256:a580…
    Port:          8080/TCP
    State:         Running
      Started:     Sun, 02 Jul 2017 15:00:41 -0700
    Ready:         True
    Restart Count: 0
    Environment:   <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-cg5f5 (ro)


最后是与这个pods相关的事件信息(image何时被pulled之类的)


Events:
  Seen From              SubObjectPath           Type      Reason    Message
  ---- ----              -------------           --------  ------    -------
  50s  default-scheduler                         Normal    Scheduled Success…
  49s  kubelet, node1    spec.containers{kuard}  Normal    Pulling   pulling…
  47s  kubelet, node1    spec.containers{kuard}  Normal    Pulled    Success…
  47s  kubelet, node1    spec.containers{kuard}  Normal    Created   Created…
  47s  kubelet, node1    spec.containers{kuard}  Normal    Started   Started…


Deleting a Pod

两种方式删除pods


$ kubectl delete pods/kuard
$ kubectl delete -f kuard-pod.yaml


需要注意的是,pods不是马上就被删除的。pods会有一个Terminating的状态。在默认terminating的30秒钟,pods不会接受新的请求,但可以处理目前手头未完成的请求。

另外当你的pods删除后,一切相关的数据也会被删除。如果你想要持久化数据,就需要用`PersistentVolume

Accessing Your Pod

我们可以通过Port Forwarding将一个pod的服务直接暴露


$ kubectl port-forward kuard 8080:8080


这条命令会讲pods与你的主机通过k8s master打通。在这条命令运行期间,你都可以通过http://localhost:8080.来访问pods.

获得pods的log


$ kubectl logs kuard


h和tail一样,加个f就是流式输出了.


kubectl logs -f kuard


The kubectl logscommand always tries to get logs from the currently running container. Adding the --previousflag will get logs from a previous instance of the container. This is useful, for example, if your containers are continuously restarting due to a problem at container startup.

Running Commands in Your Container with exec

公司里比较常用的是dashboard

单条命令:


$ kubectl exec kuard date


交互式终端:


$ kubectl exec -it kuard ash


Copying Files to and from Containers

临时要把pod里文件拿出来的时候用。和docker cp的用法基本一样


$ kubectl cp <pod-name>:/captures/capture3.txt ./capture3.txt


当然也可以把本机的东西扔进pods


$ kubectl cp $HOME/config.txt <pod-name>:/config.txt


Generally speaking, copying files into a container is an anti-pattern. You really should treat the contents of a container as immutable. But occasionally it’s the most immediate way to stop the bleeding and restore your service to health, since it is quicker than building, pushing, and rolling out a new image. Once the bleeding is stopped, however, it is critically important that you immediately go and do the image build and rollout, or you are guaranteed to forget the local change that you made to your container and overwrite it in the subsequent regularly scheduled rollout.

Health Checks健康检查

process health check. This health check simply ensures that the main process of your application is always running. If it isn’t, Kubernetes restarts it.
However, in most cases, a simple process check is insufficient. For example, if your process has deadlocked and is unable to serve requests, a process health check will still believe that your application is healthy since its process is still running.
To address this, Kubernetes introduced health checks for application liveness. Liveness health checks run application-specific logic (e.g., loading a web page) to verify that the application is not just still running, but is functioning properly. Since these liveness health checks are application-specific, you have to define them in your Pod manifest.

Liveness Probe

这个健康检查是per container维度的。也就是每个container都会有一个lp进程。我们定义一个kuard-pod-health.yaml来设定一个lp检查 ——


apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:blue
      name: kuard
      livenessProbe:
        httpGet: # 请求方式
          path: /healthy # 请求路径
          port: 8080 # 请求端口
        initialDelaySeconds: 5 # 启动5秒后才开始轮训
        timeoutSeconds: 1 # timeout设置
        periodSeconds: 10 # 每10秒call一次
        failureThreshold: 3 # 连续3次失败就会重启
      ports:
        - containerPort: 8080
          name: http
          protocol: TCP


While the default response to a failed liveness check is to restart the Pod, the actual behavior is governed by the Pod’srestartPolicy.There are three options for the restart policy: Always(the default), OnFailure(restart only on liveness failure or nonzero process exit code), or Never.

Readiness Probe

Liveness不过就重启,readiness不过只会暂停接受请求。直至恢复。

Resource Management (资源管理)

Resource Requests: Minimum Required Resources

下面的配置文件kuard-pod-resreq.yaml声明最小资源配置,k8s会保证Pods能够被分配到的最小系统资源


apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:blue
      name: kuard
      resources:
        requests:
          cpu: "500m"
          memory: "128Mi"
      ports:
        - containerPort: 8080
          name: http
          protocol: TCP


Resources are requested per container, not per Pod.The total resources requested by the Pod is the sum of all resources requested by all containers in the Pod. The reason for this is that in many cases the different containers have very different CPU requirements. For example, in the web server and data synchronizer Pod, the web server is user-facing and likely needs a great deal of CPU, while the data synchronizer can make do with very little.

REQUEST LIMIT DETAILS (下限)

k8s的调度会保证单个节点上的所有pods资源不会超过节点的cpacity.一个例子:

Imagine that we have container whose code attempts to use all available CPU cores. Suppose that we create a Pod with this container that requests 0.5 CPU. Kubernetes schedules this Pod onto a machine with a total of 2 CPU cores.
As long as it is the only Pod on the machine, it will consume all 2.0 of the available cores, despite only requesting 0.5 CPU.
If a second Pod with the same container and the same request of 0.5 CPU lands on the machine, then each Pod will receive 1.0 cores.
If a third identical Pod is scheduled, each Pod will receive 0.66 cores. Finally, if a fourth identical Pod is scheduled, each Pod will receive the 0.5 core it requested, and the node will be at capacity. Memory requests are handled similarly to CPU, but there is an important difference.If a container is over its memory request, the OS can’t just remove memory from the process, because it’s been allocated. Consequently, when the system runs out of memory, thekubeletterminates containers whose memory usage is greater than their requested memory.These containers are automatically restarted, but with less available memory on the machine for the container to consume.

Capping Resource Usage with Limits(上限)

一样,举个例子kuard-pod-reslim.yaml


apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:blue
      name: kuard
      resources:
        requests:
          cpu: "500m"
          memory: "128Mi"
        limits:
          cpu: "1000m"
          memory: "256Mi"
      ports:
        - containerPort: 8080
          name: http
          protocol: TCP


Persisting Data with Volumes (持久化存储)

To add a volume to a Pod manifest, there are two new stanzas to add to our configuration.The first is a new spec.volumessection.This array defines all of the volumes that may be accessed by containers in the Pod manifest. It’s important to note that not all containers are required to mount all volumes defined in the Pod. The second addition is the volumeMountsarray in the container definition. This array defines the volumes that are mounted into a particular container, and the path where each volume should be mounted. Note that two different containers in a Pod can mount the same volume at different mount paths.

一个例子kuard-pod-vol.yaml


apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  volumes:
    - name: "kuard-data"
      hostPath:
        path: "/var/lib/kuard"
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:blue
      name: kuard
      volumeMounts:
        - mountPath: "/data"
          name: "kuard-data"
      ports:
        - containerPort: 8080
          name: http
          protocol: TCP


差不多了,最后把文中写到的知识点都融合一下。许多应用都是有状态的,我们需要持久化的存储一些数据。我们也想保证应用能一直健康的运行(也就是需要做lp和rp 的check)。我们就可以通过下面这个kuard-pod-full.yaml来创建


apiVersion: v1
kind: Pod
metadata:
  name: kuard
spec:
  volumes:
    - name: "kuard-data"
      nfs:
        server: my.nfs.server.local
        path: "/exports"
  containers:
    - image: gcr.io/kuar-demo/kuard-amd64:blue
      name: kuard
      ports:
        - containerPort: 8080
          name: http
          protocol: TCP
      resources:
        requests:
          cpu: "500m"
          memory: "128Mi"
        limits:
          cpu: "1000m"
          memory: "256Mi"
      volumeMounts:
        - mountPath: "/data"
          name: "kuard-data"
      livenessProbe:
        httpGet:
          path: /healthy
          port: 8080
        initialDelaySeconds: 5
        timeoutSeconds: 1
        periodSeconds: 10
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 30
        timeoutSeconds: 1
        periodSeconds: 10
        failureThreshold: 3