赞
踩
kubernetes
入门学习Deployment
yaml
文件 nginx-deploy.yaml
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本 kind: Deployment #该配置的类型,我们使用的是 Deployment metadata: #译名为元数据,即 Deployment 的一些基本属性和信息 name: nginx-deployment #Deployment 的名称 labels: #标签,方便后面通过一些方式来选取得标记,key=value 得形式 app: nginx #为该Deployment设置key为app,value为nginx的标签 spec: #这是关于该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用 replicas: 1 #使用该Deployment创建一个应用程序实例 selector: #标签选择器,与上面的标签共同作用,用来选取标签为什么得选择器 matchLabels: #选择包含标签app:nginx的资源 app: nginx template: #这是选择或创建的Pod的模板 metadata: #Pod的元数据 labels: #Pod的标签,上面的selector即选择包含标签app:nginx的Pod app: nginx spec: #期望Pod实现的功能(即在pod中部署) containers: #生成container,与docker中的container是同一种 - name: nginx #container的名称 image: nginx:1.7.9 #使用镜像nginx:1.7.9创建container,该container默认80端口可访问
yaml
文件kubectl apply -f nginx-deploy.yaml
# -n 是 namespace ,命名空间
kubectl get deploy -n default
deployment
kubectl get deploy -A
# 查看nginx deployment的详情
kubectl describe deploy nginx -n test
# 查看pod nginx 的详情
kubectl deploy pod -n test nginx-ds-585449566-hc5jv
docker logs -f
)kubectl logs -f -n test nginx-ds-585449566-hc5jv
kubectl exec -n test -it nginx-ds-585449566-hc5jv /bin/bash
# 该命令将会在未来被替代
kubectl exec -n test nginx-ds-585449566-hc5jv -- "curl localhost"
ClusterIP
(默认)Service
只在集群内布可以访问NodePort
NAT
在集群中每个worker
节点同一个端口上公布服务。这种方式下,可以通过集群中任意节点+端口号的方式访问服务,此时ClusterIP
的访问方式仍然可用。LoadBalancer
ClusterIP
和NodePort
的访问方式仍然可用。nginx deployment
的Service
apiVersion: v1 kind: Service metadata: name: nginx-service #Service 的名称 labels: #Service 自己的标签 app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签 spec: #这是关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问 selector: #标签选择器 app: nginx #选择包含标签 app:nginx 的 Pod ports: - name: nginx-port #端口的名字 protocol: TCP #协议类型 TCP/UDP port: 80 #集群内的其他容器组可通过 80 端口访问 Service nodePort: 32600 #通过任意节点的 32600 端口访问 Service targetPort: 80 #将请求转发到匹配 Pod 的 80 端口 type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
yaml
文件kubectl apply -f nginx-svc.yaml -n test
kubectl config set-context --current --namespace=test
kubernetes
的进阶学习kubernetes
对象当使用指令性的命令行(imperative commands)时,用户通过向kubectl
命令提供参数的方式,直接操作集群中的 Kubernetes 对象。此时,用户无需编写或修改 .yaml
文件。
kubectl create deploy nginx --image nginx:latest -n test
使用指令性的对象配置(imperative object configuration)时,需要向 kubectl
命令指定具体的操作(create,replace,apply,delete
等),可选参数以及至少一个配置文件的名字。配置文件中必须包括一个完整的对象的定义,可以是yaml
格式,也可以是json
格式。
# 创建对象
kubectl create -f nginx.yaml
# 删除对象
kubectl delete -f nginx.yaml -f redis.yaml
# 替换对象
kubectl replace -f nginx.yaml
当使用声明式的对象配置时,用户操作本地存储的Kubernetes对象配置文件,然而,在将文件传递给kubectl
命令时,并不指定具体的操作,由 kubectl
自动检查每一个对象的状态并自行决定是创建、更新、还是删除该对象。使用这种方法时,可以直接针对一个或多个文件目录进行操作(对不同的对象可能需要执行不同的操作)
# 查看具体的变更
kubectl diff -f configs/
kubectl apply -f configs
# 递归处理目录中的内容
kubectl diff -R -f configs/
kubectl apply -R -f configs/
Label
)label
是附加在Kubernetes对象上的一组名值对,其意图是按照对用户有意义的方式来标识Kubernetes对象,同时,又不对Kubernetes的核心逻辑产生影响。标签可以用来组织和选择一组Kubernetes对象。您可以在创建Kubernetes对象时为其添加标签,也可以在创建以后再为其添加标签。每个Kubernetes对象可以有多个标签,同一个对象的标签的Key
必须唯一,例如:
metadata:
labels:
key1: value1
key2: value2
与 name
和 UID
不同,标签不一定是唯一的。通常来讲,会有多个Kubernetes对象包含相同的标签。通过使用标签选择器(label selector
),用户/客户端可以选择一组对象。标签选择器(label selector
)是 Kubernetes 中最主要的分类和筛选手段。
Kubernetes api server支持两种形式的标签选择器,equality-based
基于等式的 和set-based
基于集合的。标签选择器可以包含多个条件,并使用逗号分隔,此时只有满足所有条件的 Kubernetes 对象才会被选中。
envionment = prod
tier != frontend
也可以使用逗号分隔的两个等式 environment=production,tier!=frontend
,此时将选中所有 environment
为 prod
且tier
不为front
的对象。
以Pod
的节点选择器 为例,下面的Pod
可以被调度到包含标签 accelerator=nvidia-tesla-p100
的节点上:
apiVersion: v1
kind: Pod
metadata:
name: cuda-test
spec:
containers:
- name: cuda-test
image: "k8s.gcr.io/cuda-vector-add:v0.1"
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
accelerator: nvidia-tesla-p100
in
、notin
、exists
。例如:# 选择所有的包含 `environment` 标签且值为 `production` 或 `qa` 的对象
environment in (production, qa)
# 选择所有的 `tier` 标签不为 `frontend` 和 `backend`的对象,或不含 `tier` 标签的对象
tier notin (frontend, backend)
# 选择所有包含 `partition` 标签的对象
partition
# 选择所有不包含 `partition` 标签的对象
!partition
基于集合的选择方式是一个更宽泛的基于等式的选择方式
例如,environment=production
等价于 environment in (production)
;
environment!=production
等价于 environment notin (production)
。
基于集合的选择方式可以和基于等式的选择方式可以混合使用,例如: partition in (customerA, customerB),environment!=qa
kubectl get pods -l environment=prod,tier=front
kubectl get pods -l ’environment in (prod),tier in (front)‘
Service
Service
中 通过spec.selector
字段来选择一组Pod
,并将服务请求转发到Pod上
selector:
component: redis
Job
、Deployment
、ReplicaSet
和 DaemonSet
同时支持基于等式的选择方式和基于集合的选择方式。例如
selector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
matchLabels
是一个 {key,value}
组成的 map
。map
中的一个{key,value}
条目相当于 matchExpressions
中的一个元素,其 key
为 map
的 key
,operator
为 In
, values
数组则只包含 value
一个元素。matchExpression
等价于基于集合的选择方式,支持的 operator
有 In
、NotIn
、Exist
s 和 DoesNotExist
。当 operator
为 In
或 NotIn
时,values
数组不能为空。所有的选择条件都以 AND 的形式合并计算,即所有的条件都满足才可以算是匹配。
annotation
metadata:
annotations:
key1: value1
key2: value2
所有的对象都支持两个字段是metadata.name
和metadata.namespace
,在字段选择器中使用不支持的字段,将报错,可以指定多个字段选择器,用,
隔开
kubectl get pods --field-selector status.phase=Running -n test
postStart
和 preStop
处理程序lifecycle-demo.yaml
apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: nginx lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]
Pod phase
pod phase
代表其所处生命周期的阶段。
phase | 描述 |
---|---|
Pending | Kubernetes 已经创建并确认该Pod 。此时可能有两种情况: - Pod 还未完成调度(例如没有合适的节点- 正在从 docker registry 下载镜像 |
Running | 该 Pod 已经被绑定到一个节点,并且该 Pod 所有的容器都已经成功创建。其中至少有一个容器正在运行,或者正在启动/重启 |
Succeded | Pod 中的所有容器都已经成功终止,并且不会再被重启 |
Failed | Pod 中的所有容器都已经终止,至少一个容器终止于失败状态:容器的进程退出码不是 0,或者被系统 kill |
Unknow | 因为某些未知原因,不能确定 Pod 的状态,通常的原因是 master 与 Pod 所在节点之间的通信故障 |
如果容器中的进程在碰到问题时可以自己 crash,您并不需要执行健康检查;kubelet
可以自动的根据Pod
的 restart policy
(重启策略)执行对应的动作
如果您希望在容器的进程无响应后,将容器 kill 掉并重启,则指定一个健康检查 liveness probe
,并同时指定 restart policy
(重启策略)为 Always
或者 OnFailure
如果您想在探测 Pod
确实就绪之后才向其分发服务请求,请指定一个就绪检查 readiness probe
。此时,就绪检查的内容可能和健康检查相同。就绪检查适合如下几类容器:
定义 Pod
或工作负载时,可以指定 restartPolicy
,可选的值有:
Always
(默认值)OnFailure
Never
创建一个Pod
,该Pod
包含一个应用程序容器(工作容器)和一个初始化容器(Init Container
)。初始化容器执行结束之后,应用程序容器(工作容器)才开始启动。
apiVersion: v1 kind: Pod metadata: name: init-demo spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 volumeMounts: - name: workdir mountPath: /usr/share/nginx/html initContainers: - name: install image: nginx command: - "/bin/bash" - "-c" args: [ "echo '<!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <title>Title</title> </head> <body> <h1>Hello World1</h1> </body> </html>' > /work-dir/index1.html; echo '<!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <title>Title</title> </head> <body> <h1>Hello World2</h1> </body> </html>' > /work-dir/index2.html" ] volumeMounts: - name: workdir mountPath: "/work-dir" dnsPolicy: Default volumes: - name: workdir emptyDir: {}
Pod
中初始化容器和应用程序共享了同一个数据卷,舒适化容器将该共享数据集挂在到/work-dir
路径,应用程序容器将共享数据卷挂在到/usr/share/nginx/html
路径。初始化容器执行command
命令后就退出容器。
执行该命令时,初始化容器将结果写入了应用程序nginx
服务器对应的html根路径下的index.html
。
PodDisruptionBudget(PDB)
应用程序管理员可以为每一个应用程序创建 PodDisruptionBudget
对象(PDB
)。PDB
限制了多副本应用程序在自愿的毁坏情况发生时,最多有多少个副本可以同时停止。例如,一个 web 前端的程序需要确保可用的副本数不低于总副本数的一定比例。属于一种保护机制。
PodDisruptionBudget
包含三个字段:
.spec.selector
用于指定 PDB
适用的Pod
。此字段为必填.spec.minAvailable
:当完成驱逐时,最少仍然要保留多少个Pod
可用。该字段可以是一个整数,也可以是一个百分比.spec.maxUnavailable
: 当完成驱逐时,最多可以有多少个 Pod
被终止。该字段可以是一个整数,也可以是一个百分比在一个 PodDisruptionBudget
中,只能指定maxUnavailable
和 minAvailable
中的一个。 maxUnavailable
只能应用到那些有控制器的 Pod
上。
PodDisruptionBudget 并不能真正确保指定数量(或百分比)的Pod始终保持可用。
例如,当 Pod 数量已经为 PDB 中指定的最小数时,某一个节点可能意外宕机,
导致 Pod 数量低于 PDB 中指定的数量。 PodDisruptionBudget 只能保护应用避免受到 自愿毁坏 的影响,
而不是所有原因的毁坏。
使用 minAvailable
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: zookeeper
使用 maxUnavailable
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
app: zookeeper
查看pdb
kubectl get pdb
ReplicaSet (RS)
kubernetes
中 ReplicaSet
用来维护一个数量稳定的 Pod
副本集合,可以保证某种定义一样的 Pod
始终有指定数量的副本数在运行。
ReplicaSet
的工作方式selector
: 用于指定哪些Pod
属于该 ReplicaSet
的管辖范围replicas
: 副本数,用于指定该 ReplicaSet
应该维持多少个 Pod
副本template
: Pod
模板,在 ReplicaSet
使用 Pod
模板的定义创建新的 Pod
ReplicaSet
控制器将通过创建或删除 Pod
,以使得当前 Pod
数量达到 replicas
指定的期望值,通过selector
字段的定义,识别哪些 Pod
应该由其管理。如果 Pod
没有 ownerReference
字段,或者 ownerReference
字段指向的对象不是一个控制器,且该 Pod
匹配了 ReplicaSet
的 selector
,则该 Pod
的 ownerReference
将被修改为 该 ReplicaSet
的引用(包括不是由该RS创建的Pod
)。
ReplicaSet
ReplicaSet
用来维护一个数量稳定的 Pod
副本集合。Deployment
是一个更高级别的概念,可以管理 ReplicaSet
,并提供声明式的更新,以及其他的许多有用的特性。因此,推荐用户总是使用Deployment
,而不是直接使用 ReplicaSet
,除非您需要一些自定义的更新应用程序的方式,或者您完全不更新应用。
示例:
apiVersion: apps/v1 kind: ReplicaSet metadata: name: frontend labels: app: guestbook tier: frontend spec: # modify replicas according to your case replicas: 3 selector: matchLabels: tier: frontend template: metadata: labels: tier: frontend spec: containers: - name: nginx image: nginx
ReplicaSet
的定义与其他Kubernetes
对象一样,ReplicaSet
需要的字段有:
apiVersion
:apps/v1
kind
:始终为 ReplicaSet
metadata
spec
:ReplicaSet
的详细定义
PodTemplate
.spec.template
字段是一个 Pod Template,为必填字段,且其中必须定义
.spec.template.metadata.labels
字段。在前面的ReplicaSet例子中,定义了 label 为 tier: frontend。请小心该字段不要与其他控制器的 selector
重合,以免这些控制器尝试接管该 Pod
。
.spec.template.spec.restartPolicy
的默认值为Always
Pod Selector
.spec.selector
字段为一个 标签选择器,用于识别可以接管哪些 Pod
。在前面的例子中,标签选择器为Replicas
spec.replicas
字段用于指定同时运行的 Pod
的副本数。ReplicaSet
将创建或者删除由其管理的 Pod
,以便使副本数与该字段指定的值匹配。ReplicaSet
ReplicaSet
及Pod
kubectl delete -f nginx-rs.yaml
ReplicaSet
kubectl delete nginx-rs --casade=false
修改Pod
的标签,可以使Pod
脱离ReplicaSet
的管理
Deployment (deploy)
Deployment
下面的 yaml 文件定义了一个 Deployment
,该 Deployment
将创建一个有 3 个 nginx Pod
副本的 ReplicaSet
(副本集):
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
在这个例子中:
nginx-deployment
的 Deployment
(部署),名称由 .metadata.name
字段指定Deployment
将创建 3 个Pod
副本,副本数量由 .spec.replicas
字段指定.spec.selector
字段指定了 Deployment 如何找到由它管理的 Pod
。此案例中,我们使用了 Pod template 中定义的一个标签(app: nginx
)。对于极少数的情况,这个字段也可以定义更加复杂的规则.template
字段包含了如下字段:
.template.metadata.labels
字段,指定了 Pod
的标签(app: nginx
).template.spec.containers[].image
字段,表明该 Pod
运行一个容器 nginx:1.7.9.template.spec.containers[].name
字段,表明该容器的名字是 nginxDeployment
kubectl apply -f nginx-ds.yaml
可以为该命令增加 --record
选项,此时 kubectl
会将kubectl apply -f nginx-ds.yaml --record
写入 Deployment 的 annotation
(注解) kubernetes.io/change-cause
中。这样,您在将来就可以回顾某一个 Deployment 版本变化的原因
查看 Deployment 的发布状态(rollout status
),执行命令 kubectl rollout status deploy nginx-ds
查看 Pod 的标签,执行命令kubectl get pods --show-labels
Deployment
nginx:1.7.9
更新到 nginx:1.9.1
kubectl set image deploy nginx-ds nginx=nginx:1.9.1 --record
或者也可以edit
该 Deployment,并将 .spec.template.spec.containers[0].image
从 nginx:1.7.9
修改为 nginx:1.9.1
kubectl edit deployments.apps nginx-ds
kubectl rollout status deployment nginx-ds
Deployment
Deployment
的更新历史kubectl rollout history deployment nginx-ds
检查 Deployment 的历史版本,输出结果如下所示:deployment.apps/nginx-ds
REVISION CHANGE-CAUSE
2 image update to 1.9.1
3 kubectl apply --filename=nginx-ds.yaml --record=true
CHANGE-CAUSE
是该 revision
(版本)创建时从 Deployment 的 annotation kubernetes.io/change-cause
拷贝而来。
可以通过如下方式制定 CHANGE-CAUSE 信息:
kubectl annotate deploy nginx-ds kubernetes.io/change-cause="image update to 1.9.1"
--record
选项.metadata.annotation
信息kubectl rollout history deploy nginx-ds --revision=2
查看revision(版本)的详细信息。输出结果如下:deployment.apps/nginx-ds with revision #2
Pod Template:
Labels: app=nginx
pod-template-hash=694854bbcb
Annotations: kubernetes.io/change-cause: image update to 1.9.1
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
revision
(版本)kubectl rollout undo deployment nginx-ds
将当前版本回滚到前一个版本Deployment
执行命令 kubectl scale deploy nginx --replicas=3
实现手动伸缩
执行命令kubectl autoscale deployment nginx --max=5 --min=3 --cpu-percent=80
cpu在百分之下最大5个 最小三个副本自动伸缩
horizontalpodautoscalers.autoscaling (hpa)
kubectl get hpa
Deployment
kubectl rollout pause deployment nginx
暂停 Deployment
,kubectl rollout resume deployment nginx
继续改Deployment
通过 Deployment 中 .spec.revisionHistoryLimit
字段,可指定为该 Deployment 保留多少个旧的 ReplicaSet
。超出该数字的将被在后台进行垃圾回收。该字段的默认值是 10
。如果该字段被设为0
,Kubernetes 将清理掉该 Deployment 的所有历史版本(revision),因此,您将无法对该 Deployment 执行回滚操作 kubectl rollout undo
通过 Deployment 中 .spec.strategy
字段,可以指定使用 滚动更新 RollingUpdate
的部署策略还是使用 重新创建 Recreate
的部署策略
字段名称 | 可选值 | 字段描述 |
---|---|---|
类型 | 滚动更新,重新创建 | 如果选择重新创建,Deployment 将先删除原有副本集中的所有 Pod ,然后再创建新的副本集和新的Pod 。如此,更新过程中将出现一段应用程序不可用的情况; |
最大超出副本数 | 数字或百分比 | 滚动更新过程中,可以超出期望副本数的最大值。该取值可以是一个绝对值(例如:5),也可以是一个相对于期望副本数的百分比(例如:10%);如果填写百分比,则以期望副本数乘以该百分比后向上取整的方式计算对应的绝对值 ;当最大超出副本数 maxUnavailable 为 0 时,此数值不能为 0;默认值为 25%。例如:假设此值被设定为 30%,当滚动更新开始时,新的副本集(ReplicaSet )可以立刻扩容,但是旧 Pod 和新 Pod 的总数不超过 Deployment 期待副本数(spec.repilcas )的 130%。一旦旧 Pod 被终止后,新的副本集可以进一步扩容,但是整个滚动更新过程中,新旧 Pod 的总数不超过 Deployment 期待副本数(spec.repilcas )的 130%。 |
最大不可用副本数 | 数字或百分比 | 滚动更新过程中,不可用副本数的最大值。该取值可以是一个绝对值(例如:5),也可以是一个相对于期望副本数的百分比(例如:10%);如果填写百分比,则以期望副本数乘以该百分比后向下取整的方式计算对应的绝对值 ;当最大超出副本数 maxSurge 为 0 时,此数值不能为 0;默认值为 25%;例如:假设此值被设定为 30%,当滚动更新开始时,旧的副本集(ReplicaSet )可以缩容到期望副本数的 70%;在新副本集扩容的过程中,一旦新的 Pod 已就绪,旧的副本集可以进一步缩容,整个滚动更新过程中,确保新旧就绪副本数之和不低于期望副本数的 70%。 |
如果您想使用 Deployment 将最新的应用程序版本发布给一部分用户(或服务器),您可以为每个版本创建一个 Deployment,此时,应用程序的新旧两个版本都可以同时获得生产上的流量。
Deployment
包含了 3 个Pod
副本,Service
通过label selector
app: nginx 选择对应的 Pod,nginx 的标签为 1.7.9apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 --- apiVersion: v1 kind: Service metadata: name: nginx-service labels: app: nginx spec: selector: app: nginx ports: - name: nginx-port protocol: TCP port: 80 nodePort: 32600 targetPort: 80 type: NodePort
Deployment
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment-canary labels: app: nginx track: canary spec: replicas: 1 selector: matchLabels: app: nginx track: canary template: metadata: labels: app: nginx track: canary spec: containers: - name: nginx image: nginx:1.8.0
局限性
按照 Kubernetes 默认支持的这种方式进行金丝雀发布,有一定的局限性:
不能根据用户注册时间、地区等请求中的内容属性进行流量分配
同一个用户如果多次调用该Service
,有可能第一次请求到了旧版本的 Pod
,第二次请求到了新版本的 Pod
在 Kubernetes
中不能解决上述局限性的原因是:Kubernetes Service 只在 TCP 层面解决负载均衡的问题,并不对请求响应的消息内容做任何解析和识别。如果想要更完善地实现金丝雀发布,可以考虑如下三种选择:
Spring Cloud
灰度发布Istio
灰度发布StatefulSet
StatefulSet
使用场景StatefulSet
顾名思义,用于管理 Stateful
(有状态)的应用程序。
StatefulSet 管理 Pod 时,确保其 Pod 有一个按顺序增长的 ID。
与 Deployment
相似,StatefulSet
基于一个 Pod 模板管理其 Pod。与 Deployment
最大的不同在于 StatefulSet
始终将一系列不变的名字分配给其 Pod。这些 Pod 从同一个模板创建,但是并不能相互替换:每个 Pod
都对应一个特有的持久化存储标识。
同其他所有控制器一样,StatefulSet
也使用相同的模式运作:用户在 StatefulSet
中定义自己期望的结果,StatefulSet
控制器执行需要的操作,以使得该结果被达成。
场景:
PersistantVolumeClaimTemplate
)如果一个应用程序不需要稳定的网络标识,或者不需要按顺序部署、删除、增加副本,您应该考虑使用 Deployment
这类无状态(stateless)的控制器。
StatefulSet 的基本信息
Headless Service
,用于控制网络域StatefulSet
,副本数为 3volumeClaimTemplates
提供稳定的存储(每一个 Pod ID 对应自己的存储卷,且Pod
重建后,仍然能找到对应的存储卷)apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels serviceName: "nginx" replicas: 3 # by default is 1 template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "my-storage-class" resources: requests: storage: 1Gi
DaemonSet
Service
Service
概述为何需要Service
?
Kubernetes
中 Pod
是随时可以消亡的(节点故障、容器内应用程序错误等原因)。如果使用Deployment
运行您的应用程序,Deployment
将会在 Pod
消亡后再创建一个新的Pod
以维持所需要的副本数。每一个 Pod
有自己的 IP 地址,然而,对于 Deployment
而言,对应Pod
集合是动态变化的。
Kubernetes Service
Kubernetes 中 Service 是一个 API 对象,通过 kubectl + YAML 或者 Kuboard,定义一个 Service,可以将符合 Service 指定条件的 Pod 作为可通过网络访问的服务提供给服务调用者。
Service 是 Kubernetes 中的一种服务发现机制:
Service
的详细描述Service
app=MyApp
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
Service
分配一个 IP 地址(ClusterIP
或 集群内 IP
),供 Service Proxy 使用selector
的 Pod
,并将最新的结果更新到与 Service
同名 my-service 的 Endpoint
对象中。Pod
的定义中,Port
可能被赋予了一个名字,您可以在 Service
的 targetPort
字段引用这些名字,而不是直接写端口号。这种做法可以使得您在将来修改后端程序监听的端口号,而无需影响到前端程序。Service
的默认传输协议是 TCP
,您也可以使用其他 支持的传输协议。Service
可以在一个 Service
对象中定义多个端口,但必须为每个端口定义一个名字
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: MyApp ports: - name: http protocol: TCP port: 80 nodePort: 32080 targetPort: 9376 - name: https protocol: TCP port: 443 targetPort: 9377 # nodeport 模式 type: NodePort
Ingress Nginx
暴露服务Ingress
Ingress
是Kubernetes 的一种API对象,将集群内部的Service通过HTTP/HTTPS 方式暴露到集群外部,并通过规则定义HTTP/HTTPS 的路由。Ingress 具备如下特性:集群外部可访问URL,负载均衡,SSL Termination,按域路由。
Ingress Controller
Ingress Controller
(通常需要负载均衡器配合)负责实现Ingress API 对象所声明的能力。
使用 Ingress Nginx
实现 Ingress Controller
Helm 3
(Kubernetes包管理工具)wget https://get.helm.sh/helm-v3.4.1-linux-amd64.tar.gz
tar zxvf helm-v3.4.1-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm
Helm
安装 Ingress Nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm pull ingress-nginx/ingress-nginx
tar -zxvf ingress-nginx-3.12.0.tgz
# 编辑valuse.yaml 文件
vim values.yaml
## nginx configuration ## Ref: https://github.com/kubernetes/ingress-nginx/blob/master/controllers/nginx/configuration.md ## controller: image: repository: registry.cn-hangzhou.aliyuncs.com/k8s_gcr_io_allen/ingress-nginx-controller tag: "v0.41.2" pullPolicy: IfNotPresent # www-data -> uid 101 runAsUser: 101 allowPrivilegeEscalation: true # Configures the ports the nginx-controller listens on containerPort: http: 80 https: 443 # Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/ config: {} ## Annotations to be added to the controller config configuration configmap ## configAnnotations: {} # Will add custom headers before sending traffic to backends according to https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/customization/custom-headers proxySetHeaders: {} # Will add custom headers before sending response traffic to the client according to: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#add-headers addHeaders: {} # Optionally customize the pod dnsConfig. dnsConfig: {} # Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. # By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller # to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. dnsPolicy: ClusterFirst # Bare-metal considerations via the host network https://kubernetes.github.io/ingress-nginx/deploy/baremetal/#via-the-host-network # Ingress status was blank because there is no Service exposing the NGINX Ingress controller in a configuration using the host network, the default --publish-service flag used in standard cloud setups does not apply reportNodeInternalIp: false # Required for use with CNI based kubernetes installations (such as ones set up by kubeadm), # since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920 # is merged hostNetwork: false ## Use host ports 80 and 443 ## Disabled by default ## hostPort: enabled: false ports: http: 80 https: 443 ## Election ID to use for status update ## electionID: ingress-controller-leader ## Name of the ingress class to route through this controller ## ingressClass: nginx # labels to add to the pod container metadata podLabels: {} # key: value ## Security Context policies for controller pods ## podSecurityContext: {} ## See https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ for ## notes on enabling and using sysctls ### sysctls: {} # sysctls: # "net.core.somaxconn": "8192" ## Allows customization of the source of the IP address or FQDN to report ## in the ingress status field. By default, it reads the information provided ## by the service. If disable, the status field reports the IP address of the ## node or nodes where an ingress controller pod is running. publishService: enabled: true ## Allows overriding of the publish service to bind to ## Must be <namespace>/<service_name> ## pathOverride: "" ## Limit the scope of the controller ## scope: enabled: false namespace: "" # defaults to .Release.Namespace ## Allows customization of the configmap / nginx-configmap namespace ## configMapNamespace: "" # defaults to .Release.Namespace ## Allows customization of the tcp-services-configmap ## tcp: configMapNamespace: "" # defaults to .Release.Namespace ## Annotations to be added to the tcp config configmap annotations: {} ## Allows customization of the udp-services-configmap ## udp: configMapNamespace: "" # defaults to .Release.Namespace ## Annotations to be added to the udp config configmap annotations: {} ## Additional command line arguments to pass to nginx-ingress-controller ## E.g. to specify the default SSL certificate you can use ## extraArgs: # default-ssl-certificate: "ailuoli-ingress-nginx-secret" extraArgs: {} ## Additional environment variables to set extraEnvs: [] # extraEnvs: # - name: FOO # valueFrom: # secretKeyRef: # key: FOO # name: secret-resource ## DaemonSet or Deployment ## kind: DaemonSet ## Annotations to be added to the controller Deployment or DaemonSet ## annotations: {} # keel.sh/pollSchedule: "@every 60m" ## Labels to be added to the controller Deployment or DaemonSet ## labels: {} # keel.sh/policy: patch # keel.sh/trigger: poll # The update strategy to apply to the Deployment or DaemonSet ## updateStrategy: {} # rollingUpdate: # maxUnavailable: 1 # type: RollingUpdate # minReadySeconds to avoid killing pods before we are ready ## minReadySeconds: 0 ## Node tolerations for server scheduling to nodes with taints ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ ## tolerations: [] # - key: "key" # operator: "Equal|Exists" # value: "value" # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" ## Affinity and anti-affinity ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity ## affinity: {} # # An example of preferred pod anti-affinity, weight is in the range 1-100 # podAntiAffinity: # preferredDuringSchedulingIgnoredDuringExecution: # - weight: 100 # podAffinityTerm: # labelSelector: # matchExpressions: # - key: app.kubernetes.io/name # operator: In # values: # - ingress-nginx # - key: app.kubernetes.io/instance # operator: In # values: # - ingress-nginx # - key: app.kubernetes.io/component # operator: In # values: # - controller # topologyKey: kubernetes.io/hostname # # An example of required pod anti-affinity # podAntiAffinity: # requiredDuringSchedulingIgnoredDuringExecution: # - labelSelector: # matchExpressions: # - key: app.kubernetes.io/name # operator: In # values: # - ingress-nginx # - key: app.kubernetes.io/instance # operator: In # values: # - ingress-nginx # - key: app.kubernetes.io/component # operator: In # values: # - controller # topologyKey: "kubernetes.io/hostname" ## Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in. ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ ## topologySpreadConstraints: [] # - maxSkew: 1 # topologyKey: failure-domain.beta.kubernetes.io/zone # whenUnsatisfiable: DoNotSchedule # labelSelector: # matchLabels: # app.kubernetes.io/instance: ingress-nginx-internal ## terminationGracePeriodSeconds ## wait up to five minutes for the drain of connections ## terminationGracePeriodSeconds: 300 ## Node labels for controller pod assignment ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ ## nodeSelector: kubernetes.io/os: linux ingressApp: ingress ## Liveness and readiness probe values ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes ## livenessProbe: failureThreshold: 5 initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 port: 10254 readinessProbe: failureThreshold: 3 initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 port: 10254 # Path of the health check endpoint. All requests received on the port defined by # the healthz-port parameter are forwarded internally to this path. healthCheckPath: "/healthz" ## Annotations to be added to controller pods ## podAnnotations: {} replicaCount: 1 minAvailable: 1 # Define requests resources to avoid probe issues due to CPU utilization in busy nodes # ref: https://github.com/kubernetes/ingress-nginx/issues/4735#issuecomment-551204903 # Ideally, there should be no limits. # https://engineering.indeedblog.com/blog/2019/12/cpu-throttling-regression-fix/ resources: # limits: # cpu: 100m # memory: 90Mi requests: cpu: 100m memory: 90Mi # Mutually exclusive with keda autoscaling autoscaling: enabled: false minReplicas: 1 maxReplicas: 11 targetCPUUtilizationPercentage: 50 targetMemoryUtilizationPercentage: 50 autoscalingTemplate: [] # Custom or additional autoscaling metrics # ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-custom-metrics # - type: Pods # pods: # metric: # name: nginx_ingress_controller_nginx_process_requests_total # target: # type: AverageValue # averageValue: 10000m # Mutually exclusive with hpa autoscaling keda: apiVersion: "keda.sh/v1alpha1" # apiVersion changes with keda 1.x vs 2.x # 2.x = keda.sh/v1alpha1 # 1.x = keda.k8s.io/v1alpha1 enabled: false minReplicas: 1 maxReplicas: 11 pollingInterval: 30 cooldownPeriod: 300 restoreToOriginalReplicaCount: false triggers: [] # - type: prometheus # metadata: # serverAddress: http://<prometheus-host>:9090 # metricName: http_requests_total # threshold: '100' # query: sum(rate(http_requests_total{deployment="my-deployment"}[2m])) behavior: {} # scaleDown: # stabilizationWindowSeconds: 300 # policies: # - type: Pods # value: 1 # periodSeconds: 180 # scaleUp: # stabilizationWindowSeconds: 300 # policies: # - type: Pods # value: 2 # periodSeconds: 60 ## Enable mimalloc as a drop-in replacement for malloc. ## ref: https://github.com/microsoft/mimalloc ## enableMimalloc: true ## Override NGINX template customTemplate: configMapName: "" configMapKey: "" service: enabled: true annotations: {} labels: {} # clusterIP: "" ## List of IP addresses at which the controller services are available ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips ## externalIPs: [] # loadBalancerIP: "" loadBalancerSourceRanges: [] enableHttp: true enableHttps: true ## Set external traffic policy to: "Local" to preserve source IP on ## providers supporting it ## Ref: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer # externalTrafficPolicy: "" # Must be either "None" or "ClientIP" if set. Kubernetes will default to "None". # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies # sessionAffinity: "" # specifies the health check node port (numeric port number) for the service. If healthCheckNodePort isn’t specified, # the service controller allocates a port from your cluster’s NodePort range. # Ref: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip # healthCheckNodePort: 0 ports: http: 80 https: 443 targetPorts: http: 80 https: 443 type: NodePort # type: NodePort # nodePorts: # http: 32080 # https: 32443 # tcp: # 8080: 32808 nodePorts: http: "80" https: "443" tcp: 8080: 8080 udp: {} ## Enables an additional internal load balancer (besides the external one). ## Annotations are mandatory for the load balancer to come up. Varies with the cloud service. internal: enabled: false annotations: {} ## Restrict access For LoadBalancer service. Defaults to 0.0.0.0/0. loadBalancerSourceRanges: [] ## Set external traffic policy to: "Local" to preserve source IP on ## providers supporting it ## Ref: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer # externalTrafficPolicy: "" extraContainers: [] ## Additional containers to be added to the controller pod. ## See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. # - name: my-sidecar # image: nginx:latest # - name: lemonldap-ng-controller # image: lemonldapng/lemonldap-ng-controller:0.2.0 # args: # - /lemonldap-ng-controller # - --alsologtostderr # - --configmap=$(POD_NAMESPACE)/lemonldap-ng-configuration # env: # - name: POD_NAME # valueFrom: # fieldRef: # fieldPath: metadata.name # - name: POD_NAMESPACE # valueFrom: # fieldRef: # fieldPath: metadata.namespace # volumeMounts: # - name: copy-portal-skins # mountPath: /srv/var/lib/lemonldap-ng/portal/skins extraVolumeMounts: [] ## Additional volumeMounts to the controller main container. # - name: copy-portal-skins # mountPath: /var/lib/lemonldap-ng/portal/skins extraVolumes: [] ## Additional volumes to the controller pod. # - name: copy-portal-skins # emptyDir: {} extraInitContainers: [] ## Containers, which are run before the app containers are started. # - name: init-myservice # image: busybox # command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] admissionWebhooks: annotations: {} enabled: false failurePolicy: Fail # timeoutSeconds: 10 port: 8443 certificate: "/usr/local/certificates/cert" key: "/usr/local/certificates/key" namespaceSelector: {} objectSelector: {} service: annotations: {} # clusterIP: "" externalIPs: [] # loadBalancerIP: "" loadBalancerSourceRanges: [] servicePort: 443 type: ClusterIP patch: enabled: true image: repository: docker.io/jettech/kube-webhook-certgen tag: v1.5.0 pullPolicy: IfNotPresent ## Provide a priority class name to the webhook patching job ## priorityClassName: "" podAnnotations: {} nodeSelector: {} tolerations: [] runAsUser: 2000 metrics: port: 10254 # if this port is changed, change healthz-port: in extraArgs: accordingly enabled: false service: annotations: {} # prometheus.io/scrape: "true" # prometheus.io/port: "10254" # clusterIP: "" ## List of IP addresses at which the stats-exporter service is available ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips ## externalIPs: [] # loadBalancerIP: "" loadBalancerSourceRanges: [] servicePort: 9913 type: ClusterIP # externalTrafficPolicy: "" # nodePort: "" serviceMonitor: enabled: false additionalLabels: {} namespace: "" namespaceSelector: {} # Default: scrape .Release.Namespace only # To scrape all, use the following: # namespaceSelector: # any: true scrapeInterval: 30s # honorLabels: true targetLabels: [] metricRelabelings: [] prometheusRule: enabled: false additionalLabels: {} # namespace: "" rules: [] # # These are just examples rules, please adapt them to your needs # - alert: NGINXConfigFailed # expr: count(nginx_ingress_controller_config_last_reload_successful == 0) > 0 # for: 1s # labels: # severity: critical # annotations: # description: bad ingress config - nginx config test failed # summary: uninstall the latest ingress changes to allow config reloads to resume # - alert: NGINXCertificateExpiry # expr: (avg(nginx_ingress_controller_ssl_expire_time_seconds) by (host) - time()) < 604800 # for: 1s # labels: # severity: critical # annotations: # description: ssl certificate(s) will expire in less then a week # summary: renew expiring certificates to avoid downtime # - alert: NGINXTooMany500s # expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"5.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 # for: 1m # labels: # severity: warning # annotations: # description: Too many 5XXs # summary: More than 5% of all requests returned 5XX, this requires your attention # - alert: NGINXTooMany400s # expr: 100 * ( sum( nginx_ingress_controller_requests{status=~"4.+"} ) / sum(nginx_ingress_controller_requests) ) > 5 # for: 1m # labels: # severity: warning # annotations: # description: Too many 4XXs # summary: More than 5% of all requests returned 4XX, this requires your attention ## Improve connection draining when ingress controller pod is deleted using a lifecycle hook: ## With this new hook, we increased the default terminationGracePeriodSeconds from 30 seconds ## to 300, allowing the draining of connections up to five minutes. ## If the active connections end before that, the pod will terminate gracefully at that time. ## To effectively take advantage of this feature, the Configmap feature ## worker-shutdown-timeout new value is 240s instead of 10s. ## lifecycle: preStop: exec: command: - /wait-shutdown priorityClassName: "" ## Rollback limit ## revisionHistoryLimit: 10 # Maxmind license key to download GeoLite2 Databases # https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases maxmindLicenseKey: "" ## Default 404 backend ## defaultBackend: ## enabled: false image: repository: k8s.gcr.io/defaultbackend-amd64 tag: "1.5" pullPolicy: IfNotPresent # nobody user -> uid 65534 runAsUser: 65534 runAsNonRoot: true readOnlyRootFilesystem: true allowPrivilegeEscalation: false extraArgs: {} serviceAccount: create: true name: ## Additional environment variables to set for defaultBackend pods extraEnvs: [] port: 8080 ## Readiness and liveness probes for default backend ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/ ## livenessProbe: failureThreshold: 3 initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 5 readinessProbe: failureThreshold: 6 initialDelaySeconds: 0 periodSeconds: 5 successThreshold: 1 timeoutSeconds: 5 ## Node tolerations for server scheduling to nodes with taints ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ ## tolerations: [] # - key: "key" # operator: "Equal|Exists" # value: "value" # effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)" affinity: {} ## Security Context policies for controller pods ## See https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ for ## notes on enabling and using sysctls ## podSecurityContext: {} # labels to add to the pod container metadata podLabels: {} # key: value ## Node labels for default backend pod assignment ## Ref: https://kubernetes.io/docs/user-guide/node-selection/ ## nodeSelector: {} ## Annotations to be added to default backend pods ## podAnnotations: {} replicaCount: 1 minAvailable: 1 resources: {} # limits: # cpu: 10m # memory: 20Mi # requests: # cpu: 10m # memory: 20Mi autoscaling: enabled: false minReplicas: 1 maxReplicas: 2 targetCPUUtilizationPercentage: 50 targetMemoryUtilizationPercentage: 50 service: annotations: {} # clusterIP: "" ## List of IP addresses at which the default backend service is available ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips ## externalIPs: [] # loadBalancerIP: "" loadBalancerSourceRanges: [] servicePort: 80 type: ClusterIP priorityClassName: "" ## Enable RBAC as per https://github.com/kubernetes/ingress/tree/master/examples/rbac/nginx and https://github.com/kubernetes/ingress/issues/266 rbac: create: true scope: false # If true, create & use Pod Security Policy resources # https://kubernetes.io/docs/concepts/policy/pod-security-policy/ podSecurityPolicy: enabled: false serviceAccount: create: true name: ## Optional array of imagePullSecrets containing private registry credentials ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ imagePullSecrets: [] # - name: secretName # TCP service key:value pairs # Ref: https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tcp ## tcp: {} # 8080: "default/example-tcp-svc:9000" # UDP service key:value pairs # Ref: https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/udp ## udp: {} # 53: "kube-system/kube-dns:53"
这里选择是要NodePort
得方式部署这个ingress nginx
,默认方式是使用 LoadBlancer
得,所以需要修改一些配置
controller.image.repository
: registry.cn-hangzhou.aliyuncs.com/k8s_gcr_io_allen/ingress-nginx-controller
image 得仓库要是可用得,默认的是谷歌得镜像,无法访问。controller.kind
:DaemonSet
这个apiVersion建议使用 DaemonSetcontroller.nodeSelector.ingressApp:
ingress
这里新增个label 选择部署得节点controller.service.type
:NodePort
这里得类型改为NodePort,并且将端口号暴漏出去,注意这里需要把集群得端口范围改为1-65535
nodePorts:
http: "80"
https: "443"
tcp:
8080: 8080
udp: {}
kubectl create secret tls ailuoli-nginx-secret --cert=ailuoli.cn.crt --key=ailuoli.cn.key -n test
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest --- apiVersion: v1 kind: Service metadata: name: nginx-service labels: app: nginx spec: selector: app: nginx ports: - name: http protocol: TCP port: 80 targetPort: 80 - name: https protocol: TCP port: 443 targetPort: 443 --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress-for-nginx # Ingress 的名字,仅用于标识 annotations: # 路径匹配规则,匹配后路径rewrite 为 / ,例如访问 https://ailuoli.cn/nginx,实际得路径匹配到了/nginx规则,路由到真正得服务则是https://ailuoli.cn/ nginx.ingress.kubernetes.io/rewrite-target: / kubernetes.io/ingress.class: nginx # 设置http请求强制路由到https nginx.ingress.kubernetes.io/ssl-redirect: "true" spec: rules: # Ingress 中定义 L7 路由规则 - host: ailuoli.cn # 根据 virtual hostname 进行路由(请使用您自己的域名) http: paths: # 按路径进行路由 - path: /nginx backend: serviceName: nginx-service # 指定后端的 Service 为之前创建的 nginx-service servicePort: 80 tls: - hosts: - ailuoli.cn secretName: ailuoli-ingress-nginx-secret
执行创建 Deployment
,Service
,Ingress
kubectl apply -f nginx-ingress.yaml
Volume
kubernetes volume
主要解决得问题
emptyDir
emptyDir
类型的数据卷在容器组被创建时分配给该容器组,并且直到容器组被移除,该数据卷才被释放。该数据卷初始分配时,始终是个空目录。同一容器组中的不通容器都可以对该目录执行读写操作,并且共享其中的数据,当容器组被删除时,emptyDir
数据卷中的数据将被永久删除。nfs
nfs
类型的数据卷可以加载NFS 到容器组/容器。容器组被移除时,将仅仅umount(写在)NFS数据卷,NFS中的数据仍将被保留。cephfs
cephfs
数据卷可以挂载一个外部CephFS卷到容器组中。hostPath
hostPath
类型的数据卷将Pod所在的节点文件系统上某一个文件或文件夹挂载进容器组。hostPath
指定 path 字段以外,您还可以为其指定 type
字段,可选的type
字段描述如下:Type 字段取值 | 描述 |
---|---|
空字符串(default)用于向后兼容,此时,kubernetes 在挂载 hostPath 数据卷前不会执行任何检查 | |
DirectoryOrCreate | 如果指定的 hostPath 路径不存在,kubernetes 将在节点的该路径上创建一个空文件夹,权限设置为 0755,与 kubelet 进程具备相同的 group 和 ownership |
Directory | 指定 hostPath 路径必须存在,且是一个文件夹 |
FileOrCreate | 如果指定的 hostPath 路径不存在,kubernetes 将在节点的该路径上创建一个空的文件,权限设置为 0644,与 kubelet 进程具备相同的 group 和 ownership |
File | 指定 hostPath 路径必须存在,且是一个文件 |
Socket | 指定 hostPath 路径必须存在,且是一个 Unix Socket |
CharDevice | 指定 hostPath 路径必须存在,且是一个 character device |
BlockDevice | 指定 hostPath 路径必须存在,且是一个 block device |
configMap
ConfigMap
提供了一种向容器组注入配置信息的途径。ConfigMap
中的数据可以被Pod中的容器作为一个数据卷挂载。secret
secret
数据卷可以用来注入敏感信息(例如密码)到容器组。您可以将敏感信息存入 kubernetes secret 对象,并通过 Volume(数据卷)以文件的形式挂载到容器组(或容器)。secret
数据卷使用 tmpfs(基于 RAM 的文件系统)挂载。persistentVolumeClaim
persistentVolumeClaim
数据卷用来挂载 PersistentVolume 存储卷。PersistentVolume 存储卷为用户提供了一种在无需关心具体所在云环境的情况下”声明“ 所需持久化存储的方式。我们需要在同一个 Pod 的不同容器间共享数据卷。使用 volumeMounts.subPath
属性,可以使容器在挂载数据卷时指向数据卷内部的一个子路径,而不是直接指向数据卷的根路径。
下面的例子中,一个 LAMP(Linux Apache Mysql PHP)应用的 Pod 使用了一个共享数据卷,HTML 内容映射到数据卷的 html
目录,数据库的内容映射到了 mysql
目录
apiVersion: v1 kind: Pod metadata: name: my-lamp-site spec: containers: - name: mysql image: mysql env: - name: MYSQL_ROOT_PASSWORD value: "rootpasswd" volumeMounts: - mountPath: /var/lib/mysql name: site-data subPath: mysql readOnly: false - name: php image: php:7.0-apache volumeMounts: - mountPath: /var/www/html name: site-data subPath: html readOnly: false volumes: - name: site-data persistentVolumeClaim: claimName: my-lamp-site-data
使用 volumeMounts.subPathExpr
字段,可以通过容器的环境变量指定容器内路径。使用此特性时,必须启用 VolumeSubpathEnvExpansion
如下面的例子,该 Pod 使用 subPathExpr
在 hostPath
数据卷 /var/log/pods
中创建了一个目录 pod1
(该参数来自于Pod的名字)。此时,宿主机目录 /var/log/pods/pod1
挂载到了容器的 /logs 路径:
apiVersion: v1 kind: Pod metadata: name: pod1 spec: containers: - name: container1 env: - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name image: busybox command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ] volumeMounts: - name: workdir1 mountPath: /logs subPathExpr: $(POD_NAME) readOnly: false restartPolicy: Never volumes: - name: workdir1 hostPath: path: /var/log/pods
数据卷的挂载传播(Mount Propagation)由 Pod 的 spec.containers[*].volumeMounts.mountPropagation
字段控制。可选的取值有:
None
: 默认值。在数据卷被挂载到容器之后,此数据卷不会再接受任何后续宿主机或其他容器挂载到该数据卷对应目录下的子目录的挂载。同样的,在容器中向该数据卷对应目录挂载新目录时,宿主机也不能看到。对应 Linux 的 private mount propagation 选项 。HostToContainer
: 在数据卷被挂载到容器之后,宿主机向该数据卷对应目录添加挂载时,对容器是可见的。对应 Linux 的 rslave mount propagation 选项。Bidirectional
: 在数据卷被挂载到容器之后,宿主机向该数据卷对应目录添加挂载时,对容器是可见的;同时,从容器中向该数据卷创建挂载,同样也对宿主机可见。对应 Linux 的 rshared mount propagation 选项PersistentVolume
与管理计算资源相比,管理存储资源是一个完全不同的问题。为了更好的管理存储,Kubernetes 引入了 PersistentVolume
和 PersistentVolumeClaim
两个概念,将存储管理抽象成如何提供存储以及如何使用存储两个关注点。
PersistentVolume
(PV 存储卷)是集群中的一块存储空间,由集群管理员管理、或者由 Storage Class(存储类)自动管理。PV(存储卷)和 node(节点)一样,是集群中的资源(kubernetes 集群由存储资源和计算资源组成)。PersistentVolumeClaim
(存储卷声明)是一种类型的 Volume(数据卷),PersistentVolumeClaim
(存储卷声明)引用的 PersistentVolume
(存储卷)有自己的生命周期,该生命周期独立于任何使用它的容器组。PersistentVolume
(存储卷)描述了如何提供存储的细节信息(NFS、cephfs等存储的具体参数)。PersistentVolumeClaim
(PVC 存储卷声明)代表用户使用存储的请求。Pod 容器组消耗 node 计算资源,PVC 存储卷声明消耗 PersistentVolume
存储资源。Pod 容器组可以请求特定数量的计算资源(CPU / 内存);PersistentVolumeClaim
可以请求特定大小/特定访问模式(只能被单节点读写/可被多节点只读/可被多节点读写)的存储资源。PersistentVolume
是集群中的存储资源,通常由集群管理员创建和管理StorageClass
用于对PersistentVolume
进行分类,如果正确配置,StorageClass
也可以根据 PersistentVolumeClaim
的请求动态创建 Persistent Volume
PersistentVolumeClaim
是使用该资源的请求,通常由应用程序提出请求,并指定对应的 StorageClass
和需求的空间大小PersistentVolumeClaim
可以做为数据卷的一种,被挂载到容器组/容器中使用静态提供static
PersistentVolume
,它们包含了可供集群中应用程序使用的关于实际存储的具体信息。动态提供Dynamic
StorageClass
(存储类)且 PersistentVolumeClaim
关联了该 StorageClass
的情况下,kubernetes 集群可以为应用程序动态创建 PersistentVolume
。如果一个 PersistentVolume
是动态提供给一个新的 PersistentVolumeClaim
,Kubernetes master 会始终将其绑定到该PersistentVolumeClaim
。除此之外,应用程序将被绑定一个不小于(可能大于)其 PersistentVolumeClaim
中请求的存储空间大小的 PersistentVolume
。一旦绑定,PersistentVolumeClaim
将拒绝其他PersistentVolume
的绑定关系。PVC 与 PV 之间的绑定关系是一对一的映射。
对于 Pod 容器组来说,PersistentVolumeClaim
存储卷声明是一种类型的 Volume 数据卷。Kubernetes 集群将 PersistentVolumeClaim
所绑定的 PersistentVolume
挂载到容器组供其使用。
Storage Object in Use Protection
)的目的是确保正在被容器组使用的 PersistentVolumeClaim
以及其绑定的 PersistentVolume
不能被系统删除,以避免可能的数据丢失。PersistentVolumeClaim
,则该 PVC 不会立即被移除掉,而是推迟到该 PVC 不在被任何容器组使用时才移除;同样的如果管理员删除了一个已经绑定到 PVC 的 PersistentVolume
,则该 PV 也不会立刻被移除掉,而是推迟到其绑定的 PVC 被删除后才移除掉。当用户不在需要其数据卷时,可以删除掉其 PersistentVolumeClaim
,此时其对应的 PersistentVolume
将被集群回收并再利用。Kubernetes 集群根据 PersistentVolume
中的 reclaim policy(回收策略)决定在其被回收时做对应的处理。当前支持的回收策略有:Retained(保留)、Recycled(重复利用)、Deleted(删除)
保留 Retain
保留策略需要集群管理员手工回收该资源。当绑定的 PersistentVolumeClaim 被删除后,PersistentVolume 仍然存在,并被认为是”已释放“。但是此时该存储卷仍然不能被其他 PersistentVolumeClaim 绑定,因为前一个绑定的 PersistentVolumeClaim 对应容器组的数据还在其中。集群管理员可以通过如下步骤回收该 PersistentVolume:
删除 Delete
删除策略将从 kubernete 集群移除 PersistentVolume
以及其关联的外部存储介质(云环境中的 AWA EBS、GCE PD、Azure Disk 或 Cinder volume)。
再利用 Recycle
再利用策略将在 PersistentVolume
回收时,执行一个基本的清除操作(rm -rf /thevolume/*),并使其可以再次被新的 PersistentVolumeClaim
绑定。
集群管理员也可以自定义一个 recycler pod template,用于执行清除操作
nfs
做存储 创建 StorageClass
nfs server
yum install -y nfs-utils
mkdir /data/nfsdata/
chmod 777 /data/nfsdata/
编辑 /etc/exports
文件,内容如下
/data/nfsdata/ *(rw,sync,insecure,no_subtree_check,no_root_squash)
其中 *
可以指定那些 ip 可以共享该文件夹
systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server
添加公网 ip 作为网卡
cat > /etc/sysconfig/network-scripts/ifcfg-eth0:1 <<EOF
BOOTPROTO=static
DEVICE=eth0:1
IPADDR=120.53.234.127
PREFIX=32
TYPE=Ethernet
USERCTL=no
ONBOOT=yes
EOF
nfs server
yum install -y nfs-utils
# 检查服务端是否设有共享目录
showmount -e ailuoli.cn
执行命令挂载nfs服务器上的共享目录到本机路径
mkdir /data/share
mount -t nfs ailuoli.cn:/data/nfsdata /data/share
#写一个测试文件
echo "hello nfs server" > /data/share/test.txt
验证nfs server 有没有
cat /data/nfsdata/test.txt
取消挂载
umount /data/share
Storage Class
来自动创建 PVC使用 helm
部署 nfs-client-provisioner
helm repo add stable https://charts.helm.sh/stable
helm pull stable/nfs-client-provisioner
tar -zxvf nfs-client-provisioner-1.2.11.tgz
修改 values.yaml
nfs:
server: ailuoli.cn
path: /data/nfsdata
... 删除策略
reclaimPolicy: Retain
执行创建 nfs-client
helm install nfs-client .
# 查看创建好的 Storage Class
kubectl get sc
测试下是否可以正常创建 PVC,创建 pvc-test.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
执行文件
kubectl apply -f pvc-test.yaml
查看 pvc
kubectl get pvc
结果如下,status 为 Bound 就为正常
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-mysql-0 Bound pvc-be7fdb16-e579-4857-b2ef-e5015b56e6f8 8Gi RWO nfs-client 9h
编辑该文件
vim /etc/kubernetes/manifests/kube-apiserver.yaml
添加此配置
- --feature-gates=RemoveSelfLink=false
ConfigMap
可以使用 kubectl create configmap
命令基于目录,文件,字面值来创建
kubectl create configmap <map-name> <data-source>
kubectl create configmap test-config --from-file=./dev/
查看configmaps
kubectl get configmaps test-config -o yaml
apiVersion: v1 data: ailuoli-dev.properties: from=git-dev-1.0-t service1-dev.properties: profile=dev-1.0 kind: ConfigMap metadata: creationTimestamp: "2020-12-16T03:17:38Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:ailuoli-dev.properties: {} f:service1-dev.properties: {} manager: kubectl-create operation: Update time: "2020-12-16T03:17:38Z" name: test-config namespace: test resourceVersion: "2387780" selfLink: /api/v1/namespaces/test/configmaps/test-config uid: 87f7843a-8230-4bb8-ad22-4085c0b108a9
kubectl create configmap test-config2 --from-file=./ailuoli-dev.properties
可以使用多个 --from-file
来创建 configMap
kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties --from-file=configure-pod-container/configmap/ui.properties
使用 --from-env-file
来创建 configMap
kubectl create configmap test-env-config --from-env-file=./ailuoli-test.properties
apiVersion: v1 data: from: git-test-1.0 kind: ConfigMap metadata: creationTimestamp: "2020-12-16T03:33:00Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:from: {} manager: kubectl-create operation: Update time: "2020-12-16T03:33:00Z" name: test-env-config namespace: test resourceVersion: "2389938" selfLink: /api/v1/namespaces/test/configmaps/test-env-config uid: 5bfba06b-7073-487f-80e3-a1e6384eeaeb
同样 --from-env-file
也可以使用多个
kubectl create configmap config-multi-env-files \
--from-env-file=configure-pod-container/configmap/game-env-file.properties \
--from-env-file=configure-pod-container/configmap/ui-env-file.properties
定义从文件创建 ConfigMap
时要使用的键
kubectl create configmap test-config3 --from-file=testailuoli=./ailuoli-dev.properties
apiVersion: v1 data: testailuoli: from=Ailuoli-Ailuoli-Ailuoli kind: ConfigMap metadata: creationTimestamp: "2020-12-16T03:43:05Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:testailuoli: {} manager: kubectl-create operation: Update time: "2020-12-16T03:43:05Z" name: test-config3 namespace: test resourceVersion: "2391353" selfLink: /api/v1/namespaces/test/configmaps/test-config3 uid: 9dafdda6-3085-451c-9e41-b02ffe81d367
ConfigMap
--from-literal
根据命令行定义文字值:
kubectl create configmap test-config4 --from-literal=hello1=world1 --from-literal=hello2=world2
apiVersion: v1 data: hello1: world1 hello2: world2 kind: ConfigMap metadata: creationTimestamp: "2020-12-16T06:28:51Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:hello1: {} f:hello2: {} manager: kubectl-create operation: Update time: "2020-12-16T06:28:51Z" name: test-config4 namespace: test resourceVersion: "2414579" selfLink: /api/v1/namespaces/test/configmaps/test-config4 uid: d05fa08b-44ca-4bdf-aaf4-38b47477190a
ConfigMap
自1.14 开始,kubectl 开始支持 kustomization.yaml。
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: test-config5
files:
- configmap/config-repos/ailuoli-dev.properties
# - test=configmap/config-repos/ailuoli-dev.properties
# 自定义key
EOF
kubectl apply -k .
apiVersion: v1 data: ailuoli-dev.properties: from=Ailuoli-Ailuoli-Ailuoli kind: ConfigMap metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","data":{"ailuoli-dev.properties":"from=Ailuoli-Ailuoli-Ailuoli"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"test-config5-245dh9m2fd","namespace":"test"}} creationTimestamp: "2020-12-16T09:40:42Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:ailuoli-dev.properties: {} f:metadata: f:annotations: .: {} f:kubectl.kubernetes.io/last-applied-configuration: {} manager: kubectl-client-side-apply operation: Update time: "2020-12-16T09:40:42Z" name: test-config5-245dh9m2fd namespace: test resourceVersion: "2441461" selfLink: /api/v1/namespaces/test/configmaps/test-config5-245dh9m2fd uid: 0f97cda8-0c6c-47db-9599-1287e3dea642
ConfigMap
定义容器环境变量apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest env: - name: test-config4 valueFrom: configMapKeyRef: key: hello1 name: test-config4
ConfigMap
数据添加到一个 Volume
中apiVersion: v1 kind: Pod metadata: name: dapi-test-pod spec: containers: - name: test-container image: k8s.gcr.io/busybox command: [ "/bin/sh", "-c", "ls /etc/config/" ] volumeMounts: - name: config-volume mountPath: /etc/config volumes: - name: config-volume configMap: # Provide the name of the ConfigMap containing the files you want # to add to the container name: special-config items: #使用 path 字段为特定的 ConfigMap 项目指定预期的文件路径。 在这里,SPECIAL_LEVEL 将挂载在 config-volume 数据卷中 /etc/config/keys 目录下。 - key: SPECIAL_LEVEL path: keys restartPolicy: Never
apiVersion: v1 kind: Pod metadata: name: frontend spec: containers: - name: app image: images.my-company.example/app:v4 env: - name: MYSQL_ROOT_PASSWORD value: "password" resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m" - name: log-aggregator image: images.my-company.example/log-aggregator:v6 resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"
Pod 中存在属性 Node selector
/ Node affinity
用于将Pod指定到合适的节点。相对的,节点中存在 污点属性 taints
,使得节点可以排斥某些 Pod
污点和容忍(taints and )成对工作,以确保Pod
不会被调度到不合适的节点上。
Pod
增加容忍 (toleration, 一个节点可以有多个容忍)Pod
kubectl taint
命令,可以向节点添加污点kubectl taint nodes node1 key=value:NoSchedule
该命令向节点 node1
添加了一个污点。污点是一个键值对,污点得键为key
,值为value
,污点效果为 NoSchedule
。此污点意味着kubernetes
不会向该节点调度任何Pod
,除非该 Pod
有一个匹配得容忍(toleration
)
kubectl taint nodes node1 key:NoSchedule-
Pod
添加容忍PodSpec
中有一个tolerations
字段,可用于向Pod添加容忍。
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent tolerations: - key: "example-key" operator: "Exists" effect: "NoSchedule"
当满足如下条件时,k8s 认为容忍和污点匹配:
key
) 相同effect
)相同operator
为:
Exists
(此时污点中不该指定 value
)Equal
(此时容忍的 value
应与污点的 value
相同)operator
,则默认为 Equal
特殊情况:
key
但是定义了 operator
为 Exists
,Kubernetes 认为此容忍匹配所有的污点.tolerations:
- operator: "Exists"
effect
但是定义了key
,Kubernetes 认为此容忍匹配所有effect
.tolerations:
- key: "key"
operator: "Exists
effect
效果有
NoSchedule
PreferNoSchedule
比 NoSchedule
更宽容一些,Kubernetes将尽量避免将没有匹配容忍的Pod
调度该节点上,但是并不是不可以NoExecute
不能在节点上运行(如果已经运行,将被驱逐 )kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
同时有一个Pod带有两个容忍:
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
在这个案例中,Pod 上有两个容忍,匹配了节点的前两个污点,只有节点的第三个污点对该 Pod 来说不可忽略,该污点的效果为 NoSchedule
:
NoExecute
效果的污点已被 Pod 上的第二个容忍匹配,因此被忽略)可以设置 Pod在多久后被驱逐tolerationSeconds
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
kubernetes 的节点控制器在碰到某些特定的条件时,将自动为节点添加污点,默认启用。
node.kubernetes.io/not-ready
: 节点未就绪。对应着 NodeCondition Ready 为 False 的情况node.kubernetes.io/unreachable
: 节点不可触达。对应着 NodeCondition Ready 为 Unknown 的情况node.kubernetes.io/out-of-disk
:节点磁盘空间已满node.kubernetes.io/memory-pressure
:节点内存吃紧node.kubernetes.io/disk-pressure
:节点磁盘吃紧node.kubernetes.io/network-unavailable
:节点网络不可用node.kubernetes.io/unschedulable
:节点不可调度node.cloudprovider.kubernetes.io/uninitialized
:如果 kubelet 是由 “外部” 云服务商启动的,该污点用来标识某个节点当前为不可用的状态。在“云控制器”(cloud-controller-manager)初始化这个节点以后,kubelet将此污点移除tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
如果 Pod 没有 node.kubernetes.io/not-ready
容忍, Kubernetes 将自动为 Pod 添加一个 tolerationSeconds=300
的 node.kubernetes.io/not-ready
容忍。同样的,如果 Pod 没有 node.kubernetes.io/unreachable
容忍,Kubernetes 将自动为 Pod 添加一个 tolerationSeconds=300
的node.kubernetes.io/unreachable
容忍
这类自动添加的容忍确保了 Pod 在节点发生 not-ready 和 unreachable 问题时,仍然在节点上保留 5 分钟。
DaemonSet Pod
相对特殊一些,他们在创建时就添加了不带 tolerationSeconds
的 NoExecute
效果的容忍,适用的污点有:
node.kubernetes.io/unreachable
node.kubernetes.io/not-ready
这将确保 DaemonSet Pod
始终不会被驱逐
Secret
和创建其他类型 API对象一样,可以现在yaml
文件定义好Secret,然后通过 kubectl apply -f
命令创建。此时可以通过两种方式在yaml
中定义Secret
data
: 使用 字段 时,取值的欸容必须是 base64
编码stringDate
: 使用stringData时,更为方便,可以直接将取值以明文方式写在yaml文件中yaml
中定义dataecho -n 'admin' | base64
echo -n '123456' | base64
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
username: admin
password: a1234567890
但是这种写法在yaml
文件annotation
中仍然可以看见铭文
apiVersion: v1 data: password: YTEyMzQ1Njc4OTA= username: YWRtaW4= kind: Secret metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"secret-test","namespace":"test"},"stringData":{"password":"a1234567890","username":"admin"},"type":"Opaque"} creationTimestamp: "2020-12-24T06:45:47Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:password: {} f:username: {} f:metadata: f:annotations: .: {} f:kubectl.kubernetes.io/last-applied-configuration: {} f:type: {} manager: kubectl-client-side-apply operation: Update time: "2020-12-24T06:45:47Z" name: secret-test namespace: test resourceVersion: "4249564" selfLink: /api/v1/namespaces/test/secrets/secret-test uid: 6228d000-976f-49ca-8122-4940425b1c35 type: Opaque
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
stringData:
username: administrator
echo 'YTEyMzQ1Njc4OTA=' | base64 --decode
kubectl edit secrets mysecret
Security Context
在 Pod 的定义中增加 securityContext
字段,即可为 Pod 执行 Security 相关的设定。securityContext
字段是一个 PodSecurityContext
对象。通过该字段指定的内容将对该 Pod 中所有的容器生效。
apiVersion: v1 kind: Pod metadata: name: security-context-demo spec: securityContext: runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 volumes: - name: sec-ctx-vol emptyDir: {} containers: - name: sec-ctx-demo image: busybox command: [ "sh", "-c", "sleep 1h" ] volumeMounts: - name: sec-ctx-vol mountPath: /data/demo securityContext: allowPrivilegeEscalation: false
spec.securityContext.runAsUser
字段指定了该 Pod 中所有容器的进程都以UserID 1000 的身份运行,spec.securityContext.runAsGroup
字段指定了该 Pod 中所有容器的进程都以GroupID 3000 的身份运行
spec.securityContext.fsGroup
字段指定了该 Pod 的 fsGroup 为 2000/data/demo
的数据卷为 sec-ctx-demo
) 的所有者以及在该数据卷下创建的任何文件,其 GroupID 为 2000Linux Capabilities
使用 Linux Capabilities
可以为容器内的进程授予某些特定的权限(而不是 root 用户的所有权限)。在容器定义的 securityContext
中添加 capabilities
字段,可以向容器添加或删除Linux Capability
。
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-4
spec:
containers:
- name: sec-ctx-demo-4
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
Kubernetes
高级学习所有Kubernetes 集群都有两类用户,Kubernetes管理的Service Account
和 普通用户
与普通用户相对,Service Account
是通过 Kubernetes API 管理的用户。Service Account
是名称空间级别的对象,可能由 ApiServer 自动创建,或者通过调用 API 接口创建。Service Account
都绑定了一组 Secret
,Secret
可以被挂载到 Pod 中,以便 Pod 中的进程可以获得调用 Kubernetes API 的权限。
集群内外的任何一个进程,在调用 API Server 的接口时,都必须认证其身份,或者被当做一个匿名用户。可能的场景有:
Kubernetes 的认证策略(Authentication Strategies)是:通过 authentication plugin
认证发起 API 请求的用户身份,认证方式有 client certificates、bearer tokens、authenticating proxy、HTTP basic auth。当 API Server 接收到 HTTP 请求时,authentication plugin 会尝试将如下属性附加到请求:
Username
:唯一标识用户的一个字符串。例如 kube-admin 或者 jane@example.comUID
:唯一标识用户的一个字符串,相较于 username,提供更强的一致性和唯一性。(某些 Identity Provider 可能允许用户更改 username)Groups
:一组字符串,标识用户所属的用户组额外字段
:Key,Value 都是 String 的 Map,包含一些 对 authorizer 可能有用的信息\上述所有的字段对认证系统来说都是透明的,且只对 authorizer 有意义(authentication plugin 将认证结果中的某些字段赋值到上述字段中,认证系统只是按照自己的方式正常工作,并不知道上述这些字段的存在)。这使得 Kubernetes 可以同时支持多种认证方式,在实际工作中,您通常应该至少配置两种认证方式:
Kubernetes 明确地区分了 user account 和 service account 的概念,原因如下:
Admission Controller
(opens new window)是 apiserver 的一部分,它在 Pod 创建或者更新时,对 Pod 执行一些修改。此控制器激活时(默认处于激活状态),当 Pod 被创建或修改时,该控制器将执行如下动作:
ServiceAccount
,将 ServiceAccount
设置为 defaultServiceAccount
存在,否则拒绝创建或者修改 PodImagePullSecrets
,则 ServiceAccount
中的 ImagePullSecrets
将被添加到 Pod 上volume
(其中包含了访问 APIServer 的 token)volumeSource
,并挂载到路径/var/run/secrets/kubernetes.io/serviceaccount
TokenController 作为 controller-manager 的一部分运行。以异步的方式执行如下动作:
ServiceAccount
的创建,并创建一个对应的 Secret
以允许访问 APIServerServiceAccount
的删除,并删除所有对应的 ServiceAccountToken SecretsSecret
的添加,确保其引用的 ServiceAccount
以存在,并在需要时向 Secret 添加 TokenSecret
的删除,并在需要的情况下将对应 ServiceAccount
中对 Secret 的引用也删除掉。。。。 未完待续
Kubernetes
实战使用kubectl port-forward
访问kubernetes集群中的Redis Server ,Debug 时很有效
apiVersion: apps/v1 kind: Deployment metadata: name: redis-master labels: app: redis spec: selector: matchLabels: app: redis role: master tier: backend replicas: 1 template: metadata: labels: app: redis role: master tier: backend spec: containers: - name: master image: redis resources: requests: cpu: 100m memory: 100Mi ports: - containerPort: 6379 --- apiVersion: v1 kind: Service metadata: name: redis-master labels: app: redis role: master tier: backend spec: ports: - port: 6379 targetPort: 6379 selector: app: redis role: master tier: backend
这时redis 的pod就创建好了,Service
使用的ClusterIP
# 这几个命令执行任意一个即可
kubectl port-forward redis-master-765d459796-258hz 7000:6379
kubectl port-forward pods/redis-master-765d459796-258hz 7000:6379
kubectl port-forward deployment/redis-master 7000:6379
kubectl port-forward rs/redis-master 7000:6379
kubectl port-forward svc/redis-master 7000:6379
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。