• Kubernetes学习笔记【2年以前的笔记】


    Kubernetes学习笔记

    知识储备

    1. 熟悉linux基础命令
    2. 熟悉docker的基本原理和操作
    3. 了解ssl证书工作原理
    4. 了解负载均衡工作原理(L4/L7)
    5. 了解分布式概念
    6. 了解域名解析原理
    7. 了解网络协议

    目标

    1. k8s环境搭建,掌握在线kubeadm和完全离线安装两种方法

    2. k8s故障排查

    3. 目标:

      #1. 自我修复
      #2. 弹性伸缩
      #3. 自动部署和回滚
      #4. 服务发现和负载均衡
      #5. 机密和配置管理
      #6. 存储编排
      #7. 批处理
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    4. 自动装箱

    5. 自我修复

    6. 水平拓展

    7. 服务发现

    8. 滚动更新,k8s是生成一个,然后杀死一个容器,如果新的版本有问题,可通过k8s快速回滚

    9. 版本回退

    10. 密钥和配置管理

    11. 存储编排

    12. 批处理

    疑问

    1. k8s各个核心功能都是由哪个组件实现的?

    2. 为什么要用Flannel?因为容器要跨docker进行通信。

    3. k8s集群的时候要保证一半以上的服务器正常才能正常运行???不集群单机master,单机worker就行?

    4. k8s是什么?难学不?

    5. 用能在哪里?怎么用?怎么和docker结合?

    6. k8s架构是什么?

    7. k8s功能有哪些?

    8. SSL证书工作原理?

    9. 负载均衡工作原理?

    10. 分布式概念?

    11. 网络协议有哪些?

    12. namespace/service有什么用?service:1 昨为访问的同意入口,2 用来发布服务

    13. 安装k8s分别要准备哪些包?

    14. 为什么要有loaderbanlace?

    15. worker node通过https访问master node有什么用?

    16. 要DNS做啥?因为pod可能随时有新的替换,ip经常变换,所以使用coredns

    17. 如何导入普通的docker镜像,不用docker pull

    18. master创建控制器有哪些?

    19. master创建Pod之后如何进行node pod端口映射?

    20. 如何通过web界面来管理k8s?Kubernetes dashboard/kuboard,都只能作为辅助,没有完备功能,用kuboard比较多

    21. port/targetPort/nodePort分别是什么作用?

    22. 滚动更新后数据库的数据怎么办?

    23. 流程迁移是什么?怎么做?-- 就是把物理机或者阿里云上的项目迁移到k8s

    24. 证书:谁给谁颁发证书?master自建CA,给etcd颁发证书,也要给api-server颁发,根据谁访问谁

    25. 证书:生成证书中的每一条命令是做什么的?

    26. 证书:如果etcd和api-server分别生成不同的证书,有什么后果?能不能这样?

    27. 证书:tocken.svg是谁生成的?可以自己生成。

    28. master节点:独立master和独立的etcd,为什么安装master的时候,api-server启动不来?–初步猜想,api-server配置不到位,—对的,因为api-server配置的etcd证书路径搞错了

    29. master节点:一样的配置,为什么不一样的结果?131挂了之后,为什么130没有顶上?

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WrahayMY-1655996178099)(E:\IT\Kubernetes\疑问1-1.jpg)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0ooCVfP-1655996178101)(E:\IT\Kubernetes\疑问1-0.jpg)]

    30. 有证书,为什么不让访问:

      curl -L --cacert /opt/kubernetes/ssl/ca.pem  https://192.168.11.130:6443/api
      {
        "kind": "Status",
        "apiVersion": "v1",
        "metadata": {
      
        },
        "status": "Failure",
        "message": "forbidden: User \"system:anonymous\" cannot get path \"/api\"",
        "reason": "Forbidden",
        "details": {
      
        },
        "code": 403
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    31. pod:部署master/worker/worker-docker之后,镜像操作是直接在master上操作还是要在worker上一个一个拉取每个镜像?-- 是的,每一台worker节点都要下载镜像,也可以下载一个,然后批量导入其他worker,所以要有批量管理

    32. kubelet apply -f xxxx.yml:这是安装软件用的吗?

    33. 当挂掉一个pod的时候,为什么其他节点没有自动替换上去?需要时间:

      [xy@master-130 ~/k8s-files 16:58:39]$ kubectl get pods -o wide
      NAME                               READY   STATUS        RESTARTS   AGE   IP           NODE              NOMINATED NODE   READINESS GATES
      my-nginx-1-18-0-67f4f6b779-d8d5v   1/1     Running       0          20m   10.244.0.3   worker-etcd-133   <none>           <none>
      my-nginx-1-18-0-67f4f6b779-m68k4   0/1     Terminating   0          48m   10.244.1.4   worker-etcd-134   <none>           <none>
      [xy@master-130 ~/k8s-files 16:59:23]$
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    34. flanel:不用安装吗?还是网络插件cni就是了?

    35. 暴露端口给物理机后?继续用路由器映射80端口?

    36. 创建节点除了基于kubectl create deployment;kubectl run $NAME --image=xxxx --replicas=1之外,还有哪些?-- yml文件

    37. 发布服务的时候区分节点端口、容器端口、服务端口

    38. k8s最小单位不是容器,而是pod,一个pod里面可以有多个容器。

    39. k8s集群必须要保证时间同步。

    40. k8s最重要的是要保证参数正确。

    41. Linux命令前面加“/”表示使用原生命令,不是用别名

    42. k8s安装docker的时候一定要注意版本!

    43. workder node安装完毕之后,所有的操作都是在master node上执行

    44. 创建pod的时候,workder node就会自动拉取docker 镜像

    45. 默认情况下,k8s只能在master节点上执行管理操作命令,如果想在worker节点上管理,则需要进行配置

    46. 玩k8s和docker,大部分时间是在制作容器镜像

    47. 排除故障:重启服务-重启服务器-查看日志-排错-查看配置-重启服务-重启服务器,通常k8s启动不了是因为配置问题

    48. 一定要保证时间一致,保证证书授权时间没错

    49. etcd,所有的数据都是保存到etcd服务器中,所以部署k8s集群之前,要先部署etcd

    50. 证书:master访问etcd,需要给etcd颁发一个证书,worker访问api-server,需要给api-server颁发一个证书

    51. etcd,如果etcd没有启动,那么kube-apiserver就会有问题

    52. k8s每个版本支持的docker是特定的,通过github或者官网查看选择

    53. pods,如何删除创建的docker容器?pods和deployment区别?

    54. kubelet/kube-proxy没有开机自启,即便设置了开机自启

    55. master挂掉后,worker也能正常工作

    56. 概念:controller/service/namespace/selector到底是啥东西?

    57. k8s除了有核心组件之外,还有哪些附加组件

    58. 安装完k8s worker会自动帮你安装docker?这是针对使用yum方式?是的,针对yum方式,使用yum方式的时候,分别对应:

      yum install -y kubernetes-master-xxxx
      yum install -y kubernetes-node-xxx
      
      • 1
      • 2

      yum方式安装的kubelet,如果发现docker没有启动,那么就会启动docker。

      yum方式安装的k8s没有启用证书

    59. 为什么yum方式安装的worker节点有一个存活,master都能使用kubectl get nodes,而二进制方式得要2个以上存活的worker才能使用kubectl get nodes

    60. kubectl cskubectl get nodes有什么区别?

    61. 安装了flannel,还需要coreDNSm不?两者功能一样吗?

    62. RC replication controller又是什么?

    63. RC和POD如何关联起来?通过label

    64. 滚动更新后的数据库数据怎么办??

    65. 创建deployment/service/pod/rc,到底有什么区别?

    66. pod探针怎么用?

    67. RC/RC/deployment是啥

    68. PV/PVC是啥?如何保证多个POD数据一致?–先创建pv,然后创建pvc,pvc会绑定到符合需要最小的pv上

    69. 假如改变运行的一个Pod中的数据,然后删掉,就会出现数据的丢失,那么如何保证一致?使用pv/pvc,然后用pod使用pvc,接着删了该pod,重新启动新的pod就能实现共享了,每个worder node都要安装nfs,不然挂载不了,启动不了pod,但是后期一般使用glusterfs

    70. glusterfs分布式复制卷怎么用?

    71. glusterfs如何与PV/PVC关联?

    犯错

    1. api-server证书搞错,etcd证书路径搞错,导致master的api-server没起来

    2. controller/scheduler监听127.0.0.1:8080失败怎么回事?

    3. 创建nginx的pods,没启动成功

      #错误信息
       Warning  FailedCreatePodSandBox  11m                  kubelet, worker-etcd-135  Failed create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "b3ff30406d49c90f3597dad2143459b3a3cbb4fc56fdcb9009975ce1d984ef66" network for pod "my-nginx-1.18.0-5d8c89cddf-p4plv": networkPlugin cni failed to set up pod "my-nginx-1.18.0-5d8c89cddf-p4plv_default" network: open /run/flannel/subnet.env: no such file or directory
        # 这是因为cni没全部安装好
      
      • 1
      • 2
      • 3
    4. 暴露端口的时候出错

      [xy@master-130 ~/k8s-files 16:00:04]$ kubectl expose deployment my-nginx-1.18.0 --port=80 --type=NodePort
      The Service "my-nginx-1.18.0" is invalid: metadata.name: Invalid value: "my-nginx-1.18.0": a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name',  or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')
      [xy@master-130 ~/k8s-files 16:00:09]$
      
      # 这是因为deployment的时候取名字出错!名字只能字母开头,并且只能有小写字母和数字横行
      
      • 1
      • 2
      • 3
      • 4
      • 5
    5. kube-apiserver没能自启动

    6. kubelet没能自启动,因为配置文件出过错了

      #配置文件出错
        1 [Unit]
        2 Description=Kubernetes Kubelet
        3 After=docker.service
        4 Before=docker.service
        5
        6 [Service]
        7 EnvironmentFile=/opt/kubernetes/cfg/kubelet.conf
        8 ExecStart=/opt/kubernetes/bin/kubelet $KUBELET_OPTS
        9 Restart=on-failure
       10 LimitNOFILE=65536
       11
       12 [Install]
       13 WantedBy=multi-user.target
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    总结

    1. kubectl get csr一直出现unknown,可能是bug,centos7.5以前的版本都和kubectl有冲突

    2. 假如有其他主机A的pod替换挂掉的主机B的pod,那么,当A重启的时候,K8s会自动删除该主机A上的pod

    3. 当集群中worker的个数少于一半还是一台的时候,master就无法使用了,整个集群也挂了

    4. 每个版本的yml配置文件的appversion可能写法都不一样

    5. 弹性伸缩只要把发布服务的yaml文件的replicas合理增减,重新发布就行了

    6. 滚动更新只要把镜像版本改了,重新部署pod就可以。

    7. controller manager:自我修复、故障检测、滚动更新、自动拓展

    8. scheduler:筛选合适的worker node来调度pod

    9. cAdvisor:监控,已经集成到kubelet上

    10. 网络插件:Flannel,用于容器之间的通信,类似vpn

    11. flannel也要用到etcd

    12. 没有启动etcd,kube-apiserver也能起来

    13. 有了flannel,为了使docker内的容器相互通信,一般还要设置iptables -P FORWARD ACCEPT,这是因为docker 1.13之后决定的,为了方便,设置docker启动后使用,在systemd/system/docker.service文件的[service]中添加:

      ExecStartPost=/usr/sbin/iptales -P FORWARD ACCEPT

    14. **排错非常好的命令:journalctl -xefu kubelet **

    15. kubelet启动失败一般是配置文件有问题或者docker没起来或者三关闭没做好

    16. 一个Pod资源控制docker最少启动2个容器:业务容器和基础pod容器,绑定在一起的

    17. kubeclt yml文件编写帮助:kubectl explain XXXX,例如:pod.spec.container

    18. 使用yml创建pod的时候,如果没有指定name,就会使用随机的名字

    19. port:vip,也就是cluster IP的端口,targetPort:pod的IP,nodePort:宿主机端口,端口服务由kube-proxy管理

    20. RC保证高可用,service保证能被外界访问

    21. deployment解决RC一个问题:RC进行滚动更新的时候SVC段时间不可用

    22. deployment先起RS,RS再启动POD

    23. service yml文件就类似kubectl exposse 暴露端口

    24. 使用deployment进行版本更新的时候,直接kubectl edit deployment $name ,把image版本改版一下就好了,不会出现rc的问题

    25. deployment比RC用得更多

    26. 只要一台worker节点上有镜像就能启动容器了,而且,有镜像的主机挂掉,pod会自动在其他worker上创建新的容器

    27. 弹性伸缩使用HPA,每个功能对应每个组件

    28. 设置kubectl 远程管理,才能使用jenkins自动化

    1、k8s架构组件

    1、master节点

    1、api-server

    2、controller-manager

    3、scheduler

    2、worker节点

    2、k8s核心概念

    可以这样理解:通过service作为统一入口进行访问,然后通过conroller进行创建pod

    1、pod

    2、controller

    3、serverice

    3、部署方式

    0、minikube

    单机用来玩的,没法实验测试生产。

    1、kubeadm

    很简单,只需要两个命令,kubeadmin init/kube join

    优点:

    部署简单

    缺点:

    屏蔽很多细节,遇到问题很难排查,不利于维护

    所以还是推荐用二进制来部署

    2、二进制方式

    部署步骤

    0、初始化服务器

    1、安装ssl证书

    2、安装etcd

    3、安装master

    4、安装worker node节点

    5、网络插件安装

    有什么用?

    6、授权aip server

    使api server能访问kubelet

    4、案例

    1、安装包方式

    不管几个master,都必须要安装奇数台etcd服务器

    1、单master

    1. 架构图:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ws184JZW-1655996178101)(单master架构图.jpg)]

    2. 准备安装包

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CnPWK7EC-1655996178102)(安装包.jpg)]

      • ssl证书安装包
      • etcd安装包
      • master安装包
      • worker安装包
    3. 初始化(三关闭三配置)

      这步骤在所有服务器上操作

      • 关闭swap,因为不关闭,k8s可能起不来

        vim /etc/fstabl
        #然后注释swap行
        #接着重启,使用free -m确认都是0就表示关闭成功 
        
        • 1
        • 2
        • 3
      • 关闭selinux

        sudo vim /etc/selinux/conf
        SELINUX=disabled
        
        • 1
        • 2
      • 关闭防火墙

        #关闭防火墙,关闭自启
        sudo systemctl stop firewalld
        sudo systemctl disable firewalld
        
        • 1
        • 2
        • 3
      • 配置唯一主机名,固定IP

        sudo hostnamectl set-hostname worker-etcd-133
        sudo hostnamectl set-hostname worker-etcd-134
        sudo hostnamectl set-hostname worker-etcd-135
        sudo hostnamectl set-hostname master-130
        
        • 1
        • 2
        • 3
        • 4
      • 配置名称解析

        #每个主机hosts文件 
        # sudo vim /etc/hosts
        192.168.11.130 master-130
        192.168.11.131 master-131
        192.168.11.132 master-132
        192.168.11.133 worker-etcd-133
        192.168.11.134 worker-etcd-134
        192.168.11.135 worker-etcd-135
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
      • 配置时间解析,保持所有服务器时间同步

        # 每个服务器都这样执行
        # 1. 安装chrony
        sudo yum install -y chrony
        # 2. 配置master为主时间服务器
        sudo vim /etc/chrony.conf
        server npt1.aliyun.com iburst
        local stratum 10
        # 3. 配置其他服务器参考master
        sudo vim /etc/chrony.conf
        server 192.168.11.130 iburst
        # 4. 重启每台主机chrony服务、设置开机自启
        sudo systemctl restart chronyd
        sudo sytemctl enable chronyd	
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
    4. 安装ssl颁发证书,给etcd颁发证书

      这一步在master上进行

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jc2X7R87-1655996178102)(E:\IT\Kubernetes\SSL证书解压.jpg)]

      # 如上图,使用TSL.tar.gz安装包,在master上进行操作,解压后入上所示
      # 文件解释;
      # cfssl.sh: 把建立ca用到的执行文件放入bin目录中,这是第一步
      # etcd/server.json: 配置etcd服务器IP
      # etcd/generate_etcd_cert.sh: 自建CA,然后把证书颁发给etcd
      
      
      # 1. 安装建立CA需要的文件
      sudo ./cfssl.sh
      
      # 2.配置etcd服务器ip,hosts就是etcd所在服务器
      sudo vim etcd/server-csr.json
      {
          "CN": "etcd",
          "hosts": [
              "192.168.11.133",
              "192.168.11.134",
              "192.168.11.135"
              ],
          "key": {
              "algo": "rsa",
              "size": 2048
          },
          "names": [
              {
                  "C": "CN",
                  "L": "BeiJing",
                  "ST": "BeiJing"
              }
          ]
      }
      
      # 3. 给etcd颁发证书,这一步用root会提示找不到命令,用普通用户即可,生成信息如下:
      ./generate_etcd_cert.sh
      [xy@master-130 ~/k8s-files/ca/TLS/etcd 20:43:30]$ ./generate_etcd_cert.sh
      2020/10/17 20:43:33 [INFO] generating a new CA key and certificate from CSR
      2020/10/17 20:43:33 [INFO] generate received request
      2020/10/17 20:43:33 [INFO] received CSR
      2020/10/17 20:43:33 [INFO] generating key: rsa-2048
      2020/10/17 20:43:33 [INFO] encoded CSR
      2020/10/17 20:43:33 [INFO] signed certificate with serial number 415345260549328062060225119338713862468115542887
      2020/10/17 20:43:33 [INFO] generate received request
      2020/10/17 20:43:33 [INFO] received CSR
      2020/10/17 20:43:33 [INFO] generating key: rsa-2048
      2020/10/17 20:43:33 [INFO] encoded CSR
      2020/10/17 20:43:33 [INFO] signed certificate with serial number 592175594331669672882850326788833412250199862440
      2020/10/17 20:43:33 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
      websites. For more information see the Baseline Requirements for the Issuance and Management
      of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
      specifically, section 10.2.3 ("Information Requirements").
      [xy@master-130 ~/k8s-files/ca/TLS/etcd 20:43:33]$ cd ..
      [xy@master-130 ~/k8s-files/ca/TLS 20:43:59]$ ls -Ra
      .:
      .  ..  cfssl  cfssl-certinfo  cfssljson  cfssl.sh  etcd  k8s
      
      ./etcd:
      .  ..  ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem  generate_etcd_cert.sh  server.csr  server-csr.json  server-key.pem  server.pem
      
      ./k8s:
      .  ..  ca-config.json  ca-csr.json  generate_k8s_cert.sh  kube-proxy-csr.json  server-csr.json
      [xy@master-130 ~/k8s-files/ca/TLS 20:44:10]$
      
      # 解释
      # ca-key.pem: CA服务器自己的私钥
      # ca.pem: CA自己的公钥
      # server-key.pem: 给etcd的私钥
      # server.pem: 给etcd的公钥
      
      
      • 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
    5. 安装etcd

      用到的安装包:etcd.tar.gz,这一步骤要在etcd服务器上操作

      部署之前,一定要确认已经颁发了证书,前面生成的证书这时候起到作用了

      #安装步骤
      # 0. 首先把之前生成的证书复制过来
      scp ca.pem server.pem server-key.pem xxxxxxxxxxxxx #命令略
      # 1. 解压etcd.tar.gz
      tar -zxvf etcd.tar.gz
      # 结果如下:
      [xy@worker-etcd-135 ~/k8s 23:18:18]$ ls -R
      .:
      ca.pem  etcd  etcd.service  etcd.tar.gz  server-key.pem  server.pem  test-etcd.sh
      
      ./etcd:
      bin  cfg  ssl
      
      ./etcd/bin:
      etcd  etcdctl
      
      ./etcd/cfg:
      etcd.conf
      
      ./etcd/ssl:
      ca.pem  server-key.pem  server.pem
      
      # 2. 查看etcd.service 
      [xy@worker-etcd-135 ~/k8s 23:18:35]$ cat etcd.service
      [Unit]
      Description=Etcd Server
      After=network.target
      After=network-online.target
      Wants=network-online.target
      
      [Service]
      Type=notify
      EnvironmentFile=/opt/etcd/cfg/etcd.conf
      ExecStart=/opt/etcd/bin/etcd \
              --name=${ETCD_NAME} \
              --data-dir=${ETCD_DATA_DIR} \
              --listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
              --listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
              --advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \
              --initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
              --initial-cluster=${ETCD_INITIAL_CLUSTER} \
              --initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \
              --initial-cluster-state=new \
              --cert-file=/opt/etcd/ssl/server.pem \
              --key-file=/opt/etcd/ssl/server-key.pem \
              --peer-cert-file=/opt/etcd/ssl/server.pem \
              --peer-key-file=/opt/etcd/ssl/server-key.pem \
              --trusted-ca-file=/opt/etcd/ssl/ca.pem \
              --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem
      Restart=on-failure
      LimitNOFILE=65536
      
      [Install]
      WantedBy=multi-user.target
      
      # 3. 把etcd.service复制到/usr/lib/systemd/system/目录下
      sudo cp etcd.service /usr/lib/systemd/system/
      
      # 4. 由2中的service配置决定,把etcd目录以及子目录、文件全部复制到 /opt目录下
      sudo cp -fr ./etcd /opt/
      
      # 5. 修改 /opt/etcd/cfg/etcd.conf文件
      #[Member]
      #etcd名字,唯一
      ETCD_NAME="etcd-1"
      #数据存储目录
      ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
      #etcd本机与其他etcd服务器通信端口
      ETCD_LISTEN_PEER_URLS="https://192.168.31.61:2380"
      #本机与master api-server通信端口
      ETCD_LISTEN_CLIENT_URLS="https://192.168.31.61:2379"
      
      #[Clustering]
      ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.31.61:2380"
      ETCD_ADVERTISE_CLIENT_URLS="https://192.168.31.61:2379"
      #所有集群etcd,注意名字、IP、etcd通信端口
      ETCD_INITIAL_CLUSTER="etcd-1=https://192.168.31.61:2380,etcd-2=https://192.168.31.62:2380,etcd-3=https://192.168.31.63:2380"
      #所有集群都要相同token
      ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
      ETCD_INITIAL_CLUSTER_STATE="new"
      
      # 6. 把之前生成的证书复制到/opt/etcd/ssl/目录下
      sudo cp *.pem /opt/etcd/ssl/
      
      # 7. 启动etcd并设置开机自启
      sudo systemctl start etcd
      sudo systemctl enable etcd
      
      # 8. 所有etcd服务器都设置、启动完毕之后,进行检查
      vim test-etcd.sh
      [xy@worker-etcd-135 ~/k8s 23:31:11]$ cat test-etcd.sh
      /opt/etcd/bin/etcdctl \
                      --ca-file=/opt/etcd/ssl/ca.pem \
                      --cert-file=/opt/etcd/ssl/server.pem \
                      --key-file=/opt/etcd/ssl/server-key.pem \
                      --endpoints="https://192.168.11.133:2379, \
                      https://192.168.11.134:2379, \
                      https://192.168.11.135:2379" \
                      cluster-health 
      # 出现如下结果表示OK
      [xy@worker-etcd-135 ~/k8s 23:33:29]$ sudo ./test-etcd.sh
      [sudo] xy 的密码:
      member 33ceecf846d01472 is healthy: got healthy result from https://192.168.11.133:2379
      member 614223a3a4feca74 is healthy: got healthy result from https://192.168.11.135:2379
      member ec7bd6dfa6720360 is healthy: got healthy result from https://192.168.11.134:2379
      cluster is healthy
      
      
      
      • 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
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
    6. 给API-SERVER生成证书

      在master上进行

      # 1.修改server-csr.json
      [xy@master-130 ~/k8s-files/ca/TLS/k8s 00:48:36]$ ls
      ca-config.json  ca-csr.json  generate_k8s_cert.sh  kube-proxy-csr.json  server-csr.json
      [xy@master-130 ~/k8s-files/ca/TLS/k8s 00:48:37]$ cat server-csr.json
      {
          "CN": "kubernetes",
          "hosts": [
            "10.0.0.1",
            "127.0.0.1",
            "kubernetes",
            "kubernetes.default",
            "kubernetes.default.svc",
            "kubernetes.default.svc.cluster",
            "kubernetes.default.svc.cluster.local",
            "192.168.11.130"
          ],
          "key": {
              "algo": "rsa",
              "size": 2048
          },
          "names": [
              {
                  "C": "CN",
                  "L": "BeiJing",
                  "ST": "BeiJing",
                  "O": "k8s",
                  "OU": "System"
              }
          ]
      }
      # 2. 生成证书
      [xy@master-130 ~/k8s-files/ca/TLS/k8s 00:49:18]$ ./generate_k8s_cert.sh
      2020/10/18 00:49:36 [INFO] generating a new CA key and certificate from CSR
      2020/10/18 00:49:36 [INFO] generate received request
      2020/10/18 00:49:36 [INFO] received CSR
      2020/10/18 00:49:36 [INFO] generating key: rsa-2048
      2020/10/18 00:49:37 [INFO] encoded CSR
      2020/10/18 00:49:37 [INFO] signed certificate with serial number 
      ···
      ···
      [xy@master-130 ~/k8s-files/ca/TLS/k8s 00:49:38]$ ls
      ca-config.json  ca-csr.json  ca.pem                kube-proxy.csr       kube-proxy-key.pem  server.csr       server-key.pem
      ca.csr          ca-key.pem   generate_k8s_cert.sh  kube-proxy-csr.json  kube-proxy.pem      server-csr.json  server.pem
      [xy@master-130 ~/k8s-files/ca/TLS/k8s 00:49:43]$
      
      • 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
    7. 安装master

      这一步骤在master服务器上操作,用到k8s-master.tar.gz包

      一定要注意api-server和etcd证书路径

      # 1. 解压
      tar -zxvf k8s-master.tar.gz -C k8s-master
      [xy@master-130 ~/k8s-files/k8s-master 00:51:48]$ ls
      kube-apiserver.service  kube-controller-manager.service  kubernetes  kube-scheduler.service
      
      # 2. 复制3个service到/usr/lib/systemd/system/目录下
      sudo cp kube-*.service /usr/lib/systemd/system/
      
      # 3. 复制kubernetes文件到/opt目录下
      sudo cp ./kubernetes /opt
      
      # 4. 修改api-server配置文件
      [xy@master-130 ~/k8s-files/k8s-master 00:58:00]$ sudo vim /opt/kubernetes/cfg/kube-apiserver.conf
      KUBE_APISERVER_OPTS="--logtostderr=false \
      --v=2 \
      --log-dir=/opt/kubernetes/logs \
      --etcd-servers=https://192.168.11.133:2379,https://192.168.11.134:2379,https://192.168.11.135:2379 \
      --bind-address=192.168.11.130 \
      --secure-port=6443 \
      --advertise-address=192.168.11.130 \
      --allow-privileged=true \
      --service-cluster-ip-range=10.0.0.0/24 \
      --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \
      --authorization-mode=RBAC,Node \
      --enable-bootstrap-token-auth=true \
      --token-auth-file=/opt/kubernetes/cfg/token.csv \
      --service-node-port-range=30000-32767 \
      --kubelet-client-certificate=/opt/kubernetes/ssl/server.pem \
      --kubelet-client-key=/opt/kubernetes/ssl/server-key.pem \
      --tls-cert-file=/opt/kubernetes/ssl/server.pem  \
      --tls-private-key-file=/opt/kubernetes/ssl/server-key.pem \
      --client-ca-file=/opt/kubernetes/ssl/ca.pem \
      --service-account-key-file=/opt/kubernetes/ssl/ca-key.pem \
      --etcd-cafile=/opt/etcd/ssl/ca.pem \
      --etcd-certfile=/opt/etcd/ssl/server.pem \
      --etcd-keyfile=/opt/etcd/ssl/server-key.pem \
      --audit-log-maxage=30 \
      --audit-log-maxbackup=3 \
      --audit-log-maxsize=100 \
      --audit-log-path=/opt/kubernetes/logs/k8s-audit.log"
      
      # 5. 复制前面一步生成的api-server需要的证书,还有复制之前etcd的证书
      #注意:这个是api-server证书
      sudo cp ca*.pem server*.pem /opt/kubernetes/ssl/
      #注意:这个是etcd的证书
      sudo cp ca*.pem server*.pem /opt/etcd/ssl/
      
      # 6. 启动api-server controller scheduler并设置开机自启
      [xy@master-130 ~/k8s-files 01:06:25]$ sudo systemctl start kube-apiserver
      [xy@master-130 ~/k8s-files 01:07:08]$ sudo systemctl start kube-controller-manager
      [xy@master-130 ~/k8s-files 01:07:22]$ sudo systemctl start kube-scheduler
      [xy@master-130 ~/k8s-files 01:07:36]$ sudo systemctl enable kube-apiserver
      Created symlink from /etc/systemd/system/multi-user.target.wants/kube-apiserver.service to /usr/lib/systemd/system/kube-apiserver.service.
      [xy@master-130 ~/k8s-files 01:07:56]$ sudo systemctl enable kube-controller-manager
      Created symlink from /etc/systemd/system/multi-user.target.wants/kube-controller-manager.service to /usr/lib/systemd/system/kube-controller-manager.service.
      [xy@master-130 ~/k8s-files 01:08:07]$ sudo systemctl enable kube-scheduler
      Created symlink from /etc/systemd/system/multi-user.target.wants/kube-scheduler.service to /usr/lib/systemd/system/kube-scheduler.service.
      [xy@master-130 ~/k8s-files 01:08:20]$
      
      
      # 7. 检查是否启动成功 ,很遗憾,我这里出错了
      sudo ps -aux|grep kube
      #或者
      sudo cp /opt/kubernetes/bin/kubectl /bin
      sudo kubectl get cs
      
      
      
      • 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
    8. 安装worker组件

      这一步骤在worker上做,用到k8s-node.tar.gz包

      1. 二进制文件安装docker

        # 1. 解压k8s-node包到worker,里面有个docker压缩包
        [xy@worker-etcd-133 ~/k8s/worker 22:21:02]$ ls
        cni-plugins-linux-amd64-v0.8.2.tgz  docker  k8s-node.tar.gz  kubelet.service  kube-proxy.service  kubernetes
        
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:21:14]$ ls
        daemon.json  docker-18.09.6.tgz  docker.service
        
        # 2. 解压docker-18.09包
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:25:36]$ tar -zxvf docker-18.09.6.tgz
        docker/
        docker/docker
        docker/docker-init
        docker/ctr
        docker/docker-proxy
        docker/runc
        docker/containerd
        docker/dockerd
        docker/containerd-shim
        
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:25:47]$ ls
        docker  docker-18.09.6.tgz  docker.service
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:25:56]$ ls -R
        .:
        docker  docker-18.09.6.tgz  docker.service
        ./docker:
        containerd  containerd-shim  ctr  docker  dockerd  docker-init  docker-proxy  runc
        
        # 3. 由docker.service脚本文件决定,先把docker.service放入sytem目录,再把docker18.09的二进制文件复制到/usr/bin/
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:25:21]$ cat docker.service
        [Unit]
        Description=Docker Application Container Engine
        Documentation=https://docs.docker.com
        After=network-online.target firewalld.service containerd.service
        Wants=network-online.target
        
        [Service]
        Type=notify
        ExecStart=/usr/bin/dockerd
        ExecReload=/bin/kill -s HUP $MAINPID
        TimeoutSec=0
        RestartSec=2
        Restart=always
        StartLimitBurst=3
        StartLimitInterval=60s
        LimitNOFILE=infinity
        LimitNPROC=infinity
        LimitCORE=infinity
        TasksMax=infinity
        Delegate=yes
        KillMode=process
        
        [Install]
        WantedBy=multi-user.target
        
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:26:48]$ sudo mv docker.service /usr/lib/systemd/system/
        [xy@worker-etcd-133 ~/k8s/worker/docker 22:27:19]$ sudo mv docker/* /usr/bin/
        
        # 4. 设置docker镜像加速,设置开机自动
        sudo mkdir -p /etc/docker
        sudo tee /etc/docker/daemon.json <<-'EOF'
        {
          "registry-mirrors": ["https://xxx.mirror.aliyuncs.com"]
        }
        EOF
        sudo systemctl daemon-reload
        sudo systemctl restart docker
        
        
        
        • 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
      2. 安装kubelet、kube-proxy、网络插件

        这一步主要在worker上操作

        # 1. 在上一步解压的包中,把kubelet.service/kube-proxy.service复制到/usr/lib/systemd/system/下
        # 移动kubernetes整个文件夹到/opt下
        sudo mv kube*.service /usr/lib/systemd/system/
        sudo mv kubernetes /opt/
        
        # 2. 配置kubelet/kube-proxy,配置2文件的apiserver ip,2文件hostname
        cd /opt/kubernetes
        
        # 3. 复制apiserver证书到ssl上
        
        # 4. 启动并设置开机自启kubelet、kube-proxy
        
        # 5. 查看tail -f /opt/kubernetes/logs/kubelet.INFO,出现以下就表示成功,即使日志有ERROR文件
        tail -f /opt/kubernetes/logs/kubelet.INFO
        I1019 23:27:40.423238    1965 feature_gate.go:216] feature gates: &{map[]}
        I1019 23:27:40.423309    1965 feature_gate.go:216] feature gates: &{map[]}
        I1019 23:27:40.934987    1965 mount_linux.go:168] Detected OS with systemd
        I1019 23:27:40.935123    1965 server.go:410] Version: v1.16.0
        I1019 23:27:40.935161    1965 feature_gate.go:216] feature gates: &{map[]}
        I1019 23:27:40.935203    1965 feature_gate.go:216] feature gates: &{map[]}
        I1019 23:27:40.935274    1965 plugins.go:100] No cloud provider specified.
        I1019 23:27:40.935286    1965 server.go:526] No cloud provider specified: "" from the config file: ""
        I1019 23:27:40.935314    1965 bootstrap.go:119] Using bootstrap kubeconfig to generate TLS client cert, key and kubeconfig file
        I1019 23:27:40.936837    1965 bootstrap.go:150] No valid private key and/or certificate found, reusing existing private key or creating a new one
        
        # 5. 接着到master上颁发证书
        [root@master-130 /home/xy/k8s-files/ca/TLS/k8s 23:28:30]# kubectl get csr
        NAME                                                   AGE     REQUESTOR           CONDITION
        node-csr-0NsTe5nCafOTVksuLTTDn442X4V2s90CnbEODBm0rAM   6m50s   kubelet-bootstrap   Pending
         root@master-130 /home/xy/k8s-files/ca/TLS/k8s 23:34:30]# kubectl certificate approve node-csr-0NsTe5nCafOTVksuLTTDn442X4V2s90CnbEODBm0rAM
         
        [root@master-130 /home/xy/k8s-files/ca/TLS/k8s 23:35:26]# kubectl get csr
        NAME                                                   AGE     REQUESTOR           CONDITION
        node-csr-0NsTe5nCafOTVksuLTTDn442X4V2s90CnbEODBm0rAM   7m53s   kubelet-bootstrap   Approved,Issued
        
        [root@master-130 /home/xy/k8s-files/ca/TLS/k8s 23:35:56]# kubectl get node
        NAME              STATUS     ROLES    AGE   VERSION
        worker-etcd-133   NotReady   <none>   66s   v1.16.0
        
        # 6. 安装网络插件cni,在worker上进行
        [xy@worker-etcd-133 ~/k8s/worker 23:45:29]$ tar -zxvf cni-plugins-linux-amd64-v0.8.2.tgz -C cni
        ./
        ./flannel
        ./ptp
        ./host-local
        ./firewall
        ./portmap
        ./tuning
        ./vlan
        ./host-device
        ./bandwidth
        ./sbr
        ./static
        ./dhcp
        ./ipvlan
        ./macvlan
        ./loopback
        ./bridge
        [xy@worker-etcd-133 ~/k8s/worker 23:45:33]$ ls
        cni  cni-plugins-linux-amd64-v0.8.2.tgz  k8s-node.tar.gz
        [xy@worker-etcd-133 ~/k8s/worker 23:45:34]$ cd cni
        [xy@worker-etcd-133 ~/k8s/worker/cni 23:45:37]$ ls
        bandwidth  bridge  dhcp  firewall  flannel  host-device  host-local  ipvlan  loopback  macvlan  portmap  ptp  sbr  static  tuning  vlan
        
        [root@worker-etcd-133 /home/xy/k8s/worker/cni 23:46:41]# mkdir -pv /opt/cni/bin /etc/cni/net.d
        mkdir: 已创建目录 "/opt/cni"
        mkdir: 已创建目录 "/opt/cni/bin"
        mkdir: 已创建目录 "/etc/cni"
        mkdir: 已创建目录 "/etc/cni/net.d"
        [root@worker-etcd-133 /home/xy/k8s/worker/cni 23:46:44]# cp * /opt/cni/bin/
        
        # 7. 接下来再到master上进行操作,时间插件安装
        kubectl apply -f kube-flannel.yml
        #查看每个node节点状态
        kubectl get nodes
        [xy@master-130 ~ 13:45:51]$ kubectl get nodes
        NAME              STATUS   ROLES    AGE    VERSION
        worker-etcd-133   Ready    <none>   14h    v1.16.0
        worker-etcd-134   Ready    <none>   143m   v1.16.0
        worker-etcd-135   Ready    <none>   37m    v1.16.0
        [xy@master-130 ~ 13:45:57]$ kubectl get node
        NAME              STATUS   ROLES    AGE    VERSION
        worker-etcd-133   Ready    <none>   14h    v1.16.0
        worker-etcd-134   Ready    <none>   144m   v1.16.0
        worker-etcd-135   Ready    <none>   38m    v1.16.0
        [xy@master-130 ~ 13:47:20]$ kubectl get node -n system-node
        NAME              STATUS   ROLES    AGE    VERSION
        worker-etcd-133   Ready    <none>   14h    v1.16.0
        worker-etcd-134   Ready    <none>   145m   v1.16.0
        worker-etcd-135   Ready    <none>   39m    v1.16.0
        [xy@master-130 ~ 13:48:00]$
        
        
        
        
        • 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
        • 83
        • 84
        • 85
        • 86
        • 87
        • 88
        • 89
        • 90
        • 91
        • 92
        • 93
        • 94
      3. 授权apiserver可以访问kubelet

        [xy@master-130 ~/k8s-files 13:52:43]$ sudo kubectl  apply -f apiserver-to-kubelet-rbac.yaml
        clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
        clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created
        
        
        • 1
        • 2
        • 3
        • 4
    9. 启动nginx容器

      这一步主要在master上做

      # 1. 先给所有worker拉取nginx镜像,这一步只要在worker上做
      sudo docker pull nginx:1.18.0
      # 也可以在一台主机上拉取,然后导出镜像,再传给其他服务器,节省时间
      sudo docker pull nginx:1.18.0
      sudo docker save nginx:1.18.0>~/nginx-1.18.0.tar.gz
      scp ~/nginx-1.18.0.tar.gz xxx@xxx:~
      sudo docker load i ~/nginx-1.18.0.tar.gz
      
      
      # 2. 然后部署镜像,这步在master上做
      kubectl create deployment nginx-1-18-0 --image=nginx:1.18.0
      #查看depoloyment
      kubectl get deployment 
      [xy@master-130 ~/k8s-files 16:14:26]$ kubectl get deployment
      NAME              READY   UP-TO-DATE   AVAILABLE   AGE
      my-nginx-1-18-0   1/1     1            1           11m
      
      #这时候会自动创建pod,可以查看pods
      kubectl get pods
      [xy@master-130 ~/k8s-files 16:21:57]$ kubectl get pods
      NAME                               READY   STATUS    RESTARTS   AGE
      my-nginx-1-18-0-67f4f6b779-m68k4   1/1     Running   0          12m
      
      # 3. 查看deployment或者pods具体信息,谷中
      kubectl describe deployment/pod $NAME
      
      # 4. 启动pod后暴露端口给外部
      kubectl expose deployment my-nginx-1-18-0 --port=80 --type=NodePort
      
      # 5. 查看暴露端口详细, 其他主机就能通过端口访问了
      kubectl get service
      
      # 6. 至此,集群可以用了
      
      
      
      • 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

    2、多master

    2、kubeadm方式

    5、安装coreDNS【重要】

    为什么要安装?因为挂掉的pod有其他pod替换,而新pod的ip一直变,为实现动态通信

    安装

    6、实现worker上管理集群

    步骤:

    1. 复制master的kubectl到worker上
    2. 生成管理员admin证书
    3. 生成kubeconfig证书
      1. 设置集群参数
      2. 设置客户端认证参数

    7、创建POD的yml文件编写【重点】

  • 相关阅读:
    电气滑环更换原因分析
    番茄插件番茄助手下载
    Linux 基础命令&进阶
    ffmpeg视频处理常用命令
    特殊矩阵:零矩阵(Zero)幺矩阵(Ones)单位矩阵(Identity)随机矩阵(Random)#matlab
    Leetcode刷题详解——被围绕的区域
    Golang 单元测试合集整理,(我最常用 gomonkey)欢迎收藏
    Spring Boot EasyPOI 使用指定模板导出Excel
    prometheus/grafana监控数据收集与展示——k8s从入门到高并发系列教程(九)
    Gradle学习第一篇——自定义Gradle插件
  • 原文地址:https://blog.csdn.net/Hatakefiftyfifty/article/details/125436227