Deploy Charmed Kubeflow to Microk8s behind a web proxy

Deploying Charmed Kubeflow on MicroK8s behind a web proxy requires some configuration. The target machine’s environment must be prepared to handle the web proxy prior to deployment. Additionally, Kubeflow components must be configured to work with the web proxy.

Prepare your environment

Before you get to Installing Charmed Kubeflow, first you need to set up your client with proxy setttings, and install Microk8s and Juju with proxy configurations.

Configure snap

  • Save the value of your proxy server address (PROXY) for reuse:
PROXY=http://<username>:<password>@<proxy IP>:<proxy port>/

The proxy IP and proxy port are usually given by your network administrator Add the username:<password>@ part only if the proxy server is configured with credentials, check with your network administrator.

  • Set the snap proxy settings
sudo snap set system proxy.http=$PROXY
sudo snap set system proxy.https=$PROXY

This will enable you to install snap packages

  • Restart snap service
sudo systemctl restart snapd.service

Configure Microk8s

  • Install Microk8s:
sudo snap install microk8s --classic --channel=1.29-strict/stable
  • Add the current user to the Microk8s group:
sudo usermod -a -G snap_microk8s $USER
newgrp snap_microk8s

This way you don’t have to use sudo for every Microk8s command.

  • Enable microk8s add-ons needed to run Charmed Kubeflow. Note that the metallb range can change depending on the use case and the env, but we use this one in all our guides.
sudo microk8s enable dns:$(resolvectl status | grep "Current DNS Server" | awk '{print $NF}')	# This sets the dns to your current nameserver
sudo microk8s enable storage ingress metallb:10.64.140.43-10.64.140.49
  • Get the values cluster-cidr and service-cluster-ip-range stored in /var/snap/microk8s/current/args/kube-proxy and /var/snap/microk8s/current/args/kube-apiserver respectively, and store these values in a variable.
cat /var/snap/microk8s/current/args/kube-proxy | grep cluster-cidr

# Sample output
--cluster-cidr=<cluster cidr> # copy this value for the next command

CLUSTER_CIDR=<cluster cidr>
cat /var/snap/microk8s/current/args/kube-apiserver | grep service-cluster-ip-range

# Sample output
-service-cluster-ip-range=<service cluster ip range>  # copy this value for the next command

SERVICE_CIDR=<service cluster ip range>

You will need these two values in the next step and later when installing Juju.

See more: Microk8s | Installing behind a proxy

  • Get the Internal IP of the nodes where your cluster is running, you can check that by running:
microk8s kubectl get nodes -o wide

Take note of the INTERNAL-IP value. Save the IP(s) in a variable with suffix /24, comma-separated if you have a multi-node cluster.

NODE_IP=<nodes internal ip(s)>/24
  • Set the proxy settings in containerd-env. Modify the containerd-env file located in ${SNAP_DATA}/args/containerd-env (normally /var/snap/microk8s/current/args/containerd-env):
HTTPS_PROXY=http://<username>:<password>@<proxy IP>:<proxy port>/
NO_PROXY=<cluster-cidr>,<service-cluster-ip-range>,<nodes internal ip(s)>/24,127.0.0.1
  • Restart the microk8s snap to pick up the changes:
sudo snap restart microk8s
  • Check that Microk8s is running with the desired add-ons:
microk8s status

# Sample output:
microk8s is running
high-availability: no
  datastore master nodes: 127.0.0.1:19001
  datastore standby nodes: none
addons:
  enabled:
    dns                  # (core) CoreDNS
    ha-cluster           # (core) Configure high availability on the current node
    hostpath-storage     # (core) Storage class; allocates storage from host directory
    ingress              # (core) Ingress controller for external access
    metallb              # (core) Loadbalancer for your Kubernetes cluster
    storage              # (core) Alias to hostpath-storage add-on, deprecated

Configure Juju

  • Export the system proxy settings used by the Juju client. Make sure to set the metallb as you configured it when installing Microk8s. Make sure to replace <hostname> with your own hostname.
export http_proxy=$PROXY
export https_proxy=$PROXY
export no_proxy=$CLUSTER_CIDR,\ 
$SERVICE_CIDR\ 
127.0.0.1,\ 
$NODE_IP,\ 
<hostname>,\  
.svc,\ 
.local,\ 
10.64.140.0/24,\  # This is the metallb IP range
.nip.io
  • Install Juju
sudo snap install juju --classic --channel=3.4/stable
  • Create a Juju controller in your Microk8s cluster and set the proxy model default values. Change the metallb value if you configured it differently.
juju bootstrap microk8s uk8s --model-default juju-http-proxy=$http_proxy \
--model-default juju-https-proxy=$https_proxy \
--model-default juju-no-proxy=$no_proxy
  • Add Juju model
juju add-model kubeflow 
  • Make sure Kubeflow model has your proxy settings, run:
juju model-config

You should see the proxy settings in the juju-http-proxy, juju-https-proxy, and juju-no-proxy variables.

Deploy Charmed Kubeflow

  • Deploy Kubeflow bundle
juju deploy kubeflow --channel 1.9/stable --trust

Watch the progress and wait until all charms are Active:

juju status --watch 5s
  • Configure the dashboard URL and credentials. Follow the steps from the Get started tutorial.
  • Check if you can access the dashboard URL
curl -I http://10.64.140.43 --noproxy '*'

You should see a 302 Found response similar to this:

HTTP/1.1 302 Found
location: http://10.64.140.43.nip.io/dex/auth?client_id=authservice-oidc&redirect_uri=%2Fauthservice%2Foidc%2Fcallback&response_type=code&scope=openid+profile+email+groups&state=MTY3OTY2MTYwOXxFd3dBRURWaE9EUnFha3ByZDNwRWEyZzVhREk9fBanXjJZJn5xKjDyvnrMc83mpkCyOt6ATbR0oox_Ppqm
date: Fri, 24 Mar 2023 12:40:09 GMT
x-envoy-upstream-service-time: 482
server: istio-envoy
transfer-encoding: chunked

Using Kubeflow components behind a proxy

Before you dive into the Charmed Kubeflow components, make sure you know the necessary component configurations for a proxy environment.

Notebooks

Apply the following PodDefault to your user namespace so each notebook you create will have proxy configurations set. The NO_PROXY and no_proxy values would be the same as you configured in the Juju model.

cat <<EOF | kubectl apply -n $USER_NAMESPACE -f -
apiVersion: kubeflow.org/v1alpha1
kind: PodDefault
metadata:
  name: notebook-proxy
spec:
  desc: Add proxy settings
  env:
  - name: HTTP_PROXY
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: http_proxy
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: HTTPS_PROXY
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: https_proxy
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: NO_PROXY
    value: <cluster cidr>,<service cluster ip range>,127.0.0.1,<nodes internal ip(s)>/24,<cluster hostname>,.svc,.local
  - name: no_proxy
    value: <cluster cidr>,<service cluster ip range>,127.0.0.1,<nodes internal ip(s)>/24,<cluster hostname>,.svc,.local,.kubeflow
  selector:
    matchLabels:
      notebook-proxy: "true"
EOF

You should now be able to see Add proxy settings when creating a new notebook under Advanced Options > Configurations. Always select that option. Screenshot from 2023-03-23 11-36-11

Katib

Before running a Katib experiment, add your proxy environment variables to your experiment definition for each container under spec.trialTemplate.trialSpec.spec.template.spec.containers

env:
  - name: HTTP_PROXY
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: http_proxy
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: HTTPS_PROXY
    value: http://10.0.1.119:3128/ # replace with $PROXY
  - name: https_proxy
    value: http://10.0.1.119:3128/ # replace with $PROXY
Expand to see full Katib experiment example
apiVersion: kubeflow.org/v1beta1
kind: Experiment
metadata:
  name: grid-proxy
spec:
  objective:
    type: maximize
    goal: 0.99
    objectiveMetricName: Validation-accuracy
    additionalMetricNames:
      - Train-accuracy
  algorithm:
    algorithmName: grid
  parallelTrialCount: 1
  maxTrialCount: 1
  maxFailedTrialCount: 1
  parameters:
    - name: lr
      parameterType: double
      feasibleSpace:
        min: "0.001"
        max: "0.01"
        step: "0.001"
    - name: num-layers
      parameterType: int
      feasibleSpace:
        min: "2"
        max: "5"
    - name: optimizer
      parameterType: categorical
      feasibleSpace:
        list:
          - sgd
          - adam
          - ftrl
  trialTemplate:
    primaryContainerName: training-container
    trialParameters:
      - name: learningRate
        description: Learning rate for the training model
        reference: lr
      - name: numberLayers
        description: Number of training model layers
        reference: num-layers
      - name: optimizer
        description: Training model optimizer (sdg, adam or ftrl)
        reference: optimizer
    trialSpec:
      apiVersion: batch/v1
      kind: Job
      spec:
        template:
          metadata:
            annotations:
              sidecar.istio.io/inject: "false"
          spec:
            containers:
              - name: training-container
                image: docker.io/kubeflowkatib/mxnet-mnist:latest
                command:
                  - "python3"
                  - "/opt/mxnet-mnist/mnist.py"
                  - "--batch-size=64"
                  - "--lr=${trialParameters.learningRate}"
                  - "--num-layers=${trialParameters.numberLayers}"
                  - "--optimizer=${trialParameters.optimizer}"
                env:
                  - name: HTTP_PROXY
                    value: http://10.0.1.119:3128/
                  - name: http_proxy
                    value: http://10.0.1.119:3128/
                  - name: HTTPS_PROXY
                    value: http://10.0.1.119:3128/
                  - name: https_proxy
                    value: http://10.0.1.119:3128/
            restartPolicy: Never

Pipelines

If your pipeline needs to download data or pull an image, you can inject your proxy environment variables into a pipeline from inside a notebook with the KFP SDK as done in this example notebook.

Istio

If you’re having trouble accessing the Charmed Kubeflow components, you might need to configure proxy settings for Istio.

kubectl apply -n kubeflow -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: proxy
spec:
  hosts:
  - my-company-proxy.com # ignored
  addresses:
  - 10.0.1.119/32 # replace with proxy IP
  ports:
  - number: 3128 # replace with proxy port
    name: tcp
    protocol: TCP
  location: MESH_EXTERNAL
EOF
2 Likes

Hi,

It is mentioned in the document to install microk8s from channel 1.24/stable which is a very older version.

And for the juju installation, it is given as:

sudo snap install juju --classic

which installs the version 3.5.3 nowadays.

With this version of juju, it is not possible to bootstrap a controller within microk8s:


ERROR "/var/snap/juju/28060/microk8s/credentials/client.config" does not exist: juju "3.5.3" can only work with strictly confined microk8s

So, the document should be reviewed.