kubernetes学习资料

Kubernetes 学习资料(版本:1.21)

一、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 

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#initializing-your-control-plane-node

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。

 容器编排系统的:

  1. Kubernetes
  2. Swarm
  3. Mesos Marathon

  1.  Kubernetes 是Google在2014年开源的一个容器集群管理系统,Kubernetes简称K8S。
  2. 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

 输出类似于:

 

[root@k8s-master ~]# kubectl rollout history deployment.v1.apps/nginx-deployment

 

  •  要查看修订历史的详细信息,运行:

[root@k8s-master ~]# kubectl rollout history deployment.v1.apps/nginx-deployment --revision=1 

  •  回滚到之前的修订版本
  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控制器的用途

  1.   Pod副本数量管理,不断对比当前Pod数量与期望Pod数量
  2.   Deployment每次发布都会创建一个RS作为记录,用于实现回滚
  3.   #查看RS记
    [root@k8s-master ~]# kubectl get rs
    
  4. #版本对应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特点:

  1.   一个Pod可以理解为是一个应用实例,提供服务
  2. Pod中容器始终部署在一个Node上
  3. Pod中容器共享网络、存储资源
  4. Kubernetes直接管理Pod,而不是容器

Pod主要用法:

  1.    运行单个容器:最常见的用法,在这种情况下,可以将Pod看做是单个容器的抽象封装
  2.    运行多个容器:封装多个紧密耦合且需要共享资源的应用程序

运行多个容器:

  1.     两个应用之间发生文件交互
  2.     两个应用需要通过127.0.0.1或者socket通信
  3.     两个应用需要发生频繁的调用

 资源共享实现机制:

 将业务容器的网络加入到“负责网络容器”实现网络共享。共享存储:容器通过数据卷共享数据

#实现网络资源共享机制

  1. 单独拉起一个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
    
  2. 通过命令部署单独的pod;
    [root@k8s-master ~]# kubectl apply -f net-t1.yaml
  3. 查看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存在的不足

  1.      一个端口只能一个服务使用,端口需提前规划
  2.     只支持4层负载均衡
  3.      基于IP地址和端口转发

Ingress:

  1.          Ingress:公开了从集群外部到集群内服务的HTTP和HTTPS路由的规则集合,而具体实现流量路由则是由Ingress Controller负责。 
  2.         Ingress:K8s中的一个抽象资源,给管理员提供一个暴露应用的入口定义方法
  3.         Ingress Controller:根据Ingress生成具体的路由规则,并对Pod负载均衡器
  4.          基于应用层协议转发,例如: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 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

  1.         ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
  2.         ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
  3.         ReadWriteMany(RWX):读写权限,可以被多个节点挂载

RECLAIM POLICY(回收策略):
目前PV 支持的策略有三种:

  1.         Retain(保留):保留数据,需要管理员手工清理数据
  2.         Recycle(回收):清除PV 中的数据,效果相当于执行rm -rf /ifs/kuberneres/*
  3.         Delete(删除):与PV 相连的后端存储同时删除

STATUS(状态):
一个PV 的生命周期中,可能会处于4中不同的阶段:

  1.         Available(可用):表示可用状态,还未被任何PVC 绑定
  2.         Bound(已绑定):表示PV 已经被PVC 绑定
  3.         Released(已释放):PVC 被删除,但是资源还未被集群重新声明
  4.         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数据有两种方式:

  1.                   变量注入
  2.                   数据卷挂载

 实例:创建一个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 对象:RoleClusterRoleRoleBinding 和 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集群进行版本升级

原文地址:https://www.cnblogs.com/yyuuee/p/15221549.html