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

入门

使用 minikube

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

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

安装 minikube 后

ruby 复制代码
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 的权限登录配置会极其复杂劝退。

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

准备 docker 镜像

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

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

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

perl 复制代码
index page / index page v2

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

部署服务

创建 namespace,方便管理和清理

arduino 复制代码
kubectl create namespace test 

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

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

appV1.yaml

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 创建

bash 复制代码
kubectl apply -f ./yaml/deploy/appv1.yaml -n test

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

访问 minikube 网络

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

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

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

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

创建 Service

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

创建 service.yaml

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
bash 复制代码
kubectl apply -f ./yaml/deploy/service.yaml -n test
kubectl get svc -n test

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

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

js 复制代码
minikube service deploy-service -n test  

创建 Ingress 体验灰度发布

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

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
bash 复制代码
kubectl apply -f ./yaml/deploy/appServiceV2.yaml -n test
kubectl get svc -n test

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

测试一下 v2 的 service

js 复制代码
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

bash 复制代码
minikube addons enable ingress

创建 ingress1.yaml

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

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
bash 复制代码
kubectl apply -f ./yaml/deploy/ingress1.yaml -n test
kubectl apply -f ./yaml/deploy/ingress2.yaml -n test
kubectl get ingress -n test 

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

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

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

裸机搭建

创建虚拟机

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

创建集群

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

github.com/lework/kain...

进入 192.168.31.153 终端,执行

ini 复制代码
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 (机器)上。

搭建完成后查看

arduino 复制代码
kubectl get nodes

内网 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 配置较为麻烦。

scss 复制代码
// 在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 ,如

bash 复制代码
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml

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

yaml 复制代码
      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 可用。

部署服务

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

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

部署 Ingress

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

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

arduino 复制代码
kubectl get service -n ingress-nginx

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

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

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

总结

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

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

相关推荐
小湘西3 小时前
持续集成(Continuous Integration)
ci/cd
2401_858120536 小时前
Eureka服务下线机制解析:确保服务注册与发现的准确性
云原生·eureka
hay_lee6 小时前
一台docker机器如何实现构建多平台镜像
运维·docker·云原生·容器
爱煲汤的夏二7 小时前
CI脚本的python基础
java·python·ci/cd
The Straggling Crow7 小时前
k8s record 20240705
云原生·容器·kubernetes
lendq7 小时前
k8s-第九节-命名空间
linux·容器·kubernetes
文静小土豆7 小时前
K8S 部署 EFK
云原生·容器·kubernetes
喜欢猪猪7 小时前
Zookeeper底层原理
分布式·zookeeper·云原生
acro_0910 小时前
基于python 的动态虚拟主机
运维·服务器·云原生·apache
爱吃龙利鱼13 小时前
k8s学习--基于k8s的ELK日志收集的详细过程
运维·学习·elk·云原生·容器·kubernetes