update kubeflow dip-catalog

This commit is contained in:
ChanghoWoo
2025-01-13 02:31:27 +00:00
parent 1dc1181a03
commit 5451f16d72
1959 changed files with 602337 additions and 0 deletions
@@ -0,0 +1,29 @@
# This makefile is a quick test to verify all manifests can be hydrated.
test: aws azure dev gcp platform-agnostic platform-agnostic-multi-user plain plain-multi-user
aws: FORCE
kubectl kustomize env/aws
azure: FORCE
kubectl kustomize env/azure
dev: FORCE
kubectl kustomize env/dev
gcp: FORCE
kubectl kustomize env/gcp
platform-agnostic: FORCE
kubectl kustomize env/platform-agnostic
platform-agnostic-multi-user: FORCE
kustomize build --load-restrictor LoadRestrictionsNone env/platform-agnostic-multi-user
plain: FORCE
kubectl kustomize env/plain
plain-multi-user: FORCE
kustomize build --load-restrictor LoadRestrictionsNone env/plain-multi-user
FORCE: ;
@@ -0,0 +1,105 @@
# Install Kubeflow Pipelines Tekton Standalone using Kustomize Manifests
This folder contains [Kubeflow Pipelines Standalone](https://www.kubeflow.org/docs/components/pipelines/installation/standalone-deployment/)
Kustomize manifests.
Kubeflow Pipelines Standalone is one option to install Kubeflow Pipelines. You can review all other options in
[Installation Options for Kubeflow Pipelines](https://www.kubeflow.org/docs/components/pipelines/installation/overview/).
## Install options for different envs
To install Kubeflow Pipelines Standalone, follow [Kubeflow Pipelines Standalone Deployment documentation](https://www.kubeflow.org/docs/components/pipelines/installation/standalone-deployment/).
There are environment specific installation instructions not covered in the official deployment documentation, they are listed below.
### (env/platform-agnostic) install on any Kubernetes cluster
Note: `kubectl` client version `v1.20.0`+ to support the new kustomize plugins.
Install:
```bash
KFP_ENV=platform-agnostic
kubectl apply -k cluster-scoped-resources/
kubectl wait crd/applications.app.k8s.io --for condition=established --timeout=60s
kubectl apply -k "env/${KFP_ENV}/"
kubectl wait pods -l application-crd-id=kubeflow-pipelines -n kubeflow --for condition=Ready --timeout=1800s
kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8080:80
```
Now you can access Kubeflow Pipelines UI in your browser by <http://localhost:8080>.
You can install them by changing `KFP_ENV` in above instructions to the variation you want.
Data:
Application data are persisted in in-cluster PersistentVolumeClaim storage.
### (env/ibm) install on IBM Cloud with in-cluster PersistentVolumeClaim storage
IBM Cloud uses the NFS storage with UID support to make sure all pods can run as non-root users.
Please follow the [IKS group ID storage setup](https://www.kubeflow.org/docs/ibm/deploy/install-kubeflow-on-iks/#ibm-cloud-group-id-storage-setup)
before running the above standalone install commands.
### (env/gcp) install on Google Cloud with Cloud Storage and Cloud SQL
Cloud Storage and Cloud SQL are better for operating a production cluster.
Refer to [Google Cloud Instructions](sample/README.md) for installation.
### (env/aws) install on AWS with S3 and RDS MySQL
S3 and RDS MySQL are better for operating a production cluster.
Refer to [AWS Instructions](env/aws/README.md) for installation.
Note: Community maintains a different opinionated installation manifests for AWS, refer to [e2fyi/kubeflow-aws](https://github.com/e2fyi/kubeflow-aws/tree/master/pipelines).
## Uninstall
If the installation is based on CloudSQL/GCS, after the uninstall, the data is still there,
reinstall a newer version can reuse the data.
```bash
### 1. namespace scoped
# Depends on how you installed it:
kubectl kustomize env/platform-agnostic/ | kubectl delete -f -
# or
kubectl kustomize env/dev | kubectl delete -f -
# or
kubectl kustomize env/gcp | kubectl delete -f -
# or
kubectl delete applications/pipeline -n kubeflow
### 2. cluster scoped
kubectl delete -k cluster-scoped-resources/
```
## Folder Structure
### Overview
* User facing manifest entrypoints are `cluster-scoped-resources` package and `env/<env-name>` package.
* `cluster-scoped-resources` should collect all cluster-scoped resources.
* `env/<env-name>` should collect env specific namespace-scoped resources.
* Note, for multi-user envs, they already included cluster-scoped resources.
* KFP core components live in `base/<component-name>` folders.
* If a component requires cluster-scoped resources, it should have a folder inside named `cluster-scoped` with related resources, but note that `base/<component-name>/kustomization.yaml` shouldn't include the `cluster-scoped` folder. `cluster-scoped` folders should be collected by top level `cluster-scoped-resources` folder.
* KFP core installations are in `base/installs/<install-type>`, they only include the core KFP components, not third party ones.
* Third party components live in `third-party/<component-name>` folders.
### For direct deployments
Env specific overlays live in `env/<env-name>` folders, they compose above components to get ready for directly deploying.
### For downstream consumers
Please compose `base/installs/<install-type>` and third party dependencies based on your own requirements.
### Rationale
Constraints for namespaced installation we need to comply with (that drove above structure):
* CRDs must be applied separately, because if we apply CRs in the same `kubectl apply` command, the CRD may not have been accepted by k8s api server (e.g. Application CRD).
* [A Kubeflow 1.0 constraint](https://github.com/kubeflow/pipelines/issues/2884#issuecomment-577158715) is that we should separate cluster scoped resources from namespace scoped resources, because sometimes different roles are required to deploy them. Cluster scoped resources usually need a cluster admin role, while namespaced resources can be deployed by individual teams managing a namespace.
@@ -0,0 +1,49 @@
# Note, this application.yaml is not included by default for most environments.
apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
name: $(kfp-app-name)
annotations:
kubernetes-engine.cloud.google.com/icon: >-
data:image/png;base64,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
marketplace.cloud.google.com/deploy-info: '{"partner_id": "google-cloud-ai-platform", "product_id": "kubeflow-pipelines", "partner_name": "Google Cloud AI Platform"}'
spec:
addOwnerRef: true
selector:
matchLabels:
application-crd-id: kubeflow-pipelines
descriptor:
version: $(kfp-app-version)
type: Kubeflow Pipelines
description: |-
Reusable end-to-end ML workflow
maintainers:
- name: Google Cloud AI Platform
url: https://cloud.google.com/ai-platform/
- name: Kubeflow Pipelines
url: https://github.com/kubeflow/pipelines
links:
- description: 'Kubeflow Pipelines Documentation'
url: https://www.kubeflow.org/docs/pipelines/
notes: |-
Please go to [Hosted Kubeflow Pipelines Console](https://console.cloud.google.com/ai-platform/pipelines/clusters).
info:
- name: Console
value: 'https://console.cloud.google.com/ai-platform/pipelines/clusters'
componentKinds:
- group: v1
kind: ServiceAccount
- group: rbac.authorization.k8s.io/v1
kind: Role
- group: rbac.authorization.k8s.io/v1
kind: RoleBinding
- group: v1
kind: Service
- group: v1
kind: ConfigMap
- group: v1
kind: Secret
- group: apps/v1
kind: Deployment
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- application.yaml
@@ -0,0 +1,29 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache-deployer-deployment
labels:
app: cache-deployer
spec:
replicas: 1
selector:
matchLabels:
app: cache-deployer
strategy:
type: Recreate
template:
metadata:
labels:
app: cache-deployer
spec:
containers:
- name: main
image: gcr.io/ml-pipeline/cache-deployer:dummy
imagePullPolicy: Always
env:
- name: NAMESPACE_TO_WATCH
valueFrom:
fieldRef:
fieldPath: metadata.namespace
serviceAccountName: kubeflow-pipelines-cache-deployer-sa
restartPolicy: Always
@@ -0,0 +1,17 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app: kubeflow-pipelines-cache-deployer-role
name: kubeflow-pipelines-cache-deployer-role
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- get
- patch
- list
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubeflow-pipelines-cache-deployer-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubeflow-pipelines-cache-deployer-role
subjects:
- kind: ServiceAccount
name: kubeflow-pipelines-cache-deployer-sa
@@ -0,0 +1,35 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app: kubeflow-pipelines-cache-deployer-clusterrole
name: kubeflow-pipelines-cache-deployer-clusterrole
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
- certificatesigningrequests/approval
verbs:
- create
- delete
- get
- update
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- create
- delete
- get
- list
- patch
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- kubernetes.io/*
verbs:
- approve
@@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeflow-pipelines-cache-deployer-clusterrolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubeflow-pipelines-cache-deployer-clusterrole
subjects:
- kind: ServiceAccount
name: kubeflow-pipelines-cache-deployer-sa
# namespace will be added by kustomize automatically according to the namespace field in kustomization.yaml
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubeflow-pipelines-cache-deployer-sa
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cache-deployer-clusterrole.yaml
- cache-deployer-clusterrolebinding.yaml
# HACK: although a service account(SA) is not a cluster-scoped resource.
# Presence of a SA referred by a clusterrolebinding allows kustomize to auto-add
# namespace for the clusterrolebinding's SA ref.
- cache-deployer-sa.yaml
@@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cluster-scoped
- cache-deployer-role.yaml
- cache-deployer-rolebinding.yaml
- cache-deployer-deployment.yaml
commonLabels:
app: cache-deployer
images:
- name: gcr.io/ml-pipeline/cache-deployer
newTag: 1.8.4
@@ -0,0 +1,82 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache-server
labels:
app: cache-server
spec:
replicas: 1
selector:
matchLabels:
app: cache-server
template:
metadata:
labels:
app: cache-server
spec:
containers:
- name: server
image: gcr.io/ml-pipeline/cache-server:dummy
env:
- name: CACHE_IMAGE
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: cacheImage
- name: CACHE_NODE_RESTRICTIONS
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: cacheNodeRestrictions
- name: DBCONFIG_DRIVER
value: mysql
- name: DBCONFIG_DB_NAME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: cacheDb
- name: DBCONFIG_HOST_NAME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbHost
- name: DBCONFIG_PORT
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbPort
- name: DBCONFIG_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
- name: DBCONFIG_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: NAMESPACE_TO_WATCH
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args: ["--db_driver=$(DBCONFIG_DRIVER)",
"--db_host=$(DBCONFIG_HOST_NAME)",
"--db_port=$(DBCONFIG_PORT)",
"--db_name=$(DBCONFIG_DB_NAME)",
"--db_user=$(DBCONFIG_USER)",
"--db_password=$(DBCONFIG_PASSWORD)",
"--namespace_to_watch=$(NAMESPACE_TO_WATCH)",
]
imagePullPolicy: Always
ports:
- containerPort: 8443
name: webhook-api
volumeMounts:
- name: webhook-tls-certs
mountPath: /etc/webhook/certs
readOnly: true
volumes:
- name: webhook-tls-certs
secret:
secretName: webhook-server-tls
serviceAccountName: kubeflow-pipelines-cache
@@ -0,0 +1,44 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app: kubeflow-pipelines-cache-role
name: kubeflow-pipelines-cache-role
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- tekton.dev
resources:
- taskruns
- taskruns/status
verbs:
- get
- list
- watch
- update
- patch
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubeflow-pipelines-cache-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubeflow-pipelines-cache-role
subjects:
- kind: ServiceAccount
name: kubeflow-pipelines-cache
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubeflow-pipelines-cache
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: cache-server
spec:
selector:
app: cache-server
ports:
- port: 443
targetPort: webhook-api
@@ -0,0 +1,14 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cache-deployment.yaml
- cache-service.yaml
- cache-role.yaml
- cache-rolebinding.yaml
- cache-sa.yaml
commonLabels:
app: cache-server
images:
- name: gcr.io/ml-pipeline/cache-server
newName: quay.io/aipipeline/cache-server
newTag: 1.7.1
@@ -0,0 +1,61 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kubeflow
resources:
- ../../pipeline
- ../../cache
- ../../cache-deployer
- pipeline-install-config.yaml
- mysql-secret.yaml
# Used by Kustomize
replacements:
- source:
name: pipeline-install-config
kind: ConfigMap
version: v1
fieldpath: data.appName
targets:
- select:
kind: Application
version: app.k8s.io/v1beta1
fieldPaths:
- metadata.name
- source:
name: pipeline-install-config
kind: ConfigMap
version: v1
fieldpath: data.appVersion
targets:
- select:
kind: Application
version: app.k8s.io/v1beta1
fieldPaths:
- spec.descriptor.version
- source:
name: pipeline-install-config
kind: ConfigMap
version: v1
fieldpath: data.bucketName
targets:
- select:
kind: ConfigMap
name: workflow-controller-configmap
fieldPaths:
- data.artifactRepository.s3.bucket
- source:
name: pipeline-install-config
kind: ConfigMap
version: v1
fieldpath: data.defaultPipelineRoot
targets:
- select:
kind: ConfigMap
name: kfp-launcher
fieldPaths:
- data.defaultPipelineRoot
configurations:
- params.yaml
@@ -0,0 +1,7 @@
kind: Secret
apiVersion: v1
metadata:
name: mysql-secret
stringData:
username: root
password: ""
@@ -0,0 +1,10 @@
# Allow Kustomize var to replace following fields.
varReference:
- path: data/config
kind: ConfigMap
- path: data/defaultPipelineRoot
kind: ConfigMap
- path: metadata/name
kind: Application
- path: spec/descriptor/version
kind: Application
@@ -0,0 +1,79 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: pipeline-install-config
data:
warning: |
1. Do not use kubectl to edit this configmap, because some values are used
during kustomize build. Instead, change the configmap and apply the entire
kustomize manifests again.
2. After updating the configmap, some deployments may need to be restarted
until the changes take effect. A quick way to restart all deployments in a
namespace: `kubectl rollout restart deployment -n <your-namespace>`.
appName: pipeline
appVersion: 1.8.4
dbHost: mysql
dbPort: "3306"
mlmdDb: metadb
cacheDb: cachedb
pipelineDb: mlpipeline
objectStoreHost: minio-service
objectStorePort: "9000"
bucketName: mlpipeline
## defaultPipelineRoot: Optional. Default pipeline root in v2 compatible mode.
## https://www.kubeflow.org/docs/components/pipelines/sdk/v2/v2-compatibility/
##
## If the field is not set, kfp-launcher configmaps won't be created and
## v2 compatible mode defaults to minio://mlpipeline/v2/artifacts as pipeline
## root.
##
## When not in Kubeflow Pipelines multi-user mode, the config works as you
## would normally expect.
##
## In Kubeflow Pipelines multi-user mode, the config creates default
## kfp-launcher configmaps in each user's namespace. Users can edit the
## kfp-launcher configmap's defaultPipelineRoot field afterwards to configure
## namespace-specific default pipeline root. The namespace specific changes in
## kfp-launcher configmap won't be overridden by pipeline-install-config.
##
## Caveat: when you update the config from a non-empty value, only new
## namespaces get the updated config by default. Owners of existing namespaces
## must delete the kfp-launcher configmap to get the new default config value.
##
## Examples:
## defaultPipelineRoot: minio://mlpipeline/v2/artifacts
## defaultPipelineRoot: gs://your-bucket/path/to/artifacts
## defaultPipelineRoot: s3://your-bucket/path/to/artifacts
##
## V2 Compatible Mode Feature stage:
## [Beta](https://github.com/kubeflow/pipelines/blob/master/docs/release/feature-stages.md#beta)
defaultPipelineRoot: ""
## autoUpdatePipelineDefaultVersion: States if the pipeline version
## should be updated by defult for a versioned pipeline or not when a new
## version is uploaded. This sets the deployment wide definition.
autoUpdatePipelineDefaultVersion: "true"
## cronScheduleTimezone: States the timezone which should be used for
## the cron scheduler. If not specified the local timezone of the
## cluster will be used. Valid values are UTC, Local or values according to
## the IANA Time Zone database, such as "America/New_York" and "Asia/Shanghai".
## Feature stage:
## [Alpha](https://github.com/kubeflow/pipelines/blob/master/docs/release/feature-stages.md#alpha)
cronScheduleTimezone: "UTC"
## cacheImage is the image that the mutating webhook will use to patch
## cached steps with. Will be used to echo a message announcing that
## the cached step result will be used. If not set it will default to
## 'registry.access.redhat.com/ubi8/ubi-minimal'
cacheImage: "registry.access.redhat.com/ubi8/ubi-minimal"
## cacheNodeRestrictions the dummy container runing if output is cached
## will run with the same affinity and node selector as the default pipeline
## step. This is defaulted to 'false' to allow the pod to be scheduled on
## any node and avoid defaulting to specific nodes. Allowed values are:
## 'false' and 'true'.
cacheNodeRestrictions: "false"
## ConMaxLifeTime will set the connection max lifetime for MySQL
## this is very important to setup when using external databases.
## See this issue for more details: https://github.com/kubeflow/pipelines/issues/5329
## Note: this value should be a string that can be parsed by `time.ParseDuration`.
## If this value doesn't include a unit abbreviation, the units will be assumed
## to be nanoseconds.
ConMaxLifeTime: "120s"
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ml-pipeline
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ml-pipeline
subjects:
- kind: ServiceAccount
name: ml-pipeline
@@ -0,0 +1,78 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ml-pipeline
rules:
- apiGroups:
- ""
resources:
- pods
- pods/log
verbs:
- get
- list
- delete
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- kubeflow.org
resources:
- scheduledworkflows
verbs:
- create
- get
- list
- update
- patch
- delete
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
- runs
- customruns
- tasks
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- custom.tekton.dev
resources:
- pipelineloops
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
@@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-pipeline
spec:
template:
spec:
containers:
- name: ml-pipeline-api-server
envFrom:
- configMapRef:
name: pipeline-api-server-config
env:
- name: KUBEFLOW_USERID_HEADER
value: kubeflow-userid
- name: KUBEFLOW_USERID_PREFIX
value: ""
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cluster-role-binding.yaml
- cluster-role.yaml
configMapGenerator:
- name: pipeline-api-server-config
envs:
- params.env
@@ -0,0 +1,4 @@
MULTIUSER=true
DEFAULTPIPELINERUNNERSERVICEACCOUNT=default-editor
VISUALIZATIONSERVICE_NAME=ml-pipeline-visualizationserver
VISUALIZATIONSERVICE_PORT=8888
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeflow-pipelines-cache-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubeflow-pipelines-cache-role
subjects:
- kind: ServiceAccount
name: kubeflow-pipelines-cache
@@ -0,0 +1,42 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubeflow-pipelines-cache-role
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- tekton.dev
resources:
- taskruns
- taskruns/status
verbs:
- get
- list
- watch
- update
- patch
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: cache-server
spec:
template:
spec:
containers:
- name: server
env:
- name: NAMESPACE_TO_WATCH
value: ''
valueFrom: null
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
app: cache-server
resources:
- cluster-role.yaml
- cluster-role-binding.yaml
@@ -0,0 +1,106 @@
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ml-pipeline-ui
namespace: kubeflow
spec:
selector:
matchLabels:
app: ml-pipeline-ui
rules:
- from:
- source:
namespaces:
- istio-system
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ml-pipeline
namespace: kubeflow
spec:
selector:
matchLabels:
app: ml-pipeline
rules:
- from:
- source:
principals:
- cluster.local/ns/kubeflow/sa/ml-pipeline
- cluster.local/ns/kubeflow/sa/ml-pipeline-ui
- cluster.local/ns/kubeflow/sa/ml-pipeline-persistenceagent
- cluster.local/ns/kubeflow/sa/ml-pipeline-scheduledworkflow
- cluster.local/ns/kubeflow/sa/ml-pipeline-viewer-crd-service-account
- cluster.local/ns/kubeflow/sa/kubeflow-pipelines-cache
# allow access by any trusted principal
- from:
- source:
requestPrincipals: ["*"]
# For user workloads, which cannot user http headers for authentication
- when:
- key: request.headers[kubeflow-userid]
notValues: ['*']
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ml-pipeline-visualizationserver
namespace: kubeflow
spec:
selector:
matchLabels:
app: ml-pipeline-visualizationserver
rules:
- from:
- source:
principals:
- cluster.local/ns/kubeflow/sa/ml-pipeline
- cluster.local/ns/kubeflow/sa/ml-pipeline-ui
- cluster.local/ns/kubeflow/sa/ml-pipeline-persistenceagent
- cluster.local/ns/kubeflow/sa/ml-pipeline-scheduledworkflow
- cluster.local/ns/kubeflow/sa/ml-pipeline-viewer-crd-service-account
- cluster.local/ns/kubeflow/sa/kubeflow-pipelines-cache
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: service-cache-server
namespace: kubeflow
spec:
selector:
matchLabels:
app: cache-server
rules:
- {}
---
apiVersion: "networking.istio.io/v1alpha3"
kind: DestinationRule
metadata:
name: ml-pipeline-ui
spec:
host: ml-pipeline-ui.kubeflow.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
---
apiVersion: "networking.istio.io/v1alpha3"
kind: DestinationRule
metadata:
name: ml-pipeline
spec:
host: ml-pipeline.kubeflow.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
---
apiVersion: "networking.istio.io/v1alpha3"
kind: DestinationRule
metadata:
name: ml-pipeline-visualizationserver
spec:
host: ml-pipeline-visualizationserver.kubeflow.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
@@ -0,0 +1,46 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kubeflow
commonLabels:
app.kubernetes.io/name: kubeflow-pipelines
app.kubernetes.io/component: ml-pipeline
resources:
- ../generic
- view-edit-cluster-roles.yaml
- api-service
- pipelines-ui
- pipelines-profile-controller
- scheduled-workflow
- viewer-controller
- persistence-agent
- cache
- metadata-writer
- istio-authorization-config.yaml
- virtual-service.yaml
patches:
- path: api-service/deployment-patch.yaml
- path: pipelines-ui/deployment-patch.yaml
- path: pipelines-ui/configmap-patch.yaml
- path: scheduled-workflow/deployment-patch.yaml
- path: viewer-controller/deployment-patch.yaml
- path: persistence-agent/deployment-patch.yaml
- path: metadata-writer/deployment-patch.yaml
- path: cache/deployment-patch.yaml
replacements:
- source:
name: ml-pipeline
kind: Deployment
fieldpath: metadata.namespace
targets:
- select:
kind: VirtualService
name: ml-pipeline-ui
fieldPaths:
- spec.http.0.route.0.destination.host
options:
delimiter: .
index: 1
configurations:
- params.yaml
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubeflow-pipelines-metadata-writer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubeflow-pipelines-metadata-writer-role
subjects:
- kind: ServiceAccount
name: kubeflow-pipelines-metadata-writer
@@ -0,0 +1,45 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubeflow-pipelines-metadata-writer-role
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-writer
spec:
template:
spec:
containers:
- name: main
env:
- name: NAMESPACE_TO_WATCH
value: ''
valueFrom: null
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cluster-role.yaml
- cluster-role-binding.yaml
@@ -0,0 +1,4 @@
# Allow Kustomize var to replace following fields.
varReference:
- path: spec/http/route/destination/host
kind: VirtualService
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ml-pipeline-persistenceagent-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ml-pipeline-persistenceagent-role
subjects:
- kind: ServiceAccount
name: ml-pipeline-persistenceagent
@@ -0,0 +1,38 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ml-pipeline-persistenceagent-role
rules:
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- get
- list
- watch
- apiGroups:
- kubeflow.org
resources:
- scheduledworkflows
verbs:
- get
- list
- watch
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
- runs
- customruns
- tasks
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-pipeline-persistenceagent
spec:
template:
spec:
containers:
- name: ml-pipeline-persistenceagent
env:
- name: NAMESPACE
value: ''
valueFrom: null
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cluster-role.yaml
- cluster-role-binding.yaml
@@ -0,0 +1,41 @@
# Change resyncPeriodSeconds to 1 hour from insane 20 seconds
# Only sync namespaces with pipelines.kubeflow.org/enabled = "true"
apiVersion: metacontroller.k8s.io/v1alpha1
kind: CompositeController
metadata:
name: kubeflow-pipelines-profile-controller
spec:
generateSelector: true
resyncPeriodSeconds: 3600
parentResource:
apiVersion: v1
resource: namespaces
childResources:
- apiVersion: v1
resource: secrets
updateStrategy:
method: OnDelete
- apiVersion: v1
resource: configmaps
updateStrategy:
method: OnDelete
- apiVersion: apps/v1
resource: deployments
updateStrategy:
method: InPlace
- apiVersion: v1
resource: services
updateStrategy:
method: InPlace
- apiVersion: networking.istio.io/v1alpha3
resource: destinationrules
updateStrategy:
method: InPlace
- apiVersion: security.istio.io/v1beta1
resource: authorizationpolicies
updateStrategy:
method: InPlace
hooks:
sync:
webhook:
url: http://kubeflow-pipelines-profile-controller/sync
@@ -0,0 +1,49 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubeflow-pipelines-profile-controller
spec:
replicas: 1
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: profile-controller
image: python:3.7
command: ["python", "/hooks/sync.py"]
envFrom:
- configMapRef:
name: kubeflow-pipelines-profile-controller-env
env:
- name: KFP_VERSION
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: appVersion
- name: KFP_DEFAULT_PIPELINE_ROOT
valueFrom:
configMapKeyRef:
optional: true
name: pipeline-install-config
key: defaultPipelineRoot
- name: MINIO_ACCESS_KEY
valueFrom:
secretKeyRef:
name: mlpipeline-minio-artifact
key: accesskey
- name: MINIO_SECRET_KEY
valueFrom:
secretKeyRef:
name: mlpipeline-minio-artifact
key: secretkey
volumeMounts:
- name: hooks
mountPath: /hooks
ports:
- containerPort: 8080
volumes:
- name: hooks
configMap:
name: kubeflow-pipelines-profile-controller-code
@@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kubeflow
commonLabels:
app: kubeflow-pipelines-profile-controller
resources:
- service.yaml
- deployment.yaml
- composite-controller.yaml
configMapGenerator:
- name: kubeflow-pipelines-profile-controller-code
files:
- sync.py
- name: kubeflow-pipelines-profile-controller-env
envs:
- params.env
@@ -0,0 +1,3 @@
pytest
pytest-lazy-fixture
requests
@@ -0,0 +1,9 @@
# Build venv with required packages
VENV=".venv"
PYTHON_VENV="${VENV}/bin/python"
python -m venv $VENV
$PYTHON_VENV -m pip install -U pip
$PYTHON_VENV -m pip install -r requirements-dev.txt
# Run tests
$PYTHON_VENV -m pytest ./test_sync.py
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: kubeflow-pipelines-profile-controller
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
@@ -0,0 +1,396 @@
# Copyright 2020-2021 The Kubeflow Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import os
import base64
def main():
settings = get_settings_from_env()
server = server_factory(**settings)
server.serve_forever()
def get_settings_from_env(controller_port=None,
visualization_server_image=None, frontend_image=None,
visualization_server_tag=None, frontend_tag=None, disable_istio_sidecar=None,
minio_access_key=None, minio_secret_key=None, kfp_default_pipeline_root=None):
"""
Returns a dict of settings from environment variables relevant to the controller
Environment settings can be overridden by passing them here as arguments.
Settings are pulled from the all-caps version of the setting name. The
following defaults are used if those environment variables are not set
to enable backwards compatibility with previous versions of this script:
visualization_server_image: gcr.io/ml-pipeline/visualization-server
visualization_server_tag: value of KFP_VERSION environment variable
frontend_image: gcr.io/ml-pipeline/frontend
frontend_tag: value of KFP_VERSION environment variable
disable_istio_sidecar: Required (no default)
minio_access_key: Required (no default)
minio_secret_key: Required (no default)
"""
settings = dict()
settings["controller_port"] = \
controller_port or \
os.environ.get("CONTROLLER_PORT", "8080")
settings["visualization_server_image"] = \
visualization_server_image or \
os.environ.get("VISUALIZATION_SERVER_IMAGE", "gcr.io/ml-pipeline/visualization-server")
settings["frontend_image"] = \
frontend_image or \
os.environ.get("FRONTEND_IMAGE", "gcr.io/ml-pipeline/frontend")
# Look for specific tags for each image first, falling back to
# previously used KFP_VERSION environment variable for backwards
# compatibility
settings["visualization_server_tag"] = \
visualization_server_tag or \
os.environ.get("VISUALIZATION_SERVER_TAG") or \
os.environ["KFP_VERSION"]
settings["frontend_tag"] = \
frontend_tag or \
os.environ.get("FRONTEND_TAG") or \
os.environ["KFP_VERSION"]
settings["disable_istio_sidecar"] = \
disable_istio_sidecar if disable_istio_sidecar is not None \
else os.environ.get("DISABLE_ISTIO_SIDECAR") == "true"
settings["minio_access_key"] = \
minio_access_key or \
base64.b64encode(bytes(os.environ.get("MINIO_ACCESS_KEY"), 'utf-8')).decode('utf-8')
settings["minio_secret_key"] = \
minio_secret_key or \
base64.b64encode(bytes(os.environ.get("MINIO_SECRET_KEY"), 'utf-8')).decode('utf-8')
# KFP_DEFAULT_PIPELINE_ROOT is optional
settings["kfp_default_pipeline_root"] = \
kfp_default_pipeline_root or \
os.environ.get("KFP_DEFAULT_PIPELINE_ROOT")
return settings
def server_factory(visualization_server_image,
visualization_server_tag, frontend_image, frontend_tag,
disable_istio_sidecar, minio_access_key,
minio_secret_key, kfp_default_pipeline_root=None,
url="", controller_port=8080):
"""
Returns an HTTPServer populated with Handler with customized settings
"""
class Controller(BaseHTTPRequestHandler):
def sync(self, parent, children):
# parent is a namespace
namespace = parent.get("metadata", {}).get("name")
pipeline_enabled = parent.get("metadata", {}).get(
"labels", {}).get("pipelines.kubeflow.org/enabled")
if pipeline_enabled != "true":
return {"status": {}, "children": []}
desired_configmap_count = 1
desired_resources = []
if kfp_default_pipeline_root:
desired_configmap_count = 2
desired_resources += [{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "kfp-launcher",
"namespace": namespace,
},
"data": {
"defaultPipelineRoot": kfp_default_pipeline_root,
},
}]
# Compute status based on observed state.
desired_status = {
"kubeflow-pipelines-ready":
len(children["Secret.v1"]) == 1 and
len(children["ConfigMap.v1"]) == desired_configmap_count and
len(children["Deployment.apps/v1"]) == 2 and
len(children["Service.v1"]) == 2 and
len(children["DestinationRule.networking.istio.io/v1alpha3"]) == 1 and
len(children["AuthorizationPolicy.security.istio.io/v1beta1"]) == 1 and
"True" or "False"
}
# Generate the desired child object(s).
desired_resources += [
{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": "metadata-grpc-configmap",
"namespace": namespace,
},
"data": {
"METADATA_GRPC_SERVICE_HOST":
"metadata-grpc-service.kubeflow",
"METADATA_GRPC_SERVICE_PORT": "8080",
},
},
# Visualization server related manifests below
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "ml-pipeline-visualizationserver"
},
"name": "ml-pipeline-visualizationserver",
"namespace": namespace,
},
"spec": {
"selector": {
"matchLabels": {
"app": "ml-pipeline-visualizationserver"
},
},
"template": {
"metadata": {
"labels": {
"app": "ml-pipeline-visualizationserver"
},
"annotations": disable_istio_sidecar and {
"sidecar.istio.io/inject": "false"
} or {},
},
"spec": {
"containers": [{
"image": f"{visualization_server_image}:{visualization_server_tag}",
"imagePullPolicy":
"IfNotPresent",
"name":
"ml-pipeline-visualizationserver",
"ports": [{
"containerPort": 8888
}],
"resources": {
"requests": {
"cpu": "50m",
"memory": "200Mi"
},
"limits": {
"cpu": "500m",
"memory": "1Gi"
},
}
}],
"serviceAccountName":
"default-editor",
},
},
},
},
{
"apiVersion": "networking.istio.io/v1alpha3",
"kind": "DestinationRule",
"metadata": {
"name": "ml-pipeline-visualizationserver",
"namespace": namespace,
},
"spec": {
"host": "ml-pipeline-visualizationserver",
"trafficPolicy": {
"tls": {
"mode": "ISTIO_MUTUAL"
}
}
}
},
{
"apiVersion": "security.istio.io/v1beta1",
"kind": "AuthorizationPolicy",
"metadata": {
"name": "ml-pipeline-visualizationserver",
"namespace": namespace,
},
"spec": {
"selector": {
"matchLabels": {
"app": "ml-pipeline-visualizationserver"
}
},
"rules": [{
"from": [{
"source": {
"principals": ["cluster.local/ns/kubeflow/sa/ml-pipeline"]
}
}]
}]
}
},
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "ml-pipeline-visualizationserver",
"namespace": namespace,
},
"spec": {
"ports": [{
"name": "http",
"port": 8888,
"protocol": "TCP",
"targetPort": 8888,
}],
"selector": {
"app": "ml-pipeline-visualizationserver",
},
},
},
# Artifact fetcher related resources below.
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "ml-pipeline-ui-artifact"
},
"name": "ml-pipeline-ui-artifact",
"namespace": namespace,
},
"spec": {
"selector": {
"matchLabels": {
"app": "ml-pipeline-ui-artifact"
}
},
"template": {
"metadata": {
"labels": {
"app": "ml-pipeline-ui-artifact"
},
"annotations": disable_istio_sidecar and {
"sidecar.istio.io/inject": "false"
} or {},
},
"spec": {
"containers": [{
"name":
"ml-pipeline-ui-artifact",
"image": f"{frontend_image}:{frontend_tag}",
"imagePullPolicy":
"IfNotPresent",
"ports": [{
"containerPort": 3000
}],
"env": [
{
"name": "MINIO_ACCESS_KEY",
"valueFrom": {
"secretKeyRef": {
"key": "accesskey",
"name": "mlpipeline-minio-artifact"
}
}
},
{
"name": "MINIO_SECRET_KEY",
"valueFrom": {
"secretKeyRef": {
"key": "secretkey",
"name": "mlpipeline-minio-artifact"
}
}
}
],
"resources": {
"requests": {
"cpu": "10m",
"memory": "70Mi"
},
"limits": {
"cpu": "100m",
"memory": "500Mi"
},
}
}],
"serviceAccountName":
"default-editor"
}
}
}
},
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "ml-pipeline-ui-artifact",
"namespace": namespace,
"labels": {
"app": "ml-pipeline-ui-artifact"
}
},
"spec": {
"ports": [{
"name":
"http", # name is required to let istio understand request protocol
"port": 80,
"protocol": "TCP",
"targetPort": 3000
}],
"selector": {
"app": "ml-pipeline-ui-artifact"
}
}
},
]
print('Received request:\n', json.dumps(parent, indent=2, sort_keys=True))
print('Desired resources except secrets:\n', json.dumps(desired_resources, indent=2, sort_keys=True))
# Moved after the print argument because this is sensitive data.
desired_resources.append({
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "mlpipeline-minio-artifact",
"namespace": namespace,
},
"data": {
"accesskey": minio_access_key,
"secretkey": minio_secret_key,
},
})
return {"status": desired_status, "children": desired_resources}
def do_POST(self):
# Serve the sync() function as a JSON webhook.
observed = json.loads(
self.rfile.read(int(self.headers.get("content-length"))))
desired = self.sync(observed["parent"], observed["children"])
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(bytes(json.dumps(desired), 'utf-8'))
return HTTPServer((url, int(controller_port)), Controller)
if __name__ == "__main__":
main()
@@ -0,0 +1,286 @@
import os
from unittest import mock
import threading
from sync import get_settings_from_env, server_factory
import json
import pytest
import requests
# Data sets passed to server
DATA_INCORRECT_CHILDREN = {
"parent": {
"metadata": {
"labels": {
"pipelines.kubeflow.org/enabled": "true"
},
"name": "myName"
}
},
"children": {
"Secret.v1": [],
"ConfigMap.v1": [],
"Deployment.apps/v1": [],
"Service.v1": [],
"DestinationRule.networking.istio.io/v1alpha3": [],
"AuthorizationPolicy.security.istio.io/v1beta1": [],
}
}
DATA_CORRECT_CHILDREN = {
"parent": {
"metadata": {
"labels": {
"pipelines.kubeflow.org/enabled": "true"
},
"name": "myName"
}
},
"children": {
"Secret.v1": [1],
"ConfigMap.v1": [1],
"Deployment.apps/v1": [1, 1],
"Service.v1": [1, 1],
"DestinationRule.networking.istio.io/v1alpha3": [1],
"AuthorizationPolicy.security.istio.io/v1beta1": [1],
}
}
DATA_MISSING_PIPELINE_ENABLED = {"parent": {}, "children": {}}
# Default values when environments are not explicit
DEFAULT_FRONTEND_IMAGE = "gcr.io/ml-pipeline/frontend"
DEFAULT_VISUALIZATION_IMAGE = "gcr.io/ml-pipeline/visualization-server"
# Variables used for environment variable sets
VISUALIZATION_SERVER_IMAGE = "vis-image"
VISUALIZATION_SERVER_TAG = "somenumber.1.2.3"
FRONTEND_IMAGE = "frontend-image"
FRONTEND_TAG = "somehash"
KFP_VERSION = "x.y.z"
MINIO_ACCESS_KEY = "abcdef"
MINIO_SECRET_KEY = "uvwxyz"
# "Environments" used in tests
ENV_VARIABLES_BASE = {
"MINIO_ACCESS_KEY": MINIO_ACCESS_KEY,
"MINIO_SECRET_KEY": MINIO_SECRET_KEY,
"CONTROLLER_PORT": "0", # HTTPServer randomly assigns the port to a free port
}
ENV_KFP_VERSION_ONLY = dict(ENV_VARIABLES_BASE,
**{
"KFP_VERSION": KFP_VERSION,
}
)
ENV_IMAGES_NO_TAGS = dict(ENV_VARIABLES_BASE,
**{
"KFP_VERSION": KFP_VERSION,
"VISUALIZATION_SERVER_IMAGE": VISUALIZATION_SERVER_IMAGE,
"FRONTEND_IMAGE": FRONTEND_IMAGE,
}
)
ENV_IMAGES_WITH_TAGS = dict(ENV_VARIABLES_BASE,
**{
"VISUALIZATION_SERVER_IMAGE": VISUALIZATION_SERVER_IMAGE,
"FRONTEND_IMAGE": FRONTEND_IMAGE,
"VISUALIZATION_SERVER_TAG": VISUALIZATION_SERVER_TAG,
"FRONTEND_TAG": FRONTEND_TAG,
}
)
ENV_IMAGES_WITH_TAGS_AND_ISTIO = dict(ENV_IMAGES_WITH_TAGS,
**{
"DISABLE_ISTIO_SIDECAR": "false",
}
)
def generate_image_name(imagename, tag):
return f"{str(imagename)}:{str(tag)}"
@pytest.fixture(
scope="function",
)
def sync_server(request):
"""
Starts the sync HTTP server for a given set of environment variables on a separate thread
Yields:
* the server (useful to interrogate for the server address)
* environment variables (useful to interrogate for correct responses)
"""
environ = request.param
with mock.patch.dict(os.environ, environ):
# Create a server at an available port and serve it on a thread as a daemon
# This will result in a collection of servers being active - not a great way
# if this fixture is run many times during a test, but ok for now
settings = get_settings_from_env()
server = server_factory(**settings)
server_thread = threading.Thread(target=server.serve_forever)
# Put on daemon so it doesn't keep pytest from ending
server_thread.daemon = True
server_thread.start()
yield server, environ
@pytest.fixture(
scope="function",
)
def sync_server_from_arguments(request):
"""
Starts the sync HTTP server for a given set of parameters passed as arguments, with server on a separate thread
Yields:
* the server (useful to interrogate for the server address)
* environment variables (useful to interrogate for correct responses)
"""
environ = {k.lower(): v for k, v in request.param.items()}
settings = environ
server = server_factory(**settings)
server_thread = threading.Thread(target=server.serve_forever)
# Put on daemon so it doesn't keep pytest from ending
server_thread.daemon = True
server_thread.start()
yield server, environ
@pytest.mark.parametrize(
"sync_server, data, expected_status, expected_visualization_server_image, expected_frontend_server_image",
[
(
ENV_KFP_VERSION_ONLY,
DATA_INCORRECT_CHILDREN,
{"kubeflow-pipelines-ready": "False"},
generate_image_name(DEFAULT_VISUALIZATION_IMAGE, KFP_VERSION),
generate_image_name(DEFAULT_FRONTEND_IMAGE, KFP_VERSION),
),
(
ENV_IMAGES_NO_TAGS,
DATA_INCORRECT_CHILDREN,
{"kubeflow-pipelines-ready": "False"},
generate_image_name(ENV_IMAGES_NO_TAGS["VISUALIZATION_SERVER_IMAGE"], KFP_VERSION),
generate_image_name(ENV_IMAGES_NO_TAGS["FRONTEND_IMAGE"], KFP_VERSION),
),
(
ENV_IMAGES_WITH_TAGS,
DATA_INCORRECT_CHILDREN,
{"kubeflow-pipelines-ready": "False"},
generate_image_name(ENV_IMAGES_WITH_TAGS["VISUALIZATION_SERVER_IMAGE"],
ENV_IMAGES_WITH_TAGS["VISUALIZATION_SERVER_TAG"]),
generate_image_name(ENV_IMAGES_WITH_TAGS["FRONTEND_IMAGE"], ENV_IMAGES_WITH_TAGS["FRONTEND_TAG"]),
),
(
ENV_IMAGES_WITH_TAGS,
DATA_CORRECT_CHILDREN,
{"kubeflow-pipelines-ready": "True"},
generate_image_name(ENV_IMAGES_WITH_TAGS["VISUALIZATION_SERVER_IMAGE"],
ENV_IMAGES_WITH_TAGS["VISUALIZATION_SERVER_TAG"]),
generate_image_name(ENV_IMAGES_WITH_TAGS["FRONTEND_IMAGE"], ENV_IMAGES_WITH_TAGS["FRONTEND_TAG"]),
),
],
indirect=["sync_server"]
)
def test_sync_server_with_pipeline_enabled(sync_server, data, expected_status,
expected_visualization_server_image, expected_frontend_server_image):
"""
Nearly end-to-end test of how Controller serves .sync as a POST
Tests case where metadata.labels.pipelines.kubeflow.org/enabled exists, and thus
we should produce children
Only does spot checks on children to see if key properties are correct
"""
server, environ = sync_server
# server.server_address = (url, port_as_integer)
url = f"http://{server.server_address[0]}:{str(server.server_address[1])}"
print("url: ", url)
print("data")
print(json.dumps(data, indent=2))
x = requests.post(url, data=json.dumps(data))
results = json.loads(x.text)
# Test overall status of whether children are ok
assert results['status'] == expected_status
# Poke a few children to test things that can vary by environment variable
assert results['children'][1]["spec"]["template"]["spec"]["containers"][0][
"image"] == expected_visualization_server_image
assert results['children'][5]["spec"]["template"]["spec"]["containers"][0][
"image"] == expected_frontend_server_image
@pytest.mark.parametrize(
"sync_server_from_arguments, data, expected_status, expected_visualization_server_image, "
"expected_frontend_server_image",
[
(
ENV_IMAGES_WITH_TAGS_AND_ISTIO,
DATA_CORRECT_CHILDREN,
{"kubeflow-pipelines-ready": "True"},
generate_image_name(ENV_IMAGES_WITH_TAGS["VISUALIZATION_SERVER_IMAGE"],
ENV_IMAGES_WITH_TAGS["VISUALIZATION_SERVER_TAG"]),
generate_image_name(ENV_IMAGES_WITH_TAGS["FRONTEND_IMAGE"], ENV_IMAGES_WITH_TAGS["FRONTEND_TAG"]),
),
],
indirect=["sync_server_from_arguments"]
)
def test_sync_server_with_direct_passing_of_settings(
sync_server_from_arguments, data, expected_status, expected_visualization_server_image,
expected_frontend_server_image):
"""
Nearly end-to-end test of how Controller serves .sync as a POST, taking variables as arguments
Only does spot checks on children to see if key properties are correct
"""
server, environ = sync_server_from_arguments
# server.server_address = (url, port_as_integer)
url = f"http://{server.server_address[0]}:{str(server.server_address[1])}"
print("url: ", url)
print("data")
print(json.dumps(data, indent=2))
x = requests.post(url, data=json.dumps(data))
results = json.loads(x.text)
# Test overall status of whether children are ok
assert results['status'] == expected_status
# Poke a few children to test things that can vary by environment variable
assert results['children'][1]["spec"]["template"]["spec"]["containers"][0][
"image"] == expected_visualization_server_image
assert results['children'][5]["spec"]["template"]["spec"]["containers"][0][
"image"] == expected_frontend_server_image
@pytest.mark.parametrize(
"sync_server, data, expected_status, expected_children",
[
(ENV_IMAGES_WITH_TAGS, DATA_MISSING_PIPELINE_ENABLED, {}, []),
],
indirect=["sync_server"]
)
def test_sync_server_without_pipeline_enabled(sync_server, data, expected_status,
expected_children):
"""
Nearly end-to-end test of how Controller serves .sync as a POST
Tests case where metadata.labels.pipelines.kubeflow.org/enabled does not
exist and thus server returns an empty reply
"""
server, environ = sync_server
# server.server_address = (url, port_as_integer)
url = f"http://{server.server_address[0]}:{str(server.server_address[1])}"
x = requests.post(url, data=json.dumps(data))
results = json.loads(x.text)
# Test overall status of whether children are ok
assert results['status'] == expected_status
assert results['children'] == expected_children
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ml-pipeline-ui
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ml-pipeline-ui
subjects:
- kind: ServiceAccount
name: ml-pipeline-ui
@@ -0,0 +1,57 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ml-pipeline-ui
rules:
- apiGroups:
- ""
resources:
- pods
- pods/log
verbs:
- get
- apiGroups:
- ""
resources:
- events
verbs:
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- apiGroups:
- "kubeflow.org"
resources:
- viewers
verbs:
- create
- get
- list
- watch
- delete
- apiGroups:
- "argoproj.io"
resources:
- workflows
verbs:
- get
- list
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
- tasks
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
@@ -0,0 +1,13 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: ml-pipeline-ui-configmap
data:
# Temporary workarounds:
# 1. Using default-editor because default-viewer isn't bound to workload identity
viewer-pod-template.json: |-
{
"spec": {
"serviceAccountName": "default-editor"
}
}
@@ -0,0 +1,34 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-pipeline-ui
spec:
template:
spec:
volumes:
- name: config-volume
configMap:
name: ml-pipeline-ui-configmap
containers:
- name: ml-pipeline-ui
env:
- name: VIEWER_TENSORBOARD_POD_TEMPLATE_SPEC_PATH
value: /etc/config/viewer-pod-template.json
- name: DEPLOYMENT
value: KUBEFLOW
- name: ARTIFACTS_SERVICE_PROXY_NAME
value: ml-pipeline-ui-artifact
- name: ARTIFACTS_SERVICE_PROXY_PORT
value: '80'
- name: ARTIFACTS_SERVICE_PROXY_ENABLED
value: 'true'
- name: ENABLE_AUTHZ
value: 'true'
- name: KUBEFLOW_USERID_HEADER
value: kubeflow-userid
- name: KUBEFLOW_USERID_PREFIX
value: ""
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kubeflow
commonLabels:
app: ml-pipeline-ui
resources:
- cluster-role.yaml
- cluster-role-binding.yaml
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ml-pipeline-scheduledworkflow-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ml-pipeline-scheduledworkflow-role
subjects:
- kind: ServiceAccount
name: ml-pipeline-scheduledworkflow
@@ -0,0 +1,66 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ml-pipeline-scheduledworkflow-role
rules:
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- kubeflow.org
resources:
- scheduledworkflows
- scheduledworkflows/finalizers
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- ''
resources:
- events
verbs:
- create
- patch
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
- runs
- customruns
- tasks
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- custom.tekton.dev
resources:
- pipelineloops
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-pipeline-scheduledworkflow
spec:
template:
spec:
containers:
- name: ml-pipeline-scheduledworkflow
env:
- name: NAMESPACE
value: '' # Empty namespace let viewer controller watch all namespaces
valueFrom: null # HACK: https://github.com/kubernetes-sigs/kustomize/issues/2606
@@ -0,0 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kubeflow
resources:
- cluster-role.yaml
- cluster-role-binding.yaml
@@ -0,0 +1,132 @@
# NOTE: IMPORTANT
# We need to separate out actual rules from aggregation rules due to
# https://github.com/kubernetes/kubernetes/issues/65171
# TL;DR: We can't have both aggregation and rules in a [Cluster]Role. When that
# is the case, the rules get ignored.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-edit: "true"
name: kubeflow-pipelines-edit
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-pipelines-edit: "true"
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-pipelines-edit: "true"
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-view: "true"
name: kubeflow-pipelines-view
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-pipelines-view: "true"
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-pipelines-edit: "true"
name: aggregate-to-kubeflow-pipelines-edit
rules:
- apiGroups:
- pipelines.kubeflow.org
resources:
- pipelines
- pipelines/versions
verbs:
- create
- delete
- update
- apiGroups:
- pipelines.kubeflow.org
resources:
- experiments
verbs:
- archive
- create
- delete
- unarchive
- apiGroups:
- pipelines.kubeflow.org
resources:
- runs
verbs:
- archive
- create
- delete
- retry
- terminate
- unarchive
- apiGroups:
- pipelines.kubeflow.org
resources:
- jobs
verbs:
- create
- delete
- disable
- enable
- apiGroups:
- kubeflow.org
verbs:
- '*'
resources:
- scheduledworkflows
- apiGroups:
- argoproj.io
verbs:
- '*'
resources:
- cronworkflows
- cronworkflows/finalizers
- workflows
- workflows/finalizers
- workfloweventbindings
- workflowtemplates
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-pipelines-view: "true"
name: aggregate-to-kubeflow-pipelines-view
rules:
- apiGroups:
- pipelines.kubeflow.org
resources:
- pipelines
- pipelines/versions
- experiments
- runs
- jobs
verbs:
- get
- list
- apiGroups:
- kubeflow.org
resources:
- viewers
verbs:
- create
- get
- delete
- apiGroups:
- pipelines.kubeflow.org
resources:
- visualizations
verbs:
- create
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ml-pipeline-viewer-crd-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ml-pipeline-viewer-controller-role
subjects:
- kind: ServiceAccount
name: ml-pipeline-viewer-crd-service-account
@@ -0,0 +1,31 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ml-pipeline-viewer-controller-role
rules:
- apiGroups:
- '*'
resources:
- deployments
- services
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- kubeflow.org
resources:
- viewers
- viewers/finalizers
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-pipeline-viewer-crd
spec:
template:
spec:
containers:
- name: ml-pipeline-viewer-crd
env:
- name: NAMESPACE
value: '' # Empty namespace let viewer controller watch all namespaces
valueFrom: null
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cluster-role.yaml
- cluster-role-binding.yaml
@@ -0,0 +1,21 @@
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: ml-pipeline-ui
spec:
gateways:
- kubeflow-gateway
hosts:
- '*'
http:
- match:
- uri:
prefix: /pipeline
rewrite:
uri: /pipeline
route:
- destination:
host: ml-pipeline-ui.$(kfp-namespace).svc.cluster.local
port:
number: 80
timeout: 300s
@@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- metadata-grpc-configmap.yaml
- metadata-grpc-deployment.yaml
- metadata-grpc-service.yaml
- metadata-envoy-deployment.yaml
- metadata-envoy-service.yaml
- metadata-grpc-sa.yaml
images:
- name: gcr.io/ml-pipeline/metadata-envoy
newTag: 1.8.4
@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-envoy-deployment
labels:
component: metadata-envoy
spec:
replicas: 1
selector:
matchLabels:
component: metadata-envoy
template:
metadata:
labels:
component: metadata-envoy
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: container
image: gcr.io/ml-pipeline/metadata-envoy:dummy
ports:
- name: md-envoy
containerPort: 9090
- name: envoy-admin
containerPort: 9901
@@ -0,0 +1,14 @@
kind: Service
apiVersion: v1
metadata:
labels:
app: metadata-envoy
name: metadata-envoy-service
spec:
selector:
component: metadata-envoy
type: ClusterIP
ports:
- port: 9090
protocol: TCP
name: md-envoy
@@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: metadata-grpc-configmap
labels:
component: metadata-grpc-server
data:
METADATA_GRPC_SERVICE_HOST: "metadata-grpc-service"
METADATA_GRPC_SERVICE_PORT: "8080"
@@ -0,0 +1,76 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-grpc-deployment
labels:
component: metadata-grpc-server
spec:
replicas: 1
selector:
matchLabels:
component: metadata-grpc-server
template:
metadata:
labels:
component: metadata-grpc-server
spec:
containers:
- name: container
# ! Sync to the same MLMD version:
# * backend/metadata_writer/requirements.in and requirements.txt
# * @kubeflow/frontend/src/mlmd/generated
# * .cloudbuild.yaml and .release.cloudbuild.yaml
# * manifests/kustomize/base/metadata/base/metadata-grpc-deployment.yaml
# * test/tag_for_hosted.sh
image: gcr.io/tfx-oss-public/ml_metadata_store_server:1.5.0
env:
- name: DBCONFIG_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
- name: DBCONFIG_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: MYSQL_DATABASE
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: mlmdDb
- name: MYSQL_HOST
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbHost
- name: MYSQL_PORT
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbPort
command: ["/bin/metadata_store_server"]
args: ["--grpc_port=8080",
"--mysql_config_database=$(MYSQL_DATABASE)",
"--mysql_config_host=$(MYSQL_HOST)",
"--mysql_config_port=$(MYSQL_PORT)",
"--mysql_config_user=$(DBCONFIG_USER)",
"--mysql_config_password=$(DBCONFIG_PASSWORD)",
"--enable_database_upgrade=true"
]
ports:
- name: grpc-api
containerPort: 8080
livenessProbe:
tcpSocket:
port: grpc-api
initialDelaySeconds: 3
periodSeconds: 5
timeoutSeconds: 2
readinessProbe:
tcpSocket:
port: grpc-api
initialDelaySeconds: 3
periodSeconds: 5
timeoutSeconds: 2
serviceAccountName: metadata-grpc-server
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: metadata-grpc-server
@@ -0,0 +1,14 @@
kind: Service
apiVersion: v1
metadata:
labels:
app: metadata
name: metadata-grpc-service
spec:
selector:
component: metadata-grpc-server
type: ClusterIP
ports:
- port: 8080
protocol: TCP
name: grpc-api
@@ -0,0 +1,9 @@
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: metadata-grpc-service
spec:
host: metadata-grpc-service.kubeflow.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
@@ -0,0 +1,11 @@
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: metadata-grpc-service
spec:
action: ALLOW
selector:
matchLabels:
component: metadata-grpc-server
rules:
- {}
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- istio-authorization-policy.yaml
- destination-rule.yaml
- virtual-service.yaml
@@ -0,0 +1,21 @@
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: metadata-grpc
namespace: kubeflow
spec:
gateways:
- kubeflow-gateway
hosts:
- '*'
http:
- match:
- uri:
prefix: /ml_metadata
rewrite:
uri: /ml_metadata
route:
- destination:
host: metadata-envoy-service.kubeflow.svc.cluster.local
port:
number: 9090
@@ -0,0 +1,45 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kubeflow
resources:
- ../../base
- metadata-db-pvc.yaml
- metadata-db-deployment.yaml
- metadata-db-service.yaml
configMapGenerator:
- envs:
- params.env
name: metadata-db-parameters
secretGenerator:
- envs:
- secrets.env
name: metadata-db-secrets
generatorOptions:
disableNameSuffixHash: true
images:
- name: mysql
newName: mysql
newTag: 8.0.3
replacements:
- source:
name: metadata-db
kind: Service
version: v1
targets:
- select:
kind: Deployment
name: metadata-grpc-deployment
fieldPaths:
- spec.template.spec.containers.[name=container].args.2
options:
delimiter: =
index: 1
patches:
- path: patches/metadata-grpc-deployment.yaml
@@ -0,0 +1,51 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-db
labels:
component: db
spec:
selector:
matchLabels:
component: db
replicas: 1
strategy:
type: Recreate
template:
metadata:
name: db
labels:
component: db
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: db-container
image: mysql:8.0.3
args:
- --datadir
- /var/lib/mysql/datadir
envFrom:
- configMapRef:
name: metadata-db-parameters
- secretRef:
name: metadata-db-secrets
ports:
- name: dbapi
containerPort: 3306
readinessProbe:
exec:
command:
- "/bin/bash"
- "-c"
- "mysql -D $$MYSQL_DATABASE -p$$MYSQL_ROOT_PASSWORD -e 'SELECT 1'"
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
volumeMounts:
- name: metadata-mysql
mountPath: /var/lib/mysql
volumes:
- name: metadata-mysql
persistentVolumeClaim:
claimName: metadata-mysql
@@ -0,0 +1,10 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: metadata-mysql
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: metadata-db
labels:
component: db
spec:
type: ClusterIP
ports:
- port: 3306
protocol: TCP
name: dbapi
selector:
component: db
@@ -0,0 +1,3 @@
MYSQL_DATABASE=metadb
MYSQL_PORT=3306
MYSQL_ALLOW_EMPTY_PASSWORD=true
@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-grpc-deployment
spec:
template:
spec:
containers:
- name: container
# Remove existing environment variables
env:
- $patch: replace
envFrom:
- configMapRef:
name: metadata-db-parameters
- secretRef:
name: metadata-db-secrets
- configMapRef:
name: metadata-grpc-configmap
args: ["--grpc_port=$(METADATA_GRPC_SERVICE_PORT)",
"--mysql_config_host=$(MLMD_DB_HOST)",
"--mysql_config_database=$(MYSQL_DATABASE)",
"--mysql_config_port=$(MYSQL_PORT)",
"--mysql_config_user=$(MYSQL_USER_NAME)",
"--mysql_config_password=$(MYSQL_ROOT_PASSWORD)"]
@@ -0,0 +1,2 @@
MYSQL_USER_NAME=root
MYSQL_ROOT_PASSWORD=test
@@ -0,0 +1,132 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-pipeline
spec:
template:
spec:
containers:
- name: ml-pipeline-api-server
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: OBJECTSTORECONFIG_HOST
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: objectStoreHost
- name: OBJECTSTORECONFIG_PORT
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: objectStorePort
- name: OBJECTSTORECONFIG_SECURE
value: "false"
- name: CLIENTQPS
value: "50"
- name: CLIENTBURST
value: "50"
- name: OBJECTSTORECONFIG_BUCKETNAME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: bucketName
- name: DBCONFIG_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
- name: DBCONFIG_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: DBCONFIG_DBNAME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: pipelineDb
- name: DBCONFIG_HOST
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbHost
- name: DBCONFIG_PORT
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbPort
- name: OBJECTSTORECONFIG_ACCESSKEY
valueFrom:
secretKeyRef:
name: mlpipeline-minio-artifact
key: accesskey
- name: OBJECTSTORECONFIG_SECRETACCESSKEY
valueFrom:
secretKeyRef:
name: mlpipeline-minio-artifact
key: secretkey
- name: PIPELINE_RUNTIME
value: tekton
- name: ARTIFACT_BUCKET
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: artifact_bucket
- name: ARTIFACT_ENDPOINT
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: artifact_endpoint
- name: ARTIFACT_ENDPOINT_SCHEME
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: artifact_endpoint_scheme
- name: ARCHIVE_LOGS
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: archive_logs
- name: TRACK_ARTIFACTS
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: track_artifacts
- name: STRIP_EOF
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: strip_eof
- name: ARTIFACT_SCRIPT
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: artifact_script
- name: ARTIFACT_IMAGE
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: artifact_image
- name: MOVERESULTS_IMAGE
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: moveresults_image
- name: INJECT_DEFAULT_SCRIPT
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: inject_default_script
- name: APPLY_TEKTON_CUSTOM_RESOURCE
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: apply_tekton_custom_resource
- name: TERMINATE_STATUS
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: terminate_status
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- scheduled-workflow-crd.yaml
- viewer-crd.yaml
@@ -0,0 +1,39 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: scheduledworkflows.kubeflow.org
spec:
group: kubeflow.org
names:
kind: ScheduledWorkflow
listKind: ScheduledWorkflowList
plural: scheduledworkflows
singular: scheduledworkflow
shortNames:
- swf
scope: Namespaced
versions:
- name: v1beta1
schema:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
x-kubernetes-map-type: atomic
status:
type: object
x-kubernetes-preserve-unknown-fields: true
x-kubernetes-map-type: atomic
required:
- spec
- status
type: object
served: true
storage: true
@@ -0,0 +1,34 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: viewers.kubeflow.org
spec:
group: kubeflow.org
names:
kind: Viewer
listKind: ViewerList
plural: viewers
singular: viewer
shortNames:
- vi
scope: Namespaced
versions:
- name: v1beta1
schema:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
x-kubernetes-map-type: atomic
required:
- spec
type: object
served: true
storage: true
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubeflow-pipelines-container-builder
@@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: kfp-launcher
data:
defaultPipelineRoot: $(kfp-default-pipeline-root)
@@ -0,0 +1,35 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: kfp-tekton-config
data:
artifact_bucket: "mlpipeline"
artifact_endpoint: "minio-service.kubeflow:9000"
artifact_endpoint_scheme: "http://"
artifact_image: "minio/mc:RELEASE.2020-11-25T23-04-07Z"
archive_logs: "true"
moveresults_image: "busybox:1.34.1"
track_artifacts: "true"
strip_eof: "true"
inject_default_script: "true"
apply_tekton_custom_resource: "true"
terminate_status: "Cancelled"
artifact_script: |-
push_artifact() {
if [ -f "$2" ] || [ -d "$2" ]; then
tar -cvzf $1.tgz -C $(dirname $2) $(basename $2)
mc cp $1.tgz storage/$ARTIFACT_BUCKET/artifacts/$PIPELINERUN/$PIPELINETASK/$1.tgz
else
echo "$2 file does not exist. Skip artifact tracking for $1"
fi
}
push_log() {
cat /var/log/containers/$PODNAME*$NAMESPACE*step-main*.log > step-main.log
push_artifact main-log step-main.log
}
strip_eof() {
if [ -f "$2" ]; then
awk 'NF' $2 | head -c -1 > $1_temp_save && cp $1_temp_save $2
fi
}
mc config host add storage ${ARTIFACT_ENDPOINT_SCHEME}${ARTIFACT_ENDPOINT} $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY
@@ -0,0 +1,61 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- metadata-writer
- cluster-scoped
- ml-pipeline-apiserver-deployment.yaml
- ml-pipeline-apiserver-role.yaml
- ml-pipeline-apiserver-rolebinding.yaml
- ml-pipeline-apiserver-sa.yaml
- ml-pipeline-apiserver-service.yaml
- ml-pipeline-persistenceagent-deployment.yaml
- ml-pipeline-persistenceagent-role.yaml
- ml-pipeline-persistenceagent-rolebinding.yaml
- ml-pipeline-persistenceagent-sa.yaml
- ml-pipeline-scheduledworkflow-deployment.yaml
- ml-pipeline-scheduledworkflow-role.yaml
- ml-pipeline-scheduledworkflow-rolebinding.yaml
- ml-pipeline-scheduledworkflow-sa.yaml
- ml-pipeline-ui-deployment.yaml
- ml-pipeline-ui-configmap.yaml
- ml-pipeline-ui-role.yaml
- ml-pipeline-ui-rolebinding.yaml
- ml-pipeline-ui-sa.yaml
- ml-pipeline-ui-service.yaml
- ml-pipeline-viewer-crd-role.yaml
- ml-pipeline-viewer-crd-rolebinding.yaml
- ml-pipeline-viewer-crd-deployment.yaml
- ml-pipeline-viewer-crd-sa.yaml
- ml-pipeline-visualization-deployment.yaml
- ml-pipeline-visualization-sa.yaml
- ml-pipeline-visualization-service.yaml
- pipeline-runner-role.yaml
- pipeline-runner-rolebinding.yaml
- pipeline-runner-sa.yaml
- container-builder-sa.yaml
- viewer-sa.yaml
- kfp-pipeline-config.yaml
- kfp-launcher-configmap.yaml
patches:
- path: apiserver-deployment.yaml
- path: metadata-writer-deployment.yaml
images:
- name: gcr.io/ml-pipeline/api-server
newName: quay.io/aipipeline/api-server
newTag: 1.7.1
- name: gcr.io/ml-pipeline/persistenceagent
newName: quay.io/aipipeline/persistenceagent
newTag: 1.7.1
- name: gcr.io/ml-pipeline/scheduledworkflow
newName: quay.io/aipipeline/scheduledworkflow
newTag: 1.7.1
- name: gcr.io/ml-pipeline/frontend
newName: quay.io/aipipeline/frontend
newTag: 1.7.1
- name: gcr.io/ml-pipeline/viewer-crd-controller
newTag: 1.8.4
- name: gcr.io/ml-pipeline/visualization-server
newTag: 1.8.4
- name: gcr.io/ml-pipeline/metadata-writer
newName: quay.io/aipipeline/metadata-writer
newTag: 1.7.1
@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-writer
labels:
app: metadata-writer
spec:
replicas: 1
selector:
matchLabels:
app: metadata-writer
template:
metadata:
labels:
app: metadata-writer
spec:
containers:
- name: main
env:
- name: NAMESPACE_TO_WATCH
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: PIPELINE_RUNTIME
value: tekton
- name: ARCHIVE_LOGS
valueFrom:
configMapKeyRef:
name: kfp-tekton-config
key: archive_logs
serviceAccountName: kubeflow-pipelines-metadata-writer
@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- metadata-writer-deployment.yaml
- metadata-writer-role.yaml
- metadata-writer-rolebinding.yaml
- metadata-writer-sa.yaml
images:
- name: gcr.io/ml-pipeline/metadata-writer
newTag: 1.8.4
@@ -0,0 +1,27 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: metadata-writer
labels:
app: metadata-writer
spec:
replicas: 1
selector:
matchLabels:
app: metadata-writer
template:
metadata:
labels:
app: metadata-writer
spec:
containers:
- name: main
image: gcr.io/ml-pipeline/metadata-writer:dummy
env:
- name: NAMESPACE_TO_WATCH
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: PIPELINE_RUNTIME
value: tekton
serviceAccountName: kubeflow-pipelines-metadata-writer
@@ -0,0 +1,45 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app: kubeflow-pipelines-metadata-writer-role
name: kubeflow-pipelines-metadata-writer-role
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- get
- list
- watch
- update
- patch
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
verbs:
- get
- list
- watch
- update
- patch
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubeflow-pipelines-metadata-writer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubeflow-pipelines-metadata-writer-role
subjects:
- kind: ServiceAccount
name: kubeflow-pipelines-metadata-writer
@@ -0,0 +1,4 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubeflow-pipelines-metadata-writer
@@ -0,0 +1,114 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ml-pipeline
name: ml-pipeline
spec:
selector:
matchLabels:
app: ml-pipeline
template:
metadata:
labels:
app: ml-pipeline
annotations:
cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
spec:
containers:
- env:
- name: AUTO_UPDATE_PIPELINE_DEFAULT_VERSION
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: autoUpdatePipelineDefaultVersion
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: OBJECTSTORECONFIG_SECURE
value: "false"
- name: OBJECTSTORECONFIG_BUCKETNAME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: bucketName
- name: DBCONFIG_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
- name: DBCONFIG_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: DBCONFIG_DBNAME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: pipelineDb
- name: DBCONFIG_HOST
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbHost
- name: DBCONFIG_PORT
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: dbPort
- name: DBCONFIG_CONMAXLIFETIME
valueFrom:
configMapKeyRef:
name: pipeline-install-config
key: ConMaxLifeTime
- name: OBJECTSTORECONFIG_ACCESSKEY
valueFrom:
secretKeyRef:
name: mlpipeline-minio-artifact
key: accesskey
- name: OBJECTSTORECONFIG_SECRETACCESSKEY
valueFrom:
secretKeyRef:
name: mlpipeline-minio-artifact
key: secretkey
- name: PIPELINE_RUNTIME
value: tekton
image: gcr.io/ml-pipeline/api-server:dummy
imagePullPolicy: Always
name: ml-pipeline-api-server
ports:
- name: http
containerPort: 8888
- name: grpc
containerPort: 8887
readinessProbe:
exec:
command:
- wget
- -q # quiet
- -S # show server response
- -O
- "-" # Redirect output to stdout
- http://localhost:8888/apis/v1/healthz
initialDelaySeconds: 3
periodSeconds: 5
timeoutSeconds: 2
livenessProbe:
exec:
command:
- wget
- -q # quiet
- -S # show server response
- -O
- "-" # Redirect output to stdout
- http://localhost:8888/apis/v1/healthz
initialDelaySeconds: 3
periodSeconds: 5
timeoutSeconds: 2
resources:
requests:
cpu: 250m
memory: 500Mi
serviceAccountName: ml-pipeline
@@ -0,0 +1,80 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app: ml-pipeline
name: ml-pipeline
rules:
- apiGroups:
- ""
resources:
- pods
- pods/log
verbs:
- get
- list
- delete
- apiGroups:
- argoproj.io
resources:
- workflows
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- tekton.dev
resources:
- pipelineruns
- taskruns
- conditions
- runs
- customruns
- tasks
verbs:
- create
- get
- list
- watch
- update
- patch
- delete
- apiGroups:
- kubeflow.org
resources:
- scheduledworkflows
verbs:
- create
- get
- list
- update
- patch
- delete
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- custom.tekton.dev
resources:
- pipelineloops
verbs:
- create
- get
- list
- watch
- update
- patch
- delete

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