kubernetes学习资料 Kubernetes 学习资料(版本:1.21) ConfigMap Secret 使用 RBAC 鉴权的概念: 网络策略 Network Policies:
一、K8S核心概念与集群搭建
#kubernetes集群搭建
部署K8S的2种方式
.kubeadm
Kubeadm是一个工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。
部署地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
.二进制
从官方下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。
下载地址:https://github.com/kubernetes/kubernetes/releases
CentOS 7(使用 yum 进行安装)
# step 1: 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 # Step 2: 添加软件源信息 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # Step 3 sudo sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo # Step 4: 更新并安装Docker-CE sudo yum makecache fast sudo yum -y install docker-ce # Step 4: 开启Docker服务 sudo service docker start # 注意: # 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。 # vim /etc/yum.repos.d/docker-ce.repo # 将[docker-ce-test]下方的enabled=0修改为enabled=1 # # 安装指定版本的Docker-CE: # Step 1: 查找Docker-CE的版本: # yum list docker-ce.x86_64 --showduplicates | sort -r # Loading mirror speeds from cached hostfile # Loaded plugins: branch, fastestmirror, langpacks # docker-ce.x86_64 17.03.1.ce-1.el7.centos docker-ce-stable # docker-ce.x86_64 17.03.1.ce-1.el7.centos @docker-ce-stable # docker-ce.x86_64 17.03.0.ce-1.el7.centos docker-ce-stable # Available Packages # Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos) # sudo yum -y install docker-ce-[VERSION]
#docker镜像加速的配置
通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
# mkdir -p /etc/docker # tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://m9s0cjt1.mirror.aliyuncs.com"] } EOF # systemctl daemon-reload # systemctl restart docker
#Kubernetes的基础知识
部署Kubernetes集群主要有两种方式:
- kubeadm
Kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。
- 二进制包
从github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。
这里采用kubeadm搭建集群。
kubeadm工具功能:
kubeadm init | 初始化一个Master节点 |
kubeadm join | 将工作节点加人集群 |
kubeadm upgrade | 升级k8s版本 |
kubeadm token | 管理kubeadm join使用的令牌 |
kubeadm reset | 清空kubeadm init 或者kubeadm join对主机所做的任何修改 |
kubeadm version | 打印kubeadm版本 |
kubeadm alpha |
预览可用的新功能 |
#Kubernetes的安装准备环境
服务器规划:
服务器名称 | IP |
demo-master | 192.168.178.90 |
demo-node1 | 192.168.178.91 |
demo-node2 | 192.168.178.92 |
#Kubernetes的架构
#Kubernetes的初始化安装(每个节点都需要做)
----> 关闭防火墙
[root@demo-master ~]# systemctl stop firewalld [root@demo-master ~]# systemctl disable firewalld Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service. Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
----> 关闭selinux
[root@demo-master ~]# sed -i 's/enforcing/disabled/' /etc/selinux/config [root@demo-master ~]# setenforce 0
----> 关闭swap
[root@demo-master ~]# swapoff -a [root@demo-master ~]# sed -ri 's/.*swap.*/#&/' /etc/fstab
----> 在master上编辑hosts(注意只在master上)
cat >> /etc/hosts << EOF 192.168.178.90 demo-master1 192.168.178.91 demo-node1 192.168.178.92 demo-node2 EOF
----> 将桥接的IPv4流量传递到iptables的链
[root@demo-master ~]# cat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF [root@demo-master ~]# sysctl --system
----> 时间同步
[root@demo-master ~]# yum -y install ntpdate [root@demo-master ~]# ntpdate time.windows.com
#Kubernetes的安装(添加阿里云YUM软件源)
[root@demo-master ~]# cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF
#安装kubeadm kubelet kubectl
yum install -y kubelet-1.21.0 kubeadm-1.21.0 kubectl-1.21.0 systemctl enable kubelet
#部署kubernetes Master
在master节点上单独执行:
kubeadm init --apiserver-advertise-address=192.168.178.90 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.21.0 --service-cidr=10.99.0.0/12 --pod-network-cidr=10.200.0.0/16 --ignore-preflight-errors=all
- --apiserver-advertise-address 集群通告地址
- --image-repository 由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址
- --kubernetes-version K8s版本,与上面安装的一致
- --service-cidr 集群内部虚拟网络,Pod统一访问入口
- --pod-network-cidr Pod网络,,与下面部署的CNI网络组件yaml中保持一致
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
在node节点上执行
kubeadm join 192.168.178.90:6443 --token n6psi2.9p918j0vqvvmidlg --discovery-token-ca-cert-hash sha256:8c3afb6c64372774def7df9ddd2dc11fcf3cc58bef8a4cb269b287a20175f322
#部署kubernetes 的网络插件
https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file
Calico是一个纯三层的数据中心网络方案,是目前Kubernetes主流的网络方案。
下载calico.yaml的文件
wget https://docs.projectcalico.org/manifests/calico.yaml
修改完后文件后,部署:
[root@demo-master ~]# vim calico.yaml
- name: CALICO_IPV4POOL_CIDR value: "10.200.0.0/16"
用yaml文件部署calico网络
[root@demo-master ~]# kubectl apply -f calico.yaml
[root@demo-master ~]# kubectl get nodes
CoreDNS问题处理:
在所有节点上重新pull拉起coreDNS镜像
[root@demo-master ~]# docker pull registry.aliyuncs.com/google_containers/coredns:1.8.0 1.8.0: Pulling from google_containers/coredns c6568d217a00: Pull complete 5984b6d55edf: Pull complete [root@demo-master ~]# docker tag registry.aliyuncs.com/google_containers/coredns:1.8.0 registry.aliyuncs.com/google_containers/coredns/coredns:v1.8.0
安装目录:/etc/kubernetes/
组件配置文件目录:/etc/kubernetes/manifests/
#测试kubernetes集群搭建的情况
[root@demo-master ~]# kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
[root@demo-master ~]# kubectl expose deployment nginx --port=80 --type=NodePort
service/nginx exposed
[root@demo-master ~]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-6799fc88d8-22mln 1/1 Running 0 39s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27m
service/nginx NodePort 10.103.40.162 <none> 80:30430/TCP 7s
#部署dashboard
Dashboard是官方提供的一个UI,可用于基本管理K8s资源。
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml
默认Dashboard只能集群内部访问,修改Service为NodePort类型,暴露到外部:
vi recommended.yaml ... kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: ports: - port: 443 targetPort: 8443 nodePort: 30001 selector: k8s-app: kubernetes-dashboard type: NodePort ...
部署:
[root@demo-master ~]# kubectl apply -f kubernetes-dashboard.yaml namespace/kubernetes-dashboard created serviceaccount/kubernetes-dashboard created service/kubernetes-dashboard created secret/kubernetes-dashboard-certs created secret/kubernetes-dashboard-csrf created secret/kubernetes-dashboard-key-holder created configmap/kubernetes-dashboard-settings created role.rbac.authorization.k8s.io/kubernetes-dashboard created clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created deployment.apps/kubernetes-dashboard created service/dashboard-metrics-scraper created deployment.apps/dashboard-metrics-scraper created
创建service account并绑定默认cluster-admin管理员集群角色:
[root@demo-master ~]# kubectl create serviceaccount dashboard-admin -n kube-system serviceaccount/dashboard-admin created [root@demo-master ~]# kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin clusterrolebinding.rbac.authorization.k8s.io/dashboard-admin created
#kubernetes基本概念
自动安装脚本:
#!/bin/bash # 在 master 节点和 worker 节点都要执行 # 安装 containerd # 参考文档如下 # https://kubernetes.io/docs/setup/production-environment/container-runtimes/#containerd cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # Setup required sysctl params, these persist across reboots. cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-ip6tables = 1 EOF # Apply sysctl params without reboot sysctl --system # 卸载旧版本 yum remove -y containerd.io # 设置 yum repository yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 安装 containerd yum install -y containerd.io-1.4.3 mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml sed -i "s#k8s.gcr.io#registry.aliyuncs.com/k8sxio#g" /etc/containerd/config.toml sed -i '/containerd.runtimes.runc.options/a SystemdCgroup = true' /etc/containerd/config.toml sed -i "s#https://registry-1.docker.io#${REGISTRY_MIRROR}#g" /etc/containerd/config.toml systemctl daemon-reload systemctl enable containerd systemctl restart containerd # 安装 nfs-utils # 必须先安装 nfs-utils 才能挂载 nfs 网络存储 yum install -y nfs-utils yum install -y wget # 关闭 防火墙 systemctl stop firewalld systemctl disable firewalld # 关闭 SeLinux setenforce 0 sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config # 关闭 swap swapoff -a yes | cp /etc/fstab /etc/fstab_bak cat /etc/fstab_bak |grep -v swap > /etc/fstab # 配置K8S的yum源 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 remove -y kubelet kubeadm kubectl # 安装kubelet、kubeadm、kubectl # 将 ${1} 替换为 kubernetes 版本号,例如 1.20.1 yum install -y kubelet-${1} kubeadm-${1} kubectl-${1} crictl config runtime-endpoint /run/containerd/containerd.sock # 重启 docker,并启动 kubelet systemctl daemon-reload systemctl enable kubelet && systemctl start kubelet containerd --version kubelet --version
Master 负责管理集群 负责协调集群中的所有活动,例如调度应用程序,维护应用程序的状态,扩展和更新应用程序。
Node节点(即Work)是VM(虚拟机)或物理计算机,充当k8s集群中的工作计算机。 每个Node节点都有一个Kubelet,它管理该Node节点并负责与Master节点通信。该Node节点还应具有用于处理容器操作的工具,例如Docker。
容器编排系统的:
- Kubernetes
- Swarm
- Mesos Marathon
- Kubernetes 是Google在2014年开源的一个容器集群管理系统,Kubernetes简称K8S。
- Kubernetes用于容器化应用程序的部署,扩展和管理,目标是让部署容器化应用简单高效。
官方网站:http://www.kubernetes.io
官方文档:https://kubernetes.io/zh/docs/home/
#kubernetes集群控制组件
Master组件
. kube-apiserverKubernetes API
集群的统一入口,各组件协调者,以RESTful API提供接口服务,所有对象资源的增删改查和监听操作都交给APIServer处理后再提交给Etcd存储。
. kube-controller-manager
处理集群中常规后台任务,一个资源对应一个控制器,而ControllerManager就是负责管理这些控制器的。
. kube-scheduler
根据调度算法为新创建的Pod选择一个Node节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
. etcd
分布式键值存储系统。用于保存集群状态数据,比如Pod、Service等对象信息。
Node组件
.kubelet
kubelet是Master在Node节点上的Agent,管理本机运行容器的生命周期,比如创建容器、Pod挂载数据卷、下载secret、获取容器和节点状态等工作。kubelet将每个Pod转换成一组容器。
.kube-proxy
在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作。
.docker或rocket
容器引擎,运行容器。
二、K8S监控与日志管理
Metrics Server是一个集群范围的资源使用情况的数据聚合器。作为一个应用部署在集群中。Metric server从每个节点上KubeletAPI收集指标,通过Kubernetes聚合器注册在Master APIServer中。为集群提供Node、Pods资源利用率指标
Metrics-Server工作流程图
Metrics-Server部署
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:aggregated-metrics-reader
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rules:
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metrics-server:system:auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: metrics-server-auth-reader
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1beta1.metrics.k8s.io
spec:
service:
name: metrics-server
namespace: kube-system
group: metrics.k8s.io
version: v1beta1
insecureSkipTLSVerify: true
groupPriorityMinimum: 100
versionPriority: 100
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: metrics-server
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: metrics-server
namespace: kube-system
labels:
k8s-app: metrics-server
spec:
selector:
matchLabels:
k8s-app: metrics-server
template:
metadata:
name: metrics-server
labels:
k8s-app: metrics-server
spec:
serviceAccountName: metrics-server
volumes:
# mount in tmp so we can safely use from-scratch images and/or read-only containers
- name: tmp-dir
emptyDir: {}
containers:
- name: metrics-server
image: lizhenliang/metrics-server:v0.3.7
imagePullPolicy: IfNotPresent
args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-insecure-tls #告诉metrics-server服务器不验证kubelet提供的https证书
- --kubelet-preferred-address-types=InternalIP
- --kubelet-insecure-tls
ports:
- name: main-port
containerPort: 4443
protocol: TCP
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
volumeMounts:
- name: tmp-dir
mountPath: /tmp
nodeSelector:
kubernetes.io/os: linux
kubernetes.io/arch: "amd64"
---
apiVersion: v1
kind: Service
metadata:
name: metrics-server
namespace: kube-system
labels:
kubernetes.io/name: "Metrics-server"
kubernetes.io/cluster-service: "true"
spec:
selector:
k8s-app: metrics-server
ports:
- port: 443
protocol: TCP
targetPort: main-port
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: system:metrics-server
rules:
- apiGroups:
- ""
resources:
- pods
- nodes
- nodes/stats
- namespaces
- configmaps
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: system:metrics-server
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
[root@k8s-master ~]# kubectl apply -f metrics-server.yaml
[root@k8s-master ~]# kubectl get apiservices |grep metrics
v1beta1.metrics.k8s.io kube-system/metrics-server True 17d
#管理kubernetes组件日志
systemd守护进程管理的组件:
journalctl -u kubelet
Pod部署的组件:
kubectl logs kube-proxy-btz4p -n kube-system
系统日志:
/var/log/messages
#查看kubernetes容器标准输出日志
[root@k8s-master ~]# kubectl logs nginx-6799fc88d8-r4vrh
[root@k8s-master ~]# kubectl logs -f nginx-6799fc88d8-r4vrh
[root@k8s-master ~]# kubectl logs -f nginx-6799fc88d8-r4vrh -c nginx
标准输出在宿主机的路径:
[root@k8s-master ~]# cd /var/lib/docker/containers
[root@k8s-master containers]# ll
#收集kubernetes日志的方法
针对标准输出:以DaemonSet方式在每个Node上部署一个日志收集程序,采集/var/lib/docker/containers/ 目录下的容器日志
针对容器中日志文件:在pod中增加一个容器运行日志采集器,使用emtyDir共享日志目录让日志采集器读取到日志文件
三、K8S管理应用程序生命周期(Deployment)
#kubernetes部署应用程序流程
#Deployments的主要功能
一个 Deployment 为 Pods 和 ReplicaSets 提供声明式的更新能力。
• 管理Pod和ReplicaSet
• 具有上线部署、副本设定、滚动升级、回滚等功能
• 提供声明式更新,例如只更新一个新的Image
---> 部署的过程:(命令行部署方式)
[root@k8s-master ~]# kubectl create deployment web2 --image=lizhenlian/java-demo
deployment.apps/web2 created
[root@k8s-master ~]# kubectl expose deployment web2 --port=80 --type=NodePort --target-port=8080 --name=web2
service/web2 exposed
[root@k8s-master ~]# kubectl get pod,deployment,svc
[root@k8s-master ~]# kubectl edit svc web2 (可以在线编辑deployment的yaml文件)
格式:kubectl edit <pod的名称>
---> 部署的过程:(Yaml文件部署方式)
YAML语法格式:
• 缩进表示层级关系
• 不支持制表符“tab”缩进,使用空格缩进
• 通常开头缩进2 个空格
• 字符后缩进1 个空格,如冒号、逗号等
• “---” 表示YAML格式,一个文件的开始
• “#”注释
定义一个deployment的yaml文件:vim nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.17
定义一个Service的yaml文件:vim nginx-service.yaml
apiVersion: v1 kind: Service metadata: name: nginx-service #Service 的名称 labels: #Service 自己的标签 app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签 spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问 selector: #标签选择器 app: nginx #选择包含标签 app:nginx 的 Pod ports: - name: nginx-port #端口的名字 protocol: TCP #协议类型 TCP/UDP port: 80 #集群内的其他容器组可通过 80 端口访问 Service nodePort: 32600 #通过任意节点的 32600 端口访问 Service targetPort: 80 #将请求转发到匹配 Pod 的 80 端口 type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
一个deployment+service共同部署的Yaml文件
apiVersion: apps/v1 kind: Deployment metadata: name: web5 namespace: default spec: replicas: 2 selector: matchLabels: app: web5 template: metadata: labels: app: web5 spec: containers: - name: web5 image: nginx:1.17 --- apiVersion: v1 kind: Service metadata: name: web5 namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: web5 type: NodePort
[root@k8s-master ~]# kubectl apply -f nginx-d1.yaml
[root@k8s-master ~]# kubectl get pods,deployment,svc
---> Scaling(伸缩)应用程序
伸缩 的实现可以通过更改 nginx-deployment.yaml 文件中部署的 replicas(副本数)来完成
修改了 Deployment 的 replicas 为 4 后,Kubernetes 又为该 Deployment 创建了 3 新的 Pod,这 4 个 Pod 有相同的标签。因此Service A通过标签选择器与新的 Pod建立了对应关系,将访问流量通过负载均衡在 4 个 Pod 之间进行转发。
通过修改部署中的replicas(副本数)来完成扩展
[root@k8s-master ~]# kubectl edit deployment web5
---> 滚动更新(多 Deployment 动态更新)
[root@k8s-master ~]# kubectl edit deployment web5
在yaml文件中修改:image: nginx:1.8
使用新的镜像替换原来版本nginx镜像
[root@k8s-master ~]# kubectl apply -f <yaml文件>
deployment.apps/web5 edited
[root@k8s-master ~]# watch kubectl get pods -l app=web5 (观察镜像替换的过程)
---> 回滚操作Deployment的详细过程:
有时,你可能想要回滚 Deployment;例如,当 Deployment 不稳定时(例如进入反复崩溃状态)。 默认情况下,Deployment 的所有上线记录都保留在系统中,以便可以随时回滚 (你可以通过修改修订历史记录限制来更改这一约束)。
- 假设你在更新 Deployment 时犯了一个拼写错误,将镜像名称命名设置为
nginx:1.161
而不是nginx:1.16.1
[root@k8s-master ~]# kubectl get deployment nginx-deployment
修改了这里:
升级错误出现这样:
[root@k8s-master ~]# kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.161 --record=true
输出类似于:
deployment.apps/nginx-deployment image updated
error: unable to find container named "nginx"
- 通过检查上线状态来验证:
[root@k8s-master ~]# kubectl rollout status deployment/nginx-deployment
输出类似于:
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
- 查看副本工作情况:
[root@k8s-master ~]# kubectl get rs
- 查看所创建的 Pod,你会注意到新 ReplicaSet 所创建的 1 个 Pod 卡顿在镜像拉取循环中。
[root@k8s-master ~]# kubectl get pods
- 获取 Deployment 描述信息:
[root@k8s-master ~]# kubectl describe deployment
输出类似于:
- 检查 Deployment 上线历史,检查 Deployment 修订历史:
[root@k8s-master ~]# kubectl rollout history deployment.v1.apps/nginx-deployment
- 要查看修订历史的详细信息,运行:
[root@k8s-master ~]# kubectl rollout history deployment.v1.apps/nginx-deployment --revision=1
- 回滚到之前的修订版本
- 撤消当前上线并回滚到以前的修订版本:
[root@k8s-master ~]# kubectl rollout undo deployment.v1.apps/nginx-deployment
输出类似于:
deployment.apps/nginx-deployment rolled back
2.使用 --to-revision
来回滚到特定修订版本
[root@k8s-master ~]# kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=1
输出类似于:
deployment.apps/nginx-deployment rolled back
3.检查回滚是否成功以及 Deployment 是否正在运行:
[root@k8s-master ~]# kubectl get deployment nginx-deployment
输出类似于:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 7h49m
4.获取 Deployment 描述信息:
[root@k8s-master ~]# kubectl describe deployment nginx-deployment
回滚操作命令格式:(回滚是重新部署某一次部署时的状态,即当时版本所有配置)
kubectl rollout history deployment/web # 查看历史发布版本
kubectl rollout undo deployment/web # 回滚上一个版本
kubectl rollout undo deployment/web --to-revision=2 # 回滚历史指定版本
最后,项目下线:
kubectl delete deploy/web
kubectl delete svc/web
#ReplicaSet控制器的用途
- Pod副本数量管理,不断对比当前Pod数量与期望Pod数量
- Deployment每次发布都会创建一个RS作为记录,用于实现回滚
-
#查看RS记
[root@k8s-master ~]# kubectl get rs
- #版本对应RS记录
[root@k8s-master ~]# kubectl rollout history deployment web5 deployment.apps/web5 REVISION CHANGE-CAUSE 3 <none> 4 <none>
ReplicaSet :确保任何时间都有指定数量的 Pod 副本在运行。 然而,Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,我们建议使用 Deployment 而不是直接使用 ReplicaSet,除非 你需要自定义更新业务流程或根本不需要更新。
新建一个ReplicaSet:
apiVersion: apps/v1 kind: ReplicaSet metadata: name: frontend labels: app: guestbook tier: frontend spec: # modify replicas according to your case replicas: 3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: - name: php-redis image: nginx:1.17
[root@k8s-master ~]# kubectl apply -f my-rs.yaml #部署ReplicaSet
[root@k8s-master ~]# kubectl get rs #查看ReplicaSet
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 13m
[root@k8s-master ~]# kubectl describe rs/frontend #查看ReplicaSet的详细信息
[root@k8s-master ~]# kubectl get pods #查看rs创建的pod
NAME READY STATUS RESTARTS AGE
frontend-cphq5 1/1 Running 0 15m
frontend-drkgs 1/1 Running 0 15m
frontend-kbbct 1/1 Running 0 15m
[root@k8s-master ~]# kubectl get pods frontend-kbbct -o yaml >t2.yaml #通过命令导出pod的yaml文件
[root@k8s-master ~]# kubectl get rs frontend -o yaml >rs1.yaml #通过命令导出ReplicaSet的yaml文件
删除 ReplicaSet 和它的 Pod
要删除 ReplicaSet 和它的所有 Pod,使用 kubectl delete
命令。 默认情况下,垃圾收集器 自动删除所有依赖的 Pod。
[root@k8s-master ~]# kubectl delete rs frontend replicaset.apps "frontend" deleted
四、K8S管理应用程序生命周期(POD)
# Pods
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。Pod (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。
除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。 你也可以在集群中支持临时性容器 的情况下,为调试的目的注入临时性容器。
Pod是Kubernetes创建和管理的最小单元,一个Pod由一个容器或多个容器组成,这些容器共享存储、网络。
Pod特点:
- 一个Pod可以理解为是一个应用实例,提供服务
- Pod中容器始终部署在一个Node上
- Pod中容器共享网络、存储资源
- Kubernetes直接管理Pod,而不是容器
Pod主要用法:
- 运行单个容器:最常见的用法,在这种情况下,可以将Pod看做是单个容器的抽象封装
- 运行多个容器:封装多个紧密耦合且需要共享资源的应用程序
运行多个容器:
- 两个应用之间发生文件交互
- 两个应用需要通过127.0.0.1或者socket通信
- 两个应用需要发生频繁的调用
资源共享实现机制:
将业务容器的网络加入到“负责网络容器”实现网络共享。共享存储:容器通过数据卷共享数据
#实现网络资源共享机制
-
单独拉起一个pod;pod里面部署两个容器。
apiVersion: v1 kind: Pod metadata: labels: app: test name: pod-net-test namespace: default spec: containers: - image: busybox name: test command: ["/bin/sh","-c","sleep 12h"] - image: nginx name: web
-
通过命令部署单独的pod;
[root@k8s-master ~]# kubectl apply -f net-t1.yaml
- 查看POD的运行情况
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-net-test 2/2 Running 0 13m
4.通过命令进入POD中的容器
[root@k8s-master ~]# kubectl exec -it pod-net-test -c test -- sh
/ # ip addr
: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1440 qdisc noqueue
link/ether 12:76:2e:fb:9f:86 brd ff:ff:ff:ff:ff:ff
inet 10.244.169.153/32 scope global eth0
[root@k8s-master ~]# kubectl exec -it pod-net-test -c web -- sh
/ # netstat -antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 :::80 :::* LISTEN - #监听80端口
/ # wget 127.0.0.1:80
Connecting to 127.0.0.1:80 (127.0.0.1:80)
5. 从新进入POD中的web容器中
[root@k8s-master ~]# kubectl exec -it pod-net-test -c web -- sh
# cd /usr/share/nginx/html
# ls
50x.html index.html
# echo "yuanye is 12345">index.html
# cat index.html
yuanye is 12345
6.再进入POD中的busybox容器中查看
[root@k8s-master ~]# kubectl exec -it pod-net-test -c test -- sh
/ # wget 127.0.0.1:80
Connecting to 127.0.0.1:80 (127.0.0.1:80)
saving to 'index.html'
index.html 100% |**************************************************| 16 0:00:00 ETA
'index.html' saved
/ # cat index.html
yuanye is 12345
这就是k8s的网络资源模式:和docker container 一样,启动了infra Container容器 ,/pause:3.4.1容器就是这个基础容器
#实现数据卷的共享机制
1.先创建一个pod 的yaml文件
apiVersion: v1 kind: Pod metadata: labels: app: test name: pod-volume-test namespace: default spec: containers: - image: busybox name: test command: ["/bin/sh","-c","sleep 12h"] volumeMounts: # 数据卷挂载 - name: log # 指定挂载的数据卷名称 mountPath: /data # 数据卷挂载到容器中的路径 - image: nginx name: web volumeMounts: - name: log mountPath: /usr/share/nginx/html volumes: # 定义数据卷 - name: log # 数据卷名称 emptyDir: {} # 数据卷类型
2.根据yaml文件部署POD
[root@k8s-master ~]# kubectl apply -f pod-vol.yaml
3.查看POD的运行状况
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-volume-test 2/2 Running 0 4m39s
4 . 验证文件的共享
[root@k8s-master ~]# kubectl exec -it pod-volume-test -c test -- sh
/ # cd /data
/data # ls
/data # touch yuan.txt
/data # exit
[root@k8s-master ~]# kubectl exec -it pod-volume-test -c web -- sh
# cd /usr/share/nginx/html
# ls
yuan.txt
# POD的管理命令
---------------------创建Pod:---------------------------------------
kubectl apply -f pod.yaml
或者使用命令:kubectl run nginx --image=nginx
-------------------------------查看Pod:-------------------------------
kubectl get pods
kubectl describe pod <Pod名称>
-------------------------------查看日志:-------------------------------
kubectl logs <Pod名称> [-c CONTAINER]
kubectl logs <Pod名称> [-c CONTAINER] -f
-------------------------------进入容器终端:--------------------------
kubectl exec <Pod名称> [-c CONTAINER] -- bash
-------------------------------删除Pod:-------------------------------
kubectl delete pod <Pod名称>
# POD的重启策略,健康检查
重启策略(restartPolicy):
• Always:当容器终止退出后,总是重启容器,默认策略。
• OnFailure:当容器异常退出(退出状态码非0)时,才重启容器。
• Never:当容器终止退出,从不重启容器。
健康检查有以下两种类型:
• livenessProbe(存活检查):如果检查失败,将杀死容器,根据Pod 的restartPolicy来操作。
• readinessProbe(就绪检查):如果检查失败,Kubernetes会把Pod从service endpoints中剔除。
支持以下三种检查方法:
• httpGet:发送HTTP请求,返回200-400范围状态码为成功。
• exec:执行Shell命令返回状态码是0为成功。
• tcpSocket:发起TCP Socket建立成功。
建立一个有健康检查的pod
---> POD健康检查的演示:
1、通过create的方式导出一个deployment的yaml文件
[root@k8s-master ~]# kubectl create deployment pod-check --image=nginx --dry-run=client -o yaml>check-dep.yaml
2、编辑yaml文件
apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-check name: pod-check spec: replicas: 3 selector: matchLabels: app: pod-check strategy: {} template: metadata: labels: app: pod-check spec: containers: - image: nginx:1.16 name: nginx resources: {} livenessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /index.html port: 80 initialDelaySeconds: 10 periodSeconds: 10
存活检查:
livenessProbe:
httpGet: #因为容器为nginx,所以用httpGet方式进行存活检查
path: /index.html #跟踪检查nginx的主页
port: 80 #跟踪检查端口
initialDelaySeconds: 10 #启动容器后多少秒进行健康检查
periodSeconds: 10 #每隔多少秒检查一次
就绪检查:
readinessProbe:
httpGet: #因为容器为nginx,所以用httpGet方式进行存活检查
path: /index.html
port: 80
initialDelaySeconds: 10 #启动容器后多少秒进行健康检查
periodSeconds: 10 #每隔多少秒检查一次
3、apply一个deployment的yaml文件
kubectl apply -f check-deployment.yaml
4、观察deployment的启动情况
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-check-67fd5d95b8-24prt 1/1 Running 0 17h
pod-check-67fd5d95b8-rmjj5 1/1 Running 0 17h
pod-check-67fd5d95b8-xbttq 1/1 Running 0 17h
5、进行存活检查的试验,通过命令进入到容器中
[root@k8s-master ~]# kubectl exec -it pod-check-67fd5d95b8-24prt -- bash
root@pod-check-67fd5d95b8-24prt:/#
root@pod-check-67fd5d95b8-24prt:/# cd /usr/share/nginx/html
root@pod-check-67fd5d95b8-24prt:/usr/share/nginx/html# ls
50x.html index.html
root@pod-check-67fd5d95b8-24prt:/usr/share/nginx/html# rm index.html
root@pod-check-67fd5d95b8-24prt:/usr/share/nginx/html# command terminated with exit code 137
index.html文件被删除后,存活检查就自动终止了这个容器,重新拉起新的容器。
---> POD环境变量的演示:
1、编辑一个环境变量演示的POD
apiVersion: v1 kind: Pod metadata: name: pod-env spec: containers: - name: test image: busybox command: ["sh","-c","sleep 3600"] env: # 变量值从Pod属性获取 - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: MY_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: MY_POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: ABC value: "123456"
# 变量值从Pod属性获取
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
2、观察pod的运行情况
[root@k8s-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-env 1/1 Running 0 51s
3、进入容器查看环境变量:
[root@k8s-master ~]# kubectl exec -it pod-env sh
/ # echo $ABC
123456
/ # echo $MY_POD_NAMESPACE
/ # echo $MY_POD_IP
10.244.169.139
# POD对象:Init Container
Init Container:顾名思义,用于初始化工作,执行完就结束,可以理解为一次性任务。
• 支持大部分应用容器配置,但不支持健康检查
• 优先应用容器执行
应用场景:
• 环境检查:例如确保应用容器依赖的服务启动后再启动应用容器
• 初始化配置:例如给应用容器准备配置文件
---> 示例:部署一个web网站,网站程序没有打到镜像中,而是希望从代码仓库中动态拉取放到应用容器中。
1、编辑一个yaml文件
apiVersion: v1 kind: Pod metadata: name: init-demo spec: initContainers: - name: d1 image: busybox command: - wget - "-O" - "/opt/index.html" - http://39.106.226.142 (如果不能解析DNS,就换成IP地址) volumeMounts: - name: wwwroot mountPath: "/opt" containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html volumes: - name: wwwroot emptyDir: {}
2、查看init初始化容器的运行效果
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
init-demo 0/1 Init:Error 0 6s
3、查看init初始化容器的运行情况
[root@k8s-master ~]# kubectl logs init-demo -c d1 (d1是initContainers的容器运行名称)
Connecting to 43.129.209.143 (43.129.209.143:80)
index.html 100% |*******************************| 21077 0:00:00 ETA (表示已经下载了index.html文件到共享存储中了)
4、进入第二个容器查看下载到共享文件夹的文件
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
init-demo 1/1 Running 0 5m33s
[root@k8s-master ~]# kubectl exec -it init-demo -- bash
Defaulted container "nginx" out of: nginx, d1 (init)
root@init-demo:/# cd /usr/share/nginx/html
root@init-demo:/usr/share/nginx/html# ls
index.html
# POD中容器类型
Pod中会有这几种类型的容器:
• Infrastructure Container:基础容器,维护整个Pod网络空间
• InitContainers:初始化容器, 先于业务容器开始执行
• Containers:业务容器,并行启动
# 静态POD
静态Pod特点:
• Pod由特定节点上的kubelet管理
• 不能使用控制器
• Pod名称标识当前节点名称
在kubelet配置文件启用静态Pod的参数:
[root@k8s-master ~]# vim /var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1 authentication: anonymous: enabled: false webhook: cacheTTL: 0s enabled: true x509: clientCAFile: /etc/kubernetes/pki/ca.crt authorization: mode: Webhook webhook: cacheAuthorizedTTL: 0s cacheUnauthorizedTTL: 0s cgroupDriver: cgroupfs clusterDNS: - 10.96.0.10 clusterDomain: cluster.local cpuManagerReconcilePeriod: 0s evictionPressureTransitionPeriod: 0s fileCheckFrequency: 0s healthzBindAddress: 127.0.0.1 healthzPort: 10248 httpCheckFrequency: 0s imageMinimumGCAge: 0s kind: KubeletConfiguration logging: {} nodeStatusReportFrequency: 0s nodeStatusUpdateFrequency: 0s rotateCertificates: true runtimeRequestTimeout: 0s shutdownGracePeriod: 0s shutdownGracePeriodCriticalPods: 0s staticPodPath: /etc/kubernetes/manifests streamingConnectionIdleTimeout: 0s syncFrequency: 0s volumeStatsAggPeriod: 0s
staticPodPath: /etc/kubernetes/manifests (注:将部署的pod yaml放到该目录会由kubelet自动创建。)
[root@k8s-master ~]# ll /etc/kubernetes/manifests/
total 16
-rw------- 1 root root 2226 Sep 14 14:23 etcd.yaml #etcd的yaml文件
-rw------- 1 root root 3335 Sep 14 14:23 kube-apiserver.yaml #apiserver的yaml文件
-rw------- 1 root root 2827 Sep 14 14:23 kube-controller-manager.yaml #controller-manager的yaml文件
-rw------- 1 root root 1413 Sep 14 14:23 kube-scheduler.yaml #scheduler的yaml文件
五、K8S的Pod调度
# 创建一个Pod的工作流程
Kubernetes基于list-watch机制的控制器架构,实现组件间交互的解耦。其他组件监控自己负责的资源,当这些资源发生变化时,kube-apiserver会通知这些组件,这个过程类似于发布与订阅。
容器资源限制:limits(容器里应用程序使用的最大资源上限)
•resources.limits.cpu
•resources.limits.memory
容器使用的最小资源需求,作为容器调度时资源分配的依据:requests
(请求值,预留值,不是实际使用值,用于资源分配的参考值。)
•resources.requests.cpu
•resources.requests.memory
#实例:pod资源调度
1、编辑yaml文件
[root@master ~]# vim test-resources.yaml
apiVersion: v1 kind: Pod metadata: name: web spec: containers: - name: web image: nginx resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
2、部署实例
[root@master ~]# kubectl apply -f test-resources.yaml
3、通过kubectl describe 查看pod运行的情况,观察pod资源调度的详细情况
[root@master ~]# kubectl describe pod web 查看pod的运行详细情况。
4、通过查看node1上运行的情况,了解pod资源调用情况,该pod是运行在node1上的,然后通过命令可以查看node1上的
所有pod运行资源的调度情况;
[root@master ~]# kubectl describe node node1
(CPU单位:可以写m也可以写浮点数,例如0.5=500m,1=1000m)
(K8s会根据Request的值去查找有足够资源的Node来调度此Pod)
(requests 一般良性参考值小于limits的20%---30%)
(节点上的limits总和不能超宿主机实际物理配置的20%)
(当请求的资源值大于节点的资源情况,pod就会处于pendding状态,无法调度)
#通过命令可以查看node节点上的资源情况
[root@master ~]# kubectl describe node |grep cpu
#nodeSelector
nodeSelector:用于将Pod调度到匹配Label的Node上,如果没有匹配的标签会调度失败。
作用:
•约束Pod到特定的节点运行
•完全匹配节点标签
应用场景:
•专用节点:根据业务线将Node分组管理
•配备特殊硬件:部分Node配有SSD硬盘、GPU
示例:确保Pod分配到具有SSD硬盘的节点上
1、编辑一个带ssd标签的yaml文件
apiVersion: v1 kind: Pod metadata: name: pod-selector spec: nodeSelector: disktype: "ssd" containers: - name: test-selector image: nginx:1.19
2、查看pod的部署情况,因为node上没有disktype: “ssd”的标签,所以是pending状态
3、给node1节点添加标签
[root@master ~]# kubectl label nodes node2 disktype=ssd
验证节点标签:
[root@master ~]# kubectl get nodes --show-labels
4、验证pod的部署情况
[root@master ~]# kubectl get pods -o wide
#nodeAffinity
nodeAffinity:节点亲和类似于nodeSelector,可以根据节点上的标签来约束Pod可以调度到哪些节点。
相比nodeSelector:
•匹配有更多的逻辑组合,不只是字符串的完全相等,支持的操作符有:In、NotIn、Exists、DoesNotExist、Gt、Lt
•调度分为软策略和硬策略,而不是硬性要求
•硬(required):必须满足
•软(preferred):尝试满足,但不保证
#Taint(污点)Tolerations(污点容忍)
Taints:避免Pod调度到特定Node上
Tolerations:允许Pod调度到持有Taints的Node上
应用场景:
•专用节点:根据业务线将Node分组管理,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
•配备特殊硬件:部分Node配有SSD硬盘、GPU,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
•基于Taint的驱逐
示例:Tain't污点
1、查看节点上的Taint(污点)的情况
[root@master ~]# kubectl describe node master|grep Taint
[root@master ~]# kubectl describe node |grep Taint
2、给节点添加污点(Tiant)
[root@master ~]# kubectl taint node node1 disktype=ssd:NoSchedule
[root@master ~]# kubectl describe node |grep Taint
3、编辑一个可以被node1节点上调度的yaml文件
apiVersion: v1 kind: Pod metadata: name: pod-selector spec: nodeSelector: disktype: "ssd" containers: - name: test-selector image: nginx:1.19
4、调度部署一个带有节点选择的pod
不被节点所调度,原因是:
[root@master ~]# kubectl describe pod pod-selector
5、添加污点容忍在调度
apiVersion: v1 kind: Pod metadata: name: pod-selector spec: nodeSelector: disktype: "ssd" tolerations: - key: "disktype" #污点的键值 operator: "Equal" #等于 value: "ssy" #污点的键值对应 effect: "NoSchedule" containers: - name: test-selector image: nginx:1.19
Tolerations(污点容忍)的操作方法
tolerations:
- key: "disktype" #污点的键值
operator: "Equal" #等于
value: "ssy" #污点的键值对应
effect: "NoSchedule"
6、删除节点的污点
[root@master ~]# kubectl taint node node1 disktype=ssd:NoSchedule- #后面跟一个减号,中间没有空格
Taint污点的一下操作方法
给节点添加污点
格式:kubectl taint node [node] key=value:[effect]
例如:kubectl taint node k8s-node1 gpu=yes:NoSchedule
验证:kubectl describe node k8s-node1 |grep Taint
其中[effect] 可取值:
•NoSchedule :一定不能被调度
•PreferNoSchedule:尽量不要调度,非必须配置容忍
•NoExecute:不仅不会调度,还会驱逐Node上已有的Pod
示例:Tain't污 点,给一个节点添加3个污点
kubectl taint nodes node1 key1=value1:NoSchedule kubectl taint nodes node1 key1=value1:NoExecute kubectl taint nodes node1 key2=value2:NoSchedule
Pod,它有两个容忍度:-------------------->
tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoSchedule" - key: "key1" operator: "Equal" value: "value1" effect: "NoExecute"
这种情况,上述pod不会被分配到该节点,因为其没有容忍度和第三个污点相匹配。
给一个节点添加了一个 effect 值为 NoExecute
的污点, 则任何不能忍受这个污点的 Pod 都会马上被驱逐, 任何可以忍受这个污点的 Pod 都不会被驱逐。
但是,如果 Pod 存在一个 effect 值为 NoExecute
的容忍度指定了可选属性 tolerationSeconds
的值,则表示在给节点添加了上述污点之后, Pod 还能继续在节点上运行的时间。如:
tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoExecute" tolerationSeconds: 3600
#nodeName
nodeName:指定节点名称,用于将Pod调度到指定的Node上,不经过调度器 即使是node1节点上有污点的,都能顺利调度。
应用场景:主要是在开发中使用,直接调度到节点上运行容器。
1、编辑有nodeName的yaml文件
apiVersion: v1
kind: Pod
metadata:
name: test-nodename
labels:
app: nginx
spec:
nodeName: node1
containers:
- name: nginx
image: nginx:1.17
2、部署及查看是否运行到节点node1上
[root@master ~]# kubectl apply -f test-nodename.yaml
[root@master ~]# kubectl get pods -o wide
直接就分配到node1这个节点上。
#DaemonSet
DaemonSet功能:
DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
DaemonSet 的一些典型用法:
- 在每个节点上运行集群守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行监控守护进程
应用场景:网络插件、监控Agent、日志Agent
如:calico组件,proxy组件都是每个节点上运行的。
示例:DaemonSet的使用
1、部署一个日志采集程序
[root@master ~]# kubectl create deployment web8 --image=nginx --dry-run=client -o yaml>test-daemonset.yaml
[root@master ~]# vim test-daemonset.yaml
apiVersion: apps/v1 kind: DaemonSet metadata: name: test-daemonset namespace: kube-system spec: selector: matchLabels: name: test-daemonset template: metadata: labels: app: test-daemonset spec: containers: - image: elastic/filebeat:7.3.2 name: log
2、部署后查看情况,但是只运行了两个node节点
[root@master ~]# kubectl apply -f test-daemonset.yaml
[root@master ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE test-daemonset-k55pq 1/1 Running 0 6m25s test-daemonset-mt6qf 1/1 Running 0 6m25s
3、查原因,原来是master上有污点,说明DaemonSet的调度也受污点的影响。
[root@master ~]# kubectl describe node |grep Taint
Taints: node-role.kubernetes.io/master:NoSchedule
Taints: <none>
Taints: <none>
4、删除master上的污点
[root@master ~]# kubectl describe node |grep Taint
Taints: node-role.kubernetes.io/master:NoSchedule
Taints: <none>
Taints: <none>
[root@master ~]# kubectl taint nodes master node-role.kubernetes.io/master:NoSchedule-
node/master untainted
[root@master ~]# kubectl describe node |grep Taint
Taints: <none>
Taints: <none>
Taints: <none>
5、从新部署DaemonSet,再查看部署情况,master上的污点一经去除,DaemonSet就自动部署了
[root@master ~]# kubectl get pods -n kube-system
[root@master ~]# kubectl get pods -o wide -n kube-system |grep test-daemonset
test-daemonset-6vhgs 1/1 Running 0 6m17s 10.244.219.65 master test-daemonset-k55pq 1/1 Running 0 19m 10.244.104.26 node2 test-daemonset-mt6qf 1/1 Running 0 19m 10.244.166.148 node1
六、K8S网络(Service与Ingress篇)
@Service的学习部分
service : 将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
使用 Kubernetes,你无需修改应用程序即可使用不熟悉的服务发现机制。
Kubernetes 为 Pods 提供自己的 IP 地址,并为一组 Pod 提供相同的 DNS 名, 并且可以在它们之间进行负载均衡。
Service: 引入主要是解决Pod的动态变化,提供统一访问入口:
• 防止Pod失联,准备找到提供同一个服务的Pod(服务发现)
• 定义一组Pod的访问策略(负载均衡)
• Service通过标签关联一组Pod
• Service使用iptables或者ipvs为一组Pod提供负载均衡能力
[root@master ~]# kubectl expose deployment pod-selector --port=80 --target-port=80 --dry-run=client -o yaml >test-service.yaml
###### 通过kubectl创建svc的方法 ############
kubectl expose rc nginx --port=80 --target-port=8000 kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000 kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https kubectl expose rs nginx --port=80 --target-port=8000 kubectl expose deployment nginx --port=80 --target-port=8000 kubectl expose pod valid-pod --port=444 --name=frontend
示例:通现有的pod创建一个与之关联的svc
1、查看kubectl中现有的pod,并创建一个与之关联的svc
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-selector 1/1 Running 0 9m20s
[root@master ~]# kubectl expose pod pod-selector --port=80 --type=NodePort --name=f1
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
f1 NodePort 10.101.45.147 <none> 80:30971/TCP 25s
2、在浏览器上进行测试
3、查看该svc的ep情况
[root@master ~]# kubectl get ep
NAME ENDPOINTS AGE f1 10.244.104.27:80 2m37s
svc的yaml文件:也可以通过YAML文件进行部署。
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP #服务类型
ports:
- port: 80 #Service端口
protoclol: TCP #协议
targetPort: 80 #容器端口(应用程序监听端口)
selector:
app: web #指定关联pod的标签
Service的多端口定义:对于某些服务,需要公开多个端口,Service也需要配置多个端口定义,通过端口名称区分。
apiVersion: v1 kind: Service metadata: name: web spec: type: ClusterIP ports: - name: http port: 80 protocol: TCP targetPort: 80 - name: https port: 443 protocol: TCP targetPort: 443 selector: app: web
Service三种常用类型:
ClusterIP:默认,分配一个稳定的IP地址,即VIP,只能在集群内部访问。
NodePort:在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群IP地址。这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了。也会在每台Node上监听端口接收用户流量,在实际情况下,对用户暴露的只会有一个IP和端口,那这么多台Node该使用哪台让用户访问呢?
访问地址:<任意NodeIP>:<NodePort>
端口范围:30000-32767
LoadBalancer:与NodePort类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台(例如阿里云、腾讯云、AWS等)上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。
Service代理模式:
* (1) 第一种代理模式:IPtabels
1、查看k8s集群内的svc
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE f1 NodePort 10.101.45.147 <none> 80:30019/TCP 42h kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d16h test-web5 NodePort 10.100.32.68 <none> 80:32074/TCP 72m
2、查看test-web5的iptables转发情况
[root@master ~]# iptables-save|grep test-web5
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/test-web5" -m tcp --dport 32074 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/test-web5" -m tcp --dport 32074 -j KUBE-SVC-R4AN3NJI2MCEMEEW
3、查看KUBE-SVC-R4AN3NJI2MCEMEEW的iptables转发情况
-A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-QTID6BIIMABWQ25O -A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-RKGA2BK4C2R5IJDB -A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -j KUBE-SEP-NQ5HVJ2SU7ICHFKQ
(--mode random --probability 0.33333333349 )这个就是实现负载均衡的的权重和转发概率。最后一条记录:
-A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -j KUBE-SEP-NQ5HVJ2SU7ICHFKQ
是上面两条都不能成功转发后默认的转发记录:
4、如果test-web5中扩展了4个pod后的转发情况
[root@master ~]# kubectl scale deployment test-web5 --replicas=4
deployment.apps/test-web5 scaled
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE test-web5-7dbf57497-4hc9k 1/1 Running 1 82m test-web5-7dbf57497-6bx8z 1/1 Running 1 82m test-web5-7dbf57497-7z7bt 1/1 Running 1 62m test-web5-7dbf57497-8p4f2 1/1 Running 0 11s
[root@master ~]# kubectl get ep
NAME ENDPOINTS AGE test-web5 10.244.104.34:80,10.244.104.37:80,10.244.166.152:80 + 1 more... 83m
[root@master ~]# iptables-save|grep KUBE-SVC-R4AN3NJI2MCEMEEW
-A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-QTID6BIIMABWQ25O -A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-RKGA2BK4C2R5IJDB -A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-NQ5HVJ2SU7ICHFKQ -A KUBE-SVC-R4AN3NJI2MCEMEEW -m comment --comment "default/test-web5" -j KUBE-SEP-CJO4UEZOBF7U6YA5
5、根据每条转发后面的链进行查看转发到那个pod上
[root@master ~]# iptables-save |grep KUBE-SEP-QTID6BIIMABWQ25O
-A KUBE-SEP-QTID6BIIMABWQ25O -p tcp -m comment --comment "default/test-web5" -m tcp -j DNAT --to-destination 10.244.104.34:80
从IP地址可以看出,iptables转发到第一个POD上的服务上,
[root@master ~]# iptables-save |grep KUBE-SEP-RKGA2BK4C2R5IJDB
-A KUBE-SEP-RKGA2BK4C2R5IJDB -p tcp -m comment --comment "default/test-web5" -m tcp -j DNAT --to-destination 10.244.104.37:80
[root@master ~]# kubectl get ep
test-web5 10.244.104.34:80,10.244.104.37:80,10.244.166.152:80 + 1 more... 90m
让他查看第2个链就知道转发到第2个pod上的IP地址。
* (2) 第二种代理模式:IPVS
1、查看kube-proxy的转发规则
[root@master ~]# kubectl logs kube-proxy-zlrj4 -n kube-system|more
I0926 01:33:49.791612 1 node.go:172] Successfully retrieved node IP: 192.168.178.12
I0926 01:33:49.791690 1 server_others.go:140] Detected node IP 192.168.178.12
W0926 01:33:49.791770 1 server_others.go:592] Unknown proxy mode "", assuming iptables proxy
I0926 01:33:49.825375 1 server_others.go:206] kube-proxy running in dual-stack mode, IPv4-primary
I0926 01:33:49.825435 1 server_others.go:212] Using iptables Proxier. #说明kube-proxy使用IPtables转发规则
2、修改kube-proxy的转发规则为:IPVS
[root@master ~]# kubectl edit configmap kube-proxy -n kube-system
打开kube-proxy的配置文件进行修改,在vim中查询:/mode:
修改:mode: "ipvs"
删除kube-proxy的所有pod让kube-proxy重建:
[root@master ~]# for p in $(kubectl get pods --namespace=kube-system -l k8s-app=kube-proxy -o name);
> do kubectl delete --namespace=kube-system $p; done
3、在节点上安装IPVS的工具:ipvsadmin
[root@master ~]# yum install -y ipvsadm
4、通过命令:ipvsadm -L -n查看IPVS的转发规则
[root@node1 ~]# ipvsadm -L -n
5、查看IPVS 的转发的情况
TCP 172.17.0.1:32074 rr -> 10.244.104.34:80 Masq 1 0 0 -> 10.244.104.37:80 Masq 1 0 0 -> 10.244.166.152:80 Masq 1 0 0 -> 10.244.166.155:80 Masq 1 0 0
* (3) IPtables和IPVS比较
Iptables:
• 灵活,功能强大
• 规则遍历匹配和更新,呈线性时延
IPVS:
• 工作在内核态,有更好的性能
• 调度算法丰富:rr,wrr,lc,wlc,ip hash...
* (4) Service DNS名称访问
CoreDNS:是一个DNS服务器,Kubernetes默认采用,以Pod部署在集群中,CoreDNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。
CoreDNS YAML文件:https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns/coredns
ClusterIP A记录格式:<service-name>.<namespace-name>.svc.cluster.local
示例:my-svc.my-namespace.svc.cluster.local
--------------------- 通过命令的演示,DNS的解析情况--------------------------------------------
[root@master ~] # kubectl run dns-t --image=busybox:1.28.4 -- sleep 24h
[root@master ~] # kubectl get pods
NAME READY STATUS RESTARTS AGE
dns-t 1/1 Running 0 22s
[root@master ~] # kubectl exec -it dns-t -- sh
/ # ---->这个是busybox运行的命令提示符:
/ # nslookup kubernetes
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
[root@master ~] # kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
f1 NodePort 10.101.45.147 <none> 80:30019/TCP 47h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d22h
test-web5 NodePort 10.100.32.68 <none> 80:32074/TCP 6h51m
/ # nslookup test-web5
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: test-web5
Address 1: 10.100.32.68 test-web5.default.svc.cluster.local
===================================================================================
@Ingress的学习部分
Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。
Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及提供基于名称的虚拟主机等能力。
Ingress 控制器 通常负责通过负载均衡器来实现 Ingress,尽管它也可以配置边缘路由器或其他前端来帮助处理流量。
通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的服务。
NodePort存在的不足:
- 一个端口只能一个服务使用,端口需提前规划
- 只支持4层负载均衡
- 基于IP地址和端口转发
Ingress:
- Ingress:公开了从集群外部到集群内服务的HTTP和HTTPS路由的规则集合,而具体实现流量路由则是由Ingress Controller负责。
- Ingress:K8s中的一个抽象资源,给管理员提供一个暴露应用的入口定义方法
- Ingress Controller:根据Ingress生成具体的路由规则,并对Pod负载均衡器
- 基于应用层协议转发,例如:HTTP,基于域名
Ingress Controller有很多实现,我们这里采用官方维护的Nginx控制器。
项目地址:https://github.com/kubernetes/ingress-nginx
--->Ingress控制器的创建
1、Ingress Controller的namespace名称空间的创建
apiVersion: v1 kind: Namespace metadata: name: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx
2、Ingress Controller的configMap的创建
kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx
3、Ingress Controller的ServiceAccount的创建
apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx
4、Ingress Controller的rbac的创建
apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses verbs: - get - list - watch - apiGroups: - "extensions" - "networking.k8s.io" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: nginx-ingress-role namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<nginx>" # This has to be adapted if you change either parameter
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
5、Ingress Controller的APP的创建
apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx-ingress-controller namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" spec: hostNetwork: true #实现负载均衡 # wait up to five minutes for the drain of connections terminationGracePeriodSeconds: 300 serviceAccountName: nginx-ingress-serviceaccount nodeSelector: kubernetes.io/os: linux containers: - name: nginx-ingress-controller image: lizhenliang/nginx-ingress-controller:0.30.0 #修改成国内的镜像 args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --publish-service=$(POD_NAMESPACE)/ingress-nginx - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: allowPrivilegeEscalation: true capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 101 runAsUser: 101 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 protocol: TCP - name: https containerPort: 443 protocol: TCP livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 10 lifecycle: preStop: exec: command: - /wait-shutdown --- apiVersion: v1 kind: LimitRange metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: limits: - min: memory: 90Mi cpu: 100m type: Container
6、部署Ingress Controller
[root@master ~]# kubectl apply -f ingress-controller.yaml
[root@master ~]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE nginx-ingress-controller-9h9cj 1/1 Running 0 2m30s nginx-ingress-controller-cghjt 1/1 Running 0 2m30s nginx-ingress-controller-pk48r 1/1 Running 0 2m30s
7、创建Ingress规则,使用Ingress(规范化,标准化)
upstream yyy { server 192.168.178.11:80 server 192.168.178.12:80 } server { listen 80; server_name web.yuanye.com; location / { proxy_pass http://yyy; } }
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: yuan_web
spec:
rules:
- host: web.yuanye.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-web5 #k8s中的已经有的服务
port:
number: 80
8、部署Ingress的规则
[root@master ~]# vim test-ingress.yaml
[root@master ~]# kubectl apply -f test-ingress.yaml
ingress.networking.k8s.io/yuan-web created
[root@master ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE yuan-web <none> web.yuanye.com 80 7s
8、绑定本地host来解析web.yuanye.com
[root@master ~]# kubectl get pods -n ingress-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-ingress-controller-9h9cj 1/1 Running 0 27m 192.168.178.11 node1 <none> <none> nginx-ingress-controller-cghjt 1/1 Running 0 27m 192.168.178.12 node2 <none> <none> nginx-ingress-controller-pk48r 1/1 Running 0 27m 192.168.178.10 master <none> <none>
[root@master ~]# ss -antp |grep 80
[root@master ~]# vim /etc/hosts
192.168.178.10 master web.yuanye.com
192.168.178.11 node1
192.168.178.12 node2
在集群内部就可以用web.yuanye.com访问test-web5的网页内容:
---> Ingress规则配置:HTTPS
1、安装cfssl进行认证
要下载一个cfssl.tar.gz的软件包,在解压
[root@master ~]# tar zxvf cfssl.tar.gz
[root@master ~]# mv cfssl* /usr/bin/
[root@master ~]# mkdir ssl
[root@master ~]# cd ssl
2、编辑cfssl脚本文件进行证书创建
[root@master ssl]# vim certs.sh cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
cat > ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
cat > web.yuanye.com-csr.json <<EOF
{
"CN": "web.yuanye.com",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "BeiJing",
"ST": "BeiJing"
}
]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes web.yuanye.com-csr.json | cfssljson -bare web.yuanye.com
3、安装cfssl进行认证
[root@master ssl]# sh certs.sh
2021/09/27 09:28:51 [INFO] generating a new CA key and certificate from CSR 2021/09/27 09:28:51 [INFO] generate received request 2021/09/27 09:28:51 [INFO] received CSR 2021/09/27 09:28:51 [INFO] generating key: rsa-2048 2021/09/27 09:28:51 [INFO] encoded CSR
[root@master ssl]# ls
4、将证书文件保存到Secret中
[root@master ssl]# kubectl create secret tls web-yuanye-com --cert=web.yuanye.com.pem --key=web.yuanye.com-key.pem
出现:secret/web-yuanye-com created 提示,表示成功!
[root@master ssl]# kubectl get secret
NAME TYPE DATA AGE
default-token-4ct6f kubernetes.io/service-account-token 3 6d16h
web-yuanye-com kubernetes.io/tls 2 56s
5、编辑Ingress的yaml文件
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: yuanye-https spec: tls: - hosts: - web.yuanye.com secretName: web-yuanye-com rules: - host: web.yuanye.com http: paths: - path: / pathType: Prefix backend: service: name: test-web5 port: number: 80
6、部署Ingress的yaml文件
[root@master ssl]# kubectl apply -f ingress-https.yaml
[root@master ssl]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE yuan-web <none> web.yuanye.com 80 69m yuanye-https <none> web.yuanye.com 80, 443 42s
7、验证
---> Ingress Controller怎样工作
Ingress Controller:通过与Kubernetes API 交互,动态的去感知集群中Ingress 规则变化,然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段Nginx 配置,应用到管理的Nginx服务,然后热加载生效。以此来达到Nginx负载均衡器配置及动态更新的问题。
数据包流程:客户端->Ingress Controller(nginx)-> 分布在各节点Pod
[root@master ~]# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-9h9cj 1/1 Running 0 108m
nginx-ingress-controller-cghjt 1/1 Running 0 108m
nginx-ingress-controller-pk48r 1/1 Running 0 108m
[root@master ~]# kubectl exec -it nginx-ingress-controller-9h9cj -n ingress-nginx -- bash
bash-5.0$ ps -ef
PID USER TIME COMMAND 1 www-data 0:00 /usr/bin/dumb-init -- /nginx-ingress-controller --configmap=ingress-nginx/nginx-configurati 7 www-data 0:09 /nginx-ingress-controller --configmap=ingress-nginx/nginx-configuration --tcp-services-conf 35 www-data 0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf 320 www-data 0:00 nginx: worker process 321 www-data 0:00 nginx: worker process 322 www-data 0:00 nginx: worker process 323 www-data 0:00 nginx: worker process 347 www-data 0:00 nginx: worker process 357 www-data 0:00 nginx: worker process 400 www-data 0:00 nginx: worker process 423 www-data 0:00 nginx: worker process 424 www-data 0:00 nginx: cache manager process 586 www-data 0:00 bash 592 www-data 0:00 ps -ef
维护了两个进程:
nginx: 实现pod的负载均衡
nginx-ingress-controller:访问k8s api 获取创建的Ingress,生成对应的nginx配置文件,并且生效
bash-5.0$ cat /etc/nginx/nginx.conf|grep web.yuanye.com
## start server web.yuanye.com server_name web.yuanye.com ; ## end server web.yuanye.com
七、K8S存储(PV、PVC、Secret、ConfigMap篇)
背 景
Kubernetes: 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁 持久卷。对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
卷 的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。 所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放 的内容。
.spec.volumes
字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts
字段中声明卷在容器中的挂载位置。 容器中的进程看到的是由它们的 Docker 镜像和卷组成的文件系统视图。 Docker 镜像 位于文件系统层次结构的根部。各个卷则挂载在镜像内的指定路径上。 卷不能挂载到其他卷之上,也不能与其他卷有硬链接。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。
Kubernetes 卷(Volume) 抽象概念能够解决这两个问题:
问题1:当容器崩溃时,kubelet会重建容器,容器内文件会丢失
问题2:一个Pod中运行多个容器并需要共享文件
Kubernetes 常用的数据卷(Volume):
-----------------------------------------------------------------------------------------------------------
本地节点上 | hostPath emptyDir |
网络 | NFS Ceph GlusterFS |
公有云 | AWS EBS |
K8S资源 |
configMap secret |
-----------------------------------------------------------------------------------------------------------
(一)、emptyDir 临时数据卷
emptyDir卷:是一个临时存储卷,与Pod生命周期绑定一起,如果Pod删除了卷也会被删除。应用场景:Pod中容器之间数据共享
1、部署一个emptyDir临时卷的pod
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: w1
image: centos
command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
volumeMounts:
- name: data
mountPath: /data
- name: r1
image: centos
command: ["bash","-c","tail -f /data/hello"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
emptyDir: {}
[root@master ~]# kubectl apply -f test-emptydir.yaml
[root@master ~]# kubectl exec -it my-pod -c w1 -- bash
[root@my-pod data]# cat hello
[root@master ~]# kubectl exec -it my-pod -c r1 -- bash
2、查看emptyDir临时卷在宿主机的目录位置
[root@master ~]# kubectl get pods -o wide |grep my-pod
my-pod 1/2 NotReady 0 118s 10.244.166.170 node1 <none> <none>
[root@node1 ~]# cd /var/lib/kubelet/pods
[root@node1 ~]# docker ps |grep my-pod
7889bd31ae46 centos k8s_w1_my-pod_default_35b609a9-291b-4fd3-8f40-43c88a44e3db_1
[root@node1 pods]# cd 35b609a9-291b-4fd3-8f40-43c88a44e3db
[root@node1 35b609a9-291b-4fd3-8f40-43c88a44e3db]# ls
drwxr-xr-x 3 root root 18 Sep 28 08:29 kubernetes.io~empty-dir drwxr-xr-x 3 root root 35 Sep 28 08:29 kubernetes.io~projected
[root@node1 kubernetes.io~empty-dir]# cd data
[root@node1 data]# cat hello
emptyDir在宿主机上的工作目录:
/var/lib/kubelet/pods/<pod-id (通过docket ps|grep <pod的名称>)>/kubernetes.io~empty-dir/data
(二)、hostPath 节点数据卷
hostPath卷:挂载Node文件系统(Pod所在节点)上文件或者目录到Pod中的容器。应用场景:Pod中容器需要访问宿主机文件
1、用yaml文件部署一个hostPath卷的pod
apiVersion: v1 kind: Pod metadata: name: my-hostpath spec: containers: - name: busybox image: busybox args: - /bin/sh - -c - sleep 36000 volumeMounts: - name: data mountPath: /data volumes: - name: data hostPath: path: /tmp type: Directory
[root@master ~]# kubectl apply -f test-hostpath.yaml
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE my-hostpath 1/1 Running 0 37s
2、查看运行情况(可以用pod来收集宿主上的信息)
通过命令查看my-hostpath容器运行在那个节点上:
[root@master ~]# kubectl get pod -o wide |grep my-hostpath
my-hostpath 1/1 Running 0 2m36s 10.244.166.171 node1
进到宿主机节点上node1上的/tmp目录
[root@node1 tmp]# touch t.txt
[root@node1 tmp]# ls
t.txt
进入到my-hostpath的容器中查看
[root@master ~]# kubectl exec -it my-hostpath -- sh
/ # cd /data
/data # ls
t.txt
(三)、NFS 网络数据卷
NFS卷:提供对NFS挂载支持,可以自动将NFS共享路径,挂载到Pod中
NFS:是一个主流的文件共享服务器。
1、在node2上安装NFS服务端,其他节点安装NFS客户端
[root@node2 ~]# yum -y install nfs-utils
[root@node2 ~]# vim /etc/exports #配置nfs的共享目录
/yfs/k8s *(rw,no_root_squash)
[root@node2 ~]# mkdir -p /yfs/k8s
[root@node2 ~]# systemctl start nfs
[root@node2 ~]# systemctl enable nfs
在node1上测试挂载情况:
[root@node1 ~]# mount -t nfs 192.168.178.12:/yfs/k8s /mnt
[root@node1 ~]# df -Th
192.168.178.12:/yfs/k8s nfs4 92G 9.3G 83G 11% /mnt
验证挂载的目录具备读写权限:
在客户端的写文件:----->
[root@node1 ~]# cd /mnt [root@node1 mnt]# echo "11244">t.txt [root@node1 mnt]# ls t.txt
在NFS服务器端的文件:---->
[root@node2 ~]# cd /yfs/k8s [root@node2 k8s]# ll total 4 -rw-r--r-- 1 root root 6 Sep 28 11:28 t.txt
在NFS客户端卸载刚才挂载的 /mnt:---->
[root@node1 ~]# umount /mnt/
2、示例:将Nginx网站程序根目录持久化到NFS存储,为多个Pod提供网站程序文件
编辑Deployment的yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-web6
spec:
selector:
matchLabels:
app: nfs-web6
replicas: 3
template:
metadata:
labels:
app: nfs-web6
spec:
containers:
- name: nfs-web6
image: nginx
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
volumes:
- name: wwwroot
nfs:
server: 192.168.178.12
path: /yfs/k8s
[root@master ~]# kubectl apply -f test-nfs.yaml
4、进到容器看共享目录的情况
[root@master ~]# kubectl exec -it nfs-web6-65747989d9-mr7k8 -- bash
root@nfs-web6-65747989d9-mr7k8:/# cd /usr/share/nginx/html
root@nfs-web6-65747989d9-mr7k8:/usr/share/nginx/html# ls
index.html
在NFS的服务器端node2上/ynfs/k8s中编辑index.html文件,然后在浏览器中访问:
[root@node2 k8s]# vim index.html
[root@master ~]# vim test-nfs.svc.yaml #部署一个为nfs-web6的svc
apiVersion: v1 kind: Service metadata: name: nfs-web6 namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nfs-web6 type: NodePort
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nfs-web6 NodePort 10.101.117.24 <none> 80:32185/TCP 106m
[root@master ~]# vim test-nfs-ingress.yaml #部署一个为nfs-web6的Ingress 域名为:web.yuan.com
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nfs-in-web6 spec: rules: - host: web.yuan.com http: paths: - path: / pathType: Prefix backend: service: name: nfs-web6 port: number: 80
[root@master ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE nfs-in-web6 <none> web.yuan.com 80 108m
在浏览器查看:
(四)、持久数据卷 ,让存储和应用的职责逻辑分离,静态的PV
PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理
PersistentVolumeClaim(PVC):让用户不需要关心具体的Volume实现细节
Pod申请PVC作为卷来使用,Kubernetes通过PVC查找绑定的PV,并Mount给Pod。
1、编辑pv的yaml文件,创建一个pv
[root@master ~]# vim test-pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: yuan-pvc spec: capacity: storage: 5Gi accessModes: - ReadWriteMany nfs: server: 192.168.178.12 path: /yfs/k8s
[root@master ~]# kubectl apply -f test-pv.yaml
persistentvolume/yuan-pvc created
[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE yuan-pvc 5Gi RWX Retain Available
2、编辑pvc的deployment的yaml文件,创建一个带pvc存储
apiVersion: apps/v1 kind: Deployment metadata: name: web spec: selector: matchLabels: app: pvc-web7 replicas: 3 template: metadata: labels: app: pvc-web7 spec: containers: - name: pvc-web7 image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html volumes: - name: wwwroot persistentVolumeClaim: claimName: yuan-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: yuan-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi --- apiVersion: v1 kind: Service metadata: name: pvc-service spec: selector: app: pvc-web7 ports: - protocol: TCP port: 80 targetPort: 80
type: NodePort
[root@master ~]# kubectl apply -f test-pvc.yaml
deployment.apps/web created
[root@master ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE yuan-pvc Bound yuan-pvc 5Gi RWX 3m40s
进到pod中来:--->
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE pvc-web7-8677566cbd-6j58l 1/1 Running 0 16m pvc-web7-8677566cbd-fbrdq 1/1 Running 0 16m
[root@master ~]# kubectl exec -it pvc-web7-8677566cbd-6j58l -- bash
在POD中显示挂载的情况了:--->
root@pvc-web7-8677566cbd-6j58l:/# df -Th
Filesystem Type Size Used Avail Use% Mounted on 192.168.178.12:/yuan/k8s nfs4 92G 9.7G 83G 11% /usr/share/nginx/html
-------------------------------------PV 生命周期-----------------------------------
AccessModes(访问模式):
AccessModes 是用来对PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
- ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
- ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
- ReadWriteMany(RWX):读写权限,可以被多个节点挂载
RECLAIM POLICY(回收策略):
目前PV 支持的策略有三种:
- Retain(保留):保留数据,需要管理员手工清理数据
- Recycle(回收):清除PV 中的数据,效果相当于执行rm -rf /ifs/kuberneres/*
- Delete(删除):与PV 相连的后端存储同时删除
STATUS(状态):
一个PV 的生命周期中,可能会处于4中不同的阶段:
- Available(可用):表示可用状态,还未被任何PVC 绑定
- Bound(已绑定):表示PV 已经被PVC 绑定
- Released(已释放):PVC 被删除,但是资源还未被集群重新声明
- Failed(失败):表示该PV 的自动回收失败
-------------------------------------
一个pv只能由一个pvc使用,不能动态的弹性的分配给其他项目。pv只要和pvc一经bund(绑定)就无法分配个其他pod的pvc使用了。
现在PV使用方式称为静态供给,需要K8s运维工程师提前创建一堆PV,供开发者使用。
(五)、PV 动态供给(StorageClass)
K8s开始支持PV动态供给,使用StorageClass对象实现。不需要运维人员维护pv的创建。
K8s默认不支持NFS动态供给,需要单独部署社区开发的插件。
项目地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
部署支持NFS的插件:
1、解压文件
[root@master ~]# unzip nfs-external-provisioner.zip
[root@master nfs-external-provisioner]# vim deployment.yaml
2、建NFS服务器端
[root@node2 ~]# mkdir -p /pvc
[root@node2 ~]# vim /etc/exports
/yfs/k8s *(rw,no_root_squash) /yuan/k8s *(rw,no_root_squash) /pvc *(rw,no_root_squash)
[root@node2 ~]# systemctl restart nfs #修改完/etc/exports后重新启动NFS服务器
3、修改pvc申请yaml文件deployment.yaml
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.178.12
- name: NFS_PATH
value: /pvc
volumes:
- name: nfs-client-root
nfs:
server: 192.168.178.12
path: /pvc
4、查看存储类的yaml文件和创建给給类
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME' parameters: archiveOnDelete: "false"
[root@master nfs-external-provisioner]# kubectl apply -f . #后面带一个点,包含文件夹下的都要创建
[root@master nfs-external-provisioner]# kubectl get pods
NAME READY STATUS RESTARTS AGE nfs-client-provisioner-78c88996f8-68rm9 1/1 Running 0 76s
5、创建使用动态pv的应用Deployment和Service
apiVersion: apps/v1 kind: Deployment metadata: name: sc-web8 spec: selector: matchLabels: app: sc-web8 replicas: 3 template: metadata: labels: app: sc-web spec: containers: - name: sc-web8 image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html volumes: - name: wwwroot apiVersion: apps/v1 kind: Deployment metadata: name: sc-web8 spec: selector: matchLabels: app: sc-web8 replicas: 3 template: metadata: labels: app: sc-web spec: containers: - name: sc-web8 image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html volumes: - name: wwwroot persistentVolumeClaim: claimName: yuan-sc
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: yuan-sc spec: storageClassName: "managed-nfs-storage" accessModes: - ReadWriteMany resources: requests: storage: 11Gi
[root@master ~]# kubectl apply -f test-sc.yaml
[root@master ~]# kubectl get svc,pv,pvc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/yuan-sc NodePort 10.105.174.111 <none> 80:31048/TCP 55s NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/pvc-87a3440b-9fd2-47a4-89c0-0e92912851cc 11Gi RWX NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/yuan-sc Bound pvc-87a3440b-9fd2-47a4-89c0-0e92912851cc 11Gi RWX managed-nfs-storage 55s
验证:
[root@node2 ~]# cd /pvc
[root@node2 pvc]# ll
total 0
drwxrwxrwx 2 root root 6 Sep 29 15:14 default-yuan-sc-pvc-87a3440b-9fd2-47a4-89c0-0e92912851cc
(六)、有状态应用部署:StatefulSet 控制器
无状态: Deployment控制器设计原则:管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node运行,可随意扩容和缩容。这种应用称为“无状态”,例如Web服务
有状态: 在实际的场景中,这并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有依赖关系,例如主从关系、主备关系,这种应用称为“有状态”,例如MySQL主从、Etcd集群
StatefulSet 控制器 ,用来管理有状态应用的工作负载 API 对象
StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值:
- 稳定的、唯一的网络标识符。
- 稳定的、持久的存储。
- 有序的、优雅的部署和缩放。
- 有序的、自动的滚动更新。
应用场景:分布式应用、数据库集群
稳定的网络ID
使用Headless Service(相比普通Service只是将spec.clusterIP定义为None)来维护Pod网络身份。并且添加serviceName: “nginx”字段指定StatefulSet控制器要使用这个Headless Service。
DNS解析名称:<statefulsetName-index>.<service-name> .<namespace-name>.svc.cluster.local。
稳定的存储
StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC。
StatefulSet与Deployment区别:有身份的!
身份三要素:
•域名
•主机名
•存储(PVC)
##实例:部署一个StatefulSet的实例
[root@master ~]# vim test-statefulset.yaml
[root@master ~]# vim test-statefulset.yaml apiVersion: v1 kind: Service metadata: name: sts-web labels: app: sts-web8 spec: ports: - port: 80 name: sts-web8 clusterIP: None selector: app: sts-web8 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: sts-web8 spec: selector: matchLabels: app: sts-web8 serviceName: "sts" replicas: 3 template: metadata: labels: app: sts-web8 spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: wwwroot spec: accessModes: ["ReadWriteOnce"] storageClassName: "managed-nfs-storage" resources: requests: storage: 2Gi
[root@master ~]# kubectl apply -f test-statefulset.yaml
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE sts-web8-0 1/1 Running 0 38s sts-web8-1 1/1 Running 0 20s sts-web8-2 0/1 Pending 0 1s
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE f1 NodePort 10.101.45.147 <none> 80:30019/TCP 5d17h kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d sts-web ClusterIP None <none> 80/TCP 15m
[root@master ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE wwwroot-sts-web8-0 Bound pvc-769585f8-7ac7-47a7-8f1b-da2bf959ad8e 2Gi RWO managed-nfs-storage 5m39s wwwroot-sts-web8-1 Bound pvc-b0afcc4c-4619-400d-9671-88307a7898d0 2Gi RWO managed-nfs-storage 5m21s wwwroot-sts-web8-2 Bound pvc-a02150da-4410-45af-bb43-b2d59488ea3e 2Gi RWO managed-nfs-storage 5m2s
[root@node2 ~]# cd /pvc
[root@node2 pvc]# ll
drwxrwxrwx 2 root root 6 Sep 30 09:27 default-wwwroot-sts-web8-0-pvc-769585f8-7ac7-47a7-8f1b-da2bf959ad8e drwxrwxrwx 2 root root 6 Sep 30 09:27 default-wwwroot-sts-web8-1-pvc-b0afcc4c-4619-400d-9671-88307a7898d0 drwxrwxrwx 2 root root 6 Sep 30 09:27 default-wwwroot-sts-web8-2-pvc-a02150da-4410-45af-bb43-b2d59488ea3e
显示出statefulSet的pod的主机名:
[root@master ~]# kubectl exec sts-web8-0 -- hostname
sts-web8-0
演示独立存储:
在NFS服务器上在sts-web8-0的存储上建一个文件:
[root@node2 default-wwwroot-sts-web8-0-pvc-769585f8-7ac7-47a7-8f1b-da2bf959ad8e]# touch t1.txt
[root@node2 default-wwwroot-sts-web8-0-pvc-769585f8-7ac7-47a7-8f1b-da2bf959ad8e]# ll
total 0
-rw-r--r-- 1 root root 0 Sep 30 09:35 t1.txt
在sts-web8-0(对应的pod)的statsfulset的pod上看有没有建好的文件:
[root@master ~]# kubectl exec -it sts-web8-0 -- bash
root@sts-web8-0:/# cd /usr/share/nginx/html
root@sts-web8-0:/usr/share/nginx/html# ls
t1.txt
在sts-web8-1(其他pod)的statsfulset的pod上看有没有建好的文件:
[root@master ~]# kubectl exec -it sts-web8-1 -- bash
root@sts-web8-1:/# cd /usr/share/nginx/html
root@sts-web8-1:/usr/share/nginx/html# ls
下面就没有文件,说明:statefulSet的pod是独立存储的
参考文档:https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
(七)、应用程序数据存储ConfigMap,Secret
ConfigMap:存储配置文件
Secret:存储敏感数据
ConfigMap
ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
ConfigMap 将您的环境配置信息和 容器镜像 解耦,便于应用配置的修改。
ConfigMap 动机是:使用 ConfigMap 来将你的配置数据和应用程序代码分开。
创建ConfigMap后,数据实际会存储在K8s中Etcd,然后通过创建Pod时引用该数据。应用场景:应用程序配置
Pod使用configmap数据有两种方式:
- 变量注入
- 数据卷挂载
实例:创建一个configMap资源:
1、编辑一个confiMap的yaml文件:
apiVersion: v1 kind: ConfigMap metadata: name: configmap-demo data: a: "123" b: "456" yuan.pro: | port: 30092 host: 192.168.178.12
2、编辑一个含有configMap调用的yaml应用:
1 --- 2 apiVersion: v1 3 kind: Pod 4 metadata: 5 name: configmap-demo-pod 6 spec: 7 containers: 8 - name: demo 9 image: nginx 10 env: 11 - name: y1 12 valueFrom: 13 configMapKeyRef: 14 name: configmap-demo 15 key: a 16 - name: y2 17 valueFrom: 18 configMapKeyRef: 19 name: configmap-demo 20 key: b 21 volumeMounts: 22 - name: config 23 mountPath: "/config" 24 readOnly: true 25 volumes: 26 - name: config 27 configMap: 28 name: configmap-demo 29 items: 30 - key: "yuan.pro" 31 path: "yuan.pro"
[root@master ~]# kubectl apply -f test-configmap.yaml
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE configmap-demo-pod 1/1 Running 0 9m4s
3、查看configMap的创建情况:
[root@master ~]# kubectl get configmap
NAME DATA AGE configmap-demo 3 17m
[root@master ~]# kubectl exec -it configmap-demo-pod -- bash
root@configmap-demo-pod:/# env |grep y
y2=456 y1=123
root@configmap-demo-pod:/# cd /config
root@configmap-demo-pod:/config# ls
yuan.pro
root@configmap-demo-pod:/config# cat yuan.pro
port: 30092 host: 192.168.178.12
Secret
Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。
Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将机密数据写入非易失性存储。
Secret 类似于 ConfigMap 但专门用于保存机密数据。
Pod 可以用三种方式之一来使用 Secret:
- 作为挂载到一个或多个容器上的 卷 中的文件。
- 作为容器的环境变量
- 由 kubelet 在为 Pod 拉取镜像时使用
Secret 的类型
内置类型 | 用法 |
---|---|
Opaque |
用户定义的任意数据 |
kubernetes.io/service-account-token |
服务账号令牌 |
kubernetes.io/dockercfg |
~/.dockercfg 文件的序列化形式 |
kubernetes.io/dockerconfigjson |
~/.docker/config.json 文件的序列化形式 |
kubernetes.io/basic-auth |
用于基本身份认证的凭据 |
kubernetes.io/ssh-auth |
用于 SSH 身份认证的凭据 |
kubernetes.io/tls |
用于 TLS 客户端或者服务器端的数据 |
bootstrap.kubernetes.io/token |
启动引导令牌数据 |
kubectl create secret 支持三种数据类型:
- docker-registry:存储镜像仓库认证信息
- generic: 从文件、目录或者字符串创建,例如存储用户名密码
- tls: 存储证书,例如HTTPS证书
[root@master ~]# kubectl create crerte --help #通过这个命令查看Secret支持的这三种类型
Available Commands:
docker-registry Create a secret for use with a Docker registry
generic Create a secret from a local file, directory or literal value
tls Create a TLS secret
实例:创建一个Secret的POD资源:
1、编辑一个Secret的POD应用yaml文件:
[root@master ~]# echo -n 'yuanye' |base64
eXVhbnll
[root@master ~]# echo -n 'anshunyuan'|base64
YW5zaHVueXVhbg==
apiVersion: v1 kind: Secret metadata: name: db-user-pass type: Opaque data: username: eXVhbnll password: YW5zaHVueXVhbg==
2、编辑POD应用yaml文件:
apiVersion: v1 kind: Pod metadata: name: secret-demo-pod spec: containers: - name: demo image: nginx env: - name: USER valueFrom: secretKeyRef: name: db-user-pass key: username - name: PASS valueFrom: secretKeyRef: name: db-user-pass key: password volumeMounts: - name: config mountPath: "/config" readOnly: true volumes: - name: config secret: secretName: db-user-pass items: - key: username path: my-username
[root@master ~]# kubectl apply -f test-secret.yaml
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE secret-demo-pod 1/1 Running 0 3m38s
3、查看Secret的情况:
[root@master ~]# kubectl get secret
NAME TYPE DATA AGE db-user-pass Opaque 2 4m53s
4、进到Secret的容器中验证:
[root@master ~]# kubectl exec -it secret-demo-pod -- bash
root@secret-demo-pod:/# env |grep USER
USER=yuanye
root@secret-demo-pod:~# env |grep PASS
PASS=anshunyuan
root@secret-demo-pod:/# cd config
root@secret-demo-pod:/config# cat my-username
yuanye
--------------------YUANYE 2021.10.1----------------------------
八、K8S安全
使用 RBAC 鉴权的概念:
基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对 计算机或网络资源的访问的方法。
RBAC 鉴权机制使用 rbac.authorization.k8s.io
API 组 来驱动鉴权决定,允许你通过 Kubernetes API 动态配置策略。
要启用 RBAC,在启动 API 服务器 时将 --authorization-mode
参数设置为一个逗号分隔的列表并确保其中包含 RBAC
。
K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。
1. Authentication(鉴权)
2. Authorization(授权)
3. Admission Control(准入控制)
•客户端要想访问K8s集群API Server,一般需要证书、Token或者用户名+密码;如果Pod访问,需要ServiceAccount
(一)K8s Apiserver提供三种客户端身份认证:
• HTTPS 证书认证:基于CA证书签名的数字证书认证(kubeconfig)
• HTTP Token认证:通过一个Token来识别用户(serviceaccount)
• HTTP Base认证:用户名+密码的方式认证(1.19版本弃用)
(二)RBAC(Role-Based Access Control,基于角色的访问控制):负责完成授权(Authorization)工作。
RBAC根据API请求属性,决定允许还是拒绝。
比较常见的授权维度:
• user:用户名
• group:用户分组
• 资源,例如pod、deployment
• 资源操作方法:get,list,create,update,patch,watch,delete
• 命名空间
• API组
(三)RBAC(Role-Based Access Control,基于角色的访问控制),是K8s默认授权策略,并且是动态配置策略(修改即时生效)。
主体(subject)
• User:用户
• Group:用户组
• ServiceAccount:服务账号
角 色
• Role:授权特定命名空间的访问权限
• ClusterRole:授权所有命名空间的访问权限
角色绑定
• RoleBinding:将角色绑定到主体(即subject)
• ClusterRoleBinding:将集群角色绑定到主体
(四)RBAC API声明的对象
RBAC API 声明了四种 Kubernetes 对象:Role、ClusterRole、RoleBinding 和 ClusterRoleBinding。
(五)RBAC API的根证书 HTTPS证书认证:
[root@master ~]# ls .kube/ #存放k8s的根证书的
cache config
(六)RBAC API的根证书 HTTP Token认证:
通过Token来识别用户,主要node加入时加入集群时的Token,
(七)通过kubectl exec 查看kube-apiserver中的准入控制:默认启用的准入控制
[root@master ~]# kubectl exec kube-apiserver-master -n kube-system -- kube-apiserver -h |grep enable-admission-plugins
1 ( 2 NamespaceLifecycle, 3 LimitRanger, 4 ServiceAccount, 5 TaintNodesByCondition, 6 Priority, 7 DefaultTolerationSeconds, 8 DefaultStorageClass, 9 StorageObjectInUseProtection, 10 PersistentVolumeClaimResize, 11 RuntimeClass, 12 CertificateApproval, 13 CertificateSigning, 14 CertificateSubjectRestriction, 15 DefaultIngressClass, 16 MutatingAdmissionWebhook, 17 ValidatingAdmissionWebhook, 18 ResourceQuota 19 )
案例:为指定用户授权访问不同命名空间权限 ,为了安全性,先不能给他太大权限,因此先给他授权访问default命名空间Pod读取权限。
实施步骤:
1. 用K8S CA签发客户端证书
[root@master rbac]# vim cert.sh
1 cat > ca-config.json <<EOF 2 { 3 "signing": { 4 "default": { 5 "expiry": "87600h" 6 }, 7 "profiles": { 8 "kubernetes": { 9 "usages": [ 10 "server auth", 11 "client auth" 12 ], 13 "expiry": "87600h" 14 } 15 } 16 } 17 } 18 EOF 19 20 cat > yuanye-csr.json <<EOF 21 { 22 "CN": "yuanye", 23 "hosts": [], 24 "key": { 25 "algo": "rsa", 26 "size": 2048 27 }, 28 "names": [ 29 { 30 "C": "CN", 31 "ST": "Guizhou", 32 "L": "Guizhou", 33 "O": "k8s", 34 "OU": "System" 35 } 36 ] 37 } 38 EOF 39 40 cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config=ca-config.json -profile=kubernetes yuanye-csr.json | cfssljson -bare yuanye
[root@master rbac]# bash cert.sh
[root@master rbac]# ll
1 [root@master rbac]# ll 2 total 32 3 -rw-r--r-- 1 root root 292 Oct 8 10:16 ca-config.json 4 -rw-r--r-- 1 root root 741 Oct 8 10:14 cert.sh 5 -rw-r--r-- 1 root root 622 Sep 1 2019 kubeconfig.sh 6 -rw-r--r-- 1 root root 477 Aug 25 2019 rbac.yaml 7 -rw-r--r-- 1 root root 997 Oct 8 10:16 yuanye.csr 8 -rw-r--r-- 1 root root 219 Oct 8 10:16 yuanye-csr.json 9 -rw------- 1 root root 1675 Oct 8 10:16 yuanye-key.pem 10 -rw-r--r-- 1 root root 1277 Oct 8 10:16 yuanye.pem
2. 生成kubeconfig授权文件
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://192.168.178.10:6443 --kubeconfig=yuanye.kubeconfig # 设置客户端认证 kubectl config set-credentials yuanye --client-key=yuanye-key.pem --client-certificate=yuanye.pem --embed-certs=true --kubeconfig=yuanye.kubeconfig # 设置默认上下文 kubectl config set-context kubernetes --cluster=kubernetes --user=yuanye --kubeconfig=yuanye.kubeconfig # 设置当前使用配置 kubectl config use-context kubernetes --kubeconfig=yuanye.kubeconfig
[root@master rbac]# bash kubeconfig.sh
[root@master rbac]# kubectl --kubeconfig=yuanye.kubeconfig get pods
Error from server (Forbidden): pods is forbidden: User "yuanye" cannot list resource "pods" in API group "" in the namespace "default" #因为yuanye这个用户没有权限查看pods
3. 创建RBAC权限策略
kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "watch", "list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: read-pods namespace: default subjects: - kind: User name: yuanye apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
- apiGroups: [""]
# api组,如:apps组,空值表示核心API组,像namespace,pod,service,pv,pvc都在核心组里面。
resources: ["pods"]
# 表示资源名称(复数),如:pods,deployments,services。
verbs: ["get", "watch", "list"]
# 表示对资源的操作方法。
[root@master rbac]# kubectl api-resources|grep pod #查看API的资源组
[root@master rbac]# kubectl api-resources |grep deployment
deployments deploy apps/v1
[root@master rbac]# kubectl apply -f rbac.yaml
[root@master rbac]# kubectl --kubeconfig=yuanye.kubeconfig get pods
NAME READY STATUS RESTARTS AGE configmap-demo-pod 1/1 Running 1 6d15h dns-t 1/1 Running 8 11d init-demo 1/1 Running 7 14d my-hostpath 1/1 Running 11 10d nfs-client-provisioner-78c88996f8-68rm9 1/1 Running 1 8d
修改rbac的配置yaml文件:
- apiGroups: ["","apps"] resources: ["pods","services","deployments"] verbs: ["get", "watch", "list"]
yuanye用户就能访问deployment和service了
[root@master rbac]# kubectl --kubeconfig=yuanye.kubeconfig get deployment
NAME READY UP-TO-DATE AVAILABLE AGE nfs-client-provisioner 1/1 1 1 8d nfs-web 0/0 0 0 9d sc-web8 3/3 3 3 8d test-web5 0/0 0 0 12d
[root@master rbac]# kubectl --kubeconfig=yuanye.kubeconfig delete pods secret-demo-pod
Error from server (Forbidden): pods "secret-demo-pod" is forbidden: User "yuanye" cannot delete resource "pods" in API group "" in the namespace "default" #说明yuanye这个用户不具有delete删除pod的权限 verbs: ["get", "watch", "list"]
[root@master rbac]# alias k8s=kubectl --kubeconfig=yuanye.kubeconfig #用别名的方式简化命令行
[root@master rbac]# k8s get pods
[root@master rbac]# k8s delete pods my-hostpath #通过verbs: ["get", "watch", "list","delete"]的配置,yuanye用户具备删除权限。
案例:为一个服务账号分配只能创建deployment、daemonset、statefulset的权限。
1、# 创建集群角色
[root@master ~]# kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,daemonsets,statefulsets
clusterrole.rbac.authorization.k8s.io/deployment-clusterrole created
2 # 创建服务账号
[root@master ~]# kubectl create ns app-team1
namespace/app-team1 created
[root@master ~]# kubectl create serviceaccount cicd-token -n app-team1
serviceaccount/cicd-token created
3 # 将服务账号绑定角色
[root@master ~]# kubectl create rolebinding cicd-token
> --serviceaccount=app-team1:cicd-tokey
> --clusterrole=deployment-clusterrole -n app-team1
rolebinding.rbac.authorization.k8s.io/cicd-token created
4 # 测试服务账号权限
[root@master ~]# kubectl --as=system:serviceaccount:app-team1:cicd-token
> get pods -n app-team1
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:app-team1:cicd-token" cannot list resource "pods" in API group "" in the namespace "app-team1"
5 # 通过yaml创建出一个服务账号sa
1 apiVersion: v1 2 kind: ServiceAccount 3 metadata: 4 name: yuan-token 5 namespace: app-team2 6 7 --- 8 apiVersion: rbac.authorization.k8s.io/v1 9 kind: ClusterRole 10 metadata: 11 name: deployment-clusterrole 12 rules: 13 - apiGroups: ["","apps"] 14 resources: ["pods","deployments","daemonsets","statefulsets"] 15 verbs: ["get","create","list"] 16 17 --- 18 apiVersion: rbac.authorization.k8s.io/v1 19 kind: RoleBinding 20 metadata: 21 name: yuan-token 22 namespace: app-team2 23 roleRef: 24 apiGroup: rbac.authorization.k8s.io 25 kind: ClusterRole 26 name: deployment-clusterrole 27 subjects: 28 - kind: ServiceAccount 29 name: yuan-token 30 namespace: app-team2
[root@master acc]# alias k9=kubectl --as=system:serviceaccount:app-team2:yuan-token #用别名的方式把长命令格式
[root@master acc]# k9 get pods -n app-team2 #这样就简化了命令行格式
No resources found in app-team2 namespace.
网络策略 Network Policies:
Kubernetes 集群网络没任何网络限制,Pod 可以与任何其他Pod 通信,在某些场景下就需要进行网络控制,减少网络攻击面,提高安全性,这就会用到网络策略。
网络策略(Network Policy):是一个K8s资源,用于限制Pod出入流量,提供Pod级别和Namespace级别网络访问控制。
网络策略的应用场景:
• 应用程序间的访问控制,例如项目A不能访问项目B的Pod
• 开发环境命名空间不能访问测试环境命名空间Pod
• 当Pod暴露到外部时,需要做Pod白名单
• 多租户网络环境隔离
Ingress的编写:
1 apiVersion: networking.k8s.io/v1 2 kind: NetworkPolicy 3 metadata: 4 name: test-network-policy 5 namespace: default 6 spec: 7 podselector: 8 matchLabels: 9 role: db 10 policyTypes: 11 - Ingress 12 - Egress 13 ingress: 14 - from: 15 - ipBlock: 16 cidr: 172.17.0.0/16 17 except: 18 - 172.17.1.0/24 19 - namespaceSelector: 20 matchLabels: 21 project: myproject 22 - podselector: 23 matchLabels: 24 role: frontend 25 ports: 26 - protocol: TCP 27 port: 6379
ingress: #ingress的编写方式:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podselector:
matchLabels:
role: frontend
podSelector: 目标Pod,根据标签选择。
policyTypes: 策略类型,指定策略用于入站、出站流量。
Ingress: from是可以访问的白名单,可以来自于IP段、命名空间、Pod标签等,
ports: 是可以访问的端口。
Egress的编写:
egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports:
Egress:这个Pod组可以访问外部的IP段和端口。
案例1:拒绝其他命名空间Pod访问
需求:test命名空间下所有pod可以互相访问,也可以访问其他命名空间Pod,但其他命名空间不能访问test命名空间Pod。
1、先创建一个test的命名空间,在其命名空间中创建两个应用:
[root@master ~]# kubectl create ns test
namespace/test created
[root@master ~]# kubectl run web --image=nginx -n test
pod/web created
[root@master ~]# kubectl run busybox1 --image=busybox -n test -- sleep 12h
pod/busybox1 created
[root@master ~]# kubectl get pods -n test
NAME READY STATUS RESTARTS AGE busybox1 1/1 Running 0 70s web 1/1 Running 0 105s
2、在default中创建busybox2的应用:
[root@master ~]# kubectl run busybox2 --image=busybox -- sleep 12h
pod/busybox2 created
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE busybox2 1/1 Running 0 63s
3、测试pod的访问,不加网络Network Policy测试:
[root@master ~]# kubectl get pods -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox1 1/1 Running 0 8m21s 10.244.166.156 node1 <none> <none> web 1/1 Running 0 8m56s 10.244.166.157 node1 <none> <none>
[root@master ~]# kubectl exec -it busybox1 -n test -- sh #这个是在test命名空间中的访问
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80) saving to 'index.html' index.html 100% |**************************************************| 615 0:00:00 ETA 'index.html' saved
[root@master ~]# kubectl exec -it busybox2 -- sh #这个是在default命名空间中的访问
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80) saving to 'index.html' index.html 100% |**************************************************| 615 0:00:00 ETA 'index.html' saved
4、编辑网络Network Policy的yaml文件:
[root@master ~]# vim test-networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-namespaces
namespace: test
spec:
podSelector: {} # 未配置,匹配本命名空间所有pod
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {}
[root@master ~]# kubectl apply -f test-networkpolicy.yaml
networkpolicy.networking.k8s.io/deny-all-namespaces created
查看networkpolicy的情况:
[root@master ~]# kubectl get networkpolicy -n test
NAME POD-SELECTOR AGE
deny-all-namespaces <none> 8m29s
5、应用网络Network Policy后的测试:
[root@master ~]# kubectl get pods -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox1 1/1 Running 0 34m 10.244.166.156 node1 <none> <none> web 1/1 Running 0 35m 10.244.166.157 node1 <none> <none>
[root@master ~]# kubectl exec -it busybox1 -n test -- sh #这个是test命名空间内的访问,是可以的
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80) wget: can't open 'index.html': File exists / # ls bin etc index.html root tmp var dev home proc sys usr / # rm index.html -rf / # wget 10.244.166.157 Connecting to 10.244.166.157 (10.244.166.157:80) saving to 'index.html' index.html 100% |**************************************************| 615 0:00:00 ETA 'index.html' saved
[root@master ~]# kubectl exec -it busybox2 -- sh #default的命名空间的pod就不能访问test空间中的pod
/ # ls
bin etc index.html root tmp var dev home proc sys usr / # rm index.html -rf / # wget 10.244.166.157 Connecting to 10.244.166.157 (10.244.166.157:80)
6、delete网络Network Policy:
[root@master ~]# kubectl get networkpolicy -n test
NAME POD-SELECTOR AGE
deny-all-namespaces <none> 8m29s
[root@master ~]# kubectl delete -f test-networkpolicy.yaml
networkpolicy.networking.k8s.io "deny-all-namespaces" deleted
[root@master ~]# kubectl get networkpolicy -n test
No resources found in test namespace.
案例2:同一个命名空间下应用之间限制访问
需求:将test命名空间携带run=web标签的Pod隔离,只允许test命名空间携带run=client1标签的Pod访问80端口。
1、拉取lanels为run=client1的应用:
[root@master ~]# kubectl get pods -n test --show-labels
NAME READY STATUS RESTARTS AGE LABELS busybox1 1/1 Running 0 3h46m run=busybox1 web 1/1 Running 0 3h47m run=web
[root@master ~]# kubectl run client1 --image=busybox -n test -- sleep 12h
pod/client1 created
[root@master ~]# kubectl get pods -n test --show-labels
NAME READY STATUS RESTARTS AGE LABELS busybox1 1/1 Running 0 3h47m run=busybox1 client1 0/1 ContainerCreating 0 15s run=client1 web 1/1 Running 0 3h48m run=web
2、编辑网络策略的yaml文件及apply应用:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: app-to-app namespace: test spec: podSelector: matchLabels: run: web policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: run: client1 ports: - protocol: TCP port: 80
[root@master ~]# kubectl apply -f test-app-networkpolicy.yaml
networkpolicy.networking.k8s.io/app-to-app created
[root@master ~]# kubectl get networkpolicy -n test
NAME POD-SELECTOR AGE
app-to-app run=web 57s
3、测试:这个是run=client1
[root@master ~]# kubectl get pods -n test --show-labels
NAME READY STATUS RESTARTS AGE LABELS busybox1 1/1 Running 0 4h2m run=busybox1 client1 1/1 Running 0 15m run=client1 web 1/1 Running 0 4h3m run=web
[root@master ~]# kubectl exec -it client1 -n test -- sh
/ # exit
[root@master ~]# kubectl get pods -n test -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES busybox1 1/1 Running 0 4h3m 10.244.166.156 node1 <none> <none> client1 1/1 Running 0 16m 10.244.219.77 master <none> <none> web 1/1 Running 0 4h4m 10.244.166.157 node1 <none> <none>
[root@master ~]# kubectl exec -it client1 -n test -- sh
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80) saving to 'index.html' index.html 100% |**************************************************| 615 0:00:00 ETA 'index.html' saved
4、测试:这个是run=busybox1 ,这个就不能访问了
[root@master ~]# kubectl exec -it busybox1 -n test -- sh #这个是同一个命名test空间也不能访问,因为标签不匹配
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80)
[root@master ~]# kubectl exec -it busybox2 -- sh #不同的命名空间,也不能访问,因为标签不匹配
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80)
案例3:只允许指定命名空间中的应用访问
需求:只允许dev命名空间中的Pod访问test命名空间中的pod 80端口,命名空间打标签:kubectl label namespace dev name=dev
1、先建立DEV的命名空间,并在该空间拉起一个busybox的应用
[root@master ~]# kubectl create ns dev
namespace/dev created
[root@master ~]# kubectl run client --image=busybox -n dev -- sleep 12h
pod/client created
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE client 1/1 Running 0 89s
2、在dev中的pod的client可以访问test中的pod的80端口,而其他命名空间中pod的busybox就不能访问
3、编辑networkpolicy的yaml文件并应用
[root@master ~]# vim test-allow-port.yaml
1 apiVersion: networking.k8s.io/v1 2 kind: NetworkPolicy 3 metadata: 4 name: allow-port-from-namespace 5 namespace: test 6 spec: 7 podSelector: {} 8 policyTypes: 9 - Ingress 10 ingress: 11 - from: 12 - namespaceSelector: # 匹配命名空间标签 13 matchLabels: 14 name: dev 15 ports: 16 - protocol: TCP 17 port: 80
[root@master ~]# kubectl apply -f test-allow-port.yaml
[root@master ~]# kubectl get networkpolicy -n test
NAME POD-SELECTOR AGE allow-port-from-namespace <none> 73s
4、基于命名空间的标签:
[root@master ~]# kubectl get ns --show-labels
NAME STATUS AGE LABELS app-team1 Active 3d kubernetes.io/metadata.name=app-team1 app-team2 Active 2d23h kubernetes.io/metadata.name=app-team2 default Active 20d kubernetes.io/metadata.name=default dev Active 21m kubernetes.io/metadata.name=dev ingress-nginx Active 14d app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx,kubernetes.io/metadata.name=ingress-nginx kube-node-lease Active 20d kubernetes.io/metadata.name=kube-node-lease kube-public Active 20d kubernetes.io/metadata.name=kube-public kube-system Active 20d kubernetes.io/metadata.name=kube-system kubernetes-dashboard Active 20d kubernetes.io/metadata.name=kubernetes-dashboard test Active 4h38m kubernetes.io/metadata.name=test
[root@master ~]# kubectl label namespace dev name=dev #给dev打一个标签
5、测试
[root@master ~]# kubectl exec -it client -n dev -- sh #这个是基于Dev的命名空间,是可以访问的
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80) saving to 'index.html' index.html 100% |**************************************************| 615 0:00:00 ETA 'index.html' saved
[root@master ~]# kubectl exec -it busybox2 -- sh #这个是default命名空间的,不能访问,因为标签不匹配
/ # wget 10.244.166.157
Connecting to 10.244.166.157 (10.244.166.157:80)
(网络策略需要网络组件支持的,支持网络组件的实现:calico。flannel不支持网络策略。)
九、K8S集群维护
---->Etcd数据库备份与恢复(kubeadm部署方式)
1、Etcd数据库备份:
[root@master ~]# ETCDCTL_API=3 etcdctl #ETCDCTL_API=3 指定etcd的版本为3
> snapshot save snap1.db #sanapshot save 指定备份文件
> --endpoints=https://127.0.0.1:2379 #指定etcd的ip地址和侦听的端口号
> --cacert=/etc/kubernetes/pki/etcd/ca.crt # 指定CA认证文件存放位置
> --cert=/etc/kubernetes/pki/etcd/server.crt
> --key=/etc/kubernetes/pki/etcd/server.key
2、删除当前的pod在恢复etcd:
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE busybox2 1/1 Running 2 28h
3、暂停k8s服务:(只要把manifests目录移动就能暂停kubernetes的服务)
[root@master kubernetes]# mv manifests manifests.back
[root@master kubernetes]# kubectl get pods
4、恢复etcd备份文件:
[root@master ~]# mv /var/lib/etcd/ /var/lib/etcd.bak
[root@master ~]# ETCDCTL_API=3 etcdctl
> snapshot restore snap1.db
> --data-dir=/var/lib/etcd
5、启动kube-apiserver和etcd容器:
[root@master ~]# mv /etc/kubernetes/manifests.bak /etc/kubernetes/manifests
[root@master kubernetes]# kubectl get pods
NAME READY STATUS RESTARTS AGE busybox2 1/1 Running 2 28h
----> Etcd数据库备份与恢复(二进制部署方式)
备份etcd:
ETCDCTL_API=3 etcdctl
snapshot save snap.db
--endpoints=https://192.168.31.71:2379
--cacert=/opt/etcd/ssl/ca.pem
--cert=/opt/etcd/ssl/server.pem
--key=/opt/etcd/ssl/server-key.pem
恢复:
1、先暂停kube-apiserver和etcd
systemctl stop kube-apiserver
systemctl stop etcd
mv /var/lib/etcd/default.etcd /var/lib/etcd/default.etcd.bak
2、在每个节点上恢复
ETCDCTL_API=3 etcdctl snapshot restore snap.db
--name etcd-1
--initial-cluster="etcd-1=https://192.168.31.71:2380,etcd-2
=https://192.168.31.72:2380,etcd-3=https://192.168.31.73:2380"
--initial-cluster-token=etcd-cluster
--initial-advertise-peer-urls=https://192.168.31.71:2380
--data-dir=/var/lib/etcd/default.etcd
3、启动kube-apiserver和etcd
systemctl start kube-apiserver
systemctl start etcd
---->kubeadm对K8s集群进行版本升级