零、示例

首先给出一个 Deployment+HPA+ PodDisruptionBudget 的完整 demo,后面再详细介绍其中的每一个部分:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: my-app-v3
  5. namespace: prod
  6. labels:
  7. app: my-app
  8. spec:
  9. replicas: 3
  10. strategy:
  11. type: RollingUpdate
  12. rollingUpdate:
  13. maxSurge: 10% # 滚动更新时,每次最多更新 10% 的 Pods
  14. maxUnavailable: 0 # 滚动更新时,不允许出现不可用的 Pods,也就是说始终要维持 3 个可用副本
  15. selector:
  16. matchLabels:
  17. app: my-app
  18. version: v3
  19. template:
  20. metadata:
  21. labels:
  22. app: my-app
  23. version: v3
  24. spec:
  25. affinity:
  26. podAntiAffinity:
  27. preferredDuringSchedulingIgnoredDuringExecution: # 非强制性条件
  28. - weight: 100 # weight 用于为节点评分,会优先选择评分最高的节点(只有一条规则的情况下,这个值没啥意义)
  29. podAffinityTerm:
  30. labelSelector:
  31. matchExpressions:
  32. - key: app
  33. operator: In
  34. values:
  35. - my-app
  36. - key: version
  37. operator: In
  38. values:
  39. - v3
  40. # 将 pod 尽量打散在多个可用区
  41. topologyKey: topology.kubernetes.io/zone
  42. requiredDuringSchedulingIgnoredDuringExecution: # 强制性要求(这个建议按需添加)
  43. # 注意这个没有 weights,必须满足列表中的所有条件
  44. - labelSelector:
  45. matchExpressions:
  46. - key: app
  47. operator: In
  48. values:
  49. - my-app
  50. - key: version
  51. operator: In
  52. values:
  53. - v3
  54. # Pod 必须运行在不同的节点上
  55. topologyKey: kubernetes.io/hostname
  56. securityContext:
  57. # runAsUser: 1000 # 设定用户
  58. # runAsGroup: 1000 # 设定用户组
  59. runAsNonRoot: true # Pod 必须以非 root 用户运行
  60. seccompProfile: # security compute mode
  61. type: RuntimeDefault
  62. nodeSelector:
  63. eks.amazonaws.com/nodegroup: common # 使用专用节点组,如果希望使用多个节点组,可改用节点亲和性
  64. volumes:
  65. - name: tmp-dir
  66. emptyDir: {}
  67. containers:
  68. - name: my-app-v3
  69. image: my-app:v3 # 建议使用私有镜像仓库,规避 docker.io 的镜像拉取限制
  70. imagePullPolicy: IfNotPresent
  71. volumeMounts:
  72. - mountPath: /tmp
  73. name: tmp-dir
  74. lifecycle:
  75. preStop:
  76. exec:
  77. command:
  78. - /bin/sh
  79. - -c
  80. - "while [ $(netstat -plunt | grep tcp | wc -l | xargs) -ne 0 ]; do sleep 1; done"
  81. resources: # 资源请求与限制,建议配置成相等的,避免资源竞争
  82. requests:
  83. cpu: 1000m
  84. memory: 1Gi
  85. limits:
  86. cpu: 1000m
  87. memory: 1Gi
  88. securityContext:
  89. # 将容器层设为只读,防止容器文件被篡改
  90. ## 如果需要写入临时文件,建议额外挂载 emptyDir 来提供可读写的数据卷
  91. readOnlyRootFilesystem: true
  92. # 禁止 Pod 做任何权限提升
  93. allowPrivilegeEscalation: false
  94. capabilities:
  95. # drop ALL 的权限比较严格,可按需修改
  96. drop:
  97. - ALL
  98. startupProbe: # 要求 kubernetes 1.18+
  99. httpGet:
  100. path: /actuator/health # 直接使用健康检查接口即可
  101. port: 8080
  102. periodSeconds: 5
  103. timeoutSeconds: 1
  104. failureThreshold: 20 # 最多提供给服务 5s * 20 的启动时间
  105. successThreshold: 1
  106. livenessProbe:
  107. httpGet:
  108. path: /actuator/health # spring 的通用健康检查路径
  109. port: 8080
  110. periodSeconds: 5
  111. timeoutSeconds: 1
  112. failureThreshold: 5
  113. successThreshold: 1
  114. # Readiness probes are very important for a RollingUpdate to work properly,
  115. readinessProbe:
  116. httpGet:
  117. path: /actuator/health # 简单起见可直接使用 livenessProbe 相同的接口,当然也可额外定义
  118. port: 8080
  119. periodSeconds: 5
  120. timeoutSeconds: 1
  121. failureThreshold: 5
  122. successThreshold: 1
  123. ---
  124. apiVersion: autoscaling/v2beta2
  125. kind: HorizontalPodAutoscaler
  126. metadata:
  127. labels:
  128. app: my-app
  129. name: my-app-v3
  130. namespace: prod
  131. spec:
  132. scaleTargetRef:
  133. apiVersion: apps/v1
  134. kind: Deployment
  135. name: my-app-v3
  136. maxReplicas: 50
  137. minReplicas: 3
  138. metrics:
  139. - type: Resource
  140. resource:
  141. name: cpu
  142. target:
  143. type: Utilization
  144. averageUtilization: 70
  145. ---
  146. apiVersion: policy/v1
  147. kind: PodDisruptionBudget
  148. metadata:
  149. name: my-app-v3
  150. namespace: prod
  151. labels:
  152. app: my-app
  153. spec:
  154. minAvailable: 75%
  155. selector:
  156. matchLabels:
  157. app: my-app
  158. version: v3

一、优雅停止(Gracful Shutdown)与 502/504 报错

如果 Pod 正在处理大量请求(比如 1000 QPS+)时,因为节点故障或「竞价节点」被回收等原因被重新调度,

你可能会观察到在容器被 terminate 的一段时间内出现少量 502/504。

为了搞清楚这个问题,需要先理解清楚 terminate 一个 Pod 的流程:

  1. Pod 的状态被设为「Terminating」,(几乎)同时该 Pod 被从所有关联的 Service Endpoints 中移除
  2. preStop 钩子被执行,它可以是一个命令,或者一个对 Pod 中容器的 http 调用
    1. 如果你的程序在收到 SIGTERM 信号时,无法优雅退出,就可以考虑使用 preStop
    2. 如果让程序本身支持优雅退出比较麻烦的话,用 preStop 实现优雅退出是一个非常好的方式
  3. 将 SIGTERM 发送给 Pod 中的所有容器
  4. 继续等待,直到超过 spec.terminationGracePeriodSeconds 设定好的时间,这个值默认为 30s
    1. 需要注意的是,这个优雅退出的等待计时是与 preStop 同步开始的!而且它也不会等待 preStop 结束!
  5. 如果超过了 spec.terminationGracePeriodSeconds 容器仍然没有停止,k8s 将会发送 SIGKILL 信号给容器
  6. 进程全部终止后,整个 Pod 完全被清理掉

注意:1 和 2 两个工作是异步发生的,所以可能会出现「Pod 还在 Service Endpoints 中,但是 preStop 已经执行了」的情况,我们需要考虑到这种状况的发生。

了解了上面的流程后,我们就能分析出两种错误码出现的原因:

  • 502:应用程序在收到 SIGTERM 信号后直接终止了运行,导致部分还没有被处理完的请求直接中断,代理层返回 502 表示这种情况
  • 504:Service Endpoints 移除不够及时,在 Pod 已经被终止后,仍然有个别请求被路由到了该 Pod,得不到响应导致 504

通常的解决方案是,在 Pod 的 preStop 步骤加一个 15s 的等待时间。

其原理是:在 Pod 处理 terminating 状态的时候,就会被从 Service Endpoints 中移除,也就不会再有新的请求过来了。

preStop 等待 15s,基本就能保证所有的请求都在容器死掉之前被处理完成(一般来说,绝大部分请求的处理时间都在 300ms 以内吧)。

一个简单的示例如下,它使 Pod 被终止时,总是先等待 15s,再发送 SIGTERM 信号给容器:

  1. containers:
  2. - name: my-app
  3. # 添加下面这部分
  4. lifecycle:
  5. preStop:
  6. exec:
  7. command:
  8. - /bin/sleep
  9. - "15"

更好的解决办法,是直接等待所有 tcp 连接都关闭(需要镜像中有 netstat):

  1. containers:
  2. - name: my-app
  3. # 添加下面这部分
  4. lifecycle:
  5. preStop:
  6. exec:
  7. command:
  8. - /bin/sh
  9. - -c
  10. - "while [ $(netstat -plunt | grep tcp | wc -l | xargs) -ne 0 ]; do sleep 1; done"

参考

二、节点维护与Pod干扰预算

在我们通过 kubectl drain 将某个节点上的容器驱逐走的时候,

kubernetes 会依据 Pod 的「PodDistruptionBuget」来进行 Pod 的驱逐。

如果不设置任何明确的 PodDistruptionBuget,Pod 将会被直接杀死,然后在别的节点重新调度,这可能导致服务中断!

PDB 是一个单独的 CR 自定义资源,示例如下:

  1. apiVersion: policy/v1beta1
  2. kind: PodDisruptionBudget
  3. metadata:
  4. name: podinfo-pdb
  5. spec:
  6. # 如果不满足 PDB,Pod 驱逐将会失败!
  7. minAvailable: 1 # 最少也要维持一个 Pod 可用
  8. # maxUnavailable: 1 # 最大不可用的 Pod 数
  9. selector:
  10. matchLabels:
  11. app: podinfo

如果在进行节点维护时(kubectl drain),Pod 不满足 PDB,drain 将会失败,示例:

  1. > kubectl drain node-205 --ignore-daemonsets --delete-local-data
  2. node/node-205 cordoned
  3. WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-nfhj7, kube-system/kube-proxy-94dz5
  4. evicting pod default/podinfo-7c84d8c94d-h9brq
  5. evicting pod default/podinfo-7c84d8c94d-gw6qf
  6. error when evicting pod "podinfo-7c84d8c94d-h9brq" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
  7. evicting pod default/podinfo-7c84d8c94d-h9brq
  8. error when evicting pod "podinfo-7c84d8c94d-h9brq" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
  9. evicting pod default/podinfo-7c84d8c94d-h9brq
  10. error when evicting pod "podinfo-7c84d8c94d-h9brq" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
  11. evicting pod default/podinfo-7c84d8c94d-h9brq
  12. pod/podinfo-7c84d8c94d-gw6qf evicted
  13. pod/podinfo-7c84d8c94d-h9brq evicted
  14. node/node-205 evicted

上面的示例中,podinfo 一共有两个副本,都运行在 node-205 上面。我给它设置了干扰预算 PDB minAvailable: 1

然后使用 kubectl drain 驱逐 Pod 时,其中一个 Pod 被立即驱逐走了,而另一个 Pod 大概在 15 秒内一直驱逐失败。

因为第一个 Pod 还没有在新的节点上启动完成,它不满足干扰预算 PDB minAvailable: 1 这个条件。

大约 15 秒后,最先被驱逐走的 Pod 在新节点上启动完成了,另一个 Pod 满足了 PDB 所以终于也被驱逐了。这才完成了一个节点的 drain 操作。

ClusterAutoscaler 等集群节点伸缩组件,在缩容节点时也会考虑 PodDisruptionBudget. 如果你的集群使用了 ClusterAutoscaler 等动态扩缩容节点的组件,强烈建议设置为所有服务设置 PodDisruptionBudget.

最佳实践 Deployment + HPA + PodDisruptionBudget

一般而言,一个服务的每个版本,都应该包含如下三个资源:

  • Deployment: 管理服务自身的 Pods 嘛
  • HPA: 负责 Pods 的扩缩容,通常使用 CPU 指标进行扩缩容
  • PodDisruptionBudget(PDB): 建议按照 HPA 的目标值,来设置 PDB.
    • 比如 HPA CPU 目标值为 60%,就可以考虑设置 PDB minAvailable=65%,保证至少有 65% 的 Pod 可用。这样理论上极限情况下 QPS 均摊到剩下 65% 的 Pods 上也不会造成雪崩(这里假设 QPS 和 CPU 是完全的线性关系)

三、节点亲和性与节点组

我们一个集群,通常会使用不同的标签为节点组进行分类,比如 kubernetes 自动生成的一些节点标签:

  • kubernetes.io/os: 通常都用 linux
  • kubernetes.io/arch: amd64, arm64
  • topology.kubernetes.io/regiontopology.kubernetes.io/zone: 云服务的区域及可用区

我们使用得比较多的,是「节点亲和性」以及「Pod 反亲和性」,另外两个策略视情况使用。

1. 节点亲和性

如果你使用的是 aws,那 aws 有一些自定义的节点标签:

  • eks.amazonaws.com/nodegroup: aws eks 节点组的名称,同一个节点组使用同样的 aws ec2 实例模板

    • 比如 arm64 节点组、amd64/x64 节点组
    • 内存比例高的节点组如 m 系实例,计算性能高的节点组如 c 系列
    • 竞价实例节点组:这个省钱啊,但是动态性很高,随时可能被回收
    • 按量付费节点组:这类实例贵,但是稳定。

假设你希望优先选择竞价实例跑你的 Pod,如果竞价实例暂时跑满了,就选择按量付费实例。

nodeSelector 就满足不了你的需求了,你需要使用 nodeAffinity,示例如下:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: xxx
  5. namespace: xxx
  6. spec:
  7. # ...
  8. template:
  9. # ...
  10. spec:
  11. affinity:
  12. nodeAffinity:
  13. # 优先选择 spot-group-c 的节点
  14. preferredDuringSchedulingIgnoredDuringExecution:
  15. - preference:
  16. matchExpressions:
  17. - key: eks.amazonaws.com/nodegroup
  18. operator: In
  19. values:
  20. - spot-group-c
  21. weight: 80 # weight 用于为节点评分,会优先选择评分最高的节点
  22. # 如果没 spot-group-c 可用,也可选择 ondemand-group-c 的节点跑
  23. requiredDuringSchedulingIgnoredDuringExecution:
  24. nodeSelectorTerms:
  25. - matchExpressions:
  26. - key: eks.amazonaws.com/nodegroup
  27. operator: In
  28. values:
  29. - spot-group-c
  30. - ondemand-group-c
  31. containers:
  32. # ...

2. Pod 反亲和性

通常建议为每个 Deployment 的 template 配置 Pod 反亲和性,把 Pods 打散在所有节点上:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: xxx
  5. namespace: xxx
  6. spec:
  7. # ...
  8. template:
  9. # ...
  10. spec:
  11. replicas: 3
  12. affinity:
  13. podAntiAffinity:
  14. preferredDuringSchedulingIgnoredDuringExecution: # 非强制性条件
  15. - weight: 100 # weight 用于为节点评分,会优先选择评分最高的节点
  16. podAffinityTerm:
  17. labelSelector:
  18. matchExpressions:
  19. - key: app
  20. operator: In
  21. values:
  22. - xxx
  23. - key: version
  24. operator: In
  25. values:
  26. - v12
  27. # 将 pod 尽量打散在多个可用区
  28. topologyKey: topology.kubernetes.io/zone
  29. requiredDuringSchedulingIgnoredDuringExecution: # 强制性要求
  30. # 注意这个没有 weights,必须满足列表中的所有条件
  31. - labelSelector:
  32. matchExpressions:
  33. - key: app
  34. operator: In
  35. values:
  36. - xxx
  37. - key: version
  38. operator: In
  39. values:
  40. - v12
  41. # Pod 必须运行在不同的节点上
  42. topologyKey: kubernetes.io/hostname

四、Pod 的就绪探针、存活探针与启动探针

在 Kubernetes 1.18 之前,通用的手段是在「就绪探针」和「存活探针」中添加较长的 initialDelaySeconds 来实现类似「启动探针」的功能——探测前先等待容器慢启动。

Pod 提供如下三种探针,均支持使用 Command、HTTP API、TCP Socket 这三种手段来进行服务可用性探测。

  • startupProbe 启动探针(Kubernetes v1.18 [beta]): 此探针通过后,「就绪探针」与「存活探针」才会进行存活性与就绪检查

    • 用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉
    • 程序将最多有 failureThreshold * periodSeconds 的时间用于启动,比如设置 failureThreshold=20periodSeconds=5,程序启动时间最长就为 100s,如果超过 100s 仍然未通过「启动探测」,容器会被杀死。
  • readinessProbe 就绪探针:

    • 就绪探针失败次数超过 failureThreshold 限制(默认三次),服务将被暂时从 Service 的 Endpoints 中踢出,直到服务再次满足 successThreshold.
  • livenessProbe 存活探针: 检测服务是否存活,它可以捕捉到死锁等情况,及时杀死这种容器。
    • 存活探针失败可能的原因:

      • 服务发生死锁,对所有请求均无响应
      • 服务线程全部卡在对外部 redis/mysql 等外部依赖的等待中,导致请求无响应
    • 存活探针失败次数超过 failureThreshold 限制(默认三次),容器将被杀死,随后根据重启策略执行重启。
      • kubectl describe pod 会显示重启原因为 State.Last State.Reason = Error, Exit Code=137,同时 Events 中会有 Liveness probe failed: ... 这样的描述。

上述三类探测器的参数都是通用的,五个时间相关的参数列举如下:

  1. # 下面的值就是 k8s 的默认值
  2. initialDelaySeconds: 0 # 默认没有 delay 时间
  3. periodSeconds: 10
  4. timeoutSeconds: 1
  5. failureThreshold: 3
  6. successThreshold: 1

示例:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: my-app-v3
  5. spec:
  6. # ...
  7. template:
  8. # ...
  9. spec:
  10. containers:
  11. - name: my-app-v3
  12. image: xxx.com/app/my-app:v3
  13. imagePullPolicy: IfNotPresent
  14. # ... 省略若干配置
  15. startupProbe:
  16. httpGet:
  17. path: /actuator/health # 直接使用健康检查接口即可
  18. port: 8080
  19. periodSeconds: 5
  20. timeoutSeconds: 1
  21. failureThreshold: 20 # 最多提供给服务 5s * 20 的启动时间
  22. successThreshold: 1
  23. livenessProbe:
  24. httpGet:
  25. path: /actuator/health # spring 的通用健康检查路径
  26. port: 8080
  27. periodSeconds: 5
  28. timeoutSeconds: 1
  29. failureThreshold: 5
  30. successThreshold: 1
  31. # Readiness probes are very important for a RollingUpdate to work properly,
  32. readinessProbe:
  33. httpGet:
  34. path: /actuator/health # 简单起见可直接使用 livenessProbe 相同的接口,当然也可额外定义
  35. port: 8080
  36. periodSeconds: 5
  37. timeoutSeconds: 1
  38. failureThreshold: 5
  39. successThreshold: 1

五、Pod 安全 {#security}

这里只介绍 Pod 中安全相关的参数,其他诸如集群全局的安全策略,不在这里讨论。

1. Pod SecurityContext

通过设置 Pod 的 SecurityContext,可以为每个 Pod 设置特定的安全策略。

SecurityContext 有两种类型:

  1. spec.securityContext: 这是一个 PodSecurityContext 对象

    • 顾名思义,它对 Pod 中的所有 contaienrs 都有效。
  2. spec.containers[*].securityContext: 这是一个 SecurityContext 对象
    • container 私有的 SecurityContext

这两个 SecurityContext 的参数只有部分重叠,重叠的部分 spec.containers[*].securityContext 优先级更高。

我们比较常遇到的一些提升权限的安全策略:

  1. 特权容器:spec.containers[*].securityContext.privileged
  2. 添加(Capabilities)可选的系统级能力: spec.containers[*].securityContext.capabilities.add
    1. 只有 ntp 同步服务等少数容器,可以开启这项功能。请注意这非常危险。
  3. Sysctls: 系统参数: spec.securityContext.sysctls

权限限制相关的安全策略有(强烈建议在所有 Pod 上按需配置如下安全策略!):

  1. spec.volumes: 所有的数据卷都可以设定读写权限
  2. spec.securityContext.runAsNonRoot: true Pod 必须以非 root 用户运行
  3. spec.containers[*].securityContext.readOnlyRootFileSystem:true 将容器层设为只读,防止容器文件被篡改。
    1. 如果微服务需要读写文件,建议额外挂载 emptydir 类型的数据卷。
  4. spec.containers[*].securityContext.allowPrivilegeEscalation: false 不允许 Pod 做任何权限提升!
  5. spec.containers[*].securityContext.capabilities.drop: 移除(Capabilities)可选的系统级能力

还有其他诸如指定容器的运行用户(user)/用户组(group)等功能未列出,请自行查阅 Kubernetes 相关文档。

一个无状态的微服务 Pod 配置举例:

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: <Pod name>
  5. spec:
  6. containers:
  7. - name: <container name>
  8. image: <image>
  9. imagePullPolicy: IfNotPresent
  10. # ......此处省略 500 字
  11. securityContext:
  12. readOnlyRootFilesystem: true # 将容器层设为只读,防止容器文件被篡改。
  13. allowPrivilegeEscalation: false # 禁止 Pod 做任何权限提升
  14. capabilities:
  15. drop:
  16. # 禁止容器使用 raw 套接字,通常只有 hacker 才会用到 raw 套接字。
  17. # raw_socket 可自定义网络层数据,避开 tcp/udp 协议栈,直接操作底层的 ip/icmp 数据包。可实现 ip 伪装、自定义协议等功能。
  18. # 去掉 net_raw 会导致 tcpdump 无法使用,无法进行容器内抓包。需要抓包时可临时去除这项配置
  19. - NET_RAW
  20. # 更好的选择:直接禁用所有 capabilities
  21. # - ALL
  22. securityContext:
  23. # runAsUser: 1000 # 设定用户
  24. # runAsGroup: 1000 # 设定用户组
  25. runAsNonRoot: true # Pod 必须以非 root 用户运行
  26. seccompProfile: # security compute mode
  27. type: RuntimeDefault

2. seccomp: security compute mode

seccomp 和 seccomp-bpf 允许对系统调用进行过滤,可以防止用户的二进制文对主机操作系统件执行通常情况下并不需要的危险操作。它和 Falco 有些类似,不过 Seccomp 没有为容器提供特别的支持。

视频:

Kubernetes Deployment 最佳实践的更多相关文章

  1. Kubernetes YAML最佳实践和策略

    Kubernetes工作负载最常用YAML格式的文件来定义. YAML的问题之一就是很难描述清单文件之间的约束或关系. 如果你希望检查是否已从受信任的注册表中提取部署到群集中的所有映像,该怎么办? 如 ...

  2. Kubernetes生产环境最佳实践

    点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 众所周知,Kubernetes很难! 以下是在生产中使用 ...

  3. 生产环境容器落地最佳实践 --JFrog 内部K8s落地旅程

    引言 Kubernetes已经成为市场上事实上领先的编配工具,不仅对技术公司如此,对所有公司都是如此,因为它允许您快速且可预测地部署应用程序.动态地伸缩应用程序.无缝地推出新特性,同时有效地利用硬件资 ...

  4. Kubernetes集群的监控报警策略最佳实践

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/79652064 本文为Kub ...

  5. 可能是Asp.net Core On host、 docker、kubernetes(K8s) 配置读取的最佳实践

    写在前面 为了不违反广告法,我竭尽全力,不过"最佳实践"确是标题党无疑,如果硬要说的话 只能是个人最佳实践. 问题引出 ​ 可能很多新手都会遇到同样的问题:我要我的Asp.net ...

  6. 验证Kubernetes YAML的最佳实践和策略

    本文来自Rancher Labs Kubernetes工作负载最常见的定义是YAML格式的文件.使用YAML所面临的挑战之一是,它相当难以表达manifest文件之间的约束或关系. 如果你想检查所有部 ...

  7. 在CentOS 7.6 以 kubeadm 安装 Kubernetes 1.15 最佳实践

    前言 Kubernetes作为容器编排工具,简化容器管理,提升工作效率而颇受青睐.很多新手部署Kubernetes由于"scientifically上网"问题举步维艰,本文以实战经 ...

  8. Kubernetes 微服务最佳实践

    本文由个人笔记 ryan4yin/knowledge 整理而来 本文主要介绍我个人在使用 Kubernetes 的过程中,总结出的一套「Kubernetes 配置」,是我个人的「最佳实践」. 其中大部 ...

  9. 在 Kubernetes 容器集群,微服务项目最佳实践

    转载自:https://mp.weixin.qq.com/s/WYu3gDwKKf06f_FYbO9YRg 本文主要介绍我个人在使用 Kubernetes 的过程中,总结出的一套「Kubernetes ...

随机推荐

  1. SPOJ16636 Journey IE2

    SPOJ16636 Journey IE2 更好的阅读体验 在Byteland有n个城市,编号从1到n.这些城市由m条双向道路网络连接.众所周知,每一对城市最多只能由一条道路连接. Byteman最近 ...

  2. cookie和session和localStorage的区别

    这三个都是保存在浏览器端,而且都是同源的. Session仅在当前浏览器窗口关闭有效,不能持久保存 Localstorage始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据 Cookie只在设置 ...

  3. VS Code C/C++开发环境配置

    VS Code C/C++开发环境配置 一.安装 ​ 1.前往官网下载安装即可 https://code.visualstudio.com/ ​ 2.进入VS Code安装如下插件 二.C/C++开发 ...

  4. py3.8安装

    ubantu python3.8# 命令下载wget https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tar.xz#解压tar -xvJf P ...

  5. .NET CLI简单教程和项目结构

    WHAT IS .NET CLI ? .NET 命令行接口 (CLI) 工具是用于开发.生成.运行和发布 .NET 应用程序的跨平台工具链. 来源:.NET CLI | Microsoft Docs ...

  6. Spring DeferredResult 异步请求

    Spring DeferredResult 异步请求 一.背景 二.分析 三.实现要求 四.后端代码实现 五.运行结果 1.超时操作 2.正常操作 六.DeferredResult运行原理 六.注意事 ...

  7. GitHub Universe 2021|MS Reactor 邀你共聚年度盛会

    GitHub Universe 2021 将于2021年10月27-28日(PDT)在线直播,MS Reactor 将与 CSDN 合作进行转播,与你一同观看这场全球开发者盛会. 关于 GitHub ...

  8. Stack2 攻防世界题目分析

    ---XCTF 4th-QCTF-2018 前言,怎么说呢,这题目还是把我折磨的可以的,我一开始是没有看到后面的直接狙击的,只能说呢. 我的不经意间的粗心,破坏了你许多的温柔 1.气的我直接检查保护: ...

  9. 你一定不知道的Unsafe用法

    Unsafe是什么 首先我们说Unsafe类位于rt.jar里面sun.misc包下面,Unsafe翻译过来是不安全的,这倒不是说这个类是不安全的,而是说开发人员使用Unsafe是不安全的,也就是不推 ...

  10. [WPF] 在 Windows 11 中处理 WindowChrome 的圆角

    1. Windows 11 的圆角 在直角统治了微软的 UI 设计多年以后,微软突然把直角骂了一顿,说还是圆角好看,于是 Windows 11 随处都可看到圆角设计.Windows 11 使用 3 个 ...