一、Kubernetes管理文件介绍
Kubernetes最常用的配置文件格式为yaml格式,yaml因为支持注释,可以很好的表示复杂的数据格式,正在越来越多地被其它程序作为配置文件来使用。
Yaml(发音/ˈjæməl/)格式介绍
缩进
Yaml只支持空格作为缩进,不支持tab作为缩进。可以使用两个空格或者四个空格表示一层,但是整个yaml文件必须统一,要么全部使用两个空格作为缩进要么全部使用四个空格作为缩进,不允许混合使用。
注释
Yaml使用#作为一行的注释,当yaml碰到以#开头的行时将作为注释对待。
字典数据结构
字典数据结构使用key:value格式,例如:
apiVersion: v1
kind: ConfigMap
metadata:
name: dns
解释为: 键值 apiVersion值为 v1, 键值 kind值为 ConfigMap, 键值 metadata值又为一个字典数据结构。
数组数据结构
例如:
favAnimals:
- cat
- dog
- elephant
键值favAnimals的值为一个数组,这个数组值为 cat, dog, elephant。
一个更复杂的yaml结构解释
apiVersion: v1
kind: Service
metadata:
name: sms
spec:
selector:
run: deployment-sms
ports:
- protocol: TCP
name: http
port: 18000
targetPort: 8000
键值apiVersion值为 v1,键值kind值为Service,键值metadata值为 name: sms,键值 spec值为
selector:
run: deployment-sms
ports:
- protocol: TCP
name: http
port: 18000
targetPort: 8000
键值 ports值为一个数组,这个数组有一个值,值为
protocol: TCP
name: http
port: 18000
targetPort: 8000
多个yaml文件合并为一个
Kubernetes支持多个yaml文件合为一个文件编写,每个yaml块使用 --- 分隔。合并的yaml文件有先后顺序之分,如果有依赖关系的话,被依赖的yaml文件必须放在前面。
二、Kubernetes简介
Kubernetes优势
Kubernetes是一个集中的容器container管理环境,它提供一种更加方便的资源管理办法,方便服务快捷地做到扩展和伸缩以满足业务量的变化需求。
Kubernetes架构
Kubernetes是master+node节点架构,我们业务系统的容器只运行在node上面。
Master节点用于kubernetes任务分配调度,运行的组件有:kube-apiserver, etcd, kube-scheduler, cloud-controller-manager。
Node机器运行的组件有:kubelet, kube-proxy, 以及运行时的容器Container Runtime。
Kubernetes api
Kubernetes api完整地定义了kubernetes使用的对象参数,v1.12版本api定义地址:
https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/
Kubectl客户端
Kubectl是最常用到的命令,它用于跟apiServer通讯,把yaml里配置的对象在kubernetes集群里生效。它也用于查看kubernetes对象的状态。
三、业务系统进kubernetes
业务系统一般比较关心,配置文件如何解决,日志如何解决,如何运行镜像,现在就这些比较关心的问题进行讨论。
定义配置文件
Kubernetes的ConfigMap对象用于把配置参数映射到kubernetes集群里的方式,这些业务参数或者environment环境变量都将定义在yaml文件里,以原子最小单位的形式供其它要使用它们的系统重复使用。
Y_DNS解决
Openresty需要使用resolver xxx.xxx.xxx.xxx; 指令来指定DNS服务器用来解析域名。一般我们在run.sh里定义Y_DNS环境变量的方式把DNS传入使用start.lua来生成resolver.conf的方式来定义openresty的resolver。解决办法,把Y_DNS作为ConfigMap定义到kubernetes系统。
dns-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: dns
data:
Y_DNS: 172.0.0.1
解释:
第1行,定义apiVersion,apiVersion是kubernetes api必须的元素。
第2行,定义类别kind,这是一个ConfigMap类别,用于定义配置参数。
第3行,定义ConfigMap的一些基本元数据,其中name是metadata里必须定义的,给这个ConfigMap起一个名字为dns,后续在其它yaml里可以使用这个名字来引用我们定义的配置信息。所以定义名字时应该具有唯一性。
第5行,data后面的将是该dns ConfigMap的具体内容。
第6行,我们定义了一个ConfigMap变量YBS_DNS,它的值是 172.0.0.1,这是一个kubernetes集群DNS。
device配置文件解决
device配置文件有两层目录,一层在/sms目录下,一层在/device/status目录下,一层目录下的配置文件放在一个yaml文件里,这样才能够后续映射到不同的目录里。
下面截取了device-config.yaml部分代码
---
apiVersion: v1
kind: ConfigMap
metadata:
name: device-conf
data:
addr.ini: |
[addr]
sms_url = http://sms.default.svc.cluster.local:18000/sms/print
---
apiVersion: v1
kind: ConfigMap
metadata:
name: device-status-conf
data:
device_status.ini: |
[status]
1 = ok
解释:
第1行,因为把device两个yaml配置放在了一个文件里,使用---分隔表示一个文件的内容。
第2行,同样的,定义了apiVersion
第3行,定义kind的,为ConfigMap类别
第4,5行,定义metadata,主要定义了name名字,注意该名字的唯一性。
第7行开始为ConfigMap的数据data,注意这儿跟dns-config.yaml里不同,它定义了一个配置文件样式, addr.ini : | 前面addr.ini为配置文件的名字,后续在其它yaml文件里引用映射到一个目录下,那么该文件名就是addr.ini,后面的 | 表示后续的内容为addr.ini文件的数据。
同理,从10行以后是定义的/device/status目录下的配置文件内容。
sms配置文件
---
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap-sms
data:
client.ini: |
[jpush]
key=aa
secret=76basdt
mysql.ini: |
[config]
host=mysql.ws.com
port=3306
定义模块运行参数
Kubertnetes的一大优势就是能够定义业务系统的运行份数,动态伸缩,下面我们来看下定义sms运行状态的一种新kubernetes类型Deployment。
sms Deployment
sms-deployment.yaml
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: deployment-sms
spec:
replicas: 2
template:
metadata:
labels:
run: deployment-sms
spec:
containers:
- name: deployment-sms
image: registry:5000/sms:20210101
env:
- name: Y_DNS
valueFrom:
configMapKeyRef:
name: dns
key : Y_DNS
ports:
- containerPort: 8000
volumeMounts:
- name: volume-sms
mountPath: /home/openresty/openresty/nginx/sms/conf
readOnly: true
- name: volume-log
mountPath: /data/log
volumes:
- name: volume-sms
configMap:
name: configmap-sms
- name: volume-log
hostPath:
path: /data/log
解释:
第1行,yaml内容分隔符。
第2行,定义apiVersion。
第3行,该对象的类别为Deployment,Deployment对象用于定义业务系统的运行状态信息。
第4,5行,定义该对象的一些metadata,其中我们定义了该对象的名字。
第6行,spec定义该Deployment的一些规范。
第7行,replicas定义该业务系统将要运行的份数,我们定义为运行2份。
第8行,template内容定义要运行的业务系统的模板信息。
第11行,定义运行的container名字,这儿的名字在14行定义。
第13行,定义运行的container数组,这儿数组里定义了一个container。
第14行,该container的名字是deployment-sms,第11行填的名字就是这儿定义的名字。
第15行,要启动container的镜像名称。
第16至21行,前面dns-config.yaml里定义的dns ConfigMap变量。
第22,23行,定义container启动的端口。
第24至37行,定义mount挂载的卷。
我们先看30至37行,我们定义了两个volume,32行至34行volume的名字为 volume-sms,它引用的是前面sms ConfigMap的配置参数。35行至37行volume的名字为volume-log,它引用的是一个物理路径 /data/log。
我们再来看24至29行,这儿我们来使用下面定义的volume,第25至27行,我们使用下面定义的volume-sms,也就是使用了一个ConfigMap,我们把这个ConfigMap内容挂载到到container容器的路径/home/openresty/openresty/nginx/sms/conf,这样我们就把ini的配置文件挂到了该目录下,并且设置了只读权限。第28,29行,我们使用了下面定义的volume-log,这是一个物理路径,我们把它挂载到container里的/data/log。
总结:我们在sms Deployment里定义了sms要运行的份数,使用的环境变量,配置文件要挂载的目录,日志文件的目录这些关键的信息。
sms Service
在前面我们定义了sms的运行时,那么现在sms运行起来了,是否就可以供device等系统使用了呢?答案是否定的,kubernetes规定内部的HTTP(S)服务要供kubernetes内部系统使用的话,必须把它expose为一个service服务。下面我们来看下一个service要如何定义。
---
apiVersion: v1
kind: Service
metadata:
name: sms
spec:
selector:
run: deployment-sms
ports:
- protocol: TCP
name: http
port: 18000
targetPort: 8000
第3行,我们定义了它的种类为service。
第5行,我们定义了该service的名字。
第7,8行,我们使用了selector选择了一个运行时容器,就是前面定义的deployment-sms运行时容器。
第10至13行,我们定义了该service expose的端口,第10,11行说明它是一个http的服务,第13行容器内监听的端口是8000,第12行我们把该服务暴露为18000端口,这样外部使用该sms服务将使用18000端口。
device调用sms的URL配置
device因为需要调用sms,而sms也部署在kubernetes里,前面说到如果kubernetes内部的服务要被其它系统调用的话,必须把被调用的系统expose为一个service,那么这个service的域名也是有一定讲究的,它的域名组成为 service名字.default.svc.cluster.local,这样device配置文件里定义的sms配置实际为 sms.default.svc.cluster.local:18000。
device Deployment
device同理我们要先定义一个运行时来运行它的容器,也即定义一个deployment,同理在该deployment里我们需要定义device运行时使用的环境变量,运行的镜像名称,要挂载的配置文件路径,日志挂载目录等。我们来看下device deployment的定义:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: deployment-device
spec:
replicas: 2
template:
metadata:
labels:
run: deployment-device
spec:
containers:
- name: deployment-device
image: registry:5000/device:20210101
env:
- name: Y_DNS
valueFrom:
configMapKeyRef:
name: dns
key : Y_DNS
- name: Y_CONFIG_URL
value: http://127.0.0.1:8000/ini/
ports:
- containerPort: 8000
volumeMounts:
- name: device-conf
mountPath: /home/openresty/openresty/nginx/ini/device
readOnly: true
- name: device-status-conf
mountPath: /home/openresty/openresty/nginx/ini/device/status
readOnly: true
- name: log
mountPath: /data/log
volumes:
- name: device-conf
configMap:
name: device-conf
- name: device-status-conf
configMap:
name: device-status-conf
- name: log
hostPath:
path: /data/log
第4行,我们给这个deployment定义了一个名字。
第6行,我们定义了device容器运行的复制份数为2份。
第12至43行,我们定义了要运行的容器内容。
第13行,我们给要运行的容器定义名字为deployment-device。第10行这里run运行的就是该容器的名字。
第14行,定义要运行的镜像版本号。
第15行,定义env环境变量到容器里。后面的16至22行都是环境变量的定义。
第16至20行,我们使用了前面dns-config.yaml里的ConfigMap来映射到环境变量Y_DNS。
第21,22行,我们定义了另一个环境变量Y_CONFIG_URL,它的值为http://127.0.0.1:8000/ini/。
第23,24行定义了容器里服务使用的端口,也即nginx.conf里面监听的端口。
第34至43行,我们先定义使用的volume。
第25至33行,我们把要使用的volume挂载到容器目录里。
至此device系统也已经运行起来了,前面说kubernetes内部的服务要供内部系统使用要定义一个service,那么kubernetes内部的系统要供kubernetes外部服务调用呢?答案是要定义一个NodePort来供外部调用,或者定义一个Ingress来供外部调用。
device NodePort
---
apiVersion: v1
kind: Service
metadata:
name: device
spec:
type: NodePort
selector:
run: deployment-device
ports:
- protocol: TCP
name: http
port: 8000
targetPort: 8000
nodePort: 30072
第3行,其实这儿定义的类别还是Service类别,但是与前面device service的区别。
第5行,为这个Service定义个名字。
第6至15行,定义该service的spec。
第7行,定义它的类型为NodePort,供kubernetes外部系统调用。
第8,9行,选择前面定义的容器运行时名字。
第10,15行定义该NodePort对外提供服务的端口。
第14行,前面运行时容器nginx.conf监听的端口。
第13行,kubernetes内部系统可以访问的映射端口。
第15行,外部服务访问该服务的外部监听端口。
device Ingress
---
apiVersion: v1
kind: Service
metadata:
name: device-service
namespace: {{ namespace }}
spec:
selector:
run: device
ports:
- protocol: TCP
name: http
port: 8000
targetPort: 8000
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: device-ingress
namespace: {{ namespace }}
spec:
rules:
- host: k8s.{{ namespace }}.com
http:
paths:
- path: /device
backend:
serviceName: device-service
servicePort: 30072
第7至14行,定义该service的spec,不需要再声明类型为NodePort。
第14行,前面运行时容器nginx.conf监听的端口。
第13行,kubernetes内部系统可以访问的映射端口。
第18行,类别是Ingress类别。
第24行,访问地址。
第27行,待转发的uri。
第29行,转发的Service服务名称,对应第5行的名称。
第30行,外部服务访问该服务的外部监听端口。
四、小结
环境变量env
环境变量的声明有两种方法,方法一在容器运行时Deployment里直接定义,该方法直观,缺点是这样定义的环境变量只能供该Deployment使用。方法二是使用ConfigMap定义,在运行时容器Deployment里引用该ConfigMap作为环境变量,该方法的好处是可以供其它对象统一调用,如果要修改只需要修改一个地方就可以全部生效。
配置文件ConfigMap
配置文件可以使用ConfigMap原样定义,后面在运行时容器Deployment里映射到容器的相应目录即可。
运行时容器Deployment
Deployment定义了一个容器运行时的参数,运行的副本个数,使用的镜像版本,使用的环境变量,映射的目录。
Kubernetes内部调用的Service
一个系统以Deployment的方式把容器运行起来了,如果它要供kubernetes内部系统调用的话,必须暴露端口等参数,以Service的形式定义。Kubernetes其它系统要使用该内部服务的话则以kubernetes内部域名的形式配置在参数里。
外部系统访问Kubernetes内服务
Kubernetes内系统要能够被外部系统调用的话,必须定义一个Service,并且为NodePort的形式把端口映射出去。
五、Kubernetes常用命令
获取所有命名空间上的pod:
kubectl get pod -o wide --all-namespaces查看pod IP时使用:
kubectl get services查看dsecp-sso-server-w5tx2 日志:
kubectl describe --namespace=default po ips通过yaml文件创建:
kubectl create -f xxx.yaml (不建议使用,无法更新,必须先delete)
kubectl apply -f xxx.yaml(创建+更新,可以重复使用)通过yaml文件删除:
kubectl delete -f xxx.yaml查看kube-system namespace下面的pod/svc/deployment 等等(-o wide 选项可以查看存在哪个对应的节点):
kubectl get pod/svc/deployment -n kube-system查看所有namespace下面的pod/svc/deployment等等:
kubectl get pod/svc/deployment --all-namcpaces重启pod(无法删除对应的应用,因为存在deployment/rc之类的副本控制器,删除pod也会重新拉起来):
kubectl get pod -n kube-system查看pod描述:
kubectl describe pod XXX -n kube-system查看pod 日志 (如果pod有多个容器需要加-c 容器名):
kubectl logs xxx -n kube-system删除应用(先确定是由说明创建的,再删除对应的kind):
kubectl delete deployment xxx -n kube-system根据label删除:
kubectl delete pod -l app=flannel -n kube-system扩容:
kubectl scale deployment spark-worker-deployment --replicas=8