在安装完 Kubernets 之后,下一步就该开始玩耍 Kubernetes 了,当你玩 Kubernetes 的时候,你会有一个很直观的感受,那么就是在 Kubernetes 中,一切都是资源,你可以通过 get/describe/delete 来操作这些资源,那么这些资源本质上都是做什么用可能你还不太了解。所以,第一种我要介绍的资源就是 Kubernetes 中的原子资源:Pod。
Kubernetes 最初大家对它的定位是容器编排工具,但是,事实上我们在使用的时候并不是直接和容器打交道,反而是一种叫作 Pod 的资源接触得比较多。Pod 可以理解为运行某一种服务的资源,内部其实还是容器,那么为什么不直接用容器就好了,还要引入一个和容器差不多的概念:Pod。
注意,这里的用词是“差不多”的概念,意思就是有一些区别,而这些区别却是影响很重要的点,假设这么一个场景,你想提供一个开箱即用的博客系统,以前在容器的时候你可以就将代码和数据库都塞到同一个 Container 里面了,然后别人直接 docker run
就开启了一个博客系统,但是,这样的模式却是有很多问题,这里列举几个:
- 透明性:如果我分别看一下博客系统的日志和数据库的日志会比较麻烦,
docker logs
是不大可能用了; - 组件解耦:你的博客系统升级的时候,每次升级的 Container 都得包含数据库在里面,数据迁移啥的不麻烦吗;
- 方便使用:如果有一天,你的博客系统挂了,你想知道是应用出 Bug 了还是数据库挂了,这怎么整;
- 更加高效:如果我设置了每个 Container 只能占用一个核,那这个应用和数据库不是得抢资源啦。
所以 Pod 存在得意义就出来了,你可以提供开箱即用的资源:Pod,但是缺不用放在同一个容器里面。
Pod 的操作
在 Kubernetes 里面,操作 Pod 也是极为简单的,在 K8S 中,对于集群资源的操作虽然使用命令行都是没关系的,但是,推荐使用 YAML 配置文件来更好一些,复用性自然不用说,命令执行也简单呀,而且还遍于追踪管理。
在操作一种资源之前,我们需要先对这个资源进行定义,在 K8S 中,常用的方式是用 YAML 配置文件配置,下面我就给出一个简单的执行 Nginx 的配置:
[root@liqiang.io]# cat /home/liqiang.io/blog/kubernetes/guide/chap03/00-simple-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: first-pod
labels:
app: nginx
spec:
containers:
- name: 00-simple-pod-nginx
image: nginx:1.17.0
这就是一个 K8S 资源定义的比较通用的方式了,对于 K8S 的资源(包括自定义的)来说,这几个字段都是必包含的:
- apiVersion:资源的版本,可以理解成你要创建的是
PodV1{}
还是PodVn{}
- Kind:资源的类型,很明显啦,你要创建资源对象,肯定得指定资源类型
- metadata:
- name:表示创建出来得资源的名字,这个从名字上看的出来
- labels:labels 是 K8S 中重要的一项,很多其他操作和资源都是通过 labels 来进行的
- spec:这个就是一个资源的参数了
例如我这里是运行一个 Nginx 的 Pod,那么就需要指定我要运行的是哪个版本的 Nginx,运行的 Container 叫什么名字,除此之外就可以不指定其他参数了。启动一个 Pod 很简单,你可以通过:
[root@liqiang.io]# kubectl apply -f 00-simple-pod.yaml
pod/first-pod created
就这么简单,你就让你定义的资源运行在了 K8S 之上,对于更新也是那么简单,分两步:
- 修改一下资源的定义文件
- 再次执行
kubectl apply -f 00-simple-pod.yaml
就可以了
那么我们要怎么知道我执行的这个 Pod 的状态呢?这个很简单,可以直接通过:
[root@liqiang.io]# kubectl get pods first-pod
NAME READY STATUS RESTARTS AGE
first-pod 0/1 ContainerCreating 0 8m2s
这样就可以看到我们 Pod 的状态了,很显然,这里的 Pod 并没有成功运行起来,而是出于一个叫作 ContainerCreating
的状态,那么我们想知道更多关于这个 Pod,或者说 Pod 里面的 Container 的细节,那么可以尝试看一下这个 Pod 的详情:
[root@liqiang.io]# kubectl describe pods first-pod
Name: first-pod
... ...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 10m default-scheduler Successfully assigned default/first-pod to host-79
Warning FailedCreatePodSandBox 6m40s (x8 over 9m52s) kubelet, host-79 Failed create pod sandbox: rpc error: code = Unknown desc = failed pulling image "k8s.gcr.io/pause:3.1": Error response from daemon: Get https://k8s.gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
Warning DNSConfigForming 5m2s (x12 over 10m) kubelet, host-79 Nameserver limits were exceeded, some nameservers have been omitted, the applied nameserver line is: 192.168.1.21 192.168.48.1 8.8.8.8
Warning MissingClusterDNS <invalid> (x23 over 10m) kubelet, host-79 pod: "first-pod_default(a79f2657-9a6a-11e9-9a22-5254006b0617)". kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to "Default" policy.
OK,很明显,从这个 Events 中可以看到问题就除在 K8S 在拉取镜像的时候出现了问题,而且也明确得告诉了我们这个 Pod 所在的机器是哪个,所以我们需要解决这个网络问题,解决方式多种,当你解决之后,再来看一下:
[root@liqiang.io]# k get pods first-pod
NAME READY STATUS RESTARTS AGE
first-pod 1/1 Running 0 51m
可以看到这个时候 Pod 的状态就是 Running
了,就表示我们的 Pod 已经创建成功了。
设置环境变量为运行参数
[root@liqiang.io]# kubectl descirbe pods
spec:
containers:
- args:
- -c
- /config/envoy.yaml
- --log-path
- /log/$(POD_NAME).log
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
小结
本文就介绍了一下 K8S 的基本单元 Pod,并且介绍了一下 K8S 中资源的通用结构以及 Pod 的一些基本操作。下面是一些没有提到的 Pod 附带信息。
Pod 和 Container 的状态
- Pod 状态
- Pending:Kubernetes 已经接受了 Pod 的配置,但是还没有创建容器,例如可能还在拉取镜像或者调度不成功。
- Running:Pod 已经被调度成功,并且已经和某个 node 绑定了,所有的容器都被创建了。
- Succeeded:Pod 中的所有容器都已经成功运行完毕并且退出。
- Failed:Pod 中至少有一个容器以不正常的状态退出,当处于这个状态的时候,需要定位一下原因了。
- Unknown:Pod 的状态不能被 kubelet 汇报给 kube-apiserver,这很有可能是 worker 和 master 的通讯出现了问题。
- Container 状态
- Waiting:Default state of container. If container is not in either Running or Terminated state, it is in Waiting state. A container in Waiting state still runs its required operations, like pulling images, applying Secrets, etc. Along with this state, a message and reason about the state are displayed to provide more information.
- Running:Indicates that the container is executing without issues. Once a container enters into Running, postStart hook (if any) is executed. This state also displays the time when the container entered Running state.
- Terminated:Indicates that the container completed its execution and has stopped running. A container enters into this when it has successfully completed execution or when it has failed for some reason. Regardless, a reason and exit code is displayed, as well as the container’s start and finish time. Before a container enters into Terminated, preStop hook (if any) is executed.
日志
- 查看 pod 日志
kubectl logs <pod-name>
- 查看 pod 中某个容器的日志
kubectl logs <pod-id> -c <container-id>
- 限制
- 每天或者每次日志文件达到10MB大小时, 容器日志都会自动轮替。
kubectl logs
命令仅显示最后一次轮替后的日志条目; - 只能获取仍然存在的 pod 的日志。当一个 pod 被删除时,它的日志也会被删除;
- 每天或者每次日志文件达到10MB大小时, 容器日志都会自动轮替。
外部访问 POD
- 将本地网络端口转发到 pod 中的端口:
kubectl port-forward
注解
向Kubemetes引入新特性时,通常也会使用注解 。一般来说,新功能的 alpha 和 beta 版本不会向 API 对象引入任何新字段,因此使用的是注解 而不是字段,一旦所需的API更改变得清晰并得到所有相关人员的认可,就会引入新的字段并废弃相关注解。
大量使用注解可以为每个pod或其他API对象添加说明,以便每个使用该集群的入都可以快速查找有关每个单独对象的信息。
Pod 探针
三种类型的 handler
- ExecAction: Executes a specified command inside the Container. The diagnostic is considered successful if the command exits with a status code of 0.
- CPSocketAction: Performs a TCP check against the Container’s IP address on a specified port. The diagnostic is considered successful if the port is open.
- TPGetAction: Performs an HTTP Get request against the Container’s IP address on a specified port and path. The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400.
三种探针结果
- Success: The Container passed the diagnostic.
- Failure: The Container failed the diagnostic.
- Unknown: The diagnostic failed, so no action should be taken.
重启策略
- Always
- OnFailure
- Never