一,Kubernetes基础入门

1.基础知识

  1. ![module_01.f6dc9f93.svg](https://cdn.nlark.com/yuque/0/2021/svg/12610368/1627611673137-ed7fd8d6-bb01-4d9f-9145-0ee59121e2db.svg#align=left&display=inline&height=150&margin=%5Bobject%20Object%5D&name=module_01.f6dc9f93.svg&originHeight=150&originWidth=263&size=2329&status=done&style=none&width=263)<br />以上展示了一个master(主节点)和6个worker(工作节点)的k8s集群
  2. ![module_01_cluster.8f54b2c5.svg](https://cdn.nlark.com/yuque/0/2021/svg/12610368/1627611775170-6957690d-2ad7-4bb0-9364-014e404ca31a.svg#align=left&display=inline&height=385&margin=%5Bobject%20Object%5D&name=module_01_cluster.8f54b2c5.svg&originHeight=385&originWidth=476&size=41817&status=done&style=none&width=476)

docker是每一个worker节点的运行时环境。

kubelet负责控制所有容器的启动停止,保证节点工作正常,已经帮助节点交互master。

2.部署一个应用

  1. # kubectl create 帮我们创建k8s集群中的一些对象
  2. kubectl create --help
  3. #Create a deployment named my-nginx that runs the nginx image
  4. kubectl create deployment my-nginx --image=nginx
  5. # Create a deployment with command
  6. kubectl create deployment my-nginx --image=nginx -- date
  7. # Create a deployment named my-nginx that runs the nginx image with 3 replicas.
  8. kubectl create deployment my-nginx --image=nginx --replicas=3
  9. # Create a deployment named my-nginx that runs the nginx image and expose port 80.
  10. kubectl create deployment my-nginx --image=nginx --port=80

Deployment(部署)

  • 在k8s中,通过发布 Deployment,可以创建应用程序 (docker image) 的实例 (docker container),这个实例会被包含在称为 Pod 的概念中,Pod 是 k8s 中最小可管理单元。
  • 在 k8s 集群中发布 Deployment 后,Deployment 将指示 k8s 如何创建和更新应用程序的实例,master 节点将应用程序实例调度到集群中的具体的节点上。
  • 创建应用程序实例后,Kubernetes Deployment Controller 会持续监控这些实例。如果运行实例的 worker 节点关机或被删除,则 Kubernetes Deployment Controller 将在群集中资源最优的另一个 worker 节点上重新创建一个新的实例。这提供了一种自我修复机制来解决机器故障或维护问题。
  • 在容器编排之前的时代,各种安装脚本通常用于启动应用程序,但是不能够使应用程序从机器故障中恢复。通过创建应用程序实例并确保它们在集群节点中的运行实例个数,Kubernetes Deployment 提供了一种完全不同的方式来管理应用程序。
  • Deployment 处于 master 节点上,通过发布 Deployment,master 节点会选择合适的 worker 节点创建 Container(即图中的正方体),Container 会被包含在 Pod (即蓝色圆圈)里。
  1. ![module_02_first_app.svg](https://cdn.nlark.com/yuque/0/2021/svg/12610368/1627611883216-e3c10166-7c6d-43a3-a0a6-8279d820798a.svg#align=left&display=inline&height=385&margin=%5Bobject%20Object%5D&name=module_02_first_app.svg&originHeight=385&originWidth=476&size=33030&status=done&style=none&width=476)

3.应用程序探索

  • 了解Kubernetes Pods(容器组)
  • 了解Kubernetes Nodes(节点)
  • 排查故障

创建 Deployment 后,k8s创建了一个 Pod(容器组) 来放置应用程序实例(container 容器)。

image.png

3.1、了解Pod

Pod (容器组) 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。这些资源包括:

  • 共享存储,称为卷(Volumes),即图上紫色圆柱
  • 网络,每个 Pod(容器组)在集群中有个唯一的 IP,pod(容器组)中的 container(容器)共享该IP地址
  • container(容器)的基本信息,例如容器的镜像版本,对外暴露的端口等

Pod(容器组)是 k8s 集群上的最基本的单元。当我们在 k8s 上创建 Deployment 时,会在集群上创建包含容器的 Pod (而不是直接创建容器)。每个Pod都与运行它的 worker 节点(Node)绑定,并保持在那里直到终止或被删除。如果节点(Node)发生故障,则会在群集中的其他可用节点(Node)上运行相同的 Pod(从同样的镜像创建 Container,使用同样的配置,IP 地址不同,Pod 名字不同)。

TIP 重要:

  • Pod 是一组容器(可包含一个或多个应用程序容器),以及共享存储(卷 Volumes)、IP 地址和有关如何运行容器的信息。
  • 如果多个容器紧密耦合并且需要共享磁盘等资源,则他们应该被部署在同一个Pod(容器组)中。

3.2、了解Node

Pod(容器组)总是在 Node(节点) 上运行。Node(节点)是 kubernetes 集群中的计算机,可以是虚拟机或物理机。每个 Node(节点)都由 master 管理。一个 Node(节点)可以有多个Pod(容器组),kubernetes master 会根据每个 Node(节点)上可用资源的情况,自动调度 Pod(容器组)到最佳的 Node(节点)上。

每个 Kubernetes Node(节点)至少运行:

  • Kubelet,负责 master 节点和 worker 节点之间通信的进程;管理 Pod(容器组)和 Pod(容器组)内运行的 Container(容器)。
  • kube-proxy,负责进行流量转发
  • 容器运行环境(如Docker)负责下载镜像、创建和运行容器等。

image.png

3.3、故障排除

  • kubectl get - 显示资源列表 ```sh

    kubectl get 资源类型

获取类型为Deployment的资源列表

kubectl get deployments

获取类型为Pod的资源列表

kubectl get pods

获取类型为Node的资源列表

kubectl get nodes

  1. ```sh
  2. # 查看所有名称空间的 Deployment
  3. kubectl get deployments -A
  4. kubectl get deployments --all-namespaces
  5. # 查看 kube-system 名称空间的 Deployment
  6. kubectl get deployments -n kube-system
  1. #####并不是所有的对象都在名称空间中
  2. # 在名称空间里
  3. kubectl api-resources --namespaced=true
  4. # 不在名称空间里
  5. kubectl api-resources --namespaced=false
  • kubectl describe - 显示有关资源的详细信息 ```sh

    kubectl describe 资源类型 资源名称

查看名称为nginx-XXXXXX的Pod的信息

kubectl describe pod nginx-XXXXXX

查看名称为nginx的Deployment的信息

kubectl describe deployment my-nginx

  1. - **kubectl logs** - 查看pod中的容器的打印日志(和命令docker logs 类似)
  2. ```sh
  3. # kubectl logs Pod名称
  4. #查看名称为nginx-pod-XXXXXXX的Pod内的容器打印的日志
  5. #本案例中的 nginx-pod 没有输出日志,所以您看到的结果是空的
  6. kubectl logs -f nginx-pod-XXXXXXX
  • kubectl exec - 在pod中的容器环境内执行命令(和命令docker exec 类似) ```sh

    kubectl exec Pod名称 操作命令

在名称为nginx-pod-xxxxxx的Pod中运行bash

kubectl exec -it nginx-pod-xxxxxx /bin/bash

注意:新版1.21.0 提示这个命令会过期

  1. <a name="2b792782"></a>
  2. ### 3.4、kubectl run
  3. 也可以独立跑一个Pod
  4. ```sh
  5. ## kubectl run --help
  6. kubectl run nginx --image=nginx

4、应用外部可见

4.1、目标

  • 了解 Kubernetes 中的 Service
  • 了解 标签(Label) 和 标签选择器(Label Selector) 对象如何与 Service 关联
  • 在 Kubernetes 集群外用 Service 暴露应用

4.2、Kubernetes Service 总览

  • Kubernetes Pod 是转瞬即逝的。
  • Pod 实际上拥有 生命周期。 当一个工作 Node 挂掉后, 在 Node 上运行的 Pod 也会消亡。
  • ReplicaSet 会自动地通过创建新的 Pod 驱动集群回到目标状态,以保证应用程序正常运行。
  • Kubernetes 的 Service 是一个抽象层,它定义了一组 Pod 的逻辑集,并为这些 Pod 支持外部流量暴露、负载平衡和服务发现。
    • Service 使从属 Pod 之间的松耦合成为可能。 和其他 Kubernetes 对象一样, Service 用 YAML (更推荐) 或者 JSON 来定义. Service 下的一组 Pod 通常由 LabelSelector (请参阅下面的说明为什么您可能想要一个 spec 中不包含selector的服务)来标记。
    • 尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service ,这些 IP 不会暴露在群集外部。Service 允许您的应用程序接收流量。Service 也可以用在 ServiceSpec 标记type的方式暴露
      • ClusterIP (默认) - 在集群的内部 IP 上公开 Service 。这种类型使得 Service 只能从集群内访问。
      • NodePort - 使用 NAT 在集群中每个选定 Node 的相同端口上公开 Service 。使用<NodeIP>:<NodePort> 从集群外部访问 Service。是 ClusterIP 的超集。
      • LoadBalancer - 在当前云中创建一个外部负载均衡器(如果支持的话),并为 Service 分配一个固定的外部IP。是 NodePort 的超集。
      • ExternalName - 通过返回带有该名称的 CNAME 记录,使用任意名称(由 spec 中的externalName指定)公开 Service。不使用代理。这种类型需要kube-dns的v1.7或更高版本。

4.3、Service 和 Label

  1. ![module_04_services.svg](https://cdn.nlark.com/yuque/0/2021/svg/12610368/1627612215677-cbe73b7b-963a-4a55-be61-0874d3c5d7cf.svg#align=left&display=inline&height=440&margin=%5Bobject%20Object%5D&name=module_04_services.svg&originHeight=440&originWidth=394&size=43362&status=done&style=none&width=394)

Service 通过一组 Pod 路由通信。Service 是一种抽象,它允许 Pod 死亡并在 Kubernetes 中复制,而不会影响应用程序。在依赖的 Pod (如应用程序中的前端和后端组件)之间进行发现和路由是由Kubernetes Service 处理的。

Service 匹配一组 Pod 是使用 标签(Label)和选择器(Selector), 它们是允许对 Kubernetes 中的对象进行逻辑操作的一种分组原语。标签(Label)是附加在对象上的键/值对,可以以多种方式使用:

  • 指定用于开发,测试和生产的对象
  • 嵌入版本标签
  • 使用 Label 将对象进行分类

module_04_labels.svg

4.4、kubectl expose

  1. kubectl expose deployment tomcat6 --port=8912 --target-port=8080 --type=NodePort
  2. ## --port:集群内访问service的端口 8912
  3. ## --target-port: pod容器的端口 8080
  4. ## --nodePort: 每个机器开发的端口 30403
  5. ## 进行验证
  6. kubectl get svc
  7. curl ip:port
  8. ## kubectl exec 进去pod修改,并测试负载均衡

5、伸缩应用程序-扩缩容

目标

  • 用 kubectl 扩缩应用程序
  • 扩缩一个 Deployment

我们创建了一个 Deployment ,然后通过 服务提供访问 Pod 的方式。我们发布的 Deployment 只创建了一个 Pod 来运行我们的应用程序。当流量增加时,我们需要对应用程序进行伸缩操作以满足系统性能需求。

1619086037936.png

  1. ## 扩展
  2. kubectl scale --replicas=3 deployment tomcat6
  3. #持续观测效果
  4. watch kubectl get pods -o wide

6、执行滚动升级

目标

  • 使用 kubectl 执行滚动更新

滚动更新允许通过使用新的实例逐步更新 Pod 实例从而实现 Deployments 更新,停机时间为零。

与应用程序扩展类似,如果暴露了 Deployment,服务(Service)将在更新期间仅对可用的 pod 进行负载均衡。可用 Pod 是应用程序用户可用的实例。

滚动更新允许以下操作:

  • 将应用程序从一个环境提升到另一个环境(通过容器镜像更新)
  • 回滚到以前的版本
  • 持续集成和持续交付应用程序,无需停机

image.png

image.png
image.png

image.png

  1. #应用升级: tomcat:alpine、tomcat:jre8-alpine
  2. kubectl set image deployment.apps/tomcat6 tomcat=tomcat:jre8-alpine #可以携带--record参数,记录变更
  3. ##回滚升级
  4. ### 查看历史记录
  5. kubectl rollout history deployment.apps/tomcat6
  6. kubectl rollout history deploy tomcat6
  7. ### 回滚到指定版本
  8. kubectl rollout undo deployment.apps/tomcat6 --to-revision=1
  9. kubectl rollout undo deploy tomcat6 --to-revision=1

7、以上用配置文件方式

1、部署一个应用

  1. apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
  2. kind: Deployment #该配置的类型,我们使用的是 Deployment
  3. metadata: #译名为元数据,即 Deployment 的一些基本属性和信息
  4. name: nginx-deployment #Deployment 的名称
  5. labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组,目前不需要理解
  6. app: nginx #为该Deployment设置key为app,value为nginx的标签
  7. spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
  8. replicas: 1 #使用该Deployment创建一个应用程序实例
  9. selector: #标签选择器,与上面的标签共同作用,目前不需要理解
  10. matchLabels: #选择包含标签app:nginx的资源
  11. app: nginx
  12. template: #这是选择或创建的Pod的模板
  13. metadata: #Pod的元数据
  14. labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod
  15. app: nginx
  16. spec: #期望Pod实现的功能(即在pod中部署)
  17. containers: #生成container,与docker中的container是同一种
  18. - name: nginx #container的名称
  19. image: nginx:1.7.9 #使用镜像nginx:1.7.9创建container,该container默认80端口可访问

kubectl apply -f xxx.yaml

2、暴露应用

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: nginx-service #Service 的名称
  5. labels: #Service 自己的标签
  6. app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签
  7. spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问
  8. selector: #标签选择器
  9. app: nginx #选择包含标签 app:nginx 的 Pod
  10. ports:
  11. - name: nginx-port #端口的名字
  12. protocol: TCP #协议类型 TCP/UDP
  13. port: 80 #集群内的其他容器组可通过 80 端口访问 Service
  14. nodePort: 32600 #通过任意节点的 32600 端口访问 Service
  15. targetPort: 80 #将请求转发到匹配 Pod 的 80 端口
  16. type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer

3、扩缩容

修改deployment.yaml 中的 replicas 属性即可

完成后运行 kubectl apply -f xxx.yaml

4、滚动升级

修改deployment.yaml 中的 imageName 属性等

完成后运行 kubectl apply -f xxx.yaml

以上都可以直接 kubectl edit deploy/service 等,修改完成后自动生效

二、其他

1、查看Kubernetes适配的docker版本

[https://github.com/kubernetes/kubernetes/releases](https://github.com/kubernetes/kubernetes/releases) 查看他的changelog,搜索适配的docker版本即可。

2、弃用dockershim的问题

[https://kubernetes.io/zh/blog/2020/12/02/dockershim-faq/](https://kubernetes.io/zh/blog/2020/12/02/dockershim-faq/)

  • 使用containerd:``[https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#containerd](https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#containerd)
  • 配置docker:[https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#docker](https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#docker)

    3、部署dashboard

    [https://github.com/kubernetes/dashboard](https://github.com/kubernetes/dashboard)
    type: NodePort
    #访问测试
    每次访问都需要令牌
    kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

    4、master初始化的日志

  1. [root@i-iqrlgkwc ~]# kubeadm init \
  2. > --apiserver-advertise-address=10.170.11.8 \
  3. > --image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \
  4. > --kubernetes-version v1.21.0 \
  5. > --service-cidr=10.96.0.0/16 \
  6. > --pod-network-cidr=192.168.0.0/16
  7. [init] Using Kubernetes version: v1.21.0
  8. [preflight] Running pre-flight checks
  9. [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
  10. [preflight] Pulling images required for setting up a Kubernetes cluster
  11. [preflight] This might take a minute or two, depending on the speed of your internet connection
  12. [preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
  13. [certs] Using certificateDir folder "/etc/kubernetes/pki"
  14. [certs] Generating "ca" certificate and key
  15. [certs] Generating "apiserver" certificate and key
  16. [certs] apiserver serving cert is signed for DNS names [k8s-01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.170.11.8]
  17. [certs] Generating "apiserver-kubelet-client" certificate and key
  18. [certs] Generating "front-proxy-ca" certificate and key
  19. [certs] Generating "front-proxy-client" certificate and key
  20. [certs] Generating "etcd/ca" certificate and key
  21. [certs] Generating "etcd/server" certificate and key
  22. [certs] etcd/server serving cert is signed for DNS names [k8s-01 localhost] and IPs [10.170.11.8 127.0.0.1 ::1]
  23. [certs] Generating "etcd/peer" certificate and key
  24. [certs] etcd/peer serving cert is signed for DNS names [k8s-01 localhost] and IPs [10.170.11.8 127.0.0.1 ::1]
  25. [certs] Generating "etcd/healthcheck-client" certificate and key
  26. [certs] Generating "apiserver-etcd-client" certificate and key
  27. [certs] Generating "sa" key and public key
  28. [kubeconfig] Using kubeconfig folder "/etc/kubernetes"
  29. [kubeconfig] Writing "admin.conf" kubeconfig file
  30. [kubeconfig] Writing "kubelet.conf" kubeconfig file
  31. [kubeconfig] Writing "controller-manager.conf" kubeconfig file
  32. [kubeconfig] Writing "scheduler.conf" kubeconfig file
  33. [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
  34. [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
  35. [kubelet-start] Starting the kubelet
  36. [control-plane] Using manifest folder "/etc/kubernetes/manifests"
  37. [control-plane] Creating static Pod manifest for "kube-apiserver"
  38. [control-plane] Creating static Pod manifest for "kube-controller-manager"
  39. [control-plane] Creating static Pod manifest for "kube-scheduler"
  40. [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
  41. [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
  42. [kubelet-check] Initial timeout of 40s passed.
  43. [apiclient] All control plane components are healthy after 66.504822 seconds
  44. [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
  45. [kubelet] Creating a ConfigMap "kubelet-config-1.21" in namespace kube-system with the configuration for the kubelets in the cluster
  46. [upload-certs] Skipping phase. Please see --upload-certs
  47. [mark-control-plane] Marking the node k8s-01 as control-plane by adding the labels: [node-role.kubernetes.io/master(deprecated) node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
  48. [mark-control-plane] Marking the node k8s-01 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
  49. [bootstrap-token] Using token: os234q.tqr5fxmvapgu0b71
  50. [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
  51. [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
  52. [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
  53. [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
  54. [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
  55. [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
  56. [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
  57. [addons] Applied essential addon: CoreDNS
  58. [addons] Applied essential addon: kube-proxy
  59. Your Kubernetes control-plane has initialized successfully!
  60. To start using your cluster, you need to run the following as a regular user:
  61. mkdir -p $HOME/.kube
  62. sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  63. sudo chown $(id -u):$(id -g) $HOME/.kube/config
  64. Alternatively, if you are the root user, you can run:
  65. export KUBECONFIG=/etc/kubernetes/admin.conf
  66. You should now deploy a pod network to the cluster.
  67. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  68. https://kubernetes.io/docs/concepts/cluster-administration/addons/
  69. Then you can join any number of worker nodes by running the following on each as root:
  70. kubeadm join 10.170.11.8:6443 --token os234q.tqr5fxmvapgu0b71 \
  71. --discovery-token-ca-cert-hash sha256:68251032e1f77a7356e784bdeb8e1f7f728cb0fb31c258dc7b44befc9f516f85