-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 48dd214
Showing
23 changed files
with
1,022 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[flake8] | ||
exclude = .git,__pycache__,venv,.venv | ||
max-line-length = 120 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
# Documentation: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses | ||
name: github_workflow | ||
run-name: GitHub Workflow | ||
|
||
env: | ||
## Common environment variables | ||
# Service name (must be lowercase and not contain any spaces) | ||
SERVICE_NAME: ${{ vars.SERVICE_NAME }} | ||
# Path to the model | ||
MODEL_PATH: ${{ vars.MODEL_PATH }} | ||
# S3 access key ID | ||
S3_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY_ID }} | ||
# S3 secret access key | ||
S3_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_ACCESS_KEY }} | ||
|
||
## Development environment variables | ||
# The URLs of the Core Engine to which the service should connect | ||
DEV_CORE_ENGINE_URLS: ${{ vars.DEV_CORE_ENGINE_URLS }} | ||
# The URL that the service (dev) should be accessible at | ||
DEV_SERVICE_URL: ${{ vars.DEV_SERVICE_URL }} | ||
# The Kubernetes namespace that the service should be deployed to | ||
DEV_NAMESPACE: ${{ vars.DEV_NAMESPACE }} | ||
# Maximum number of tasks the service can accept | ||
DEV_MAX_TASKS: ${{ vars.DEV_MAX_TASKS }} | ||
# Number of retries on the Engine for announcement | ||
DEV_ENGINE_ANNOUNCE_RETRIES: ${{ vars.DEV_ENGINE_ANNOUNCE_RETRIES }} | ||
# Delay between each retry | ||
DEV_ENGINE_ANNOUNCE_RETRY_DELAY: ${{ vars.DEV_ENGINE_ANNOUNCE_RETRY_DELAY }} | ||
# Logging level | ||
DEV_LOG_LEVEL: ${{ vars.DEV_LOG_LEVEL }} | ||
# Kube configuration | ||
DEV_KUBE_CONFIG: ${{ secrets.DEV_KUBE_CONFIG }} | ||
|
||
## Production environment variables | ||
# The URLs of the Core Engine to which the service should connect | ||
PROD_CORE_ENGINE_URLS: ${{ vars.PROD_CORE_ENGINE_URLS }} | ||
# The URL that the service (dev) should be accessible at | ||
PROD_SERVICE_URL: ${{ vars.PROD_SERVICE_URL }} | ||
# The Kubernetes namespace that the service should be deployed to | ||
PROD_NAMESPACE: ${{ vars.PROD_NAMESPACE }} | ||
# Maximum number of tasks the service can accept | ||
PROD_MAX_TASKS: ${{ vars.PROD_MAX_TASKS }} | ||
# Number of retries on the Engine for announcement | ||
PROD_ENGINE_ANNOUNCE_RETRIES: ${{ vars.PROD_ENGINE_ANNOUNCE_RETRIES }} | ||
# Delay between each retry | ||
PROD_ENGINE_ANNOUNCE_RETRY_DELAY: ${{ vars.PROD_ENGINE_ANNOUNCE_RETRY_DELAY }} | ||
# Logging level | ||
PROD_LOG_LEVEL: ${{ vars.PROD_LOG_LEVEL }} | ||
# Kube configuration | ||
PROD_KUBE_CONFIG: ${{ secrets.PROD_KUBE_CONFIG }} | ||
|
||
# Allow one concurrent deployment | ||
concurrency: | ||
group: github_workflow | ||
cancel-in-progress: true | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
- prod | ||
|
||
pull_request: | ||
|
||
# Allows you to run this workflow manually from the Actions tab | ||
workflow_dispatch: | ||
|
||
jobs: | ||
review: | ||
runs-on: ubuntu-latest | ||
if: ${{ vars.RUN_CICD == 'true' }} | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Lint Python app | ||
uses: swiss-ai-center/common-code/.github/actions/lint-python-app@main | ||
with: | ||
python-app-path: ./model-serving | ||
|
||
train: | ||
needs: review | ||
runs-on: ubuntu-latest | ||
if: ${{ vars.RUN_CICD == 'true' }} | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Run ML experiment with DVC | ||
uses: swiss-ai-center/common-code/.github/actions/run-ml-experiment-with-dvc@main | ||
with: | ||
ml-experiment-path: ./model-creation | ||
s3-access-key-id: ${{ env.S3_ACCESS_KEY_ID }} | ||
s3-secret-access-key: ${{ env.S3_SECRET_ACCESS_KEY }} | ||
|
||
- name: Upload model | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: model | ||
path: ${{ env.MODEL_PATH }} | ||
retention-days: 5 | ||
|
||
test: | ||
needs: train | ||
runs-on: ubuntu-latest | ||
if: ${{ vars.RUN_CICD == 'true' }} | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Download model | ||
uses: actions/download-artifact@v3 | ||
with: | ||
name: model | ||
path: ./model-serving | ||
|
||
- name: Test Python app | ||
uses: swiss-ai-center/common-code/.github/actions/test-python-app@main | ||
with: | ||
python-app-path: ./model-serving | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
release: | ||
needs: test | ||
runs-on: ubuntu-latest | ||
if: ${{ vars.RUN_CICD == 'true' && success() && github.ref == 'refs/heads/main' && (vars.DEPLOY_DEV == 'true' || vars.DEPLOY_PROD == 'true') }} | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Download model | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: model | ||
path: ./model-serving | ||
|
||
- name: Build and push Docker image to GitHub | ||
id: build-and-push-docker-image-to-github | ||
uses: swiss-ai-center/common-code/.github/actions/build-and-push-docker-image-to-github@main | ||
with: | ||
docker-registry-username: ${{ github.actor }} | ||
docker-registry-password: ${{ secrets.GITHUB_TOKEN }} | ||
docker-image-name: ${{ github.repository }} | ||
docker-image-context: ./model-serving | ||
outputs: | ||
docker-image-tags: ${{ steps.build-and-push-docker-image-to-github.outputs.docker-image-tags }} | ||
|
||
deploy-dev: | ||
needs: release | ||
runs-on: ubuntu-latest | ||
if: ${{ vars.RUN_CICD == 'true' && success() && github.ref == 'refs/heads/main' && vars.DEPLOY_DEV == 'true' }} | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Get service Docker image SHA tag | ||
shell: bash | ||
run: | | ||
docker_image_tags=(${{ needs.release.outputs.docker-image-tags }}) | ||
docker_image_sha_tag="${docker_image_tags[1]}" | ||
echo "SERVICE_DOCKER_IMAGE_SHA_TAG=$docker_image_sha_tag" >> "$GITHUB_ENV" | ||
- name: Prepare configuration files | ||
uses: swiss-ai-center/common-code/.github/actions/prepare-kubernetes-configuration-files@main | ||
with: | ||
service-name: ${{ env.SERVICE_NAME }} | ||
service-url: ${{ env.DEV_SERVICE_URL }} | ||
service-docker-image-tag: ${{ env.SERVICE_DOCKER_IMAGE_SHA_TAG }} | ||
configuration-files-location: ./model-serving/kubernetes | ||
environment: development | ||
log-level: ${{ env.DEV_LOG_LEVEL }} | ||
engine-urls: ${{ env.DEV_CORE_ENGINE_URLS }} | ||
max-tasks: ${{ env.DEV_MAX_TASKS }} | ||
engine-announce-retries: ${{ env.DEV_ENGINE_ANNOUNCE_RETRIES }} | ||
engine-announce-retry-delay: ${{ env.DEV_ENGINE_ANNOUNCE_RETRY_DELAY }} | ||
|
||
- name: Remove unnecessary keys from configuration files | ||
uses: swiss-ai-center/common-code/.github/actions/remove-unnecessary-keys-from-kubernetes-configuration-files@main | ||
with: | ||
configuration-files-location: ./kubernetes | ||
|
||
- name: Deploy service on the Kubernetes cluster | ||
uses: swiss-ai-center/common-code/.github/actions/execute-command-on-kubernetes-cluster@main | ||
with: | ||
kube-config: ${{ env.DEV_KUBE_CONFIG }} | ||
kube-namespace: ${{ env.DEV_NAMESPACE }} | ||
kubectl-context: ./model-serving/kubernetes | ||
kubectl-args: | | ||
apply \ | ||
-f config-map.yml \ | ||
-f stateful.yml \ | ||
-f service.yml \ | ||
-f ingress.yml | ||
deploy-prod: | ||
needs: release | ||
runs-on: ubuntu-latest | ||
if: ${{ vars.RUN_CICD == 'true' && success() && github.ref == 'refs/heads/main' && vars.DEPLOY_PROD == 'true' }} | ||
steps: | ||
- name: Clone repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Get service Docker image SHA tag | ||
shell: bash | ||
run: | | ||
docker_image_tags=(${{ needs.release.outputs.docker-image-tags }}) | ||
docker_image_sha_tag="${docker_image_tags[1]}" | ||
echo "SERVICE_DOCKER_IMAGE_SHA_TAG=$docker_image_sha_tag" >> "$GITHUB_ENV" | ||
- name: Prepare configuration files | ||
uses: swiss-ai-center/common-code/.github/actions/prepare-kubernetes-configuration-files@main | ||
with: | ||
service-name: ${{ env.SERVICE_NAME }} | ||
service-url: ${{ env.PROD_SERVICE_URL }} | ||
service-docker-image-tag: ${{ env.SERVICE_DOCKER_IMAGE_SHA_TAG }} | ||
configuration-files-location: ./model-serving/kubernetes | ||
environment: production | ||
log-level: ${{ env.PROD_LOG_LEVEL }} | ||
engine-urls: ${{ env.PROD_CORE_ENGINE_URLS }} | ||
max-tasks: ${{ env.PROD_MAX_TASKS }} | ||
engine-announce-retries: ${{ env.PROD_ENGINE_ANNOUNCE_RETRIES }} | ||
engine-announce-retry-delay: ${{ env.PROD_ENGINE_ANNOUNCE_RETRY_DELAY }} | ||
|
||
- name: Deploy service on the Kubernetes cluster | ||
uses: swiss-ai-center/common-code/.github/actions/execute-command-on-kubernetes-cluster@main | ||
with: | ||
kube-config: ${{ env.PROD_KUBE_CONFIG }} | ||
kube-namespace: ${{ env.PROD_NAMESPACE }} | ||
kubectl-context: ./model-serving/kubernetes | ||
kubectl-args: | | ||
apply \ | ||
-f config-map.yml \ | ||
-f stateful.yml \ | ||
-f service.yml \ | ||
-f ingress.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
## Python | ||
|
||
# Environments | ||
.venv | ||
venv | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
|
||
# Pytest cache | ||
.pytest_cache | ||
|
||
# Pytest Coverage | ||
.coverage | ||
|
||
## IntelliJ's IDEs | ||
|
||
.idea | ||
|
||
## Visual Studio Code | ||
|
||
.vscode | ||
|
||
## macOS | ||
|
||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Create a new service (model from scratch) template | ||
|
||
This repository contains the Python + FastAPI template to create a service with | ||
a model built from scratch compatible with the Core engine. | ||
|
||
Please read the documentation at | ||
<https://docs.swiss-ai-center.ch/how-to-guides/how-to-create-a-new-service> to | ||
understand how to use this template. | ||
|
||
## Guidelines | ||
|
||
TODO: Add instructions on how to edit this template. | ||
|
||
### Publishing and deploying using a CI/CD pipeline | ||
|
||
This is the recommended way to publish and deploy your service if you have | ||
access to GitHub Actions or GitLab CI. | ||
|
||
TODO | ||
|
||
### Publishing and deploying manually | ||
|
||
This is the recommended way to publish and deploy your service if you do not | ||
have access to GitHub Actions or GitLab CI or do not want to use these services. | ||
|
||
TODO | ||
|
||
## Checklist | ||
|
||
These checklists allow you to ensure everything is set up correctly. | ||
|
||
### Common tasks | ||
|
||
- [ ] Rename the project in the [`pyproject.toml`](./pyproject.toml) file | ||
- [x] Add files that must be ignored to the [`.gitignore`](.gitignore) configuration file | ||
- [ ] TODO | ||
|
||
### Publishing and deploying using a CI/CD pipeline | ||
|
||
> [!NOTE] | ||
> This checklist is specific to the _Publishing and deploying using a CI/CD | ||
> pipeline_ section. | ||
- [x] Add the environment variables | ||
- [ ] TODO | ||
|
||
### Publishing and deploying manually | ||
|
||
> [!NOTE] | ||
> This checklist is specific to the _Publishing and deploying manually_ section. | ||
- [x] Edit the [`.env`](.env) configuration file | ||
- [ ] TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# model-creation | ||
|
||
<!-- TODO 1: Update the description of the service and the link to the documentation. --> | ||
_Check the [related documentation](https://docs.swiss-ai-center.ch/reference/core-concepts/service/) for more information._ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Log level | ||
LOG_LEVEL=debug | ||
|
||
# Environment | ||
ENVIRONMENT=development | ||
|
||
# The Core engine URLs | ||
ENGINE_URLS=["http://localhost:8080"] | ||
|
||
# The Service Port | ||
SERVICE_PORT=9090 | ||
|
||
# The Service URL+Port | ||
SERVICE_URL="http://host.docker.internal:${SERVICE_PORT}" | ||
|
||
# The maximum of tasks the service can process | ||
MAX_TASKS=50 | ||
|
||
# The number of times the service tries to announce itself to the engine | ||
ENGINE_ANNOUNCE_RETRIES=5 | ||
|
||
# The number of seconds between each retry | ||
ENGINE_ANNOUNCE_RETRY_DELAY=3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Check parent `.gitignore` file for complete ignored files |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Base image | ||
FROM python:3.11 | ||
|
||
# Install all required packages to run the model | ||
# TODO: 1. Add any additional packages required to run your model | ||
# RUN apt update && apt install --yes package1 package2 ... | ||
|
||
# Work directory | ||
WORKDIR /app | ||
|
||
# Copy requirements file | ||
COPY ./requirements.txt . | ||
COPY ./requirements-all.txt . | ||
|
||
# Install dependencies | ||
RUN pip install --requirement requirements.txt --requirement requirements-all.txt | ||
|
||
# Copy sources | ||
COPY src src | ||
|
||
# Copy model | ||
# TODO: 2. Change the name of the model file to match the name of your model file | ||
COPY mnist_model.h5 . | ||
|
||
# Environment variables | ||
ENV ENVIRONMENT=${ENVIRONMENT} | ||
ENV LOG_LEVEL=${LOG_LEVEL} | ||
ENV ENGINE_URL=${ENGINE_URL} | ||
ENV MAX_TASKS=${MAX_TASKS} | ||
ENV ENGINE_ANNOUNCE_RETRIES=${ENGINE_ANNOUNCE_RETRIES} | ||
ENV ENGINE_ANNOUNCE_RETRY_DELAY=${ENGINE_ANNOUNCE_RETRY_DELAY} | ||
|
||
# Exposed ports | ||
EXPOSE 80 | ||
|
||
# Switch to src directory | ||
WORKDIR "/app/src" | ||
|
||
# Command to run on start | ||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# model-serving | ||
|
||
<!-- TODO 1: Update the description of the service and the link to the documentation. --> | ||
_Check the [related documentation](https://docs.swiss-ai-center.ch/reference/core-concepts/service/) for more information._ |
Oops, something went wrong.