• K8s全套快速入门


    K8s快速入门

    1 介绍

    • google开源的容器化管理工具
    • 机器数量十几台、上百台时,就可以考虑使用k8s
    • 高可用、自动容灾恢复、灰度更新、一键回滚历史版本、方便伸缩扩展等

    k8s集群架构:

    通常:一主多从

    • master:主节点,控制平台,不需要很高性能,不跑任务,通常一个就行了,也可以开多个主节点来提高集群可用度。
    • worker:工作节点,可以是虚拟机或物理计算机,任务都在这里跑,机器性能需要好点;通常都有很多个,可以不断加机器扩大集群;每个工作节点由主节点管理

    在这里插入图片描述
    k8s中重要概念:

    1. pod

    豆荚,K8S 调度、管理的最小单位,一个 Pod 可以包含一个或多个容器,每个 Pod 有自己的虚拟IP。一个工作节点可以有多个 pod,主节点会考量负载自动调度 pod 到哪个节点运行。
    在这里插入图片描述

    1. k8s组件
    • kube-apiserver: API服务器,公开了k8s API
    • etcd:键值数据库(类比redis),保存所有集群的数据
    • kube-scheduler:调用Pod到哪个节点运行
    • kube-controller:集群控制器
    • cloud-controller:与云服务商交互

    在这里插入图片描述

    2 安装k8s集群

    k8s-集群搭建的三种方式,目前主流的搭建k8s集群的方式有kubeadm、minikube,二进制包。

    1. kubeadm
    • 是一个工具,用于快速搭建kubernetes集群,目前应该是比较方便和推荐的,简单易用
    • kubeadm是Kubernetes 1.4开始新增的特性
    • kubeadm init 以及 kubeadm join 这两个命令可以快速创建 kubernetes 集群
    1. minikube
    • 一般用于本地开发、测试和学习,不能用于生产环境
    • 是一个工具,minikube快速搭建一个运行在本地的单节点的Kubernetes
    1. 二进制包
    • 在官网下载相关的组件的二进制包,上面的两个是工具,可以快速搭建集群,也就是相当于用程序脚本帮我们装好了集群,前两者属于自动部署,简化部署操作,自动部署屏蔽了很多细节,使得对各个模块感知很少,遇到问题很难排查,如果手动安装,对kubernetes理解也会更全面。
    • 目前生产环境的主流搭建方式,已在生产环境验证,kubeadm也可以搭建生产环境

    注意:本教程以minikube为主

    2.1 通过minikube

    ①前期准备

    minikube 是一个本地k8s,聚焦于快捷构建k8s学习与开发环境,在有虚拟化的环境运行 minikube start即可运行。

    • 注意:需要先有docker环境
    • 如果没有docker环境的,参考:https://editor.csdn.net/md/?articleId=127816970
    • 注意:CPU至少要两颗
    ②安装minikube
    # 1. 下载minikuke包
    curl -Lo minikube https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.18.1/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
    
    # 2. 添加镜像
    sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
    enabled=1
    gpgcheck=1
    repo_gpgcheck=1
    gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
    EOF
    
    # 3. 安装kubectl
    sudo yum install -y kubectl
    
    # 4. 初始化minikube
    minikube start --driver=docker
    
    # 如果报错The "docker" driver should not be used with root privileges.
    # 则执行如下命令
    minikube start --force --driver=docker
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    bug:

    1. 执行命令:rm -f /var/run/yum.pid,如果害怕强制停止引发错误的话,可以等待一会儿,过一会儿,错误会自动解决
      在这里插入图片描述
    2. 如果是使用vmware的话,报错:centos7开机无法进入图形界面,出现sda assuming drive cache write through报错信息,
    • 解决方案:
    修改 /etc/modprobe.d/dccp-blacklist.conf 内容,加入 blacklist intel_rapl
    vim /etc/modprobe.d/dccp-blacklist.conf
    blacklist intel_rapl
    
    • 1
    • 2
    • 3
    1. 如果报错X Exiting due to K8S_INSTALL_FAILED: updating control plane: downloading binaries: downloading kube…
    • 解决方案:
    # 1. 删除docker中的minikube
    minikube delete
    # 2. 重新下载并启动[如果是root账户则执行下面命令时,添加上 --force, 反之则删除]
    minikube start --force --kubernetes-version=v1.23.8 --image-mirror-country='cn' --image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'
    
    • 1
    • 2
    • 3
    • 4

    最后结果:
    在这里插入图片描述

    ③配置kubectl

    我们上面已经安装了minikube,因此有两个选择:有kubectl 来替代minikube kubectl --或者直接安装kubectl
    kubectl来替代minikube kubectl --,–不能省略

    方法一:设置alias

    # 1. 添加临时alias【或者修改配置文件设置永久的】
    alias kubectl="minikube kubectl --"
    # 或者设置永久的alias
    # echo "alias kubectl=minikube kubectl --" >> ~/.bashrc
    # source ~/.bashrc
    
    • 1
    • 2
    • 3
    • 4
    • 5

    查看所有pod:kubectl get pod -A 等价于minikube kubectl – get pods -A

    方法二:安装kubectl

    #2. 直接安装kubectl
    # 修改镜像地址
    sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
    enabled=1
    gpgcheck=1
    repo_gpgcheck=1
    gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
    EOF
    
    # 安装kubectl
    sudo yum install -y kubectl
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    完成之后执行命令查看所有pod:

    kubectl get pod -A

    结果:
    在这里插入图片描述

    2.2 裸机搭建

    • 主节点需要组件:
    • docker(也可以是其他容器运行时,如:Mesos等)
    • kubectl集群命令行交互工具
    • kubeadm集群初始化工具
    • 工作节点需要组件:
    • docker(或其他容器运行时)
    • kubelet管理Pod和容器,确保他们健康稳定运行
    • kube-proxy网络代理,负责网络相关工作
    ①购买云服务器

    腾讯云 TKE(控制台搜索容器)
    登录阿里云控制台 - 产品搜索 Kubernetes

    • 购买好3台云服务器【cpu至少2核,内存最好2G以上】
    • 根据需求,自行选择购买模式,我这里选择按量付费
    1. 基础配置:
      在这里插入图片描述
    2. 网络配置:

    因为我们本身不需要使用太多流量,所以这里我直接选择按量付费

    在这里插入图片描述

    ②配置云服务器
    1. 每个节点设置主机名并修改hosts
    # 每个节点分别设置对应主机名[标识]
    hostnamectl set-hostname master
    hostnamectl set-hostname node1
    hostnamectl set-hostname node2
    
    # 修改hosts文件【ip选择云服务器内网的ip】
    # 每个云服务器都需要配置,配置完之后,服务器之间可以互ping
    vim /etc/hosts
    10.206.0.11 node1
    10.206.0.6 node2
    10.206.0.13 master
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    在这里插入图片描述

    测试是否可以互通

    在这里插入图片描述

    2. 关闭SE(security enhance) Linux
    # 所有节点关闭 SELinux
    setenforce 0
    sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
    
    • 1
    • 2
    • 3
    3. 所有服务器关闭防火墙(云服务器默认关闭)
    # 所有节点确保防火墙关闭
    systemctl stop firewalld
    systemctl disable firewalld
    
    • 1
    • 2
    • 3
    4. 添加安装源安装对应组件(docker-ce、kubelet、kubectl、kubeadm)

    以下命令均是所有结点(云服务器)执行

    # 添加 k8s 安装源
    cat <<EOF > kubernetes.repo
    [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
    mv kubernetes.repo /etc/yum.repos.d/
    
    # 添加 Docker 安装源
    yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
    # 安装所需组件
    yum install -y kubelet-1.22.4 kubectl-1.22.4 kubeadm-1.22.4 docker-ce
    
    # 设置开启自启
    systemctl enable kubelet
    systemctl start kubelet
    systemctl enable docker
    systemctl start docker
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    5. 修改docker配置
    # kubernetes 官方推荐 docker 等使用 systemd 作为 cgroupdriver,否则 kubelet 启动不了
    cat <<EOF > daemon.json
    {
      "exec-opts": ["native.cgroupdriver=systemd"],
      "registry-mirrors": ["https://ud6340vz.mirror.aliyuncs.com"]
    }
    EOF
    mv daemon.json /etc/docker/
    
    # 重启生效
    systemctl daemon-reload
    systemctl restart docker
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    6. kubeadm初始化集群(仅在master节点执行)

    初始化集群控制台:

    # 初始化集群控制台 Control plane
    # 失败了可以用 kubeadm reset 重置
    kubeadm init --image-repository=registry.aliyuncs.com/google_containers
    
    # 执行上面命令之后会生成kubeadm join xxx,记得把 kubeadm join xxx 保存起来
    # 忘记了重新获取:kubeadm token create --print-join-command
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    保存好上图绿色框出来的部分,该命令是将其他节点加入master集群

    kubeadm join 10.206.0.13:6443 --token xxxxx \
    	--discovery-token-ca-cert-hash sha256:xxxxxx
    
    • 1
    • 2

    复制授权文件(master节点(master云服务器)执行)

    # 复制授权文件,以便 kubectl 可以有权限访问集群
    # 如果你其他节点需要访问集群,需要从主节点复制这个文件过去其他节点
    mkdir -p $HOME/.kube
    cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    chown $(id -u):$(id -g) $HOME/.kube/config
    
    # 在其他机器上创建 ~/.kube/config 文件也能通过 kubectl 访问到集群
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    7. 将工作节点加入集群(只在工作节点执行:node1、node2)

    执行开始保存好的kubeadm join xxx

    • 注意:需要将\去掉之后执行,如下:
    kubeadm join 10.206.0.13:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxxxxx
    
    • 1

    在这里插入图片描述

    8. master节点上安装网络插件

    注意:只在master节点执行以下命令来安装网络插件,否则node一直是Not Ready状态

    # 很有可能国内网络访问不到这个资源,你可以网上找找国内的源安装 flannel
    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    
    # 如果上面的插件安装失败,可以选用 Weave,下面的命令二选一就可以了。
    kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
    kubectl apply -f http://static.corecore.cn/weave.v2.8.1.yaml
    
    # 更多其他网路插件查看下面介绍,自行网上找 yaml 安装
    https://blog.csdn.net/ChaITSimpleLove/article/details/117809007
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    结果:
    在这里插入图片描述

    相关插件安装

    ①kubectl命令自动补全(命令)
    1. 安装bash-completion
    sudo yum -y install bash-completion
    source /usr/share/bash-completion/bash_completion
    
    • 1
    • 2
    1. 查看是否安装成功:
    • type _init_completion
      在这里插入图片描述
    1. 导入补全脚本
      echo ‘source <(kubectl completion bash)’ >>~/.bashrc
    2. 添加脚本到目录【需要切换为root用户】
      kubectl completion bash >/etc/bash_completion.d/kubectl
    3. 重启shell之后生效

    3 部署应用到集群(pod、deployment)

    3.1 部署方式(命令、文件)

    部署方式主要有两种:通过命令方式或者通过yml配置文件方式

    1. 通过命令直接部署
    kubectl run testapp --image=ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1
    
    • 1
    1. 通过yml配置文件方式
    • 配置单个Pod:
    apiVersion: v1
    kind: Pod
    metadata:
      name: test-pod
    spec:
      # 定义容器,可以多个
      containers:
        - name: test-k8s # 容器名字
          image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 镜像
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 配置为Deployment:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      # 部署名字
      name: test-k8s
    spec:
      replicas: 2
      # 用来查找关联的 Pod,所有标签都匹配才行
      selector:
        matchLabels:
          app: test-k8s
      # 定义 Pod 相关数据
      template:
        metadata:
          labels:
            app: test-k8s
        spec:
          # 定义容器,可以多个
          containers:
          - name: test-k8s # 容器名字
            image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 镜像
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    Deployment是通过label来关联Pods

    在这里插入图片描述
    总结:deployment、service与pod关系

    ①deployment根据Pod的标签关联到Pod,是为了管理pod的生命周期
    ②service根据Pod的标签关联到pod,是为了让外部访问到pod,给pod做负载均衡

    • 需要注意:
    1. deployment控制器关联的Pod,Pod的name和hostname(如果不手动指定)就是deployment控制器的Name
    2. StatefulSet控制器关联的Pod,Pod的Name和Hostname(如果不手动指定)就是StatefulSet控制器的Name + 序号

    3.2 部署应用实战及命令

    ①部署

    部署一个node.js web应用,源码地址:GitHub,如果遇到网络问题打不开,也可以直接使用下方的app.yaml

    app.yaml

    apiVersion: apps/v1
    # 表示类型为Deployment
    kind: Deployment
    metadata:
      # 部署名字
      name: test-k8s
    spec:
      replicas: 5
      # 用来查找关联的 Pod,所有标签都匹配才行
      selector:
        matchLabels:
          app: test-k8s
      # 定义 Pod 相关数据
      template:
        metadata:
          labels:
          	# 标签
            app: test-k8s
        spec:
          # 定义容器,可以多个【这一部分就是上面的单个pod】
          containers:
            - name: test-k8s # 容器名字【需要与labels对应】
              image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 镜像[上传到了腾讯云]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注意:粘贴的时候通过:set paste进入粘贴模式,否则vim会自动对yaml文件进行排版

    # 在master执行部署命令
    kubectl apply -f app.yaml
    
    • 1
    • 2
    • bug1:云服务器中的node节点执行部署的时候报错
      在这里插入图片描述

    原因:kubectl 需要kubernetes-admin来运行

    # 1. 通过命令远程复制文件
    scp /etc/kubernetes/admin.conf 175.27.128.45:/etc/kubernetes/admin.conf
    
    # 或者直接将master节点上的admin.conf下载到本地,然后通过ftp传输到node节点
    # 2. 配置环境变量
    echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
    # 3. 使环境变量生效
    source ~/.bash_profile
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    重新尝试,结果:
    在这里插入图片描述

    • bug2:k8s pod一直处于ContainerCreating状态
    # 查看pod详细信息
    kubectl describe pod pod-name 
    
    • 1
    • 2

    发现报错信息:network: open /run/flannel/subnet.env: no such file or directory

    • 解决办法:
    # 1. 在每个节点上创建/run/flannel/subnet.env
    vim /run/flannel/subnet.env
    # 2. 写入以下内容,等待一会儿即可恢复
    FLANNEL_NETWORK=10.244.0.0/16
    FLANNEL_SUBNET=10.244.0.1/24
    FLANNEL_MTU=1450
    FLANNEL_IPMASQ=true
    
    # 3. 重新在master节点执行kubectl apply -f app.yml
    kubectl apply -f app.yml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结果:

    本次部署,在node1、node2均有pod
    在这里插入图片描述

    ②实战命令
    1. 部署应用(kubectl apply -f app.yaml)
    # 部署应用
    kubectl apply -f app.yaml
    
    • 1
    • 2

    报错:error: error validating “app.yaml”: error validating data: apiVersion not set; if you choose to ignore these errors, turn validation off with --validate=false

    从中我们看到是因为缺少了apiVersion,后来排查发现是vim的:set paste模式下,我们要先按下i,进入插入模式之后再复制

    在这里插入图片描述

    2. 查看deployment(kubectl get deployment)
    # 查看deployment
    kubectl get deployment
    
    • 1
    • 2

    在这里插入图片描述

    3. 查看pod(kubectl get pod -o wide)
    # 查看pod
    kubectl get pod -o wide
    
    • 1
    • 2

    在这里插入图片描述

    4. 查看pod详情(kubectl describe pod pod-name)
    # 查看pod详情
    kubectl describe pod test-k8s-8598bbb8c6-62c8m 
    
    • 1
    • 2

    在这里插入图片描述

    5. 查看log(kubectl logs pod-name)
    # 查看log
    kubectl logs test-k8s-8598bbb8c6-ngmw9
    
    # 持续查看日志
    kubectl logs test-k8s-8598bbb8c6-ngmw9 -f
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    6. 进入pod容器终端(kubectl exec -it pod-name – base)
    # 进入pod容器终端,如果pod中有多个容器,则可以 -c container-name 可以指定进入哪个容器
    kubectl exec -it pod-name -- bash
    # kubectl exec -it test-k8s-8598bbb8c6-knztk -- bash
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    7. 伸缩扩展副本(kubectl scale deployment deployment-name --replicas=5)
    # 通过命令行
    kubectl scale deploymnet test-k8s --replicas=5
    
    # 或者通过修改yaml中的replicas配置项值,然后应用文件
    kubectl apply -f xxx.yaml
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    在这里插入图片描述

    8. 把集群内端口映射到节点(kubectl port-forward pod-name 8090:8080)
    # 8090(外面端口):8080(容器里面端口)
    kubectl port-forward pod-name 8090:8080
    # kubectl port-forward test-k8s-8598bbb8c6-2ff7w 8090:8080
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    9. 查看历史(kubectl rollout history deployment deployment-name)
    kubectl rollout history deployment deployment-name
    # kubectl rollout history deployment test-k8s
    
    • 1
    • 2

    在这里插入图片描述

    10. 回到上个版本(kubectl rollout undo deployment deployment-name)
    kubectl rollout undo deployment deployment-name
    # kubectl rollout undo deployment test-k8s
    
    • 1
    • 2
    11. 回到指定版本(kubectl rollout undo deployment deployment-name --to-revision=2)
    kubectl rollout undo deployment deployment-name --to-revision=2
    # kubectl rollout undo deployment test-k8s --to-revision=2
    
    • 1
    • 2
    12. 删除部署(kubectl delete deployment deployment-name)
    kubectl delete deployment deployment-name
    # kubectl delete deployment test-k8s
    
    • 1
    • 2

    在这里插入图片描述

    ③存在的问题

    目前Deployment的部署方式存在以下几个问题:

    1. 每次只能访问一个Pod,没有负载均衡的自动转发到不同Pod
    2. 访问的时候需要端口转发
    3. Pod重新创建之后IP就变化了,名字也会跟着变化,不便于管理

    4 Service

    注意:这里我选择使用安装了minikube的linux实验
    因为Deployment的部署方式存在以下几个问题:

    • 每次只能访问一个Pod,没有自动负载均衡
    • 访问的时候需要端口转发
    • Pod重创之后IP和名字都会发生变化

    service特性:

    1. Service通过label关联对应的Pod
    2. Service生命周期不跟Pod绑定,不会因为Pod重新创建而改变IP
    3. 提供了负载均衡功能,自动转发流量到不同Pod
    4. 可以对集群外部提供访问端口
    5. 集群内部可通过服务名字访问

    4.1 创建service(默认:ClusterIP,集群内部访问)

    ① 首先启动minikube(安装配置参考本文2.1节)并启动一个Pod

    app.yaml:

    apiVersion: apps/v1
    # 表示类型为Deployment
    kind: Deployment
    metadata:
      # 部署名字
      name: test-k8s
    spec:
      replicas: 5
      # 用来查找关联的 Pod,所有标签都匹配才行
      selector:
        matchLabels:
          app: test-k8s
      # 定义 Pod 相关数据
      template:
        metadata:
          labels:
          	# 标签
            app: test-k8s
        spec:
          # 定义容器,可以多个【这一部分就是上面的单个pod】
          containers:
            - name: test-k8s # 容器名字【需要与labels对应】
              image: ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v1 # 镜像[上传到了腾讯云]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    镜像已经放在了腾讯云上,主要是一个简单的js代码,有两个页面:index page和hello,访问的同时会打印出hostname

    # 启动minikube
    minikube start --force --driver=docker
    # 启动pod
    kubectl apply -f app.yaml
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    ②创建一个service,通过标签test-k8s跟对应的Pod关联上

    service.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: test-k8s
    spec:
      selector:
        app: test-k8s
      type: ClusterIP # 默认
      ports:
        - port: 8080        # 本 Service 的端口
          targetPort: 8080  # 容器端口
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    # 应用配置
    kubectl apply -f service.yaml
    
    • 1
    • 2
    ③查看service服务
    # kubectl get service
    kubectl get svc
    
    • 1
    • 2
    ④ 查看服务详情
    kubectl describe svc test-k8s
    # kubectl describe svc service-name
    
    • 1
    • 2

    在这里插入图片描述

    从上图我们可以发现,Endpoints是各个Pod的IP,也就是他会把流量转发到这些节点

    • 服务的默认类型时ClusterIP,只能在集群内部访问,因此我们可以进入到Pod里面访问
    # kubectl exec -it pod-name -- bash # 进入容器内部执行curl命令访问
    
    # curl http://service-name:port # 访问内容
    curl http://test-k8s:8080
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    拓展:如果要在集群外部访问,我们也可以通过端口转发实现(临时使用)
    kubectl port-forward service/test-k8s 8888:8080

    • kubectl port-forward service/service-name 主机port:容器内部port
    • 如果使用的是minikube,也可以这样 minikebu service test-k8s
      在这里插入图片描述
    • 注意:使用虚拟机的不能在本机windows浏览器直接输入虚拟机ip访问,因为此时虚拟机是容器的宿主机,如果要呈现效果,只有在虚拟机上打开浏览器访问

    4.2 对外暴露服务

    上面我们是通过端口转发的方式临时让外面访问到集群里面的服务,如果我们想直接把集群服务暴露出来,我们可以直接使用NodePortLoadbalancer类型的service

    ①单个端口
    1. 将service.yaml配置文件中的Type模式改为NodePort并在ports模块下添加nodePort

    service.yaml:

    apiVersion: v1
    kind: Service
    metadata:
      name: test-k8s
    spec:
      selector:
        app: test-k8s
      # 默认 ClusterIP 集群内可访问,NodePort 节点可访问,LoadBalancer 负载均衡模式(需要负载均衡器才可用)
      type: NodePort
      ports:
        - port: 8080        # 本 Service 的端口
          targetPort: 8080  # 容器端口
          nodePort: 31000   # 节点端口,范围固定 30000 ~ 32767
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 应用并测试

    访问的时候需要关闭防火墙:systemctl stop firewalld

    # 重新应用service.yaml
    kubectl apply -f service.yaml
    # 访问
    curl http://localhost:31000/hello/easydoc
    
    • 1
    • 2
    • 3
    • 4

    从上图中我们可以看到网页的信息被转发到了不同Pod并且是有负载均衡的

    • 注意:如果你是用 minikube,因为是模拟集群,你的电脑并不是节点,节点是 minikube 模拟出来的,所以你并不能直接在电脑上访问到服务

    Loadbalancer 也可以对外提供服务,这需要一个负载均衡器的支持,因为它需要生成一个新的 IP 对外服务,否则状态就一直是 pendding,这个很少用了,后面我们会讲更高端的 Ingress 来代替它。

    ②多端口

    如果使用多端口,我们必须配置 ports下面的name

    apiVersion: v1
    kind: Service
    metadata:
      name: test-k8s
    spec:
      selector:
        app: test-k8s
      type: NodePort
      ports:
        - port: 8080        # 本 Service 的端口
          name: test-k8s    # 必须配置
          targetPort: 8080  # 容器端口
          nodePort: 31000   # 节点端口,范围固定 30000 ~ 32767
        - port: 8090
          name: test-other
          targetPort: 8090
          nodePort: 32000
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    ③总结

    k8s的service有不同的类型,下面是说明

    类型说明
    ClusterIP默认的,仅在集群内可访问
    NodePort暴露端口到节点,提供了集群外部访问的入口,端口范围固定:30000~32767
    LoadBalancer需要负载均衡器(通常都需要云服务商提供,裸机可以安装METALLB测试),会额外生成一个IP对外服务;K8S支持的负载均衡器:负载均衡器
    Headless适合数据库,ClusterIP设置为None就变成Headless了,不会再分配IP

    5 Statefulset(有状态应用)

    • 特点:会固定每个Pod名字,但是IP不固定;用于管理有状态应用,如数据库等
    • 不足:Pod重建后,数据库的内容会丢失,不能持久化

    5.1 部署

    StatefulSet是用来管理有状态的应用,例如数据库。
    前面我们部署的应用,都是不需要存储数据,不需要记住状态的,可以随意扩充副本,每个副本都是一样的,可以替代的。

    • 但是像数据库、Redis这类有状态的,则不能随意扩充副本
    • StatefulSet会固定每个Pod的名字,但是Pod的IP不固定
    1. 编写mongo.yaml配置文件

    mongo.yaml:

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mongodb
    spec:
      serviceName: mongodb
      replicas: 3
      selector:
        matchLabels:
          app: mongodb
      template:
        metadata:
          labels:
            app: mongodb
        spec:
          containers:
            - name: mongo
              image: mongo:4.4
              # IfNotPresent 仅本地没有镜像时才远程拉,Always 永远都是从远程拉,Never 永远只用本地镜像,本地没有则报错
              imagePullPolicy: IfNotPresent
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: mongodb
    spec:
      selector:
        app: mongodb
      type: ClusterIP
      # HeadLess
      clusterIP: None
      ports:
        - port: 27017
          targetPort: 27017
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    1. 执行命令部署
    kubectl apply -f mongo.yaml
    
    • 1

    5.2 特性

    • Service的Cluster-IP是空的,Pod名字也是固定的
    • Pod创建和销毁是有顺序的,创建是顺序的,销毁是逆序的
    • Pod重建不会改变名字,但是会改变IP,因此不要使用IP直连

    Endpoints 会多一个 hostname:
    在这里插入图片描述

    访问时,如果直接使用Service名字连接,会随机转发请求

    • 要连接指定Pod,可以这样pod-name.service-name
    • 运行一个临时Pod连接数据测试如下:
    kubectl run mongodb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mongodb:4.4.10-debian-10-r20 --command -- bash
    
    • 1

    Web应用连接MongoDB

    在集群内部,我们可以通过服务名字访问到不同服务:

    • 指定连接第一个:mongodb-0.mongodb
      在这里插入图片描述
    # 获取所有信息
    kubectl get all
    
    • 1
    • 2

    在这里插入图片描述

    6 数据持久化

    StatefulSet虽然可以保证Pod的name一定,但是Pod重启之后会丢失数据,因此我们需要让数据持久化

    • k8s集群不会为我们处理数据的持久化存储,所以我们可以专门挂在一个磁盘来确保数据的安全
    1. 本地存储:可以挂载某个节点上的目录,但是这需要限定Pod在这个节点上运行
    2. 云存储:不限定节点,不受集群影响,安全稳定;需要云服务商提供,裸机集群是没有的
    3. NFS(network file system):不限定节点,不受集群影响

    6.1 hostPath挂载示例

    把节点上的一个目录挂载到Pod,但是已经不推荐使用了
    优:配置方式简单,需要手动指定Pod跑在某个固定的节点
    缺:仅供单节点测试使用,不适用于多节点集群

    • minikube 提供了 hostPath 存储
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mongodb
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mongodb
      serviceName: mongodb
      template:
        metadata:
          labels:
            app: mongodb
        spec:
          containers:
            - name: mongo
              image: mongo:4.4
              # IfNotPresent 仅本地没有镜像时才远程拉,Always 永远都是从远程拉,Never 永远只用本地镜像,本地没有则报错
              imagePullPolicy: IfNotPresent
              volumeMounts:
                - mountPath: /data/db # 容器里面的挂载路径
                  name: mongo-data    # 卷名字,必须跟下面定义的名字一致
          volumes:
            - name: mongo-data              # 卷名字
              hostPath:
                path: /data/mongo-data      # 节点上的路径
                type: DirectoryOrCreate     # 指向一个目录,不存在时自动创建
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    6.2 更高级抽象(SC、PV、PVC)

    在这里插入图片描述

    6.2.1 Storage Class(SC)

    将存储卷分为不同的种类,例如:SSD、普通磁盘、本地磁盘,按需使用。文档

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: slow
    provisioner: kubernetes.io/aws-ebs
    parameters:
      type: io1
      iopsPerGB: "10"
      fsType: ext4
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    6.2.2 Persistent Volume(PV)

    描述卷的具体信息,例如磁盘代销,访问模式。文档

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: mongodata
    spec:
      capacity:
        storage: 2Gi
      volumeMode: Filesystem  # Filesystem(文件系统) Block(块)
      accessModes:
        - ReadWriteOnce       # 卷可以被一个节点以读写方式挂载
      persistentVolumeReclaimPolicy: Delete
      storageClassName: local-storage
      local:
        path: /root/data
      nodeAffinity:
        required:
          # 通过 hostname 限定在某个节点创建存储卷
          nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                    - node2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    6.2.3 Persistent Volume Claim(PVC)

    对存储需求的一个声明,可以理解为一个申请单,系统根据这个申请单去找一个合适的PV,还可以根据PVC自动创建PV。

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mongodata
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "local-storage"
      resources:
        requests:
          storage: 2Gi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    6.2.4 为什么要有多层抽象
    • 更好的分工,运维人员提供好存储,开发人员不需要关注磁盘细节,只需要写一个申请单
    • 方便云服务商提供不同类型的,配置细节不需要开发者关注,只需要一个申请单
    • 动态创建,开发人员写好申请单后,供应商可以根据需求自动创建所需存储卷

    6.3 云服务商存储挂载

    在这里插入图片描述

    6.4 本地存储挂在

    不支持动态创建,需要提前创建好

    三个存储抽象文件可以合在一起写,通过---分隔开

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mongodb
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mongodb
      template:
        metadata:
          labels:
            app: mongodb
        spec:
          containers:
            image: mongo:5.0
            imagePullPolicy: IfNotPresent
            name: mongo
            volumeMounts:
              - mountPath: /data/db
                name: mongo-data
          volumes:
            - name: mongo-data
              persistentVolumeClaim:
                 claimName: mongodata
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: mongodb
    spec:
      clusterIP: None
      ports:
      - port: 27017
        protocol: TCP
        targetPort: 27017
      selector:
        app: mongodb
      type: ClusterIP
    ---
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-storage
    provisioner: kubernetes.io/no-provisioner
    volumeBindingMode: WaitForFirstConsumer
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: mongodata
    spec:
      capacity:
        storage: 2Gi
      volumeMode: Filesystem  # Filesystem(文件系统) Block(块)
      accessModes:
        - ReadWriteOnce       # 卷可以被一个节点以读写方式挂载
      persistentVolumeReclaimPolicy: Delete
      storageClassName: local-storage
      local:
        path: /root/data
      nodeAffinity:
        required:
          # 通过 hostname 限定在某个节点创建存储卷
          nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                    - node2
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mongodata
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "local-storage"
      resources:
        requests:
          storage: 2Gi
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    现有问题:

    当前数据库的连接地址是写死在代码里的,另外还有数据库的密码需要配置。

    • 后续处理:configMap

    7 Configmap & Secret(配置)

    7.1 Configmap

    像我们上面搭建的mongodb,对于数据库来说连接地址是可能根据部署环境而变化的,我们不应该写死在代码了。

    • k8s为我们提供了ConfigMap,可以方便的配置一些变量

    configmap.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: mongo-config
    data:
      mongoHost: mongodb-0.mongodb
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # 应用配置文件
    kubectl apply -f configmap.yaml
    # 查看
    kubectl configmap mongo-config -o yaml
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    7.2 Secret

    对于一些重要的数据,例如:密码、TOKEN等,我们可以放到secret中。文档配置证书

    secret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: mongo-secret
    # Opaque 用户定义的任意数据,更多类型介绍 https://kubernetes.io/zh/docs/concepts/configuration/secret/#secret-types
    type: Opaque
    data:
      # 数据要 base64。https://tools.fun/base64.html
      mongo-username: bW9uZ291c2Vy
      mongo-password: bW9uZ29wYXNz
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    # 应用
    kubectl apply -f secret.yaml
    # 查看
    kubectl get secret mongo-secret -o yaml
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    ①作为环境变量使用
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mongodb
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: mongodb
      template:
        metadata:
          labels:
            app: mongodb
        spec:
          containers:
            - name: mongo
              image: mongo:4.4
              # IfNotPresent 仅本地没有镜像时才远程拉,Always 永远都是从远程拉,Never 永远只用本地镜像,本地没有则报错
              imagePullPolicy: IfNotPresent
              env:
              - name: MONGO_INITDB_ROOT_USERNAME
                valueFrom:
                  secretKeyRef:
                    name: mongo-secret
                    key: mongo-username
              - name: MONGO_INITDB_ROOT_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: mongo-secret
                    key: mongo-password
              # Secret 的所有数据定义为容器的环境变量,Secret 中的键名称为 Pod 中的环境变量名称
              # envFrom:
              # - secretRef:
              #     name: mongo-secret
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    ②挂在为文件(更适合证书文件)

    挂在后,会在容器对应路径生成文件,一个key一个文件,内容就是value。文档

    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
      - name: mypod
        image: redis
        volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
          readOnly: true
      volumes:
      - name: foo
        secret:
          secretName: mysecret
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    8 Helm & namespace(软件库 & 命名空间)

    8.1 Helm

    ①介绍

    Helm类似npm、pip、docker hub,可以为一个软件库,可以方便快速的为集群安装一些第三方软件。

    • 使用Helm可以非常方便的搭建出来MongoDB/MySQL副本集群,YAML文件别人也替我们写好了,可以直接使用。官网应用中心
    ②安装Helm

    安装文档

    curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
    
    • 1
    ③通过Helm搭建Mongo集群
    # 安装
    helm repo add bitnami https://charts.bitnami.com/bitnami
    helm install my-mongo bitnami/mongodb
    
    # 指定密码和架构
    helm install my-mongo bitnami/mongodb --set architecture="replicaset",auth.rootPassword="mongopass"
    
    # 删除
    helm ls
    helm delete my-mongo
    
    # 查看密码
    kubectl get secret my-mongo-mongodb -o json
    kubectl get secret my-mongo-mongodb -o yaml > secret.yaml
    
    # 临时运行一个包含 mongo client 的 debian 系统
    kubectl run mongodb-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mongodb:4.4.10-debian-10-r20 --command -- bash
    
    # 进去 mongodb
    mongo --host "my-mongo-mongodb" -u root -p mongopass
    
    # 也可以转发集群里的端口到宿主机访问 mongodb
    kubectl port-forward svc/my-mongo-mongodb 27017:27018
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    8.2 namespace

    如果一个集群中部署了多个应用,所有应用都在一起,就不太好管理,也可能导致名字冲突等。

    • namespace:命名空间,把应用划分到不同的空间,方便管理
    # 创建命名空间
    kubectl create namespace testapp
    # 部署应用到指定的命名空间
    kubectl apply -f app.yml --namespace testapp
    # 查询
    kubectl get pod --namespace kube-system
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    但是,每次命令都加上--namespace会很繁琐

    • 我们可以使用kubens>快速切换namespace
    • kubens下载地址:https://github.com/ahmetb/kubectx
    • 下载好之后配置好环境变量就可以使用了

    在这里插入图片描述

    9 Ingress(统一访问入口)

    9.1 介绍

    Ingress为外部访问集群提供了一个统一入口,避免了对外暴露集群端口

    • 功能类似于Nginx(基于nginx做了扩展,Lua脚本),可以根据域名、路径将请求转发到不同Service
    • 可以配置https

    与LoadBalancer区别?

    1. LoadBalancer需要对外暴露端口,不安全
    2. LoadBalancer无法根据域名、路径将流量转发到不同Service,多个Service需要开启多个LoadBalancer
    3. 功能单一,无法配置https

    在这里插入图片描述

    9.2 使用(云服务厂商为例)

    要使用Ingress,需要一个负载均衡器 + Ingress Controller

    • 如果是裸机(bare metal)搭建的集群,需要我们自己安装一个负载均衡插件,我们可以安装METALLB

    文档:
    Minikube中部署Ingress Controller:nginx
    Helm中安装:Nginx

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: simple-example
    spec:
      ingressClassName: nginx
      rules:
      - host: tools.fun
        http:
          paths:
          - path: /easydoc
            pathType: Prefix
            backend:
              service:
                name: service1
                port:
                  number: 4200
          - path: /svnbucket
            pathType: Prefix
            backend:
              service:
                name: service2
                port:
                  number: 8080
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    腾讯云配置Ingress:
    在这里插入图片描述

    参考文章:
    https://blog.csdn.net/qq_21187515/article/details/101460039
    https://blog.csdn.net/haohaifeng002/article/details/116788698

  • 相关阅读:
    【WebRTC---源码篇】(十:一)WEBRTC 发送视频RTP包
    深入浅出Spring注解(22)
    Mac 下载新Sourcetree 管理 Gitlab 代码(下载及提交)
    Vue3 - 使用 mitt.js 进行组件通信(兄弟关系)
    cookie信息无法获取问题研究
    2022/7/26 考试总结
    高斯消元c++实现
    MySQL事务
    归并排序-面试例子
    OSPF高等特性——Forwarding Address
  • 原文地址:https://blog.csdn.net/weixin_45565886/article/details/130698024