目录
1.语法规则
2.资源属性
3.使用Docker Compose生成k8s资源
4.简单示例:从私有仓库拉取镜像并部署
5.如何使用外部变量
6.对外映射端口
7.存储
Volume
PV
PVC
8.有状态集群服务
StatefulSet
Headless Service
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
”#” 表示注释,从这个字符一直到行尾,都会被解析器忽略
apiVersion: v1 #必选,版本号,1.9.0之前的版本使用apps/v1beta2,可通过kubectl api-versions 查看
kind: Pod #必选,指定创建资源的角色/类型
metadata: #必选,元数据
name: string #必选,资源的名字,在同一个namespace中必须唯一
namespace: string #必选,命名空间
labels: #自定义标签
- name: string #自定义标签名字
annotations: #自定义注释列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口号名称
containerPort: int #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存清楚,容器启动的初始可用数量
livenessProbe: #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged:false
restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork:false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
查看指定属性的详细描述:
查看资源类型
kubectl api-resources -o wide --namespaced=true
通过命令查看如何定义资源
kubectl explain deployment
查看子属性描述
kubectl explain deployment.spec
安装 Kompose
yum -y install kompose
进入 docker-compose.yml 文件所在的目录,转换为 kubectl 可用的文件
kompose -f docker-compose.yml convert
1.配置Secret
Secret 是一个对象,存储一系列的敏感信息。
kubectl create secret docker-registry docker-reg-secret --docker-server=xxx.xxx.x.xxx:2375 --docker-username=admin --docker-password=Harbor12345
2.创建资源清单文件mydemo.yaml
apiVersion: v1
kind: Pod
metadata:
name: mydemo
labels:
app: myapp
version: v1
spec:
imagePullSecrets:
- name: docker-reg-secret
containers:
- name: test
image: xxx.xxx.x.xxx:2375/test/demo:0.0.1
3.运行
kubectl apply -f mydemo.yaml
4.查看
更改资源清单:
apiVersion: v1
kind: Pod
metadata:
name: mydemo
labels:
app: myapp
version: v1
spec:
imagePullSecrets:
- name: docker-reg-secret
containers:
- name: test
image: $HARBOR_REGISTRY_HOST/test/demo:$IMAGE_TAG
在shell脚本里使用export为变量赋值(临时,变量在关闭shell时失效)
export IMAGE_TAG=0.0.2-test
export HARBOR_REGISTRY_HOST=222.212.85.199:12375
启动时使用如下命令:
envsubst < demo.yaml | kubectl apply -f -
Pod更新成功
k8s默认使用NodePort对外映射端口范围是30000-32767
vim /etc/kubernetes/manifests/kube-apiserver.yaml
找到 --service-cluster-ip-range 这一行,在这一行的下一行增加如下内容:
- --service-node-port-range=1-65535
重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
emptyDir <单节点存储卷>
一个emptyDir第一次创建是在一个pod被指定到具体node的时候,并且会一直存在在pod的生命周期当中,它初始化是一个空的目录,pod中的容器都可以读写这个目录,这个目录可以被挂在到各个容器相同或者不相同的的路径下。当一个pod因为任何原因被移除的时候,这些数据会被永久删除。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除pod。
参考:
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node2
containers:
- name: nginx-web
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html
volumes:
- name: html
emptyDir: {}
hostPath <单节点存储卷/跨节点存储卷>
指定挂载本地的目录的名称和路径,即便pod已经被删除了,volume卷中的数据还会留存在node节点中,简单易用,无需额外支持。依赖宿主机磁盘容量,pod与宿主机存在强耦合,不利于管理。当pod部署多个副本并分配到不同host时,数据不共享;当pod漂移时,数据不同步;当node故障时,数据易丢失。
参考:
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node2 #指定工作在节点2上
containers:
- name: nginx-web
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html #容器目录
name: html
volumes:
- name: html
hostPath: #类型为hostPath,即宿主机文件路径
path: /data/nginx/html #宿主机目录
nfs <跨节点存储卷>
即便pod已经被删除了,nfs仅仅是解除挂在状态而已,这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递.并且,nfs可以同时被多个pod挂在并进行读写。
nfs:
path: /sharedata/public
server: xxx.xxx.xxx.xxx
记得给nfs服务器上的文件赋权:
chmod go+w xxxxx
Persistent Volume是一个K8S资源对象,可以单独创建。它不和Pod直接发生关系,而是通过Persistent Volume Claim来实现动态绑定。
样例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
namespace: default
labels:
pv: nfs-pv
spec:
storageClassName: nfs
capacity:
storage: 1Gi
accessModes: #访问模式
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain #回收策略
nfs:
server: xxx.xxx.xxx.xxx
path: "/nfs/data/nginx" #NFS目录,需要该目录在NFS上存在
PV 的访问模式(accessModes)有三种:
ReadWriteOnce(RWO):可读可写,只支持被单个Pod 挂载。
ReadOnlyMany(ROX):以只读的方式被多个Pod 挂载。
ReadWriteMany(RWX):以读写的方式被多个Pod 共享。
PV 的回收策略(persistentVolumeReclaimPolicy,即 PVC 释放卷的时候 PV 该如何操作)也有三种:
Retain:kubernetes什么也不做,保留 Volume(需要手动清理)
Delete:删除该PV及里面的数据
Recycle:将PV里的数据删除,然后把PV的状态变成Available,又可以被新的PVC绑定使用。
Persistent Volume提供了各种存储资源,而Persistent Volume Claim提出需要的存储标准,然后从现有存储资源中匹配或者动态建立新的资源,最后将两者进行绑定。它与 Pod 相似,Pod 消耗 Node 资源,PVC 消耗 PV 资源。
参考:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi #容量
selector:
matchLabels:
pv: nfs-pv #关联pv的label,key/value要一致
Pods使用的是PersistentVolumeClaim而非PersistentVolume:
volumes:
- name: nfs
persistentVolumeClaim:
claimName: nfs-pvc
一般情况下,web server自身都是不需要保存数据的,对于 web server,数据会保存在专门做持久化的节点上。所以这些节点可以随意扩容或者缩容,只要简单的增加或减少副本的数量就可以。但是很多有状态的程序都需要集群式的部署,意味着节点需要形成群组关系,每个节点需要一个唯一的ID(例如Kafka BrokerId, Zookeeper myid)来作为集群内部每个成员的标识,集群内节点之间进行内部通信时需要用到这些标识。传统的做法是管理员会把这些程序部署到稳定的,长期存活的节点上去,这些节点有持久化的存储和静态的IP地址。这样某个应用的实例就跟底层物理基础设施比如某台机器,某个IP地址耦合在一起了。
StatefulSet是用于管理有状态应用程序的工作负载API对象。通过把标识分配给应用程序的某个不依赖于底层物理基础设施的特定实例来解耦这种依赖关系。(不使用静态的IP,而是通过DNS域名去找到某台特定机器)
StatefulSet使用前提:Kubernetes集群的版本 >=1.5
StatefulSet特点:
1.稳定的网络身份,通过Headless Service
2.稳定的存储,通过PV/PVC 来实现的
3.序号命名规则,当一个StatefulSet挂掉,新创建的StatefulSet会被赋予跟原来的Pod一样的名字,通过这个名字来匹配到原来的存储,实现了状态保存。
参考:
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: nginx-statefulset
namespace: default
spec:
serviceName: my-service
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
nginx-statefulset-0 1/1 Running 0 73s
nginx-statefulset-1 1/1 Running 0 46s
nginx-statefulset-2 1/1 Running 0 24s
要定义一个服务(Service)为无头服务(Headless Service),需要把Service定义中的ClusterIP配置项设置为空: spec.clusterIP:None。和普通Service相比,Headless Service没有ClusterIP(所以没有负载均衡),它会给一个集群内部的每个成员提供一个唯一的DNS域名来作为每个成员的网络标识,集群内部成员之间使用域名通信。无头服务管理的域名格式如下:
$(service_name).$(k8s_namespace).svc.cluster.local。
其中的 "cluster.local"是集群的域名,除非做了配置,否则集群域名默认就是cluster.local。StatefulSet下创建的每个Pod,得到一个对应的DNS子域名,格式如下:
$(podname).$(governing_service_domain)
这里 governing_service_domain是由StatefulSet中定义的serviceName来决定。而普通Service情况下,Pod名字后面是随机数,需要通过Service来做负载均衡。
参考:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
clusterIP: None
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 9376