Remove deprecated services and unnecessary folders

This commit is contained in:
Rebecca McFadden 2019-07-29 20:50:22 -07:00
parent 4dd4d1069a
commit 7b166d211f
452 changed files with 0 additions and 63624 deletions

View File

@ -1,87 +0,0 @@
# Kubeflow Container Build Pipeline
trigger:
- master
pr: none
stages:
- stage: ContainerConfig
displayName: 'Configure and Register Containers'
jobs:
- job: Containers
pool:
name: default
steps:
- task: AzureCLI@1
inputs:
azureSubscription: 'Shared Data Platform - R+D (1308a130-d549-44e1-ba66-ce8c487d76e3)'
scriptLocation: 'inlineScript'
inlineScript: '
sudo az acr login -n kubeflowregistry &&
cd code &&
cd preprocess &&
sudo docker build -t kubeflowregistry.azurecr.io/kubeflow/preprocess:$BUILD_SOURCEVERSION . &&
sudo docker push kubeflowregistry.azurecr.io/kubeflow/preprocess:$BUILD_SOURCEVERSION '
displayName: 'Build & Push Preprocess Image'
- task: AzureCLI@1
inputs:
azureSubscription: 'Shared Data Platform - R+D (1308a130-d549-44e1-ba66-ce8c487d76e3)'
scriptLocation: 'inlineScript'
inlineScript: '
cd code &&
cd training &&
sudo docker build -t kubeflowregistry.azurecr.io/kubeflow/training:$BUILD_SOURCEVERSION . &&
sudo docker push kubeflowregistry.azurecr.io/kubeflow/training:$BUILD_SOURCEVERSION '
displayName: 'Build & Push Training Image'
- task: AzureCLI@1
inputs:
azureSubscription: 'Shared Data Platform - R+D (1308a130-d549-44e1-ba66-ce8c487d76e3)'
scriptLocation: 'inlineScript'
inlineScript: '
cd code &&
cd register &&
sudo docker build -t kubeflowregistry.azurecr.io/kubeflow/register:$BUILD_SOURCEVERSION . &&
sudo docker push kubeflowregistry.azurecr.io/kubeflow/register:$BUILD_SOURCEVERSION '
displayName: 'Build & Push Register Image'
# Moved KF step to build
- stage: KubeflowTrigger
dependsOn: ContainerConfig
displayName: 'Trigger Kubeflow Pipeline'
variables:
- group: kf-variables
jobs:
- job: Kubeflow
pool:
name: default
steps:
- task: AzureCLI@1
env:
KF_MAPPED_SERVICE_PRINCIPAL_PASSWORD: $(KF_SERVICE_PRINCIPAL_PASSWORD)
inputs:
azureSubscription: 'Shared Data Platform - R+D (1308a130-d549-44e1-ba66-ce8c487d76e3)'
scriptLocation: 'inlineScript'
inlineScript: |
az aks get-credentials -g kubeflow-mlops-rg -n kubeflow-mlops-cluster
kubectl port-forward --namespace kubeflow svc/ml-pipeline 8888:8888 &
kubepid=$!
sudo apt-get install python3-setuptools
pip3 install wheel
pip3 install kfp
touch script.py
echo "import kfp" >> script.py
echo "client = kfp.Client(host='localhost:8888')" >> script.py
echo "client.run_pipeline('$KF_EXPERIMENT_ID', 'Run ${BUILD_BUILDID}', params={'imagetag': '${BUILD_SOURCEVERSION}', 'tenant-id': '$KF_TENANT_ID', 'service-principal-id': '$KF_SERVICE_PRINCIPAL_ID', 'service-principal-password': '$KF_MAPPED_SERVICE_PRINCIPAL_PASSWORD', 'subscription-id': '$KF_SUBSCRIPTION_ID', 'resource-group': '$KF_RESOURCE_GROUP', 'workspace': '$KF_WORKSPACE', 'persistent-volume-name': '$KF_PERSISTENT_VOLUME_NAME', 'persistent-volume-path': '$KF_PERSISTENT_VOLUME_PATH', 'data-download': '$KF_DATA_DOWNLOAD', 'epochs': '$KF_EPOCHS', 'batch': '$KF_BATCH', 'learning-rate': '$KF_LEARNING_RATE', 'model-name': '$KF_MODEL_NAME'}, pipeline_id='$KF_PIPELINE_ID')" >> script.py
cat script.py
python3 script.py
kill $kubepid
displayName: 'Trigger Kubeflow Pipeline'

View File

@ -1,9 +0,0 @@
FROM tensorflow/tensorflow:2.0.0a0-gpu-py3
RUN pip install azure-cli
RUN az extension add -n azure-cli-ml
RUN pip install --upgrade pip
COPY profile.sh /scripts/profile.sh
COPY inferenceconfig.json /scripts/inferenceconfig.json
COPY score.py /scripts/score.py
COPY environment.yml /scripts/environment.yml
ENTRYPOINT bash

View File

@ -1,45 +0,0 @@
apiVersion: kfdef.apps.kubeflow.org/v1alpha1
kind: KfDef
metadata:
creationTimestamp: null
name: kflow
namespace: kubeflow
spec:
appdir: /home/rebec/kubeflow-and-mlops/code/kflow
componentParams:
ambassador:
- name: ambassadorServiceType
value: NodePort
components:
- ambassador
- argo
- centraldashboard
- jupyter-web-app
- katib
- metacontroller
- notebook-controller
- pipeline
- pytorch-operator
- tensorboard
- tf-job-operator
packages:
- argo
- common
- examples
- gcp
- jupyter
- katib
- metacontroller
- modeldb
- mpi-job
- pipeline
- pytorch-job
- seldon
- tensorboard
- tf-serving
- tf-training
repo: /home/rebec/kubeflow-and-mlops/code/kflow/.cache/v0.5.1/kubeflow
useBasicAuth: false
useIstio: false
version: v0.5.1
status: {}

View File

@ -1,4 +0,0 @@
/lib
/.ksonnet/registries
/app.override.yaml
/.ks_environment

View File

@ -1,76 +0,0 @@
apiVersion: 0.3.0
environments:
default:
destination:
namespace: kubeflow
server: https://taco-cls-taco-rg-1308a1-e98d0802.hcp.eastus.azmk8s.io:443
k8sVersion: v1.14.0
path: default
kind: ksonnet.io/app
libraries:
kubeflow/argo:
name: argo
registry: kubeflow
version: ""
kubeflow/common:
name: common
registry: kubeflow
version: ""
kubeflow/examples:
name: examples
registry: kubeflow
version: ""
kubeflow/gcp:
name: gcp
registry: kubeflow
version: ""
kubeflow/jupyter:
name: jupyter
registry: kubeflow
version: ""
kubeflow/katib:
name: katib
registry: kubeflow
version: ""
kubeflow/metacontroller:
name: metacontroller
registry: kubeflow
version: ""
kubeflow/modeldb:
name: modeldb
registry: kubeflow
version: ""
kubeflow/mpi-job:
name: mpi-job
registry: kubeflow
version: ""
kubeflow/pipeline:
name: pipeline
registry: kubeflow
version: ""
kubeflow/pytorch-job:
name: pytorch-job
registry: kubeflow
version: ""
kubeflow/seldon:
name: seldon
registry: kubeflow
version: ""
kubeflow/tensorboard:
name: tensorboard
registry: kubeflow
version: ""
kubeflow/tf-serving:
name: tf-serving
registry: kubeflow
version: ""
kubeflow/tf-training:
name: tf-training
registry: kubeflow
version: ""
name: ks_app
registries:
kubeflow:
protocol: fs
uri: /home/rebec/kubeflow-and-mlops/code/kflow/.cache/v0.5.1/kubeflow
version: 0.0.1

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.ambassador;
local ambassador = import "kubeflow/common/ambassador.libsonnet";
local instance = ambassador.new(env, params);
instance.list(instance.all)

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.argo;
local argo = import "kubeflow/argo/argo.libsonnet";
local instance = argo.new(env, params);
instance.list(instance.all)

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.centraldashboard;
local centraldashboard = import "kubeflow/common/centraldashboard.libsonnet";
local instance = centraldashboard.new(env, params);
instance.list(instance.all)

View File

@ -1,7 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["jupyter-web-app"];
local jupyter_ui = import "kubeflow/jupyter/jupyter-web-app.libsonnet";
local instance = jupyter_ui.new(env, params);
instance.list(instance.all)

View File

@ -1,16 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.katib;
local k = import "k.libsonnet";
local studyjobcontroller = import "kubeflow/katib/studyjobcontroller.libsonnet";
local suggestion = import "kubeflow/katib/suggestion.libsonnet";
local vizier = import "kubeflow/katib/vizier.libsonnet";
local namespace = env.namespace;
std.prune(
k.core.v1.list.new(vizier.all(params, namespace))
+ k.core.v1.list.new(suggestion.all(params, namespace))
+ k.core.v1.list.new(studyjobcontroller.all(params, namespace))
)

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.metacontroller;
local metacontroller = import "kubeflow/metacontroller/metacontroller.libsonnet";
local instance = metacontroller.new(env, params);
instance.list(instance.all)

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["notebook-controller"];
local notebooks = import "kubeflow/jupyter/notebook_controller.libsonnet";
local instance = notebooks.new(env, params);
instance.list(instance.all)

View File

@ -1,93 +0,0 @@
{
global: {},
components: {
// Component-level parameters, defined initially from 'ks prototype use ...'
// Each object below should correspond to a component in the components/ directory
ambassador: {
ambassadorImage: 'quay.io/datawire/ambassador:0.37.0',
ambassadorNodePort: 0,
ambassadorServiceType: 'NodePort',
name: 'ambassador',
platform: 'none',
replicas: 3,
},
argo: {
artifactRepositoryAccessKeySecretKey: 'accesskey',
artifactRepositoryAccessKeySecretName: 'mlpipeline-minio-artifact',
artifactRepositoryBucket: 'mlpipeline',
artifactRepositoryEndpoint: 'minio-service.kubeflow:9000',
artifactRepositoryInsecure: 'true',
artifactRepositoryKeyPrefix: 'artifacts',
artifactRepositorySecretKeySecretKey: 'secretkey',
artifactRepositorySecretKeySecretName: 'mlpipeline-minio-artifact',
executorImage: 'argoproj/argoexec:v2.2.0',
name: 'argo',
uiImage: 'argoproj/argoui:v2.2.0',
workflowControllerImage: 'argoproj/workflow-controller:v2.2.0',
},
centraldashboard: {
image: 'gcr.io/kubeflow-images-public/centraldashboard:v0.5.0',
name: 'centraldashboard',
},
"jupyter-web-app": {
image: 'gcr.io/kubeflow-images-public/jupyter-web-app:v0.5.0',
name: 'jupyter-web-app',
policy: 'Always',
port: '80',
prefix: 'jupyter',
rokSecretName: 'secret-rok-{username}',
ui: 'default',
},
katib: {
katibUIImage: 'gcr.io/kubeflow-images-public/katib/katib-ui:v0.1.2-alpha-156-g4ab3dbd',
metricsCollectorImage: 'gcr.io/kubeflow-images-public/katib/metrics-collector:v0.1.2-alpha-156-g4ab3dbd',
name: 'katib',
studyJobControllerImage: 'gcr.io/kubeflow-images-public/katib/studyjob-controller:v0.1.2-alpha-156-g4ab3dbd',
suggestionBayesianOptimizationImage: 'gcr.io/kubeflow-images-public/katib/suggestion-bayesianoptimization:v0.1.2-alpha-156-g4ab3dbd',
suggestionGridImage: 'gcr.io/kubeflow-images-public/katib/suggestion-grid:v0.1.2-alpha-156-g4ab3dbd',
suggestionHyperbandImage: 'gcr.io/kubeflow-images-public/katib/suggestion-hyperband:v0.1.2-alpha-156-g4ab3dbd',
suggestionRandomImage: 'gcr.io/kubeflow-images-public/katib/suggestion-random:v0.1.2-alpha-156-g4ab3dbd',
vizierCoreImage: 'gcr.io/kubeflow-images-public/katib/vizier-core:v0.1.2-alpha-156-g4ab3dbd',
vizierCoreRestImage: 'gcr.io/kubeflow-images-public/katib/vizier-core-rest:v0.1.2-alpha-156-g4ab3dbd',
vizierDbImage: 'mysql:8.0.3',
},
metacontroller: {
image: 'metacontroller/metacontroller:v0.3.0',
name: 'metacontroller',
},
"notebook-controller": {
controllerImage: 'gcr.io/kubeflow-images-public/notebook-controller:v20190401-v0.4.0-rc.1-308-g33618cc9-e3b0c4',
injectGcpCredentials: 'true',
name: 'notebook-controller',
},
pipeline: {
name: 'pipeline',
},
"pytorch-operator": {
cloud: 'null',
deploymentNamespace: 'null',
deploymentScope: 'cluster',
disks: 'null',
name: 'pytorch-operator',
pytorchDefaultImage: 'null',
pytorchJobImage: 'gcr.io/kubeflow-images-public/pytorch-operator:v0.5.0',
},
tensorboard: {
defaultTbImage: 'tensorflow/tensorflow:1.8.0',
logDir: 'logs',
name: 'tensorboard',
servicePort: 9000,
serviceType: 'ClusterIP',
targetPort: 6006,
},
"tf-job-operator": {
cloud: 'null',
deploymentNamespace: 'null',
deploymentScope: 'cluster',
name: 'tf-job-operator',
tfDefaultImage: 'null',
tfJobImage: 'gcr.io/kubeflow-images-public/tf_operator:v0.5.0',
tfJobUiServiceType: 'ClusterIP',
},
},
}

View File

@ -1,14 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.pipeline;
local k = import "k.libsonnet";
local pipelineBase = import "kubeflow/pipeline/pipeline.libsonnet";
// updatedParams includes the namespace from env by default.
local updatedParams = params + env;
local pipeline = pipelineBase {
params+: updatedParams,
};
std.prune(k.core.v1.list.new(pipeline.parts.all))

View File

@ -1,7 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["pytorch-operator"];
local k = import "k.libsonnet";
local operator = import "kubeflow/pytorch-job/pytorch-operator.libsonnet";
k.core.v1.list.new(operator.all(params, env))

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components.tensorboard;
local tensorboard = import "kubeflow/tensorboard/tensorboard.libsonnet";
local instance = tensorboard.new(env, params);
instance.list(instance.all)

View File

@ -1,6 +0,0 @@
local env = std.extVar("__ksonnet/environments");
local params = std.extVar("__ksonnet/params").components["tf-job-operator"];
local tfJobOperator = import "kubeflow/tf-training/tf-job-operator.libsonnet";
local instance = tfJobOperator.new(env, params);
instance.list(instance.all)

View File

@ -1,4 +0,0 @@
local components = std.extVar("__ksonnet/components");
components + {
// Insert user-specified overrides here.
}

View File

@ -1,9 +0,0 @@
local base = import "base.libsonnet";
// uncomment if you reference ksonnet-lib
// local k = import "k.libsonnet";
// local deployment = k.apps.v1beta2.deployment;
base + {
// Insert user-specified overrides here. For example if a component is named \"nginx-deployment\", you might have something like:\n")
// "nginx-deployment"+: deployment.mixin.metadata.withLabels({foo: "bar"})
}

View File

@ -1,17 +0,0 @@
local params = std.extVar("__ksonnet/params");
local globals = import "globals.libsonnet";
local envParams = params + {
components +: {
// Insert component parameter overrides here. Ex:
// guestbook +: {
// name: "guestbook-dev",
// replicas: params.global.replicas,
// },
},
};
{
components: {
[x]: envParams.components[x] + globals, for x in std.objectFields(envParams.components)
},
}

View File

@ -1,3 +0,0 @@
approvers:
- IronPan
reviewers:

View File

@ -1,35 +0,0 @@
# Argo
> Prototypes for deploying Argo and running Argo Workflows
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Quickstart](#quickstart)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Quickstart
*The following commands use the `io.ksonnet.pkg.argo` prototype to deploy the Argo Workflow operator on your Kubernetes cluster*
First, create a cluster and install the ksonnet CLI (see root-level [README.md](../../README.md)).
If you haven't yet created a [ksonnet application](https://ksonnet.io/docs/tutorial#1-initialize-your-app), do so using `ks init <app-name>`.
Finally, in the ksonnet application directory, run the following:
```shell
# Install the kubeflow argo package
$ ks pkg install kubeflow/argo
# Expand prototype as a Jsonnet file, place in a file in the
# `components/` directory. (YAML and JSON are also available.)
$ ks prototype use io.ksonnet.pkg.argo argo \
--namespace default \
--name argo
# Apply to server.
$ ks apply default -c argo
```

View File

@ -1,485 +0,0 @@
{
// TODO(jlewi): Do we need to add parts corresponding to a service account and cluster binding role?
// see https://github.com/argoproj/argo/blob/master/cmd/argo/commands/install.go
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env,
// CRD's are not namespace scoped; see
// https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/
local workflowCRD = {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "workflows.argoproj.io",
},
spec: {
group: "argoproj.io",
names: {
kind: "Workflow",
listKind: "WorkflowList",
plural: "workflows",
shortNames: [
"wf",
],
singular: "workflow",
},
scope: "Namespaced",
version: "v1alpha1",
},
}, // crd
workflowCRD:: workflowCRD,
// Deploy the controller
local workflowController = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "workflow-controller",
},
name: "workflow-controller",
namespace: params.namespace,
},
spec: {
progressDeadlineSeconds: 600,
replicas: 1,
revisionHistoryLimit: 10,
selector: {
matchLabels: {
app: "workflow-controller",
},
},
strategy: {
rollingUpdate: {
maxSurge: "25%",
maxUnavailable: "25%",
},
type: "RollingUpdate",
},
template: {
metadata: {
creationTimestamp: null,
labels: {
app: "workflow-controller",
},
},
spec: {
containers: [
{
args: [
"--configmap",
"workflow-controller-configmap",
],
command: [
"workflow-controller",
],
env: [
{
name: "ARGO_NAMESPACE",
valueFrom: {
fieldRef: {
apiVersion: "v1",
fieldPath: "metadata.namespace",
},
},
},
],
image: params.workflowControllerImage,
imagePullPolicy: "IfNotPresent",
name: "workflow-controller",
resources: {},
terminationMessagePath: "/dev/termination-log",
terminationMessagePolicy: "File",
},
],
dnsPolicy: "ClusterFirst",
restartPolicy: "Always",
schedulerName: "default-scheduler",
securityContext: {},
serviceAccount: "argo",
serviceAccountName: "argo",
terminationGracePeriodSeconds: 30,
},
},
},
}, // deploy
workflowController:: workflowController,
local argoUI = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "argo-ui",
},
name: "argo-ui",
namespace: params.namespace,
},
spec: {
progressDeadlineSeconds: 600,
replicas: 1,
revisionHistoryLimit: 10,
selector: {
matchLabels: {
app: "argo-ui",
},
},
strategy: {
rollingUpdate: {
maxSurge: "25%",
maxUnavailable: "25%",
},
type: "RollingUpdate",
},
template: {
metadata: {
creationTimestamp: null,
labels: {
app: "argo-ui",
},
},
spec: {
containers: [
{
env: [
{
name: "ARGO_NAMESPACE",
valueFrom: {
fieldRef: {
apiVersion: "v1",
fieldPath: "metadata.namespace",
},
},
},
{
name: "IN_CLUSTER",
value: "true",
},
{
name: "BASE_HREF",
value: "/argo/",
},
],
image: params.uiImage,
imagePullPolicy: "IfNotPresent",
name: "argo-ui",
resources: {},
terminationMessagePath: "/dev/termination-log",
terminationMessagePolicy: "File",
readinessProbe: {
httpGet: {
path: "/",
port: 8001,
},
},
},
],
dnsPolicy: "ClusterFirst",
restartPolicy: "Always",
schedulerName: "default-scheduler",
securityContext: {},
serviceAccount: "argo-ui",
serviceAccountName: "argo-ui",
terminationGracePeriodSeconds: 30,
},
},
},
}, // deployUi
argoUI:: argoUI,
local argUIService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "argo-ui",
},
name: "argo-ui",
namespace: params.namespace,
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: argo-ui-mapping",
"prefix: /argo/",
"service: argo-ui." + params.namespace,
]),
}, //annotations
},
spec: {
ports: [
{
port: 80,
targetPort: 8001,
},
],
selector: {
app: "argo-ui",
},
sessionAffinity: "None",
type: "NodePort",
},
},
argUIService:: argUIService,
local workflowControllerConfigmap = {
apiVersion: "v1",
data: {
config: std.format(|||
{
executorImage: %s,
artifactRepository:
{
s3: {
bucket: %s,
keyPrefix: %s,
endpoint: %s,
insecure: %s,
accessKeySecret: {
name: %s,
key: %s
},
secretKeySecret: {
name: %s,
key: %s
}
}
}
}
|||,
[
params.executorImage,
params.artifactRepositoryBucket,
params.artifactRepositoryKeyPrefix,
params.artifactRepositoryEndpoint,
params.artifactRepositoryInsecure,
params.artifactRepositoryAccessKeySecretName,
params.artifactRepositoryAccessKeySecretKey,
params.artifactRepositorySecretKeySecretName,
params.artifactRepositorySecretKeySecretKey,
]),
},
kind: "ConfigMap",
metadata: {
name: "workflow-controller-configmap",
namespace: params.namespace,
},
},
workflowControllerConfigmap:: workflowControllerConfigmap,
local argoServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "argo",
namespace: params.namespace,
},
}, // service account
argoServiceAccount:: argoServiceAccount,
// Keep in sync with https://github.com/argoproj/argo/blob/master/cmd/argo/commands/const.go#L20
// Permissions need to be cluster wide for the workflow controller to be able to process workflows
// in other namespaces. We could potentially use the ConfigMap of the workflow-controller to
// scope it to a particular namespace in which case we might be able to restrict the permissions
// to a particular namespace.
local argoClusterRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "argo",
},
name: "argo",
},
rules: [
{
apiGroups: [""],
resources: [
"pods",
"pods/exec",
],
verbs: [
"create",
"get",
"list",
"watch",
"update",
"patch",
],
},
{
apiGroups: [""],
resources: [
"configmaps",
],
verbs: [
"get",
"watch",
"list",
],
},
{
apiGroups: [
"",
],
resources: [
"persistentvolumeclaims",
],
verbs: [
"create",
"delete",
],
},
{
apiGroups: [
"argoproj.io",
],
resources: [
"workflows",
],
verbs: [
"get",
"list",
"watch",
"update",
"patch",
],
},
],
}, // operator-role
argoClusterRole:: argoClusterRole,
local argoClusterRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "argo",
},
name: "argo",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "argo",
},
subjects: [
{
kind: "ServiceAccount",
name: "argo",
namespace: params.namespace,
},
],
}, // role binding
argoClusterRoleBinding:: argoClusterRoleBinding,
local argoUIServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "argo-ui",
namespace: params.namespace,
},
}, // service account
argoUIServiceAccount:: argoUIServiceAccount,
// Keep in sync with https://github.com/argoproj/argo/blob/master/cmd/argo/commands/const.go#L44
// Permissions need to be cluster wide for the workflow controller to be able to process workflows
// in other namespaces. We could potentially use the ConfigMap of the workflow-controller to
// scope it to a particular namespace in which case we might be able to restrict the permissions
// to a particular namespace.
local argoUIRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "argo",
},
name: "argo-ui",
},
rules: [
{
apiGroups: [""],
resources: [
"pods",
"pods/exec",
"pods/log",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [""],
resources: [
"secrets",
],
verbs: [
"get",
],
},
{
apiGroups: [
"argoproj.io",
],
resources: [
"workflows",
],
verbs: [
"get",
"list",
"watch",
],
},
],
}, // operator-role
argoUIRole:: argoUIRole,
local argUIClusterRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "argo-ui",
},
name: "argo-ui",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "argo-ui",
},
subjects: [
{
kind: "ServiceAccount",
name: "argo-ui",
namespace: params.namespace,
},
],
}, // role binding
argUIClusterRoleBinding:: argUIClusterRoleBinding,
parts: self,
all:: [
self.workflowCRD,
self.workflowController,
self.argoUI,
self.argUIService,
self.workflowControllerConfigmap,
self.argoServiceAccount,
self.argoClusterRole,
self.argoClusterRoleBinding,
self.argoUIServiceAccount,
self.argoUIRole,
self.argUIClusterRoleBinding,
],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,35 +0,0 @@
{
"name": "argo",
"apiVersion": "0.0.1",
"kind": "ksonnet.io/parts",
"description": "Prototypes for running Argo workflows.\n",
"author": "kubeflow team <kubeflow-team@google.com>",
"contributors": [
{
"name": "Jeremy Lewi",
"email": "jlewi@google.com"
}
],
"repository": {
"type": "git",
"url": "https://github.com/kubeflow/kubeflow"
},
"bugs": {
"url": "https://github.com/kubeflow/kubeflow/issues"
},
"keywords": [
"kubeflow",
"argo",
"workflows"
],
"quickStart": {
"prototype": "io.ksonnet.pkg.argo",
"componentName": "argo",
"flags": {
"name": "argo",
"namespace": "",
},
"comment": "Deploy Argo"
},
"license": "Apache 2.0"
}

View File

@ -1,20 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.argo
// @description Deploy Argo workflow engine
// @shortDescription Argo workflow engine
// @param name string Name to give to the component
// @optionalParam workflowControllerImage string argoproj/workflow-controller:v2.2.0 workflowControllerImage
// @optionalParam uiImage string argoproj/argoui:v2.2.0 uiImage
// @optionalParam executorImage string argoproj/argoexec:v2.2.0 executorImage
// @optionalParam artifactRepositoryKeyPrefix string artifacts artifactRepositoryKeyPrefix
// @optionalParam artifactRepositoryEndpoint string minio-service.kubeflow:9000 artifactRepositoryEndpoint
// @optionalParam artifactRepositoryBucket string mlpipeline artifactRepositoryBucket
// @optionalParam artifactRepositoryInsecure string true artifactRepositoryInsecure
// @optionalParam artifactRepositoryAccessKeySecretName string mlpipeline-minio-artifact artifactRepositoryAccessKeySecretName
// @optionalParam artifactRepositoryAccessKeySecretKey string accesskey artifactRepositoryAccessKeySecretKey
// @optionalParam artifactRepositorySecretKeySecretName string mlpipeline-minio-artifact artifactRepositorySecretKeySecretName
// @optionalParam artifactRepositorySecretKeySecretKey string secretkey artifactRepositorySecretKeySecretKey
local argo = import "kubeflow/argo/argo.libsonnet";
local instance = argo.new(env, params);
instance.list(instance.all)

View File

@ -1,452 +0,0 @@
local argo = import "kubeflow/argo/argo.libsonnet";
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local params = {
name: "argo",
workflowControllerImage: "argoproj/workflow-controller:v2.2.0",
uiImage: "argoproj/argoui:v2.2.0",
executorImage: "argoproj/argoexec:v2.2.0",
artifactRepositoryKeyPrefix: "artifacts",
artifactRepositoryEndpoint: "minio-service.kubeflow:9000",
artifactRepositoryBucket: "mlpipeline",
artifactRepositoryInsecure: "true",
artifactRepositoryAccessKeySecretName: "mlpipeline-minio-artifact",
artifactRepositoryAccessKeySecretKey: "accesskey",
artifactRepositorySecretKeySecretName: "mlpipeline-minio-artifact",
artifactRepositorySecretKeySecretKey: "secretkey",
};
local env = {
namespace: "kubeflow",
};
local instance = argo.new(env, params);
local testCases = [
{
actual: instance.parts.workflowCRD,
expected: {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "workflows.argoproj.io",
},
spec: {
group: "argoproj.io",
names: {
kind: "Workflow",
listKind: "WorkflowList",
plural: "workflows",
shortNames: [
"wf",
],
singular: "workflow",
},
scope: "Namespaced",
version: "v1alpha1",
},
},
},
{
actual: instance.parts.workflowController,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "workflow-controller",
},
name: "workflow-controller",
namespace: "kubeflow",
},
spec: {
progressDeadlineSeconds: 600,
replicas: 1,
revisionHistoryLimit: 10,
selector: {
matchLabels: {
app: "workflow-controller",
},
},
strategy: {
rollingUpdate: {
maxSurge: "25%",
maxUnavailable: "25%",
},
type: "RollingUpdate",
},
template: {
metadata: {
creationTimestamp: null,
labels: {
app: "workflow-controller",
},
},
spec: {
containers: [
{
args: [
"--configmap",
"workflow-controller-configmap",
],
command: [
"workflow-controller",
],
env: [
{
name: "ARGO_NAMESPACE",
valueFrom: {
fieldRef: {
apiVersion: "v1",
fieldPath: "metadata.namespace",
},
},
},
],
image: "argoproj/workflow-controller:v2.2.0",
imagePullPolicy: "IfNotPresent",
name: "workflow-controller",
resources: {},
terminationMessagePath: "/dev/termination-log",
terminationMessagePolicy: "File",
},
],
dnsPolicy: "ClusterFirst",
restartPolicy: "Always",
schedulerName: "default-scheduler",
securityContext: {},
serviceAccount: "argo",
serviceAccountName: "argo",
terminationGracePeriodSeconds: 30,
},
},
},
},
},
{
actual: instance.parts.argoUI,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "argo-ui",
},
name: "argo-ui",
namespace: "kubeflow",
},
spec: {
progressDeadlineSeconds: 600,
replicas: 1,
revisionHistoryLimit: 10,
selector: {
matchLabels: {
app: "argo-ui",
},
},
strategy: {
rollingUpdate: {
maxSurge: "25%",
maxUnavailable: "25%",
},
type: "RollingUpdate",
},
template: {
metadata: {
creationTimestamp: null,
labels: {
app: "argo-ui",
},
},
spec: {
containers: [
{
env: [
{
name: "ARGO_NAMESPACE",
valueFrom: {
fieldRef: {
apiVersion: "v1",
fieldPath: "metadata.namespace",
},
},
},
{
name: "IN_CLUSTER",
value: "true",
},
{
name: "BASE_HREF",
value: "/argo/",
},
],
image: "argoproj/argoui:v2.2.0",
imagePullPolicy: "IfNotPresent",
name: "argo-ui",
readinessProbe: {
httpGet: {
path: "/",
port: 8001,
},
},
resources: {},
terminationMessagePath: "/dev/termination-log",
terminationMessagePolicy: "File",
},
],
dnsPolicy: "ClusterFirst",
restartPolicy: "Always",
schedulerName: "default-scheduler",
securityContext: {},
serviceAccount: "argo-ui",
serviceAccountName: "argo-ui",
terminationGracePeriodSeconds: 30,
},
},
},
},
},
{
actual: instance.parts.argUIService,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
annotations: {
"getambassador.io/config": "---\napiVersion: ambassador/v0\nkind: Mapping\nname: argo-ui-mapping\nprefix: /argo/\nservice: argo-ui.kubeflow",
},
labels: {
app: "argo-ui",
},
name: "argo-ui",
namespace: "kubeflow",
},
spec: {
ports: [
{
port: 80,
targetPort: 8001,
},
],
selector: {
app: "argo-ui",
},
sessionAffinity: "None",
type: "NodePort",
},
},
},
{
actual: instance.parts.workflowControllerConfigmap,
expected: {
apiVersion: "v1",
data: {
config: "{\nexecutorImage: argoproj/argoexec:v2.2.0,\nartifactRepository:\n{\n s3: {\n bucket: mlpipeline,\n keyPrefix: artifacts,\n endpoint: minio-service.kubeflow:9000,\n insecure: true,\n accessKeySecret: {\n name: mlpipeline-minio-artifact,\n key: accesskey\n },\n secretKeySecret: {\n name: mlpipeline-minio-artifact,\n key: secretkey\n }\n }\n}\n}\n",
},
kind: "ConfigMap",
metadata: {
name: "workflow-controller-configmap",
namespace: "kubeflow",
},
},
},
{
actual: instance.parts.argoServiceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "argo",
namespace: "kubeflow",
},
},
},
{
actual: instance.parts.argoClusterRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "argo",
},
name: "argo",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"pods",
"pods/exec",
],
verbs: [
"create",
"get",
"list",
"watch",
"update",
"patch",
],
},
{
apiGroups: [
"",
],
resources: [
"configmaps",
],
verbs: [
"get",
"watch",
"list",
],
},
{
apiGroups: [
"",
],
resources: [
"persistentvolumeclaims",
],
verbs: [
"create",
"delete",
],
},
{
apiGroups: [
"argoproj.io",
],
resources: [
"workflows",
],
verbs: [
"get",
"list",
"watch",
"update",
"patch",
],
},
],
},
},
{
actual: instance.parts.argoClusterRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "argo",
},
name: "argo",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "argo",
},
subjects: [
{
kind: "ServiceAccount",
name: "argo",
namespace: "kubeflow",
},
],
},
},
{
actual: instance.parts.argoUIServiceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "argo-ui",
namespace: "kubeflow",
},
},
},
{
actual: instance.parts.argoUIRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "argo",
},
name: "argo-ui",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"pods",
"pods/exec",
"pods/log",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [
"",
],
resources: [
"secrets",
],
verbs: [
"get",
],
},
{
apiGroups: [
"argoproj.io",
],
resources: [
"workflows",
],
verbs: [
"get",
"list",
"watch",
],
},
],
},
},
{
actual: instance.parts.argUIClusterRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "argo-ui",
},
name: "argo-ui",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "argo-ui",
},
subjects: [
{
kind: "ServiceAccount",
name: "argo-ui",
namespace: "kubeflow",
},
],
},
},
];
testSuite.run(testCases)

View File

@ -1,3 +0,0 @@
approvers:
- gaocegege
reviewers:

View File

@ -1,11 +0,0 @@
# common
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [common](#common)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
This ksonnet package contains kubeflow common prototypes such as ambassador, spartakus, etc. You can install this using `ks pkg install kubeflow/common`. `ks prototype list` should list the available prototypes. `ks prototype describe <name>` should describe the prototype.

View File

@ -1,226 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local ambassadorService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
service: "ambassador",
},
name: "ambassador",
namespace: params.namespace,
},
spec: {
ports: [
{
name: "ambassador",
port: 80,
targetPort: 80,
[if (params.ambassadorServiceType == 'NodePort') &&
(params.ambassadorNodePort >= 30000) &&
(params.ambassadorNodePort <= 32767)
then 'nodePort']: params.ambassadorNodePort,
},
],
selector: {
service: "ambassador",
},
type: params.ambassadorServiceType,
},
}, // service
ambassadorService:: ambassadorService,
local adminService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
service: "ambassador-admin",
},
name: "ambassador-admin",
namespace: params.namespace,
},
spec: {
ports: [
{
name: "ambassador-admin",
port: 8877,
targetPort: 8877,
},
],
selector: {
service: "ambassador",
},
type: "ClusterIP",
},
}, // adminService
adminService:: adminService,
local ambassadorRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
name: "ambassador",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"services",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [
"",
],
resources: [
"configmaps",
],
verbs: [
"create",
"update",
"patch",
"get",
"list",
"watch",
],
},
{
apiGroups: [
"",
],
resources: [
"secrets",
],
verbs: [
"get",
"list",
"watch",
],
},
],
}, // role
ambassadorRole:: ambassadorRole,
local ambassadorServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "ambassador",
namespace: params.namespace,
},
}, // serviceAccount
ambassadorServiceAccount:: ambassadorServiceAccount,
local ambassadorRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
name: "ambassador",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "ambassador",
},
subjects: [
{
kind: "ServiceAccount",
name: "ambassador",
namespace: params.namespace,
},
],
}, // roleBinding
ambassadorRoleBinding:: ambassadorRoleBinding,
local ambassadorDeployment = {
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
name: "ambassador",
namespace: params.namespace,
},
spec: {
replicas: params.replicas,
template: {
metadata: {
labels: {
service: "ambassador",
},
namespace: params.namespace,
},
spec: {
containers: [
{
env: [
{
name: "AMBASSADOR_NAMESPACE",
valueFrom: {
fieldRef: {
fieldPath: "metadata.namespace",
},
},
},
],
image: params.ambassadorImage,
name: "ambassador",
resources: {
limits: {
cpu: 1,
memory: "400Mi",
},
requests: {
cpu: "200m",
memory: "100Mi",
},
},
readinessProbe: {
httpGet: {
path: "/ambassador/v0/check_ready",
port: 8877,
},
initialDelaySeconds: 30,
periodSeconds: 30,
},
livenessProbe: {
httpGet: {
path: "/ambassador/v0/check_alive",
port: 8877,
},
initialDelaySeconds: 30,
periodSeconds: 30,
},
},
],
restartPolicy: "Always",
serviceAccountName: "ambassador",
},
},
},
}, // deploy
ambassadorDeployment:: ambassadorDeployment,
parts:: self,
all:: [
self.ambassadorService,
self.adminService,
self.ambassadorRole,
self.ambassadorServiceAccount,
self.ambassadorRoleBinding,
self.ambassadorDeployment,
],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,197 +0,0 @@
{
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local ui_name = params.name + "-login",
local authService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: params.name,
},
name: params.name,
namespace: params.namespace,
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: AuthService",
"name: " + params.name,
"auth_service: " + params.name + "." + params.namespace + ":8085",
'allowed_headers:\n- "x-from-login"',
]),
}, //annotations
},
spec: {
ports: [
{
port: 8085,
targetPort: 8085,
},
],
selector: {
app: params.name,
},
type: "ClusterIP",
},
},
authService:: authService,
local authDeployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: params.name,
namespace: params.namespace,
},
spec: {
// replicas here should always be 1:
// we store auth cookies in memory and we don't support share them among pods.
replicas: 1,
strategy: {
type: "RollingUpdate",
},
template: {
metadata: {
labels: {
app: params.name,
},
},
spec: {
containers: [
{
image: params.image,
name: "app",
workingDir: "/opt/kubeflow",
env: [
{
name: "USERNAME",
valueFrom: {
secretKeyRef: {
name: params.authSecretName,
key: "username",
},
},
},
{
name: "PASSWORDHASH",
valueFrom: {
secretKeyRef: {
name: params.authSecretName,
key: "passwordhash",
},
},
},
],
command: [
"/opt/kubeflow/gatekeeper",
],
args: [
"--username=$(USERNAME)",
"--pwhash=$(PASSWORDHASH)",
],
ports: [
{
containerPort: 8085,
},
],
},
],
},
},
},
},
authDeployment:: authDeployment,
local loginService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: ui_name,
},
name: ui_name,
namespace: params.namespace,
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: kflogin-mapping",
"prefix: /kflogin",
"rewrite: /kflogin",
"timeout_ms: 300000",
"service: " + ui_name + "." + params.namespace,
"use_websocket: true",
]),
}, //annotations
},
spec: {
ports: [
{
port: 80,
targetPort: 5000,
},
],
selector: {
app: ui_name,
},
type: "ClusterIP",
},
},
loginService:: loginService,
local loginDeployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: ui_name,
namespace: params.namespace,
},
spec: {
replicas: 1,
strategy: {
type: "RollingUpdate",
},
template: {
metadata: {
labels: {
app: ui_name,
},
},
spec: {
containers: [
{
image: params.imageui,
name: "app",
ports: [
{
containerPort: 5000,
},
],
},
],
},
},
},
},
loginDeployment:: loginDeployment,
parts:: self,
all:: [
self.authService,
self.authDeployment,
self.loginService,
self.loginDeployment,
],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,221 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local centralDashboardDeployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: params.namespace,
},
spec: {
template: {
metadata: {
labels: {
app: "centraldashboard",
},
},
spec: {
containers: [
{
image: params.image,
name: "centraldashboard",
ports: [
{
containerPort: 8082,
},
],
},
],
serviceAccountName: "centraldashboard",
},
},
},
}, // deployUi
centralDashboardDeployment:: centralDashboardDeployment,
local centralDashboardService = {
// Due to https://github.com/ksonnet/ksonnet/issues/670, escaped characters in
// jsonnet files are not interpreted correctly by ksonnet, which causes runtime
// parsing failures. This is fixed in ksonnet 0.12.0, so we can merge this back
// to the jsonnet file when we take a dependency on ksonnet 0.12.0 or later.
local annotations = function(namespace) {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: centralui-mapping",
"prefix: /",
"rewrite: /",
"service: centraldashboard." + namespace,
]),
},
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: params.namespace,
annotations: annotations(params.namespace),
},
spec: {
ports: [
{
port: 80,
targetPort: 8082,
},
],
selector: {
app: "centraldashboard",
},
sessionAffinity: "None",
type: "ClusterIP",
},
}, //service
centralDashboardService:: centralDashboardService,
local centralDashboardServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "centraldashboard",
namespace: params.namespace,
},
}, // service account
centralDashboardServiceAccount:: centralDashboardServiceAccount,
local centralDashboardRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "Role",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: params.namespace,
},
rules: [
{
apiGroups: [""],
resources: [
"pods",
"pods/exec",
"pods/log",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [""],
resources: [
"secrets",
],
verbs: [
"get",
],
},
],
}, // role
centralDashboardRole:: centralDashboardRole,
local centralDashboardRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "RoleBinding",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: params.namespace,
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "Role",
name: "centraldashboard",
},
subjects: [
{
kind: "ServiceAccount",
name: "centraldashboard",
namespace: params.namespace,
},
],
}, // role binding
centralDashboardRoleBinding:: centralDashboardRoleBinding,
local centralDashboardClusterRole = {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRole",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
},
rules: [
{
apiGroups: [""],
resources: [
"namespaces",
"events"
],
verbs: [
"get",
"list",
"watch",
],
}
],
}, // clusterrole
centralDashboardClusterRole:: centralDashboardClusterRole,
local centralDashboardClusterRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "centraldashboard",
},
subjects: [
{
kind: "ServiceAccount",
name: "centraldashboard",
namespace: params.namespace,
},
],
}, // clusterrolebinding
centralDashboardClusterRoleBinding:: centralDashboardClusterRoleBinding,
parts:: self,
all:: [
self.centralDashboardDeployment,
self.centralDashboardService,
self.centralDashboardServiceAccount,
self.centralDashboardRole,
self.centralDashboardRoleBinding,
self.centralDashboardClusterRole,
self.centralDashboardClusterRoleBinding,
],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,94 +0,0 @@
{
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local service = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: params.name,
},
name: params.name,
namespace: params.namespace,
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: " + params.name + "-mapping",
"prefix: /" + params.name,
"rewrite: /",
"service: " + params.name + "." + params.namespace,
]),
}, //annotations
},
spec: {
ports: [
{
port: 80,
targetPort: 8080,
},
],
selector: {
app: params.name,
},
type: "ClusterIP",
},
},
service:: service,
local deployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: params.name,
namespace: params.namespace,
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: params.name,
},
},
spec: {
containers: [
{
image: params.image,
name: "app",
ports: [
{
containerPort: 8080,
},
],
readinessProbe: {
httpGet: {
path: "/headers",
port: 8080,
},
initialDelaySeconds: 5,
periodSeconds: 30,
},
},
],
},
},
},
},
deployment:: deployment,
parts:: self,
all:: [
self.service,
self.deployment,
],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,35 +0,0 @@
{
"name": "common",
"apiVersion": "0.0.1",
"kind": "ksonnet.io/parts",
"description": "Common components of Kubeflow.\n",
"author": "kubeflow team <kubeflow-team@google.com>",
"contributors": [
{
"name": "Jeremy Lewi",
"email": "jlewi@google.com"
}
],
"repository": {
"type": "git",
"url": "https://github.com/kubeflow/kubeflow"
},
"bugs": {
"url": "https://github.com/kubeflow/kubeflow/issues"
},
"keywords": [
"kubeflow",
"tensorflow"
],
"quickStart": {
"prototype": "io.ksonnet.pkg.kubeflow",
"componentName": "common",
"flags": {
"name": "common",
"namespace": "default",
"disks": ""
},
"comment": "Common Kubeflow components."
},
"license": "Apache 2.0"
}

View File

@ -1,14 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.ambassador
// @description Ambassador Component
// @shortDescription Ambassador
// @param name string Name
// @optionalParam platform string none supported platforms {none|gke|minikube}
// @optionalParam ambassadorServiceType string ClusterIP The service type for the API Gateway {ClusterIP|NodePort|LoadBalancer}.
// @optionalParam ambassadorNodePort number 0 Optional nodePort to use when ambassadorServiceType is NodePort {30000-32767}.
// @optionalParam ambassadorImage string quay.io/datawire/ambassador:0.37.0 The image for the API Gateway.
// @optionalParam replicas number 3 The number of replicas.
local ambassador = import "kubeflow/common/ambassador.libsonnet";
local instance = ambassador.new(env, params);
instance.list(instance.all)

View File

@ -1,12 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.basic-auth
// @description Provides http basic auth for all ambassador traffic.
// @shortDescription Http basic auth.
// @param name string Name for the component
// @optionalParam authSecretName string kubeflow-login Contains username and passwordhash for UI/API auth.
// @optionalParam image string gcr.io/kubeflow-images-public/gatekeeper:v0.5.0 Auth service image to use.
// @optionalParam imageui string gcr.io/kubeflow-images-public/kflogin-ui:v0.5.0 UI image to use.
local basicauth = import "kubeflow/common/basic-auth.libsonnet";
local instance = basicauth.new(env, params);
instance.list(instance.all)

View File

@ -1,10 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.centraldashboard
// @description centraldashboard Component
// @shortDescription centraldashboard
// @param name string Name
// @optionalParam image string gcr.io/kubeflow-images-public/centraldashboard:v0.5.0 Image for the central dashboard
local centraldashboard = import "kubeflow/common/centraldashboard.libsonnet";
local instance = centraldashboard.new(env, params);
instance.list(instance.all)

View File

@ -1,10 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.echo-server
// @description Provides a simple server for testing connections; primarily IAP.
// @shortDescription A simple echo server.
// @param name string Name for the component
// @optionalParam image string gcr.io/kubeflow-images-staging/echo-server:v20180628-44f08d31 The image to use.
local echoserver = import "kubeflow/common/echo-server.libsonnet";
local instance = echoserver.new(env, params);
instance.list(instance.all)

View File

@ -1,11 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.spartakus
// @description spartakus component for usage collection
// @shortDescription spartakus component for usage collection
// @param name string Name
// @optionalParam usageId string unknown_cluster Optional id to use when reporting usage to kubeflow.org
// @optionalParam reportUsage string false Whether or not to report Kubeflow usage to kubeflow.org.
local spartakus = import "kubeflow/common/spartakus.libsonnet";
local instance = spartakus.new(env, params);
instance.list(instance.all)

View File

@ -1,122 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env {
reportUsageBool: util.toBool(_params.reportUsage),
},
// Spartakus needs to be able to get information about the cluster to create a report.
local clusterRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"nodes",
],
verbs: [
"get",
"list",
],
},
],
}, // role
clusterRole:: clusterRole,
local clusterRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "spartakus",
},
subjects: [
{
kind: "ServiceAccount",
name: "spartakus",
namespace: params.namespace,
},
],
}, // operator-role binding
clusterRoleBinding:: clusterRoleBinding,
local serviceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus",
namespace: params.namespace,
},
},
serviceAccount:: serviceAccount,
local volunteer = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: "spartakus-volunteer",
namespace: params.namespace,
labels: {
app: "spartakus",
},
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "spartakus-volunteer",
},
},
spec: {
containers: [
{
image: "gcr.io/google_containers/spartakus-amd64:v1.1.0",
name: "volunteer",
args: [
"volunteer",
"--cluster-id=" + params.usageId,
"--database=https://stats-collector.kubeflow.org",
],
},
],
serviceAccountName: "spartakus",
}, // spec
},
},
}, // deployment
volunteer:: volunteer,
parts:: self,
all:: if params.reportUsageBool then (
[
self.clusterRole,
self.clusterRoleBinding,
self.serviceAccount,
self.volunteer,
]
) else [],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,231 +0,0 @@
local ambassador = import "kubeflow/common/ambassador.libsonnet";
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local params = {
name: "ambassador",
platform: "gke",
ambassadorServiceType: "ClusterIP",
ambassadorImage: "quay.io/datawire/ambassador:0.37.0",
replicas: 3,
};
local env = {
namespace: "kubeflow",
};
local instance = ambassador.new(env, params);
local testCases = [
{
actual: instance.parts.ambassadorService,
expected:
{
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
service: "ambassador",
},
name: "ambassador",
namespace: "kubeflow",
},
spec: {
ports: [
{
name: "ambassador",
port: 80,
targetPort: 80,
},
],
selector: {
service: "ambassador",
},
type: "ClusterIP",
},
},
},
{
actual: instance.parts.adminService,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
service: "ambassador-admin",
},
name: "ambassador-admin",
namespace: "kubeflow",
},
spec: {
ports: [
{
name: "ambassador-admin",
port: 8877,
targetPort: 8877,
},
],
selector: {
service: "ambassador",
},
type: "ClusterIP",
},
},
},
{
actual: instance.parts.ambassadorRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
name: "ambassador",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"services",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [
"",
],
resources: [
"configmaps",
],
verbs: [
"create",
"update",
"patch",
"get",
"list",
"watch",
],
},
{
apiGroups: [
"",
],
resources: [
"secrets",
],
verbs: [
"get",
"list",
"watch",
],
},
],
},
},
{
actual: instance.parts.ambassadorServiceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "ambassador",
namespace: "kubeflow",
},
},
},
{
actual: instance.parts.ambassadorRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
name: "ambassador",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "ambassador",
},
subjects: [
{
kind: "ServiceAccount",
name: "ambassador",
namespace: "kubeflow",
},
],
},
},
{
actual: instance.parts.ambassadorDeployment,
expected:
{
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
name: "ambassador",
namespace: "kubeflow",
},
spec: {
replicas: 3,
template: {
metadata: {
labels: {
service: "ambassador",
},
namespace: "kubeflow",
},
spec: {
containers: [
{
env: [
{
name: "AMBASSADOR_NAMESPACE",
valueFrom: {
fieldRef: {
fieldPath: "metadata.namespace",
},
},
},
],
image: "quay.io/datawire/ambassador:0.37.0",
livenessProbe: {
httpGet: {
path: "/ambassador/v0/check_alive",
port: 8877,
},
initialDelaySeconds: 30,
periodSeconds: 30,
},
name: "ambassador",
readinessProbe: {
httpGet: {
path: "/ambassador/v0/check_ready",
port: 8877,
},
initialDelaySeconds: 30,
periodSeconds: 30,
},
resources: {
limits: {
cpu: 1,
memory: "400Mi",
},
requests: {
cpu: "200m",
memory: "100Mi",
},
},
},
],
restartPolicy: "Always",
serviceAccountName: "ambassador",
},
},
},
},
},
];
testSuite.run(testCases)

View File

@ -1,167 +0,0 @@
local centraldashboard = import "../centraldashboard.libsonnet";
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local params = {
image: "gcr.io/kubeflow-images-public/centraldashboard:v0.3.0",
};
local env = {
namespace: "kftest",
};
local centraldash = centraldashboard.new(params, env);
local testCases = [
{
actual: centraldash.centralDashboardDeployment,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: "kftest",
},
spec: {
template: {
metadata: {
labels: {
app: "centraldashboard",
},
},
spec: {
containers: [
{
image: "gcr.io/kubeflow-images-public/centraldashboard:v0.3.0",
name: "centraldashboard",
ports: [
{
containerPort: 8082,
},
],
},
],
serviceAccountName: "centraldashboard",
},
},
},
},
},
{
actual: centraldash.centralDashboardService,
expected: {
local annotations = function(namespace) {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: centralui-mapping",
"prefix: /",
"rewrite: /",
"service: centraldashboard." + namespace,
]),
},
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: "kftest",
annotations: annotations("kftest"),
},
spec: {
ports: [
{
port: 80,
targetPort: 8082,
},
],
selector: {
app: "centraldashboard",
},
sessionAffinity: "None",
type: "ClusterIP",
},
},
},
{
actual: centraldash.centralDashboardServiceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "centraldashboard",
namespace: "kftest",
},
},
},
{
actual: centraldash.centralDashboardRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "Role",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: "kftest",
},
rules: [
{
apiGroups: [""],
resources: [
"pods",
"pods/exec",
"pods/log",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [""],
resources: [
"secrets",
],
verbs: [
"get",
],
},
],
},
},
{
actual: centraldash.centralDashboardRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "RoleBinding",
metadata: {
labels: {
app: "centraldashboard",
},
name: "centraldashboard",
namespace: "kftest",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "Role",
name: "centraldashboard",
},
subjects: [
{
kind: "ServiceAccount",
name: "centraldashboard",
namespace: "kftest",
},
],
},
},
];
testSuite.run(testCases)

View File

@ -1,88 +0,0 @@
local echoServer = import "kubeflow/common/echo-server.libsonnet";
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local params = {
name: "echo-server",
image: "gcr.io/kubeflow-images-staging/echo-server:v20180628-44f08d31",
};
local env = {
namespace: "kubeflow",
};
local instance = echoServer.new(env, params);
local testCases = [
{
actual: instance.parts.service,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
annotations: {
"getambassador.io/config": "---\napiVersion: ambassador/v0\nkind: Mapping\nname: echo-server-mapping\nprefix: /echo-server\nrewrite: /\nservice: echo-server.kubeflow",
},
labels: {
app: "echo-server",
},
name: "echo-server",
namespace: "kubeflow",
},
spec: {
ports: [
{
port: 80,
targetPort: 8080,
},
],
selector: {
app: "echo-server",
},
type: "ClusterIP",
},
},
},
{
actual: instance.parts.deployment,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: "echo-server",
namespace: "kubeflow",
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "echo-server",
},
},
spec: {
containers: [
{
image: "gcr.io/kubeflow-images-staging/echo-server:v20180628-44f08d31",
name: "app",
ports: [
{
containerPort: 8080,
},
],
readinessProbe: {
httpGet: {
path: "/headers",
port: 8080,
},
initialDelaySeconds: 5,
periodSeconds: 30,
},
},
],
},
},
},
},
},
];
testSuite.run(testCases)

View File

@ -1,122 +0,0 @@
local spartakus = import "kubeflow/common/spartakus.libsonnet";
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local params = {
name: "spartakus",
usageId: "unknown_cluster",
reportUsage: "false",
};
local env = {
namespace: "kubeflow",
};
local instance = spartakus.new(env, params);
local testCases = [
{
actual: instance.parts.clusterRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"nodes",
],
verbs: [
"get",
"list",
],
},
],
},
},
{
actual: instance.parts.clusterRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "spartakus",
},
subjects: [
{
kind: "ServiceAccount",
name: "spartakus",
namespace: "kubeflow",
},
],
},
},
{
actual: instance.parts.serviceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus",
namespace: "kubeflow",
},
},
},
{
actual: instance.parts.volunteer,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "spartakus",
},
name: "spartakus-volunteer",
namespace: "kubeflow",
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "spartakus-volunteer",
},
},
spec: {
containers: [
{
args: [
"volunteer",
"--cluster-id=unknown_cluster",
"--database=https://stats-collector.kubeflow.org",
],
image: "gcr.io/google_containers/spartakus-amd64:v1.1.0",
name: "volunteer",
},
],
serviceAccountName: "spartakus",
},
},
},
},
},
];
testSuite.run(testCases)

View File

@ -1,56 +0,0 @@
local util = import "../util.libsonnet";
std.assertEqual(util.lower("aTruez"), "atruez") &&
std.assertEqual(util.lower("ATrUez"), "atruez") &&
std.assertEqual(util.lower("atruez"), "atruez") &&
std.assertEqual(util.lower("ATRUEZ"), "atruez") &&
std.assertEqual(util.toBool(false), false) &&
std.assertEqual(util.toBool(true), true) &&
std.assertEqual(util.toBool("true"), true) &&
std.assertEqual(util.toBool("True"), true) &&
std.assertEqual(util.toBool("TRUE"), true) &&
std.assertEqual(util.toBool("false"), false) &&
std.assertEqual(util.toBool("False"), false) &&
std.assertEqual(util.toBool("FALSE"), false) &&
std.assertEqual(util.toBool("random string"), false) &&
std.assertEqual(util.toBool(1), true) &&
std.assertEqual(util.toBool(0), false) &&
std.assertEqual(util.toBool(123), true) &&
std.assertEqual(util.toArray("a,b,c,d"), ["a", "b", "c", "d"]) &&
std.assertEqual(util.toArray("ca, or,fl, mo"), ["ca", "or", "fl", "mo"]) &&
std.assertEqual(std.length(util.toArray(2)), 0) &&
std.assertEqual(std.length(util.toArray("hello world")), 1) &&
std.assertEqual(std.length(util.toArray([1, 2, 3, 4])), 0) &&
std.assertEqual(util.sort(["Craydad", "CCall", "crayon"]), ["CCall", "Craydad", "crayon"]) &&
std.assertEqual(
{
new():: self + {
local configMap = {
kind: "ConfigMap",
},
local service = {
kind: "Service",
},
list:: util.list([configMap, service]),
},
}.new().list,
{
apiVersion: "v1",
items: [
{
kind: "ConfigMap",
},
{
kind: "Service",
},
],
kind: "List",
}
) &&
std.assertEqual(
util.setDiff(
util.sort(["CCall", "Craydad", "crayon", "fuzzball"]),
util.sort(["CCall", "Craydad", "crayon"])
),
["fuzzball"]
)

View File

@ -1,29 +0,0 @@
// Some useful routines.
{
run:: function(testCases) {
local testEqual(x) = x {
pass: x.actual == x.expected,
},
local curry(testCases) = {
// For each test case determine whether expected matches equals
local testCasesWithResults = std.map(
testEqual,
testCases,
),
return::
testCasesWithResults,
}.return,
// Compute test suite.
local foldResults(left, right) = {
pass: left.pass && right.pass,
},
local initResult = { pass: true },
local suiteResult = std.foldl(foldResults, curry(testCases), initResult),
local testSuite = suiteResult {
testCases: curry(testCases),
},
result::
testSuite,
}.result,
}

View File

@ -1,207 +0,0 @@
// Some useful routines.
{
local k = import "k.libsonnet",
local util = self,
// Convert a string to lower case.
lower:: function(x) {
local cp(c) = std.codepoint(c),
local lowerLetter(c) = if cp(c) >= 65 && cp(c) < 91 then
std.char(cp(c) + 32)
else c,
result:: std.join("", std.map(lowerLetter, std.stringChars(x))),
}.result,
// Convert non-boolean types like string,number to a boolean.
// This is primarily intended for dealing with parameters that should be booleans.
toBool:: function(x) {
result::
if std.type(x) == "boolean" then
x
else if std.type(x) == "string" then
std.asciiUpper(x) == "TRUE"
else if std.type(x) == "number" then
x != 0
else
false,
}.result,
// Convert a comma-delimited string to an Array
toArray:: function(str) {
local trim(str) = {
rest::
if std.startsWith(str, " ") then
std.substr(str, 1, std.length(str) - 1)
else
str,
}.rest,
result::
if std.type(str) == "string" && str != "null" && std.length(str) > 0 then
std.map(trim, std.split(str, ","))
else [],
}.result,
foldl:: function(key, value, objs) {
local aux(arr, i, running) =
if i >= std.length(arr) then
running
else
aux(arr, i + 1, running { [key(arr[i])]+: value(arr[i]) }) tailstrict,
return:: aux(objs, 0, {},),
}.return,
sort:: function(arr, compare=function(a, b) {
return::
if a == b then
0
else
if a < b then
-1
else
1,
}.return) {
local _sort(arr, compare) = {
local l = std.length(arr),
local f = {
local pivot = arr[0],
local rest = std.makeArray(l - 1, function(i) arr[i + 1]),
local lessorequal(x) = compare(x, pivot) <= 0,
local greater(x) = compare(x, pivot) > 0,
local left = _sort(std.filter(lessorequal, rest), compare) tailstrict,
local right = _sort(std.filter(greater, rest), compare) tailstrict,
return:: left + [pivot] + right,
}.return,
return::
if l == 0 then
[]
else
f,
}.return,
return:: _sort(arr, compare),
}.return,
setDiff:: function(a, b, compare=function(a, b) {
return::
if a == b then
0
else if a < b then
-1
else
1,
}.return) {
local aux(a, b, i, j, acc) =
if i >= std.length(a) then
acc
else
if j >= std.length(b) then
aux(a, b, i + 1, j, acc + [a[i]]) tailstrict
else
if compare(a[i], b[j]) == 0 then
aux(a, b, i + 1, j + 1, acc) tailstrict
else
if compare(a[i], b[j]) == -1 then
aux(a, b, i + 1, j, acc + [a[i]]) tailstrict
else
aux(a, b, i, j + 1, acc) tailstrict,
return:: aux(a, b, 0, 0, []) tailstrict,
}.return,
getApiVersionKindAndMetadata(resource):: {
return::
if std.objectHas(resource.metadata, "resourceVersion") then {
apiVersion: resource.apiVersion,
kind: resource.kind,
metadata: {
labels: resource.metadata.labels,
name: resource.metadata.name,
namespace: resource.metadata.namespace,
resourceVersion: resource.metadata.resourceVersion,
}
} else {
apiVersion: resource.apiVersion,
kind: resource.kind,
metadata: {
labels: resource.metadata.labels,
name: resource.metadata.name,
namespace: resource.metadata.namespace,
},
},
}.return,
groupByResource(resources):: {
local getKey(resource) = {
return::
resource.kind,
}.return,
local getValue(resource) = {
return::
{ [resource.metadata.name]+: resource },
}.return,
return:: util.foldl(getKey, getValue, resources),
}.return,
comparator(a, b):: {
return::
if a.metadata.name == b.metadata.name then
0
else
if a.metadata.name < b.metadata.name then
-1
else
1,
}.return,
validateResource(resource):: {
return::
if std.type(resource) == "object" &&
std.objectHas(resource, "kind") &&
std.objectHas(resource, "apiVersion") &&
std.objectHas(resource, "metadata") &&
std.objectHas(resource.metadata, "name") then
true
else
false,
}.return,
extractGroups(obj)::
if std.type(obj) == "object" then
[obj[key] for key in std.objectFields(obj)]
else
[],
extractResources(group)::
if std.type(group) == "object" then
[group[key] for key in std.objectFields(group)]
else
[],
curryResources(resources, exists):: {
local existingResource(resource) = {
local resourceExists(kind, name) = {
return::
if std.objectHas(resources, kind) &&
std.objectHas(resources[kind], name) then
true
else
false,
}.return,
return::
if util.validateResource(resource) then
resourceExists(resource.kind, resource.metadata.name)
else
false,
}.return,
local missingResource(resource) = {
return::
existingResource(resource) == false,
}.return,
return::
if exists == true then
existingResource
else
missingResource,
}.return,
// Produce a list of manifests. obj must be an array
list(obj):: k.core.v1.list.new(obj,),
}

View File

@ -1,8 +0,0 @@
{
"Major": "0",
"Minor": "2",
"Patch": "devel",
"GitCommit": "",
"BuildDate": "",
"ksonnetVersion": "0.9.2",
}

View File

@ -1,15 +0,0 @@
{
all(params):: [
{
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "kubeflow-version",
namespace: params.namespace,
},
data: {
"kubeflow-version": importstr "version-info.json",
},
},
],
}

View File

@ -1,22 +0,0 @@
{
"name": "kubeflow examples",
"apiVersion": "0.0.1",
"kind": "ksonnet.io/parts",
"description": "kubeflow examples.\n",
"author": "kubeflow-team <kubeflow-discuss@googlegroups.com>",
"contributors": [
],
"repository": {
"type": "git",
"url": "https://github.com/kubeflow/kubeflow"
},
"bugs": {
"url": "https://github.com/kubeflow/kubeflow/issues"
},
"keywords": [
"kubernetes",
"kubeflow",
"machine learning"
],
"license": "Apache 2.0",
}

View File

@ -1,88 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.katib-studyjob-test-v1alpha1
// @description katib-studyjob-test
// @shortDescription A Katib StudyJob using random suggestion
// @param name string Name for the job.
local k = import "k.libsonnet";
local name = params.name;
local namespace = env.namespace;
local studyjob = {
apiVersion: "kubeflow.org/v1alpha1",
kind: "StudyJob",
metadata: {
name: name,
namespace: namespace,
},
spec: {
studyName: name,
owner: "crd",
optimizationtype: "maximize",
objectivevaluename: "Validation-accuracy",
optimizationgoal: 0.99,
requestcount: 1,
metricsnames: ["accuracy"],
parameterconfigs: [
{
name: "--lr",
parametertype: "double",
feasible: {
min: "0.01",
max: "0.03",
},
},
{
name: "--num-layers",
parametertype: "int",
feasible: {
min: "2",
max: "5",
},
},
{
name: "--optimizer",
parametertype: "categorical",
feasible: {
list: ["sgd", "adam", "ftrl"],
},
},
],
workerSpec: {
goTemplate: {
rawTemplate: |||
apiVersion: batch/v1
kind: Job
metadata:
name: {{.WorkerID}}
namespace: {{.NameSpace}}
spec:
template:
spec:
containers:
- name: {{.WorkerID}}
image: katib/mxnet-mnist-example
command:
- "python"
- "/mxnet/example/image-classification/train_mnist.py"
- "--batch-size=64"
{{- with .HyperParameters}}
{{- range .}}
- "{{.Name}}={{.Value}}"
{{- end}}
{{- end}}
restartPolicy: Never
|||,
},
},
suggestionSpec: {
suggestionAlgorithm: "random",
requestNumber: 1,
},
},
};
k.core.v1.list.new([
studyjob,
])

View File

@ -1,14 +0,0 @@
// @apiVersion 1
// @name io.ksonnet.pkg.tensorboard
// @description Tensorboard components
// @shortDescription ksonnet components for Tensorboard
// @param name string Name to give to each of the components
// @optionalParam logDir string logs Name of the log directory holding the TF events file
// @optionalParam targetPort number 6006 Name of the targetPort
// @optionalParam servicePort number 9000 Name of the servicePort
// @optionalParam serviceType string ClusterIP The service type for tensorboard service
// @optionalParam defaultTbImage string tensorflow/tensorflow:1.8.0 default tensorboard image to use
local tensorboard = import "kubeflow/tensorboard/tensorboard.libsonnet";
local instance = tensorboard.new(env, params);
instance.list(instance.all)

View File

@ -1,82 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.tf-job-simple-v1beta1
// @description tf-job-simple
// @shortDescription A simple TFJob to run CNN benchmark
// @param name string Name for the job.
local k = import "k.libsonnet";
local name = params.name;
local namespace = env.namespace;
local image = "gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3";
local tfjob = {
apiVersion: "kubeflow.org/v1beta1",
kind: "TFJob",
metadata: {
name: name,
namespace: namespace,
},
spec: {
tfReplicaSpecs: {
Worker: {
replicas: 1,
template: {
spec: {
containers: [
{
args: [
"python",
"tf_cnn_benchmarks.py",
"--batch_size=32",
"--model=resnet50",
"--variable_update=parameter_server",
"--flush_stdout=true",
"--num_gpus=1",
"--local_parameter_device=cpu",
"--device=cpu",
"--data_format=NHWC",
],
image: image,
name: "tensorflow",
workingDir: "/opt/tf-benchmarks/scripts/tf_cnn_benchmarks",
},
],
restartPolicy: "OnFailure",
},
},
},
Ps: {
template: {
spec: {
containers: [
{
args: [
"python",
"tf_cnn_benchmarks.py",
"--batch_size=32",
"--model=resnet50",
"--variable_update=parameter_server",
"--flush_stdout=true",
"--num_gpus=1",
"--local_parameter_device=cpu",
"--device=cpu",
"--data_format=NHWC",
],
image: image,
name: "tensorflow",
workingDir: "/opt/tf-benchmarks/scripts/tf_cnn_benchmarks",
},
],
restartPolicy: "OnFailure",
},
},
tfReplicaType: "PS",
},
},
},
};
k.core.v1.list.new([
tfjob,
])

View File

@ -1,82 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.tf-job-simple-v1beta2
// @description tf-job-simple
// @shortDescription A simple TFJob to run CNN benchmark
// @param name string Name for the job.
local k = import "k.libsonnet";
local name = params.name;
local namespace = env.namespace;
local image = "gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3";
local tfjob = {
apiVersion: "kubeflow.org/v1beta2",
kind: "TFJob",
metadata: {
name: name,
namespace: namespace,
},
spec: {
tfReplicaSpecs: {
Worker: {
replicas: 1,
template: {
spec: {
containers: [
{
args: [
"python",
"tf_cnn_benchmarks.py",
"--batch_size=32",
"--model=resnet50",
"--variable_update=parameter_server",
"--flush_stdout=true",
"--num_gpus=1",
"--local_parameter_device=cpu",
"--device=cpu",
"--data_format=NHWC",
],
image: image,
name: "tensorflow",
workingDir: "/opt/tf-benchmarks/scripts/tf_cnn_benchmarks",
},
],
restartPolicy: "OnFailure",
},
},
},
Ps: {
template: {
spec: {
containers: [
{
args: [
"python",
"tf_cnn_benchmarks.py",
"--batch_size=32",
"--model=resnet50",
"--variable_update=parameter_server",
"--flush_stdout=true",
"--num_gpus=1",
"--local_parameter_device=cpu",
"--device=cpu",
"--data_format=NHWC",
],
image: image,
name: "tensorflow",
workingDir: "/opt/tf-benchmarks/scripts/tf_cnn_benchmarks",
},
],
restartPolicy: "OnFailure",
},
},
tfReplicaType: "PS",
},
},
},
};
k.core.v1.list.new([
tfjob,
])

View File

@ -1,82 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.tf-job-simple
// @description tf-job-simple
// @shortDescription A simple TFJob to run CNN benchmark
// @param name string Name for the job.
local k = import "k.libsonnet";
local name = params.name;
local namespace = env.namespace;
local image = "gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3";
local tfjob = {
apiVersion: "kubeflow.org/v1alpha2",
kind: "TFJob",
metadata: {
name: name,
namespace: namespace,
},
spec: {
tfReplicaSpecs: {
Worker: {
replicas: 1,
template: {
spec: {
containers: [
{
args: [
"python",
"tf_cnn_benchmarks.py",
"--batch_size=32",
"--model=resnet50",
"--variable_update=parameter_server",
"--flush_stdout=true",
"--num_gpus=1",
"--local_parameter_device=cpu",
"--device=cpu",
"--data_format=NHWC",
],
image: image,
name: "tensorflow",
workingDir: "/opt/tf-benchmarks/scripts/tf_cnn_benchmarks",
},
],
restartPolicy: "OnFailure",
},
},
},
Ps: {
template: {
spec: {
containers: [
{
args: [
"python",
"tf_cnn_benchmarks.py",
"--batch_size=32",
"--model=resnet50",
"--variable_update=parameter_server",
"--flush_stdout=true",
"--num_gpus=1",
"--local_parameter_device=cpu",
"--device=cpu",
"--data_format=NHWC",
],
image: image,
name: "tensorflow",
workingDir: "/opt/tf-benchmarks/scripts/tf_cnn_benchmarks",
},
],
restartPolicy: "OnFailure",
},
},
tfReplicaType: "PS",
},
},
},
};
k.core.v1.list.new([
tfjob,
])

View File

@ -1,94 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.tf-serving-simple
// @description tf-serving-simple
// @shortDescription tf-serving-simple
// @param name string Name to give to each of the components
local k = import "k.libsonnet";
local namespace = "default";
local appName = import "param://name";
local modelBasePath = "gs://kubeflow-models/inception";
local modelName = "inception";
local image = "gcr.io/kubeflow-images-public/tf-model-server-cpu:v20180327-995786ec";
local service = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: appName,
},
name: appName,
namespace: namespace,
},
spec: {
ports: [
{
name: "grpc-tf-serving",
port: 9000,
targetPort: 9000,
},
],
selector: {
app: appName,
},
type: "ClusterIP",
},
};
local deployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: appName,
},
name: appName,
namespace: namespace,
},
spec: {
template: {
metadata: {
labels: {
app: appName,
},
},
spec: {
containers: [
{
args: [
"/usr/bin/tensorflow_model_server",
"--port=9000",
"--model_name=" + modelName,
"--model_base_path=" + modelBasePath,
],
image: image,
imagePullPolicy: "IfNotPresent",
name: "inception",
ports: [
{
containerPort: 9000,
},
],
resources: {
limits: {
cpu: "4",
memory: "4Gi",
},
requests: {
cpu: "1",
memory: "1Gi",
},
},
},
],
},
},
},
};
k.core.v1.list.new([
service,
deployment,
])

View File

@ -1,179 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.tf-serving-with-istio
// @description tf-serving-with-istio
// @shortDescription tf-serving-with-istio
// @param name string Name to give to each of the components
local k = import "k.libsonnet";
local namespace = "default";
local appName = import "param://name";
local modelBasePath = "gs://kubeflow-models/inception";
local modelName = "inception";
local image = "gcr.io/kubeflow-images-public/tf-model-server-cpu:v20180327-995786ec";
local httpProxyImage = "gcr.io/kubeflow-images-public/tf-model-server-http-proxy:v20180327-995786ec";
local routeRule = {
apiVersion: "config.istio.io/v1alpha2",
kind: "RouteRule",
metadata: {
name: appName,
namespace: namespace,
},
spec: {
destination: {
name: "tf-serving",
},
precedence: 0,
route: [
{
labels: {
version: "v1",
},
},
],
},
};
local service = {
apiVersion: "v1",
kind: "Service",
metadata: {
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: tfserving-mapping-tf-serving-get",
"prefix: /models/tf-serving/",
"rewrite: /",
"method: GET",
"service: tf-serving." + namespace + ":8000",
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: tfserving-mapping-tf-serving-post",
"prefix: /models/tf-serving/",
"rewrite: /model/tf-serving:predict",
"method: POST",
"service: tf-serving." + namespace + ":8000",
]),
},
labels: {
app: appName,
},
name: appName,
namespace: namespace,
},
spec: {
ports: [
{
name: "grpc-tf-serving",
port: 9000,
targetPort: 9000,
},
{
name: "http-tf-serving-proxy",
port: 8000,
targetPort: 8000,
},
],
selector: {
app: appName,
},
type: "ClusterIP",
},
};
local deployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: appName,
},
name: appName,
namespace: namespace,
},
spec: {
template: {
metadata: {
labels: {
app: appName,
},
annotations: {
"sidecar.istio.io/inject": "true",
},
},
spec: {
containers: [
{
args: [
"/usr/bin/tensorflow_model_server",
"--port=9000",
"--model_name=" + modelName,
"--model_base_path=" + modelBasePath,
],
image: image,
imagePullPolicy: "IfNotPresent",
name: "inception",
ports: [
{
containerPort: 9000,
},
],
resources: {
limits: {
cpu: "4",
memory: "4Gi",
},
requests: {
cpu: "1",
memory: "1Gi",
},
},
},
{
name: appName + "-http-proxy",
image: httpProxyImage,
imagePullPolicy: "IfNotPresent",
command: [
"python",
"/usr/src/app/server.py",
"--port=8000",
"--rpc_port=9000",
"--rpc_timeout=10.0",
],
env: [],
ports: [
{
containerPort: 8000,
},
],
resources: {
requests: {
memory: "1Gi",
cpu: "1",
},
limits: {
memory: "4Gi",
cpu: "4",
},
},
securityContext: {
runAsUser: 1000,
fsGroup: 1000,
},
},
],
},
},
},
};
k.core.v1.list.new([
routeRule,
service,
deployment,
])

View File

@ -1,102 +0,0 @@
local tensorboard = import "kubeflow/tensorboard/tensorboard.libsonnet";
local params = {
name: "tensorboard",
logDir: "logs",
targetPort: "6006",
servicePort: "9000",
serviceType: "LoadBalancer",
defaultTbImage: "tensorflow/tensorflow:1.9.0",
};
local env = {
namespace: "test-kf-001",
};
local instance = tensorboard.new(env, params);
std.assertEqual(
instance.tbService,
{
apiVersion: "v1",
kind: "Service",
metadata: {
annotations: {
"getambassador.io/config": "---\napiVersion: ambassador/v0\nkind: Mapping\nname: tb-mapping-tensorboard-get\nprefix: /tensorboard/ tensorboard/\nrewrite: /\nmethod: GET\nservice: tensorboard.test-kf-001:9000",
},
labels: {
app: "tensorboard",
},
name: "tensorboard",
namespace: "test-kf-001",
},
spec: {
ports: [
{
name: "tb",
port: "9000",
targetPort: "6006",
},
],
selector: {
app: "tensorboard",
},
type: "LoadBalancer",
},
}
) &&
std.assertEqual(
instance.tbDeployment,
{
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "tensorboard",
},
name: "tensorboard",
namespace: "test-kf-001",
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "tensorboard",
},
},
spec: {
containers: [
{
args: [
"--logdir=logs",
"--port=6006",
],
command: [
"/usr/local/bin/tensorboard",
],
image: "tensorflow/tensorflow:1.9.0",
imagePullPolicy: "IfNotPresent",
name: "tensorboard",
ports: [
{
containerPort: "6006",
},
],
resources: {
limits: {
cpu: "4",
memory: "4Gi",
},
requests: {
cpu: "1",
memory: "1Gi",
},
},
},
],
},
},
},
}
)

View File

@ -1,7 +0,0 @@
approvers:
- abhi-g
- jlewi
- kunmingg
- lluunn
- r2d4
- richardsliu

View File

@ -1,12 +0,0 @@
# gcp
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [gcp](#gcp)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
> This ksonnet package contains GCP specific prototypes.

View File

@ -1,451 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env {
hostname: if std.objectHas(_params, "hostname") then _params.hostname else "null",
ingressName: "envoy-ingress"
},
local namespace = params.namespace,
// Test if the given hostname is in the form of: "NAME.endpoints.PROJECT.cloud.goog"
local isCloudEndpoint(str) = {
local toks = if std.type(str) == "null" then [] else std.split(str, "."),
result::
(std.length(toks) == 5 && toks[1] == "endpoints" && toks[3] == "cloud" && toks[4] == "goog"),
}.result,
local initServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "envoy",
namespace: namespace,
},
}, // initServiceAccount
initServiceAccount:: initServiceAccount,
local initClusterRoleBinding = {
kind: "ClusterRoleBinding",
apiVersion: "rbac.authorization.k8s.io/v1beta1",
metadata: {
name: "envoy",
},
subjects: [
{
kind: "ServiceAccount",
name: "envoy",
namespace: namespace,
},
],
roleRef: {
kind: "ClusterRole",
name: "envoy",
apiGroup: "rbac.authorization.k8s.io",
},
}, // initClusterRoleBinding
initClusterRoleBinding:: initClusterRoleBinding,
local initClusterRole = {
kind: "ClusterRole",
apiVersion: "rbac.authorization.k8s.io/v1beta1",
metadata: {
name: "envoy",
namespace: namespace,
},
rules: [
{
apiGroups: [""],
resources: ["services", "configmaps", "secrets"],
verbs: ["get", "list", "patch", "update"],
},
{
apiGroups: ["extensions"],
resources: ["ingresses"],
verbs: ["get", "list", "update", "patch"],
},
],
}, // initClusterRoleBinding
initClusterRole:: initClusterRole,
local configMap = {
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "envoy-config",
namespace: namespace,
},
data: {
"update_backend.sh": importstr "update_backend.sh",
},
},
configMap:: configMap,
local whoamiService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "whoami",
},
name: "whoami-app",
namespace: params.namespace,
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: whoami-mapping",
"prefix: /whoami",
"rewrite: /whoami",
"service: whoami-app." + namespace,
]),
}, //annotations
},
spec: {
ports: [
{
port: 80,
targetPort: 8081,
},
],
selector: {
app: "whoami",
},
type: "ClusterIP",
},
}, // whoamiService
whoamiService:: whoamiService,
local whoamiApp = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: "whoami-app",
namespace: params.namespace,
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "whoami",
},
},
spec: {
containers: [
{
env: [
{
name: "PORT",
value: "8081",
},
],
image: "gcr.io/cloud-solutions-group/esp-sample-app:1.0.0",
name: "app",
ports: [
{
containerPort: 8081,
},
],
readinessProbe: {
failureThreshold: 2,
httpGet: {
path: "/healthz",
port: 8081,
scheme: "HTTP",
},
periodSeconds: 10,
successThreshold: 1,
timeoutSeconds: 5,
},
},
],
},
},
},
},
whoamiApp:: whoamiApp,
// Run the process to update the backend service
local backendUpdater = {
apiVersion: "apps/v1",
kind: "StatefulSet",
metadata: {
name: "backend-updater",
namespace: namespace,
labels: {
service: "backend-updater",
},
},
spec: {
selector: {
matchLabels: {
service: "backend-updater",
},
},
template: {
metadata: {
labels: {
service: "backend-updater",
},
},
spec: {
serviceAccountName: "envoy",
containers: [
{
name: "backend-updater",
image: params.ingressSetupImage,
command: [
"bash",
"/var/envoy-config/update_backend.sh",
],
env: [
{
name: "NAMESPACE",
value: namespace,
},
{
name: "SERVICE",
value: "ambassador",
},
{
name: "GOOGLE_APPLICATION_CREDENTIALS",
value: "/var/run/secrets/sa/admin-gcp-sa.json",
},
{
name: "HEALTHCHECK_PATH",
value: "/whoami",
},
{
name: "INGRESS_NAME",
value: params.ingressName,
},
],
volumeMounts: [
{
mountPath: "/var/envoy-config/",
name: "config-volume",
},
{
name: "sa-key",
readOnly: true,
mountPath: "/var/run/secrets/sa",
},
],
},
],
volumes: [
{
configMap: {
name: "envoy-config",
},
name: "config-volume",
},
{
name: "sa-key",
secret: {
secretName: "admin-gcp-sa",
},
},
],
},
},
},
}, // backendUpdater
backendUpdater:: backendUpdater,
// TODO(danisla): Remove afer https://github.com/kubernetes/ingress-gce/pull/388 is resolved per #1327.
local ingressBootstrapConfigMap = {
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "ingress-bootstrap-config",
namespace: namespace,
},
data: {
"ingress_bootstrap.sh": importstr "ingress_bootstrap.sh",
},
},
ingressBootstrapConfigMap:: ingressBootstrapConfigMap,
local ingressBootstrapJob = {
apiVersion: "batch/v1",
kind: "Job",
metadata: {
name: "ingress-bootstrap",
namespace: namespace,
},
spec: {
template: {
spec: {
restartPolicy: "OnFailure",
serviceAccountName: "envoy",
containers: [
{
name: "bootstrap",
image: params.ingressSetupImage,
command: ["/var/ingress-config/ingress_bootstrap.sh"],
env: [
{
name: "NAMESPACE",
value: namespace,
},
{
name: "TLS_SECRET_NAME",
value: params.secretName,
},
{
name: "TLS_HOST_NAME",
value: params.hostname,
},
{
name: "INGRESS_NAME",
value: "envoy-ingress",
},
],
volumeMounts: [
{
mountPath: "/var/ingress-config/",
name: "ingress-config",
},
],
},
],
volumes: [
{
configMap: {
name: "ingress-bootstrap-config",
// TODO(danisla): replace with std.parseOctal("0755") after upgrading to ksonnet 0.12
defaultMode: 493,
},
name: "ingress-config",
},
],
},
},
},
}, // ingressBootstrapJob
ingressBootstrapJob:: ingressBootstrapJob,
local ingress = {
apiVersion: "extensions/v1beta1",
kind: "Ingress",
metadata: {
name: "envoy-ingress",
namespace: namespace,
annotations: {
"kubernetes.io/tls-acme": "true",
"ingress.kubernetes.io/ssl-redirect": "true",
"kubernetes.io/ingress.global-static-ip-name": params.ipName,
"certmanager.k8s.io/issuer": params.issuer,
},
},
spec: {
rules: [
{
[if params.hostname != "null" then "host"]: params.hostname,
http: {
paths: [
{
backend: {
// Due to https://github.com/kubernetes/contrib/blob/master/ingress/controllers/gce/examples/health_checks/README.md#limitations
// Keep port the servicePort the same as the port we are targeting on the backend so that servicePort will be the same as targetPort for the purpose of
// health checking.
serviceName: "ambassador",
servicePort: 80,
},
path: "/*",
},
],
},
},
],
},
}, // iapIngress
ingress:: ingress,
local certificate = if params.privateGKECluster == "false" then (
{
apiVersion: "certmanager.k8s.io/v1alpha1",
kind: "Certificate",
metadata: {
name: params.secretName,
namespace: namespace,
},
spec: {
secretName: params.secretName,
issuerRef: {
name: params.issuer,
kind: "ClusterIssuer",
},
commonName: params.hostname,
dnsNames: [
params.hostname,
],
acme: {
config: [
{
http01: {
ingress: "envoy-ingress",
},
domains: [
params.hostname,
],
},
],
},
},
} // certificate
),
certificate:: certificate,
local cloudEndpoint = if isCloudEndpoint(params.hostname) then (
{
local makeEndpointParams(str) = {
local toks = std.split(str, "."),
result:: {
name: toks[0],
project: toks[2],
},
}.result,
local endpointParams = makeEndpointParams(params.hostname),
apiVersion: "ctl.isla.solutions/v1",
kind: "CloudEndpoint",
metadata: {
name: endpointParams.name,
namespace: namespace,
},
spec: {
project: endpointParams.project,
targetIngress: {
name: "envoy-ingress",
namespace: namespace,
},
},
} // cloudEndpoint
),
cloudEndpoint:: cloudEndpoint,
parts:: self,
all:: [
self.initServiceAccount,
self.initClusterRoleBinding,
self.initClusterRole,
self.whoamiService,
self.whoamiApp,
self.backendUpdater,
self.configMap,
self.ingressBootstrapConfigMap,
self.ingressBootstrapJob,
self.ingress,
self.certificate,
self.cloudEndpoint,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,189 +0,0 @@
{
local k = import "k.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local certificateCRD = {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "certificates.certmanager.k8s.io",
},
spec: {
group: "certmanager.k8s.io",
version: "v1alpha1",
names: {
kind: "Certificate",
plural: "certificates",
},
scope: "Namespaced",
},
},
certificateCRD:: certificateCRD,
local clusterIssuerCRD = {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "clusterissuers.certmanager.k8s.io",
},
spec: {
group: "certmanager.k8s.io",
version: "v1alpha1",
names: {
kind: "ClusterIssuer",
plural: "clusterissuers",
},
scope: "Cluster",
},
},
clusterIssuerCRD:: clusterIssuerCRD,
local issuerCRD = {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "issuers.certmanager.k8s.io",
},
spec: {
group: "certmanager.k8s.io",
version: "v1alpha1",
names: {
kind: "Issuer",
plural: "issuers",
},
scope: "Namespaced",
},
},
issuerCRD:: issuerCRD,
local serviceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "cert-manager",
namespace: params.namespace,
},
},
serviceAccount:: serviceAccount,
local clusterRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
name: "cert-manager",
},
rules: [
{
apiGroups: ["certmanager.k8s.io"],
resources: ["certificates", "issuers", "clusterissuers"],
verbs: ["*"],
},
{
apiGroups: [""],
resources: ["secrets", "events", "endpoints", "services", "pods", "configmaps"],
verbs: ["*"],
},
{
apiGroups: ["extensions"],
resources: ["ingresses"],
verbs: ["*"],
},
],
},
clusterRole:: clusterRole,
local clusterRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
name: "cert-manager",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "cert-manager",
},
subjects: [
{
name: "cert-manager",
namespace: params.namespace,
kind: "ServiceAccount",
},
],
},
clusterRoleBinding:: clusterRoleBinding,
local deploy = {
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
name: "cert-manager",
namespace: params.namespace,
labels: {
app: "cert-manager",
},
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "cert-manager",
},
},
spec: {
serviceAccountName: "cert-manager",
containers: [
{
name: "cert-manager",
image: params.certManagerImage,
imagePullPolicy: "IfNotPresent",
args: [
"--cluster-resource-namespace=" + params.namespace,
"--leader-election-namespace=" + params.namespace,
],
},
],
},
},
},
},
deploy:: deploy,
local issuerLEProd = {
apiVersion: "certmanager.k8s.io/v1alpha1",
kind: "ClusterIssuer",
metadata: {
name: "letsencrypt-prod",
},
spec: {
acme: {
server: params.acmeUrl,
email: params.acmeEmail,
privateKeySecretRef: {
name: "letsencrypt-prod-secret",
},
http01: {
},
},
},
},
issuerLEProd:: issuerLEProd,
parts:: self,
all:: [
self.certificateCRD,
self.clusterIssuerCRD,
self.issuerCRD,
self.serviceAccount,
self.clusterRole,
self.clusterRoleBinding,
self.deploy,
self.issuerLEProd,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,214 +0,0 @@
{
local k = import "k.libsonnet",
new(_env, _params):: {
local params = {
cloudEndpointsImage: "gcr.io/cloud-solutions-group/cloud-endpoints-controller:0.2.1",
} + _params + _env,
local endpointsCRD = {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "cloudendpoints.ctl.isla.solutions",
},
spec: {
group: "ctl.isla.solutions",
version: "v1",
scope: "Namespaced",
names: {
plural: "cloudendpoints",
singular: "cloudendpoint",
kind: "CloudEndpoint",
shortNames: [
"cloudep",
"ce",
],
},
},
}, // endpointsCRD
endpointsCRD:: endpointsCRD,
local endpointsClusterRole = {
kind: "ClusterRole",
apiVersion: "rbac.authorization.k8s.io/v1beta1",
metadata: {
name: "cloud-endpoints-controller",
},
rules: [
{
apiGroups: [""],
resources: ["services", "configmaps"],
verbs: ["get", "list"],
},
{
apiGroups: ["extensions"],
resources: ["ingresses"],
verbs: ["get", "list"],
},
],
},
endpointsClusterRole:: endpointsClusterRole,
local endpointsClusterRoleBinding = {
kind: "ClusterRoleBinding",
apiVersion: "rbac.authorization.k8s.io/v1beta1",
metadata: {
name: "cloud-endpoints-controller",
},
subjects: [
{
kind: "ServiceAccount",
name: "cloud-endpoints-controller",
namespace: params.namespace,
},
],
roleRef: {
kind: "ClusterRole",
name: "cloud-endpoints-controller",
apiGroup: "rbac.authorization.k8s.io",
},
},
endpointsClusterRoleBinding:: endpointsClusterRoleBinding,
local endpointsService = {
apiVersion: "v1",
kind: "Service",
metadata: {
name: "cloud-endpoints-controller",
namespace: params.namespace,
},
spec: {
type: "ClusterIP",
ports: [
{
name: "http",
port: 80,
},
],
selector: {
app: "cloud-endpoints-controller",
},
},
}, // endpointsService
endpointsService:: endpointsService,
local endpointsServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "cloud-endpoints-controller",
namespace: params.namespace,
},
}, // endpointsServiceAccount
endpointsServiceAccount:: endpointsServiceAccount,
local endpointsDeploy = {
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
name: "cloud-endpoints-controller",
namespace: params.namespace,
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "cloud-endpoints-controller",
},
},
spec: {
serviceAccountName: "cloud-endpoints-controller",
terminationGracePeriodSeconds: 5,
containers: [
{
name: "cloud-endpoints-controller",
image: params.cloudEndpointsImage,
imagePullPolicy: "Always",
env: [
{
name: "GOOGLE_APPLICATION_CREDENTIALS",
value: "/var/run/secrets/sa/" + params.secretKey,
},
],
volumeMounts: [
{
name: "sa-key",
readOnly: true,
mountPath: "/var/run/secrets/sa",
},
],
readinessProbe: {
httpGet: {
path: "/healthz",
port: 80,
scheme: "HTTP",
},
periodSeconds: 5,
timeoutSeconds: 5,
successThreshold: 1,
failureThreshold: 2,
},
},
],
volumes: [
{
name: "sa-key",
secret: {
secretName: params.secretName,
},
},
],
},
},
},
}, // endpointsDeploy
endpointsDeploy:: endpointsDeploy,
local endpointsCompositeController = {
apiVersion: "metacontroller.k8s.io/v1alpha1",
kind: "CompositeController",
metadata: {
name: "cloud-endpoints-controller",
},
spec: {
generateSelector: true,
resyncPeriodSeconds: 2,
parentResource: {
apiVersion: "ctl.isla.solutions/v1",
resource: "cloudendpoints",
},
childResources: [],
clientConfig: {
service: {
name: "cloud-endpoints-controller",
namespace: params.namespace,
caBundle: "...",
},
},
hooks: {
sync: {
webhook: {
url: "http://cloud-endpoints-controller." + params.namespace + "/sync",
},
},
},
},
}, // endpointsCompositeController
endpointsCompositeController:: endpointsCompositeController,
parts:: self,
local all = [
self.endpointsCRD,
self.endpointsClusterRole,
self.endpointsClusterRoleBinding,
self.endpointsService,
self.endpointsServiceAccount,
self.endpointsDeploy,
self.endpointsCompositeController,
],
all:: all,
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,71 +0,0 @@
#!/usr/bin/env bash
#
# A script to modify envoy config to perform JWT validation
# given the information for the service.
# Script executed by the iap container to configure IAP. When finished, the envoy config is created with the JWT audience.
[ -z ${NAMESPACE} ] && echo Error NAMESPACE must be set && exit 1
[ -z ${SERVICE} ] && echo Error SERVICE must be set && exit 1
PROJECT=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/project/project-id)
if [ -z ${PROJECT} ]; then
echo Error unable to fetch PROJECT from compute metadata
exit 1
fi
PROJECT_NUM=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id)
if [ -z ${PROJECT_NUM} ]; then
echo Error unable to fetch PROJECT_NUM from compute metadata
exit 1
fi
checkIAP() {
# created by init container.
. /var/shared/healthz.env
# If node port or backend id change, so does the JWT audience.
CURR_NODE_PORT=$(kubectl --namespace=${NAMESPACE} get svc ${SERVICE} -o jsonpath='{.spec.ports[0].nodePort}')
CURR_BACKEND_ID=$(gcloud compute --project=${PROJECT} backend-services list --filter=name~k8s-be-${CURR_NODE_PORT}- --format='value(id)')
[ "$BACKEND_ID" == "$CURR_BACKEND_ID" ]
}
# Activate the service account
for i in $(seq 1 10); do
gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} && break || sleep 10
done
# Print out the config for debugging
gcloud config list
NODE_PORT=$(kubectl --namespace=${NAMESPACE} get svc ${SERVICE} -o jsonpath='{.spec.ports[0].nodePort}')
while [[ -z ${BACKEND_ID} ]]; do
BACKEND_ID=$(gcloud compute --project=${PROJECT} backend-services list --filter=name~k8s-be-${NODE_PORT}- --format='value(id)')
echo "Waiting for backend id PROJECT=${PROJECT} NAMESPACE=${NAMESPACE} SERVICE=${SERVICE} filter=name~k8s-be-${NODE_PORT}-..."
sleep 2
done
echo BACKEND_ID=${BACKEND_ID}
NODE_PORT=$(kubectl --namespace=${NAMESPACE} get svc ${SERVICE} -o jsonpath='{.spec.ports[0].nodePort}')
BACKEND_SERVICE=$(gcloud --project=${PROJECT} compute backend-services list --filter=name~k8s-be-${NODE_PORT}- --uri)
JWT_AUDIENCE="/projects/${PROJECT_NUM}/global/backendServices/${BACKEND_ID}"
# For healthcheck compare.
echo "JWT_AUDIENCE=${JWT_AUDIENCE}" > /var/shared/healthz.env
echo "NODE_PORT=${NODE_PORT}" >> /var/shared/healthz.env
echo "BACKEND_ID=${BACKEND_ID}" >> /var/shared/healthz.env
kubectl get configmap -n ${NAMESPACE} envoy-config -o jsonpath='{.data.envoy-config\.json}' |
sed -e "s|{{JWT_AUDIENCE}}|${JWT_AUDIENCE}|g" >/var/shared/envoy-config.json
echo "Restarting envoy"
curl -s ${ENVOY_ADMIN}/quitquitquit
# Verify IAP every 10 seconds.
while true; do
if ! checkIAP; then
echo "$(date) WARN: IAP check failed, restarting container."
exit 1
fi
sleep 10
done

View File

@ -1,115 +0,0 @@
#!/bin/bash
set -e
usage() {
cat <<EOF
Generate certificate suitable for use with an sidecar-injector webhook service.
This script uses k8s' CertificateSigningRequest API to a generate a
certificate signed by k8s CA suitable for use with sidecar-injector webhook
services. This requires permissions to create and approve CSR. See
https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster for
detailed explantion and additional instructions.
The server key/cert k8s CA cert are stored in a k8s secret.
usage: ${0} [OPTIONS]
The following flags are required.
--service Service name of webhook.
--namespace Namespace where webhook service and secret reside.
--secret Secret name for CA certificate and server certificate/key pair.
EOF
exit 1
}
while [[ $# -gt 0 ]]; do
case ${1} in
--service)
service="$2"
shift
'
--secret)
secret="$2"
shift
'
--namespace)
namespace="$2"
shift
'
*)
usage
'
esac
shift
done
[ -z ${service} ] && service=gcp-cred-webhook
[ -z ${secret} ] && secret=gcp-cred-webhook-certs
[ -z ${namespace} ] && namespace=${NAMESPACE}
[ -z ${namespace} ] && namespace=default
echo ${service}
echo ${namespace}
echo ${secret}
if [ ! -x "$(command -v openssl)" ]; then
echo "openssl not found"
exit 1
fi
csrName=${service}.${namespace}
tmpdir=$(mktemp -d)
echo "creating certs in tmpdir ${tmpdir} "
# x509 outputs a self signed certificate instead of certificate request, later used as self signed root CA
openssl req -x509 -newkey rsa:2048 -keyout ${tmpdir}/self_ca.key -out ${tmpdir}/self_ca.crt -days 365 -nodes -subj /C=/ST=/L=/O=/OU=/CN=test-certificate-authority
cat <<EOF >> ${tmpdir}/csr.conf
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${service}
DNS.2 = ${service}.${namespace}
DNS.3 = ${service}.${namespace}.svc
EOF
openssl genrsa -out ${tmpdir}/server-key.pem 2048
openssl req -new -key ${tmpdir}/server-key.pem -subj "/CN=${service}.${namespace}.svc" -out ${tmpdir}/server.csr -config ${tmpdir}/csr.conf
# Self sign
openssl x509 -req -days 365 -in ${tmpdir}/server.csr -CA ${tmpdir}/self_ca.crt -CAkey ${tmpdir}/self_ca.key -CAcreateserial -out ${tmpdir}/server-cert.pem
# create the secret with CA cert and server cert/key
kubectl create secret generic ${secret} \
--from-file=key.pem=${tmpdir}/server-key.pem \
--from-file=cert.pem=${tmpdir}/server-cert.pem \
--dry-run -o yaml |
kubectl -n ${namespace} apply -f -
cat ${tmpdir}/self_ca.crt
# -a means base64 encode
caBundle=`cat ${tmpdir}/self_ca.crt | openssl enc -a -A`
echo ${caBundle}
patchString='[{"op": "replace", "path": "/webhooks/0/clientConfig/caBundle", "value":"{{CA_BUNDLE}}"}]'
patchString=`echo ${patchString} | sed "s|{{CA_BUNDLE}}|${caBundle}|g"`
echo ${patchString}
checkWebhookConfig() {
currentBundle=$(kubectl get mutatingwebhookconfigurations -n ${namespace} gcp-cred-webhook -o jsonpath='{.webhooks[0].clientConfig.caBundle}')
[[ "$currentBundle" == "$caBundle" ]]
}
while true; do
if ! checkWebhookConfig; then
echo "patching ca bundle for webhook configuration..."
kubectl patch mutatingwebhookconfiguration gcp-cred-webhook \
--type='json' -p="${patchString}"
fi
sleep 10
done

View File

@ -1,104 +0,0 @@
{
local k = import "k.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local persistentVolume = {
apiVersion: "v1",
kind: "PersistentVolume",
metadata: {
name: params.name,
namespace: params.namespace,
},
spec: {
capacity: {
storage: params.storageCapacity,
},
accessModes: [
"ReadWriteMany",
],
nfs: {
path: params.path,
server: params.serverIP,
},
},
},
persistentVolume:: persistentVolume,
local persistentVolumeClaim = {
apiVersion: "v1",
kind: "PersistentVolumeClaim",
metadata: {
name: params.name,
namespace: params.namespace,
},
spec: {
accessModes: [
"ReadWriteMany",
],
storageClassName: "nfs-storage",
volumeName: params.name,
resources: {
requests: {
storage: params.storageCapacity,
},
},
},
},
persistentVolumeClaim:: persistentVolumeClaim,
// Set 777 permissions on the GCFS NFS so that non-root users
// like jovyan can use that NFS share
local gcfsPersmissions = {
apiVersion: "batch/v1",
kind: "Job",
metadata: {
name: "set-gcfs-permissions",
namespace: params.namespace,
},
spec: {
template: {
spec: {
containers: [
{
name: "set-gcfs-permissions",
image: params.image,
command: [
"chmod",
"777",
"/kubeflow-gcfs",
],
volumeMounts: [
{
mountPath: "/kubeflow-gcfs",
name: params.name,
},
],
},
],
restartPolicy: "OnFailure",
volumes: [
{
name: params.name,
persistentVolumeClaim: {
claimName: params.name,
readOnly: false,
},
},
],
},
},
},
},
gcfsPersmissions:: gcfsPersmissions,
parts:: self,
all:: [
self.persistentVolume,
self.persistentVolumeClaim,
self.gcfsPersmissions,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,130 +0,0 @@
{
local k = import "k.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local daemonset = {
"apiVersion": "extensions/v1beta1",
"kind": "DaemonSet",
"metadata": {
"name": "nvidia-driver-installer",
"namespace": "kube-system",
"labels": {
"k8s-app": "nvidia-driver-installer"
}
},
"spec": {
"template": {
"metadata": {
"labels": {
"name": "nvidia-driver-installer",
"k8s-app": "nvidia-driver-installer"
}
},
"spec": {
"affinity": {
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [
{
"matchExpressions": [
{
"key": "cloud.google.com/gke-accelerator",
"operator": "Exists"
}
]
}
]
}
}
},
"tolerations": [
{
"operator": "Exists"
}
],
"hostNetwork": true,
"hostPID": true,
"volumes": [
{
"name": "dev",
"hostPath": {
"path": "/dev"
}
},
{
"name": "nvidia-install-dir-host",
"hostPath": {
"path": "/home/kubernetes/bin/nvidia"
}
},
{
"name": "root-mount",
"hostPath": {
"path": "/"
}
}
],
"initContainers": [
{
"image": "cos-nvidia-installer:fixed",
"imagePullPolicy": "Never",
"name": "nvidia-driver-installer",
"resources": {
"requests": {
"cpu": 0.15
}
},
"securityContext": {
"privileged": true
},
"env": [
{
"name": "NVIDIA_INSTALL_DIR_HOST",
"value": "/home/kubernetes/bin/nvidia"
},
{
"name": "NVIDIA_INSTALL_DIR_CONTAINER",
"value": "/usr/local/nvidia"
},
{
"name": "ROOT_MOUNT_DIR",
"value": "/root"
}
],
"volumeMounts": [
{
"name": "nvidia-install-dir-host",
"mountPath": "/usr/local/nvidia"
},
{
"name": "dev",
"mountPath": "/dev"
},
{
"name": "root-mount",
"mountPath": "/root"
}
]
}
],
"containers": [
{
"image": "gcr.io/google-containers/pause:2.0",
"name": "pause"
}
]
}
}
}
},
daemonset:: daemonset,
parts:: self,
all:: [
self.daemonset,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,51 +0,0 @@
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: default-routes
namespace: kubeflow
spec:
hosts:
- "*"
gateways:
- kubeflow-gateway
http:
- match:
- uri:
exact: /healthz
route:
- destination:
port:
number: 80
host: whoami-app.kubeflow.svc.cluster.local
- match:
- uri:
exact: /whoami
route:
- destination:
port:
number: 80
host: whoami-app.kubeflow.svc.cluster.local
- match:
- uri:
prefix: /
route:
- destination:
port:
number: 80
host: ambassador.kubeflow.svc.cluster.local
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: kubeflow-gateway
namespace: kubeflow
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -x
set -e
# This is a workaround until this is resolved: https://github.com/kubernetes/ingress-gce/pull/388
# The long-term solution is to use a managed SSL certificate on GKE once the feature is GA.
# The ingress is initially created without a tls spec.
# Wait until cert-manager generates the certificate using the http-01 challenge on the GCLB ingress.
# After the certificate is obtained, patch the ingress with the tls spec to enable SSL on the GCLB.
# Wait for certificate.
until kubectl -n ${NAMESPACE} get secret ${TLS_SECRET_NAME} 2>/dev/null; do
echo "Waiting for certificate..."
sleep 2
done
kubectl -n ${NAMESPACE} patch ingress ${INGRESS_NAME} --type='json' -p '[{"op": "add", "path": "/spec/tls", "value": [{"secretName": "'${TLS_SECRET_NAME}'", "hosts":["'${TLS_HOST_NAME}'"]}]}]'
echo "Done"

View File

@ -1,23 +0,0 @@
apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
name: ingress-jwt
namespace: istio-system
spec:
targets:
- name: istio-ingressgateway
ports:
- number: 80
origins:
- jwt:
issuer: https://cloud.google.com/iap
jwksUri: https://www.gstatic.com/iap/verify/public_key-jwk
audiences:
- {{JWT_AUDIENCE}}
jwtHeaders:
- x-goog-iap-jwt-assertion
trigger_rules:
- excluded_paths:
- exact: /healthz
- prefix: /.well-known/acme-challenge
principalBinding: USE_ORIGIN

View File

@ -1,189 +0,0 @@
{
local k = import "k.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local metricServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
namespace: params.namespace,
},
},
metricServiceAccount:: metricServiceAccount,
local metricRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"services",
"events",
],
verbs: [
"*",
],
},
],
},
metricRole:: metricRole,
local metricRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "metric-collector",
},
subjects: [
{
kind: "ServiceAccount",
name: "metric-collector",
namespace: params.namespace,
},
],
},
metricRoleBinding:: metricRoleBinding,
local service = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
service: "metric-collector",
},
name: "metric-collector",
namespace: params.namespace,
annotations: {
"prometheus.io/scrape": "true",
"prometheus.io/path": "/",
"prometheus.io/port": "8000",
},
},
spec: {
ports: [
{
name: "metric-collector",
port: 8000,
targetPort: 8000,
protocol: "TCP",
},
],
selector: {
app: "metric-collector",
},
type: "ClusterIP",
},
},
service:: service,
local deploy = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
namespace: params.namespace,
},
spec: {
replicas: 1,
selector: {
matchLabels: {
app: "metric-collector",
},
},
template: {
metadata: {
labels: {
app: "metric-collector",
},
namespace: params.namespace,
},
spec: {
containers: [
{
env: [
{
name: "GOOGLE_APPLICATION_CREDENTIALS",
value: "/var/run/secrets/sa/admin-gcp-sa.json",
},
{
name: "CLIENT_ID",
valueFrom: {
secretKeyRef: {
name: params.oauthSecretName,
key: "client_id",
},
},
},
],
command: [
"python3",
"/opt/kubeflow-readiness.py",
],
args: [
"--url=" + params.targetUrl,
"--client_id=$(CLIENT_ID)",
],
volumeMounts: [
{
name: "sa-key",
readOnly: true,
mountPath: "/var/run/secrets/sa",
},
],
image: params.metricImage,
name: "exporter",
},
],
serviceAccountName: "metric-collector",
restartPolicy: "Always",
volumes: [
{
name: "sa-key",
secret: {
secretName: "admin-gcp-sa",
},
},
],
},
},
},
}, // deploy
deploy:: deploy,
parts:: self,
all:: [
self.metricServiceAccount,
self.metricRole,
self.metricRoleBinding,
self.service,
self.deploy,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,35 +0,0 @@
{
"name": "gcp",
"apiVersion": "0.0.1",
"kind": "ksonnet.io/parts",
"description": "Core components of Kubeflow.\n",
"author": "kubeflow team <kubeflow-team@google.com>",
"contributors": [
{
"name": "Jeremy Lewi",
"email": "jlewi@google.com"
}
],
"repository": {
"type": "git",
"url": "https://github.com/kubeflow/kubeflow"
},
"bugs": {
"url": "https://github.com/kubeflow/kubeflow/issues"
},
"keywords": [
"kubeflow",
"tensorflow"
],
"quickStart": {
"prototype": "io.ksonnet.pkg.kubeflow",
"componentName": "gcp",
"flags": {
"name": "gcp",
"namespace": "default",
"disks": ""
},
"comment": "GCP specific Kubeflow components."
},
"license": "Apache 2.0"
}

View File

@ -1,221 +0,0 @@
{
local k = import "k.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local namespace = {
apiVersion: "v1",
kind: "Namespace",
metadata: {
name: "stackdriver",
},
},
namespace:: namespace,
local clusterRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
name: "prometheus",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"nodes",
"nodes/proxy",
"services",
"endpoints",
"pods",
],
verbs: [
"get",
"list",
"watch",
],
},
{
apiGroups: [
"extensions",
],
resources: [
"ingresses",
],
verbs: [
"get",
"list",
"watch",
],
},
{
nonResourceURLs: [
"/metrics",
],
verbs: [
"get",
],
},
],
},
clusterRole:: clusterRole,
local serviceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "prometheus",
namespace: "stackdriver",
},
},
serviceAccount:: serviceAccount,
local clusterRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
name: "prometheus-stackdriver",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "prometheus",
},
subjects: [
{
kind: "ServiceAccount",
name: "prometheus",
namespace: "stackdriver",
},
],
},
clusterRoleBinding:: clusterRoleBinding,
local service = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
name: "prometheus",
},
name: "prometheus",
namespace: "stackdriver",
},
spec: {
ports: [
{
name: "prometheus",
port: 9090,
protocol: "TCP",
},
],
selector: {
app: "prometheus",
},
type: "ClusterIP",
},
},
service:: service,
local configMap = {
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "prometheus",
namespace: "stackdriver",
},
data: {
"prometheus.yml": (importstr "prometheus.yml") % {
"project-id-placeholder": params.projectId,
"cluster-name-placeholder": params.clusterName,
"zone-placeholder": params.zone,
},
},
},
configMap:: configMap,
local deployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: "prometheus",
namespace: "stackdriver",
},
spec: {
replicas: 1,
selector: {
matchLabels: {
app: "prometheus",
},
},
template: {
metadata: {
annotations: {
"prometheus.io/scrape": "true",
},
labels: {
app: "prometheus",
},
name: "prometheus",
namespace: "stackdriver",
},
spec: {
containers: [
{
image: "gcr.io/stackdriver-prometheus/stackdriver-prometheus:release-0.4.2",
imagePullPolicy: "Always",
name: "prometheus",
ports: [
{
containerPort: 9090,
name: "web",
},
],
resources: {
limits: {
cpu: "400m",
memory: "1000Mi",
},
requests: {
cpu: "20m",
memory: "50Mi",
},
},
volumeMounts: [
{
mountPath: "/etc/prometheus",
name: "config-volume",
},
],
},
],
serviceAccountName: "prometheus",
volumes: [
{
configMap: {
name: "prometheus",
},
name: "config-volume",
},
],
},
},
},
},
deployment:: deployment,
parts:: self,
all:: [
self.namespace,
self.clusterRole,
self.serviceAccount,
self.clusterRoleBinding,
self.service,
self.configMap,
self.deployment,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
},
}

View File

@ -1,140 +0,0 @@
# Source: https://github.com/stackdriver/prometheus/blob/master/documentation/examples/prometheus.yml
global:
external_labels:
_stackdriver_project_id: %(project-id-placeholder)s
_kubernetes_cluster_name: %(cluster-name-placeholder)s
_kubernetes_location: %(zone-placeholder)s
# Scrape config for nodes (kubelet).
#
# Rather than connecting directly to the node, the scrape is proxied though the
# Kubernetes apiserver. This means it will work if Prometheus is running out of
# cluster, or can't connect to nodes for some other reason (e.g. because of
# firewalling).
scrape_configs:
- job_name: 'kubernetes-nodes'
# Default to scraping over https. If required, just disable this or change to
# `http`.
scheme: https
# This TLS & bearer token file config is used to connect to the actual scrape
# endpoints for cluster components. This is separate to discovery auth
# configuration because discovery & scraping are two separate concerns in
# Prometheus. The discovery auth config is automatic if Prometheus runs inside
# the cluster. Otherwise, more config options have to be provided within the
# <kubernetes_sd_config>.
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/${1}/proxy/metrics
# Example scrape config for pods
#
# The relabeling allows the actual pod scrape endpoint to be configured via the
# following annotations:
#
# * `prometheus.io/scrape`: Only scrape pods that have a value of `true`
# * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
# * `prometheus.io/port`: Scrape the pod on the indicated port instead of the
# pod's declared ports (default is a port-free target if none are declared).
- job_name: 'kubernetes-pods-containers'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
# Scrape config for service endpoints.
#
# The relabeling allows the actual service scrape endpoint to be configured
# via the following annotations:
#
# * `prometheus.io/scrape`: Only scrape services that have a value of `true`
# * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
# to set this to `https` & most likely set the `tls_config` of the scrape config.
# * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
# * `prometheus.io/port`: If the metrics are exposed on a different port to the
# service then set this appropriately.
- job_name: 'kubernetes-service-endpoints'
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
# Scrape config for k8s services
- job_name: 'kubernetes-services'
kubernetes_sd_configs:
- role: service
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
- source_labels: [__address__,__meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)(?::\d+);(\d+)
replacement: $1:$2
remote_write:
- url: "https://monitoring.googleapis.com:443/"
queue_config:
# Capacity should be 2*max_samples_per_send.
capacity: 2000
max_samples_per_send: 1000
max_shards: 10000
write_relabel_configs:
# These labels are generally redundant with the Stackdriver monitored resource labels.
- source_labels: [job]
target_label: job
replacement: ""
- source_labels: [instance]
target_label: instance
replacement: ""

View File

@ -1,15 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.basic-auth-ingress
// @description Provides ingress prototypes for setting up basic auth on GKE.
// @shortDescription Ingress for IAP on GKE.
// @param name string Name for the component
// @param ipName string The name of the global ip address to use.
// @optionalParam secretName string envoy-ingress-tls The name of the secret containing the SSL certificates.
// @optionalParam hostname string null The hostname associated with this ingress. Eg: mykubeflow.example.com
// @optionalParam issuer string letsencrypt-prod The cert-manager issuer name.
// @optionalParam ingressSetupImage string gcr.io/kubeflow-images-public/ingress-setup:latest The image for setting up ingress.
// @optionalParam privateGKECluster string false Is the k8s cluster a private GKE cluster
local basicauth = import "kubeflow/gcp/basic-auth-ingress.libsonnet";
local instance = basicauth.new(env, params);
instance.list(instance.all)

View File

@ -1,12 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.cert-manager
// @description Provides cert-manager prototypes for generating SSL certificates.
// @shortDescription Certificate generation on GKE.
// @param name string Name for the component
// @param acmeEmail string The Lets Encrypt account email address
// @optionalParam acmeUrl string https://acme-v02.api.letsencrypt.org/directory The ACME server URL, set to https://acme-staging-v02.api.letsencrypt.org/directory for staging API.
// @optionalParam certManagerImage string quay.io/jetstack/cert-manager-controller:v0.4.0 certManagerImage
local certManager = import "kubeflow/gcp/cert-manager.libsonnet";
local instance = certManager.new(env, params);
instance.list(instance.all)

View File

@ -1,11 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.cloud-endpoints
// @description Provides cloud-endpoints prototypes for creating Cloud Endpoints services and DNS records.
// @shortDescription Cloud Endpoint domain creation.
// @param name string Name for the component
// @optionalParam secretName string admin-gcp-sa Name of secret containing the json service account key.
// @optionalParam secretKey string admin-gcp-sa.json Name of the key in the secret containing the JSON service account key.
local cloudEndpoints = import "kubeflow/gcp/cloud-endpoints.libsonnet";
local instance = cloudEndpoints.new(env, params);
instance.list(instance.all)

View File

@ -1,13 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.google-cloud-filestore-pv
// @description Creates PV and PVC based on Google Cloud Filestore NFS
// @shortDescription Creates PV and PVC based on Google Cloud Filestore NFS
// @param name string Name for the component
// @optionalParam storageCapacity string 1T Storage Capacity
// @optionalParam path string /kubeflow Path in NFS server
// @param serverIP string Google Cloud Filestore Server IP
// @optionalParam image string gcr.io/kubeflow-images-public/ubuntu:18.04 The docker image to use
local google_cloud_file_store_pv = import "kubeflow/gcp/google-cloud-filestore-pv.libsonnet";
local instance = google_cloud_file_store_pv.new(env, params);
instance.list(instance.all)

View File

@ -1,9 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.gpu-driver
// @description Provides gpu-driver prototype in kubeflow gcp package
// @shortDescription Gpu Driver.
// @param name string Name for the component
local gpuDriver = import "kubeflow/gcp/gpu-driver.libsonnet";
local instance = gpuDriver.new(env, params);
instance.list(instance.all)

View File

@ -1,21 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.iap-ingress
// @description Provides ingress prototypes for setting up IAP on GKE.
// @shortDescription Ingress for IAP on GKE.
// @param name string Name for the component
// @param ipName string The name of the global ip address to use.
// @optionalParam secretName string envoy-ingress-tls The name of the secret containing the SSL certificates.
// @optionalParam hostname string null The hostname associated with this ingress. Eg: mykubeflow.example.com
// @optionalParam issuer string letsencrypt-prod The cert-manager issuer name.
// @optionalParam envoyImage string gcr.io/kubeflow-images-public/envoy:v20180309-0fb4886b463698702b6a08955045731903a18738 The image for envoy.
// @optionalParam ingressSetupImage string gcr.io/kubeflow-images-public/ingress-setup:latest The image for setting up ingress.
// @optionalParam disableJwtChecking string false Disable JWT checking.
// @optionalParam oauthSecretName string kubeflow-oauth The name of the secret containing the OAuth client_id and client_secret.
// @optionalParam privateGKECluster string false Is the k8s cluster a private GKE cluster
// @optionalParam useIstio string false The namespace where Istio is installed
// @optionalParam istioNamespace string istio-system The namespace where Istio is installed
// @optionalParam espSampleAppImage string gcr.io/cloud-solutions-group/esp-sample-app:1.0.0 The sample app used with IAP
local iap = import "kubeflow/gcp/iap.libsonnet";
local instance = iap.new(env, params);
instance.list(instance.all)

View File

@ -1,13 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.metric-collector
// @description Provides metric-collector prototypes for monitoring kubeflow availability on GCP.
// @shortDescription Service monitor for kubeflow on GCP.
// @param name string Name for the component
// @param targetUrl string Https url of kubeflow service on GCP; target of monitoring.
// @optionalParam namespace string null Namespace to use for the components. It is automatically inherited from the environment if not set.
// @optionalParam metricImage string gcr.io/kubeflow-images-public/metric-collector:latest Image for running metric exporter of kubeflow availability.
// @optionalParam oauthSecretName string kubeflow-oauth The name of the secret containing the OAuth client_id and client_secret.
local metricCollector = import "kubeflow/gcp/metric-collector.libsonnet";
local instance = metricCollector.new(env, params);
instance.list(instance.all)

View File

@ -1,12 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.prometheus
// @description Provides prometheus prototype in kubeflow gcp package
// @shortDescription Prometheus Service.
// @param name string Name for the component
// @param projectId string GCP project id.
// @param clusterName string GKE cluster name.
// @param zone string GKE cluster zone.
local prometheus = import "kubeflow/gcp/prometheus.libsonnet";
local instance = prometheus.new(env, params);
instance.list(instance.all)

View File

@ -1,11 +0,0 @@
// @apiVersion 0.1
// @name io.ksonnet.pkg.gcp-credentials-admission-webhook
// @description This prototype creates a admission controller which injects credentials into pods
// @shortDescription This prototype creates a admission controller which injects credentials into pods
// @param name string Name to give to each of the components
// @optionalParam image string gcr.io/kubeflow-images-public/gcp-admission-webhook:v20190401-v0.4.0-rc.1-309-g4014fa2e-dirty-be6212 The image for the webhook.
// @optionalParam webhookSetupImage string gcr.io/kubeflow-images-public/ingress-setup:latest The image for setting up ingress.
local webhook = import "kubeflow/gcp/webhook.libsonnet";
local instance = webhook.new(env, params);
instance.list(instance.all)

View File

@ -1,84 +0,0 @@
#!/usr/bin/env bash
#
# A simple shell script to configure the backend timeouts and health checks by using gcloud.
[ -z ${NAMESPACE} ] && echo Error NAMESPACE must be set && exit 1
[ -z ${SERVICE} ] && echo Error SERVICE must be set && exit 1
[ -z ${INGRESS_NAME} ] && echo Error INGRESS_NAME must be set && exit 1
PROJECT=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/project/project-id)
if [ -z ${PROJECT} ]; then
echo Error unable to fetch PROJECT from compute metadata
exit 1
fi
PROJECT_NUM=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id)
if [ -z ${PROJECT_NUM} ]; then
echo Error unable to fetch PROJECT_NUM from compute metadata
exit 1
fi
# Activate the service account
gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS}
# Print out the config for debugging
gcloud config list
NODE_PORT=$(kubectl --namespace=${NAMESPACE} get svc ${SERVICE} -o jsonpath='{.spec.ports[0].nodePort}')
echo "node port is ${NODE_PORT}"
while [[ -z ${BACKEND_NAME} ]]; do
BACKENDS=$(kubectl --namespace=${NAMESPACE} get ingress ${INGRESS_NAME} -o jsonpath='{.metadata.annotations.ingress\.kubernetes\.io/backends}')
echo "fetching backends info with ${INGRESS_NAME}: ${BACKENDS}"
BACKEND_NAME=$(echo $BACKENDS | grep -o "k8s-be-${NODE_PORT}--[0-9a-z]\+")
echo "backend name is ${BACKEND_NAME}"
sleep 2
done
while [[ -z ${BACKEND_ID} ]]; do
BACKEND_ID=$(gcloud compute --project=${PROJECT} backend-services list --filter=name~${BACKEND_NAME} --format='value(id)')
echo "Waiting for backend id PROJECT=${PROJECT} NAMESPACE=${NAMESPACE} SERVICE=${SERVICE} filter=name~${BACKEND_NAME}"
sleep 2
done
echo BACKEND_ID=${BACKEND_ID}
JWT_AUDIENCE="/projects/${PROJECT_NUM}/global/backendServices/${BACKEND_ID}"
# For healthcheck compare.
mkdir -p /var/shared
echo "JWT_AUDIENCE=${JWT_AUDIENCE}" > /var/shared/healthz.env
echo "NODE_PORT=${NODE_PORT}" >> /var/shared/healthz.env
echo "BACKEND_ID=${BACKEND_ID}" >> /var/shared/healthz.env
if [[ -z ${USE_ISTIO} ]]; then
# TODO(https://github.com/kubeflow/kubeflow/issues/942): We should publish the modified envoy
# config as a config map and use that in the envoy sidecars.
kubectl get configmap -n ${NAMESPACE} envoy-config -o jsonpath='{.data.envoy-config\.json}' |
sed -e "s|{{JWT_AUDIENCE}}|${JWT_AUDIENCE}|g" > /var/shared/envoy-config.json
else
# Apply the jwt validation policy
cat /var/envoy-config/jwt-policy-template.yaml | sed -e "s|{{JWT_AUDIENCE}}|${JWT_AUDIENCE}|g" > /var/shared/jwt-policy.yaml
kubectl apply -f /var/shared/jwt-policy.yaml
fi
echo "Clearing lock on service annotation"
kubectl patch svc "${SERVICE}" -p "{\"metadata\": { \"annotations\": {\"backendlock\": \"\" }}}"
checkBackend() {
# created by init container.
. /var/shared/healthz.env
# If node port or backend id change, so does the JWT audience.
CURR_NODE_PORT=$(kubectl --namespace=${NAMESPACE} get svc ${SERVICE} -o jsonpath='{.spec.ports[0].nodePort}')
read -ra toks <<<"$(gcloud compute --project=${PROJECT} backend-services list --filter=name~k8s-be-${CURR_NODE_PORT}- --format='value(id,timeoutSec)')"
CURR_BACKEND_ID="${toks[0]}"
CURR_BACKEND_TIMEOUT="${toks[1]}"
[[ "$BACKEND_ID" == "$CURR_BACKEND_ID" && "${CURR_BACKEND_TIMEOUT}" -eq 3600 ]]
}
# Verify configuration every 10 seconds.
while true; do
if ! checkBackend; then
echo "$(date) WARN: Backend check failed, restarting container."
exit 1
fi
sleep 10
done

View File

@ -1,219 +0,0 @@
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local certManager = import "kubeflow/gcp/cert-manager.libsonnet";
local params = {
name: "cert-manager",
acmeEmail: "joe@acme.com",
acmeUrl: "https://acme-v02.api.letsencrypt.org/directory",
certManagerImage: "quay.io/jetstack/cert-manager-controller:v0.4.0",
};
local env = {
namespace: "kf-001",
};
local instance = certManager.new(env, params);
local testCases = [
{
actual: instance.parts.certificateCRD,
expected: {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "certificates.certmanager.k8s.io",
},
spec: {
group: "certmanager.k8s.io",
names: {
kind: "Certificate",
plural: "certificates",
},
scope: "Namespaced",
version: "v1alpha1",
},
},
},
{
actual: instance.parts.clusterIssuerCRD,
expected: {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "clusterissuers.certmanager.k8s.io",
},
spec: {
group: "certmanager.k8s.io",
names: {
kind: "ClusterIssuer",
plural: "clusterissuers",
},
scope: "Cluster",
version: "v1alpha1",
},
},
},
{
actual: instance.parts.issuerCRD,
expected: {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "issuers.certmanager.k8s.io",
},
spec: {
group: "certmanager.k8s.io",
names: {
kind: "Issuer",
plural: "issuers",
},
scope: "Namespaced",
version: "v1alpha1",
},
},
},
{
actual: instance.parts.serviceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "cert-manager",
namespace: "kf-001",
},
},
},
{
actual: instance.parts.clusterRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
name: "cert-manager",
},
rules: [
{
apiGroups: [
"certmanager.k8s.io",
],
resources: [
"certificates",
"issuers",
"clusterissuers",
],
verbs: [
"*",
],
},
{
apiGroups: [
"",
],
resources: [
"secrets",
"events",
"endpoints",
"services",
"pods",
"configmaps",
],
verbs: [
"*",
],
},
{
apiGroups: [
"extensions",
],
resources: [
"ingresses",
],
verbs: [
"*",
],
},
],
},
},
{
actual: instance.parts.clusterRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
name: "cert-manager",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "cert-manager",
},
subjects: [
{
kind: "ServiceAccount",
name: "cert-manager",
namespace: "kf-001",
},
],
},
},
{
actual: instance.parts.deploy,
expected: {
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "cert-manager",
},
name: "cert-manager",
namespace: "kf-001",
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "cert-manager",
},
},
spec: {
containers: [
{
args: [
"--cluster-resource-namespace=kf-001",
"--leader-election-namespace=kf-001",
],
image: "quay.io/jetstack/cert-manager-controller:v0.4.0",
imagePullPolicy: "IfNotPresent",
name: "cert-manager",
},
],
serviceAccountName: "cert-manager",
},
},
},
},
},
{
actual: instance.parts.issuerLEProd,
expected: {
apiVersion: "certmanager.k8s.io/v1alpha1",
kind: "ClusterIssuer",
metadata: {
name: "letsencrypt-prod",
},
spec: {
acme: {
email: "joe@acme.com",
http01: {},
privateKeySecretRef: {
name: "letsencrypt-prod-secret",
},
server: "https://acme-v02.api.letsencrypt.org/directory",
},
},
},
},
];
testSuite.run(testCases)

View File

@ -1,232 +0,0 @@
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local cloudEndpoints = import "kubeflow/gcp/cloud-endpoints.libsonnet";
local params = {
name: "cloud-endpoints",
secretName: "admin-gcp-sa",
secretKey: "admin-gcp-sa.json",
};
local env = {
namespace: "kf-001",
};
local instance = cloudEndpoints.new(env, params);
local testCases = [
{
actual: instance.parts.endpointsCRD,
expected: {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "cloudendpoints.ctl.isla.solutions",
},
spec: {
group: "ctl.isla.solutions",
names: {
kind: "CloudEndpoint",
plural: "cloudendpoints",
shortNames: [
"cloudep",
"ce",
],
singular: "cloudendpoint",
},
scope: "Namespaced",
version: "v1",
},
},
},
{
actual: instance.parts.endpointsClusterRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
name: "cloud-endpoints-controller",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"services",
"configmaps",
],
verbs: [
"get",
"list",
],
},
{
apiGroups: [
"extensions",
],
resources: [
"ingresses",
],
verbs: [
"get",
"list",
],
},
],
},
},
{
actual: instance.parts.endpointsClusterRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
name: "cloud-endpoints-controller",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "cloud-endpoints-controller",
},
subjects: [
{
kind: "ServiceAccount",
name: "cloud-endpoints-controller",
namespace: "kf-001",
},
],
},
},
{
actual: instance.parts.endpointsService,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
name: "cloud-endpoints-controller",
namespace: "kf-001",
},
spec: {
ports: [
{
name: "http",
port: 80,
},
],
selector: {
app: "cloud-endpoints-controller",
},
type: "ClusterIP",
},
},
},
{
actual: instance.parts.endpointsServiceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "cloud-endpoints-controller",
namespace: "kf-001",
},
},
},
{
actual: instance.parts.endpointsDeploy,
expected: {
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
name: "cloud-endpoints-controller",
namespace: "kf-001",
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "cloud-endpoints-controller",
},
},
spec: {
containers: [
{
env: [
{
name: "GOOGLE_APPLICATION_CREDENTIALS",
value: "/var/run/secrets/sa/admin-gcp-sa.json",
},
],
image: "gcr.io/cloud-solutions-group/cloud-endpoints-controller:0.2.1",
imagePullPolicy: "Always",
name: "cloud-endpoints-controller",
readinessProbe: {
failureThreshold: 2,
httpGet: {
path: "/healthz",
port: 80,
scheme: "HTTP",
},
periodSeconds: 5,
successThreshold: 1,
timeoutSeconds: 5,
},
volumeMounts: [
{
mountPath: "/var/run/secrets/sa",
name: "sa-key",
readOnly: true,
},
],
},
],
serviceAccountName: "cloud-endpoints-controller",
terminationGracePeriodSeconds: 5,
volumes: [
{
name: "sa-key",
secret: {
secretName: "admin-gcp-sa",
},
},
],
},
},
},
},
},
{
actual: instance.parts.endpointsCompositeController,
expected: {
apiVersion: "metacontroller.k8s.io/v1alpha1",
kind: "CompositeController",
metadata: {
name: "cloud-endpoints-controller",
},
spec: {
childResources: [],
clientConfig: {
service: {
caBundle: "...",
name: "cloud-endpoints-controller",
namespace: "kf-001",
},
},
generateSelector: true,
resyncPeriodSeconds: 2,
hooks: {
sync: {
webhook: {
url: "http://cloud-endpoints-controller.kf-001/sync",
},
},
},
parentResource: {
apiVersion: "ctl.isla.solutions/v1",
resource: "cloudendpoints",
},
},
},
},
];
testSuite.run(testCases)

View File

@ -1,110 +0,0 @@
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local googleCloudFilestorePv = import "kubeflow/gcp/google-cloud-filestore-pv.libsonnet";
local params = {
name: "google-cloud-filestore-pv",
storageCapacity: "1T",
path: "/kubeflow",
serverIP: "10.10.10.10",
image: "gcr.io/kubeflow-images-public/ubuntu:18.04",
};
local env = {
namespace: "kf-001",
};
local instance = googleCloudFilestorePv.new(env, params);
local testCases = [
{
actual: instance.parts.persistentVolume,
expected: {
apiVersion: "v1",
kind: "PersistentVolume",
metadata: {
name: "google-cloud-filestore-pv",
namespace: "kf-001",
},
spec: {
accessModes: [
"ReadWriteMany",
],
capacity: {
storage: "1T",
},
nfs: {
path: "/kubeflow",
server: "10.10.10.10",
},
},
},
},
{
actual: instance.parts.persistentVolumeClaim,
expected: {
apiVersion: "v1",
kind: "PersistentVolumeClaim",
metadata: {
name: "google-cloud-filestore-pv",
namespace: "kf-001",
},
spec: {
accessModes: [
"ReadWriteMany",
],
resources: {
requests: {
storage: "1T",
},
},
storageClassName: "nfs-storage",
volumeName: "google-cloud-filestore-pv",
},
},
},
{
actual: instance.parts.gcfsPersmissions,
expected: {
apiVersion: "batch/v1",
kind: "Job",
metadata: {
name: "set-gcfs-permissions",
namespace: "kf-001",
},
spec: {
template: {
spec: {
containers: [
{
command: [
"chmod",
"777",
"/kubeflow-gcfs",
],
image: "gcr.io/kubeflow-images-public/ubuntu:18.04",
name: "set-gcfs-permissions",
volumeMounts: [
{
mountPath: "/kubeflow-gcfs",
name: "google-cloud-filestore-pv",
},
],
},
],
restartPolicy: "OnFailure",
volumes: [
{
name: "google-cloud-filestore-pv",
persistentVolumeClaim: {
claimName: "google-cloud-filestore-pv",
readOnly: false,
},
},
],
},
},
},
},
},
];
testSuite.run(testCases)

View File

@ -1,275 +0,0 @@
local iap = import "../iap.libsonnet";
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local testCases = [
{
actual: iap.new(
{ namespace: "namespace" },
{
envoyPort: 8080,
useIstio: "false",
espSampleAppImage: "gcr.io/cloud-solutions-group/esp-sample-app:1.0.0",
}
).service,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
service: "envoy",
},
annotations: {
"beta.cloud.google.com/backend-config": '{"ports": {"envoy":"iap-backendconfig"}}',
},
name: "envoy",
namespace: "namespace",
},
spec: {
ports: [
{
name: "envoy",
port: 8080,
targetPort: 8080,
},
],
selector: {
service: "envoy",
},
type: "NodePort",
},
},
},
{
actual: iap.new(
{ namespace: "namespace" },
{
envoyPort: 8080,
ipName: "ipName",
hostname: "hostname",
issuer: "issuer",
useIstio: "false",
espSampleAppImage: "gcr.io/cloud-solutions-group/esp-sample-app:1.0.0",
}
).ingress,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Ingress",
metadata: {
name: "envoy-ingress",
namespace: "namespace",
annotations: {
"kubernetes.io/tls-acme": "true",
"ingress.kubernetes.io/ssl-redirect": "true",
"kubernetes.io/ingress.global-static-ip-name": "ipName",
"certmanager.k8s.io/issuer": "issuer",
},
},
spec: {
rules: [
{
host: "hostname",
http: {
paths: [
{
backend: {
serviceName: "envoy",
servicePort: 8080,
},
path: "/*",
},
],
},
},
],
},
},
},
{
actual: iap.new(
{
namespace: "namespace",
},
{
envoyPort: 8080,
ipName: "ipName",
hostname: "null",
issuer: "issuer",
useIstio: "false",
espSampleAppImage: "gcr.io/cloud-solutions-group/esp-sample-app:1.0.0",
}
).ingress,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Ingress",
metadata: {
name: "envoy-ingress",
namespace: "namespace",
annotations: {
"kubernetes.io/tls-acme": "true",
"ingress.kubernetes.io/ssl-redirect": "true",
"kubernetes.io/ingress.global-static-ip-name": "ipName",
"certmanager.k8s.io/issuer": "issuer",
},
},
spec: {
rules: [
{
http: {
paths: [
{
backend: {
serviceName: "envoy",
servicePort: 8080,
},
path: "/*",
},
],
},
},
],
},
},
},
{
actual: iap.new(
{
namespace: "namespace",
},
{
secretName: "secretName",
hostname: "hostname",
issuer: "issuer",
privateGKECluster: "false",
useIstio: "false",
espSampleAppImage: "gcr.io/cloud-solutions-group/esp-sample-app:1.0.0",
}
).certificate,
expected: {
apiVersion: "certmanager.k8s.io/v1alpha1",
kind: "Certificate",
metadata: {
name: "secretName",
namespace: "namespace",
},
spec: {
secretName: "secretName",
issuerRef: {
name: "issuer",
kind: "ClusterIssuer",
},
commonName: "hostname",
dnsNames: [
"hostname",
],
acme: {
config: [
{
http01: {
ingress: "envoy-ingress",
},
domains: [
"hostname",
],
},
],
},
},
},
},
{
actual: iap.new(
{
namespace: "namespace",
},
{
useIstio: "false",
espSampleAppImage: "cloud-solutions-group/esp-sample-app:5.0.0",
}
).whoamiApp,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: "whoami-app",
namespace: "namespace",
},
spec: {
replicas: 1,
template: {
metadata: {
labels: {
app: "whoami",
},
},
spec: {
containers: [
{
env: [
{
name: "PORT",
value: "8081",
},
],
image: "cloud-solutions-group/esp-sample-app:5.0.0",
name: "app",
ports: [
{
containerPort: 8081,
},
],
readinessProbe: {
failureThreshold: 2,
httpGet: {
path: "/healthz",
port: 8081,
scheme: "HTTP",
},
periodSeconds: 10,
successThreshold: 1,
timeoutSeconds: 5,
},
},
],
},
},
},
},
},
{
actual: iap.new(
{
namespace: "namespace",
},
{
useIstio: "false",
espSampleAppImage: "gcr.io/cloud-solutions-group/esp-sample-app:1.0.0",
}
).whoamiService,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "whoami",
},
name: "whoami-app",
namespace: "namespace",
},
spec: {
ports: [
{
port: 80,
targetPort: 8081,
},
],
selector: {
app: "whoami",
},
type: "ClusterIP",
},
},
},
];
testSuite.run(testCases)

View File

@ -1,196 +0,0 @@
local testSuite = import "kubeflow/common/testsuite.libsonnet";
local metricCollector = import "kubeflow/gcp/metric-collector.libsonnet";
local params = {
name: "metric-collector",
targetUrl: "https://foo.com",
metricImage: "gcr.io/kubeflow-images-public/metric-collector:latest",
oauthSecretName: "bar",
};
local env = {
namespace: "kf-001",
};
local instance = metricCollector.new(env, params);
local testCases = [
{
actual: instance.parts.metricServiceAccount,
expected: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
namespace: "kf-001",
},
},
},
{
actual: instance.parts.metricRole,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRole",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
},
rules: [
{
apiGroups: [
"",
],
resources: [
"services",
"events",
],
verbs: [
"*",
],
},
],
},
},
{
actual: instance.parts.metricRoleBinding,
expected: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "ClusterRoleBinding",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "metric-collector",
},
subjects: [
{
kind: "ServiceAccount",
name: "metric-collector",
namespace: "kf-001",
},
],
},
},
{
actual: instance.parts.service,
expected: {
apiVersion: "v1",
kind: "Service",
metadata: {
annotations: {
"prometheus.io/path": "/",
"prometheus.io/port": "8000",
"prometheus.io/scrape": "true",
},
labels: {
service: "metric-collector",
},
name: "metric-collector",
namespace: "kf-001",
},
spec: {
ports: [
{
name: "metric-collector",
port: 8000,
protocol: "TCP",
targetPort: 8000,
},
],
selector: {
app: "metric-collector",
},
type: "ClusterIP",
},
},
},
{
actual: instance.parts.deploy,
expected: {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
labels: {
app: "metric-collector",
},
name: "metric-collector",
namespace: "kf-001",
},
spec: {
replicas: 1,
selector: {
matchLabels: {
app: "metric-collector",
},
},
template: {
metadata: {
labels: {
app: "metric-collector",
},
namespace: "kf-001",
},
spec: {
containers: [
{
args: [
"--url=https://foo.com",
"--client_id=$(CLIENT_ID)",
],
command: [
"python3",
"/opt/kubeflow-readiness.py",
],
env: [
{
name: "GOOGLE_APPLICATION_CREDENTIALS",
value: "/var/run/secrets/sa/admin-gcp-sa.json",
},
{
name: "CLIENT_ID",
valueFrom: {
secretKeyRef: {
key: "client_id",
name: "bar",
},
},
},
],
image: "gcr.io/kubeflow-images-public/metric-collector:latest",
name: "exporter",
volumeMounts: [
{
mountPath: "/var/run/secrets/sa",
name: "sa-key",
readOnly: true,
},
],
},
],
restartPolicy: "Always",
serviceAccountName: "metric-collector",
volumes: [
{
name: "sa-key",
secret: {
secretName: "admin-gcp-sa",
},
},
],
},
},
},
},
},
];
testSuite.run(testCases)

File diff suppressed because one or more lines are too long

View File

@ -1,51 +0,0 @@
#!/bin/bash
#
# A simple shell script to configure the backend timeouts and health checks by using gcloud.
[ -z ${NAMESPACE} ] && echo Error NAMESPACE must be set && exit 1
[ -z ${SERVICE} ] && echo Error SERVICE must be set && exit 1
PROJECT=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/project/project-id)
if [ -z ${PROJECT} ]; then
echo Error unable to fetch PROJECT from compute metadata
exit 1
fi
# Activate the service account, allow 5 retries
for i in {1..5}; do gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} && break || sleep 10; done
NODE_PORT=$(kubectl --namespace=${NAMESPACE} get svc ${SERVICE} -o jsonpath='{.spec.ports[0].nodePort}')
while [[ -z ${BACKEND_SERVICE} ]];
do BACKEND_SERVICE=$(gcloud --project=${PROJECT} compute backend-services list --filter=name~k8s-be-${NODE_PORT}- --uri);
echo "Waiting for the backend-services resource PROJECT=${PROJECT} NODEPORT=${NODE_PORT} SERVICE=${SERVICE}...";
sleep 2;
done
while [[ -z ${HEALTH_CHECK_URI} ]];
do HEALTH_CHECK_URI=$(gcloud compute --project=${PROJECT} health-checks list --filter=name~k8s-be-${NODE_PORT}- --uri);
echo "Waiting for the healthcheck resource PROJECT=${PROJECT} NODEPORT=${NODE_PORT} SERVICE=${SERVICE}...";
sleep 2;
done
# Since we create the envoy-ingress ingress object before creating the envoy
# deployment object, healthcheck will not be configured correctly in the GCP
# load balancer. It will default the healthcheck request path to a value of
# / instead of the intended /healthz.
# Manually update the healthcheck request path to /healthz
if [[ ${HEALTHCHECK_PATH} ]]; then
gcloud --project=${PROJECT} compute health-checks update http ${HEALTH_CHECK_URI} --request-path=${HEALTHCHECK_PATH}
else
gcloud --project=${PROJECT} compute health-checks update http ${HEALTH_CHECK_URI} --request-path=/healthz
fi
if [[ ${USE_ISTIO} ]]; then
# Create the route so healthcheck can pass
kubectl apply -f /var/envoy-config/healthcheck_route.yaml
fi
# Since JupyterHub uses websockets we want to increase the backend timeout
echo Increasing backend timeout for JupyterHub
gcloud --project=${PROJECT} compute backend-services update --global ${BACKEND_SERVICE} --timeout=3600
echo "Backend updated successfully. Waiting 1 hour before updating again."
sleep 3600

View File

@ -1,243 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env {
hostname: if std.objectHas(_params, "hostname") then _params.hostname else "null",
},
local namespace = params.namespace,
local deployment = {
apiVersion: "extensions/v1beta1",
kind: "Deployment",
metadata: {
name: "gcp-cred-webhook",
namespace: namespace,
},
spec: {
template: {
metadata: {
labels: {
app: "gcp-cred-webhook"
},
},
spec: {
containers: [
{
name: "gcp-cred-webhook",
image: params.image,
volumeMounts: [{
name: "webhook-cert",
mountPath: "/etc/webhook/certs",
readOnly: true,
}],
},
],
volumes: [
{
name: "webhook-cert",
secret: {
secretName: "gcp-cred-webhook-certs",
},
},
],
},
},
},
}, // deployment
deployment:: deployment,
local service = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "gcp-cred-webhook",
},
name: "gcp-cred-webhook",
namespace: namespace,
},
spec: {
selector: {
app: "gcp-cred-webhook",
},
ports: [
{
port: 443,
targetPort: 443,
},
],
},
}, // service
service:: service,
local webhookConfig = {
apiVersion: "admissionregistration.k8s.io/v1beta1",
kind: "MutatingWebhookConfiguration",
metadata: {
name: "gcp-cred-webhook",
// This is cluster scope.
},
webhooks: [
{
// name has to be fully qualified X.X.X
name: "gcp-cred-webhook.kubeflow.org",
clientConfig: {
service: {
name: "gcp-cred-webhook",
namespace: namespace,
path: "/add-cred"
},
// To be patched.
caBundle: "",
},
rules: [
{
operations: ["CREATE"],
apiGroups: [""],
apiVersions: ["v1"],
resources: ["pods"],
},
],
},
],
}, // webhookConfig
webhookConfig:: webhookConfig,
local webhookBootstrapJob = {
apiVersion: "apps/v1",
kind: "StatefulSet",
metadata: {
name: "webhook-bootstrap",
namespace: namespace,
},
spec: {
selector: {
matchLabels: {
service: "webhook-bootstrap",
},
},
template: {
metadata: {
labels: {
service: "webhook-bootstrap",
},
},
spec: {
restartPolicy: "Always",
serviceAccountName: "webhook-bootstrap",
containers: [
{
name: "bootstrap",
image: params.webhookSetupImage,
command: [
"sh",
"/var/webhook-config/create_ca.sh",
],
env: [
{
name: "NAMESPACE",
value: namespace,
},
],
volumeMounts: [
{
mountPath: "/var/webhook-config/",
name: "webhook-config",
},
],
},
],
volumes: [
{
configMap: {
name: "webhook-bootstrap-config",
},
name: "webhook-config",
},
],
},
},
},
}, // webhookBootstrapJob
webhookBootstrapJob:: webhookBootstrapJob,
local initServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "webhook-bootstrap",
namespace: namespace,
},
}, // initServiceAccount
initServiceAccount:: initServiceAccount,
local initClusterRoleBinding = {
kind: "ClusterRoleBinding",
apiVersion: "rbac.authorization.k8s.io/v1beta1",
metadata: {
name: "webhook-bootstrap",
},
subjects: [
{
kind: "ServiceAccount",
name: "webhook-bootstrap",
namespace: namespace,
},
],
roleRef: {
kind: "ClusterRole",
name: "webhook-bootstrap",
apiGroup: "rbac.authorization.k8s.io",
},
}, // initClusterRoleBinding
initClusterRoleBinding:: initClusterRoleBinding,
local initClusterRole = {
kind: "ClusterRole",
apiVersion: "rbac.authorization.k8s.io/v1beta1",
metadata: {
name: "webhook-bootstrap",
},
rules: [
{
apiGroups: ["admissionregistration.k8s.io"],
resources: ["mutatingwebhookconfigurations"],
verbs: ["*"],
},
{
apiGroups: [""],
resources: ["secrets"],
verbs: ["*"],
},
],
}, // initClusterRoleBinding
initClusterRole:: initClusterRole,
local webhookConfigmap = {
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "webhook-bootstrap-config",
namespace: namespace,
},
data: {
"create_ca.sh": importstr "create_ca.sh",
}
}, // webhookConfigmap
webhookConfigmap:: webhookConfigmap,
all:: [
self.deployment,
self.service,
self.webhookBootstrapJob,
self.webhookConfigmap,
self.webhookConfig,
self.initServiceAccount,
self.initClusterRole,
self.initClusterRoleBinding,
],
list(obj=self.all):: k.core.v1.list.new(obj,),
}
}

View File

@ -1,6 +0,0 @@
approvers:
- ioandr
- kkasravi
- pdmack
reviewers:
- vkoukis

View File

@ -1,118 +0,0 @@
# Configuration file for the default JupyterHub Spawner UI
# Each key corresponds to a JupyterHub Spawner UI option
# If a key is missing, the respective Spawner UI option will be left untouched
#
# Each Spawner UI option is configured by two keys: `value` and `readOnly`
# - The `value` key contains the default value
# - The `readOnly` key determines if the option will be available to users
#
# If the 'readOnly' key is present and set to 'true', the respective option
# will be disabled for users and only set by the admin
# If the 'readOnly' key is missing (defaults to 'false'), the respective option
# will be available for users
#
# Please note that some values (e.g. {username}) may be templated
# and expanded according to KubeSpawner's rules
#
# For more information regarding JupyterHub KubeSpawner and its configuration:
# https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html
spawnerFormDefaults:
image:
# The container Image for the user's Jupyter Notebook
# If readonly, this value must be a member of the list below
value: gcr.io/kubeflow-images-public/tensorflow-1.13.1-notebook-cpu:v0.5.0
# The list of available standard container Images
options:
- gcr.io/kubeflow-images-public/tensorflow-1.5.1-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.5.1-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.6.0-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.6.0-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.7.0-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.7.0-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.8.0-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.8.0-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.9.0-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.9.0-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.10.1-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.10.1-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.11.0-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.11.0-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.12.0-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.12.0-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.13.1-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-1.13.1-notebook-gpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-2.0.0a-notebook-cpu:v0.5.0
- gcr.io/kubeflow-images-public/tensorflow-2.0.0a-notebook-gpu:v0.5.0
# By default, custom container Images are allowed
# Uncomment the following line to only enable standard container Images
readOnly: false
cpu:
# CPU for user's Notebook
value: '0.5'
# readOnly: true
memory:
# Memory for user's Notebook
value: 1.0Gi
workspaceVolume:
# Workspace Volume to be attached to user's Notebook
# Each Workspace Volume is declared with the following attributes:
# Type, Name, Size, MountPath and Access Mode
value:
type:
# The Type of the Workspace Volume
# Supported values: 'New', 'Existing'
value: New
name:
# The Name of the Workspace Volume
# Note that this is a templated value
# value: {username}-workspace
value: {username}-workspace
size:
# The Size of the Workspace Volume (in Gi)
value: '10'
mountPath:
# The Path that the Workspace Volume will be mounted
readOnly: true
value: /home/jovyan
accessModes:
# The Access Mode of the Workspace Volume
# Supported values: 'ReadWriteOnce', 'ReadWriteMany', 'ReadOnlyMany'
value: ReadWriteOnce
dataVolumes:
# List of additional Data Volumes to be attached to the user's Notebook
value: []
# Each Data Volume is declared with the following attributes:
# Type, Name, Size, MountPath and Access Mode
#
# For example, a list with 2 Data Volumes:
#value:
# - value:
# type:
# value: New
# name:
# value: {username}-vol-1
# size:
# value: '10'
# mountPath:
# value: /home/jovyan/{username}-vol-1
# accessModes:
# value: ReadWriteOnce
# - value:
# type:
# value: New
# name:
# value: {username}-vol-2
# size:
# value: '5'
# mountPath:
# value: /home/jovyan/{username}-vol-2
# accessModes:
# value: ReadWriteOnce
#
# Uncomment the following line to make the Data Volumes list readonly
#readOnly: true
extraResources:
# Extra Resource Limits for user's Notebook
# Note that braces are escaped
value: "{{}}"

View File

@ -1,296 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _env + _params,
local defaultSpawnerData = {
// Default JH Spawner UI files
"spawner_ui_config.yaml": importstr "./config.yaml",
},
local jupyterConfig = {
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: params.name + "-config",
namespace: params.namespace,
},
data: defaultSpawnerData,
},
jupyterConfig:: jupyterConfig,
serviceAccount:: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: params.name,
},
name: params.name,
namespace: params.namespace,
},
},
clusterRole:: {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRole",
metadata: {
name: params.name + "-cluster-role",
},
rules: [
{
apiGroups: [""],
resources: ["namespaces"],
verbs: ["get", "list", "create", "delete"]
},
{
apiGroups: ["kubeflow.org"],
resources: ["notebooks"],
verbs: ["get", "list", "create", "delete"],
},
{
apiGroups: [""],
resources: ["persistentvolumeclaims"],
verbs: ["create", "delete", "get", "list"],
},
{
apiGroups: ["storage.k8s.io"],
resources: ["storageclasses"],
verbs: ["get", "list"],
},
{
apiGroups: [""],
resources: ["secrets"],
verbs: ["get", "list"],
},
]
},
clusterRoleBinding:: {
kind: "ClusterRoleBinding",
apiVersion: "rbac.authorization.k8s.io/v1",
metadata: {
name: params.name + "-binding"
},
subjects: [
{
kind: "ServiceAccount",
name: params.name,
namespace: params.namespace
},
],
roleRef: {
kind: "ClusterRole",
name: params.name + "-cluster-role",
apiGroup: "rbac.authorization.k8s.io",
},
},
notebookRole:: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "Role",
metadata: {
name: "jupyter-notebook-role",
namespace: params.namespace,
},
rules: [
{
apiGroups: [
"",
],
resources: [
"pods",
"pods/log",
"secrets",
"services",
],
verbs: [
"*",
],
},
{
apiGroups: [
"",
"apps",
"extensions",
],
resources: [
"deployments",
"replicasets",
],
verbs: [
"*",
],
},
{
apiGroups: [
"kubeflow.org",
],
resources: [
"*",
],
verbs: [
"*",
],
},
{
apiGroups: [
"batch",
],
resources: [
"jobs",
],
verbs: [
"*",
],
},
],
},
notebookServiceAccount:: {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "jupyter-notebook",
namespace: params.namespace,
},
},
notebookRoleBinding:: {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "RoleBinding",
metadata: {
name: "jupyter-notebook-role-binding",
namespace: params.namespace,
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "Role",
name: "jupyter-notebook-role",
},
subjects: [
{
kind: "ServiceAccount",
name: "jupyter-notebook",
namespace: params.namespace,
},
],
},
svc:: {
apiVersion: "v1",
kind: "Service",
metadata: {
name: params.name,
namespace: params.namespace,
labels: {
run: params.name
},
annotations:{
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: webapp_mapping",
"prefix: /" + params.prefix + "/",
"service: " + params.name + "." + params.namespace,
"add_request_headers: ",
" x-forwarded-prefix: /" + params.prefix
]),
},
},
spec: {
type: "ClusterIP",
ports: [{
port: 80,
targetPort: 5000,
protocol: "TCP",
name: "http",
}],
selector: {
app: params.name
},
},
},
depl :: {
apiVersion: "apps/v1",
kind: "Deployment",
metadata: {
name: params.name,
namespace: params.namespace,
labels: {
app: params.name,
},
},
spec: {
replicas: 1,
selector: {
matchLabels: {
app: params.name,
},
},
template: {
metadata:{
labels: {
app: params.name,
},
},
spec: {
serviceAccountName: params.name,
containers: [{
name: params.name,
image: params.image,
env: std.prune([
{
name: "ROK_SECRET_NAME",
value: params.rokSecretName,
},
{
name: "UI",
value: params.ui,
},
]),
volumeMounts: [
{
mountPath: "/etc/config",
name: "config-volume",
},
],
ports: [{
containerPort: 5000,
}],
imagePullPolicy: params.policy,
}],
volumes: [
{
configMap: {
name: params.name + "-config",
},
name: "config-volume",
},
],
},
},
},
},
parts:: self,
all:: [
self.svc,
self.depl,
self.jupyterConfig,
self.serviceAccount,
self.clusterRoleBinding,
self.clusterRole,
self.notebookServiceAccount,
self.notebookRole,
self.notebookRoleBinding,
],
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,423 +0,0 @@
{
local k = import "k.libsonnet",
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _params + _env,
local defaultSpawnerData = {
// Default JH Spawner UI files
"template.html": importstr "ui/default/template.html",
"script.js": importstr "ui/default/script.js",
"style.css": importstr "ui/default/style.css",
"spawner.py": std.strReplace(importstr "ui/default/spawner.py", "\\\n", ""),
"spawner_ui_config.yaml": importstr "ui/default/config.yaml",
},
local rokSpawnerData = {
// Base files that Rok UI extends or overrides
"default_template.html": importstr "ui/default/template.html",
"default_style.css": importstr "ui/default/style.css",
"default_spawner.py": importstr "ui/default/spawner.py",
// Rok UI files
"template.html": importstr "ui/rok/template.html",
"script.js": importstr "ui/rok/script.js",
"style.css": importstr "ui/rok/style.css",
"spawner.py": std.strReplace(importstr "ui/rok/spawner.py", "\\\n", ""),
"spawner_ui_config.yaml": importstr "ui/rok/config.yaml",
},
local kubeSpawnerConfig = {
apiVersion: "v1",
kind: "ConfigMap",
metadata: {
name: "jupyter-config",
namespace: params.namespace,
},
// JH config file
local config = {
"jupyter_config.py": std.strReplace(importstr "jupyter_config.py", "\\\n", ""),
},
data: config +
if params.ui == "rok" then rokSpawnerData
else if params.ui == "default" then defaultSpawnerData,
},
kubeSpawnerConfig:: kubeSpawnerConfig,
local notebookService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "jupyter",
},
name: "jupyter-0",
namespace: params.namespace,
annotations: {
"prometheus.io/scrape": "true",
},
},
spec: {
// We want a headless service so we set the ClusterIP to be None.
// This headless server is used by individual Jupyter pods to connect back to the Hub.
clusterIP: "None",
ports: [
{
name: "hub",
port: 8000,
},
],
selector: {
app: "jupyter",
},
},
},
notebookService:: notebookService,
local hubService = {
apiVersion: "v1",
kind: "Service",
metadata: {
labels: {
app: "jupyter-lb",
},
name: "jupyter-lb",
namespace: params.namespace,
annotations: {
"getambassador.io/config":
std.join("\n", [
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: jupyter-lb-hub-mapping",
"prefix: /hub/",
"rewrite: /hub/",
"timeout_ms: 300000",
"service: jupyter-lb." + params.namespace,
"use_websocket: true",
"---",
"apiVersion: ambassador/v0",
"kind: Mapping",
"name: jupyter-lb-user-mapping",
"prefix: /user/",
"rewrite: /user/",
"timeout_ms: 300000",
"service: jupyter-lb." + params.namespace,
"use_websocket: true",
]),
}, //annotations
},
spec: {
ports: [
{
name: "hub",
port: 80,
targetPort: 8000,
},
],
selector: {
app: "jupyter",
},
type: params.serviceType,
},
},
hubService:: hubService,
local hubStatefulSet = {
apiVersion: "apps/v1beta1",
kind: "StatefulSet",
metadata: {
name: "jupyter",
namespace: params.namespace,
},
spec: {
replicas: 1,
serviceName: "",
template: {
metadata: {
labels: {
app: "jupyter",
},
},
spec: {
containers: [
{
command: [
"jupyterhub",
"-f",
"/etc/config/jupyter_config.py",
],
image: params.image,
name: "jupyter",
volumeMounts: [
{
mountPath: "/etc/config",
name: "config-volume",
},
],
ports: [
// Port 8000 is used by the hub to accept incoming requests.
{
containerPort: 8000,
},
// Port 8081 accepts callbacks from the individual Jupyter pods.
{
containerPort: 8081,
},
],
env: std.prune([
{
name: "KF_AUTHENTICATOR",
value: params.jupyterHubAuthenticator,
},
{
name: "DEFAULT_JUPYTERLAB",
value: params.useJupyterLabAsDefault,
},
{
name: "STORAGE_CLASS",
value: params.storageClass,
},
{
name: "ROK_SECRET_NAME",
value: params.rokSecretName,
},
if params.platform == "gke" then
{
name: "GCP_SECRET_NAME",
value: params.gcpSecretName,
},
if params.platform == "minikube" && std.toString(params.notebookUid) != "-1" then
{
name: "NOTEBOOK_UID",
value: std.toString(params.notebookUid),
},
if params.platform == "minikube" && std.toString(params.notebookGid) != "-1" then
{
name: "NOTEBOOK_GID",
value: std.toString(params.notebookGid),
},
if params.platform == "minikube" then
{
name: "ACCESS_LOCAL_FS",
value: std.toString(params.accessLocalFs),
},
]),
}, // jupyter container
],
serviceAccountName: "jupyter",
volumes: [
{
configMap: {
name: "jupyter-config",
},
name: "config-volume",
},
],
},
},
updateStrategy: {
type: "RollingUpdate",
},
},
},
hubStatefulSet:: hubStatefulSet,
// contents based on https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/master/jupyterhub/templates/hub/rbac.yaml
local hubRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "Role",
metadata: {
name: "jupyter-role",
namespace: params.namespace,
},
rules: [
{
apiGroups: [
"",
],
resources: [
"pods",
"persistentvolumeclaims",
],
verbs: [
"get",
"watch",
"list",
"create",
"delete",
],
},
{
apiGroups: [
"",
],
resources: [
"events",
"secrets",
],
verbs: [
"get",
"watch",
"list",
],
},
],
},
hubRole:: hubRole,
local notebookRole = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "Role",
metadata: {
name: "jupyter-notebook-role",
namespace: params.namespace,
},
rules: [
{
apiGroups: [
"",
],
resources: [
"pods",
"pods/log",
"secrets",
"services",
],
verbs: [
"*",
],
},
{
apiGroups: [
"",
"apps",
"extensions",
],
resources: [
"deployments",
"replicasets",
],
verbs: [
"*",
],
},
{
apiGroups: [
"kubeflow.org",
],
resources: [
"*",
],
verbs: [
"*",
],
},
{
apiGroups: [
"batch",
],
resources: [
"jobs",
],
verbs: [
"*",
],
},
],
},
notebookRole:: notebookRole,
local hubServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: "jupyter",
},
name: "jupyter",
namespace: params.namespace,
},
},
hubServiceAccount:: hubServiceAccount,
local notebookServiceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "jupyter-notebook",
namespace: params.namespace,
},
},
notebookServiceAccount:: notebookServiceAccount,
local hubRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "RoleBinding",
metadata: {
name: "jupyter-role",
namespace: params.namespace,
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "Role",
name: "jupyter-role",
},
subjects: [
{
kind: "ServiceAccount",
name: "jupyter",
namespace: params.namespace,
},
],
},
hubRoleBinding:: hubRoleBinding,
local notebookRoleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1beta1",
kind: "RoleBinding",
metadata: {
name: "jupyter-notebook-role",
namespace: params.namespace,
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "Role",
name: "jupyter-notebook-role",
},
subjects: [
{
kind: "ServiceAccount",
name: "jupyter-notebook",
namespace: params.namespace,
},
],
},
notebookRoleBinding:: notebookRoleBinding,
local localstorage = (import "localstorage.libsonnet"),
pv:: localstorage.pv,
pvclaim:: localstorage.pvclaim,
parts:: self,
all:: [
self.kubeSpawnerConfig,
self.notebookService,
self.hubStatefulSet,
self.hubRole,
self.notebookRole,
self.hubService,
self.hubServiceAccount,
self.notebookServiceAccount,
self.hubRoleBinding,
self.notebookRoleBinding,
] + std.flattenArrays([
if params.accessLocalFs == "true" then [
self.pv,
self.pvclaim,
] else [],
]),
list(obj=self.all):: util.list(obj),
},
}

View File

@ -1,136 +0,0 @@
# -*- coding: utf-8 -*-
"""
Configuration file for JupyterHub.
Kubeflow uses this file as the configuration file for JupyterHub. It contains
all glue code necessary to integrate JupyterHub with the remaining Kubeflow
components.
Note that this file is also responsible for importing the UI-specific Spawner
class from <ui-dir>/spawner.py, and setting the `spawner_class` configuration
option.
"""
import os
from importlib.util import spec_from_file_location, module_from_spec
from jhub_remote_user_authenticator.remote_user_auth import \
RemoteUserAuthenticator
SERVICE_ACCOUNT_SECRET_MOUNT = '/var/run/secrets/sa'
# Import the UI-specific Spawner
spec = spec_from_file_location('spawner', '/etc/config/spawner.py')
spawner = module_from_spec(spec)
spec.loader.exec_module(spawner)
###################################################
# JupyterHub Options
###################################################
c.JupyterHub.ip = '0.0.0.0'
c.JupyterHub.hub_ip = '0.0.0.0'
# Don't try to cleanup servers on exit - since in general for k8s, we want
# the hub to be able to restart without losing user containers
c.JupyterHub.cleanup_servers = False
###################################################
###################################################
# Spawner Options
###################################################
c.JupyterHub.spawner_class = spawner.KubeFormSpawner
c.KubeSpawner.cmd = 'start-singleuser.sh'
c.KubeSpawner.args = ['--allow-root']
# gpu images are very large ~15GB. need a large timeout.
c.KubeSpawner.start_timeout = 60 * 30
# Increase timeout to 5 minutes to avoid HTTP 500 errors on JupyterHub
c.KubeSpawner.http_timeout = 60 * 5
# Volume setup
c.KubeSpawner.singleuser_uid = 1000
c.KubeSpawner.singleuser_fs_gid = 100
c.KubeSpawner.singleuser_working_dir = '/home/jovyan'
# Allow environment vars to override uid and gid.
# This allows local host path mounts to be read/writable
env_uid = os.environ.get('NOTEBOOK_UID')
if env_uid:
c.KubeSpawner.singleuser_uid = int(env_uid)
env_gid = os.environ.get('NOTEBOOK_GID')
if env_gid:
c.KubeSpawner.singleuser_fs_gid = int(env_gid)
access_local_fs = os.environ.get('ACCESS_LOCAL_FS')
if access_local_fs == 'true':
def modify_pod_hook(spawner, pod):
pod.spec.containers[0].lifecycle = {
'postStart': {
'exec': {
'command': [
'ln', '-s', '/mnt/local-notebooks',
'/home/jovyan/local-notebooks'
]
}
}
}
return pod
c.KubeSpawner.modify_pod_hook = modify_pod_hook
###################################################
# Persistent volume options
###################################################
# Set user_storage_pvc_ensure to False to prevent KubeSpawner from handling PVCs
# We natively handle PVCs via KubeFormSpawner and its dedicated methods
# NOTE: user_storage_pvc_ensure has been deprecated in a future release
c.KubeSpawner.storage_pvc_ensure = False
c.KubeSpawner.user_storage_pvc_ensure = False
volumes = []
volume_mounts = []
gcp_secret_name = os.environ.get('GCP_SECRET_NAME')
if gcp_secret_name:
volumes.append({
'name': gcp_secret_name,
'secret': {
'secretName': gcp_secret_name,
}
})
volume_mounts.append({
'name': gcp_secret_name,
'mountPath': SERVICE_ACCOUNT_SECRET_MOUNT
})
c.KubeSpawner.volumes = volumes
c.KubeSpawner.volume_mounts = volume_mounts
storage_class = None
if os.environ.get('STORAGE_CLASS') != 'null':
storage_class = os.environ.get('STORAGE_CLASS')
rok_secret_name = ''
if os.environ.get('ROK_SECRET_NAME') != 'null':
rok_secret_name = os.environ.get('ROK_SECRET_NAME')
# Set both service_account and singleuser_service_account because
# singleuser_service_account has been deprecated in a future release
c.KubeSpawner.service_account = 'jupyter-notebook'
c.KubeSpawner.singleuser_service_account = 'jupyter-notebook'
# Authenticator
if os.environ.get('KF_AUTHENTICATOR') == 'iap':
c.JupyterHub.authenticator_class = RemoteUserAuthenticator
c.RemoteUserAuthenticator.header_name = 'x-goog-authenticated-user-email'
else:
c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator'
if os.environ.get('DEFAULT_JUPYTERLAB').lower() == 'true':
c.KubeSpawner.default_url = '/lab'
# Set extra spawner configuration variables
c.KubeSpawner.extra_spawner_config = {
'gcp_secret_name': gcp_secret_name,
'storage_class': storage_class,
'rok_secret_name': rok_secret_name,
}

View File

@ -1,64 +0,0 @@
{
local pv = {
kind: 'PersistentVolume',
apiVersion: 'v1',
metadata: {
name: 'local-volume',
labels: {
type: 'local',
},
},
spec: {
persistentVolumeReclaimPolicy: 'Delete',
storageClassName: 'local-storage',
capacity: {
storage: '10Gi',
},
accessModes: [
'ReadWriteOnce',
],
'local': {
path: '/mnt/local',
},
nodeAffinity: {
required: {
nodeSelectorTerms: [
{
matchExpressions: [
{
key: 'kubernetes.io/hostname',
operator: 'In',
values: [
'minikube',
],
},
],
},
],
},
},
},
},
pv:: pv,
local pvclaim = {
kind: 'PersistentVolumeClaim',
apiVersion: 'v1',
metadata: {
name: 'local-notebooks',
},
spec: {
storageClassName: 'local-storage',
accessModes: [
'ReadWriteOnce',
],
resources: {
requests: {
storage: '10Gi',
},
},
volumeName: 'local-volume',
},
},
pvclaim:: pvclaim,
}

View File

@ -1,193 +0,0 @@
{
local util = import "kubeflow/common/util.libsonnet",
new(_env, _params):: {
local params = _env + _params,
local notebooksCRD = {
apiVersion: "apiextensions.k8s.io/v1beta1",
kind: "CustomResourceDefinition",
metadata: {
name: "notebooks.kubeflow.org",
},
spec: {
group: "kubeflow.org",
version: "v1alpha1",
scope: "Namespaced",
subresources: {
status: {},
},
names: {
plural: "notebooks",
singular: "notebook",
kind: "Notebook",
},
},
status: {
acceptedNames: {
kind: "",
plural: "",
},
conditions: [],
storedVersions: [],
},
},
notebooksCRD:: notebooksCRD,
local controllerService = {
apiVersion: "v1",
kind: "Service",
metadata: {
name: "notebooks-controller",
namespace: params.namespace,
},
spec: {
selector: {
app: "notebooks-controller",
},
ports: [
{
port: 443,
},
],
},
},
controllerService:: controllerService,
local controllerDeployment = {
apiVersion: "apps/v1beta1",
kind: "Deployment",
metadata: {
name: "notebooks-controller",
namespace: params.namespace,
},
spec: {
selector: {
matchLabels: {
app: "notebooks-controller",
},
},
template: {
metadata: {
labels: {
app: "notebooks-controller",
},
},
spec: {
serviceAccountName: "notebook-controller",
containers: [
{
name: "manager",
image: params.controllerImage,
imagePullPolicy: "Always",
command: [
"/manager",
],
env: if util.toBool(params.injectGcpCredentials) then [
{
name: "POD_LABELS",
value: "gcp-cred-secret=user-gcp-sa,gcp-cred-secret-filename=user-gcp-sa.json",
},
] else [],
},
],
},
},
},
},
controllerDeployment:: controllerDeployment,
local serviceAccount = {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
labels: {
app: "notebook-controller",
},
name: "notebook-controller",
namespace: params.namespace,
},
},
serviceAccount:: serviceAccount,
local role = {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRole",
metadata: {
name: "notebooks-controller",
},
rules: [
{
apiGroups: [
"apps",
],
resources: [
"statefulsets",
"deployments",
],
verbs: [
"*",
],
},
{
apiGroups: [
"",
],
resources: [
"services",
"pods",
],
verbs: [
"*",
],
},
{
apiGroups: [
"kubeflow.org",
],
resources: [
"notebooks",
"notebooks/status",
],
verbs: [
"*",
],
},
],
},
role:: role,
local roleBinding = {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "ClusterRoleBinding",
metadata: {
name: "notebooks-controller",
},
roleRef: {
apiGroup: "rbac.authorization.k8s.io",
kind: "ClusterRole",
name: "notebooks-controller",
},
subjects: [
{
kind: "ServiceAccount",
name: "notebook-controller",
namespace: params.namespace,
},
],
},
roleBinding:: roleBinding,
parts:: self,
all:: [
self.notebooksCRD,
self.controllerService,
self.serviceAccount,
self.controllerDeployment,
self.role,
self.roleBinding,
],
list(obj=self.all):: util.list(obj),
},
}

Some files were not shown because too many files have changed in this diff Show More