参考资料:《kubernetes 从入门到实践》 赵卓编著 中国工信出版集团

《kubernetes in action》中文版 七牛容器云团队译 中国工信出版集团

可以使用$ kubectl explain pod命令详细查看Pod资源所支持的所有字段的详细说明,如果要进一步查看每个字段的详情,例如,对于spec字段可以使用命令$ kubectl explain pod.spec进行查看

command和args设置会分别覆盖原Docker镜像中定义的EntryPoint与CMD


修改启动参数,应编辑/etc/kubernetes/manifests/kube-apiserver.yaml文件,然后在spec属性部分加入- --token-auth-file=/etc/kubernetes/pki/token_auth_file参数,

可以通过$ kubectl api-resources --namespaced=false命令查看不在命名空间下的资源。

k8s会将日志输出到控制台,并以“-json.log”结尾将日志文件存放到/var/lib/docker/containers目录中。而/var/log则是Linux系统日志的目
可以在Kubernetes源码中找到各种可用的官方插件示例,其路径位于源码库cluster/addons中

通过使kubectl反向代理API Server,可以直接使用kubectl命令的认证授权来访问API Server。

kubectl命令的认证是使用~/.kube/config文件进行的。通过$ kubectl config view命令
可以看到认证信息,也可以看到k8s server暴露的接口

由于使用https访问会涉及证书问题,因此这里curl使用--insecure来忽略证书异常。
每个命名空间都有一个默认的ServiceAccount,如果在创建Pod时没有明确指定用哪个ServiceAccount,就会用默认的ServiceAccount。

默认情况下只有Kubernetes集群内的机器(Master和Node)以及Pod应用可以访问Service组

所以必须要将--pod-network-cidr参数设置为10.244.0.0/16,它是kube-flannel.yml文件配置的默认网段

集群角色可以访问全部命名空间下的资源,也可以访问不在命名空间里的资源

因为ClusterRole是不限制命名空间的,所以如果想既给某个认证主体绑定 ClusterRole,又想限制它能够使用的命名空间,就可以将它与RoleBinding关联以达到限定效果

Pod和Service的IP地址只在Kubernetes集群(即Master和Node)内能访问,集群外部的机器是无法访问的

无头服务:这种类型的Service只能在集群内的Pod中访问,集群中的机器无法直接访问。这种方式主要供StatefulSet使用。

通过NodePort发布服务,会在   各个集群机器(即Master和Node)   上打开端口

提示:nodeport的取值范围为30000~32767。

Kubernetes的Service会由externalIP地址发布出去,这样集群之外的机器就可以通过这个外部IP地址来访问Service。
externalIP可以用在任何类型的发布方式(即ClusterIP、NodePort、LoadBalancer、External Name)中

Kubernetes的Service会由externalIP地址发布出去,这样集群之外的机器就可以通过这个外部IP地址来访问Service。

externalIP可以用在任何类型的发布方式(即ClusterIP、NodePort、LoadBalancer、External Name)中

Master节点至少需要两个CPU

通过DownwardAPI可传递Pod和容器自身的运行信息。它的主要作用是向Pod中运行的容器暴露Pod自身的信息,Downward API允许容器在不使用Kubernetes客户端或

StatefulSet控制器拥有独有的更新属性.spec.updateStrategy.rollingUpdate. partition。这种方式类似于金丝雀部署,如果将partition设置为4,只有编号大于或等于4的Pod才会进行更新,编号小于partition的Pod将不会更新。

Kubernetes分配给Service一个固定IP,这是一个虚拟IP(也称为ClusterIP),并不是一个真实存在的IP,而是由Kubernetes虚拟出来的。虚拟IP的范围通过Kubernetes API Server的启动参数--service-cluster-ip-range=10.254.0.0/16配置

Service支持基于源IP地址的会话保持,通过.spec.sessionAffinity设置为ClientIP

kebelete启动参数中设置
--cluster-domain=cluster.local 
默认情况下,Pod不会调度到Master节点上。如果希望将Master节点也当作Node来使用,可以执行以下命令。

kubectl taint node master node-role.Kubernetes.io/master-

Job执行完成后是不会自动删除的。有没有自动删除的办法呢?答案是肯定的。只需要修改yml文件,加上一个spec.ttlSecondsAfterFinished属性,该属性用于确定在所有任务执行完成后,需要等待多少秒才可删除Job。。

所以ReplicaSet控制器也不具有滚动更新、版本查看和回滚等功能。

要验证集群是否正常工作,可以使用以下所示的 kubectl cluster-info命令。

创建别名:下面的代码添加到 ~/.bashrc 或类似的文件中:
tab命令行补全只在使用完整的 kubectl 命令时会起作用(当使用别名 k 时不会起作用)需要改变 kubectl completion 的输出来修复:

API服务器对外暴露了一个名为ComponentStatus的API资源,用来显示每个控制平面组件的健康状态。可以通过kubectl列出各个组件以及它们的状态
kubectl get cs

注意 kubectl attach命令和kubectl exec命令类似,区别是:前者会附属到容器中运行着的主进程上,而后者是重新运行一个进程

为了保证高可用性,控制平面的每个组件可以有多个实例。etcd和API服务器的多个实例可以同时并行工作,但是,调度器和控制器管理器在给定时间内只能有一个实例起作用,其他实例处于待命模式。

所有的Kubernetes包含一个 metadata.resourceVersion字段,当更新对象时,客户端需要返回该值到API服务器。如果版本值与etcd中存储的不匹配,API服务器会拒绝该更新

etcd实例数量应该是奇数

默认情况下,归属同一服务和ReplicaSet的pod会分散在多个节点上。但不保证每次都是这样。不过可以通过定义pod的亲缘性、非亲缘规则强制pod分散在集群内或者集中在一起
可以在集群中运行多个调度器而非单个。可以通过在pod特性中设置schedulerName属性指定调度器来调度特定的pod。

删除一个Namespace资源时,该命名空间里的所有资源都会被删除。


kube-dns服务的IP地址在集群每个容器的 /etc/reslv.conf文件的nameserver中定义。

尽管Ingress资源的定义指向一个Service,Ingress控制器会直接将流量转到服务的pod而不经过服务IP。

被暂停的容器将一个pod所有的容器收纳到一起。暂停的容器是一个基础容器,它的唯一目的就是保存所有的命名空间。所有pod的其他用户定义容器使用pod的该基础容器的命名空间

Container Network Interface(CNI)插件建立的

Kubernetes规定pod必须通过非NAT网络进行连接

安装一个网络插件并不难,只需要部署一个包含DaemonSet以及其他支持资源的YAML。每个插件项目首页都会提供这样一个YAML文件。如你所想,DaemonSet用于往所有集群节点部署一个网络代理,然后会绑定CNI接口到节点。但是,注意Kubetlet需要用--network-plugin=cni命令启动才能使用CNI。

和Service相关的任何事情都由每个节点上运行的kube-proxy进程处理。

发送到服务虚拟IP/端口对的网络包会被修改、重定向到一个随机选择的后端pod

通过deployment实现高可用,需要你的应用可以水平扩展

领导选举机制:它是一种分布式环境中多应用实例对谁是领导者达成一致的方式。例如,领导者要么是唯一执行任务的那个,其他所有节点都在等待该领导者宕机,然后自己变成领导者;或者是都是活跃的,但是领导者是唯一能够执行写操作的,而其他的只能读数据。这样能保证两个实例不会做同一个任务,否则会因为竞争条件导致不可预测的系统行为。

一个Kubernetes中领导选举的例子:https://github.com/kubernetes/contrib/tree/master/election。

etcd会跨实例复制数据,所以三节点中其中一个宕机并不会影响处理读写操作

控制平面组件使用的领导选举机制:选举领导时这些组件不需要互相通信。领导选举机制的实现方式是在API服务器中创建一个资源,而且甚至不是什么特殊种类的资源——Endpoint资源就可以拿来用于达到

读书笔记3
如果你创建了一个ClusterRoleBinding并在它里面引用了ClusterRole,在绑定中列出的主体可以在所有命名空间中查看指定的资源。相反,如果你创建的是一个RoleBinding,那么在绑定中列出的主体只能查看在RoleBinding命名空间中的资源。

ServiceAccount只不过是一种运行在pod中的应用程序和API服务器身份认证的一种方式

pod只能使用同一个命名空间中的ServiceAccount

角色定义了可以做什么操作,而绑定定义了谁可以做这些操作

不过通过Downward API的方式获取的元数据是相当有限的,如果需要获取更多的元数据,需要使用直接访问Kubernetes API服务器的方式

通过运行kubectl cluster-info命令来得到服务器的URL。

kubectl proxy 命令启动了一个代理服务来接收来自你本机的HTTP连接并转发至API服务器,同时处理身份认证

在容器内通过查询KUBERNETES_SERVICE_HOST和KUBERNETES_SERVICE_PORT这两个环境变量就可以获取API服务器的IP地址和端口。

使用宿主机的网络:可以通过将pod spec中的hostNetwork设置为true实现。在图中首先注意到的是,对于一个使用hostPort的pod,到达宿主节点的端口的连接会被直接转发到pod的对应端口上;然而在NodePort服务中,到达宿主节点的端口的连接将被转发到随机选取的pod上(这个pod可能在其他节点上)。另外一个区别是,对于使用hostPort的pod,仅有运行了这类pod的节点会绑定对应的端口;而NodePort类型的服务会在所有的节点上绑定端口,即使这个节点上没有运行对应的pod

不要混淆使用hostPort的pod和通过NodePort服务暴露的pod。如图13.2所示,它们是不同的。

为了使用一个与镜像中不同的用户ID来运行pod,需要设置该pod的securityContext.runAsUser选项。

特权模式:通过将容器的securityContext中的privileged设置为true实现。
特权模式的pod可以看到宿主节点上的所有设备。这意味着它可以自由使用任何设备

kube-proxy pod就使用了特权模式

如果使用主机名来构建关系,必须使用StatefulSet

如果一个应用在其中一个依赖缺失的情况下无法工作,那么它需要通过它的Readiness探针来通知这个情况

终止宽限期可以通过pod spec中的spec.terminationGracePeriod Periods字段来设置。默认情况下,值为30,

好的实践第一步是添加一个指向应用根URL的HTTP GET请求的就绪探针。在很多情况下,这样做就足够了,免得你还需要在应用中实现一个特殊的readiness endpoint。

可以让容器中的进程向容器的文件系统中指定文件写入一个终止消息。这个文件的内容会在容器终止后被Kubelet读取。这个进程需要写入终止消息的文件默认路径是 /dev/termination-log,当然这个路径也可以在pod spec中容器定义的部分设置terminationMessagePath字段来自定义。

如果容器没有向任何文件写入消息,可以将terminationMessage Policy字段的值设置为FallbackToLogsOnError。在这种情况下,容器的最后几行日志会被当作终止消息

如果希望看到之前容器的日志,那么在使用kubectl logs命令的时候,加上选项--previous

使用Ksonnet作为编写YAML/JSON manifest文件的额外选择

Secret的大小限于1MB。

Kubelet,它与API服务器通信,并管理它所在节点的容器

Kubernetes Service Proxy(kube-proxy),它负责组件之间的负载均衡网络流量

运行在容器中的进程是运行在主机操作系统上的

安装Kubernetes集群的方法有许多。这些方法在http://kubernetes.io的文档中有详细描述

 kubectl cluster-info
kubectl  get  cs
kubectl  get  node -l  gpu=true
kubectl get nodes-L gpu

如果启用了交换分区则无法启动Kubelet,

它将它们的YAML描述符部署到 /etc/kubernetes/manifests 目录。Kubelet会监控该目录,

在无头Service中,每一个Pod都会生成专属的访问域名,其访问格式为{PodName}. {ServiceName}.{Namespace}.svc.{ClusterDomain}

注意 每天或者每次日志文件达到10MB大小时,容器日志都会自动轮替。kubectl logs命令仅显示最后一次轮替后的日志条目。

如果想要在不通过service的情况下与某个特定的pod进行通信(出于调试或其他原因),Kubernetes将允许我们配置端口转发到该pod。可以通过kubectl port-forward命令完成上述操作。例如以下命令会将机器的本地端口8888转发到我们的kubia-manual pod的端口8080:

kubectl port-forward  --address 0.0.0.0   pod/idcard-ocr-v1-66c7d5dc76-h9zz6  -n test-mid 8888:8080

金丝雀发布是指在部署新版本时,先只让一小部分用户体验新版本以观察新版本的表现,然后再向所有用户进行推广,这样可以防止暴露有问题的版本给过多的用户

在更改现有标签时,需要使用--overwrite选项

creation_method!=manual 选择带有creation_method标签,并且值不等于manual的pod
env in(prod,devel)选择带有env标签且值为prod或devel的pod
env notin(prod,devel)选择带有env标签,但其值不是prod或devel的

注解则可以包含相对更多的数据(总共不超过256KB)

删除使用一个标签选择器来删除它

存活探针:如果HTTP响应状态码是2xx或3xx),则认为探测成功。
Exec探针如果状态码是0,则探测成功
TCP探针:建立TCP连接。如果连接成功建立,则探测成功。

你想知道为什么前一个容器终止时,你想看到的是前一个容器的日志,而不是当前容器的。可以通过添加--previous选项来完成:

如果你在容器中运行Java应用程序,请确保使用HTTP GET存活探针,而不是启动全新JVM以获取存活信息的Exec探针。任何基于JVM或类似的应用程序也是如此,它们的启动过程需要大量的计算资源。


更改pod模板就像用一个曲奇刀替换另一个。它只会影响你之后切出的曲奇,并且不会影响你已经剪切的曲奇

虽然ReplicationController的标签选择器只允许包含某个标签的匹配pod,但ReplicaSet的选择器还允许匹配缺少某个标签的pod,或包含特定标签名的pod,不管其值如何
————————
operator:
In:Label的值必须与其中一个指定的values匹配。
NotIn:Label的值与任何指定的values不匹配。
Exists:pod必须包含一个指定名称的标签(值不重要)。使用此运算符时,不应指定values字段。
DoesNotExist:pod不得包含有指定名称的标签。values属性不得指定
———————
如果你指定了多个表达式,则所有这些表达式都必须为true才能使选择器与pod匹配

节点可以被设置为不可调度的,防止pod被部署到节点上。DaemonSet甚至会将pod部署到这些节点上,因为无法调度的属性只会被调度器使用,而DaemonSet管理的pod则完全绕过调度器。

#驱逐节点上的所有Pod(包括Daemonset的容器)
kubectl drain <node name> --ignore-daemonsets
驱逐节点上的所有Pod(不包括Daemonset的容器)
kubectl drain <node name> --ignore-daemonsets=flase

恢复被调度权
kubectl uncordon <node name>

job: 除非使用--show-all(或-a)开关,否则在列出pod时不显示已完成的pod。完成后pod未被删除的原因是允许你查阅其日志。


job可以并行或串行方式运行它们。这是通过在Job配置中设置completions和parallelism属性来完成的。

如果希望特定客户端产生的所有请求每次都指向同一个pod,可以设置服务的sessionAffinity属性为ClientIP

注意 在创建一个有多个端口的服务时候,必须给每个端口指定名字。

为什么要采用命名端口的方式?最大的好处就是即使更换端口号也无须更改服务spec。你的pod现在对http服务用的是8080,但是假设过段时间你决定将端口更换为80呢?
如果你采用了命名的端口,仅仅需要做的就是改变spec pod 中的端口号


注意 pod是否使用内部的DNS服务器是根据pod中spec的dnsPolicy属性来决定的。
通过查看/etc/resolv.conf文件来确定dns服务器的地址


如果创建了不包含pod选择器的服务,Kubernetes将不会创建Endpoint资源

Endpoint对象需要与服务具有相同的名称,并包含该服务的目标IP地址和端口列表

type设置为ExternalName的service是没有ip的,CNAME记录指向完全限定的域名而不是数字IP地址。

如果Kubernetes在不支持Load Badancer服务的环境中运行,则不会调配负载平衡器,但该服务仍将表现得像一个NodePort服务。这是因为Load Badancer服务是NodePort服务的扩展。

为什么浏览器每次都会遇到同一个pod?
浏览器使用keep-alive连接,并通过单个连接发送所有请求,而curl每次都会打开一个新连接。服务在连接级别工作,所以当首次打开与服务的连接时,会选择一个随机集群,然后将属于该连接的所有网络数据包全部发送到单个集群。即使会话亲和性设置为None,用户也会始终使用相同的pod(直到连接关闭)。

一个重要的原因是每个LoadBalancer 服务都需要自己的负载均衡器,以及独有的公有IP地址,而Ingress只需要一个公网IP就能为许多服务提供访问。

ingress可以提供一些服务不能实现的功能,诸如基于cookie的会话亲和性(session affinity)等功能。

获取Ingress的IP地址:kubectl  get  ingress

不同的 Ingress 控制器支持不同的注解。

为Ingress创建TLS认证
当客户端创建到Ingress控制器的TLS连接时,控制器将终止TLS连接。客户端和控制器之间的通信是加密的,而控制器和后端pod之间的通信则不是。运行在pod上的应用程序不需要支持TLS
需要将证书和私钥附加到Ingress。

与存活探针不同,如果容器未通过准备检查,则不会被终止或重新启动。这是存活探针与就绪探针之间的重要区别。

即使使用headless服务,客户也可以通过连接到服务的DNS名称来连接到pod上,就像使用常规服务一样。但是对于headless服务,由于DNS返回了pod的IP,客户端直接连接到该pod,而不是通过服务代理


作为卷来使用的emptyDir,是在承载pod的工作节点的实际磁盘上创建的,因此其性能取决于节点的磁盘类型。但我们可以通知Kubernetes在tmfs文件系统(存在内存而非硬盘)上创建emptyDir。因此,将emptyDir的medium设置为

持久卷不属于任何命名空间(见图6.7),它跟节点一样是集群层面的资源。

与持久卷类似,StorageClass资源并非命名空间。

RWO、ROX、RWX涉及可以同时使用卷的工作节点的数量而并非pod的数量。

PV可能包含前一个声明人的数据,如果集群管理员还没来得及清理,那么不应该将这个卷绑定到全新的声明中。

手动回收持久卷并使其恢复可用的唯一方法是删除和重新创建持久卷资源

存在两种其他可行的回收策略:Recycle 和Delete。第一种删除卷的内容并使卷可用于再次声明,通过这种方式,持久卷可以被不同的持久卷声明和pod反复使用,Delete策略删除底层存储

如果希望PVC使用预先配置的PV,请将storageClassName显式设置为""。如果尚未将storageClassName属性设置为空字符串,则尽管已存在适当的预配置持久卷,但动态卷置备程序仍将配置新的持久卷。

ConfigMap创建自多种选项:完整文件夹、单独文件、自定义键名的条目下的文件(替代文件名作键名)以及字面量。

如果ConfigMap包含不少条目,为每个条目单独设置环境变量的过程是单调乏味且容易出错的。可以通过envFrom属性字段将所有条目暴露作为环境变量,而非使用前面例子中的env字段。

原因在于CONFIG_FOO-BAR包含破折号,这并不是一个合法的环境变量名称。Kubernetes不会主动转换键名(例如不会将破折号转换为下画线)。如果ConfigMap的某键名格式不正确,创建环境变量时会忽略对应的条目(忽略时不会发出事件通知)。

在字段pod.spec.containers.args中无法直接引用ConfigMap的条目,但是可以利用ConfigMap条目初始化某个环境变量,然后再在参数字段中引用该环境变量

挂载某一文件夹会隐藏该文件夹中已存在的文件。Linux系统挂载文件系统至非空文件夹时通常表现如此。
通过属性subPath可以将该文件挂载的同时又不影响文件夹中的其他文件。


Deployment会被回滚到上一个版本。kubectl rollout undo deployment kinaa
提示 undo 命令也可以在滚动升级 过程中运行,并直接停止滚动升级。在升级过程中已创建的pod会被删除并被老版本的pod替代


可以使用 kubectl rollout history 来显示升级的版本

重要的是要知道 maxUnavailable 是相对于期望副本数而言的。如果replica的数量设置为3,maxUnavailable 设置为1,则更新过程中必须保持至少两个(3-1)pod始终处于可用状态,而不可用pod数量可以超过一个

一个Statefulset创建的每个pod都有一个从零开始的顺序索引,这个会体现在pod的名称和主机名上,同样还会体现在pod对应的固定存储上

缩容一个Statefulset将会最先删除最高索引值的实例

Statefulset在有实例不健康的情况下是不允许做缩容操作的

上一节通过在同一YAML文件中添加三个横杠(---)来区分定义多个资源,这里使用另外一种方法,定义一个List对象,然后把各个资源作为List对象的各个项目。上述两种方法的效果是一样的。

读书笔记5

kubectl使用的配置通常存储在~/.kube/config 文件中。如果存储在其他位置,环境变量KUBECONFIG需要指向配置文件的位置。

可以通过在KUBECONFIG环境变量中指定多个配置文件(使用冒号分隔它们)来让kubectl一次性加载全部配置。


NoExecute不同于NoSchedule以及PreferNoSchedule,后两者只在调度期间起作用,而NoExecute也会影响正在节点上运行着的pod。如果在一个节点上添加了NoExecute污点,那些在该节点上运行着的pod,如果没有容忍这个NoExecute污点,将会从这个节点去除。

RequiredDuringExecution,表示如果去除掉节点上的某个标签,那些需要节点包含该标签的pod将会被剔除


在调度时,默认情况下,标签选择器只有匹配同一命名空间中的pod。但是,可以通过在labelSelector同一级添加namespaces字段,实现从其他的命名空间选择pod的功能。

3种污点类型:NoSchedule完全阻止调度,PreferNoSchedule不强制阻止调度,NoExecute会将已经在运行的pod从节点上剔除

pod对资源的请求量和限制量是它所包含的所有容器的请求量和限制量之和。

资源总量代表节点所有的资源总和,包括那些可能对pod不可用的资源。有些资源会为Kubernetes或者系统组件预留。调度器的决策仅仅基于可分配资源量。

CPU是一种可压缩资源,一旦系统为进程分配了一块内存,这块内存在进程主动释放之前将无法被回收。

在容器内看到的始终是节点的内存,而不是容器本身的内存
即使你为容器设置了最大可用内存的限额,top 命令显示的是运行该容器的节点的内存数量,而容器无法感知到此限制。

与内存完全一样,无论有没有配置CPU limits,容器内也会看到节点所有的CPU。将CPU限额配置为1,并不会神奇地只为容器暴露一个核。CPU limits做的只是限制容器使用的CPU时间。

不要依赖应用程序从系统获取的CPU数量,你可能需要使用Downward API将CPU限额传递至容器并使用这个值。也可以通过cgroup系统直接获取配置的CPU限制,请查看下面的文件:/sys/fs/cgroup/cpu/cpu.cfs_quota_us
/sys/fs/cgroup/cpu/cpu.cfs_period_us

为每个容器设置requests和limits是一个很好的实践。

LimitRange中配置的limits只能应用于单独的pod或容器。用户仍然可以创建大量的pod吃掉集群所有可用资源。LimitRange并不能防止这个问题,而相反,我们将在下文了解的ResourceQuota对象可以做到这点。

ResourceQuota对象仅仅作用于在其后创建的pod—— 并不影响已经存在的pod。

在集群中运行Heapster可以通过 kubectl top 命令获得节点和单个pod的资源

如果容器使用过量的CPU,系统不会杀死这个容器,但如果使用过量的内存会被杀死


Kubernetes从v1.18版本开始支持用户在生命周期字段中将容器标记为Sidecar,这类容器全部转为

唯一不同之处是,需要手动为Sidecar容器在lifecycle字段中嵌套定义type类型的值为Sidecar

提供JSON和YAML互转的在线网站为:http://www.json2yaml.com/。


访问格式为{PodName}. {ServiceName}.{Namespace}.svc.{ClusterDomain}:端口

静态 Pod 在指定的节点上由 kubelet 守护进程直接管理,不需要 API 服务器 监管。 与由控制面管理的 Pod(例如,Deployment) 不同;kubelet 监视每个静态 Pod(在它崩溃之后重新启动)。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐