【Enjoy Kubernetes】1. 基础入门

1. Why Kubernetes

容器化技术展示了强大的先进性,build once,run every where,现在越来越多的应用从罗金属部署,迁移到容器部署。

容器虽好,但它好比也只是跑起来的单独应用,我们需要一个类似操作系统的平台去维护这些容器的生命周期,以及容器间的交互。其实在k8s面世之前,一款闭源的docker swarm一直充当这个容器编排的角色,但由于商业公司出于盈利的考虑,导致它深度绑定了docker(docker不是容器),此时google拿出王炸Kubernetes(内部已经玩太多年了),Kubernetes提供了一个以"容器为中心的基础架构",满足在生产环境中运行应用的一些常见需求,如:

  • 多个进程(作为容器运行)协同工作。(Pod)
  • 存储系统挂载
  • Distributing secrets
  • 应用健康检测
  • 应用实例的复制
  • Pod自动伸缩/扩展
  • Naming and discovering
  • 负载均衡
  • 滚动更新
  • 资源监控
  • 日志访问
  • 调试应用程序
  • 提供认证和授权
  • 支持公有云,私有云,混合云,多重云(multi-cloud)
  • 模块化,插件化,可挂载,可组合
  • 无缝对接新的应用功能
  • 节省资源,优化硬件资源的使用

2. Component

2.1. Master组件

Master组件可以在集群中任何节点上运行。但是为了简单起见,通常在一台VM/机器上启动所有Master组件,并且不会在此VM/机器上运行用户容器。

  • kube-apiserver用于暴露Kubernetes API。任何的资源请求/调用操作都是通过kube-apiserver提供的接口进行
  • etcd是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划
  • kube-controller-manager运行管理控制器,它们是集群中处理常规任务的后台线程。这些控制器包括:节点(Node)控制器;副本(Replication)控制器,负责维护系统中每个副本中的pod;端点(Endpoints)控制器,填充Endpoints对象(即连接Services&Pods);Service Account和Token控制器,为新的Namespace 创建默认帐户访问API Token
  • kube-scheduler 监视新创建没有分配到NodePod,为Pod选择一个Node。
  • 插件(addon)是实现集群pod和Services功能的 。Pod由Deployments,ReplicationController等进行管理。Namespace 插件对象是在kube-system Namespace中创建。
  • 集群DNS
  • kube-ui提供集群状态基础信息查看,有用户界面
  • 容器资源监控提供一个UI浏览监控数据
  • Cluster-level logging,负责保存容器日志,搜索/查看日志。
  • 节点控制器(Node Controller)是管理节点的Kubernetes master组件,节点控制器在节点的生命周期中具有多个角色。第一个 是在注册时将CIDR块分配给节点。第二个 是使节点控制器的内部列表与云提供商的可用机器列表保持最新。当在云环境中运行时,每当节点不健康时,节点控制器将询问云提供程序是否该节点的VM仍然可用,如果不可用,节点控制器会从其节点列表中删除该节点。第三是 监测节点的健康状况。当节点变为不可访问时,节点控制器负责将NodeStatus的NodeReady条件更新为ConditionUnknown,随后从节点中卸载所有pod ,如果节点继续无法访问,(默认超时时间为40 --node-monitor-period秒,开始报告ConditionUnknown,之后为5m开始卸载)。节点控制器按每秒来检查每个节点的状态。从Kubernetes 1.6开始,节点控制器还负责驱逐在节点上运行的NoExecutepod。

2.2. Node组件

Node是Kubernetes REST API中的最高级别资源

Node是Kubernetes中的工作节点,最开始被称为minion。一个Node可以是VM或物理机。每个Node(节点)具有运行pod的一些必要服务,并由Master组件进行管理,Node节点上的服务包括Docker、kubelet和kube-proxy。

组件包含:

  • kubelet是主要的节点代理,它会监视已分配给节点的pod,具体功能:
    • 安装Pod所需的volume。
    • 下载Pod的Secrets。
    • Pod中运行的 docker(或experimentally,rkt)容器。
    • 定期执行容器健康检查。
    • Reports the status of the pod back to the rest of the system, by creating a mirror pod if necessary.
    • Reports the status of the node back to the rest of the system.
  • docker用于运行容器
  • kube-proxy通过在主机上维护网络规则并执行连接转发来实现Kubernetes服务抽象。
  • rkt运行容器,作为docker工具的替代方案。
  • supervisord是一个轻量级的监控系统,用于保障kubelet和docker运行。
  • fluentd是一个守护进程,可提供cluster-level logging

节点的状态信息包含:

  • Address:ExternalIP:可以被集群外部路由到的IP。InternalIP:只能在集群内进行路由的节点的IP地址。
  • conditions字段描述所有Running节点的状态。OutOfDisk,Ready(True:如果节点是健康的并准备好接收pod;False:如果节点不健康并且不接受pod;Unknown:如果节点控制器在过去40秒内没有收到node的状态报告。), MemoryPressure, DiskPressure
  • capacity:描述节点上可用的资源:CPU、内存和可以调度到节点上的最大pod数。
  • info:关于节点的一些基础信息,如内核版本、Kubernetes版本(kubelet和kube-proxy版本)、Docker版本(如果有使用)、OS名称等。信息由Kubelet从节点收集
  • node容量:如果要明确保留非pod过程的资源,可以创建一个占位符pod

3. 一切皆对象

Kubernetes对象是Kubernetes系统中的持久实体。Kubernetes使用这些实体来表示集群的状态。具体来说,他们可以描述:

  • 容器化应用正在运行(以及在哪些节点上)
  • 这些应用可用的资源
  • 关于这些应用如何运行的策略,如重新策略,升级和容错

每个Kubernetes对象都包含两个嵌套对象字段,用于管理Object的配置:Object Spec和Object Status。Spec描述了对象所需的状态,Status描述了对象的实际状态,并由Kubernetes系统提供和更新。

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        
        
# kubectl create -f docs/user-guide/nginx-deployment.yaml --record

Kubernetes REST API中的所有对象都用Name和UID来明确地标识。

4. Namespaces

Kubernetes可以使用Namespaces(命名空间)创建多个虚拟集群。

资源的Names在Namespace中具有唯一性。

(1) 命令行直接创建
$ kubectl create namespace new-namespace

(2) 通过文件创建
$ cat my-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: new-namespace

$ kubectl create -f ./my-namespace.yaml


kubectl delete namespaces new-namespace
# 删除一个namespace会自动删除所有属于该namespace的资源。
# default和kube-system命名空间不可删除。
# PersistentVolumes是不属于任何namespace的,但PersistentVolumeClaim是属于某个特定namespace的。
# Events是否属于namespace取决于产生events的对象。

$ kubectl get namespaces
NAME          STATUS    AGE
default       Active    1d
kube-system   Active    1d


$ kubectl --namespace=<insert-namespace-name-here> run nginx --image=nginx
$ kubectl --namespace=<insert-namespace-name-here> get pods

为Namespaces进行配额

# 1. pod配额
apiVersion: v1
kind: ResourceQuota
metadata:
  name: pod-demo
spec:
  hard:
    pods: "2"

# 2. cpu配额
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-limit-range
spec:
  limits:
  - default:
      cpu: 1 # 定义容器可以使用的最大资源。
    defaultRequest:
      cpu: 0.5 # 定义容器启动时所需的资源,500m: 表示该容器请求 500 毫核(milli-CPU),即 0.5 个 CPU 核心。
    type: Container    

# 3. 内存配额
apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  - default:
      memory: 512Mi
    defaultRequest:
      memory: 256Mi
    type: Container   

# 4. 内存限额
apiVersion: v1
kind: LimitRange
metadata:
  name: mem-min-max-demo-lr
spec:
  limits:
  - max:
      memory: 1Gi
    min:
      memory: 500Mi
    type: Container


# 5. cpu+内存配额
apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-demo
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi


# 6. cpu限额
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-min-max-demo-lr
spec:
  limits:
  - max:
      cpu: "800m"
    min:
      cpu: "200m"
    type: Container

5. label与selector

Labels其实就一对 key/value ,被关联到对象上,标签的使用我们倾向于能够标示对象的特殊特点,并且对用户而言是有意义的。

kubectl get pods -l environment=production,tier=frontend

kubectl get pods -l 'environment in (production),tier in (frontend)'

kubectl get pods -l 'environment in (production, qa)'

kubectl get pods -l 'environment,environment notin (frontend)'

一个service针对的pods的集合是用标签选择器来定义的。

selector:
    component: redis

Job,DeploymentReplica Set,和Daemon Set,支持set-based要求。

selector:
  matchLabels:
    component: redis
  matchExpressions:
    - {key: tier, operator: In, values: [cache]}
    - {key: environment, operator: NotIn, values: [dev]}

6. Volume

在Docker中也有一个docker Volume的概念 ,Docker的Volume只是磁盘中的一个目录,生命周期不受管理。当然Docker现在也提供Volume将数据持久化存储,但支持功能比较少(例如,对于Docker 1.7,每个容器只允许挂载一个Volume,并且不能将参数传递给Volume)。

另一方面,Kubernetes Volume具有明确的生命周期 - 与pod相同。因此,Volume的生命周期比Pod中运行的任何容器要持久,在容器重新启动时能可以保留数据,当然,当Pod被删除不存在时,Volume也将消失。注意,Kubernetes支持许多类型的Volume,Pod可以同时使用任意类型/数量的Volume。

内部实现中,一个Volume只是一个目录,目录中可能有一些数据,pod的容器可以访问这些数据。至于这个目录是如何产生的、支持它的介质、其中的数据内容是什么,这些都由使用的特定Volume类型来决定。

# 1. 使用emptyDir,当Pod分配到Node上时,将会创建emptyDir,并且只要Node上的Pod一直运行,Volume就会一直存。当Pod(不管任何原因)从Node上被删除时,emptyDir也同时会删除,存储的数据也将永久删除。
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

# 2. hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod需要使用Node上的文件,可以使用hostPath。
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data
      
# 3. awsElasticBlockStore可以挂载AWS上的EBS盘到容器,需要Kubernetes运行在AWS的EC2上。

# 4. NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,
# 而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。Pod被删除时,Volume被卸载,内容被保留。这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递。

          
# 5. secret: secret volume用于将敏感信息(如密码)传递给pod。可以将secrets存储在Kubernetes API中,使用的时候以文件的形式挂载到pod中,而不用连接api。
# 6. persistentVolumeClaim用来挂载持久化磁盘的。PersistentVolumes是用户在不知道特定云环境的细节的情况下,实现持久化存储
# 7. downwardAPI:通过环境变量的方式告诉容器Pod的信息
# 8. configMap

7. 集群通信原理

本文主要介绍master和Kubernetes集群之间通信路径。其目的是允许用户自定义安装,以增强网络配置,使集群可以在不受信任(untrusted)的网络上运行。

https://cloud.tencent.com/developer/article/2242235

https://zhuanlan.zhihu.com/p/81667781

https://blog.csdn.net/lywzgzl/article/details/100780553

7.1. 服务间通信

ClusterIP Service、DNS 和 Kube-Proxy

传统服务间通信:

k8s网络模型:

集群内的 Pod 到 Pod 通信

根据 Kubernetes 网络模型:

  1. 集群中的每个 pod 都有自己唯一的集群范围 IP 地址
  2. 所有 pod 都可以与集群内的每个 pod 通信
  3. 通信在没有 NAT 的情况下发生,这意味着目标 pod 可以看到源 pod 的真实 IP 地址。Kubernetes 认为容器网络或在其上运行的应用程序是可信的,不需要在网络级别进行身份验证

Kubernetes 可以在一组 Pod 之上创建一个层,该层可以为该组提供单个 IP 地址并可以提供基本的负载平衡。

通过持久 IP 地址上的 ClusterIP 服务公开的 Pod,客户端与服务对话,而不是直接与 Pod 对话。

这种抽象是由 Kubernetes 中一个名为ClusterIP service的服务对象提供的。它在多个节点上产生,从而在集群中创建单个服务。它可以接收任何端口上的请求并将其转发到 pod 上的任何端口。

ClusterIP 使用 Kubernetes 中标签和选择器的标准模式来不断扫描匹配选择标准的 pod。Pod 有标签,服务有选择器来查找标签。使用它,可以进行基本的流量拆分,其中新旧版本的微服务在同一个 clusterIP 服务后共存。

现在服务 B 已经获得了一个持久的 IP 地址,服务 A 仍然需要知道这个 IP 地址是什么,然后才能与服务 B 通信。

Kubernetes 支持使用 CoreDNS 进行名称解析。服务 A 应该知道它需要与之通信的 ClusterIP 的名称(和端口)。

  1. CoreDNS 扫描集群,每当创建 ClusterIP 服务时,它的条目就会添加到 DNS 服务器(如果已配置,它还会为每个 pod 添加一个条目,但它与服务到服务的通信无关)。
  2. 接下来,CoreDNS 将自己暴露为 cluster IP 服务(默认称为 kube-dns),并且该服务被配置为 pod 中的 nameserver。
  3. 发起请求的 Pod 从 DNS 获取 ClusterIP 服务的 IP 地址,然后可以使用 IP 地址和端口发起请求。

到目前为止,从本文来看,似乎是 ClusterIP 服务将请求调用转发到后端 Pod。但实际上,它是由 Kube-proxy 完成的。

Kube-proxy 在每个节点上运行,并监视 Service 及其选择的 Pod(实际上是 Endpoint 对象)。

  1. 当节点上运行的 pod 向 ClusterIP 服务发出请求时,kube-proxy 会拦截它。
  2. 通过查看目的 IP 地址和端口,可以识别目的 ClusterIP 服务。并将此请求的目的地替换为实际 Pod 所在的端点地址。

总结:

ClusterIP Service、CoreDNS、客户端 Pod、Kube-Proxy、EndPoint的交互

  1. 目标的 ClusterIP 服务在 CoreDNS 中注册
  2. DNS 解析:每个 pod 都有一个 resolve.conf 文件,其中包含 CoreDNS 服务的 IP 地址,pod 执行 DNS 查找。
  3. Pod 使用它从 DNS 收到的 IP 地址和它已经知道的端口来调用 clusterIP 服务。
  4. 目标地址转换:Kube-proxy 将目标 IP 地址更新为服务 B 的 Pod 可用的地址。

7.2. 组件间通信

8. Pod

8.1. 简介

Kubernetes中的Pod使用可分两种主要方式:

  • Pod中运行一个容器。"one-container-per-Pod"模式是Kubernetes最常见的用法; 在这种情况下,你可以将Pod视为单个封装的容器,但是Kubernetes是直接管理Pod而不是容器。
  • Pods中运行多个需要一起工作的容器。Pod可以封装紧密耦合的应用,它们需要由多个容器组成,它们之间能够共享资源,这些容器可以形成一个单一的内部service单位 - 一个容器共享文件,另一个"sidecar"容器来更新这些文件。Pod将这些容器的存储资源作为一个实体来管理。

网络

每个Pod被分配一个独立的IP地址,Pod中的每个容器共享网络命名空间,包括IP地址和网络端口。Pod内的容器可以使用localhost相互通信。当Pod中的容器与Pod 外部通信时,他们必须协调如何使用共享网络资源(如端口)。

存储

Pod可以指定一组共享存储volumes 。Pod中的所有容器都可以访问共享volumes

管理

Pod不会自愈。如果Pod运行的Node故障,或者是调度器本身故障,这个Pod就会被删除。同样的,如果Pod所在Node缺少资源或者Pod处于维护状态,Pod也会被驱逐。Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例。虽然可以直接使用Pod,但是在Kubernetes中通常是使用Controller来管理Pod的。

包含一个或者多个Pod的Controller示例:

8.2. 设计模式

sidecar模式:

Init模式:

因为 Init 容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有如下优势:

  • 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
  • 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要 FROM 另一个镜像,只需要在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具。
  • 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
  • Init 容器使用 Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用程序容器则不能。
  • 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以 Init 容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。

8.3. 安全策略

PodSecurityPolicy 是一个内置的准入控制器, 允许集群管理员控制 Pod 规约中涉及安全的敏感内容。

首先,在集群中创建一个或多个 PodSecurityPolicy 资源来定义 Pod 必须满足的要求。 然后,创建 RBAC 规则来决定为特定的 Pod 应用哪个 PodSecurityPolicy。 如果 Pod 满足其 PSP 的要求,则照常被允许进入集群。 在某些情况下,PSP 还可以修改 Pod 字段,有效地为这些字段创建新的默认值。 如果 Pod 不符合 PSP 要求,则被拒绝进入集群,并且无法运行。

简单说来,就是PodSecurityPolicy 可以设置pod里的进程只能以某个UID运行,或者设置pod只能使用某一类型存储,不能使用其他,比如只能使用nfs存储

  1. role -> 命名空间 -> 创建/删除/查看pod 通过用户赋予role角色,达到权限控制

    root@k8scludes1:~/minsvcbug# vim role1.yaml

    #role1角色对pod,svc,secret具有get,list,watch,create,delete权限
    root@k8scludes1:~/minsvcbug# cat role1.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    creationTimestamp: null
    name: role1
    rules:

    • apiGroups:
      • ""
        resources:
      • pods
      • services
      • secrets
        verbs:
      • get
      • list
      • watch
      • create
      • delete

    kubectl create rolebinding rolebindingtotom --role=role1 --user=tom

  2. psp规则启用

    apiVersion: policy/v1beta1
    kind: PodSecurityPolicy
    metadata:
    name: psp-deny-privileges-pod
    spec:

    Don't allow privileged pods!

    privileged: false

    The rest fills in some required fields.

    seLinux:
    rule: RunAsAny
    supplementalGroups:
    rule: RunAsAny
    runAsUser:
    rule: RunAsAny
    fsGroup:
    rule: RunAsAny
    volumes:

    • '*'
  • 在启用了PSP之后,没有任何PSP规则的情况下,任何用户(包括管理员)都不能创建pod;

  • 在启用了PSP之后,且创建了PSP规则,要确保用户能访问到此PSP规则,创建clusterrole,让用户能use某条PSP规则;

  • 能不能成功创建pod,决定权在于是否具备创建pod的RBAC权限,有对应的RBAC权限之后,创建的pod是否满足PSP规则。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
    creationTimestamp: null
    name: clusterrole-access-psp-rule
    rules:

    • apiGroups:

      • policy
        resourceNames:
      • psp-deny-privileges-pod
        resources:
      • podsecuritypolicies
        verbs:
      • use

      kubectl create rolebinding rolebinding-clusterrole-access-psp --clusterrole=clusterrole-access-psp-rule --user=tom

限定数据卷使用某一个目录

allowedHostPaths:

  • pathPrefix: "/tmp"

指定使用宿主机网络

privileged: true

hostNetwork: true

rule: MustRunAs

#MustRunAs 表示pod必须以1000-2000的UID身份运行

ranges:

  • min: 1000

max: 2000

#指定hostport的端口范围为1000-8090

hostPorts:

  • min: 1000

max: 8090

8.4. 探活

Pod 的(phase)是 Pod 在其生命周期中的简单宏观概述。

下面是 phase 可能的值:

挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。

运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。

成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。

失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。

未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。

探针 是由 kubelet 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 Handler。有三种类型的处理程序:

  • ExecAction:在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
  • TCPSocketAction:对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
  • HTTPGetAction:对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。

readinessProbe(就绪探针):指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址

如果您希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针,并指定restartPolicy 为 Always 或 OnFailure。

如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与存活探针相同,但是 spec 中的就绪探针的存在意味着 Pod 将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量。

8.5. Preset

Pod Preset 是一种 API 资源,在 pod 创建时,用户可以用它将额外的运行时需求信息注入 pod。 使用标签选择器(label selector)来指定 Pod Preset 所适用的 pod。

用户提交的 pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: website
  labels:
    app: website
    role: frontend
spec:
  containers:
    - name: website
      image: ecorp/website
      ports:
        - containerPort: 80
用户提交的 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: etcd-env-config
data:
  number_of_members: "1"
  initial_cluster_state: new
  initial_cluster_token: DUMMY_ETCD_INITIAL_CLUSTER_TOKEN
  discovery_token: DUMMY_ETCD_DISCOVERY_TOKEN
  discovery_url: http://etcd_discovery:2379
  etcdctl_peers: http://etcd:2379
  duplicate_key: FROM_CONFIG_MAP
  REPLACE_ME: "a value"
Pod Preset 示例:

kind: PodPreset
apiVersion: settings.k8s.io/v1alpha1
metadata:
  name: allow-database
  namespace: myns
spec:
  selector:
    matchLabels:
      role: frontend
  env:
    - name: DB_PORT
      value: 6379
    - name: duplicate_key
      value: FROM_ENV
    - name: expansion
      value: $(REPLACE_ME)
  envFrom:
    - configMapRef:
        name: etcd-env-config
  volumeMounts:
    - mountPath: /cache
      name: cache-volume
    - mountPath: /etc/app/config.json
      readOnly: true
      name: secret-volume
  volumes:
    - name: cache-volume
      emptyDir: {}
    - name: secret-volume
      secret:
         secretName: config-details

通过环境变量向容器暴露 Pod 信息

env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: MY_POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: MY_POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: MY_POD_SERVICE_ACCOUNT
          valueFrom:
            fieldRef:
              fieldPath: spec.serviceAccountName

8.6. Deployment

  • 使用Deployment来创建ReplicaSet。ReplicaSet在后台创建pod。检查启动状态,看它是成功还是失败。
  • 然后,通过更新Deployment的PodTemplateSpec字段来声明Pod的新状态。这会创建一个新的ReplicaSet,Deployment会按照控制的速率将pod从旧的ReplicaSet移动到新的ReplicaSet中。
  • 如果当前状态不稳定,回滚到之前的Deployment revision。每次回滚都会更新Deployment的revision。
  • 扩容Deployment以满足更高的负载。
  • 暂停Deployment来应用PodTemplateSpec的多个修复,然后恢复上线。
  • 根据Deployment 的状态判断上线是否hang住了。
  • 清除旧的不必要的 ReplicaSet。

您可以使用kubectl rollout status命令监控 Deployment 的进度。

kubectl rollout status deploy/nginx

kubectl create -f https://kubernetes.io/docs/user-guide/nginx-deployment.yaml --record

kubectl rollout undo deployment/nginx-deployment --to-revision=2

kubectl describe deployments
Name:           nginx-deployment
Namespace:      default
CreationTimestamp:  Tue, 15 Mar 2016 12:01:06 -0700
Labels:         app=nginx
Selector:       app=nginx
Replicas:       3 updated | 3 total | 3 available | 0 unavailable
StrategyType:       RollingUpdate
MinReadySeconds:    0
RollingUpdateStrategy:  1 max unavailable, 1 max surge
OldReplicaSets:     <none>
NewReplicaSet:      nginx-deployment-1564180365 (3/3 replicas created)
Events:
  FirstSeen LastSeen    Count   From                     SubobjectPath   Type        Reason              Message
  --------- --------    -----   ----                     -------------   --------    ------              -------
  36s       36s         1       {deployment-controller }                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-2035384211 to 3
  23s       23s         1       {deployment-controller }                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 1
  23s       23s         1       {deployment-controller }                 Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 2
  23s       23s         1       {deployment-controller }                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 2
  21s       21s         1       {deployment-controller }                 Normal      ScalingReplicaSet   Scaled down replica set nginx-deployment-2035384211 to 0
  21s       21s         1       {deployment-controller }                 Normal      ScalingReplicaSet   Scaled up replica set nginx-deployment-1564180365 to 3

最佳实践:金丝雀

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  ports:
  - name: nginx-port
    protocol: TCP
    port: 80  // 服务端口
    nodePort: 32600 //外部使用端口
    targetPort: 80  // pod端口
  type: NodePort
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-canary
  labels:
    app: nginx
    track: canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      track: canary
  template:
    metadata:
      labels:
        app: nginx
        track: canary
    spec:
      containers:
      - name: nginx
        image: nginx:1.8.0
  • TIP
    • 因为 Service 的LabelSelector 是 app: nginx,由 nginx-deploymentnginx-deployment-canary 创建的 Pod 都带有标签 app: nginx,所以,Service 的流量将会在两个 release 之间分配
    • 在新旧版本之间,流量分配的比例为两个版本副本数的比例,此处为 1:3
  • 当您确定新的版本没有问题之后,可以将 nginx-deployment 的镜像标签修改为新版本的镜像标签,并在完成对 nginx-deployment 的滚动更新之后,删除 nginx-deployment-canary 这个 Deployment

9. StatefulSets

有状态系统服务设计:

  • 稳定性,唯一的网络标识符。
  • 稳定性,持久化存储。
  • 有序的部署和扩展。
  • 有序的删除和终止。
  • 有序的自动滚动更新。

Pod的存储,必须基于请求storage class的PersistentVolume Provisioner或由管理员预先配置来提供。

  • 对于具有N个副本的StatefulSet,当部署Pod时,将会顺序从{0..N-1}开始创建。

  • Pods被删除时,会从{N-1..0}的相反顺序终止。

  • 在将缩放操作应用于Pod之前,它的所有前辈必须运行和就绪。

  • 对Pod执行扩展操作时,前面的Pod必须都处于Running和Ready状态。

  • 在Pod终止之前,所有successors都须完全关闭。

    apiVersion: v1
    kind: Service
    metadata:
    name: nginx
    labels:
    app: nginx
    spec:
    ports:
    - port: 80
    name: web
    clusterIP: None
    selector:
    app: nginx

    apiVersion: apps/v1beta1
    kind: StatefulSet
    metadata:
    name: web
    spec:
    serviceName: "nginx"
    replicas: 3
    template:
    metadata:
    labels:
    app: nginx
    spec:
    terminationGracePeriodSeconds: 10
    containers:
    - name: nginx
    image: gcr.io/google_containers/nginx-slim:0.8
    ports:
    - containerPort: 80
    name: web
    volumeMounts:
    - name: www
    mountPath: /usr/share/nginx/html
    volumeClaimTemplates:
    - metadata:
    name: www
    spec:
    accessModes: [ "ReadWriteOnce" ] # 单节点可读写
    storageClassName: my-storage-class
    resources:
    requests:
    storage: 1Gi

kubectl get pods -w -l app=nginx

---Pods 的创建、删除、状态更新等实时信息

kubectl create -f web.yaml 
service "nginx" created
statefulset "web" created

上面的命令创建了两个 Pod,每个都运行了一个 NGINX web 服务器。获取 nginx Service 和 web StatefulSet 来验证是否成功的创建了它们。

kubectl get service nginx
NAME      CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx     None         <none>        80/TCP    12s

kubectl get statefulset web
NAME      DESIRED   CURRENT   AGE
web       2         1         20s

StatefulSet 中的 Pod 拥有一个唯一的顺序索引和稳定的网络身份标识。

kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh 
nslookup web-0.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.6

nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.6
kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           48s

使用 kubectl scale 扩展副本数为5。

kubectl scale sts web --replicas=5
statefulset "web" scaled
kubectl patch sts web -p '{"spec":{"replicas":3}}'
"web" patched

灰度扩容

你可以使用 RollingUpdate 更新策略的 partition 参数来分段更新一个 StatefulSet。分段的更新将会使 StatefulSet 中的其余所有 Pod 保持当前版本的同时仅允许改变 StatefulSet 的.spec.template。

Patch web StatefulSet 来对 updateStrategy 字段添加一个分区。

kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset "web" patched

再次 Patch StatefulSet 来改变容器镜像。

kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.7"}]'
statefulset "web" patched

删除 StatefulSet 中的 Pod。

kubectl delete po web-2
pod "web-2" deleted

等待 Pod 变成 Running 和 Ready。

kubectl get po -lapp=nginx -w
NAME      READY     STATUS              RESTARTS   AGE
web-0     1/1       Running             0          4m
web-1     1/1       Running             0          4m
web-2     0/1       ContainerCreating   0          11s
web-2     1/1       Running   0         18s

获取 Pod 的容器。

kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'
gcr.io/google_containers/nginx-slim:0.8

请注意,虽然更新策略是 RollingUpdate,StatefulSet 控制器还是会使用原始的容器恢复 Pod。这是因为 Pod 的序号比 updateStrategy 指定的 partition 更小。

10. Ingress

10.1.1. Service 的负载均衡

  • 基本功能
    • Kubernetes Service 提供了对 Pods 的负载均衡访问,允许用户通过一个稳定的 IP 地址和端口来访问一组 Pods。
    • Service 主要用于集群内部或外部访问 Pods,支持多种类型(如 ClusterIP、NodePort 和 LoadBalancer)。
  • 使用场景
    • 当您需要在集群内部或通过节点 IP 直接访问 Pods 时,Service 是合适的选择。
    • 对于简单的应用场景,Service 可以满足负载均衡的需求。

10.1.2. Ingress 的负载均衡

  • 高级路由功能
    • Ingress 提供了更复杂的路由和负载均衡能力。它可以根据请求的 URL 路径、主机名等条件路由流量到不同的 Service。
    • Ingress 允许您通过单一入口点(通常是一个外部负载均衡器)来管理多个 Service 的流量。
  • SSL/TLS 终止
    • Ingress 支持 SSL/TLS 终止,这意味着它可以处理 HTTPS 请求并将流量以 HTTP 形式转发到后端服务。
  • 使用场景
    • 当您需要在一个域名下管理多个 Service 时,Ingress 是理想的选择。例如,您可以使用 Ingress 将 example.com 的流量路由到不同的服务,如 /app1/app2
    • 适用于需要处理复杂路由、负载均衡和安全性需求的场景。

为了使Ingress正常工作,集群中必须运行Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为kube-controller-manager二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的Ingress controller或者自己实现一个。

https://kubernetes.github.io/ingress-nginx/deploy/

foo.bar.com --|                 |-> foo.bar.com s1:80
              | 178.91.123.132  |
bar.foo.com --|                 |-> bar.foo.com s2:80      

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
  - host: bar.foo.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80

11. Service

Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 ------ 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(查看下面了解,为什么可能需要没有 selector 的 Service)实现的。

举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 ------ frontend 不需要关心它们调用了哪个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。 Service 定义的抽象能够解耦这种关联。

# selector模式
kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP # Kubernetes Service 能够支持 TCP 和 UDP 协议,默认 TCP 协议。
      port: 80
      targetPort: 9376 # Service 能够将一个接收端口映射到任意的 targetPort


# 非selector模式 
kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

kind: Endpoints
apiVersion: v1
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 1.2.3.4
    ports:
      - port: 9376       # 请求将被路由到用户定义的 Endpoint(该示例中为 1.2.3.4:9376)


# 对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务
kind: Service
apiVersion: v1
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

11.1. service

userspace代理模式下Service概览图

iptables 代理模式

这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始选择的 Pod 没有响应,iptables 代理能够自动地重试另一个 Pod,所以它需要依赖 readiness probes

11.2. service dns记录

DNS 服务器监视着创建新 Service 的 Kubernetes API,从而为每一个 Service 创建一组 DNS 记录。

例如,有一个名称为 "my-service" 的 Service,它在 Kubernetes 集群中名为 "my-ns" 的 Namespace 中,为 "my-service.my-ns" 创建了一条 DNS 记录。 在名称为 "my-ns" 的 Namespace 中的 Pod 应该能够简单地通过名称查询找到 "my-service"。 在另一个 Namespace 中的 Pod 必须限定名称为 "my-service.my-ns"。 这些名称查询的结果是 Cluster IP。

有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。

为了保证每个 Service 被分配到一个唯一的 IP,需要一个内部的分配器能够原子地更新 etcd 中的一个全局分配映射表,这个更新操作要先于创建每一个 Service。 为了使 Service能够获取到 IP,这个映射表对象必须在注册中心存在,否则创建 Service 将会失败,指示一个 IP 不能被分配。 一个后台 Controller 的职责是创建映射表(从 Kubernetes 的旧版本迁移过来,旧版本中是通过在内存中加锁的方式实现),并检查由于管理员干预和清除任意 IP 造成的不合理分配,这些 IP 被分配了但当前没有 Service 使用它们。

两种方式:

$ kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
KUBERNETES_SERVICE_PORT=443
MY_NGINX_SERVICE_HOST=10.0.162.149
KUBERNETES_SERVICE_HOST=10.0.0.1
MY_NGINX_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT_HTTPS=443
$ kubectl run curl --image=radial/busyboxplus:curl -i --tty
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
Hit enter for command prompt

然后,按回车并执行命令 nslookup my-nginx:

[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
Server:    10.0.0.10
Address 1: 10.0.0.10

Name:      my-nginx
Address 1: 10.0.162.149

11.3. 调试

$ kubectl get svc my-nginx
NAME       CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
my-nginx   10.0.162.149   <none>        80/TCP    21s
$ kubectl describe svc my-nginx
Name:                my-nginx
Namespace:           default
Labels:              run=my-nginx
Selector:            run=my-nginx
Type:                ClusterIP
IP:                  10.0.162.149
Port:                <unset> 80/TCP
Endpoints:           10.244.2.5:80,10.244.3.4:80
Session Affinity:    None
No events.

$ kubectl get ep my-nginx
NAME       ENDPOINTS                     AGE
my-nginx   10.244.2.5:80,10.244.3.4:80   1m

从相同 Namespace 下的 Pod 中运行:

u@pod$ nslookup hostnames
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local

如果失败,那么您的 Pod 和 Service 可能位于不同的 Namespaces 中,请尝试使用限定命名空间的名称:

u@pod$ nslookup hostnames.default
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local

如果您能够使用完全限定的名称查找,但不能使用相对名称,则需要检查 /etc/resolv.conf 文件是否正确。

u@pod$ cat /etc/resolv.conf
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5
$ kubectl get endpoints hostnames
NAME        ENDPOINTS
hostnames   10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376

这证实 endpoints 控制器已经为您的 Service 找到了正确的 Pods。如果 hostnames 行为空,则应检查 Service 的 spec.selector 字段,以及您实际想选择的 Pods 的 metadata.labels 的值。常见的错误是设置出现了问题,例如 Service 想选择 run=hostnames,但是 Deployment 指定的是 app=hostnames。

确认 kube-proxy 正在您的节点上运行。您应该得到如下内容:

u@node$ ps auxw | grep kube-proxy
root  4194  0.4  0.1 101864 17696 ?    Sl Jul04  25:43 /usr/local/bin/kube-proxy --mas

在某些操作系统是一个文件,如 /var/log/messages kube-proxy.log,而其他操作系统使用 journalctl 访问日志。您应该看到类似的东西:

I1027 22:14:53.995134    5063 server.go:200] Running in resource-only container "/kube-proxy"
I1027 22:14:53.998163    5063 server.go:247] Using iptables Proxier.
I1027 22:14:53.999055    5063 server.go:255] Tearing down userspace rules. Errors here are acceptable.
I1027 22:14:54.038140    5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns-tcp" to [10.244.1.3:53]
I1027 22:14:54.038164    5063 proxier.go:352] Setting endpoints for "kube-system/kube-dns:dns" to [10.244.1.3:53]
I1027 22:14:54.038209    5063 proxier.go:352] Setting endpoints for "default/kubernetes:https" to [10.240.0.2:443]
I1027 22:14:54.038238    5063 proxier.go:429] Not syncing iptables until Services and Endpoints have been received from master
I1027 22:14:54.040048    5063 proxier.go:294] Adding new service "default/kubernetes:https" at 10.0.0.1:443/TCP
I1027 22:14:54.040154    5063 proxier.go:294] Adding new service "kube-system/kube-dns:dns" at 10.0.0.10:53/UDP
I1027 22:14:54.040223    5063 proxier.go:294] Adding new service "kube-system/ku

kube-proxy 无法正确运行的可能原因之一是找不到所需的 conntrack 二进制文件。在一些 Linux 系统上,这也是可能发生的,这取决于您如何安装集群,例如,您正在从头开始安装 Kubernetes。如果是这样的话,您需要手动安装 conntrack 包(例如,在 Ubuntu 上使用 sudo apt install conntrack),然后重试。

11.3.1.1. Userspace

u@node$ iptables-save | grep hostnames
-A KUBE-PORTALS-CONTAINER -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j REDIRECT --to-ports 48577
-A KUBE-PORTALS-HOST -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames:default" -m tcp --dport 80 -j DNAT --to-destination 10.240.115.247:48577

您的 Service 上的每个端口应该有两个规则(本例中只有一个)- "KUBE-PORTALS-CONTAINER" 和 "KUBE-PORTALS-HOST"。如果您没有看到这些,请尝试将 -V 标志设置为 4 之后重新启动 kube-proxy,然后再次查看日志。

几乎没有人应该再使用 "userspace" 模式了,所以我们不会在这里花费更多的时间。

11.3.1.2. Iptables

u@node$ iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNB

KUBE-SERVICES 中应该有 1 条规则,KUBE-SVC-(hash) 中每个 endpoint 有 1 或 2 条规则(取决于 SessionAffinity),每个 endpoint 中应有 1 条 KUBE-SEP-(hash) 链。

检查kube-dns是否正常

kubectl get pods --namespace=kube-system -l k8s-app=kube-dns

kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns
kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq
kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c healthz

kubectl get svc --namespace=kube-system

11.4. 安全连接

生成secret 配置

$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json
$ kubectl create -f /tmp/secret.json
secret "nginxsecret" created
$ kubectl get secrets
NAME                  TYPE                                  DATA      AGE
default-token-il9rc   kubernetes.io/service-account-token   1         1d
nginxsecret           Opaque                                2         1m

security app svr

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: my-nginx
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: nginxhttps
        image: bprashanth/nginxhttps:1.0
        ports:
        - containerPort: 443
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/ssl # 每个容器访问挂载在 /etc/nginx/ssl 卷上的秘钥
          name: secret-volume

客户端

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: curl-deployment
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: curlpod
    spec:
      volumes:
      - name: secret-volume
        secret:
          secretName: nginxsecret
      containers:
      - name: curlpod
        command:
        - sh
        - -c
        - while true; do sleep 1; done
        image: radial/busyboxplus:curl
        volumeMounts:
        - mountPath: /etc/nginx/ssl
          name: secret-volume
$ kubectl create -f ./curlpod.yaml
$ kubectl get pods -l app=curlpod
NAME                               READY     STATUS    RESTARTS   AGE
curl-deployment-1515033274-1410r   1/1       Running   0          1m
$ kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt
...
<title>Welcome to nginx!</title>
...

12. 命令大全

kubectl用于运行Kubernetes集群命令的管理工具。

https://blog.csdn.net/qq_49186423/article/details/128459253

`get      #显示一个或多个资源

`describe  #显示资源详情

`create    #从文件或标准输入创建资源

`edit   #从文件或标准输入更新资源

`delete   #通过文件名、标准输入、资源名或者 label 删除资源

`log       #输出 pod 中一个容器的日志

`rolling-update  #对指定的 RC 执行滚动升级

`exec  #在容器内部执行命令

`port-forward #将本地端口转发到 Pod

`proxy   #为 Kubernetes API server 启动代理服务器

`run     #在集群中使用指定镜像启动容器

`expose   #将 SVC 或 pod 暴露为新的 kubernetes service

`label     #更新资源的 label

`config   #修改 kubernetes 配置文件

`cluster-info #显示集群信息

`api-versions #以"组/版本"的格式输出服务端支持的 API 版本

`version       #输出服务端和客户端的版本信息

`help         #显示各个命令的帮助信息

`ingress-nginx  #管理 ingress 服务的插件(官方安装和使用方式)
# 查看Master状态
kubectl get componentstatuses (简写cs)

# 查看所有命名空间
kubectl get namespace

# 列出所有的pods
kubectl get pods -A

# 显示更多的pods列表信息(例如 pod的ip和所处的node)
kubectl get pods -o wide

# 列出名字为mysql-default-0的rc
kubectl get replicationcontroller mysql-default-0

# 获取名字为mysql-default-0的pod的信息,并以json格式输出
kubectl get -o json pod mysql-default-0

# 根据pod文件查找pod,并以json格式输出
kubectl get -f pod.yaml -o json

# 获取pod容器的状态
kubectl get -o template pod/mysql-default-0 --template {{.status.phase}}

# 同时获取所有的rc和service replicasets (可简写为"rs")
kubectl get rc,services

# 获取符合条件的所有rc,svc,pod
kubectl get rc/web service/frontend pods/mysql-default-0

# 获取指定命名空间的cm configmaps (可简写为"cm")
kubectl get cm -n namespace

# 编辑指定的cm
kubectl edit cm -n namespace cm名称

# 获取指定命名空间的deploy
kubectl get deploy -n namespace

# 编辑指定的deploy
kubectl edit deploy -n namespace deploy名称

# 获取指定命名空间的secrets
kubectl get secrets -n namespace

# 编辑指定的secrets
kubectl edit secrets -n namespace secret名称
z
# 获取所有resource
kubectl get all
1)将pod.json中的配置应用到pod
kubectl apply -f ./pod.json 

2)将控制台输入的JSON配置应用到Pod

cat pod.json | kubectl apply -f -

3)创建资源

kubectl apply -f ./my-manifest.yaml   

4)使用多个文件创建

kubectl apply -f ./my1.yaml -f ./my2.yaml 

5)基于目录下的所有清单文件创建资源

kubectl apply -f ./dir    

6)从 URL 中创建资源

kubectl apply -f https://git.io/vPieo
描述一个node详细信息
kubectl describe nodes ulgqv45xaqziqeri -n defalut

描述一个pod
kubectl describe pods/kube-apiserver-db1 -n kube-system

描述nginx.yaml中的资源类型和名称指定的pod
kubectl describe -f nginx.yaml

描述所有的pod
kubectl describe pods --all-namespaces

描述所有包含label k8s-app=calico-kube-controllers的pod

kubectl describe po -l k8s-app=calico-kube-controllers --all-namespaces
通过配置文件名或stdin创建一个集群资源对象。

支持JSON和YAML格式的文件。

kubectl create -f ./nginx.yaml

通过stdin的JSON创建一个pod。

cat pod.json | kubectl create -f -
# 使用 pod.yaml 文件中指定的类型和名称删除 pod。
kubectl delete -f pod.yaml

# 删除标签名= 的所有 pod 和服务。
kubectl delete pods,services -l name=<label-name>

# 删除所有具有标签名称= 的 pod 和服务,包括未初始化的那些。
kubectl delete pods,services -l name=<label-name> --include-uninitialized

# 删除所有 pod,包括未初始化的 pod。
kubectl delete pods --all
1)编辑名为"mysql"的service

kubectl edit svc/mysql

2)使用替代的编辑器

KUBE_EDITOR="nano" kubectl edit svc/docker-registry

3)编辑名为"myjob"的service,输出JSON格式 V1 API版本

kubectl edit job.v1.batch/myjob -o json

4)以YAML格式输出编辑deployment"mydeployment",并将修改的配置保存在annotation中

kubectl edit deployment/mydeployment -o yaml --save-config
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f

kubectl logs -f <pod_name> # 类似tail -f的方式查看(tail -f 实时查看日志文件 tail -f 日志文件log)
# 例如
kubectl exec my-pod --bash -c 'ps -ef| grep hello'

# 获取命名空间下的POD,进行批量操作
kubectl get pods -o name -n your-namespace |grep -v "demo\|hello" | xargs -I{} kubectl -n your-namespace exec {} -- bash -c  'ps ux|grep ng'
# 启动一个 Nginx 实例。
kubectl run nginx --image=nginx

# 启动一个 hazelcast 单个实例,并开放容器的5701端口。
kubectl run hazelcast --image=hazelcast --port=5701

# 运行一个 hazelcast 单个实例,并设置容器的环境变量"DNS_DOMAIN=cluster" and "POD_NAMESPACE=default"。
kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"

# 启动一个 replicated 实例去复制 nginx。
kubectl run nginx --image=nginx --replicas=5

# 试运行。不创建他们的情况下,打印出所有相关的 API 对象。
kubectl run nginx --image=nginx --dry-run

# 用可解析的 JSON 来覆盖加载 `deployment` 的 `spec`,来运行一个 nginx 单个实例。
kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'

# 运行一个在前台运行的 busybox 单个实例,如果退出不会重启。
kubectl run -i --tty busybox --image=busybox --restart=Never

# 使用默认命令来启动 nginx 容器,并且传递自定义参数(arg1 .. argN)给 nginx。
kubectl run nginx --image=nginx -- <arg1> <arg2> ... <argN>

# 使用不同命令或者自定义参数来启动 nginx 容器。
kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>

# 启动 perl 容器来计算 bpi(2000) 并打印出结果。
kubectl run pi --image=perl --restart=OnFailure -- perl -Mbignum=bpi -wle 'print bpi(2000)'

13. k8s basic

https://www.youtube.com/watch?v=DhvYfNMOh6A&list=PLLasX02E8BPCrIhFrc_ZiINhbRkYMKdPT

13.1. how service mesh work

服务网格实际上谈论的是更像东西向负载均衡。这意味着,我这里有一个服务 S1,我想与另一个服务 S2 进行通信。如何使流量在这两者之间流动? 答案是sidecar,您可以让应用程序开发人员专注于开发他们的应用程序,让服务网格负责将流量代理到世界其他地方。 我不必考虑如何将服务网格整合到我的应用程序中,我只需将其容器添加到我的 Pod 定义中,服务就会自动显示。因为所有这些都发生在本地主机上,我不需要担心证书,或任何其他类型的身份验证,因为网络流量都被限制在 Pod 的内部。

服务网格为您提供的主要特性是什么?嗯,有三个。

第一个是授权的概念,基本上是服务授权。基本上是说,"那么,如果我是服务一,我能与服务二交流吗"。另一方面,如果我是服务一,服务三能与我交流吗。 这在建立最低权限和其他类型的访问控制方面非常有用。

第二件事是实验或金丝雀。所以如果我是服务一,我要与服务二交流,可能有两个不同版本的服务二。他们可能是服务V1,也可能是服务 V2,这是我将要推出的服务的下一个版本。现在我可能想要进行实验,说,"我希望我的 99% 流量发送到生产"。我知道它可以工作的服务v1的版本,但我想进行一个百分之一的实验将流量发送到另一个版本。测试一段时间。也许是为了看看它是否正确工作。 因为再次在这个边车中,它为您代理,当它进行代理时,它可以将 99% 的流量发送到一个方向,将 1% 的流量发送到另一个方向。重要的是应用程序甚至不知道这种区别。

服务网格为您提供的第三件事是,如果您有您的应用程序和服务网格,并且通过该代理进行通信,这个代理实际上可以收集大量的指标。它可以收集诸如延迟、HTTP 错误、用户代理等许多对您有用的指标(如果您正在抛出 500,特定请求需要多长时间,什么样的客户端正在与您交流?),然后将这些内容推送到类似 Azure 监控的度量服务器,或开源项目如 Prometheus

服务网格接口,或 SMI。SMI 是一组 API,它们向 Kubernetes 注册。然后有实现这些内容的提供者。

因此您可以让 Consul 实现这些 API。您可以让 Istio 实现这些 API。您可以让 Linkerd 实现这些 API。

13.2. Simple Application Management on k8s with Operators

Kubernetes Operator 是一个重要的 Kubernetes 组件,它允许开发者封装和自动化整个应用程序的部署、管理和运维任务。通过 Operator,可以将专业知识和操作流程编码成软件,以便高效地管理在 Kubernetes 上运行的应用。

  1. 定义自定义资源(CRD):Operator 首先需要定义一种或多种自定义资源,这些资源代表了要管理的应用程序或服务的配置和状态。
  2. 实现自定义控制器:控制器是 Operator 的核心,负责监控指定的资源,当资源状态发生变化时,控制器会根据资源的当前状态和期望状态来调整,确保应用或服务处于正确的状态。
  3. 自动化操作逻辑:控制器中会编码应用管理的业务逻辑,如升级、备份、恢复等操作,这些逻辑以前可能需要人工介入执行,现在可以自动完成。

13.3. Monitoring and Alerting

Kubernetes本身实际上提供了大量的可立即使用的指标,Kubernetes指标,这非常棒,因为这意味着您不必为端口、CPU、内存、网络使用或磁盘设置监控,所有这些信息都是从运行在机器上的容器中自动获取并推送到Kubernetes指标服务器中的。从那里,它们可以被推送像Prometheus这样的开源监控解决方案中。因此,只需将您的容器部署到Kubernetes中,您就可以访问大量监控信。

通常,这类似于延迟,并且您将设置一些目标。您将设置一个SLO或服务水平目标,比如说,"我认为在99分位数时,我的延迟应该小于500毫秒。" 这一点非常重要,因为在测量平均值或中间50分位数时是有趣的,但实际上它可能掩盖了很多很糟糕的问题。因为如果您在平均值上还好,但是每100次中有一次非常缓慢,那么您仍然会给一个客户提供一个非常糟糕的客户体验,并且随着时间的推移,实际上数字法则表明每个客户都会有这种糟糕的体验。因此,我们既关注平均值,但更重要的是关注99分位数,以便真正了解我们的服务在规模上的表现如何。

13.4. Pod Lifecycle

Kubernetes中,一个Pod是调度的原子单位。它可以包含一个或多个容器。可能是像一个Web服务器和一个辅助容器这样的东西。我们不会太多地讨论容器本身,但我们要讨论的是当你创建那个Pod时会发生什么。在Kubernetes中,它的生命周期是如何工作的呢?

Pending 意味着Kubernetes API已经接受了你的Pod。它准备就绪,但它还没有被调度到一个机器上。你可能有多个正在运行的虚拟机,可以运行那个Pod。有调度程序,负责查看各种资源,也许一个CPU和两个G的内存,并找到一个特定机器上的Pod的位置。所以一旦发生了这种情况,一旦调度程序说,嘿,这个Pod正在运行,比方说在节点3上。一旦它说Pod正在节点3上运行,它就会从Pending状态转变到Creating状态。

Creating状态是怎么回事呢?首先发生的事情显然是需要拉取镜像。现在,镜像可能在某个基于云的存储库中。也许它在Azure容器注册表中。所以正在发生的事情是节点本身正在到Azure容器注册表中去,将镜像拉取到节点上。现实中,Kubernetes更倾向于将容器调度到镜像已经存在的节点上。所以如果镜像已经存在于这个节点上,这个拉取步骤将被跳过,因为如果镜像已经存在,显然就没有必要再次拉取。好了,一旦容器镜像被拉取,容器就会转变为运行状态。一旦容器处于运行状态,你的程序就启动运行了,一切都在愉快地运行着。但是当然,坏事也可能发生,你的容器可能会崩溃。所以我们在这个容器内运行一个进程。如果碰巧崩溃了,Kubernetes会重新启动它。所以当它重新启动时,如果它重新启动了太多次,你的Pod可能会进入一个叫做CrashLoopBackOff的状态。这实际上意味着,嘿,我看到你的容器崩溃了太多次,而不是徒劳地一次又一次地重新启动它,这需要很多资源,而且需要CPU来维护其他Pod的Kubelet可能正在使用的资源。实际上,它会退后一步。它会说,"嘿,我曾经试图立即重新启动它,现在也许我会等待10秒。如果失败了,也许我会等待20秒,依此类推。所以当你运行kube control get pods时,你会看到所有这些状态,包括pending、running和CrashLoopBackOff。

Pod生命周期还有一些更高级的部分。特别是,人们最常做的事情是你可以开始挂载健康事件。所以你可以为Pod添加生命周期事件,例如健康或就绪。当你将这些URL附加到Pod时,Kubelet会使用这些URL来测试你的Pod是否健康。如果不健康,如果返回的不是200,它将重新启动你的Pod,就像它崩溃了一样,并且如果发生次数过多,会导致CrashLoopBackOff。如果检查就绪性,它将确定是否将其添加到负载均衡中。此外,Pod本身还有一些生命周期钩子,用于帮助你与其他事物集成。第一个是post start。这是一个你可以注册的webhook。这个webhook会在你的容器启动后立即调用。然后是pre-stop,它会在你的容器终止之前立即调用。所以如果你想在启动后执行某些操作,你可以注册一个post start钩子。如果你想在容器终止之前执行某些操作,你可以注册一个pre-stop钩子。与生命周期集成的另一个部分是你实际上可以在你的Pod中定义一个init容器。这是一个单独的容器镜像。它的工作是在你的Pod中的所有其他容器启动之前提供一定程度的初始化。所以如果你指定了一个init容器,那么这个容器将首先运行到完成。如果返回为0,那么你的Pod中的所有其他容器将开始运行。这是一个很好的方法,可以用来做一些像模式迁移或从一些存储帐户中下载文件等初始化工作,以便在启动Pod之前完成。

13.5. Admissing Controller

我们开始讨论准入控制器

我想首先从简要概述当请求进入 Kubernetes 时的样子开始。 基本上有三个部分。显然是发出 API 调用的人或潜在的自动化,这会发送给 API 服务器,最终发送到 etcd 数据库。

在 API 服务器内部,有代码用于进行授权的 RBAC,也进行身份验证。这使您可以说,"嘿,这个用户可以或不可以在集群中执行某些操作",但是可能有很多您希望执行的内容,这些内容涉及修改或验证 API 对象,查看 API 对象本身的内容以便做出决策,甚至进行修改,这就是入场控制器的作用。因此,入场控制器是在认证和授权之后发生的事情,用户经过授权后会调用入场控制器,这些通常是 Web 钩子,因此您可以动态注册入场控制器。

Kubernetes 构建策略,使用验证入场控制器将其整合到 Kubernetes 中。使用像开放策略代理人团队的 RegO 这样的策略引擎,您实际上可以说,我希望每个副本集必须至少有三个副本。这是您无法通过授权或身份验证表达的内容,但是这是您可以通过策略表达的内容。显然,这是因为您希望确保某人在复制其应用程序以提高可靠性时做得很好。您还可以说,我的 Kubernetes 集群中的每个对象都必须具有资源所有者的电子邮件的注释。当您构建自动化程序时,例如提醒某人可能有一个需要删除的资源或一个存在问题的资源时,这变得非常有价值。在系统中具有这种标准化的元数据使得构建自动化变得更加容易,而确保人们这样做的唯一方式是通过策略,因此如果他们没有这样做并且他们没有在请求中包含这一点,请求将被拒绝。显然,构建入场控制器可能是一件复杂的事情。像 Gatekeeper 这样的项目的伟大之处在于,它们会自动为您集成入场控制,您只需要在集群中安装它们。

一个典型的变更入场控制器的示例是说,"嘿,我们将添加默认 CPU 限制"。当有人创建一个 pod 时,他们没有提供 CPU 和内存资源的一组,我们会为他们设置一些默认值。也许我们会将默认请求设置为一个内核和两个千兆字节的内存,这只是为了确保用户能够愉快地使用。因为如果您创建一个 pod 而不指定资源限制,一般来说 Kubernetes 将会过度包装和过载集群,事情会开始崩溃,应用程序将无法正常工作。因此,通过变更入场控制器,我们帮助用户找到快乐的路径,而不是让他们陷入会对其应用程序和用户造成实际损害的地方。另一个流行的变更入场控制器的示例是服务网格。现在,服务网格通常涉及与您的应用程序容器相邻的一些 Sidecar 容器,将该 Sidecar 注入的最简单方法是使用变更入场控制器来修改用户创建的 pod 以添加该 Sidecar。这样,您不必教育应用程序开发人员,也不必更改应用程序本身的任何配置,就可以将该 Sidecar 应用于他们创建的所有 pod。同样,如果您需要从特定容器的版本 1 到版本 2,如果您通过变更入场控制器进行集中处理和标准化,您就可以确保更改每个人都在使用的版本,而无需要求每个人都去更改他们的 YAML 文件。

13.6. Getting production ready in Kubernetes

如何将系统投入生产并考虑到Ingress安全Namespaces的信息 ?

你应该考虑的事项非常广泛,所以我们来谈谈一些一般性的领域。

首先要考虑的是你的集群本身,记住你的集群API以及集群中的内容、集群中的机器都是应用程序的安全边界。

因此,你需要考虑如何正确地保护这个集群。一定要考虑RBAC,以及谁有权限访问该集群。例如,你可能希望区分开具有读取权限的开发人员和具有写入权限的操作员。

仔细考虑指向你的Kubernetes集群的CICD管道,这是代码能够推送到集群的唯一方式,确保你可以在这里进行验证、漏洞检测的流程。同样,你应该考虑通过DaemonSet在集群本身上运行入侵检测和漏洞检测,这样你就可以找到集群中存在的问题。

当然,安全只是其中的一部分。你还需要考虑如何正确地操作这个集群?

你可以直接通过DaemonSet将这些东西( ELK)安装到集群上,确保你有所有这些措施,这样当出现问题时,你不必慌乱地想办法如何监控它,而是要着手解决问题。

故障转移,显然你应该在不止一个地区。

因此,如果你在区域一有一个集群,在区域二有一个集群,并且在发生灾难时要从区域一切换到区域二,你应该考虑练习这个,确保你实际上能够做到。 那么你需要能够从DNS系统和你的集群这里进行适当的健康检查,这样如果发生了不好的事情,它将会将流量从美国转移到你的欧洲集群。同样,如果你在这里有数据存储,你需要考虑如何在这两个地点之间复制数据

13.7. RBAC

在最简单的层面上,您显然不希望这个人无意干扰另一个人。例如,一个开发人员可能会无意中删除其他人的工作或者获取正在开发的可能是机密的项目的可见性。有许多原因让您希望将您的 Kubernetes 切分为一个用户可以看到的地方,另一个用户可以看到的地方,并且让他们无法窥视彼此的工作。当您考虑到开发人员、运维人员、集群管理员之间的差异时,就更加清楚,这些不同类型的角色需要与 Kubernetes 集群内的不同能力相关联,这就是 RBAC 或基于角色的访问控制的概念发挥作用的地方。

基于角色的访问控制中的角色定义了一个动作的概念,比如获取或列出,以及一组名词,比如 pod、卷等。因此,一个角色定义了对一组资源可以执行的操作。

一个角色定义了对一组资源可以执行的操作。这是 Kubernetes 中的一个资源,就像其他所有内容一样。因此,这是一个 restful 资源,预定义了许多这样的资源,您也可以使用 YAML 文件自己创建它们。因此,您可以将任意一组特权表示为 Kubernetes 集群内的资源。但是,仅有角色本身并不实际授予任何权限,因为我们尚未将此角色与可能发出 API 调用的任何人相关联,这就是绑定发挥作用的地方。因此,您可以创建一个角色绑定,它基本上是一个人(比如我)和一个特定角色(比如集群管理员)之间的映射。因此,角色绑定将这两个部分结合在一起,因此,我具有此角色中定义的特权。现在,我可以有多个角色。我还可以获得编辑权限,或者任何经过设计的自定义角色。我可以访问任意数量的角色,您还可以使用组。实际上,通常这是管理事物的更好方法,如果您定义一个组。例如,开发团队,您可以将该开发团队与特定角色关联起来。通过这种方式,加入该团队或者离开该团队的任何人都会获得或丧失对那些特定特权的访问。

因此,您实际上可以说某人不仅可以访问 pod,还可以只能访问"my-team"命名空间中的 pod,因此您可以限制,"your-team"。我可能可以访问"my-team"中的 pod,但我无法访问"your-team"中的 pod。您可以通过在此命名空间内创建角色绑定来实现此目的。因此,您可以创建两种不同类型的角色绑定。一种是集群角色绑定,显然,根据其名称,集群角色绑定为整个集群提供权限。它可以为集群资源提供权限,也可以为集群中任何命名空间内的资源提供权限。显然,集群角色绑定非常强大,您需要谨慎地应用它们,因为它们不仅适用于任何现有的命名空间,还适用于您可能创建的任何未来的命名空间。还有角色绑定,它们在特定命名空间的上下文中提供特权。因此,显然,集群角色绑定是一个集群级对象,角色绑定是一个命名空间对象。因此,例如,如果我有"my-team"命名空间,如果我在此处创建一个绑定到编辑角色的角色绑定。这为我提供了能力,如果它是在编辑和我的之间的角色绑定,这为我提供了在此命名空间的上下文中进行编辑的权限,而不是在其他任何命名空间。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # 空字符串""表明使用core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: Caden
 apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io


# ClusterRoleBinding在整个集群级别和所有namespaces将特定的subject与ClusterRole绑定,授予权限

[root@master pos]# kubectl config use-context Caden@kubernetes  #Caden
Switched to context "Caden@kubernetes".
[root@master pos]# kubectl get pods  #请求pods资源,可看到
NAME                            READY   STATUS    RESTARTS   AGE
Caden-deploy-654cd9c85c-d4xc4   1/1     Running   0          44h
Caden-deploy-654cd9c85c-lhsfl   1/1     Running   0          44h
[root@master pos]# kubectl get svc   #请求svc资源,被拒绝
Error from server (Forbidden): services is forbidden: User "Caden" cannot list resource "services" in API group "" in the namespace "default"

13.8. How Configuration Management works

13.9. secrets management

你好,我是来自Microsoft Azure的Brendan Burns。我将讨论Kubernetes中的密码管理。显然,在Kubernetes中,应用程序的基本单位是一个Pod,该Pod内部包含多个容器。但是当其中一个容器需要访问一个密码时会发生什么呢?好吧,一个密码可能是数据库的密码,也可能是访问API或将应用程序提供到Web上所需的证书。幸运的是,Kubernetes实际上内置了密码管理。因此,您实际上可以声明一个密码资源,而在Kubernetes中,密码实际上是一组键值对,并且您可以在特定密码的上下文中实际上有多个键值对。您还可以将值用作文件的内容。因此,在某些情况下,键值对可能是类似于DB密码是foo的内容,这不是我的真实数据库密码,所以请不要尝试使用它。或者它可能是证书,并且这将是文件的内容。好的。那么现在我们如何将这两个东西联系在一起呢?好吧,我们将一个密码放入一个Pod中使用一个卷。因此,您实际上可以在Pod的卷列表中声明密码卷,然后说,"嘿,你知道吗,我想将这个卷挂载到容器的特定路径中"比如说/certs。这样,如果您有类似Nginx Web服务器的东西,它可以查找这个certs目录,找到它需要的证书,以便安全地为您的应用程序提供服务。同样,您还可以将一个密码作为环境变量挂载进来。因此,在您的代码中,您可能会说类似于getenv("DB_password")。这样,您可以从存在于Pod上下文中的环境变量加载数据库密码。因此,取决于您希望如何使用该密码,您可以选择将其表示为文件或表示为环境变量。现在,当我们考虑密码时,需要注意的一件事是,密码本身的内容以未加密形式存储在Kubernetes中的etcd中。这意味着每个访问etcd的人潜在地都可以访问您的密码。显然,对于一些人来说,这是一个值得关注的问题,特别是当您处于需要非常小心处理密码的高安全性情况时。因此,最近在Kubernetes中开发了密钥管理故事集成,以便您实际上可以提供一个加密密钥到该etcd数据库。因此,您实际上可以将您的Kubernetes API服务器与密钥管理存储(例如Azure Key Vault或HashiCorp Vault)集成,或者任何一种密钥管理存储。它实际上会从该密钥管理存储中获取一个密钥,并在存储到etcd之前加密您的密码。这意味着即使有人获得了etcd后面的数据存储的访问权限,它们也会使用您在此处的密钥进行加密,显然您也会在这里有访问控制,以限制访问该密钥的人数。值得注意的是,然而,任何具有对Kubernetes API的访问权限的人可能也有能力访问这些密码。因此,您显然也希望在Kubernetes API上使用基于资源的访问控制,以确保只有正确的人可以访问您放入Kubernetes上下文中的密码。尽管如此,这给了您一个关于如何管理应用程序密码的想法,显然,最佳做法是使用这些密码,而不是将那些凭据存储在您的docker镜像,源代码控制或其他任何地方。因此,请学习并使用它来安全地部署密码到您的应用程序。

13.10. stateful applications

你好。我来自Microsoft Azure的Brendan Burns,我将讨论Kubernetes中有状态应用程序的基础知识。因此,对于任何有状态的应用程序,您需要考虑如何实现数据弹性和数据复制。在某些情况下,像MySQL这样的应用程序实际上是相当难以进行数据复制的。您可以使用集群化的MySQL,但这并不是标准设置。考虑到这一点,在Kubernetes中,您可能会做与通常情况下处理MySQL相同的事情,并运行与持久卷相关联的MySQL服务器的单个实例。这个持久卷将附加到基于云的存储,比如Azure Disk,或者在本地部署时,可能会附加到类似ISCSI的存储设备。无论哪种情况,这将负责维护您的应用程序的状态,即使您的MySQL pod不得不从一台机器移动到另一台机器。

但是,当我们开始考虑更多云原生应用程序时,比如Cassandra或MongoDB,那里复制更容易实现,那么我们需要开始考虑Kubernetes内部的基本构件。现在,当Kubernetes开始时,您可以使用名为副本集的东西来进行复制。使用副本集时,每个副本都被视为完全相同。它们的应用程序名称末尾有随机哈希值。如果发生扩展事件,例如扩展减少,随机选择一个容器并删除。这些特征使得副本集非常难以映射到有状态应用程序。特别是,许多有状态应用程序希望它们的主机名保持不变。有时您需要找到一个主节点或根节点来启动,一个种子节点来启动。因此,使用副本集和有状态应用程序的这些复杂性导致了最终开发出有状态集。在Kubernetes中的有状态集类似于副本集,但它增加了一些保证,使得在Kubernetes内部管理有状态应用程序变得更容易。特别是,有状态集中的副本具有索引。因此,我们知道这是副本零。您知道这是副本一。您知道这是副本二。它们具有稳定的主机名。例如,像我的服务器零等。当Kubernetes决定扩展或缩减有状态集时,它会以一种被充分理解的方式执行。例如,当您最初创建有状态集时,将创建第一个副本,Kubernetes会等待其变为健康和可用状态,然后才创建第二个副本。这意味着当第二个副本正在创建时,您可以依赖于零索引可供您连接。同样,当第一个副本变为健康时,将创建下一个副本,同样可以指向有状态集的原始成员。这使得更容易会合,声明初始领导者,以及创建有状态应用程序时需要的许多其他功能。同样,当您缩减规模时,Kubernetes也会从最高索引开始删除。因此,如果您将这个从三个副本缩减到两个副本,它将从这里的副本索引二开始减少。

有状态集还提供了开发DNS名称的功能,这些DNS名称实际上会指向单个副本。因此,使用副本集时,您可能会有一个服务,并且它将指向一个副本集。也许这称为前端。这将创建一个DNS条目,但它只会为前端创建一个DNS条目。如果您使用有状态集,您实际上可以创建一个服务,以便为Cassandra创建一个DNS条目,它将指向Cassandra集群的任何副本,但您还将获得cassandra zero.cassandra的DNS条目,以及类似的dash one和dash two,对于每个副本。这意味着如果您不关心要访问有状态应用程序的哪个副本,例如,从这个Cassandra集群中读取,您始终可以使用这个服务,您将获得负载均衡和您期望的其他所有内容。但是,如果您需要知道特定的副本,您仍然可以使用命名来发现有状态集中每个特定索引的指针。这也使得更容易配置您的应用程序,配置可能需要显式列表的客户端。因为这个主机名也是稳定的,无论您如何扩展或缩减,您可以确保这些DNS名称将始终保持恒定,只要有状态集存在。当然,当您创建这些有状态集时,您也将考虑到持久性。在某些情况下,使用本地持久性可能是可以接受的。那里有一些云原生存储应用程序,Cassandra就是一个很好的例子,在这些应用程序之间实际上正在进行复制。在那种情况下,您可能不需要使用持久卷,因为数据本身在集群的所有成员之间进行了复制。但是,如果您选择使用持久卷,您将需要使用持久卷声明。在您的有状态集上下文中,持久卷声明,这样当创建该有状态集并创建每个副本时,Kubernetes将为有状态集中的每个副本创建不同的磁盘。希望这给您展示了在Kubernetes中如何开发有状态应用程序,您可以使用传统有状态应用程序的单例模式或者Kubernetes中提供的有状态集资源,无论是否使用持久卷,来在Kubernetes中开发有状态应用程序。

13.11. How volumes and storage work

13.12. Setting up a Kubernetes build pipeline

14. 最佳实践

14.1. 计算存储网络监控

Heapster 汇聚整个集群范围内的所有监控和事件数据。当前,Heapster 原生支持 Kubernetes 并且可以在所有 Kubernetes 安装中运行。 与普通 Kubernetes 应用类似, Heapster 在集群中以 pod 形式运行。Heapster pod 自动发现集群中所有节点并从节点上运行的 Kubernetes 代理进程 (Kubelet) 中查询资源使用信息。 Kubelet 则从 cAdvisor 获取数据。Heapster将收集的信息按照 pod 及其相关标签进行分组,然后将其推送到用于存储和可视化的后端中。

14.2. TLS管理

每个 Kubernetes 集群都有一个集群根证书颁发机构(CA)。 集群中的组件通常使用 CA 来验证 API server 的证书,由API服务器验证 kubelet 客户端证书等。为了支持这一点,CA 证书包被分发到集群中的每个节点,并作为一个 sercret 附加分发到默认 service account 上。 或者,您的工作负载可以使用此 CA 建立信任。 您的应用程序可以使用类似于 ACME草案 的协议,使用 certificates.k8s.io API 请求证书签名。

14.3. 同pod内通信

volumes:
  - name: shared-data
    emptyDir: {}

  containers:

  - name: nginx-container
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html

  - name: debian-container
    image: debian
    volumeMounts:
    - name: shared-data
      mountPath: /pod-data

14.4. service连接前后端

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 7
  template:
    metadata:
      labels:
        app: hello
        tier: backend
        track: stable
    spec:
      containers:
        - name: hello
          image: "gcr.io/google-samples/hello-go-gke:1.0"
          ports:
            - name: http
              containerPort: 80


# kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/hello.yaml
# kubectl describe deployment hello


kind: Service
apiVersion: v1
metadata:
  name: hello
spec:
  selector:
    app: hello
    tier: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: http

# kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/hello-service.yaml 



upstream hello {
    server hello;
}

server {
    listen 80;

    location / {
        proxy_pass http://hello;
    }
}

kind: Service
apiVersion: v1
metadata:
  name: frontend
spec:
  selector:
    app: hello
    tier: frontend
  ports:
    - protocol: "TCP"
      port: 80
      targetPort: 80
  type: LoadBalancer
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
        tier: frontend
        track: stable
    spec:
      containers:
        - name: nginx
          image: "gcr.io/google-samples/hello-frontend:1.0"
          lifecycle:
            preStop:
              exec:
                command: ["/usr/sbin/nginx","-s","quit"]

kubectl get service frontend

NAME       CLUSTER-IP      EXTERNAL-IP        PORT(S)  AGE
frontend   10.51.252.116   XXX.XXX.XXX.XXX    80/TCP   1m

curl http://<EXTERNAL-IP>

{"message":"Hello"}

14.5. pod应用排查指南

14.5.1. 分诊

  • 调试 Pod

  • 调试副本控制器

  • 调试服务

    $ kubectl describe pods ${POD_NAME}

查看 pod 中容器的状态。它们都是Running?最近有没有重新启动?

如果 pod 卡在 Pending 状态,意味着它不能被调度到节点上。通常这是因为没有足够的资源导致调度被阻止了。查看 kubectl describe ... 命令的输出。应该有来自调度器说明为什么它无法调度您的 pod 的消息。原因包括:

  • 您没有足够的资源:您可能已经耗尽了集群中 CPU 或内存的供应,在这种情况下,您需要删除 Pod、调整资源请求或向集群添加新节点。
  • 您正在使用 hostPort:当您将 Pod 绑定到一个 hostPort,可调度的 pod 的数量是有限的。在大多数情况下,hostPort 是不需要的,可以尝试使用 Service 对象来暴露您的 Pod。如果您确实需要 hostPort,那么您只能调度与 Kubernetes 集群中节点数量相同的 Pod。

pod 一直是 waiting 状态

如果一个 Pod 停留在 Waiting 状态,则它已被调度到一个工作节点,但不能在该机器上运行。同样,来自 kubectl describe ... 命令的信息应该是可以分析其原因的。Waitingpod 最常见的原因是无法拉取镜像。有三件事要检查:

  • 确保您有正确的镜像名称。
  • 您是否将镜像推送到仓库?
  • 在您的机器运行 docker pull <image>,查看镜像是否能够拉取。

pod崩溃

$ kubectl logs ${POD_NAME} ${CONTAINER_NAME}

rc日志

kubectl describe rc ${CONTROLLER_NAME}

调试服务

kubectl get endpoints ${SERVICE_NAME}

$ kubectl get pods --selector=name=nginx,type=frontend

14.5.2. 网络流量未被转发

  • 您的 pod 工作正常吗?查找重新启动次数,并 调试 pod。
  • 您可以直接连接到您的 pod 吗?获取 Pod 的 IP 地址,并尝试直接连接到该 IP。
  • 您的应用是否在您配置的端口上运行?Kubernetes 不会执行端口重映射,所以如果您的应用在 8080 上运行,则该 containerPort 字段需要为8080。

14.6. k8s审计

Kubernetes 审计功能提供了与安全相关的按时间顺序排列的记录集,记录单个用户、管理员或系统其他组件影响系统的活动顺序。 它能帮助集群管理员处理以下问题:

  • 发生了什么?
  • 什么时候发生的?
  • 谁触发的?
  • 为什么发生?
  • 在哪观察到的?
  • 它从哪触发的?
  • 它将产生什么后果?

您可以使用 --audit-policy-file 标志将包含策略的文件传递给 kube-apiserver。如果不设置该标志,则不记录事件。 注意: kind 和 apiVersion 字段以及 rules 必须 在审计策略文件中提供。没有(0)规则的策略或者不提供有效的 apiVersion 和 kind 值的策略将被视为非法配置。

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| apiVersion: http://audit.k8s.io/v1beta1 # This is required. kind: Policy # Don't generate audit events for all requests in RequestReceived stage. omitStages: - "RequestReceived" rules: # Log pod changes at RequestResponse level - level: RequestResponse resources: - group: "" # Resource "pods" doesn't match requests to any subresource of pods, # which is consistent with the RBAC policy. resources: ["pods"] # Log "pods/log", "pods/status" at Metadata level - level: Metadata resources: - group: "" resources: ["pods/log", "pods/status"] # Don't log requests to a configmap called "controller-leader" - level: None resources: - group: "" resources: ["configmaps"] resourceNames: ["controller-leader"] # Don't log watch requests by the "system:kube-proxy" on endpoints or services - level: None users: ["system:kube-proxy"] verbs: ["watch"] resources: - group: "" # core API group resources: ["endpoints", "services"] # Don't log authenticated requests to certain non-resource URL paths. - level: None userGroups: ["system:authenticated"] nonResourceURLs: - "/api*" # Wildcard matching. - "/version" # Log the request body of configmap changes in kube-system. - level: Request resources: - group: "" # core API group resources: ["configmaps"] # This rule only applies to resources in the "kube-system" namespace. # The empty string "" can be used to select non-namespaced resources. namespaces: ["kube-system"] # Log configmap and secret changes in all other namespaces at the Metadata level. - level: Metadata resources: - group: "" # core API group resources: ["secrets", "configmaps"] # Log all other resources in core and extensions at the Request level. - level: Request resources: - group: "" # core API group - group: "extensions" # Version of group should NOT be included. # A catch-all rule to log all other requests at the Metadata level. - level: Metadata # Long-running requests like watches that fall under this rule will not # generate an audit event in RequestReceived. omitStages: - "RequestReceived" |

您可以使用最低限度的审计策略文件在元数据级别记录所有请求:

# Log all requests at the Metadata level.
apiVersion: audit.k8s.io/v1beta1
kind: Policy
rules:
- level: Metadata

Log 后端将审计事件写入 JSON 格式的文件。您可以使用以下 kube-apiserver 标志配置 Log 审计后端:

  • --audit-log-path 指定用来写入审计事件的日志文件路径。不指定此标志会禁用日志后端。- 意味着标准化
  • --audit-log-maxage 定义了保留旧审计日志文件的最大天数
  • --audit-log-maxbackup 定义了要保留的审计日志文件的最大数量
  • --audit-log-maxsize 定义审计日志文件的最大大小(兆字节)

检查 /var/log/audit-*.log 中不同命名空间的审计内容

我们可以用fluentd 来采集和收集日志

14.7. kubectl备忘录

kubectl自动补全

设置 kubectl 与其通信的 Kubernetes 集群

$ kubectl config view # 显示合并的 kubeconfig 设置。

# 同时使用多个 kubeconfig 文件,并且查看合并的配置
$ KUBECONFIG=~/.kube/config:~/.kube/kubconfig2 kubectl config view

# 查看名称为 "e2e" 的用户的密码
$ kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'

$ kubectl config current-context              # 显示当前上下文
$ kubectl config use-context my-cluster-name  # 设置默认的上下文为 my-cluster-name

# 在 kubeconf 中添加一个支持基本鉴权的新集群。
$ kubectl config set-credentials kubeuser/foo.kubernetes.com --username=kubeuser --password=kubepassword

# 使用特定的用户名和命名空间设置上下文。
$ kubectl config set-context gce --user=cluster-admin --namespace=foo \
  && kubectl config use-context gce

Kubernetes 清单可以用 json 或 yaml 来定义。使用的文件扩展名包括 .yaml, .yml 和 .json。

$ kubectl create -f ./my-manifest.yaml           # 创建资源
$ kubectl create -f ./my1.yaml -f ./my2.yaml     # 从多个文件创建资源
$ kubectl create -f ./dir                        # 通过目录下的所有清单文件创建资源
$ kubectl create -f https://git.io/vPieo         # 使用 url 获取清单创建资源
$ kubectl run nginx --image=nginx                # 开启一个 nginx 实例
$ kubectl explain pods,svc                       # 获取 pod 和服务清单的描述文档

# 通过标准输入创建多个 YAML 对象
$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-sleep
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000000"
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox-sleep-less
spec:
  containers:
  - name: busybox
    image: busybox
    args:
    - sleep
    - "1000"
EOF

# 使用多个 key 创建一个 secret
$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: $(echo -n "s33msi4" | base64)
  username: $(echo -n "jane" | base64)
EOF
# 具有基本输出的 get 命令
$ kubectl get services                          # 列出命名空间下的所有 service
$ kubectl get pods --all-namespaces             # 列出所有命名空间下的 pod
$ kubectl get pods -o wide                      # 列出命名空间下所有 pod,带有更详细的信息
$ kubectl get deployment my-dep                 # 列出特定的 deployment
$ kubectl get pods --include-uninitialized      # 列出命名空间下所有的 pod,包括未初始化的对象

# 有详细输出的 describe 命令
$ kubectl describe nodes my-node
$ kubectl describe pods my-pod

$ kubectl get services --sort-by=.metadata.name # List Services Sorted by Name

# 根据重启次数排序,列出所有 pod
$ kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'

# 查询带有标签 app=cassandra 的所有 pod,获取它们的 version 标签值
$ kubectl get pods --selector=app=cassandra rc -o \
  jsonpath='{.items[*].metadata.labels.version}'

# 获取命名空间下所有运行中的 pod
$ kubectl get pods --field-selector=status.phase=Running

# 所有所有节点的 ExternalIP
$ kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'

# 列出输出特定 RC 的所有 pod 的名称
# "jq" 命令对那些 jsonpath 看来太复杂的转换非常有用,可以在这找到:https://stedolan.github.io/jq/
$ sel=${$(kubectl get rc my-rc --output=json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"')%?}
$ echo $(kubectl get pods --selector=$sel --output=jsonpath={.items..metadata.name})

# 检查那些节点已经 ready
$ JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \
 && kubectl get nodes -o jsonpath="$JSONPATH" | grep "Ready=True"

# 列出某个 pod 目前在用的所有 Secret
$ kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq

# 列出通过 timestamp 排序的所有 Event
$ kubectl get events --sort-by=.metadata.creationTimestamp
$ kubectl rolling-update frontend-v1 -f frontend-v2.json           # 滚动更新 pod:frontend-v1
$ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2  # 变更资源的名称并更新镜像
$ kubectl rolling-update frontend --image=image:v2                 # 更新 pod 的镜像
$ kubectl rolling-update frontend-v1 frontend-v2 --rollback        # 中止进行中的过程
$ cat pod.json | kubectl replace -f -                              # 根据传入标准输入的 JSON 替换一个 pod

# 强制替换,先删除,然后再重建资源。会导致服务中断。
$ kubectl replace --force -f ./pod.json

# 为副本控制器(rc)创建服务,它开放 80 端口,并连接到容器的 8080 端口
$ kubectl expose rc nginx --port=80 --target-port=8000

# 更新单容器的 pod,将其镜像版本(tag)更新到 v4
$ kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -

$ kubectl label pods my-pod new-label=awesome                      # 增加标签
$ kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq       # 增加注释
$ kubectl autoscale deployment foo --min=2 --max=10                # 将名称为 foo 的 deployment 设置为自动扩缩容
$ kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' # 部分更新节点

# 更新容器的镜像,spec.containers[*].name 是必需的,因为它们是一个合并键
$ kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'

# 使用带有数组位置信息的 json 修补程序更新容器镜像
$ kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'

# 使用带有数组位置信息的 json 修补程序禁用 deployment 的 livenessProbe
$ kubectl patch deployment valid-deployment  --type json   -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'

# 增加新的元素到数组指定的位置中
$ kubectl patch sa default --type='json' -p='[{"op": "add", "path": "/secrets/1", "value": {"name": "whatever" } }]'
$ kubectl scale --replicas=3 rs/foo                                 # 缩放名称为 'foo' 的 replicaset,调整其副本数为 3
$ kubectl scale --replicas=3 -f foo.yaml                            # 缩放在 "foo.yaml" 中指定的资源,调整其副本数为 3
$ kubectl scale --current-replicas=2 --replicas=3 deployment/mysql  # 如果名称为 mysql 的 deployment 目前规模为 2,将其规模调整为 3
$ kubectl scale --replicas=5 rc/foo rc/bar rc/baz                   # 缩放多个副本控制器
$ kubectl logs my-pod                                 # 转储 pod 日志到标准输出
$ kubectl logs my-pod -c my-container                 # 有多个容器的情况下,转储 pod 中容器的日志到标准输出
$ kubectl logs -f my-pod                              # pod 日志流向标准输出
$ kubectl logs -f my-pod -c my-container              # 有多个容器的情况下,pod 中容器的日志流到标准输出
$ kubectl run -i --tty busybox --image=busybox -- sh  # 使用交互的 shell 运行 pod
$ kubectl attach my-pod -i                            # 关联到运行中的容器
$ kubectl port-forward my-pod 5000:6000               # 在本地监听 5000 端口,然后转到 my-pod 的 6000 端口
$ kubectl exec my-pod -- ls /                         # 1 个容器的情况下,在已经存在的 pod 中运行命令
$ kubectl exec my-pod -c my-container -- ls /         # 多个容器的情况下,在已经存在的 pod 中运行命令
$ kubectl top pod POD_NAME --containers               # 显示 pod 及其容器的度量

$ kubectl cordon my-node                                                # 标记节点 my-node 为不可调度
$ kubectl drain my-node                                                 # 准备维护时,排除节点 my-node
$ kubectl uncordon my-node                                              # 标记节点 my-node 为可调度
$ kubectl top node my-node                                              # 显示给定节点的度量值
$ kubectl cluster-info                                                  # 显示 master 和 service 的地址
$ kubectl cluster-info dump                                             # 将集群的当前状态转储到标准输出
$ kubectl cluster-info dump --output-directory=/path/to/cluster-state   # 将集群的当前状态转储到目录 /path/to/cluster-state

# 如果带有该键和效果的污点已经存在,则将按指定的方式替换其值
$ kubectl taint nodes foo dedicated=special-user:NoSchedule

15. Reference

https://book.douban.com/subject/35498478/

https://book.douban.com/subject/34438220/

https://book.douban.com/subject/35424872/

http://docs.kubernetes.org.cn/

https://www.infoq.cn/article/ouJ6INDxsBxdlOo8j8fu

https://www.cnblogs.com/lvzhenjiang/p/14196982.html

https://www.cnblogs.com/renshengdezheli/p/18230999

https://developer.aliyun.com/article/1321847

http://docs.kubernetes.org.cn/227.html

https://kubernetes.feisky.xyz/

https://www.youtube.com/watch?v=q1PcAawa4Bg&list=PLLasX02E8BPCrIhFrc_ZiINhbRkYMKdPT&index=1

https://www.zhihu.com/question/48833333?sort=created

https://www.kubernetes.org.cn/1885.

相关推荐
滿7 分钟前
处理错误的两种方式:try...catch 与 then...catch
java·开发语言
SomeB1oody16 分钟前
【Rust自学】3.6. 控制流:循环
开发语言·后端·rust
Ttang2319 分钟前
Tomcat原理(4)——尝试手动Servlet的实现
java·开发语言·servlet·java-ee·tomcat·intellij-idea
菜鸟赵大宝21 分钟前
【C++】C++实现字符串大小写转换功能
开发语言·c++
计算机毕设指导61 小时前
基于Springboot林业产品推荐系统【附源码】
java·开发语言·spring boot·后端·mysql·spring·intellij-idea
Teacher_Wyh1 小时前
算法知识-18-STL
开发语言·c++·算法
CQU_JIAKE1 小时前
12.8&12.9[java exp4][debug]跨域问题原因详解
java·开发语言
Dave_Young1 小时前
C++ QT chip layout tool开发浅思
开发语言·c++·qt
YZW01231 小时前
QT之QML学习:QFileDialog 报错log4cplus:ERROR解决方案
开发语言·qt·学习
忒可君1 小时前
C# winform 字符串通过枚举类型转成int类型的数据
开发语言·c#