OpenShiftでコンテナの詳細を調べる
OpenShift Origin(OKD)に、Node.jsアプリケーションをデプロイしていろいろ試すというエントリで「コンテナに引数を設定してみる」でargs
を利用しているところで「ですがまあ、これは不正解な気がします。」と書いていてソース方面を見にいくという方法を取っていますが、それをOpenShift上できちんと裏付け調査する方法について書いておきます。
アプリケーションは以下のサンプルを利用しています。手元の環境ではOCP 3.9を利用していますがokd 3.10でも一緒です。
oc new-app https://github.com/sclorg/nodejs-ex
現在のコンテナで何が実行されるかはコンテナイメージメタデータのEntrypointとCmdを見る必要があります。コンテナイメージメタデータはImageStreamに入っていてImageStreamTagというvirtual objectを通して参照できるようになっています。
$ oc get istag NAME DOCKER REF UPDATED IMAGENAME nodejs-ex:latest docker-registry.default.svc:5000/test-nodejs/nodejs-ex@sha256:7222ec78ef8e9f84a119fece9eeb49053718e4bd7fba6d203c23ea7fe30f99f5 36 minutes ago sha256:7222ec78ef8e9f84a119fece9eeb49053718e4bd7fba6d203c23ea7fe30f99f5 $ oc export istag nodejs-ex:latest apiVersion: v1 generation: 1 image: dockerImageLayers: - (省略) dockerImageMetadata: Config: Cmd: - /usr/libexec/s2i/run Entrypoint: - container-entrypoint Env: (以下省略)
ちなみにistagはvirtual objectであるせいか、oc export istag
やoc get istag -o yaml
というようにオブジェクト名の指定を省略した場合はコンテナメタデータなどの詳細を表示しないという挙動となるようです。上のようにoc export istag nodejs-ex:latest
と指定する必要があります。ちょっとはまりました。
OpenShiftではクライアントサイドにocコマンドさえあれば、dockerなどがインストールされていなくてもこういったコンテナの詳細が調査できるのが便利です。
次にcontainer-entrypoint
と/usr/libexec/s2i/run
は何か、という話になりますが、これはコンテナイメージ内を調査する必要があります。コンテナイメージ内の調査は場合によって以下の3種類のどれかを利用します。
- 既存のPodに
oc rsh
(Entrypint, Cmdが既に実行されている状態の調査)- 例:
oc rsh dc/node-ex
- 例:
- 既存のDeploymentConfigに
oc debug
(Entrypint, Cmd実行前の状態の調査)- 例:
oc debug dc/node-ex
- 例:
oc run
(s2iイメージなどDeploymentConfigなどが存在しないイメージの調査)- 例:
oc run foo --image=docker-registry.default.svc:5000/test-nodejs/nodejs-ex@sha256:7222ec78ef8e9f84a119fece9eeb49053718e4bd7fba6d203c23ea7fe30f99f5 --command -- tail -f /dev/null
- 例:
今回は直接rshで問題ありません。
oc rsh dc/nodejs-ex
コンテナに入ったら必要なファイルなどを調査します。
sh-4.2$ which container-entrypoint /usr/bin/container-entrypoint sh-4.2$ cat $(which container-entrypoint) #!/bin/bash exec "$@" $ cat /usr/libexec/s2i/run #!/bin/bash # S2I run script for the 'nodejs' image. # The run script executes the server that runs your application. # # For more information see the documentation: # https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md # set -e if [ -e "/opt/app-root/etc/generate_container_user" ]; then source /opt/app-root/etc/generate_container_user fi # Runs the nodejs application server. If the container is run in development mode, # hot deploy and debugging are enabled. run_node() { echo -e "Environment: \n\tDEV_MODE=${DEV_MODE}\n\tNODE_ENV=${NODE_ENV}\n\tDEBUG_PORT=${DEBUG_PORT}" if [ "$DEV_MODE" == true ]; then echo "Launching via nodemon..." exec nodemon --inspect="$DEBUG_PORT" else echo "Launching via npm..." exec npm run -d $NPM_RUN fi } #Set the debug port to 5858 by default. if [ -z "$DEBUG_PORT" ]; then export DEBUG_PORT=5858 fi # Set the environment to development by default. if [ -z "$DEV_MODE" ]; then export DEV_MODE=false fi # If NODE_ENV is not set by the user, then NODE_ENV is determined by whether # the container is run in development mode. if [ -z "$NODE_ENV" ]; then if [ "$DEV_MODE" == true ]; then export NODE_ENV=development else export NODE_ENV=production fi fi # If the official dockerhub node image is used, skip the SCL setup below # and just run the nodejs server if [ -d "/usr/src/app" ]; then run_node fi # Allow users to inspect/debug the builder image itself, by using: # $ docker run -i -t openshift/centos-nodejs-builder --debug # [ "$1" == "--debug" ] && exec /bin/bash run_node
起動はNPM_RUN
環境変数を引数にしているようなので、これを調整するのが正解だとわかります。デフォルトの定義を調べます。
$ oc export istag nodejs-ex:latest | grep NPM_RUN - NPM_RUN=start
というわけで、 NPM_RUN='start arg1'
と設定するのがこのイメージのお作法である、で正解です。
s2iに限らず、どのようなイメージでもoc import-image
とoc run
してしまえばImageStreamとDeploymentConfigが出来るのでOpenShift上でイメージの調査ができるようになります。
Kubernetes/OpenShiftのバージョンアップとクラスタをどのように分けるか問題
Kubernetes/OpenShiftのバージョンアップをどのようにするか、およびクラスタをどのように分けるかという問題はk8s関連のmeetupでよく出る話題です。昨日のレッドハット on Cloud Dayでも出たので、現時点での自分が知っている情報や考えを書いておきます。
現時点で自分が一番しっくりくるそれなりな規模の構成はdev, testing, staging, prodの4種類を2クラスタずつ用意、8クラスタの構成です。規模によってはtesting, stagingは一つにしてしまってもいいと思います。
各ステージのクラスタ、たとえばprod1, prod2はBlue-green deploymentのような形で利用します。たとえばprod1はk8s 1.7, prod2は一つ新しいk8s 1.8となっていて、新規のデプロイは全てバージョンの新しいほうであるprod2に行います。各アプリケーションへのトラフィックはLBでprod1, prod2へ振り分けを切り換えられるように構成します。また、アプリケーションがクラスタを移動する際にストレージのPVのデータの移行がストレートにできないので、その部分は何らかの仕組みを用意する必要があります。
移行期間を置いてprod1のアプリが全部prod2へ移行されたあと、prod1のアップグレードを行ったり、もしくはクリーンに作り直して再度利用可能にし(もちろん事前にprod3を作っておいてprod1を破棄でも良い)、新規のデプロイメントはこちらにデプロイするようにします。このような2クラスタに分ける構成では、片方のクラスタで障害があっても、もう片方のクラスタにすぐデプロイできる体制ができているはずなので、バックアップとしても機能します。また、k8sのアップグレードがアプリケーションに影響しない、もしくは常にクリーンインストールを行うことでアップグレードという作業自体をなくすことができる構成になります。ワークロードはクラスタを分けても分けなくても変わらない、デプロイされているアプリの総数は変わらないはずなので、コンピューティングノードのノード数のオーバヘッドはほどんどありません。
逆にdev, test, prodのワークロードをnode selectorで分けて全部ひとつのクラスタにするという構成もあります。リソース共有の効率化、集約度向上、運用負荷が非常に軽くなるなどの利点も多くありますが、いくつか懸念があります。
- masterやetcdのバグで環境がダウンするリスク
- masterやetcdのワークロードはdev, test, prodで共有することになるので、たとえばdevでk8s APIやネットワーク帯域を利用するアプリの負荷テストなどで環境ダウンのリスク
- バージョンアップで動作しなくなる
k8sはソフトウェアなので当然バグはあります。最近のものを挙げるとmaster APIへのLBの数秒のメンテを行ったらノードが全てNodeNotReadyになってPodも全部NotReadyになるというようなクラスタごと使えなくなるようなバグもやはりあります。そのような状況を許容できる、泣かないのであればクラスタを分けないという選択肢もアリだとは思います。
もちろんクラスタを分けて複数クラスタを運用するコストも小さくはないので、どの程度のAvailabilityやResiliencyが必要かによって構成を選択しましょう。
バージョンアップの問題はさまざまです。master/etcdが起動しなくなるものや、Podのvalidationのルールが変わって以前のバージョンでは動いてたものが動かなくなったり、それらを消そうとしても新しいバージョンのvalidationに引っかかって消えないPodやnamespaceができたり、それら消えない中途半端なオブジェクトが残っているとバージョンアップのプロセスがエラーになって進まなかったり、というような感じです。根本的な解決にはetcdのデータを直接修正したり消したりというような、それなりの知識が必要かつ危険度の高いアクションが必要になることがあります。アップグレードの前に少なくともスナップショット取得、バックアップリストアは必ずテストしましょう。
あとはどのk8sを選択すればいいか、どのような運用体制が必要かという話があったのでついでに。
- Non-managed k8s
- OpenShift
- Managed k8s (GKE, AKS, EKS, etc)
- インフラ専任いらない
なぜか小規模なのにオンプレNon-managed k8sを選択してしまって大変、という話をたまに聞きますが、Managed使った方がいいと思います。オンプレk8sは立ち上げのコストが高いので、安易に手を出すと時間が溶けやすいので注意しましょう。
また、Managedを使うにしてもGKE, AKS, EKS, etc.どれを使えばいいのですか、という話もありましたが、既にどれかクラウド環境を使っているような方はManagedなデータベースなど他の機能への連携もありますしとりあえずそのままそちらのサービスを使う、ということが多いのではないかと思います。そのような前提が無いのであれば、どれを利用しても良いんじゃないかと思います。
Container SIG Meet-up 2018 SummerでKubernetesのServiceとかIngressの話をしました
Container SIG Meet-up 2018 SummerでKubernetes Service, Ingress and OpenShift Routerというお題でお話しました。
資料は以下に置いています。
- slide.com: https://redhat.slides.com/tkimura/k8s-service-ingress/?token=cenh3zy-
- PDF: https://drive.google.com/file/d/1ZuJiUY2MppzzTLjHRMF3L93-Emd5Yh5V/view
slide.comはRed Hatのコーポレートアカウントを使っているのですが、設定が変わったようでpublicの設定ができないようになっていて、token付きのexternalのURL共有でなんか微妙な感じに。slide.comはプレゼンテーション用に画像でインポートしたものなので、文字やリンクをクリックしたい場合はPDFを利用してください。
さて、最後にService IPでアクセスしてるとコネクションベースのヘルスチェックがないのでノードダウン時に40秒間くらいアクセスできたりできなかったりするので注意してね、という話をしたのですが、その生ログを一応載せておきます。
以下2 replicaのpodのClusterIPへのアクセスです。末尾kwgjf
とbkz58
の2つのPodが確認できます。
[cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:51 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:51 EDT 2018 hello-sinatra-3-bkz58 [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:53 EDT 2018 hello-sinatra-3-bkz58 [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:54 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:55 EDT 2018 hello-sinatra-3-bkz58 [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:56 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:22:57 EDT 2018 hello-sinatra-3-kwgjf
片方のPodが載っているノードをpoweroff -f
してダウンの状況にします。curlを再開するとハングしたりするのでCtrl-cしたりしないといけなくなったり、curl: (7) Failed connect to 172.30.81.27:8080; No route to host
が返却されたりするのが確認できます。生きているPodへ振り分けられた場合は問題なくレスポンスが返却されています。
$ date; ssh stack86-33 sudo poweroff -f Wed May 23 03:24:06 EDT 2018 Powering off. ^CKilled by signal 2. [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:26 EDT 2018 ^C [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:29 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:30 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:31 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:32 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:33 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:34 EDT 2018 ^C [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:38 EDT 2018 hello-sinatra-3-kwgjf [cloud-user@stack86-32 ~]$ date; curl 172.30.81.27:8080/hostname; echo Wed May 23 03:24:38 EDT 2018 curl: (7) Failed connect to 172.30.81.27:8080; No route to host
クライアント側で地道にタイムアウトとリトライができる場合はそれでいいのですが、既存のソフトウェアを動かしたいようなユースケースでそのあたりの設定ができない場合とか困ります。今のところこれをうまくハンドリングする定石みたいなものはないと思っているのですが、何か良い案があれば教えてください。OpenShiftのhttp/TLSトラフィックでの限定的なワークアラウンドとしては、Route作ってアクセスするとOpenShift RouterのHAProxyを通るのでHAProxyがヘルスチェックつきで接続管理とロードバランスしてくれます。将来的にはIstioとかがデフォルトでいい感じにハンドリングしてくれることを期待しています。
KubernetesのReadWriteOnceなvolume
よく聞かれるトピックでブログに書いてたと思ってたんだけど実は書いてなかったようだ。Amazon EBSとかGCEPersistentDiskとかAzureDiskとかGluster Block Storageとかを利用するReadWriteOnceのvolumeのお話。
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
access modeがReadWriteOnceというvolumeはいわゆるブロックデバイスタイプのvolumeであり、複数のホストから同時に同一のvolumeを利用することはできない(もし実際に複数ホストから同時に書き込まれるとデータが壊れる)。複数のホストから同時に利用できないので、ReplicaSetでスケールさせた場合にpodを複数ホストに分散させることはできない。このためReplicaSetで利用する場合はホスト障害やホストのメンテナンス停止への耐性はなく、ReadWriteOnceを利用するpodは必ず一旦停止してから別ノード上にRecreateされる必要があるためゼロダウンタイムでのpod再デプロイは不可能となる。後述するクラスタ対応ソフトウェアでStatefulSetであればReadWriteOnceを利用しても問題ない。
このようなReadWriteOnceのハンドリングは実際にはvolume pluginで実装されている。podを作成する時の前処理として、Amazon EBSなどのvolume pluginは、volumeをホストにattachする。逆に、podが削除されるときには、volumeをdetachするようになっている。正常な場合の再デプロイでは、コンテナ停止に伴いvolumeをコンテナが動作していたホストからdetach、コンテナ再スケジュール、作成に伴いvolumeをコンテナが動作するホストへattach、という流れで利用される。
https://github.com/kubernetes/kubernetes/tree/master/pkg/volume
volumeがattachされているホストが障害となったときは、volumeがdetach状態にならないまま利用中のステータスで残ることがある。ホスト障害とは言っても、単にネットワークが不通である可能性があるのでホストが実際にダウンしているかどうか判断することはできず、ホストの状態は「Unknown=不定」と考えなければならない。ホスト自体は実際には健康に動作していてvolumeにデータ書き込んでいるかもしれない。このような場合、volumeがdetachされずにpodが別ホストで再スケジュールされるような状況が発生するが、volumeが他ホストにattachされたままになっているのでpod作成時の前処理のvolumeのattachは失敗する。volumeを利用中のホストが本当にダウンしているかどうかもわからないため、強制的にdetachしてattachというわけにもいかない。このようなケースでは大抵マニュアルでの対処が必要となり、現在attachされているホストが停止していることを確認したのち、ブロックストレージの管理インタフェースなどからマニュアルでvolumeをdetachすることで再度そのvolumeが利用可能な状態になり、podの作成処理が進むようになる。volumeがattachされているホストが障害になったときに、自動でホストのダウンを確認してdetachしてくれるようなブロックストレージもあるかもしれないが、基本的にはそのような期待はしないほうがいい。
このように一見ReadWriteOnceはReadWriteManyより制約が多く劣っているように見えるが、劣っているのではなくストレージの性格が異なることを理解する必要がある。ReadWriteOnceのブロックデバイスはfsyncなどを利用するシビアなディスク書き込みを行うようなソフトウェア、いわゆるデータベースやデータストア系のソフトウェアのストレージとして適している。ReadWriteManyをサポートするNFSやGlusterFSのようなネットワークファイルシステムは、そのようなソフトウェアのストレージとして利用すると、一般的に不整合やデータ破損が発生しやすい。また、大抵このようなデータベース系ソフトウェアはReplicaSetでのpodのスケーリング、つまり同一のデータ領域を参照する複数インスタンスの同時起動をサポートしていないため、基本的にReadWriteManyにするユースケースがない。例えばOpenShiftのログ基盤で利用されているElasticSearchは、NFSやGlusterFSだとデータ破損が発生するので、NFSなどのネットワークストレージの利用をサポートしておらず、ReadWriteOnceのブロックデバイスを利用する必要がある。
分散を前提としていてクラスタリングをサポートしているetcd、ElasticSearch、Cassandraなどのソフトウェアでは、ネットワーク経由でのデータ複製や同期機能が備わっているので、PodごとにPVを割り当てることのできるStatefulSetを利用することにより、ReadWriteOnceのストレージを利用していてもスケール可能であり、適切に設定されている限りホスト障害などのときも必要な復旧作業と並行してリクエストに応答できるようになっているはずなのでダウンタイムなしで運用することができる。
OpenShiftにfluentd公式イメージのdaemonsetをデプロイする
OpenShiftにはConfigMapで設定変更できるfluentdが用意されているので、このブログ記事の内容は大抵の人は必要ないはずです。特定の新しいバージョンのfluentdが必須であるとか、あえて別にfluentd公式イメージをデプロイする理由がある人だけ読んでください。
OpenShiftの上でfluentd-docker-imageを動かすにはどうすればいいのか,みたいな質問が稀に来るので誰か記事かいて欲しい
— SKSの申し子 (@repeatedly) 2018年4月19日
https://github.com/fluent/fluentd-kubernetes-daemonset と対応するリファレンスKubernetes Logging with Fluentd、リポジトリ上のfluentd-daemonset-elasticsearch-rbac.yaml見ると、Service account fluentd
で/var/log
をhostPathマウントして読み込むのでrootアクセスが必要、privilegedコンテナにする必要があるようです。privileged sccをfluentdサービスアカウントに追加して、containerのsecurityContext.privilegedをtrueに変更、podを再作成して反映させます。
oc project kube-system oc create -f https://raw.githubusercontent.com/fluent/fluentd-kubernetes-daemonset/master/fluentd-daemonset-elasticsearch-rbac.yaml oc adm policy add-scc-to-user privileged -z fluentd oc patch ds fluentd -p "spec: template: spec: containers: - name: fluentd securityContext: privileged: true" oc delete pod -l k8s-app=fluentd-logging
このprivilegedコンテナにするだけの変更でとりあえず動いているように見えます。対応するElasticSearchを用意して確認まではしてません。
privilegedコンテナでroot権限の設定なので対象イメージが信頼できる場合のみ設定しましょう。
AzureのAKSのkubectl describe nodeを見る
Kubernetesで実際のメモリを超えるコンテナアプリを動かすと、どうなるか? - あさのひとりごとにスケジューリングリソースの解説がされていますが、一番重要なkubectl describe node
の生のデータが掲載されていないのがちょっともったいないかなと思ったので一応貼っておきます。
aksの準備から終了まではこんな感じです。
az login az provider register -n Microsoft.ContainerService az provider register -n Microsoft.Network az provider register -n Microsoft.Compute az provider register -n Microsoft.Storage az group list az group create -n testaks -l eastus az aks get-versions -l eastus az aks create -g testaks -n testaks --node-count 2 --kubernetes-version 1.9.6 az aks install-cli az aks get-credentials -g testaks -n testaks kubectl get node kubectl describe node az aks delete -g testaks -n testaks
kubectl describe node
の結果は以下です。Allocatableのmemoryが3319Mi、node末尾0のAllocated resourcesのMemory Requestsが290Mi、node末尾1が294Miなので、この例では両ノード3000Mi程度アロケーション可能です。この状態でrequests.memoryが1.5Gi==1536Miのpodを複数スケジュールしようとすると恐らく3つめでFailedSchedulingとなると思います。1500Miであれば4 podスケジューリングできます。最初からデプロイされるkube-systemのpod群の配置は不定なので、場合によっては少し偏ってしまい元記事のように3 podスケジューリングできて4 pod目がfailするという状況にもなるでしょう。
Name: aks-nodepool1-16184948-0 Roles: agent Labels: agentpool=nodepool1 beta.kubernetes.io/arch=amd64 beta.kubernetes.io/instance-type=Standard_DS1_v2 beta.kubernetes.io/os=linux failure-domain.beta.kubernetes.io/region=eastus failure-domain.beta.kubernetes.io/zone=0 kubernetes.azure.com/cluster=MC_testaks_testaks_eastus kubernetes.io/hostname=aks-nodepool1-16184948-0 kubernetes.io/role=agent storageprofile=managed storagetier=Premium_LRS Annotations: node.alpha.kubernetes.io/ttl=0 volumes.kubernetes.io/controller-managed-attach-detach=true CreationTimestamp: Fri, 13 Apr 2018 05:10:06 +0000 Taints: <none> Unschedulable: false Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- NetworkUnavailable False Fri, 13 Apr 2018 05:11:13 +0000 Fri, 13 Apr 2018 05:11:13 +0000 RouteCreated RouteController created a route OutOfDisk False Fri, 13 Apr 2018 05:23:02 +0000 Fri, 13 Apr 2018 05:10:06 +0000 KubeletHasSufficientDisk kubelet has sufficient disk space available MemoryPressure False Fri, 13 Apr 2018 05:23:02 +0000 Fri, 13 Apr 2018 05:10:06 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Fri, 13 Apr 2018 05:23:02 +0000 Fri, 13 Apr 2018 05:10:06 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure Ready True Fri, 13 Apr 2018 05:23:02 +0000 Fri, 13 Apr 2018 05:11:08 +0000 KubeletReady kubelet is posting ready status. AppArmor enabled Addresses: InternalIP: 10.240.0.4 Hostname: aks-nodepool1-16184948-0 Capacity: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 1 memory: 3501592Ki pods: 110 Allocatable: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 1 memory: 3399192Ki pods: 110 System Info: Machine ID: 2c3d39f8fac841cb9df23cf4453420a9 System UUID: 707CF566-AC50-D649-9A23-F6A03C86DE52 Boot ID: ec9a15b2-af2e-4f84-92a5-5525d78c20f8 Kernel Version: 4.13.0-1011-azure OS Image: Debian GNU/Linux 9 (stretch) Operating System: linux Architecture: amd64 Container Runtime Version: docker://1.13.1 Kubelet Version: v1.9.6 Kube-Proxy Version: v1.9.6 PodCIDR: 10.244.0.0/24 ExternalID: /subscriptions/31c0faff-6b3e-4b51-86e2-6c9595e05454/resourceGroups/MC_testaks_testaks_eastus/providers/Microsoft.Compute/virtualMachines/aks-nodepool1-16184948-0 ProviderID: azure:///subscriptions/31c0faff-6b3e-4b51-86e2-6c9595e05454/resourceGroups/MC_testaks_testaks_eastus/providers/Microsoft.Compute/virtualMachines/aks-nodepool1-16184948-0 Non-terminated Pods: (6 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits --------- ---- ------------ ---------- --------------- ------------- kube-system kube-dns-v20-7c556f89c5-9grpn 110m (11%) 0 (0%) 120Mi (3%) 220Mi (6%) kube-system kube-dns-v20-7c556f89c5-s8x25 110m (11%) 0 (0%) 120Mi (3%) 220Mi (6%) kube-system kube-proxy-4n2xd 100m (10%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-svc-redirect-qwrtf 0 (0%) 0 (0%) 0 (0%) 0 (0%) kube-system kubernetes-dashboard-546f987686-khjvt 100m (10%) 100m (10%) 50Mi (1%) 50Mi (1%) kube-system tunnelfront-6f9ff58869-jxcfn 0 (0%) 0 (0%) 0 (0%) 0 (0%) Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) CPU Requests CPU Limits Memory Requests Memory Limits ------------ ---------- --------------- ------------- 420m (42%) 100m (10%) 290Mi (8%) 490Mi (14%) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Starting 15m kubelet, aks-nodepool1-16184948-0 Starting kubelet. Normal NodeAllocatableEnforced 15m kubelet, aks-nodepool1-16184948-0 Updated Node Allocatable limit across pods Normal NodeHasNoDiskPressure 14m (x7 over 15m) kubelet, aks-nodepool1-16184948-0 Node aks-nodepool1-16184948-0 status is now: NodeHasNoDiskPressure Normal NodeHasSufficientDisk 13m (x8 over 15m) kubelet, aks-nodepool1-16184948-0 Node aks-nodepool1-16184948-0 status is now: NodeHasSufficientDisk Normal NodeHasSufficientMemory 13m (x8 over 15m) kubelet, aks-nodepool1-16184948-0 Node aks-nodepool1-16184948-0 status is now: NodeHasSufficientMemory Normal Starting 12m kube-proxy, aks-nodepool1-16184948-0 Starting kube-proxy. Name: aks-nodepool1-16184948-1 Roles: agent Labels: agentpool=nodepool1 beta.kubernetes.io/arch=amd64 beta.kubernetes.io/instance-type=Standard_DS1_v2 beta.kubernetes.io/os=linux failure-domain.beta.kubernetes.io/region=eastus failure-domain.beta.kubernetes.io/zone=1 kubernetes.azure.com/cluster=MC_testaks_testaks_eastus kubernetes.io/hostname=aks-nodepool1-16184948-1 kubernetes.io/role=agent storageprofile=managed storagetier=Premium_LRS Annotations: node.alpha.kubernetes.io/ttl=0 volumes.kubernetes.io/controller-managed-attach-detach=true CreationTimestamp: Fri, 13 Apr 2018 05:10:11 +0000 Taints: <none> Unschedulable: false Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- NetworkUnavailable False Fri, 13 Apr 2018 05:11:13 +0000 Fri, 13 Apr 2018 05:11:13 +0000 RouteCreated RouteController created a route OutOfDisk False Fri, 13 Apr 2018 05:23:03 +0000 Fri, 13 Apr 2018 05:10:11 +0000 KubeletHasSufficientDisk kubelet has sufficient disk space available MemoryPressure False Fri, 13 Apr 2018 05:23:03 +0000 Fri, 13 Apr 2018 05:10:11 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available DiskPressure False Fri, 13 Apr 2018 05:23:03 +0000 Fri, 13 Apr 2018 05:10:11 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure Ready True Fri, 13 Apr 2018 05:23:03 +0000 Fri, 13 Apr 2018 05:11:11 +0000 KubeletReady kubelet is posting ready status. AppArmor enabled Addresses: InternalIP: 10.240.0.5 Hostname: aks-nodepool1-16184948-1 Capacity: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 1 memory: 3501592Ki pods: 110 Allocatable: alpha.kubernetes.io/nvidia-gpu: 0 cpu: 1 memory: 3399192Ki pods: 110 System Info: Machine ID: 5b4fb70dfc744759821a92694f9d5993 System UUID: 45C3EA49-8E12-0146-964D-5EFB5A4E3E8A Boot ID: e7160774-de86-4a16-9bd3-9f43af1cdd57 Kernel Version: 4.13.0-1011-azure OS Image: Debian GNU/Linux 9 (stretch) Operating System: linux Architecture: amd64 Container Runtime Version: docker://1.13.1 Kubelet Version: v1.9.6 Kube-Proxy Version: v1.9.6 PodCIDR: 10.244.1.0/24 ExternalID: /subscriptions/31c0faff-6b3e-4b51-86e2-6c9595e05454/resourceGroups/MC_testaks_testaks_eastus/providers/Microsoft.Compute/virtualMachines/aks-nodepool1-16184948-1 ProviderID: azure:///subscriptions/31c0faff-6b3e-4b51-86e2-6c9595e05454/resourceGroups/MC_testaks_testaks_eastus/providers/Microsoft.Compute/virtualMachines/aks-nodepool1-16184948-1 Non-terminated Pods: (3 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits --------- ---- ------------ ---------- --------------- ------------- kube-system heapster-6599f48877-mhr5s 138m (13%) 138m (13%) 294Mi (8%) 294Mi (8%) kube-system kube-proxy-2lv22 100m (10%) 0 (0%) 0 (0%) 0 (0%) kube-system kube-svc-redirect-q54pd 0 (0%) 0 (0%) 0 (0%) 0 (0%) Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) CPU Requests CPU Limits Memory Requests Memory Limits ------------ ---------- --------------- ------------- 238m (23%) 138m (13%) 294Mi (8%) 294Mi (8%) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Starting 15m kubelet, aks-nodepool1-16184948-1 Starting kubelet. Normal NodeAllocatableEnforced 15m kubelet, aks-nodepool1-16184948-1 Updated Node Allocatable limit across pods Normal NodeHasNoDiskPressure 14m (x7 over 15m) kubelet, aks-nodepool1-16184948-1 Node aks-nodepool1-16184948-1 status is now: NodeHasNoDiskPressure Normal NodeHasSufficientDisk 14m (x8 over 15m) kubelet, aks-nodepool1-16184948-1 Node aks-nodepool1-16184948-1 status is now: NodeHasSufficientDisk Normal NodeHasSufficientMemory 14m (x8 over 15m) kubelet, aks-nodepool1-16184948-1 Node aks-nodepool1-16184948-1 status is now: NodeHasSufficientMemory Normal Starting 12m kube-proxy, aks-nodepool1-16184948-1 Starting kube-proxy.
Resource requestとlimitの基本はOpenShiftのResource requestとlimitをどうぞ。
OpenShift CNSでgluster-blockを有効化する
OpenShiftではAnsibleのインベントリにglusterfsグループを定義するとCNSをセットアップしてくれる。
[glusterfs] node[01:03].example.com glusterfs_devices='[ "/dev/sda" ]'
しかしこの記述でセットアップされるのは普通のglusterfsファイルシステムマウントのみで、ブロックデバイスを提供するgluster-blockはprovisionerのみセットアップされるようだ。nodeホストのセットアップは行われないので、別に実行する必要がある。
CNSのドキュメントをみながらセットアップしてみる。
$ ansible nodes -b -a "yum install iscsi-initiator-utils device-mapper-multipath rpcdind -y" $ cat << EOF > multipath.conf device { vendor "LIO-ORG" user_friendly_names "yes" # names like mpatha path_grouping_policy "failover" # one path per group path_selector "round-robin 0" failback immediate path_checker "tur" prio "const" no_path_retry 120 rr_weight "uniform" } EOF $ ansible nodes -b -m copy -a "src=./multipath.conf dest=/etc/multipath.conf" $ ansible nodes -b -a "mpathconf --enable" $ ansible nodes -b -a "systemctl restart multipathd rpcbind" $ ansible nodes -b -a "systemctl enable multipathd rpcbind" $ oc project glusterfs $ oc delete pod --all
きちんと設定できていれば、DaemonSetのglusterfs pod内でgluster-blockdが起動する。oc rsh
してsystemctl status gluster-blockd
を確認すれば良い。
gluster-blockのstorageclassとsecretを定義する。secretはglusterfsで既に設定されているheketi-storage-admin-secretの値をそのまま流用した。
$ oc project glusterfs $ oc export secret heketi-storage-admin-secret > heketi-storage-admin-secret.yaml $ cp -a heketi-storage-admin-secret.yaml gluster-block-secret.yaml $ vi gluster-block-secret.yaml # change name and type $ diff heketi-storage-admin-secret.yaml gluster-block-secret.yaml 7,8c7,8 < name: heketi-storage-admin-secret < type: kubernetes.io/glusterfs --- > name: gluster-block-secret > type: gluster.org/glusterblock $ cat << EOF > gluster-block.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gluster-block parameters: resturl: http://heketi-storage-glusterfs.apps.s.nekop.io restuser: admin restsecretname: gluster-block-secret restsecretnamespace: glusterfs provisioner: gluster.org/glusterblock reclaimPolicy: Delete EOF $ oc create -f gluster-block-secret.yaml $ oc create -f gluster-block.yaml
PVCを作ってPVできればOK。できない場合はglusterfsプロジェクトのglusterblock-storage-provisioner-dc podのログを確認。
oc run sleep --image=registry.access.redhat.com/rhel7 -- tail -f /dev/null oc volume dc/sleep --add -t pvc --name=rwo-block --claim-name=rwo-block --mount-path=/rwo-block --claim-size=1Gi --claim-mode=ReadWriteOnce --claim-class=gluster-block oc get pvc -w