k8s集合
一 kubernetes 简介
-
在Docker 作为高级容器引擎快速发展的同时,在Google内部,容器技术已经应用了很多年
-
Borg系统运行管理着成千上万的容器应用。
-
Kubernetes项目来源于Borg,可以说是集结了Borg设计思想的精华,并且吸收了Borg系统中的经验和教训。
-
Kubernetes对计算资源进行了更高层次的抽象,通过将容器进行细致的组合,将最终的应用服务交给用户。
K8s 就像是数据中心的“操作系统”,帮你管理成千上万个容器。
概念 | 作用 |
---|---|
Pod | K8s 最小调度单位,一个 Pod 可包含多个容器。 |
Deployment | 管理 Pod 的副本数和滚动更新。 |
Service | 为 Pod 提供稳定的网络访问入口(负载均衡)。 |
Namespace | 逻辑隔离集群资源(如测试/生产环境)。 |
ConfigMap/Secret | 管理配置信息和敏感数据。 |
kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
-
自我修复:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器
-
弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
-
服务发现:服务可以通过自动发现的形式找到它所依赖的服务
-
负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
-
版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
-
存储编排:可以根据容器自身的需求自动创建存储卷
二 K8S集群环境搭建
2.1 k8s中容器的管理方式
kubelet 如何把 Pod 调度到节点并最终变成真正的容器进程
-
dockershim(已退役)
-
旧时代 kubelet 内置的“翻译器”,把 CRI 调用翻译成 Docker Engine 能听懂的命令。
-
Kubernetes 1.24 删除,现已不可用。
-
-
cri-dockerd
-
社区/Mirantis 维护的 独立进程,替代退役的 dockershim,让 kubelet 继续通过 CRI 与 Docker Engine 交互。
-
-
CRI-O
-
红帽主推的 轻量级 CRI 实现,直接对接 runc,不依赖 Docker Engine。
-
CRI-O的方式是Kubernetes创建容器最直接的一种方式,在创建集群的时候,需要借助于cri-o插件的方式来实现Kubernetes集群的创建。
-
-
containerd
- 默认情况下,K8S在创建集群时使用的方式
- CNCF 毕业项目,内置 CRI-plugin,天生支持 CRI,无需额外翻译层。
2.2 k8s 集群部署
2.2.1 k8s 环境部署说明
K8S中文官网:Kubernetes
主机名 | ip | 角色 |
---|---|---|
harbor | 192.168.217.200 | harbor仓库 |
k8s-master | 192.168.217.100 | master,k8s集群控制节点 |
k8s-node1 | 192.168.217.10 | worker,k8s集群工作节点 |
k8s-node2 | 192.168.217.20 | worker,k8s集群工作节点 |
- 所有节点禁用selinux和防火墙
- 所有节点同步时间和解析
[root@k8s-master ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.217.100 k8s-master
192.168.217.10 k8s-node1
192.168.217.20 k8s-node2
192.168.217.200 reg.timinglee.org
2.2.2 集群环境初始化
所有k8s集群节点执行以下步骤
2.2.2.1.所有禁用swap和本地解析
彻底关闭 Linux 的 swap,防止 kubelet 启动失败。
所有节点执行
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl mask swap.target 永久屏蔽 swap.target,无论任何服务依赖 swap.target,都当它不存在。生成到 /dev/null 的符号链接,确保重启后 swap 分区不会被自动挂载。
Created symlink /etc/systemd/system/swap.target → /dev/null.
[root@master ~]# swapoff -a #立即生效关闭当前所有已激活的 swap 设备/文件。
2.2.2.2.所有安装docker
配置仓库
[root@k8s-master ~]# vim /etc/yum.repos.d/docker.repo
[docker]
name=docker
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable/
gpgcheck=0
安装:
[root@k8s-master ~]# dnf install docker-ce -y
2.2.2.3.所有节点设定docker的资源管理模式为systemd
[root@k8s-master ~]# cat /etc/docker/daemon.json
{"registry-mirrors": ["https://reg.timinglee.org"], #harbor仓库"exec-opts": ["native.cgroupdriver=systemd"]
}
[root@k8s-master ~]#
2.2.2.4.所有阶段复制harbor仓库中的证书并启动docker
部署harbor仓库
#解压下载的压缩包
[root@docker ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@docker ~]# ls
anaconda-ks.cfg certs harbor-offline-installer-v2.5.4.tgz
auth harbor
[root@docker ~]# cd harbor/[root@docker harbor]# cp harbor.yml.tmpl harbor.yml
#设置仓库名和密码
[root@docker harbor]# vim harbor.ymlhostname: reg.timinglee.orgcertificate: /data/certs/timinglee.org.crtprivate_key: /data/certs/timinglee.org.keyharbor_admin_password: 123[root@docker harbor]# ./install.sh --helpPlease set --with-notary #证书签名
Please set --with-trivy #安全扫描
Please set --with-chartmuseum if needs enable Chartmuseum in Harbor[root@docker harbor]# ./install.sh --with-chartmuseum#管理harbor的容器 要进入harbor这个目录执行
[root@docker harbor]# docker compose stop #停止
[root@docker harbor]# docker compose up -d #启动
将harbor仓库的证书复制到节点
[root@reg harbor]# ll -s /etc/docker/certs.d/reg.timinglee.org/ca.crt
4 -rw-r--r-- 1 root root 2191 Aug 11 06:12 /etc/docker/certs.d/reg.timinglee.org/ca.crt
[root@reg harbor]#[root@k8s-master ~]#scp /etc/docker/certs.d/reg.timinglee.org/ca.crt root@192.168.217.10:/etc/docker/certs.d/reg.timinglee.org/启动docker
[root@k8s-master ~]# systemctl enable --now docker登录仓库:
[root@k8s-master ~]# docker login reg.timinglee.org
Username: admin
Password:WARNING! Your credentials are stored unencrypted in '/root/.docker/config. json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/Login Succeeded
[root@k8s-master ~]#[root@k8s-master ~]# docker info
2.2.2.5 安装K8S部署工具
#部署软件仓库,添加K8S源
[root@k8s-master ~]# vim /etc/yum.repos.d/k8s.repo
[k8s]
name=k8s
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/rpm
gpgcheck=0#安装软件
[root@k8s-master ~]# dnf install kubelet-1.30.0 kubeadm-1.30.0 kubectl-1.30.0 -y
2.2.2.6 设置kubectl命令补齐功能
#安装 bash-completion 软件包,它提供了 /usr/share/bash-completion/bash_completion 脚本,是大多数 CLI 补全功能的基础。
[root@k8s-master ~]# dnf install bash-completion -y#把 kubectl 的 Bash 补全脚本追加到当前用户的 ~/.bashrc 末尾,保证以后每次登录 shell 都会自动加载。
[root@k8s-master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc#让修改立即生效,无需重新登录。
[root@k8s-master ~]# source ~/.bashrc
2.2.2.7 在所节点安装cri-docker
k8s从1.24版本开始移除了dockershim,所以需要安装cri-docker插件才能使用docker
软件下载:https://github.com/Mirantis/cri-dockerd
[root@k8s-master ~]# dnf install libcgroup-0.41-19.el8.x86_64.rpm \
> cri-dockerd-0.3.14-3.el8.x86_64.rpm -y[root@k8s-master ~]# vim /lib/systemd/system/cri-docker.service
[Unit]
Description=CRI Interface for Docker Application Container Engine
Documentation=https://docs.mirantis.com
After=network-online.target firewalld.service docker.service
Wants=network-online.target
Requires=cri-docker.socket[Service]
Type=notify#指定网络插件名称及基础容器镜像
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.timinglee.org/k8s/pause:3.9ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always[root@k8s-master ~]# systemctl daemon-reload
[root@k8s-master ~]# systemctl start cri-docker
[root@k8s-master ~]# ll /var/run/cri-dockerd.sock
srw-rw---- 1 root docker 0 8月 26 22:14 /var/run/cri-dockerd.sock #cri-dockerd的套接字文件
2.2.2.8 在master节点拉取K8S所需镜像
#拉取k8s集群所需要的镜像
[root@k8s-master ~]# kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock#上传镜像到harbor仓库
[root@k8s-master ~]# docker images | awk '/google/{ print $1":"$2}' \
| awk -F "/" '{system("docker tag "$0" reg.timinglee.org/k8s/"$3)}'[root@k8s-master ~]# docker images | awk '/k8s/{system("docker push "$1":"$2)}'
2.2.2.9 集群初始化
#启动kubelet服务
[root@k8s-master ~]# systemctl status kubelet.service#执行初始化命令
[root@k8s-master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository reg.timinglee.org/k8s \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock#指定集群配置文件变量
[root@k8s-master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile#当前节点没有就绪,因为还没有安装网络插件,容器没有运行
[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master.timinglee.org NotReady control-plane 4m25s v1.30.0
root@k8s-master ~]# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-647dc95897-2sgn8 0/1 Pending 0 6m13s
kube-system coredns-647dc95897-bvtxb 0/1 Pending 0 6m13s
...
在此阶段如果生成的集群token找不到了可以重新生成
[root@k8s-master ~]# kubeadm token create --print-join-command
kubeadm join 192.168.217.100:6443 --token 5hwptm.zwn7epa6pvatbpwf --discovery-token-ca-cert-hash sha256:52f1a83b70ffc8744db5570288ab51987ef2b563bf906ba4244a300f61e9db23
2.2.2.10 安装flannel网络插件
官方网站:https://github.com/flannel-io/flannel
#下载flannel的yaml部署文件
[root@k8s-master ~]# wget https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml#下载镜像:
[root@k8s-master ~]# docker pull docker.io/flannel/flannel:v0.25.5
[root@k8s-master ~]# docekr docker.io/flannel/flannel-cni-plugin:v1.5.1-flannel1#上传镜像到仓库
[root@k8s-master ~]# docker tag flannel/flannel:v0.25.5 \
reg.timinglee.org/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker push reg.timinglee.org/flannel/flannel:v0.25.5[root@k8s-master ~]# docker tag flannel/flannel-cni-plugin:v1.5.1-flannel1 \
reg.timinglee.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
[root@k8s-master ~]# docker push reg.timinglee.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
#编辑kube-flannel.yml 修改镜像下载位置
[root@k8s-master ~]# vim kube-flannel.yml#需要修改以下几行
[root@k8s-master ~]# grep -n image kube-flannel.yml
146: image: reg.timinglee.org/flannel/flannel:v0.25.5
173: image: reg.timinglee.org/flannel/flannel-cni-plugin:v1.5.1-flannel1
184: image: reg.timinglee.org/flannel/flannel:v0.25.5#安装flannel网络插件
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml
2.2.2.11 节点扩容
基本配置和上面的一样
加入集群,在node节点上做
[root@k8s-node1~]# kubeadm join 192.168.217.100:6443 --token 5hwptm.zwn7epa6pvatbpwf --discovery-token-ca-cert-hash #这里我的192,168.217.100是我k8s的master主机
在master阶段中查看所有node的状态,当status都是ready状态就说明okl
三 k8s的pod管理及优化
-
Pod是可以创建和管理Kubernetes计算的最小可部署单元
-
一个Pod代表着集群中运行的一个进程,每个pod都有一个唯一的ip。
-
一个pod类似一个豌豆荚,包含一个或多个容器(通常是docker)
-
多个容器间共享IPC、Network和UTC namespace。
3.1 创建自主式pod (生产不推荐)
优点:
灵活性高:
可以精确控制 Pod 的各种配置参数,包括容器的镜像、资源限制、环境变量、命令和参数等,满足特定的应用需求。
学习和调试方便:
对于学习 Kubernetes 的原理和机制非常有帮助,通过手动创建 Pod 可以深入了解 Pod 的结构和配置方式。在调试问题时,可以更直接地观察和调整 Pod 的设置。
适用于特殊场景:
在一些特殊情况下,如进行一次性任务、快速验证概念或在资源受限的环境中进行特定配置时,手动创建 Pod 可能是一种有效的方式。
缺点:
管理复杂:
如果需要管理大量的 Pod,手动创建和维护会变得非常繁琐和耗时。难以实现自动化的扩缩容、故障恢复等操作。
缺乏高级功能:
无法自动享受 Kubernetes 提供的高级功能,如自动部署、滚动更新、服务发现等。这可能导致应用的部署和管理效率低下。
可维护性差:
手动创建的 Pod 在更新应用版本或修改配置时需要手动干预,容易出现错误,并且难以保证一致性。相比之下,通过声明式配置或使用 Kubernetes 的部署工具可以更方便地进行应用的维护和更新。
#查看所有pods
[root@k8s-master ~]# kubectl get pods
No resources found in default namespace.#建立一个名为test的pod
[root@master ~]# kubectl run test --image nginx
pod/test created
#查看test的状态
[root@master ~]# kubectl get pods test
NAME READY STATUS RESTARTS AGE
test 0/1 Pending 0 9s#显示pod的较为详细的信息
[root@master ~]# kubectl get pods test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test 0/1 Pending 0 12s <none> <none> <none> <none>
[root@master ~]#
3.2 利用控制器管理pod(推荐)
高可用性和可靠性:
自动故障恢复:如果一个 Pod 失败或被删除,控制器会自动创建新的 Pod 来维持期望的副本数量。确保应用始终处于可用状态,减少因单个 Pod 故障导致的服务中断。
健康检查和自愈:可以配置控制器对 Pod 进行健康检查(如存活探针和就绪探针)。如果 Pod 不健康,控制器会采取适当的行动,如重启 Pod 或删除并重新创建它,以保证应用的正常运行。
可扩展性:
轻松扩缩容:可以通过简单的命令或配置更改来增加或减少 Pod 的数量,以满足不同的工作负载需求。例如,在高流量期间可以快速扩展以处理更多请求,在低流量期间可以缩容以节省资源。
水平自动扩缩容(HPA):可以基于自定义指标(如 CPU 利用率、内存使用情况或应用特定的指标)自动调整 Pod 的数量,实现动态的资源分配和成本优化。
版本管理和更新:
滚动更新:对于 Deployment 等控制器,可以执行滚动更新来逐步替换旧版本的 Pod 为新版本,确保应用在更新过程中始终保持可用。可以控制更新的速率和策略,以减少对用户的影响。
回滚:如果更新出现问题,可以轻松回滚到上一个稳定版本,保证应用的稳定性和可靠性。
声明式配置:
简洁的配置方式:使用 YAML 或 JSON 格式的声明式配置文件来定义应用的部署需求。这种方式使得配置易于理解、维护和版本控制,同时也方便团队协作。
期望状态管理:只需要定义应用的期望状态(如副本数量、容器镜像等),控制器会自动调整实际状态与期望状态保持一致。无需手动管理每个 Pod 的创建和删除,提高了管理效率。
服务发现和负载均衡:
自动注册和发现:Kubernetes 中的服务(Service)可以自动发现由控制器管理的 Pod,并将流量路由到它们。这使得应用的服务发现和负载均衡变得简单和可靠,无需手动配置负载均衡器。
流量分发:可以根据不同的策略(如轮询、随机等)将请求分发到不同的 Pod,提高应用的性能和可用性。
多环境一致性:
一致的部署方式:在不同的环境(如开发、测试、生产)中,可以使用相同的控制器和配置来部署应用,确保应用在不同环境中的行为一致。这有助于减少部署差异和错误,提高开发和运维效率。
示例
[root@master ~]# kubectl create deployment hh --image myapp:v1
deployment.apps/hh created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hh-857cb68d9f-b99c5 1/1 Running 0 87s 192.168.166.146 node1 <none> <none>
[root@master ~]#
扩容
[root@master ~]# kubectl scale deployment hh --replicas 4
运行容器由一个变为4个
缩容
[root@master ~]# kubectl scale deployment hh --replicas 2 #通过修改--replicas后跟的数值来控制运行容器的数量
3.3利用yaml文件部署
获取资源帮助
kubectl explain pod.spec.containers
示例:
1.运行简单的单个容器pod
[root@master ~]# kubectl run test --image myapp:v1 --dry-run=client -o yaml > test.yml
[root@master ~]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: test #pod标签name: test #pod名称
spec:containers:- image: myapp:v1 #pod使用的镜像name: test #容器名称
修改完yml文件后运行
[root@master ~]# kubectl apply -f test.yml #-f后跟文件名
删除
[root@master ~]# kubectl delete -f test.yml
2.运行简单的多个容器pod
在一个pod中开启多个容器时一定要确保容器彼此不能互相干扰
[root@master ~]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:containers:- image: busyboxplus:latestname: busyboxcommand:- /bin/sh- -c- sleep 100000- image: nginx:latestname: nginx
[root@master ~]# kubectl apply -f test.yml
pod/test unchanged
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test 2/2 Running 0 79s
[root@master ~]#
3.端口映射
[root@master ~]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:containers:- image: myapp:v1name: myappv1ports:- name: httpcontainerPort: 80hostPort: 80protocol: TCP
[root@master ~]# kubectl apply -f test.yml
pod/test unchanged
4.如何设定环境变量
[root@master hh]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:containers:- image: busyboxplus:latestname: busyboxcommand: ["/bin/sh","-c","echo $NAME;sleep 3000000"]env:- name: NAMEvalue: haha
[root@master hh]# kubectl logs pods/test busybox
haha
[root@master hh]#
5.资源限制
资源限制会影响pod的Qos Class资源优先级,资源优先级分为Guaranteed > Burstable > BestEffort
QoS(Quality of Service)即服务质量
资源设定 | 优先级类型 |
---|---|
资源限定未设定 | BestEffort |
资源限定设定且最大和最小不一致 | Burstable |
资源限定设定且最大和最小一致 | Guaranteed |
[root@master hh]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:containers:- image: myapp:v1name: myappresources:limits:cpu: 500mmemory: 200Mrequests:cpu: 500mmemory: 200M
[root@master hh]# kubectl describe pods test
6.容器启动管理
[root@master hh]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:restartPolicy: Always #kubelet 会不停地在本节点重启这个 Pod 的容器containers:- image: myapp:v1name: myapp
[root@master hh]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test 1/1 Running 1 6m48s 192.168.166.159 node1 <none> <none>
[root@master hh]#
到pod运行的node节点上删除容器,观察是否会重启
[root@node1 ~]# docker ps | grep myapp
862ce93039b3 d4a5e0eaa84f "nginx -g 'daemon of…" 1 second ago Up 1 second k8s_myapp_test_default_8e3d402c-8677-40cb-a11a-b19260e71877_2
[root@node1 ~]# docker rm -f 862ce93039b3
862ce93039b3
7.选择运行节点
[root@master hh]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:restartPolicy: AlwaysnodeSelector:kubernetes.io/hostname: node2 #手动选择运行的节点containers:- image: myapp:v1name: myapp
8.共享宿主机网络
[root@master hh]# cat test.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testname: test
spec:hostNetwork: truerestartPolicy: AlwaysnodeSelector:kubernetes.io/hostname: node2containers:- image: busyboxplus:latestname: busyboxcommand:- /bin/sh- -c- sleep 100000
[root@master hh]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test 1/1 Running 0 97s 192.168.217.20 node2 <none> <none>
[root@master hh]#
四 k8s中的控制器应用
官方文档:
工作负载管理 | Kubernetes
控制器也是管理pod的一种手段
-
自主式pod:pod退出或意外关闭后不会被重新创建
-
控制器管理的 Pod:在控制器的生命周期里,始终要维持 Pod 的副本数目
Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod
当建立控制器后,会把期望值写入etcd,k8s中的apiserver检索etcd中我们保存的期望状态,并对比pod的当前状态,如果出现差异代码自驱动立即恢复
类型:
控制器名称 | 控制器用途 |
---|---|
Replication Controller | 比较原始的pod控制器,已经被废弃,由ReplicaSet替代 |
ReplicaSet | ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行 |
Deployment | 一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力 |
DaemonSet | DaemonSet 确保全指定节点上运行一个 Pod 的副本 |
StatefulSet | StatefulSet 是用来管理有状态应用的工作负载 API 对象。 |
Job | 执行批处理任务,仅执行一次任务,保证任务的一个或多个Pod成功结束 |
CronJob | Cron Job 创建基于时间调度的 Jobs。 |
HPA全称Horizontal Pod Autoscaler | 根据资源利用率自动调整service中Pod数量,实现Pod水平自动缩放 |
4.1 replicaset控制器
replicaset参数说明
参数名称 | 字段类型 | 参数说明 |
---|---|---|
spec | Object | 详细定义对象,固定值就写Spec |
spec.replicas | integer | 指定维护pod数量 |
spec.selector | Object | Selector是对pod的标签查询,与pod数量匹配 |
spec.selector.matchLabels | string | 指定Selector查询标签的名称和值,以key:value方式指定 |
spec.template | Object | 指定对pod的描述信息,比如lab标签,运行容器的信息等 |
spec.template.metadata | Object | 指定pod属性 |
spec.template.metadata.labels | string | 指定pod标签 |
spec.template.spec | Object | 详细定义对象 |
spec.template.spec.containers | list | Spec对象的容器列表定义 |
spec.template.spec.containers.name | string | 指定容器名称 |
spec.template.spec.containers.image | string | 指定容器镜像 |
示例:
#生成yml文件
[root@k8s-master ~]# kubectl create deployment replicaset --image myapp:v1 --dry-run=client -o yaml > replicaset.yml[root@k8s-master ~]# vim replicaset.yml
apiVersion: apps/v1
kind: ReplicaSet
metadata:name: replicaset #指定pod名称,一定小写,如果出现大写报错
spec:replicas: 2 #指定维护pod数量为2selector: #指定检测匹配方式matchLabels: #指定匹配方式为匹配标签app: myapp #指定匹配的标签为app=myapptemplate: #模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: myappspec:containers:- image: myapp:v1name: myapp[root@k8s-master ~]# kubectl apply -f replicaset.yml
replicaset.apps/replicaset created[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-l4xnr 1/1 Running 0 96s app=myapp
replicaset-t2s5p 1/1 Running 0 96s app=myapp#replicaset是通过标签匹配pod
[root@k8s-master ~]# kubectl label pod replicaset-l4xnr app=timinglee --overwrite
pod/replicaset-l4xnr labeled
[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-gd5fh 1/1 Running 0 2s app=myapp #新开启的pod
replicaset-l4xnr 1/1 Running 0 3m19s app=timinglee
replicaset-t2s5p 1/1 Running 0 3m19s app=myapp#恢复标签后
[root@k8s2 pod]# kubectl label pod replicaset-example-q2sq9 app-
[root@k8s2 pod]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-example-q2sq9 1/1 Running 0 3m14s app=nginx
replicaset-example-th24v 1/1 Running 0 3m14s app=nginx
replicaset-example-w7zpw 1/1 Running 0 3m14s app=nginx#replicaset自动控制副本数量,pod可以自愈
[root@k8s-master ~]# kubectl delete pods replicaset-t2s5p
pod "replicaset-t2s5p" deleted[root@k8s-master ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
replicaset-l4xnr 1/1 Running 0 5m43s app=myapp
replicaset-nxmr9 1/1 Running 0 15s app=myapp回收资源
[root@k8s2 pod]# kubectl delete -f rs-example.yml
4.2 deployment 控制器
-
为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。
-
Deployment控制器并不直接管理pod,而是通过管理ReplicaSet来间接管理Pod
-
Deployment管理ReplicaSet,ReplicaSet管理Pod
-
Deployment 为 Pod 和 ReplicaSet 提供了一个申明式的定义方法
-
在Deployment中ReplicaSet相当于一个版本
示例:
#生成yaml文件
[root@k8s-master ~]# kubectl create deployment deployment --image myapp:v1 --dry-run=client -o yaml > deployment.yml[root@k8s-master ~]# vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: deployment
spec:replicas: 3selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:containers:- image: myapp:v1name: myapp
#建立pod
root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/deployment created
4.3 daemonset控制器
DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, 也会为他们新增一个 Pod ,当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
DaemonSet 的典型用法:
-
在每个节点上运行集群存储 DaemonSet,例如 glusterd、ceph。
-
在每个节点上运行日志收集 DaemonSet,例如 fluentd、logstash。
-
在每个节点上运行监控 DaemonSet,例如 Prometheus Node Exporter、zabbix agent等
-
一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用
-
一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求
示例:
[root@k8s2 pod]# cat daemonset.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:name: daemonset
spec:selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:tolerations: #对于污点节点的容忍- effect: NoScheduleoperator: Existscontainers:- name: nginximage: nginx#回收
[root@k8s2 pod]# kubectl delete -f daemonset.yml
4.4 job 控制器
job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务
Job特点如下:
-
当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
-
当成功结束的pod达到指定的数量时,Job将完成执行
示例:
[root@k8s2 pod]# vim job.yml
apiVersion: batch/v1
kind: Job
metadata:name: pi
spec:completions: 6 #一共完成任务数为6 parallelism: 2 #每次并行完成2个template:spec:containers:- name: piimage: perl:5.34.0command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] #计算Π的后2000位restartPolicy: Never #关闭后不自动重启backoffLimit: 4 #运行失败后尝试4重新运行[root@k8s2 pod]# kubectl apply -f job.yml
关于重启策略设置的说明:
如果指定为OnFailure,则job会在pod出现故障时重启容器
而不是创建pod,failed次数不变
如果指定为Never,则job会在pod出现故障时创建新的pod
并且故障pod不会消失,也不会重启,failed次数加1
如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了
4.5cronjob 控制器
- Cron Job 创建基于时间调度的 Jobs。
- CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,
- CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。
- CronJob可以在特定的时间点(反复的)去运行job任务。
示例:
[root@k8s2 pod]# vim cronjob.yml
apiVersion: batch/v1
kind: CronJob
metadata:name: hello
spec:schedule: "* * * * *"jobTemplate:spec:template:spec:containers:- name: helloimage: busyboximagePullPolicy: IfNotPresentcommand:- /bin/sh- -c- date; echo Hello from the Kubernetes clusterrestartPolicy: OnFailure[root@k8s2 pod]# kubectl apply -f cronjob.yml
五 k8s中的微服务
5.1 什么是微服务
微服务:用控制器来完成集群的工作负载,那么应用如何暴漏出去?需要通过微服务暴漏出去后才能被访问
-
Service是一组提供相同服务的Pod对外开放的接口。
-
借助Service,应用可以实现服务发现和负载均衡。
-
service默认只支持4层负载均衡能力,没有7层功能。(可以通过Ingress实现)
5.2类型:
微服务类型 | 作用描述 |
---|---|
ClusterIP | 默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问 |
NodePort | 将Service通过指定的Node上的端口暴露给外部,访问任意一个NodeIP:nodePort都将路由到ClusterIP |
LoadBalancer | 在NodePort的基础上,借助cloud provider创建一个外部的负载均衡器,并将请求转发到 NodeIP:NodePort,此模式只能在云服务器上使用 |
ExternalName | 将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定 |
示例:
#生成控制器文件并建立控制器
[root@k8s-master ~]# kubectl create deployment timinglee --image myapp:v1 --replicas 2 --dry-run=client -o yaml > timinglee.yaml#生成微服务yaml追加到已有yaml中
[root@k8s-master ~]# kubectl expose deployment timinglee --port 80 --target-port 80 --dry-run=client -o yaml >> timinglee.yaml[root@k8s-master ~]# vim timinglee.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: timingleename: timinglee
spec:replicas: 2selector:matchLabels:app: timingleetemplate:metadata:creationTimestamp: nulllabels:app: timingleespec:containers:- image: myapp:v1name: myapp
--- #不同资源间用---隔开apiVersion: v1
kind: Service
metadata:labels:app: timingleename: timinglee
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: timinglee[root@k8s-master ~]# kubectl apply -f timinglee.yaml
deployment.apps/timinglee created
service/timinglee created[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19h
timinglee ClusterIP 10.99.127.134 <none> 80/TCP 16s
默认使用iptables调度
[root@k8s-master ~]# kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19h <none>
timinglee ClusterIP 10.99.127.134 <none> 80/TCP 119s app=timinglee #集群内部IP 134#可以在火墙中查看到策略信息
[root@k8s-master ~]# iptables -t nat -nL
KUBE-SVC-I7WXYK76FWYNTTGM 6 -- 0.0.0.0/0 10.99.127.134 /* default/timinglee cluster IP */ tcp dpt:80
5.3微服务类型详解
5.3.1 clusterip
特点:
clusterip模式只能在集群内访问,并对集群内的pod提供健康检测和自动发现功能
示例:
[root@master hh]# cat clusterip.yml
apiVersion: v1
kind: Service
metadata:labels:app: clusteripname: clusterip
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: hahatype: ClusterIP
[root@master hh]#service创建后集群DNS提供解析
[root@master hh]# kubectl -n kube-system get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 9d[root@master service]# dig myappv1.default.svc.cluster.local @10.96.0.10
5.3.2 ClusterIP中的特殊模式headless
headless(无头服务)
对于无头 Services
并不会分配 Cluster IP,kube-proxy不会处理它们, 而且平台也不会为它们进行负载均衡和路由,集群访问通过dns解析直接指向到业务pod上的IP,所有的调度有dns单独完成
示例:
[root@master hh]# cat headless.yml
apiVersion: v1
kind: Service
metadata:labels:app: headlessname: headless
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: headlesstype: ClusterIPclusterIP: None
[root@master hh]#
[root@master hh]# kubectl get svc
headless kubernetes nginx-svc
[root@master hh]# kubectl get svc headless
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
headless ClusterIP None <none> 80/TCP 16s
[root@master hh]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.17.0.1:30467 rr-> 192.168.104.20:443 Masq 1 0 0
TCP 172.17.0.1:31008 rr-> 192.168.104.20:80 Masq 1 0 0
TCP 192.168.217.50:80 rr-> 192.168.104.20:80 Masq 1 0 0
TCP 192.168.217.50:443 rr-> 192.168.104.20:443 Masq 1 0 0
TCP 192.168.217.100:30467 rr-> 192.168.104.20:443 Masq 1 0 0
TCP 192.168.217.100:31008 rr-> 192.168.104.20:80 Masq 1 0 0
TCP 10.96.0.1:443 rr-> 192.168.217.100:6443 Masq 1 4 0
TCP 10.96.0.10:53 rr-> 192.168.219.69:53 Masq 1 0 0-> 192.168.219.70:53 Masq 1 0 0
。。。
5.3.3 nodeport
通过ipvs暴漏端口从而使外部主机通过master节点的对外ip:<port>来访问pod业务
其访问过程为: nodeport → ClusterIP →pods
示例:
[root@master hh]# cat nodeport.yml
apiVersion: v1
kind: Service
metadata:labels:app: nodeport-servicename: nodeport-service
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: nodeporttype: NodePort
[root@master hh]# kubectl apply -f nodeport.yml
service/nodeport-service created
[root@master hh]# kubectl get svc nodeport-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nodeport-service NodePort 10.104.136.138 <none> 80:30791/TCP 10s
5.3.4 loadbalancer
云平台会为我们分配vip并实现访问,如果是裸金属主机那么需要metallb来实现ip的分配
loadbalancer → nodeport → ClusterIP →pods
示例:
[root@master hh]# cat loadbalancer.yml
---
apiVersion: v1
kind: Service
metadata:labels:app: balancer-servicename: balancer-service
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: balancertype: LoadBalancer
[root@master hh]#
5.3.5 metalLB
功能:为LoadBalancer分配vip
官网:Installation :: MetalLB, bare metal load-balancer for Kubernetes
部署:
1.设置ipvs模式
[root@master service]# kubectl edit cm -n kube-system kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"ipvs:strictARP: true #默认就是不需要改[root@k8s-master ~]# kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'2.下载部署文件
[root@k8s2 metallb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
3.修改文件中镜像地址,与harbor仓库路径保持一致
4.上传镜像到harbor
[root@k8s-master ~]# docker pull quay.io/metallb/controller:v0.14.8
[root@k8s-master ~]# docker pull quay.io/metallb/speaker:v0.14.8[root@k8s-master ~]# docker tag quay.io/metallb/speaker:v0.14.8 reg.timinglee.org/metallb/speaker:v0.14.8
[root@k8s-master ~]# docker tag quay.io/metallb/controller:v0.14.8 reg.timinglee.org/metallb/controller:v0.14.8[root@k8s-master ~]# docker push reg.timinglee.org/metallb/speaker:v0.14.8
[root@k8s-master ~]# docker push reg.timinglee.org/metallb/controller:v0.14.8
部署服务
[root@master service]# kubectl apply -f metallb-native.yaml
[root@master service]# kubectl -n metallb-system get pods
NAME READY STATUS RESTARTS AGE
controller-65957f77c8-fc5b5 1/1 Running 1 (20h ago) 23h
speaker-8zslv 1/1 Running 118 (5m38s ago) 22h
speaker-flrjq 1/1 Running 67 (<invalid> ago) 3h18m
speaker-ws4fh 1/1 Running 750 (4m38s ago) 5d18h
配置分配地址段
[root@master service]# cat configmap.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:name: first-pool #地址池名称namespace: metallb-system
spec:addresses:- 192.168.217.50-192.168.217.99 #修改为自己本地地址段 --- #个不同的kind中间必须加分割
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:name: examplenamespace: metallb-system
spec:ipAddressPools:- first-pool #使用地址池
[root@master service]#
[root@k8s-master ~]# kubectl apply -f configmap.yml
ipaddresspool.metallb.io/first-pool created
l2advertisement.metallb.io/example created[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21h
timinglee-service LoadBalancer 10.109.36.123 192.168.217.50 80:31595/TCP 9m9s#通过分配地址从集群外访问服务
[root@reg ~]# curl 192.168.217.50
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
5.3.6 externalname
-
开启services后,不会被分配IP,而是用dns解析CNAME固定域名来解决ip变化问题
-
一般应用于外部业务和pod沟通或外部业务迁移到pod内时
-
在应用向集群迁移过程中,externalname在过度阶段就可以起作用了。
-
集群外的资源迁移到集群时,在迁移的过程中ip可能会变化,但是域名+dns解析能完美解决此问题
示例:
[root@master hh]# cat externalname.yml
apiVersion: v1
kind: Service
metadata:labels:app: haha-servicename: haha-service
spec:selector:app: hahatype: ExternalNameexternalName: www.haha.org[root@master hh]#[root@master hh]# kubectl get services haha-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
haha-service ExternalName <none> www.haha.org <none> 12s
测试:
六 k8s下的存储管理
6.1 configmap
6.1.1功能:
-
configMap用于保存配置数据,以键值对形式存储。
-
configMap 资源提供了向 Pod 注入配置数据的方法。
-
镜像和配置文件解耦,以便实现镜像的可移植性和可复用性。
-
etcd限制了文件大小不能超过1M
6.1.2 创建方式:
1. 字面值创建
[root@master ~]# kubectl create cm lee-config --from-literal fname=timing --from-literal name=lee
configmap/lee-config created[root@k8s-master ~]# kubectl describe cm lee-config
Name: lee-config
Namespace: default
Labels: <none>
Annotations: <none>Data #键值信息显示
====
fname:
----
timing
lname:
----
leeBinaryData
====Events: <none>
2.通过文件创建
[root@k8s-master ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 114.114.114.114[root@k8s-master ~]# kubectl create cm lee2-config --from-file /etc/resolv.conf
configmap/lee2-config created
[root@k8s-master ~]# kubectl describe cm lee2-config
Name: lee2-config
Namespace: default
Labels: <none>
Annotations: <none>Data
====
resolv.conf:
----
# Generated by NetworkManager
nameserver 114.114.114.114BinaryData
====Events: <none>
3. 通过目录创建
[root@k8s-master ~]# mkdir leeconfig
[root@k8s-master ~]# cp /etc/fstab /etc/rc.d/rc.local leeconfig/
[root@k8s-master ~]# kubectl create cm lee3-config --from-file leeconfig/
configmap/lee3-config created
[root@k8s-master ~]# kubectl describe cm lee3-config
Name: lee3-config
Namespace: default
Labels: <none>
Annotations: <none>Data
====
fstab:
----#
# /etc/fstab
# Created by anaconda on Fri Jul 26 13:04:22 2024
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=6577c44f-9c1c-44f9-af56-6d6b505fcfa8 / xfs defaults 0 0
UUID=eec689b4-73d5-4f47-b999-9a585bb6da1d /boot xfs defaults 0 0
UUID=ED00-0E42 /boot/efi vfat umask=0077,shortname=winnt 0 2
#UUID=be2f2006-6072-4c77-83d4-f2ff5e237f9f none swap defaults 0 0rc.local:
----
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.touch /var/lock/subsys/local
mount /dev/cdrom /rhel9BinaryData
====Events: <none>
4.通过yaml文件创建
[root@master configmap]# kubectl create configmap test --from-literal name=lee --dry-run=client -o yaml > test.yml
[root@master configmap]# cat test.yml
apiVersion: v1
kind: ConfigMap
metadata:name: test
data:username: hashpassword: "123"
[root@master configmap]#[root@master configmap]# kubectl apply -f test.yml
configmap/test created
[root@master configmap]# kubectl describe -f test.yml
Name: test
Namespace: default
Labels: <none>
Annotations: <none>Data
====
password:
----
123
username:
----
hashBinaryData
====Events: <none>
[root@master configmap]#
6.2 secrets配置管理
6.2.1 功能介绍
-
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。
-
敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活
-
Pod 可以用两种方式使用 secret:
-
作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里。
-
当 kubelet 为 pod 拉取镜像时使用。
-
-
Secret的类型:
-
Service Account:Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改 pod 以使用此类型的 secret。
-
Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
-
kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息
-
6.2.2 创建
1. 从文件创建
[root@k8s-master secrets]# echo -n timi> username.txt
[root@k8s-master secrets]# echo -n xixi > password.txt
root@k8s-master secrets]# kubectl create secret generic userlist --from-file username.txt --from-file password.txt
secret/userlist created
[root@master secrets]# kubectl get secrets userlist -o yaml
apiVersion: v1
data:password: dGltaQ==username: eGl4aQ==
kind: Secret
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"v1","data":{"password":"dGltaQ==","username":"eGl4aQ=="},"kind":"Secret","metadata":{"annotations":{},"creationTimestamp":null,"name":"userlist","namespace":"default"},"type":"Opaque"}creationTimestamp: "2025-08-16T17:06:05Z"name: userlistnamespace: defaultresourceVersion: "178365"uid: 2432fd18-e1fe-4eb2-86e9-a4462126d96d
type: Opaque
编写yaml文件
[root@master secrets]# echo -n timi | base64
dGltaQ==
[root@master secrets]# echo -n xixi | base64
eGl4aQ==
[root@master secrets]#[root@master secrets]# cat userlist.yml
apiVersion: v1
kind: Secret
metadata:creationTimestamp: nullname: userlist
type: Opaque
data:username: eGl4aQ==password: dGltaQ==
[root@master secrets]#[root@master secrets]# kubectl describe secrets userlist
Name: userlist
Namespace: default
Labels: <none>
Annotations: <none>Type: OpaqueData
====
username: 4 bytes
password: 4 bytes
[root@master secrets]#
6.2.3 Secret的使用方法
6.2.3.1.将Secret挂载到Volume中
[root@master secrets]# cat nginx-sc.yml
apiVersion: v1
kind: Pod
metadata:labels:run: ngix-scname: ngix-sc
spec:containers:- image: nginxname: ngix-scvolumeMounts:- name: secretsmountPath: /secretreadOnly: truevolumes:- name: secretssecret:secretName: userlist
[root@master secrets]# kubectl apply -f nginx-sc.yml
pod/ngix-sc created
[root@master secrets]# kubectl exec pods/ngix-sc -it -- /bin/bash
root@ngix-sc:/# cd /secret/
root@ngix-sc:/secret# ls
password username
root@ngix-sc:/secret#
6.2.3.2.向指定路径映射 secret 密钥
#向指定路径映射
[root@k8s-master secrets]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:labels:run: nginx1name: nginx1
spec:containers:- image: nginxname: nginx1volumeMounts:- name: secretsmountPath: /secretreadOnly: truevolumes:- name: secretssecret:secretName: userlistitems:- key: usernamepath: my-users/username[root@k8s-master secrets]# kubectl apply -f pod2.yaml
pod/nginx1 created
[root@k8s-master secrets]# kubectl exec pods/nginx1 -it -- /bin/bash
root@nginx1:/# cd secret/
root@nginx1:/secret# ls
my-users
root@nginx1:/secret# cd my-users
root@nginx1:/secret/my-users# ls
username
root@nginx1:/secret/my-users# cat username
6.2.3.3.将Secret设置为环境变量
[root@k8s-master secrets]# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:labels:run: busyboxname: busybox
spec:containers:- image: busyboxname: busyboxcommand:- /bin/sh- -c- envenv:- name: USERNAMEvalueFrom:secretKeyRef:name: userlistkey: username- name: PASSvalueFrom:secretKeyRef:name: userlistkey: passwordrestartPolicy: Never
[root@k8s-master secrets]# kubectl apply -f pod3.yaml
pod/busybox created
[root@k8s-master secrets]# kubectl logs pods/busybox
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=busybox
MYAPP_V1_SERVICE_HOST=10.104.84.65
MYAPP_V2_SERVICE_HOST=10.105.246.219
SHLVL=1
HOME=/root
MYAPP_V1_SERVICE_PORT=80
MYAPP_V1_PORT=tcp://10.104.84.65:80
MYAPP_V2_SERVICE_PORT=80
MYAPP_V2_PORT=tcp://10.105.246.219:80
MYAPP_V1_PORT_80_TCP_ADDR=10.104.84.65
USERNAME=timinglee
MYAPP_V2_PORT_80_TCP_ADDR=10.105.246.219
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
。。。
6.2.3.4.存储docker registry的认证信息
建立私有仓库并上传镜像
#建立用于docker认证的secret[root@k8s-master secrets]# kubectl create secret docker-registry docker-auth --docker-server reg.timinglee.org --docker-username admin --docker-password lee --docker-email timinglee@timinglee.org
secret/docker-auth created
[root@master secrets]# cat myapp-sc.yml
apiVersion: v1
kind: Pod
metadata:labels:run: myapp-scname: myapp-sc
spec:containers:- image: reg.timinglee.org/test-sc/myapp:v1name: myapp-scimagePullSecrets: #不设定无法下载- name: docker-auth
[root@master secrets]#
未设置时
设置后
6.3volumes配置管理
-
容器中文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题
-
当容器崩溃时,kubelet将重新启动容器,容器中的文件将会丢失,因为容器会以干净的状态重建。
-
当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。
-
Kubernetes 卷具有明确的生命周期与使用它的 Pod 相同
-
卷比 Pod 中运行的任何容器的存活期都长,在容器重新启动时数据也会得到保留
-
当一个 Pod 不再存在时,卷也将不再存在。
-
Kubernetes 可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。
-
卷不能挂载到其他卷,也不能与其他卷有硬链接。 Pod 中的每个容器必须独立地指定每个卷的挂载位置。
6.3.1 emptyDir卷
[root@master volumes]# cat vo-pod.yml
apiVersion: v1
kind: Pod
metadata:labels:run: vo-podname: vo-pod
spec:containers:- image: nginxname: nginxvolumeMounts:- mountPath: /usr/share/nginx/htmlname: vo- image: busyboxplusname: busyboxcommand:- /bin/sh- -c- sleep 100000volumeMounts:- mountPath: /cachename: vovolumes:- name: voemptyDir:medium: MemorysizeLimit: 100Mi
[root@master volumes]#[root@master volumes]# kubectl get pods
NAME READY STATUS RESTARTS AGE
vo-pod 2/2 Running 0 6m16s
[root@master volumes]#[root@master volumes]# kubectl exec -it pods/vo-pod -c nginx -- /bin/bash
root@vo-pod:/# ls
bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var
root@vo-pod:/# cd /usr/share/nginx/html/
root@vo-pod:/usr/share/nginx/html# ls
index.html[root@master ~]# kubectl exec -it pods/vo-pod -c busybox -- /bin/sh
/ # cd cache/
/cache # ls
/cache # echo hello > index.html
/cache # ls
index.html
/cache # curl localhost
hello
/cache #
6.3.2 hostpath卷
[root@master volumes]# cat host-pod.yml
apiVersion: v1
kind: Pod
metadata:labels:run: host-podname: host-pod
spec:containers:- image: busyboxplusname: busyboxcommand:- /bin/sh- -c- sleep 100000volumeMounts:- mountPath: /cachename: vovolumes:- name: vohostPath:path: /datatype: DirectoryOrCreate #当目录不存在时自动创建,有则不管
[root@master volumes]#测试:
[root@master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
host-pod 1/1 Running 0 15s 10.244.2.7 node2 <none> <none>[root@master volumes]# kubectl exec -it pods/host-pod -- /bin/sh
/ # ls
bin dev home lib64 media opt root sbin tmp var
cache etc lib linuxrc mnt proc run sys usr
/
在node2上的根目录上自动创建了一个data目录
[root@node2 ~]# ls /
afs boot dev home lib64 mnt proc root sbin sys usr
bin data etc lib media opt rhel9.2 run srv tmp var
起初目录是空的
[root@node2 ~]# cd /data/
[root@node2 data]# ls
[root@node2 data]# touch hh{1..10}
[root@node2 data]# ls
hh1 hh10 hh2 hh3 hh4 hh5 hh6 hh7 hh8 hh9
[root@node2 data]#[root@master volumes]# kubectl exec -it pods/host-pod -- /bin/sh
/ # ls
bin dev home lib64 media opt root sbin tmp var
cache etc lib linuxrc mnt proc run sys usr
/ # cd cache/
/cache # ls #空的
/cache # ls #node2上创建文件后
hh1 hh10 hh2 hh3 hh4 hh5 hh6 hh7 hh8 hh9
#当容器停止了node2上的数据仍然存在
[root@master volumes]# kubectl delete -f host-pod.yml --force
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "host-pod" force deleted
[root@master volumes]# kubectl get pods
No resources found in default namespace.
[root@master volumes]#
#文件仍然存在
[root@node2 data]# ls
hh1 hh10 hh2 hh3 hh4 hh5 hh6 hh7 hh8 hh9
[root@node2 data]#
6.3.3nfs 卷
数据持久化存储和数据互通
#部署nfs主机
[root@reg ~]# dnf install nfs-utils -y
[root@reg ~]# systemctl enable --now nfs-server.service[root@reg ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)[root@reg ~]# exportfs -rv
exporting *:/nfsdata[root@reg ~]# showmount -e
Export list for reg.timinglee.org:
/nfsdata *#在k8s所有节点中安装nfs-utils
[root@k8s-master & node1 & node2 ~]# dnf install nfs-utils -y
[root@master volumes]# cat 1-nfs.yml && 2-nfs.yml
apiVersion: v1
kind: Pod
metadata:labels:run: nfs1 ##nfs2name: nfs1 ##nfs2
spec:containers:- image: nginxname: nginxvolumeMounts:- mountPath: /usr/share/nginx/htmlname: vovolumes:- name: vonfs:server: 192.168.217.200path: /nfs_data[root@master volumes]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs1 1/1 Running 0 21s 10.244.2.8 node2 <none> <none>
nfs2 1/1 Running 0 14s 10.244.2.9 node2 <none> <none>
[root@master volumes]# curl 10.244.2.8
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>
[root@master volumes]# kubectl exec -it pods/nfs1 -- /bin/bash
root@nfs1:/# ls
bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint.d etc lib media opt root sbin sys usr
root@nfs1:/# ls /
bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint.d etc lib media opt root sbin sys usr
root@nfs1:/# cd /usr/share/nginx/html/
root@nfs1:/usr/share/nginx/html# ls #空的
#写入数据
[root@reg ~]# cd /nfs_data/
[root@reg nfs_data]# ls
[root@reg nfs_data]# echo hello nfs > index.html
[root@reg nfs_data]# cat index.html
hello nfs
#一定要进去加载一下,否则不会挂载
root@nfs1:/usr/share/nginx/html# ls #同步
index.html
#再次访问:
[root@master volumes]# curl 10.244.2.8
hello nfs
[root@master volumes]# showmount -e 192.168.217.200
Export list for 192.168.217.200:
/nfs_data * #表示 /nfs_data目录被导出,允许所有客户端(* 表示任意主机)访问。#一个用于查询 NFS(Network File System)服务器导出共享目录的命令。这个命令会列出 IP 地址为 192.168.217.200 的 NFS 服务器上所有可供客户端挂载的共享目录。showmount:用于显示 NFS 服务器上的挂载信息。
-e:表示 "export",即显示 NFS 服务器导出的共享目录列表。
192.168.217.200:目标 NFS 服务器的 IP 地址。
6.3.4 PersistentVolume持久卷
PersistentVolume(持久卷,简称PV)
-
pv是集群内由管理员提供的网络存储的一部分。
-
PV也是集群中的一种资源。是一种volume插件,
-
但是它的生命周期却是和使用它的Pod相互独立的。
-
PV这个API对象,捕获了诸如NFS、ISCSI、或其他云存储系统的实现细节
-
pv有两种提供方式:静态和动态
-
静态PV:集群管理员创建多个PV,它们携带着真实存储的详细信息,它们存在于Kubernetes API中,并可用于存储使用
-
动态PV:当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass
-
PersistentVolumeClaim(持久卷声明,简称PVC)
-
是用户的一种存储请求
-
它和Pod类似,Pod消耗Node资源,而PVC消耗PV资源
-
Pod能够请求特定的资源(如CPU和内存)。PVC能够请求指定的大小和访问的模式持久卷配置
-
PVC与PV的绑定是一对一的映射。没找到匹配的PV,那么PVC会无限期得处于unbound未绑定状态
静态pv实例:
#在nfs主机中建立实验目录
[root@reg ~]# mkdir /nfsdata/pv{1..3}#编写创建pv的yml文件,pv是集群资源,不在任何namespace中
[root@k8s-master pvc]# vim pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:name: pv1
spec:capacity:storage: 5GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: RetainstorageClassName: nfsnfs:path: /nfsdata/pv1server: 172.25.254.250---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv2
spec:capacity:storage: 15GivolumeMode: FilesystemaccessModes:- ReadWriteManypersistentVolumeReclaimPolicy: RetainstorageClassName: nfsnfs:path: /nfsdata/pv2server: 172.25.254.250
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv3
spec:capacity:storage: 25GivolumeMode: FilesystemaccessModes:- ReadOnlyManypersistentVolumeReclaimPolicy: RetainstorageClassName: nfsnfs:path: /nfsdata/pv3server: 172.25.254.250[root@k8s-master pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pv1 5Gi RWO Retain Available nfs <unset> 4m50s
pv2 15Gi RWX Retain Available nfs <unset> 4m50s
pv3 25Gi ROX Retain Available nfs <unset> 4m50s#建立pvc,pvc是pv使用的申请,需要保证和pod在一个namesapce中
[root@k8s-master pvc]# vim pvc.ym
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc1
spec:storageClassName: nfsaccessModes:- ReadWriteOnceresources:requests:storage: 1Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc2
spec:storageClassName: nfsaccessModes:- ReadWriteManyresources:requests:storage: 10Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc3
spec:storageClassName: nfsaccessModes:- ReadOnlyManyresources:requests:storage: 15Gi
[root@k8s-master pvc]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
pvc1 Bound pv1 5Gi RWO nfs <unset> 5s
pvc2 Bound pv2 15Gi RWX nfs <unset> 4s
pvc3 Bound pv3 25Gi ROX nfs <unset> 4s#在其他namespace中无法应用
[root@k8s-master pvc]# kubectl -n kube-system get pvc
No resources found in kube-system namespace.
在pod中使用pvc
[root@k8s-master pvc]# vim pod.yml
apiVersion: v1
kind: Pod
metadata:name: timinglee
spec:containers:- image: nginxname: nginxvolumeMounts:- mountPath: /usr/share/nginx/htmlname: vol1volumes:- name: vol1persistentVolumeClaim:claimName: pvc1[root@k8s-master pvc]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
timinglee 1/1 Running 0 83s 10.244.2.54 k8s-node2 <none> <none>
[root@k8s-master pvc]# kubectl exec -it pods/timinglee -- /bin/bash
root@timinglee:/# curl localhost
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.27.1</center>
</body>
</html>
root@timinglee:/# cd /usr/share/nginx/
root@timinglee:/usr/share/nginx# ls
html
root@timinglee:/usr/share/nginx# cd html/
root@timinglee:/usr/share/nginx/html# ls[root@reg ~]# echo timinglee > /data/pv1/index.html[root@k8s-master pvc]# kubectl exec -it pods/timinglee -- /bin/bash
root@timinglee:/# cd /usr/share/nginx/html/
root@timinglee:/usr/share/nginx/html# ls
index.html [root@reg pv1]# echo hello pv > index.html
[root@reg pv1]# ls
index.html
[root@reg pv1]#[root@master volumes]# kubectl exec -it pods/pod -- /bin/bash
root@pod:/# cd /usr/share/nginx/html/
root@pod:/usr/share/nginx/html# ls
index.html
root@pod:/usr/share/nginx/html# curl localhost
hello pv
root@pod:/usr/share/nginx/html# exit
6.4 存储类storageclass
6.4.1 部署NFS Client Provisioner
1.创建sa并授权
[root@master volumes]# cat rbac.yml
apiVersion: v1
kind: Namespace
metadata:name: nfs-client-provisioner
---
apiVersion: v1
kind: ServiceAccount
metadata:name: nfs-client-provisionernamespace: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: nfs-client-provisioner-runner
rules:- apiGroups: [""]resources: ["nodes"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["events"]verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: run-nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: nfs-client-provisioner
roleRef:kind: ClusterRolename: nfs-client-provisioner-runnerapiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisionernamespace: nfs-client-provisioner
rules:- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisionernamespace: nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisionernamespace: nfs-client-provisioner
roleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: rbac.authorization.k8s.io
[root@master volumes]#
查看rbac信息
[root@master volumes]# kubectl -n nfs-client-provisioner get sa
NAME SECRETS AGE
default 0 15m
nfs-client-provisioner 0 15m
[root@master volumes]#
2.部署应用
[root@master volumes]# cat deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nfs-client-provisionerlabels:app: nfs-client-provisionernamespace: nfs-client-provisioner
spec:replicas: 1strategy:type: Recreateselector:matchLabels:app: nfs-client-provisionertemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisionercontainers:- name: nfs-client-provisionerimage: nfs-subdir-external-provisioner:v4.0.2volumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner- name: NFS_SERVERvalue: 192.168.217.200- name: NFS_PATHvalue: /nfs_datavolumes:- name: nfs-client-rootnfs:server: 192.168.217.200path: /nfs_data[root@master volumes]#[root@master volumes]# kubectl -n nfs-client-provisioner get deployments.apps nfs-client-provisioner
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 11m
[root@master volumes]#
3.创建存储类
[root@master volumes]# cat class.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:archiveOnDelete: "false"[root@master volumes]# kubectl apply -f class.yml
storageclass.storage.k8s.io/nfs-client created
[root@master volumes]# kubectl get storageclasses.storage.k8s.io
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 19s[root@master volumes]# cat class_pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: test-claim
spec:storageClassName: nfs-clientaccessModes:- ReadWriteManyresources:requests:storage: 1G
[root@master volumes]#
[root@master volumes]# kubectl apply -f class_pvc.yml
persistentvolumeclaim/test-claim created
[root@master volumes]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
test-claim Bound pvc-615dae92-dff6-426a-8934-8c216140352b 1G RWX nfs-client <unset> 11s
[root@master volumes]#
5. 创建pvc
[root@master storage]# cat class-pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: test-claim
spec:storageClassName: nfs-clientaccessModes:- ReadWriteManyresources:requests:storage: 1G
[root@master storage]#
[root@master storage]# kubectl apply -f class-pvc.yml
persistentvolumeclaim/test-claim created
5.创建测试pod
[root@k8s-master storageclass]# vim pod.yml
kind: Pod
apiVersion: v1
metadata:name: test-pod
spec:containers:- name: test-podimage: busyboxcommand:- "/bin/sh"args:- "-c"- "touch /mnt/SUCCESS && exit 0 || exit 1"volumeMounts:- name: nfs-pvcmountPath: "/mnt"restartPolicy: "Never"volumes:- name: nfs-pvcpersistentVolumeClaim:claimName: test-claim[root@k8s-master storageclass]# kubectl apply -f pod.yml[root@reg ~]# ls /data/default-test-claim-pvc-b1aef9cc-4be9-4d2a-8c5e-0fe7716247e2/
SUCCESS
6.设置默认存储类
-
在未设定默认存储类时pvc必须指定使用类的名称
-
在设定存储类后创建pvc时可以不用指定storageClassName
#一次性指定多个pvc
[root@k8s-master pvc]# vim pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc1
spec:storageClassName: nfs-clientaccessModes:- ReadWriteOnceresources:requests:storage: 1Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc2
spec:storageClassName: nfs-clientaccessModes:- ReadWriteManyresources:requests:storage: 10Gi---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: pvc3
spec:storageClassName: nfs-clientaccessModes:- ReadOnlyManyresources:requests:storage: 15Gi
设定默认存储类
[root@k8s-master storageclass]# kubectl edit sc nfs-client
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"nfs-client"},"parameters":{"archiveOnDelete":"false"},"provisioner":"k8s-sigs.io/nfs-subdir-external-provisioner"}storageclass.kubernetes.io/is-default-class: "true" #设定默认存储类creationTimestamp: "2024-09-07T13:49:10Z"name: nfs-clientresourceVersion: "218198"uid: 9eb1e144-3051-4f16-bdec-30c472358028
parameters:archiveOnDelete: "false"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate#测试,未指定storageClassName参数
[root@k8s-master storageclass]# vim pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: test-claim
spec:accessModes:- ReadWriteManyresources:requests:storage: 1Gi[root@k8s-master storageclass]# kubectl apply -f pvc.yml
persistentvolumeclaim/test-claim created
[root@k8s-master storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
test-claim Bound pvc-b96c6983-5a4f-440d-99ec-45c99637f9b5 1Gi RWX nfs-client <unset> 7s
6.5statefulset控制器
6.5.1 功能
- Statefulset是为了管理有状态服务的问题设计的
- StatefulSet将应用状态抽象成了两种情况:
- 拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样
- 存储状态:应用的多个实例分别绑定了不同存储数据。
- StatefulSet给所有的Pod进行了编号,编号规则是:$(statefulset名称)-$(序号),从0开始。
- Pod被删除后重建,重建Pod的网络标识也不会改变,Pod的拓扑状态按照Pod的“名字+编号”的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,Pod对应的DNS记录。
6.5.2 构建方法
#建立无头服务
kubectl create service clusterip my-headless-svc \--clusterip="None" \--tcp=80:8080 \--dry-run=client -o yaml > headless-service.yaml
[root@k8s-master statefulset]# vim headless.yml
apiVersion: v1
kind: Service
metadata:name: nginx-svclabels:app: nginx
spec:ports:- port: 80name: webclusterIP: Noneselector:app: nginx
[root@k8s-master statefulset]# kubectl apply -f headless.yml#建立statefulset
[root@k8s-master statefulset]# vim statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web
spec:serviceName: "nginx-svc"replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxvolumeMounts:- name: wwwmountPath: /usr/share/nginx/htmlvolumeClaimTemplates:- metadata:name: wwwspec:storageClassName: nfs-clientaccessModes:- ReadWriteOnceresources:requests:storage: 1Gi
[root@k8s-master statefulset]# kubectl apply -f statefulset.yml
statefulset.apps/web configured
root@k8s-master statefulset]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 3m26s
web-1 1/1 Running 0 3m22s
web-2 1/1 Running 0 3m18s[root@reg nfsdata]# ls /nfsdata/
default-test-claim-pvc-34b3d968-6c2b-42f9-bbc3-d7a7a02dcbac
default-www-web-0-pvc-0390b736-477b-4263-9373-a53d20cc8f9f
default-www-web-1-pvc-a5ff1a7b-fea5-4e77-afd4-cdccedbc278c
default-www-web-2-pvc-83eff88b-4ae1-4a8a-b042-8899677ae854
七 k8s中网络通信与调度
7.1 通信架构
-
k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等
-
CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist
-
插件使用的解决方案如下
-
虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
-
多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
-
硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。
-
-
容器间通信:
-
同一个pod内的多个容器间的通信,通过lo即可实现pod之间的通信
-
同一节点的pod之间通过cni网桥转发数据包。
-
不同节点的pod之间的通信需要网络插件支持
-
-
pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换
-
pod和外网通信:iptables的MASQUERADE
-
Service与集群外部客户端的通信;(ingress、nodeport、loadbalancer)
flannel网络插件
插件 | 功能 |
---|---|
VXLAN | 即Virtual Extensible LAN(虚拟可扩展局域网),是Linux本身支持的一网种网络虚拟化技术。VXLAN可以完全在内核态实现封装和解封装工作,从而通过“隧道”机制,构建出覆盖网络(Overlay Network) |
VTEP | VXLAN Tunnel End Point(虚拟隧道端点),在Flannel中 VNI的默认值是1,这也是为什么宿主机的VTEP设备都叫flannel.1的原因 |
Cni0 | 网桥设备,每创建一个pod都会创建一对 veth pair。其中一端是pod中的eth0,另一端是Cni0网桥中的端口(网卡) |
Flannel.1 | TUN设备(虚拟网卡),用来进行 vxlan 报文的处理(封包和解包)。不同node之间的pod数据流量都从overlay设备以隧道的形式发送到对端 |
Flanneld | flannel在每个主机中运行flanneld作为agent,它会为所在主机从集群的网络地址空间中,获取一个小的网段subnet,本主机内所有容器的IP地址都将从中分配。同时Flanneld监听K8s集群数据库,为flannel.1设备提供封装数据时必要的mac、ip等网络数据信息 |
原理
- 当容器发送IP包,通过veth pair 发往cni网桥,再路由到本机的flannel.1设备进行处理。
- VTEP设备之间通过二层数据帧进行通信,源VTEP设备收到原始IP包后,在上面加上一个目的MAC地址,封装成一个内部数据帧,发送给目的VTEP设备。
- 内部数据桢,并不能在宿主机的二层网络传输,Linux内核还需要把它进一步封装成为宿主机的一个普通的数据帧,承载着内部数据帧通过宿主机的eth0进行传输。
- Linux会在内部数据帧前面,加上一个VXLAN头,VXLAN头里有一个重要的标志叫VNI,它是VTEP识别某个数据桢是不是应该归自己处理的重要标识。
- flannel.1设备只知道另一端flannel.1设备的MAC地址,却不知道对应的宿主机地址是什么。在linux内核里面,网络设备进行转发的依据,来自FDB的转发数据库,这个flannel.1网桥对应的FDB信息,是由flanneld进程维护的。
- linux内核在IP包前面再加上二层数据帧头,把目标节点的MAC地址填进去,MAC地址从宿主机的ARP表获取。
- 此时flannel.1设备就可以把这个数据帧从eth0发出去,再经过宿主机网络来到目标节点的eth0设备。目标主机内核网络栈会发现这个数据帧有VXLAN Header,并且VNI为1,Linux内核会对它进行拆包,拿到内部数据帧,根据VNI的值,交给本机flannel.1设备处理,flannel.1拆包,根据路由表发往cni网桥,最后到达目标容器。
calico网络插件
-
纯三层的转发,中间没有任何的NAT和overlay,转发效率最好。
-
Calico 仅依赖三层路由可达。Calico 较少的依赖性使它能适配所有 VM、Container、白盒或者混合环境场景。
-
Felix:监听ECTD中心的存储获取事件,用户创建pod后,Felix负责将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。同样如果用户制定了隔离策略,Felix同样会将该策略创建到ACL中,以实现隔离。
-
BIRD:一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,路由的时候到这里
部署:
删除flannel插件
[root@k8s-master ~]# kubectl delete -f kube-flannel.yml删除所有节点上flannel配置文件,避免冲突
[root@k8s-master & node1-2 ~]# rm -rf /etc/cni/net.d/10-flannel.conflist下载部署文件
[root@k8s-master calico]# curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico-typha.yaml -o calico.yaml下载镜像上传至仓库:
[root@k8s-master ~]# docker pull docker.io/calico/cni:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/node:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/kube-controllers:v3.28.1
[root@k8s-master ~]# docker pull docker.io/calico/typha:v3.28.1更改yml设置
[root@k8s-master calico]# vim calico.yaml
4835 image: calico/cni:v3.28.1
4835 image: calico/cni:v3.28.1
4906 image: calico/node:v3.28.1
4932 image: calico/node:v3.28.1
5160 image: calico/kube-controllers:v3.28.1
5249 - image: calico/typha:v3.28.14970 - name: CALICO_IPV4POOL_IPIP
4971 value: "Never"4999 - name: CALICO_IPV4POOL_CIDR
5000 value: "10.244.0.0/16"
5001 - name: CALICO_AUTODETECTION_METHOD
5002 value: "interface=eth0"[root@k8s-master calico]# kubectl apply -f calico.yaml
[root@k8s-master calico]# kubectl -n kube-system get pods
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-6849cb478c-g5h5p 1/1 Running 0 75s
calico-node-dzzjp 1/1 Running 0 75s
calico-node-ltz7n 1/1 Running 0 75s
calico-node-wzdnq 1/1 Running 0 75s
calico-typha-fff9df85f-vm5ks 1/1 Running 0 75s
coredns-647dc95897-nchjr 1/1 Running 1 (139m ago) 4d7h
coredns-647dc95897-wjbg2 1/1 Running 1 (139m ago) 4d7h
etcd-k8s-master 1/1 Running 1 (139m ago) 4d7h
kube-apiserver-k8s-master 1/1 Running 1 (139m ago) 3d10h
kube-controller-manager-k8s-master 1/1 Running 3 (139m ago) 4d7h
kube-proxy-9g5z2 1/1 Running 1 (139m ago) 3d10h
kube-proxy-cd5wk 1/1 Running 1 (139m ago) 3d10h
kube-proxy-mvq4c 1/1 Running 1 (139m ago) 3d10h
kube-scheduler-k8s-master 1/1 Running 3 (139m ago) 4d7h测试:
[root@k8s-master calico]# kubectl run web --image myapp:v1
pod/web created
[root@k8s-master calico]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 5s 10.244.169.129 k8s-node2 <none> <none>
[root@k8s-master calico]# curl 10.244.169.129
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
7.2 k8s调度器
7.2.1 作用:
-
调度是指将未调度的Pod自动分配到集群中的节点的过程
-
调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod
-
调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行
7.2.2 原理:
-
创建Pod
-
用户通过Kubernetes API创建Pod对象,并在其中指定Pod的资源需求、容器镜像等信息。
-
-
调度器监视Pod
-
Kubernetes调度器监视集群中的未调度Pod对象,并为其选择最佳的节点。
-
-
选择节点
-
调度器通过算法选择最佳的节点,并将Pod绑定到该节点上。调度器选择节点的依据包括节点的资源使用情况、Pod的资源需求、亲和性和反亲和性等。
-
-
绑定Pod到节点
-
调度器将Pod和节点之间的绑定信息保存在etcd数据库中,以便节点可以获取Pod的调度信息。
-
-
节点启动Pod
-
节点定期检查etcd数据库中的Pod调度信息,并启动相应的Pod。如果节点故障或资源不足,调度器会重新调度Pod,并将其绑定到其他节点上运行。
-
7.2.3 方法
1.nodename
-
nodeName 是节点选择约束的最简单方法,但一般不推荐
-
如果 nodeName 在 PodSpec 中指定了,则它优先于其他的节点选择方法
-
使用 nodeName 来选择节点的一些限制
-
如果指定的节点不存在。
-
如果指定的节点没有资源来容纳 pod,则pod 调度失败。
-
云环境中的节点名称并非总是可预测或稳定的
-
#建立pod文件
[[root@k8s-master scheduler]# kubectl run testpod --image myapp:v1 --dry-run=client -o yaml > pod1.yml#设置调度
[root@k8s-master scheduler]# vim pod1.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:nodeName: node2containers:- image: myapp:v1name: testpod#建立pod
[root@k8s-master scheduler]# kubectl apply -f pod1.yml
pod/testpod created[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 18s 10.244.169.130 k8s-node2 <none> <none>
2.Nodeselector(通过标签控制节点)
-
nodeSelector 是节点选择约束的最简单推荐形式
-
给选择的节点添加标签:
kubectl label nodes k8s-node1 lab=lee
-
可以给多个节点设定相同标签
#查看节点标签
[root@k8s-master scheduler]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane 5d3h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-node1 Ready <none> 5d3h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 5d3h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux#设定节点标签
[root@k8s-master scheduler]# kubectl label nodes k8s-node1 lab=timinglee
node/k8s-node1 labeled
#取消标签:
kubectl label node k8s-node1 lab-[root@k8s-master scheduler]# kubectl get nodes k8s-node1 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-node1 Ready <none> 5d3h v1.30.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux,lab=timinglee#调度设置
[root@k8s-master scheduler]# vim pod2.yml
apiVersion: v1
kind: Pod
metadata:labels:run: testpodname: testpod
spec:nodeSelector:lab: timingleecontainers:- image: myapp:v1name: testpod[root@k8s-master scheduler]# kubectl apply -f pod2.yml
pod/testpod created
[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testpod 1/1 Running 0 4s 10.244.36.65 k8s-node1 <none> <none>
7.3 affinity(亲和性)
官方文档 :
将 Pod 指派给节点 | Kubernetes
nodeAffinity节点亲和
-
那个节点服务指定条件就在那个节点运行
-
requiredDuringSchedulingIgnoredDuringExecution 必须满足,但不会影响已经调度
-
preferredDuringSchedulingIgnoredDuringExecution 倾向满足,在无法满足情况下也会调度pod
-
IgnoreDuringExecution 表示如果在Pod运行期间Node的标签发生变化,导致亲和性策略不能满足,则继续运行当前的Pod。
-
-
nodeaffinity还支持多种规则匹配条件的配置如
#给node1打上标签
[root@master scheduler]# kubectl label nodes node1 disk=haha
node/node1 labeled
[root@master scheduler]# kubectl get nodes -l disk=haha
NAME STATUS ROLES AGE VERSION
node1 Ready <none> 8d v1.30.0#In
[root@master scheduler]# cat node-p.yml
apiVersion: v1
kind: Pod
metadata:name: node-affinity
spec:containers:- name: nginximage: nginxaffinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: diskoperator: Invalues:- haha#node1上有这个标签所以在这个列表值内
#所以运行在node1上
[root@master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity 1/1 Running 0 28s 192.168.166.130 node1 <none> <none>
[root@master scheduler]##NotIn
[root@master scheduler]# cat node-p.yml
apiVersion: v1
kind: Pod
metadata:name: node-affinity
spec:containers:- name: nginximage: nginxaffinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: diskoperator: NotInvalues:- haha
#NOTin:label 的值不在列表内
#node2上没有这个标签所有不在列表值内所有会在node2上运行
[root@master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity 1/1 Running 0 17s 192.168.104.1 node2 <none> <none>
[root@master scheduler]#
Podaffinity(pod的亲和)
-
那个节点有符合条件的POD就在那个节点运行
-
podAffinity 主要解决POD可以和哪些POD部署在同一个节点中的问题
-
podAntiAffinity主要解决POD不能和哪些POD部署在同一个节点中的问题。它们处理的是Kubernetes集群内部POD和POD之间的关系。
-
Pod 间亲和与反亲和在与更高级别的集合(例如 ReplicaSets,StatefulSets,Deployments 等)一起使用时,
-
Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。
[root@k8s-master scheduler]# vim example4.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxaffinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: "kubernetes.io/hostname"[root@k8s-master scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-658496fff-d58bk 1/1 Running 0 39s 10.244.169.133 k8s-node2 <none> <none>
nginx-deployment-658496fff-g25nq 1/1 Running 0 39s 10.244.169.134 k8s-node2 <none> <none>
nginx-deployment-658496fff-vnlxz 1/1 Running 0 39s 10.244.169.135 k8s-node2 <none> <none>
Podantiaffinity(pod反亲和)
[root@master scheduler]# cat antaffinity.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deploymentlabels:app: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxaffinity:podAntiAffinity: #反亲和requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: "kubernetes.io/hostname"
[root@master scheduler]#
7.4 Taints(污点模式,禁止调度)
-
Taints(污点)是Node的一个属性,设置了Taints后,默认Kubernetes是不会将Pod调度到这个Node上
-
Kubernetes如果为Pod设置Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去
-
可以使用命令 kubectl taint 给节点增加一个 taint:
$ kubectl taint nodes <nodename> key=string:effect #命令执行方法
$ kubectl taint nodes node1 key=value:NoSchedule #创建
$ kubectl describe nodes server1 | grep Taints #查询
$ kubectl taint nodes node1 key- #删除
[effect] 可取值:
effect值 | 解释 |
---|---|
NoSchedule | POD 不会被调度到标记为 taints 节点 |
PreferNoSchedule | NoSchedule 的软策略版本,尽量不调度到此节点 |
NoExecute | 如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出 |
示例:
[root@master scheduler]# cat tain1.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: webname: web
spec:replicas: 2selector:matchLabels:app: webtemplate:metadata:labels:app: webspec:containers:- image: nginxname: nginx[root@master scheduler]# kubectl apply -f tain1.yml
deployment.apps/web created
[root@master scheduler]#
[root@master scheduler]# kubectl taint node node1 Taintype=badnode:NoSchedule
node/node1 tainted
增加容器
[root@master scheduler]# kubectl scale deployment web --replicas 4
deployment.apps/web scaled
#去掉node1上的污点标记
[root@master scheduler]# kubectl taint node node1 Taintype-
node/node1 untainted
#将node2设置为NoExecute即驱赶,将已有的驱赶到其他节点上
[root@master scheduler]# kubectl taint node node2 Taintype=badnode:NoExecute
node/node2 tainted
[root@master scheduler]#
tolerations(污点容忍)
-
tolerations中定义的key、value、effect,要与node上设置的taint保持一直:
-
如果 operator 是 Equal ,则key与value之间的关系必须相等。
-
如果 operator 是 Exists ,value可以省略
-
如果不指定operator属性,则默认值为Equal。
-
-
还有两个特殊值:
-
当不指定key,再配合Exists 就能匹配所有的key与value ,可以容忍所有污点。
-
当不指定effect ,则匹配所有的effect
-
#设定节点污点
[root@k8s-master scheduler]# kubectl taint node k8s-node1 name=lee:NoExecute
node/k8s-node1 tainted
[root@k8s-master scheduler]# kubectl taint node k8s-node2 nodetype=bad:NoSchedule
node/k8s-node2 tainted[root@k8s-master scheduler]# vim example7.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: webname: web
spec:replicas: 6selector:matchLabels:app: webtemplate:metadata:labels:app: webspec:containers:- image: nginxname: nginx#写一种即可tolerations: #容忍所有污点- operator: Existstolerations: #容忍effect为Noschedule的污点- operator: Existseffect: NoScheduletolerations: #容忍指定kv的NoSchedule污点- key: nodetypevalue: badeffect: NoSchedule
八 kubernetes中的认证授权
8.1 kubernetes API 访问控制
Authentication(认证)
-
认证方式现共有8种,可以启用一种或多种认证方式,只要有一种认证方式通过,就不再进行其它方式的认证。通常启用X509 Client Certs和Service Accout Tokens两种认证方式。
-
Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和(Users Accounts) 普通账户。k8s中账号的概念不是我们理解的账号,它并不真的存在,它只是形式上存在。
Authorization(授权)
-
必须经过认证阶段,才到授权请求,根据所有授权策略匹配请求资源属性,决定允许或拒绝请求。授权方式现共有6种,AlwaysDeny、AlwaysAllow、ABAC、RBAC、Webhook、Node。默认集群强制开启RBAC。
Admission Control(准入控制)
-
用于拦截请求的一种方式,运行在认证、授权之后,是权限认证链上的最后一环,对请求API资源对象进行修改和校验。
UserAccount与ServiceAccount
-
用户账户是针对人而言的。 服务账户是针对运行在 pod 中的进程而言的。
-
用户账户是全局性的。 其名称在集群各 namespace 中都是全局唯一的,未来的用户资源不会做 namespace 隔离, 服务账户是 namespace 隔离的。
-
集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 ( 即权限最小化原则 )。
ServiceAccount
-
服务账户控制器(Service account controller)
-
服务账户管理器管理各命名空间下的服务账户
-
每个活跃的命名空间下存在一个名为 “default” 的服务账户
-
-
服务账户准入控制器(Service account admission controller)
-
相似pod中 ServiceAccount默认设为 default。
-
保证 pod 所关联的 ServiceAccount 存在,否则拒绝该 pod。
-
如果pod不包含ImagePullSecrets设置那么ServiceAccount中的ImagePullSecrets 被添加到pod中
-
将挂载于 /var/run/secrets/kubernetes.io/serviceaccount 的 volumeSource 添加到 pod 下的每个容器中
-
将一个包含用于 API 访问的 token 的 volume 添加到 pod 中
-
ServiceAccount示例:
建立名字为admin的ServiceAccount
[root@k8s-master ~]# kubectl create sa timinglee
serviceaccount/timinglee created
[root@k8s-master ~]# kubectl describe sa timinglee
Name: timinglee
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>建立secrets
[root@k8s-master ~]# kubectl create secret docker-registry docker-login --docker-username admin --docker-password 123 --docker-server reg.timinglee.org --docker-email lee@timinglee.org
secret/docker-login created
[root@k8s-master ~]# kubectl describe secrets docker-login
Name: docker-login
Namespace: default
Labels: <none>
Annotations: <none>Type: kubernetes.io/dockerconfigjsonData
====
.dockerconfigjson: 119 bytes将secrets注入到sa中
imagePullSecrets:
- name: docker-auth[root@k8s-master ~]# kubectl edit sa timinglee
apiVersion: v1
imagePullSecrets:
- name: docker-login
kind: ServiceAccount
metadata:creationTimestamp: "2024-09-08T15:44:04Z"name: timingleenamespace: defaultresourceVersion: "262259"uid: 7645a831-9ad1-4ae8-a8a1-aca7b267ea2d[root@k8s-master ~]# kubectl describe sa timinglee
Name: timinglee
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: docker-login
Mountable secrets: <none>
Tokens: <none>
Events: <none>建立私有仓库并且利用pod访问私有仓库
在创建pod时会镜像下载会受阻,因为docker私有仓库下载镜像需要认证
[root@k8s-master auth]# vim example1.yml
[root@k8s-master auth]# kubectl apply -f example1.yml
pod/testpod created
[root@k8s-master auth]# kubectl describe pod testpodWarning Failed 5s kubelet Failed to pull image "reg.timinglee.org/lee/nginx:latest": Error response from daemon: unauthorized: unauthorized to access repository: lee/nginx, action: pull: unauthorized to access repository: lee/nginx, action: pullWarning Failed 5s kubelet Error: ErrImagePullNormal BackOff 3s (x2 over 4s) kubelet Back-off pulling image "reg.timinglee.org/lee/nginx:latest"Warning Failed 3s (x2 over 4s) kubelet Error: ImagePullBackOffpod绑定sa[root@k8s-master auth]# vim example1.yml
apiVersion: v1
kind: Pod
metadata:name: testpod
spec:serviceAccountName: timingleecontainers:- image: reg.timinglee.org/lee/nginx:latestname: testpod[root@k8s-master auth]# kubectl apply -f example1.yml
pod/testpod created
[root@k8s-master auth]# kubectl get pods
NAME READY STATUS RESTARTS AGE
testpod 1/1 Running 0 2s
8.2 认证(创建认证用户)
8.2.1 创建UserAccount
#建立证书
[root@k8s-master auth]# cd /etc/kubernetes/pki/
[root@master pki]# openssl genrsa -out hello.key 2048
[root@master pki]# openssl req -new -key hello.key -out hello.csr -subj "/CN=hello"
[root@master pki]# openssl x509 -req -in hello.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out hello.crt -days 365
Certificate request self-signature ok
subject=CN = hello[root@k8s-master pki]# openssl x509 -in timinglee.crt -text -noout
Certificate:Data:Version: 1 (0x0)Serial Number:76:06:6c:a7:36:53:b9:3f:5a:6a:93:3a:f2:e8:82:96:27:57:8e:58Signature Algorithm: sha256WithRSAEncryptionIssuer: CN = kubernetesValidityNot Before: Sep 8 15:59:55 2024 GMTNot After : Sep 8 15:59:55 2025 GMTSubject: CN = timingleeSubject Public Key Info:Public Key Algorithm: rsaEncryptionPublic-Key: (2048 bit)Modulus:00:a6:6d:be:5d:7f:4c:bf:36:96:dc:4e:1b:24:64:f7:4b:57:d3:45:ad:e8:b5:07:e7:78:2b:9e:6e:53:2f:16:ff:00:f4:c8:41:2c:89:3d:86:7c:1b:16:08:2e:2c:bc:2c:1e:df:60:f0:80:60:f9:79:49:91:1d:9f:47:16:9a:d1:86:c7:4f:02:55:27:12:93:b7:f4
...
#建立k8s中的用户
[root@master pki]# kubectl config set-credentials timi --client-certificate /etc/kubernetes/pki/hello.crt --client-key /etc/kubernetes/pki/hello.key --embed-certs=true
User "timi" set.
[root@master pki]#[root@master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:certificate-authority-data: DATA+OMITTEDserver: https://192.168.217.100:6443name: kubernetes
contexts:
- context:cluster: kubernetesuser: kubernetes-adminname: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-adminuser:client-certificate-data: DATA+OMITTEDclient-key-data: DATA+OMITTED
- name: timiuser:client-certificate-data: DATA+OMITTEDclient-key-data: DATA+OMITTED#为用户创建集群的安全上下文
[root@master pki]# kubectl config set-context timi@kubernetes --cluster kubernetes --user timi
Context "timi@kubernetes" created.
[root@master pki]##切换用户,用户在集群中只有用户身份没有授权
[root@master pki]# kubectl config use-context timi@kubernetes
Switched to context "timi@kubernetes".
[root@master pki]# kubectl get pods
Error from server (Forbidden): pods is forbidden: User "hello" cannot list resource "pods" in API group "" in the namespace "default"
[root@master pki]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
[root@master pki]##切换会集群管理
[root@k8s-master ~]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".#如果需要删除用户
[root@k8s-master pki]# kubectl config delete-user timinglee
deleted user timinglee from /etc/kubernetes/admin.conf
8.2.2 RBAC(Role Based Access Control)
基于角色访问控制授权:
-
允许管理员通过Kubernetes API动态配置授权策略。RBAC就是用户通过角色与权限进行关联。
-
RBAC只有授权,没有拒绝授权,所以只需要定义允许该用户做什么即可
-
RBAC的三个基本概念
-
Subject:被作用者,它表示k8s中的三类主体, user, group, serviceAccount
-
-
Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
-
RoleBinding:定义了“被作用者”和“角色”的绑定关系
-
RBAC包括四种类型:Role、ClusterRole、RoleBinding、ClusterRoleBinding
-
Role 和 ClusterRole
-
Role是一系列的权限的集合,Role只能授予单个namespace 中资源的访问权限。
-
-
ClusterRole 跟 Role 类似,但是可以在集群中全局使用。
-
Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用
-
cluster-amdin、admin、edit、view
rrole授权实施
#生成role的yaml文件
[root@k8s-master rbac]# kubectl create role myrole --dry-run=client --verb=get --resource pods -o yaml > myrole.yml#更改文件内容
[root@k8s-master rbac]# vim myrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:creationTimestamp: nullname: myrole
rules:
- apiGroups:- ""resources:- podsverbs:- get- watch- list- create- update- path- delete#创建role
[root@k8s-master rbac]# kubectl apply -f myrole.yml
[root@k8s-master rbac]# kubectl describe role myrole
Name: myrole
Labels: <none>
Annotations: <none>
PolicyRule:Resources Non-Resource URLs Resource Names Verbs--------- ----------------- -------------- -----pods [] [] [get watch list create update path delete]
#建立角色绑定
[root@k8s-master rbac]# kubectl create rolebinding timinglee --role myrole --namespace default --user hello --dry-run=client -o yaml > rolebinding-myrole.yml[root@master role]# cat rolebinding-myrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: timinamespace: default #角色绑定必须指定namespace
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: myrole
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: hello
[root@master role]#[root@k8s-master rbac]# kubectl apply -f rolebinding-myrole.yml
rolebinding.rbac.authorization.k8s.io/timi created
[root@k8s-master rbac]# kubectl get rolebindings.rbac.authorization.k8s.io timi
NAME ROLE AGE
timi Role/myrole 9s
#切换用户测试授权
[root@k8s-master rbac]# kubectl config use-context timinglee@kubernetes
Switched to context "timi@kubernetes".[root@k8s-master rbac]# kubectl get pods
No resources found in default namespace.
[root@k8s-master rbac]# kubectl get svc #只针对pod进行了授权,所以svc依然不能操作
Error from server (Forbidden): services is forbidden: User "hello" cannot list resource "services" in API group "" in the namespace "default"#切换回管理员
[root@k8s-master rbac]# kubectl config use-context kubernetes-admin@kubernetes
Switched to context "kubernetes-admin@kubernetes".
clusterrole授权实施
#建立集群角色
[root@k8s-master rbac]# kubectl create clusterrole myclusterrole --resource=deployment --verb get --dry-run=client -o yaml > myclusterrole.yml
[root@master role]# cat myclusterrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: myclusterrole
rules:
- apiGroups:- appsresources:- deploymentsverbs:- get- list- watch- create- update- path- delete
- apiGroups:- ""resources:- podsverbs:- get- list- watch- create- update- path- delete
- apiGroups:- ""resources:- servicesverbs:- get- list- watch- create- update- path- delete
[root@master role]#[root@master role]# kubectl describe clusterrole myclusterrole
Name: myclusterrole
Labels: <none>
Annotations: <none>
PolicyRule:Resources Non-Resource URLs Resource Names Verbs--------- ----------------- -------------- -----pods [] [] [get list watch create update path delete]services [] [] [get list watch create update path delete]deployments.apps [] [] [get list watch create update path delete]
[root@master role]##建立集群角色绑定
[root@k8s-master rbac]# kubectl create clusterrolebinding clusterrolebind-myclusterrole --clusterrole myclusterrole --user hello --dry-run=client -o yaml > clusterrolebind-myclusterrole.yml[root@master role]# cat clusterrolebind-myclusterrole.yml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: clusterrolebind-myclusterrole
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: myclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: hello
[root@master role]#[root@master role]# kubectl describe clusterrolebindings.rbac.authorization.k8s.io clusterrolebind-myclusterrole
Name: clusterrolebind-myclusterrole
Labels: <none>
Annotations: <none>
Role:Kind: ClusterRoleName: myclusterrole
Subjects:Kind Name Namespace---- ---- ---------User hello
[root@master role]##测试:
[root@k8s-master rbac]# kubectl get pods -A
[root@k8s-master rbac]# kubectl get deployments.apps -A
[root@k8s-master rbac]# kubectl get svc -A
Error from server (Forbidden): services is forbidden: User "timinglee" cannot list resource "services" in API group "" at the cluster scope