zoukankan      html  css  js  c++  java
  • 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集群进行版本升级

  • 相关阅读:
    关系数据库元数据处理类(一) 创建元数据实体
    常用通用简单文件上传功能
    基于NOPI的Execl模板转换类,直接将Execl模板转换对应的Entity
    CSS彻底研究(3)
    CSS彻底研究(2)
    CSS彻底研究(1)
    CLR via C#
    前端JS模版库kino.razor
    CLR via C#
    CLR via C#
  • 原文地址:https://www.cnblogs.com/yyuuee/p/15221549.html
Copyright © 2011-2022 走看看