Using Go Memory and Processor Limits with Kubernetes DownwardAPI

As many know, Go is a designed for performance with an emphasis on memory management and garbage collection. When used within cgroups with Kubernetes and Red Hat OpenShift Go maximizes for the available memory on the node and the available processors. This approach, as noted by Uber’s automaxprocs, a shared system can see slightly degraded performance when allocated CPUs are not limited to the actually available CPUs (e.g., a prescribed limit).

Using environment variables, Go lets a user control Memory limits and processor limits.

GOMEMLIMIT limits the Go heap and all other runtime memory runtime/debug.SetMemoryLimit

GOMAXPROCS limits the number of operating system threads that can execute user-level Go code simultaneously.

There is an opensource go packages to control GOMAXPROCS automatically when used with cgroups called automaxproces.

In OpenShift/Kubernetes, there is a concept of spec.containers[].resources.limits for cpus and memory, as described in the article Resource Management for Pods and Containers.

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: myimage
    resources:
      limits:
        memory: "128Mi"
        cpu: 2

To facilitate sharing these details to a container Kubernetes provides the downwardAPI. The downwardAPI provides the details as an environment variableor a file.

To see how this works in combination:

  1. Create a yaml test.yaml with resources.limits and env.valueFrom.fieldRef.fieldPath set to the GOMEMLIMIT and GOMAXPROCS value you want.
kind: Namespace
apiVersion: v1
metadata:
  name: demo
---
apiVersion: v1
kind: Pod
metadata:
  name: dapi-go-limits
  namespace: demo
spec:
  containers:
    - name: test-container
      image: registry.access.redhat.com/ubi8/pause
      resources:
        limits:
          memory: 128Mi
          cpu: "2"
      command:
        - sh
        - '-c'
      args:
        - >-
          while true; do echo -en '\n'; printenv GOMEMLIMIT; printenv GOMAXPROCS
          sleep 10; done;
      env:
        - name: GOMEMLIMIT
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.memory
        - name: GOMAXPROCS
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.cpu
  restartPolicy: Never
  1. Apply the file to the oc apply -f test.yaml

  2. Check the logs file

$ oc -n demo logs pod/dapi-go-limits
134217728
2
  1. Delete the pod when you are done with the demonstration
$ oc -n demo delete pod/dapi-go-limits
pod "dapi-go-limits" deleted

There is a clear / easy way to control go runtime configuration.

Reference

  • https://kubernetes.io/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/
  • https://stackoverflow.com/questions/17853831/what-is-the-gomaxprocs-default-value
  • https://github.com/uber-go/automaxprocs#performance
  • https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.