首页系统综合问题Kubernates证书过期问题的解决

Kubernates证书过期问题的解决

时间2023-05-13 05:42:20发布分享专员分类系统综合问题浏览145

今天小编给各位分享expired的知识,文中也会对其通过Kubernates证书过期问题的解决和Kubernetes——安全认证等多篇文章进行知识讲解,如果文章内容对您有帮助,别忘了关注本站,现在进入正文!

内容导航:

  • Kubernates证书过期问题的解决
  • Kubernetes——安全认证
  • 深入理解Kubernetes的认证与授权机制
  • kubernetes常见故障
  • 一、Kubernates证书过期问题的解决

    使用kubeadm安装的kubernates(版本号为:1.9.0),使用了一年以后出现问题。问题状态为不管使用kubectl 的什么指令,都报出以下的异常

    Unable to connect to the server: x509: certificate has expired or is not yet valid

    原因为apiserver证书时间到期,需要重新生成证书,使用kubeadm部署集群的时候,1.13.x版本可以直接renew,但是1.9.0没有需要重新生成证书。

    使用kubeadm部署集群的时候,CA的有效期为10年,可以使用原CA进行签发证书,即ca.crt、front-proxy-ca.crt。

    一、备份原证书和配置文件
    cd /etc/kubernetesmv admin.conf admin.conf.bakmv controller-manager.conf controller-manager.conf.bakmv kubelet.conf kubelet.conf.bakmv scheduler.conf scheduler.conf.bakcd pkimv apiserver.crt apiserver.crt.bakmv apiserver.key apiserver.key.bakmv apiserver-kubelet-client.crt apiserver-kubelet-client.crt.bakmv apiserver-kubelet-client.key apiserver-kubelet-client.key.bakmv front-proxy-client.crt front-proxy-client.crt.bakmv front-proxy-client.key front-proxy-client.key.bak
    二、生成新证书
    kubeadm alpha phase certs apiserver --apiserver-advertise-address 192.168.13.80(我这里是HA的地址)kubeadm alpha phase certs apiserver-kubelet-clientkubeadm alpha phase certs front-proxy-client
    三、生成新的配置文件
    kubeadm alpha phase kubeconfig all --apiserver-advertise-address 192.168.13.80(我这里是HA的地址)
    四、替换老的admin.conf配置文件

    cp /etc/kubernetes/admin.conf /root/.kube/config

    五、重启服务

    需要重启kube-apiserver,kube-controller-manager, kube-scheduler

    docker ps | grep xxxx

    docker kill -s HUP {容器ID}

    kill掉容器后,会自动重构

    查看证书有效时间

    openssl x509 -in front-proxy-client.crt -noout -text |grep Not Not Before: Apr 12 01:35:40 2018 GMT Not After : Apr 11 10:26:06 2020 GMT

    完成以上步骤,证书就更新完成了。

    PS:在生成证书的时候需要访问谷歌dl.k8s.io,需要进行代理。

    一、Kubernetes——安全认证

    Kubernetes作为一个分布式集群的管理工具,保证集群的安全性是其中一个重要的任务,API Server是集群内部各个组件通信的中介,也是外部控制的入口。所以Kubernetes的安全机制基本就是围绕保护API Server来设计的。Kubernetes使用了认证(Authentication)、鉴权(Authorization)、准入控制(Admission Control)三步来保证API Server的安全。

    kubeconfig文件包含集群参数(CA证书、API Server地址),客户端参数(上面生成的证书和私钥)、集群Context信息(集群名称、用户名)。Kubernetes组件通过启动时指定不同的kubeconfig文件可以切换到不同的集群。

    Pod中的容器访问API Server,因为Pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了,Kubernetes使用了Service Account解决Pod访问API Server的认证问题。

    Kubernetes设计了一种资源叫做Secret,分为两类,一种是用于ServiceAccount的service-account-token,另一种是用于保存用户自定义保密信息的Oqaque,ServiceAccount中用到包含三个部分:Token、ca.crt、namespace

    上面的认证过程,只是确认通信的双方都确认对方是可信的,进而可以互相通信。
    鉴权是确定请求方有哪些资源权限,API Server 内部通过用户认证后,然后进入授权流程。对合法用户进行授权并且随后在用户访问时进行鉴权,是权限管理的重要环节。API Server目前支持以下几种授权策略(通过API Server的启动参数 --authorization-mode 设置)

    RBAC(Role-Based Access Control,基于角色的访问控制)在Kubernetes v1.5引入,在v1.6版本时升级为Beta版本,并成为kubeadm安装方式下的默认选项,组建其重要程度。相对于其他的访问控制方式,RBAC具有如下优势。

    要使用RBAC授权模式,则需要在API Server的启动参数中加上 --authorization-mode=RBAC 。

    角色绑定

    主体(subject)

    BAC引入了4个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding。同其他API资源对象一样,用户可以使用kubectl或者API调用方式操作这些资源对象。

    需要注意的是Kubernetes并不会提供用户管理,那么User、Group、ServiceAccount指定的用户又是从哪里来的呢?Kubernetes组件(kubectl、kube-proxy)或是其他自定义的用户在向CA申请证书时,需要提供一个证书请求文件。

    在RBAC API中Role表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过RBAC对其进行减少的操作;Role可以定义在一个namespace中,如果想要跨namespace则可以创建ClusterRole

    rules中的参数说明:

    ClusterRole
    ClusterRole处理具有和Role一致的命名空间内资源的管理能力,因其集群级别的范围,还可以用于以下特殊元素的授权。

    下面的ClusterRole可以让用户有权访问任意一个或所有命名空间的secrets(视其绑定方式而定):

    RoleBinding可以将角色中定义的权限授予用户或用户组,RoleBinding包含一组权限列表(subjects),权限列表中包含有不同形式的待授予权限资源类型(users、groups、Service Account);RoleBinding同样包含对被Bind的Role引用,RoleBinding适用于某个命名空间内授权,ClusterRoleBinding适用于集群范围内授权。

    下面例子中的RoleBinding将在default命名空间中把pod-reader角色授予用户jane,这一操作让jane可以读取default命名空间中的Pod:

    RoleBinding也可以引用ClusterRole,来对当前namespace内用户、用户组或ServiceAccount进行授权,这种操作允许集群管理员在整个集群内定义一些通用ClusterRole,然后在不同的namespace中使用RoleBinding来引用
    例如,以下RoleBinding引用一个ClusterRole,这个ClusterRole具有整个集群内对secrets的访问权限,但是其授权用户dave只能访问development空间中的secrets(因为RoleBinding定义在development命名空间)

    集群角色绑定中的角色只能是集群角色,用于进行集群级别或者对所有命名空间都生效的授权。下面的例子允许manager组的用户读取任意namespace中的secret:

    示例1:普通角色的资源列表:

    解释:如上限定在default的命名空间的名为pod-and-pod-logs-reader的普通角色,对pod和pods/log资资源就有get和list的权限。

    示例2:更精细粒度的资源控制,可通过resourceNamess指定特定的资源实例,以限制角色只能够对具体的某个实例进行访问控制。

    解释:如上限定在default的命名空间的名为configmap-updater的普通角色,对名为my-configmap的configmaps类型的特定资源,具有update和get权限。

    示例1:类型为user(用户)。

    示例2:类型为group(组)。

    示例3:查看default的服务账户。

    Kubernetes系统通过三个独⽴的组件间的相互协作来实现服务账户的⾃动化,三个组件具体为:Admission Controllers准⼊控制器、令牌控制器(token controller)和Service Account账户控制器。Service Account控制器负责为名称空间管理相应的资源,并确保每个名称空间中都存在⼀个名为“default”的Service Account对象。

    当请求通过了前面的认证和授权之后,还需要经过准入控制处理通过之后,apiserver 才会处理这个请求。Admission Control 有一个准入控制列表,我们可以通过命令行设置选择执行哪几个准入控制器。只有所有的准入控制器都检查通过之后,apiserver 才执行该请求,否则返回拒绝。

    在kubernetes中,一些高级特性正常运行的前提条件为,将一些准入模块处于enable状态。总结下,对于kubernetes apiserver,如果不适当的配置准入控制模块,他就不能称作是一个完整的server,某些功能也不会正常的生效。

    允许所有请求

    拒绝所有请求

    强制设置Pod拉取镜像策略为Always。这样能够保证私有镜像只能被有拉取权限的使用者使用。

    它会拦截所有想在privileged container上执行命令的请求。(如果自己的集群支持privileged container,自己又希望限制用户在这些privileged container上执行命令,那么强烈推荐使用它。)

    这个插件禁止那些通过主机执行而获得privileges去执行exec和attach Pod的命令。

    通过webhook决定image策略,需要同时配置–admission-control-config-file

    一个serviceAccount为运行在pod内的进程添加了相应的认证信息。当准入模块中开启了此插件(默认开启),如果pod没有serviceAccount属性,将这个pod的serviceAccount属性设为“default”;确保pod使用的serviceAccount始终存在;如果LimitSecretReferences 设置为true,当这个pod引用了Secret对象却没引用ServiceAccount对象,弃置这个pod;如果这个pod没有包含任何ImagePullSecrets,则serviceAccount的ImagePullSecrets被添加给这个pod;如果MountServiceAccountToken为true,则将pod中的container添加一个VolumeMount 。

    它会观察所有的请求,确保在namespace中ResourceQuota对象处列举的container没有任何异常。如果在kubernetes中使用了ResourceQuota对象,就必须使用这个插件来约束container。(推荐在admission control参数列表中,这个插件排最后一个。)

    实现配额控制。他会观察所有的请求,确保没有违反已经定义好的约束条件,这些条件定义在namespace中LimitRange对象中。如果在kubernetes中使用LimitRange对象,则必须使用这个插件。

    禁止创建设置了 Security Context 的 pod。这个插件将会将使用了 SecurityContext的pod中定义的选项全部失效。关于 SecurityContext的描述:SecurityContext 在container中定义了操作系统级别的安全设定(uid, gid, capabilities, SELinux等等)。

    确保处于termination状态的namespace不再接收新的对象创建请求,并拒绝请求不存在的namespace。

    根据镜像的历史使用记录,为容器设置默认资源请求和限制

    为PVC设置默认StorageClass

    设置Pod的默认forgiveness toleration为5分钟

    使用Pod Security Policies时必须开启

    限制kubelet仅可访问node、endpoint、pod、service以及secret、configmap、PV和PVC等相关的资源(v1.7版本以上才支持)

    参考:

    二、深入理解Kubernetes的认证与授权机制

    众所周知,任意一个系统的安全机制的核心都是基于 认证与授权 (Authentication and Authorization),即首先通过某种方式确认“你”的身份,再根据一定的授权策略确定“你”在我的系统里面能做什么操作。对于K8S来说,就是体现为客户端对于 kube-apiserver 的api接口操作的鉴权(客户端可以是集群内的工作负载pod,任意服务器上的kubectl程序,或是计算节点上的kubelet组件等等)。Kubernets项目作为一个成熟的开源云计算基础设施项目,让我们来看看他们是如何解决认证与授权这两个核心问题的:

    k8s的用户认证机制的官方文档地址: 。

    Kubernetes中的用户类型分为 service accounts 和 normal users 两类。service accounts是k8s内部自建的一套用户认证体系,主要用于pod里直接调用kube-apiserver过程中的认证。而普通用户类型依赖于外部认证服务,k8本身不关心。

    当创建service account对象时,会对应的创建一个secret对象,内含了这个用户的认证token,当pod启动时,只要yaml里申明了绑定特定的service account账号,那么系统会自动把secret的token注入到pod中的指定目录,接下来当pod调用apiserver接口时,系统都会自动的附加上这个token,这样apiserver就可以识别出这个pod的身份,结合role和rolebinding的配置信息,就可以正确的授权了。service account是基于k8内部的认证体系,使用起来比较方便,直接在集群内创建sa资源即可。此种类型的用户不是本篇文章讨论的重点,想了解具体的操作可以参考我之前的这篇文章: 构建云原生微服务网关系列-篇二:Zuul ,里面有详细的service account的使用说明。

    本文讨论的重点,针对普通用户类型,很多人的理解会比较模糊,对此官网有一段说明:

    也就是说,k8项目认为普通用户认证应该由外部服务供应商解决,k8本身不关心认证过程,只要告诉他最终的认证结果,即这个用户是“谁”。认证方式可以用公私钥对,或者openstack 的 keystone认证服务、google的Google Accounts服务,甚至是一个有着用户名和密码列表的文件,对于k8s来说,都是一样的。不管用何种方式去认证,最终结果都是告诉k8s,这个用户是“谁”,也就是它的用户id。这里需要注意的时,对于普通用户类型,k8是不会存储用户信息的,而对于service account类型的用户,k8会保存在etcd里面。普通用户也无法通过api调用直接创建。

    Kubernetes 支持使用客户端证书、bearer token、认证代理或者http basic auth等方式进行认证,而无论使用哪种方式,认证插件都需要将以下的用户信息和http请求进行关联:

    api-server目前支持的认证方式有:

    使用由 k8s 根 CA 签发的证书,提取cn字段作为用户id,O字段作为用户组。我们可以使用openssl工具来进行证书的签发(kubernetes 1.4之后支持了证书中携带用户组信息):

    上述操作会生成一个证书请求,username为 jbeda ,并同时属于两个用户组 app1 和 app2 。

    静态token列表文件,需要预先在 API Server 服务器上放置该文件,并且在api server的启动参数中加上 --token-auth-file=SOMEFILE ,token文件为csv格式,应至少包含token, user name, user uid这三个字段(逗号分隔)以及一个可选的group names字段,例如:

    注意如果用户组有多个的话,整个用户组需要用双引号括起来。

    1.18版本进入稳定版的新特性,支持可以在集群启动时动态的创建和管理token,配置比较多,这里不多赘述,有兴趣直接参考官方文档

    跟静态 Token 文件类似,只是使用了用户名密码的形式进行认证,使用的是http basic auth类型的认证方式,启动参数为 --basic-auth-file=SOMEFILE ,文件格式为:

    很好理解,不多说了

    之前介绍过了,k8s内部用户体系 Service Account 使用的 Token,认证方式也是bearer token。这里需要注意的是官方文档有一个描述:

    因为api-server本身并不关注流量是从哪里过来的,所以基于service account创建的token,只要你拿到了这个token,是可以从 集群外部 发起请求的,api-server会将此请求认证为对应的service account用户。拿到token的方式官网也做了说明:

    注意和serviceaccount绑定的secret类型为 kubernetes.io/service-account-token ,其中token字段即为我们需要的令牌(jwt格式),拿着这个令牌就可以直接发起请求了。 注意在secret中保存的token是经过base64编码的,实际使用时还需要先进行base64解码操作,可以使用jwt.io网站来查看这个令牌,以下是k8s签发的一个jwt令牌payload部分字段的示例:

    新出来的一种认证方式,基于Oauth2,比较复杂,有兴趣可以参考官方文档,这里不介绍了。对于Oauth2认证以及JWT技术比较感兴趣的,可以参考我之前的博文 深入理解Spring Cloud Security OAuth2及JWT 。(阅读量4万多了,也算爆款了:)

    搞定了认证,接下来就是授权了。得益于k8s优良的设计,认证和授权是解耦的,所以只要k8系统识别出了用户身份(username或者uid),接下来要做的事情就是一样的了。关于授权部分的官方文档地址:

    事实上k8s本身也支持多种授权类型,比如rbac,abac,node,dynamic admission 等等。这里只介绍下最常用的rbac(基于角色的访问控制),实际使用中,api-server开启 --authorization-mode=RBAC 参数,即启动了rbac功能。

    如果你对于rbac本身已经比较了解,那么其实k8s里面的rbac功能就非常容易理解了。涉及rbac的有两个api对象,role定义了一个角色,申明了此角色可以操作的功能列表,rolebinding其实就是把用户和角色做了一个绑定。

    role的api对象示例:

    这个yaml定义了一个Role对象,名称为 pod-reader , 作用域为 default 这个namespace,可以对 pods 这个对象进行 get 、 watch 、 list 操作。
    kubernetes完整的操作类型列表如下,都很好理解,不一一说明了:

    值得注意的是,有些资源还有子类型,比如pod的logs,如果需要查看,也是需要授权的(添加 pods/log 资源类型)

    RoleBinding资源的作用也非常容易理解, 就是绑定Role和用户。下面是一个RoleBinding的示例:

    这个例子里把一个类型为User,name叫做jane的用户,和pod-reader的Role做了绑定。注意subjects里面的 kind 字段,即用户类型,前面介绍过了,分别是 User 、 Group 和 ServiceAccount 。绑定完成之后,当使用 jane 这个用户身份对k8s的api进行调用,就可以进行指定的 watch 、 get 、 list 操作了。

    这两资源其实和Role、RoleBinding的配置方式是完全一样的,区别在于ClusterRole和ClusterRoleBinding的作用域是集群范围的,并且可以操作 node 这样的集群范围资源,而Role、RoleBinding在metadata中需要指定namespace字段,其他方面没有区别。

    弄清原理之后,现在让我们来实际操作一下,目标是使用kubectl客户端工具对于给定的k8集群进行受限操作。基于上述的认证策略的介绍,我们使用 客户端证书 方式来进行用户认证,即使用K8集群的根证书来签发一个用户证书,使用该证书来进行用户认证及授权操作。

    关于RSA证书的制作,可以参考官网文档: ,这里我们使用常用的openssl工具来制作证书:

    1、创建一个2048位长度的RSA格式私钥

    2、创建证书签名请求(csr),CN-对应Username O-对应用户组,上面的文章中已经介绍过

    3、使用集群根证书签发这个证书请求(days是证书到期时间,可根据实际需要配置)

    首先先找到一台准备作为客户端访问k8集群的linux服务器(或者windows、mac都可以),确保客户端与集群的api-server端口网络联通(一般为6443端口,注意必须是https连接),出于安全考虑,最好开一个操作k8的专用的操作系统账号。把集群master节点中的kubectl二进制文件拷贝至此服务器/usr/bin目录内,同时拷贝release.csr、release.key、ca.pem这三个文件至服务器上的指定目录。

    在新建用户的home目录下创建.kube目录,在此目录下新建config文件(或者直接执行kubectl config set-cluster test操作,kubectl会自动创建该文件),编辑该文件填写如下内容:

    完成之后可以执行 kubectl config view 来验证一下配置是否正确。

    使用管理员登陆k8集群,进行权限配置,这里以添加集群范围的运维用户权限为例:

    可以看到,我们定义了一个角色 release ,用于应用的部署及日常运维操作。为了满足日常运维,给其分配了一组受限的资源权限。

    具体来说,该角色对"deployments","services","configmap","pvc"资源有全部的操作权限,对于"nodes","events","pods","pods/log","endpoints"只有查看权限,对于其他资源没有任何权限。

    这里我们定义了一个ClusterRoleBinding,把User和ClusterRole进行了绑定,到这里全部操作就完成了。

    登陆客户端,一切顺利的话,执行 kubectl get pods 就可以返回远程集群的default命名空间下的pods列表了,其他配置的权限应该也可以正常操作。而如果这个用户想访问受限资源,比如想查看secrets信息,则会出现如下的报错信息(403 Forbidden):

    验证成功!

    基于上述的描述,可以知道,其实在集群里面创建一个service account,把它的token拷贝出来,配置在客户端的kubectl配置文件中,可以达到同样的效果,这里就不再演示了。

    因为service account的token机密信息实际上都是存放于secret对象中,而secret经常被人吐槽的是存放的数据是明文(只是做了base64编码),所以这里多说一句secret的安全性问题。其实k8s是支持secret加密存放的,支持的加密类型还挺多,具体可以看我这篇文章: 使用加密插件加密secrets中的数据 。但其实我并不建议使用这种方式,原因是使用加密插件只能加密存放在etcd里面的数据,而使用api server调取出的数据仍然是解密过后的,这意味着你执行 kubectl get secrets 或者是进入容器的环境变量查看,仍然可以看到明文数据。k8s项目更推荐的权限管理方式是:

    做好上面两点,对于一般公司的安全管控来讲已经足够,毕竟集群管理员的权限只是掌握在很小一部分人的手中。而对于安全审计要求更高的企业(比如金融机构),审计可能会有要求敏感数据必须加密存放,此时可使用api-server的加密插件。

    三、kubernetes常见故障

    kubernetes常见故障

    1. 节点CNI不可用,其它节点无法连接到故障节点的Pod

    2. Subpath方式挂载的Configmap,特定条件下出现Pod无限重启的问题

    3. 集群DNS服务器无法通过上游DNS解析外部名称

    4. 节点假死,但是持有的Ceph RBD的Watcher不释放,导致有状态服务的Pod调度走后仍然无法启动

    5. 误删Etcd数据、持久卷

    有四个有用的命令可以对Pod进行故障排除:

    kubectl logs 有助于检索Pod容器的日志

    kubectl describe pod 检索与Pod相关的事件列表很有用

    kubectl get pod 用于提取存储在Kubernetes中的Pod的YAML定义

    kubectl exec -ti bash 在Pod的一个容器中运行交互式命令很有用

    常见Pod错误

    Pod可能会出现启动和运行时错误。

    启动错误包括:

    ImagePullBackoff

    ImageInspectError

    ErrImagePull

    ErrImageNeverPull

    RegistryUnavailable

    InvalidImageName

    运行时错误包括:

    CrashLoopBackOff

    RunContainerError

    KillContainerError

    VerifyNonRootError

    RunInitContainerError

    CreatePodSandboxError

    ConfigPodSandboxError

    KillPodSandboxError

    SetupNetworkError

    TeardownNetworkError

    有些错误比其他错误更常见。

    以下是最常见的错误列表以及如何修复它们的方法。

    ImagePullBackOff

    当Kubernetes无法获取到Pod中某个容器的镜像时,将出现此错误。

    共有三个可能的原因:

    镜像名称无效-例如,你拼错了名称,或者image不存在

    你为image指定了不存在的标签

    你尝试检索的image属于一个私有registry,而Kubernetes没有凭据可以访问它

    前两种情况可以通过更正image名称和标记来解决。

    针对第三种情况,你应该将私有registry的访问凭证通过Secret添加到k8s中并在Pod中引用它。

    官方文档中有一个有关如何实现此目标的示例。

    CrashLoopBackOff

    如果容器无法启动,则Kubernetes将显示错误状态为:CrashLoopBackOff。

    通常,在以下情况下容器无法启动:

    应用程序中存在错误,导致无法启动

    你未正确配置容器

    Liveness探针失败太多次

    你应该尝试从该容器中检索日志以调查其失败的原因。

    如果由于容器重新启动太快而看不到日志,则可以使用以下命令:

    $ kubectl logs --previous 

    这个命令打印前一个容器的错误消息。

    RunContainerError

    当容器无法启动时,出现此错误。

    甚至在容器内的应用程序启动之前。

    该问题通常是由于配置错误,例如:

    挂载不存在的卷,例如ConfigMap或Secrets

    将只读卷安装为可读写

    你应该使用kubectl describe pod 命令收集和分析错误。

    处于Pending状态的Pod

    当创建Pod时,该Pod保持Pending状态。

    为什么?

    假设你的调度程序组件运行良好,可能的原因如下:

    集群没有足够的资源(例如CPU和内存)来运行Pod

    当前的命名空间具有ResourceQuota对象,创建Pod将使命名空间超过配额

    该Pod绑定到一个处于pending状态的 PersistentVolumeClaim

    最好的选择是检查kubectl describe命令输出的“事件”部分内容:

    $ kubectl describe pod  

    对于因ResourceQuotas而导致的错误,可以使用以下方法检查集群的日志:

    $ kubectl get events --sort-by=.metadata.creationTimestamp 

    处于未就绪状态的Pod

    如果Pod正在运行但未就绪(not ready),则表示readiness就绪探针失败。

    当“就绪”探针失败时,Pod未连接到服务,并且没有流量转发到该实例。

    就绪探针失败是应用程序的特定错误,因此你应检查kubectl describe中的“ 事件”部分以识别错误。

    2. 服务的故障排除

    如果你的Pod正在运行并处于就绪状态,但仍无法收到应用程序的响应,则应检查服务的配置是否正确。

    service旨在根据流量的标签将流量路由到Pod。

    因此,你应该检查的第一件事是服务关联了多少个Pod。

    你可以通过检查服务中的端点(endpoint)来做到这一点:

    $ kubectl describe service | grep Endpoints 

    端点是一对,并且在服务(至少)以Pod为目标时,应该至少有一个端点。

    如果“端点”部分为空,则有两种解释:

    你没有运行带有正确标签的Pod(提示:你应检查自己是否在正确的命名空间中)

    service的selector标签上有错字

    如果你看到端点列表,但仍然无法访问你的应用程序,则targetPort可能是你服务中的罪魁祸首。

    你如何测试服务?

    无论服务类型如何,你都可以使用kubectl port-forward来连接它:

    $kubectl port-forward service/ 3000:80 

    这里:

    是服务的名称

    3000 是你希望在计算机上打开的端口

    80 是服务公开的端口

    3.Ingress的故障排除

    如果你已到达本节,则:

    Pod正在运行并准备就绪

    服务会将流量分配到Pod

    但是你仍然看不到应用程序的响应。

    这意味着最有可能是Ingress配置错误。

    由于正在使用的Ingress控制器是集群中的第三方组件,因此有不同的调试技术,具体取决于Ingress控制器的类型。

    但是在深入研究Ingress专用工具之前,你可以用一些简单的方法进行检查。

    Ingress使用serviceName和servicePort连接到服务。

    你应该检查这些配置是否正确。

    你可以通过下面命令检查Ingress配置是否正确:

    $kubectl describe ingress  

    如果backend一列为空,则配置中必然有一个错误。

    如果你可以在“backend”列中看到端点,但是仍然无法访问该应用程序,则可能是以下问题:

    你如何将Ingress暴露于公共互联网

    你如何将集群暴露于公共互联网

    你可以通过直接连接到Ingress Pod来将基础结构问题与Ingress隔离开。

    首先,获取你的Ingress控制器Pod(可以位于其他名称空间中):

    $ kubectl get pods --all-namespaces 

    NAMESPACE NAME READY STATUS 

    kube-system coredns-5644d7b6d9-jn7cq 1/1 Running 

    kube-system etcd-minikube 1/1 Running 

    kube-system kube-apiserver-minikube 1/1 Running 

    kube-system kube-controller-manager-minikube 1/1 Running 

    kube-system kube-proxy-zvf2h 1/1 Running 

    kube-system kube-scheduler-minikube 1/1 Running 

    kube-system nginx-ingress-controller-6fc5bcc 1/1 Running 

    描述它以检索端口:

    # kubectl describe pod nginx-ingress-controller-6fc5bcc 

    --namespace kube-system \ 

    | grep Ports 

    最后,连接到Pod:

    $ kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system 

    此时,每次你访问计算机上的端口3000时,请求都会转发到Pod上的端口80。

    现在可以用吗?

    如果可行,则问题出在基础架构中。你应该调查流量如何路由到你的集群。

    如果不起作用,则问题出在Ingress控制器中。你应该调试Ingress。

    如果仍然无法使Ingress控制器正常工作,则应开始对其进行调试。

    目前有许多不同版本的Ingress控制器。

    热门选项包括Nginx,HAProxy,Traefik等。

    你应该查阅Ingress控制器的文档以查找故障排除指南。

    由于Ingress Nginx是最受欢迎的Ingress控制器,因此在下一部分中我们将介绍一些有关调试ingress-nginx的技巧。

    调试Ingress Nginx

    Ingress-nginx项目有一个Kubectl的官方插件。

    你可以用kubectl ingress-nginx来:

    检查日志,后端,证书等。

    连接到ingress

    检查当前配置

    你应该尝试的三个命令是:

    kubectl ingress-nginx lint,它会检查 nginx.conf

    kubectl ingress-nginx backend,以检查后端(类似于kubectl describe ingress )

    kubectl ingress-nginx logs,查看日志

    请注意,你可能需要为Ingress控制器指定正确的名称空间–namespace 。

    ------------------------------------------------------------------------------------------------------

    kubernetes之故障排查和节点维护(二)

    系列目录

    案例现场:

    测试环境集群本来正常,突然间歇性地出现服务不能正常访问,过一会儿刷新页面又可以正常访问了.进入到服务所在的pod查看输出日志并没有发现异常.使用kubectl get node命令正好发现一个节点是NotReady状态

    为了方便观察,使用kubectl get node --watch来观测一段时间,发现k8s-node1节点不断的在Ready和NotReady状态之间切换(使用kubectl get node -o wide可以查看节点的ip信息).

    进入到出现问题的节点,使用命令journalctl -f -u kubelet来查看kubelet的日志信息,把错误日志截出来一段搜索一下,发现问题和这个问题基本上是一样的,发现这个问题的时间和github上issue提出的时间是在同一天,也没有看到解决办法.但是基本能确定是因为集群中k8s-node1上的kubernetes版本不一致造成的(从上面截图上可以看到,这个节点的版本是1.14.1其它的都是1.13.1,是怎么升上来的不清楚,可能是其它同事误操作升级导致的)

    搜索kubernetes NotReady查看了一些解决经验,很多都是重启docker,重启kubectl等,然后都解决不了问题.于是尝试重置这个节点.

    从集群中删除Node

    由于这个节点上运行着服务,直接删除掉节点会导致服务不可用.我们首先使用kubectl drain命令来驱逐这个节点上的所有pod

    kubectl drain k8s-node1 --delete-local-data --force --ignore-daemonsets

    以上命令中--ignore-daemonsets往往需要指定的,这是因为deamonset会忽略unschedulable标签(使用kubectl drain时会自动给节点打上不可调度标签),因此deamonset控制器控制的pod被删除后可能马上又在此节点上启动起来,这样就会成为死循环.因此这里忽略daemonset.

    实际在使用kubectl drain时候,命令行一直被阻塞,等了很久还在被阻塞.使用kubectl get pod命令查看pod状态时.其中一个叫作busybox的pod一直处于Terminating状态. 使用kubectl delete pod busybox同样无法删除它.这时候可以使用命令kubectl delete pods busybox --grace-period=0 --force来强制马上删除pod.

    这时候控制台阻塞状态结束.下面执行命令kubectl delete node k8s-node1来删除这个节点.然后我们重新安装kubelet,kubeadm和kubectl

    卸载旧版本

    如果是通过yum方式安装的,可以通过yum list installed|grep xxx形式来找到已安装的组件,然后删除它们.删除以后重新安装.

    这里之所以要重新安装是因为版本升级成了较为新的版本,如果版本是一样的,其它的不确定因素导致节点不稳定,又找不到具体原因,则可以通过kubeadm reset来重置安装.

    重置命令并不会重置设置的iptables规则和IPVS如果想要重置iptables,则需要执行以下命令:

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X

    如果想要重置IPVS,则需要执行以下命令:

    ipvsadm -C

    这里我能够基本确定是由于版本不一致导致的,因此我并不重置iptables和IPVS,仅仅是重装组件.

    重新加入集群

    重置完成以后,我们把删除掉的k8s-node1节点使用kubeadm join重新加入到集群中

    如果忘记了主节点初始化时候生成的加入token,可以在主节点上执行kubeadm token create --print-join-command重新生成加入token,然后把生成的命令复制到要加入集群的节点上执行.

    重新加入集群后,观察了一段时间,一直是Ready状态,感觉终于稳定了,但是同事又反馈部署服务时出现以下错误

    Failed create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "5159f7918d520aee74c5a08c8707f34b61bcf1c340bfc444125331034e1f57f6" network for pod "test-58f4789cb7-7nlk8": NetworkPlugin cni failed to set up pod "test-58f4789cb7-7nlk8_default" network: failed to set bridge addr: "cni0" already has an IP address different from 10.244.4.1/24

    幸好有伟大的互联网,通过搜索,找到以下解决方案

    由于这次启动以后初次部署pod就失败了,因此此节点上还没有运行的服务,我们不需要执行kubectl drain,可以直接把这个节点删除.然后执行以下命令

    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

    完了以后重新加入集群.这次可以正常工作了.

    -----------------------------------------------------------------

    关于expired的问题,通过《深入理解Kubernetes的认证与授权机制》、《kubernetes常见故障》等文章的解答希望已经帮助到您了!如您想了解更多关于expired的相关信息,请到本站进行查找!

    爱资源吧版权声明:以上文中内容来自网络,如有侵权请联系删除,谢谢。

    expired
    AJ电脑出现蓝屏怎么办?蓝屏问题排除方法 algexe人工智能应用分析:深度学习与算法应用