我们已经有了一个简易版的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出现问题的时候,方便去自动恢复

发表评论

邮箱地址不会被公开。 必填项已用*标注