K8S 集群架构

K8S 集群架构

 
master
主节点,控制平台,不需要很高性能,不跑任务,通常一个就行了,也可以开多个主节点来提高集群可用度
worker
工作节点,可以是虚拟机或物理计算机,任务都在这里跑,机器性能需要好点;通常都有很多个,可以不断加机器扩大集群;每个工作节点由主节点管理
重要概念 Pod
K8S 调度、管理的最小单位,一个 pod可以包含一个或多个容器,每个 Pod 有自己的虚拟 IP。一个工作节点可以有多个 pod,主节点会考量负载自动调度 pod 到哪个节点运行

部署应用到集群中

Deployment

创建一组 pod(由多个 Docker 容器组成) 的集合 Deployments | Kubernetes
 
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 # 镜像

 

Deployment 通过 label 关联起来 Pods

Service

定义不同 Deployment 之间访问的方方式以及外部访问 Deployment 的方式 服务(Service) | Kubernetes
 
apiVersion: v1
kind: Service
metadata:
  name: test-k8s
spec:
  selector:
    app: test-k8s
  type: ClusterIP
  ports:
    - port: 8080        # 本 Service 的端口
      targetPort: 8080  # 容器端口

 

服务的默认类型是ClusterIP,只能在集群内部访问,我们可以进入到 Pod 里面访问: kubectl exec -it pod-name -- bash curl http://test-k8s:8080

对外暴露服务

上面我们是通过端口转发的方式可以在外面访问到集群里的服务,如果想要直接把集群服务暴露出来,我们可以使用 NodePort 和 Loadbalancer 类型的 Service
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

 

ClusterIP
默认的,仅在集群内可用
NodePort
暴露端口到节点,提供了集群外部访问的入口 端口范围固定 30000 ~ 32767
LoadBalancer
需要负载均衡器(通常都需要云服务商提供,裸机可以安装 METALLB 测试) 会额外生成一个 IP 对外服务

StatefulSet

StatefulSet 是用来管理有状态的应用,例如数据库。 前面我们部署的应用,都是不需要存储数据,不需要记住状态的,可以随意扩充副本,每个副本都是一样的,可替代的。 而像数据库、Redis 这类有状态的,则不能随意扩充副本。 StatefulSet 会固定每个 Pod 的名字 StatefulSet | Kubernetes
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

 

StatefulSet 特性

  • Service 的 CLUSTER-IP 是空的,Pod 名字也是固定的。
  • Pod 创建和销毁是有序的,创建是顺序的,销毁是逆序的。
  • Pod 重建不会改变名字,除了IP,所以不要用IP直连
访问时,如果直接使用 Service 名字连接,会随机转发请求

数据持久化

kubernetes 集群不会为你处理数据的存储,我们可以为数据库挂载一个磁盘来确保数据的安全。 你可以选择云存储、本地磁盘、NFS。
  • 本地磁盘:可以挂载某个节点上的目录,但是这需要限定 pod 在这个节点上运行
  • 云存储:不限定节点,不受集群影响,安全稳定;需要云服务商提供,裸机集群是没有的。
  • NFS:不限定节点,不受集群影响

更高级的抽象

 
Storage Class (SC)
将存储卷划分为不同的种类,例如:SSD,普通磁盘,本地磁盘,按需使用。 Storage Classes | Kubernetes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "10"
  fsType: ext4

 

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

 

Persistent Volume Claim (PVC)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongodata
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: "local-storage"
  resources:
    requests:
      storage: 2Gi

 

为什么要这么多层抽象
  • 更好的分工,运维人员负责提供好存储,开发人员不需要关注磁盘细节,只需要写一个申请单。
  • 方便云服务商提供不同类型的,配置细节不需要开发者关注,只需要一个申请单。
  • 动态创建,开发人员写好申请单后,供应商可以根据需求自动创建所需存储卷。

ConfigMap

数据库连接地址,这种可能根据部署环境变化的,我们不应该写死在代码里。 Kubernetes 为我们提供了 ConfigMap,可以方便的配置一些变量。ConfigMap | Kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongoHost: mongodb-0.mongodb

 

Secret

一些重要数据,例如密码、TOKEN,我们可以放到 secret 中。Secret | Kubernetes
注意,数据要进行 Base64 编码 Base64编码、解码,BASE64转图片,图片转BASE64 - 在线工具
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

 

使用方法

作为环境变量使用
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

 

挂载为文件(更适合证书文件)
挂载后,会在容器中对应路径生成文件,一个 key 一个文件,内容就是 valueSecret | Kubernetes
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

 

Helm

Helm类似 npmpipdocker hub, 可以理解为是一个软件库,可以方便快速的为我们的集群安装一些第三方软件。 使用 Helm 我们可以非常方便的就搭建出来 MongoDB / MySQL 副本集群,YAML 文件别人都给我们写好了,直接使用。官网应用中心

安装 Helm

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

安装 MongoDB 示例

# 安装
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

命名空间

如果一个集群中部署了多个应用,所有应用都在一起,就不太好管理,也可以导致名字冲突等。 我们可以使用 namespace 把应用划分到不同的命名空间,跟代码里的 namespace 是一个概念,只是为了划分空间。
# 创建命名空间
kubectl create namespace testapp
# 部署应用到指定的命名空间
kubectl apply -f app.yml --namespace testapp
# 查询
kubectl get pod --namespace kube-system

Ingress

Ingress 为外部访问集群提供了一个 统一 入口,避免了对外暴露集群端口; 功能类似 Nginx,可以根据域名、路径把请求转发到不同的 Service。 可以配置 https
跟 LoadBalancer 有什么区别? LoadBalancer 需要对外暴露端口,不安全; 无法根据域名、路径转发流量到不同 Service,多个 Service 则需要开多个 LoadBalancer; 功能单一,无法配置 https
 

使用

要使用 Ingress,需要一个负载均衡器 + Ingress Controller 如果是裸机(bare metal) 搭建的集群,你需要自己安装一个负载均衡插件,可以安装 METALLB 如果是云服务商,会自动给你配置,否则你的外部 IP 会是 “pending” 状态,无法使用。
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

 

posted on 2022-11-25 06:19  Ryanyanglibin  阅读(215)  评论(0编辑  收藏  举报

导航