Skip to content

Commit

Permalink
feat(eval): runtime support image build on server (#1885)
Browse files Browse the repository at this point in the history
* build image for runtime

* build image for runtime

* build image for runtime: add comment

* refactor && add runtime build

* refactor && add runtime build

* refactor && add runtime build

* add existed job check

* add api

* add api

* add error log

* change image from labels to annotations

* change image from labels to annotations

* fix secret error

* fix secret error

* fix secret error

* fix secret error

* fix secret error

* fix secret error

* fix entrypoint problem

* rebase main code

* rebase main code

* rebase main code

* refactor build func

* code style

* use cache(remote repo)

* fix ut

* remove docker image function

* optimise code

* fix dependency cycle

* fix dependency cycle

* fix job yaml error

* fix string judge bug

* rename sql name

* add conflict code
  • Loading branch information
goldenxinxing authored Mar 8, 2023
1 parent 67dad2f commit a24c902
Show file tree
Hide file tree
Showing 37 changed files with 915 additions and 415 deletions.
50 changes: 31 additions & 19 deletions client/scripts/sw-docker-entrypoint
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ VERBOSE="-vvvv"
STEP=${SW_TASK_STEP:-""}
TASK_INDEX=${SW_TASK_INDEX:-0}
TASK_NUM=${SW_TASK_NUM:-0}
RUNTIME_RESTORED=${SW_USER_RUNTIME_RESTORED:-0}

_update_python_alter() {
echo "-->[Preparing] set python/python3 to $1 ..."
Expand Down Expand Up @@ -57,6 +58,8 @@ set_pip_cache() {
}

set_py_and_sw() {
pre_config

_MANIFEST_RUNTIME=$(swcli -o json runtime info ${SW_RUNTIME_VERSION} | jq -r ".config.environment.python") || exit 1
_RUNTIME="python${_MANIFEST_RUNTIME}"

Expand All @@ -73,6 +76,8 @@ set_py_and_sw() {
fi
_update_python_alter "$PY_VER"

set_pip_cache

if [ "$PY_VER" != "$_RUNTIME" ] || [ "$DETECTED_SW_VER" != "$ORIGIN_SW_VER" ]; then
# ignore the editable dev version
if [ "$DETECTED_SW_VER" != "0.0.0.dev0" ]; then
Expand All @@ -83,25 +88,24 @@ set_py_and_sw() {
fi
}

# TODO support run remote on standalone mode
pull_model_and_runtime() {
echo '-->[Preparing] start to pull model and runtime ...'

swcli instance login --token "${SW_TOKEN}" --alias server ${SW_INSTANCE_URI}
swcli model copy cloud://server/project/${SW_PROJECT}/model/${SW_MODEL_VERSION} .
swcli runtime copy cloud://server/project/${SW_PROJECT}/runtime/${SW_RUNTIME_VERSION} .
}

run() {
echo "-->[Running] start to run evaluation: ${STEP}, use $(which swcli) cli ..."
if [ "${RUNTIME_RESTORED}" != "1" ]; then
swcli ${VERBOSE} eval run --step=${STEP} --task-index=${TASK_INDEX} --override-task-num=${TASK_NUM} --model ${SW_MODEL_VERSION} --version=${SW_EVALUATION_VERSION} --runtime ${SW_RUNTIME_VERSION} || exit 1
else
swcli ${VERBOSE} eval run --step=${STEP} --task-index=${TASK_INDEX} --override-task-num=${TASK_NUM} --model ${SW_MODEL_VERSION} --version=${SW_EVALUATION_VERSION} || exit 1
fi

swcli ${VERBOSE} eval run --step=${STEP} --task-index=${TASK_INDEX} --override-task-num=${TASK_NUM} --model ${SW_MODEL_VERSION} --version=${SW_EVALUATION_VERSION} --runtime ${SW_RUNTIME_VERSION} || exit 1
}

serve() {
echo "-->[Serving] start to serve, use $(which swcli) cli ..."
export
swcli ${VERBOSE} model serve --model "${SW_MODEL_VERSION}" --runtime "${SW_RUNTIME_VERSION}" --host 0.0.0.0 || exit 1
if [ "${RUNTIME_RESTORED}" != "1" ]; then
swcli ${VERBOSE} model serve --model "${SW_MODEL_VERSION}" --runtime "${SW_RUNTIME_VERSION}" --host 0.0.0.0 || exit 1
else
swcli ${VERBOSE} model serve --model "${SW_MODEL_VERSION}" --host 0.0.0.0 || exit 1
fi
}

welcome() {
Expand All @@ -121,15 +125,23 @@ welcome() {
fi
}

eval_task_prepare(){
pre_config
prepare(){
if [ "${SW_INSTANCE_URI}" != "local" ]
then
# only remote
pull_model_and_runtime
echo '-->[Preparing] pulling model ...'
swcli instance login --token "${SW_TOKEN}" --alias server ${SW_INSTANCE_URI}
swcli model copy cloud://server/project/${SW_PROJECT}/model/${SW_MODEL_VERSION} .
if [ "${RUNTIME_RESTORED}" != "1" ]; then
echo '-->[Preparing] pulling runtime ...'
swcli runtime copy cloud://server/project/${SW_PROJECT}/runtime/${SW_RUNTIME_VERSION} .
fi
fi
if [ "${RUNTIME_RESTORED}" != "1" ]; then
set_py_and_sw
else
$(bash "${SW_USER_RUNTIME_WORKDIR:-/opt/starwhale.user/runtime}"/activate.sw)
fi
set_py_and_sw
set_pip_cache
}

welcome $1
Expand All @@ -138,12 +150,12 @@ case "$1" in
pre_config
;;
run)
eval_task_prepare $1 && run
prepare $1 && run
;;
serve)
eval_task_prepare $1 && serve
prepare $1 && serve
;;
*)
eval_task_prepare "starwhale" && exec "$@"
prepare "starwhale" && exec "$@"
;;
esac
3 changes: 1 addition & 2 deletions client/starwhale/core/runtime/template/Dockerfile.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ FROM ${BASE_IMAGE}

ARG TARGETARCH

ENTRYPOINT []
WORKDIR /opt/starwhale.user/runtime

LABEL starwhale_runtime_dockerize=1
Expand All @@ -26,7 +25,7 @@ ENV SW_PIP_CACHE_DIR=/root/.cache/pip
RUN python3 -m pip config set global.cache-dir ${SW_PIP_CACHE_DIR}

RUN swcli -vvv runtime restore /opt/starwhale.user/runtime \
&& bash /opt/starwhale.user/runtime/activate.sw
&& $(bash /opt/starwhale.user/runtime/activate.sw)

ENV SW_USER_RUNTIME_NAME={{runtime_name}}
ENV SW_USER_RUNTIME_VERSION={{runtime_version}}
Expand Down
2 changes: 2 additions & 0 deletions docker/Dockerfile.starwhale
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ ARG TARGETARCH=amd64
ARG SW_VERSION=0.1.0
ENV SW_VERSION ${SW_VERSION}

SHELL ["/bin/bash", "-c"]

ARG LOCAL_PYPI_HOSTNAME=host.nexus
ARG PORT_NEXUS=8081
ARG ENABLE_E2E_TEST_PYPI_REPO=0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ ResponseEntity<ResponseMessage<PageInfo<RuntimeVo>>> listRuntime(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
required = true,
schema = @Schema())
@PathVariable("projectUrl")
String projectUrl,
Expand Down Expand Up @@ -98,6 +99,7 @@ ResponseEntity<ResponseMessage<String>> revertRuntimeVersion(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
required = true,
schema = @Schema())
@PathVariable("projectUrl")
String projectUrl,
Expand All @@ -117,10 +119,7 @@ ResponseEntity<ResponseMessage<String>> revertRuntimeVersion(
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER')")
ResponseEntity<ResponseMessage<String>> deleteRuntime(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl")
String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
Expand All @@ -134,10 +133,7 @@ ResponseEntity<ResponseMessage<String>> deleteRuntime(
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyRole('OWNER')")
ResponseEntity<ResponseMessage<String>> recoverRuntime(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl);
Expand All @@ -150,10 +146,7 @@ ResponseEntity<ResponseMessage<String>> recoverRuntime(
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER', 'GUEST')")
ResponseEntity<ResponseMessage<RuntimeInfoVo>> getRuntimeInfo(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl,
Expand All @@ -166,10 +159,7 @@ ResponseEntity<ResponseMessage<RuntimeInfoVo>> getRuntimeInfo(
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER')")
ResponseEntity<ResponseMessage<String>> modifyRuntime(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl,
Expand All @@ -184,10 +174,7 @@ ResponseEntity<ResponseMessage<String>> modifyRuntime(
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER')")
ResponseEntity<ResponseMessage<String>> manageRuntimeTag(
@Parameter(
in = ParameterIn.PATH,
description = "Project url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl,
Expand All @@ -206,6 +193,7 @@ ResponseEntity<ResponseMessage<PageInfo<RuntimeVersionVo>>> listRuntimeVersion(
@Parameter(
in = ParameterIn.PATH,
description = "Project Url",
required = true,
schema = @Schema())
@PathVariable("projectUrl")
String projectUrl,
Expand Down Expand Up @@ -248,10 +236,7 @@ ResponseEntity<ResponseMessage<PageInfo<RuntimeVersionVo>>> listRuntimeVersion(
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER')")
ResponseEntity<ResponseMessage<String>> upload(
@Parameter(
in = ParameterIn.PATH,
description = "Project url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@Pattern(regexp = BUNDLE_NAME_REGEX, message = "Runtime name is invalid.")
Expand All @@ -270,10 +255,7 @@ ResponseEntity<ResponseMessage<String>> upload(
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER')")
void pull(
@Parameter(
in = ParameterIn.PATH,
description = "Project url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl,
Expand All @@ -291,10 +273,22 @@ void pull(
method = RequestMethod.HEAD)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER', 'GUEST')")
ResponseEntity<?> headRuntime(
@Parameter(
in = ParameterIn.PATH,
description = "Project url",
schema = @Schema())
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("versionUrl") String versionUrl);

@Operation(summary = "build image for runtime", description = "build image for runtime")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "ok")})
@RequestMapping(
value = "/project/{projectUrl}/runtime/{runtimeUrl}/version/{versionUrl}/image/build",
produces = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.POST)
@PreAuthorize("hasAnyRole('OWNER', 'MAINTAINER')")
ResponseEntity<?> buildRuntimeImage(
@Parameter(in = ParameterIn.PATH, required = true, description = "Project url", schema = @Schema())
@PathVariable("projectUrl") String projectUrl,
@Parameter(in = ParameterIn.PATH, required = true, schema = @Schema())
@PathVariable("runtimeUrl") String runtimeUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,10 @@ public ResponseEntity<?> headRuntime(String projectUrl, String runtimeUrl, Strin
return ResponseEntity.notFound().build();
}
}

@Override
public ResponseEntity<?> buildRuntimeImage(String projectUrl, String runtimeUrl, String versionUrl) {
runtimeService.buildImage(projectUrl, runtimeUrl, versionUrl);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,64 +16,29 @@

package ai.starwhale.mlops.common;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.util.StringUtils;

@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class DockerImage {

String registry;
String image;

/**
* please refer to https://github.com/distribution/distribution/blob/v2.7.1/reference/reference.go
*/
private static final Pattern PATTERN_IMAGE_FULL = Pattern.compile("^(.+?)\\/(.+)$");

/**
* @param imageNameFull such as ghcr.io/starwhale-ai/starwhale:0.3.5-rc123.dev12432344
* @param registry such as ghcr.io
* @param image such as starwhale-ai/starwhale:0.3.5-rc123.dev12432344
*/
public DockerImage(String imageNameFull) {
Matcher matcher = PATTERN_IMAGE_FULL.matcher(imageNameFull);
if (!matcher.matches()) {
this.registry = "";
this.image = imageNameFull;
} else {
String candidateRegistry = matcher.group(1);
if (isDomain(candidateRegistry)) {
this.registry = candidateRegistry;
image = matcher.group(2);
} else {
this.registry = "";
this.image = imageNameFull;
}

}
}

private static final Pattern PATTERN_DOMAIN_LOCAL_HOST = Pattern.compile("localhost(:\\d+)?");

private static boolean isDomain(String candidate) {
return candidate.contains(".") || PATTERN_DOMAIN_LOCAL_HOST.matcher(candidate).matches();
public DockerImage(String registry, String image) {
this.registry = registry;
this.image = image;
}

private static final String SLASH = "/";

public String resolve(String newRegistry) {
if (!StringUtils.hasText(newRegistry)) {
newRegistry = this.registry;
}
return StringUtils.trimTrailingCharacter(newRegistry, '/') + SLASH + image;
public String toString() {
return StringUtils.trimTrailingCharacter(registry, '/') + SLASH + image;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
public class DockerSetting {

String registry;
String userName;
String password;

public static DockerSetting empty() {
return new DockerSetting("");
return new DockerSetting("", "", "");
}

}
Loading

0 comments on commit a24c902

Please sign in to comment.