Kubernetes 入门
文章目录
- Kubernetes 入门
- 一、Kubernetes 环境部署
- 1. 环境准备
- 2. 测试部署 Nginx
- 3. 在任意节点使用 kubectl
- 二、深入 pod
- 1. 使用配置文件部署引用
- 2. 探针
- 三、资源调度
- 1.标签与选择器
- 2.Deployment
- 3.StatefulSet
- 4.DaemonSet
- 5.HPA
- 6. Service
- 7. Ingress
- 8. 配置管理
- 1. ConfigMap
- 2. SubPath
- 3. 配置的热更新
- 9. 存储管理
- 1. Volumes
- 10. NFS
- 11. PC 与 PVC
- 12. 存储类 StorageClass
- 13. Provisioner
- 四、高级调度
- 1. CornJob 计划任务
- 2. 初始化容器(InitContainer)
- 3. 污点与容忍
- 4. 亲和力(Affinity)
- 5. 认证与鉴权 (偏运维)
一、Kubernetes 环境部署
k8s 官方文档
1. 环境准备
虚拟机三台:
虚拟机名称 | 软件 |
---|---|
k8s-master(主机) | docker、kubeadm、kubelet、kubectl |
k8s-node1(从机) | docker、kubeadm、kubelet、kubectl |
k8s-node2 (从机) | docker、kubeadm、kubelet、kubectl |
kubeadm:是一个命令行工具,用于在Kubernetes集群中初始化和管理Master节点。它可以自动化许多手动设置步骤,使得集群的部署更加简单和快速。
kubelet:是Kubernetes集群中的一个重要组件,它运行在每个节点上,负责管理容器的生命周期。kubelet会监控Pod的状态,并确保Pod中的容器始终处于运行状态。
kubectl:是Kubernetes的命令行工具,用于与Kubernetes API进行交互。它可以用来创建、删除、管理Pod、Deployment、Service等Kubernetes资源,并获取集群的状态信息。kubectl是Kubernetes的主要管理工具之一,可以帮助管理员更好地管理和维护Kubernetes集群。
-
docker 安装参考此处
-
k8s集群安装方式,这里选择 kubeadm
-
iptable设置:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sudo sysctl --system
-
配置国内源,这里选择的阿里云
cat > /etc/yum.repos.d/kubernetes.repo <<EOF [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF
-
安装 kubeadm kubectl kubelet (可以指定版本)
yum -y install kubeadm-1.23.6 kubectl-1.23.6 kubelet-1.23.6
-
-
主节点:k8s-master 初始化:
[root@localhost ~]# kubeadm init \ --apiserver-advertise-address=192.168.10.136 \ --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version v1.23.6 \ --service-cidr=10.96.0.0/12 \ --pod-network-cidr=10.244.0.0/16
-
如果出现版本错误的问题,可以进行对应版本的卸载,命令如下:
yum remove -y kubelet-1.24.9 kubeadm-1.24.9 kubectl-1.24.9
-
如果出现如下错误,执行 kubeadm reset。
-
初始化后可以查看kubelet 启动状态,这里是启动失败了:systemctl status kubelet
-
然后可以查看详细错误信息:journalctl -xefu kubelet
-
如果初始化报如下错误:将 swap 关闭即可(关闭后记得重启kubelet,systemctl restart kubelet)。可通过命令 swapoff -a 退出。或者修改配置进行固话。vim /etc/fstab
-
如果报 cgroupfs错误:需要修改 docker 的 cgroup driver。
-
通过命令 vim /etc/docker/daemon.json 进行修改,添加如下配置
-
然后执行命令 systemctl daemon-reload 使之生效,在重启docker(systemctl restart docker),然后在查看docker 信息,发现驱动已被改:
-
然后在重启 kubelet (systemctl restart kubelet)
-
如果报未认证的信息,是因为集群还未部署,没有可用用户。我们进行重新设置,先执行 kubeadm reset,在进行初始化(参考前面的初始化操作kubeadm init…),发现启动成功了!
-
-
启动 kubelet
systemctl enable kubelet.service
-
到这里我们的master配置完成,可以查看集群节点信息,这时候应该只有一个主节点信息:
- 这里查看节点信息如下报错:
- 可执行如下命令解决:参考文章地址
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
- 可执行如下命令解决:参考文章地址
- 如果你想修改节点信息,如果你当前在master节点上,只有你一个主节点,你可直接清空所有集群配置(kubeadm reset),在修改主机名称:hostnamectl set-hostname k8s-master,在执行 su root 命令。记住还需手动清除文件在执行上面的命令,mkdir -p $HOME/.kube … ,因为你清空了集群信息,但是这个文件下的信息并没有清除,需要手动清除(rm -rf $HOME/.kube),不然会报错(参考文章),报错信息如下:到这里便可以了。
- 如果你想修改从节点的名称,参考此文章
- 这里查看节点信息如下报错:
-
接下来配置从节点信息,并加入到集群中。
- 安装 docker、docker、kubeadm、kubelet、kubectl 和主节点一样,记得修改从节点的hostname。
- 查看master主机token,做认证用:kubeadm token list
- 获取主机master主机hash值:openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^. //'’
-
使用这个token 和 hash值将从机加入到mater主机上,在从机上执行命令:kubeadm join [主机ip地址:6443] --token [主机token] --discovery-token-ca-cert-hash sha256:[主机hash值]
- 如果出现如下错误:执行 kubeadm reset 命令,在加入即可。
- 如果出现如下错误:执行 kubeadm reset 命令,在加入即可。
-
加入成功后:
-
这里都还是notReady 状态,我们查看所有的pods信息:
kubectl get pods -n kube-system // 用于获取Kubernetes集群中kube-system命名空间中的所有Pod的详细信息。 //kubectl是Kubernetes的命令行工具,用于管理Kubernetes集群中的资源。 //Pod是Kubernetes的最小部署单元,可以包含一个或多个容器,并共享相同的网络 //命名空间和存储卷。kube-system命名空间是Kubernetes中的一个特殊命名空间, //用于存储系统级别的资源,如kube-dns、kube-proxy等。
- 接下来进行网络的配置:
- 下载配置文件,我们在 /opt文件夹下创建k8s文件夹用来存放我们下载的文件,在该文件夹下执行:curl https://docs.projectcalico.org/manifests/calico.yaml -O
- 这里下载的文件如果出现文件内容只有内容:Redirecting to https://docs.tigera.io/calico/latest/manifests/calico.yaml,则是文件路径发生变化了,需要根据别的路径进行下来:此处可查看最新命令,我这里执行的命令式:curl https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/custom-resources.yaml -O
- 这里下载 calico.yaml 文件一定要注意版本问题。需查询 calico版本 与 k8s版本的对应关系
- 修改该配置文件信息,找到 CALICO_IPV4POOL_CIDR 进行修改value值,信息为我们前面执行 kubeadm init 中的 –pod-network-didr 的值:
-
删除镜像 docker.io/前缀,避免下载过慢导致失败:sed -i ‘s#docker.io/##g’ calico.yaml
-
查看需要下载的镜像:grep image calico.yaml
-
镜像进行逐个下载。
-
一个 不进行下载,直接通过命令:kubectl apply -f calico.yaml 直接进行构建。
-
可查看其对应的信息:kubectl get po -n kube-system
-
查看 calico-kube-controllers-779998bd5-hpwxt 的信息:kubectl describe po calico-kube-controllers-779998bd5-hpwxt -n kube-system
-
这时候我们在查看节点信息,发现都已经准备好了,如果出现未准备好的,可能是镜像为未载好:
-
缺失的进行可直接进行 docker pull 进行下载:
其他命令补充:
-
查看 kubelet 版本:
kubelet --version
-
清除 yum 仓库:
yum makecache
- 用于在yum软件包管理器中重新生成本地软件包缓存。该命令会从yum配置文件中指定的远程软件包仓库中下载最新的软件包列表,并将其存储在本地缓存中,以便在后续的软件包安装、更新或卸载操作中使用。重新生成本地软件包缓存可以确保yum管理器使用最新的软件包列表,并能够更快地查找和安装软件包。
-
清空所有缓存:
yum clean all
-
查看节点健康状态:
kubectl get componentstatus
-
token 过期则可以新建token:kubeadm token create --print-join-command 默认有效期24小时,若想久一些可以结合–ttl参数,设为0则永不过期。
2. 测试部署 Nginx
-
部署nginx:kubectl create deployment nginx --image=nginx
-
暴露端口:kubectl expose deployment nginx --port=80 --type=NodePort
-
查看暴露的端口信息:kubectl get pod,svc
-
测试访问 nginx:curl 192.168.10.136:31810
3. 在任意节点使用 kubectl
- 目前我们只能够在主节点使用 kubectl 相关命令,比如我在从节点是用 kubctl get nodes:
- 发现不能访问,这是用为只有我们的主节点才有 api-server 服务,而我们的从节点必须要去主节点去调用该服务,所以需要配置该信息。
-
将 master 节点中 /etc/kubernetes/admin.conf 拷贝到需要运行的服务器的 /etc/kubernetes 目录中,执行命令:scp /etc/kubernetes/admin.conf root@k8s-node1:/etc/kubernetes如果没有配置主机名称,k8s-node1 需要换成ip地址。如果需要验证输入密码验证,根据提示输入即可。
-
在从机上配置环境变量:echo “export KUBECONFIG=/etc/kubernetes/admin.conf” >> ~/.bash_profile
-
是配置生效:source ~/.bash_profile
-
测试发现可以访问了。
-
-
二、深入 pod
-
获取所有正在运行的 pod :kubectl get pods
- Pod是Kubernetes中的最小可调度和管理的单元,它是一个或多个容器的集合,共享同一个网络命名空间、存储和其他资源。
- Pod是Kubernetes中的最小可调度和管理的单元,它是一个或多个容器的集合,共享同一个网络命名空间、存储和其他资源。
-
获取当前集群中所有部署(Deployment)的信息:kubectl get deploy
- Deployment是一种资源对象,用于定义和管理Pod的创建和更新。通过Deployment,您可以指定要运行的Pod副本数量、容器镜像、端口映射等信息,并且可以轻松地进行滚动更新和回滚。
- Deployment是一种资源对象,用于定义和管理Pod的创建和更新。通过Deployment,您可以指定要运行的Pod副本数量、容器镜像、端口映射等信息,并且可以轻松地进行滚动更新和回滚。
-
用于删除指定的部署(Deployment),可以通过指定部署的名称来删除该部署及其相关的Pod和其他相关资源,比如删除 nginx 的 deployment :kubctl delete deploy nginx
-
于获取当前集群中所有服务(Service)的信息:kubectl get service
-
删除指定的服务(service):kubectl delete svc nginx
1. 使用配置文件部署引用
-
创建 yml 文件:touch nginx-demo.yaml
-
K8S 的资源清单
参数名 类型 字段说明 apiVersion String K8S APl 的版本,可以用 kubectl api versions 命令查询 kind String yam 文件定义的资源类型和角色 metadata Object 元数据对象,下面是它的属性 metadata.name String 元数据对象的名字,比如 pod 的名字 metadata.namespace String 元数据对象的命名空间 Spec Object 详细定义对象 spec.containers[] list 定义 Spec 对象的容器列表 spec.containers[].name String 为列表中的某个容器定义名称 spec.containers[].image String 为列表中的某个容器定义需要的镜像名称 spec.containers[].imagePullPolicy string 定义镜像拉取策略,有 Always、Never、IfNotPresent 三个值可选
- Always(默认):意思是每次都尝试重新拉取镜像
- Never:表示仅适用本地镜像
- IfNotPresent:如果本地有镜像就使用本地镜像,没有就拉取在线镜像。spec.containers[].command[] list 指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令。 spec.containers[].args[] list 指定容器启动命令参数,因为是数组可以指定多个。 spec.containers[].workingDir string 指定容器的工作目录 spec.containers[].volumeMounts[] list 指定容器内部的存储卷配置 spec.containers[].volumeMounts[].name string 指定可以被容器挂载的存储卷的名称 spec.containers[].volumeMounts[].mountPath string 指定可以被容器挂载的存储卷的路径 spec.containers[].volumeMounts[].readOnly string 设置存储卷路径的读写模式,ture 或者 false,默认是读写模式 spec.containers[].ports[] list 指定容器需要用到的端口列表 spec.containers[].ports[].name string 指定端口的名称 spec.containers[].ports[].containerPort string 指定容器需要监听的端口号 spec.containers[].ports[].hostPort string 指定容器所在主机需要监听的端口号,默认跟上面 containerPort 相同,注意设置了 hostPort 同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,这样会冲突) spec.containers[].ports[].protocol string 指定端口协议,支持 TCP 和 UDP,默认值为 TCP spec.containers[].env[] list 指定容器运行前需设置的环境变量列表 spec.containers[].env[].name string 指定环境变量名称 spec.containers[].env[].value string 指定环境变量值 spec.containers[].resources Object 指定资源限制和资源请求的值(这里开始就是设置容器的资源上限) spec.containers[].resources.limits Object 指定设置容器运行时资源的运行上限 spec.containers[].resources.limits.cpu string 指定 CPU 的限制,单位为 Core 数,将用于 docker run –cpu-shares 参数 spec.containers[].resources.limits.memory string 指定 mem 内存的限制,单位为 MIB、GiB spec.containers[].resources.requests Object 指定容器启动和调度时的限制设置 spec.containers[].resources.requests.cpu string CPU请求,单位为core数,容器启动时初始化可用数量 spec.containers[].resources.requests.memory string 内存请求,单位为MIB、GiB,容器启动的初始化可用数量 spec.restartPolicy string 定义 pod 的重启策略,可选值为 Always、OnFailure、Never,默认值为 Always。
- Always:pod 一旦终止运行,则无论容器是如何终止的,kubelet 服务都将重启它。
- OnFailure:只有 pod 以非零退出码终止时,kubelet 才会重启该容器。如果容器正常结束(退出码为0),则 kubectl 将不会重启它。
- Never:Pod 终止后,kubelet 将退出码报告给 master,不会重启该 podspec.nodeSelector Object 定义 Node 的 label 过滤标签,以 key:value 格式指定 spec.imagePullSecrets Object 定义 pull 镜像时使用 secret 名称,以 name:secretkey 格式指定 spec.hostNetwork Boolean 定义是否使用主机网络模式,默认值为 false。设置 true 表示使用宿主机网络,不使用 docker 网桥,同时设置了 true将无法在同一台宿主机上启动第二个副本 -
实战:
apiVersion: v1 # api 文档版本 kind: Pod # 资源对象类型,也可以配置为像Deployment、StatefulSet这一类的对象 metadata: # Pod 相关的元数据,用于描述 Pod 的数据 name: nginx-demo # Pod 的名称 labels: # 定义 Pod 的标签 type: app # 自定义 label 标签,名字为 type,值为 app test: 1.0.0 # 自定义 label 标签,描述 Pod 版本号 namespace: 'default' # 命名空间的配置 spec: # 期望 Pod 按照这里面的描述进行创建 containers: # 对于 Pod 中的容器描述 - name: nginx # 容器的名称 image: nginx:1.7.9 # 指定容器的镜像 imagePullPolicy: IfNotPresent # 镜像拉取策略,指定如果本地有就用本地的,如果没有就拉取远程的 command: # 指定容器启动时执行的命令 - nginx - -g - 'daemon off;' # nginx -g 'daemon off;' workingDir: /usr/share/nginx/html # 定义容器启动后的工作目录 ports: - name: http # 端口名称 containerPort: 80 # 描述容器内要暴露什么端口 protocol: TCP # 描述该端口是基于哪种协议通信的 env: # 环境变量 - name: JVM_OPTS # 环境变量名称 value: '-Xms128m -Xmx128m' # 环境变量的值 resources: requests: # 最少需要多少资源 cpu: 100m # 限制 cpu 最少使用 0.1 个核心 memory: 128Mi # 限制内存最少使用 128兆 limits: # 最多可以用多少资源 cpu: 200m # 限制 cpu 最多使用 0.2 个核心 memory: 256Mi # 限制 最多使用 256兆 restartPolicy: OnFailure # 重启策略,只有失败的情况才会重启
-
创建 pod:kubectl create -f nginx-demo.yaml
-
查看对应 pod 发现正在创建了:kubectl get pod:
-
这时候我们也可以查看对应日志信息: kubectl describe po nginx-demo
2. 探针
-
探针:容器内应用的监测机制,根据不同的探针来判断容器应用当前的状态。
-
探针的类型:
-
startupProbe:会先禁用其他探针,直到 startupProbe 成功后,其他探针才会继续。由于有时候不能准确预估应用一定是多长时间启动成功,因此配置另外两种方式不方便配置初始化时长来检测,而配置了 startupProbe 后,只有在应用启动成功了,才会执行另外两种探针,可以更加方便的结合使用另外两种探针使用。
- 配置信息:
startupProbe: httpGet: path: /api/startup port: 80
- 应用:由于没有接口:/api/path,所有启动会失败,报404。
- 我们也可以请求已存在的文件,则请求成功,比如:
- 配置信息:
-
LivenessProbe:用于探测容器中应用是否运行,如果探测失败,kubelet 会根据配置的重启策略进行重启,若没有配置,默认就认为容器启动成功,不会执行重启策略。
-
配置信息:
livenessProbe: failureThreshold: 5 httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 periodSeconds: 10
-
应用:当服务启动后,即 startupProbe 探针完成后,会使用该探针,如下例子,我们检查改文件不存在时,则进行重启。
-
-
ReadinessProbe:用于探测容器内的程序是否健康,它的返回值如果返回success,name就认为该容器已经完全启动,并且该容器可以接收外部流量。
-
配置信息:
readinessProbe: failureThreshold: 3 # 错误次数 httpGet: path: /ready port: 8181 scheme: HTTP periodSeconds: 10 # 间隔时间 successThreshold: 1 timeoutSeconds: 1
-
控制服务的访问,即当前探针成功后,才会进行服务的提供。
-
-
-
探针的方式:
-
ExecAction:可以指定执行什么命令,非常灵活。
- 应用:即启动成功后执行该命令。
- 可查看对应的文件是否打印了 success:
- 应用:即启动成功后执行该命令。
-
TCPSocketAction
- 应用:当前例子的pod感觉最适合的一种方式,意思是说我们的nginx提供服务的端口80可以访问了,则认为服务启动成功了。
- 应用:当前例子的pod感觉最适合的一种方式,意思是说我们的nginx提供服务的端口80可以访问了,则认为服务启动成功了。
-
HTTPGetAction (应用可看前面)
-
-
探针的生命周期:
- 创建(Creation):
- 用户或控制器创建一个Pod的定义,其中包含了容器的相关信息,如镜像、环境变量、资源需求等。
- 用户通过API服务器或调用命令行工具(如kubectl)来提交Pod的定义。
- 用户通过API服务器或调用命令行工具(如kubectl)来提交Pod的定义。
- 调度(Scheduling):
- 调度器(Scheduler)从集群中选择最合适的节点来部署Pod。
- 调度器会根据Pod的资源需求和约束,如节点上的资源可用性、亲和性和反亲和性规则等,选择一个合适的节点。
- 创建一个Pod的绑定(Binding)即将Pod与节点绑定,使其被调度到该节点。
- 启动(Initialization):
- 调度完成后,Kubernetes会通知相关节点上的kubelet进程以启动容器。
- 调度完成后,Kubernetes会通知相关节点上的kubelet进程以启动容器。
- 运行(Running):
- Kubernetes监控容器的运行状态,一旦容器进入Running状态,Kubernetes认为Pod已成功启动。
- 这时,容器可以通过网络访问和相互通信。
- 终止(Termination):
- Pod会在不同的情况下终止,如用户手动删除、控制器删除、故障、资源不足等。
- 当Pod终止时,Kubernetes将自动清理相关的资源,如容器、网络和存储卷。
- 在终止之前,可以通过预停止(PreStop)钩子执行指定的操作,如保存状态、发送信号等。
- 重新调度(Rescheduling):
- 如果Pod所在的节点不再可用,Kubernetes会重新调度该Pod到其他节点,保证高可用和服务的继续运行。
- Pod的重新调度将重新经历调度、初始化、运行等阶段,并在新的节点上启动对应容器。
- 弹性扩展(Scaling):
- Pod可以根据需求进行弹性扩展,即增加或减少Pod的副本数。
- 通过控制器(如Deployment或ReplicaSet)的配置,可以实现自动扩展和自动缩放的功能。
- 创建(Creation):
-
测试 postStart 和 preStop。需要注意 terminationGracePeriodSeconds(默认30s):即关闭pod前给的宽限时间,最多该时间后即关闭pod,所以我们设置 preStop 中需要执行的任务时,所设置的时间要小于 terminationGracePeriodSeconds 的时间,防止还未执行完就关闭了。
三、资源调度
1.标签与选择器
-
label(标签)
- Label是一组键值对(Key-Value)的元数据,用于给Kubernetes中的资源对象打上标记。
- 通过为资源对象打上Label,可以在逻辑上对它们进行分类、归类或打上特定的标记。
- 相关命令:
- 查看 pod 的label:
- kubectl get po --show-labels
- kubectl get po --show-labels
- 给指定 pod 添加 label:
- kubectl label po [pod 名称] [label名-lable值]
- kubectl label po [pod 名称] [label名-lable值]
- 给指定 pod 修改 label
- kubectl label po [pod名称] [label名-label新值] --overwrite
- kubectl label po [pod名称] [label名-label新值] --overwrite
- 查看 pod 的label:
- 注:以上修改只是零时的,如果我们修改了pod的上层结构 deployment,则这些我们添加的零时label就会丢失。如果我们想永久生效,则需要在对应的pod的配置文件中去添加,执行:kubectl edit po [pod名称]
-
Selector(选择器)
- Selector是用于根据Label筛选资源对象的机制。
- Selector基于Label进行匹配,可以根据键值对来选择特定的资源对象。
- Selector可以用于Kubernetes资源的各种操作,如查询、筛选、关联、删除等。
- Kubernetes提供了几种类型的Selector:Equality Selector、Set Selector和Match Expression。
- Equality Selector使用"=“、”==“、”!="等操作符来匹配键值对。
- Set Selector使用"in"、“notin”、“exists”、"notexists"等操作符来匹配一组键值对。
- Match Expression使用更复杂的逻辑和条件来匹配Label,支持AND、OR和NOT操作。
- 相关命令:
- 根据 label 查找 pod,单值匹配,类似 sql 中的 =,命令为:kubectl get po -l [要查询的label名=要查询的label值]
- 根据 label 查找 pod,多值匹配,类似 sql 中的 in,命令为:kubectl get po -l ‘要查询的label名 in (要查询的label值1,要查询的label值2)’
- 多条件 & 查询:多个条件之间用,隔开
- 根据 label 查找 pod,单值匹配,类似 sql 中的 =,命令为:kubectl get po -l [要查询的label名=要查询的label值]
-
通过使用Label和Selector,可以实现以下功能:
- 根据Label对资源对象进行分类、管理和部署。
- 通过Label Selector来选择特定的资源对象进行操作。
- 在Pod之间建立关联关系,如Service通过Label Selector选择对应的Pod进行负载均衡。
- 控制器(如Deployment、ReplicaSet)使用Selector来管理一组具有相同Label的Pod。
- 通过在资源对象上定义Label和Selector,可以为Kubernetes提供更强大的管理和操作能力。
2.Deployment
-
创建一个 deployment:kubectl create deploy [deployName] --image=[镜像名称]
-
获取我们创建的 deployment:kubectl get deployments 或 kubectl get deploy
-
deploy、replicaSet、pod 之前的关系:
- deploy 中嵌套了 replicaSet,replicaset 中嵌套了 pod。
- deploy 中嵌套了 replicaSet,replicaset 中嵌套了 pod。
-
获取指定deploy的配置信息,以 yaml 文件的形式输出出来:kubctl get deploy [deploy名称] -o yaml
-
编写自己的 deploy:nginx-deploy.yaml
-
我们可以通过新创建的yaml文件进行创建 deploy :kubectl create -f xxx.yaml --record
- –record 会在 annotation 中记录当前命令创建或升级了资源,后续可以查看做过哪些变动操作。
-
滚动更新:
-
只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作。
-
目前默认副本数为1,我们改为三个:会创建三个pod,那么滚动更新就是这三个pod一个一个的更新。
-
除了在配置文件中修改 template 中的值,我们还可以通过命令修改里面的值从而触发滚动更新:
- 修改 nginx 版本号:kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
- 或者通过我们前面说的修改配置文件来修改: kubectl edit deployment/nginx-deployment
- UP-TO-DATE 表示已经有多少副本达到了配置中要求的数目。
-
查看滚动更新的过程:kubectl rollout status deploy <deployment_name>
-
滚动更新过程(图解):1. RS1 中包含两个 pod,RS2 中包含0个pod。2. 将 RS1 中的第一个pod 更新到 RS2中,RS1 中对应的该 pod 删除 3. 同理对 RS1 其他的pod进行相同操作,知道 RS1 中的所有pod更新到 RS2。(红色表示已经删除的pod)
-
多个滚动更新并行:假设当前有 5 个 nginx:1.7.9 版本,你想将版本更新为 1.9.1,当更新成功第三个以后,你马上又将期望更新的版本改为 1.9.2,那么此时会立马删除之前的三个,停止对更新为1.9.1 的任务,并且立马开启更新 1.9.2 的任务。
-
-
回滚:有时候你可能想回退一个Deployment,例如,当Deployment不稳定时,比如一直crash looping。默认情况下,kubernetes会在系统中保存前两次的Deployment的rollout历史记录,以便你可以随时会退(你可以修改revision history limit来更改保存的revision数)。
-
案例:更新 deployment 时参数不小心写错,如 nginx:1.9.1 写成了 nginx:1.91:kubectl set image deployment/nginx-deploy nginx=nginx:1.91监控滚动升级状态,由于镜像名称错误,下载镜像失败,因此更新过程会卡住。kubectl rollout status deployments nginx-deploy
-
结束监听后,获取 rs 信息,我们可以看到新增的 rs 副本数是 2 个 kubectl get rs。通过 kubectl get pods 获取 pods 信息,我们可以看到关联到新的 rs 的 pod,状态处于 ImagePullBackOff 状态。
-
为了修复这个问题,我们需要找到需要回退的 revision 进行回退通过 kubectl rollout history deployment/nginx-deploy 可以获取 revison 的列表。
-
-
扩容和缩容:
-
扩容:我们可以修改 deploy 的配置文件,修改 replicas 的值进行扩容,也可以通过命令:kubectl scale --replicas=[扩容后的数量] deploy [deployName]
-
由于我们的模板 template 是没有改变的,所以我们的rs也不会改变。只是对应的pod数量改变了。
-
缩容同理,只是数量设置小点的。
-
-
暂停与恢复:
-
由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout,通过 kubectl rollout pause deployment 就可以实现暂停,直到你下次恢复后才会继续进行滚动更新。暂停期间修改 template 中的信息是不会发生更新的,即不会怎家rs。
-
可以通过命令:kubectl rollout resume deploy [deploy名称] 来进行恢复,即继续进行更新操作,rs 也会增加。
-
我们也可以查看每个版本所改动的内容。 kubectl rollout history deploy [deployName] – revision=[版本号]
-
3.StatefulSet
-
我们希望实现pod更新后,里面的数据还是持久化保存的,以及能够使用域名访问,利用 DNS。
-
编写配置文件:
-
在创建服务之前,我们可以发现只有 k8s 服务,以及sts 为空:
-
创建服务:kubectl create -f web.yaml
-
在来查看 svc 和 sts,发现增加了我们创建的服务。
-
如果我们的配置文件修改了,并且已经创建了服务,则可以进行文件替换。kubectl replace sts [sts服务名称] -f [新配置文件名称]
-
我们发现pod服务有对应的两个,但是无法通过域名 web-0 或 web-1 进行访问。
-
启动 dns 服务:
-
dns 域名服务会帮助我们堆域名与服务地址进行映射,从而直接访问域名就能够获得服务。
-
扩容: kubectl scale statefulset web --replicas=5 或者传入json字符串 kubectl scale statefulset web —p ‘{“spec”:{“replicas”:5}}’
-
缩容:kubectl patch statefulset web --replicas=3 或者传入json字符串 kubectl patch statefulset web -p ‘{“spec”:{“replicas”:3}}’
-
镜像更新:(目前还不支持直接更新 image,需要 patch 来间接实现)(目前还不支持直接更新 image,需要 patch 来间接实现)。kubectl patch sts web --type=‘json’ -p=‘[{“op”: “replace”, “path”: “/spec/template/spec/containers/0/image”, “value”:“nginx:1.9.1”}]’
-
RollingUpdate:StatefulSet 也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的。
- 编辑 sts 的web。发现使用的就是滚动更新。
- 编辑 sts 的web。发现使用的就是滚动更新。
-
OnDelete:只有在 pod 被删除时会进行更新操作。将sts web 配置修改如下,则只会在pod被删除后才会发生更新,即便再去修改 template 里的信息,也不会发生更新的操作。比如现在的nginx版本为1.7,将版本修改为1.9退出后发现我们的pod中的nginx 并没有更新,还是1.7版本,如果我们将pod-4删除了,发现该pod又会被创建,使用的就是我们修改后最新的配置文件,即nginx 版本为1.9。那么其他的pod其实还是没有更新的,还是1.7。
-
-
灰度发布/金丝雀发布:我们先只更新少量的服务器,等测试没问题后我们才逐步对剩下的服务器进行滚动更新。即可以分很多次逐渐更新完所有服务器,并不是说只是分两次更新。
-
利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果。
-
例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod。
-
利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新。
-
将 partition 的值更新为3,表示我们在更新pod时,>=3 的pod才会更新。
-
我们发现修改了partition的信息后,在修改配置文件 nginx 容器的版本号后,只有 web-3 和 web-4 的pod发生了更新。如果我们测试没问题的话,继续更新后面的pod,可以在将 partition 的值进行修改。
-
-
级联删除:删除 statefulset 时会同时删除 pods 。kubectl delete statefulset web
-
非级联删除:删除 statefulset 时不会删除 pods,删除 sts 后,pods 就没人管了,此时再删除 pod 不会重建的
kubectl deelte sts web --cascade=false。
4.DaemonSet
-
案例:
- 假设我们下载有三个 Node ,我们在上面分别部署 商品服务,营销服务,用户服务等等。这时候我们有这样的场景:Node1 上的商品服务去调用Node2上的用户服务,用户服务去调用 Node3上的订单服务,而订单服务有需要掉用仓库服务,如果这个流程中出现错误了,我们排查到底是哪个环节出错了就需要到不同的Node上去查看对应的日志,这非常的麻烦。
- 现在我们可以通过创建Node4,将所有的日志发送到该节点的饿 es 上进行存储,这样我们查询日志的时候只需要到该节点查看即可。我们可以通过每一个Node上部署一个Funentd 的pod,它可以帮我们收集当前Node上的日志,但是每一个Node上都需要去部署这样的 fluntd 的pod,这也很麻烦。
- 我们可以创建 daemonset 守护经常,它可以帮我们自当往 nodeSelector 指定的符合条件的Node上去添加 我们的Fluentd 的pod,即便我们后面新增了Node,只要该Node满足 NodeSelector 筛选的条件,也会自动添加上 fluntd 的pod。这非常的方便。
-
编写配置文件:没有添加选择器,Selector,默认配置到所有从节点中。
-
加上 selector ,去匹配所有 type:micorservices。
-
发现只有一个能匹配上
-
这时候我们在给 node2 添加上这个 type,发现立刻会给node2也配置一个 fluentd 的pod。
-
同样的也支持滚动更新,也默认就是滚动更新,建议使用Ondelete,因为这样可以避免修改一次,所有的node上都发生更新,而是根据需求,去对应的node上去删除对应的pod(比如这里是fluentd),从而触发更新。
5.HPA
- 实现自动扩/缩容,开启指标服务:
- 下载 metrics-server 组件配置文件:wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
- 修改镜像地址为国内的地址:sed -i ‘s/k8s.gcr.io/metrics-server/registry.cn-hangzhou.aliyuncs.com/google_containers/g’ metrics-server-components.yaml
- 修改容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加 --kubelet-insecure-tls 参数
- 安装组件 kubectl apply -f metrics-server-components.yaml
- 查看 pod 状态 kubectl get pods --all-namespaces | grep metrics
- cpu、内存指标监控:实现 cpu 或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpu 或 resources.requests.memory 才可以,可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容
- 创建一个 HPA:
- 先准备一个好一个有做资源限制的 deployment
- 执行命令 kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5
- 通过 kubectl get hpa 可以获取 HPA 信息
- 测试:
- 找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载 while true; do wget -q -O- http://ip:port > /dev/null ; done
- 可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看 pods 的扩容情况 kubectl get pods
- 查看 pods 资源使用情况 kubectl top pods
- 扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况
- 创建一个 HPA:
6. Service
- 网络访问过程图:
- svc 的配置信息:
-
查看 service 服务:kubectl get svc
-
查看 nginx 服务信息: kubectl describe svc nginx-svc
-
通过service name 进行访问:kubectl exec -it [svc名称] --sh 或者通过 curl https://[svc名称]
-
默认是在当前的 namespace 中访问,如果需要夸 namespace 访问 pod,则在 servicName 后面加上 .< namespace> 即可:curl http://nginx-svc.default
-
k8s 代理外部服务:需求,我们k8s内部进行服务部署的时候,希望可以将部署的应用统一访问 k8s 内部的代理服务,而有代理服务来访问我们的外部服务。这样我们访问的外部服务一单发生变化,不用去修改我们部署的每一个应用的配置(访问该外部服务的配置),而只需要修改我们统一访问的内部代理服务的配置即可。
-
-
编写 我们专门用来访问外部 service 的配置文件时,不指定 selector 属性。
-
创建 svc 服务: kubectl create -f nginx-svc -external.yaml
-
查看发现确实有了该服务:
-
并且发现没有自动创建我们的 endpoint 了:
-
我们需要手动创建 endpoint ,编写配置文件,注意 app 和 name 属性必须和我们的 svc 配置文件编写的一致!!
-
创建 endpoint :kubectl create -f nginx-ep-external.yaml
-
查看详细的代理信息:
-
测试:
-
-
前面我们是通过访问目的ip地址来进行访问的,我们也可以改成通过域名访问,修改 service 的配置文件即可:
-
service 的类型:
- ClusterIP:只能在集群内部使用,不配置类型的话默认就是 ClusterIP
- ExternalName:返回定义的 CNAME 别名,可以配置为域名
- NodePort:会在所有安装了 kube-proxy 的节点都绑定一个端口,此端口可以代理至对应的 Pod,集群外部可以使用任意节点 ip + NodePort 的端口号访问到集群中对应 Pod 中的服务。当类型设置为 NodePort 后,可以在 ports 配置中增加 nodePort 配置指定端口,需要在下方的端口范围内,如果不指定会随机指定端口.端口范围:30000~32767端口范围配置在 /usr/lib/systemd/system/kube-apiserver.service 文件中
- LoadBalancer:使用云服务商(阿里云、腾讯云等)提供的负载均衡器服务
7. Ingress
-
做外部服务的统一入口,有点类似Nginx。
-
和Nginx对比:Nginx 是 Ingress 的实现之一
-
安装 Nginx-Ingress
-
下载 helm:https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz,可以将helm 理解为Java中的Maven。
-
解压该文件:tar -zxvf [文件名]
-
将解压的 helm 拷贝到 /usr/local/bin 目录下即安装完成
-
查看helm 版本号:helm version
-
添加我们的 ingress 的仓库:helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
-
以及查看我们的仓库列表:helm repo list
-
我们就可以用这个仓库进行搜索了:helm search repo ingress-nginx
-
下载仓库里的包:helm pull ingress-nginx/ingress-nginx,下载后也需要进行解压
-
解压后的文件:
-
修改 values.yaml 中的镜像地址,
- 改成国内的。registry: registry.cn-hangzhou.aliyuncs.com
- image: google_containers/nginx-ingress-controller
-
增加 ingress=“true”
-
为 ingress 专门创建一个 namespace:kubectl create ns ingress-nginx
-
希望我们的 ingress 部署在 master 节点上:kubectl label node k8s-master ingress=true 其实就是怎家label,匹配我们的选择器 Selector 筛选规则。
-
安装 ingress-nginx :helm install ingress-nginx ./ingress-nginx -n ingress-nginx .
-
往node1添加也添加标签:ingress=true,因为k8s默认不在master上安装pod,还无法查看到到pod
-
发现开始创建pod了,名且是在我们刚刚添加标签的 node1上:
-
-
创建一个 ingress:
-
创建配置信息:
-
创建 ingress:
-
测试发现外部可以访问 Nginx 服务了:
-
-
多域名配置:
8. 配置管理
- 前面我们写的配置都是写在容器中的,是一种硬编码,那么这里的配置管理就可以解决这样的问题,k8s提供了两种方式:
- ConfigMap:非加密的
- Secret:加密的(默认是用的base64编码,但是可以进行加密配置)
1. ConfigMap
-
创建 ConfigMap:kubectl create configmap -h 或者使用缩写 kubectl create cm -h
-
查看配置:它会将该目录下的所有文件作为配置文件加载到配置中。
-
我们test目录下创建两个配置文件:dp.properties 和 redis.properties
-
创建配置文件:
-
我们也可以指定某个配置文件进行创建:
-
我们也可以创建的时候指定名称:
-
-
使用我们创建的 ConfigMap,比如我们在创建pod的配置文件时,可以引用之我们的ConfigMap
-
创建 pod ,然后查看pod的配置发现,ConfigMap 中的配置已经加载到 pod 配置中了。
-
-
配置文件不可变,只需要在 ConfigMap 中添加配置:immutable = true 即可
2. SubPath
-
是指在容器内将一个特定的卷或者只读卷(emptyDir、hostPath、persistentVolumeClaim)挂载到指定的路径的操作。subPath的作用是为容器中的某个路径提供一个卷的子路径,而不是将整个卷挂载到容器中。
-
使用subPath可以实现以下目的:
- 共享卷:多个容器可以在同一个Pod中共享卷,并将各自的数据挂载到不同的子路径上。
- 存储区分:将同一个卷挂载到不同的子路径上,可以提供给容器不同的存储区域,例如日志文件、配置文件等。
-
举个例子:
apiVersion: v1 kind: Pod metadata: name: subpath-example spec: containers: - name: my-container image: nginx volumeMounts: - name: my-volume mountPath: /data subPath: subdirectory volumes: - name: my-volume emptyDir: {}
- 在上述示例中,我们定义了一个Pod,其中包含一个名为my-container的容器。我们将一个名为my-volume的emptyDir卷挂载到了容器的路径/data/subdirectory。
- 这意味着在容器内部,/data/subdirectory路径是一个卷的子路径。任何在该容器中写入/data/subdirectory路径的操作都将在my-volume卷中创建文件或目录。而卷中的其他内容对容器是不可见的。
- 值得注意的是,如果在多个容器中使用相同的卷和subPath,每个容器会在指定的子路径下创建各自的文件和目录。
- 使用subPath可以提供更灵活的存储配置,将卷的不同部分挂载到容器的不同路径中。这样可以使容器的数据管理更加清晰和方便。
3. 配置的热更新
-
假设有一个应用程序需要从配置文件中读取数据库的连接信息。首先,在Kubernetes中创建一个名为database-config的ConfigMap,包含了数据库连接的相关配置:
apiVersion: v1 kind: ConfigMap metadata: name: database-config data: database-url: "jdbc:mysql://localhost:3306/mydb" database-username: "username" database-password: "password"
-
然后,在部署该应用程序的Pod的配置中,引用这个ConfigMap的数据:
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 1 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: my-app image: my-app-image ports: - containerPort: 8080 envFrom: - configMapRef: name: database-config
-
接下来,当需要更新数据库连接的配置时,只需修改database-config的ConfigMap:
apiVersion: v1 kind: ConfigMap metadata: name: database-config data: database-url: "jdbc:mysql://newhost:3306/mydb" database-username: "newusername" database-password: "newpassword"
-
Kubernetes会自动检测到ConfigMap的变化,并将最新的配置信息传递给应用程序所在的Pod。应用程序可以通过环境变量或挂载文件等方式读取最新的配置。
-
这样,不需要重启Pod或重新部署应用程序,就实现了配置的热更新。这个机制可以帮助用户在应用程序运行时灵活地调整配置,而不会中断服务。
9. 存储管理
1. Volumes
-
HostPath:将节点上的文件或目录挂载到 Pod 上,此时该目录会变成持久化存储目录,即使 Pod 被删除后重启,也可以重新加载到该目录,该目录下的文件不会丢失。
-
添加pod配置信息:两个文件加实现数据共享。
-
实现了主机与容器之间数据的共享。即主机的数据修改后容器可以获取到,容器的数据修改后,主机也可以获取到。
-
emptyDir:如果一个 pod 中有两个容器,为了这两个容器管理更加的方便。
- 是一种卷类型,用于在容器之间共享临时数据。emptyDir卷在容器创建时被创建,并且可以由同一个Pod中的多个容器共享。它提供了一个空目录,容器可以读写其中的文件。emptyDir卷的数据在Pod终止时会被清理,并且在Pod重新启动时重新创建。
-
emptyDir卷适用于以下情况:
- 在多个容器之间共享临时数据:当多个容器需要共享一些临时数据,而不需要持久化存储时,可以使用emptyDir卷。
- 用作临时工作目录:当需要一个临时目录来存储计算结果、临时文件等时,可以将emptyDir作为工作目录。
-
可以通过在Pod的配置文件中定义一个volume,然后将这个volume挂载到需要共享数据的容器中来使用emptyDir卷。以下是一个示例:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: container-a image: <image> volumeMounts: - name: shared-data mountPath: /data - name: container-b image: <image> volumeMounts: - name: shared-data mountPath: /data volumes: - name: shared-data emptyDir: {}
- 在上面的示例中,我们定义了一个名为shared-data的emptyDir卷,并将其挂载到两个容器container-a和container-b的/data目录下。这样,两个容器就可以通过这个共享目录来读写数据。
- 需要注意的是,emptyDir卷的生命周期绑定到Pod而不是单个容器。当Pod终止时,emptyDir卷中的数据将被永久删除。如果需要持久化存储数据,可以考虑使用其他类型的卷,如PersistentVolumeClaim(PVC)或者其他外部存储解决方案。
10. NFS
-
nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。
-
nfs安装:yum install nfs-utils -y
- 启动 nfs : systemctl start nfs-server
- 查看 nfs 版本: cat /proc/fs/nfsd/versions
- 创建共享目录:
- mkdir -p /data/nfs/rw/www/wolfcode
-
设置 pod nfs 配置信息:
-
启动pod后测试:发现可以访问到我们配置的路径下的信息
11. PC 与 PVC
-
层级关系图:
-
PV是一种集群中的资源,用于表示持久化存储的实际卷。它绑定到某个特定的存储设备,可以是物理存储设备(如磁盘)或云端存储服务(如AWS EBS、Azure Disk等)。PV是管理员定义和管理的资源,可以被多个Pod在其生命周期内共享。PV定义了存储容量、访问模式等属性。它是对具体存储策略的抽象与规范化。
-
PVC是用于申请和使用PV的资源对象。它是Pod对PV的一种请求,通过PVC,Pod可以声明所需的存储资源。PVC定义了所需的存储资源(如存储容量、访问模式)和其他约束条件。PVC通常由应用开发者创建和使用,它在逻辑上是与特定的应用或特定的命名空间关联的。
-
创建 PV 配置文件:
-
创建 pv :kubectl create -f xxx.yaml
-
获取 pv:kubectl get pv
- pv 的四种状态:
- Avaliable:空闲
- Bound:已经被 PVC 绑定
- Released:pvc 被删除,资源已回收,但是 pv 未被重新使用
- Failed:自动回收失败
- pv 的四种状态:
-
创建 pvc 配置文件:
-
创建 pvc:
-
过去 pvc :kubectl get pvc ,状态为已绑定了
-
这时候发现对应的 pv 也是已绑定的状态:
-
接下来是将 pod 与 pvc 进行绑定:
-
配制 pod 配置文件:
-
然后创建 pod 就可以了。
12. 存储类 StorageClass
-
StorageClass是用于动态创建PersistentVolume(PV)的对象。它定义了PV的属性,如存储提供者、存储类型、访问模式等,并提供了一种可扩展的方式来自动创建PV,以满足PersistentVolumeClaim(PVC)的需求。
-
一个StorageClass对象表示一种存储策略,可以与多个PVC关联。当创建一个PVC,并指定了对应的StorageClass,Kubernetes会根据StorageClass的定义,动态创建一个合适的PV。这种自动创建PV的机制可以减轻管理员的负担,并使存储的管理更加灵活和可扩展。
-
下面是一个使用StorageClass的示例:
-
首先,定义一个StorageClass,如下所示:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/aws-ebs parameters: type: gp2
-
然后,创建一个PVC,并指定使用上述的StorageClass,如下所示:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: storageClassName: fast accessModes: - ReadWriteOnce resources: requests: storage: 5Gi
-
在上述示例中,首先定义了一个StorageClass,使用AWS EBS作为存储提供者,指定了存储类型为gp2。
-
然后创建了一个PVC,使用了上述的StorageClass,并请求了5GB的存储容量。当创建PVC时,Kubernetes会检查是否存在与这个StorageClass匹配的PV,如果不存在,就会根据StorageClass的定义自动创建一个PV。
-
通过StorageClass,Kubernetes提供了一种动态创建PV的能力,让存储的管理更加灵活和可扩展。管理员可以根据不同的需求定义不同的StorageClass,并将其关联到PVC上,使得存储资源可以根据应用程序的需要进行动态调整和分配。这使得存储资源的使用更加高效,并提高了应用程序的可靠性和可伸缩性。
13. Provisioner
-
是一种用于动态创建PersistentVolume(PV)的插件。它负责与底层的存储提供者进行交互,并根据定义的存储类(StorageClass)的要求,动态地创建和管理PV。
-
一个常见的例子是使用AWS提供的Elastic Block Store(EBS)来作为存储提供者。在这种情况下,我们可以使用 kubernetes.io/aws-ebs Provisioner。
-
首先,我们需要定义一个StorageClass,它指定了要使用哪个Provisioner以及其他相关的属性。例如,我们可以创建一个名为 “ebs-sc” 的StorageClass:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ebs-sc provisioner: kubernetes.io/aws-ebs parameters: type: gp2 # EBS卷的类型
-
接下来,我们创建一个PersistentVolumeClaim(PVC),用于请求一个具体的存储资源。PVC指定了需要的存储容量和存储类,例如:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteOnce # 读写模式 resources: requests: storage: 1Gi # 请求的存储容量 storageClassName: ebs-sc # 使用的存储类
-
然后,当我们创建这个PVC时,kubernetes.io/aws-ebs Provisioner将会被触发。它将会根据StorageClass的定义,调用AWS的API,动态创建一个1GB的EBS存储卷,并为这个PVC提供所需的存储资源。 kubectl create -f my-pvc.yaml
-
一旦PVC创建成功,我们可以使用它来创建一个Pod,并将这个PVC作为一个卷挂载到容器中:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-app image: my-image volumeMounts: - name: data-volume mountPath: /data volumes: - name: data-volume persistentVolumeClaim: claimName: my-pvc
-
当Pod启动时,PVC将会被自动绑定到一个可用的PV,并将PV作为一个卷挂载到容器中的指定路径(/data)。这样,容器就可以使用持久化的存储了。
-
这个例子展示了如何使用Provisioner来动态创建和管理PV。通过定义合适的StorageClass,Kubernetes可以根据需要动态分配和回收存储资源,实现存储资源的动态管理和分配,提高了存储资源的利用率和系统的可靠性。不同的存储提供者可以使用不同的Provisioner来满足各种需求。
-
Provisioner和StorageClass是Kubernetes中存储管理的两个重要概念,它们之间有如下关系:
- Provisioner是一个用于动态创建PersistentVolume(PV)的插件,它与底层的存储提供者进行交互。Provisioner负责根据定义的StorageClass的要求,动态地创建和管理PV。
- StorageClass是用于定义存储的属性和行为的对象。它指定了要使用哪个Provisioner以及其他相关的属性。通过创建StorageClass,集群管理员可以为不同类型的存储提供不同的属性和参数。
- Provisioner和StorageClass的关系是一对多的关系。一个Provisioner可以对应多个StorageClass,但一个StorageClass只能指定一个Provisioner。
- 在PersistentVolumeClaim(PVC)中,可以指定使用的StorageClass。当创建PVC时,Kubernetes根据PVC中指定的StorageClass信息来选择对应的Provisioner进行PV的动态创建。这样,通过不同的StorageClass,可以根据需要选择不同类型的存储提供者。
- 总结来说,Provisioner是用于动态创建PV的插件,而StorageClass用于定义存储的属性和行为,包括选择哪个Provisioner。通过使用StorageClass,我们可以灵活地定义和管理集群中的存储资源,使其能够满足不同的需求和要求。
四、高级调度
1. CornJob 计划任务
-
CronJob是Kubernetes中的一种资源类型,用于在指定的时间间隔或者固定时间点执行任务。它基于类似于Linux下的cron表达式来设置任务的执行时机。CronJob允许我们在集群中自动地运行一个或多个容器化的任务,而无需手动执行或编写脚本。
-
CronJob的主要特性包括:
- 任务调度:可以设置任务在固定时间点执行(如每天的某个时间、每个星期中的某个时间等)或者在一定时间间隔内重复执行(如每隔5分钟、每隔2小时等)。
- 容错性:CronJob提供了一些可配置的选项,如任务超时时间、重试机制和失败策略,以确保任务的稳定执行。
- 任务历史:CronJob会记录任务的执行历史,包括成功与否、执行的时间等信息。可以通过kubectl命令或者API查询任务的执行情况。
-
创建CornJob 配置文件:
-
创建服务
-
获取 CornJob :kubectl get cj 或者 kubectl get cornjob
2. 初始化容器(InitContainer)
-
是Kubernetes中的一种容器类型,它与Pod中的其他容器(称为主容器)一起运行,但在主容器启动之前运行。InitContainer主要用于在主容器运行之前进行一些初始化任务,例如预加载数据、配置环境变量或者执行一些初始化脚本。
-
InitContainer的特性如下:
- 顺序执行:一个Pod可以包含多个InitContainer,它们将按照定义的顺序逐个运行。只有当当前的InitContainer成功完成并且退出后,才会启动下一个InitContainer或者主容器。
- 具备相同的网络和存储命名空间:InitContainer和主容器共享相同的网络和存储命名空间。这意味着InitContainer和主容器可以在同一个网络环境中进行通信,也可以使用相同的存储卷。
- 对主容器无感知:InitContainer对于主容器是无感知的,主容器只在所有InitContainer成功运行并退出后才会启动。在主容器启动之前,InitContainer能够进行必要的初始化工作,例如下载文件、安装软件等。
-
下面是一个示例,说明如何创建一个使用InitContainer的Pod:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: main-container image: my-image:tag command: ["my-command"] initContainers: - name: init-container image: busybox:latest command: ["sh", "-c", "echo init-container is running"]
- 上述示例中,创建了一个名为"my-pod"的Pod,它包含一个主容器和一个InitContainer。主容器使用"my-image:tag"镜像运行,并执行"my-command"命令。InitContainer使用"busybox:latest"镜像运行,并执行简单的无限循环打印出信息。
- 当这个Pod被创建时,InitContainer会在主容器启动之前运行。InitContainer的输出可以在Pod的日志中查看。只有当InitContainer成功完成并退出后,主容器才会启动并执行指定的命令。
- 通过使用InitContainer,可以确保在主容器运行之前进行必要的初始化工作,例如加载配置文件、进行数据预处理或者设置环境变量。这为应用程序的正常运行提供了必要的准备工作,同时也增强了Kubernetes中容器的可靠性和灵活性。
3. 污点与容忍
- 污点:
-
污点(Taint)是节点上的一种标记,用于阻止Pod调度到不符合指定条件的节点上。污点用于限制哪些Pod可以在节点上运行,从而实现更精确的调度策略。
-
是标注在节点上的,当我们在一个节点上打上污点以后,k8s 会认为尽量不要将 pod 调度到该节点上,除非该 pod 上面表示可以容忍该污点,且一个节点可以打多个污点,此时则需要 pod 容忍所有污点才会被调度该节点。
-
污点由三个主要组成部分组成:
- 键(Key):标记的名称,通常表示某种资源或特性。
- 值(Value):与键关联的值,用于进一步描述资源或特性。
- 效果(Effect):指定污点对Pod调度的影响。有以下三种效果:
- NoSchedule:阻止Pod被调度到具有此污点的节点上。
- PreferNoSchedule:优先考虑不调度Pod到具有此污点的节点上,但不是强制性的。
- NoExecute:当Pod已经运行在具有此污点的节点上时,节点上的现有Pod将被驱逐。
-
常用命令:
- 为节点打上污点 :kubectl taint node k8s-master key=value:NoSchedule
- 移除污点 kubectl taint node k8s-master key=value:NoSchedule
- 查看污点 kubectl describe no k8s-master
-
以下是一个使用污点的示例:定义了一个名为"taint-node"的节点,并在该节点上添加了一个名为"dedicated=high-performance"的污点,效果为NoSchedule。这表示任何不具有相应容忍度的Pod将不会被调度到该节点上。
apiVersion: v1 kind: Node metadata: name: taint-node spec: taints: - key: dedicated value: high-performance effect: NoSchedule
-
- 容忍(Toleration) 是一个Pod规格中的字段,用于指定Pod能够容忍的节点上的污点。容忍度规则通过与节点上的污点进行匹配来判断Pod是否能够被调度到该节点上。 容忍度规则由以下几个组成部分组成:
-
键(Key):表示节点上污点的名称。
-
操作符(Operator):指定匹配规则的操作符,有以下几种选项:
- Equal(等于):要求污点的值必须与容忍度规则完全相等。
- Equal(等于):要求污点的值必须与容忍度规则完全相等。
-
值(Value):与污点的值进行匹配。对于操作符为Equal的情况,必须完全匹配值。
-
我们可以通过在Pod规格中添加相应的容忍度,来使Pod能够在具有污点的节点上运行。以下是一个具有容忍度的示例:定义了一个名为"toleration-pod"的Pod,并在Pod的tolerations字段中定义了一个匹配污点的容忍度规则,该规则表示Pod能够在具有"dedicated=high-performance"污点的节点上运行。通过使用污点和容忍度,我们可以灵活地控制Pod的调度,将特定类型的Pod调度到适合的节点上,实现资源的优化和隔离。
apiVersion: v1 kind: Pod metadata: name: toleration-pod spec: containers: - name: my-container image: nginx tolerations: - key: dedicated operator: Equal value: high-performance effect: NoSchedule
-
4. 亲和力(Affinity)
- 亲和性(Affinity)是一种机制,用于指定Pod与其他Pod或节点之间的关系,以控制它们之间的调度关系。通过使用亲和性规则,我们可以让Pod倾向于与其相关的其他资源(例如节点或其他Pod)部署在同一个节点上,或者与它们分布在不同的节点上。
- Pod的亲和性可以通过两种方式来定义:
- 亲和性规则(Affinity Rule):通过指定一个或多个亲和性规则来定义Pod与其他Pod之间的关系,以控制它们在相同或不同节点上的调度。亲和性规则又分为两种类型:
-
节点亲和性(Node Affinity):规定Pod与节点之间的关系,它是通过对节点的标签进行匹配来实现的。举个例子:
apiVersion: v1 kind: Pod metadata: name: node-affinity-pod spec: containers: - name: my-container image: nginx affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-type operator: In values: - high-performance
-
在这个示例中,我们创建了一个Pod,将其命名为"node-affinity-pod"。该Pod使用节点亲和性规则,要求将其调度到具有标签"node-type=high-performance"的节点上。这样可以确保该Pod会被调度到高性能的节点上运行。
- RequiredDuringSchedulingIgnoredDuringExecution:硬亲和力,即支持必须部署在指定的节点上,也支持必须不部署在指定的节点上
- PreferredDuringSchedulingIgnoredDuringExecution:软亲和力:尽量部署在满足条件的节点上,或尽量不要部署在被匹配的节点上
-
匹配类型有:
- In:部署在满足条件的节点上
- NotIn:匹配不在条件中的节点,实现节点反亲和性
- Exists:只要存在 key 名字就可以,不关心值是什么
- DoesExist:匹配指定 key 名不存在的节点,实现节点反亲和性
- Gt:value 为数值,且节点上的值小于指定的条件
- Lt:value 为数值,且节点上的值大于指定条件
-
Pod亲和性(Pod Affinity):规定Pod与其他Pod之间的关系,这样可以控制它们在同一个节点上或者分散在不同节点上的调度,举个例子:
apiVersion: v1 kind: Pod metadata: name: pod-affinity-pod1 labels: app: web spec: containers: - name: my-container image: nginx --- apiVersion: v1 kind: Pod metadata: name: pod-affinity-pod2 labels: app: web spec: containers: - name: my-container image: nginx --- apiVersion: v1 kind: Pod metadata: name: pod-affinity-pod3 spec: containers: - name: my-container image: nginx affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - web topologyKey: "kubernetes.io/hostname"
-
在这个示例中,我们创建了三个Pod,命名为"pod-affinity-pod1"、“pod-affinity-pod2"和"pod-affinity-pod3”。前两个Pod具有相同的标签"app=web",而第三个Pod没有该标签。第三个Pod使用Pod亲和性规则,要求将其与具有相同标签"app=web"的Pod调度到同一个节点上,并使用"kubernetes.io/hostname"作为拓扑键(topology key)。
-
通过这样的设置,前两个具 有相同标签的Pod将会被调度到同一个节点上,而没有该标签的Pod则可以被调度到任意节点上。
-
亲和性的使用可以带来很多好处。例如,将具有类似功能或相互依赖的应用程序部署到同一节点上可以提高它们之间的通信速度和性能。此外,对于需要特定硬件或某些共享资源的Pod,您可以使用亲和性规则将它们调度到适合的节点上,以便充分利用这些资源。
-
- 反亲和性规则(Anti-Affinity Rule):与亲和性规则相反,用于指定Pod与其他资源之间的排斥关系,以避免它们部署在同一个节点上。
- 亲和性规则(Affinity Rule):通过指定一个或多个亲和性规则来定义Pod与其他Pod之间的关系,以控制它们在相同或不同节点上的调度。亲和性规则又分为两种类型:
5. 认证与鉴权 (偏运维)
-
所有 Kubernetes 集群有两类用户:由 Kubernetes 管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。
- 普通账户是假定被外部或独立服务管理的,由管理员分配 keys,用户像使用 Keystone 或 google 账号一样,被存储在包含 usernames 和 passwords 的 list 的文件里。
- 需要注意:在 Kubernetes 中不能通过 API 调用将普通用户添加到集群中。
- 普通帐户是针对(人)用户的,服务账户针对 Pod 进程。
- 普通帐户是全局性。在集群所有namespaces中,名称具有惟一性。
- 通常,群集的普通帐户可以与企业数据库同步,新的普通帐户创建需要特殊权限。服务账户创建目的是更轻量化,允许集群用户为特定任务创建服务账户。
- 普通帐户和服务账户的审核注意事项不同。
- 对于复杂系统的配置包,可以包括对该系统的各种组件的服务账户的定义。
-
详细介绍下 k8s 中的认证,并举例说明
-
详细介绍下 k8s 中的认证,并举例说明
- 用户(User):Kubernetes中的用户实体,可以代表一个人或一个组织。
- 角色(Role):一组定义的权限集合,可以分配给用户。
- 主体(Subject):主体可以是用户、组、服务账户等。
- 角色绑定(RoleBinding):将角色分配给主体的机制。通过角色绑定,可以将角色授权给特定的用户或组。
-
举个例子来说明。假设我们有一个Kubernetes集群,我们想要创建一个具有查看Pod和创建Deployment的权限的用户。首先,我们需要创建一个Role对象来定义用户的权限:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-viewer rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: ["deployments"] verbs: ["create"]
-
然后,我们需要创建一个RoleBinding对象来将该角色授予用户或组:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: pod-viewer-binding subjects: - kind: User name: alice # 用户名为alice roleRef: kind: Role name: pod-viewer apiGroup: rbac.authorization.k8s.io
-
上述示例中,创建了一个名为pod-viewer的角色,并定义了可以对Pod进行查看的权限和对Deployment进行创建的权限。然后,RoleBinding将该角色授予了用户alice。
-
当alice使用她的凭据进行认证后,她只能执行与角色所定义的权限一致的操作,即可以查看Pod和创建Deployment。
-
通过使用RBAC,可以灵活地管理集群中不同用户和组织的访问权限,从而实现更细粒度的授权控制。