kubetnetes中新建应用的最佳实践

1 基础规约

1.1 尽量避免使用默认命名空间

虽然为每个Kubernetes集群都创建了默认名称空间,但不建议将所有创建的资源添加到默认名称空间中,因为存在特权升级,资源名称冲突,随着资源扩展操作延迟以及Kubernetes对象管理不当的风险。

1.2 避免使用latest标签的镜像

不建议将容器镜像与latest标签一起使用,也不要在镜像中未指定标签(默认为latest),因为这会导致所使用的镜像版本混乱

1.3 使用完整的镜像声明

为了保持可移植性,建议使用完整的镜像名称。如果更改了运行的集群或者节点时,具有完整名称的镜像可确保应用程序不会中断。

1
2
3
4
5
6
7
8
9
10
11
# 虽然可以正常使用但是尽量还是指定那个镜像仓库和项目避免出现歧义
spec:
containers:
- name: mypod
image: nginx:1.17.0

# 修改后
spec:
containers:
- name: mypod
image: docker.io/nginx:1.17.0

1.4 尽量避免使用HostPath作为应用存储持久化

  • 由于在没有指定节点调度的情况下,pod可能调度到任意集群的节点上;如果此时pod使用了HostPath作为持久化存储则会导致应用的数据丢失
  • 无法对HostPath中使用的存储进行感知
  • 主机上的文件只能由root用户写入;所以必须要以root用户身份在特权容器中运行进程,或修改主机上的文件许可权才能写入hostPath

1.5 清理掉集群中未被使用的pv、pvc、configm、secret

定时清理集群中的无用或者没被引用的资源,减少集群管理的无用资源

1.6 做好资源的request和limit

为容器指定资源限制时,调度程序可以更好地决定要在其上放置Pod的节点,并以指定的方式处理节点上的资源争用。

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: docker.io/nginx:1.17.0
name: test-container
resources:
limits:
cpu: 100m
requests:
cpu: 50m

1.7 使用deployment而不是pod来创建应用

当用pod创建应用时,一旦删除掉pod所有应用信息都会丢失且应用也不会重启;所以建议使用deployment来创建应用

1.8 定时清理集群中测试或者无用的应用

定时清理集群中的无用或者没被引用的应用数据,减少集群管理的无用资源和资源消耗

1.9 给Java类型应用设置堆内存限制

如果只设置容器的资源限制而不对java应用的堆内存进行限制,会在应用流量较大时导致堆内存飙升超过k8s的资源限制被杀掉,然后再拉起,这样循环。所有应该对Java -Xmx最大的堆内存进行设置,并且这个值要比limit的内存值低10%左右,这样的话当应用堆内存升高时会自动触发java的垃圾回收机制。

1.10 滚动更新应用设置一定的休眠时间

滚动更新是关闭现有的pod,再起一新的pod,apiserver会通知给kubelet会关闭老的pod容器,并且从service后端摘掉,这样就不分发新的流量了,然后再告诉kube-proxy,处理新的转发规则,然后调度到节点上,其实这也是一个pod的上下线周期。

但是转发新的pod时间段里,它是有间隔的,关闭pod之后会有一个等待时间,在这个时间内,可能还会接入一些新的流量,但是它的服务已经不再处理新的请求了,所以会导致连接拒绝了。

解决方法是给Pod加入preStop时间,也就是在关闭这个pod 时加个休眠的时间。你关闭的容器不会马上退出,然后休眠5秒钟,再去关闭着应用,这5秒能够足够让kube-proxy刷新规则。

1
2
3
4
5
6
7
lifecycle :
preStop:
exec:
command :
- sh
- -c
- “sleep 5

1.11 使用reloader自动更新应用

当应用配置了configmap和secret时,reloader通过根据应用的annotion识别应用的配置是否更新来达到自动更新的目的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
## configmap类型
kind: Deployment
metadata:
annotations:
configmap.reloader.stakater.com/reload: "foo-configmap"
spec:
template: metadata:

kind: Deployment
metadata:
annotations:
configmap.reloader.stakater.com/reload: "foo-configmap,bar-configmap,baz-configmap"
spec:
template: metadata:

## secret类型
kind: Deployment
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo-secret"
spec:
template: metadata:

kind: Deployment
metadata:
annotations:
secret.reloader.stakater.com/reload: "foo-secret,bar-secret,baz-secret"
spec:
template: metadata:

2 安全规约

2.1 停止使用特权容器

privileged仅将模式用于受信任的容器。由于特权模式允许容器进程访问主机,因此恶意容器会严重破坏主机并降低群集上的服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 直接声明特权容器(不推荐)
spec:
containers:
- name: mypod
image: nginx
securityContext:
privileged: true

# 准确的指定所需要的权限
spec:
containers:
- name: mypod
image: nginx
securityContext:
capabilities:
add:
- NET_ADMIN

2.2 Run As Non-Root

如果允许pod中的容器以进程ID (PID) 0运行,则主机可能受到恶意活动的影响。

1
2
3
4
5
6
7
spec:
# 声明不以Root运行此容器
securityContext:
runAsNonRoot: true
containers:
- name: mypod
image: nginx

3 参考

checks

clusterlint