Kubernetes 1.11已经发布一个多月了。我们线上的版本都是按照比官方最新版本低一个版本的节奏。 因此可以开始考虑将团队线上环境的Kubernetes集群从1.9升级到1.10了。 本文记录了在测试环境中的演练过程。

1.准备

当前Kubernetes 1.10的小版本是1.10.6。 在升级之前一定要多读几遍官方的升级须知Kubernetes 1.10 - Action Required Before Upgrading

其中针对我们对Kubernetes的使用情况,有几个需要我们注意的地方:

  • --pod-infra-container-image Pod的pause镜像由3.0升级到了3.1,即k8s.gcr.io/pause-amd64:3.1,这个需要提前准备
  • 通过kubelet的配置文件--config指定的参数和原来kubelet命令行参数的有很多有不同的默认值,在切换到--config时一定要注意这一点
  • kubelet的cadvisor端口被废弃了,它的默认值在Kubernetes 1.12将变成0,在1.13将会被彻底移除

Kubernetes 1.10所需的外部依赖和一些组件的版本:

  • etcd 3.1.12
  • 以下docker版本在Kubernetes 1.10上进行过验证:docker 1.11.2, 1.13.1, 17.03.x (支持的最小docker版本是1.11)
  • CNI 0.6.0和Kubernetes 1.9依赖的版本相同
  • CSI更新到了0.2.0
  • dashboard 1.8.3
  • heapster 1.5.0
  • kube-dns 1.14.8
  • flannel 0.10.0
  • kube-state-metrics 1.3.1

2.使用ansible升级Kubernetes

2.1 master节点

我们的集群有3个master节点,在使用ansible升级master节点(kube-apiserver, kube-scheduler, kube-controller-manager)时,通过修改ansible role的inventory文件,只先升级第一个master节点,当测试没有问题后再升级剩余两个master节点。master节点的升级十分顺利,对ansible role的修改也不大。

2.2 node节点

同样也是先选择一个node节点升级做测试,如果这个节点上有业务Pod正在运行,可以先将这个节点排干(drain),将业务容器转移到其他的node节点上。 测试环境中的升级十分顺利,算上下载二进制文件,半个小时就完成了集群的升级,各个核心组件成功升级到了1.10.6。

注意提前准备--pod-infra-container-imagek8s.gcr.io/pause-amd64:3.1

2.3 Kubelet动态配置

Kubelet动态配置(Dynamic Kubelet Configuration beta)特性,在Kubernetes 1.10进入Beta阶段,可以在Node不下线的情况下改变Kubelet的配置。从Kubernetes 1.11开始kubelet的绝大多数命令行flag参数都被标记为DEPRECATED,而官方推荐我们使用--config指定配置文件,并在配置文件中指定原来这些flag所配置的内容。 因此,我们决定在这次将Kubernetes升级到1.10的过程中为kubelet启用--config指定配置文件,需要在我们的ansible role中加入相关的配置task。

config.yaml:

 1apiVersion: kubelet.config.k8s.io/v1beta1
 2kind: KubeletConfiguration
 3address: {{ k8s_node_address }}
 4authentication:
 5  anonymous:
 6    enabled: true
 7authorization:
 8  mode: AlwaysAllow
 9cgroupDriver: cgroupfs
10cgroupsPerQOS: true
11clusterDNS:
12- 10.96.0.10
13clusterDomain: cluster.local
14containerLogMaxFiles: 5
15containerLogMaxSize: 10Mi
16contentType: application/vnd.kubernetes.protobuf
17cpuCFSQuota: true
18cpuManagerPolicy: none
19cpuManagerReconcilePeriod: 10s
20enableControllerAttachDetach: true
21enableDebuggingHandlers: true
22enforceNodeAllocatable:
23- pods
24eventBurst: 10
25eventRecordQPS: 5
26evictionHard:
27  imagefs.available: 15%
28  memory.available: 100Mi
29  nodefs.available: 10%
30  nodefs.inodesFree: 5%
31evictionPressureTransitionPeriod: 5m0s
32failSwapOn: false
33fileCheckFrequency: 20s
34hairpinMode: promiscuous-bridge
35healthzBindAddress: 127.0.0.1
36healthzPort: 10248
37httpCheckFrequency: 20s
38imageGCHighThresholdPercent: 85
39imageGCLowThresholdPercent: 80
40imageMinimumGCAge: 2m0s
41iptablesDropBit: 15
42iptablesMasqueradeBit: 14
43kubeAPIBurst: 10
44kubeAPIQPS: 5
45makeIPTablesUtilChains: true
46maxOpenFiles: 1000000
47maxPods: 110
48nodeStatusUpdateFrequency: 10s
49oomScoreAdj: -999
50podPidsLimit: -1
51port: 10250
52registryBurst: 10
53registryPullQPS: 5
54resolvConf: /etc/resolv.conf
55rotateCertificates: true
56runtimeRequestTimeout: 2m0s
57serializeImagePulls: true
58staticPodPath: {{ kube_pod_manifest_dir }}
59streamingConnectionIdleTimeout: 4h0m0s
60syncFrequency: 1m0s
61volumeStatsAggPeriod: 1m0s