K8s学习
一、 kubernetes 概述
1 、 kubernetes 基本介绍
kubernetes,简称 K8s,是用 8 代替 8 个字符“ubernete”而成的缩写。是一个开源
的,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的
应用简单并且高效(powerful),Kubernetes 提供了应用部署,规划,更新,维护的一种
机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配
置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等
操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于
可移植性。
新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件
系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,
由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进
行迁移。
容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间
成一对一关系也使容器有更大优势,使用容器可以在 build 或 release 的阶段,为应用创
建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,
这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更“透明”,
这更便于监控和管理。
Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、
应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便
对应用请求进行负载均衡。
在 Kubernetes 中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通
过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需
要运维人员去进行复杂的手工配置和处理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-njDV8NL2-1641264633446)(K8s学习.assets/02-第一部分 概述特性和架构组件.png)]
二、探针机制
1. 探针介绍
探针有两种类型:存活探针和就绪探针。
Kubelet使用liveness probe(存活探针)来确定何时重启容器。当应用程序处于运行状态但无法做进一步操作,liveness探针将捕获到deadlock,重启处于该状态下的容器,使应用程序在存在bug的情况下依然能够继续运行下去。
Kubelet使用readiness probe(就绪探针)来确定容器是否已经就绪可以接受流量。只有当Pod中的容器都处于就绪状态时kubelet才会认定该Pod处于就绪状态。该信号的作用是控制哪些Pod应该作为service的后端。如果Pod处于非就绪状态,那么它们将会被从service的load balancer中移除。
2. 定义 liveness命令
Liveness探针有三种检测方式,分别是exec方式、http方式和tcp方式。
1. 定义一个exec的liveness探针案例
apiVersion: v1
kind: Podmetadata:
labels:
test: liveness
name: liveness-execspec:
containers:
\- name: liveness
args:
\- /bin/sh
\- -c
\- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
image: gcr.io/google_containers/busybox
livenessProbe:
exec:
command:
\- cat
\- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
该配置文件给Pod配置了一个容器。periodSeconds 规定kubelet要每隔5秒执行一次liveness probe。 initialDelaySeconds 告诉kubelet在第一次执行probe之前要的等待5秒钟。探针检测命令是在容器中执行 cat /tmp/healthy 命令。如果命令执行成功,将返回0,kubelet就会认为该容器是活着的并且很健康。如果返回非0值,kubelet就会杀掉这个容器并重启它。
容器启动时,执行命令:
/bin/sh -c “touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600”
在容器生命的最初30秒内有一个 /tmp/healthy 文件,在这30秒内 cat /tmp/healthy命令会返回一个成功的返回码。30秒后, cat /tmp/healthy 将返回失败的返回码。
2. 定义一个HTTP的liveness探针案例
apiVersion: v1kind: Podmetadata:
labels:
test: liveness
name: liveness-httpspec:
containers:
\- name: liveness
args:
\- /server
image: gcr.io/google_containers/liveness
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
\- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 3
periodSeconds: 3
该配置文件只定义了一个容器,livenessProbe 指定kubelete需要每隔3秒执行一次liveness probe。initialDelaySeconds 指定kubelet在该执行第一次探测之前需要等待3秒钟。该探针将向容器中的server的8080端口发送一个HTTP GET请求。如果server的/healthz路径的handler返回一个成功的返回码,kubelet就会认定该容器是活着的并且很健康。如果返回失败的返回码,kubelet将杀掉该容器并重启它。
任何大于200小于400的返回码都会认定是成功的返回码。其他返回码都会被认为是失败的返回码。
3. 定义一个TCP的liveness探针案例
第三种liveness probe使用TCP Socket。 使用此配置,kubelet将尝试在指定端口上打开容器的套接字。 如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。
TCP检查的配置与HTTP检查非常相似。 此示例同时使用了readiness和liveness probe。 容器启动后5秒钟,kubelet将发送第一个readiness probe。 这将尝试连接到端口8080上的goproxy容器。如果探测成功,则该pod将被标记为就绪。Kubelet将每隔10秒钟执行一次该检查。
除了readiness probe之外,该配置还包括liveness probe。 容器启动15秒后,kubelet将运行第一个liveness probe。 就像readiness probe一样,这将尝试连接到goproxy容器上的8080端口。如果liveness probe失败,容器将重新启动。
使用命名的端口
可以使用命名的ContainerPort作为HTTP或TCP liveness检查:
ports:
\- name: liveness-port
containerPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
3. 定义readiness探针
应用程序有时暂时无法对外部流量提供服务。 例如,应用程序可能需要在启动期间加载大量数据或配置文件。 在这种情况下,在不杀死应用程序,也不想发送请求的情况下。可以使用readiness probe来检测和减轻这些情况。 Pod中的容器可以报告自己还没有准备,不能处理Kubernetes服务发送过来的流量。
Readiness probe的配置跟liveness probe很像。唯一的不同是使用 readinessProbe而不是livenessProbe,检测方式也是相同,有三种方式。
readinessProbe:
exec:
command:
\- cat
\- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
Readiness probe的HTTP和TCP的探测器配置跟liveness probe一样。
Readiness和livenss probe可以并行用于同一容器。 使用两者可以确保流量无法到达未准备好的容器,并且容器在失败时重新启动。
4. 配置Probe参数
Probe中有很多精确和详细的配置,通过它们你能准确的控制liveness和readiness检查:
· initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒。
· periodSeconds:执行探测的频率。默认是10秒,最小1秒。
· timeoutSeconds:探测超时时间。默认1秒,最小1秒。
· successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。
· failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。
HTTP probe中可以给 httpGet设置其他配置项:
· host:连接的主机名,默认连接到pod的IP。你可能想在http header中设置”Host”而不是使用IP。
· scheme:连接使用的schema,默认HTTP。
· path: 访问的HTTP server的path。
· httpHeaders:自定义请求的header。HTTP运行重复的header。
· port:访问的容器的端口名字或者端口号。端口号必须介于1和65525之间。
对于HTTP探测器,kubelet向指定的路径和端口发送HTTP请求以执行检查。 Kubelet将probe发送到容器的IP地址,除非地址被httpGet中的可选host字段覆盖。
三、K8s容器亲和性
1. Node Affinity
Affinity 翻译成中文是“亲和性”,它对应的是 Anti-Affinity,我们翻译成“互斥”。这两个词比较形象,可以把 pod 选择 node 的过程类比成磁铁的吸引和互斥,不同的是除了简单的正负极之外,pod 和 node 的吸引和互斥是可以灵活配置的。
Affinity的优点:
· 匹配有更多的逻辑组合,不只是字符串的完全相等
· 调度分成软策略(soft)和硬策略(hard),在软策略下,如果没有满足调度条件的节点,pod会忽略这条规则,继续完成调度。
目前主要的node affinity:
(1)requiredDuringSchedulingIgnoredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中IgnoreDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,pod也会继续运行。
(2)requiredDuringSchedulingRequiredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中RequiredDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,则重新选择符合要求的节点。
(3)preferredDuringSchedulingIgnoredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。
(4)preferredDuringSchedulingRequiredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。其中RequiredDuringExecution表示如果后面节点标签发生了变化,满足了条件,则重新调度到满足条件的节点。
这里的匹配逻辑是label在某个列表中,可选的操作符有:
· In: label的值在某个列表中
· NotIn:label的值不在某个列表中
· Exists:某个label存在
· DoesNotExist:某个label不存在
· Gt:label的值大于某个值(字符串比较)
· Lt:label的值小于某个值(字符串比较)
案例:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
\- labelSelector:
matchExpressions:
\- key: "role"
operator: In
values:
\- coordinator
topologyKey: "kubernetes.io/hostname"
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
\- matchExpressions:
\- key: "kubernetes.io/hostname"
operator: In
values:
\- jfimpala017
\- jfimpala019
四、语法案例
apiVersion: v1
kind: Service
matadata: # 元数据
name: string # service的名称
namespace: string # 命名空间
labels: # 自定义标签属性列表
- name: string
annotations: # 自定义注解属性列表
- name: string
spec: # 详细描述
selector: [] # label selector配置,将选择具有label标签的Pod作为管理
type: string # service的类型,指定service的访问方式,默认为
clusterIP: string # 虚拟服务地址
sessionAffinity: string # 是否支持session
ports: # service需要暴露的端口列表
- name: string # 端口名称
protocol: string # 端口协议,支持TCP和UDP,默认TCP
port: int # 服务监听的端口号
targetPort: int # 需要转发到后端Pod的端口号
nodePort: int # 当type = NodePort时,指定映射到物理机的端口号
status: # 当spce.type=LoadBalancer时,设置外部负载均衡器的地址
loadBalancer: # 外部负载均衡器
ingress: # 外部负载均衡器
ip: string # 外部负载均衡器的Ip地址值
hostname: string # 外部负载均衡器的主机名
externalTrafficPolicy: Local # 与主机ip端口绑定在一起,即该主机的该端口只与该命名空间下的选择这个server的pod通信
---
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磁盘
#单个pod的语法,与控制器类型的pod语法相似,可互用
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
五、K8s集群部署
1.卸载k8s组件
在卸载K8s组件前,先执行kubeadm reset命令,清空K8s集群设置
kubeadm reset
卸载管理组件
yum erase -y kubelet kubectl kubeadm kubernetes-cni
删除基础组件镜像。基础组件通过Docker镜像部署,因此只需要强制删除对应镜像即可卸载。
docker rmi -f k8s.gcr.io/kube-apiserver:v1.15.1
docker rmi -f k8s.gcr.io/kube-controller-manager:v1.15.1
docker rmi -f k8s.gcr.io/kube-scheduler:v1.15.1
docker rmi -f k8s.gcr.io/kube-proxy:v1.15.1
docker rmi -f k8s.gcr.io/pause:3.1
docker rmi -f k8s.gcr.io/etcd:3.3.10
docker rmi -f k8s.gcr.io/coredns:1.3.1
2.卸载Docker
杀死docker有关的容器:
docker kill $(docker ps -a -q)
删除所有docker容器:
docker rm $(docker ps -a -q)
删除所有docker镜像:
docker rmi $(docker images -q)
停止 docker 服务:
systemctl stop docker
删除docker相关存储目录:
rm -rf /etc/docker
rm -rf /run/docker
rm -rf /var/lib/dockershim
rm -rf /var/lib/docker
如果删除不掉,则先umount:
umount /var/lib/docker/devicemapper
然后再重新执行上面那步“删除docker相关存储目录”。
经过上面一系列准备后,我们终于到了最后环节,开始删除docker。
查看系统已经安装了哪些docker包:
[root@localhost ~]# yum list installed | grep docker
containerd.io.x86_64 1.2.13-3.2.el7 @docker-ce-stable
docker-ce.x86_64 3:19.03.12-3.el7 @docker-ce-stable
docker-ce-cli.x86_64 1:19.03.12-3.el7 @docker-ce-stable
卸载相关包:
[root@localhost ~]# yum remove containerd.io.x86_64 docker-ce.x86_64 docker-ce-cli.x86_64
接着会出现选择提示,直接输入“y”然后回车就可以。
注意,卸载相关包的时候,是要根据上面查询出来的包名对应上去。我是通过“yum list installed | grep docker”命令搜索出我这边安装了以下包:
containerd.io.x86_64
docker-ce.x86_64
docker-ce-cli.x86_64
所以我删除的时候,是直接一次性删除三个,拼接成以下命令:
yum remove containerd.io.x86_64 docker-ce.x86_64 docker-ce-cli.x86_64
到时大家根据自己的实际情况来删除即可。
执行完上述操作后,我们重新执行以下命令,看是否已经成功删除:
yum list installed | grep docker
不再出现相关信息,证明删除成功,再看看docker命令:
[root@localhost ~]# docker version
-bash: /usr/bin/docker: No such file or directory
因此,成功卸载Docker
3.Kubernetes集群升级(kubeadm升级方式)
参考:(128条消息) Kubernetes集群升级(kubeadm升级方式)_???111的博客-优快云博客
1、升级前的版本确认(相同的大版本号下的小版本升级还是跨版本升级)
例如:从1.12.0升级到1.12.7 或者 从1.12.7升级到1.13.0
2、配置kubernetes安装源(已配置kubernetes源,此处跳过)
Debian/Ubuntu添加源方式:
apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
CentOS/RHEL/Fedora添加源方式:
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
setenforce 0
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet && systemctl start kubelet
注意:如果需要安装特定版本,请参照如下方式
查看版本:
yum --enablerepo=kubernetes list kubelet kubeadm kubectl --showduplicates | sort -r
安装特定版本
yum --enablerepo=kubernetes install kubelet-1.17.0-0 kubeadm-1.17.0-0 kubectl-1.17.0-0
3、验证安装的版本
kubeadm version
4、查看升级后的所需镜像
kubeadm config images list
这里可以提前下载好镜像
kubeadm config images list > images.txt
for i in `cat images.txt`; do docker pull $i; done
5、在主节点上运行如下命令(此命令检查您的群集是否可以升级,并获取可以升级到的版本)
kubeadm upgrade plan
6、选择要升级到的版本,然后运行相应的命令(此处从1.12.7版本升级到1.13.0)
kubeadm upgrade apply v1.13.0
7、将控制节点设置为不可调度
kubectl drain $NODE --ignore-daemonsets
8、重启控制节点的kubelet服务
systemctl daemon-reload
systemctl restart kubelet
9、逐一将除控制节点以外的其他需要升级的节点设置为不可调度
kubectl cordon $NODENAME
kubectl drain $NODENAME
9、在除控制节点的所有节点上逐一执行如下命令升级(注意执行如下命令前,需要先按照步骤2的方法升级程序包)
kubeadm upgrade node config --kubelet-version v1.13.0
10、重新启动升级后节点的kubelet服务
systemctl daemon-reload
systemctl restart kubelet
11、恢复节点为可调度(在控制节点上操作)
kubectl uncordon $NODE
参考:https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-13/
转载于:https://www.cnblogs.com/a120608yby/p/10684296.html
4.、 kubernetes 集群搭建( kubeadm 方式 )
1、 前置知识点
目前生产部署 Kubernetes 集群主要有两种方式:
(1)kubeadm
Kubeadm 是一个 K8s 部署工具,提供 kubeadm init 和 kubeadm join,用于快速部
署 Kubernetes 集群。
官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
(2)二进制包
从 github 下载发行版的二进制包,手动部署每个组件,组成 Kubernetes 集群。
Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可
控,推荐使用二进制包部署 Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很
多工作原理,也利于后期维护。
2 、kubeadm 部署方式介绍
kubeadm 是官方社区推出的一个用于快速部署 kubernetes 集群的工具,这个工具能通
过两条指令完成一个 kubernetes 集群的部署:
第一、创建一个 Master 节点 kubeadm init
第二, 将 Node 节点加入到当前集群中 $ kubeadm join <Master 节点的 IP 和端口 >
3 、安装要求
在开始之前,部署 Kubernetes 集群机器需要满足以下几个条件:
- 一台或多台机器,操作系统 CentOS7.x-86_x64
- 硬件配置:2GB 或更多 RAM,2 个 CPU 或更多 CPU,硬盘 30GB 或更多
- 集群中所有机器之间网络互通
- 可以访问外网,需要拉取镜像
- 禁止 swap 分区
4 、系统初始化
4.1 关闭防火墙:
$ systemctl stop firewalld
$ systemctl disable firewalld
4.2 关闭 selinux:
$ sed -i ‘s/enforcing/disabled/’ /etc/selinux/config # 永久
$ setenforce 0 # 临时
4.3 关闭 swap:
$ swapoff -a # 临时
$ vim /etc/fstab # 永久
4.4 主机名:
$ hostnamectl set-hostname
4.5 在 master 添加 hosts:
$ cat >> /etc/hosts << EOF
192.168.31.61 k8s-master
192.168.31.62 k8s-node1
192.168.31.63 k8s-node2
EOF
4.6 将桥接的 IPv4 流量传递到 iptables 的链:
$ cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sysctl --system # 生效
4.7 时间同步:
$ yum install ntpdate -y
$ ntpdate time.windows.com
5、所有节点安装 Docker/kubeadm/kubelet
Kubernetes 默认 CRI(容器运行时)为 Docker,因此先安装 Docker。
(1)安装 Docker
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
$ yum -y install docker-ce-18.06.1.ce-3.el7
$ systemctl enable docker && systemctl start docker
$ docker --version
(2)添加阿里云 YUM 软件源
设置仓库地址
cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
(3) 新增kubernetes源
[root@master ~]# cat < /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
[] 中括号中的是repository id,唯一,用来标识不同仓库
name 仓库名称,自定义
baseurl 仓库地址
enable 是否启用该仓库,默认为1表示启用
gpgcheck 是否验证从该仓库获得程序包的合法性,1为验证
repo_gpgcheck 是否验证元数据的合法性 元数据就是程序包列表,1为验证
gpgkey=URL 数字签名的公钥文件所在位置,如果gpgcheck值为1,此处就需要指定gpgkey文件的位置,如果gpgcheck值为0就不需要此项了
更新缓存
[root@master ~]# yum clean all
[root@master ~]# yum -y makecache
(4)安装kubelet
查看版本:
yum --enablerepo=kubernetes list kubelet kubeadm kubectl --showduplicates | sort -r
安装特定版本
yum --enablerepo=kubernetes install kubelet-1.17.1-0 kubeadm-1.17.1-0 kubectl-1.17.1-0
systemctl enable kubelet && systemctl start kubelet
6、部署 Kubernetes Master
每次重启服务时需:kubeadm reset
(1)在 192.168.241.139(Master)执行
kubeadm init
–apiserver-advertise-address=192.168.241.129
–image-repository registry.aliyuncs.com/google_containers
–kubernetes-version v1.17.1
–service-cidr=10.1.0.0/16
–pod-network-cidr=10.244.0.0/16
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iTFlYHTn-1641264633449)(K8s学习.assets/image-20211222154108652.png)]
将当前用户配置为集群管理员(如果不配置,下次连接时会无法使用kubectl)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
部署flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
7、Node节点安装
1.安装kubelet、kubeadm和kubectl
同master节点
2.下载镜像
同master节点
3.加入集群
以下操作master上执行
3.1 查看令牌
[root@master ~]# kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
j5eoyz.zu0x6su7wzh752b3 2019-06-04T17:40:41+08:00 authentication,signing The default bootstrap token generated by ‘kubeadm init’. system:bootstrappers:kubeadm:default-node-token
发现之前初始化时的令牌已过期
3.2 生成新的令牌
[root@master ~]# kubeadm token create
1zl3he.fxgz2pvxa3qkwxln
3.3 生成新的加密串
[root@master ~]# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null |
openssl dgst -sha256 -hex | sed ‘s/^.* //’
3.4 node节点加入集群
在node节点上分别执行如下操作:
kubeadm join --token y2sv1g.tcd4a3oqdkvrdqnz --discovery-token-ca-cert-hash sha256:be750378aab8c32a635aff8ada8a0626a17f9371d62fc8252b7620382f5a742e 192.168.241.129:6443
加入完毕后,我们用命令kubectl get nodes获取所有节点
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 115m v1.15.9
k8s-node1 NotReady <none> 111m v1.15.9
k8s-node2 Ready <none> 111m v1.15.9
验证安装信息
检查系统基础模块健康度
[root@k8s-master ~]# kubectl get componentstatus
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true"}
检查node状态,如果有工作节点NotReady,等几分钟一般就会正常
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 115m v1.15.9
k8s-node1 NotReady <none> 111m v1.15.9
k8s-node2 Ready <none> 111m v1.15.9
检查系统pod状态
[root@k8s-master ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-94d74667-l8lqt 1/1 Running 0 115m
coredns-94d74667-svgrk 1/1 Running 0 115m
etcd-k8s-master 1/1 Running 0 115m
kube-apiserver-k8s-master 1/1 Running 0 114m
kube-controller-manager-k8s-master 1/1 Running 0 115m
kube-flannel-ds-amd64-64zsm 1/1 Running 0 2m5s
kube-flannel-ds-amd64-csb8h 1/1 Running 0 2m5s
kube-flannel-ds-amd64-nfcsh 1/1 Running 0 2m5s
kube-proxy-b669n 1/1 Running 0 112m
kube-proxy-d84cb 1/1 Running 0 115m
kube-proxy-w7tv7 1/1 Running 0 111m
kube-scheduler-k8s-master 1/1 Running 0 115m
8、测试 kubernetes 集群
在 Kubernetes 集群中创建一个 pod,验证是否正常运行:
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
访问地址:http://NodeIP:Port
删除app
kubectl delete pods nginx-86c57db685-45wgx
查看详细
kubectl get pods -o wide
192.168.241.129:31236
9、部署 Dashboard
[root@k8s-master ~]# wget https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml
[root@k8s-master ~]# vim kubernetes-dashboard.yaml
修改内容:
109 spec:
110 containers:
111 - name: kubernetes-dashboard
112 image: lizhenliang/kubernetes-dashboard-amd64:v1.10.1 # 修改此行
......
157 spec:
158 type: NodePort # 增加此行
159 ports:
160 - port: 443
161 targetPort: 8443
162 nodePort: 30001 # 增加此行
163 selector:
164 k8s-app: kubernetes-dashboard
[root@k8s-master ~]# kubectl apply -f kubernetes-dashboard.yaml
在火狐浏览器访问(google受信任问题不能访问)地址:192.168.241.139:30001
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ae4y1DnE-1641264633451)(K8s学习.assets/image-20211222210428560.png)]
[root@k8s-master ~]# kubectl create serviceaccount dashboard-admin -n kube-system
serviceaccount/dashboard-admin created
[root@k8s-master ~]# kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin
--serviceaccount=kube-system:dashboard-admin
[root@k8s-master ~]# kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
Name: dashboard-admin-token-d9jh2
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: dashboard-admin
kubernetes.io/service-account.uid: 4aa1906e-17aa-4880-b848-8b3959483323
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1025 bytes
namespace: 11 bytes
token: eyJhbGciOiJ...(省略如下)...AJdQ
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4tZDlqaDIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNGFhMTkwNmUtMTdhYS00ODgwLWI4NDgtOGIzOTU5NDgzMzIzIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.OkF6h7tVQqmNJniCHJhY02G6u6dRg0V8PTiF8xvMuJJUphLyWlWctgmplM4kjKVZo0fZkAthL7WAV5p_AwAuj4LMfo1X5IpxUomp4YZyhqgsBM0A2ksWoKoLDjbizFwOty8TylWlsX1xcJXZjmP9OvNgjjSq5J90N5PnxYIIgwAMP3fawTP7kUXxz5WhJo-ogCijJCFyYBHoqHrgAbk9pusI8DpGTNIZxBMxkwPPwFwzNCOfKhD0c8HjhNeliKsOYLryZObRdmTQXmxsDfxynTKsRxv_EPQb99yW9GXJPQL0OwpYb4b164CFv857ENitvvKEOU6y55P9hFkuQuAJdQ
解决其他浏览器不能访问的问题
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEN6phx5-1641264633454)(K8s学习.assets/copycode.gif)]](javascript:void(0)😉
[root@k8s-master ~]# cd /etc/kubernetes/pki/
[root@k8s-master pki]# mkdir ui
[root@k8s-master pki]# cp apiserver.crt ui/
[root@k8s-master pki]# cp apiserver.key ui/
[root@k8s-master pki]# cd ui/
[root@k8s-master ui]# mv apiserver.crt dashboard.pem
[root@k8s-master ui]# mv apiserver.key dashboard-key.pem
[root@k8s-master ui]# kubectl delete secret kubernetes-dashboard-certs -n kube-system
[root@k8s-master ui]# kubectl create secret generic kubernetes-dashboard-certs --from-file=./ -n kube-system
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DthA40MO-1641264633455)(K8s学习.assets/copycode.gif)]](javascript:void(0)😉
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCvj2U0D-1641264633458)(K8s学习.assets/copycode.gif)]](javascript:void(0)😉
[root@k8s-master]# vim kubernetes-dashboard.yaml #回到这个yaml的路径下修改
修改 dashboard-controller.yaml 文件,在args下面增加证书两行
- --tls-key-file=dashboard-key.pem
- --tls-cert-file=dashboard.pem
[root@k8s-master ~]kubectl apply -f kubernetes-dashboard.yaml
[root@k8s-master ~]# kubectl create serviceaccount dashboard-admin -n kube-system
serviceaccount/dashboard-admin created
[root@k8s-master ~]# kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin
--serviceaccount=kube-system:dashboard-admin
[root@k8s-master ~]# kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
Name: dashboard-admin-token-zbn9f
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: dashboard-admin
kubernetes.io/service-account.uid: 40259d83-3b4f-4acc-a4fb-43018de7fc19
Type: kubernetes.io/service-account-token
Data
====
namespace: 11 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkYXNoYm9hcmQtYWRtaW4tdG9rZW4temJuOWYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGFzaGJvYXJkLWFkbWluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNDAyNTlkODMtM2I0Zi00YWNjLWE0ZmItNDMwMThkZTdmYzE5Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRhc2hib2FyZC1hZG1pbiJ9.E0hGAkeQxd6K-YpPgJmNTv7Sn_P_nzhgCnYXGc9AeXd9k9qAcO97vBeOV-pH518YbjrOAx_D6CKIyP07aCi_3NoPlbbyHtcpRKFl-lWDPdg8wpcIefcpbtS6uCOrpaJdCJjWFcAEHdvcfmiFpdVVT7tUZ2-eHpRTUQ5MDPF-c2IOa9_FC9V3bf6XW6MSCZ_7-fOF4MnfYRa8ucltEIhIhCAeDyxlopSaA5oEbopjaNiVeJUGrKBll8Edatc7-wauUIJXAN-dZRD0xTULPNJ1BsBthGQLyFe8OpL5n_oiHM40tISJYU_uQRlMP83SfkOpbiOpzuDT59BBJB57OQtl3w
ca.crt: 1025 bytes
1.用create命令生成yaml文件
kubectl create deployment nginx --image=nginx -o yaml --dry-run
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
kubectl get deploy nginx -o=yaml --export > m2.yaml
三、k8s服务总结
1、一次性job与定时job
容器按照持续运行的时间可分为两类:服务类容器和工作类容器。
服务类容器通常持续提供服务,需要一直运行,比如 http server,daemon 等。工作类容器则是一次性任务,比如批处理程序,完成后容器就退出。
Kubernetes 的 Deployment、ReplicaSet 和 DaemonSet 都用于管理服务类容器;对于工作类容器,我们用 Job。
一、job的应用
1、编写job的yaml文件myjob.yaml:
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H99bQ8KT-1641264633460)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# cat myjob.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job
spec:
template:
spec:
containers:
- name: job
image: reg.yunwei.com/learn/busybox:latest
command: ["echo","hello kubernetes"]
restartPolicy: Never
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dh2L3rOq-1641264633461)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
① batch/v1 是当前 Job 的 apiVersion。
② 指明当前资源的类型为 Job。
③ restartPolicy 指定什么情况下需要重启容器。对于 Job,只能设置为 Never 或者 OnFailure。对于其他 controller(比如 Deployment)可以设置为 Always 。
2、启动job
[root@ren7 yaml]# kubectl apply -f myjob.yaml
job.batch/job created
3、查看job的状态
[root@ren7 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
job 1/1 3s 84s
4、查看pod的状态
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-m9shb 0/1 Completed 0 2m40s
显示completed已经完成
5、查看pod的标准输出
[root@ren7 yaml]# kubectl logs job-m9shb
hello kubernetes
二、job失败的情况
如果job失败了会怎么样呢?
1、修改myjob.yaml文件,故意引入一个错误:
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbeajtS8-1641264633463)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# cat myjob.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job
spec:
template:
spec:
containers:
- name: job
image: reg.yunwei.com/learn/busybox:latest
command: ["echorrr","hello kubernetes"]
restartPolicy: Never
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nVYsAixg-1641264633464)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
2、删除之前的job
[root@ren7 yaml]# kubectl delete -f myjob.yaml
job.batch "job" deleted
[root@ren7 yaml]# kubectl get pod
No resources found.
3、运行新的job并查看状态
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3k8E89vd-1641264633466)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# kubectl apply -f myjob.yaml
job.batch/job created
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-l9spb 0/1 ContainerCannotRun 0 5s
job-mk5fp 0/1 ContainerCreating 0 1s
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-2phbq 0/1 ContainerCreating 0 2s
job-l9spb 0/1 ContainerCannotRun 0 16s
job-mk5fp 0/1 ContainerCannotRun 0 12s
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MxiDdvD-1641264633467)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
发现没有创建成功,显示0
并且可以看到有多个pod,状态均不正常。
4、使用 kubectldescribe pod 查看某个pod的启动日志
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ApOZEbZq-1641264633469)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# kubectl describe pods job-2phbq
Name: job-2phbq
Namespace: default
Node: 192.168.11.5/192.168.11.5
Start Time: Fri, 25 Oct 2019 19:02:56 +0800
Labels: controller-uid=f7746782-f716-11e9-867d-000c297d011c
job-name=job
Annotations: <none>
Status: Failed
IP: 172.20.72.146
Controlled By: Job/job
Containers:
job:
Container ID: docker://858e1dffa45cad2e43fa096b002a925f15dfc07ad08b406c4c2ad01fe68c2ccd
Image: reg.yunwei.com/learn/busybox:latest
Image ID: docker-pullable://reg.yunwei.com/learn/busybox@sha256:dd97a3fe6d721c5cf03abac0f50e2848dc583f7c4e41bf39102ceb42edfd1808
Port: <none>
Host Port: <none>
Command:
echorrr
hello kubernetes
State: Terminated
Reason: ContainerCannotRun
Message: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"echorrr\": executable file not found in $PATH": unknown
Exit Code: 127
Started: Fri, 25 Oct 2019 19:02:58 +0800
Finished: Fri, 25 Oct 2019 19:02:58 +0800
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-qvqql (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-qvqql:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-qvqql
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 11m default-scheduler Successfully assigned default/job-2phbq to 192.168.11.5
Normal Pulling 11m kubelet, 192.168.11.5 Pulling image "reg.yunwei.com/learn/busybox:latest"
Normal Pulled 11m kubelet, 192.168.11.5 Successfully pulled image "reg.yunwei.com/learn/busybox:latest"
Normal Created 11m kubelet, 192.168.11.5 Created container job
Warning Failed 11m kubelet, 192.168.11.5 Error: failed to start container "job": Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"echorrr\": executable file not found in $PATH": unknown
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AlRF0NzQ-1641264633475)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
日志显示没有可执行程序符合我们的预期。
为什么kubectl get pod 会看到这么多个失败的pod?
原因是:当第一个 Pod 启动时,容器失败退出,根据 restartPolicy: Never,此失败容器不会被重启,但 Job DESIRED 的 Pod 是 1,目前 SUCCESSFUL 为 0,不满足,所以 Job controller 会启动新的 Pod,直到 SUCCESSFUL 为 1。对于我们这个例子,SUCCESSFUL 永远也到不了 1,所以 Job controller 会一直创建新的 Pod。为了终止这个行为,只能删除 Job。
[root@ren7 yaml]# kubectl delete -f myjob.yaml
job.batch "job" deleted
[root@ren7 yaml]# kubectl get pod
No resources found.
如果将 restartPolicy 设置为 OnFailure 会怎么样?下面我们实践一下,修改 myjob.yml 后重新启动。
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kSPXTVUA-1641264633479)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# vim myjob.yaml #依旧是错误命令,且改了restartPolicy: OnFailure
[root@ren7 yaml]# kubectl apply -f myjob.yaml
job.batch/job created
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-9fd6w 0/1 ContainerCreating 0 2s
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-9fd6w 0/1 RunContainerError 0 14s
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-9fd6w 0/1 RunContainerError 1 27s
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-9fd6w 0/1 CrashLoopBackOff 2 36s
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n65yv5pr-1641264633482)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
完成依然为0。
这里只有一个 Pod,不过 RESTARTS 为 2,而且不断增加,说明 OnFailure 生效,容器失败后会自动重启。
三、并行执行job
有时,我们希望能同时运行多个pod,提高job的执行效率。
1、设置parallelism
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-unEM0QkO-1641264633483)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# cat myjob.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job
spec:
parallelism: 2
template:
spec:
containers:
- name: job
image: reg.yunwei.com/learn/busybox:latest
restartPolicy: Never
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9q8W7Gb-1641264633484)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
2、执行该yaml文件
[root@ren7 yaml]# kubectl apply -f myjob.yaml
job.batch/job created
3、查看job
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-anTlasNE-1641264633485)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-5jkpz 0/1 ContainerCreating 0 3s
job-svs94 0/1 ContainerCreating 0 3s
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-5jkpz 0/1 Completed 0 10s
job-svs94 0/1 Completed 0 10s
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O1q7Un65-1641264633492)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
job一共启动了两个pod,而且AGE相同,可见是并行运行的。
4、还可以通过 completions 设置 Job 成功完成 Pod 的总数:
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-89EHnq5J-1641264633494)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# cat myjob.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: job
spec:
parallelism: 2
completions: 6
template:
spec:
containers:
- name: job
image: reg.yunwei.com/learn/busybox:latest
restartPolicy: Never
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XvkB8a6m-1641264633496)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
5、查看相应的pod和job
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9nanK2JQ-1641264633497)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
job-82gll 0/1 Completed 0 18s
job-gsn55 0/1 Completed 0 18s
job-h6gnw 0/1 Completed 0 11s
job-nz5vs 0/1 Completed 0 14s
job-v48cr 0/1 Completed 0 15s
job-vx5gt 0/1 Completed 0 10s
[root@ren7 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
job 6/6 11s 72s
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8tgvzNy-1641264633499)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
如果不指定 completions 和 parallelism,默认值均为 1。
上面的例子只是为了演示 Job 的并行特性,实际用途不大。不过现实中确实存在很多需要并行处理的场景。比如批处理程序,每个副本(Pod)都会从任务池中读取任务并执行,副本越多,执行时间就越短,效率就越高。这种类似的场景都可以用 Job 来实现。
四、定时执行job
Linux 中有 cron 程序定时执行任务,Kubernetes 的 CronJob 提供了类似的功能,可以定时执行 Job。
1、CronJob 配置文件示例如下:
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXbERoyu-1641264633500)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
[root@ren7 yaml]# cat myjob1.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: timing
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: timing
image: reg.yunwei.com/learn/busybox:latest
command: ["echo","hello k8s cronjob!"]
restartPolicy: OnFailure
[[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iYsARwSw-1641264633508)(K8s学习.assets/copycode-16412272730031.gif)]](javascript:void(0)😉
① batch/v1beta1 是当前 CronJob 的 apiVersion。
② 指明当前资源的类型为 CronJob。
③ schedule 指定什么时候运行 Job,其格式与 Linux cron 一致。这里 */1 * * * * 的含义是每一分钟启动一次。
④ jobTemplate 定义 Job 的模板,格式与前面 Job 一致。
2、通过 kubectl apply 创建 CronJob
[root@ren7 yaml]# kubectl apply -f myjob1.yaml
cronjob.batch/timing created
3、查看crontab的状态
[root@ren7 yaml]# kubectl get job
No resources found.
[root@ren7 yaml]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
timing */1 * * * * False 0 <none> 15s
4、等待几分钟再次查看jobs的执行情况
[root@ren7 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
timing-1572005160 1/1 3s 2m29s
timing-1572005220 1/1 3s 89s
timing-1572005280 1/1 3s 29s
可以看到每隔一分钟就会启动一个job。
过段时间查看pod
[root@ren7 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
timing-1572005340-5fds8 0/1 Completed 0 2m40s
timing-1572005400-8qsd4 0/1 Completed 0 99s
timing-1572005460-hnsh7 0/1 Completed 0 39s
5、执行kubectl logs 可查看某个 Job 的pod运行日志:
[root@ren7 yaml]# kubectl logs timing-1572005340-5fds8
hello k8s cronjob!
查看pod会遗留很多已经完成的pod,只需要删除即可。
[root@ren7 yaml]# kubectl delete -f myjob1.yaml
cronjob.batch "timing" deleted
[root@ren7 yaml]# kubectl get pods
No resources found.
2、k8s之Secret
Secret详解
secret用来保存小片敏感数据的k8s资源,例如密码,token,或者秘钥。这类数据当然也可以存放在Pod或者镜像中,但是放在Secret中是为了更方便的控制如何使用数据,并减少暴露的风险。
用户可以创建自己的secret,系统也会有自己的secret。
Pod需要先引用才能使用某个secret
Pod有2种方式来使用secret:
1. 作为volume的一个域被一个或多个容器挂载
2. 在拉取镜像的时候被kubelet引用。
內建的Secrets:
由ServiceAccount创建的API证书附加的秘钥k8s自动生成的用来访问apiserver的Secret,所有Pod会默认使用这个Secret与apiserver通信
创建自己的Secret:
方式1:使用kubectl create secret命令
方式2:yaml文件创建Secret
命令方式创建secret:
假如某个Pod要访问数据库,需要用户名密码,分别存放在2个文件中:username.txt,password.txt
例子:
[root@kub-k8s-master ~]# echo -n 'admin' > ./username.txt
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' > ./password.txt
kubectl create secret指令将用户名密码写到secret中,并在apiserver创建Secret
[root@kub-k8s-master ~]# kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
secret/db-user-pass created
查看创建结果:
[root@kub-k8s-master ~]# kubectl get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 2 54s
default-token-6svwp kubernetes.io/service-account-token 3 4d11h
注: opaque:英[əʊˈpeɪk] 美[oʊˈpeɪk] 模糊
查看详细信息:
[root@kub-k8s-master ~]# kubectl describe secrets/db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 12 bytes
username.txt: 5 bytes
get或describe指令都不会展示secret的实际内容,这是出于对数据的保护的考虑,如果想查看实际内容使用命令:
[root@kub-k8s-master ~]# kubectl get secret db-user-pass -o json
base64解码:
[root@kub-k8s-master ~]# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
1f2d1e2e67df
yaml方式创建Secret:
创建一个secret.yaml文件,内容用base64编码:明文显示容易被别人发现,这里先转码。
[root@kub-k8s-master ~]# echo -n 'admin' | base64
YWRtaW4=
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
创建一个secret.yaml文件,内容用base64编码
[root@kub-k8s-master prome]# vim secret.yml
---
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque #模糊
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
创建:
[root@kub-k8s-master prome]# kubectl apply -f secret.yml
secret/mysecret created
解析Secret中内容,还是经过编码的—需要解码
[root@kub-k8s-master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-7vc82 kubernetes.io/service-account-token 3 30h
mysecret Opaque 2 6s
[root@kub-k8s-master prome]# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2019-10-21T03:07:56Z"
name: mysecret
namespace: default
resourceVersion: "162855"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 36bcd07d-92eb-4755-ac0a-a5843ed986dd
type: Opaque
使用Secret
一个Pod中引用Secret的列子:
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: testredis
image: daocloud.io/library/redis
volumeMounts: #挂载一个卷
- name: foo #这个名字需要与定义的卷的名字一致
mountPath: "/etc/foo" #挂载到容器里哪个目录下,随便写
readOnly: true
volumes: #数据卷的定义
- name: foo #卷的名字这个名字自定义
secret: #卷是直接使用的secret。
secretName: mysecret #调用刚才定义的secret
创建:
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml
pod/mypod created
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/
root@mypod:/etc/foo# ls
password username
root@mypod:/etc/foo# cat password
1f2d1e2e67df
每一个被引用的Secret都要在spec.volumes中定义
如果Pod中的多个容器都要引用这个Secret那么每一个容器定义中都要指定自己的volumeMounts,但是Pod定义中声明一次spec.volumes就好了。
映射secret key到指定的路径
[root@kub-k8s-master prome]# kubectl delete -f pod_use_secret.yaml
pod "mypod" deleted
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: testredis
image: daocloud.io/library/redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
items: #定义一个items
- key: username #将那个key重新定义到那个目录下
path: my-group/my-username #相对路径,相对于/etc/foo的路径
2.创建
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml
pod/mypod created
3.从volume中读取secret的值
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/my-group
root@mypod:/etc/foo/my-group# ls
my-username
root@mypod:/etc/foo/my-group# cat my-username
admin
root@mypod:/etc/foo/my-group#
username被映射到了文件/etc/foo/my-group/my-username而不是/etc/foo/username
被挂载的secret内容自动更新
也就是如果修改一个Secret的内容,那么挂载了该Secret的容器中也将会取到更新后的值,但是这个时间间隔是由kubelet的同步时间决定的。
1.设置base64加密
[root@kub-k8s-master prome]# echo qianfeng | base64
cWlhbmZlbmcK
2.将admin替换成qianfeng
[root@kub-k8s-master prome]# vim secret.yml
---
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: cWlhbmZlbmcK #修改为qianfeng的base64加密后的
password: MWYyZDFlMmU2N2Rm
1.创建
[root@kub-k8s-master prome]# kubectl apply -f secret.yml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
secret/mysecret configured
2.连接pod容器
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# cd /etc/foo/my-group
root@mypod:/etc/foo/my-group# ls
my-username
root@mypod:/etc/foo/my-group# cat my-username
qianfeng
以环境变量的形式使用Secret
[root@kub-k8s-master prome]# kubectl delete -f pod_use_secret.yaml
pod "mypod" deleted
[root@kub-k8s-master prome]# vim pod_use_secret.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: testredis
image: daocloud.io/library/redis
env: #定义环境变量
- name: SECRET_USERNAME #创建新的环境变量名称
valueFrom:
secretKeyRef: #调用的key是什么
name: mysecret #变量的值来自于mysecret
key: username #username里面的值
2.创建使用secret的pod容器
[root@kub-k8s-master prome]# kubectl apply -f pod_use_secret.yaml
pod/mypod created
3.连接
[root@kub-k8s-master prome]# kubectl exec -it mypod /bin/bash
root@mypod:/data# echo $SECRET_USERNAME #打印一下定义的变量
qianfeng
实验
方法1. 使用 kubectl create secret 指令创建Secret对象
[root@kub-k8s-master ~]# vim user.txt
admin
[root@kub-k8s-master ~]# vim passwd.txt
c1oudc0w!
创建secret
[root@kub-k8s-master ~]# kubectl create secret generic user --from-file=user.txt
secret/user created
[root@kub-k8s-master ~]# kubectl create secret generic pass --from-file=passwd.txt
secret/pass created
user.txt 和 passwd.txt 文件里,存放的就是用户名和密码;而 user 和 pass,则是为 Secret 对象指定的名字。
查看Secret 对象:
[root@kub-k8s-master ~]# kubectl get secrets
NAME TYPE DATA AGE
pass Opaque 1 56s
user Opaque 1 71s
方法2. 通过编写 YAML 文件的方式来创建这个 Secret 对象
Secret 对象要求这些数据必须是经过 Base64 转码的,以免出现明文密码的安全隐患。
转码操作:
[root@kub-k8s-master ~]# echo -n 'admin' | base64
YWRtaW4=
[root@kub-k8s-master ~]# echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm
注意:像这样创建的 Secret 对象,它里面的内容仅仅是经过了转码,并没有被加密。生产环境中,需要在 Kubernetes 中开启 Secret 的加密插件,增强数据的安全性。
[root@kub-k8s-master prome]# vim create_secret.yml
---
apiVersion: v1
kind: Secret
metadata:
name: mysecret-01
type: Opaque
data:
user: YWRtaW4=
pass: MWYyZDFlMmU2N2Rm
[root@kub-k8s-master prome]# kubectl apply -f create_secret.yml
secret/mysecret-01 created
[root@kub-k8s-master prome~]# kubectl get secret
用yaml方式创建的secret调用方法如下:
[root@kub-k8s-master prome]# vim test-projected-volume.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-secret-volume
image: daocloud.io/library/nginx
volumeMounts:
- name: mysql-cred
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: mysql-cred
secret:
secretName: mysecret-01
创建这个 Pod:
[root@kub-k8s-master prome]# kubectl apply -f test-projected-volume.yaml
pod/test-projected-volume1 created
验证这些 Secret 对象是不是已经在容器里了:
[root@kub-k8s-master prome]# kubectl exec -it test-projected-volume /bin/bash
root@test-projected-volume:/# ls
bin dev home lib64 mnt proc root sbin sys usr
boot etc lib media opt projected-volume run srv tmp var
root@test-projected-volume:/# ls projected-volume/
pass user
root@test-projected-volume:/# cat projected-volume/pass
1f2d1e2e67df
root@test-projected-volume:/# cat projected-volume/user
admin
root@test-projected-volume:/#
注意:
如果报错:上面这条命令会报错如下
# kubectl exec -it test-projected-volume /bin/sh
error: unable to upgrade connection: Forbidden (user=system:anonymous, verb=create, resource=nodes, subresource=proxy)
解决:绑定一个cluster-admin的权限
# kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/system:anonymous created
结果中看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。
而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。
总结问题:
1、ngnix启动一直处于创建中
1、查看报错日志
kubectl describe pod nginx-86c57db685-gfxzp
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MRpx8iHn-1641264633511)(K8s学习.assets/image-20211227013132293.png)]
2、去对应节点查看日志
journalctl -u kubelet -n 1000
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cFxn8ijD-1641264633514)(K8s学习.assets/image-20211227013213737.png)]
3、补救措施
[Kubernetes]node节点pod无法启动/节点删除网络重置
node1之前反复添加过,添加之前需要清除下网络
root@master1:/var/lib/kubelet# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-8586cf59-6zw9k 1/1 Running 0 9m 10.244.3.3 node2
nginx-8586cf59-jk5pc 0/1 ContainerCreating 0 9m node1
nginx-8586cf59-vm9h4 0/1 ContainerCreating 0 9m node1
nginx-8586cf59-zjb84 1/1 Running 0 9m 10.244.3.2 node2
root@node1:~# journalctl -u kubelet
failed: rpc error: code = Unknown desc = NetworkPlugin cni failed to set up pod “nginx-8586cf59-rm4sh_default” network: failed to set bridge addr: “cni0” already has an IP address different from 10.244.2.1/24
12252 cni.go:227] Error while adding to cni network: failed to set bridge addr: “cni0” already
排查节点日志:journalctl -u kubelet
重置kubernetes服务,重置网络。删除网络配置,link
kubeadm reset
systemctl stop kubelet
systemctl stop docker
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf /etc/cni/
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig docker0 down
ip link delete cni0
ip link delete flannel.1
systemctl start docker
获取master的join token
kubeadm token create --print-join-command
加入节点
kubeadm join --token 55c2c6.2a4bde1bc73a6562 192.168.1.144:6443 --discovery-token-ca-cert-hash sha256:0fdf8cfc6fecc18fded386
限
kubectl create clusterrolebinding system:anonymous --clusterrole=cluster-admin --user=system:anonymous
clusterrolebinding.rbac.authorization.k8s.io/system:anonymous created
结果中看到,保存在 Etcd 里的用户名和密码信息,已经以文件的形式出现在了容器的 Volume 目录里。
而这个文件的名字,就是 kubectl create secret 指定的 Key,或者说是 Secret 对象的 data 字段指定的 Key。
# 总结问题:
## 1、ngnix启动一直处于创建中
1、查看报错日志
kubectl describe pod nginx-86c57db685-gfxzp
[外链图片转存中...(img-MRpx8iHn-1641264633511)]
2、去对应节点查看日志
journalctl -u kubelet -n 1000
[外链图片转存中...(img-cFxn8ijD-1641264633514)]
3、补救措施
[Kubernetes]node节点pod无法启动/节点删除网络重置
node1之前反复添加过,添加之前需要清除下网络
root@master1:/var/lib/kubelet# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-8586cf59-6zw9k 1/1 Running 0 9m 10.244.3.3 node2
nginx-8586cf59-jk5pc 0/1 ContainerCreating 0 9m <none> node1
nginx-8586cf59-vm9h4 0/1 ContainerCreating 0 9m <none> node1
nginx-8586cf59-zjb84 1/1 Running 0 9m 10.244.3.2 node2
root@node1:~# journalctl -u kubelet
failed: rpc error: code = Unknown desc = NetworkPlugin cni failed to set up pod "nginx-8586cf59-rm4sh_default" network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.2.1/24
12252 cni.go:227] Error while adding to cni network: failed to set bridge addr: "cni0" already
排查节点日志:journalctl -u kubelet
重置kubernetes服务,重置网络。删除网络配置,link
kubeadm reset
systemctl stop kubelet
systemctl stop docker
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf /etc/cni/
ifconfig cni0 down
ifconfig flannel.1 down
ifconfig docker0 down
ip link delete cni0
ip link delete flannel.1
systemctl start docker
获取master的join token
kubeadm token create --print-join-command
加入节点
kubeadm join --token 55c2c6.2a4bde1bc73a6562 192.168.1.144:6443 --discovery-token-ca-cert-hash sha256:0fdf8cfc6fecc18fded386