• Kubernetes中的核心机制


    1 RBAC访问控制

    用户在访问Kubernets集群时都要经过api server作认证、鉴权和准入控制才能访问到对应的资源。

    其中**认证(Authentication)**是对用户身份作判断,只有通过的用户才能对集群进行访问,常用方式有

    • https证书认证,基于ca证书
    • http token认证,通过token来识别用户
    • http基本认证,用户名 + 密码认证

    **鉴权(Authorization)**就是对用户是否拥有访问特定资源的权利作判断。

    准入控制 Admission Control用于拦截请求的一种方式,是权限认证链上的最后一环,对请求API资源对象进行修改和校验。

    其中鉴权常用到方式是基于角色的访问控制(Role Based Access Control,RBAC),其中不同的角色 Role对不同的命名空间 namespace访问权限,将用户进行角色绑定 RoleBinding之后,就成为了该角色并且可以访问对应的资源

    如下所示为在K8S中使用RBAC进行鉴权的过程

    首先创建命名空间roledemo

    kubectl create ns roledemo
    
    • 1

    创建pod,通过参数-n指定分配到空间roledemo

    kubectl run nginx --image=nginx -n roledemo
    
    • 1

    创建角色,如下所示为角色对应的配置文件rbac-role.yaml,

    kind: Role
    apiVersion: rbac.authorization.k8s.io/vl
    metadata:
      namespace: ctnrs
      name: pod-reader
    rules:
    - apiGroups: [""] 
      resources: [ r,pods ”]
      # 角色只对pod 有 get、list权限
      verbs: ["get", "watch", "list"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    kubectl apply -f rbac-role.yaml
    
    • 1

    创建角色绑定,通过配置文件role-rolebinding.yaml创建角色绑定

    kind: RoleBinding                                
    apiVersion: rbac.authorization.k8s.io/vl
    metadata:
      name: read-pods
      namespace: roletest
    subjects:
    - kind: User
      name: lucy
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role 
      name: pod-reader
      apiGroup: rbac.authorization.k8s.io
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    kubectl apply -f rbac-rolebinding.yaml
    
    • 1

    最后在指定命名空间查看pod可以返回结果,但是无法查看svc,因为角色没有权限

    # 用get命令查看 pod 【有权限】
    kubectl get pods -n roledemo
    # 用get命令查看svc 【没权限】
    kubectl get svc -n roledmeo
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    2 Ingress服务管理

    在pod部署容器之后,通过NodePort对外暴露服务的 ip + 端口号,从而可以访问到应用。但这样带来的弊端是

    1. 一个应用占用一个端口,容易造成端口号冲突
    2. 服务是有状态的,服务对应到特定pod的端口,当pod挂掉后,新启一个pod还需要再次配置IP和端口号。

    因此采用Ingress对所有服务进行统一管理,将域名映射到对应的service,然后再由service统一管理相同的pod
    在这里插入图片描述

    域名映射

    首先创建一个nginx应用,对外暴露端口

    # 创建pod
    kubectl create deployment web --image=nginx
    # 对外暴露端口
    kubectl expose deployment web --port=80 --target-port=80 --type:NodePort
    
    • 1
    • 2
    • 3
    • 4

    接下来需要通过配置文件ingress-con.yaml部署ingress,可以从ingress官网获取该文件,K8S会根据他自动下载和安装好ingress

    apiVersion: v1
    kind: Namespace
    metadata:
      name: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    
    ---
    
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: nginx-configuration
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    kubectl apply -f ingress-con.yaml
    
    • 1

    接下来配置ingress的访问规则ingress-http.yaml,如下所示将对example.ctnrs.com/的所有请求映射到名为web到service的80端口

    # http
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: example-ingress
    spec:
      rules:
      # 配置访问的域名
      - host: example.ctnrs.com
        http:
          paths:
          # 要映射的后台应用
          - path: /
            backend:
              serviceName: web
              servicePort: 80
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    kubectl apply -f ingress-http.yaml
    
    • 1

    配置完成后就可以通过域名example.ctnrs.com访问容器的nginx服务了。这里如果该域名如果不是真实域名,需要在hosts文件中指定该域名映射的IP地址。

    路径重写

    通过ingress可以对请求的域名进行重写,例如将example.ctnrs.com/service重新映射到容器内的example.ctnrs.com/nginx

    apiVersion: networking.k8s.io/v1
    kind: Ingress  
    metadata:
      annotations:
      	# 配置路径重写的规则
        nginx.ingress.kubernetes.io/rewrite-target: /$2
      name: ingress-host-bar
    spec:
      ingressClassName: nginx
      rules:
      - host: "hello.atguigu.com"
        http:
          paths:
          - pathType: Prefix
            path: "/"
            backend:
              service:
                name: hello-server
                port:
                  number: 8000
      - host: "demo.atguigu.com"
        http:
          paths:
          - pathType: Prefix
            # 将路径映射到/nginx
            path: "/nginx(/|$)(.*)"
            backend:
              service:
                name: nginx-demo  ## java,比如使用路径重写,去掉前缀nginx
                port:
                  number: 8000
    
    • 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

    流量限制

    ingress还可以对请求路径的流量进行限制。这里的pathType设置匹配路径对模式为精确匹配,即只匹配根路径/,对于/nginx不会匹配到

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-limit-rate
      annotations:
      	# 配置每秒允许一个请求
        nginx.ingress.kubernetes.io/limit-rps: "1"
    spec:
      ingressClassName: nginx
      rules:
      - host: "haha.atguigu.com"
        http:
          paths:
          # 路径精确匹配
          - pathType: Exact
            path: "/"
            backend:
              service:
                name: nginx-demo
                port:
                  number: 8000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3 包管理工具Helm

    之前在进行应用部署的时候都需要通过deployment、service和ingress等配置文件对应用进行设置和部署,当应用过多时,这些yaml配置文件数量将成倍增加并且难以维护和管理。这时就需要一个管理系统对每个应用的配置文件作为整体进行管理。Helm 是一个 Kubernetes 的包管理工具,类似于Linux 下的包管理器 yum/apt 等,可以很方便的将之前打包好的 yaml 文件部署到 K8S 上。

    Helm将一系列用于描述 k8s应用的相关资源文件集合称作Chart,并通过命令行工具对应用的Chart进行创建、打包、发 布和管理。一个 chart 被 Helm 运行后将会生成对应的一个release,根据不同的release对应用的版本进行管理,例如更新和回滚等。

    3.1 安装配置

    只需要从官网下载并解压到指定文件夹即可。首先在官网找到对应版本的下载地址:https://github.com/helm/helm/releases ,通过wget下载该文件,并解压到/usr/bin目录下

    wget https://get.helm.sh/helm-vv3.2.1-linux-amd64.tar.gz 
    
    tar zxvf helm-v3.2.1-linux-amd64.tar.gz 
    mv linux-amd64/helm /usr/bin/
    # 添加镜像源
    helm repo add stable http://mirror.azure.cn/kubernetes/charts helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts helm repo update
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.2 部署应用

    通过Helm可以很便捷地部署一个k8s应用,首先在仓库中搜索要安装的chart并查看其信息

    #查找 chart 
    helm search repo weave 
    
    NAME CHART VERSION APP VERSION DESCRIPTION 
    aliyun/weave-cloud 0.1.2 Weave Cloud is a add-on to Kubernetes which pro... 
    aliyun/weave-scope 0.9.21.6.5 A Helm chart for the Weave Scope cluster visual... 
    stable/weave-cloud 0.3.71.4.0 Weave Cloud is a add-on to Kubernetes which pro... 
    stable/weave-scope 1.1.101.12.0 A Helm chart for the Weave Scope cluster visual... 
    #查看 chart 信息 
    helm show chart stable/mysql 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    通过install命令安装指定chart,并查看其安装信息

    #安装包 
    helm install ui stable/weave-scope 
    
    #查看应用 
    helm list 
    NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION 
    ui default 12020-05-2817:45:01.696109626 +0800 CST deployed weave-scope-1.1.101.12.0 
    
    # 查看发布状态
    helm status ui 
    NAME: ui
    LAST DEPLOYED: Thu May 2817:45:012020 
    NAMESPACE: default 
    STATUS: deployed 
    REVISION: 1 
    NOTES: You should now be able to access the Scope frontend in your web browser, by using kubectl port-forward: kubectl -n default port-forward $(kubectl -n default get endpoints \ ui-weave-scope -o jsonpath='{.subsets[0].addresses[0].targetRef.name}') 8080:4040 then browsing to http://localhost:8080/. For more details on using Weave Scope, see the Weave Scope documentation: https://www.weave.works/docs/scope/latest/introducing/ 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    最后修改 service Type: NodePort 暴露端口即可访问 ui

    3.3 构建chart

    通过以上几步就完成了weave-scope的部署,而我们在使用中一般不会直接部署仓库上下载的chart,而是根据自己的实际需要进行配置,这时我们可以手动对chart包进行构建、打包和发布

    首先创建一个chart包 mychart

    helm create nginx 
    
    # nginx包的目录结构 
    nginx/ 
    ├── charts 				目录里存放这个 chart 依赖的所有子 chart
    ├── Chart.yaml 			 用于描述这个 Chart 的基本信息,包括名字、描述信息以及版本等
    ├── templates 			目录里面存放所有 yaml 模板文件
    │ ├── deployment.yaml 
    │ ├── _helpers.tpl 		放置模板助手的地方,可以在整个 chart 中重复使用
    │ ├── ingress.yaml
    │ ├── NOTES.txt 		用于介绍 Chart 帮助信息
    │ └── service.yaml 
    └── values.yaml 		用于存储 templates 目录中模板文件中用到变量的值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    之后编辑Chart的信息

    vim nginx/Chart.yaml 
    
    apiVersion: v2 
    name: nginx 
    description: A Helm chart for Kubernetes 
    type: application 
    version: 0.1.0 
    appVersion: 1.15
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其中的values.yaml文件用于存放一些全局的变量,然后在templates中可以读取变量的值,进而利用模板实现动态化地构建chart

    vim nginx/values.yaml 
    
    replicas: 3 
    image: nginx 
    tag: 1.15 
    serviceport: 80 
    targetport: 80 
    label: nginx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    之后对配置文件deployment.yaml 和service.yaml进行个性化修改,其中可以通过{{.Values.变量名称}}的方式访问到定义在values.yaml文件中的变量

    vim nginx/templates/deployment.yaml 
    
    apiVersion: apps/v1 
    kind: Deployment
    metadata: 
      labels: 
        app: {{ .Values.label }} 
      name: {{ .Release.Name }} 
    spec: 
      replicas: {{ .Values.replicas }} 
      selector: 
        matchLabels: 
          app: {{ .Values.label }} 
      template: 
        metadata: 
          labels: 
            app: {{ .Values.label }} 
        spec: 
          containers: 
          - image: {{ .Values.image }}:{{ .Values.tag }} 
            name: web
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    vim nginx/templates/service.yaml 
    
    apiVersion: v1 
    kind: Service 
    metadata: 
      labels: 
        app: {{ .Values.label }} 
      name: {{ .Release.Name }} 
    spec: 
      ports: 
      - port: {{ .Values.serviceport }} 
        protocol: TCP 
        targetPort: {{ .Values.targetport }} 
      selector: 
        app: {{ .Values.label }} 
      type: NodePort
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    最后就可以安装改chart包nginx,作为应用web

    helm install web nginx
    
    • 1

    还可以通过helm对应用的版本进行升级、回滚

    # 升级镜像
    helm upgrade --set imageTag=1.17 web nginx
    # 更新配置
    helm upgrade -f values.yaml web nginx 
    # 将应用回滚到第一个版本
    helm rollback web 1 
    # 卸载发行版
    helm uninstall web 
    # 查看历史版本配置信息 
    helm get all --revision 1 web
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.4 模板语法

    Helm模板提供了类似于if分支、range循环等功能用于处理更为复杂的模板渲染过程

    如下所示使用if根据不同情况进行模板deployment.yaml的渲染

    template: 
      metadata: 
        labels:
          app: nginx 
    {{ if eq .Values.devops "k8s" }} 
          devops: 123 
    {{ else }}
          devops: 456 
    {{ end }}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如下所示通过range遍历arr数组中的内容,其中的 .代表当前读取的元素

    apiVersion: v1 
    kind: ConfigMap 
    metadata: 
      name: {{ .Release.Name }} 
    data: 
      test: | 
      {{- range .Values.arr }} 
        {{ . }} 
      {{- end }}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    其中使用{{.Release.Name}}将 release 的名称插入到模板中。这里的 Release 就是 Helm 的内置对象

    5 Secret

    Kubernets可以将一些共用的配置文件放在etcd中存储,当其他Pod需要时可以直接从中获取而不必逐个进行手动配置。对于一般的配置文件可以使用Config Map进行存放,而对于涉密内容可以使用Secret。

    加密数据如密码等一般存放在Secret文件中,然后让Pod容器以挂载Volume方式进行访问,Secret会对数据进行编码加密从而保证数据安全。

    有两种访问Secret内容的方式,一种是直接以变量的形式写入配置文件挂载到Pod;另一种是作为文件的形式挂载到Pod,然后在其中访问该文件

    5.1 变量挂载

    首先创建加密文件mysecret,如下所示为其配置文件 secret.yaml,可以看到其中有编码后的username和password

    apiVersion: vl
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque
    data:
      # 通过变量的形式挂载到pod
      username: YWRtaW4=
      password: MWYyZDFlMmU2N2Rm
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    根据上面的文件创建加密文件mysecret

    kubectl create -f secret.yaml
    
    • 1

    创建容器mypod,在其中通过变量的形式直接应用mysecret中定义的加密数据

    apiVersion: vl
    kind: Pod
    metadata:
       name: mypod
    spec:
       containers:
       - name: nginx
         image: nginx
         env:
           - name: SECRET_USERMAME
             valueFrom:
               # 以变量的方式进行挂载username
               secretKeyRef:
                 name: mysecret
                 key: username
           - name: SECRET_PASSWORD
             valueFrom:
               # 以变量的方式进行挂载password
               secretKeyRef:
                 name: mysecret
                 key: password
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在命令行执行如下命令,可以看到输出变量的内容

    # 进入容器内部
    kubectl exec -it mypod bash
    # 查看变量
    echo $SECRET_USERNAME
    admin
    echo $SECRET PAS9/VORD
    If2dle2e67df
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果要删除这个Pod

    kubectl delete -f secret-val.yaml
    
    • 1

    5.2 volume挂载

    跟上面相似,首先需要创建好加密文件mysecret

    然后根据如下文件创建容器mypod,将加密文件挂载到指定的目录下,这样在容器中就可以在该目录下访问到加密文件的内容

    apiVersion: vl
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
      - name: nginxj
        image: nginx
        # 将加密文件挂载到/etc/foo目录
        volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
          readonly: true
      volumes:
      # 挂载加密文件
      - name: foo
        secret:
          secretName: mysecret
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    # 进入容器
    kubectl exec -it mypod bash
    # 查看
    ls /etc/foo
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    6 ConfigMap

    ConfigMap作用是存储不加密的数据到etcd中,然后以变量或数据卷Volume挂载到容器中。例如可以将不需要加密的配置文件放到ConfigMap

    例如下面有一个redis的配置文件 redis.properties

    redis.port=127.0.0.1
    redis.port=6379
    redis.password=123456
    
    • 1
    • 2
    • 3

    根据上面的文件创建ConfigMap文件redis-config并进行查看

    kubectl create configmap redis-config --from-file=redis.properties
    # 查看其详细信息
    kubectl describe cm redis-config
    
    Name:         redis-config
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    Data
    
    redis.properties:
    redis.host=127.0.0.1
    redis.port=6379
    redis.pa$sword=123456
    Events: <none>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6.1 Volume数据卷形式挂载

    如下所示将上面创建的ConfigMap文件以Volume的形式挂载到指定的目录

    apiVersion: vl                          
    kind: Pod
    metadata:
       name: mypod
    spec:
      containers:
        - name: busybox
          image: busybox
          # 以命令行的形式输出挂载文件的内容
          command: [ "/bin/sh","-c", "cat /etc/config/redis.properties" ]
          volumeMounts:
          # 将文件挂载到指定目录
          - name: config-volume
            mountPath: /etc/config
      volumes:
      # 将配置文件redis-config以数据卷的形式进行挂载
        - name: config-volume
          configMap:
            name: redis-config
      restartPolicy: Never
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    然后使用该yaml文件创建pod,由于配置文件中通过命令行的形式对文件内容进行了输出,通过查看日志信息便可以看到内容

    # 创建
    kubectl apply -f cm.yaml
    # 查看日志
    kubectl logs mypod
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    6.2 变量挂载

    首先创建 ConfigMap文件myconfig,在其中的data字段声明变量信息

    apiVersion: vl
    kind: ConfigMap
    metadata:
      name: myconfig
      namespace: default
    data:
      # 声明变量信息
      special.level: info
      special.type: hello
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    根据上面的配置文件创建ConfigMap

    # 创建pod
    kubectl apply -f myconfig.yaml
    
    • 1
    • 2

    之后在创建Pod的时候就可以变量的形式访问上面ConfigMap中的信息

    apiVersion: vl                               
    kind: Pod
    metadata:
       name: mypod
    spec:
      containers:
        - name: busybox
          image: busybox
          command: [ "/bin/sh", "echo $(LEVEL) $(TYPE)"]
          env:
            - name: LEVEL
              valueFrom:
                # 以变量的形式访问ConfigMap中的内容
                configMapKeyRef:
                  name: myconfig
                  key: special.level
            - name: TYPE
              valueFrom:
                # 以变量的形式访问ConfigMap中的内容
                configMapKeyRef:
                  name: myconfig
                  key: special.type
      restartPolicy: Never
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    查看日志输出配置文件中的内容

    kubectl logs mypod
    
    • 1

    在这里插入图片描述

  • 相关阅读:
    Rainbond 5.6 版本发布,增加多种安装方式,优化拓扑图操作体验
    头歌答案HTML——基础
    攻防演练蓝队|Windows应急响应入侵排查
    JUC并发编程与源码分析笔记03-CompletableFuture
    (五)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
    【二分图】 二分图上匹配问题 和 匈牙利算法正确性说明
    UDS - 深论Security Access Service
    Java中位运算符优先级低于算术运算符
    Halcon相机外参自理解
    计算机网络——常考的面试题
  • 原文地址:https://blog.csdn.net/theVicTory/article/details/126534133