godaddy/kubernetes-client

Use within Google Cloud Functions

Open

#262 opened on May 7, 2018

View on GitHub
 (12 comments) (18 reactions) (0 assignees)JavaScript (206 forks)batch import
help wanted

Repository metrics

Stars
 (954 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

I wanted to kick off a job in my GKE cluster from a Google Cloud Function reacting to changes in Cloud Storage. Since there's no .kube/config it wasn't clear to me how to do that with the new fromKubeConfig initialization. I got it working by piecing together a config object from data retrieved by google-auth-library and @google-cloud/container clients. I'll leave it here to both ask if this way makes sense and to serve as an example for others trying to do something similar.

const {auth} = require('google-auth-library');
const container = require('@google-cloud/container');
const job = require('./job.json');
const kube = require('kubernetes-client');

const clusterClient = new container.v1.ClusterManagerClient();
const request = {
  projectId: process.env.GCLOUD_PROJECT,
  zone: 'us-east4-b',
  clusterId: 'cluster-2',
};

function getCluster() {
  return clusterClient.getCluster(request)
    .then(results => {
      return results[0];
    });
}

function getToken() {
  return auth.getClient()
    .then(client => {
      return client.getAccessToken();
    })
    .then(tokenResponse => {
      return tokenResponse.token;
    });
}

// kubeClient is a lazy global used for caching.
// https://cloud.google.com/functions/docs/bestpractices/tips#use_global_variables_to_reuse_objects_in_future_invocations
let kubeClient;

function getKubeClient(cluster, token) {
  kubeClient = new kube.Client({config: kube.config.fromKubeconfig({
    apiVersion: 'v1',
    kind: 'Config',
    preferences: {},
    'current-context': 'a',
    contexts: [
      {
        name: 'a',
        context: {
          cluster: 'a',
          user: 'a'
        }
      }
    ],
    clusters: [
      {
        name: 'a',
        cluster: {
          'certificate-authority-data': cluster.masterAuth.clusterCaCertificate,
          server: `https://${cluster.endpoint}`
        }
      }
    ],
    users: [
      {
        name: 'a',
        user: {
          'auth-provider': {
            config: {
              'access-token': token,
              'cmd-args': 'config config-helper --format=json',
              'cmd-path': '/google/google-cloud-sdk/bin/gcloud',
              'token-key': '{.credential.access_token}'
            },
            name: 'gcp'
          }
        }
      }
    ]
  })});
  return kubeClient.loadSpec();
}

exports.updateJob = (event) => {
  return (kubeClient && Promise.resolve(kubeClient) ||
    Promise.all([getCluster(), getToken()]).then(([cluster, token]) => {
      return getKubeClient(cluster, token);
    }))
    .then(kubeClient => {
      // Strip extension from filename to get job name
      const name = event.data.name.replace(/\.[^/.]+$/, "");
      job.metadata.generateName = `${name}-update-`;
      job.spec.template.spec.volumes[0].configMap.name = name;
      return kubeClient.apis.batch.v1.namespaces('default').jobs.post({body: job});
    })
    .then(res => {
      console.log('Job created:', res.body.metadata.name);
    });
};

Contributor guide