我们已经有了一个简易版的Kubernetes集群,虽然和生产环境有一定的差距,但是还是一个准生产级别的Kubernetes集群了
我们就先尝试发布第一个容器化的应用
我们首先了解的是,Kubernetes只能确认发布自己认识的镜像容器,那么怎么才是Kubernetes认识的呢?
编写合适的配置文件
配置文件可以是JSON或者YAML的,为了方便阅读和理解,后面我们会统一来用YAML来处理
Kubernetes和Docker项目的不同处,就是其建议使用文件,虽然Kubernetes支持直接的命令行,但是更加合适的方式,是将容器的定义,参数,配置,记录在一个YAML文件中,然后直接kubectl create -f 配置文件
这样的话,无论管理的容器有什么变化,都可以被记录下来
比如,如下例子
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对象,当你为这个对象各个字段填好值交给Kubernetes之后,Kubernetes就会创建这些对象对应的容器或者其他类型的API资源
可以看到这个YAML文件的Kind,说明了这个API对象的类型,是一个Deployment
所谓的Deployment,是一个定义多副本应用的对象,这个对象负责在Pod发生变化的时候,对每个副本进行滚动形式的更新
然后我们设置了replicas为2,即Pod副本个数为2
然后,我定义了一个Pod模板,这个模板中描述了Pod的真正的细节,这个Pod中有且只定义了一个容器,名为nginx,采用的镜像是nginx:1.7.9,监听的端口是80
这样一个API对象管理另一个API对象的方法,在Kubernetes中,叫做控制器模式,Deployment扮演的正是Pod的控制器的角色
而且,每一个API对象都有Metadata的字段,这个字段是API对象的标识,也就是元数据,也是从K8S中找到这个对象的主要依据
其中的Label,是一组key-value格式的标签,而像是Deployment这样的控制器对象,可以通过Labels字段从Kubernetes中过滤出关心的被控制对象
我们先从nginx的metadata中声明了labels了app为nginx
然后在上面的nginx-deployment中声明匹配的label为
app:nginx的Pod为被管理的对象,并且确保了Pod的数量严格等于2个
在Metedata中,还有一个和Labels相同层级的字段Annotations,专门携带一些内部信息,给Kubernetes提供
Kubernetes的APi对象的定义,可以分为Metedata和spec两个部分,前者是这个对象的元数据,后者是这个对象的独有定义,描述其要表达的功能
然后我们使用了kubectl的命令将其运行起来
kubectl create -f nginx-deployment.yaml
$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deployment-67594d6bf6-9gdvr 1/1 Running 0 10m
nginx-deployment-67594d6bf6-v6j7w 1/1 Running 0 10m
kubectl get的作用,就是从Kubernetes里面获取指定的API对象,我们加上了一个-l,表示获取所有匹配app:nginx标签的Pod,在命令行中,匹配的参数使用=而非:表示
这样这个Deployment所管理的Pod都能运行了
再加上kubectl describe命令,查看一个API对象的细节
$ kubectl describe pod nginx-deployment-67594d6bf6-9gdvr
Name: nginx-deployment-67594d6bf6-9gdvr Namespace: default Priority: 0 PriorityClassName: <none> Node: node-1/10.168.0.3 Start Time: Thu, 16 Aug 2018 08:48:42 +0000 Labels: app=nginx pod-template-hash=2315082692 Annotations: <none> Status: Running IP: 10.32.0.23 Controlled By: ReplicaSet/nginx-deployment-67594d6bf6 … Events: Type Reason Age From Message —- —— —- —- ——- Normal Scheduled 1m default-scheduler Successfully assigned default/nginx-deployment-67594d6bf6-9gdvr to node-1 Normal Pulling 25s kubelet, node-1 pulling image “nginx:1.7.9” Normal Pulled 17s kubelet, node-1 Successfully pulled image “nginx:1.7.9” Normal Created 17s kubelet, node-1 Created container Normal Started 17s kubelet, node-1 Started container |
在kubectl describe命令返回的结果中,可以看到其返回的详细信息,主要有一个部分很重要,就是Events事件
在Kubernetes执行的过程中,所有的操作,都记录在这个Events中,都显示在这个字段中
对于这个Pod,我们看见其被创建之后,被调度器调度到了node-1,然后启动了Pod中的容器
如果出现了问题,这就是我们查看的最重要的一句,我们可以借助这个查看到非常详细的错误信息
如果我们需要将这个Nginx的服务的版本从1.7.9升级到1.8,怎么办
我们直接修改这个YAML文件就行
将YAML文件中的nginx:1.7.9修改为1.8
…
spec: containers: – name: nginx image: nginx:1.8 #这里被从1.7.9修改为1.8 ports: – containerPort: 80 |
这样就修改完成了yaml,如何生效到kubernetes中呢?
可以使用kubectl replace命令来完成更新
kubectl replace -f nginx-deployment.yaml
但是,最好的操作方式时候,
kubectl apply -f nginx-deployment.yaml
这是Kubernetes声明式API推荐的方式,作为用户,不必关心操作是创建还是跟更新,执行的命令都是kubectl apply,而Kubernetes会根据YAML的变化,自动处理具体的操作
这样,就减少了开发人员和运维人员之间的沟通成本
至少开发人员,每次,修改了容器内容,修改了对应的yaml文件,而运维人员不会关心每次修改的内容,而是每次直接到手了kubectl apply进行更新
这就是Kubernetes应用的基本操作了
当应用本身发生变化的时候,我们通过容器来进行同步,当应用部署参数发生了变化的时候,YAML就是沟通和信任的媒介
然后,我们尝试声明一个Volume
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: {} |
我们声明了一个volumes的字段,定义了Pod的所有Volume,名字是nginx-vol,类型是emptyDir
这个emptyDir,等于不显式声明宿主机目录的Volume,所以,Kubernetes会在宿主机上次创建一个临时目录,挂载声明的Volume上
在K8S中,这个临时目录是由K8S创建的,而不是交由Docker自己去创建的 _data目录
然后我们在容器内使用,volumeMounts字段声明自己要挂载哪个Volume,并通过mountPath来定义在容器内的目录
volume必然可以指定挂载哪个目录,使用方式叫做hostPath,比如下面的方式
…
volumes: – name: nginx-vol hostPath: path: ” /var/data” |
容器Volume挂载的宿主机目录变为了 /var/data
然后我们修改完成后,使用kubectl apply指令进行更新这个Deployment
$ kubectl apply -f nginx-deployment.yaml
然后使用get命令,查看这两个Pod被逐一的更新
这样就是滚动更新这两个Pod
这样我们看一下最新的Pod的详情,就可以看出Volume的信息已经出现在了Container描述部分
作为一个平台化的项目,Kubernetes可以提供的Volume不止这些,还可以使用kubectl exec指令,进入这个Pod当中,查看这个Volume目录
$ kubectl exec -it nginx-deployment-5c678cfb6d-lg9lw — /bin/bash
# ls /usr/share/nginx/html
最后,想要从集群中删除这个Nginx,直接执行
kubectl delete -f nginx-deployment.yaml
本章中,我们看出来Kubernetes使用方式,是通过YAML文件描述所需要部署的API对象,统一使用kubectl apply命令完成对这个对象的创建和更新操作
kubernetes中最小的API对象是Pod,Pod可以等价为一个应用,一个pod由多个紧密协作的容器组成,在Kubernetes中,我们经常看到其通过一个API对象来管理另一种API对象,比如Deployment和Pod之间关系,Pod作为最小的对象,是其他对象控制的,这就是容器编排的重要方式
一个API对象,由Metadata和Spec两个部分组成,其中Metedata中的Labels字段,是Kubernetes过滤的重要手段
容器中使用的数据卷,就是Volume,正是Pod的Spec字段的一部分,Pod每一个容器,则需要显式的声明自己要挂载哪个Volume
基于YAML的管理方式,让其和Docker Mesos的使用方式都不一样,从docker run的命令行操作,向kubectl apply YAML文件声明式API的转变,是每一个容器技术学习者,必须跨过的门槛
那么整体的制作流程中,我们的流程如下
先制作镜像
然后根据合适的Kubernetes API,编写对应的YAML文件
最后在Kubernetes上部署这个YAML文件
那么,在回来管理的时候,就尽可能的通过修改YAML文件实现吧,不要使用命令行工具了
1.相比较于编写一个单独的Pod YAML,更推荐写一个replicas=1的Deployment
是否是单独书写一个Pod的yaml,会导致在Pod出现问题的时候,没法自动的进行恢复工作,而使用一个Deployment去管理这个Pod,可以在Pod出现问题的时候,方便去自动恢复