1. k8s集群升级
k8s二进制文件下载地址:https://github.com/kubernetes/kubernetes/releases
1.1 查看集群版本信息
root@k8s-ansible-client:~# kubectl get node -A
NAME STATUS ROLES AGE VERSION
192.168.20.147 Ready node 13d v1.21.0
192.168.20.189 Ready,SchedulingDisabled master 13d v1.21.0
192.168.20.201 Ready,SchedulingDisabled master 13d v1.21.0
192.168.20.236 Ready node 13d v1.21.0
192.168.20.249 Ready,SchedulingDisabled master 13d v1.21.0
192.168.20.253 Ready node 13d v1.21.0
1.2 二进制包下载
root@k8s-ansible-client:/usr/local/src# wget https://dl.k8s.io/v1.22.2/kubernetes.tar.gz
root@k8s-ansible-client:/usr/local/src# wget https://dl.k8s.io/v1.22.2/kubernetes-client-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# wget https://dl.k8s.io/v1.22.2/kubernetes-server-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# https://dl.k8s.io/v1.22.2/kubernetes-node-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# ll -lrt
total 488340
drwxr-xr-x 10 root root 4096 Aug 24 16:42 ../
-rw-r--r-- 1 root root 342548639 Sep 16 07:37 kubernetes-server-linux-amd64.tar.gz
-rw-r--r-- 1 root root 126097180 Sep 16 07:37 kubernetes-node-linux-amd64.tar.gz
-rw-r--r-- 1 root root 30821781 Sep 16 07:37 kubernetes-client-linux-amd64.tar.gz
-rw-r--r-- 1 root root 566795 Sep 16 07:37 kubernetes.tar.gz
drwxr-xr-x 2 root root 4096 Oct 8 22:28 ./
root@k8s-ansible-client:/usr/local/src#
1.3 升级版本
# 解压二进制包
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes.tar.gz
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes-server-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes-node-linux-amd64.tar.gz
root@k8s-ansible-client:/usr/local/src# tar xf kubernetes-client-linux-amd64.tar.gz
1.3.1 master版本升级
先升级master-1
# 将master上kube-lb里面的配置文件去掉master-1
root@k8s-master-1:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-2:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-3:~# vim /etc/kube-lb/conf/kube-lb.conf
# 重启kube-lb服务
root@k8s-master-1:~# systemctl restart kube-lb
root@k8s-master-2:~# systemctl restart kube-lb
root@k8s-master-3:~# systemctl restart kube-lb
# 关闭mater-1上的服务
root@k8s-master-1:~# systemctl stop kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
# 覆盖mater-1上的二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet kubectl root@k8s-master-1:/usr/local/bin
The authenticity of host 'k8s-master-1 (192.168.20.201)' can't be established.
ECDSA key fingerprint is SHA256:mEyjijhaO0Gy5tMg1uTqQXjWOPiW1tf491hnlWUT3Wk.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'k8s-master-1' (ECDSA) to the list of known hosts.
kube-apiserver 100% 119MB 108.8MB/s 00:01
kube-controller-manager 100% 113MB 98.9MB/s 00:01
kube-scheduler 100% 47MB 93.8MB/s 00:00
kube-proxy 100% 41MB 104.8MB/s 00:00
kubelet 100% 146MB 107.2MB/s 00:01
kubectl 100% 45MB 95.3MB/s 00
# 启动服务
root@k8s-master-1:~# systemctl start kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
验证版本
root@k8s-master-1:~# kubectl get node -A
NAME STATUS ROLES AGE VERSION
192.168.20.147 Ready node 13d v1.21.0
192.168.20.189 Ready,SchedulingDisabled master 13d v1.21.0
192.168.20.201 Ready,SchedulingDisabled master 13d v1.22.2
192.168.20.236 Ready node 13d v1.21.0
192.168.20.249 Ready,SchedulingDisabled master 13d v1.21.0
192.168.20.253 Ready node 13d v1.21.0
将master上kube-lb配置文件mater-1加回来,去掉其他两台master节点,进行升级,步骤参考mater-1升级
root@k8s-master-2:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-2:~# systemctl restart kube-lb
root@k8s-master-2:~# systemctl stop kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
root@k8s-master-3:~# vim /etc/kube-lb/conf/kube-lb.conf
root@k8s-master-3:~# systemctl restart kube-lb
root@k8s-master-3:~# systemctl stop kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
# 覆盖mater-2、master-3上的二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet kubectl root@k8s-master-2:/usr/local/bin
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet kubectl root@k8s-master-3:/usr/local/bin
# 启动服务
root@k8s-master-2:~# systemctl start kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
root@k8s-master-3:~# systemctl start kube-apiserver kube-controller-manager kube-proxy kube-scheduler kubelet
版本验证
root@k8s-master-1:~# kubectl get node -A
NAME STATUS ROLES AGE VERSION
192.168.20.147 Ready node 14d v1.21.0
192.168.20.189 Ready,SchedulingDisabled master 14d v1.22.2
192.168.20.201 Ready,SchedulingDisabled master 14d v1.22.2
192.168.20.236 Ready node 14d v1.21.0
192.168.20.249 Ready,SchedulingDisabled master 14d v1.22.2
192.168.20.253 Ready node 14d v1.21.0
最后恢复kube-lb配置文件,并且重启kube-lb服务
1.3.2 work节点版本升级
work节点认证信息存在 /root/.kube/config文件下
升级work-1节点
# 先停服务
root@k8s-work-1:~# systemctl stop kubelet kube-proxy
#scp二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-proxy kubelet kubectl k8s-work-1:/usr/local/bin
# 启动服务
root@k8s-work-1:~# systemctl start kubelet kube-proxy
升级work-2节点
# 先停服务
root@k8s-work-2:~# systemctl stop kubelet kube-proxy
#scp二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-proxy kubelet kubectl k8s-work-2:/usr/local/bin
# 启动服务
root@k8s-work-2:~# systemctl start kubelet kube-proxy
升级work-3节点
# 先停服务
root@k8s-work-3:~# systemctl stop kubelet kube-proxy
#scp二进制文件
root@k8s-ansible-client:/usr/local/src/kubernetes/server/bin# scp kube-proxy kubelet kubectl k8s-work-3:/usr/local/bin
# 启动服务
root@k8s-work-3:~# systemctl start kubelet kube-proxy
验证版本
root@k8s-master-1:~# kubectl get node -A
NAME STATUS ROLES AGE VERSION
192.168.20.147 Ready node 14d v1.22.2
192.168.20.189 Ready,SchedulingDisabled master 14d v1.22.2
192.168.20.201 Ready,SchedulingDisabled master 14d v1.22.2
192.168.20.236 Ready node 14d v1.22.2
192.168.20.249 Ready,SchedulingDisabled master 14d v1.22.2
192.168.20.253 Ready node 14d v1.22.2
2. k8s yaml文件详解
Kubernetes只支持YAML和JSON格式创建资源对象
JSON格式用于接口之间消息的传递,YAML格式用于配置和管理
YAML是专门用来写配置文件的语言,非常简洁和强大,使用比json更方便。它实质上是一种通用的数据串行化格式。
2.1 YAML文件优点
- YAML文件易于人类阅读,具有表达性和可扩展性。
- YAML文件易于实现和使用。
- 可在编程语言之间轻松移植。
- 与敏捷语言的原生数据结构相匹配。
- YAML文件具有一致模型,支持通用工具。
- YAML文件支持One-pass处理。
- 使用方便,因此您无需再将所有的参数添加到命令行中。
- 易于维护 – 可以将YAML文件添加到源控件中以跟踪更改。
- 灵活便捷 – 可以使用YAML创建更加复杂的结构(相对于使用命令行可以创建的结构)
2.2 YAML与 JSON 和 XML 的关系
- XML 是许多领域的优先采用格式。XML 最初设计为与标准通用标记语言 (SGML) 向后兼容,后者旨在支持结构化文档。因此,XML存在许多设计上的约束。
- JSON 的设计理念是简单性和通用性,并且易于生成和解析。JSON 格式的可读性低,但是这种格式的数据每一种现代编程环境都可以轻松处理。
- YAML 的设计目标是提升可读性,提供更加完善的信息模型。YAML 的生成和解析更加复杂,因此可以将其视为 JSON 的自然超集。每个JSON 文件都是一个有效的 YAML 文件。
2.3 YAML文件的结构
键值对 – YAML 文件中的基本条目类型是键值对。键值对的格式是键和冒号,之后是空格,然后是值。
数组/列表 – 列表会在列表名称下列出一些项目。列表的元素以 - 开头。可以有 n 个列表,但是,数组中各个元素的缩进非常重要。
字典/地图 – YAML 文件的更复杂类型是字典和地图。
编写yaml文件的准则,如下:
- 大小写敏感
- 缩进标识层级关系
- 不支持制表符缩进,使用空格缩进
- 通常开头缩进两个空格
- 字符后缩进一个空格,如冒号,逗号等
- “—”表示YAML格式,一个文件的开始
- “#”表示注释
- 在Kubernetes中,只需要知道两种结构类型即可:
- Lists
- Maps
2.4 YAML在Kubernetes中的使用
- Kubernetes 资源是通过声明的方式创建的,因此可以使用 YAML 文件。
- Kubernetes 资源(比如 Pod、服务和部署)是使用 YAML 文件创建的。
2.4.1 YAML Maps
Map顾名思义指的是字典,即一个Key:Value 的键值对信息。例如:
apiVersion: v1
kind: Pod
注:---为可选的分隔符 ,当需要在一个文件中定义多个结构的时候需要使用。上述内容表示有两个键apiVersion和kind,分别对应的值为v1和Pod。
Maps的value既能够对应字符串也能够对应一个Maps。例如:
apiVersion: v1
kind: Pod
metadata:
name: kube100-site
labels:
app: web
注:上述的YAML文件中,metadata这个KEY对应的值为一个Maps,而嵌套的labels这个KEY的值又是一个Map。实际使用中可视情况进行多层嵌套。
YAML处理器根据行缩进来知道内容之间的关联。上述例子中,使用两个空格作为缩进,但空格的数据量并不重要,只是至少要求一个空格并且所有缩进保持一致的空格数 。例如,name和labels是相同缩进级别,因此YAML处理器知道他们属于同一map;它知道app是lables的值因为app的缩进更大。
注意:在YAML文件中绝对不要使用tab键
2.4.2 YAML Lists
List即列表,就是数组,例如:
args:
-beijing
-shanghai
-shenzhen
-guangzhou
-wuhan
可以指定任何数量的项在列表中,每个项的定义以破折号(-)开头,并且与父元素之间存在缩进。在JSON格式中,表示如下:
{
"args": ["beijing", "shanghai", "shenzhen", "guangzhou"]
}
当然Lists的子项也可以是Maps,Maps的子项也可以是List,例如:
apiVersion: v1
kind: Pod
metadata:
name: kube100-site
labels:
app: web
spec:
containers:
- name: front-end
image: nginx
ports:
- containerPort: 80
- name: flaskapp-demo
image: jcdemo/flaskapp
ports: 8080
如上述文件所示,定义一个containers的List对象,每个子项都由name、image、ports组成,每个ports都有一个KEY为containerPort的Map组成,转成JSON格式文件
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "kube100-site",
"labels": {
"app": "web"
},
},
"spec": {
"containers": [{
"name": "front-end",
"image": "nginx",
"ports": [{
"containerPort": "80"
}]
}, {
"name": "flaskapp-demo",
"image": "jcdemo/flaskapp",
"ports": [{
"containerPort": "5000"
}]
}]
}
}
2.5 使用YAML创建Pod
K8S有两种创建资源的方式:kubectl 命令和 yaml 配置文件
kubectl命令行:最为简单,一条命令就OK
yaml配置文件,例如:
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,Pod
metadata: #必选,元数据
name: string #必选,Pod名称
namespace: string #必选,Pod所属的命名空间
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
apiVersion:此处值是v1,这个版本号需要根据安装的Kubernetes版本和资源类型进行变化,记住不是写死的。
kind:此处创建的是Pod,根据实际情况,此处资源类型可以是Deployment、Job、Ingress、Service等。
metadata:包含Pod的一些meta信息,比如名称、namespace、标签等信息。
spec:包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否在容器失败时重新启动容器的属性。可在特定Kubernetes API找到完整的Kubernetes Pod的属性
查看apiVersion
root@k8s-ansible-client:~# kubectl api-versions
admissionregistration.k8s.io/v1
apiextensions.k8s.io/v1
apiregistration.k8s.io/v1
apps/v1
authentication.k8s.io/v1
authorization.k8s.io/v1
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2
batch/v1
batch/v1beta1
certificates.k8s.io/v1
coordination.k8s.io/v1
discovery.k8s.io/v1
discovery.k8s.io/v1beta1
events.k8s.io/v1
events.k8s.io/v1beta1
flowcontrol.apiserver.k8s.io/v1beta1
networking.k8s.io/v1
node.k8s.io/v1
node.k8s.io/v1beta1
policy/v1
policy/v1beta1
rbac.authorization.k8s.io/v1
scheduling.k8s.io/v1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1
下面是一个典型的容器定义
spec:
containers:
- name: front-end
image: nginx
ports:
- containerPort: 80
上述例子只是一个简单的最小定义:一个名字(front-end)、基于nginx的镜像,以及容器将会监听的指定端口号(80)。
除了上述的基本属性外,还能够指定复杂的属性,包括容器启动运行的命令、使用的参数、工作目录以及每次实例化是否拉取新的副本。 还可以指定更深入的信息,例如容器的退出日志的位置。容器可选的设置属性包括:
name、image、command、args、workingDir、ports、env、resource、volumeMounts、livenessProbe、readinessProbe、livecycle、terminationMessagePath、imagePullPolicy、securityContext、stdin、stdinOnce、tty
kubectl创建pod
root@k8s-ansible-client:~/yaml# kubectl apply -f test_pod.yaml
pod/kube100-site created
2.6 创建Deployment
apiVersion: extensions/v1beta1 #接口版本
kind: Deployment #接口类型
metadata:
name: ptengine-demo #Deployment名称
namespace: ptengine-prd #namespace 名称
labels:
app: ptengine-demo #标签
spec:
replicas: 3
strategy:
rollingUpdate: ##由于replicas为3,则整个升级,pod个数在2-4个之间
maxSurge: 1 #滚动升级时会先启动1个pod
maxUnavailable: 1 #滚动升级时允许的最大Unavailable的pod个数
template:
metadata:
labels:
app: ptengine-demo #模板名称必填
sepc: #定义容器模板,该模板可以包含多个容器
containers:
- name: ptengine-demo #镜像名称
image: reg.pt1.com/ptengine-prd/ptengine-demo:0.0.1-SNAPSHOT #镜像地址
CMD: [ "/bin/sh","-c","cat /etc/config/path/to/special-key" ] #启动CMD
args: #启动参数
- '-storage.local.retention=$(STORAGE_RETENTION)'
- '-web.external-url=$(EXTERNAL_URL)'
imagePullPolicy: IfNotPresent #如果不存在则拉取
livenessProbe: #表示container是否处于live状态。如果LivenessProbe失败,LivenessProbe将会通知kubelet对应的container不健康了。随后kubelet将kill掉container,并根据RestarPolicy进行进一步的操作。默认情况下LivenessProbe在第一次检测之前初始化值为Success,如果container没有提供LivenessProbe,则也认为是Success;
httpGet:
path: /health #如果没有心跳检测接口就为/
port: 8080
scheme: HTTP
initialDelaySeconds: 60 ##启动后延时多久开始运行检测
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
readinessProbe:
httpGet:
path: /health #如果没有健康检测接口就为/
port: 8080
scheme: HTTP
initialDelaySeconds: 30 ##启动后延时多久开始运行检测
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
resources: ##CPU内存限制
requests:
cpu: 2
memory: 2048Mi
limits:
cpu: 2
memory: 2048Mi
env: ##通过环境变量的方式,直接传递pod=自定义Linux OS环境变量
- name: LOCAL_KEY #本地Key
value: value
- name: CONFIG_MAP_KEY #local策略可使用configMap的配置Key,
valueFrom:
configMapKeyRef:
name: special-config #configmap中找到name为special-config
key: special.type #找到name为special-config里data下的key
ports:
- name: http
containerPort: 8080 #对service暴露端口
volumeMounts: #挂载volumes中定义的磁盘
- name: log-cache
mount: /tmp/log
- name: sdb #普通用法,该卷跟随容器销毁,挂载一个目录
mountPath: /data/media
- name: nfs-client-root #直接挂载硬盘方法,如挂载下面的nfs目录到/mnt/nfs
mountPath: /mnt/nfs
- name: example-volume-config #高级用法第1种,将ConfigMap的log-script,backup-script分别挂载到/etc/config目录下的一个相对路径path/to/...下,如果存在同名文件,直接覆盖。
mountPath: /etc/config
- name: rbd-pvc #高级用法第2中,挂载PVC(PresistentVolumeClaim)
#使用volume将ConfigMap作为文件或目录直接挂载,其中每一个key-value键值对都会生成一个文件,key为文件名,value为内容,
volumes: # 定义磁盘给上面volumeMounts挂载
- name: log-cache
emptyDir: {}
- name: sdb #挂载宿主机上面的目录
hostPath:
path: /any/path/it/will/be/replaced
- name: example-volume-config # 供ConfigMap文件内容到指定路径使用
configMap:
name: example-volume-config #ConfigMap中名称
items:
- key: log-script #ConfigMap中的Key
path: path/to/log-script #指定目录下的一个相对路径path/to/log-script
- key: backup-script #ConfigMap中的Key
path: path/to/backup-script #指定目录下的一个相对路径path/to/backup-script
- name: nfs-client-root #供挂载NFS存储类型
nfs:
server: 10.42.0.55 #NFS服务器地址
path: /opt/public #showmount -e 看一下路径
- name: rbd-pvc #挂载PVC磁盘
persistentVolumeClaim:
claimName: rbd-pvc1 #挂载已经申请的pvc磁盘
创建一个yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.10
ports:
- containerPort: 80
创建deployment
root@k8s-ansible-client:~/yaml# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
alpine-test 1/1 Running 25 (10h ago) 14d 172.20.108.65 192.168.20.236 <none> <none>
kube100-site 2/2 Running 0 11m 172.20.213.6 192.168.20.253 <none> <none>
nginx-deployment-748755bf57-8w4jc 1/1 Running 0 15s 172.20.191.12 192.168.20.147 <none> <none>
nginx-deployment-748755bf57-k5nlx 1/1 Running 0 15s 172.20.191.11 192.168.20.147 <none> <none>
nginx-deployment-748755bf57-ltldz 1/1 Running 0 15s 172.20.108.67 192.168.20.236 <none> <none>
nginx-test-001 1/1 Running 1 (11h ago) 25h 172.20.191.10 192.168.20.147 <none> <none>
nginx-test1 1/1 Running 25 (10h ago) 14d 172.20.191.2 192.168.20.147 <none> <none>
nginx-test2 1/1 Running 25 (10h ago) 14d 172.20.213.3 192.168.20.253 <none> <none>
nginx-test3 1/1 Running 25 (10h ago) 14d 172.20.191.3 192.168.20.147 <none> <none>
root@k8s-ansible-client:~/yaml# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 56s
3. ETCD
ETCD是用于共享配置和服务发现的分布式,一致性的KV存储系统。Github
ETCD是分布式系统中最关键数据的分布式可靠键值存储,重点在于:
- 简单:定义明确、面向用户的 API (gRPC)
- 安全:具有可选客户端证书身份验证的自动 TLS
- 快速:基准测试为 10,000 次写入/秒
- 可靠:使用 Raft 正确分布
3.1工作原理
ETCD使用Raft协议来维护集群内各个节点状态的一致性。简单说,ETCD集群是一个分布式系统,由多个节点相互通信构成整体对外服务,每个节点都存储了完整的数据,并且通过Raft协议保证每个节点维护的数据是一致的。
如图所示,每个ETCD节点都维护了一个状态机,并且,任意时刻至多存在一个有效的主节点。主节点处理所有来自客户端写操作,通过Raft协议保证写操作对状态机的改动会可靠的同步到其他节点。
ETCD工作原理核心部分在于Raft协议。
Raft协议正如论文所述,确实方便理解。主要分为三个部分:
- 选主
- 日志复制
- 安全性
3.1.1 选主
Raft协议是用于维护一组服务节点数据一致性的协议。这一组服务节点构成一个集群,并且有一个主节点来对外提供服务。当集群初始化,或者主节点挂掉后,面临一个选主问题。集群中每个节点,任意时刻处于Leader, Follower, Candidate这三个角色之一。选举特点如下:
- 当集群初始化时候,每个节点都是Follower角色;
- 集群中存在至多1个有效的主节点,通过心跳与其他节点同步数据;
- 当Follower在一定时间内没有收到来自主节点的心跳,会将自己角色改变为Candidate,并发起一次选主投票;当收到包括自己在内超过半数节点赞成后,选举成功;当收到票数不足半数选举失败,或者选举超时。若本轮未选出主节点,将进行下一轮选举(出现这种情况,是由于多个节点同时选举,所有节点均为获得过半选票)。
- Candidate节点收到来自主节点的信息后,会立即终止选举过程,进入Follower角色。
为了避免陷入选主失败循环,每个节点未收到心跳发起选举的时间是一定范围内的随机值,这样能够避免2个节点同时发起选主。
3.1.2 日志复制
所谓日志复制,是指主节点将每次操作形成日志条目,并持久化到本地磁盘,然后通过网络IO发送给其他节点。其他节点根据日志的逻辑时钟(TERM)和日志编号(INDEX)来判断是否将该日志记录持久化到本地。当主节点收到包括自己在内超过半数节点成功返回,那么认为该日志是可提交的(committed),并将日志输入到状态机,将结果返回给客户端。
这里需要注意的是,每次选主都会形成一个唯一的TERM编号,相当于逻辑时钟。每一条日志都有全局唯一的编号。
主节点通过网络IO向其他节点追加日志。若某节点收到日志追加的消息,首先判断该日志的TERM是否过期,以及该日志条目的INDEX是否比当前以及提交的日志的INDEX跟早。若已过期,或者比提交的日志更早,那么就拒绝追加,并返回该节点当前的已提交的日志的编号。否则,将日志追加,并返回成功。
当主节点收到其他节点关于日志追加的回复后,若发现有拒绝,则根据该节点返回的已提交日志编号,发生其编号下一条日志。
主节点像其他节点同步日志,还作了拥塞控制。具体地说,主节点发现日志复制的目标节点拒绝了某次日志追加消息,将进入日志探测阶段,一条一条发送日志,直到目标节点接受日志,然后进入快速复制阶段,可进行批量日志追加。
按照日志复制的逻辑,我们可以看到,集群中慢节点不影响整个集群的性能。另外一个特点是,数据只从主节点复制到Follower节点,这样大大简化了逻辑流程。
3.1.3 安全性
截止此刻,选主以及日志复制并不能保证节点间数据一致。试想,当一个某个节点挂掉了,一段时间后再次重启,并当选为主节点。而在其挂掉这段时间内,集群若有超过半数节点存活,集群会正常工作,那么会有日志提交。这些提交的日志无法传递给挂掉的节点。当挂掉的节点再次当选主节点,它将缺失部分已提交的日志。在这样场景下,按Raft协议,它将自己日志复制给其他节点,会将集群已经提交的日志给覆盖掉。
这显然是不可接受的。
其他协议解决这个问题的办法是,新当选的主节点会询问其他节点,和自己数据对比,确定出集群已提交数据,然后将缺失的数据同步过来。这个方案有明显缺陷,增加了集群恢复服务的时间(集群在选举阶段不可服务),并且增加了协议的复杂度。
Raft解决的办法是,在选主逻辑中,对能够成为主的节点加以限制,确保选出的节点已定包含了集群已经提交的所有日志。如果新选出的主节点已经包含了集群所有提交的日志,那就不需要从和其他节点比对数据了。简化了流程,缩短了集群恢复服务的时间。
这里存在一个问题,加以这样限制之后,还能否选出主呢?答案是:只要仍然有超过半数节点存活,这样的主一定能够选出。因为已经提交的日志必然被集群中超过半数节点持久化,显然前一个主节点提交的最后一条日志也被集群中大部分节点持久化。当主节点挂掉后,集群中仍有大部分节点存活,那这存活的节点中一定存在一个节点包含了已经提交的日志了。
3.2 ETCD接口
ETCD提供HTTP协议,在最新版本中支持Google gRPC方式访问。具体支持接口情况如下:
- ETCD是一个高可靠的KV存储系统,支持PUT/GET/DELETE接口;
- 为了支持服务注册与发现,支持WATCH接口(通过http long poll实现);
- 支持KEY持有TTL属性;
- CAS(compare and swap)操作;
- 支持多key的事务操作;
- 支持目录操作
3.3 ETCD集群
官网说明文档,提供了3种集群启动方式,实际上按照其实现原理分为2类:
- 通过静态配置方式启动
- 通过服务发现方式启动
3.3.1 集群节点数量与网络分割
ETCD使用RAFT协议保证各个节点之间的状态一致。根据RAFT算法原理,节点数目越多,会降低集群的写性能。这是因为每一次写操作,需要集群中大多数节点将日志落盘成功后,Leader节点才能将修改内部状态机,并返回将结果返回给客户端。
也就是说在等同配置下,节点数越少,集群性能越好。显然,只部署1个节点是没什么意义的。通常,按照需求将集群节点部署为3,5,7,9个节点。
这里能选择偶数个节点吗? 最好不要这样。原因有二:
- 偶数个节点集群不可用风险更高,表现在选主过程中,有较大概率或等额选票,从而触发下一轮选举。
- 偶数个节点集群在某些网络分割的场景下无法正常工作。试想,当网络分割发生后,将集群节点对半分割开。此时集群将无法工作。按照RAFT协议,此时集群写操作无法使得大多数节点同意,从而导致写失败,集群无法正常工作。
当网络分割后,ETCD集群如何处理的呢?
- 当集群的Leader在多数节点这一侧时,集群仍可以正常工作。少数节点那一侧无法收到Leader心跳,也无法完成选举。
- 当集群的Leader在少数节点这一侧时,集群仍可以正常工作,多数派的节点能够选出新的Leader, 集群服务正常进行。
当网络分割恢复后,少数派的节点会接受集群Leader的日志,直到和其他节点状态一致。
3.3.2 ETCD参数说明
这里只列举一些重要的参数,以及其用途。
- —data-dir 指定节点的数据存储目录,这些数据包括节点ID,集群ID,集群初始化配置,Snapshot文件,若未指定—wal-dir,还会存储WAL文件;
- —wal-dir 指定节点的was文件的存储目录,若指定了该参数,wal文件会和其他数据文件分开存储。
- —name 节点名称
- —initial-advertise-peer-urls 告知集群其他节点url.
- — listen-peer-urls 监听URL,用于与其他节点通讯
- — advertise-client-urls 告知客户端url, 也就是服务的url
- — initial-cluster-token 集群的ID
- — initial-cluster 集群中所有节点
3.3.3 ETCD命令操作
# 查看心跳信息
root@k8s-master-1:~# export NODE_IPS="192.168.20.201 192.168.20.189 192.168.20.249"
root@k8s-master-1:~# for ip in ${NODE_IPS}; do ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem endpoint health; done
https://192.168.20.201:2379 is healthy: successfully committed proposal: took = 17.919907ms
https://192.168.20.189:2379 is healthy: successfully committed proposal: took = 10.841348ms
https://192.168.20.249:2379 is healthy: successfully committed proposal: took = 11.216277ms
# 显示集群成员信息
root@k8s-master-1:~# ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table member list --endpoints=https://192.168.20.201:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem
+------------------+---------+---------------------+-----------------------------+-----------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+---------------------+-----------------------------+-----------------------------+------------+
| 569e391105c011f | started | etcd-192.168.20.189 | https://192.168.20.189:2380 | https://192.168.20.189:2379 | false |
| f212819f18bbd3b | started | etcd-192.168.20.201 | https://192.168.20.201:2380 | https://192.168.20.201:2379 | false |
| 846cf490f28e27e2 | started | etcd-192.168.20.249 | https://192.168.20.249:2380 | https://192.168.20.249:2379 | false |
+------------------+---------+---------------------+-----------------------------+-----------------------------+------------+
# 以表格方式显示节点详细状态
root@k8s-master-1:~# for ip in ${NODE_IPS}; do ETCDCTL_API=3 /usr/local/bin/etcdctl --write-out=table endpoint status --endpoints=https://${ip}:2379 --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/etcd.pem --key=/etc/kubernetes/ssl/etcd-key.pem; done
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.20.201:2379 | f212819f18bbd3b | 3.4.13 | 3.8 MB | false | false | 7 | 3596022 | 3596021 | |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.20.189:2379 | 569e391105c011f | 3.4.13 | 3.9 MB | true | false | 7 | 3596022 | 3596022 | |
+-----------------------------+-----------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
+-----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://192.168.20.249:2379 | 846cf490f28e27e2 | 3.4.13 | 3.8 MB | false | false | 7 | 3596022 | 3596022 | |
+-----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
# 列出所有key信息
root@k8s-master-1:~# /usr/local/bin/etcdctl get / --prefix --keys-only
/calico/ipam/v2/assignment/ipv4/block/172.20.108.64-26
/calico/ipam/v2/assignment/ipv4/block/172.20.168.0-26
/calico/ipam/v2/assignment/ipv4/block/172.20.182.64-26
/calico/ipam/v2/assignment/ipv4/block/172.20.191.0-26
/calico/ipam/v2/assignment/ipv4/block/172.20.196.0-26
/calico/ipam/v2/assignment/ipv4/block/172.20.213.0-26
/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-master-1
/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-master-2
/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-master-3
/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-work-1
/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-work-2
/calico/ipam/v2/handle/ipip-tunnel-addr-k8s-work-3
...
3.3.4 ETCD数据备份与恢复机制
# 备份数据
root@k8s-master-1:~# ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot save snapshot.db
{"level":"info","ts":1633877806.220544,"caller":"snapshot/v3_snapshot.go:119","msg":"created temporary db file","path":"snapshot.db.part"}
{"level":"info","ts":"2021-10-10T22:56:46.221+0800","caller":"clientv3/maintenance.go:200","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1633877806.2211795,"caller":"snapshot/v3_snapshot.go:127","msg":"fetching snapshot","endpoint":"127.0.0.1:2379"}
{"level":"info","ts":"2021-10-10T22:56:46.306+0800","caller":"clientv3/maintenance.go:208","msg":"completed snapshot read; closing"}
{"level":"info","ts":1633877806.3121157,"caller":"snapshot/v3_snapshot.go:142","msg":"fetched snapshot","endpoint":"127.0.0.1:2379","size":"3.8 MB","took":0.091485483}
{"level":"info","ts":1633877806.31222,"caller":"snapshot/v3_snapshot.go:152","msg":"saved","path":"snapshot.db"}
Snapshot saved at snapshot.db
# 恢复数据
root@k8s-master-1:~# ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot restore snapshot.db --data-dir=/opt/etcd-testdir #将数据恢复到一个新的不存在的目录中
{"level":"info","ts":1633877847.2969198,"caller":"snapshot/v3_snapshot.go:296","msg":"restoring snapshot","path":"snapshot.db","wal-dir":"/opt/etcd-testdir/member/wal","data-dir":"/opt/etcd-testdir","snap-dir":"/opt/etcd-testdir/member/snap"}
{"level":"info","ts":1633877847.3445005,"caller":"mvcc/kvstore.go:380","msg":"restored last compact revision","meta-bucket-name":"meta","meta-bucket-name-key":"finishedCompactRev","restored-compact-revision":2749686}
{"level":"info","ts":1633877847.3551688,"caller":"membership/cluster.go:392","msg":"added member","cluster-id":"cdf818194e3a8c32","local-member-id":"0","added-peer-id":"8e9e05c52164694d","added-peer-peer-urls":["http://localhost:2380"]}
{"level":"info","ts":1633877847.373978,"caller":"snapshot/v3_snapshot.go:309","msg":"restored snapshot","path":"snapshot.db","wal-dir":"/opt/etcd-testdir/member/wal","data-dir":"/opt/etcd-testdir","snap-dir":"/opt/etcd-testdir/member/snap"}
# 自动备份数据
root@k8s-master-1:~# mkdir /data/etcd-backup/ -p
root@k8s-master-1:/data/etcd-backup# cat script.sh
#!/bin/bash
source /etc/profile
DATE=`date +%Y-%m-%d_%H-%M-%S`
ETCDCTL_API=3 /usr/local/bin/etcdctl snapshot save /data/etcd-backup-dir/etcd-snapshot-${DATE}.db
ETCD数据恢复流程
当etd集群宕机数量超过集群总节点数一半以上的时候(如总数为三台宕机两台),就会导致整个集群宕机,后期需要重新恢复数据,则恢复流程如下:
- 恢复服务器系统
- 重新部署etcd集群
- 停止kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy
- 停止etcd集群
- 各ETCD节点恢复同一份备份数据
- 启动各节点并验证ETCD集群
- 启动kube-apiserver/controller-manager/scheduler/kubelet/kube-proxy
- 验证k8s master状态及pod数据
4. k8s集群常用维护命令
4.1 查看信息的命令
# 查看所有pod信息
root@k8s-master-1:~# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
default alpine-test 1/1 Running 27 (6h40m ago) 15d
default kube100-site 2/2 Running 0 23h
default nginx-deployment-748755bf57-8w4jc 1/1 Running 0 23h
default nginx-deployment-748755bf57-k5nlx 1/1 Running 0 23h
default nginx-deployment-748755bf57-ltldz 1/1 Running 0 23h
default nginx-test-001 1/1 Running 3 (7h17m ago) 2d
default nginx-test1 1/1 Running 27 (6h50m ago) 15d
default nginx-test2 1/1 Running 27 (6h50m ago) 15d
default nginx-test3 1/1 Running 27 (6h50m ago) 15d
kube-system calico-kube-controllers-647f956d86-mtpdr 1/1 Running 0 15d
kube-system calico-node-7tqpw 1/1 Running 0 15d
kube-system calico-node-hv6xc 1/1 Running 0 15d
kube-system calico-node-jcnlw 1/1 Running 0 15d
kube-system calico-node-lktp8 1/1 Running 0 15d
kube-system calico-node-mv7lp 1/1 Running 0 15d
kube-system calico-node-wqbnr 1/1 Running 0 15d
kube-system coredns-f97dc456d-9cncc 1/1 Running 0 15d
kubernetes-dashboard dashboard-metrics-scraper-856586f554-xms2j 1/1 Running 0 15d
kubernetes-dashboard kubernetes-dashboard-67484c44f6-2cjtp 1/1 Running 0 15d
# 列出资源信息
root@k8s-master-1:~# kubectl get deployment -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
default nginx-deployment 3/3 3 3 23h
kube-system calico-kube-controllers 1/1 1 1 15d
kube-system coredns 1/1 1 1 15d
kubernetes-dashboard dashboard-metrics-scraper 1/1 1 1 15d
kubernetes-dashboard kubernetes-dashboard 1/1 1 1 15d
# 展示出来pod所在的节点信息
root@k8s-master-1:~# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
alpine-test 1/1 Running 27 (6h43m ago) 15d 172.20.108.65 192.168.20.236 <none> <none>
kube100-site 2/2 Running 0 23h 172.20.213.6 192.168.20.253 <none> <none>
nginx-deployment-748755bf57-8w4jc 1/1 Running 0 23h 172.20.191.12 192.168.20.147 <none> <none>
nginx-deployment-748755bf57-k5nlx 1/1 Running 0 23h 172.20.191.11 192.168.20.147 <none> <none>
nginx-deployment-748755bf57-ltldz 1/1 Running 0 23h 172.20.108.67 192.168.20.236 <none> <none>
nginx-test-001 1/1 Running 3 (7h20m ago) 2d1h 172.20.191.10 192.168.20.147 <none> <none>
nginx-test1 1/1 Running 27 (6h53m ago) 15d 172.20.191.2 192.168.20.147 <none> <none>
nginx-test2 1/1 Running 27 (6h53m ago) 15d 172.20.213.3 192.168.20.253 <none> <none>
nginx-test3 1/1 Running 27 (6h53m ago) 15d 172.20.191.3 192.168.20.147 <none> <none>
# 以yaml文件形式显示一个pod详细信息
root@k8s-master-1:~# kubectl get pods alpine-test -o yaml
# 以json文件形式显示一个pod详细信息
root@k8s-master-1:~# kubectl get pods alpine-test -o json
# pod启动过程中遇到问题可以使用describe 进行排查
root@k8s-master-1:~# kubectl describe pods alpine-test
4.2 apply命令
apply命令提供了比patch,edit等更严格的更新resource的方式。通过apply,用户可以将resource的configuration使用source control的方式维护在版本库中。每次有更新时,将配置文件push到server,然后使用kubectl apply将更新应用到resource。kubernetes会在引用更新前将当前配置文件中的配置同已经应用的配置做比较,并只更新更改的部分,而不会主动更改任何用户未指定的部分。
apply命令的使用方式同replace相同,不同的是,apply不会删除原有resource,然后创建新的。apply直接在原有resource的基础上进行更新。同时kubectl apply还会resource中添加一条注释,标记当前的apply。类似于git操作。
# 命令使用
root@k8s-master-1:~# kubectl apply -f xxx.yaml
4.3 delete命令
根据resource名或label删除resource。
命令格式:
root@k8s-master-1:~# kubectl delete -f xxx.yaml
root@k8s-master-1:~# kubectl delete pods xxxx-xx
root@k8s-master-1:~# kubectl delete pods -lapp=nginx-test
4.4 查看字段帮助信息
使用 kubectl explain命令可以查看yaml文件的字段中可以使用那些信息字段
例如:查看pod资源中spec下的containers下的ports可以使用哪些信息字段
root@k8s-ansible-client:~/yaml# kubectl explain pod.spec.containers.ports
KIND: Pod
VERSION: v1
RESOURCE: ports <[]Object>
DESCRIPTION:
List of ports to expose from the container. Exposing a port here gives the
system additional information about the network connections a container
uses, but is primarily informational. Not specifying a port here DOES NOT
prevent that port from being exposed. Any port which is listening on the
default "0.0.0.0" address inside a container will be accessible from the
network. Cannot be updated.
ContainerPort represents a network port in a single container.
FIELDS:
containerPort <integer> -required-
Number of port to expose on the pod's IP address. This must be a valid port
number, 0 < x < 65536.
hostIP <string>
What host IP to bind the external port to.
hostPort <integer>
Number of port to expose on the host. If specified, this must be a valid
port number, 0 < x < 65536. If HostNetwork is specified, this must match
ContainerPort. Most containers do not need this.
name <string>
If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
named port in a pod must have a unique name. Name for the port that can be
referred to by services.
protocol <string>
Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP".
4.5 deployment常见操作
更新deploy的镜像
# kubectl set image deploy nginx nginx=nginx:1.14.2
#可以使用 –-record 参数保留更新记录,后面截图的版本记录中1、2都是没有使用该参数的,3、4是使用了的
查看更新过程
# kubectl rollout status deploy nginx
# kubectl describe deploy nginx
回滚
# kubectl rollout history deploy nginx #查看历史版本
# kubectl rollout undo deploy nginx #回滚到上一个版本
# kubectl rollout history deploy nginx #查看历史记录
# kubectl rollout history deploy nginx --revision=3 #查看某个版本的详细信息
# kubectl rollout undo deploy nginx --to-revision=3 #回滚到某个版本
每次更新都会引发deploy的更新,可以先把更新暂停掉,然后调整配置,回复后就可以将暂停期间的操作一次更新。
# kubectl rollout pause deployment nginx #暂停
# kubectl rollout resume deploy nginx #恢复
5. 资源对象
5.1 资源控制器
Kubernetes的资源控制器ReplicationController(RC)、ReplicaSet(RS)、Deployment(Deploy)
5.1.1 什么是控制器
kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制pod的具体状态和行为。
部分控制器类型如下:
- ReplicationController 和 ReplicaSet
- Deployment
- DaemonSet
- StatefulSet
- Job/CronJob
- HorizontalPodAutoscaler
5.1.2 Replication Controller
RC独立于所控制的pod,通过label标签来控制目标pod的创建和销毁,他能够保证Pod持续运行,并且在任何时候都有指定数量的Pod副本。也就是说,Replication Controller可确保一个Pod或一组同类Pod总是可用。
如果存在的Pod大于设定的值,则Replication Controller将终止多余的Pod。如果太少,Replication Controller将启动更多的Pod用于保证达到设定的期望值。与手动创建Pod不同的是,用Replication Controller管理的Pod在失败、删除或终止时会自动替换。
所以,建议哪怕应用程序只需要一个Pod,也应该使用Replication Controller这种自动管理的方式来管理pod。Replication Controller所管理的pod不局限于某个节点,而是监视k8s集群的多个节点上的多个Pod。
示例:
root@k8s-ansible-client:~/yaml/20210926/01# vim rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: ng-rc
spec:
replicas: 2
selector:
app: ng-rc-80
#app1: ng-rc-81
template:
metadata:
labels:
app: ng-rc-80
#app1: ng-rc-81
spec:
containers:
- name: ng-rc-80
image: nginx
ports:
- containerPort: 80
root@k8s-ansible-client:~/yaml/20210926/01# kubectl apply -f rc.yaml
replicationcontroller/ng-rc created
root@k8s-ansible-client:~/yaml/20210926/01# kubectl get pods
NAME READY STATUS RESTARTS AGE
alpine-test 1/1 Running 29 (140m ago) 16d
kube100-site 2/2 Running 0 47h
ng-rc-jxdn4 1/1 Running 0 12s
ng-rc-s667h 1/1 Running 0 12s
nginx-deployment-748755bf57-8w4jc 1/1 Running 0 47h
nginx-deployment-748755bf57-k5nlx 1/1 Running 0 47h
nginx-deployment-748755bf57-ltldz 1/1 Running 0 47h
nginx-test-001 1/1 Running 5 (176m ago) 3d
nginx-test1 1/1 Running 29 (150m ago) 16d
nginx-test2 1/1 Running 29 (150m ago) 16d
nginx-test3 1/1 Running 29 (150m ago) 16d
5.1.3 ReplicaSet
ReplicaSet可以视为Replication Controller的增强版,他主要用作协调创建、删除和更新Pod,和Replication Controller唯一的区别是,ReplicaSet支持灵活的标签选择器,对比RC只能选择一个标签而言,RS的标签选择器是集合式的,使用这种集合方式可以实现滚动升级,包括Deployment也是通过ReplicaSet实现了POD副本自动控制功能。
官方建议虽然ReplicaSet可以单独使用,还是最好使用Deployment对象来控制Pod副本数。
示例:
root@k8s-ansible-client:~/yaml/20210926/01# vim rs.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
spec:
replicas: 2
selector:
# matchLabels:
# app: ng-rs-80
matchExpressions:
- {key: app, operator: In, values: [ng-rs-80,ng-rs-81]}
template:
metadata:
labels:
app: ng-rs-80
spec:
containers:
- name: ng-rs-80
image: nginx
ports:
- containerPort: 80
root@k8s-ansible-client:~/yaml/20210926/01# kubectl apply -f rs.yaml
replicaset.apps/frontend created
root@k8s-ansible-client:~/yaml/20210926/01# kubectl get pods
NAME READY STATUS RESTARTS AGE
alpine-test 1/1 Running 29 (142m ago) 16d
frontend-78qz8 1/1 Running 0 6s
frontend-kvxph 1/1 Running 0 6s
kube100-site 2/2 Running 0 47h
nginx-deployment-748755bf57-8w4jc 1/1 Running 0 47h
nginx-deployment-748755bf57-k5nlx 1/1 Running 0 47h
nginx-deployment-748755bf57-ltldz 1/1 Running 0 47h
nginx-test-001 1/1 Running 5 (178m ago) 3d
nginx-test1 1/1 Running 29 (151m ago) 16d
nginx-test2 1/1 Running 29 (151m ago) 16d
nginx-test3 1/1 Running 29 (151m ago) 16d
Replication Controller(复制控制器,RC)和ReplicaSet(复制集,RS)是两种简单部署Pod的方式。他们在创建和删除pod时区别不大,生产环境中用的也很少,基本使用比较高级的Deployment等资源进行pod管理。
5.1.4 Deployment
Deployment是 1.2版本引入的,用于更好的解决Pod的编排问题,内部使用了ReplicaSet实现目的。
Deployment用于部署无状态的服务,是最常用的控制器。
Deployment对于RC的最大优势是可以随时知道Pod的部署进度。处于pod的创建、调度、绑定节点及在目标节点启动对应容器哪一个过程。
典型的应用场景包括:
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
示例:
root@k8s-ansible-client:~/yaml/20210926/01# vim deployment.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
#app: ng-deploy-80 #rc
matchLabels: #rs or deployment
app: ng-deploy-80
# matchExpressions:
# - {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx:1.16.1
ports:
- containerPort: 80
root@k8s-ansible-client:~/yaml/20210926/01# kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/01# kubectl get pods,deploy
NAME READY STATUS RESTARTS AGE
pod/alpine-test 1/1 Running 29 (146m ago) 16d
pod/kube100-site 2/2 Running 0 47h
pod/nginx-deployment-5d76cf6966-m89gf 0/1 ContainerCreating 0 5s
pod/nginx-deployment-5d76cf6966-x5f8m 0/1 ContainerCreating 0 5s
pod/nginx-test-001 1/1 Running 5 (3h3m ago) 3d
pod/nginx-test1 1/1 Running 29 (156m ago) 16d
pod/nginx-test2 1/1 Running 29 (156m ago) 16d
pod/nginx-test3 1/1 Running 29 (156m ago) 16d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 0/2 2 0 5s
5.2 Service
service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现
它定义了一组Pods
的逻辑集合和一个用于访问它们的策略 - 有的时候被称之为微服务。一个Service
的目标Pod
集合通常是由Label Selector 来决定的。
举个例子,想象一个处理图片的后端运行了三个副本。这些副本都是可以替代的 - 前端不关心它们使用的是哪一个后端。尽管实际组成后端集合的Pod
可能会变化,前端的客户端却不需要知道这个变化,也不需要自己有一个列表来记录这些后端服务。Service
抽象能让你达到这种解耦。
不像 Pod
的 IP 地址,它实际路由到一个固定的目的地,Service
的 IP 实际上不能通过单个主机来进行应答。 相反,我们使用 iptables
(Linux 中的数据包处理逻辑)来定义一个虚拟IP地址(VIP),它可以根据需要透明地进行重定向。 当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。 环境变量和 DNS,实际上会根据 Service
的 VIP 和端口来进行填充。
k8s支持的4种类型的Service:
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
5.2.1 ClusterIP
这种类型的service 只能在集群内访问
先创建一个nginx-deployment:
root@k8s-ansible-client:~/yaml/20210926/02# vim deploy_node.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
#matchLabels: #rs or deployment
# app: ng-deploy3-80
matchExpressions:
- {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx:1.16.1
ports:
- containerPort: 80
#nodeSelector:
# env: group1
root@k8s-ansible-client:~/yaml/20210926/02# kubectl apply -f deploy_node.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/02# kubectl get pods,deploy
NAME READY STATUS RESTARTS AGE
pod/alpine-test 1/1 Running 29 (164m ago) 16d
pod/kube100-site 2/2 Running 0 47h
pod/nginx-deployment-5d76cf6966-2426g 1/1 Running 0 6s
pod/nginx-test-001 1/1 Running 5 (3h20m ago) 3d
pod/nginx-test1 1/1 Running 29 (173m ago) 16d
pod/nginx-test2 1/1 Running 29 (173m ago) 16d
pod/nginx-test3 1/1 Running 29 (173m ago) 16d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 1/1 1 1 6s
创建ClusterIP的Service yaml:
root@k8s-ansible-client:~/yaml/20210926/02# vim svc_service.yaml
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 88
targetPort: 80
protocol: TCP
type: ClusterIP
selector:
app: ng-deploy-80
root@k8s-ansible-client:~/yaml/20210926/02# kubectl apply -f svc_service.yaml
service/ng-deploy-80 created
root@k8s-ansible-client:~/yaml/20210926/02# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 16d
ng-deploy-80 ClusterIP 10.68.185.107 <none> 88/TCP 8s
验证,访问svc的ip:
root@k8s-master-1:~# curl http://10.68.185.107:88
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
5.2.2 NodePort
提供集群外业务访问
创建NodePort 类型service 如下:
root@k8s-ansible-client:~/yaml/20210926/02# vim svc_NodePort.yaml
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 90
targetPort: 80
nodePort: 30012
protocol: TCP
type: NodePort
selector:
app: ng-deploy-80
root@k8s-ansible-client:~/yaml/20210926/02# kubectl apply -f svc_NodePort.yaml
service/ng-deploy-80 created
root@k8s-ansible-client:~/yaml/20210926/02# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 17d <none>
ng-deploy-80 NodePort 10.68.144.210 <none> 90:30012/TCP 7s app=ng-deploy-80
从本地浏览器访问,如截图:
5.2.3 LoadBalancer
LoadBalancer类型的service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的k8s集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过Service的status.loadBalancer字段被发布出去。
5.2.4 ExternalName
类型为 ExternalName 的service将服务映射到 DNS 名称,而不是典型的选择器,例如my-service或者cassandra。 您可以使用spec.externalName参数指定这些服务。
5.3 k8s的存储Volume
5.3.1 简介
我们经常会说:容器和 Pod 是短暂的。
其含义是它们的生命周期可能很短,会被频繁地销毁和创建。容器销毁时,保存在容器内部文件系统中的数据都会被清除。
为了持久化保存容器的数据,可以使用 Kubernetes Volume。
Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。
本质上,Kubernetes Volume 是一个目录,这一点与 Docker Volume 类似。当 Volume 被 mount 到 Pod,Pod 中的所有容器都可以访问这个 Volume。Kubernetes Volume 也支持多种 backend 类型,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等。
Volume 提供了对各种 backend 的抽象,容器在使用 Volume 读写数据的时候不需要关心数据到底是存放在本地节点的文件系统中呢还是云硬盘上。对它来说,所有类型的 Volume 都只是一个目录。
5.3.2 EmptyDir
生命周期和pod一样。emptyDir的初始状态为一个没有任何内容的volume。如果Pod从集群节点上移除,那么emptyDir类型的volume中的内容会被清除。
Container遇到崩溃或重启,这时候Pod本身不会受任何影响,这种情况下emptyDir volume中的数据会保留。Container重启之后数据仍然可见。
emptyDir volume具有的这种特性适合如下场景使用:
- 存放临时文件
- 存放检查点,供container崩溃后恢复用
默认来说emptyDir类型volume的物理存储在硬盘,SSD或网络设备上。可以设置emptyDir.medium为Memory,这时候k8s会使用tempfs(基于内存的文件系统)。此时volume的容量限制收到container的内存配额的制约。
配置如下:
root@k8s-ansible-client:~/yaml/20210926/03# vim deploy_empty.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /cache
name: cache-volume-n56
volumes:
- name: cache-volume-n56
emptyDir: {}
root@k8s-ansible-client:~/yaml/20210926/03# kubectl apply -f deploy_empty.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/03# kubectl get pods,deploy -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/alpine-test 1/1 Running 29 (3h6m ago) 16d 172.20.108.65 192.168.20.236 <none> <none>
pod/kube100-site 2/2 Running 0 2d 172.20.213.6 192.168.20.253 <none> <none>
pod/nginx-deployment-7d4dcd7f7d-fsj6k 1/1 Running 0 6s 172.20.191.14 192.168.20.147 <none> <none>
pod/nginx-test-001 1/1 Running 5 (3h42m ago) 3d1h 172.20.191.10 192.168.20.147 <none> <none>
pod/nginx-test1 1/1 Running 29 (3h15m ago) 16d 172.20.191.2 192.168.20.147 <none> <none>
pod/nginx-test2 1/1 Running 29 (3h15m ago) 16d 172.20.213.3 192.168.20.253 <none> <none>
pod/nginx-test3 1/1 Running 29 (3h15m ago) 16d 172.20.191.3 192.168.20.147 <none> <none>
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx-deployment 1/1 1 1 6s ng-deploy-80 nginx app=ng-deploy-80
验证
root@k8s-ansible-client:~/yaml/20210926/03# kubectl exec -it pod/nginx-deployment-7d4dcd7f7d-fsj6k bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-deployment-7d4dcd7f7d-fsj6k:/# df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 20G 7.2G 12G 39% /
tmpfs tmpfs 64M 0 64M 0% /dev
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 20G 7.2G 12G 39% /cache
shm tmpfs 64M 0 64M 0% /dev/shm
tmpfs tmpfs 3.2G 12K 3.2G 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/acpi
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/scsi
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/firmware
5.3.3 HostPath
此模式挂载pod宿主机文件系统中的文件或目录到pod。
hostPath必须指定一个path参与,用于指定使用宿主机哪个目录。
除此之外还有一个可选的type参数,有如下值可供配置:
- (空,什么都不写):不进行任何检查
- DirectoryOrCreate:如果path对应的目录不存在,自动创建一个目录,权限为0755,所属用户和用户组于kubelet相同。
- Directory:path对应的目录必须存在。
- FileOrCreate:如果path对应的文件不存在,自动创建一个空文件,权限为0644,所属用户和用户组于kubelet相同。
- File:path对应的文件必须存在。
- Socket:path必须对应一个unix socket。
- CharDevice:path必须对应一个character device。
- BlockDevice:path必须对应一个block device。
需要注意的是由于hostPath类型volume的数据和宿主机强绑定,如果pod停止后被schedule到其他节点,pod读取到的数据会有变化。
配置如下:
root@k8s-ansible-client:~/yaml/20210926/03# vim deploy_hostPath.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /data/pop
name: cache-n56-volume
volumes:
- name: cache-n56-volume
hostPath:
path: /opt/pop
root@k8s-ansible-client:~/yaml/20210926/03# kubectl apply -f deploy_hostPath.yaml
deployment.apps/nginx-deployment created
root@k8s-ansible-client:~/yaml/20210926/03# kubectl get pods,deploy -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/alpine-test 1/1 Running 29 (3h14m ago) 16d 172.20.108.65 192.168.20.236 <none> <none>
pod/kube100-site 2/2 Running 0 2d 172.20.213.6 192.168.20.253 <none> <none>
pod/nginx-deployment-79995cfd5d-nxhp4 1/1 Running 0 9s 172.20.191.15 192.168.20.147 <none> <none>
pod/nginx-test-001 1/1 Running 5 (3h50m ago) 3d1h 172.20.191.10 192.168.20.147 <none> <none>
pod/nginx-test1 1/1 Running 29 (3h23m ago) 16d 172.20.191.2 192.168.20.147 <none> <none>
pod/nginx-test2 1/1 Running 29 (3h23m ago) 16d 172.20.213.3 192.168.20.253 <none> <none>
pod/nginx-test3 1/1 Running 29 (3h23m ago) 16d 172.20.191.3 192.168.20.147 <none> <none>
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx-deployment 1/1 1 1 9s ng-deploy-80 nginx app=ng-deploy-80
验证
root@k8s-ansible-client:~/yaml/20210926/03# kubectl exec -it pod/nginx-deployment-79995cfd5d-nxhp4 bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-deployment-79995cfd5d-nxhp4:/# df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 20G 7.2G 12G 39% /
tmpfs tmpfs 64M 0 64M 0% /dev
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 20G 7.2G 12G 39% /data/pop
shm tmpfs 64M 0 64M 0% /dev/shm
tmpfs tmpfs 3.2G 12K 3.2G 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/acpi
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/scsi
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/firmware
5.3.3 Nfs
在k8s-ansible-client上配置一个nfs,如下:
root@k8s-ansible-client:~# apt install nfs-kernel-server -y
root@k8s-ansible-client:~# mkdir -p /data/pop/{d11,js}
root@k8s-ansible-client:~# vim /etc/exports
/data/pop *(rw,sync,no_subtree_check)
root@k8s-ansible-client:~# systemctl restart nfs-kernel-server
root@k8s-ansible-client:~# showmount -e 192.168.20.250
Export list for 192.168.20.250:
/data/pop *
配置:
root@k8s-ansible-client:~/yaml/20210926/04# vim deloy_nfs.yaml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: ng-deploy-80
template:
metadata:
labels:
app: ng-deploy-80
spec:
containers:
- name: ng-deploy-80
image: nginx
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html/mysite
name: my-nfs-volume
- mountPath: /usr/share/nginx/html/js
name: my-nfs-js
volumes:
- name: my-nfs-volume
nfs:
server: 192.168.20.250
path: /data/pop/d11
- name: my-nfs-js
nfs:
server: 192.168.20.250
path: /data/pop/js
---
apiVersion: v1
kind: Service
metadata:
name: ng-deploy-80
spec:
ports:
- name: http
port: 81
targetPort: 80
nodePort: 30016
protocol: TCP
type: NodePort
selector:
app: ng-deploy-80
root@k8s-ansible-client:~/yaml/20210926/04# kubectl apply -f deloy_nfs.yaml
deployment.apps/nginx-deployment created
service/ng-deploy-80 created
root@k8s-ansible-client:~/yaml/20210926/04# kubectl get pods,deploy -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/alpine-test 1/1 Running 29 (3h26m ago) 16d 172.20.108.65 192.168.20.236 <none> <none>
pod/kube100-site 2/2 Running 0 2d 172.20.213.6 192.168.20.253 <none> <none>
pod/nginx-deployment-f868c4766-crtjs 1/1 Running 0 3s 172.20.108.72 192.168.20.236 <none> <none>
pod/nginx-test-001 1/1 Running 5 (4h3m ago) 3d1h 172.20.191.10 192.168.20.147 <none> <none>
pod/nginx-test1 1/1 Running 29 (3h36m ago) 16d 172.20.191.2 192.168.20.147 <none> <none>
pod/nginx-test2 1/1 Running 29 (3h36m ago) 16d 172.20.213.3 192.168.20.253 <none> <none>
pod/nginx-test3 1/1 Running 29 (3h36m ago) 16d 172.20.191.3 192.168.20.147 <none> <none>
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/nginx-deployment 1/1 1 1 3s ng-deploy-80 nginx app=ng-deploy-80
root@k8s-ansible-client:~/yaml/20210926/04# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 17d
ng-deploy-80 NodePort 10.68.201.133 <none> 81:30016/TCP 7s
验证
root@k8s-ansible-client:~/yaml/20210926/04# kubectl exec -it pod/nginx-deployment-f868c4766-crtjs /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-deployment-f868c4766-crtjs:/# df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 20G 7.4G 12G 40% /
tmpfs tmpfs 64M 0 64M 0% /dev
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/ubuntu--vg-ubuntu--lv ext4 20G 7.4G 12G 40% /etc/hosts
shm tmpfs 64M 0 64M 0% /dev/shm
192.168.20.250:/data/pop/js nfs4 20G 13G 6.2G 67% /usr/share/nginx/html/js
tmpfs tmpfs 3.2G 12K 3.2G 1% /run/secrets/kubernetes.io/serviceaccount
192.168.20.250:/data/pop/d11 nfs4 20G 13G 6.2G 67% /usr/share/nginx/html/mysite
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/acpi
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/scsi
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/firmware
# 创建两个文件
root@k8s-ansible-client:/data/pop# cd d11/
root@k8s-ansible-client:/data/pop/d11# ls
root@k8s-ansible-client:/data/pop/d11# echo "test202110112338" > index.html
root@k8s-ansible-client:/data/pop/d11# cd ../js/
root@k8s-ansible-client:/data/pop/js# ls
root@k8s-ansible-client:/data/pop/js# echo "111111111" > test.js
浏览器访问,如截图: