first add

This commit is contained in:
baim0
2023-09-16 20:09:12 +08:00
commit 21d5023570
14 changed files with 7161 additions and 0 deletions
BIN
View File
Binary file not shown.
+380
View File
@@ -0,0 +1,380 @@
---
title: 01 descheduler
date: 2023-04-20 21:23:07
tags:
- kubernetes杂谈
categories:
- kubernetes杂谈
---
原创:阳明,摘录其社区运营公众号,kubernetes技术圈
从 kube-scheduler 的角度来看,它是通过一系列算法计算出最佳节点运行 Pod,当出现新的 Pod 进行调度时,调度程序会根据其当时对 Kubernetes 集群的资源描述做出最佳调度决定,但是 Kubernetes 集群是非常动态的,由于整个集群范围内的变化,比如一个节点为了维护,我们先执行了驱逐操作,这个节点上的所有 Pod 会被驱逐到其他节点去,但是当我们维护完成后,之前的 Pod 并不会自动回到该节点上来,因为 Pod 一旦被绑定了节点是不会触发重新调度的,由于这些变化,Kubernetes 集群在一段时间内就可能会出现不均衡的状态,所以需要均衡器来重新平衡集群。
![image-20230420213109481](http://qiniu.baim0.cn/img/image-20230420213109481.png)
当然我们可以去手动做一些集群的平衡,比如手动去删掉某些 Pod,触发重新调度就可以了,但是显然这是一个繁琐的过程,也不是解决问题的方式。为了解决实际运行中集群资源无法充分利用或浪费的问题,可以使用 descheduler 组件对集群的 Pod 进行调度优化,descheduler 可以根据一些规则和配置策略来帮助我们重新平衡集群状态,其核心原理是根据其策略配置找到可以被移除的 Pod 并驱逐它们,其本身并不会进行调度被驱逐的 Pod,而是依靠默认的调度器来实现,目前支持的策略有:
- RemoveDuplicates
- LowNodeUtilization
- HighNodeUtilization
- RemovePodsViolatingInterPodAntiAffinity
- RemovePodsViolatingNodeAffinity
- RemovePodsViolatingNodeTaints
- RemovePodsViolatingTopologySpreadConstraint
- RemovePodsHavingTooManyRestarts
- PodLifeTime
- RemoveFailedPods
这些策略都是可以启用或者禁用的,作为策略的一部分,也可以配置与策略相关的一些参数,默认情况下,所有策略都是启用的。另外,还有一些通用配置,如下:
- nodeSelector:限制要处理的节点
- evictLocalStoragePods: 驱逐使用 LocalStorage 的 Pods
- ignorePvcPods: 是否忽略配置 PVC 的 Pods,默认是 False
- maxNoOfPodsToEvictPerNode:节点允许的最大驱逐 Pods 数
我们可以通过如下所示的 DeschedulerPolicy 来配置:
```yaml
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
nodeSelector: "node=node1" # 如果没有设置,所有内容都将被处理,无需进行此设置。
maxNoOfPodsToEvictPerNode: 5000 # 如果没有设置,就不需要进行限制。
maxNoOfPodsToEvictPerNamespace: 5000
profiles:
- name: ProfileName
pluginConfig:
- name: "DefaultEvictor"
args:
evictSystemCriticalPods: true
evictFailedBarePods: true
evictLocalStoragePods: true
nodeFit: true
plugins:
evict:
enabled:
- "DefaultEvictor"
deschedule:
enabled:
- ...
balance:
enabled:
- ...
[...]
```
## 安装
descheduler 可以以 CronJob 或者 Deployment 的形式运行在 k8s 集群内,同样我们可以使用 Helm Chart 来安装 descheduler:
```bash
➜ helm repo add descheduler https://kubernetes-sigs.github.io/descheduler/
```
通过 Helm Chart 我们可以配置 descheduler 以 CronJob 或者 Deployment 方式运行,默认情况下 descheduler 会以一个 critical pod 运行,以避免被自己或者 kubelet 驱逐了,需要确保集群中有 system-cluster-critical 这个 Priorityclass:
```bash
➜ kubectl get priorityclass system-cluster-critical
NAME VALUE GLOBAL-DEFAULT AGE
system-cluster-critical 2000000000 false 87d
```
使用 Helm Chart 安装默认情况下会以 CronJob 的形式运行,执行周期为 schedule: "*/2 * * * *",这样每隔两分钟会执行一次 descheduler 任务,默认的配置策略如下所示:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: descheduler
data:
policy.yaml: |
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
LowNodeUtilization:
enabled: true
params:
nodeResourceUtilizationThresholds:
targetThresholds:
cpu: 50
memory: 50
pods: 50
thresholds:
cpu: 20
memory: 20
pods: 20
RemoveDuplicates:
enabled: true
RemovePodsHavingTooManyRestarts:
enabled: true
params:
podsHavingTooManyRestarts:
includingInitContainers: true
podRestartThreshold: 100
RemovePodsViolatingInterPodAntiAffinity:
enabled: true
RemovePodsViolatingNodeAffinity:
enabled: true
params:
nodeAffinityType:
- requiredDuringSchedulingIgnoredDuringExecution
RemovePodsViolatingNodeTaints:
enabled: true
RemovePodsViolatingTopologySpreadConstraint:
enabled: true
params:
includeSoftConstraints: false
```
通过配置 DeschedulerPolicy 的 strategies,可以指定 descheduler 的执行策略,这些策略都是可以启用或禁用的,下面我们会详细介绍,这里我们使用默认策略即可,使用如下命令直接安装即可:
```bash
➜ helm upgrade --install descheduler descheduler/descheduler --set image.repository=cnych/descheduler -n kube-system
```
部署完成后会创建一个 CronJob 资源对象来平衡集群状态:
```bash
➜ kubectl get cronjob -n kube-system
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
descheduler */2 * * * * False 1 8s 117s
➜ kubectl get job -n kube-system
NAME COMPLETIONS DURATION AGE
descheduler-28032982 1/1 15s 17s
➜ kubectl get pods -n kube-system -l job-name=descheduler-28032982
NAME READY STATUS RESTARTS AGE
descheduler-28032982-vxn24 0/1 Completed 0 31s
```
正常情况下就会创建一个对应的 Job 来执行 descheduler 任务,我们可以通过查看日志可以了解做了哪些平衡操作:
```bash
➜ kubectl logs -f descheduler-28032982-vxn24 -nkube-system
I0420 08:22:10.019936 1 named_certificates.go:53] "Loaded SNI cert" index=0 certName="self-signed loopback" certDetail="\"apiserver-loopback-client@1681978930\" [serving] validServingFor=[apiserver-loopback-client] issuer=\"apiserver-loopback-client-ca@1681978929\" (2023-04-20 07:22:09 +0000 UTC to 2024-04-19 07:22:09 +0000 UTC (now=2023-04-20 08:22:10.019885292 +0000 UTC))"
I0420 08:22:10.020138 1 secure_serving.go:210] Serving securely on [::]:10258
I0420 08:22:10.020301 1 tlsconfig.go:240] "Starting DynamicServingCertificateController"
I0420 08:22:10.021237 1 policyconfig.go:211] converting Deschedule plugin: %sRemovePodsViolatingInterPodAntiAffinity
I0420 08:22:10.021255 1 policyconfig.go:211] converting Deschedule plugin: %sRemovePodsViolatingNodeAffinity
I0420 08:22:10.021262 1 policyconfig.go:211] converting Deschedule plugin: %sRemovePodsViolatingNodeTaints
I0420 08:22:10.021269 1 policyconfig.go:202] converting Balance plugin: %sRemovePodsViolatingTopologySpreadConstraint
I0420 08:22:10.021280 1 policyconfig.go:202] converting Balance plugin: %sLowNodeUtilization
I0420 08:22:10.021296 1 policyconfig.go:202] converting Balance plugin: %sRemoveDuplicates
I0420 08:22:10.021312 1 policyconfig.go:211] converting Deschedule plugin: %sRemovePodsHavingTooManyRestarts
# ......
I0420 08:22:11.630980 1 removeduplicates.go:162] "Duplicate found" pod="kruise-system/kruise-controller-manager-7d78fc5c97-pxsqx"
I0420 08:22:11.630997 1 removeduplicates.go:103] "Processing node" node="node2"
I0420 08:22:11.631052 1 removeduplicates.go:103] "Processing node" node="node3"
I0420 08:22:11.631113 1 removeduplicates.go:103] "Processing node" node="master1"
I0420 08:22:11.631184 1 removeduplicates.go:194] "Adjusting feasible nodes" owner={namespace:kruise-system kind:ReplicaSet name:kruise-controller-manager-7d78fc5c97 imagesHash:openkruise/kruise-manager:v1.3.0} from=4 to=3
I0420 08:22:11.631200 1 removeduplicates.go:203] "Average occurrence per node" node="node1" ownerKey={namespace:kruise-system kind:ReplicaSet name:kruise-controller-manager-7d78fc5c97 imagesHash:openkruise/kruise-manager:v1.3.0} avg=1
I0420 08:22:11.647438 1 evictions.go:162] "Evicted pod" pod="kruise-system/kruise-controller-manager-7d78fc5c97-pxsqx" reason="" strategy="RemoveDuplicates" node="node1"
I0420 08:22:11.647494 1 descheduler.go:408] "Number of evicted pods" totalEvicted=1
I0420 08:22:11.647583 1 reflector.go:227] Stopping reflector *v1.Namespace (0s) from k8s.io/client-go/informers/factory.go:150
I0420 08:22:11.647702 1 reflector.go:227] Stopping reflector *v1.PriorityClass (0s) from k8s.io/client-go/informers/factory.go:150
I0420 08:22:11.647761 1 tlsconfig.go:255] "Shutting down DynamicServingCertificateController"
I0420 08:22:11.647764 1 reflector.go:227] Stopping reflector *v1.Node (0s) from k8s.io/client-go/informers/factory.go:150
I0420 08:22:11.647811 1 secure_serving.go:255] Stopped listening on [::]:10258
......
```
从日志中我们就可以清晰的知道因为什么策略驱逐了哪些 Pods。
## PDB
由于使用 descheduler 会将 Pod 驱逐进行重调度,但是如果一个服务的所有副本都被驱逐的话,则可能导致该服务不可用。如果服务本身存在单点故障,驱逐的时候肯定就会造成服务不可用了,这种情况我们强烈建议使用反亲和性和多副本来避免单点故障,但是如果服务本身就被打散在多个节点上,这些 Pod 都被驱逐的话,这个时候也会造成服务不可用了,这种情况下我们可以通过配置 PDB(PodDisruptionBudget) 对象来避免所有副本同时被删除,比如我们可以设置在驱逐的时候某应用最多只有一个副本不可用,则创建如下所示的资源清单即可:
```bash
# pdb-demo.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: pdb-demo
spec:
maxUnavailable: 1 # 设置最多不可用的副本数量,或者使用 minAvailable,可以使用整数或百分比
selector:
matchLabels: # 匹配Pod标签
app: demo
```
关于 PDB 的更多详细信息可以查看官方文档:https://kubernetes.io/docs/tasks/run-application/configure-pdb/。
所以如果我们使用 descheduler 来重新平衡集群状态,那么我们强烈建议给应用创建一个对应的 PodDisruptionBudget 对象进行保护。
## 策略
### PodLifeTime:驱逐超过指定时间限制的 pod
该策略用于驱逐比 maxPodLifeTimeSeconds 更旧的 Pods,可以通过 podStatusPhases 来配置哪类状态的 Pods 会被驱逐,建议为每个应用程序创建一个 PDB,以确保应用程序的可用性,比如我们可以配置如下所示的策略来驱逐运行超过 7 天的 Pod:
```bash
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"PodLifeTime":
enabled: true
params:
maxPodLifeTimeSeconds: 604800 # Pods 运行最多7天
```
### RemoveDuplicates
该策略确保只有一个和 Pod 关联的 RS、Deployment 或者 Job 资源对象运行在同一节点上。如果还有更多的 Pod 则将这些重复的 Pod 进行驱逐,以便更好地在集群中分散 Pod。如果某些节点由于某些原因崩溃了,这些节点上的 Pod 漂移到了其他节点,导致多个与 RS 关联的 Pod 在同一个节点上运行,就有可能发生这种情况,一旦出现故障的节点再次准备就绪,就可以启用该策略来驱逐这些重复的 Pod。
![image-20230420213133127](http://qiniu.baim0.cn/img/image-20230420213133127.png)
RemoveDuplicates
配置策略的时候,可以指定参数 excludeOwnerKinds 用于排除类型,这些类型下的 Pod 不会被驱逐:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemoveDuplicates":
enabled: true
params:
removeDuplicates:
excludeOwnerKinds:
- "ReplicaSet"
```
### LowNodeUtilization
该策略主要用于查找未充分利用的节点,并从其他节点驱逐 Pod,以便 kube-scheduler 重新将它们调度到未充分利用的节点上。该策略的参数可以通过字段 nodeResourceUtilizationThresholds 进行配置。
节点的利用率不足可以通过配置 thresholds 阈值参数来确定,可以通过 CPU、内存和 Pods 数量的百分比进行配置。如果节点的使用率均低于所有阈值,则认为该节点未充分利用。
![image-20230420213145484](http://qiniu.baim0.cn/img/image-20230420213145484.png)
LowNodeUtilization
此外,还有一个可配置的阈值 targetThresholds,用于计算可能驱逐 Pods 的潜在节点,该参数也可以配置 CPU、内存以及 Pods 数量的百分比进行配置。thresholds 和 targetThresholds 可以根据你的集群需求进行动态调整,如下所示示例:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"LowNodeUtilization":
enabled: true
params:
nodeResourceUtilizationThresholds:
thresholds:
"cpu": 20
"memory": 20
"pods": 20
targetThresholds:
"cpu": 50
"memory": 50
"pods": 50
```
需要注意的是:
- 仅支持以下三种资源类型:cpu、memory、pods
- thresholds 和 targetThresholds 必须配置相同的类型
- 参数值的访问是 0-100(百分制)
- 相同的资源类型,thresholds 的配置不能高于 targetThresholds 的配置
如果未指定任何资源类型,则默认是 100%,以避免节点从未充分利用变为过度利用。和 LowNodeUtilization 策略关联的另一个参数是 numberOfNodes,只有当未充分利用的节点数大于该配置值的时候,才可以配置该参数来激活该策略,该参数对于大型集群非常有用,其中有一些节点可能会频繁使用或短期使用不足,默认情况下,numberOfNodes 为 0。
### RemovePodsViolatingInterPodAntiAffinity
该策略可以确保从节点中删除违反 Pod 反亲和性的 Pod,比如某个节点上有 podA 这个 Pod,并且 podB 和 podC(在同一个节点上运行)具有禁止它们在同一个节点上运行的反亲和性规则,则 podA 将被从该节点上驱逐,以便 podB 和 podC 运行正常运行。当 podB 和 podC 已经运行在节点上后,反亲和性规则被创建就会发送这样的问题。
![image-20230420213157979](http://qiniu.baim0.cn/img/image-20230420213157979.png)
RemovePodsViolatingInterPodAntiAffinity
要禁用该策略,直接配置成 false 即可:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingInterPodAntiAffinity":
enabled: false
```
### RemovePodsViolatingNodeTaints
该策略可以确保从节点中删除违反 NoSchedule 污点的 Pod,比如有一个名为 podA 的 Pod,通过配置容忍 key=value:NoSchedule 允许被调度到有该污点配置的节点上,如果节点的污点随后被更新或者删除了,则污点将不再被 Pods 的容忍满足,然后将被驱逐:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingNodeTaints":
enabled: true
```
### RemovePodsViolatingNodeAffinity
该策略确保从节点中删除违反节点亲和性的 Pod。比如名为 podA 的 Pod 被调度到了节点 nodeA,podA 在调度的时候满足了节点亲和性规则 requiredDuringSchedulingIgnoredDuringExecution,但是随着时间的推移,节点 nodeA 不再满足该规则了,那么如果另一个满足节点亲和性规则的节点 nodeB 可用,则 podA 将被从节点 nodeA 驱逐,如下所示的策略配置示例:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingNodeAffinity":
enabled: true
params:
nodeAffinityType:
- "requiredDuringSchedulingIgnoredDuringExecution"
```
### RemovePodsViolatingTopologySpreadConstraint
该策略确保从节点驱逐违反拓扑分布约束的 Pods,具体来说,它试图驱逐将拓扑域平衡到每个约束的 maxSkew 内所需的最小 Pod 数,不过该策略需要 k8s 版本高于 1.18 才能使用。
默认情况下,此策略仅处理硬约束,如果将参数 includeSoftConstraints 设置为 True,也将支持软约束。
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsViolatingTopologySpreadConstraint":
enabled: true
params:
includeSoftConstraints: false
```
### RemovePodsHavingTooManyRestarts
该策略确保从节点中删除重启次数过多的 Pods,它的参数包括 podRestartThreshold(这是应将 Pod 逐出的重新启动次数),以及包括InitContainers,它确定在计算中是否应考虑初始化容器的重新启动,策略配置如下所示:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemovePodsHavingTooManyRestarts":
enabled: true
params:
podsHavingTooManyRestarts:
podRestartThreshold: 100
includingInitContainers: true
```
## Filter Pods
在驱逐 Pods 的时候,有时并不需要所有 Pods 都被驱逐,descheduler 提供了两种主要的方式进行过滤:命名空间过滤和优先级过滤。
### 命名空间过滤
该策略可以配置是包含还是排除某些名称空间。可以使用该策略的有:
- PodLifeTime
- RemovePodsHavingTooManyRestarts
- RemovePodsViolatingNodeTaints
- RemovePodsViolatingNodeAffinity
- RemovePodsViolatingInterPodAntiAffinity
- RemoveDuplicates
- RemovePodsViolatingTopologySpreadConstraint
比如只驱逐某些命令空间下的 Pods,则可以使用 include 参数进行配置,如下所示:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"PodLifeTime":
enabled: true
params:
podLifeTime:
maxPodLifeTimeSeconds: 86400
namespaces:
include:
- "namespace1"
- "namespace2"
```
又或者要排除掉某些命令空间下的 Pods,则可以使用 exclude 参数配置,如下所示:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"PodLifeTime":
enabled: true
params:
podLifeTime:
maxPodLifeTimeSeconds: 86400
namespaces:
exclude:
- "namespace1"
- "namespace2"
```
### 优先级过滤
所有策略都可以配置优先级阈值,只有在该阈值以下的 Pod 才会被驱逐,我们可以通过设置 thresholdPriorityClassName(将阈值设置为指定优先级类别的值)或 thresholdPriority(直接设置阈值)参数来指定该阈值。默认情况下,该阈值设置为 system-cluster-critical 这个 PriorityClass 类的值。
比如使用 thresholdPriority:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"PodLifeTime":
enabled: true
params:
podLifeTime:
maxPodLifeTimeSeconds: 86400
thresholdPriority: 10000
```
或者使用 thresholdPriorityClassName 进行过滤:
```yaml
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"PodLifeTime":
enabled: true
params:
podLifeTime:
maxPodLifeTimeSeconds: 86400
thresholdPriorityClassName: "priorityclass1"
```
不过需要注意不能同时配置 thresholdPriority 和 thresholdPriorityClassName,如果指定的优先级类不存在,则 descheduler 不会创建它,并且会引发错误。
## 注意事项
当使用 descheduler 驱除 Pods 的时候,需要注意以下几点:
- 关键性 Pod 不会被驱逐,比如 priorityClassName 设置为 system-cluster-critical 或 system-node-critical 的 Pod
- 不属于 RS、Deployment 或 Job 管理的 Pods 不会被驱逐
- DaemonSet 创建的 Pods 不会被驱逐
- 使用 LocalStorage 的 Pod 不会被驱逐,除非设置 evictLocalStoragePods: true
- 具有 PVC 的 Pods 不会被驱逐,除非设置 ignorePvcPods: true
- 在 LowNodeUtilization 和 RemovePodsViolatingInterPodAntiAffinity 策略下,Pods 按优先级从低到高进行驱逐,如果优先级相同,Besteffort 类型的 Pod 要先于 Burstable 和 Guaranteed 类型被驱逐
- annotations 中带有 descheduler.alpha.kubernetes.io/evict 字段的 Pod 都可以被驱逐,该注释用于覆盖阻止驱逐的检查,用户可以选择驱逐哪个 Pods
- 如果 Pods 驱逐失败,可以设置 --v=4 从 descheduler 日志中查找原因,如果驱逐违反 PDB 约束,则不会驱逐这类 Pods
+100
View File
@@ -0,0 +1,100 @@
---
title: 02 如何让你的集群更加整洁一点
date: 2023-04-20 22:23:07
tags:
- kubernetes杂谈
categories:
- kubernetes杂谈
---
## 问题背景
首先,你有没有遇到过这样的情况
```bash
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
namespace: default
labels:
test-label: test
managedFields:
- manager: kubectl
operation: Apply
apiVersion: v1
time: "2010-10-10T0:00:00Z"
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:labels:
f:test-label: {}
f:data:
f:key: {}
data:
key: some value
```
这特么的一堆括号是什么东西??????
有什么用????????
其实是记录的迭代的信息。要说有啥用,其实真的没有啥用
## 结论
以kubectl get no场景为例,当集群节点非常多的时候,集群pod非常多的时候,建议优化关闭不需要的字段。
```bash
ServerSideApply=false
```
kubectl get 资源的执行过程,是以500个对象为一个分页,从apiserver到etcd进行一致性读操作,将全部分页读到本地 并显示;过程中,会get每个资源对象的yaml。通过kubectl get <资源> -v 9 可以看到详细执行过程。所以减少单个资源 对象的yaml size,可以缩短kubectl get 的执行时间。
## 优缺点
关闭ServerSideApply featureGate (https://kubernetes.io/zh-cn/docs/reference/using-api/server-side-apply/ ),关闭managedFields更新。需要修改apiserver参数,期间apiserver会滚动更新,对生产业务无影响。
优点:
关闭之后,该字段不会更新,从而控制该字段导致的持续增长。针对新开集群操作后,可以避免后续get资源的时 候产生较大的数据量,造成kubectl缓慢。随开随用。
缺点:
在后续部署的时候,yaml中无法携带managedFields字段,否则会apply失败。
关闭了之后你会发现:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
namespace: default
labels:
test-label: test
data:
key: some value
```
哇擦,好整洁,但是只对新增的资源生效哦,不会对已有的资源有改变。
@@ -0,0 +1,78 @@
---
title: 03 如何删除终止状态的名称空间
date: 2023-04-22 21:25:07
tags:
- kubernetes杂谈
categories:
- kubernetes杂谈
---
尝试删除Kubernetes命名空间后,长时间停留在终止状态。本文介绍如何解决命名空间处于终止状态的问题。
## 问题现象
尝试删除Kubernetes命名空间后,长时间停留在终止状态。
```csharp
kubectl delete ns <namespacename>
Error from server (Conflict): Operation cannot be fulfilled on namespaces "<namespacename>": The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system.
kubectl describe ns <namespacename>
Name: <namespacename>
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"<namespacename>","namespace":""}}
Status: Terminating
```
## 可能原因
通常是因为从集群中删除的这些命名空间下存在资源。
## 解决方案
删除命名空间的finalizers。
该选项将会快速清除处于终止状态的命名空间,但可能会导致属于该命名空间的资源留在集群中,因为无法自动删除它们。在finalizers数组为空并且状态为终止之后,Kubernetes将删除命名空间。
1. 打开Shell终端,为您的Kubernetes集群创建一个反向代理。
```bash
kubectl proxy
```
输出示例如下:
```bash
Starting to serve on 127.0.0.1:8001
```
2. 打开一个新的Shell终端,通过定义环境变量来连接到Kubernetes集群,使用curl测试连接性和授权。
```bash
export TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t')
curl http://localhost:8001/api/v1/namespaces --header "Authorization: Bearer $TOKEN" --insecure
```
3. 获取命名空间定义的内容,以命名空间istio-system为例。
```sql
kubectl get namespace istio-system -o json > istio-system.json
```
4. 将finalizers数组置为空,并重新保存文件。
```json
"spec": {
"finalizers": [
]
},
```
5. 执行以下命令去除finalizers,以命名空间istio-system为例。
```bash
curl -X PUT --data-binary @istio-system.json http://localhost:8001/api/v1/namespaces/istio-system/finalize -H "Content-Type: application/json" --header "Authorization: Bearer $TOKEN" --insecure
```
+295
View File
@@ -0,0 +1,295 @@
---
title: 04 coredns相关配置
date: 2023-04-30 13:52:07
tags:
- kubernetes杂谈
categories:
- kubernetes杂谈
---
## 场景说明
使用`dnsPolicy: ClusterFirst`策略。示例配置如下:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: default
spec:
containers:
- image: alpine
command:
- sleep
- "10000"
imagePullPolicy: Always
name: alpine
dnsPolicy: ClusterFirst
```
关于**dnsPolicy**配置和场景说明,请参见[DNS原理和配置说明](https://help.aliyun.com/document_detail/188179.htm#task-1985778)。
## CoreDNS的默认配置
在命名空间kube-system下,ACK集群有一个CoreDNS配置项(有关如何查看配置项的具体步骤,请参见[管理配置项](https://help.aliyun.com/document_detail/86769.htm#section-hly-ioi-ozy))。CoreDNS会基于该配置项启用和配置插件。不同CoreDNS版本的配置项有略微差异,修改配置前请仔细阅读[CoreDNS官方文档](https://coredns.io/plugins/)。以下是一个1.6.2版本CoreDNS默认采用的配置文件:
```bash
Corefile: |
.:53 {
errors
log
health {
lameduck 15s
}
ready
kubernetes {{.ClusterDomain}} in-addr.arpa ip6.arpa {
pods verified
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
```
**说明** 配置文件中`ClusterDomain`代指集群创建过程中填写的集群本地域名,默认值为`cluster.local`。
| 参数 | 描述 |
| :------------------------- | :----------------------------------------------------------- |
| **errors** | 错误信息到标准输出。 |
| **health** | CoreDNS自身健康状态报告,默认监听端口8080,一般用来做健康检查。您可以通过`http://localhost:8080/health`获取健康状态。 |
| **ready** | CoreDNS插件状态报告,默认监听端口8181,一般用来做可读性检查。可以通过`http://localhost:8181/ready`获取可读状态。当所有插件都运行后,ready状态为200。 |
| **kubernetes** | CoreDNS Kubernetes插件,提供集群内服务解析能力。 |
| **prometheus** | CoreDNS自身metrics数据接口。可以通过`http://localhost:9153/metrics`获取prometheus格式的监控数据。 |
| **forward**(或**proxy**) | 将域名查询请求转到预定义的DNS服务器。默认配置中,当域名不在Kubernetes域时,将请求转发到预定义的解析器(/etc/resolv.conf)中。默认使用宿主机的/etc/resolv.conf配置。 |
| **cache** | DNS缓存。 |
| **loop** | 环路检测,如果检测到环路,则停止CoreDNS。 |
| **reload** | 允许自动重新加载已更改的Corefile。编辑ConfigMap配置后,请等待两分钟以使更改生效。 |
| **loadbalance** | 循环DNS负载均衡器,可以在答案中随机A、AAAA、MX记录的顺序。 |
## CoreDNS的扩展配置
针对以下不同场景,您可以扩展CoreDNS的配置:
- 场景一:开启日志服务
如果需将CoreDNS每次域名解析的日志打印出来,您可以开启Log插件,在Corefile里加上log。示例配置如下:
```bash
Corefile: |
.:53 {
errors
log
health {
lameduck 15s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
```
- 场景二:特定域名使用自定义DNS服务器
如果example.com类型后缀的域名需要经过自建DNS服务器(IP为10.10.0.10)进行解析的话,您可为域名配置一个单独的服务块。示例配置如下:
```bash
example.com:53 {
errors
cache 30
forward . 10.10.0.10
prefer_udp
}
```
完整配置如下:
```bash
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
example.com:53 {
errors
cache 30
forward . 10.10.0.10
prefer_udp
}
```
- 场景三:外部域名完全使用自建DNS服务器
如果您需要使用的自建DNS服务的域名没有统一的域名后缀,您可以选择所有集群外部域名都使用自建DNS服务器(此时需要您将自建的DNS服务不能解析的域名转发到阿里云DNS,禁止直接更改集群ECS上的/etc/resolv.conf文件)。例如,您自建的DNS服务器IP为10.10.0.10和10.10.0.20,可以更改**forward**参数进行配置。示例配置如下:
```bash
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . 10.10.0.10 10.10.0.20{
prefer_udp
}
cache 30
loop
reload
loadbalance
}
```
- 场景四:自定义Hosts
如果您需要为特定域名指定hosts,如为www.example.com指定IP为127.0.0.1,可以使用Hosts插件来配置。示例配置如下:
```go
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
ready
hosts {
127.0.0.1 www.example.com
fallthrough
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
```
**重要** 请配置**fallthrough**,否则会造成非定制Hosts域名解析失败。
- 场景五:集群外部访问集群内服务
如果您希望运行在集群ECS上的进程能够访问到集群内的服务,虽然可以通过将ECS的/etc/resolv.conf文件内`nameserver`配置为集群kube-dns的ClusterIP地址来达到目的,但不推荐您直接更改ECS的/etc/resolv.conf文件的方式来达到任何目的。
内网场景下,您可以将集群内的服务通过内网SLB进行暴露,然后在[云解析PrivateZone控制台](https://dns.console.aliyun.com/#/dns/domainList)通过添加A记录到该SLB的内网IP进行解析。具体操作,请参见[添加解析记录](https://help.aliyun.com/document_detail/64635.html)。
- 场景六:统一域名访问服务或是在集群内对域名的做CNAME解析
您可以实现在公网、内网和集群内部通过统一域名foo.example.com访问您的服务,原理如下:
- 集群内的服务`foo.default.svc.cluster.local`通过公网SLB进行了暴露,且有域名`foo.example.com`解析到该公网SLB的IP。
- 集群内服务`foo.default.svc.cluster.local`通过内网SLB进行了暴露,且通过[云解析PrivateZone](https://dns.console.aliyun.com/#/dns/domainList)在VPC内网中将`foo.example.com`解析到该内网SLB的IP。具体步骤,请参见上述[场景四:自定义Hosts](https://help.aliyun.com/document_detail/380963.html?spm=a2c4g.750001.0.i1#section-6jf-fgj-j2f)。
- 在集群内部,您可以通过Rewrite插件将
```go
foo.example.com
```
CNAME到
```go
foo.default.svc.cluster.local
```
。示例配置如下:
```go
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
ready
rewrite stop {
name regex foo.example.com foo.default.svc.cluster.local
answer name foo.default.svc.cluster.local foo.example.com
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
```
- 场景七:禁止CoreDNS对IPv6类型的AAAA记录查询返回
当业务容器不需要AAAA记录类型时,可以在CoreDNS中将AAAA记录类型拦截,返回空(NODATA),以减少不必要的网络通信。示例配置如下:
```yaml
Corefile: |
.:53 {
errors
health {
lameduck 15s
}
#新增以下一行Template插件,其它数据请保持不变。
template IN AAAA .
}
```
BIN
View File
Binary file not shown.
+139
View File
@@ -0,0 +1,139 @@
---
title: 01 kubernetes介绍及安装
date: 2022-10-22 20:55:07
tags:
- kubernetes
categories:
- kubernetes
---
# 第一章 kubernetes介绍
本章节主要介绍应用程序在服务器上部署方式演变以及kubernetes的概念、组件和工作原理。
## 应用部署方式演变
在部署应用程序的方式上,主要经历了三个时代:
- **传统部署**:互联网早期,会直接将应用程序部署在物理机上
> 优点:简单,不需要其它技术的参与
>
> 缺点:不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响
- **虚拟化部署**:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境
> 优点:程序环境不会相互产生影响,提供了一定程度的安全性
>
> 缺点:增加了操作系统,浪费了部分资源
- **容器化部署**:与虚拟化类似,但是共享了操作系统
> 优点:
>
> ​ 可以保证每个容器拥有自己的文件系统、CPU、内存、进程空间等
>
> ​ 运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦
>
> ​ 容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署
![image-20200505183738289](http://qiniu.baim0.cn/img/image-20200505183738289.png)
容器化部署方式给带来很多的便利,但是也会出现一些问题,比如说:
- 一个容器故障停机了,怎么样让另外一个容器立刻启动去替补停机的容器
- 当并发访问量变大的时候,怎么样做到横向扩展容器数量
这些容器管理的问题统称为**容器编排**问题,为了解决这些容器编排问题,就产生了一些容器编排的软件:
- **Swarm**:Docker自己的容器编排工具
- **Mesos**:Apache的一个资源统一管控的工具,需要和Marathon结合使用
- **Kubernetes**:Google开源的的容器编排工具
![](http://qiniu.baim0.cn/img/image-20200524150339551-20221022204504153-20221022210813743.png)
## kubernetes简介
![](http://qiniu.baim0.cn/img/image-20200406232838722.png)
​
​ kubernetes,是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的秘密武器----Borg系统的一个开源版本,于2014年9月发布第一个版本,2015年7月发布第一个正式版本。
​ kubernetes的本质是**一组服务器集群**,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
- **自我修复**:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器
- **弹性伸缩**:可以根据需要,自动对集群中正在运行的容器数量进行调整
- **服务发现**:服务可以通过自动发现的形式找到它所依赖的服务
- **负载均衡**:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
- **版本回退**:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
- **存储编排**:可以根据容器自身的需求自动创建存储卷
![image-20200526203726071](http://qiniu.baim0.cn/img/image-20200526203726071.png)
## kubernetes组件
一个kubernetes集群主要是由**控制节点(master)**、**工作节点(node)**构成,每个节点上都会安装不同的组件。
**master:集群的控制平面,负责集群的决策 ( 管理 )**
> **ApiServer** : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制
>
> **Scheduler** : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
>
> **ControllerManager** : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
>
> **Etcd **:负责存储集群中各种资源对象的信息
**node:集群的数据平面,负责为容器提供运行环境 ( 干活 ) **
> **Kubelet** : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器
>
> **KubeProxy** : 负责提供集群内部的服务发现和负载均衡
>
> **Docker** : 负责节点上容器的各种操作
![](http://qiniu.baim0.cn/img/image-20200406184656917-20221022210659552.png)
下面,以部署一个nginx服务来说明kubernetes系统各个组件调用关系:
1. 首先要明确,一旦kubernetes环境启动之后,master和node都会将自身的信息存储到etcd数据库中
2. 一个nginx服务的安装请求会首先被发送到master节点的apiServer组件
3. apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上
在此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer
4. apiServer调用controller-manager去调度Node节点安装nginx服务
5. kubelet接收到指令后,会通知docker,然后由docker来启动一个nginx的pod
pod是kubernetes的最小操作单元,容器必须跑在pod中至此,
6. 一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理
​ 这样,外界用户就可以访问集群中的nginx服务了
## kubernetes概念
**Master**:集群控制节点,每个集群需要至少一个master节点负责集群的管控
**Node**:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行
**Pod**:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或者多个容器
**Controller**:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等
**Service**:pod对外服务的统一入口,下面可以维护者同一类的多个pod
**Label**:标签,用于对pod进行分类,同一类pod会拥有相同的标签
**NameSpace**:命名空间,用来隔离pod的运行环境
![](http://qiniu.baim0.cn/img/image-20200403224313355-20221022210842963.png)
File diff suppressed because it is too large Load Diff
+680
View File
@@ -0,0 +1,680 @@
---
title: 07 Service详解
date: 2022-10-22 20:58:13
tags:
- kubernetes
categories:
- kubernetes
---
# 第七章 Service详解
本章节主要介绍kubernetes的流量负载组件:Service和Ingress。
## Service介绍
​ 在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。
​ 为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。
![](http://qiniu.baim0.cn/img/image-20200408194716912-20221022205715895-20221022211426829.png)
​ Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后**它会将最新的Service信息转换成对应的访问规则**。
![](http://qiniu.baim0.cn/img/image-20200509121254425-20221022211441433.png)
~~~powershell
# 10.97.97.97:80 是service提供的访问入口
# 当访问这个入口的时候,可以发现后面有三个pod的服务在等待调用,
# kube-proxy会基于rr(轮询)的策略,将请求分发到其中一个pod上去
# 这个规则会同时在集群内的所有节点上都生成,所以在任何一个节点上访问都可以。
[root@node1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.97.97.97:80 rr
-> 10.244.1.39:80 Masq 1 0 0
-> 10.244.1.40:80 Masq 1 0 0
-> 10.244.2.33:80 Masq 1 0 0
~~~
kube-proxy目前支持三种工作模式:
**userspace 模式**
​ userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。
​ 该模式下,kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。
![](http://qiniu.baim0.cn/img/image-20200509151424280-20221022211458566.png)
**iptables 模式**
​ iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。
​ 该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
![](http://qiniu.baim0.cn/img/image-20200509152947714-20221022211513971.png)
**ipvs 模式**
​ ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此以外,ipvs支持更多的LB算法。
![](http://qiniu.baim0.cn/img/image-20200509153731363-20221022211528517.png)
~~~powershell
# 此模式必须安装ipvs内核模块,否则会降级为iptables
# 开启ipvs
[root@master ~]# kubectl edit cm kube-proxy -n kube-system
[root@master ~]# kubectl delete pod -l k8s-app=kube-proxy -n kube-system
[root@node1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.97.97.97:80 rr
-> 10.244.1.39:80 Masq 1 0 0
-> 10.244.1.40:80 Masq 1 0 0
-> 10.244.2.33:80 Masq 1 0 0
~~~
## Service类型
Service的资源清单文件:
~~~yaml
kind: Service # 资源类型
apiVersion: v1 # 资源版本
metadata: # 元数据
name: service # 资源名称
namespace: dev # 命名空间
spec: # 描述
selector: # 标签选择器,用于确定当前service代理哪些pod
app: nginx
type: # Service类型,指定service的访问方式
clusterIP: # 虚拟服务的ip地址
sessionAffinity: # session亲和性,支持ClientIP、None两个选项
ports: # 端口信息
- protocol: TCP
port: 3017 # service端口
targetPort: 5003 # pod端口
nodePort: 31122 # 主机端口
~~~
- ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
- NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
- LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
- ExternalName: 把集群外部的服务引入集群内部,直接使用
## Service使用
### 实验环境准备
在使用service之前,首先利用Deployment创建出3个pod,注意要为pod设置`app=nginx-pod`的标签
创建deployment.yaml,内容如下:
~~~yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pc-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
~~~
~~~powershell
[root@master ~]# kubectl create -f deployment.yaml
deployment.apps/pc-deployment created
# 查看pod详情
[root@master ~]# kubectl get pods -n dev -o wide --show-labels
NAME READY STATUS IP NODE LABELS
pc-deployment-66cb59b984-8p84h 1/1 Running 10.244.1.40 node1 app=nginx-pod
pc-deployment-66cb59b984-vx8vx 1/1 Running 10.244.2.33 node2 app=nginx-pod
pc-deployment-66cb59b984-wnncx 1/1 Running 10.244.1.39 node1 app=nginx-pod
# 为了方便后面的测试,修改下三台nginx的index.html页面(三台修改的IP地址不一致)
# kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/sh
# echo "10.244.1.40" > /usr/share/nginx/html/index.html
#修改完毕之后,访问测试
[root@master ~]# curl 10.244.1.40
10.244.1.40
[root@master ~]# curl 10.244.2.33
10.244.2.33
[root@master ~]# curl 10.244.1.39
10.244.1.39
~~~
### ClusterIP类型的Service
创建service-clusterip.yaml文件
~~~yaml
apiVersion: v1
kind: Service
metadata:
name: service-clusterip
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: 10.97.97.97 # service的ip地址,如果不写,默认会生成一个
type: ClusterIP
ports:
- port: 80 # Service端口
targetPort: 80 # pod端口
~~~
~~~powershell
# 创建service
[root@master ~]# kubectl create -f service-clusterip.yaml
service/service-clusterip created
# 查看service
[root@master ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-clusterip ClusterIP 10.97.97.97 <none> 80/TCP 13s app=nginx-pod
# 查看service的详细信息
# 在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口
[root@master ~]# kubectl describe svc service-clusterip -n dev
Name: service-clusterip
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP: 10.97.97.97
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.39:80,10.244.1.40:80,10.244.2.33:80
Session Affinity: None
Events: <none>
# 查看ipvs的映射规则
[root@master ~]# ipvsadm -Ln
TCP 10.97.97.97:80 rr
-> 10.244.1.39:80 Masq 1 0 0
-> 10.244.1.40:80 Masq 1 0 0
-> 10.244.2.33:80 Masq 1 0 0
# 访问10.97.97.97:80观察效果
[root@master ~]# curl 10.97.97.97:80
10.244.2.33
~~~
**Endpoint**
​ Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。
​ 一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来,**Endpoints是实现实际服务的端点集合**。换句话说,service和pod之间的联系是通过endpoints实现的。
![image-20200509191917069](http://qiniu.baim0.cn/img/image-20200509191917069.png)
**负载分发策略**
对Service的访问被分发到了后端的Pod上去,目前kubernetes提供了两种负载分发策略:
- 如果不定义,默认使用kube-proxy的策略,比如随机、轮询
- 基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上
此模式可以使在spec中添加`sessionAffinity:ClientIP`选项
~~~powershell
# 查看ipvs的映射规则【rr 轮询】
[root@master ~]# ipvsadm -Ln
TCP 10.97.97.97:80 rr
-> 10.244.1.39:80 Masq 1 0 0
-> 10.244.1.40:80 Masq 1 0 0
-> 10.244.2.33:80 Masq 1 0 0
# 循环访问测试
[root@master ~]# while true;do curl 10.97.97.97:80; sleep 5; done;
10.244.1.40
10.244.1.39
10.244.2.33
10.244.1.40
10.244.1.39
10.244.2.33
# 修改分发策略----sessionAffinity:ClientIP
# 查看ipvs规则【persistent 代表持久】
[root@master ~]# ipvsadm -Ln
TCP 10.97.97.97:80 rr persistent 10800
-> 10.244.1.39:80 Masq 1 0 0
-> 10.244.1.40:80 Masq 1 0 0
-> 10.244.2.33:80 Masq 1 0 0
# 循环访问测试
[root@master ~]# while true;do curl 10.97.97.97; sleep 5; done;
10.244.2.33
10.244.2.33
10.244.2.33
# 删除service
[root@master ~]# kubectl delete -f service-clusterip.yaml
service "service-clusterip" deleted
~~~
### HeadLiness类型的Service
​ 在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。
创建service-headliness.yaml
~~~yaml
apiVersion: v1
kind: Service
metadata:
name: service-headliness
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
type: ClusterIP
ports:
- port: 80
targetPort: 80
~~~
~~~powershell
# 创建service
[root@master ~]# kubectl create -f service-headliness.yaml
service/service-headliness created
# 获取service, 发现CLUSTER-IP未分配
[root@master ~]# kubectl get svc service-headliness -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-headliness ClusterIP None <none> 80/TCP 11s app=nginx-pod
# 查看service详情
[root@master ~]# kubectl describe svc service-headliness -n dev
Name: service-headliness
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.39:80,10.244.1.40:80,10.244.2.33:80
Session Affinity: None
Events: <none>
# 查看域名的解析情况
[root@master ~]# kubectl exec -it pc-deployment-66cb59b984-8p84h -n dev /bin/sh
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search dev.svc.cluster.local svc.cluster.local cluster.local
[root@master ~]# dig @10.96.0.10 service-headliness.dev.svc.cluster.local
service-headliness.dev.svc.cluster.local. 30 IN A 10.244.1.40
service-headliness.dev.svc.cluster.local. 30 IN A 10.244.1.39
service-headliness.dev.svc.cluster.local. 30 IN A 10.244.2.33
~~~
### NodePort类型的Service
​ 在之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是**将service的端口映射到Node的一个端口上**,然后就可以通过`NodeIp:NodePort`来访问service了。
![](http://qiniu.baim0.cn/img/image-20200620175731338-20221022211553554.png)
创建service-nodeport.yaml
~~~yaml
apiVersion: v1
kind: Service
metadata:
name: service-nodeport
namespace: dev
spec:
selector:
app: nginx-pod
type: NodePort # service类型
ports:
- port: 80
nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配
targetPort: 80
~~~
~~~powershell
# 创建service
[root@master ~]# kubectl create -f service-nodeport.yaml
service/service-nodeport created
# 查看service
[root@master ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) SELECTOR
service-nodeport NodePort 10.105.64.191 <none> 80:30002/TCP app=nginx-pod
# 接下来可以通过电脑主机的浏览器去访问集群中任意一个nodeip的30002端口,即可访问到pod
~~~
### LoadBalancer类型的Service
​ LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
![](http://qiniu.baim0.cn/img/image-20200510103945494-20221022211606870.png)
### ExternalName类型的Service
​ ExternalName类型的Service用于引入集群外部的服务,它通过`externalName`属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。
![](http://qiniu.baim0.cn/img/image-20200510113311209-20221022211619505.png)
~~~yaml
apiVersion: v1
kind: Service
metadata:
name: service-externalname
namespace: dev
spec:
type: ExternalName # service类型
externalName: www.baidu.com #改成ip地址也可以
~~~
~~~powershell
# 创建service
[root@master ~]# kubectl create -f service-externalname.yaml
service/service-externalname created
# 域名解析
[root@master ~]# dig @10.96.0.10 service-externalname.dev.svc.cluster.local
service-externalname.dev.svc.cluster.local. 30 IN CNAME www.baidu.com.
www.baidu.com. 30 IN CNAME www.a.shifen.com.
www.a.shifen.com. 30 IN A 39.156.66.18
www.a.shifen.com. 30 IN A 39.156.66.14
~~~
## Ingress介绍
​ 在前面课程中已经提到,Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:
- NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显
- LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持
​ 基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:
![](http://qiniu.baim0.cn/img/image-20200623092808049-20221022211636731.png)
​ 实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在**Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务**。在这里有两个核心概念:
- ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则
- ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等
Ingress(以Nginx为例)的工作原理如下:
1. 用户编写Ingress规则,说明哪个域名对应kubernetes集群中的哪个Service
2. Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置
3. Ingress控制器会将生成的Nginx配置写入到一个运行着的Nginx服务中,并动态更新
4. 到此为止,其实真正在工作的就是一个Nginx了,内部配置了用户定义的请求转发规则
![](http://qiniu.baim0.cn/img/image-20200516112704764-20221022211650736.png)
## Ingress使用
### 环境准备
**搭建ingress环境**
~~~powershell
# 创建文件夹
[root@master ~]# mkdir ingress-controller
[root@master ~]# cd ingress-controller/
# 获取ingress-nginx,本次案例使用的是0.30版本
[root@master ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
[root@master ingress-controller]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
# 修改mandatory.yaml文件中的仓库
# 修改quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 为quay-mirror.qiniu.com/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0
# 创建ingress-nginx
[root@master ingress-controller]# kubectl apply -f ./
# 查看ingress-nginx
[root@master ingress-controller]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/nginx-ingress-controller-fbf967dd5-4qpbp 1/1 Running 0 12h
# 查看service
[root@master ingress-controller]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.98.75.163 <none> 80:32240/TCP,443:31335/TCP 11h
~~~
**准备service和pod**
为了后面的实验比较方便,创建如下图所示的模型
![](http://qiniu.baim0.cn/img/image-20200516102419998-20221022211705664.png)
创建tomcat-nginx.yaml
~~~yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: tomcat-pod
template:
metadata:
labels:
app: tomcat-pod
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: None
type: ClusterIP
ports:
- port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-service
namespace: dev
spec:
selector:
app: tomcat-pod
clusterIP: None
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
~~~
~~~powershell
# 创建
[root@master ~]# kubectl create -f tomcat-nginx.yaml
# 查看
[root@master ~]# kubectl get svc -n dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP None <none> 80/TCP 48s
tomcat-service ClusterIP None <none> 8080/TCP 48s
~~~
### Http代理
创建ingress-http.yaml
~~~yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-http
namespace: dev
spec:
rules:
- host: nginx.itheima.com
http:
paths:
- path: /
backend:
serviceName: nginx-service
servicePort: 80
- host: tomcat.itheima.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 8080
~~~
~~~powershell
# 创建
[root@master ~]# kubectl create -f ingress-http.yaml
ingress.extensions/ingress-http created
# 查看
[root@master ~]# kubectl get ing ingress-http -n dev
NAME HOSTS ADDRESS PORTS AGE
ingress-http nginx.itheima.com,tomcat.itheima.com 80 22s
# 查看详情
[root@master ~]# kubectl describe ing ingress-http -n dev
...
Rules:
Host Path Backends
---- ---- --------
nginx.itheima.com / nginx-service:80 (10.244.1.96:80,10.244.1.97:80,10.244.2.112:80)
tomcat.itheima.com / tomcat-service:8080(10.244.1.94:8080,10.244.1.95:8080,10.244.2.111:8080)
...
# 接下来,在本地电脑上配置host文件,解析上面的两个域名到192.168.109.100(master)上
# 然后,就可以分别访问tomcat.itheima.com:32240 和 nginx.itheima.com:32240 查看效果了
~~~
### Https代理
创建证书
~~~powershell
# 生成证书
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=itheima.com"
# 创建密钥
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
~~~
创建ingress-https.yaml
~~~yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-https
namespace: dev
spec:
tls:
- hosts:
- nginx.itheima.com
- tomcat.itheima.com
secretName: tls-secret # 指定秘钥
rules:
- host: nginx.itheima.com
http:
paths:
- path: /
backend:
serviceName: nginx-service
servicePort: 80
- host: tomcat.itheima.com
http:
paths:
- path: /
backend:
serviceName: tomcat-service
servicePort: 8080
~~~
~~~powershell
# 创建
[root@master ~]# kubectl create -f ingress-https.yaml
ingress.extensions/ingress-https created
# 查看
[root@master ~]# kubectl get ing ingress-https -n dev
NAME HOSTS ADDRESS PORTS AGE
ingress-https nginx.itheima.com,tomcat.itheima.com 10.104.184.38 80, 443 2m42s
# 查看详情
[root@master ~]# kubectl describe ing ingress-https -n dev
...
TLS:
tls-secret terminates nginx.itheima.com,tomcat.itheima.com
Rules:
Host Path Backends
---- ---- --------
nginx.itheima.com / nginx-service:80 (10.244.1.97:80,10.244.1.98:80,10.244.2.119:80)
tomcat.itheima.com / tomcat-service:8080(10.244.1.99:8080,10.244.2.117:8080,10.244.2.120:8080)
...
# 下面可以通过浏览器访问https://nginx.itheima.com:31335 和 https://tomcat.itheima.com:31335来查看了
~~~
File diff suppressed because it is too large Load Diff
+384
View File
@@ -0,0 +1,384 @@
---
title: 02 集群环境搭建
date: 2022-10-22 20:56:07
tags:
- kubernetes
categories:
- kubernetes
---
# 第二章 集群环境搭建
本章节主要介绍如何搭建kubernetes的集群环境
## 环境规划
### 集群类型
kubernetes集群大体上分为两类:**一主多从**和**多主多从**。
- 一主多从:一台Master节点和多台Node节点,搭建简单,但是有单机故障风险,适合用于测试环境
- 多主多从:多台Master节点和多台Node节点,搭建麻烦,安全性高,适合用于生产环境
![image-20200404094800622](http://qiniu.baim0.cn/img/image-20200404094800622-20221022205026097.png)
> `说明:为了测试简单,本次搭建的是 一主两从 类型的集群`
### 安装方式
kubernetes有多种部署方式,目前主流的方式有kubeadm、minikube、二进制包
- minikube:一个用于快速搭建单节点kubernetes的工具
- kubeadm:一个用于快速搭建kubernetes集群的工具
- 二进制包 :从官网下载每个组件的二进制包,依次去安装,此方式对于理解kubernetes组件更加有效
> `说明:现在需要安装kubernetes的集群环境,但是又不想过于麻烦,所以选择使用kubeadm方式`
### 主机规划
| 作用 | IP地址 | 操作系统 | 配置 |
| ------ | --------------- | --------------------------- | ------------------------ |
| Master | 192.168.109.101 | Centos7.5 基础设施服务器 | 2颗CPU 2G内存 50G硬盘 |
| Node1 | 192.168.109.102 | Centos7.5 基础设施服务器 | 2颗CPU 2G内存 50G硬盘 |
| Node2 | 192.168.109.103 | Centos7.5 基础设施服务器 | 2颗CPU 2G内存 50G硬盘 |
## 环境搭建
​ 本次环境搭建需要安装三台Centos服务器(一主二从),然后在每台服务器中分别安装docker(18.06.3),kubeadm(1.17.4)、kubelet(1.17.4)、kubectl(1.17.4)程序。
### 主机安装
安装虚拟机过程中注意下面选项的设置:
- 操作系统环境:CPU(2C) 内存(2G) 硬盘(50G)
- 语言选择:中文简体
- 软件选择:基础设施服务器
- 分区选择:自动分区
- 网络配置:按照下面配置网路地址信息
~~~md
网络地址:192.168.109.100 (每台主机都不一样 分别为100、101、102)
子网掩码:255.255.255.0
默认网关:192.168.109.2
DNS: 223.5.5.5
~~~
![image-20200505213817934](http://qiniu.baim0.cn/img/image-20200505213817934-20221022205026175.png)
- 主机名设置:按照下面信息设置主机名
~~~md
master节点: master
node节点: node1
node节点: node2
~~~
![image-20200505214156148](http://qiniu.baim0.cn/img/image-20200505214156148-20221022205026250.png)
### 环境初始化
1) 检查操作系统的版本
~~~powershell
# 此方式下安装kubernetes集群要求Centos版本要在7.5或之上
[root@master ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
~~~
2) 主机名解析
为了方便后面集群节点间的直接调用,在这配置一下主机名解析,企业中推荐使用内部DNS服务器
```powershell
# 主机名成解析 编辑三台服务器的/etc/hosts文件,添加下面内容
192.168.109.100 master
192.168.109.101 node1
192.168.109.102 node2
```
3) 时间同步
kubernetes要求集群中的节点时间必须精确一致,这里直接使用chronyd服务从网络同步时间。
企业中建议配置内部的时间同步服务器
~~~powershell
# 启动chronyd服务
[root@master ~]# systemctl start chronyd
# 设置chronyd服务开机自启
[root@master ~]# systemctl enable chronyd
# chronyd服务启动稍等几秒钟,就可以使用date命令验证时间了
[root@master ~]# date
~~~
4) 禁用iptables和firewalld服务
kubernetes和docker在运行中会产生大量的iptables规则,为了不让系统规则跟它们混淆,直接关闭系统的规则
~~~powershell
# 1 关闭firewalld服务
[root@master ~]# systemctl stop firewalld
[root@master ~]# systemctl disable firewalld
# 2 关闭iptables服务
[root@master ~]# systemctl stop iptables
[root@master ~]# systemctl disable iptables
~~~
5) 禁用selinux
selinux是linux系统下的一个安全服务,如果不关闭它,在安装集群中会产生各种各样的奇葩问题
~~~powershell
# 编辑 /etc/selinux/config 文件,修改SELINUX的值为disabled
# 注意修改完毕之后需要重启linux服务
SELINUX=disabled
~~~
6) 禁用swap分区
swap分区指的是虚拟内存分区,它的作用是在物理内存使用完之后,将磁盘空间虚拟成内存来使用
启用swap设备会对系统的性能产生非常负面的影响,因此kubernetes要求每个节点都要禁用swap设备
但是如果因为某些原因确实不能关闭swap分区,就需要在集群安装过程中通过明确的参数进行配置说明
~~~powershell
# 编辑分区配置文件/etc/fstab,注释掉swap分区一行
# 注意修改完毕之后需要重启linux服务
UUID=455cc753-7a60-4c17-a424-7741728c44a1 /boot xfs defaults 0 0
/dev/mapper/centos-home /home xfs defaults 0 0
# /dev/mapper/centos-swap swap swap defaults 0 0
~~~
7)修改linux的内核参数
~~~powershell
# 修改linux的内核参数,添加网桥过滤和地址转发功能
# 编辑/etc/sysctl.d/kubernetes.conf文件,添加如下配置:
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
# 重新加载配置
[root@master ~]# sysctl -p
# 加载网桥过滤模块
[root@master ~]# modprobe br_netfilter
# 查看网桥过滤模块是否加载成功
[root@master ~]# lsmod | grep br_netfilter
~~~
8)配置ipvs功能
在kubernetes中service有两种代理模型,一种是基于iptables的,一种是基于ipvs的
两者比较的话,ipvs的性能明显要高一些,但是如果要使用它,需要手动载入ipvs模块
~~~powershell
# 1 安装ipset和ipvsadm
[root@master ~]# yum install ipset ipvsadmin -y
# 2 添加需要加载的模块写入脚本文件
[root@master ~]# cat <<EOF > /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
# 3 为脚本文件添加执行权限
[root@master ~]# chmod +x /etc/sysconfig/modules/ipvs.modules
# 4 执行脚本文件
[root@master ~]# /bin/bash /etc/sysconfig/modules/ipvs.modules
# 5 查看对应的模块是否加载成功
[root@master ~]# lsmod | grep -e ip_vs -e nf_conntrack_ipv4
~~~
9) 重启服务器
上面步骤完成之后,需要重新启动linux系统
~~~powershell
[root@master ~]# reboot
~~~
### 安装docker
~~~powershell
# 1 切换镜像源
[root@master ~]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
# 2 查看当前镜像源中支持的docker版本
[root@master ~]# yum list docker-ce --showduplicates
# 3 安装特定版本的docker-ce
# 必须指定--setopt=obsoletes=0,否则yum会自动安装更高版本
[root@master ~]# yum install --setopt=obsoletes=0 docker-ce-18.06.3.ce-3.el7 -y
# 4 添加一个配置文件
# Docker在默认情况下使用的Cgroup Driver为cgroupfs,而kubernetes推荐使用systemd来代替cgroupfs
[root@master ~]# mkdir /etc/docker
[root@master ~]# cat <<EOF > /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://kn0t2bca.mirror.aliyuncs.com"]
}
EOF
# 5 启动docker
[root@master ~]# systemctl restart docker
[root@master ~]# systemctl enable docker
# 6 检查docker状态和版本
[root@master ~]# docker version
~~~
### 安装kubernetes组件
~~~powershell
# 由于kubernetes的镜像源在国外,速度比较慢,这里切换成国内的镜像源
# 编辑/etc/yum.repos.d/kubernetes.repo,添加下面的配置
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
# 安装kubeadm、kubelet和kubectl
[root@master ~]# yum install --setopt=obsoletes=0 kubeadm-1.17.4-0 kubelet-1.17.4-0 kubectl-1.17.4-0 -y
# 配置kubelet的cgroup
# 编辑/etc/sysconfig/kubelet,添加下面的配置
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd"
KUBE_PROXY_MODE="ipvs"
# 4 设置kubelet开机自启
[root@master ~]# systemctl enable kubelet
~~~
### 准备集群镜像
~~~powershell
# 在安装kubernetes集群之前,必须要提前准备好集群需要的镜像,所需镜像可以通过下面命令查看
[root@master ~]# kubeadm config images list
# 下载镜像
# 此镜像在kubernetes的仓库中,由于网络原因,无法连接,下面提供了一种替代方案
images=(
kube-apiserver:v1.17.4
kube-controller-manager:v1.17.4
kube-scheduler:v1.17.4
kube-proxy:v1.17.4
pause:3.1
etcd:3.4.3-0
coredns:1.6.5
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName k8s.gcr.io/$imageName
docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done
~~~
### 集群初始化
下面开始对集群进行初始化,并将node节点加入到集群中
> 下面的操作只需要在`master`节点上执行即可
~~~powershell
# 创建集群
[root@master ~]# kubeadm init \
--kubernetes-version=v1.17.4 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12 \
--apiserver-advertise-address=192.168.109.100
# 创建必要文件
[root@master ~]# mkdir -p $HOME/.kube
[root@master ~]# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@master ~]# sudo chown $(id -u):$(id -g) $HOME/.kube/config
~~~
> 下面的操作只需要在`node`节点上执行即可
~~~powershell
# 将node节点加入集群
[root@master ~]# kubeadm join 192.168.109.100:6443 \
--token 8507uc.o0knircuri8etnw2 \
--discovery-token-ca-cert-hash \
sha256:acc37967fb5b0acf39d7598f8a439cc7dc88f439a3f4d0c9cae88e7901b9d3f
# 查看集群状态 此时的集群状态为NotReady,这是因为还没有配置网络插件
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 6m43s v1.17.4
node1 NotReady <none> 22s v1.17.4
node2 NotReady <none> 19s v1.17.4
~~~
### 安装网络插件
kubernetes支持多种网络插件,比如flannel、calico、canal等等,任选一种使用即可,本次选择flannel
> 下面操作依旧只在`master`节点执行即可,插件使用的是DaemonSet的控制器,它会在每个节点上都运行
~~~powershell
# 获取fannel的配置文件
[root@master ~]# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 修改文件中quay.io仓库为quay-mirror.qiniu.com
# 使用配置文件启动fannel
[root@master ~]# kubectl apply -f kube-flannel.yml
# 稍等片刻,再次查看集群节点的状态
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 15m v1.17.4
node1 Ready <none> 8m53s v1.17.4
node2 Ready <none> 8m50s v1.17.4
~~~
至此,kubernetes的集群环境搭建完成
## 服务部署
接下来在kubernetes集群中部署一个nginx程序,测试下集群是否在正常工作。
~~~powershell
# 部署nginx
[root@master ~]# kubectl create deployment nginx --image=nginx:1.14-alpine
# 暴露端口
[root@master ~]# kubectl expose deployment nginx --port=80 --type=NodePort
# 查看服务状态
[root@master ~]# kubectl get pods,service
NAME READY STATUS RESTARTS AGE
pod/nginx-86c57db685-fdc2k 1/1 Running 0 18m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 82m
service/nginx NodePort 10.104.121.45 <none> 80:30073/TCP 17m
# 4 最后在电脑上访问下部署的nginx服务
~~~
![](http://qiniu.baim0.cn/img/image-20200405142656921-20221022205026308-20221022210919661.png)
+536
View File
@@ -0,0 +1,536 @@
---
title: 03 资源管理
date: 2022-10-22 20:56:09
tags:
- kubernetes
categories:
- kubernetes
---
# 第三章 资源管理
本章节主要介绍yaml语法和kubernetes的资源管理方式
## 资源管理介绍
在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes。
>​ kubernetes的本质上就是一个集群系统,用户可以在集群中部署各种服务,所谓的部署服务,其实就是在kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。
>
>​ kubernetes的最小管理单元是pod而不是容器,所以只能将容器放在`Pod`中,而kubernetes一般也不会直接管理Pod,而是通过`Pod控制器`来管理Pod的。
>
>​ Pod可以提供服务之后,就要考虑如何访问Pod中服务,kubernetes提供了`Service`资源实现这个功能。
>
>​ 当然,如果Pod中程序的数据需要持久化,kubernetes还提供了各种`存储`系统。
![](http://qiniu.baim0.cn/img/image-20200406225334627-20221022204610663-20221022205026477-20221022205156354-20221022210936856.png)
> 学习kubernetes的核心,就是学习如何对集群上的`Pod、Pod控制器、Service、存储`等各种资源进行操作
## YAML语言介绍
​ YAML是一个类似 XML、JSON 的标记性语言。它强调以**数据**为中心,并不是以标识语言为重点。因而YAML本身的定义比较简单,号称"一种人性化的数据格式语言"。
~~~xml
<heima>
<age>15</age>
<address>Beijing</address>
</heima>
~~~
~~~yaml
heima:
age: 15
address: Beijing
~~~
YAML的语法比较简单,主要有下面几个:
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格( 低版本限制 )
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注释
YAML支持以下几种数据类型:
- 纯量:单个的、不可再分的值
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hash) / 字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
~~~yaml
# 纯量, 就是指的一个简单的值,字符串、布尔值、整数、浮点数、Null、时间、日期
# 1 布尔类型
c1: true (或者True)
# 2 整型
c2: 234
# 3 浮点型
c3: 3.14
# 4 null类型
c4: ~ # 使用~表示null
# 5 日期类型
c5: 2018-02-17 # 日期必须使用ISO 8601格式,即yyyy-MM-dd
# 6 时间类型
c6: 2018-02-17T15:02:31+08:00 # 时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
# 7 字符串类型
c7: heima # 简单写法,直接写值 , 如果字符串中间有特殊字符,必须使用双引号或者单引号包裹
c8: line1
line2 # 字符串过多的情况可以拆成多行,每一行会被转化成一个空格
~~~
~~~yaml
# 对象
# 形式一(推荐):
heima:
age: 15
address: Beijing
# 形式二(了解):
heima: {age: 15,address: Beijing}
~~~
~~~yaml
# 数组
# 形式一(推荐):
address:
- 顺义
- 昌平
# 形式二(了解):
address: [顺义,昌平]
~~~
> 小提示:
>
> ​ 1 书写yaml切记`:` 后面要加一个空格
>
> ​ 2 如果需要将多段yaml配置放在一个文件中,中间要使用`---`分隔
>
> ​ 3 下面是一个yaml转json的网站,可以通过它验证yaml是否书写正确
>
> ​ https://www.json2yaml.com/convert-yaml-to-json
## 资源管理方式
- 命令式对象管理:直接使用命令去操作kubernetes资源
`kubectl run nginx-pod --image=nginx:1.17.1 --port=80`
- 命令式对象配置:通过命令配置和配置文件去操作kubernetes资源
`kubectl create/patch -f nginx-pod.yaml`
- 声明式对象配置:通过apply命令和配置文件去操作kubernetes资源
`kubectl apply -f nginx-pod.yaml`
| 类型 | 操作对象 | 适用环境 | 优点 | 缺点 |
| -------------- | -------- | -------- | -------------- | -------------------------------- |
| 命令式对象管理 | 对象 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪 |
| 命令式对象配置 | 文件 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 |
| 声明式对象配置 | 目录 | 开发 | 支持目录操作 | 意外情况下难以调试 |
### 命令式对象管理
**kubectl命令**
​ kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署。kubectl命令的语法如下:
~~~md
kubectl [command] [type] [name] [flags]
~~~
**comand**:指定要对资源执行的操作,例如create、get、delete
**type**:指定资源类型,比如deployment、pod、service
**name**:指定资源的名称,名称大小写敏感
**flags**:指定额外的可选参数
~~~powershell
# 查看所有pod
kubectl get pod
# 查看某个pod
kubectl get pod pod_name
# 查看某个pod,以yaml格式展示结果
kubectl get pod pod_name -o yaml
~~~
**资源类型**
kubernetes中所有的内容都抽象为资源,可以通过下面的命令进行查看:
~~~powershell
kubectl api-resources
~~~
经常使用的资源有下面这些:
<table>
<tr>
<th>资源分类</th>
<th>资源名称</th>
<th>缩写</th>
<th>资源作用</th>
</tr>
<tr>
<td rowspan="2">集群级别资源</td>
<td>nodes</td>
<td>no</td>
<td>集群组成部分</td>
</tr>
<tr>
<td>namespaces</td>
<td>ns</td>
<td>隔离Pod</td>
</tr>
<tr>
<td>pod资源</td>
<td>pods</td>
<td>po</td>
<td>装载容器</td>
</tr>
<tr>
<td rowspan="8">pod资源控制器</td>
<td>replicationcontrollers</td>
<td>rc</td>
<td>控制pod资源</td>
</tr>
<tr>
<td>replicasets</td>
<td>rs</td>
<td>控制pod资源</td>
</tr>
<tr>
<td>deployments</td>
<td>deploy</td>
<td>控制pod资源</td>
</tr>
<tr>
<td>daemonsets</td>
<td>ds</td>
<td>控制pod资源</td>
</tr>
<tr>
<td>jobs</td>
<td></td>
<td>控制pod资源</td>
</tr>
<tr>
<td>cronjobs</td>
<td>cj</td>
<td>控制pod资源</td>
</tr>
<tr>
<td>horizontalpodautoscalers</td>
<td>hpa</td>
<td>控制pod资源</td>
</tr>
<tr>
<td>statefulsets</td>
<td>sts</td>
<td>控制pod资源</td>
</tr>
<tr>
<td rowspan="2">服务发现资源</td>
<td>services</td>
<td>svc</td>
<td>统一pod对外接口</td>
</tr>
<tr>
<td>ingress</td>
<td>ing</td>
<td>统一pod对外接口</td>
</tr>
<tr>
<td rowspan="3">存储资源</td>
<td>volumeattachments</td>
<td></td>
<td>存储</td>
</tr>
<tr>
<td>persistentvolumes</td>
<td>pv</td>
<td>存储</td>
</tr>
<tr>
<td>persistentvolumeclaims</td>
<td>pvc</td>
<td>存储</td>
</tr>
<tr>
<td rowspan="2">配置资源</td>
<td>configmaps</td>
<td>cm</td>
<td>配置</td>
</tr>
<tr>
<td>secrets</td>
<td></td>
<td>配置</td>
</tr>
</table>
**操作**
kubernetes允许对资源进行多种操作,可以通过--help查看详细的操作命令
~~~powershell
kubectl --help
~~~
经常使用的操作有下面这些:
<table>
<tr>
<th>命令分类</th>
<th>命令</th>
<th>翻译</th>
<th>命令作用</th>
</tr>
<tr>
<td rowspan="6">基本命令</td>
<td>create</td>
<td>创建</td>
<td>创建一个资源</td>
</tr>
<tr>
<td>edit</td>
<td>编辑</td>
<td>编辑一个资源</td>
</tr>
<tr>
<td>get</td>
<td>获取</td>
<td>获取一个资源</td>
</tr>
<tr>
<td>patch</td>
<td>更新</td>
<td>更新一个资源</td>
</tr>
<tr>
<td>delete</td>
<td>删除</td>
<td>删除一个资源</td>
</tr>
<tr>
<td>explain</td>
<td>解释</td>
<td>展示资源文档</td>
</tr>
<tr>
<td rowspan="10">运行和调试</td>
<td>run</td>
<td>运行</td>
<td>在集群中运行一个指定的镜像</td>
</tr>
<tr>
<td>expose</td>
<td>暴露</td>
<td>暴露资源为Service</td>
</tr>
<tr>
<td>describe</td>
<td>描述</td>
<td>显示资源内部信息</td>
</tr>
<tr>
<td>logs</td>
<td>日志</td>
<td>输出容器在 pod 中的日志</td>
</tr>
<tr>
<td>attach</td>
<td>缠绕</td>
<td>进入运行中的容器</td>
</tr>
<tr>
<td>exec</td>
<td>执行</td>
<td>执行容器中的一个命令</td>
</tr>
<tr>
<td>cp</td>
<td>复制</td>
<td>在Pod内外复制文件</td>
</tr>
<tr>
<td>rollout</td>
<td>首次展示</td>
<td>管理资源的发布</td>
</tr>
<tr>
<td>scale</td>
<td>规模</td>
<td>扩(缩)容Pod的数量</td>
</tr>
<tr>
<td>autoscale</td>
<td>自动调整</td>
<td>自动调整Pod的数量</td>
</tr>
<tr>
<td rowspan="2">高级命令</td>
<td>apply</td>
<td>rc</td>
<td>通过文件对资源进行配置</td>
</tr>
<tr>
<td>label</td>
<td>标签</td>
<td>更新资源上的标签</td>
</tr>
<tr>
<td rowspan="2">其他命令</td>
<td>cluster-info</td>
<td>集群信息</td>
<td>显示集群信息</td>
</tr>
<tr>
<td>version</td>
<td>版本</td>
<td>显示当前Server和Client的版本</td>
</tr>
</table>
下面以一个namespace / pod的创建和删除简单演示下命令的使用:
~~~powershell
# 创建一个namespace
[root@master ~]# kubectl create namespace dev
namespace/dev created
# 获取namespace
[root@master ~]# kubectl get ns
NAME STATUS AGE
default Active 21h
dev Active 21s
kube-node-lease Active 21h
kube-public Active 21h
kube-system Active 21h
# 在此namespace下创建并运行一个nginx的Pod
[root@master ~]# kubectl run pod --image=nginx -n dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/pod created
# 查看新创建的pod
[root@master ~]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
pod-864f9875b9-pcw7x 1/1 Running 0 21s
# 删除指定的pod
[root@master ~]# kubectl delete pod pod-864f9875b9-pcw7x
pod "pod-864f9875b9-pcw7x" deleted
# 删除指定的namespace
[root@master ~]# kubectl delete ns dev
namespace "dev" deleted
~~~
### 命令式对象配置
命令式对象配置就是使用命令配合配置文件一起来操作kubernetes资源。
1) 创建一个nginxpod.yaml,内容如下:
~~~yaml
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Pod
metadata:
name: nginxpod
namespace: dev
spec:
containers:
- name: nginx-containers
image: nginx:1.17.1
~~~
2)执行create命令,创建资源:
~~~powershell
[root@master ~]# kubectl create -f nginxpod.yaml
namespace/dev created
pod/nginxpod created
~~~
此时发现创建了两个资源对象,分别是namespace和pod
3)执行get命令,查看资源:
~~~powershell
[root@master ~]# kubectl get -f nginxpod.yaml
NAME STATUS AGE
namespace/dev Active 18s
NAME READY STATUS RESTARTS AGE
pod/nginxpod 1/1 Running 0 17s
~~~
这样就显示了两个资源对象的信息
4)执行delete命令,删除资源:
~~~powershell
[root@master ~]# kubectl delete -f nginxpod.yaml
namespace "dev" deleted
pod "nginxpod" deleted
~~~
此时发现两个资源对象被删除了
~~~md
总结:
命令式对象配置的方式操作资源,可以简单的认为:命令 + yaml配置文件(里面是命令需要的各种参数)
~~~
### 声明式对象配置
声明式对象配置跟命令式对象配置很相似,但是它只有一个命令apply。
~~~powershell
# 首先执行一次kubectl apply -f yaml文件,发现创建了资源
[root@master ~]# kubectl apply -f nginxpod.yaml
namespace/dev created
pod/nginxpod created
# 再次执行一次kubectl apply -f yaml文件,发现说资源没有变动
[root@master ~]# kubectl apply -f nginxpod.yaml
namespace/dev unchanged
pod/nginxpod unchanged
~~~
~~~md
总结:
其实声明式对象配置就是使用apply描述一个资源最终的状态(在yaml中定义状态)
使用apply操作资源:
如果资源不存在,就创建,相当于 kubectl create
如果资源已存在,就更新,相当于 kubectl patch
~~~
> 扩展:kubectl可以在node节点上运行吗 ?
​ kubectl的运行是需要进行配置的,它的配置文件是\$HOME/.kube,如果想要在node节点运行此命令,需要将master上的.kube文件复制到node节点上,即在master节点上执行下面操作:
~~~powershell
scp -r HOME/.kube node1: HOME/
~~~
> 使用推荐: 三种方式应该怎么用 ?
创建/更新资源 使用声明式对象配置 kubectl apply -f XXX.yaml
删除资源 使用命令式对象配置 kubectl delete -f XXX.yaml
查询资源 使用命令式对象管理 kubectl get(describe) 资源名称
+592
View File
@@ -0,0 +1,592 @@
---
title: 04 kubernetes实战入门
date: 2022-10-22 20:56:10
tags:
- kubernetes
categories:
- kubernetes
---
# 第四章 实战入门
本章节将介绍如何在kubernetes集群中部署一个nginx服务,并且能够对其进行访问。
## Namespace
​ Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现**多套环境的资源隔离**或者**多租户的资源隔离**。
​ 默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的。但是在实际中,可能不想让两个Pod之间进行互相的访问,那此时就可以将两个Pod划分到不同的namespace下。kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的"组",以方便不同的组的资源进行隔离使用和管理。
​ 可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理,这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等等,来实现租户可用资源的管理。
![](http://qiniu.baim0.cn/img/image-20200407100850484-20221022205353320-20221022211006971.png)
kubernetes在集群启动之后,会默认创建几个namespace
~~~powershell
[root@master ~]# kubectl get namespace
NAME STATUS AGE
default Active 45h # 所有未指定Namespace的对象都会被分配在default命名空间
kube-node-lease Active 45h # 集群节点之间的心跳维护,v1.13开始引入
kube-public Active 45h # 此命名空间下的资源可以被所有人访问(包括未认证用户)
kube-system Active 45h # 所有由Kubernetes系统创建的资源都处于这个命名空间
~~~
下面来看namespace资源的具体操作:
**查看**
~~~powershell
# 1 查看所有的ns 命令:kubectl get ns
[root@master ~]# kubectl get ns
NAME STATUS AGE
default Active 45h
kube-node-lease Active 45h
kube-public Active 45h
kube-system Active 45h
# 2 查看指定的ns 命令:kubectl get ns ns名称
[root@master ~]# kubectl get ns default
NAME STATUS AGE
default Active 45h
# 3 指定输出格式 命令:kubectl get ns ns名称 -o 格式参数
# kubernetes支持的格式有很多,比较常见的是wide、json、yaml
[root@master ~]# kubectl get ns default -o yaml
apiVersion: v1
kind: Namespace
metadata:
creationTimestamp: "2020-04-05T04:44:16Z"
name: default
resourceVersion: "151"
selfLink: /api/v1/namespaces/default
uid: 7405f73a-e486-43d4-9db6-145f1409f090
spec:
finalizers:
- kubernetes
status:
phase: Active
# 4 查看ns详情 命令:kubectl describe ns ns名称
[root@master ~]# kubectl describe ns default
Name: default
Labels: <none>
Annotations: <none>
Status: Active # Active 命名空间正在使用中 Terminating 正在删除命名空间
# ResourceQuota 针对namespace做的资源限制
# LimitRange针对namespace中的每个组件做的资源限制
No resource quota.
No LimitRange resource.
~~~
**创建**
~~~powershell
# 创建namespace
[root@master ~]# kubectl create ns dev
namespace/dev created
~~~
**删除**
~~~powershell
# 删除namespace
[root@master ~]# kubectl delete ns dev
namespace "dev" deleted
~~~
**配置方式**
首先准备一个yaml文件:ns-dev.yaml
~~~yaml
apiVersion: v1
kind: Namespace
metadata:
name: dev
~~~
然后就可以执行对应的创建和删除命令了:
​ 创建:kubectl create -f ns-dev.yaml
​ 删除:kubectl delete -f ns-dev.yaml
## Pod
Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中。
Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器。
![](http://qiniu.baim0.cn/img/image-20200407121501907-20221022205353365-20221022211031210.png)
kubernetes在集群启动之后,集群中的各个组件也都是以Pod方式运行的。可以通过下面命令查看:
~~~powershell
[root@master ~]# kubectl get pod -n kube-system
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6955765f44-68g6v 1/1 Running 0 2d1h
kube-system coredns-6955765f44-cs5r8 1/1 Running 0 2d1h
kube-system etcd-master 1/1 Running 0 2d1h
kube-system kube-apiserver-master 1/1 Running 0 2d1h
kube-system kube-controller-manager-master 1/1 Running 0 2d1h
kube-system kube-flannel-ds-amd64-47r25 1/1 Running 0 2d1h
kube-system kube-flannel-ds-amd64-ls5lh 1/1 Running 0 2d1h
kube-system kube-proxy-685tk 1/1 Running 0 2d1h
kube-system kube-proxy-87spt 1/1 Running 0 2d1h
kube-system kube-scheduler-master 1/1 Running 0 2d1h
~~~
**创建并运行**
kubernetes没有提供单独运行Pod的命令,都是通过Pod控制器来实现的
~~~powershell
# 命令格式: kubectl run (pod控制器名称) [参数]
# --image 指定Pod的镜像
# --port 指定端口
# --namespace 指定namespace
[root@master ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev
deployment.apps/nginx created
~~~
**查看pod信息**
~~~powershell
# 查看Pod基本信息
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx-5ff7956ff6-fg2db 1/1 Running 0 43s
# 查看Pod的详细信息
[root@master ~]# kubectl describe pod nginx-5ff7956ff6-fg2db -n dev
Name: nginx-5ff7956ff6-fg2db
Namespace: dev
Priority: 0
Node: node1/192.168.109.101
Start Time: Wed, 08 Apr 2020 09:29:24 +0800
Labels: pod-template-hash=5ff7956ff6
run=nginx
Annotations: <none>
Status: Running
IP: 10.244.1.23
IPs:
IP: 10.244.1.23
Controlled By: ReplicaSet/nginx-5ff7956ff6
Containers:
nginx:
Container ID: docker://4c62b8c0648d2512380f4ffa5da2c99d16e05634979973449c98e9b829f6253c
Image: nginx:1.17.1
Image ID: docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 08 Apr 2020 09:30:01 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-hwvvw (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-hwvvw:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-hwvvw
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned dev/nginx-5ff7956ff6-fg2db to node1
Normal Pulling 4m11s kubelet, node1 Pulling image "nginx:1.17.1"
Normal Pulled 3m36s kubelet, node1 Successfully pulled image "nginx:1.17.1"
Normal Created 3m36s kubelet, node1 Created container nginx
Normal Started 3m36s kubelet, node1 Started container nginx
~~~
**访问Pod**
~~~powershell
# 获取podIP
[root@master ~]# kubectl get pods -n dev -o wide
NAME READY STATUS RESTARTS AGE IP NODE ...
nginx-5ff7956ff6-fg2db 1/1 Running 0 190s 10.244.1.23 node1 ...
#访问POD
[root@master ~]# curl http://10.244.1.23:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
~~~
**删除指定Pod**
~~~powershell
# 删除指定Pod
[root@master ~]# kubectl delete pod nginx-5ff7956ff6-fg2db -n dev
pod "nginx-5ff7956ff6-fg2db" deleted
# 此时,显示删除Pod成功,但是再查询,发现又新产生了一个
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx-5ff7956ff6-jj4ng 1/1 Running 0 21s
# 这是因为当前Pod是由Pod控制器创建的,控制器会监控Pod状况,一旦发现Pod死亡,会立即重建
# 此时要想删除Pod,必须删除Pod控制器
# 先来查询一下当前namespace下的Pod控制器
[root@master ~]# kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 9m7s
# 接下来,删除此PodPod控制器
[root@master ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted
# 稍等片刻,再查询Pod,发现Pod被删除了
[root@master ~]# kubectl get pods -n dev
No resources found in dev namespace.
~~~
**配置操作**
创建一个pod-nginx.yaml,内容如下:
~~~yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: dev
spec:
containers:
- image: nginx:1.17.1
name: pod
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
~~~
然后就可以执行对应的创建和删除命令了:
​ 创建:kubectl create -f pod-nginx.yaml
​ 删除:kubectl delete -f pod-nginx.yaml
## Label
Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。
Label的特点:
- 一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等等
- 一个资源对象可以定义任意数量的Label ,同一个Label也可以被添加到任意数量的资源对象上去
- Label通常在资源对象定义时确定,当然也可以在对象创建后动态添加或者删除
可以通过Label实现资源的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。
> 一些常用的Label 示例如下:
>
> - 版本标签:"version":"release", "version":"stable"......
> - 环境标签:"environment":"dev","environment":"test","environment":"pro"
> - 架构标签:"tier":"frontend","tier":"backend"
标签定义完毕之后,还要考虑到标签的选择,这就要使用到Label Selector,即:
​ Label用于给某个资源对象定义标识
​ Label Selector用于查询和筛选拥有某些标签的资源对象
当前有两种Label Selector:
- 基于等式的Label Selector
name = slave: 选择所有包含Label中key="name"且value="slave"的对象
env != production: 选择所有包括Label中的key="env"且value不等于"production"的对象
- 基于集合的Label Selector
name in (master, slave): 选择所有包含Label中的key="name"且value="master"或"slave"的对象
name not in (frontend): 选择所有包含Label中的key="name"且value不等于"frontend"的对象
标签的选择条件可以使用多个,此时将多个Label Selector进行组合,使用逗号","进行分隔即可。例如:
​ name=slave,env!=production
​ name not in (frontend),env!=production
**命令方式**
~~~powershell
# 为pod资源打标签
[root@master ~]# kubectl label pod nginx-pod version=1.0 -n dev
pod/nginx-pod labeled
# 为pod资源更新标签
[root@master ~]# kubectl label pod nginx-pod version=2.0 -n dev --overwrite
pod/nginx-pod labeled
# 查看标签
[root@master ~]# kubectl get pod nginx-pod -n dev --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-pod 1/1 Running 0 10m version=2.0
# 筛选标签
[root@master ~]# kubectl get pod -n dev -l version=2.0 --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-pod 1/1 Running 0 17m version=2.0
[root@master ~]# kubectl get pod -n dev -l version!=2.0 --show-labels
No resources found in dev namespace.
#删除标签
[root@master ~]# kubectl label pod nginx-pod version- -n dev
pod/nginx-pod labeled
~~~
**配置方式**
~~~yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: dev
labels:
version: "3.0"
env: "test"
spec:
containers:
- image: nginx:1.17.1
name: pod
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
~~~
然后就可以执行对应的更新命令了:kubectl apply -f pod-nginx.yaml
## Deployment
​ 在kubernetes中,Pod是最小的控制单元,但是kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成的。Pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建pod。
​ 在kubernetes中Pod控制器的种类有很多,本章节只介绍一种:Deployment。
![](http://qiniu.baim0.cn/img/image-20200408193950807-20221022205353445-20221022211056261.png)
**命令操作**
~~~powershell
# 命令格式: kubectl run deployment名称 [参数]
# --image 指定pod的镜像
# --port 指定端口
# --replicas 指定创建pod数量
# --namespace 指定namespace
[root@master ~]# kubectl run nginx --image=nginx:1.17.1 --port=80 --replicas=3 -n dev
deployment.apps/nginx created
# 查看创建的Pod
[root@master ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
nginx-5ff7956ff6-6k8cb 1/1 Running 0 19s
nginx-5ff7956ff6-jxfjt 1/1 Running 0 19s
nginx-5ff7956ff6-v6jqw 1/1 Running 0 19s
# 查看deployment的信息
[root@master ~]# kubectl get deploy -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 3/3 3 3 2m42s
# UP-TO-DATE:成功升级的副本数量
# AVAILABLE:可用副本的数量
[root@master ~]# kubectl get deploy -n dev -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx 3/3 3 3 2m51s nginx nginx:1.17.1 run=nginx
# 查看deployment的详细信息
[root@master ~]# kubectl describe deploy nginx -n dev
Name: nginx
Namespace: dev
CreationTimestamp: Wed, 08 Apr 2020 11:14:14 +0800
Labels: run=nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: run=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: run=nginx
Containers:
nginx:
Image: nginx:1.17.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-5ff7956ff6 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 5m43s deployment-controller Scaled up replicaset nginx-5ff7956ff6 to 3
# 删除
[root@master ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted
~~~
**配置操作**
创建一个deploy-nginx.yaml,内容如下:
~~~yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
run: nginx
template:
metadata:
labels:
run: nginx
spec:
containers:
- image: nginx:1.17.1
name: nginx
ports:
- containerPort: 80
protocol: TCP
~~~
然后就可以执行对应的创建和删除命令了:
​ 创建:kubectl create -f deploy-nginx.yaml
​ 删除:kubectl delete -f deploy-nginx.yaml
## Service
通过上节课的学习,已经能够利用Deployment来创建一组Pod来提供具有高可用性的服务。
虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两问题:
- Pod IP 会随着Pod的重建产生变化
- Pod IP 仅仅是集群内可见的虚拟IP,外部无法访问
这样对于访问这个服务带来了难度。因此,kubernetes设计了Service来解决这个问题。
Service可以看作是一组同类Pod**对外的访问接口**。借助Service,应用可以方便地实现服务发现和负载均衡。
![image-20200408194716912](http://qiniu.baim0.cn/img/image-20200408194716912-20221022205353547.png)
**操作一:创建集群内部可访问的Service**
~~~powershell
# 暴露Service
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed
# 查看service
[root@master ~]# kubectl get svc svc-nginx -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
svc-nginx1 ClusterIP 10.109.179.231 <none> 80/TCP 3m51s run=nginx
# 这里产生了一个CLUSTER-IP,这就是service的IP,在Service的生命周期中,这个地址是不会变动的
# 可以通过这个IP访问当前service对应的POD
[root@master ~]# curl 10.109.179.231:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
.......
</body>
</html>
~~~
**操作二:创建集群外部也可访问的Service**
~~~powershell
# 上面创建的Service的type类型为ClusterIP,这个ip地址只用集群内部可访问
# 如果需要创建外部也可以访问的Service,需要修改type为NodePort
[root@master ~]# kubectl expose deploy nginx --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx2 exposed
# 此时查看,会发现出现了NodePort类型的Service,而且有一对Port(80:31928/TC)
[root@master ~]# kubectl get svc svc-nginx-1 -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
svc-nginx2 NodePort 10.100.94.0 <none> 80:31928/TCP 9s run=nginx
# 接下来就可以通过集群外的主机访问 节点IP:31928访问服务了
# 例如在的电脑主机上通过浏览器访问下面的地址
http://192.168.109.100:31928/
~~~
**删除Service**
~~~powershell
[root@master ~]# kubectl delete svc svc-nginx-1 -n dev service "svc-nginx-1" deleted
~~~
**配置方式**
创建一个svc-nginx.yaml,内容如下:
~~~yaml
apiVersion: v1
kind: Service
metadata:
name: svc-nginx
namespace: dev
spec:
clusterIP: 10.109.179.231
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: nginx
type: ClusterIP
~~~
然后就可以执行对应的创建和删除命令了:
​ 创建:kubectl create -f svc-nginx.yaml
​ 删除:kubectl delete -f svc-nginx.yaml
> **小结**
>
> ​ 至此,已经掌握了Namespace、Pod、Deployment、Service资源的基本操作,有了这些操作,就可以在kubernetes集群中实现一个服务的简单部署和访问了,但是如果想要更好的使用kubernetes,就需要深入学习这几种资源的细节和原理。
File diff suppressed because it is too large Load Diff