VPS上に作ったkubernetesクラスタをv1.13系からv1.14系にアップグレードする

はじめに

f:id:inajob:20190418200920p:plain

僕はVultrという海外VPSのマシンを2台借りて、すごくチープなKubernetesクラスタを構築しています。下記が少し古いですが、セットアップ方法です。

inajob.hatenablog.jp

 

で、記事にはしていなかったのですが、このクラスタ、アップグレードを重ねてv1.13.2の状態になっていました。

 

今回この記事では、v1.13.2から最新のv1.14.1にバージョンアップした方法を紹介しようと思います。

 

アップグレードの苦労

今までのバージョンでのアップグレードは、実は何度も失敗してきました。失敗というのはKubernetesクラスタを構成するコンポーネントが立ち上がらなくなってしまい、kubeadmによるupgradeができなくなってしまうことです。

そうなるとクラスタを1から作り直していたのですが、そうすると当然クラスタ内にデプロイしていたアプリケーションを再度デプロイしなおす必要があります。クラスタ内で動作しているアプリケーションのmanifestは手元にあるので、それほど苦労することもないのですが、、結構悔しいです。

 

注意:これは我が家のクラスタがmaster 1台という推奨とは違う構成になっているのが主な原因です。masterを3台などでHA構成することで、ローリングアップデートができるようになり、そうすればアップグレードももっと簡単にできます。(激安クラスタの運命ですね。。)

 

ということで、今回は慎重に作業しようと誓いながら作業を始めました。

 宣伝コーナー!!

僕がKubernetesクラスタを動かしているVultrという海外のVPSサービスです。下記リンクから申し込むと$50のクーポンがつくはずです。

前述の記事の方法でセットアップすれば実質無料でおよそ5か月Kubernetesクラスタを運用できます。

よく似たサービスにDigitalOceanがありますが、VultrはTokyoリージョンがあるという点が大きな違いとなっています。

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

www.vultr.com

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

参考

本家にかなり詳しいアップグレードマニュアルがあります。なので詳しい人はこれを見ればアップグレードできるはず・・です。

kubernetes.io

 素直に指示に従ってみる

 まずはmasterのアップグレードです

 # apt-get update
 # apt-mark unhold kubeadm && apt-get update && apt-get install -y kubeadm=1.14.1-00 && apt-mark hold kubeadm
 ...
 The following packages have unmet dependencies:
  kubelet : Depends: kubernetes-cni (= 0.6.0) but 0.7.5-00 is to be installed

あれ?

kubernetes-cniというものをバージョンアップしようとしたが、kubeletが期待しているものと違う。ということらしい。

以前のインストールでkubeletのバージョンはapt-markによって固定しているので、それが原因でしょう。

しかし、ここでkubeletの固定を解除して、一気にkubeadmとkubeletをアップグレードしてはいけません。毎回ここで間違えます。そうするとkubeadmがkubeletの新しい設定を作る前に新しいkubeletが起動してしまい、コンポーネントが正しく起動しなくなってしまうことが過去にありました。

(今回もダメなのかどうかは確かめていないのでわかりませんが・・)

 ひとまずmasterをv1.13.5にアップグレードする

とりあえず、今はv1.13.2ですが、これをいきなりv1.14.1にするのではなくv1.13.5というv1.13系の最新のパッチバージョンに上げたのちに、v1.14.1にする。という作戦でいくことにしました。

 

# apt-mark unhold kubeadm && apt-get update && apt-get install -y kubeadm=1.13.5-00 && apt-mark hold kubeadm
 The following packages have unmet dependencies:
  kubelet : Depends: kubernetes-cni (= 0.6.0) but 0.7.5-00 is to be installed
 E: Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.

 

 え、これもできないのか・・

パッチバージョン間のバージョンアップ方法はドキュメントに明記していないが、このタイミングならkubeadmとkubeletを一気に上げても大丈夫では? と考え

# apt-mark unhold kubeadm kubelet && apt-get update && apt-get install -y kubeadm=1.13.5-00 kubelet=1.13.5-00 && apt-mark hold kubeadm kubelet
 

 を実行。無事 v1.13.5にアップグレードできた。

v1.13.5のkubeadmでクラスタ

# kubeadm upgrade plan
 [preflight] Running pre-flight checks.
 [upgrade] Making sure the cluster is healthy:
 [upgrade/config] Making sure the configuration is correct:
 [upgrade/config] Reading configuration from the cluster...
 [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
 [upgrade] Fetching available versions to upgrade to
 [upgrade/versions] Cluster version: v1.13.2
 [upgrade/versions] kubeadm version: v1.13.5
 I0418 02:03:25.771423   15661 version.go:237] remote version is much newer: v1.14.1; falling back to: stable-1.13
 [upgrade/versions] Latest stable version: v1.13.5
 [upgrade/versions] Latest version in the v1.13 series: v1.13.5
 
 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
 COMPONENT   CURRENT       AVAILABLE
 Kubelet     1 x v1.13.2   v1.13.5
             1 x v1.13.5   v1.13.5
 
 Upgrade to the latest version in the v1.13 series:
 
 COMPONENT            CURRENT   AVAILABLE
 API Server           v1.13.2   v1.13.5
 Controller Manager   v1.13.2   v1.13.5
 Scheduler            v1.13.2   v1.13.5
 Kube Proxy           v1.13.2   v1.13.5
 CoreDNS              1.2.6     1.2.6
 Etcd                 3.2.24    3.2.24
 
 You can now apply the upgrade by executing the following command:
 
         kubeadm upgrade apply v1.13.5
 
 _____________________________________________________________________

できそう!

ということでアップグレード

 # kubeadm upgrade apply v1.13.5 
 
 [upgrade/staticpods] Moved new manifest to "/etc/kubernetes/manifests/kube-apiserver.yaml" and backed up old manifest to "/etc/kubernetes/tmp/kubeadm-backup-manifests-2019-04-18-02-04-52/kube-apiserver.yaml"
 [upgrade/staticpods] Waiting for the kubelet to restart the component
 [upgrade/staticpods] This might take a minute or longer depending on the component/version gap (timeout 5m0s)
 Static pod: kube-apiserver-kubernetes hash: 1b4484ac0b54c491dc5cfe4d158f31c0
 Static pod: kube-apiserver-kubernetes hash: 1b4484ac0b54c491dc5cfe4d158f31c0
 Static pod: kube-apiserver-kubernetes hash: 1b4484ac0b54c491dc5cfe4d158f31c0
 Static pod: kube-apiserver-kubernetes hash: 1b4484ac0b54c491dc5cfe4d158f31c0
 Static pod: kube-apiserver-kubernetes hash: 1b4484ac0b54c491dc5cfe4d158f31c0
 [upgrade/apply] FATAL: couldn't upgrade control plane. kubeadm has tried to recover everything into the earlier state. Errors faced

死んだ!!!

 

kubeletのログを見ると、このログを最後にkube-apiserverが起動していない、nodeのconditionが異常だったのかな?

Apr 18 02:09:59 kubernetes kubelet[15375]: W0418 02:09:59.079140   15375 eviction_manager.go:160] Failed to admit pod kube-apiserver-kubernetes_kube-system(1b4484ac0b54c491dc5cfe4d158f31c0) - node has conditions: [DiskPressure]

あきらめずにkubeletをrestartしてみる

# systemctl restart kubelet

無事kube-apiserverが復活 何だったんだ・・

# docker ps |grep apiserver
 1044739d1d01        177db4b8e93a                        "kube-apiserver --au…"   About a minute ago   Up About a minute                       k8s_kube-apiserver_kube-apiserver-kubernetes_kube-system_1b4484ac0b54c491dc5cfe4d158f31c0_0
 d0b403dc4ec2        k8s.gcr.io/pause:3.1                "/pause"                 About a minute ago   Up About a minute                       k8s_POD_kube-apiserver-kubernetes_kube-system_1b4484ac0b54c491dc5cfe4d158f31c0_0

もう一度アップグレードを実行してみる。

# kubeadm upgrade apply v1.13.5
 ...
 [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.13.5". Enjoy!
 
 [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.

今度はうまくいった!

$ kubectl get nodes
 NAME         STATUS    ROLES     AGE       VERSION
 kubernetes   Ready     master    129d      v1.13.5
 worker01     Ready     <none>    129d      v1.13.2

kubectlでも上がっていることが確認できた。

 

workerをv1.13.5にアップグレードする

workerも上げておく

# apt-mark unhold kubeadm kubelet && apt-get update && apt-get install -y kubeadm=1.13.5-00 kubelet=1.13.5-00 && apt-mark hold kubeadm kubelet

(kubeadmは上げておく必要があったかな?)

$ kubectl get nodes
 NAME         STATUS    ROLES     AGE       VERSION
 kubernetes   Ready     master    129d      v1.13.5
 worker01     Ready     <none>    129d      v1.13.5

 

masterをv1.14.1にアップグレードする

ここからはあっさりとアップグレードできました。

# apt-mark unhold kubeadm && apt-get update && apt-get install -y kubeadm=1.14.1-00 && apt-mark hold kubeadm
 ...
 The following packages will be upgraded:
   kubeadm
 1 upgraded, 0 newly installed, 0 to remove and 6 not upgraded.
 Need to get 8,150 kB of archives.
 After this operation, 3,171 kB of additional disk space will be used.
 Get:1 https://packages.cloud.google.com/apt kubernetes-xenial/main amd64 kubeadm amd64 1.14.1-00 [8,150 kB]
 Fetched 8,150 kB in 0s (9,463 kB/s)
 (Reading database ... 99264 files and directories currently installed.)
 Preparing to unpack .../kubeadm_1.14.1-00_amd64.deb ...
 Unpacking kubeadm (1.14.1-00) over (1.13.5-00) ...
 Setting up kubeadm (1.14.1-00) ...
 kubeadm set on hold.

 

# kubeadm upgrade plan
 ...
 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
 COMPONENT   CURRENT       AVAILABLE
 Kubelet     2 x v1.13.5   v1.14.1
 
 Upgrade to the latest stable version:
 
 COMPONENT            CURRENT   AVAILABLE
 API Server           v1.13.5   v1.14.1
 Controller Manager   v1.13.5   v1.14.1
 Scheduler            v1.13.5   v1.14.1
 Kube Proxy           v1.13.5   v1.14.1
 CoreDNS              1.2.6     1.3.1
 Etcd                 3.2.24    3.3.10
 
 You can now apply the upgrade by executing the following command:
 
         kubeadm upgrade apply v1.14.1
 
 _____________________________________________________________________
 
 $ kubeadm upgrade apply v1.14.1
 ...
 [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.14.1". Enjoy!
 
 [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
 
 $ apt-mark unhold kubelet &&apt-get update && apt-get install -y kubelet=1.14.1-00 kubectl=1.14.1-00 && apt-mark hold kubelet
 ...
 # systemctl restart kubelet

 

$ kubectl get nodes
 NAME         STATUS    ROLES     AGE       VERSION
 kubernetes   Ready     master    129d      v1.14.1
 worker01     Ready     <none>    129d      v1.13.5

workerをv1.14.1にアップグレードする

こちらも簡単。少しマニュアルとは違う指定にしましたが、この辺はお好みで。

# apt-mark unhold kubeadm && apt-get update && apt-get install -y kubeadm=1.14.1-00 && apt-mark hold kubeadm
 // どうせworkerが1つしかないからdrainは意図的に行わない
 
 # kubeadm upgrade node config --kubelet-version v1.14.1
 [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.14" ConfigMap in the kube-system namespace
 [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
 [upgrade] The configuration for this node was successfully updated!
 [upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.
 
 //まちがえてkubeletが上がらないようにholdしておく
 # apt-mark unhold kubelet && apt-get install -y kubelet=1.14.1-00 kubectl=1.14.1-00 && apt-mark hold kubelet
 # systemctl restart kubelet

 

すべてがv1.14.1になりました

$ kubectl get nodes
 NAME         STATUS    ROLES     AGE       VERSION
 kubernetes   Ready     master    129d      v1.14.1
 worker01     Ready     <none>    129d      v1.14.1

 

おまけ:metrics-serverの設定

metrics-serverを入れないとkubectl top node, kubectl top podが動作しません。

ということでこの機会にmetrics-serverも入れることにします。

といっても、下記のmanifestを使うだけです。

github.com

 

我が家の環境の場合は

        command:
          - /metrics-server
          - --kubelet-preferred-address-types=InternalIP
          - --kubelet-insecure-tls

と2つ引数を変更する必要がありました。

 

kubelet-preferred-address-typesはnodeの名前でDNS解決できない環境で設定する必要があります。

kubelet-insecure-tlsは手抜きでやっています。本当はちゃんとした証明書を使うようにすべきです。

 

そして無事にkubectl top nodesが実行できました。

$ kubectl top node
NAME         CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
kubernetes   154m         15%    646Mi           82%
worker01     338m         33%    611Mi           77%