From a61dd2a06caddd4210664da94b9bb93bbc15b0fa Mon Sep 17 00:00:00 2001 From: Mathew Wicks Date: Thu, 20 Jul 2023 17:07:24 -0700 Subject: [PATCH] redirect ibm distribution docs to new website (#3546) Signed-off-by: Mathew Wicks --- content/en/_redirects | 3 +- content/en/docs/distributions/ibm/OWNERS | 5 +- content/en/docs/distributions/ibm/_index.md | 6 +- .../distributions/ibm/create-cluster-vpc.md | 289 ---------------- .../docs/distributions/ibm/create-cluster.md | 189 ---------- .../en/docs/distributions/ibm/deploy/OWNERS | 6 - .../docs/distributions/ibm/deploy/_index.md | 5 - .../ibm/deploy/authentication.md | 274 --------------- .../ibm/deploy/deployment-process.md | 38 -- .../ibm/deploy/iks-compatibility.md | 39 --- .../install-kubeflow-on-IBM-openshift.md | 99 ------ .../ibm/deploy/install-kubeflow-on-iks.md | 327 ------------------ .../ibm/deploy/uninstall-kubeflow.md | 43 --- content/en/docs/distributions/ibm/iks-e2e.md | 86 ----- .../en/docs/distributions/ibm/kfp-tekton.png | Bin 105695 -> 0 bytes .../en/docs/distributions/ibm/pipelines.md | 160 --------- .../en/docs/distributions/ibm/using-icr.md | 80 ----- 17 files changed, 8 insertions(+), 1641 deletions(-) delete mode 100644 content/en/docs/distributions/ibm/create-cluster-vpc.md delete mode 100644 content/en/docs/distributions/ibm/create-cluster.md delete mode 100644 content/en/docs/distributions/ibm/deploy/OWNERS delete mode 100644 content/en/docs/distributions/ibm/deploy/_index.md delete mode 100644 content/en/docs/distributions/ibm/deploy/authentication.md delete mode 100644 content/en/docs/distributions/ibm/deploy/deployment-process.md delete mode 100644 content/en/docs/distributions/ibm/deploy/iks-compatibility.md delete mode 100644 content/en/docs/distributions/ibm/deploy/install-kubeflow-on-IBM-openshift.md delete mode 100644 content/en/docs/distributions/ibm/deploy/install-kubeflow-on-iks.md delete mode 100644 content/en/docs/distributions/ibm/deploy/uninstall-kubeflow.md delete mode 100644 content/en/docs/distributions/ibm/iks-e2e.md delete mode 100644 content/en/docs/distributions/ibm/kfp-tekton.png delete mode 100644 content/en/docs/distributions/ibm/pipelines.md delete mode 100644 content/en/docs/distributions/ibm/using-icr.md diff --git a/content/en/_redirects b/content/en/_redirects index 35223bc4af..20a0512718 100644 --- a/content/en/_redirects +++ b/content/en/_redirects @@ -202,4 +202,5 @@ docs/started/requirements/ /docs/started/getting-started/ /docs/components/istio/* /docs/external-add-ons/istio/:splat /docs/components/feature-store/* /docs/external-add-ons/feature-store/:splat /docs/components/serving/* /docs/external-add-ons/serving/:splat -/docs/distributions/gke/* https://googlecloudplatform.github.io/kubeflow-gke-docs/docs/:splat \ No newline at end of file +/docs/distributions/gke/* https://googlecloudplatform.github.io/kubeflow-gke-docs/docs/:splat +/docs/distributions/ibm/* https://ibm.github.io/manifests/ \ No newline at end of file diff --git a/content/en/docs/distributions/ibm/OWNERS b/content/en/docs/distributions/ibm/OWNERS index 41cc4556df..787c80886c 100644 --- a/content/en/docs/distributions/ibm/OWNERS +++ b/content/en/docs/distributions/ibm/OWNERS @@ -1,6 +1,3 @@ approvers: - Tomcli - - yhwang -reviewers: - - Tomcli - - yhwang + - yhwang \ No newline at end of file diff --git a/content/en/docs/distributions/ibm/_index.md b/content/en/docs/distributions/ibm/_index.md index 1e4a0ae2d2..9ad051b888 100644 --- a/content/en/docs/distributions/ibm/_index.md +++ b/content/en/docs/distributions/ibm/_index.md @@ -1,5 +1,9 @@ +++ -title = "Kubeflow on IBM Cloud" +title = "Kubeflow on IKS" description = "Running Kubeflow on IBM Cloud Kubernetes Service (IKS)" weight = 20 +++ + +[Kubeflow on IKS](https://ibm.github.io/manifests/) is an open source distribution of the Kubeflow manifests. + +For more information, see the [Kubeflow on IKS documentation](https://ibm.github.io/manifests/docs/). diff --git a/content/en/docs/distributions/ibm/create-cluster-vpc.md b/content/en/docs/distributions/ibm/create-cluster-vpc.md deleted file mode 100644 index c79b8dbe9e..0000000000 --- a/content/en/docs/distributions/ibm/create-cluster-vpc.md +++ /dev/null @@ -1,289 +0,0 @@ -+++ -title = "Create or access an IBM Cloud Kubernetes cluster on a VPC" -description = "Instructions for creating or connecting to a Kubernetes cluster on IBM Cloud vpc-gen2" -weight = 4 -+++ - -## Create and setup a new cluster - -Follow these steps to create and setup a new IBM Cloud Kubernetes Service(IKS) cluster on `vpc-gen2` provider. - -A `vpc-gen2` cluster does not expose each node to the public internet directly and thus has more secure -and more complex network setup. It is recommended setup for secured production use cases of Kubeflow. - -### Setting environment variables - -Choose the region and the worker node provider for your cluster, and set the environment variables. - -```shell -export KUBERNERTES_VERSION=1.18 -export CLUSTER_ZONE=us-south-3 -export CLUSTER_NAME=kubeflow-vpc -``` - -where: - -- `KUBERNETES_VERSION`: Run `ibmcloud ks versions` to see the supported Kubernetes versions. Refer to - [Supported version matrix](https://www.kubeflow.org/docs/started/k8s/overview/#minimum-system-requirements). -- `CLUSTER_ZONE`: Run `ibmcloud ks locations` to list supported zones. For example, choose `us-south-3` to create your - cluster in the Dallas (US) data center. -- `CLUSTER_NAME` must be lowercase and unique among any other Kubernetes - clusters in the specified `${CLUSTER_ZONE}`. - -**Notice**: Refer to [Creating clusters](https://cloud.ibm.com/docs/containers?topic=containers-clusters) in the IBM -Cloud documentation for additional information on how to set up other providers and zones in your cluster. - -### Choosing a worker node flavor - -The worker nodes flavor name varies from zones and providers. Run -`ibmcloud ks flavors --zone ${CLUSTER_ZONE} --provider vpc-gen2` to list available flavors. - -Below are some examples of flavors supported in the `us-south-3` zone with `vpc-gen2` node provider: - -```shell -ibmcloud ks flavors --zone us-south-3 --provider vpc-gen2 -``` - -Example output: - -``` -For more information about these flavors, see 'https://ibm.biz/flavors' -Name Cores Memory Network Speed OS Server Type Storage Secondary Storage Provider -bx2.16x64 16 64GB 16Gbps UBUNTU_18_64 virtual 100GB 0B vpc-gen2 -bx2.2x8† 2 8GB 4Gbps UBUNTU_18_64 virtual 100GB 0B vpc-gen2 -bx2.32x128 32 128GB 16Gbps UBUNTU_18_64 virtual 100GB 0B vpc-gen2 -bx2.48x192 48 192GB 16Gbps UBUNTU_18_64 virtual 100GB 0B vpc-gen2 -bx2.4x16 4 16GB 8Gbps UBUNTU_18_64 virtual 100GB 0B vpc-gen2 -... -``` - -The recommended configuration for a cluster is at least 8 vCPU cores with 16GB memory. Hence, we recommend -`bx2.4x16` flavor to create a two-worker-node cluster. Keep in mind that you can always scale the cluster -by adding more worker nodes should your application scales up. - -Now set the environment variable with the flavor you choose. - -```shell -export WORKER_NODE_FLAVOR=bx2.4x16 -``` - -## Create an IBM Cloud Kubernetes cluster for `vpc-gen2` infrastructure - -Creating a `vpc-gen2` based cluster needs a VPC, a subnet and a public gateway attached to it. Fortunately, this is a one -time setup. Future `vpc-gen2` clusters can reuse the same VPC/subnet(with attached public-gateway). - -1. Begin with installing a `vpc-infrastructure` plugin: - - ```shell - ibmcloud plugin install vpc-infrastructure - ``` - - Refer to this [link](https://cloud.ibm.com/docs/containers?topic=containers-vpc_ks_tutorial), for more information. - -2. Target `vpc-gen 2` to access gen 2 VPC resources: - - ```shell - ibmcloud is target --gen 2 - ``` - - Verify that the target is correctly set up: - - ```shell - ibmcloud is target - ``` - - Example output: - - ``` - Target Generation: 2 - ``` - -3. Create or use an existing VPC: - - a) Use an existing VPC: - - ```shell - ibmcloud is vpcs - ``` - - - Example output: - ``` - Listing vpcs for generation 2 compute in all resource groups and region ... - ID Name Status Classic access Default network ACL Default security group Resource group - r006-hidden-68cc-4d40-xxxx-4319fa3gxxxx my-vpc1 available false husker-sloping-bee-resize blimp-hasty-unaware-overflow kubeflow - ``` - - If the above list contains the VPC that can be used to deploy your cluster - make a note of its ID. - - b) To create a new VPC, proceed as follows: - - ```shell - ibmcloud is vpc-create my-vpc - ``` - - Example output: - - ``` - Creating vpc my-vpc in resource group kubeflow under account IBM as ... - - ID r006-hidden-68cc-4d40-xxxx-4319fa3fxxxx - Name my-vpc - ... - ``` - - **Save the ID in a variable `VPC_ID` as follows, so that we can use it later.** - - ```shell - export VPC_ID=r006-hidden-68cc-4d40-xxxx-4319fa3fxxxx - ``` - -4. Create or use an existing subnet: - - a) To use an existing subnet: - - ```shell - ibmcloud is subnets - ``` - - Example output: - - ``` - Listing subnets for generation 2 compute in all resource groups and region ... - ID Name Status Subnet CIDR Addresses ACL Public Gateway VPC Zone Resource group - 0737-27299d09-1d95-4a9d-a491-a6949axxxxxx my-subnet available 10.240.128.0/18 16373/16384 husker-sloping-bee-resize my-gateway my-vpc us-south-3 kubeflow - ``` - - If the above list contains the subnet corresponding to your VPC, that can be used to deploy your cluster - make sure - you note it's ID. - - b) To create a new subnet: - - List address prefixes and note the CIDR block corresponding to a Zone; - in the below example, for Zone: `us-south-3` the CIDR block is : `10.240.128.0/18`. - - ```shell - ibmcloud is vpc-address-prefixes $VPC_ID - ``` - - Example output: - - ``` - Listing address prefixes of vpc r006-hidden-68cc-4d40-xxxx-4319fa3fxxxx under account IBM as user new@user-email.com... - ID Name CIDR block Zone Has subnets Is default Created - r006-xxxxxxxx-4002-46d2-8a4f-f69e7ba3xxxx rising-rectified-much-brew 10.240.0.0/18 us-south-1 false true 2021-03-05T14:58:39+05:30 - r006-xxxxxxxx-dca9-4321-bb6c-960c4424xxxx retrial-reversal-pelican-cavalier 10.240.64.0/18 us-south-2 false true 2021-03-05T14:58:39+05:30 - r006-xxxxxxxx-7352-4a46-bfb1-fcbac6cbxxxx subfloor-certainly-herbal-ajar 10.240.128.0/18 us-south-3 false true 2021-03-05T14:58:39+05:30 - ``` - - - Now create a subnet as follows: - - ```shell - ibmcloud is subnet-create my-subnet $VPC_ID $CLUSTER_ZONE --ipv4-cidr-block "10.240.128.0/18" - ``` - - Example output: - - ``` - Creating subnet my-subnet in resource group kubeflow under account IBM as user new@user-email.com... - - ID 0737-27299d09-1d95-4a9d-a491-a6949axxxxxx - Name my-subnet - ``` - - - Make sure you export the subnet IDs follows: - - ```shell - export SUBNET_ID=0737-27299d09-1d95-4a9d-a491-a6949axxxxxx - ``` - -5. Create a `vpc-gen2` based Kubernetes cluster: - - ```shell - ibmcloud ks cluster create vpc-gen2 \ - --name $CLUSTER_NAME \ - --zone $CLUSTER_ZONE \ - --version ${KUBERNETES_VERSION} \ - --flavor ${WORKER_NODE_FLAVOR} \ - --vpc-id ${VPC_ID} \ - --subnet-id ${SUBNET_ID} \ - --workers 2 - ``` - -6. Attach a public gateway - - This step is mandatory for Kubeflow deployment to succeed, because pods need public internet access to download images. - - - First, check if your cluster is already assigned a public gateway: - - ```shell - ibmcloud is pubgws - ``` - - Example output: - - ``` - Listing public gateways for generation 2 compute in all resource groups and region ... - ID Name Status Floating IP VPC Zone Resource group - r006-xxxxxxxx-5731-4ffe-bc51-1d9e5fxxxxxx my-gateway available xxx.xxx.xxx.xxx my-vpc us-south-3 default - - ``` - - In the above run, the gateway is already attached for the vpc: `my-vpc`. In case no gateway is attached, proceed with - the rest of the setup. - - - Next, attach a public gateway by running the following command: - - ```shell - ibmcloud is public-gateway-create my-gateway $VPC_ID $CLUSTER_ZONE - ``` - - Example output: - ``` - ID: r006-xxxxxxxx-5731-4ffe-bc51-1d9e5fxxxxxx - ``` - - Save the above generated gateway ID as follows: - - ```shell - export GATEWAY_ID="r006-xxxxxxxx-5731-4ffe-bc51-1d9e5fxxxxxx" - ``` - - - Finally, attach the public gateway to the subnet: - - ```shell - ibmcloud is subnet-update $SUBNET_ID --public-gateway-id $GATEWAY_ID - ``` - - Example output: - - ``` - Updating subnet 0737-27299d09-1d95-4a9d-a491-a6949axxxxxx under account IBM as user new@user-email.com... - - ID 0737-27299d09-1d95-4a9d-a491-a6949axxxxxx - Name my-subnet - ... - ``` - -### Verifying the cluster - -To use the created cluster, switch the Kubernetes context to point to the cluster: - -```shell -ibmcloud ks cluster config --cluster ${CLUSTER_NAME} -``` - -Make sure all worker nodes are up with the command below: - -```shell -kubectl get nodes -``` - -and verify that all the nodes are in `Ready` state. - -### Delete the cluster - -Delete the cluster including it's storage: - -```shell -ibmcloud ks cluster rm --force-delete-storage -c ${CLUSTER_NAME} -``` diff --git a/content/en/docs/distributions/ibm/create-cluster.md b/content/en/docs/distributions/ibm/create-cluster.md deleted file mode 100644 index 046eb3e785..0000000000 --- a/content/en/docs/distributions/ibm/create-cluster.md +++ /dev/null @@ -1,189 +0,0 @@ -+++ -title = "Create or access an IBM Cloud Kubernetes cluster" -description = "Instructions for creating or connecting to a Kubernetes cluster on IBM Cloud" -weight = 3 -+++ - -This guide describes how to create a Kubernetes cluster with IBM Cloud Kubernetes Service. - -[IBM Cloud Kubernetes Service](https://www.ibm.com/cloud/kubernetes-service) provides powerful tools and services to help deploy highly available containerized apps in Kubernetes clusters and to automate, isolate, secure, manage, and monitor your workloads across zones or regions. - -## Prerequisites - -1. `IBMid` - - To get started, first go to [IBM Cloud](https://ibm.biz/Bdqgck) to create your `IBMid` if you do not have one. - -2. Installing the IBM Cloud CLI - - Follow the instructions in this [Getting started with the IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cli-getting-started#overview) guide to install the IBM Cloud CLI. - -3. Installing the IBM Cloud Kubernetes Service plug-in with the command - - ```shell - ibmcloud plugin install container-service - ``` - - Refer to this [link](https://cloud.ibm.com/docs/cli?topic=containers-kubernetes-service-cli) for more info on IBM Cloud Kubernetes Service CLI. - -4. Authenticating with IBM Cloud - - ```shell - ibmcloud login - ``` - - Use your registered email and password for your `IBMid` to log in to IBM Cloud. - -## Connecting to an existing cluster - -If you have an existing cluster, use it to install Kubeflow as far as it meets the minimum system requirement. - -Get the Kubeconfig file: - -```shell -ibmcloud ks cluster config --cluster $CLUSTER_NAME -``` - -From here on, go to [Install Kubeflow on IKS](/docs/ibm/deploy/install-kubeflow-on-iks) for more information. - - -## Create and setup a new cluster - -* Use a `classic` provider if you want to try out Kubeflow. -* Use a `vpc-gen2` provider if you are familiar with Cloud networking and want to deploy Kubeflow on a secure environment. - -A `classic` provider exposes each cluster node to the public internet and therefore has -a relatively simpler networking setup. Services exposed using Kubernetes `NodePort` need to be secured using -authentication mechanism. - -To create a cluster with `vpc-gen2` provider, follow the -[Create a cluster on IKS with a `vpc-gen2` provider](/docs/ibm/create-cluster-vpc) -guide. - -The next section will explain how to create and set up a new IBM Cloud Kubernetes Service (IKS) - -### Setting environment variables - -Choose the region and the worker node provider for your cluster, and set the environment variables. - -```shell -export KUBERNETES_VERSION=1.21 -export CLUSTER_ZONE=dal13 -export WORKER_NODE_PROVIDER=classic -export CLUSTER_NAME=kubeflow -``` - -where: - -- `KUBERNETES_VERSION` specifies the Kubernetes version for the cluster. Run `ibmcloud ks versions` to see the supported - Kubernetes versions. If this environment variable is not set, the cluster will be created with the default version set - by IBM Cloud Kubernetes Service. Refer to - [Minimum system requirements](https://www.kubeflow.org/docs/started/k8s/overview/#minimum-system-requirements) - and choose a Kubernetes version compatible with the Kubeflow release to be deployed. -- `CLUSTER_ZONE` identifies the regions or location where cluster will be created. Run `ibmcloud ks locations` to - list supported IBM Cloud Kubernetes Service locations. For example, choose `dal13` to create your cluster in the - Dallas (US) data center. -- `WORKER_NODE_PROVIDER` specifies the kind of IBM Cloud infrastructure on which the Kubernetes worker nodes will be - created. The `classic` type supports worker nodes with GPUs. There are other worker nodes providers including - `vpc-classic` and `vpc-gen2` where zone names and worker flavors will be different. Run - `ibmcloud ks zones --provider classic` to list zone names for `classic` provider and set the `CLUSTER_ZONE` - accordingly. -- `CLUSTER_NAME` must be lowercase and unique among any other Kubernetes - clusters in the specified `${CLUSTER_ZONE}`. - -**Notice**: Refer to [Creating clusters](https://cloud.ibm.com/docs/containers?topic=containers-clusters) in the IBM -Cloud documentation for additional information on how to set up other providers and zones in your cluster. - -### Choosing a worker node flavor - -The worker node flavor name varies from zones and providers. Run -`ibmcloud ks flavors --zone ${CLUSTER_ZONE} --provider ${WORKER_NODE_PROVIDER}` to list available flavors. - -For example, the following are some worker node flavors supported in the `dal13` zone with a `classic` node provider. - -```shell -ibmcloud ks flavors --zone dal13 --provider classic -``` - -Example output: - -``` -OK -For more information about these flavors, see 'https://ibm.biz/flavors' -Name Cores Memory Network Speed OS Server Type Storage Secondary Storage Provider -b2c.16x64 16 64GB 1000Mbps UBUNTU_16_64 virtual 25GB 100GB classic -b2c.32x128 32 128GB 1000Mbps UBUNTU_16_64 virtual 25GB 100GB classic -b2c.4x16 4 16GB 1000Mbps UBUNTU_16_64 virtual 25GB 100GB classic -b2c.56x242 56 242GB 1000Mbps UBUNTU_16_64 virtual 25GB 100GB classic -b2c.8x32 8 32GB 1000Mbps UBUNTU_16_64 virtual 25GB 100GB classic -b3c.16x64 16 64GB 1000Mbps UBUNTU_18_64 virtual 25GB 100GB classic -b3c.32x128 32 128GB 1000Mbps UBUNTU_18_64 virtual 25GB 100GB classic -b3c.4x16 4 16GB 1000Mbps UBUNTU_18_64 virtual 25GB 100GB classic -b3c.56x242 56 242GB 1000Mbps UBUNTU_18_64 virtual 25GB 100GB classic -b3c.8x32 8 32GB 1000Mbps UBUNTU_18_64 virtual 25GB 100GB classic -... -``` - -Choose a flavor that will work for your applications. For the purpose of the Kubeflow deployment, the recommended -configuration for a cluster is at least 8 vCPU cores with 16GB memory. Hence you can either choose the `b3c.8x32` flavor -to create a one-worker-node cluster or choose the `b3c.4x16` flavor to create a two-worker-node cluster. Keep in mind -that you can always scale the cluster by adding more worker nodes should your application scales up. - -Now, set the environment variable with the worker node flavor of your choice: - -```shell -export WORKER_NODE_FLAVOR=b3c.4x16 -``` - -### Creating an IBM Cloud Kubernetes cluster - -Run with the following command to create a cluster: - -Replace the `workers` parameter above with the desired number of worker nodes. - -If you're starting in a fresh account with no public and private VLANs, they are created automatically for you -when creating a Kubernetes cluster with worker nodes provider `classic` for the first time. If you already have VLANs -configured in your account, retrieve them via `ibmcloud ks vlans --zone ${CLUSTER_ZONE}` and include the public and -private VLAN ids (set in the `PUBLIC_VLAN_ID` and `PRIVATE_VLAN_ID` environment variables) in the command. - -```shell -ibmcloud ks cluster create ${WORKER_NODE_PROVIDER} \ - --name=$CLUSTER_NAME \ - --zone=$CLUSTER_ZONE \ - --version=${KUBERNETES_VERSION} \ - --flavor ${WORKER_NODE_FLAVOR} \ - --workers=2 \ - --private-vlan ${PRIVATE_VLAN_ID} \ - --public-vlan ${PUBLIC_VLAN_ID} -``` - -Wait until the cluster is deployed and configured. It can take a while for the cluster to be ready. Run with following -command to periodically check the state of your cluster. Your cluster is ready when the state is `normal`. - -```shell -ibmcloud ks clusters --provider ${WORKER_NODE_PROVIDER} |grep ${CLUSTER_NAME} |awk '{print "Name:"$1"\tState:"$3}' -``` - -### Verifying the cluster - -To use the created cluster, switch the Kubernetes context to point to the cluster with the command - -```shell -ibmcloud ks cluster config --cluster ${CLUSTER_NAME} -``` - -Make sure all worker nodes are up with the command below - -```shell -kubectl get nodes -``` - -and make sure all the nodes are in `Ready` state. - -### Delete the cluster - -Delete the cluster including it's storage: - -```shell -ibmcloud ks cluster rm --force-delete-storage -c ${CLUSTER_NAME} -``` diff --git a/content/en/docs/distributions/ibm/deploy/OWNERS b/content/en/docs/distributions/ibm/deploy/OWNERS deleted file mode 100644 index 41cc4556df..0000000000 --- a/content/en/docs/distributions/ibm/deploy/OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -approvers: - - Tomcli - - yhwang -reviewers: - - Tomcli - - yhwang diff --git a/content/en/docs/distributions/ibm/deploy/_index.md b/content/en/docs/distributions/ibm/deploy/_index.md deleted file mode 100644 index 57473894a8..0000000000 --- a/content/en/docs/distributions/ibm/deploy/_index.md +++ /dev/null @@ -1,5 +0,0 @@ -+++ -title = "Kubeflow Deployment on IBM Cloud" -description = "Instructions for Kubeflow deployment on IBM Cloud" -weight = 4 -+++ diff --git a/content/en/docs/distributions/ibm/deploy/authentication.md b/content/en/docs/distributions/ibm/deploy/authentication.md deleted file mode 100644 index 2700efa5dc..0000000000 --- a/content/en/docs/distributions/ibm/deploy/authentication.md +++ /dev/null @@ -1,274 +0,0 @@ -+++ -title = "Securing the Kubeflow authentication with HTTPS" -description = "How to secure the Kubeflow authentication with HTTPS using the network load balancer" -weight = 10 -+++ - -This guide describes how to secure the Kubeflow authentication with HTTPS. -You can enable HTTPS for Kubeflow dashboard (and other web UIs) using the -network load balancer (NLB) feature of the IBM Cloud Kubernetes service—choose -the `classic` worker nodes provider in the -[Setting environment variables](../../create-cluster#setting-environment-variables) -section of the Create an IBM Cloud cluster guide. - -**Note**: For details on NLB, go to the official -[Classic: About network load balancers](https://cloud.ibm.com/docs/containers?topic=containers-loadbalancer-about) -guide. - -## Prerequisites - -* Install and configure the -[IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cli-getting-started). -* Install -[multi-user, auth-enabled Kubeflow](../install-kubeflow-on-iks/#multi-user-auth-enabled). - -## Setting up an NLB - -To set up an NLB for your Kubernetes cluster, follow the official -[Classic: Setting up basic load balancing with an NLB 1.0](https://cloud.ibm.com/docs/containers?topic=containers-loadbalancer) -guide. Notice that the setup process for a multi-zone cluster differs from that -of a single-zone cluster. For details, go to -[Setting up an NLB 1.0 in a multi-zone cluster](https://cloud.ibm.com/docs/containers?topic=containers-loadbalancer#multi_zone_config). - -1. To use the existing Istio ingress gateway (instead of creating a new -service), you need to update the service type of `istio-ingressgateway` to -`LoadBalancer` from `NodePort`. Run the following command: - - ```shell - kubectl patch svc istio-ingressgateway -n istio-system -p '{"spec":{"type":"LoadBalancer"}}' - ``` - -2. Verify that the NLB was created successfully. It might take a few minutes for -the service to be created and an IP address to be made available. Run the -command below and check if you can see the `LoadBalancer Ingress` IP address: - - ```shell - kubectl describe service istio-ingressgateway -n istio-system | grep "LoadBalancer Ingress" - ``` - -3. Store the external IP of the `istio-ingressgateway` service in an environment -variable: - - ```shell - export INGRESS_GATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') - ``` - -## Exposing the Kubeflow dashboard with DNS and TLS termination - -The following instructions use the Kubeflow dashboard as an example. However, -they apply to other web UI applications, since they all go through the Istio -ingress gateway. - -1. Store the Kubernetes cluster name in an environment variable by running the -following command: - - ```shell - export CLUSTER_NAME= - ``` - -2. Create a DNS domain and certificates for the IP of the service -`istio-ingressgateway` in namespace `istio-system`: - - ```shell - ibmcloud ks nlb-dns create classic --cluster $CLUSTER_NAME --ip $INGRESS_GATEWAY_IP --secret-namespace istio-system - ``` - -3. List the registered domain names: - - ```shell - ibmcloud ks nlb-dns ls --cluster $CLUSTER_NAME - ``` - -4. Wait until the status of the certificate—the fourth field—of the new domain -name becomes `created`. Then, save the value of the column `SSL Cert Secret -Name` in environment variables by running these commands (replace -`{SECRET_NAME}` with the secret's name as shown in the `SSL Cert Secret Name` -column): - - ```shell - export INGRESS_GATEWAY_SECRET={SECRET_NAME} - ``` - - **Note**: If there is more than one entry in the output, choose the one - that matches the IP address from `LoadBalancer Ingress` (step 2) of service - `istio-ingressgateway`. - -5. Create a secret named `istio-ingressgateway-certs` for the -`istio-ingressgateway` pods in namespace `istio-system`: - - ```shell - kubectl get secret $INGRESS_GATEWAY_SECRET -n istio-system -o yaml > istio-ingressgateway-certs.yaml - ``` - -6. Update the `istio-ingressgateway-certs.yaml` file by changing the value of -`metadata.name` to `istio-ingressgateway-certs` and the value of -`metadata.namespace` to `istio-system`. Then, run the following commands: - - ```shell - kubectl apply -f istio-ingressgateway-certs.yaml -n istio-system - kubectl rollout restart deploy istio-ingressgateway -n istio-system - rm istio-ingressgateway-certs.yaml - ``` - -7. Update the gateway `kubeflow-gateway` to expose port `443`. Create a resource -file `kubeflow-gateway.yaml` as follows by replacing `` with the value -of the column `Hostname` in step 4: - - ```YAML - apiVersion: networking.istio.io/v1alpha3 - kind: Gateway - metadata: - name: kubeflow-gateway - namespace: kubeflow - spec: - selector: - istio: ingressgateway - servers: - - hosts: - - '' - port: - name: https - number: 443 - protocol: HTTPS - tls: - mode: SIMPLE - privateKey: /etc/istio/ingressgateway-certs/tls.key - serverCertificate: /etc/istio/ingressgateway-certs/tls.crt - ``` - -8. Verify that the traffic is routed via HTTPS by using the value of -above-mentioned `Hostname` in your browser. It should redirect traffic from an -HTTP address to HTTPS address automatically. - -**Note**: The certificates for the NLB DNS host secret expire every **90** days. -The secret in the `default` namespace is automatically renewed by IBM Cloud -Kubernetes Service 37 days before it expires. After this secret is updated, you -must manually copy it to the `istio-ingressgateway-certs` secret by repeating -commands in step 5 and 6. - -## Optional - KServe configuration - -With this HTTPS setup, you need to make additional changes to get KServe to work. - -1. First, update the Knative domain that is used for the KServe routes to the -hostname that you used when updating `kubeflow-gateway`. - - ```shell - kubectl edit configmap config-domain -n knative-serving - ``` - - This will open your default text editor, and you will see something like: - - ```YAML - apiVersion: v1 - data: - _example: | - ################################ - # # - # EXAMPLE CONFIGURATION # - # # - ################################ - # ... - example.com: | - kind: ConfigMap - ... - ``` - - Add a line above the `_example` key with your hostname as the key and an empty string value. - Be sure to update ``: - - ```YAML - apiVersion: v1 - data: - : "" - _example: | - ... - kind: ConfigMap - ... - ``` - - Then, save and exit. The routes for your InferenceServices will start using this new domain. - -2. Since the certificates provided by IBM Cloud only allow for a single level of domain name added -to the base domain, the domain template for Knative needs to be adjusted so that the certificates -will be valid for the InferenceService routes. - - ```shell - kubectl edit configmap config-network -n knative-serving - ``` - - This will open your default text editor, and you will again see something like: - - ```YAML - apiVersion: v1 - data: - _example: | - ################################ - # # - # EXAMPLE CONFIGURATION # - # # - ################################ - # ... - kind: ConfigMap - ... - ``` - - Add a line above the `_example` key with the `domainTemplate` key like the following: - - ```YAML - apiVersion: v1 - data: - domainTemplate: "{{.Name}}-{{.Namespace}}.{{.Domain}}" - _example: | - ... - kind: ConfigMap - ... - ``` - - Save and exit. The default template uses a two-level subdomain (i.e. `{{.Name}}.{{.Namespace}}.{{.Domain}}`), - so this just adjusts it to use one. - - -3. Adjust `kubeflow-gateway` one more time, adding a wildcard host in the HTTPS `hosts` section. - - ```shell - kubectl edit gateway kubeflow-gateway -n kubeflow - ``` - - This will open your default text editor, but you can also optionally edit `kubeflow-gateway.yaml` file - you created previously. Here, just add another entry to the HTTPS `hosts` list containing your hostname prepended - with a `*.` so that the Knative subdomains are properly routed. - - ```YAML - apiVersion: networking.istio.io/v1alpha3 - kind: Gateway - metadata: - name: kubeflow-gateway - namespace: kubeflow - spec: - selector: - istio: ingressgateway - servers: - - hosts: - - '' - - '*.' - port: - name: https - number: 443 - protocol: HTTPS - tls: - mode: SIMPLE - privateKey: /etc/istio/ingressgateway-certs/tls.key - serverCertificate: /etc/istio/ingressgateway-certs/tls.crt - ``` - - Save and exit. - -After these adjustments, InferenceServices should now be reachable via HTTPS. To test out an external -prediction, you can use the `authservice_session` cookie for the Kubeflow dashboard site from the browser. Once -the content of the cookie is retrieved from the browser, it can be added as a header in your request -(e.g. `"Cookie: authservice_session=MTYwNz..."`). For example: - -```shell -curl -v https://sklearn-iris-kserve-test.kf-dev-442dbba0442be6c8c50f31ed96b00532-0001.sjc03.containers.appdomain.cloud/v1/models/sklearn-iris:predict -d '{"instances": [[6.8, 2.8, 4.8, 1.4],[6.0, 3.4, 4.5, 1.6]]}' -H "Cookie: authservice_session=MTYwODMyODk5M3xOd3dBTkVzeU5VSlJRazlQVnpWT1dGUldWa0ZXVDBRMVFsY3pVVFZHVVVGV01rWkRORmd6VmxCVVNsQkVSa2xaUlZVMFRUVldVMEU9fJBHfRCAvs6nSh_J04VlBEq_yqhkUvc5Z1Mqahe9klOd" -``` diff --git a/content/en/docs/distributions/ibm/deploy/deployment-process.md b/content/en/docs/distributions/ibm/deploy/deployment-process.md deleted file mode 100644 index b8702b06e0..0000000000 --- a/content/en/docs/distributions/ibm/deploy/deployment-process.md +++ /dev/null @@ -1,38 +0,0 @@ -+++ -title = "Kubeflow Deployment Process" -description = "How kubeflow installation works" -weight = 5 -+++ - -## Understanding the Kubeflow deployment process - -The deployment process is controlled by the following commands: - -* **kustomize build** - Use kustomize to generate configuration files defining - the various resources for your deployment. . -* **kubectl apply** - Apply the resources created by `kustomize build` to the - kubenetes cluster - -### Repository layout - -IBM manifests repository contains the following files and directories: - -* **iks-single** directory: A kustomize file for single-user deployment -* **iks-multi** directory: A kustomize file for multi-user deployment - -* **others** Other files are used to compose Kubeflow resources - -## Kubeflow installation - -Starting from Kubeflow 1.3, the official installation documentation uses a combination of `kustomize` and `kubectl` to install Kubeflow. - -### Install kubectl and kustomize - -* [Install kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) -* [Download kustomize 5.0.0](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.0.0) - - ## Next Steps - - 1. Check [Kubeflow Compatibility](/docs/distributions/ibm/deploy/iks-compatibility) - 2. Go here for installing [Kubeflow on IKS](/docs/distributions/ibm/deploy/install-kubeflow-on-iks) - 3. Go here for installing [Kubeflow on IBM OpenShift](/docs/distributions/ibm/deploy/install-kubeflow-on-ibm-openshift) diff --git a/content/en/docs/distributions/ibm/deploy/iks-compatibility.md b/content/en/docs/distributions/ibm/deploy/iks-compatibility.md deleted file mode 100644 index 3140aae514..0000000000 --- a/content/en/docs/distributions/ibm/deploy/iks-compatibility.md +++ /dev/null @@ -1,39 +0,0 @@ -+++ -title = "IBM Cloud Kubernetes and Kubeflow Compatibility" -description = "Compatibility matrix for Kubeflow on IBM Cloud by Kubernetes version" -weight = 6 -+++ - -## Compatibility - -The following table relates compatibility between Kubernetes versions 1.22+ of IBM Cloud Kubernetes service and Kubeflow version 1.7. - -
- - - - - - - - - - - - - - - - - -
IBM Cloud Kubernetes VersionsKubeflow 1.7.0
1.24Compatible
1.25Compatible
-
- -- **Incompatible**: the combination is not known to work together -- **Compatible**: all Kubeflow features have been tested and verified for the IKS Kubernetes version -- **No known issues**: the combination has not been fully tested but there are no reported issues - - -## Next Steps - -1. 2. Go here for installing [Kubeflow on IKS](/docs/distributions/ibm/deploy/install-kubeflow-on-iks) \ No newline at end of file diff --git a/content/en/docs/distributions/ibm/deploy/install-kubeflow-on-IBM-openshift.md b/content/en/docs/distributions/ibm/deploy/install-kubeflow-on-IBM-openshift.md deleted file mode 100644 index 4beda402be..0000000000 --- a/content/en/docs/distributions/ibm/deploy/install-kubeflow-on-IBM-openshift.md +++ /dev/null @@ -1,99 +0,0 @@ -+++ -title = "Install Kubeflow on OpenShift" -description = "Instructions for deploying Kubeflow on IBM Cloud OpenShift" -weight = 7 -+++ - -**This guide has not yet been updated for Kubeflow 1.3** - -This guide describes how to use the kfctl binary to deploy Kubeflow on IBM Cloud Kubernetes Service (IKS). - -## Prerequisites - -* Authenticate with IBM Cloud - - Log into IBM Cloud at [IBM Cloud](https://cloud.ibm.com) - -* Install OpenShift CLI - - OpenShift CLI is the way to manage and access OpenShift cluster. You can [Install OpenShift CLI](https://cloud.ibm.com/docs/openshift?topic=openshift-openshift-cli) from this instructions. - -* Create and access a OpenShift cluster on IKS - - To deploy Kubeflow on IBM Cloud, you need a cluster running OpenShift on IKS. If you don't have a cluster running, follow the [Create an IBM Cloud OpenShift cluster](https://cloud.ibm.com/docs/openshift?topic=openshift-clusters) guide. - - To access the cluster follow these directions [Access OpenShift Cluster](https://cloud.ibm.com/docs/openshift?topic=openshift-access_cluster). We can easily get access from the openshift console on IBM Cloud[Connecting to the cluster from the console](https://cloud.ibm.com/docs/openshift?topic=openshift-access_cluster#access_oc_console). - - -## Installation - -If you're experiencing issues during the installation because of conflicts on your Kubeflow deployment, you can [uninstall Kubeflow](/docs/ibm/deploy/uninstall-kubeflow) and install it again. - -### Single user - -Run the following commands to set up and deploy Kubeflow for a single user without any authentication. - -**Note**: By default, Kubeflow deployment on IBM Cloud uses the [Kubeflow pipeline with the Tekton backend](https://github.com/kubeflow/kfp-tekton#kubeflow-pipelines-with-tekton). -If you want to use the Kubeflow pipeline with the Argo backend, you can change `CONFIG_URI` to this kfdef instead - -``` -https://raw.githubusercontent.com/kubeflow/manifests/v1.2-branch/kfdef/kfctl_openshift.v1.2.0.yaml -``` - -```shell -# Set KF_NAME to the name of your Kubeflow deployment. This also becomes the -# name of the directory containing your configuration. -# For example, your deployment name can be 'my-kubeflow' or 'kf-test'. -export KF_NAME= - -# Set the path to the base directory where you want to store one or more -# Kubeflow deployments. For example, /opt/. -# Then set the Kubeflow application directory for this deployment. -export BASE_DIR= -export KF_DIR=${BASE_DIR}/${KF_NAME} - -# Set the configuration file to use, such as: -export CONFIG_FILE=kfctl_ibm.yaml -export CONFIG_URI="https://raw.githubusercontent.com/kubeflow/manifests/master/distributions/kfdef/kfctl_openshift.master.kfptekton.yaml" - -# Generate Kubeflow: -mkdir -p ${KF_DIR} -cd ${KF_DIR} - -wget ${CONFIG_URI} -O ${CONFIG_FILE} - -# On MacOS -sed -i '' -e 's#https://github.com/kubeflow/manifests/archive/master.tar.gz#https://github.com/kubeflow/manifests/archive/552a4ba84567ed8c0f9abca12f15b8eed000426c.tar.gz#g' ${CONFIG_FILE} - -# On Linux -sed -i -e 's#https://github.com/kubeflow/manifests/archive/master.tar.gz#https://github.com/kubeflow/manifests/archive/552a4ba84567ed8c0f9abca12f15b8eed000426c.tar.gz#g' ${CONFIG_FILE} - -# Deploy Kubeflow. You can customize the CONFIG_FILE if needed. -kfctl apply -V -f ${CONFIG_FILE} -``` - -* **${KF_NAME}** - The name of your Kubeflow deployment. - If you want a custom deployment name, specify that name here. - For example, `my-kubeflow` or `kf-test`. - The value of KF_NAME must consist of lower case alphanumeric characters or - '-', and must start and end with an alphanumeric character. - The value of this variable cannot be greater than 25 characters. It must - contain just a name, not a directory path. - This value also becomes the name of the directory where your Kubeflow - configurations are stored, that is, the Kubeflow application directory. - -* **${KF_DIR}** - The full path to your Kubeflow application directory. - -The Kubeflow deployment is exposed with a Route. To find the Route you can use - -``` -oc get route -n istio-system istio-ingressgateway -o=jsonpath='{.spec.host}' -``` - -## Next steps - -To secure the Kubeflow dashboard with HTTPS, follow the steps in [Exposing the Kubeflow dashboard with DNS and TLS termination](/docs/ibm/deploy/authentication/#setting-up-an-nlb). - -## Additional information - -You can find general information about Kubeflow configuration in the guide to [configuring Kubeflow with kfctl and kustomize](/docs/other-guides/kustomize/). diff --git a/content/en/docs/distributions/ibm/deploy/install-kubeflow-on-iks.md b/content/en/docs/distributions/ibm/deploy/install-kubeflow-on-iks.md deleted file mode 100644 index 07e9a25681..0000000000 --- a/content/en/docs/distributions/ibm/deploy/install-kubeflow-on-iks.md +++ /dev/null @@ -1,327 +0,0 @@ -+++ -title = "Install Kubeflow on IKS" -description = "Instructions for deploying Kubeflow on IBM Cloud Kubernetes Service" -weight = 6 -+++ - -This guide describes how to use the kustomize + kubectl to deploy Kubeflow on IBM Cloud Kubernetes Service (IKS). - -## Prerequisites - -* Authenticate with IBM Cloud - - Log into IBM Cloud using the [IBM Cloud Command Line Interface (CLI)](https://www.ibm.com/cloud/cli) as follows: - - ```shell - ibmcloud login - ``` - - Or, if you have federated credentials, run the following command: - - ```shell - ibmcloud login --sso - ``` - -* Create and access a Kubernetes cluster on IKS - - To deploy Kubeflow on IBM Cloud, you need a cluster running on IKS. If you don't have a cluster running, follow the [Create an IBM Cloud cluster](/docs/ibm/create-cluster) guide. - - Run the following command to switch the Kubernetes context and access the cluster: - - ```shell - ibmcloud ks cluster config --cluster - ``` - - Replace `` with your cluster name. - -* kustomize (version 5.0.0) ([download link](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.0.0)) - -* [Python 3](https://www.python.org/downloads/) with [passlib](https://pypi.org/project/passlib/) - and [bcrypt](https://pypi.org/project/bcrypt/) packages installed - -### Storage setup for a **Classic** IBM Cloud Kubernetes cluster - -**Note**: This section is only required when the worker nodes provider `WORKER_NODE_PROVIDER` is set to `classic`. For other infrastructures, IBM Cloud Storage with Group ID support is already set up as the cluster's default storage class. - -When you use the `classic` worker node provider of an IBM Cloud Kubernetes cluster, it uses the regular [IBM Cloud File Storage](https://www.ibm.com/cloud/file-storage) based on NFS as the default storage class. File Storage is designed to run RWX (read-write multiple nodes) workloads with proper security built around it. Therefore, File Storage [does not allow `fsGroup` securityContext](https://cloud.ibm.com/docs/containers?topic=containers-security#container) unless it's configured with Group ID, which is needed for the [OIDC authentication service](https://github.com/arrikto/oidc-authservice) and Kubeflow Jupyter server. - -Therefore, you're recommended to set up the default storage class with Group ID support so that you can get the best experience from Kubeflow. - -1. Set the File Storage with Group ID support as the default storage class. - - ```shell - NEW_STORAGE_CLASS=ibmc-file-gold-gid - OLD_STORAGE_CLASS=$(kubectl get sc -o jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io\/is-default-class=="true")].metadata.name}') - kubectl patch storageclass ${NEW_STORAGE_CLASS} -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' - - # List all the (default) storage classes - kubectl get storageclass | grep "(default)" - ``` - - Example output: - ``` - ibmc-file-gold-gid (default) ibm.io/ibmc-file Delete Immediate false 14h - ``` - -2. Make sure `ibmc-file-gold-gid` is the only `(default)` storage class. If there are two or more rows in the above output, unset the previous `(default)` storage classes with the command below: - ```shell - kubectl patch storageclass ${OLD_STORAGE_CLASS} -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}' - ``` - -### Storage setup for **vpc-gen2** IBM Cloud Kubernetes cluster - -**Note**: To deploy Kubeflow, you don't need to change the storage setup for `vpc-gen2` Kubernetes cluster. - -Currently, there is no option available for setting up RWX (read-write multiple nodes) type of storages. -RWX is not a mandatory requirement to run Kubeflow and most pipelines. -It is required by certain sample jobs/pipelines where multiple pods write results to a common storage. -A job or a pipeline can also write to a common object storage like `minio`, so the absence of this feature is -not a blocker for working with Kubeflow. -Examples of jobs/pipelines that will not work, are: -[Distributed training with Kubeflow TFJob](https://github.com/kubeflow/training-operator/tree/master/examples/tensorflow/mnist_with_summaries) - -If you are on `vpc-gen2` and still need RWX, you may try [portworx enterprise product](https://portworx.com/products/features/). -To set it up on IBM Cloud use the [portworx install with IBM Cloud](https://docs.portworx.com/portworx-install-with-kubernetes/cloud/ibm/) guide. - - -## Installation - -Choose either **single user** or **multi-tenant** section based on your usage. - -If you're experiencing issues during the installation because of conflicts on your Kubeflow deployment, you can [uninstall Kubeflow](/docs/ibm/deploy/uninstall-kubeflow) and install it again. - -## Single user - -Using kustomize together with kubectl to deploy kubeflow: - -1. Clone the manifest repo as follows: - - ```shell - git clone https://github.com/IBM/manifests.git -b v1.7-branch ibm-manifests-17 - ``` - -2. Change directory to `ibm-manifests-17`: - - ```shell - cd ibm-manifests-17 - ``` - -3. Generate password for default user: `user@example.com` - ```shell - python3 -c 'from passlib.hash import bcrypt; import getpass; print(bcrypt.using(rounds=12, ident="2y").hash(getpass.getpass()))' - ``` - Type your password and press `` after you see `Password:` prompt. Copy the hash code for next step. - -4. Edit `dist/stacks/ibm/application/dex-auth/custom-env.yaml` and fill the relevant field - with the hash code from previous step: - ``` - staticPasswords: - - email: user@example.com - hash: - ``` - You can also change the email value if needed. - -5. Apply the `kustomize` file under `iks-single` folder for single user deployment: - - ```shell - while ! kustomize build iks-single 2>/dev/null | awk '!/well-defined/' | kubectl apply -f -; do echo "Retrying to apply resources"; sleep 10; done - ``` - -### Accessing your cluster - -The Kubeflow endpoint is exposed with [NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#nodeport) `30380`. To get a static ip, you can [expose the Kubeflow endpoint as a LoadBalancer](#expose-the-kubeflow-endpoint-as-a-loadbalancer) and access the **EXTERNAL_IP**. - -For single-user Kubeflow, IBM Cloud uses Dex authentication by default. You can access the cluster using -the email and password you specified in step 3 and 4 of [Single User](#single-user) - -## Multi-user, auth-enabled - -Run the following steps to deploy Kubeflow with [IBM Cloud AppID](https://cloud.ibm.com/catalog/services/app-id) -as an authentication provider. - -The scenario is a Kubeflow cluster admin configures Kubeflow as a web -application in AppID and manages user authentication with builtin identity -providers (Cloud Directory, SAML, social log-in with Google or Facebook etc.) or -custom providers. - -### Prerequisites - -For authentication, IBM Cloud uses [AppID](https://cloud.ibm.com/catalog/services/app-id) - -1. Follow the [Creating an App ID service instance on IBM Cloud](https://cloud.ibm.com/catalog/services/app-id) guide to learn about Kubeflow authentication. -You can also learn [how to use App ID](https://cloud.ibm.com/docs/appid?topic=appid-getting-started) with different authentication methods. - -2. Follow the [Registering your app](https://cloud.ibm.com/docs/appid?topic=appid-app#app-register) - section of the App ID guide to create an application with type - _regularwebapp_ under the provisioned AppID instance. Make sure the _scope_ - contains _email_. Then retrieve the following configuration parameters from your AppID: - * `clientId` - * `secret` - * `oAuthServerUrl` - - You will be using these information in the subsequent sections. - -3. Register the Kubeflow OIDC redirect page. The Kubeflow `REDIRECT_URL` URL is - `[http|https]:///authservice/oidc/callback`, depends on if you enable the HTTPS or not. - `` is the endpoint for accessing Kubeflow. By default, the `` - on IBM Cloud is `:30380`. To get a static ip, you can - [expose the Kubeflow endpoint as a LoadBalancer](#expose-the-kubeflow-endpoint-as-a-loadbalancer) - and use the **EXTERNAL_IP** for your ``. Or use `ibmcloud ks nlb-dns` command - to map the **EXTERNAL_IP** to the generated FQDN for your cluster. In this case, you use the - generated FQDN as `kubeflow-FQDN`. If you enable HTTPS, you shall use generated FQDN. - -4. Then, you need to place the Kubeflow OIDC `REDIRECT_URL` under **Manage Authentication** > **Authentication settings** > **Add web redirect URLs**. - - APP ID Redirect Settings - - Example: - `https://my-kubeflow-442dbba0442be6c8c50f31ed96b00601-0000.sjc04.containers.appdomain.cloud/authservice/oidc/callback` -### Deploy: Using kustomize together with kubectl - -1. Clone the manifest repo as follows: - - ```shell - git clone https://github.com/IBM/manifests.git -b v1.7-branch ibm-manifests-17 - ``` - -2. Change directory to `ibm-manifests-17`: - - ```shell - cd ibm-manifests-17 - ``` - -3. Update the `dist/stacks/ibm/application/oidc-authservice-appid/params.env` - with values collected in [Prereq](#prerequisites-1) section. - You will need the following values: - * `` - replace `` - * `` - fill in the FQDN of Kubeflow, if you don't know yet, just give a dummy one like - `localhost`. Then change it after you got one. Or get default FQDN of your cluster by this command: - `ibmcloud ks nlb-dns ls -c ` (replace `` with your cluster name) - - Example: - ``` - OIDC_PROVIDER=https://us-south.appid.cloud.ibm.com/oauth/v4/f341ff8b-a088-497a-same-5da4628df7fd - REDIRECT_URL=https://my-kubeflow-442dbba0442be6c8c50f31ed96b00601-0000.sjc04.containers.appdomain.cloud/authservice/oidc/callback - OIDC_AUTH_URL=https://us-south.appid.cloud.ibm.com/oauth/v4/f341ff8b-a088-497a-same-5da4628df7fd/authorization - ``` - -4. Update the `dist/stacks/ibm/application/oidc-authservice-appid/secret_params.env` - with values collected in [Prereq](#prerequisites-1) section. - You will need the following values: - * `` - replace the `` - * `` - replace the `` - - Example: - ``` - CLIENT_SECRET=NjNhZDA3ODAtM2I3MCSECRETLTkwN2QtNDdhYmU5ZGIyMTBl - CLIENT_ID=52b3e496-8888-8888-ABC9-c0da309cdf52 - ``` - -5. You can apply the `kustomize` file in `iks-multi` folder: - - ```bash - while ! kustomize build iks-multi 2>/dev/null | awk '!/well-defined/' | kubectl apply -f -; do echo "Retrying to apply resources"; sleep 10; done - ``` - -6. If at any point the values change and you have to change them, you can either patch the - [configmap](#patch-configmap) and [secret](#patch-secret) or change the content in the - files and apply the kustomize again. You will need to restart authservice with - `kubectl delete pod -l app=authservice -n istio-system` . - - To apply just the `oidc-authservice-appid` you can use this command: - - ```bash - kustomize build dist/stacks/ibm/application/oidc-authservice-appid | kubectl apply -f - - kubectl delete pod -l app=authservice -n istio-system - ``` - -### Verify mutli-user installation - -Check the pod `authservice-0` is in running state in namespace `istio-system`: - -```SHELL -kubectl get pod -l app=authservice -n istio-system -``` - -### Extra network setup requirement for **vpc-gen2** clusters only - -**Note**: These steps are not required for `classic` clusters, i.e. where `WORKER_NODE_PROVIDER` is set to `classic`. - -A `vpc-gen2` cluster does not assign a public IP address to the Kubernetes master node by default. -It provides access via a Load Balancer, which is configured to allow only a set of ports over public internet. -Access the cluster's resources in a `vpc-gen2` cluster, using one of the following options, - -* Load Balancer method: To configure via a Load Balancer, go to [Expose the Kubeflow endpoint as a LoadBalancer](#expose-the-kubeflow-endpoint-as-a-loadbalancer). - This method is recommended when you have Kubeflow deployed with [Multi-user, auth-enabled](#multi-user-auth-enabled) support — otherwise it will expose - cluster resources to the public. - -* Socks proxy method: If you need access to nodes or NodePort in the `vpc-gen2` cluster, this can be achieved by starting another instance in the -same `vpc-gen2` cluster and assigning it a public IP (i.e. the floating IP). Next, use SSH to log into the instance or create an SSH socks proxy, - such as `ssh -D9999 root@new-instance-public-ip`. - -Then, configure the socks proxy at `localhost:9999` and access cluster services. - -* `kubectl port-forward` method: To access Kubeflow dashboard, run `kubectl -n istio-system port-forward service/istio-ingressgateway 7080:http2`. - Then in a browser, go to[http://127.0.0.1:7080/](http://127.0.0.1:7080/) - -_**Important notice**: Exposing cluster/compute resources publicly without setting up a proper user authentication mechanism -is very insecure and can have very serious consequences(even legal). If there is no need to expose cluster services publicly, -Socks proxy method or `kubectl port-forward` method are recommended._ - -## Next steps: secure the Kubeflow dashboard with HTTPS - -### Prerequisites - -For both `classic` and `vpc-gen2` cluster providers, make sure you have [Multi-user, auth-enabled](#multi-user-auth-enabled) Kubeflow set up. - -### Setup - -Follow the steps in [Exposing the Kubeflow dashboard with DNS and TLS termination](../authentication/#exposing-the-kubeflow-dashboard-with-dns-and-tls-termination). -Then, you will have the required DNS name as Kubeflow FQDN to enable the OIDC flow for AppID: - - -1. Follow the step [Adding redirect URIs](https://cloud.ibm.com/docs/appid?topic=appid-managing-idp#add-redirect-uri) - to fill a URL for AppID to redirect to Kubeflow. The URL should look like `https:///authservice/oidc/callback`. - -2. Update the secret `appid-application-configuration` with the updated Kubeflow FQDN to replace `` in below command: - - ```SHELL - export REDIRECT_URL=https:///authservice/oidc/callback - export PATCH=$(printf '{"data": {"REDIRECT_URL": "%s"}}' "$REDIRECT_URL") - - kubectl patch configmap/oidc-authservice-parameters -n istio-system -p="$PATCH" - ``` - -3. Restart the pod `authservice-0`: - - ```shell - kubectl delete pod -l app=authservice -n istio-system - ``` - -Then, visit `https:///`. The page should redirect you to AppID for authentication. - -## Troubleshooting - -### Expose the Kubeflow endpoint as a LoadBalancer - -By default, the Kubeflow deployment on IBM Cloud only exposes the endpoint as [NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#nodeport) 30380. If you want to expose the endpoint as a [LoadBalancer](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer), run: - -```shell -kubectl patch svc istio-ingressgateway -n istio-system -p '{"spec": {"type": "LoadBalancer"}}' -``` - -Then, you can locate the LoadBalancer in the **EXTERNAL_IP** column when you run the following command: - -```shell -kubectl get svc istio-ingressgateway -n istio-system -``` - -There is a small delay, usually ~5 mins, for above commands to take effect. - -### Authservice pod taking too long to restart - -You might see the `authservice-0` pod taking some time to restart. If that happens you can delete to pod which will kick off restart from kubernetes reconciler. - -```bash -kubectl delete pod -l app=authservice -n istio-system -``` diff --git a/content/en/docs/distributions/ibm/deploy/uninstall-kubeflow.md b/content/en/docs/distributions/ibm/deploy/uninstall-kubeflow.md deleted file mode 100644 index 3392ec0d16..0000000000 --- a/content/en/docs/distributions/ibm/deploy/uninstall-kubeflow.md +++ /dev/null @@ -1,43 +0,0 @@ -+++ -title = "Uninstall Kubeflow" -description = "Instructions for uninstalling Kubeflow" -weight = 20 - -+++ - -Uninstall Kubeflow on your IBM Cloud IKS cluster. - -1. Go to your Kubeflow deployment directory where you download the - IBM manifests repository: https://github.com/IBM/manifests.git - ```shell - cd ibm-manifests-17 - ``` - -2. Run the following command to get Kubeflow Profiles: - ```shell - kubectl get profile - ``` - -3. Delete all Kubeflow Profiles manually: - ```shell - kubectl delete profile --all - ``` - Use the following command to check all namespaces for Kubeflow Profiles - are removed properly: - ``` - kubectl get ns - ``` - Make sure no namespace is in the `Terminating` state. - - -4. Remove Kubeflow: - - For single-user deployment: - ```shell - kustomize build iks-single 2>/dev/null | awk '!/well-defined/' | kubectl delete -f - - ``` - - For multi-user deployment: - ```shell - kustomize build iks-multi 2>/dev/null | awk '!/well-defined/' | kubectl delete -f - - ``` diff --git a/content/en/docs/distributions/ibm/iks-e2e.md b/content/en/docs/distributions/ibm/iks-e2e.md deleted file mode 100644 index ef3c4a8066..0000000000 --- a/content/en/docs/distributions/ibm/iks-e2e.md +++ /dev/null @@ -1,86 +0,0 @@ -+++ -title = "End-to-end Kubeflow on IBM Cloud" -description = "Running Kubeflow using IBM Cloud Kubernetes Service (IKS)" -weight = 7 - -+++ -This is a guide for an end-to-end example of Kubeflow on [IBM Cloud Kubernetes Service (IKS)](https://cloud.ibm.com/docs/containers?topic=containers-getting-started). The core steps will be to take a base Tensorflow model, modify it for distributed training, serve the resulting model with TFServing, and deploy a web application that uses the trained model. - -## Introduction -### Overview of IKS - -[IBM Cloud Kubernetes Service (IKS)](https://cloud.ibm.com/docs/containers?topic=containers-getting-started) enables the deployment of containerized applications in Kubernetes clusters with specialized tools for management of the systems. - -The [IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cloud-cli-getting-started) can be used for creating, developing, and deploying cloud applications. - -Here's a list of IBM Cloud services you will use: -* [IKS][iks] -* [IBM Cloud Object Storage][ibm-cos] - -### The model and the data - -This tutorial trains a [TensorFlow][tensorflow] model on the -[MNIST dataset][mnist-data], which is the *hello world* for machine learning. - -The MNIST dataset contains a large number of images of hand-written digits in -the range 0 to 9, as well as the labels identifying the digit in each image. - -After training, the model can classify incoming images into 10 categories -(0 to 9) based on what it's learned about handwritten images. In other words, -you send an image to the model, and the model does its best to identify the -digit shown in the image. -Prediction UI - -In the above screenshot, the image shows a hand-written **7**. This image was -the input to the model. The table below the image shows a bar graph for each -classification label from 0 to 9, as output by the model. Each bar -represents the probability that the image matches the respective label. -Judging by this screenshot, the model seems pretty confident that this image -is a 7. - -### The overall workflow - -The following diagram shows what you accomplish by following this guide: - -ML workflow for training and serving an MNIST model - -In summary: - -* Setting up [Kubeflow][kubeflow] on [IKS][iks]. -* Training the model: - * Packaging a Tensorflow program in a container. - * Submitting a Tensorflow training ([tf.train][tf-train]) job. -* Using the model for prediction (inference): - * Saving the trained model to [IBM Cloud Object Storage][ibm-cos]. - * Using [Tensorflow Serving][tf-serving] to serve the model. - * Running the simple web app to send prediction request to the model and display the result. - -It's time to get started! - -## Run the MNIST Tutorial on IKS - -1. Follow the [IKS instructions](/docs/ibm/deploy/install-kubeflow) to deploy Kubeflow. -2. Launch a Jupyter notebook. -3. Launch a terminal in Jupyter and clone the Kubeflow examples repo. - ``` - git clone https://github.com/kubeflow/examples.git git_kubeflow-examples - ``` - * **Tip**: When you start a terminal in Jupyter, run the command `bash` to start - a bash terminal which is much more friendly than the default shell. - * **Tip**: You can change the URL for your notebook from '/tree' to '/lab' to switch to using Jupyterlab. -4. Open the notebook `mnist/mnist_ibm.ipynb`. -5. Follow the notebook to train and deploy MNIST on Kubeflow. - - -[kubernetes]: https://kubernetes.io/ -[kubeflow]: https://www.kubeflow.org/ -[iks]: https://www.ibm.com/cloud/container-service/ -[ibm-cos]: https://www.ibm.com/cloud/object-storage -[mnist-data]: https://yann.lecun.com/exdb/mnist/index.html -[tensorflow]: https://www.tensorflow.org/ -[tf-train]: https://www.tensorflow.org/api_guides/python/train -[tf-serving]: https://www.tensorflow.org/tfx/guide/serving diff --git a/content/en/docs/distributions/ibm/kfp-tekton.png b/content/en/docs/distributions/ibm/kfp-tekton.png deleted file mode 100644 index 4b8928a837b69650cfd8695ba4dd083b5a9243d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105695 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∨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 - -In this tutorial, we use the below single step pipeline as our example - -```python -from kfp import dsl -def echo_op(): - return dsl.ContainerOp( - name='echo', - image='busybox', - command=['sh', '-c'], - arguments=['echo "Got scheduled"'] - ) - -@dsl.pipeline( - name='echo', - description='echo pipeline' -) -def echo_pipeline( -): - echo = echo_op() -``` - -# Declare the Python Client for Kubeflow Pipelines - -## 1. Single-user Kubeflow Pipelines deployment with the SDK - -* You will be using the Kubeflow Pipelines with Tekton SDK ([`kfp-tekton`](https://pypi.org/project/kfp-tekton/)) v0.4.0 or above. -* If you have deployed Kubeflow on IBM Cloud using the -[`kfctl_ibm.v1.2.0.yaml`](https://raw.githubusercontent.com/kubeflow/manifests/v1.2-branch/kfdef/kfctl_ibm.v1.2.0.yaml) -manifest you can configure ([`kfp-tekton`](https://pypi.org/project/kfp-tekton/)) SDK to list all your Kubeflow Pipelines experiments as follows: - -```python -from kfp_tekton import TektonClient - -KUBEFLOW_PUBLIC_ENDPOINT_URL = 'http://' -KUBEFLOW_PROFILE_NAME = None -client = TektonClient(host=f'{KUBEFLOW_PUBLIC_ENDPOINT_URL}/pipeline') - -experiments = client.list_experiments(namespace=KUBEFLOW_PROFILE_NAME) -``` -**Note**: `` is the EXTERNAL_IP you exposed as a LoadBalancer following [`this instruction`](https://www.kubeflow.org/docs/ibm/deploy/install-kubeflow-on-iks/#expose-the-kubeflow-endpoint-as-a-loadbalancer). If you have not done that step during Kubeflow setup, please include port 31380 because the Kubeflow endpoint is exposed with NodePort 31380. - -## 2. Authenticating multi-user Kubeflow Pipelines with the SDK - -* You will be using the Kubeflow Pipelines SDK ([`kfp-tekton`](https://pypi.org/project/kfp-tekton/)) v0.4.0 or above. -* Note that this feature is available with multi-user, auth-enabled Kubeflow installation deployed from the [`kfctl_ibm_multi_user.v1.2.0.yaml`](https://raw.githubusercontent.com/kubeflow/manifests/v1.2-branch/kfdef/kfctl_ibm_multi_user.v1.2.0.yaml) -manifest. - -**Note**: You're highly recommended enabling HTTPS for the public endpoint of Kubeflow because this method transports sensitive information like session cookie values over edge network. - -It requires authentication via the public endpoint of Kubeflow deployment when using the Kubeflow Pipelines multi-user feature with Pipelines SDK. - -You need to provide the following three variables if you're using an in-cluster Jupyter notebook or a remote client machine: - -1. `KUBEFLOW_PUBLIC_ENDPOINT_URL` - Kubeflow public endpoint URL. You can obtain it from command `ibmcloud ks nlb-dns ls --cluster `. -1. `SESSION_COOKIE` - A session cookie starts with `authservice_session=`. You can obtain it from your browser after authenticated from Kubeflow UI. Notice that this session cookie expires in 24 hours, so you need to obtain it again after cookie expired. -1. `KUBEFLOW_PROFILE_NAME` - Your Kubeflow profile name - -Once you provide the three variables, the SDK can use the following Python code to list all your Kubeflow Pipelines experiments: - -```python -from kfp_tekton import TektonClient - -KUBEFLOW_PUBLIC_ENDPOINT_URL = 'https://xxxx..containers.appdomain.cloud' -# this session cookie looks like "authservice_session=xxxxxxx" -SESSION_COOKIE = 'authservice_session=xxxxxxx' -KUBEFLOW_PROFILE_NAME = '' - -client = TektonClient( - host=f'{KUBEFLOW_PUBLIC_ENDPOINT_URL}/pipeline', - cookies=SESSION_COOKIE -) - -experiments = client.list_experiments(namespace=KUBEFLOW_PROFILE_NAME) -``` - -Pipelines components like experiments and runs are isolated by Kubeflow profiles. A Kubeflow user can only see Pipelines experiments and runs belonging to this user's Kubeflow profile. - -# Upload pipelines - -Once you have declared the Python client, your Kubeflow pipelines can be uploaded using Python. - -Run the following code inside a Python session to upload the pipelines. This example shows different versions of the pipeline using the Python client. - -```python -import os - -# Initial version of the compiled pipeline -pipeline_file_path = 'echo_pipeline.yaml' -pipeline_name = 'echo_pipeline' - -# For the purpose of this tutorial, we will be using the same pipeline for both version. -pipeline_version_file_path = 'echo_pipeline.yaml' -pipeline_version_name = 'new_echo_pipeline' - -# Upload initial version of the pipeline -pipeline_file = os.path.join(pipeline_file_path) -pipeline = client.pipeline_uploads.upload_pipeline(pipeline_file, name=pipeline_name) - -# Upload new version of the pipeline -pipeline_version_file = os.path.join(pipeline_version_file_path) -pipeline_version = client.pipeline_uploads.upload_pipeline_version(pipeline_version_file, - name=pipeline_version_name, - pipelineid=pipeline.id) -``` - -# Run pipelines from the SDK -The `TektonClient` can run pipelines using one of the below sources: - -1. [Python DSL source code](#run-pipelines-from-the-python-dsl-source-code) -2. [Compiled pipeline file](#run-pipelines-from-the-compiled-pipeline-file) -3. [Uploaded pipelines on KFP engine](#run-pipelines-from-the-list-of-uploaded-pipelines) - -## Run pipelines from the Python DSL source code - -To learn about executing pipelines using the Python DSL source code, try the code below in a Python session using the `echo_pipeline` example. -The `create_run_from_pipeline_func` takes the DSL source code to compile and run it directly using the Kubeflow pipeline API without -uploading it to the pipeline list. This method is recommended if you are doing quick experiments without version control. - -```python -# You can overwrite the pipeline default parameters by providing a dictionary of key-value arguments. -# If you don't want to overwrite the default parameters, then define the arguments as an empty dictionary. -arguments={} - -client.create_run_from_pipeline_func(echo_pipeline, arguments=arguments, namespace=KUBEFLOW_PROFILE_NAME) -``` - -## Run pipelines from the compiled pipeline file - -Alternatively, you can also run the pipeline directly using a pre-compiled file. -```python -EXPERIMENT_NAME = 'Demo Experiments' -experiment = client.create_experiment(name=EXPERIMENT_NAME, namespace=KUBEFLOW_PROFILE_NAME) -run = client.run_pipeline(experiment.id, 'echo-pipeline', 'echo_pipeline.yaml') -``` - -## Run pipelines from the list of uploaded pipelines - -Similarly, you can also run the pipeline from the list of uploaded pipelines using the same `run_pipeline` function. - -```python -EXPERIMENT_NAME = 'Demo Experiments' -experiment = client.create_experiment(name=EXPERIMENT_NAME, namespace=KUBEFLOW_PROFILE_NAME) - -# Find the pipeline ID that you want to use. -client.list_pipelines() - -run = client.run_pipeline(experiment.id, pipeline_id='925415d5-18e9-4e08-b57f-3b06e3e54648', job_name='echo_pipeline_run') -``` diff --git a/content/en/docs/distributions/ibm/using-icr.md b/content/en/docs/distributions/ibm/using-icr.md deleted file mode 100644 index 4896205928..0000000000 --- a/content/en/docs/distributions/ibm/using-icr.md +++ /dev/null @@ -1,80 +0,0 @@ -+++ -title = "Using IBM Cloud Container Registry (ICR)" -description = "This guide covers certain scenarios involving using private container images with the IBM Cloud Container Registry (ICR)." -weight = 6 -+++ - -## Prerequisites - -* Install and configure the [IBM Cloud CLI](https://cloud.ibm.com/docs/cli?topic=cli-getting-started). -* Install the CLI plug-in for the IBM Cloud Container Registry by running the command `ibmcloud plugin install container-registry`. -* Create a namespace in ICR with the command `ibmcloud cr namespace-add `, replace `` with your preferred name. - -**Note**: The [ICR namespace](https://cloud.ibm.com/docs/Registry?topic=Registry-getting-started#gs_registry_namespace_add) is different from the Kubeflow Profile namespace. The ICR namespace is used to group container images stored in ICR, while a [Kubeflow Profile](/docs/components/multi-tenancy/overview/) namespace is a group of all Kubernetes clusters owned by a user. - -## Image pull secret - -As a Kubernetes cluster uses the Secret of `docker-registry` type to authenticate with a container registry to pull a private image, it needs an image pull secret to pull container images from IBM Cloud Container Registry. You can use the default image pull secret set up by the cluster or your account's IAM API key. - -### Using a default image pull secret - -By default, the IBM Cloud Kubernetes cluster is set up to pull images from only your account's namespace in IBM Cloud Container Registry by using the secret `all-icr-io` in the `default` namespace. A cluster admin can copy this secret to any Kubernetes namespace used as Kubeflow profile. For example, run below command to copy the secret `all-icr-io` to the `anonymous` namespace: - -``` -kubectl get secret all-icr-io -n default -o yaml \ -| sed 's/namespace: default/namespace: anonymous/g' \ -| kubectl -n anonymous create -f - -``` - -Once this secret is ready in your Kubeflow profile, a data scientist can use it to pull container images from ICR. - -See details and FAQs from the official guide [Setting up an image registry](https://cloud.ibm.com/docs/containers?topic=containers-registry). - -### Getting an IAM API Key - -You will need an IBM Cloud IAM API Key to work with ICR if you: -1. Have no access to the default image pull secret `all-icr-io` from the `default` namespace. -2. Need to access container images in other IBM Cloud accounts. -3. Need customized IAM policy by using a separate IAM service ID. - -If you don't have an IBM Cloud IAM API Key, follow the official guide [Create an API Key](https://cloud.ibm.com/docs/account?topic=account-userapikey#create_user_key). - -Once you get your IBM Cloud IAM API Key, run the following command: - -``` -kubectl -n create secret docker-registry \ ---docker-server= \ ---docker-username=iamapikey \ ---docker-password= \ ---docker-email= -``` - -**Notes**: -* ``: your namespace to use with ICR to create an image pull secret. -* ``: your IBM Cloud API Key. -* ``: a unique name for the pull image secret, such as `us-icr-io`, for example. -* ``: the image registry where your registry namespace is set up. Use regional domain name when storing container images in specific region, such as `us.icr.io` when using region `en-us` and `uk.icr.io` when using region `eu-gb`. See full list of regional domain names from the [About IBM Cloud Container Registry page](https://cloud.ibm.com/docs/Registry?topic=Registry-registry_overview#registry_regions_local). -* ``: your docker email address or any fictional email address, such as `a@b.c`. - -## Scenarios - -### Using container images from ICR in Kubeflow Pipelines - -The pull image secret may be set in Kubeflow Pipelines SDK's [`PipelineConf`](https://kubeflow-pipelines.readthedocs.io/en/stable/source/kfp.dsl.html#kfp.dsl.PipelineConf). Refer to this [`imagepullsecrets.py`](https://github.com/kubeflow/pipelines/blob/ef381aafccf916482d16774cac3b8568d06dff9e/samples/core/imagepullsecrets/imagepullsecrets.py#L55) sample in Kubeflow Pipelines project for usage. - -### Using notebook images from ICR in a Jupyter Notebook - -When a namespace is created for Kubeflow with its profile controller, a default service account `default-editor` is created in that namespace. Before creating a Notebook Server, run following command to patch the service account. Replace `` with the ICR pull image secret name and `` with the Kubeflow profile namespace. - -Replace `` with your namespace then run below command to patch the service account `default-editor` with this image pull secret: -```SHELL -kubectl patch serviceaccount default-editor \ --p '{"imagePullSecrets": [{"name": ""}]}' \ --n -``` - -The service account should be updated. Then, when you create the Notebook Server through Kubeflow dashboard, you should be able to choose a Custom Image. Afterwards, set the notebook image path from the ICR as follows: - -Notebook Custom Image