nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

OpenShiftでメモリでオートスケールをしてみる

OpenShift 全部俺 Advent Calendar 2017

まだAlpha機能ですが、CPUではなくメモリ利用量でオートスケールを設定することができます。

https://docs.openshift.org/3.11/dev_guide/pod_autoscaling.html#pod-autoscaling-memory

先に重要な点を書いておきますが、このメモリ利用量とはcgroupsのmemory.usage_in_bytesであり、これはbuff/cacheを含みます。実際には解放できるディスクキャッシュなども使用中としてレポートされ、キャッシュが活用されている限りメモリ利用は常に高い状態をキープし、オートスケールであまり意味もなくPodが増えることになるので、メモリベースのオートスケールは現状あまり使い物にならないと思います。

追記: 上記記述は古いものであり、OpenShift 3.11以降など新しいバージョンはメモリ量としてmemory.usage_in_bytesではなくより一般的な利用量と呼ぶのにふさわしい値であるWorking set (memory.stat.rss + memory.stat.cache - memory.stat.inactive_file) を返却するのでメモリオートスケールも普通に利用できます。

まずはドキュメントの通り以下の設定をmaster-config.yamlへ反映してmasterを再起動します。

apiServerArguments:
  runtime-config:
  - apis/autoscaling/v2alpha1=true

いつものRubyのサンプルを作成してrequests.memoryに64Miを指定します。

$ oc new-project test-memhpa
$ oc new-app https://github.com/nekop/hello-sinatra
$ oc set resources dc/hello-sinatra --requests=memory=64Mi
$ cat <<EOF | oc create -f -
apiVersion: autoscaling/v2alpha1
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-memory 
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: DeploymentConfig
    name: hello-sinatra
  minReplicas: 1 
  maxReplicas: 10 
  metrics:
  - type: Resource
    resource:
      name: memory
      targetAverageUtilization: 50 
EOF

作成したHPAを再度取得するとAlpha機能であるため内容のほとんどは以下のようにアノテーション内に格納されていることがわかります。

$ oc get hpa hpa-memory -o yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  annotations:
    autoscaling.alpha.kubernetes.io/conditions: '[{"type":"AbleToScale","status":"True","lastTransitionTime":"2017-12-25T02:36:07Z","reason":"ReadyForNewScale","message":"the
      last scale time was sufficiently old as to warrant a new scale"},{"type":"ScalingActive","status":"True","lastTransitionTime":"2017-12-25T02:36:07Z","reason":"ValidMetricFound","message":"the
      HPA was able to succesfully calculate a replica count from memory resource utilization
      (percentage of request)"},{"type":"ScalingLimited","status":"False","lastTransitionTime":"2017-12-25T02:36:07Z","reason":"DesiredWithinRange","message":"the
      desired replica count is within the acceptible range"}]'
    autoscaling.alpha.kubernetes.io/current-metrics: '[{"type":"Resource","resource":{"name":"memory","currentAverageUtilization":24,"currentAverageValue":"16576512"}}]'
    autoscaling.alpha.kubernetes.io/metrics: '[{"type":"Resource","resource":{"name":"memory","targetAverageUtilization":50}}]'
  creationTimestamp: 2017-12-25T02:35:37Z
  name: hpa-memory
  namespace: test-memhpa
  resourceVersion: "4241124"
  selfLink: /apis/autoscaling/v1/namespaces/test-memhpa/horizontalpodautoscalers/hpa-memory
  uid: 4a2e8f4e-e91c-11e7-b3cf-001a4a40dc83
spec:
  maxReplicas: 10
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: DeploymentConfig
    name: hello-sinatra
status:
  currentReplicas: 1
  desiredReplicas: 1

初期状態はメモリ16Mi利用しています。

$ oc adm top pod
NAME                    CPU(cores)   MEMORY(bytes)   
hello-sinatra-2-d9ft8   0m           16Mi

32MBのファイルを作ってcatしてディスクキャッシュに載せてみます。

$ oc rsh dc/hello-sinatra sh -c "dd if=/dev/zero of=/tmp/32mb bs=32M count=1; cat /tmp/32mb"

少し経過すると、メトリクスに反映されました。

$ oc adm top pod
NAME                    CPU(cores)   MEMORY(bytes)   
hello-sinatra-2-d9ft8   5m           48Mi            

HPAによるスケールアウトがトリガーされ、Podが2つに増えました。

$ oc get pod
NAME                    READY     STATUS    RESTARTS   AGE
hello-sinatra-2-b9hxt   1/1       Running   0          16s
hello-sinatra-2-d9ft8   1/1       Running   0          5m
$ oc adm top pod
NAME                    CPU(cores)   MEMORY(bytes)   
hello-sinatra-2-d9ft8   0m           48Mi            
hello-sinatra-2-b9hxt   0m           15Mi   

動作に必要なメモリが足りなくなりそうな場合にスケールアウト、というのが欲しいところですが、今のところはこのように動作に不可欠ではない解放されるメモリもカウントされてオートスケールされてしまいますので、使い道はかなり限定されそうです。