Skip to content

Commit

Permalink
chore: bump mlserver-xgboost for Seldon version 1.15.x -> 1.17.1 (#73)
Browse files Browse the repository at this point in the history
Update ROCK according to upstream changes plus:

- introduce parts that we missed in the ROCK
- use ubuntu 20.04 as base due to #39
- refactor tox.ini according to canonical/oidc-authservice-rock#14 and canonical/bundle-kubeflow#763
- update `test_rock.py` according to latest changes in chisme canonical/charmed-kubeflow-chisme#81
- pins starlette due to #80

Ref #37
Closes #52
  • Loading branch information
orfeas-k authored Jan 11, 2024
1 parent e92f9ad commit f592118
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 76 deletions.
74 changes: 37 additions & 37 deletions mlserver-xgboost/rockcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
# Based on https://github.com/SeldonIO/MLServer/blob/1.2.0/Dockerfile
# Based on https://github.com/SeldonIO/MLServer/blob/1.3.5/Dockerfile
name: mlserver-xgboost
summary: An image for Seldon MLServer XGBoost
description: |
This image is used as part of the Charmed Kubeflow product.
version: 1.2.0_22.04_1 # <upstream-version>_<base-version>_<Charmed-KF-version>
version: 1.3.5
license: Apache-2.0
base: ubuntu:22.04
base: ubuntu@20.04
run-user: _daemon_
services:
mlserver-xgboost:
override: replace
summary: "mlserver-xgboost service"
startup: enabled
# We need to build and activate the "hot-loaded" environment before MLServer starts
command: bash -c 'export PATH=/opt/conda/bin/:/opt/mlserver/.local/bin:${PATH} && \
export PYTHONPATH=/opt/mlserver/.local/lib/python3.8/site-packages/:${PYTHONPATH} && \
source /opt/conda/etc/profile.d/conda.sh && \
source /hack/activate-env.sh $MLSERVER_ENV_TARBALL && \
mlserver start $MLSERVER_MODELS_DIR'
# Do not split command in many lines using `\` because this results in
# export: command not found error during container startup
command: bash -c 'export PATH=/opt/conda/bin/:/opt/mlserver/.local/bin:${PATH}:/usr/bin && export PYTHONPATH=/opt/mlserver/.local/lib/python3.8/site-packages/:${PYTHONPATH} && eval $(/opt/conda/bin/conda shell.bash hook 2> /dev/null) && mlserver start ${MLSERVER_MODELS_DIR}'
working-dir: "/opt/mlserver"
environment:
MLSERVER_ENV_TARBALL: "/mnt/models"
MLSERVER_MODELS_DIR: "/mnt/models/environment.tar.gz"
MLSERVER_ENV_TARBALL: "/mnt/models/environment.tar.gz"
MLSERVER_MODELS_DIR: "/mnt/models"
LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/opt/conda/lib/python3.8/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH"
TRANSFORMERS_CACHE: "/opt/mlserver/.cache"
NUMBA_CACHE_DIR: "/opt/mlserver/.cache"
platforms:
amd64:

Expand All @@ -29,32 +30,24 @@ parts:
plugin: nil
source: https://github.com/SeldonIO/MLServer
source-type: git
source-tag: 1.2.0
source-tag: 1.3.5
build-packages:
- bash
- tar
- gzip
# TO-DO: Verify need for the packages below
# - libgomp
# - mesa-libGL
# - glib2-devel
# - shadow-utils
stage-packages:
- bash
- python3-dev
- python3-setuptools
- python3-pip
- python-is-python3
override-build: |
mkdir -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist
cp ${CRAFT_PART_SRC}/setup.py .
cp ${CRAFT_PART_SRC}/README.md .
mkdir -p ${CRAFT_PART_INSTALL}/opt/openapi
./hack/build-wheels.sh ${CRAFT_PART_INSTALL}/opt/mlserver/dist
override-stage: |
export ROCK_RUNTIME="xgboost"
export PYTHON_VERSION="3.8.13"
export CONDA_VERSION="4.13.0"
export PYTHON_VERSION="3.8.16"
export CONDA_VERSION="22.11.1"
export RUNTIMES="mlserver_${ROCK_RUNTIME}"
export MINIFORGE_VERSION="${CONDA_VERSION}-1"
export MINIFORGE_VERSION="${CONDA_VERSION}-4"
export MLSERVER_PATH=opt/mlserver
export CONDA_PATH=opt/conda
export PATH=/opt/mlserver/.local/bin:/opt/conda/bin:$PATH
Expand All @@ -69,23 +62,30 @@ parts:
ln -sf ${CONDA_PATH}/etc/profile.d/conda.sh etc/profile.d/conda.sh
echo ". ${CONDA_PATH}/etc/profile.d/conda.sh" >> ~/.bashrc
echo "PATH=${PATH}" >> ~/.bashrc
bash -c "${CONDA_PATH}/bin/conda init bash"
${CONDA_PATH}/bin/conda init bash
echo "conda activate base" >> ~/.bashrc
chgrp -R root opt/conda && chmod -R g+rw opt/conda
# conda writes shebangs with its path everywhere, and in crafting, that will be, for example:
# #!/root/stage/opt/conda/...
#
# Snip off the /root/stage part
bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}"
# install required wheels
mkdir -p $MLSERVER_PATH
mkdir -p ${MLSERVER_PATH}
mkdir -p ./wheels
cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver-*.whl ./wheels
cp -p ${CRAFT_PART_INSTALL}/opt/mlserver/dist/mlserver_${ROCK_RUNTIME}-*.whl ./wheels
# setup pip to be from conda
. ${CONDA_PATH}/etc/profile.d/conda.sh
pip install --prefix ${MLSERVER_PATH}/.local --upgrade pip wheel setuptools
pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver-"*.whl)
pip install --prefix ${MLSERVER_PATH}/.local $(ls "./wheels/mlserver_${ROCK_RUNTIME}-"*.whl)
# Pin starlette due to https://github.com/canonical/seldonio-rocks/issues/80
echo starlette==0.22.0 >> ${CRAFT_PART_SRC}/requirements/docker.txt
pip install --prefix ${MLSERVER_PATH}/.local -r ${CRAFT_PART_SRC}/requirements/docker.txt
chown -R root:root ${MLSERVER_PATH} && chmod -R 777 ${MLSERVER_PATH}
# conda writes shebangs with its path everywhere, and in crafting, that will be, for example:
# #!/root/stage/opt/conda/...
#
# Snip off the /root/stage part
bash -c "grep -R -E '/root/stage' opt/ 2>/dev/null | grep -v Bin | awk '{split(\$0,out,\":\"); print out[1]}' | uniq | xargs -I{} sed -i -e 's/\/root\/stage//' {}"
# replace first line of mlserver script with reference to installed Conda python
export CONDA_PYTHON="#\!\/opt\/conda\/bin\/python"
Expand All @@ -111,5 +111,5 @@ parts:
override-build: |
mkdir -p ${CRAFT_PART_INSTALL}/usr/share/rocks
(echo "# os-release" && cat /etc/os-release && echo "# dpkg-query" && \
dpkg-query --root=${CRAFT_PROJECT_DIR}/../bundles/ubuntu-22.04/rootfs/ -f '${db:Status-Abbrev},${binary:Package},${Version},${source:Package},${Source:Version}\n' -W) \
dpkg-query -f '${db:Status-Abbrev},${binary:Package},${Version},${source:Package},${Source:Version}\n' -W) \
> ${CRAFT_PART_INSTALL}/usr/share/rocks/dpkg.query
14 changes: 6 additions & 8 deletions mlserver-xgboost/tests/test_rock.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import subprocess
import yaml

from pytest_operator.plugin import OpsTest
from charmed_kubeflow_chisme.rock import CheckRock

@pytest.fixture()
Expand All @@ -29,18 +28,17 @@ def rock_test_env(tmpdir):
# tmpdir fixture we use here should clean up the other files for us

@pytest.mark.abort_on_fail
def test_rock(ops_test: OpsTest, rock_test_env):
def test_rock(rock_test_env):
"""Test rock."""
temp_dir, container_name = rock_test_env
check_rock = CheckRock("rockcraft.yaml")
rock_image = check_rock.get_image_name()
rock_image = check_rock.get_name()
rock_version = check_rock.get_version()
LOCAL_ROCK_IMAGE = f"{check_rock.get_image_name()}:{check_rock.get_version()}"
LOCAL_ROCK_IMAGE = f"{rock_image}:{rock_version}"

# TO-DO uncomment when updated chisme is published
#rock_services = check_rock.get_services()
#assert rock_services["mlserver-xgboost"]
#assert rock_services["mlserver-xgboost"]["startup"] == "enabled"
rock_services = check_rock.get_services()
assert rock_services["mlserver-xgboost"]
assert rock_services["mlserver-xgboost"]["startup"] == "enabled"

# create ROCK filesystem
subprocess.run(["docker", "run", LOCAL_ROCK_IMAGE, "exec", "ls", "-la", "/opt/mlserver/.local/lib/python3.8/site-packages/mlserver"], check=True)
Expand Down
53 changes: 22 additions & 31 deletions mlserver-xgboost/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,33 @@ setenv =
CHARM_BRANCH=main
LOCAL_CHARM_DIR=charm_repo

[testenv:unit]
[testenv:pack]
passenv = *
allowlist_externals =
bash
tox
rockcraft
deps =
juju~=2.9.0
pytest
pytest-operator
ops
charmed_kubeflow_chisme
commands =
# build and pack rock
rockcraft pack

[testenv:export-to-docker]
passenv = *
allowlist_externals =
bash
skopeo
yq
commands =
# pack rock and export to docker
bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \
VERSION=$(yq eval .version rockcraft.yaml) && \
ARCH=$(yq eval ".platforms | keys" rockcraft.yaml | awk -F " " '\''{ print $2 }'\'') && \
ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}" && \
sudo skopeo --insecure-policy copy oci-archive:$ROCK.rock docker-daemon:$ROCK:$VERSION'
# run rock tests
pytest -vvv --tb native --show-capture=all --log-cli-level=INFO {posargs} {toxinidir}/tests
ARCH=$(yq eval ".platforms | keys | .[0]" rockcraft.yaml) && \
ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}.rock" && \
DOCKER_IMAGE=$NAME:$VERSION && \
echo "Exporting $ROCK to docker as $DOCKER_IMAGE" && \\
skopeo --insecure-policy copy oci-archive:$ROCK docker-daemon:$DOCKER_IMAGE'

[testenv:sanity]
passenv = *
deps =
juju~=2.9.0
pytest
pytest-operator
ops
charmed_kubeflow_chisme
commands =
# run rock tests
Expand All @@ -56,16 +52,13 @@ allowlist_externals =
git
rm
tox
rockcraft
sed
deps =
juju~=2.9.0
juju<4.0
pytest
pytest-operator
ops
commands =
# build and pack rock
rockcraft pack
# clone related charm
rm -rf {env:LOCAL_CHARM_DIR}
git clone --branch {env:CHARM_BRANCH} {env:CHARM_REPO} {env:LOCAL_CHARM_DIR}
Expand All @@ -74,16 +67,14 @@ commands =
# upload rock to docker and microk8s cache, replace charm's container with local rock reference
bash -c 'NAME=$(yq eval .name rockcraft.yaml) && \
VERSION=$(yq eval .version rockcraft.yaml) && \
ARCH=$(yq eval ".platforms | keys" rockcraft.yaml | awk -F " " '\''{ print $2 }'\'') && \
ROCK="$\{NAME\}_$\{VERSION\}_$\{ARCH\}" && \
sudo skopeo --insecure-policy copy oci-archive:$ROCK.rock docker-daemon:$ROCK:$VERSION && \
docker save $ROCK > $ROCK.tar && \
microk8s ctr image import $ROCK.tar --digests=true && \
predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \
predictor_servers=$(jq --arg jq_rock $ROCK -r '\''.XGBOOST_SERVER.protocols.v2.image=$jq_rock'\'' <<< $predictor_servers) && \
DOCKER_IMAGE=$NAME:$VERSION && \
docker save $DOCKER_IMAGE > $DOCKER_IMAGE.tar && \
sudo microk8s ctr image import $DOCKER_IMAGE.tar --digests=true && \
predictor_servers=$(yq e ".data.predictor_servers" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2) && \
predictor_servers=$(jq --arg jq_name $NAME -r '\''.XGBOOST_SERVER.protocols.v2.image=$jq_name'\'' <<< $predictor_servers) && \
predictor_servers=$(jq --arg jq_version $VERSION -r '\''.XGBOOST_SERVER.protocols.v2.defaultImageVersion=$jq_version'\'' <<< $predictor_servers) yq e -i ".data.predictor_servers=strenv(predictor_servers)" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2'
# replace yq safe placeholder with original value
sed -i "s/namespace: YQ_SAFE/namespace: {{ namespace }}/" {env:LOCAL_CHARM_DIR}/src/templates/configmap.yaml.j2
# run charm integration test with rock
tox -c {env:LOCAL_CHARM_DIR} -e integration
tox -c {env:LOCAL_CHARM_DIR} -e seldon-servers-integration -- -k xgboost-v2

0 comments on commit f592118

Please sign in to comment.