deployml-core 0.0.59__tar.gz → 0.0.67__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. deployml_core-0.0.67/PKG-INFO +132 -0
  2. deployml_core-0.0.67/README.md +107 -0
  3. {deployml_core-0.0.59 → deployml_core-0.0.67}/pyproject.toml +5 -8
  4. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/api.py +13 -12
  5. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/cli/cli.py +828 -328
  6. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/diagnostics/doctor.py +22 -9
  7. deployml_core-0.0.67/src/deployml/docker/fastapi/main.py +200 -0
  8. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/fastapi/requirements.txt +3 -1
  9. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/grafana-container/Dockerfile +5 -6
  10. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/grafana-container/entrypoint.sh +0 -1
  11. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/mlflow/Dockerfile +1 -1
  12. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/notebook/docker.py +48 -16
  13. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/notebook/stack.py +9 -9
  14. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_run/main.tf.j2 +12 -5
  15. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_run/mlflow_main.tf.j2 +25 -5
  16. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/kubernetes_local/mlflow-deployment.yaml.j2 +35 -4
  17. deployml_core-0.0.67/src/deployml/templates/kubernetes_local/mlflow-pvc.yaml.j2 +12 -0
  18. deployml_core-0.0.67/src/deployml/terraform/modules/bigquery/cloud/gcp/main.tf +60 -0
  19. deployml_core-0.0.67/src/deployml/terraform/modules/bigquery/cloud/gcp/schemas/offline_features.json +12 -0
  20. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/cloud_sql_postgres/main.tf +68 -14
  21. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/cloud_sql_postgres/outputs.tf +28 -8
  22. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/fastapi/cloud/gcp/cloud_run/main.tf +16 -24
  23. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/fastapi/cloud/gcp/cloud_run/variables.tf +7 -1
  24. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_run/main.tf +78 -42
  25. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_run/variables.tf +1 -1
  26. deployml_core-0.0.67/src/deployml/terraform/modules/grafana/cloud/gcp/cloud_run/main.tf +131 -0
  27. deployml_core-0.0.67/src/deployml/terraform/modules/grafana/cloud/gcp/cloud_run/outputs.tf +15 -0
  28. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/grafana/cloud/gcp/cloud_run/variables.tf +7 -1
  29. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/mlflow/cloud/gcp/cloud_run/main.tf +32 -8
  30. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/mlflow/cloud/gcp/cloud_run/variables.tf +28 -1
  31. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/main.tf +15 -13
  32. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/utils/constants.py +14 -0
  33. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/utils/helpers.py +163 -25
  34. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/utils/infracost.py +6 -4
  35. deployml_core-0.0.67/src/deployml/utils/kubernetes_gke.py +569 -0
  36. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/utils/kubernetes_local.py +133 -77
  37. deployml_core-0.0.67/src/deployml/utils/platform_compat.py +193 -0
  38. deployml_core-0.0.59/PKG-INFO +0 -111
  39. deployml_core-0.0.59/README.md +0 -87
  40. deployml_core-0.0.59/src/deployml/docker/fastapi/main.py +0 -127
  41. deployml_core-0.0.59/src/deployml/enum/cloud_provider.py +0 -10
  42. deployml_core-0.0.59/src/deployml/enum/deployment_type.py +0 -13
  43. deployml_core-0.0.59/src/deployml/notebook.py +0 -19
  44. deployml_core-0.0.59/src/deployml/terraform/modules/bigquery/cloud/gcp/main.tf +0 -42
  45. deployml_core-0.0.59/src/deployml/terraform/modules/bigquery/cloud/gcp/schemas/offline_features.json +0 -7
  46. deployml_core-0.0.59/src/deployml/terraform/modules/grafana/cloud/gcp/cloud_run/main.tf +0 -75
  47. deployml_core-0.0.59/src/deployml/terraform/modules/grafana/cloud/gcp/cloud_run/outputs.tf +0 -4
  48. deployml_core-0.0.59/src/deployml/utils/banner.py +0 -22
  49. deployml_core-0.0.59/src/deployml/utils/kubernetes_gke.py +0 -393
  50. deployml_core-0.0.59/src/deployml/utils/menu.py +0 -41
  51. {deployml_core-0.0.59 → deployml_core-0.0.67}/LICENSE +0 -0
  52. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/__init__.py +0 -0
  53. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/cli/__init__.py +0 -0
  54. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/diagnostics/__init__.py +0 -0
  55. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/fastapi/.dockerignore +0 -0
  56. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/fastapi/Dockerfile +0 -0
  57. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/grafana-container/README.md +0 -0
  58. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/docker/mlflow/requirements.txt +0 -0
  59. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/enum/__init__.py +0 -0
  60. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/notebook/__init__.py +0 -0
  61. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/notebook/deployment.py +0 -0
  62. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/notebook/display.py +0 -0
  63. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/notebook/urls.py +0 -0
  64. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_run/base_main.tf.j2 +0 -0
  65. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_run/terraform.tfvars.j2 +0 -0
  66. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_run/variables.tf.j2 +0 -0
  67. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_run/wandb_main.tf.j2 +0 -0
  68. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_vm/main.tf.j2 +0 -0
  69. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_vm/terraform.tfvars.j2 +0 -0
  70. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/gcp/cloud_vm/variables.tf.j2 +0 -0
  71. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/kubernetes_local/deployment.yaml.j2 +0 -0
  72. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/kubernetes_local/mlflow-service.yaml.j2 +0 -0
  73. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/templates/kubernetes_local/service.yaml.j2 +0 -0
  74. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/bigquery/cloud/gcp/outputs.tf +0 -0
  75. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/bigquery/cloud/gcp/schemas/drift_metrics.json +0 -0
  76. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/bigquery/cloud/gcp/schemas/ground_truth.json +0 -0
  77. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/bigquery/cloud/gcp/schemas/predictions.json +0 -0
  78. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/bigquery/cloud/gcp/variables.tf +0 -0
  79. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/cloud_sql_postgres/variables.tf +0 -0
  80. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/cron/cloud/gcp/cloud_run/main.tf +0 -0
  81. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/cron/cloud/gcp/cloud_run/outputs.tf +0 -0
  82. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/cron/cloud/gcp/cloud_run/variables.tf +0 -0
  83. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/explainability_monitoring/cloud/gcp/cloud_run/main.tf +0 -0
  84. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/explainability_monitoring/cloud/gcp/cloud_run/outputs.tf +0 -0
  85. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/explainability_monitoring/cloud/gcp/cloud_run/variables.tf +0 -0
  86. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/fairness_monitoring/cloud/gcp/cloud_run/main.tf +0 -0
  87. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/fairness_monitoring/cloud/gcp/cloud_run/outputs.tf +0 -0
  88. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/fairness_monitoring/cloud/gcp/cloud_run/variables.tf +0 -0
  89. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/fastapi/cloud/gcp/cloud_run/outputs.tf +0 -0
  90. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_run/outputs.tf +0 -0
  91. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_vm/feast_env.tpl +0 -0
  92. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_vm/main.tf +0 -0
  93. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_vm/outputs.tf +0 -0
  94. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/feast/cloud/gcp/cloud_vm/variables.tf +0 -0
  95. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/mlflow/cloud/gcp/cloud_run/outputs.tf +0 -0
  96. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/mlflow/cloud/gcp/cloud_vm/main.tf +0 -0
  97. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/mlflow/cloud/gcp/cloud_vm/variables.tf +0 -0
  98. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/offline_scoring/cloud/gcp/cloud_run/main.tf +0 -0
  99. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/offline_scoring/cloud/gcp/cloud_run/outputs.tf +0 -0
  100. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/offline_scoring/cloud/gcp/cloud_run/variables.tf +0 -0
  101. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/cloud_function/main.py +0 -0
  102. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/cloud_function/requirements.txt +0 -0
  103. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/cloudbuild.yaml +0 -0
  104. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/outputs.tf +0 -0
  105. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/teardown_script.sh +0 -0
  106. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/teardown/cloud/gcp/variables.tf +0 -0
  107. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/wandb/cloud/gcp/cloud_run/main.tf +0 -0
  108. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/wandb/cloud/gcp/cloud_run/outputs.tf +0 -0
  109. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/wandb/cloud/gcp/cloud_run/variables.tf +0 -0
  110. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/wandb/cloud/gcp/cloud_vm/main.tf +0 -0
  111. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/terraform/modules/wandb/cloud/gcp/cloud_vm/variables.tf +0 -0
  112. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/utils/__init__.py +0 -0
  113. {deployml_core-0.0.59 → deployml_core-0.0.67}/src/deployml/utils/teardown.py +0 -0
@@ -0,0 +1,132 @@
1
+ Metadata-Version: 2.4
2
+ Name: deployml-core
3
+ Version: 0.0.67
4
+ Summary: Infra for academia
5
+ License-File: LICENSE
6
+ Author: Drew Hoang
7
+ Author-email: codentell@gmail.com
8
+ Requires-Python: >=3.11
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Dist: google-cloud-storage (>=3.1.1,<4.0.0)
15
+ Requires-Dist: ipython (>=9.0.0)
16
+ Requires-Dist: jinja2
17
+ Requires-Dist: jupyter (>=1.0.0)
18
+ Requires-Dist: pandas (>=2.2.1)
19
+ Requires-Dist: pyyaml
20
+ Requires-Dist: requests (>=2.28.0)
21
+ Requires-Dist: rich
22
+ Requires-Dist: typer
23
+ Description-Content-Type: text/markdown
24
+
25
+ # deployml
26
+
27
+ A CLI tool that deploys a production MLOps stack on GCP with a single command. Built for academic ML courses so students can focus on building models, not infrastructure.
28
+
29
+ ## What you get
30
+
31
+ - **MLflow** — experiment tracking, artifact storage, and model registry (backed by Cloud SQL Postgres + GCS)
32
+ - **FastAPI** — model serving endpoint that loads the latest registered model from MLflow automatically
33
+ - **Grafana** — monitoring dashboard connected to your metrics database
34
+ - **BigQuery** — `mlops` dataset with tables for features, predictions, ground truth, and drift metrics
35
+
36
+ All running on GCP Cloud Run. No servers to manage. Cloud Run services scale to zero when idle. Cloud SQL and BigQuery storage incur baseline cost. See Costs below.
37
+
38
+ ## Quick Start
39
+
40
+ **1. Install**
41
+
42
+ ```bash
43
+ pip install deployml-core
44
+ ```
45
+
46
+ **2. Initialize your GCP project** (enables APIs, creates Artifact Registry)
47
+
48
+ ```bash
49
+ deployml init --provider gcp --project-id YOUR_GCP_PROJECT_ID
50
+ ```
51
+
52
+ **3. Configure**
53
+
54
+ ```bash
55
+ cp config.example.yaml config.yaml
56
+ # Edit config.yaml and set your project_id
57
+ ```
58
+
59
+ **4. Build images**
60
+
61
+ ```bash
62
+ deployml build-images --create-repo
63
+ ```
64
+
65
+ **5. Deploy**
66
+
67
+ ```bash
68
+ deployml deploy --verbose
69
+ ```
70
+
71
+ First deploy takes ~20 minutes (Cloud SQL provisioning). Subsequent deploys are 1–2 minutes.
72
+
73
+ **6. Get your URLs**
74
+
75
+ ```bash
76
+ deployml get-urls
77
+ ```
78
+
79
+ Prints service URLs and writes a `.env` file with `MLFLOW_URL`, `FASTAPI_URL`, `GRAFANA_URL`, `BIGQUERY_PROJECT`, and `BIGQUERY_DATASET`.
80
+
81
+ ## End-to-End Example
82
+
83
+ Once deployed, the `example/` directory walks through a complete MLOps workflow using a synthetic housing price dataset:
84
+
85
+ ```bash
86
+ pip install mlflow scikit-learn pandas numpy google-cloud-bigquery db-dtypes python-dotenv requests
87
+
88
+ python example/scripts/01_load_training_data.py # load 500 rows into BigQuery
89
+ python example/scripts/02_train_model.py # train RandomForest, log to MLflow
90
+ python example/scripts/03_register_model.py # register model as Production
91
+ python example/scripts/04_make_predictions.py # serve 50 predictions via FastAPI
92
+ python example/scripts/05_generate_ground_truth.py # simulate actual outcomes
93
+ python example/scripts/06_compute_drift_metrics.py # compute feature drift + MAE
94
+ python example/scripts/07_setup_grafana.py # provision monitoring dashboard
95
+ ```
96
+
97
+ See [example/README.md](example/README.md) for details.
98
+
99
+ ## Teardown
100
+
101
+ ```bash
102
+ deployml destroy
103
+ ```
104
+
105
+ Deletes all Cloud Run services, Cloud SQL, the GCS bucket, and the BigQuery dataset, and also removes the Artifact Registry repo and the Cloud Build staging bucket that `build-images` created, so a destroyed project leaves no billing residue. Pass `--keep-images` if other workspaces in the same project share those images. Does not delete the GCP project itself.
106
+
107
+ ## Full Tutorial
108
+
109
+ See [docs/tutorials/gcp-cloud-run.md](docs/tutorials/gcp-cloud-run.md) for a step-by-step walkthrough.
110
+
111
+ ## Other deployment targets
112
+
113
+ Cloud Run is the primary, fully supported path. The CLI also supports Kubernetes for users who want a cluster:
114
+
115
+ - **Local minikube**, for testing without GCP: `mlflow-init` and `mlflow-deploy`, or `minikube-init` and `minikube-deploy`.
116
+ - **GKE** on GCP: `gke-cluster-create`, `gke-init`, then `gke-deploy` or `gke-apply`, torn down with `gke-destroy`.
117
+
118
+ MLflow keeps its data on a PersistentVolumeClaim in both, so experiments survive pod restarts. See [CLI Commands](docs/api/cli-commands.md) and the [GKE flow notes](docs/tutorials/gcp-cloud-run.md#gke-flow-notes).
119
+
120
+ ## Requirements
121
+
122
+ - Python 3.11 or newer
123
+ - `gcloud` CLI, authenticated with `gcloud auth login`, `gcloud auth application-default login`, and `gcloud auth configure-docker us-west1-docker.pkg.dev`
124
+ - Docker, running
125
+ - Terraform 1.0 or newer
126
+
127
+ Run `deployml doctor --project-id YOUR_GCP_PROJECT_ID` to verify auth, ADC, tool versions, enabled APIs, and IAM roles on your project.
128
+
129
+ ## Costs
130
+
131
+ Cloud Run scales to zero when idle. Cloud SQL Postgres and BigQuery storage do not. Expect roughly $30 to $80 per month while the stack is up. MLflow runs with `min_instances = 1` by default for snappy UI, which adds about $5 per month. Set `min_instances` to 0 if you want zero idle cost in exchange for cold starts. Always run `deployml destroy` when done.
132
+
@@ -0,0 +1,107 @@
1
+ # deployml
2
+
3
+ A CLI tool that deploys a production MLOps stack on GCP with a single command. Built for academic ML courses so students can focus on building models, not infrastructure.
4
+
5
+ ## What you get
6
+
7
+ - **MLflow** — experiment tracking, artifact storage, and model registry (backed by Cloud SQL Postgres + GCS)
8
+ - **FastAPI** — model serving endpoint that loads the latest registered model from MLflow automatically
9
+ - **Grafana** — monitoring dashboard connected to your metrics database
10
+ - **BigQuery** — `mlops` dataset with tables for features, predictions, ground truth, and drift metrics
11
+
12
+ All running on GCP Cloud Run. No servers to manage. Cloud Run services scale to zero when idle. Cloud SQL and BigQuery storage incur baseline cost. See Costs below.
13
+
14
+ ## Quick Start
15
+
16
+ **1. Install**
17
+
18
+ ```bash
19
+ pip install deployml-core
20
+ ```
21
+
22
+ **2. Initialize your GCP project** (enables APIs, creates Artifact Registry)
23
+
24
+ ```bash
25
+ deployml init --provider gcp --project-id YOUR_GCP_PROJECT_ID
26
+ ```
27
+
28
+ **3. Configure**
29
+
30
+ ```bash
31
+ cp config.example.yaml config.yaml
32
+ # Edit config.yaml and set your project_id
33
+ ```
34
+
35
+ **4. Build images**
36
+
37
+ ```bash
38
+ deployml build-images --create-repo
39
+ ```
40
+
41
+ **5. Deploy**
42
+
43
+ ```bash
44
+ deployml deploy --verbose
45
+ ```
46
+
47
+ First deploy takes ~20 minutes (Cloud SQL provisioning). Subsequent deploys are 1–2 minutes.
48
+
49
+ **6. Get your URLs**
50
+
51
+ ```bash
52
+ deployml get-urls
53
+ ```
54
+
55
+ Prints service URLs and writes a `.env` file with `MLFLOW_URL`, `FASTAPI_URL`, `GRAFANA_URL`, `BIGQUERY_PROJECT`, and `BIGQUERY_DATASET`.
56
+
57
+ ## End-to-End Example
58
+
59
+ Once deployed, the `example/` directory walks through a complete MLOps workflow using a synthetic housing price dataset:
60
+
61
+ ```bash
62
+ pip install mlflow scikit-learn pandas numpy google-cloud-bigquery db-dtypes python-dotenv requests
63
+
64
+ python example/scripts/01_load_training_data.py # load 500 rows into BigQuery
65
+ python example/scripts/02_train_model.py # train RandomForest, log to MLflow
66
+ python example/scripts/03_register_model.py # register model as Production
67
+ python example/scripts/04_make_predictions.py # serve 50 predictions via FastAPI
68
+ python example/scripts/05_generate_ground_truth.py # simulate actual outcomes
69
+ python example/scripts/06_compute_drift_metrics.py # compute feature drift + MAE
70
+ python example/scripts/07_setup_grafana.py # provision monitoring dashboard
71
+ ```
72
+
73
+ See [example/README.md](example/README.md) for details.
74
+
75
+ ## Teardown
76
+
77
+ ```bash
78
+ deployml destroy
79
+ ```
80
+
81
+ Deletes all Cloud Run services, Cloud SQL, the GCS bucket, and the BigQuery dataset, and also removes the Artifact Registry repo and the Cloud Build staging bucket that `build-images` created, so a destroyed project leaves no billing residue. Pass `--keep-images` if other workspaces in the same project share those images. Does not delete the GCP project itself.
82
+
83
+ ## Full Tutorial
84
+
85
+ See [docs/tutorials/gcp-cloud-run.md](docs/tutorials/gcp-cloud-run.md) for a step-by-step walkthrough.
86
+
87
+ ## Other deployment targets
88
+
89
+ Cloud Run is the primary, fully supported path. The CLI also supports Kubernetes for users who want a cluster:
90
+
91
+ - **Local minikube**, for testing without GCP: `mlflow-init` and `mlflow-deploy`, or `minikube-init` and `minikube-deploy`.
92
+ - **GKE** on GCP: `gke-cluster-create`, `gke-init`, then `gke-deploy` or `gke-apply`, torn down with `gke-destroy`.
93
+
94
+ MLflow keeps its data on a PersistentVolumeClaim in both, so experiments survive pod restarts. See [CLI Commands](docs/api/cli-commands.md) and the [GKE flow notes](docs/tutorials/gcp-cloud-run.md#gke-flow-notes).
95
+
96
+ ## Requirements
97
+
98
+ - Python 3.11 or newer
99
+ - `gcloud` CLI, authenticated with `gcloud auth login`, `gcloud auth application-default login`, and `gcloud auth configure-docker us-west1-docker.pkg.dev`
100
+ - Docker, running
101
+ - Terraform 1.0 or newer
102
+
103
+ Run `deployml doctor --project-id YOUR_GCP_PROJECT_ID` to verify auth, ADC, tool versions, enabled APIs, and IAM roles on your project.
104
+
105
+ ## Costs
106
+
107
+ Cloud Run scales to zero when idle. Cloud SQL Postgres and BigQuery storage do not. Expect roughly $30 to $80 per month while the stack is up. MLflow runs with `min_instances = 1` by default for snappy UI, which adds about $5 per month. Set `min_instances` to 0 if you want zero idle cost in exchange for cold starts. Always run `deployml destroy` when done.
@@ -1,7 +1,7 @@
1
1
 
2
2
  [project]
3
3
  name = "deployml-core"
4
- version = "0.0.59"
4
+ version = "0.0.67"
5
5
  description = "Infra for academia"
6
6
  authors = [
7
7
  {name = "Drew Hoang", email = "codentell@gmail.com"},
@@ -29,13 +29,10 @@ deployml = "deployml.cli.cli:main"
29
29
 
30
30
  [tool.poetry]
31
31
  packages = [{include = "deployml", from = "src"}]
32
-
33
- [tool.setuptools]
34
- include-package-data = true
35
-
36
- [tool.setuptools.package-data]
37
- mlops_infra = [
38
- "docker/**"
32
+ include = [
33
+ { path = "src/deployml/docker/**/*", format = ["sdist", "wheel"] },
34
+ { path = "src/deployml/templates/**/*", format = ["sdist", "wheel"] },
35
+ { path = "src/deployml/terraform/**/*", format = ["sdist", "wheel"] }
39
36
  ]
40
37
 
41
38
  [build-system]
@@ -29,11 +29,11 @@ Example usage:
29
29
  )
30
30
  """
31
31
  import json
32
- import subprocess
33
32
  from pathlib import Path
34
33
  from datetime import datetime, timedelta, timezone
35
34
  from typing import Optional, Dict, Any
36
35
 
36
+ from .utils.platform_compat import run_tool
37
37
  from .utils.teardown import (
38
38
  calculate_cron_from_timestamp,
39
39
  load_deployment_metadata,
@@ -68,9 +68,9 @@ def get_teardown_status(
68
68
  """
69
69
  scheduler_job_name = f"deployml-teardown-{workspace_name}"
70
70
 
71
- result = subprocess.run(
72
- ["gcloud", "scheduler", "jobs", "describe", scheduler_job_name,
73
- "--project", project_id, "--location", region, "--format", "json"],
71
+ result = run_tool(
72
+ "gcloud", ["scheduler", "jobs", "describe", scheduler_job_name,
73
+ "--project", project_id, "--location", region, "--format", "json"],
74
74
  capture_output=True,
75
75
  text=True,
76
76
  )
@@ -141,9 +141,9 @@ def update_teardown_schedule(
141
141
  scheduler_job_name = f"deployml-teardown-{workspace_name}"
142
142
 
143
143
  # Check if job exists and get current timezone
144
- result = subprocess.run(
145
- ["gcloud", "scheduler", "jobs", "describe", scheduler_job_name,
146
- "--project", project_id, "--location", region, "--format", "json"],
144
+ result = run_tool(
145
+ "gcloud", ["scheduler", "jobs", "describe", scheduler_job_name,
146
+ "--project", project_id, "--location", region, "--format", "json"],
147
147
  capture_output=True,
148
148
  text=True,
149
149
  )
@@ -168,9 +168,10 @@ def update_teardown_schedule(
168
168
  new_cron_schedule = calculate_cron_from_timestamp(teardown_scheduled_timestamp)
169
169
 
170
170
  # Update Cloud Scheduler job
171
- update_result = subprocess.run(
171
+ update_result = run_tool(
172
+ "gcloud",
172
173
  [
173
- "gcloud", "scheduler", "jobs", "update", "http", scheduler_job_name,
174
+ "scheduler", "jobs", "update", "http", scheduler_job_name,
174
175
  "--location", region,
175
176
  "--schedule", new_cron_schedule,
176
177
  "--time-zone", time_zone,
@@ -231,9 +232,9 @@ def cancel_teardown(
231
232
  """
232
233
  scheduler_job_name = f"deployml-teardown-{workspace_name}"
233
234
 
234
- result = subprocess.run(
235
- ["gcloud", "scheduler", "jobs", "delete", scheduler_job_name,
236
- "--project", project_id, "--location", region, "--quiet"],
235
+ result = run_tool(
236
+ "gcloud", ["scheduler", "jobs", "delete", scheduler_job_name,
237
+ "--project", project_id, "--location", region, "--quiet"],
237
238
  capture_output=True,
238
239
  text=True,
239
240
  )