k8s 概述
K8s 概述1. 基础知识1. kubernets 是什么Kubernetes是一个轻便、可扩展的开源平台,用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中,会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Google生产环境运行工作负载15年的经验,并吸收了来自于社区的最佳想法和实践。Kubernet
K8s 概述
1. 基础知识
1. kubernets 是什么
Kubernetes是一个轻便、可扩展的开源平台,用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中,会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Google生产环境运行工作负载15年的经验,并吸收了来自于社区的最佳想法和实践。Kubernetes经过这几年的快速发展,形成了一个大的生态环境,Google在2014年将Kubernetes作为开源项目。
2. Kubernetes的关键特性包括:
- 自动化装箱:在不牺牲可用性的条件下,基于容器对资源的要求和约束自动部署容器。同时,为了提高利用率和节省更多资源,将关键和最佳工作量结合在一起。
- 自愈能力:当容器失败时,会对容器进行重启;当所部署的Node节点有问题时,会对容器进行重新部署和重新调度;当容器未通过监控检查时,会关闭此容器;直到容器正常运行时,才会对外提供服务。
- 水平扩容:通过简单的命令、用户界面或基于CPU的使用情况,能够对应用进行扩容和缩容。
- 服务发现和负载均衡:开发者不需要使用额外的服务发现机制,就能够基于Kubernetes进行服务发现和负载均衡。
- 自动发布和回滚:Kubernetes能够程序化的发布应用和相关的配置。如果发布有问题,Kubernetes将能够回归发生的变更。
- 保密和配置管理:在不需要重新构建镜像的情况下,可以部署和更新保密和应用配置。
- 存储编排:自动挂接存储系统,这些存储系统可以来自于本地、公共云提供商(例如:GCP和AWS)、网络存储(例如:NFS、iSCSI、Gluster、Ceph、Cinder和Floker等)。
2.kubernets 架构介绍
- APISERVER:所有服务访问的统一接口
- CrontrollerManager:维持副本期望值数目
- Scheduler:负载介绍任务,选择合适的节点进行任务的分配
- ETCD:键值对数据库,存储k8s集群所有重要信息(持久化)
- kubelet:直接跟容器引擎交互实现容器的生命周期管理
- kube-proxy:负责写入规则至 IPTABLES、IPVS 实现服务映射访问
- COREDNS:可以为集群中SVC(交换虚拟电路)创建一个域名IP的对应关系解析
- DASHBOARD:给 K8S 集群提供一个 B/S (浏览器/服务器模式)结构访问解析
- INGRESS CONTROLLER:官方只能实现四层代理,INGRESS 可以实现七层代理
3. Pod 介绍
自主式 pod:
- 自主式就是没有控制器管理的 pod,而 pod 就是多个容器的集合。
- 这些容器的网络【容器开放的端口必须一致】和存储卷都和 pause 容器共享。
- 在开启一个pod的时候,必然会开启 pause。
控制器管理的 pod:
- RC 用来确保应用容器的副本数量始终和用户定义的数量一致。
- RS 在 RC 基础上,支持集合式的 selector(用标签批量操作pod)
- deployment:管理多个 RS 然后再创建 pod ,并且可以创建新版本的RS,当新的 RS 创建之后,会停用老版本的RS而不是删除。
- HPA:仅适用于Deployment 和RS ,在V1 版本中仅支持根据Pod 的CPU 利用率扩所容,比如设置当 pod 的 cpu 利用率达到 80% 时就扩容新的 pod。
- StatefulSet:是为了解决有状态服务的问题,比如数据库这种和用户交互的服务。
- DaemonSet :当有Node 加入集群时,也会为他们新增一个Pod 。应用场景为:运行集群存储daemon、日志收集、服务监控
- Job :负责批处理任务,保证批处理任务的一个或多个Pod 成功结束,即定时任务
4. 网络通讯方式
综述:
Kubernetes 的网络模型假定了所有Pod 都在一个可以直接连通的扁平的网络空间中【都在同一个网段,彼此可以互相ping通】,这在GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在。而在私有云里搭建Kubernetes 集群,我们需要自己实现这个网络假设,将不同节点上的Docker 容器之间的互相访问先打通,然后运行Kubernete。
不同 pod 同一主机之间的通讯:
Pod1 与Pod2 在同一台机器,由Docker0 网桥直接转发请求至Pod2。
不同 pod 不同主机之间的通讯:
Pod的地址是与 docker0 在同一个网段的,但 docker0 网段与宿主机网卡是两个完全不同的IP网段,并且不同Node之间的通信只能通过宿主机的物理网卡进行。将Pod的IP和所在Node的IP关联起来,通过这个关联让Pod可以互相访问。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R9LrBpAl-1653055923912)(D:\云计算工坊\图片\K8S\Snipaste_2021-05-25_10-18-09.png)]
不同层级的通讯:
如搭建 LAMP 和 Nginx 时,Nginx 要反向代理 Apache 集群,就不是直接访问 Apache 集群,而是通过访问 service,再访问 Nginx。外网访问也是如此。
2. K8S 集群部署
-
环境准备
172.16.1.142 -master # 主节点 172.16.1.143 -n001 # 从节点 01 172.16.1.144 -n002 # 从节点 02
-
系统优化
# 安装依赖包 yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wgetvimnet-tools git # 设置防火墙为 Iptables 并设置空规则 systemctl stop firewalld && systemctl disable firewalldyum -y install iptables-services && systemctl start iptables && systemctl enable iptables&& iptables -F && service iptables save # 关闭 Selinux swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab # 禁用 sawpoff setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config # 调整内核参数,对于 K8S cat > kubernetes.conf <<EOF net.bridge.bridge-nf-call-iptables=1 net.bridge.bridge-nf-call-ip6tables=1 net.ipv4.ip_forward=1 net.ipv4.tcp_tw_recycle=0 vm.swappiness=0 vm.overcommit_memory=1 fs.inotify.max_user_instances=8192 fs.inotify.max_user_watches=1048576 fs.file-max=52706963 fs.nr_open=52706963 net.ipv6.conf.all.disable_ipv6=1 net.netfilter.nf_conntrack_max=2310720 EOF cp kubernetes.conf /etc/sysctl.d/kubernetes.conf sysctl -p /etc/sysctl.d/kubernetes.conf # 设置 rsyslogd 和 systemd journald mkdir /var/log/journal # 持久化保存日志的目录 mkdir /etc/systemd/journald.conf.d cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF [Journal] # 持久化保存到磁盘 Storage=persistent # 压缩历史日志 Compress=yes SyncIntervalSec=5m RateLimitInterval=30s RateLimitBurst=1000 # 最大占用空间 10GSystemMaxUse=10G # 单日志文件最大 200M SystemMaxFileSize=200M # 日志保存时间 2 周 MaxRetentionSec=2week # 不将日志转发到 syslogForwardToSyslog=no EOF systemctl restart systemd-journald # 更换系统内核 rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm # 安装完成后检查 /boot/grub2/grub.cfg 中对应内核 menuentry 中是否包含 initrd16 配置,如果没有,再安装一次! yum --enablerepo=elrepo-kernel install -y kernel-lt # 设置开机从新内核启动 grub2-set-default 'CentOS Linux (4.4.189-1.el7.elrepo.x86_64) 7 (Core)' reboot uname -r
-
安装 K8S
# kube-proxy开启ipvs的前置条件 modprobe br_netfilter cat > /etc/sysconfig/modules/ipvs.modules <<EOF #!/bin/bash modprobe -- ip_vs modprobe -- ip_vs_rr modprobe -- ip_vs_wrr modprobe -- ip_vs_sh modprobe -- nf_conntrack_ipv4 EOF chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules &&lsmod | grep -e ip_vs -e nf_conntrack_ipv4 # 安装 Docker 软件 ### 转到 docker 部署 # 安装 Kubeadm (主从配置) cat <<EOF > /etc/yum.repos.d/kubernetes.repo [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 yum -y install kubeadm-1.15.1 kubectl-1.15.1 kubelet-1.15.1 systemctl enable kubelet.service # 配置 kubeadm 镜像文件 # 将 kubeadm-basic.images.tar.gz 文件传到 linux 主机中 tar -zxvf kubeadm-basic.images.tar.gz vim load.sh ------------------------------------------------------ #!/bin/bash ls /usr/local/src/kubeadm-basic.images > /tmp/images.txt cd /usr/local/src/kubeadm-basic.images for i in $(cat /tmp/images.txt);do docker load -i $i done ------------------------------------------------------- sh load.sh && cd ~ ############################### 以上无论主从都配 ############################### ############################### 以下只有主节点配 ############################### kubeadm config print init-defaults > kubeadm-config.yaml vim kubeadm-config.yaml # 配置以下内容,有的就改没有的就添加 ------------------------------------------------------- localAPIEndpoint: advertiseAddress: 192.168.80.142 kubernetesVersion: v1.15.1 networking: dnsDomain: cluster.local podSubnet: "10.244.0.0/16" serviceSubnet: 10.96.0.0/12 scheduler: {} --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration featureGates: SupportIPVSProxyMode: true mode: ipvs ------------------------------------------------------- kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs | tee kubeadm-init.log cat kubeadm-init.log # 根据 To start using your cluster, you need to run the following as a regular user: 下面的内容进行配置 mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config kubectl get node # 查看有没有节点,判断是否成功 # 部署网络 mkdir install-k8s/ mv kubeadm-init.log kubeadm-config.yaml install-k8s/ cd install-k8s/ mkdir core mv * core/ mkdir plugin cd plugin/ mkdir flanne # 将 kube-flannel.yml 文件传到该目录下 kubectl create -f kube-flannel.yml kubectl get pod -n kube-system # 查看有没有 flannel kubectl get node # 是不是 ready ############################### 从节点配置 ############################### kubeadm join 192.168.80.142:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:8bfee48fe1560b64828d3e375fb9944a460933e9057cf60bd5b7ede41437ea45 ## 以上两个都配
3. 资源清单
1. K8S 中的资源
综述:
K8s中所有的内容都抽象为资源,资源实例化之后,叫做对象;【自我理解:感觉就和 Java 中的类、模块差不多,需要时直接调用相应的需求即可。】
资源的分类:
(一)名称空间级别
- 工作负载型资源:Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob
- 服务发现及负载均衡型资源: Service、Ingress
- 配置与存储型资源:Volume(存储卷)、CSI
- 特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型)、Secret(保存敏感数据)、DownwardAPI(把外部环境中的信息输出给容器)
(二)集群级别的资源
- Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
(三)元数据型资源
- HPA、PodTemplate、LimitRange
2. K8S 中的常见字段介绍
(一)必须存在的字段
字段名 字段类型 说明 apiVersion string[^2] 指定 api 的版本,目前是 v1,可以用 ** kubectl apiversions
**查询kind string yml 文件中定义的资源类型是什么,比如 pod
metadata object[^3] 元数据对象 metadata.name string 元数据对象的名字,比如定义 pod 的名字 metadata.namespace string 元数据对象的命名空间,由我们自己定义 metadata.labels object 元数据对象的标签 metadata.labels.version string 元数据对象的标签的版本 spec object 详细定义对象 spec.containers[] object 定义容器某些属性 spec.containers[].name string 定义容器的名字 spec.containers[].image string 定义容器使用那个镜像
3. 简单 pod 的定义
(一)定义 pod
mkdir /kubeyml vim /kubeyml/pod001.yml ------------------------------------------------------------ apiVersion: v1 kind: Pod metadata: # 大前提 name: myapp-pod labels: app: myapp version: v1 spec: # 小前提 containers: - name: app image: 192.168.80.141:5000/codefun/myapp:v1 - name: test image: 192.168.80.141:5000/codefun/myapp:v1 ------------------------------------------------------------
(二)启动和排查错误
`kubectl` apply -f pod001.yml # 将 yml 文件生成相应的资源 `kubectl` get pod # 查看 pod 是否建立成功 # NAME READY STATUS RESTARTS AGE # myapp-pod 1/2 CrashLoopBackOff 8 4h28m # pod 名 启动数/总数 状态 重启次数 创建了多长时间 kubectl describe pod myapp-pod # 查看指定 pod 的详细信息,比如 pod 的详细信息,容器的详细信息,容器的执行事件,存储卷信息 kubectl logs -p myapp-pod -c test # 查看指定 pod 下的指定容器的日志 kubectl delete pod myapp-pod # 删除指定pod
4. 容器的生命周期
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pi9s6Zxt-1653055923913)(D:\云计算工坊\图片\K8S\容器的生命周期.png)]
1. init C 的详解与模板应用
(一)
Init
容器介绍特点:
init
容器总是运行到成功完成为止- 每个
init
容器都必须在下一个Init
容器启动之前成功完成- 如果
pod
重启,所有init c
容器必须重新执行init
容器具有应用容器的所有字段,除了就绪检测和生存检测。- 在
pod
中的每个app
和init
容器的名称必须唯一作用:
- 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的【比如在主容器启动之前,我们需要梳理某些文件或者动作,但是这些动作或文件可能只运行一次,为了减少主容器的工作量】
- 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。【也就是一部分是构建代码init c,而另一部分运行代码 主容器】
- Init容器使用LinuxNamespace它们能够具有访问Secret的权限,而应用程序容器则不能。
- 若 pod 内有依赖性强的容器,则可以使用
init c
来指定容器启动的顺序,从而保证 pod 的运行状态总结:
就是充分利用
init c
和main c
相互剥离但又能控制main c
的特点,以及优先于main c
执行的特点。
(二) 模板应用
vim /kubeyml/pod002.yml ------------------------------------------------------------------------------------------------------ apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox command: ['sh','-c','echo The app is running! && sleep 3600'] initContainers: - name: init-myservice # 检测 myservice 的 DNS,若不成功就返回 waiting for myservice 然后睡两秒再次检测。 image: busybox command: ['sh','-c','until nslookup myservice; do echo waiting for myservice; sleep 2;done;'] - name: init-mydb image: busybox command: ['sh','-c','until nslookup mydb; do echo waiting for mydb; sleep 2; done;'] ------------------------------------------------------------------------------------------------------ `kubectl` apply -f pod002.yml kubectl get pod # NAME READY STATUS RESTARTS AGE # myapp-pod 0/1 Init:0/2 0 10m cat /kubeyml/svs001.yml ------------------------------------------------------------------------------------------------------ kind: Service apiVersion: v1 metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 ------------------------------------------------------------------------------------------------------ `kubectl` apply -f svs001.yml kubectl get pod # NAME READY STATUS RESTARTS AGE # myapp-pod 0/1 Init:1/2 0 10m cat /kubeyml/svc002.yml ----------------------------------------------------------------------------------------------------- kind: Service apiVersion: v1 metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 ----------------------------------------------------------------------------------------------------- `kubectl` apply -f svc002.yml kubectl get pod # NAME READY STATUS RESTARTS AGE # myapp-pod 1/1 Running 0 13m
总结一下:
- 使用
initContainers
创建 init c
容器,并执行检测 DNS 解析命令- 当一个
init c
容器执行完后就会死亡,并且执行下一个init c
容器
2. 探针的使用
(一)什么是探针
- 探针是由
kubelet
对容器执行的定期诊断。要执行诊断,kubelet
调用由容器实现的Handler
。
(二)探针的三种处理程序
ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
TCPSocketAction
:对指定端口上的容器的IP
地址进行TCP
检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction
:对指定的端口和路径上的容器的IP
地址执行HTTP Get
请求。如果响应码大于等于200且小于400,则成功探测结果:
成功:容器通过了诊断。
失败:容器未通过诊断。
未知:诊断失败,因此不会采取任何行动
(三)探测方式
livenessProbe
:指示容器是否正在运行。如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为SuccessreadinessProbe
:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success
(四)
readinessProbe
探测实例cat /kubeyml/pod003.yml --------------------------------------- apiVersion: v1 kind: Pod metadata: name: readiness-httpget-pod namespace: default spec: containers: - name: readiness-httpget-container image: wangyanglinux/myapp:v1 imagePullPolicy: IfNotPresent # 镜像拉取规则,如果本地有就不向远程拉取 readinessProbe: # 就绪检测 httpGet: # 检测方案:httpget 方案 port: 80 path: /index1.html # 检测的路径本来就没有 initialDelaySeconds: 1 # 初始化的延迟 periodSeconds: 3 # 重试的时间 --------------------------------------- `kubectl` get pod # NAME READY STATUS RESTARTS AGE # readiness-httpget-pod 0/1 # 没有真正的开启 Running 1 86m kubectl exec -it readiness-httpget-pod -- /bin/sh ### 进入容器的命令,还可跟 -c 命令 / # cd /usr/share/nginx/html/ /usr/share/nginx/html # ls 50x.html index.html /usr/share/nginx/html # echo "hello world" > index1.html /usr/share/nginx/html # exit [root@master ~]# kubectl get pod # NAME READY STATUS RESTARTS AGE # readiness-httpget-pod 1/1## Running 1 91m
(五)生存检测案例
cat pod004.yml ## ExecAction 类型 ----------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: live-exec-pod namespace: default spec: containers: - name: live-exec-con image: busybox imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/live;sleep 10;rm -rf /tmp/live;sleep 3600"] # 创建一个文件 livenessProbe: exec: command: ["test","-e","/tmp/live"] # 检测是否有该文件 initialDelaySeconds: 1 periodSeconds: 3 ------------------------------------------------------------------------------------------ `kubectl` get pod -w # 获得 pod 的持续性状态 # AME READY STATUS RESTARTS AGE # live-exec-pod 1/1 Running 0 5s # live-exec-pod 1/1 Running 1 49s # 在这里重启了一次 cat /kubeyml/pod005.yml ## HTTPGetAction 类型 ------------------------------------------------------------------------------------------ apiVersion: v1 kind: Pod metadata: name: live-httpget-pod namespace: default spec: containers: - name: live-httpget-con image: 192.168.80.141:5000/codefun/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 8080 # 对外开放 80 端口 livenessProbe: httpGet: port: http path: /index.html # 使用 http 协议进行 get 请求,并且访问 80 端口 initialDelaySeconds: 1 periodSeconds: 3 timeoutSeconds: 10 ------------------------------------------------------------------------------------------ `kubectl` exec -it live-httpget-pod -- rm -rf /usr/share/nginx/html/index.html `kubectl` get pod # NAME READY STATUS RESTARTS AGE # live-httpget-pod 1/1 Running 1 2m45s # 这里重启了一次,因为检测不到 index.html cat /kubeyml/pod006.yml ------------------------------------------------------------------------------------------ apiVersion: v1 kind: Pod metadata: name: live-tcp-pod namespace: default spec: containers: - name: live-tcp-con image: 192.168.80.141:5000/codefun/myapp:v1 livenessProbe: initialDelaySeconds: 5 timeoutSeconds: 1 tcpSocket: port: 8080 periodSeconds: 3 ------------------------------------------------------------------------------------------ # kubectl get pod # NAME READY STATUS RESTARTS AGE # live-tcp-pod 0/1 CrashLoopBackOff 3 57s # 检测到 8080 没有监听,所以一直重启
3. 启动程序和停止程序的定义
(一) 案例实施
cat /kubeyml/pod007.yml ------------------------------------------------------------------------------------------ apiVersion: v1 kind: Pod metadata: name: lifecycle-pod spec: containers: - name: lifecycle-con image: 192.168.80.141:5000/codefun/myapp:v1 lifecycle: postStart: exec: command: ["/bin/sh","-c","echo hello world > /usr/share/message"] preStop: exec: command: ["/bin/sh","-c","echo hello bad > /usr/share/message"] ------------------------------------------------------------------------------------------ `kubectl` apply -f /kubeyml/pod007.yml # 启动时向 /usr/share/message 中插入 hello world pod/lifecycle-pod created `kubectl` exec -it lifecycle-pod -- cat /usr/share/message hello world
4. pod 的五种状态
- 挂起(Pending):Pod已被Kubernetes系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度Pod的时间和通过网络下载镜像的时间,这可能需要花点时间
- 运行中(Running):该Pod已经绑定到了一个节点上,Pod中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态
- 成功(Succeeded):Pod中的所有容器都被成功终止,并且不会再重启
- 失败(Failed):Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止
- 未知(Unknown):因为某些原因无法取得Pod的状态,通常是因为与Pod所在主机通信失败
4. 创建控制器
控制器:
用来控制和管理 pod 的工具
1. Deployment 控制器
1. 使用环境
- 确保容器应用的副本数始终保持在用户定义的副本数
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
2. 控制器基础案例
(一) 部署 RS
cat /kubeyml/rs001.yml -------------------------------------------------------------------------------------------- apiVersion: extensions/v1beta1 # 定义 api 版本,控制器好像都是这个版本 kind: ReplicaSet # 创建的类型 metadata: # 大前提 name: frontend spec: # 小前提,细节 replicas: 3 selector: # 选择器:即定义选择那些 pod 加入 RS matchLabels: tier: frontend # 定义一个标签,有此标签的 pod 加入 RS template: # 设置模板 pod metadata: labels: tier: frontend # 定义标签 spec: containers: - name: rs-nginx image: 192.168.80.141:5000/codefun/myapp:v1 env: - name: GET_HOST_FROM value: dns ports: - containerPort: 80 -------------------------------------------------------------------------------------------- `kubectl` label pod frontend-7w77k tier=codefun --overwrite=True pod/frontend-7w77k labeled `kubectl` get pod --show-labels # 又多了一个 pod NAME READY STATUS RESTARTS AGE LABELS frontend-72nzv 1/1 Running 0 5s tier=frontend frontend-7w77k 1/1 Running 0 4h14m tier=codefun frontend-mhfwb 1/1 Running 0 4h14m tier=frontend frontend-sq98s 1/1 Running 0 4h14m tier=frontend
(二)部署 Deployment
cat /kubeyml/dep001.yml -------------------------------------------------------------------------------------------- apiVersion: extensions/v1beta1 kind: Deployment # 就 kind 值不一样,其他基本相同 metadata: name: nginx-dep spec: replicas: 3 selector: # 创建没有什么意义 matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-con image: 192.168.80.141:5000/codefun/myapp:v1 ports: - containerPort: 80 -------------------------------------------------------------------------------------------- `kubectl` create -f /kubeyml/dep001.yml --record## --record参数可以记录命令,我们可以很方便的查看每次 revision 的变化 `kubectl` get deployment NAME READY UP-TO-DATE AVAILABLE AGE nginx-dep 3/3 3 3 13m
(三)Deployment 控制器的应用
(1)扩容副本
`kubectl` scale deployment deployment-name --replicas 扩容数 # 语法 ## 实例: `kubectl` scale deployment nginx-dep --replicas 5 # 将副本数扩容为 5 个 deployment.extensions/nginx-dep scaled kubectl get deployment # 只是在原来的基础上扩容,而不是新增 rs NAME DESIRED CURRENT READY AGE nginx 5 5 5 21m
(2)更新镜像
`kubectl` set image deployment/deployment-name container-name=image-name # 语法 ## 示例: `kubectl` set image deployment/nginx-dep nginx-con=wangyanglinux/myapp:v2 `kubectl` get rs # 新增一个 RS, 将 pod 滚动更新到 新的 RS NAME DESIRED CURRENT READY AGE nginx-dep-6f58ddf7d9 0 0 0 28m nginx-dep-768b498b9f 5 5 5 93s
(3)回滚 RS
### 基础命令 `kubectl` rollout undo deployment/deployment-name # 语法 ## 示例: `kubectl` rollout undo deployment/nginx-dep # 默认回滚到上一个 rs deployment.extensions/nginx-dep rolled back `kubectl` get rs NAME DESIRED CURRENT READY AGE nginx-dep-6f58ddf7d9 5 5 4 36m nginx-dep-768b498b9f 0 0 0 8m42s
查看回滚状态
kubect
l rollout status deployment/devloyment-name查看历史版本的 rs
kubectl
rollout history deployment/devloyment-name
deployment.extensions/nginx-dep
REVISION CHANGE-CAUSE
2 kubectl apply --filename=/kubeyml/dep001.yml --record=true
4 kubectl apply --filename=/kubeyml/dep001.yml --record=true
5 kubectl apply --filename=/kubeyml/dep001.yml --record=true回滚到指定的版本
kubectl
rollout undo deployment/deployment --to-revision=REVISION暂停deployment更新
kubectl rollout pause deployment/deployment-name
回滚策略
如果创建了10个 v1 版本的 deployment,当创建到第三个的时候,执行 v1 版本 改为 v2 版本的操作,这时就不会再创建 v1 版本的,而是将 v1 的三个杀死,创建 v2 版本的。
deployment 更新策略
· Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)
· eployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。默认的,它会确保最多比期望的Pod数量多一个的 Pod 是 up 的(最多1个 surge )设置历史版本的个数
您可以通过设置.spec.revisonHistoryLimit项来指定 deployment 最多保留多少 revision 历史记录。默认的会保留所有的 revision;如果将该项设置为0,Deployment 就不允许回退了.
实现:
vim /kubeyml/dep001.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-dep
spec:
replicas: 3revisionHistoryLimit: 1 # 保留两个
2. DaemonSet 控制器
1. 使用环境
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。
- 运行集群存储
- 运行日志收集
- 运行监控
2. 控制器基础案例
cat /kubeyml/dae.yml
--------------------------------------------------------------------------------------------
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: dae
labels:
app: dae-v1 # 一样
spec:
selector:
matchLabels:
name: dae-v1 # 一样
template:
metadata:
labels:
name: dae-v1 # 一样
spec:
containers:
- name: dae-v1
image: 192.168.80.141:5000/codefun/myapp:v1
--------------------------------------------------------------------------------------------
`kubectl` create -f /kubeyml/dae.yml
3. Job 和 Cronjob 控制器
1. 使用环境
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束
Cron Job 基于时间的 Job,即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
2. 控制器的基础案例
(一) job
cat /kubeyml/job001.yml -------------------------------------------------------------------------------------------- apiVersion: batch/v1 kind: Job metadata: name: demo-job spec: parallelism: 3 # 设置并行 pod 的数目,默认为一,增大可以增加执行效率 template: metadata: name: demo-job spec: containers: - name: demo-job image: busybox command: ["echo","hello world Job!"] restartPolicy: OnFailure # 失败了就重启 pod ,Never 从不重启 -------------------------------------------------------------------------------------------- `kubectl` get pod # 当 status 为 Completed 时为执行成功 NAME READY STATUS RESTARTS AGE demo-job-5zwm9 0/1 Completed 0 3m2s `kubectl` get job NAME COMPLETIONS DURATION AGE demo-job 3/1 of 3 36s 4m11s
(二)Cronjob
cat /kubeyml/cro001.yml -------------------------------------------------------------------------------------------- apiVersion: batch/v1beta1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" # 每秒执行一次 jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date;echo hello world CronJob! restartPolicy: OnFailure -------------------------------------------------------------------------------------------- `kubectl` get pod NAME READY STATUS RESTARTS AGE hello-1622117340-pgtcj 0/1 Completed 0 92s hello-1622117400-xx6wg 0/1 Completed 0 32s `kubectl` get job # cronjob 也是 job 的一种,只不过加了定时任务而已 NAME COMPLETIONS DURATION AGE hello-1622117340 1/1 18s 2m7s hello-1622117400 1/1 19s 67s hello-1622117460 0/1 7s 7s `kubectl` get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE hello */1 * * * * False 0 28s 6m57s
ronjob 各参数详解
spec.schedule
:调度,必需字段,指定任务运行周期,格式同 Cron
.spec.jobTemplate
:Job 模板,必需字段,指定需要运行的任务,格式同 Job
.spec.startingDeadlineSeconds
:启动 Job 的期限(秒级别)如果没有指定,则没有期限.
spec.concurrencyPolicy
:并发策略,该字段也是可选的。只允许指定下面策略中的一种:
Allow
(默认):允许并发运行
JobForbid
:禁止并发运行,如果前一个还没有完成,则直接跳过下一个
Replace
:取消当前正在运行的 Job,用一个新的来替换。
.spec.suspend
:挂起,该字段也是可选的。如果设置为true,后续所有执行都会被挂起。它对已经开始执行的 Job 不起作用。默认值为false。
.spec.successfulJobsHistoryLimit和.spec.failedJobsHistoryLimit
:历史限制,是可选的字段。它们指定了可以保留多少完成和失败的 Job。默认情况下,它们分别设置为3和1。设置限制的值为0,相关类型的 Job 完成后将不会被保留
5. service 介绍
1. 基础概念
1. service 的定义
一种可以访问pod集群的策略 —— 通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Selector
- service 的限制:只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kRY5cCnE-1653055923915)(D:\云计算工坊\图片\K8S\service定义.png)]
2. service 的分类
ClusterIp
:默认类型,自动分配一个仅集群内部可以访问的虚拟IP
NodePort
:在ClusterIP
基础上为Service
在每台机器上绑定一个端口,这样就可以通过主机IP:NodePort
来访问该服务
LoadBalancer
:在NodePort
的基础上,借助cloud provider
创建一个外部负载均衡器,并将请求转发到NodePort
NodePortExternalName
:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持
监听服务和端点是由apiserver负责的,通过 kube-proxy 去监控对应的 pod ,并提取相应的信息,将其写入到 iptables,当客户端想要访问 service 的时候,其实访问的的是 iptables 规则,然后导向到后端的 pod 的地址信息
客户端访问到我们的节点是由 iptables 实现的
iptables 的规则是由 kube-proxy 写入的,apiserver通过监控 kube-proxy 进行 服务和端点的发现 ,kube-proxy 会通过 pod 的标签去判断这个端点是否写入到端点集合里去。
2. 基础案例实践
(一)ClusterIP 和 NodePort
cat /kubeyml/svc003.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Service metadata: name: svc003 namespace: default spec: type: NodePort selector: app: nginx ports: - name: http port: 80 targetPort: 80 -------------------------------------------------------------------------------------------- `kubectl` apply -f /kubeyml/svc003.yml `kubectl` get svc # NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE # svc003 NodePort 10.108.138.100 <none> 80:32181/TCP 18m
(二)externalName
kind: Service apiVersion: v1 metadata: name: my-service-1 namespace: default spec: type: ExternalName externalName: hub.atguigu.com
3. nginx-ingress
(一)
service
只能实现四层暴露,而nginx-ingress
可以实现七层暴露
(二)部署过程
kubectl apply -f /root/install-k8s/plugin/ingress/mandatory.yml kubectl apply -f /root/install-k8s/plugin/ingress/service-nodePort.yml
(三)简单案例的部署
cat /kubeyml/ingress/dep-demo.yml -------------------------------------------------------------------------------------------- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-dep spec: replicas: 2 template: metadata: labels: name: nginx spec: containers: - name: nginx image: wangyanglinux/myapp:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-svc # 与 ingress 的唯一标识 spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: name: nginx --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nginx-demo spec: rules: - host: www1.codefun.com http: paths: - path: / backend: serviceName: nginx-svc # 管理那个 service servicePort: 80 -------------------------------------------------------------------------------------------- kubectl apply -f /kubeyml/ingress/dep-demo.yml curl www1.codefun.com:30051 # 发现可以访问该域名
(四)实现 https
# 创建 https 密钥 openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc" kubectl create secret tls tls-sercret --key tls.key --cert tls.crt # 编写 yml 文件 vim /kubeyml/ingress/https_ingress.yml -------------------------------------------------------------------------------------------- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nginx-ing001 spec: tls: # 注意该字段下与之前建立的密钥相对应 - hosts: - www.code666.com secretName: tls-secret rules: - host: www.code666.com http: paths: - path: / backend: serviceName: nginx-svc001 servicePort: 80 -------------------------------------------------------------------------------------------- # 在 网页上访问 https://www.code666.com:32458,注意此时映射的端口为 443!
(五)实现用户认证
# 创建密码文件 yum install -y httpd mkdir htpasswd && cd htpasswd htpasswd -c auth codefun kubectl create secret generic basic-auth --from-file=auth # 编写 yml 文件 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-dev004 spec: replicas: 2 template: metadata: labels: name: nginx004 spec: containers: - name: nginx004 image: wangyanglinux/myapp:v2 imagePullPolicy: IfNotPresent ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-svc004 spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: name: nginx004 --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nginx-ing004 annotations: nginx.ingress.kubernetes.io/auth-type: basic nginx.ingress.kubernetes.io/auth-secret: basic-auth nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - codefun' spec: rules: - host: www.codeau.com http: paths: - path: / backend: serviceName: nginx-svc004 servicePort: 80 ---
(六)域名重定向
cat /kubeyml/ingress/rew_sour.yml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: rew-sour-ing annotations: nignx.ingress.kubernetes.io/rewrite-target: http://www.code.com:30051/ spec: rules: - host: www.codefun.com http: paths: - path: / backend: serviceName: rewrite-svc02 servicePort: 80
6. k8s 中的存储
1. 保存对象为环境变量的 configMap
(一) 特点:
ConfigMap
功能在Kubernetes1.2
版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API
给我们提供了向容器中注入配置信息的机制,ConfigMap
可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制大对象
(二)以目录为单位创建 configmap
# 创建相关目录和文件,并向文件中输入信息 mkdir /root/configmap/ && cd /root/configmap cat game.properties -------------------------------------------------------------------------------------------- enemies=aliens lives=3 enemies.cheat=true enemies.cheat.level=no GoodRottensecret.code.passphrase=UUDDLRLRBABAS secret.code.allowed=truesecret.code.lives=30 -------------------------------------------------------------------------------------------- cat ui.properties -------------------------------------------------------------------------------------------- color.good=purple color.bad=yellow allow.textmode=true how.nice.to.look=fairlyNice -------------------------------------------------------------------------------------------- # 创建 configmap `kubectl` create configmap config-dir --from-file=/root/configmap/ # config-dir 为 configmap 的名字,/root/configmap/ 是 名为 config-dir 的 configmap 保存那些资源。 # --from-file 指定的资源,以文件为键,以内容为值。
(三)以字面值为单位创建 configmap
kubectl create configmap config-word --from-literal=key1=value1 --from-literal=key2=value2 kubectl describe config-world # 查看包括那些键值
(四)使用 yml 文件来创建 configmap
vim /kubeyml/env_cm.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: ConfigMap metadata: name: config-yml namespace: default data: key: value -------------------------------------------------------------------------------------------- kubectl create -f /kubeyml/env_cm.yml
(五)在 pod 中使用 configMap 中的键值
cat /kubeyml/env_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: env-pod spec: containers: - name: env-con image: wangyanglinux/myapp:v2 command: ["/bin/sh","-c","env"] # 打印所有的环境变量 env: - name: SPECIAL_LEVEL_KEY # 定义在 pod 中的 key valueFrom: # 变量来自于哪里 configMapKeyRef: name: game-config # 变量的 configmap 的名字 key: game.propreties # 变量的 key envFrom: # z直接导入整个 configmap 中的键和值 - configMapKeyRef: name: config-map-name restartPolicy: Never --------------------------------------------------------------------------------------------
(六)通过数据卷插件使用 configmap
cat /kubeyml/env_vol_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: env-vol-pod spec: containers: - name: env-vol-con image: wangyanglinux/myapp:v1 command: ["/bin/sh","-c","sleep 360s"] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: name: game-config restartPolicy: Never -------------------------------------------------------------------------------------------- kubectl apply -f /kubeyml/env_vol_pod.yml kubectl exec -it env-vol-pod -- /bin/sh / # cd /etc/config /etc/config # ls # 由此发现,将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容 kubectl edit cm game-config # 修改环境变量,容器也跟着改变,实现热部署
2. 加密存储的 secret
(一)secret 存在的意义
- Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。Secret 可以以 Volume 或者环境变量的方式使用
(二)secret 的分类
ervice Account
:用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount
目录中Opaque
:base64
编码格式的Secret,用来存储密码、密钥等kubernetes.io/dockerconfigjson
:用来存储私有 docker registry 的认证信息
(三)创建 Opaque 类型的 secret
将 secret 导入到 volume 中
# 获取 base64 加密的信息 cho -n "admin" | base64 YWRtaW4= # 此加密信息就是个假的,很容易反解密 echo -n "123456" | base64 MTIzNDU2 # 编写有关 secret 的 yml 文件 cat /kubeyml/secrets.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: password: MTIzNDU2 username: YWRtaW4= -------------------------------------------------------------------------------------------- # 编写使用 secret 的 pod cat /kubeyml/sec_vol_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: sec-pod labels: name: sec-pod spec: volumes: - name: secrets secret: secretName: mysecret # 与上文定义的相同 containers: - image: wangyanglinux/myapp:v2 name: sec-con volumeMounts: - name: secrets mountPath: /etc/config readOnly: true --------------------------------------------------------------------------------------------
将 secret 导入到环境变量中
cat /kubeyml/sec_env_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: sec-env-pod spec: containers: - name: sec-env-con image: wangyanglinux/myapp:v1 command: ["/bin/sh","-c","echo $ADMIN"] ports: - containerPort: 80 env: - name: ADMIN valueFrom: secretKeyRef: ### name: mysecret key: username --------------------------------------------------------------------------------------------
拉取私有仓库免登录
# 创建密钥 kubectl create secret docker-registry myregistrykey --docker-server=192.168.80.141:5000 --docker-username=admin --docker-password=Gx123456 --docker-email=3061552332@qq.com # 编写 yml 文件 cat /kubeyml/reg_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: reg-pod spec: containers: - name: reg-con image: 192.168.80.141:5000/codefun/nginx01:v1 imagePullSecrets: - name: myregistrykey --------------------------------------------------------------------------------------------
3. 可以共享的 volume
(一)同 pod 共享存储的
emptyDir
当 Pod 被分配给节点时,首先创建emptyDir卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除
暂存空间,例如用于基于磁盘的合并排序用作长时间;计算崩溃恢复时的检查点;Web服务器容器提供数据时,保存内容管理器容器提取的文件
案例示例
cat /kubeyml/vol_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: vol-pod namespace: default spec: containers: - name: vol-con001 image: wangyanglinux/myapp:v1 volumeMounts: - mountPath: /cache name: cache-volume # 定义相同的名字 - name: vol-con002 image: busybox imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","sleep 360s"] volumeMounts: - mountPath: /test name: cache-volume # 定义相同的名字 volumes: - name: cache-volume emptyDir: {} -------------------------------------------------------------------------------------------- kubectl apply -f /kubeyml/vol_pod.yml kubectl exec -it vol-pod -c vol-con001 -- /bin/sh / # cd cache/ /cache # date > test.txt /cache # cat test.txt Wed Jun 2 09:19:41 UTC 2021 kubectl exec -it vol-pod -c vol-con002 -- /bin/sh / # cd test /test # cat test.txt Wed Jun 2 09:19:41 UTC 2021
(二)共享到本地的
hostpath
综述
hostPath
卷将主机节点的文件系统中的文件或目录挂载到集群中用途
- 运行需要访问 Docker 内部的容器:使用
/var/lib/docker的hostPath
- 在容器中运行
cAdvisor
;使用/dev/cgroups的hostPath
- 允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在
参数总结
k
值 行为 path node 节点的目录路径 null 空字符串用于向后兼容,意味着在挂载 hostpath 卷之间不会执行任何检查 DirectoryOrCreate 如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为 077 ,与 kubelet 具有相同的组和所有权 Directory 给定的路径下必须存在目录 FileOrCreate 如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设为 0644,与 kubelet 具有相同的组和权限 File 给定路径下必须存在文件 Socket 给定路径下必须存在 UNIX 套接字 CharDevice 给定路径下必须存在字符设备 BlockDevice 给定的路径下必须存在块设备 案例实现
cat /kubeyml/vol_host_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: vol-host-pod spec: containers: - name: vol-host-con image: wangyanglinux/myapp:v2 volumeMounts: - name: vol-host-vol mountPath: /test volumes: - name: vol-host-vol hostPath: path: /data type: Directory -------------------------------------------------------------------------------------------- kubectl apply -f /kubeyml/vol_host_pod.yml kubectl exec -it vol-host-pod -- /bin/sh / # date > /test/test.txt / # cat /test/test.txt Thu Jun 3 00:42:28 UTC 2021 [root@n002 ~]# mkdir /data [root@n002 ~]# cat /data/test.txt Thu Jun 3 00:42:28 UTC 2021
4. 持久卷
概念
- PV 持久卷,由运维设置的存储。是集群中的资源,类似于 volume 之类的卷插件,但具有独立于 pod 的生命周期。此 API 对象包含存储实现的细节,如使用 NFS 来达到目录共享的功能。
- PVC 持久卷声明,由开发设置的类型。类似于 pod ,pod 消耗节点资源,PVC 消耗 PV 资源。
- 静态 PV ,集群管理员创建的 PV。
- 动态 PV , 当管理员创建的静态 PV 都不匹配用户的 PVC 时,集群可能会自己尝试动态的为 pvc 创建卷。
- PV 访问模式:
ReadWriteOnce
– 单个节点读写模式挂载ReadOnlyMany
– 多个节点只读模式挂载ReadWriteMany
– 多个节点读写模式挂载- 状态:
Available
– 可用的空闲资源Bound
– 卷已被声明绑定Released
– 声明已被删除- 回收策略:
Retain
– 手动回收Delete
– 直接删除Failed
– 自动回收失败- PV 和 PVC 匹配规则
- PVC 和 PV 的
storageClassName
必须一致- PVC 和 PV 的
accessModes
必须一致- PVC 的大小要小于或等于 PV 的大小
持久化演示说明 - NFS
# 安装 nfs 服务 yum install -y nfs-utils rpcbind mkdir /nfs{0..3} chown nfsnobody /nfs{0..3} chmod 777 /nfs{0..3} vim /etc/exports -------------------------------------------------------------------------------------------- /nfs0 *(rw,sync,no_root_squash,no_all_squash) /nfs1 *(rw,sync,no_root_squash,no_all_squash) /nfs2 *(rw,sync,no_root_squash,no_all_squash) /nfs3 *(rw,sync,no_root_squash,no_all_squash) -------------------------------------------------------------------------------------------- systemctl restart rpcbind systemctl restart nfs # 编写 pv 的 yml 文件 cat /kubeyml/mode_pv.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: PersistentVolume metadata: name: mode-pv spec: capacity: storage: 2Gi # 定义 PV 的容量 accessModes: # 定义 PV 的访问模式 - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle # 定义 PV 的回收策略 storageClassName: nfs # 与 PVS 的唯一标识 nfs: # 设置持久卷类型为 NFS path: /nfs0 # 远程的挂载目录 server: 192.168.80.141 # 远程挂载目录主机的 IP -------------------------------------------------------------------------------------------- kubectl apply -f /kubeyml/mode_pv.yml # 编写 pvc 及其他的 yml 文件 cat /kubeyml/mode_pvc.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Service metadata: name: mode-pvc-svc labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None # 定义 statefulSet 时,service 必须是无头服务 selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: mode-pvc-ss spec: selector: matchLabels: app: nginx # 与 container 互相标识 serviceName: "mode-pvc-svc" # 与 service 的唯一标识 replicas: 3 template: metadata: labels: app: nginx # 与 statefulset 互相标识 spec: containers: - name: mode-pvc-con image: wangyanglinux/myapp:v2 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www # PVC 的名字 spec: accessModes: [ "ReadWriteOnce" ] # 与 PV 的标识 storageClassName: "nfs" # 与 PV 的标识 resources: requests: storage: 1Gi # 大小 -------------------------------------------------------------------------------------------- kubectl apply -f /kubeyml/mode_pvc.yml # 另一种写法 cat mode_pv003.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: PersistentVolume metadata: name: mode-pv003 spec: capacity: storage: 2Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Delete storageClassName: mode-pvoo3 nfs: path: /nfs3 server: 192.168.80.141 -------------------------------------------------------------------------------------------- cat mode_pvc001.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mode-pvc001 spec: storageClassName: mode-pvoo3 accessModes: - ReadWriteMany resources: requests: storage: 500Mi -------------------------------------------------------------------------------------------- cat mod_pv_pod.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: mode-pv-pod spec: containers: - name: mode-pv-con image: wangyanglinux/myapp:v1 ports: - containerPort: 80 protocol: TCP volumeMounts: - name: mode-pv-vol mountPath: /test volumes: - name: mode-pv-vol persistentVolumeClaim: claimName: mode-pvc001 --------------------------------------------------------------------------------------------
statefulSet
模型
- 在
StatefulSet
中,Pod名字称为网络标识(hostname),还必须要用到共享存储。- 每一个pod不能被随意取代,pod名称不变,而pod IP是变化的,所以pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称 。
StatefulSet
为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为:$(podname).(headless servername),
- 共享存储这里用的是 NFS
7. 集群的调度器
1. 调度说明
简介
Scheduleer
是 K8S 的调度器,主要任务是把定义的 pod 分配到集群的node
上。分配时需要考虑的问题:
- 公平:如何保证每个节点都能被分配资源
- 资源的高效利用:集群所有资源最大化被使用
- 效率:能够尽快地对大批量的 pod 完成调度工作
- 灵活:允许用户根据自己的需求控制调度逻辑
Shedeler
是作为单独运行程序,启动之后会一直坚挺 API Server,获取PodSpec.NodeName
为空的 pod,对每个 pod 都会创建一个binding
,表明该 pod 应该放到哪个节点上。
调度过程
- 预选:首先过滤掉不满足条件的节点,称为
predicate
- 优选:根据节点优先级来最终决定 pod 的归属,称为
priority
预选算法:
PodFitsResources
:节点上剩余的资源是否大于 pod 请求的资源PodFitsHost
:如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配PodFitsHostPorts
:节点上已经使用的 port 是否和 pod 申请的 port 冲突PodSelectorMatches
:过滤掉和 pod 指定的 label 不匹配的节点NoDiskConflict
:已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读优选算法:
eastRequestedPriority
:通过计算 CPU 和 Memory 的使用率来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点BalancedResourceAllocation
:节点上 CPU 和 Memory 使用率越接近,权重越高。这个应该和上面的一起使用,不应该单独使用ImageLocalityPriority
:倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高选择细节:
- 如果在
predicate
过程中没有合适的节点,pod 会一直在pending
状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续priorities
过程:按照优先级大小对节点排序- 通过算法对所有的优先级项目和权重进行计算,得出最终的结果
自定义调度器
apiVersion: v1 kind: Pod metadata: name: annotation-second-scheduler labels: name: multischeduler-example spec: schedulername: my-scheduler containers: - name: name-com image: image-name:tag
2. 节点亲和性
软策略
—— 不必须匹配的策略
# 实现方法: cat /kubeyml/affinity/pre_pod001.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: pre-pod labels: app: pre-pod spec: containers: - name: pre-con image: wangyanglinux/myapp:v2 imagePullPolicy: IfNotPresent affinity: # 策略 nodeAffinity: # 节点匹配策略 preferredDuringSchedulingIgnoredDuringExecution: # 软策略 - weight: 1 # 权重 preference: # 软策略详情 matchExpressions: # 选择详请 - key: kubernetes.io/hostname # 选择 key 和 value 是什么的 node,kubectl get node --show-labels 显示可选键值 values: - n001 operator: In # 执行的操作 --------------------------------------------------------------------------------------------
operator 操作的种类
-In # label 的值在某个列表中 -NotIn # label 的值在某个列表中 -Gt # label 的值大于某个值 -Lt # label 的值小于某个值 -Exsist # 某个 label 存在 -DoesNotExist # 某个 label 不存在
硬策略
—— 必须匹配的策略,不然
pod
处于pending
cat /kubeyml/affinity/req_pod001.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: req-pod labels: app: req-pod spec: containers: - name: pre-con image: wangyanglinux/myapp:v2 imagePullPolicy: IfNotPresent affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 和软开头不一样 nodeSelectorTerms: # 和软一点都不一样 - matchExpressions: - key: kubernetes.io/hostname values: - n002 operator: In --------------------------------------------------------------------------------------------
pod 亲和性
—— 即 pod 和 pod 直接根据 label 判断是否在同一个 拓扑域 里
cat /kubeyml/affinity/req_pod002.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: req-pod002 labels: app: req-pod002 spec: containers: - name: req-con002 image: wangyanglinux/myapp:v2 imagePullPolicy: IfNotPresent affinity: podAffinity: ### requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app values: - req-pod operator: In topologyKey: kubernetes.io/hostname # podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 podAffinityTerm: labelSelector: matchExpressions: - key: app values: - pre-pod operator: In topologyKey: kubernetes.io/hostname ## 选择拓扑域,即 hostname 相同的 node --------------------------------------------------------------------------------------------
3. 污点和容忍
污点
- Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去
容忍
- 设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上
设置污点
`kubectl taint nodes` node-name key1=value1:effect ## effect 支持的三个选项: -NoSchedule # 不会将 pod 调度到有该污点的 node 上 -PreferNoSchedule # 尽量避免将 pod 调度到有该污点的 node 上 -NoExecute # 不会将 pod 调度到有该污点的 node 上,同时会将 node 上已经存在的 pod 驱逐出去
查看污点
`kubectl describe node` node-name | grep -i "taints:"
删除污点
`kubectl taint nodes` node-name key1=value1:effect- # 加个减号即可
设置容忍
cat /kubeyml/affinity/req_pod001.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Pod metadata: name: req-pod002 labels: app: req-pod002 spec: containers: - name: pre-con002 image: wangyanglinux/myapp:v2 imagePullPolicy: IfNotPresent tolerations: # 设置容忍的 key value effect 必须一致! - key: auth # 不指定 key 值时,表示容忍所有的污点 key value: codefun operator: Equal # 当值为 Exists 将会忽略 value 值 effect: NoSchedule # 当不指定 effect 值时,表示容忍所有的污点作用 tolerationSeconds: 3600 # 描述当 Pod 需要被驱逐时可以在 Pod 上继续保留运行的时间 -------------------------------------------------------------------------------------------- 当不指定 key 值时,表示容忍所有的污点
4. 固定节点调度
cat /kubeyml/dep002.yml
--------------------------------------------------------------------------------------------
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: dep-dep002
spec:
replicas: 4
template:
metadata:
labels:
app: dep-dep002
spec:
nodeName: n001 # 设置指定节点的名字
# nodeSelector: # 根据标签选择,`kubectl label nodes` node-name key1=value1 给 pod 设置标签
# app: myapp
containers:
- name: dep-con001
image: wangyanglinux/myapp:v2
ports:
- containerPort: 80
--------------------------------------------------------------------------------------------
8. 集群安全
(一)机制说明
Kubernetes
作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Server
是集群内部各个组件通信的中介,也是外部控制的入口。- 所以
Kubernetes
的安全机制基本就是围绕保护 API Server 来设计的。- Kubernetes 使用了认证(
Authentication
)、鉴权(Authorization
)、准入控制(AdmissionControl
)三步来保证API Server
的安全
(二)认证介绍
- 一共有三种认证方式(
HTTP TOKEN
、HTTP Base
、HTTPS 证书
),这里我们使用最为严格的HTTPS 证书
认证HTTPS 证书认证
过程:首先客户端和服务端都需要向CA 架构
申请证书,然后客户端和服务端通过证书来进行身份认证,最后通过随机私钥进行通讯
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zUmCPKI5-1653055923917)(D:\云计算工坊\图片\K8S\HTTPS 证书认证.png)]
(三)鉴权过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z89txgtv-1653055923918)(D:\云计算工坊\图片\K8S\鉴权.png)]
(四)实现鉴权
useradd devuser && passwd devuser # 创建实体用户 mkdir /root/install-k8s/cert/devuser/ && vim /root/install-k8s/cert/devuser/devuser-csr.json # 编写 json 文件 -------------------------------------------------------------------------------------------- { "CN": "devuser", # 用户名 "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CN", "ST": "BeiJing", "L": "BeiJing", "O": "k8s", "OU": "System" } ] } -------------------------------------------------------------------------------------------- # 下载 SSL 证书生成工具 # 我们这里是直接将相关文件直接导入到 /usr/local/bin/ 下 chmod a+x * # 给相关文件增加可执行权限 cd /etc/kubernetes/pki/ cfssl genecrt -ca=ca.crt -ca-key=ca.key -profile=kubernetes `/root/install-k8s/cert/devuser/devuser-csr.json` | cfssljson -bare `devuser` # 有飘号的需要根据情况改动 cd /root/install-k8s/cert/devuser/ export KUBE_APISERVER="https://192.168.80.142:6443" # 设置集群参数 kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=${KUBE_APISERVER} --kubeconfig=devuser.kubeconfig # 设置集群参数 kubectl config set-credentials devuser --client-certificate=/etc/kubernetes/pki/devuser.pem --client-key=/etc/kubernetes/pki/devuser-key.pem --embed-certs=true --kubeconfig=devuser.kubeconfig # 设置客户端认证参数 kubectl create namespace dev # 创建用户管理的名称空间 kubectl config set-context kubernetes --cluster=kubernetes --user=devuser --namespace=dev --kubeconfig=devuser.kubeconfig # 设置上下文 kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev # 创建角色绑定,注意相关参数 mkdir /home/devuser/./kube cp devuser.kubeconfig /home/devuser/.kube/ chown devuser:devuser /home/devuser/.kube/devuser.kubeconfig mv /home/devuser/.kube/devuser.kubeconfig /home/devuser/.kube/config su - devuser kubectl config use-context kubernetes --kubeconfig=config kubectl run nginx --image=wangyanglinux/myapp:v2 # 创建 pod 并查看他属于能够名称空间
(五)准入控制
- 准入控制是API Server的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount
9. Helm
1. 基础知识
1. 什么是 Helm
我们在部署各种 pod 的时候,需要编写各种组件的 yml 文件,非常繁琐。而
helm
就像是yum
一样,将服务的所需的文件,组件打包到一起,从而实习服务的一键化部署。helm 的重要组件:
chart
是创建一个应用的信息集合,包括各种Kubernetes
对象的配置模板、参数定义、依赖关系、文档说明等。chart 是应用部署的自包含逻辑单元。可以将chart
想象成apt
、yum
中的软件安装包
release
是chart
的运行实例,代表了一个正在运行的应用,当chart
被安装到Kubernetes
集群,就生成一个release
。chart
能够多次安装到同一个集群,每次安装都是一个release
2. Helm
的架构
Helm
包含两个组件:Helm
客户端和Tiller
服务器。Helm
客户端负责chart
和release
的创建和管理以及和Tiller
的交互。Tiller
服务器运行在Kubernetes
集群中,它会处理Helm
客户端的请求,与Kubernetes API Server
交互[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H1YNijK3-1653055923919)(D:\云计算工坊\图片\K8S\helm 架构.png)]
2. Helm
部署
cd /usr/local/src wget https://storage.googleapis.com/kubernetes-helm/helm-v2.13.1-linux-amd64.tar.gz tar -zxvf helm-v2.13.1-linux-amd64.tar.gz cd linux-amd64/ && mv helm /usr/local/bin/ mkdir /root/install-k8s/helm/ vim /root/install-k8s/helm/rbac-config.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: ServiceAccount metadata: name: tiller namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: tiller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: tiller namespace: kube-system -------------------------------------------------------------------------------------------- $ kubectl create -f rbac-config.yml $ helm init --service-account tiller --skip-refresh $ kubectl get pod -n kube-system # 查看相应的 pod 是否启动成功
3. 编写自定义chart
# 1. 编写 Chart.yaml 文件 必须以 yaml 结尾,不然不识别 mkdir /root/install-k8s/helm/hello-world/templates && cd /root/install-k8s/helm/hello-world vim Chart.yaml -------------------------------------------------------------------------------------------- name: hello-world # 必须存在的字段 version: 1.0.0 # 必须存在的字段 -------------------------------------------------------------------------------------------- # 2. 编写服务相应的 yml 文件,且都在 templates 目录下 cd /root/install-k8s/helm/hello-world/templates vim deployment.yml -------------------------------------------------------------------------------------------- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: hello-world spec: replicas: 1 template: metadata: labels: app: hello-world spec: containers: - name: hello-world image: wangyanglinux/myapp:v1 ports: - containerPort: 80 protocol: TCP -------------------------------------------------------------------------------------------- cat service.yml -------------------------------------------------------------------------------------------- apiVersion: v1 kind: Service metadata: name: hello-world spec: type: NodePort ports: - port: 80 targetPort: 80 protocol: TCP selector: app: hello-world -------------------------------------------------------------------------------------------- # 3. 回到有 Chart.yaml 文件的目录下进行安装操作 $ helm install . # 4. 列出已经部署的 Release $ helm list NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE voting-giraffe 1 DEPLOYED hello-world-1.0.0 default # 5. 查询一个特定的 Release 的状态 $ helm status RELEASE_NAME # 6. 移除所有与这个 Release 相关的 Kubernetes 资源 $ helm delete voting-giraffe # 7. 显示没有完全删除的 release $ helm list --deleted NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE voting-giraffe 1 DEPLOYED hello-world-1.0.0 default # 8. helm rollback RELEASE_NAME REVISION_NUMBER 回滚操作 $ helm rollback voting-giraffe 1 # 9. 完全删除 $ helm delete --purge voting-giraffe # 更新一个 release $ helm upgrade voting-giraffe . # 查看操作 release 历史 helm history voting-giraffe
设置参数
# 1. 在 Chart.yaml 文件的同级目录下创建参数文件 vim /root/install-k8s/helm/hello-world/values.yaml -------------------------------------------------------------------------------------------- image: repository: wangyanglinux/myapp tag: 'v2' -------------------------------------------------------------------------------------------- # 2. 修改原来的 deployment 文件的 image 字段 -------------------------------------------------------------------------------------------- image: {{ .Values.image.repository }}:{{ .Values.image.tag }} -------------------------------------------------------------------------------------------- # 3. 更新 release $ helm upgrade voting-giraffe .
4. 使用 helm
部署 dashboard
# 1. 获取安装文件源 $ helm repo add stable http://mirror.azure.cn/kubernetes/charts/ # 2. 拉取安装文件压缩包并解压 $ mkdir /root/install-k8s/helm/dashboard && cd !$ $ helm fetch stable/kubernetes-dashboard $ tar -zxvf kubernetes-dashboard-1.11.1.tgz # 3. 编写自定义配置文件 vim kubernetes-dashboard/kubernetes-dashboard.yaml -------------------------------------------------------------------------------------------- image: repository: k8s.gcr.io/kubernetes-dashboard-amd64 tag: v1.10.1 ingress: enabled: true hosts: - k8s.frognew.com annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" tls: - secretName: frognew-com-tls-secret hosts: - k8s.frognew.com rbac: clusterAdminRole: true -------------------------------------------------------------------------------------------- # 4. 安装 dashborad $ helm install . -n kubernetes-dashboard --namespace kube-system -f kubernetes-dashboard.yaml # 5. 获取相关镜像 $ docker pull sacred02/kubernetes-dashboard-amd64:v1.10.1 $ docker tag sacred02/kubernetes-dashboard-amd64:v1.10.1 k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1 $ docker rmi -f sacred02/kubernetes-dashboard-amd64:v1.10.1 # 6. 将 ClusterIP 改为 NodePort $ kubectl get svc -n kube-system $ kubectl edit svc kubernetes-dashboard -n kube-system # 7. 获取 token 令牌 $ kubectl -n kube-system get secret | grep kubernetes-dashboard-token $ kubectl describe secrect kubernetes-dashboard-token-cflxj -n kube-system # 8. 在浏览器上访问
10. 普罗米修斯
1. 基础知识
1. 普罗米修斯的特点
- 多维数据模型:由度量名称和键值对标识的时间序列数据(查找速度快)
- 内置时间序列数据库:TSDB
promQL
:灵活的查询语言,可以利用多维数据完成复杂查询- 基于
HTTP
的pull
的方式采集时间序列数据(export
:比如 MySQL 没有相应的HTTP
接口,就用export
来暴露,然后交由服务端)- 同时支持
PushGateway
组件收集数据(对于转瞬即逝的数据,export
不能及时,由他来做)- 通过服务发现或静态配置发现目标
- 支持作为数据源接入
Grafana
更多推荐
所有评论(0)