<p>I've a golang program which I need to add a new call to the <code>K8S API server</code> status (livez) api to get the health status.</p>
<p><a href="https://kubernetes.io/docs/reference/using-api/health-checks/" rel="nofollow noreferrer">https://kubernetes.io/docs/reference/using-api/health-checks/</a></p>
<p>The program should run on <strong>same cluster</strong> of the api server and need to get the <code>/livez</code> status, I've tried to find this API in client-go lib but didn't find a way to achieve it...</p>
<p><a href="https://github.com/kubernetes/client-go" rel="nofollow noreferrer">https://github.com/kubernetes/client-go</a></p>
<p>Is there a way to do it from Go program which is running on the same cluster that the API server run?</p>

<h2>Update (final answer)</h2>
<h3>Appended</h3>
<p>OP requested I modify my answer to show configs for &quot;fine-tuned&quot; or &quot;specific&quot; service accounts, without using cluster admin..</p>
<p>As far as I can tell, each pod has permissions to read from <code>/healthz</code> by default. For example, the following <code>CronJob</code> works just fine without using a <code>ServiceAccount</code> at all:</p>
<pre class="lang-yaml prettyprint-override"><code># cronjob
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: is-healthz-ok-no-svc
spec:
  schedule: &quot;*/5 * * * *&quot; # at every fifth minute
  jobTemplate:
    spec:
      template:
        spec:
######### serviceAccountName: health-reader-sa
          containers:
            - name: is-healthz-ok-no-svc
              image: oze4/is-healthz-ok:latest
          restartPolicy: OnFailure
</code></pre>
<p><a href="https://i.stack.imgur.com/9uJ2N.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/9uJ2N.png" alt="enter image description here" /></a></p>
<h3>Original</h3>
<p>I went ahead and wrote a proof of concept for this. <a href="https://github.com/oze4/healthz" rel="nofollow noreferrer">You can find the full repo here</a>, but the code is below.</p>
<h3>main.go</h3>
<pre class="lang-golang prettyprint-override"><code>package main

import (
    &quot;os&quot;
    &quot;errors&quot;
    &quot;fmt&quot;

    &quot;k8s.io/client-go/kubernetes&quot;
    &quot;k8s.io/client-go/rest&quot;
)

func main() {
    client, err := newInClusterClient()
    if err != nil {
        panic(err.Error())
    }

    path := &quot;/healthz&quot;
    content, err := client.Discovery().RESTClient().Get().AbsPath(path).DoRaw()
    if err != nil {
        fmt.Printf(&quot;ErrorBadRequst : %s\n&quot;, err.Error())
        os.Exit(1)
    }

    contentStr := string(content)
    if contentStr != &quot;ok&quot; {
        fmt.Printf(&quot;ErrorNotOk : response != 'ok' : %s\n&quot;, contentStr)
        os.Exit(1)
    }

    fmt.Printf(&quot;Success : ok!&quot;)
    os.Exit(0)
}

func newInClusterClient() (*kubernetes.Clientset, error) {
    config, err := rest.InClusterConfig()
    if err != nil {
        return &amp;kubernetes.Clientset{}, errors.New(&quot;Failed loading client config&quot;)
    }
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return &amp;kubernetes.Clientset{}, errors.New(&quot;Failed getting clientset&quot;)
    }
    return clientset, nil
}
</code></pre>
<h3>dockerfile</h3>
<pre><code>FROM golang:latest
RUN mkdir /app
ADD . /app
WORKDIR /app
RUN go build -o main .
CMD [&quot;/app/main&quot;]
</code></pre>
<h3>deploy.yaml</h3>
<p>(as CronJob)</p>
<pre class="lang-yaml prettyprint-override"><code># cronjob
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: is-healthz-ok
spec:
  schedule: &quot;*/5 * * * *&quot; # at every fifth minute
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: is-healthz-ok
          containers:
            - name: is-healthz-ok
              image: oze4/is-healthz-ok:latest
          restartPolicy: OnFailure
---
# service account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: is-healthz-ok
  namespace: default
---
# cluster role binding
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: is-healthz-ok
subjects:
  - kind: ServiceAccount
    name: is-healthz-ok
    namespace: default
roleRef:
  kind: ClusterRole
  ##########################################################################
  # Instead of assigning cluster-admin you can create your own ClusterRole #
  # I used cluster-admin because this is a homelab                         #
  ##########################################################################
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
---
</code></pre>
<h3>Screenshot</h3>
<p>of successful CronJob run</p>
<p><a href="https://i.stack.imgur.com/alaWD.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/alaWD.png" alt="enter image description here" /></a></p>
<hr />
<h2>Update 1</h2>
<p>OP was asking how to deploy &quot;in-cluster-client-config&quot; so I am providing an example deployment (one that I am using)..</p>
<p>You can find the repo <a href="https://github.com/oze4/service.remove-terminating-namespaces" rel="nofollow noreferrer">here</a></p>
<p>Example deployment (I am using a CronJob, but it could be anything):</p>
<h3>cronjob.yaml</h3>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: remove-terminating-namespaces-cronjob
spec:
  schedule: &quot;0 */1 * * *&quot; # at minute 0 of each hour aka once per hour
  #successfulJobsHistoryLimit: 0
  #failedJobsHistoryLimit: 0
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: svc-remove-terminating-namespaces
          containers:
          - name: remove-terminating-namespaces
            image: oze4/service.remove-terminating-namespaces:latest
          restartPolicy: OnFailure
</code></pre>
<h3>rbac.yaml</h3>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: v1
kind: ServiceAccount
metadata:
  name: svc-remove-terminating-namespaces
  namespace: default
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: crb-namespace-reader-writer
subjects:
- kind: ServiceAccount
  name: svc-remove-terminating-namespaces
  namespace: default
roleRef:
  kind: ClusterRole
  ##########################################################################
  # Instead of assigning cluster-admin you can create your own ClusterRole #
  # I used cluster-admin because this is a homelab                         #
  ##########################################################################
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
---
</code></pre>
<hr />
<h2>Original Answer</h2>
<p>It sounds like what you are looking for is the &quot;in-cluster-client-config&quot; from client-go.</p>
<p>It is important to remember that when using an &quot;in-cluster-client-config&quot;, the API calls within your Go code use the service account for &quot;that&quot; pod. Just wanted to make sure you were testing with an account that has permissions to read &quot;/livez&quot;.</p>
<p>I tested the following code and I am able to get &quot;livez&quot; status..</p>
<pre class="lang-golang prettyprint-override"><code>package main

import (
    &quot;errors&quot;
    &quot;flag&quot;
    &quot;fmt&quot;
    &quot;path/filepath&quot;

    &quot;k8s.io/client-go/kubernetes&quot;
    &quot;k8s.io/client-go/tools/clientcmd&quot;
    &quot;k8s.io/client-go/rest&quot;
    &quot;k8s.io/client-go/util/homedir&quot;
)

func main() {
    // I find it easiest to use &quot;out-of-cluster&quot; for tetsing
    // client, err := newOutOfClusterClient()

    client, err := newInClusterClient()
    if err != nil {
        panic(err.Error())
    }

    livez := &quot;/livez&quot;
    content, _ := client.Discovery().RESTClient().Get().AbsPath(livez).DoRaw()

    fmt.Println(string(content))
}

func newInClusterClient() (*kubernetes.Clientset, error) {
    config, err := rest.InClusterConfig()
    if err != nil {
        return &amp;kubernetes.Clientset{}, errors.New(&quot;Failed loading client config&quot;)
    }
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return &amp;kubernetes.Clientset{}, errors.New(&quot;Failed getting clientset&quot;)
    }
    return clientset, nil
}

// I find it easiest to use &quot;out-of-cluster&quot; for tetsing
func newOutOfClusterClient() (*kubernetes.Clientset, error) {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != &quot;&quot; {
        kubeconfig = flag.String(&quot;kubeconfig&quot;, filepath.Join(home, &quot;.kube&quot;, &quot;config&quot;), &quot;(optional) absolute path to the kubeconfig file&quot;)
    } else {
        kubeconfig = flag.String(&quot;kubeconfig&quot;, &quot;&quot;, &quot;absolute path to the kubeconfig file&quot;)
    }
    flag.Parse()

    // use the current context in kubeconfig
    config, err := clientcmd.BuildConfigFromFlags(&quot;&quot;, *kubeconfig)
    if err != nil {
        return nil, err
    }

    // create the clientset
    client, err := kubernetes.NewForConfig(config)
    if err != nil {
        return nil, err
    }

    return client, nil
}
</code></pre>
