K8S 入门,本地虚拟机搭建集群,实践灰度发布功能

2023年 10月 13日 62.2k 0

00069-2222109924-(masterpiece_1.2),(best quality_1.2),detailed,(high quality, highres_1.2),absurdres,HDR,8k uhd,(realistic_1.1),(close shot_1.2),.png

入门

使用 minikube

Minikube 是一种轻量级的Kubernetes 实现,可在本地计算机上创建VM 并部署仅包含一个节点的简单集群。

推荐先使用 minikube 单机体验基本功能, kubernetes.io/zh-cn/docs/… ,后面调试时仍然需要使用 minikube 来对比理解。

安装 minikube 后

minicube start
minikube dashboard 
//Opening http://127.0.0.1:51200/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...
// 端口随机

对minikube 初始化的 dashboard , 不用处理权限问题和登录,直接打开使用。如果裸机搭建,一上来这个 dashboard 的权限登录配置会极其复杂劝退。

image.png

页面主要是对各种类的 resource 的增删改查,命令不熟悉时很有帮助。

image.png

准备 docker 镜像

本处创建阿里云的镜像用于调试

// 两个版本,用于测试更新
registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v1
registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v2

简单 node 服务,8080端口,http 输出当前节点 ip 和 hostname,v2 会显示 v2


index page / index page v2

IP lo10.244.0.158, hostname: test-k8s-5cc7cf6cf9-8d84m

部署服务

创建 namespace,方便管理和清理

kubectl create namespace test 

如果系统方便安装 kubectx , 可安装后 kubens test 切换 namespace ,不方便安装则后续命令加上 -n test 指定 namespace 为 test。

本地创建 yaml 配置文件,用于 kubectl apply -f file.yaml 启动,等同于命令行创建。

appV1.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test-k8s
  # 部署名字
  name: test-k8s
spec:
  replicas: 3
  # 用来查找关联的 Pod,所有标签都匹配才行
  selector:
    matchLabels:
      app: test-k8s
  # 定义 Pod 相关数据
  template:
    metadata:
      labels:
        app: test-k8s
    spec:
      # 定义容器,可以多个
      containers:
        - name: test-k8s # 容器名字
          image: registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v1 # 镜像

从下往上看:

  • 单个 pod 是 k8s 部署的最小单元,包含一个或多个 container,代表一个应用。比如 wordpress docker 部署,单个部署就会有 wordpress+mysql 两个 containers。
  • pod 有 metadata,用于给上级抽象集合 selector,然后集群操作
  • replicas: 3 会创建一个 ReplicaSet 集合,它包含相同的 pods。 这里就是创建了 3个 一样的pod,包含在一个 ReplicaSet 里。
  • 最上面,创建一个 Deployment ,指向创建的 ReplicaSet

kubectl 创建

kubectl apply -f ./yaml/deploy/appv1.yaml -n test

在 dashboard 找到单个 Deployment , 点进去下拉找到指向的 ReplicaSet,点进去下拉找到创建的 3个 pod 。

image.png

访问 minikube 网络

minikube 跑在 docker 里,存在网络隔离。有两种方式访问 minikube 网络:

  • minikube ssh ,进到容器 bash
  • minikube tunnel

这里使用 minikube ssh,尝试访问单个 pod ,dashboard 进入某一个pod的详情。
image.png

在 minikube ssh 进入bash后 curl pod 的 ip 地址,可以访问到单个 pod。
image.png

创建 Service

Service API 是 Kubernetes 的组成部分,它是一种抽象,帮助你将 Pod 集合在网络上公开出去。 每个 Service 对象定义端点的一个逻辑集合(通常这些端点就是 Pod)以及如何访问到这些 Pod 的策略。

创建 service.yaml

apiVersion: v1
kind: Service
metadata:
  name: deploy-service
spec:
  selector:
  # 找有本属性的 pods
    app: test-k8s
  #  ClusterIP 集群内可访问,NodePort 节点可访问,LoadBalancer 负载均衡模式(需要负载均衡器才可用)
  type: NodePort
  ports:
    - port: 8080 # 本 Service 的端口
      targetPort: 8080 # 容器端口
      nodePort: 31123 # 节点端口,范围固定 30000 ~ 32767

kubectl apply -f ./yaml/deploy/service.yaml -n test
kubectl get svc -n test

image.png

在 minikube ssh 里可以curl 到 servcie 暴露的服务,并且有负载均衡,可以看到均匀打到 166,167,168 三个 pod 上。
image.png

也可用 minikube service 自动打开页面,浏览器访问体验。

minikube service deploy-service -n test  

创建 Ingress 体验灰度发布

先创建新的使用 v2 img 的 deployment 和 service ,创建单文件 appServiceV2.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test-k8s-v2
  # 部署名字
  name: test-k8s-v2
spec:
  replicas: 3
  # 用来查找关联的 Pod,所有标签都匹配才行
  selector:
    matchLabels:
      app: test-k8s-v2
  # 定义 Pod 相关数据
  template:
    metadata:
      labels:
        app: test-k8s-v2
    spec:
      # 定义容器,可以多个
      containers:
        - name: test-k8s-v2 # 容器名字
          image: registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v2 # 镜像
---
apiVersion: v1
kind: Service
metadata:
  name: test-k8s-v2
spec:
  selector:
    app: test-k8s-v2
  # 默认 ClusterIP 集群内可访问,NodePort 节点可访问,LoadBalancer 负载均衡模式(需要负载均衡器才可用)
  type: NodePort
  ports:
    - port: 8080 # 本 Service 的端口
      targetPort: 8080 # 容器端口
      nodePort: 32000 # 节点端口,范围固定 30000 ~ 32767
kubectl apply -f ./yaml/deploy/appServiceV2.yaml -n test
kubectl get svc -n test

此时有两个 service , 分别是 v1 和 v2。
image.png

测试一下 v2 的 service

minikube service test-k8s-v2 -n test  
// 自动打开浏览器页面

本地体验,浏览器多刷新几次 tab , 可以看到均匀打到不同的 IP (pod) 上,且页面显示 v2。

此时,已有 v1 v2 两个稳定的 url 负载均衡打到各自的 pod 上。此时想要一个 canary 效果,页面一半流量 v1 一半v2,则本地起一个 nginx 也能实现。但 k8s 已经提供了这功能的封装,为 Ingress。

Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。
Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。

kubernetes.io/docs/tasks/…

先安装 ingress

minikube addons enable ingress

创建 ingress1.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: k8s-test
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: deploy-service #注意这 Service 名字
                port:
                  number: 8080

ingress2.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: k8s-test-v2-canary
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/canary: 'true' #启用灰度发布功能
    nginx.ingress.kubernetes.io/canary-weight: '50'
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: test-k8s-v2
                port:
                  number: 8080
kubectl apply -f ./yaml/deploy/ingress1.yaml -n test
kubectl apply -f ./yaml/deploy/ingress2.yaml -n test
kubectl get ingress -n test 

image.png

此时 ADDRESS 为 minikube ip 的值 192.168.58.2 (docker 内网地址,本机不可达),表示已经成功。并且 ingress 默认 80,443端口。
在 minikube ssh 进 bash 后多次 curl localhost (80)

image.png

可见均匀打到 v1 ,v2 ,而且也均匀打到各个 IP (pod) 上。达到我们预期的灰度发布效果,生产环境灰度发布效果也基本复现了。 (这里也可以 minikube tunnel 后浏览器访问 localhost 体验,注意解除本地 80 端口占用。)

最后清理现场 kubectl delete namespace test 即可。如果之前没创建 namespace ,则清理就不那么方便。而 k8s 这套性能占用其实挺高,我的私有云虚拟机完全遭不住,可以及时关闭。

裸机搭建

创建虚拟机

本人沿用了私有云的 ESXi 虚拟机系统,创建了3个 CentOS 7 虚拟机,每个至少 2c4g 以上。可以本地安装虚拟机,也可以考虑租云服务商集群。

image.png

创建集群

一般为了理解,多节点裸机集群在初次都推荐手动搭建。但实际上还是用 kubeadm init , 仍然是机械化的复制命令,在这被网络和系统配置卡住没啥意义,推荐使用一键脚本搭建:

github.com/lework/kain…

进入 192.168.31.153 终端,执行

export MASTER_NODES="192.168.31.153"
export WORKER_NODES="192.168.31.151,192.168.31.152"
export SSH_USER="root"
export SSH_PASSWORD="xxx"
export SSH_PORT="22"
export KUBE_VERSION="1.20.6"
bash kainstall-centos.sh init --version 1.24.8

Kubernetes 通过将容器放入在节点(Node)上运行的 Pod 中来执行你的工作负载。 节点可以是一个虚拟机或者物理机器,取决于所在的集群配置。 每个节点包含运行 Pod 所需的服务; 这些节点由控制面负责管理。

上文使用 minikube 为本机 docker 里的单节点。而实际上节点(node)定义符合一般网络用语,可以指单个机器。假如当前集群有两个 work node ,一个 deployment 希望创建四个 pod , 则这四个 pod 就会均匀部署在两个 Node (机器)上。

搭建完成后查看

kubectl get nodes

image.png

内网 IP 为

192.168.31.153 k8s-master-node1
192.168.31.151 k8s-worker-node1
192.168.31.152 k8s-worker-node2

使用 dashboard

脚本已经安装了 dashboard ,但 rbac 配置较为麻烦。

// 在master 192.168.31.153 使用 tmux ,使用 kubectl proxy
yum install tmux
tmux
//new session
kubectl proxy --address='0.0.0.0'  --accept-hosts='^*$' --port=8001
ctrl+b d 
//quit se

访问
http://192.168.31.153:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login

发现需要登录,且限制只能 https 或localhost 才能登录。这里给出绕过办法。

kubernetes.io/zh-cn/docs/…

安装dashboard 一般使用远程yaml ,如

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

把这个下载到本地,比如 dashboard.yaml ,搜索 'args' ,只有一处,加上两行

      containers:
        - name: kubernetes-dashboard
          image: kubernetesui/dashboard:v2.7.0
          imagePullPolicy: Always
          ports:
            - containerPort: 8443
              protocol: TCP
          args:
            - --auto-generate-certificates
            - --namespace=kubernetes-dashboard
            - --enable-skip-login #add
            - --disable-settings-authorizer #add

此时登录页面可以 skip , 但进去后没有任何数据权限。需要参考这个 issue
github.com/kubernetes/…

创建 admin.yaml , 复制上面评论中的配置,kubectl apply -f , 然后未登录 dashboard 可用。

image.png

部署服务

复用上文 minikube 示例中的 yaml 创建两个 deployment ,service 注意此时设备性能大概率远不如之前单机,可以把pod 数量设置的少些。

image.png

可以看到,单个 Service 指向的pod 分别在 node1 , node2 , 即两台不同的机器。
在 153 terminal 能直接连通两个 service ip

image.png

部署 Ingress

同是复用上文的 yaml , 创建灰度 Ingress,知道 nginx 在 192.168.31.151 这个 node 节点。

image.png

但此时 curl 192.168.31.151 无法连接,输入

kubectl get service -n ingress-nginx

image.png

ingress-nginx 没有 external-ip ,就使用 Cluster-ip 测试。多次 curl 10.96.103.254

image.png

可见均匀打到 v1 ,v2 ,而且也均匀打到各个 IP (pod) 上。且此时各 Pod 实际上分布在两台虚拟机中,符合预期。

此时 Nginx 在 node1 上,可以测试把 node2 关机,同时在 master 里持续 curl , 可以发现仍然可访问部署 node1 的 pod , 即容灾高可用。再将 node2 开机,集群恢复。

总结

还未搭建更复杂的场景,比如数据持久化,有状态的应用的部署。但经过上述折腾,我们已经对 k8s 中 pod ,deployment,service,ingress,node的概念非常清楚了,也成功搭建了集群并体验了灰度发布功能,可以说彻底解锁了 k8s 的技能树。今后系统推荐的相关文章都将会成为它的养分,持续成长,最终长成参天大树。

写文章本身也是一个学习的过程,也请读者能指出文章中的疏忽错漏之处。如果本文对你有所帮助,欢迎点赞收藏。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论