使用Kubernetes的必备技能:编写配置文件。这些配置文件可以是 YAML 或者 JSON 格式的,一般都是用YAML格式。
Kubernetes不推荐直接使用命令行的方式运行容器,而是使用YAML文件的方式,即:把容器的定义、参数、配置都记录在一个YAML文件中,然后使用如下命令:
kubectl create -f <xxx.yaml>
这么做的最大好处,有一个文件能记录Kubernetes到底运行了什么。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
这个 YAML 文件,对应到 Kubernetes 中,就是一个 API Object(API 对象)。
为这个对象的各个字段填好值并提交给Kubernetes之后,Kubernetes就会负责创建出这些对象所定义的容器或者其他类型的API 资源。
可以看到,这个 YAML 文件中的 Kind 字段,指定了这个API对象的类型(Type),是一个Deployment。
所谓 Deployment,是一个定义多副本应用(即多个副本 Pod)的对象,此外,Deployment 还负责在 Pod 定义发生变化时,对每个副本进行滚动更新(Rolling Update)。
这个 YAML 文件中:
spec.replicas
) 是:2spec.template
),这个模版描述了要创建的 Pod 的细节spec.containers.image
)是nginx:1.7.9
,这个容器监听端口(containerPort
)是 80Pod就是Kubernetes世界里的“应用”,而一个应用,可以由多个容器组成。
像这样使用一种 API 对象(Deployment)管理另一种 API 对象(Pod)的方法,在 Kubernetes 中,叫作“控制器”模式(controller pattern)。
在上面的例子中,Deployment扮演的正是 Pod 的控制器的角色。
这样的每一个 API 对象都有一个叫作 Metadata 的字段,这个字段就是 API 对象的“标识”,即元数据,它也是从 Kubernetes 里找到这个对象的主要依据,这其中最主要使用到的字段是Labels。
Labels 就是一组 key-value 格式的标签。而像 Deployment 这样的控制器对象,就可以通过这个 Labels 字段从 Kubernetes 中过滤出它所关心的被控制对象。
比如,在上面这个 YAML 文件中,Deployment 会把所有正在运行的、携带“app: nginx
”标签的Pod 识别为被管理的对象,并确保这些 Pod 的总数严格等于两个。
过滤规则的定义,是在 Deployment 的“spec.selector.matchLabels
”字段,一般称之为:Label Selector。
在 Metadata中,还有一个与Labels格式、层级完全相同的字段叫Annotations,它专门用来携带 key-value 格式的内部信息。
内部信息,指的是对这些信息感兴趣的是Kubernetes 组件本身而不是用户。所以大多数Annotations,都是在 Kubernetes 运行过程中,被自动加在这个 API 对象上。
一个 Kubernetes 的 API 对象的定义,大多可以分为 Metadata 和 Spec 两个部分:
# 创建API对象
kubectl create -f nginx-deployment.yaml
# 查看API对象,-l参数获取所有匹配标签的pod
kubectl get pods -l app=nginx
# 查看一个 API 对象的细节
kubectl describe pod nginx
kubectl get
指令的作用,就是从 Kubernetes 里面获取(GET)指定的 API 对象。需要注意的是,在命令行中,所有 key-value格式的参数,都使用“=”而非“:”表示。
kubectl describe
命令返回的结果中,可以清楚地看到这个 Pod 的详细信息,比如它的 IP 地址等等。其中,有一个部分值得特别关注,就是Events(事件)。
在 Kubernetes 执行的过程中,对 API 对象的所有重要操作,都会被记录在这个对象的 Events 里,并且显示在
kubectl describe
指令返回的结果中。这个部分正是我们将来进行 Debug 的重要依据。如果有异常发生,要第一时间查看这些 Events,往往可以看到非常详细的错误信息。
上述deployment中的pod运行的是1.7.9的nginx容器,如何升级成1.8?
只要修改刚才的YAML文件即可:
...
spec:
containers:
- name: nginx
image: nginx:1.8 # 这里从 1.7.9 修改为 1.8
ports:
- containerPort: 80
这样对YAML配置文件的本地修改就完成了,通过如下命令更新到kubernetes集群中:
kubectl replace -f nginx-deployment.yaml
# 1
kubectl create -f file.yaml
# 2
kubectl replace -f file.yaml
# 3
kubectl apply -f file.yaml
# 上述的命令1和2可以用3替换掉,这也是kubernetes“声明式API”推荐的做法。
在 Kubernetes 中,Volume 是属于 Pod 对象的一部分。所以,我们就需要修改这个 YAML 文件里的 template.spec
字段,如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.8
ports:
- containerPort: 80
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nginx-vol
volumes:
- name: nginx-vol
emptyDir: {}
在 Deployment 的 Pod 模板部分添加了一个 volumes 字段,定义了这个 Pod 声明的所有 Volume。它的名字叫作 nginx-vol,类型是 emptyDir。
那什么是 emptyDir类型呢?
它其实就等同于Docker的隐式Volume参数,即:不显式声明宿主机目录的Volume。所以,Kubernetes也会在宿主机上创建一个临时目录,这个目录将来就会被绑定挂载到容器所声明的 Volume 目录上。
Kubernetes 的 emptyDir类型,只是把Kubernetes 创建的临时目录作为Volume的宿主机目录交给Docker,因为 Kubernetes 不想依赖 Docker 创建的
_data
目录。
而 Pod 中的容器,使用的是 volumeMounts 字段来声明自己要挂载哪个 Volume,并通过mountPath 字段来定义容器内的 Volume 目录,比如:/usr/share/nginx/html
。
当然,Kubernetes 也提供了显式的 Volume 定义,它叫做 hostPath。比如下面的这个 YAML 文件:
...
volumes:
- name: nginx-vol
hostPath:
path: /var/data
这样volume挂载的宿主机目录,就变成了/var/data
。
使用如下命令,进入到Pod中,即容器的Namespace中:
kubectl exec -it nginx-deployment-5c678cfb6d-lg9lw -- /bin/bash
ls /usr/share/nginx/html
从Kubernetes集群中删除部署的Deployment的命令:
kubectl delete -f nginx-deployment.yaml