mirror of https://github.com/kubeflow/examples.git
Add end2end test for Xgboost housing example (#493)
* Add e2e test for xgboost housing example * fix typo add ks apply add [ modify example to trigger tests add prediction test add xgboost ks param rename the job name without _ use - instead of _ libson params rm redudent component rename component in prow config add ames-hoursing-env use - for all names use _ for params names use xgboost_ames_accross rename component name shorten the name change deploy-test command change to xgboost- namespace init ks app fix type add confest.py change path change deploy command change dep change the query URL for seldon add ks_app with seldon lib update ks_app use ks init only rerun change to kf-v0-4-n00 cluster add ks_app use ks-13 remove --namespace use kubeflow as namespace delete seldon deployment simplify ks_app retry on 503 fix typo query 1285 move deletion after prediction wait 10s always retry till 10 mins move check to retry fix pylint move clean-up to the delete template * set up xgboost component * check in ks component& run it directly * change comments * add comment on why use 'ks delete' * add two modules to pylint whitelist * ignore tf_operator/py * disable pylint per line * reorder import
This commit is contained in:
parent
329c53cea5
commit
74378a2990
|
|
@ -28,8 +28,8 @@ import logging
|
|||
import os
|
||||
|
||||
from kubernetes import client as k8s_client
|
||||
from py import tf_job_client
|
||||
from py import test_runner
|
||||
from py import tf_job_client #pylint: disable=no-name-in-module
|
||||
from py import test_runner #pylint: disable=no-name-in-module
|
||||
|
||||
from kubeflow.testing import ks_util
|
||||
from kubeflow.testing import test_util
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import logging
|
|||
import os
|
||||
|
||||
from kubernetes import client as k8s_client
|
||||
from py import test_runner
|
||||
from py import test_runner #pylint: disable=no-name-in-module
|
||||
|
||||
from kubeflow.testing import ks_util
|
||||
from kubeflow.testing import test_util
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import logging
|
|||
import os
|
||||
|
||||
from kubernetes import client as k8s_client
|
||||
from py import tf_job_client
|
||||
from py import test_runner
|
||||
from py import tf_job_client #pylint: disable=no-name-in-module
|
||||
from py import test_runner #pylint: disable=no-name-in-module
|
||||
|
||||
from kubeflow.testing import ks_util
|
||||
from kubeflow.testing import test_util
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ Manually running the test
|
|||
|
||||
import os
|
||||
|
||||
import mnist_client
|
||||
from py import test_runner #pylint: disable=no-name-in-module
|
||||
|
||||
from py import test_runner
|
||||
import mnist_client
|
||||
|
||||
from kubeflow.testing import test_util
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ workflows:
|
|||
name: examples-e2e
|
||||
job_types:
|
||||
- presubmit
|
||||
|
||||
|
||||
# E2E test for code_search example
|
||||
- app_dir: kubeflow/examples/test/workflows
|
||||
component: code_search
|
||||
|
|
@ -16,7 +16,7 @@ workflows:
|
|||
- postsubmit
|
||||
include_dirs:
|
||||
- code_search/*
|
||||
|
||||
|
||||
# E2E test for mnist example
|
||||
- app_dir: kubeflow/examples/test/workflows
|
||||
component: mnist
|
||||
|
|
@ -38,6 +38,19 @@ workflows:
|
|||
- postsubmit
|
||||
include_dirs:
|
||||
- github_issue_summarization/*
|
||||
|
||||
# E2E test for xgboost housing example
|
||||
- app_dir: kubeflow/examples/test/workflows
|
||||
component: xgboost_ames_housing
|
||||
name: xgboost
|
||||
job_types:
|
||||
- periodic
|
||||
- presubmit
|
||||
- postsubmit
|
||||
include_dirs:
|
||||
- xgboost_ames_housing/*
|
||||
|
||||
|
||||
# Image Auto Release workflows.
|
||||
# The workflows below are related to auto building our Docker images.
|
||||
# We have separate pre/postsubmit jobs because we want to use different
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@
|
|||
namespace: "kubeflow-test-infra",
|
||||
prow_env: "BUILD_NUMBER=997a,BUILD_ID=997a,JOB_NAME=kubeflow-examples-presubmit-test,JOB_TYPE=presubmit,PULL_NUMBER=374,REPO_NAME=examples,REPO_OWNER=kubeflow",
|
||||
},
|
||||
xgboost_ames_housing: {
|
||||
bucket: "kubeflow-ci_temp",
|
||||
name: "kubeflow-xgboost-ames-housing",
|
||||
namespace: "kubeflow-test-infra",
|
||||
prow_env: "BUILD_NUMBER=997a,BUILD_ID=997a,JOB_NAME=kubeflow-examples-presubmit-test,JOB_TYPE=presubmit,PULL_NUMBER=374,REPO_NAME=examples,REPO_OWNER=kubeflow",
|
||||
},
|
||||
workflows: {
|
||||
bucket: "kubeflow-ci_temp",
|
||||
name: "kubeflow-examples-presubmit-test-374-6e32",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,514 @@
|
|||
// Test workflow for XGBoost Housing example.
|
||||
//
|
||||
local env = std.extVar("__ksonnet/environments");
|
||||
local overrides = std.extVar("__ksonnet/params").components.xgboost_ames_housing;
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
local util = import "util.libsonnet";
|
||||
|
||||
// Define default params and then combine them with any overrides
|
||||
local defaultParams = {
|
||||
// local nfsVolumeClaim: "kubeflow-testing",
|
||||
nfsVolumeClaim: "nfs-external",
|
||||
|
||||
// The name to use for the volume to use to contain test data.
|
||||
dataVolume: "kubeflow-test-volume",
|
||||
|
||||
// Default step image:
|
||||
stepImage: "gcr.io/kubeflow-ci/test-worker/test-worker:v20190116-b7abb8d-e3b0c4",
|
||||
|
||||
// Which Kubeflow cluster to use for running TFJobs on.
|
||||
kfProject: "kubeflow-ci",
|
||||
kfZone: "us-east1-d",
|
||||
kfCluster: "kf-v0-4-n00",
|
||||
|
||||
// The bucket where the model should be written
|
||||
// This needs to be writable by the GCP service account in the Kubeflow cluster (not the test cluster)
|
||||
modelBucket: "kubeflow-ci_temp",
|
||||
|
||||
// Whether to delete the namespace at the end.
|
||||
// Leaving the namespace around can be useful for debugging.
|
||||
//
|
||||
// TODO(jlewi): We should consider running a cronjob to GC namespaces.
|
||||
// But if we leave namespaces up; then we end up leaving the servers up which
|
||||
// uses up CPU.
|
||||
//
|
||||
deleteNamespace: true,
|
||||
};
|
||||
|
||||
local params = defaultParams + overrides;
|
||||
|
||||
local prowEnv = util.parseEnv(params.prow_env);
|
||||
|
||||
// Create a dictionary of the different prow variables so we can refer to them in the workflow.
|
||||
//
|
||||
// Important: We want to initialize all variables we reference to some value. If we don't
|
||||
// and we reference a variable which doesn't get set then we get very hard to debug failure messages.
|
||||
// In particular, we've seen problems where if we add a new environment and evaluate one component eg. "workflows"
|
||||
// and another component e.g "code_search.jsonnet" doesn't have a default value for BUILD_ID then ksonnet
|
||||
// fails because BUILD_ID is undefined.
|
||||
local prowDict = {
|
||||
BUILD_ID: "notset",
|
||||
BUILD_NUMBER: "notset",
|
||||
REPO_OWNER: "notset",
|
||||
REPO_NAME: "notset",
|
||||
JOB_NAME: "notset",
|
||||
JOB_TYPE: "notset",
|
||||
PULL_NUMBER: "notset",
|
||||
} + util.listOfDictToMap(prowEnv);
|
||||
|
||||
local bucket = params.bucket;
|
||||
|
||||
// mountPath is the directory where the volume to store the test data
|
||||
// should be mounted.
|
||||
local mountPath = "/mnt/" + "test-data-volume";
|
||||
// testDir is the root directory for all data for a particular test run.
|
||||
local testDir = mountPath + "/" + params.name;
|
||||
// outputDir is the directory to sync to GCS to contain the output for this job.
|
||||
local outputDir = testDir + "/output";
|
||||
local artifactsDir = outputDir + "/artifacts";
|
||||
|
||||
// Source directory where all repos should be checked out
|
||||
local srcRootDir = testDir + "/src";
|
||||
|
||||
// The directory containing the kubeflow/kubeflow repo
|
||||
local srcDir = srcRootDir + "/" + prowDict.REPO_OWNER + "/" + prowDict.REPO_NAME;
|
||||
|
||||
// These variables control where the docker images get pushed and what
|
||||
// tag to use
|
||||
local imageBase = "gcr.io/kubeflow-ci/xgboost_ames_housing";
|
||||
local imageTag = "build-" + prowDict["BUILD_ID"];
|
||||
local trainerImage = imageBase + "/model:" + imageTag;
|
||||
|
||||
// Directory where model should be stored.
|
||||
local modelDir = "gs://" + params.modelBucket + "/xgboost_ames_housing/models/" + prowDict["BUILD_ID"];
|
||||
|
||||
// value of KUBECONFIG environment variable. This should be a full path.
|
||||
local kubeConfig = testDir + "/.kube/kubeconfig";
|
||||
|
||||
// Namespace where tests should run
|
||||
local testNamespace = "xgboost-ames-housing-" + prowDict["BUILD_ID"];
|
||||
|
||||
// The directory within the kubeflow_testing submodule containing
|
||||
// py scripts to use.
|
||||
local kubeflowTestingPy = srcRootDir + "/kubeflow/testing/py";
|
||||
local tfOperatorPy = srcRootDir + "/kubeflow/tf-operator";
|
||||
|
||||
// Workflow template is the name of the workflow template; typically the name of the ks component.
|
||||
// This is used as a label to make it easy to identify all Argo workflows created from a given
|
||||
// template.
|
||||
local workflow_template = "xgboost_ames_housing";
|
||||
|
||||
// Build template is a template for constructing Argo step templates.
|
||||
//
|
||||
// step_name: Name for the template
|
||||
// command: List to pass as the container command.
|
||||
//
|
||||
// We customize the defaults for each step in the workflow by modifying
|
||||
// buildTemplate.argoTemplate
|
||||
local buildTemplate = {
|
||||
// name & command variables should be overwritten for every test.
|
||||
// Other variables can be changed per step as needed.
|
||||
// They are hidden because they shouldn't be included in the Argo template
|
||||
name: "",
|
||||
command:: "",
|
||||
image: params.stepImage,
|
||||
workingDir:: null,
|
||||
env_vars:: [],
|
||||
side_cars: [],
|
||||
pythonPath: kubeflowTestingPy,
|
||||
|
||||
activeDeadlineSeconds: 1800, // Set 30 minute timeout for each template
|
||||
|
||||
local template = self,
|
||||
|
||||
// Actual template for Argo
|
||||
argoTemplate: {
|
||||
name: template.name,
|
||||
metadata: {
|
||||
labels: prowDict + {
|
||||
workflow: params.name,
|
||||
workflow_template: workflow_template,
|
||||
step_name: template.name,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
command: template.command,
|
||||
name: template.name,
|
||||
image: template.image,
|
||||
workingDir: template.workingDir,
|
||||
env: [
|
||||
{
|
||||
// Add the source directories to the python path.
|
||||
name: "PYTHONPATH",
|
||||
value: template.pythonPath,
|
||||
},
|
||||
{
|
||||
name: "GOOGLE_APPLICATION_CREDENTIALS",
|
||||
value: "/secret/gcp-credentials/key.json",
|
||||
},
|
||||
{
|
||||
name: "GITHUB_TOKEN",
|
||||
valueFrom: {
|
||||
secretKeyRef: {
|
||||
name: "github-token",
|
||||
key: "github_token",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// We use a directory in our NFS share to store our kube config.
|
||||
// This way we can configure it on a single step and reuse it on subsequent steps.
|
||||
name: "KUBECONFIG",
|
||||
value: kubeConfig,
|
||||
},
|
||||
] + prowEnv + template.env_vars,
|
||||
volumeMounts: [
|
||||
{
|
||||
name: params.dataVolume,
|
||||
mountPath: mountPath,
|
||||
},
|
||||
{
|
||||
name: "github-token",
|
||||
mountPath: "/secret/github-token",
|
||||
},
|
||||
{
|
||||
name: "gcp-credentials",
|
||||
mountPath: "/secret/gcp-credentials",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}; // buildTemplate
|
||||
|
||||
|
||||
// Create a list of dictionary.
|
||||
// Each item is a dictionary describing one step in the graph.
|
||||
local dagTemplates = [
|
||||
{
|
||||
template: buildTemplate {
|
||||
name: "checkout",
|
||||
command:
|
||||
["/usr/local/bin/checkout.sh", srcRootDir],
|
||||
|
||||
env_vars: [{
|
||||
name: "EXTRA_REPOS",
|
||||
// TODO(jlewi): Pin to commit on master when #281 is checked in.
|
||||
value: "kubeflow/testing@HEAD:281;kubeflow/tf-operator@HEAD",
|
||||
}],
|
||||
},
|
||||
dependencies: null,
|
||||
}, // checkout
|
||||
{
|
||||
// TODO(https://github.com/kubeflow/testing/issues/257): Create-pr-symlink
|
||||
// should be done by run_e2e_workflow.py
|
||||
template: buildTemplate {
|
||||
name: "create-pr-symlink",
|
||||
command: [
|
||||
"python",
|
||||
"-m",
|
||||
"kubeflow.testing.prow_artifacts",
|
||||
"--artifacts_dir=" + outputDir,
|
||||
"create_pr_symlink",
|
||||
"--bucket=" + params.bucket,
|
||||
],
|
||||
}, // create-pr-symlink
|
||||
dependencies: ["checkout"],
|
||||
}, // create-pr-symlink
|
||||
{
|
||||
// Submit a GCB job to build the images
|
||||
template: buildTemplate {
|
||||
name: "build-images",
|
||||
command: util.buildCommand([
|
||||
[
|
||||
"gcloud",
|
||||
"auth",
|
||||
"activate-service-account",
|
||||
"--key-file=${GOOGLE_APPLICATION_CREDENTIALS}",
|
||||
],
|
||||
[
|
||||
"make",
|
||||
"build-seldon-image",
|
||||
"IMG=" + imageBase,
|
||||
"TAG=" + imageTag,
|
||||
"SOURCE=" + "../seldon_serve"
|
||||
]]
|
||||
),
|
||||
workingDir: srcDir + "/xgboost_ames_housing/test",
|
||||
},
|
||||
dependencies: ["checkout"],
|
||||
}, // build-images
|
||||
{
|
||||
// Configure KUBECONFIG
|
||||
template: buildTemplate {
|
||||
name: "get-kubeconfig",
|
||||
command: util.buildCommand([
|
||||
[
|
||||
"gcloud",
|
||||
"auth",
|
||||
"activate-service-account",
|
||||
"--key-file=${GOOGLE_APPLICATION_CREDENTIALS}",
|
||||
],
|
||||
[
|
||||
"gcloud",
|
||||
"--project=" + params.kfProject,
|
||||
"container",
|
||||
"clusters",
|
||||
"get-credentials",
|
||||
"--zone=" + params.kfZone,
|
||||
params.kfCluster,
|
||||
]]
|
||||
),
|
||||
},
|
||||
dependencies: ["checkout"],
|
||||
}, // get-kubeconfig
|
||||
{
|
||||
// Create the namespace
|
||||
// TODO(jlewi): We should add some sort of retry.
|
||||
template: buildTemplate {
|
||||
name: "create-namespace",
|
||||
command: util.buildCommand([
|
||||
[
|
||||
"echo",
|
||||
"KUBECONFIG=",
|
||||
"${KUBECONFIG}",
|
||||
],
|
||||
[
|
||||
"gcloud",
|
||||
"auth",
|
||||
"activate-service-account",
|
||||
"--key-file=${GOOGLE_APPLICATION_CREDENTIALS}",
|
||||
],
|
||||
[
|
||||
"kubectl",
|
||||
"config" ,
|
||||
"current-context",
|
||||
],
|
||||
[
|
||||
"kubectl",
|
||||
"create",
|
||||
"namespace",
|
||||
testNamespace,
|
||||
],
|
||||
# Copy the GCP secret from the kubeflow namespace to the test namespace
|
||||
[
|
||||
srcDir + "/test/copy_secret.sh",
|
||||
"kubeflow",
|
||||
testNamespace,
|
||||
"user-gcp-sa",
|
||||
]]
|
||||
),
|
||||
},
|
||||
dependencies: ["get-kubeconfig"],
|
||||
}, // create-namespace
|
||||
{
|
||||
template: buildTemplate {
|
||||
name: "deploy-seldon",
|
||||
command: util.buildCommand([[
|
||||
"ks-13",
|
||||
"param",
|
||||
"set",
|
||||
"xgboost",
|
||||
"name",
|
||||
"xgboost-ames-" + prowDict["BUILD_ID"],
|
||||
"--env=default",
|
||||
],
|
||||
[
|
||||
"ks-13",
|
||||
"param",
|
||||
"set",
|
||||
"xgboost",
|
||||
"image",
|
||||
imageBase + ":" + imageTag,
|
||||
"--env=default"
|
||||
],
|
||||
[
|
||||
"ks-13",
|
||||
"apply",
|
||||
"default",
|
||||
"-c",
|
||||
"xgboost",
|
||||
]]),
|
||||
workingDir: srcDir + "/xgboost_ames_housing/ks_app",
|
||||
},
|
||||
dependencies: ["build-images"],
|
||||
}, // deploy-seldon
|
||||
{
|
||||
template: buildTemplate {
|
||||
name: "predict-test",
|
||||
command: [
|
||||
"pytest",
|
||||
"predict_test.py",
|
||||
"-s",
|
||||
// Test timeout in seconds.
|
||||
"--timeout=500",
|
||||
"--junitxml=" + artifactsDir + "/junit_predict-test.xml",
|
||||
"--namespace=kubeflow",
|
||||
"--service=xgboost-ames-" + prowDict["BUILD_ID"],
|
||||
],
|
||||
workingDir: srcDir + "/xgboost_ames_housing/test",
|
||||
},
|
||||
dependencies: ["deploy-seldon"],
|
||||
}, // predict-test
|
||||
];
|
||||
|
||||
// Dag defines the tasks in the graph
|
||||
local dag = {
|
||||
name: "e2e",
|
||||
// Construct tasks from the templates
|
||||
// we will give the steps the same name as the template
|
||||
dag: {
|
||||
tasks: util.toArgoTaskList(dagTemplates),
|
||||
},
|
||||
}; // dag
|
||||
|
||||
// Define templates for the steps to be performed when the
|
||||
// test exits
|
||||
|
||||
local deleteTemplates = if params.deleteNamespace then
|
||||
[
|
||||
{
|
||||
// Delete the namespace
|
||||
// TODO(jlewi): We should add some sort of retry.
|
||||
template: buildTemplate {
|
||||
name: "delete-namespace",
|
||||
command: util.buildCommand([
|
||||
[
|
||||
"gcloud",
|
||||
"auth",
|
||||
"activate-service-account",
|
||||
"--key-file=${GOOGLE_APPLICATION_CREDENTIALS}",
|
||||
],
|
||||
[
|
||||
"kubectl",
|
||||
"delete",
|
||||
"namespace",
|
||||
testNamespace,
|
||||
]]
|
||||
),
|
||||
},
|
||||
}, // delete-namespace
|
||||
] else [];
|
||||
|
||||
local exitTemplates =
|
||||
deleteTemplates +
|
||||
[
|
||||
{
|
||||
// Copy artifacts to GCS for gubernator.
|
||||
// TODO(https://github.com/kubeflow/testing/issues/257): Create-pr-symlink
|
||||
// should be done by run_e2e_workflow.py
|
||||
template: buildTemplate {
|
||||
name: "copy-artifacts",
|
||||
command: [
|
||||
"python",
|
||||
"-m",
|
||||
"kubeflow.testing.prow_artifacts",
|
||||
"--artifacts_dir=" + outputDir,
|
||||
"copy_artifacts",
|
||||
"--bucket=" + bucket,
|
||||
],
|
||||
}, // copy-artifacts,
|
||||
},
|
||||
{
|
||||
// Delete the seldon deployment
|
||||
// TODO(zhenghuiwang): Seldon doesn't deploy seldon deployments into a different
|
||||
// namespace (https://github.com/kubeflow/kubeflow/issues/1712). After this
|
||||
// issue is fixed, we don't need to use `ks delete`.
|
||||
template: buildTemplate {
|
||||
name: "delete-seldon-deployment",
|
||||
command: [
|
||||
"ks-13",
|
||||
"delete",
|
||||
"default",
|
||||
"-c",
|
||||
"xgboost",
|
||||
],
|
||||
workingDir: srcDir + "/xgboost_ames_housing/ks_app",
|
||||
},
|
||||
}, // delete-seldon-deployment
|
||||
{
|
||||
// Delete the test directory in NFS.
|
||||
// TODO(https://github.com/kubeflow/testing/issues/256): Use an external process to do this.
|
||||
template:
|
||||
buildTemplate {
|
||||
name: "test-dir-delete",
|
||||
command: [
|
||||
"rm",
|
||||
"-rf",
|
||||
testDir,
|
||||
],
|
||||
|
||||
argoTemplate+: {
|
||||
retryStrategy: {
|
||||
limit: 3,
|
||||
},
|
||||
},
|
||||
}, // test-dir-delete
|
||||
dependencies: ["copy-artifacts"] + if params.deleteNamespace then ["delete-namespace"] else [],
|
||||
},
|
||||
];
|
||||
|
||||
// Create a DAG representing the set of steps to execute on exit
|
||||
local exitDag = {
|
||||
name: "exit-handler",
|
||||
// Construct tasks from the templates
|
||||
// we will give the steps the same name as the template
|
||||
dag: {
|
||||
tasks: util.toArgoTaskList(exitTemplates),
|
||||
},
|
||||
};
|
||||
|
||||
// A list of templates for the actual steps
|
||||
local stepTemplates = std.map(function(i) i.template.argoTemplate
|
||||
, dagTemplates) +
|
||||
std.map(function(i) i.template.argoTemplate
|
||||
, exitTemplates);
|
||||
|
||||
// Define the Argo Workflow.
|
||||
local workflow = {
|
||||
apiVersion: "argoproj.io/v1alpha1",
|
||||
kind: "Workflow",
|
||||
metadata: {
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
labels: prowDict + {
|
||||
workflow: params.name,
|
||||
workflow_template: workflow_template,
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
entrypoint: "e2e",
|
||||
// Have argo garbage collect old workflows otherwise we overload the API server.
|
||||
ttlSecondsAfterFinished: 7 * 24 * 60 * 60,
|
||||
volumes: [
|
||||
{
|
||||
name: "github-token",
|
||||
secret: {
|
||||
secretName: "github-token",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "gcp-credentials",
|
||||
secret: {
|
||||
secretName: "kubeflow-testing-credentials",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: params.dataVolume,
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.nfsVolumeClaim,
|
||||
},
|
||||
},
|
||||
], // volumes
|
||||
|
||||
// onExit specifies the template that should always run when the workflow completes.
|
||||
onExit: "exit-handler",
|
||||
|
||||
// The templates will be a combination of the templates
|
||||
// defining the dags executed by Argo as well as the templates
|
||||
// for the individual steps.
|
||||
templates: [dag, exitDag] + stepTemplates, // templates
|
||||
}, // spec
|
||||
}; // workflow
|
||||
|
||||
std.prune(k.core.v1.list.new([workflow]))
|
||||
|
|
@ -17,6 +17,11 @@ local envParams = params + {
|
|||
name: 'jlewi-mnist-test-479-0118-110631',
|
||||
prow_env: 'JOB_NAME=mnist-test,JOB_TYPE=presubmit,REPO_NAME=examples,REPO_OWNER=kubeflow,BUILD_NUMBER=0118-110631,BUILD_ID=0118-110631,PULL_NUMBER=479',
|
||||
},
|
||||
xgboost_ames_housing+: {
|
||||
namespace: 'kubeflow-test-infra',
|
||||
name: 'xgboost-ames-housing-test-479-0118-110631',
|
||||
prow_env: 'JOB_NAME=mnist-test,JOB_TYPE=presubmit,REPO_NAME=examples,REPO_OWNER=kubeflow,BUILD_NUMBER=0118-110631,BUILD_ID=0118-110631,PULL_NUMBER=489',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -25,4 +30,4 @@ local envParams = params + {
|
|||
[x]: envParams.components[x] + globals
|
||||
for x in std.objectFields(envParams.components)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
/lib
|
||||
/.ksonnet/registries
|
||||
/app.override.yaml
|
||||
/.ks_environment
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: 0.2.0
|
||||
environments:
|
||||
default:
|
||||
destination:
|
||||
namespace: kubeflow
|
||||
server: https://35.237.212.62
|
||||
k8sVersion: v1.11.5
|
||||
path: default
|
||||
kind: ksonnet.io/app
|
||||
libraries:
|
||||
seldon:
|
||||
name: seldon
|
||||
registry: kubeflow
|
||||
version: ""
|
||||
name: ks_app
|
||||
registries:
|
||||
kubeflow:
|
||||
protocol: fs
|
||||
uri: /home/jlewi/git_kubeflow/kubeflow
|
||||
version: 0.0.1
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
global: {},
|
||||
components: {
|
||||
// Component-level parameters, defined initially from 'ks prototype use ...'
|
||||
// Each object below should correspond to a component in the components/ directory
|
||||
seldon: {
|
||||
apifeServiceType: "NodePort",
|
||||
grpcMaxMessageSize: "4194304",
|
||||
name: "seldon",
|
||||
operatorJavaOpts: "null",
|
||||
operatorSpringOpts: "null",
|
||||
seldonVersion: "0.2.3",
|
||||
withAmbassador: "false",
|
||||
withApife: "false",
|
||||
withRbac: "true",
|
||||
},
|
||||
"xgboost": {
|
||||
endpoint: "REST",
|
||||
image: "image-path",
|
||||
imagePullSecret: "null",
|
||||
name: "xgboost",
|
||||
pvcName: "null",
|
||||
replicas: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
local env = std.extVar("__ksonnet/environments");
|
||||
local params = std.extVar("__ksonnet/params").components.seldon;
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
local core = import "kubeflow/seldon/core.libsonnet";
|
||||
|
||||
local seldonVersion = params.seldonVersion;
|
||||
|
||||
local name = params.name;
|
||||
local namespace = env.namespace;
|
||||
local withRbac = params.withRbac;
|
||||
local withApife = params.withApife;
|
||||
local withAmbassador = params.withAmbassador;
|
||||
|
||||
// APIFE
|
||||
local apifeImage = "seldonio/apife:" + seldonVersion;
|
||||
local apifeServiceType = params.apifeServiceType;
|
||||
local grpcMaxMessageSize = params.grpcMaxMessageSize;
|
||||
|
||||
// Cluster Manager (The CRD Operator)
|
||||
local operatorImage = "seldonio/cluster-manager:" + seldonVersion;
|
||||
local operatorSpringOptsParam = params.operatorSpringOpts;
|
||||
local operatorSpringOpts = if operatorSpringOptsParam != "null" then operatorSpringOptsParam else "";
|
||||
local operatorJavaOptsParam = params.operatorJavaOpts;
|
||||
local operatorJavaOpts = if operatorJavaOptsParam != "null" then operatorJavaOptsParam else "";
|
||||
|
||||
// Engine
|
||||
local engineImage = "seldonio/engine:" + seldonVersion;
|
||||
|
||||
// APIFE
|
||||
local apife = [
|
||||
core.parts(name, namespace, seldonVersion).apife(apifeImage, withRbac, grpcMaxMessageSize),
|
||||
core.parts(name, namespace, seldonVersion).apifeService(apifeServiceType),
|
||||
];
|
||||
|
||||
local rbac2 = [
|
||||
core.parts(name, namespace, seldonVersion).rbacServiceAccount(),
|
||||
core.parts(name, namespace, seldonVersion).rbacClusterRole(),
|
||||
core.parts(name, namespace, seldonVersion).rbacRole(),
|
||||
core.parts(name, namespace, seldonVersion).rbacRoleBinding(),
|
||||
core.parts(name, namespace, seldonVersion).rbacClusterRoleBinding(),
|
||||
];
|
||||
|
||||
local rbac1 = [
|
||||
core.parts(name, namespace, seldonVersion).rbacServiceAccount(),
|
||||
core.parts(name, namespace, seldonVersion).rbacRoleBinding(),
|
||||
];
|
||||
|
||||
local rbac = if std.startsWith(seldonVersion, "0.1") then rbac1 else rbac2;
|
||||
|
||||
// Core
|
||||
local coreComponents = [
|
||||
core.parts(name, namespace, seldonVersion).deploymentOperator(engineImage, operatorImage, operatorSpringOpts, operatorJavaOpts, withRbac),
|
||||
core.parts(name, namespace, seldonVersion).redisDeployment(),
|
||||
core.parts(name, namespace, seldonVersion).redisService(),
|
||||
core.parts(name, namespace, seldonVersion).crd(),
|
||||
];
|
||||
|
||||
//Ambassador
|
||||
local ambassadorRbac = [
|
||||
core.parts(name, namespace, seldonVersion).rbacAmbassadorRole(),
|
||||
core.parts(name, namespace, seldonVersion).rbacAmbassadorRoleBinding(),
|
||||
];
|
||||
|
||||
local ambassador = [
|
||||
core.parts(name, namespace, seldonVersion).ambassadorDeployment(),
|
||||
core.parts(name, namespace, seldonVersion).ambassadorService(),
|
||||
];
|
||||
|
||||
local l1 = if withRbac == "true" then rbac + coreComponents else coreComponents;
|
||||
local l2 = if withApife == "true" then l1 + apife else l1;
|
||||
local l3 = if withAmbassador == "true" && withRbac == "true" then l2 + ambassadorRbac else l2;
|
||||
local l4 = if withAmbassador == "true" then l3 + ambassador else l3;
|
||||
|
||||
l4
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
local env = std.extVar("__ksonnet/environments");
|
||||
local params = std.extVar("__ksonnet/params").components["xgboost"];
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment = {
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha2",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
deployment_version: "v1",
|
||||
project_name: params.name,
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
annotations: {
|
||||
predictor_version: "v1",
|
||||
},
|
||||
componentSpecs: [{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.image,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: params.name,
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
}],
|
||||
graph: {
|
||||
children: [
|
||||
|
||||
],
|
||||
endpoint: {
|
||||
type: params.endpoint,
|
||||
},
|
||||
name: params.name,
|
||||
type: "MODEL",
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
local components = std.extVar("__ksonnet/components");
|
||||
components + {
|
||||
// Insert user-specified overrides here.
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
local base = import "base.libsonnet";
|
||||
// uncomment if you reference ksonnet-lib
|
||||
// local k = import "k.libsonnet";
|
||||
|
||||
base + {
|
||||
// Insert user-specified overrides here. For example if a component is named \"nginx-deployment\", you might have something like:\n")
|
||||
// "nginx-deployment"+: k.deployment.mixin.metadata.labels({foo: "bar"})
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
local params = std.extVar('__ksonnet/params');
|
||||
local globals = import 'globals.libsonnet';
|
||||
local envParams = params + {
|
||||
components+: {
|
||||
xgboost+: {
|
||||
name: 'xgboost-ames-1300',
|
||||
image: 'gcr.io/kubeflow-ci/xgboost_ames_housing:build-1300',
|
||||
replicas: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
{
|
||||
components: {
|
||||
[x]: envParams.components[x] + globals
|
||||
for x in std.objectFields(envParams.components)
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
local k = import "k.libsonnet";
|
||||
local deployment = k.extensions.v1beta1.deployment;
|
||||
local container = k.apps.v1beta1.deployment.mixin.spec.template.spec.containersType;
|
||||
local service = k.core.v1.service.mixin;
|
||||
local serviceAccountMixin = k.core.v1.serviceAccount.mixin;
|
||||
local clusterRoleBindingMixin = k.rbac.v1beta1.clusterRoleBinding.mixin;
|
||||
local clusterRoleBinding = k.rbac.v1beta1.clusterRoleBinding;
|
||||
local roleBindingMixin = k.rbac.v1beta1.roleBinding.mixin;
|
||||
local roleBinding = k.rbac.v1beta1.roleBinding;
|
||||
local roleMixin = k.rbac.v1beta1.role.mixin;
|
||||
local serviceAccount = k.core.v1.serviceAccount;
|
||||
|
||||
local crdDefn = import "crd.libsonnet";
|
||||
local seldonTemplate2 = import "json/template_0.2.json";
|
||||
local seldonTemplate1 = import "json/template_0.1.json";
|
||||
|
||||
local getOperatorDeployment(x) = std.endsWith(x.metadata.name, "seldon-cluster-manager");
|
||||
local getApifeDeployment(x) = std.endsWith(x.metadata.name, "seldon-apiserver") && x.kind == "Deployment";
|
||||
local getApifeService(x) = std.endsWith(x.metadata.name, "seldon-apiserver") && x.kind == "Service";
|
||||
local getRedisDeployment(x) = std.endsWith(x.metadata.name, "redis") && x.kind == "Deployment";
|
||||
local getRedisService(x) = std.endsWith(x.metadata.name, "redis") && x.kind == "Service";
|
||||
local getServiceAccount(x) = x.kind == "ServiceAccount";
|
||||
local getClusterRole(x) = x.kind == "ClusterRole";
|
||||
local getClusterRoleBinding(x) = x.kind == "ClusterRoleBinding";
|
||||
local getRoleBinding(x) = x.kind == "RoleBinding" && x.roleRef.name == "seldon-local";
|
||||
local getAmbassadorRoleBinding(x) = x.kind == "RoleBinding" && x.roleRef.name == "ambassador";
|
||||
local getSeldonRole(x) = x.metadata.name == "seldon-local" && x.kind == "Role";
|
||||
local getAmbassadorRole(x) = x.metadata.name == "ambassador" && x.kind == "Role";
|
||||
local getAmbassadorDeployment(x) = std.endsWith(x.metadata.name, "ambassador") && x.kind == "Deployment";
|
||||
local getAmbassadorService(x) = std.endsWith(x.metadata.name, "ambassador") && x.kind == "Service";
|
||||
local getEnvNotRedis(x) = x.name != "SELDON_CLUSTER_MANAGER_REDIS_HOST";
|
||||
|
||||
{
|
||||
parts(name, namespace, seldonVersion)::
|
||||
|
||||
local seldonTemplate = if std.startsWith(seldonVersion, "0.1") then seldonTemplate1 else seldonTemplate2;
|
||||
|
||||
{
|
||||
apife(apifeImage, withRbac, grpcMaxMessageSize)::
|
||||
|
||||
local baseApife = std.filter(getApifeDeployment, seldonTemplate.items)[0];
|
||||
|
||||
local env = [
|
||||
{ name: "SELDON_CLUSTER_MANAGER_REDIS_HOST", value: name + "-redis" },
|
||||
];
|
||||
|
||||
local env2 = std.filter(getEnvNotRedis, baseApife.spec.template.spec.containers[0].env);
|
||||
|
||||
local c = baseApife.spec.template.spec.containers[0] +
|
||||
container.withImage(apifeImage) +
|
||||
container.withEnv(env + env2) +
|
||||
container.withImagePullPolicy("IfNotPresent");
|
||||
|
||||
local labels = {
|
||||
"app.kubernetes.io/name": name,
|
||||
heritage: "ksonnet",
|
||||
release: name,
|
||||
};
|
||||
|
||||
|
||||
local apiFeBase1 =
|
||||
baseApife +
|
||||
deployment.mixin.metadata.withName(name + "-seldon-apiserver") +
|
||||
deployment.mixin.metadata.withNamespace(namespace) +
|
||||
deployment.mixin.metadata.withLabelsMixin(labels) +
|
||||
deployment.mixin.spec.template.spec.withContainers([c]);
|
||||
|
||||
local extraAnnotations = { "seldon.io/grpc-max-message-size": grpcMaxMessageSize };
|
||||
|
||||
// Ensure labels copied to enclosed parts
|
||||
local apiFeBase = apiFeBase1 +
|
||||
deployment.mixin.spec.selector.withMatchLabels(apiFeBase1.metadata.labels) +
|
||||
deployment.mixin.spec.template.metadata.withLabels(apiFeBase1.metadata.labels) +
|
||||
deployment.mixin.spec.template.metadata.withAnnotationsMixin(extraAnnotations);
|
||||
|
||||
|
||||
if withRbac == "true" then
|
||||
apiFeBase +
|
||||
deployment.mixin.spec.template.spec.withServiceAccountName("seldon")
|
||||
else
|
||||
apiFeBase,
|
||||
|
||||
|
||||
apifeService(serviceType)::
|
||||
|
||||
local apifeService = std.filter(getApifeService, seldonTemplate.items)[0];
|
||||
|
||||
local labels = { "app.kubernetes.io/name": name };
|
||||
|
||||
apifeService +
|
||||
service.metadata.withName(name + "-seldon-apiserver") +
|
||||
service.metadata.withNamespace(namespace) +
|
||||
service.metadata.withLabelsMixin(labels) +
|
||||
service.spec.withType(serviceType),
|
||||
|
||||
deploymentOperator(engineImage, clusterManagerImage, springOpts, javaOpts, withRbac):
|
||||
|
||||
local op = std.filter(getOperatorDeployment, seldonTemplate.items)[0];
|
||||
|
||||
local env = [
|
||||
{ name: "JAVA_OPTS", value: javaOpts },
|
||||
{ name: "SPRING_OPTS", value: springOpts },
|
||||
{ name: "ENGINE_CONTAINER_IMAGE_AND_VERSION", value: engineImage },
|
||||
{ name: "ENGINE_CONTAINER_IMAGE_PULL_POLICY", value: "IfNotPresent" },
|
||||
{ name: "SELDON_CLUSTER_MANAGER_REDIS_HOST", value: name + "-redis" },
|
||||
{ name: "SELDON_CLUSTER_MANAGER_POD_NAMESPACE", valueFrom: { fieldRef: { apiVersion: "v1", fieldPath: "metadata.namespace" } } },
|
||||
];
|
||||
|
||||
local c = op.spec.template.spec.containers[0] +
|
||||
container.withImage(clusterManagerImage) +
|
||||
container.withEnv(env) +
|
||||
container.withImagePullPolicy("IfNotPresent");
|
||||
|
||||
|
||||
local labels = {
|
||||
"app.kubernetes.io/name": name,
|
||||
heritage: "ksonnet",
|
||||
release: name,
|
||||
};
|
||||
|
||||
local depOp1 = op +
|
||||
deployment.mixin.metadata.withName(name + "-seldon-cluster-manager") +
|
||||
deployment.mixin.metadata.withNamespace(namespace) +
|
||||
deployment.mixin.metadata.withLabelsMixin(labels) +
|
||||
deployment.mixin.spec.template.spec.withContainers([c]);
|
||||
|
||||
// Ensure labels copied to enclosed parts
|
||||
local depOp = depOp1 +
|
||||
deployment.mixin.spec.selector.withMatchLabels(depOp1.metadata.labels) +
|
||||
deployment.mixin.spec.template.metadata.withLabels(depOp1.metadata.labels);
|
||||
|
||||
|
||||
if withRbac == "true" then
|
||||
depOp +
|
||||
deployment.mixin.spec.template.spec.withServiceAccountName("seldon")
|
||||
else
|
||||
depOp,
|
||||
|
||||
redisDeployment():
|
||||
|
||||
local redisDeployment = std.filter(getRedisDeployment, seldonTemplate.items)[0];
|
||||
|
||||
local labels = {
|
||||
app: name + "-redis-app",
|
||||
"app.kubernetes.io/name": name,
|
||||
heritage: "ksonnet",
|
||||
release: name,
|
||||
};
|
||||
|
||||
local redisDeployment1 = redisDeployment +
|
||||
deployment.mixin.metadata.withName(name + "-redis") +
|
||||
deployment.mixin.metadata.withNamespace(namespace) +
|
||||
deployment.mixin.metadata.withLabelsMixin(labels);
|
||||
|
||||
redisDeployment1 +
|
||||
deployment.mixin.spec.selector.withMatchLabels(redisDeployment1.metadata.labels) +
|
||||
deployment.mixin.spec.template.metadata.withLabels(redisDeployment1.metadata.labels),
|
||||
|
||||
redisService():
|
||||
|
||||
local redisService = std.filter(getRedisService, seldonTemplate.items)[0];
|
||||
|
||||
local labels = { "app.kubernetes.io/name": name };
|
||||
|
||||
redisService +
|
||||
service.metadata.withName(name + "-redis") +
|
||||
service.metadata.withNamespace(namespace) +
|
||||
service.metadata.withLabelsMixin(labels) +
|
||||
service.spec.withSelector({ app: name + "-redis-app" }),
|
||||
|
||||
rbacServiceAccount():
|
||||
|
||||
local rbacServiceAccount = std.filter(getServiceAccount, seldonTemplate.items)[0];
|
||||
|
||||
rbacServiceAccount +
|
||||
serviceAccountMixin.metadata.withNamespace(namespace),
|
||||
|
||||
|
||||
rbacClusterRole():
|
||||
|
||||
local clusterRole = std.filter(getClusterRole, seldonTemplate.items)[0];
|
||||
|
||||
clusterRole,
|
||||
|
||||
rbacRole():
|
||||
|
||||
local role = std.filter(getSeldonRole, seldonTemplate.items)[0];
|
||||
|
||||
role +
|
||||
roleMixin.metadata.withNamespace(namespace),
|
||||
|
||||
|
||||
rbacAmbassadorRole():
|
||||
|
||||
local role = std.filter(getAmbassadorRole, seldonTemplate.items)[0];
|
||||
|
||||
role +
|
||||
roleMixin.metadata.withNamespace(namespace),
|
||||
|
||||
|
||||
rbacClusterRoleBinding():
|
||||
|
||||
local rbacClusterRoleBinding = std.filter(getClusterRoleBinding, seldonTemplate.items)[0];
|
||||
|
||||
local subject = rbacClusterRoleBinding.subjects[0]
|
||||
{ namespace: namespace };
|
||||
|
||||
rbacClusterRoleBinding +
|
||||
clusterRoleBindingMixin.metadata.withNamespace(namespace) +
|
||||
clusterRoleBinding.withSubjects([subject]),
|
||||
|
||||
rbacRoleBinding():
|
||||
|
||||
local rbacRoleBinding = std.filter(getRoleBinding, seldonTemplate.items)[0];
|
||||
|
||||
local subject = rbacRoleBinding.subjects[0]
|
||||
{ namespace: namespace };
|
||||
|
||||
rbacRoleBinding +
|
||||
roleBindingMixin.metadata.withNamespace(namespace) +
|
||||
roleBinding.withSubjects([subject]),
|
||||
|
||||
rbacAmbassadorRoleBinding():
|
||||
|
||||
local rbacRoleBinding = std.filter(getAmbassadorRoleBinding, seldonTemplate.items)[0];
|
||||
|
||||
local subject = rbacRoleBinding.subjects[0]
|
||||
{ namespace: namespace };
|
||||
|
||||
rbacRoleBinding +
|
||||
roleBindingMixin.metadata.withNamespace(namespace) +
|
||||
roleBinding.withSubjects([subject]),
|
||||
|
||||
ambassadorDeployment():
|
||||
|
||||
local ambassadorDeployment = std.filter(getAmbassadorDeployment, seldonTemplate.items)[0];
|
||||
|
||||
ambassadorDeployment +
|
||||
deployment.mixin.metadata.withName(name + "-ambassador") +
|
||||
deployment.mixin.metadata.withNamespace(namespace),
|
||||
|
||||
|
||||
ambassadorService():
|
||||
|
||||
local ambassadorService = std.filter(getAmbassadorService, seldonTemplate.items)[0];
|
||||
|
||||
ambassadorService +
|
||||
service.metadata.withName(name + "-ambassador") +
|
||||
service.metadata.withNamespace(namespace),
|
||||
|
||||
crd():
|
||||
|
||||
if std.startsWith(seldonVersion, "0.1") then crdDefn.crd1() else crdDefn.crd2(),
|
||||
|
||||
}, // parts
|
||||
}
|
||||
|
|
@ -0,0 +1,509 @@
|
|||
local podTemplateValidation = import "json/pod-template-spec-validation.json";
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
{
|
||||
|
||||
crd1()::
|
||||
{
|
||||
apiVersion: "apiextensions.k8s.io/v1beta1",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {
|
||||
name: "seldondeployments.machinelearning.seldon.io",
|
||||
},
|
||||
spec: {
|
||||
group: "machinelearning.seldon.io",
|
||||
names: {
|
||||
kind: "SeldonDeployment",
|
||||
plural: "seldondeployments",
|
||||
shortNames: [
|
||||
"sdep",
|
||||
],
|
||||
singular: "seldondeployment",
|
||||
},
|
||||
scope: "Namespaced",
|
||||
validation: {
|
||||
openAPIV3Schema: {
|
||||
properties: {
|
||||
spec: {
|
||||
properties: {
|
||||
annotations: {
|
||||
description: "The annotations to be updated to a deployment",
|
||||
type: "object",
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
oauth_key: {
|
||||
type: "string",
|
||||
},
|
||||
oauth_secret: {
|
||||
type: "string",
|
||||
},
|
||||
predictors: {
|
||||
description: "List of predictors belonging to the deployment",
|
||||
items: {
|
||||
properties: {
|
||||
annotations: {
|
||||
description: "The annotations to be updated to a predictor",
|
||||
type: "object",
|
||||
},
|
||||
graph: {
|
||||
properties: {
|
||||
children: {
|
||||
items: {
|
||||
properties: {
|
||||
children: {
|
||||
items: {
|
||||
properties: {
|
||||
children: {
|
||||
items: {},
|
||||
type: "array",
|
||||
},
|
||||
endpoint: {
|
||||
properties: {
|
||||
service_host: {
|
||||
type: "string",
|
||||
},
|
||||
service_port: {
|
||||
type: "integer",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"REST",
|
||||
"GRPC",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
implementation: {
|
||||
enum: [
|
||||
"UNKNOWN_IMPLEMENTATION",
|
||||
"SIMPLE_MODEL",
|
||||
"SIMPLE_ROUTER",
|
||||
"RANDOM_ABTEST",
|
||||
"AVERAGE_COMBINER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"UNKNOWN_TYPE",
|
||||
"ROUTER",
|
||||
"COMBINER",
|
||||
"MODEL",
|
||||
"TRANSFORMER",
|
||||
"OUTPUT_TRANSFORMER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
methods: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: [
|
||||
"TRANSFORM_INPUT",
|
||||
"TRANSFORM_OUTPUT",
|
||||
"ROUTE",
|
||||
"AGGREGATE",
|
||||
"SEND_FEEDBACK",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
},
|
||||
endpoint: {
|
||||
properties: {
|
||||
service_host: {
|
||||
type: "string",
|
||||
},
|
||||
service_port: {
|
||||
type: "integer",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"REST",
|
||||
"GRPC",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
implementation: {
|
||||
enum: [
|
||||
"UNKNOWN_IMPLEMENTATION",
|
||||
"SIMPLE_MODEL",
|
||||
"SIMPLE_ROUTER",
|
||||
"RANDOM_ABTEST",
|
||||
"AVERAGE_COMBINER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"UNKNOWN_TYPE",
|
||||
"ROUTER",
|
||||
"COMBINER",
|
||||
"MODEL",
|
||||
"TRANSFORMER",
|
||||
"OUTPUT_TRANSFORMER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
methods: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: [
|
||||
"TRANSFORM_INPUT",
|
||||
"TRANSFORM_OUTPUT",
|
||||
"ROUTE",
|
||||
"AGGREGATE",
|
||||
"SEND_FEEDBACK",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
},
|
||||
endpoint: {
|
||||
properties: {
|
||||
service_host: {
|
||||
type: "string",
|
||||
},
|
||||
service_port: {
|
||||
type: "integer",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"REST",
|
||||
"GRPC",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
implementation: {
|
||||
enum: [
|
||||
"UNKNOWN_IMPLEMENTATION",
|
||||
"SIMPLE_MODEL",
|
||||
"SIMPLE_ROUTER",
|
||||
"RANDOM_ABTEST",
|
||||
"AVERAGE_COMBINER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"UNKNOWN_TYPE",
|
||||
"ROUTER",
|
||||
"COMBINER",
|
||||
"MODEL",
|
||||
"TRANSFORMER",
|
||||
"OUTPUT_TRANSFORMER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
methods: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: [
|
||||
"TRANSFORM_INPUT",
|
||||
"TRANSFORM_OUTPUT",
|
||||
"ROUTE",
|
||||
"AGGREGATE",
|
||||
"SEND_FEEDBACK",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
replicas: {
|
||||
type: "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
},
|
||||
componentSpec: podTemplateValidation,
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
version: "v1alpha1",
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
crd2()::
|
||||
{
|
||||
apiVersion: "apiextensions.k8s.io/v1beta1",
|
||||
kind: "CustomResourceDefinition",
|
||||
metadata: {
|
||||
name: "seldondeployments.machinelearning.seldon.io",
|
||||
},
|
||||
spec: {
|
||||
group: "machinelearning.seldon.io",
|
||||
names: {
|
||||
kind: "SeldonDeployment",
|
||||
plural: "seldondeployments",
|
||||
shortNames: [
|
||||
"sdep",
|
||||
],
|
||||
singular: "seldondeployment",
|
||||
},
|
||||
scope: "Namespaced",
|
||||
validation: {
|
||||
openAPIV3Schema: {
|
||||
properties: {
|
||||
spec: {
|
||||
properties: {
|
||||
annotations: {
|
||||
description: "The annotations to be updated to a deployment",
|
||||
type: "object",
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
oauth_key: {
|
||||
type: "string",
|
||||
},
|
||||
oauth_secret: {
|
||||
type: "string",
|
||||
},
|
||||
predictors: {
|
||||
description: "List of predictors belonging to the deployment",
|
||||
items: {
|
||||
properties: {
|
||||
annotations: {
|
||||
description: "The annotations to be updated to a predictor",
|
||||
type: "object",
|
||||
},
|
||||
graph: {
|
||||
properties: {
|
||||
children: {
|
||||
items: {
|
||||
properties: {
|
||||
children: {
|
||||
items: {
|
||||
properties: {
|
||||
children: {
|
||||
items: {},
|
||||
type: "array",
|
||||
},
|
||||
endpoint: {
|
||||
properties: {
|
||||
service_host: {
|
||||
type: "string",
|
||||
},
|
||||
service_port: {
|
||||
type: "integer",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"REST",
|
||||
"GRPC",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
implementation: {
|
||||
enum: [
|
||||
"UNKNOWN_IMPLEMENTATION",
|
||||
"SIMPLE_MODEL",
|
||||
"SIMPLE_ROUTER",
|
||||
"RANDOM_ABTEST",
|
||||
"AVERAGE_COMBINER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"UNKNOWN_TYPE",
|
||||
"ROUTER",
|
||||
"COMBINER",
|
||||
"MODEL",
|
||||
"TRANSFORMER",
|
||||
"OUTPUT_TRANSFORMER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
methods: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: [
|
||||
"TRANSFORM_INPUT",
|
||||
"TRANSFORM_OUTPUT",
|
||||
"ROUTE",
|
||||
"AGGREGATE",
|
||||
"SEND_FEEDBACK",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
},
|
||||
endpoint: {
|
||||
properties: {
|
||||
service_host: {
|
||||
type: "string",
|
||||
},
|
||||
service_port: {
|
||||
type: "integer",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"REST",
|
||||
"GRPC",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
implementation: {
|
||||
enum: [
|
||||
"UNKNOWN_IMPLEMENTATION",
|
||||
"SIMPLE_MODEL",
|
||||
"SIMPLE_ROUTER",
|
||||
"RANDOM_ABTEST",
|
||||
"AVERAGE_COMBINER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"UNKNOWN_TYPE",
|
||||
"ROUTER",
|
||||
"COMBINER",
|
||||
"MODEL",
|
||||
"TRANSFORMER",
|
||||
"OUTPUT_TRANSFORMER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
methods: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: [
|
||||
"TRANSFORM_INPUT",
|
||||
"TRANSFORM_OUTPUT",
|
||||
"ROUTE",
|
||||
"AGGREGATE",
|
||||
"SEND_FEEDBACK",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
},
|
||||
endpoint: {
|
||||
properties: {
|
||||
service_host: {
|
||||
type: "string",
|
||||
},
|
||||
service_port: {
|
||||
type: "integer",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"REST",
|
||||
"GRPC",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
implementation: {
|
||||
enum: [
|
||||
"UNKNOWN_IMPLEMENTATION",
|
||||
"SIMPLE_MODEL",
|
||||
"SIMPLE_ROUTER",
|
||||
"RANDOM_ABTEST",
|
||||
"AVERAGE_COMBINER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
type: {
|
||||
enum: [
|
||||
"UNKNOWN_TYPE",
|
||||
"ROUTER",
|
||||
"COMBINER",
|
||||
"MODEL",
|
||||
"TRANSFORMER",
|
||||
"OUTPUT_TRANSFORMER",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
methods: {
|
||||
type: "array",
|
||||
items: {
|
||||
enum: [
|
||||
"TRANSFORM_INPUT",
|
||||
"TRANSFORM_OUTPUT",
|
||||
"ROUTE",
|
||||
"AGGREGATE",
|
||||
"SEND_FEEDBACK",
|
||||
],
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
},
|
||||
replicas: {
|
||||
type: "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "array",
|
||||
},
|
||||
componentSpecs:
|
||||
{
|
||||
description: "List of pods belonging to the predictor",
|
||||
type: "array",
|
||||
items: podTemplateValidation,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
version: "v1alpha2",
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
The template json files are generated from seldon-core helm charts.
|
||||
|
||||
The template_0.2.json is generated using:
|
||||
|
||||
```
|
||||
git clone --branch release-0.2 git@github.com:SeldonIO/seldon-core.git seldon-core-release-0.2
|
||||
helm template --set ambassador.enabled=true seldon-core-release-0.2/helm-charts/seldon-core > template_0.2.yaml
|
||||
kubectl convert -f template_0.2.yaml -o json > template_0.2.json
|
||||
rm template_0.2.yaml
|
||||
```
|
||||
|
||||
The template_0.1.json is generated using:
|
||||
|
||||
```
|
||||
git clone --branch release-0.1 git@github.com:SeldonIO/seldon-core.git seldon-core-release-0.1
|
||||
helm template --set ambassador.enabled=true seldon-core-release-0.1/helm-charts/seldon-core > template_0.1.yaml
|
||||
kubectl convert -f template_0.1.yaml -o json > template_0.1.json
|
||||
rm template_0.1.yaml
|
||||
```
|
||||
3336
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/json/pod-template-spec-validation.json
vendored
Normal file
3336
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/json/pod-template-spec-validation.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,333 @@
|
|||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "seldon",
|
||||
"creationTimestamp": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "RoleBinding",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "seldon",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "seldon",
|
||||
"namespace": "seldon"
|
||||
}
|
||||
],
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": "cluster-admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "seldon-cluster-manager",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-cluster-manager-server"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "seldon-cluster-manager-server"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-cluster-manager-server"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "seldon-cluster-manager-container",
|
||||
"image": "seldonio/cluster-manager:0.1.8",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "JAVA_OPTS"
|
||||
},
|
||||
{
|
||||
"name": "SPRING_OPTS"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_REDIS_HOST",
|
||||
"value": "redis"
|
||||
},
|
||||
{
|
||||
"name": "ENGINE_CONTAINER_IMAGE_AND_VERSION",
|
||||
"value": "seldonio/engine:0.1.8"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_POD_NAMESPACE",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"apiVersion": "v1",
|
||||
"fieldPath": "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent"
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 30,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccountName": "seldon",
|
||||
"serviceAccount": "seldon",
|
||||
"securityContext": {},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": 1,
|
||||
"maxSurge": 1
|
||||
}
|
||||
},
|
||||
"progressDeadlineSeconds": 2147483647
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "redis",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "redis-app"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "redis-app"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "redis-app"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "redis-container",
|
||||
"image": "redis:4.0.1",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent"
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 30,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"securityContext": {},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": 1,
|
||||
"maxSurge": 1
|
||||
}
|
||||
},
|
||||
"progressDeadlineSeconds": 2147483647
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "redis",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"app": "redis-app"
|
||||
},
|
||||
"type": "ClusterIP",
|
||||
"sessionAffinity": "None"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "seldon-apiserver",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"version": "1"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"version": "1"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"version": "1"
|
||||
},
|
||||
"annotations": {
|
||||
"prometheus.io/path": "/prometheus",
|
||||
"prometheus.io/port": "8080",
|
||||
"prometheus.io/scrape": "true"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "seldon-apiserver-container",
|
||||
"image": "seldonio/apife:0.1.8",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"containerPort": 5000,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "SELDON_ENGINE_KAFKA_SERVER",
|
||||
"value": "kafka:9092"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_REDIS_HOST",
|
||||
"value": "redis"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_POD_NAMESPACE",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"apiVersion": "v1",
|
||||
"fieldPath": "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent"
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 30,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccountName": "seldon",
|
||||
"serviceAccount": "seldon",
|
||||
"securityContext": {},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": 1,
|
||||
"maxSurge": 1
|
||||
}
|
||||
},
|
||||
"progressDeadlineSeconds": 2147483647
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "seldon-apiserver",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-apiserver-container-app"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "http",
|
||||
"protocol": "TCP",
|
||||
"port": 8080,
|
||||
"targetPort": 8080
|
||||
},
|
||||
{
|
||||
"name": "grpc",
|
||||
"protocol": "TCP",
|
||||
"port": 5000,
|
||||
"targetPort": 5000
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"app": "seldon-apiserver-container-app"
|
||||
},
|
||||
"type": "NodePort",
|
||||
"sessionAffinity": "None",
|
||||
"externalTrafficPolicy": "Cluster"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,775 @@
|
|||
{
|
||||
"kind": "List",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {},
|
||||
"items": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "seldon",
|
||||
"creationTimestamp": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Role",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "seldon-local",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"verbs": [
|
||||
"*"
|
||||
],
|
||||
"apiGroups": [
|
||||
"*"
|
||||
],
|
||||
"resources": [
|
||||
"deployments",
|
||||
"services"
|
||||
]
|
||||
},
|
||||
{
|
||||
"verbs": [
|
||||
"*"
|
||||
],
|
||||
"apiGroups": [
|
||||
"machinelearning.seldon.io"
|
||||
],
|
||||
"resources": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "ClusterRole",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "seldon-crd",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"verbs": [
|
||||
"create"
|
||||
],
|
||||
"apiGroups": [
|
||||
"apiextensions.k8s.io"
|
||||
],
|
||||
"resources": [
|
||||
"customresourcedefinitions"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "RoleBinding",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "seldon",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "seldon",
|
||||
"namespace": "seldon"
|
||||
}
|
||||
],
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "Role",
|
||||
"name": "seldon-local"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "ClusterRoleBinding",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "seldon",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "seldon",
|
||||
"namespace": "seldon"
|
||||
}
|
||||
],
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "ClusterRole",
|
||||
"name": "seldon-crd"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Role",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "ambassador",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"verbs": [
|
||||
"get",
|
||||
"list",
|
||||
"watch"
|
||||
],
|
||||
"apiGroups": [
|
||||
""
|
||||
],
|
||||
"resources": [
|
||||
"services"
|
||||
]
|
||||
},
|
||||
{
|
||||
"verbs": [
|
||||
"create",
|
||||
"update",
|
||||
"patch",
|
||||
"get",
|
||||
"list",
|
||||
"watch"
|
||||
],
|
||||
"apiGroups": [
|
||||
""
|
||||
],
|
||||
"resources": [
|
||||
"configmaps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"verbs": [
|
||||
"get",
|
||||
"list",
|
||||
"watch"
|
||||
],
|
||||
"apiGroups": [
|
||||
""
|
||||
],
|
||||
"resources": [
|
||||
"secrets"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "RoleBinding",
|
||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||
"metadata": {
|
||||
"name": "ambassador",
|
||||
"creationTimestamp": null
|
||||
},
|
||||
"subjects": [
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "seldon",
|
||||
"namespace": "seldon"
|
||||
}
|
||||
],
|
||||
"roleRef": {
|
||||
"apiGroup": "rbac.authorization.k8s.io",
|
||||
"kind": "Role",
|
||||
"name": "ambassador"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-ambassador",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"service": "ambassador"
|
||||
},
|
||||
"annotations": {
|
||||
"getambassador.io/config": "---\napiVersion: ambassador/v0\nkind: Module\nname: ambassador\nconfig:\n service_port: 8080\n"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "http",
|
||||
"protocol": "TCP",
|
||||
"port": 8080,
|
||||
"targetPort": 8080
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"service": "ambassador"
|
||||
},
|
||||
"type": "NodePort",
|
||||
"sessionAffinity": "None",
|
||||
"externalTrafficPolicy": "Cluster"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-ambassador-admin",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"service": "ambassador-admin"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "ambassador-admin",
|
||||
"protocol": "TCP",
|
||||
"port": 8877,
|
||||
"targetPort": 8877
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"service": "ambassador"
|
||||
},
|
||||
"type": "NodePort",
|
||||
"sessionAffinity": "None",
|
||||
"externalTrafficPolicy": "Cluster"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-ambassador",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"service": "ambassador"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"service": "ambassador"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"service": "ambassador"
|
||||
},
|
||||
"annotations": {
|
||||
"sidecar.istio.io/inject": "false"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "ambassador",
|
||||
"image": "quay.io/datawire/ambassador:0.35.1",
|
||||
"ports": [
|
||||
{
|
||||
"name": "http",
|
||||
"containerPort": 8080,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"name": "https",
|
||||
"containerPort": 443,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"containerPort": 8877,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "AMBASSADOR_SINGLE_NAMESPACE",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"name": "AMBASSADOR_NAMESPACE",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"apiVersion": "v1",
|
||||
"fieldPath": "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": {
|
||||
"limits": {
|
||||
"cpu": "1",
|
||||
"memory": "400Mi"
|
||||
},
|
||||
"requests": {
|
||||
"cpu": "200m",
|
||||
"memory": "128Mi"
|
||||
}
|
||||
},
|
||||
"livenessProbe": {
|
||||
"httpGet": {
|
||||
"path": "/ambassador/v0/check_alive",
|
||||
"port": "admin",
|
||||
"scheme": "HTTP"
|
||||
},
|
||||
"initialDelaySeconds": 30,
|
||||
"timeoutSeconds": 1,
|
||||
"periodSeconds": 3,
|
||||
"successThreshold": 1,
|
||||
"failureThreshold": 3
|
||||
},
|
||||
"readinessProbe": {
|
||||
"httpGet": {
|
||||
"path": "/ambassador/v0/check_ready",
|
||||
"port": "admin",
|
||||
"scheme": "HTTP"
|
||||
},
|
||||
"initialDelaySeconds": 30,
|
||||
"timeoutSeconds": 1,
|
||||
"periodSeconds": 3,
|
||||
"successThreshold": 1,
|
||||
"failureThreshold": 3
|
||||
},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent"
|
||||
},
|
||||
{
|
||||
"name": "statsd",
|
||||
"image": "datawire/prom-statsd-exporter:0.6.0",
|
||||
"ports": [
|
||||
{
|
||||
"name": "metrics",
|
||||
"containerPort": 9102,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent"
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 30,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccountName": "seldon",
|
||||
"serviceAccount": "seldon",
|
||||
"securityContext": {
|
||||
"runAsUser": 8888
|
||||
},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": 1,
|
||||
"maxSurge": 1
|
||||
}
|
||||
},
|
||||
"progressDeadlineSeconds": 2147483647
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-seldon-apiserver",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"app.kubernetes.io/component": "seldon-core-apiserver",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"app.kubernetes.io/component": "seldon-core-apiserver",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"app.kubernetes.io/component": "seldon-core-apiserver",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
},
|
||||
"annotations": {
|
||||
"prometheus.io/path": "/prometheus",
|
||||
"prometheus.io/port": "8080",
|
||||
"prometheus.io/scrape": "true"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
{
|
||||
"name": "podinfo",
|
||||
"downwardAPI": {
|
||||
"items": [
|
||||
{
|
||||
"path": "annotations",
|
||||
"fieldRef": {
|
||||
"apiVersion": "v1",
|
||||
"fieldPath": "metadata.annotations"
|
||||
}
|
||||
}
|
||||
],
|
||||
"defaultMode": 420
|
||||
}
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "seldon-apiserver-container",
|
||||
"image": "seldonio/apife:0.2.3",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"protocol": "TCP"
|
||||
},
|
||||
{
|
||||
"containerPort": 5000,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "SELDON_ENGINE_KAFKA_SERVER",
|
||||
"value": "kafka:9092"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_REDIS_HOST",
|
||||
"value": "RELEASE-NAME-redis"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_POD_NAMESPACE",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"apiVersion": "v1",
|
||||
"fieldPath": "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "podinfo",
|
||||
"mountPath": "/etc/podinfo"
|
||||
}
|
||||
],
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"securityContext": {
|
||||
"runAsUser": 8888,
|
||||
"procMount": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 30,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccountName": "seldon",
|
||||
"serviceAccount": "seldon",
|
||||
"securityContext": {},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": "25%",
|
||||
"maxSurge": "25%"
|
||||
}
|
||||
},
|
||||
"revisionHistoryLimit": 2,
|
||||
"progressDeadlineSeconds": 600
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-seldon-apiserver",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-apiserver-container-app",
|
||||
"app.kubernetes.io/component": "seldon-core-apiserver",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"name": "http",
|
||||
"protocol": "TCP",
|
||||
"port": 8080,
|
||||
"targetPort": 8080
|
||||
},
|
||||
{
|
||||
"name": "grpc",
|
||||
"protocol": "TCP",
|
||||
"port": 5000,
|
||||
"targetPort": 5000
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"app": "seldon-apiserver-container-app"
|
||||
},
|
||||
"type": "NodePort",
|
||||
"sessionAffinity": "None",
|
||||
"externalTrafficPolicy": "Cluster"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-seldon-cluster-manager",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-cluster-manager-server",
|
||||
"app.kubernetes.io/component": "seldon-core-operator",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "seldon-cluster-manager-server",
|
||||
"app.kubernetes.io/component": "seldon-core-operator",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "seldon-cluster-manager-server",
|
||||
"app.kubernetes.io/component": "seldon-core-operator",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "seldon-cluster-manager-container",
|
||||
"image": "seldonio/cluster-manager:0.2.3",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"env": [
|
||||
{
|
||||
"name": "JAVA_OPTS"
|
||||
},
|
||||
{
|
||||
"name": "SPRING_OPTS"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_REDIS_HOST",
|
||||
"value": "RELEASE-NAME-redis"
|
||||
},
|
||||
{
|
||||
"name": "ENGINE_CONTAINER_IMAGE_AND_VERSION",
|
||||
"value": "seldonio/engine:0.2.3"
|
||||
},
|
||||
{
|
||||
"name": "ENGINE_CONTAINER_IMAGE_PULL_POLICY",
|
||||
"value": "IfNotPresent"
|
||||
},
|
||||
{
|
||||
"name": "SELDON_CLUSTER_MANAGER_POD_NAMESPACE",
|
||||
"valueFrom": {
|
||||
"fieldRef": {
|
||||
"apiVersion": "v1",
|
||||
"fieldPath": "metadata.namespace"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent",
|
||||
"securityContext": {
|
||||
"runAsUser": 8888,
|
||||
"procMount": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 1,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"serviceAccountName": "seldon",
|
||||
"serviceAccount": "seldon",
|
||||
"securityContext": {},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": 1,
|
||||
"maxSurge": 1
|
||||
}
|
||||
},
|
||||
"progressDeadlineSeconds": 2147483647
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Deployment",
|
||||
"apiVersion": "apps/v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-redis",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "RELEASE-NAME-redis-app",
|
||||
"app.kubernetes.io/component": "seldon-core-redis",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"replicas": 1,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "RELEASE-NAME-redis-app",
|
||||
"app.kubernetes.io/component": "seldon-core-redis",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app": "RELEASE-NAME-redis-app",
|
||||
"app.kubernetes.io/component": "seldon-core-redis",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME",
|
||||
"chart": "seldon-core-0.2.3",
|
||||
"component": "seldon-core",
|
||||
"heritage": "Tiller",
|
||||
"release": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "redis-container",
|
||||
"image": "redis:4.0.1",
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": 6379,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"resources": {},
|
||||
"terminationMessagePath": "/dev/termination-log",
|
||||
"terminationMessagePolicy": "File",
|
||||
"imagePullPolicy": "IfNotPresent"
|
||||
}
|
||||
],
|
||||
"restartPolicy": "Always",
|
||||
"terminationGracePeriodSeconds": 30,
|
||||
"dnsPolicy": "ClusterFirst",
|
||||
"securityContext": {},
|
||||
"schedulerName": "default-scheduler"
|
||||
}
|
||||
},
|
||||
"strategy": {
|
||||
"type": "RollingUpdate",
|
||||
"rollingUpdate": {
|
||||
"maxUnavailable": 1,
|
||||
"maxSurge": 1
|
||||
}
|
||||
},
|
||||
"progressDeadlineSeconds": 2147483647
|
||||
},
|
||||
"status": {}
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "RELEASE-NAME-redis",
|
||||
"creationTimestamp": null,
|
||||
"labels": {
|
||||
"app.kubernetes.io/component": "seldon-core-redis",
|
||||
"app.kubernetes.io/name": "RELEASE-NAME"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 6379,
|
||||
"targetPort": 6379
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"app": "RELEASE-NAME-redis-app"
|
||||
},
|
||||
"type": "ClusterIP",
|
||||
"sessionAffinity": "None"
|
||||
},
|
||||
"status": {
|
||||
"loadBalancer": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "seldon",
|
||||
"apiVersion": "0.0.1",
|
||||
"kind": "ksonnet.io/parts",
|
||||
"description": "Seldon ML Deployment\n",
|
||||
"author": "seldon-core team <devext@seldon.io>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Clive Cox",
|
||||
"email": "cc@seldon.io"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kubeflow/kubeflow"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/SeldonIO/seldon-core/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"kubernetes",
|
||||
"machine learning",
|
||||
"deployment"
|
||||
],
|
||||
"quickStart": {
|
||||
"prototype": "io.ksonnet.pkg.seldon",
|
||||
"componentName": "seldon",
|
||||
"flags": {
|
||||
"name": "seldon",
|
||||
"namespace": "default"
|
||||
},
|
||||
"comment": "Seldon Core Components."
|
||||
},
|
||||
"license": "Apache 2.0"
|
||||
}
|
||||
136
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/abtest-v1alpha1.jsonnet
vendored
Normal file
136
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/abtest-v1alpha1.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-abtest-v1alpha1
|
||||
// @description An AB test between two models for the v1alpha1 CRD (Seldon 0.1.X)
|
||||
// @shortDescription An AB test between two models
|
||||
// @param name string Name to give this deployment
|
||||
// @param imageA string Docker image which contains model A
|
||||
// @param imageB string Docker image which contains model B
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpointA string REST The endpoint type for modelA : REST or GRPC
|
||||
// @optionalParam endpointB string REST The endpoint type for modelB: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment =
|
||||
{
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha1",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
project_name: params.name,
|
||||
deployment_version: "v1",
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
componentSpec:
|
||||
{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.imageA,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-1",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
{
|
||||
image: params.imageB,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-2",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
graph: {
|
||||
name: "random-ab-test",
|
||||
endpoint: {},
|
||||
implementation: "RANDOM_ABTEST",
|
||||
parameters: [
|
||||
{
|
||||
name: "ratioA",
|
||||
value: "0.5",
|
||||
type: "FLOAT",
|
||||
},
|
||||
],
|
||||
children: [
|
||||
{
|
||||
name: "classifier-1",
|
||||
endpoint: {
|
||||
type: params.endpointA,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "classifier-2",
|
||||
endpoint: {
|
||||
type: params.endpointB,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
164
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/abtest-v1alpha2.jsonnet
vendored
Normal file
164
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/abtest-v1alpha2.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-abtest-v1alpha2
|
||||
// @description An AB test between two models for the v1alpha2 CRD (Seldon 0.2.X)
|
||||
// @shortDescription An AB test between two models
|
||||
// @param name string Name to give this deployment
|
||||
// @param imageA string Docker image which contains model A
|
||||
// @param imageB string Docker image which contains model B
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpointA string REST The endpoint type for modelA : REST or GRPC
|
||||
// @optionalParam endpointB string REST The endpoint type for modelB: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment =
|
||||
{
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha2",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
project_name: params.name,
|
||||
deployment_version: "v1",
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
componentSpecs: [
|
||||
{
|
||||
metadata: {
|
||||
labels: {
|
||||
version: "v2",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.imageA,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-1",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
{
|
||||
metadata: {
|
||||
labels: {
|
||||
version: "v2",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.imageB,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-2",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
],
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
graph: {
|
||||
name: "random-ab-test",
|
||||
endpoint: {},
|
||||
implementation: "RANDOM_ABTEST",
|
||||
parameters: [
|
||||
{
|
||||
name: "ratioA",
|
||||
value: "0.5",
|
||||
type: "FLOAT",
|
||||
},
|
||||
],
|
||||
children: [
|
||||
{
|
||||
name: "classifier-1",
|
||||
endpoint: {
|
||||
type: params.endpointA,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "classifier-2",
|
||||
endpoint: {
|
||||
type: params.endpointB,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon
|
||||
// @description Seldon Core components. Operator and API FrontEnd.
|
||||
// @shortDescription Seldon Core components.
|
||||
// @param name string seldon Name to give seldon
|
||||
// @optionalParam withRbac string true Whether to include RBAC setup
|
||||
// @optionalParam withApife string false Whether to include builtin API OAuth gateway server for ingress
|
||||
// @optionalParam withAmbassador string false Whether to include Ambassador reverse proxy
|
||||
// @optionalParam apifeServiceType string NodePort API Front End Service Type
|
||||
// @optionalParam operatorSpringOpts string null cluster manager spring opts
|
||||
// @optionalParam operatorJavaOpts string null cluster manager java opts
|
||||
// @optionalParam grpcMaxMessageSize string 4194304 Max gRPC message size
|
||||
// @optionalParam seldonVersion string 0.2.3 Seldon version
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
local core = import "kubeflow/seldon/core.libsonnet";
|
||||
|
||||
local seldonVersion = import "param://seldonVersion";
|
||||
|
||||
local name = import "param://name";
|
||||
local namespace = env.namespace;
|
||||
local withRbac = import "param://withRbac";
|
||||
local withApife = import "param://withApife";
|
||||
local withAmbassador = import "param://withAmbassador";
|
||||
|
||||
// APIFE
|
||||
local apifeImage = "seldonio/apife:" + seldonVersion;
|
||||
local apifeServiceType = import "param://apifeServiceType";
|
||||
local grpcMaxMessageSize = import "param://grpcMaxMessageSize";
|
||||
|
||||
// Cluster Manager (The CRD Operator)
|
||||
local operatorImage = "seldonio/cluster-manager:" + seldonVersion;
|
||||
local operatorSpringOptsParam = import "param://operatorSpringOpts";
|
||||
local operatorSpringOpts = if operatorSpringOptsParam != "null" then operatorSpringOptsParam else "";
|
||||
local operatorJavaOptsParam = import "param://operatorJavaOpts";
|
||||
local operatorJavaOpts = if operatorJavaOptsParam != "null" then operatorJavaOptsParam else "";
|
||||
|
||||
// Engine
|
||||
local engineImage = "seldonio/engine:" + seldonVersion;
|
||||
|
||||
// APIFE
|
||||
local apife = [
|
||||
core.parts(name, namespace, seldonVersion).apife(apifeImage, withRbac, grpcMaxMessageSize),
|
||||
core.parts(name, namespace, seldonVersion).apifeService(apifeServiceType),
|
||||
];
|
||||
|
||||
local rbac2 = [
|
||||
core.parts(name, namespace, seldonVersion).rbacServiceAccount(),
|
||||
core.parts(name, namespace, seldonVersion).rbacClusterRole(),
|
||||
core.parts(name, namespace, seldonVersion).rbacRole(),
|
||||
core.parts(name, namespace, seldonVersion).rbacRoleBinding(),
|
||||
core.parts(name, namespace, seldonVersion).rbacClusterRoleBinding(),
|
||||
];
|
||||
|
||||
local rbac1 = [
|
||||
core.parts(name, namespace, seldonVersion).rbacServiceAccount(),
|
||||
core.parts(name, namespace, seldonVersion).rbacRoleBinding(),
|
||||
];
|
||||
|
||||
local rbac = if std.startsWith(seldonVersion, "0.1") then rbac1 else rbac2;
|
||||
|
||||
// Core
|
||||
local coreComponents = [
|
||||
core.parts(name, namespace, seldonVersion).deploymentOperator(engineImage, operatorImage, operatorSpringOpts, operatorJavaOpts, withRbac),
|
||||
core.parts(name, namespace, seldonVersion).redisDeployment(),
|
||||
core.parts(name, namespace, seldonVersion).redisService(),
|
||||
core.parts(name, namespace, seldonVersion).crd(),
|
||||
];
|
||||
|
||||
//Ambassador
|
||||
local ambassadorRbac = [
|
||||
core.parts(name, namespace, seldonVersion).rbacAmbassadorRole(),
|
||||
core.parts(name, namespace, seldonVersion).rbacAmbassadorRoleBinding(),
|
||||
];
|
||||
|
||||
local ambassador = [
|
||||
core.parts(name, namespace, seldonVersion).ambassadorDeployment(),
|
||||
core.parts(name, namespace, seldonVersion).ambassadorService(),
|
||||
];
|
||||
|
||||
local l1 = if withRbac == "true" then rbac + coreComponents else coreComponents;
|
||||
local l2 = if withApife == "true" then l1 + apife else l1;
|
||||
local l3 = if withAmbassador == "true" && withRbac == "true" then l2 + ambassadorRbac else l2;
|
||||
local l4 = if withAmbassador == "true" then l3 + ambassador else l3;
|
||||
|
||||
l4
|
||||
151
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/mab-v1alpha1.jsonnet
vendored
Normal file
151
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/mab-v1alpha1.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-mab-v1alpha1
|
||||
// @description An e-greeey multi-armed bandit solver between two models for the v1alpha1 CRD (Seldon 0.1.X)
|
||||
// @shortDescription An e-greeey multi-armed bandit for two models
|
||||
// @param name string Name to give this deployment
|
||||
// @param imageA string Docker image which contains model A
|
||||
// @param imageB string Docker image which contains model
|
||||
// @optionalParam mabImage string seldonio/mab_epsilon_greedy:1.1 image for multi-armed bandit model
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpointA string REST The endpoint type for modelA : REST or GRPC
|
||||
// @optionalParam endpointB string REST The endpoint type for modelB: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment =
|
||||
{
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha1",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
project_name: params.name,
|
||||
deployment_version: "v1",
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
componentSpec:
|
||||
{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.imageA,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-1",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
{
|
||||
image: params.imageB,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-2",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
{
|
||||
image: params.mabImage,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "eg-router",
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
graph: {
|
||||
name: "eg-router",
|
||||
type: "ROUTER",
|
||||
parameters: [
|
||||
{
|
||||
name: "n_branches",
|
||||
value: "2",
|
||||
type: "INT",
|
||||
},
|
||||
{
|
||||
name: "epsilon",
|
||||
value: "0.2",
|
||||
type: "FLOAT",
|
||||
},
|
||||
{
|
||||
name: "verbose",
|
||||
value: "1",
|
||||
type: "BOOL",
|
||||
},
|
||||
],
|
||||
children: [
|
||||
{
|
||||
name: "classifier-1",
|
||||
endpoint: {
|
||||
type: params.endpointA,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "classifier-2",
|
||||
endpoint: {
|
||||
type: params.endpointB,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
191
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/mab-v1alpha2.jsonnet
vendored
Normal file
191
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/mab-v1alpha2.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-mab-v1alpha2
|
||||
// @description An e-greeey multi-armed bandit solver between two models for the v1alpha2 CRD (Seldon 0.2.X)
|
||||
// @shortDescription An e-greeey multi-armed bandit for two models
|
||||
// @param name string Name to give this deployment
|
||||
// @param imageA string Docker image which contains model A
|
||||
// @param imageB string Docker image which contains model
|
||||
// @optionalParam mabImage string seldonio/mab_epsilon_greedy:1.1 image for multi-armed bandit model
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpointA string REST The endpoint type for modelA : REST or GRPC
|
||||
// @optionalParam endpointB string REST The endpoint type for modelB: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment =
|
||||
{
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha2",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
project_name: params.name,
|
||||
deployment_version: "v1",
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
componentSpecs: [
|
||||
{
|
||||
metadata: {
|
||||
labels: {
|
||||
version: "v1",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.imageA,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-1",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
{
|
||||
metadata: {
|
||||
labels: {
|
||||
version: "v2",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.imageB,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "classifier-2",
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.mabImage,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "eg-router",
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
graph: {
|
||||
name: "eg-router",
|
||||
type: "ROUTER",
|
||||
parameters: [
|
||||
{
|
||||
name: "n_branches",
|
||||
value: "2",
|
||||
type: "INT",
|
||||
},
|
||||
{
|
||||
name: "epsilon",
|
||||
value: "0.2",
|
||||
type: "FLOAT",
|
||||
},
|
||||
{
|
||||
name: "verbose",
|
||||
value: "1",
|
||||
type: "BOOL",
|
||||
},
|
||||
],
|
||||
children: [
|
||||
{
|
||||
name: "classifier-1",
|
||||
endpoint: {
|
||||
type: params.endpointA,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
name: "classifier-2",
|
||||
endpoint: {
|
||||
type: params.endpointB,
|
||||
},
|
||||
type: "MODEL",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
116
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/outlier-detector-v1alpha1.jsonnet
vendored
Normal file
116
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/outlier-detector-v1alpha1.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-outlier-detector-v1alpha1
|
||||
// @description Serve an outlier detector with a single model for the v1alpha1 CRD (Seldon 0.1.X)
|
||||
// @shortDescription Serve an outlier detector with a model
|
||||
// @param name string Name to give this deployment
|
||||
// @param image string Docker image which contains this model
|
||||
// @optionalParam outlierDetectorImage string seldonio/outlier_mahalanobis:0.3 Docker image for outlier detector
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpoint string REST The endpoint type: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment = {
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha1",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
deployment_version: "v1",
|
||||
project_name: params.name,
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
annotations: {
|
||||
predictor_version: "v1",
|
||||
},
|
||||
componentSpec:
|
||||
{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.image,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: params.name,
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
{
|
||||
image: params.outlierDetectorImage,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "outlier-detector",
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
graph: {
|
||||
name: "outlier-detector",
|
||||
type: "TRANSFORMER",
|
||||
endpoint: {
|
||||
type: "REST",
|
||||
},
|
||||
children: [{
|
||||
children: [
|
||||
],
|
||||
endpoint: {
|
||||
type: params.endpoint,
|
||||
},
|
||||
name: params.name,
|
||||
type: "MODEL",
|
||||
}],
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
124
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/outlier-detector-v1alpha2.jsonnet
vendored
Normal file
124
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/outlier-detector-v1alpha2.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-outlier-detector-v1alpha2
|
||||
// @description Serve an outlier detector with a single model for the v1alpha2 CRD (Seldon 0.2.X)
|
||||
// @shortDescription Serve an outlier detector with a model
|
||||
// @param name string Name to give this deployment
|
||||
// @param image string Docker image which contains this model
|
||||
// @optionalParam outlierDetectorImage string seldonio/outlier_mahalanobis:0.3 Docker image for outlier detector
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpoint string REST The endpoint type: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment = {
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha2",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
deployment_version: "v1",
|
||||
project_name: params.name,
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
annotations: {
|
||||
predictor_version: "v1",
|
||||
},
|
||||
componentSpecs: [
|
||||
{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.image,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: params.name,
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.outlierDetectorImage,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: "outlier-detector",
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
graph: {
|
||||
name: "outlier-detector",
|
||||
type: "TRANSFORMER",
|
||||
endpoint: {
|
||||
type: "REST",
|
||||
},
|
||||
children: [{
|
||||
children: [
|
||||
],
|
||||
endpoint: {
|
||||
type: params.endpoint,
|
||||
},
|
||||
name: params.name,
|
||||
type: "MODEL",
|
||||
}],
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
105
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/serve-simple-v1alpha1.jsonnet
vendored
Normal file
105
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/serve-simple-v1alpha1.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-serve-simple-v1alpha1
|
||||
// @description Serve a single seldon model for the v1alpha1 CRD (Seldon 0.1.X)
|
||||
// @shortDescription Serve a single seldon model
|
||||
// @param name string Name to give this deployment
|
||||
// @param image string Docker image which contains this model
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpoint string REST The endpoint type: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
local seldonDeployment = {
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha1",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
deployment_version: "v1",
|
||||
project_name: params.name,
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
annotations: {
|
||||
predictor_version: "v1",
|
||||
},
|
||||
componentSpec: {
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.image,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: params.name,
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
},
|
||||
graph: {
|
||||
children: [
|
||||
|
||||
],
|
||||
endpoint: {
|
||||
type: params.endpoint,
|
||||
},
|
||||
name: params.name,
|
||||
type: "MODEL",
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
103
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/serve-simple-v1alpha2.jsonnet
vendored
Normal file
103
xgboost_ames_housing/ks_app/vendor/kubeflow/seldon/prototypes/serve-simple-v1alpha2.jsonnet
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// @apiVersion 0.1
|
||||
// @name io.ksonnet.pkg.seldon-serve-simple-v1alpha2
|
||||
// @description Serve a single seldon model for the v1alpha2 CRD (Seldon 0.2.X)
|
||||
// @shortDescription Serve a single seldon model
|
||||
// @param name string Name to give this deployment
|
||||
// @param image string Docker image which contains this model
|
||||
// @optionalParam replicas number 1 Number of replicas
|
||||
// @optionalParam endpoint string REST The endpoint type: REST or GRPC
|
||||
// @optionalParam pvcName string null Name of PVC
|
||||
// @optionalParam imagePullSecret string null name of image pull secret
|
||||
|
||||
local k = import "k.libsonnet";
|
||||
|
||||
local pvcClaim = {
|
||||
apiVersion: "v1",
|
||||
kind: "PersistentVolumeClaim",
|
||||
metadata: {
|
||||
name: params.pvcName,
|
||||
},
|
||||
spec: {
|
||||
accessModes: [
|
||||
"ReadWriteOnce",
|
||||
],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "10Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
local seldonDeployment = {
|
||||
apiVersion: "machinelearning.seldon.io/v1alpha2",
|
||||
kind: "SeldonDeployment",
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "seldon",
|
||||
},
|
||||
name: params.name,
|
||||
namespace: env.namespace,
|
||||
},
|
||||
spec: {
|
||||
annotations: {
|
||||
deployment_version: "v1",
|
||||
project_name: params.name,
|
||||
},
|
||||
name: params.name,
|
||||
predictors: [
|
||||
{
|
||||
annotations: {
|
||||
predictor_version: "v1",
|
||||
},
|
||||
componentSpecs: [{
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: params.image,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
name: params.name,
|
||||
volumeMounts+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
mountPath: "/mnt",
|
||||
name: "persistent-storage",
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
],
|
||||
terminationGracePeriodSeconds: 1,
|
||||
imagePullSecrets+: if params.imagePullSecret != "null" && params.imagePullSecret != "" then [
|
||||
{
|
||||
name: params.imagePullSecret,
|
||||
},
|
||||
] else [],
|
||||
volumes+: if params.pvcName != "null" && params.pvcName != "" then [
|
||||
{
|
||||
name: "persistent-storage",
|
||||
volumeSource: {
|
||||
persistentVolumeClaim: {
|
||||
claimName: params.pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
] else [],
|
||||
},
|
||||
}],
|
||||
graph: {
|
||||
children: [
|
||||
|
||||
],
|
||||
endpoint: {
|
||||
type: params.endpoint,
|
||||
},
|
||||
name: params.name,
|
||||
type: "MODEL",
|
||||
},
|
||||
name: params.name,
|
||||
replicas: params.replicas,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if params.pvcName == "null" then k.core.v1.list.new([seldonDeployment]) else k.core.v1.list.new([pvcClaim, seldonDeployment])
|
||||
|
|
@ -39,7 +39,7 @@ build-s2i-image:
|
|||
# Build a serving image in a s2i image, which can be built in the above step.
|
||||
build-seldon-image:IMG?=gcr.io/kubeflow-examples/xgboost_ames_housing_seldon
|
||||
build-seldon-image:TAG?=latest
|
||||
build-seldon-image:SOURCE=../seldon_serve
|
||||
build-seldon-image:SOURCE?=../seldon_serve
|
||||
build-seldon-image:
|
||||
@echo IMG=$(IMG)
|
||||
@echo GIT_VERSION=$(GIT_VERSION)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import pytest
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--master", action="store", default="", help="IP address of GKE master")
|
||||
|
||||
parser.addoption(
|
||||
"--namespace", action="store", default="", help="namespace of server")
|
||||
|
||||
parser.addoption(
|
||||
"--service", action="store", default="",
|
||||
help="The name of the mnist K8s service")
|
||||
|
||||
@pytest.fixture
|
||||
def master(request):
|
||||
return request.config.getoption("--master")
|
||||
|
||||
@pytest.fixture
|
||||
def namespace(request):
|
||||
return request.config.getoption("--namespace")
|
||||
|
||||
@pytest.fixture
|
||||
def service(request):
|
||||
return request.config.getoption("--service")
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
"""Test xgboost_ames_housing.
|
||||
|
||||
This file tests that we can send predictions to the model
|
||||
using REST.
|
||||
|
||||
It is an integration test as it depends on having access to
|
||||
a deployed model.
|
||||
|
||||
We use the pytest framework because
|
||||
1. It can output results in junit format for prow/gubernator
|
||||
2. It has good support for configuring tests using command line arguments
|
||||
(https://docs.pytest.org/en/latest/example/simple.html)
|
||||
|
||||
Python Path Requirements:
|
||||
kubeflow/testing/py - https://github.com/kubeflow/testing/tree/master/py
|
||||
* Provides utilities for testing
|
||||
|
||||
Manually running the test
|
||||
1. Configure your KUBECONFIG file to point to the desired cluster
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import requests
|
||||
from retrying import retry
|
||||
import six
|
||||
|
||||
from kubernetes.config import kube_config
|
||||
from kubernetes import client as k8s_client
|
||||
|
||||
import pytest
|
||||
|
||||
from kubeflow.testing import util
|
||||
|
||||
@retry(wait_exponential_multiplier=10000, wait_exponential_max=100000,
|
||||
stop_max_delay=10*60*1000)
|
||||
def send_request(*args, **kwargs):
|
||||
# We don't use util.run because that ends up including the access token
|
||||
# in the logs
|
||||
token = subprocess.check_output(["gcloud", "auth", "print-access-token"])
|
||||
if six.PY3 and hasattr(token, "decode"):
|
||||
token = token.decode()
|
||||
token = token.strip()
|
||||
|
||||
headers = {
|
||||
"Authorization": "Bearer " + token,
|
||||
}
|
||||
|
||||
if "headers" not in kwargs:
|
||||
kwargs["headers"] = {}
|
||||
|
||||
kwargs["headers"].update(headers)
|
||||
|
||||
r = requests.post(*args, **kwargs)
|
||||
|
||||
if r.status_code != requests.codes.OK:
|
||||
msg = "Request to {0} exited with status code: {1} and content: {2}".format(
|
||||
*args, r.status_code, r.content)
|
||||
logging.error(msg)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
return r
|
||||
|
||||
def test_predict(master, namespace, service):
|
||||
app_credentials = os.getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
if app_credentials:
|
||||
print("Activate service account")
|
||||
util.run(["gcloud", "auth", "activate-service-account",
|
||||
"--key-file=" + app_credentials])
|
||||
|
||||
if not master:
|
||||
print("--master set; using kubeconfig")
|
||||
# util.load_kube_config appears to hang on python3
|
||||
kube_config.load_kube_config()
|
||||
api_client = k8s_client.ApiClient()
|
||||
host = api_client.configuration.host
|
||||
print("host={0}".format(host))
|
||||
master = host.rsplit("/", 1)[-1]
|
||||
|
||||
this_dir = os.path.dirname(__file__)
|
||||
test_data = os.path.join(this_dir, "query.json")
|
||||
with open(test_data) as hf:
|
||||
instances = json.load(hf)
|
||||
|
||||
# We proxy the request through the APIServer so that we can connect
|
||||
# from outside the cluster.
|
||||
url = ("https://{master}/api/v1/namespaces/{namespace}/services/{service}:8000"
|
||||
"/proxy/api/v0.1/predictions").format(
|
||||
master=master, namespace=namespace, service=service)
|
||||
logging.info("Request: %s", url)
|
||||
r = send_request(url, json=instances, verify=False)
|
||||
content = r.content
|
||||
if six.PY3 and hasattr(content, "decode"):
|
||||
content = content.decode()
|
||||
result = json.loads(content)
|
||||
assert result["data"]["tensor"]["values"] == [97522.359375, 97522.359375]
|
||||
logging.info("URL %s returned; %s", url, content)
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format=('%(levelname)s|%(asctime)s'
|
||||
'|%(pathname)s|%(lineno)d| %(message)s'),
|
||||
datefmt='%Y-%m-%dT%H:%M:%S',
|
||||
)
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
pytest.main()
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"data": {
|
||||
"tensor": {
|
||||
"shape": [
|
||||
1,
|
||||
37
|
||||
],
|
||||
"values": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36,
|
||||
37
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue