k8s-基础知识
参考文献
- Kubernetes权威指南: 从Docker到Kubernetes实践全接触
- Kubernetes in Action中文版
容器编排系统
- 容器编排是指自动化容器应用的部署,管理,扩展和联网的一系列管控操作,能后控制和自动化许多任务、包括调度和部署容器、在容器之间分配资源、扩缩容器应用规模、在主机不可用或资源不足时将容器从一台主机迁移到其他主机、负载均衡以及监视容器和主机的运行状况等.
- 容器编排系统用于完成容器编排相关的任务.
- 以
Kubernetes
,Mesos
和Docker Swarm
等为代表的这类工具通常需要用户在YAML
或JSON
格式的配置清单中描述应用程序的配置,以指示编排系统在何处检索容器镜像(私有仓库或者某外部仓库)、如何在容器之间建立网络、在何处存储日志以及如何挂载存储卷等. - 确定调度目标后,编排工具将根据预定规范管理容器的生命周期
- 以
- 容器编排系统能够为用户提供如下关键能力:
- 集群管理与基础设施抽象: 将多个虚拟机或物理机构建成协同运行的集群,并将这些硬件基础设施抽象为一个统一的资源池.
- 资源分配和优化: 基于配置清单中指定的资源需求与现实可用的资源量,利用成熟的调度算法合理调度工作负载.
- 应用部署: 支持跨主机自动部署容器化应用,支持多版本并存、滚动更新和回滚等机制
- 应用伸缩: 支持应用实例规模的自动或手动伸缩.
- 应用隔离: 支持租户、项目或应用进行访问隔离
- 服务可用性: 利用状态检测和应用重构等机制确保服务始终健康运行.
Kubernetes
集群架构
1 | +-------------+ |
- 在硬件级别,一个
Kubernetes
集群由节点组成,这些节点被分成以下两种类型:- 主节点: 它承载着
Kubernetes
控制和管理整个集群系统的控制面板 - 工作节点: 它们运行用户实际部署的应用
- 主节点: 它承载着
Master node
控制节点
Master
1 | +----------------------------------------------------------+ |
- 控制面板用于控制集群并使它工作.它包含多个组件,组件可以运行在单个主节点或者通过副本分别部署在多个节点以确保高可用性.这些组件是:
Kubernetes API Server
你和其他控制面板组件都要和它通信Scheduler
,它调度你的应用(为应用的每个可部署自检分配一个工作节点)Controller Manager
,它执行集群级别的功能,如复制组件,持续跟踪工作节点,处理节点失败等etcd
,一个可靠的分布式数据存储,它能持久化存储集群配置
- 控制面板的组件持有并控制集群状态,但是它们不运行你的应用程序,运行是由工作节点完成的.
Work node
工作节点
1 | +--------------------------------------------------------+ |
- 工作节点是运行容器化应用的机器.运行,监控和管理应用服务的任务是由以下组件完成的:
Docker,rtk
或其他容器类型Kubelet
,它与API服务器通信,并管理它所在节点的容器Kubernetes Service Proxy(kube-proxy)
,它负责组件之间的负载均衡网络流量
流程说明
- 以部署一个
nginx
服务来举例,首先要明确,一旦Kubernetes
环境启动之后,master
和node
都会将自身的信息存储到etcd
数据库中 - 一个nginx服务的安装请求会首先被发送到
master
节点的apiServer
组件 apiServer
组件会调用Scheduler
组件来决定到底应该把这个服务安装到哪个node节点上- 在此时,它会从
etcd
中读取各个node
节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer
- 在此时,它会从
apiServer
调用controller-manager
去调度node
节点安装nginx
服务node
节点的kubelet
接收到指令后,会通知docker
,然后由docker
来启动一个nginx
的pod
pod
是Kubernetes
的最小操作单元,容器必须跑在pod
中
- 一个
nginx
服务就运行了,如果需要访问nginx
,就需要通过kube-proxy
来对pod
产生访问的代理
集群类型
- 一主多从: 一台
master
节点和多台node
节点,搭建简单,但是有单机故障风险,适合测试环境 - 多主多从: 多台
master
节点和多台node
节点,搭建麻烦,安全性高,适合生产环境
安装方式
minikube
: 一个用于快速搭建单节点的Kubernetes
的工具kubeadm
: 一种用于快速搭建Kubernetes
集群的工具- 二进制包: 从官网下载每个组件的二进制包,去依次去安装.
资源说明
Kubernetes
概念
master
: 集群控制节点,每个集群需要至少一个master
节点负责集群的管控node
: 工作负载节点,有master
分配容器到这些node
工作节点上,然后node
节点上的docker
负责容器的运行pod
:Kubernetes
的最小控制单元,容器都是运行在pod
中的,一个pod
中可以有1个或多个容器controller
: 控制器,通过它来实现对pod
的管理,比如启动pod
,停止pod
,伸缩pod
的数量等.service
:pod
对外服务的统一入口,下面可以维护同一类的多个pod
label
: 标签,用户对pod
进行分类,同一类pod
会有相同的标签namespace
: 命名空间,用来隔离pod
的运行环境
minikube
启动一个minikube
虚拟机
1 | minikube start |
-
启动集群需要花费超过一分钟的时间
-
安装
Kubernetes
客户端kubectl
1
2curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube -
使用
kubectl
查看集群是否正常工作1
kubectl cluster-info
-
使用
kubectl
列出集群节点1
kubectl get nodes
-
打开使用
Minikube
的Kubernetes
集群的dashboard
1
minikube dashboard
kubeadmin
创建集群
kubeadm init
之后忘记kubeadm join
命令的信息
重新生成kubeadm join
命令
1 | kubeadm token create --print-join-command |
查看现有的 kubeadm 令牌
1 | kubeadm token list |
node
查看节点信息
1 | # kubectl get nodes |
查看当前Kubernetes
版本支持的所有对象
1 | kubectl api-resources |
pod
- 一个
pod
是一组紧密相关的容器,它们总是一起运行在同一个工作节点上,以及同一个Linux
命名空间中.每个pod
就像一个独立的逻辑机器,拥有自己的IP
,主机名,进程等,运行一个独立的应用程序.应用程序可以是单个进程,运行在单个容器中,也可以是一个应用进程或者其他支持进程,每个进程都在自己的容器中运行. - 一个
pod
的所有容器都运行在同一个逻辑机器上,而其他pod
中的容器,即使运行在同一个工作节点上,也会出现在不同节点上. pod
是逻辑主机,其行为与非容器世界中的物理主机或虚拟机非常相似.此外在同一个pod
中进程与运行在同一个物理机或虚拟机上的进程相似,只是每个进程都封装在一个容器之中.
列出pod
1 | kubectl get pods |
显示命令详细过程
-
在使用
kubectl
命令的时候,可以加上一个参数--v=9
,它会显示出详细的命令执行过程,清楚地看到发出的HTTP请求1
kubectl get pods --v=9
列出服务
1 | kubectl get services |
pod
的YAML
描述文件
1 | # kubectl get po domain-admin -o yaml |
pod
定义的主要部分
- pod定义有这么几个部分组成: 首先是
YAML
中使用的Kubernetes API
版本和YAML
描述的资源类型;其次是几乎在所有Kubernetes
资源中都可以找到的三大重要部分:metadata
包括名称、命名空间、标签和关于该容器的其他信息spec
包含pod内容的实际说明,例如pod
的容器,卷和其他数据status
包含运行中的pod
的当前信息,例如pod
所处的条件,每个容器的描述和状态,以及内部IP和其他基本信息.
Pod
中几个重要字段的含义和用法
-
nodeSelector
: 是一个供用户将Pod
和Node
进行绑定的字段1
2
3
4
5
6
7apiVersion: v1
kind: Pod
...
spec:
# 这样的一个配置,意味着这个 Pod 永远只能运行在携带了“disktype: ssd”标签(Label)的节点上;否则,它将调度失败
nodeSelector:
disktype: ssd -
nodeName
: 一旦 Pod 的这个字段被赋值,Kubernetes
项目就会被认为这个 Pod 已经经过了调度,调度的结果就是赋值的节点名字.所以,这个字段一般由调度器负责设置,但用户也可以设置它来“骗过”调度器,当然这个做法一般是在测试或者调试的时候才会用到 -
hostAliases
: 定义了 Pod 的 hosts 文件(比如 /etc/hosts)里的内容1
2
3
4
5
6
7
8
9apiVersion: v1
kind: Pod
...
spec:
hostAliases:
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
使用kubectl explain
解释API
对象字段
1 | # kubectl explain pods |
让kubectl
生成一份""文档样板’’
-
kubectl的两个特殊参数
--dry-run=client
和-o yaml
,前者是空运行,后者是生成YAML格式,结合起来使用就会让kubectl不会有实际的创建动作,而只生成YAML文件1
kubectl run ngx --image=nginx:alpine --dry-run=client -o yaml
使用kubectl create
来创建pod
1 | kubectl create -f kubia-manual.yaml |
查看应用程序日志
1 | kubectl logs <pod-name> |
- 每天或每次日志文件达到10MB大小时,容器日志都会自动轮替.
kubectl logs
命令仅显示最后一次轮替后的日志条目
1 | kubectl logs <pod-name> -c <container-name> |
向pod
发送请求
-
将本地网络端口转发到
pod
中端口1
kubectl port-forward kubia-manual 8888:8080
Pod
生命周期
状态 | 说明 |
---|---|
Pending |
这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中.但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建.比如,调度不成功 |
Running |
这个状态下,Pod 已经调度成功,跟一个具体的节点绑定.它包含的容器都已经创建成功,并且至少有一个正在运行中 |
Succeeded |
这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了.这种情况在运行一次性任务时最为常见 |
Failed |
这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出.这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志 |
Unknown |
这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题 |
删除pod
按名称删除
1 | kubectl delete po kubia-gpu |
- 在删除
pod
的过程中,实际上我们在指示Kubernetes
终止该pod
中所有容器. Kubernetes
向进程发送一个SIGTERM
信号并等待一定的秒数(默认为30),使其正常关闭.如果它没有及时关闭,则通过SIGKILL
终止该进程.
使用标签选择器删除pod
1 | # kubectl delete po -l creation_method=manual |
通过删除整个命名空间来删除pod
1 | # kubectl delete ns custom-namespace |
删除命名空间中的所有pod
,但保留命名空间
1 | # kubectl delete po --all |
删除命名空间中(几乎)所有资源
1 | # kubectl delete all --all |
- 第一个
all
指定正在删除所有资源类型,而--all
选项指定将删除所有资源实例,而不是按名称指定它们.
label
标签
- 标签是一种简单却功能强大的
Kubernetes
特性,不仅可以组织pod
,也可以组织所有其他的Kubernetes
资源. - 标签是可以附加到资源(任何
Kubernetes
对象)的任意键值对,用以选择具有该确切标签的资源(这是通过标签选择器完成的).只要标签的key
在资源内是唯一的,一个资源便可以拥有多个标签. - 通常在我们创建资源时就会将标签附加到资源上,但之后我们也可以再添加其他标签,或者修改现有标签的值,而无须重新创建资源.
创建pod
时指定标签
1 | apiVersion: v1 |
查看pod
标签
1 | # kubectl get po --show-labels |
-
使用
-L
选项指定标签分别显示在自己的列中,而不是列出所有标签1
2
3
4
5# kubectl get po -L creation_method,env
NAME READY STATUS RESTARTS AGE CREATION_METHOD ENV
domain-admin 1/1 Running 1 (16h ago) 11d
kubia-manual 1/1 Running 0 15h
kubia-manual-v2 1/1 Running 0 8m49s manual prod
修改现有pod
的标签
1 | # kubectl label po kubia-manual creation_method=manual |
1 | # 更改现有标签时,需要使用--overwrite |
标签选择器
- 标签要与标签选择器结合在一起.标签选择器允许我们选择标记特定标签的
pod
子集,并对这些pod
执行操作.可以说标签选择器是一种能够根据是否具有特定值的特定标签来过滤资源的准则. - 标签选择器根据资源的以下条件来选择资源:
- 包含(或不包含)使用特定键的标签
- 包含具有特定键和值的标签
- 包含具有特定键的标签,但其值与我们指定的不同
使用标签选择器列出pod
1 | # kubectl get po -l creation_method=manual |
windows
下会有问题,需要将单引号去掉
1 | # kubectl get po -l '!env' |
在标签选择器中使用多条件
- 在包含多个逗号分隔清空下,可以在标签选择器中同时使用多个条件,此时资源需要全部匹配才算成功匹配了选择器.
使用标签分类工作节点
- 向节点提假标签来展示这个功能特性,可以通过将标签
gpu=true
添加到其中一个节点上来实现(只需要从kubectl get nodes
返回的列表中选择一个)
1 | # kubectl get nodes |
将pod
调度到特定节点
1 | apiVersion: v1 |
Volume
Projected Volume
-
投射数据卷
-
类别
-
secret
- 它的作用,是帮你把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,你就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret
里保存的信息了
- 它的作用,是帮你把 Pod 想要访问的加密数据,存放到 Etcd 中。然后,你就可以通过在 Pod 的容器里挂载 Volume 的方式,访问到这些 Secret
-
downwardAPI
- 它的作用是:让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息。
-
configMap
-
serviceAccountToken
-
clusterTrustBundle
-
ConfigMap/Secret
-
ConfigMap用来保存明文配置,Secret用来保存秘密配置
1
2
3# 创建secret YAML样板
export out="--dry-run=client -o yaml" # 定义Shell变量
kubectl create cm info $out1
2# 创建secret YAML样板
kubectl create secret generic user --from-literal=name=root $out
注解pod
- 除了标签外,
pod
和其他对象还可以包含注解.注解也是键值对,所以它们本质上与标签非常相似.但与标签不同,注解并不是为了保存标识信息而存在的,它们不能像标签一样用于对对象进行分组.当我们选择标签选择器选择对象时,就不存在注解选择器这样的东西.
添加和修改注解
1 | # kubectl annotate pod kubia-manual holelin.com/someannotation="foo bar" |
使用命名空间对资源进行分组
列出集群中所有命名空间
1 | # kubectl get ns |
1 | # kubectl get po --namespace kube-system |
- 可以使用
-n
来代替--namespace
创建一个命名空间
-
从
YAML
文件创建命名空间,创建一个custom-namespace.yaml
,然后执行kubectl create -f custom-namespace.yaml
1
2
3
4
5
6apiVersion: v1
# 这表示我们正在定义一个命名空间
kind: Namespace
metadata:
# 这是命名空间的名称
name: custom-namespace -
使用
kubectl create namespace
命令创建命名空间1
2# kubectl create namespace custom-namespace
namespace/custom-namespace created
管理其他命名空间中的对象
-
如果想要在刚创建的命名空间中创建资源,可以选择在
metadata
字段中添加一个namespace: custom-namespace
属性,也可以使用kubectl create
命令创建资源时指定命名空间1
2# kubectl create -f kubia-manual.yaml -n custom-namespace
pod/kubia-manual created -
在列出,描述,修改或删除其他命名空间中的对象时,需要给
kubectl
命令传递--namespace/-n
选项.如果不指定命名空间 ,kubectl
将在当前上下文配置的默认命名空间中执行操作.而当前上下文的命名空间和当前上下文本身可以通过kubectl config
命令进行更改.- 要想快速切换到不同的命名空间,可以设置以下别名:
alias kcd='kubectl config set-context $(kubectl config current-context) --namespace
,然后可以使用kcd some-namespace
在命名空间之间进行切换.
- 要想快速切换到不同的命名空间,可以设置以下别名:
保持pod
健康
存活探针
Kubernetes
可以通过存活探针(liveness probe
)检查容器是否还在运行.可以为pod
中的每个容器单独指定存活探针.如果探针失败,Kubernetes
将定期执行探针并重新启动容器.Kubernetes
有以下三种探测同期的机制HTTP GET
探针对容器的IP
地址(指定的端口和路径)执行HTTP GET
请求.- 如果探测器收到响应,并且响应状态码不代表错误(换句话,如果
HTTP
响应状态码是2xx
或3xx
),则认为探测成功.如果服务器返回错误响应状态码或者根本没响应,那么探测就被认为失败,容器将被重新启动.
- 如果探测器收到响应,并且响应状态码不代表错误(换句话,如果
TCP
套接字探针尝试与容器指定端口建立TCP
连接.如果连接成功建立,则探测成功.否则,容器重新成功.Exec
探针在容器内执行任意命令,并检查命令的退出状态码.如果状态码是0,则探测成功.所有其他状态码都被认为失败.
创建基于HTTP
的存活探针
1 | apiVersion: v1 |
获取崩溃容器的应用日志
1 | kubectl logs kubia-liveness --previous |
重启容器后的pod
描述
1 | # kubectl describe po kubia-liveness |
- 可以看到容器现在正在运行,但之前由于错误而终止.退出代码为
137
,这有特殊的含义–表示该进程由外部信号终止.- 数字
137
是两个数字的总和:128+x
,其中x
是终止进程的信号编号.在这个例子,x
等于9,这是SIGKILL
的信号编号,意味这这个进程被强行终止.- 退出代码
127
表示进程被外部信号终止,退出代码为128+9(SIGKILL)
- 退出代码
143
对应128+15(SIGTERM)
- 退出代码
- 当容器被强行终止时,会创建一个全新的容器–而不是重启原来的容器.
- 数字
配置存活探针的附加属性
- 定义探针时可以自定义这些附加参数.例如,要设置初始延迟,请将
initialDelaySeconds
属性添加到存活探针的配置中.
1 | apiVersion: v1 |
- 如果没有设置初始延迟,探针将在启动时立即开始探测容器,这通常会导致探测失败,因为应用程序还没准备好开始接收请求.如果失败次数超过阀值,在应用程序能正确相应请求之前,容器就会重启.
- 务必记得设置一个初始延迟来说明应用程序的启动时间.
创建有效的存活探针
存活探针一个检查什么
- 为了更好的进行存活检查,需要将探针配置为请求特定的URL路径(例如
/health
),并让应用从内部对内部运行的所有重要组件执行状态检查,以确保他们都没有终止或停止响应.- 请确保
/health HTTP
端点不需要认证,否则探测会一直失败,导致你的容器无限重启.
- 请确保
保持探针轻量
- 存活探针不应消耗太多的计算资源,并且运行不应该花太长时间.默认情况下,探测器执行的频率相对较高,必须在一秒内执行完毕.
ReplicationController
ReplicationController
是一种Kubernetes
资源,可确保它的pod
始终保持运行状态.如果pod
因任何原因消失(例如节点从集群中消失或由于该pod
已从节点中逐出),则ReplicationController
会注意到缺少了pod
并创建替代pod
.
控制器的协调流程
ReplicationController
的工作是确保pod
的数量始终与其标签选择器匹配.如果不匹配,则ReplicationController
将根据所需,采取适当的操作来协调pod
的数量.
ReplicationController
的三部分
label selector
(标签选择器),用于确定ReplicationController
作用域有哪些pod
replica count
(副本个数),指定运行的pod
数量pod template
(pod
模板),用于创建新的pod
副本ReplicationController
的副本个数,标签选择器,甚至是pod
模板都可以随时修改,但只有副本数量的变更会影响现有的pod
.
更改控制器的标签选择器或pod
模板的效果
- 更改标签选择器和
pod
模板对现有pod
没有影响.更改标签选择器会使现有的pod
脱离ReplicationController
的范围,因此控制器会停止关注他们. - 在创建
pod
后,ReplicationController
也不关心其pod
的实际"内容"(容器镜像,环境变量及其他).因此,该模版仅影响由此ReplicationController
创建的新pod
.
使用ReplicationController
的好处
- 确保一个
pod
(或多个pod
)持续运行,方法是在现有pod
丢失是启动一个新的pod
- 集群节点发生故障时,它将为故障节点上运行的所有
pod
(即受ReplicationController
控制的节点上的那些pod
)创建替代副本. - 它能轻松实现
pod
的水平伸缩–手动和自动都可以
创建一个ReplicationController
1 | apiVersion: v1 |
- 上传文件到
API
服务器时,Kubernetes
会创建一个名为kubia
的新ReplicationController
.它确保符合标签选择器app=kubia
的pod
实例始终是三个.当没有足够的pod
时,根据提供的pod
模板创建新的pod
. - 模板中的
pod
标签必须和ReplicationController
的标签选择器匹配,否则控制器将无休止地创建新的容器.因为启动新的pod
不会使实际的副本数据量接近期望的副本数量.为了防止出现这种情况,API
服务会校验ReplicationController
的定义不会接收错误配置. - 不指定选择器也是一种选择,在这种情况下,它会自动根据
pod
模版中的标签自动配置.
获取有关ReplicationController
的信息
1 | kubectl get rc |
1 | # kubectl describe rc kubia |
控制器如何创建新的pod
-
控制器通过创建一个新的替代
pod
来响应pod
的删除操作.从技术上讲,它并没有对删除本身做反应,而是针对由此产生的状态,即pod
数量不足. -
虽然
ReplicationController
会立即收到删除的pod
的通知(API
服务器允许客户端监听资源和资源列表的更改),但这不是它创建替代pod
的原因.该通知会触发控制器检查实际的pod
数量并采取适当的措施.
修改pod
模板
-
ReplicationController
的pod
模板可以随时修改.更改pod
模板就像用一个曲奇到替换另一个,它只会影像你之后切出的曲奇,并不会影响你已经剪切的曲奇.要修改旧的pod
,你需要删除它们,并让ReplicationController
根据新模板将其替换为新的pod
. -
可以试着编辑
ReplicationController
并向pod
模板添加标签1
kubectl edit rc kubia
- 这将在你的默认文本编辑器中打开
ReplicationController
的YAML
配置.
- 这将在你的默认文本编辑器中打开
水平缩放pod
- 放大或者缩小
pod
的数量规模就和在ReplicationController
资源中更改Replicas
字段的值一样简单.更改之后,ReplicationController
将会看到存在太多的pod
并删除其中的一部分(缩容时),或者看到它们数目太少并创建pod
(扩容时).
使用kubectl scale
命令缩容
1 | # scale rc kubia --replicas=3 |
删除一个ReplicationController
-
当你通过
kubectl delete
删除ReplicationController
时,pod
也会被删除.但是由于由ReplicationController
创建的pod
不是ReplicationController
的组成部分,只是由其进行管理,因此可以值删除ReplicationController
并保持pod
运行. -
当使用
kubectl delete
删除ReplicationController
时,可以通过给命令增加--cascade=orphan
选项来保持pod
运行1
kubectl delete rc kubia --cascade=orphan
使用ReplicaSet
而不是ReplicationController
ReplicationController
是用于复制和在异常时重新调度节点的唯一Kubernetes
组件,后来又引入一个名为ReplicaSet
的类似资源.它是新一代的ReplicationController
,并且将其完全替换掉(ReplicationController
最终将被弃用).
定义ReplicaSet
1 | apiVersion: apps/v1 |
查看ReplicaSet
1 | # kubectl get rs |
使用ReplicaSet
的更富表达力的标签选择器
1 | apiVersion: apps/v1 |
- 可以给选择器添加额外的表达式,每个表达式都必须包含一个
key
,一个operator
(运算符),并且可能还有一个values
的列表(取决于运算符)In
:Label
的值必须与其中一个指定的values
匹配.NotIn
:Label
的值与任何指定的values
不匹配Exists
:pod
必须包含一个指定名称的标签(值不重要).使用此运算符时,不应指定values
字段DoesNotExists
:pod
不得包含有指定名称的标签.values
属性不得指定.
- 如果指定了多个表达式,则所有这些表达式都必须为
true
才能使选择器与pod
匹配(条件是AND
关系).如果同时指定matchLabels
和matchExpressions
,则所有标签都必须匹配,并且所有表达式必须计算为true
以使该pod
与选择器匹配.
删除ReplicaSet
1 | kubectl delete rs kubia |
DaemonSet
创建一个DaemonSet YAML
文件
1 | apiVersion: apps/v1 |
查看DaemonSet
1 | # kubectl get ds |
Job
Kubernetes
通过Job
资源提供了对此的支持,它允许你运行一种pod
,该pod
在内部进程成功结束时,不重启容器.一旦任务完成.pod
就被认为处于完成状态.- 在发上节点故障时,该节点上由
Job
管理的pod
将按照ReplicaSet
的pod
的方式,重新安排到其他节点.如果进程本身异常退出(进程返回错误退出代码时),可以将Job
配置为重新启动容器.
控制离线作业的重要字段
-
控制离线作业的重要字段
-
activeDeadlineSeconds
,设置Pod运行的超时时间。 -
backoffLimit
,设置Pod的失败重试次数。 -
completions
,Job完成需要运行多少个Pod,默认是1个
-
创建一个Job
1 | apiVersion: batch/v1 |
查看Job
1 | kubectl get job |
顺序运行Job pod
1 | apiVersion: batch/v1 |
并行运行Job pod
1 | apiVersion: batch/v1 |
CronJob
Job
资源在创建时会立即运行pod
,但是许多批处理任务需要再特定的时间运行,或者在指定的时间间隔内重复运行.Kubernetes
中的cron
任务通过创建CronJob
资源进行配置.运行任务的时间表以知名的cron
格式指定.
创建一个CronJob
1 | apiVersion: batch/v1 |
Service
创建服务
通过kubectl expose
创建服务
通过YAML
描述文件来创建服务
1 | apiVersion: v1 |
检测新的服务
1 | # kubectl get svc |
1 | # kubectl describe svc kubia |
从内部集群测试服务
-
方法一: 创建一个
pod
,它将请求发送到服务的集群IP
并记录响应 -
方法二: 使用
ssh
远程登录到其中一个Kubernetes
节点,然后使用curl
命令 -
方法三: 通过
kubectl exec
命令在一个已经存在的pod
中执行curl
命令1
2kubectl exec kubia-7fxh9 -- curl -s http://10.103.164.179
You've hit kubia-7fxh9 -
为什么使用双横杠? 双横杠(
--
)代表着kubectl
命令项的结束.在两个横杠之后的内容是指在pod
内部需要执行的命令.如果需要执行的命令并没有以横杠开始的参数,横杠也不是必须的.如下情况,如果这里不使用横杠号,-s
选项会被解析成kubectl exec
选项,会导致结果异常和歧义错误.
配置服务上的会话亲和性
-
如果希望特定客户端产生的所有请求每次都指向同一个
pod
,可以设置服务的sessionAffinity
属性为ClientIp
(而不是None
,None
是默认值)1
2
3
4
5
6
7apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
sessionAffinity: ClientIP
... -
Kubernetes
仅仅支持两种形式的会话亲和性服务:None
和ClinetIP
.
同一个服务暴露多个端口
-
创建的服务可以暴露一个端口,也可以暴露多个端口.
- 注意: 在创建一个多个端口的服务的时候,必须给每个端口指定名字.
1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
selector:
app: kubia- 标签选择器应用于整个服务,不能对每个端口做单独的配置.如果不同的
pod
有不同的端口映射关系,需要创建两个服务.
使用命名的端口
- 在
pod
定义中指定port
名称
1 | apiVersion: v1 |
1 | apiVersion: v1 |
服务发现
通过环境变量发现服务
通过DNS
发现服务
通过FQDN
连接服务
在pod
容器中运行shell
服务的类型
Service
目前有 4 种类型:ClusterIP
: 是 K8S 当前默认的Service
类型.将 service 暴露于一个仅集群内可访问的虚拟 IP 上.NodePort
: 是通过在集群内所有Node
上都绑定固定端口的方式将服务暴露出来,这样便可以通过<NodeIP>:<NodePort>
访问服务了.LoadBalancer
: 是通过Cloud Provider
创建一个外部的负载均衡器,将服务暴露出来,并且会自动创建外部负载均衡器路由请求所需的Nodeport
或ClusterIP
.ExternalName
: 是通过将服务由 DNS CNAME 的方式转发到指定的域名上将服务暴露出来,这需要kube-dns
1.7 或更高版本支持.
Endpoint
-
服务并不是和
pod
直接相连的,是通过一种资源介于两者之间–Endpoint
资源. -
Endpoint
资源就是暴露一个服务的IP
地址和端口的列表,Endpoint
资源和其他Kubernetes
资源一样.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# kubectl describe svc kubia
Name: kubia
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=kubia
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.103.164.179
IPs: 10.103.164.179
Port: <unset> 80/TCP
TargetPort: 8080/TCP
Endpoints: 10.244.0.69:8080,10.244.0.71:8080,10.244.0.72:8080
Session Affinity: None
Events: <none>1
2
3# kubectl get endpoints kubia
NAME ENDPOINTS AGE
kubia 10.244.0.54:8080,10.244.0.55:8080,10.244.0.56:8080 106m -
如果创建了不包含
pod
选择器的服务,Kubernetes
将不会创建Endpoint
资源(毕竟,缺少选择器,将不会知道服务中包含哪些pod
),这样就需要创建Endpoint
资源来指定该服务的Endpoint
列表. -
要使用手动配置
endpoint
的方式创建服务,需要创建服务和Endpoint
资源1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
ports:
- port: 80
apiVersion: v1
kind: Endpoints
metadata:
name: external-service
subsets:
- addresses:
- ip: 11.11.11.11
- ip: 22.22.22.22
ports:
- port: 80 -
Endpoint
对象需要与服务具有相同的名称,并包含该服务的目标IP地址和端列表.服务和Endpoint
资源都发布到服务器后,这样服务就可以像具有pod
选择器那样的服务正常使用.
将服务暴露给外部客户端
- 有几种方式可以在外部访问服务
- 将服务的类型设置为
NodePort
: 每个集群节点都会在节点上打开一个端口,对于NodePort
服务,每个集群节点在节点本身上打开一个端口,并将在该端口上接收到的流量重定向到基础服务.该服务仅在内部集群IP和端口才可以访问,但也可以通过所有节点上的专用端口访问. - 将服务的类型设置为
LoadBalance
,NodePort
类型的一种扩展,这使得服务可以通过一个专用的负载均衡器来访问,这是Kubernetes
中正在运行的云基础设施提供的.负载均衡器将流量重定向到跨所有节点的节点端口.客户端通过负载均衡器的IP连接到服务. - 创建一个
Ingress
资源,通过一个IP地址公开多个服务,它运行在HTTP
层(网络协议第7层)上,因此可以提供比工作在4层的服务更多的功能.
- 将服务的类型设置为
使用NodePort
类型的服务
-
通过创建
NodePort
服务,可以让Kubernetes
在其所有节点上保留一个端口(所有节点都使用相同的端口号),并将传入的连接转发给作为服务部分的pod
. -
这与常规服务类似(它们实际类型是
ClusterIP
),但是不仅可以通过服务的内部集群IP发那个访问NodePort
服务,还可以通过任何节点的IP和预留节点端口发那个访问NodePort
服务.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15apiVersion: v1
kind: Service
metadata:
name: kubia-nodeport
spec:
type: NodePort
ports:
# 服务集群IP的端口号
- port: 80
# 背后pod的目标端口号
targetPort: 8080
# 通过集群节点的30123端口访问该服务
nodePort: 30123
selector:
app: kubia
通过负载均衡器将服务暴露出来
-
负载均衡器拥有自己独一无二的可公开的访问IP地址,并将所有连接重定向到服务.可以通过负载均衡器的IP地址访问服务.
1
2
3
4
5
6
7
8
9
10
11
12
13apiVersion: v1
kind: Service
metadata:
name: kubia-loadbalancer
spec:
type: LoadBalancer
ports:
# 服务集群IP的端口号
- port: 80
# 背后pod的目标端口号
targetPort: 8080
selector:
app: kubia
通过Ingress
暴露服务
- 为什么需要
Ingress
?- 一个重要的原因是每个
LoadBalancer
服务都需要自己的负载均衡器,以及独有的公有IP地址,而Ingress
只需要一个公网IP就能为许多服务提供访问.当客户端向Ingress
发送HTTP
请求时,Ingress
会根据请求的主机名和路径决定请求转发的服务.
- 一个重要的原因是每个
认证和授权
- K8S 中几乎所有的操作都需要经过
kube-apiserver
处理,所以为了安全起见,K8S 为它提供了三类安全访问的措施.分别是:- 用于识别用户身份的认证(Authentication)
- 用于控制用户对资源访问的授权(Authorization)
- 用于资源管理方面的准入控制(Admission Control)
1 | +-----------------------------------------------------------------------------------------------------------+ |
Authentication
K8S
中的用户
-
K8S 中有两类用户,一般用户及
Service Account
- 一般用户:一般用户只能通过外部服务进行管理,由管理员进行私钥分发.这也意味着 K8S 中并没有任何表示一般用户的对象,所以一般用户是无法通过 API 直接添加到集群的.
Service Account
:由 K8S API 管理的用户,与特定的NameSpace
(命名空间)绑定.由API Server
自动创建或者通过 API 手动进行创建. 同时,它会自动挂载到Pod
中容器的/var/run/secrets/kubernetes.io/serviceaccount/
目录中,其中会包含NameSpace
token
等信息,并允许集群内进程与API Server
进行交互.
-
对集群操作的 API 都是与用户相关联的,或者被视为匿名请求.匿名请求可通过
kube-apiserver
的--anonymous-auth
参数进行控制,默认是开启的,匿名用户默认的用户名为system:anonymous
,所属组为system:unauthenticated
K8S
中的认证机制
- X509 客户端证书:这个认证机制我们并不陌生,我们前面搭建集群时,虽然没有指定配置文件,但
kubeadm
已经添加了默认参数--client-ca-file=/etc/kubernetes/pki/ca.crt
而在进行认证时,将会使用客户端证书 subject 的CN
域(Common Name)用作用户名,O
域(Organization)用作组名. - 引导 Token:当集群通过
kubeadm init
初始化完成后,将会展示一行提示,其中便携带着引导 Token.如果不使用kubeadm
时,需要设置--enable-bootstrap-token-auth=true
. - 静态 Token 文件:启动
Kube-apiserver
时,设置--token-auth-file=SOMEFILE
并在请求时,加上Authorization: Bearer TOKEN
的请求头即可. - 静态密码文件:与静态 Token 文件类似,设置
--basic-auth-file=SOMEFILE
并在请求时,加上Authorization: Basic BASE64ENCODED(USER:PASSWORD)
的头即可. Service Account Token
:这是默认启用的机制- OpenID:其实是提供了 OAuth2 的认证支持,像 Azure 或 Google 这类云厂商都提供了相关支持.
- 认证代理:主要是配合身份验证代理进行使用,比如提供一个通用的授权网关供用户使用.
Webhook
:提供 Webhook 配合一个远端服务器使用.
Authorization
- 授权,也就是在验证当前发起请求的用户是否有相关的权限
- 授权是以认证的结果为基础的,授权机制检查用户通过认证后的请求中所包含的属性来进行判断.
- K8S 支持多种授权机制,用户想要正确操作资源,则必须获得授权,所以 K8S 默认情况下的权限都是拒绝.当某种授权机制通过或者拒绝后,便会立即返回,不再去请求其他的授权机制;当所有授权机制都未通过时便会返回 403 错误了.
K8S
支持的授权机制
- ABAC(Attribute-Based Access Control):基于属性的访问控制,在使用时需要先配置
--authorization-mode=ABAC
和--authorization-policy-file=SOME_FILENAME
.ABAC 本身设计是非常好的,但是在 K8S 中使用却有点过于繁琐,这里不再赘述. - RBAC(Role-based access control):基于角色的访问控制,自 K8S 1.6 开始 beta,1.8 进入稳定版,已被大量使用.而当我们使用
kubeadm
安装集群的时候,默认将会添加--authorization-mode=Node,RBAC
的参数,表示同时开启Node
和RBAC
授权机制. - Node:这是一种特殊用途的授权机制,专门用于对
kubelet
发出的 API 请求做授权验证. - Webhook:使用外部的 Server 通过 API 进行授权校验,需要在启动时候增加
--authorization-webhook-config-file=SOME_FILENAME
以及--authorization-mode=Webhook
- AlwaysAllow:默认配置,允许全部.
- AlwaysDeny:通常用于测试,禁止全部.
Role
-
K8S 中的角色从类别上主要有两类,
Role
和ClusterRole
.Role
:可以当作是一组权限的集合,但被限制在某个Namespace
内(K8S 的Namespace
).ClusterRole
:对于集群级别的资源是不被Namespace
所限制的,并且还有一些非资源类的请求,所以便产生了它.
-
当已经了解到角色后,剩下给用户授权也就只是需要做一次绑定即可.在 K8S 中将这一过程称之为
binding
,即rolebinding
和clusterrolebinding
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31# kubectl get roles --all-namespaces=true
NAMESPACE NAME CREATED AT
kube-public kubeadm:bootstrap-signer-clusterinfo 2023-09-27T09:48:45Z
kube-public system:controller:bootstrap-signer 2023-09-27T09:48:44Z
kube-system extension-apiserver-authentication-reader 2023-09-27T09:48:44Z
kube-system kube-proxy 2023-09-27T09:48:46Z
kube-system kubeadm:kubelet-config 2023-09-27T09:48:44Z
kube-system kubeadm:nodes-kubeadm-config 2023-09-27T09:48:44Z
kube-system system::leader-locking-kube-controller-manager 2023-09-27T09:48:44Z
kube-system system::leader-locking-kube-scheduler 2023-09-27T09:48:44Z
kube-system system:controller:bootstrap-signer 2023-09-27T09:48:44Z
kube-system system:controller:cloud-provider 2023-09-27T09:48:44Z
kube-system system:controller:token-cleaner 2023-09-27T09:48:44Z
kube-system system:persistent-volume-provisioner 2023-09-27T09:48:47Z
kubernetes-dashboard kubernetes-dashboard 2023-10-08T08:58:01Z
# kubectl get rolebindings --all-namespaces=true
NAMESPACE NAME ROLE AGE
kube-public kubeadm:bootstrap-signer-clusterinfo Role/kubeadm:bootstrap-signer-clusterinfo 25d
kube-public system:controller:bootstrap-signer Role/system:controller:bootstrap-signer 25d
kube-system kube-proxy Role/kube-proxy 25d
kube-system kubeadm:kubelet-config Role/kubeadm:kubelet-config 25d
kube-system kubeadm:nodes-kubeadm-config Role/kubeadm:nodes-kubeadm-config 25d
kube-system system::extension-apiserver-authentication-reader Role/extension-apiserver-authentication-reader 25d
kube-system system::leader-locking-kube-controller-manager Role/system::leader-locking-kube-controller-manager 25d
kube-system system::leader-locking-kube-scheduler Role/system::leader-locking-kube-scheduler 25d
kube-system system:controller:bootstrap-signer Role/system:controller:bootstrap-signer 25d
kube-system system:controller:cloud-provider Role/system:controller:cloud-provider 25d
kube-system system:controller:token-cleaner Role/system:controller:token-cleaner 25d
kube-system system:persistent-volume-provisioner Role/system:persistent-volume-provisioner 25d
kubernetes-dashboard kubernetes-dashboard Role/kubernetes-dashboard 14d