Skip to content

Commit 1e23213

Browse files
feat(cogstack-cohorter): Add helm chart for cogstack-cohorter (#75)
* feat(cogstack-cohorter): Add helm chart for cogstack-cohorter * feat(cogstack-cohorter): Update helm chart files * feat(cogstack-cohorter): Add step to add Ollama Helm repo charts build workflow since it is not available via OCI * feat(cogstack-cohorter): Address code review feedback * feat(cogstack-cohorter): New line required at the end of ci-values.yaml file * feat(cogstack-cohorter): Stub data for CI build * feat(cogstack-cohorter): Fix lint errors * feat(cogstack-cohorter): Remove helm repo step from k8s chart build pipeline
1 parent 31c5cfe commit 1e23213

21 files changed

Lines changed: 1227 additions & 1 deletion

.github/linters/ct.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ chart-dirs:
66
helm-extra-args: --timeout 1000s
77
chart-repos:
88
- opensearch=https://opensearch-project.github.io/helm-charts
9+
- ollama=https://otwld.github.io/ollama-helm

.github/workflows/kubernetes-charts-build.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ jobs:
3030
- name: Set up Helm
3131
uses: azure/setup-helm@v4.3.1
3232

33-
- uses: actions/setup-python@v6.0.0
33+
- name: Set up Python
34+
uses: actions/setup-python@v6.0.0
3435
with:
3536
python-version: "3.x"
3637
check-latest: true
@@ -131,6 +132,7 @@ jobs:
131132
helm package ./medcat-service-helm --version ${{ steps.version.outputs.chart_version }}
132133
helm package ./medcat-trainer-helm --version ${{ steps.version.outputs.chart_version }} --dependency-update
133134
helm package ./cogstack-ce-helm --version ${{ steps.version.outputs.chart_version }} --dependency-update
135+
helm package ./cogstack-cohorter-helm --version ${{ steps.version.outputs.chart_version }} --dependency-update
134136
helm package ./cogstack-observability-helm --version ${{ steps.version.outputs.chart_version }} --dependency-update
135137
136138
- name: Helm OCI login to Docker Hub
@@ -141,6 +143,7 @@ jobs:
141143
helm push ./medcat-service-helm-${{ steps.version.outputs.chart_version }}.tgz oci://registry-1.docker.io/cogstacksystems
142144
helm push ./medcat-trainer-helm-${{ steps.version.outputs.chart_version }}.tgz oci://registry-1.docker.io/cogstacksystems
143145
helm push ./cogstack-ce-helm-${{ steps.version.outputs.chart_version }}.tgz oci://registry-1.docker.io/cogstacksystems
146+
helm push ./cogstack-cohorter-helm-${{ steps.version.outputs.chart_version }}.tgz oci://registry-1.docker.io/cogstacksystems
144147
helm push ./cogstack-observability-helm-${{ steps.version.outputs.chart_version }}.tgz oci://registry-1.docker.io/cogstacksystems
145148
146149
- name: Release
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Patterns to ignore when building packages.
2+
# This supports shell glob matching, relative path matching, and
3+
# negation (prefixed with !). Only one pattern per line.
4+
.DS_Store
5+
# Common VCS dirs
6+
.git/
7+
.gitignore
8+
.bzr/
9+
.bzrignore
10+
.hg/
11+
.hgignore
12+
.svn/
13+
# Common backup files
14+
*.swp
15+
*.bak
16+
*.tmp
17+
*.orig
18+
*~
19+
# Various IDEs
20+
.project
21+
.idea/
22+
*.tmproj
23+
.vscode/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
dependencies:
2+
- name: medcat-service-helm
3+
repository: oci://registry-1.docker.io/cogstacksystems
4+
version: 0.0.1
5+
- name: ollama
6+
repository: https://otwld.github.io/ollama-helm/
7+
version: 1.54.0
8+
digest: sha256:c19deffe7da9495af6f74b6a6bb26157bf7faf6abac6be8fc94638deff3bc6d3
9+
generated: "2026-04-16T14:51:41.6563526+01:00"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
apiVersion: v2
2+
name: cogstack-cohorter-helm
3+
description: CogStack Cohorter — cohort identification powered by Ollama and MedCAT
4+
type: application
5+
version: 0.0.1
6+
appVersion: "latest"
7+
8+
maintainers:
9+
- name: jocelyneholdbrook
10+
email: jocelyne@cogstack.org
11+
12+
icon: "https://avatars.githubusercontent.com/u/28688163"
13+
14+
dependencies:
15+
# MedCAT annotation service
16+
- name: medcat-service-helm
17+
version: "0.0.1"
18+
repository: "oci://registry-1.docker.io/cogstacksystems"
19+
alias: medcat
20+
condition: medcat.enabled
21+
22+
# Ollama LLM serving — https://github.com/otwld/ollama-helm
23+
- name: ollama
24+
version: ">=0.1.0"
25+
repository: "https://otwld.github.io/ollama-helm/"
26+
alias: ollama
27+
condition: ollama.enabled
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# CogStack Cohorter Helm Chart
2+
3+
CogStack Cohorter — cohort identification powered by Ollama and MedCAT
4+
5+
## Architecture
6+
7+
| Component | Image | Description |
8+
|-----------|-------|-------------|
9+
| **WebApp** | `cogstacksystems/cogstack-cohorter-webapp` | React + Node.js frontend and API |
10+
| **NL2DSL** | `cogstacksystems/cogstack-cohorter-nl2dsl` | Natural language → cohort DSL compiler |
11+
| **MedCAT** | `cogstacksystems/medcat-service` | Clinical NER and concept normalisation (subchart) |
12+
| **Ollama** | `ollama/ollama` | LLM serving backend (subchart) |
13+
14+
MedCAT and Ollama are deployed as **subcharts**:
15+
- MedCAT: [`cogstacksystems/medcat-service-helm`](https://hub.docker.com/r/cogstacksystems/medcat-service-helm) (OCI)
16+
- Ollama: [`otwld/ollama`](https://github.com/otwld/ollama-helm)
17+
18+
## Prerequisites
19+
20+
- Kubernetes 1.21+
21+
- Helm 3.10+
22+
- Sufficient node resources for the Ollama model (the default `gpt-oss:20b` requires ~14 GB of memory/VRAM)
23+
24+
## Installation
25+
26+
From Docker Hub OCI (published chart):
27+
28+
```bash
29+
helm install cogstack-cohorter oci://registry-1.docker.io/cogstacksystems/cogstack-cohorter-helm
30+
```
31+
32+
## Configuration
33+
34+
All configurable values are in [`values.yaml`](./values.yaml). Key sections:
35+
36+
### Ollama
37+
38+
```yaml
39+
ollama:
40+
enabled: true
41+
ollama:
42+
models:
43+
pull:
44+
- gpt-oss:20b # pulled automatically on first startup
45+
persistentVolume:
46+
enabled: true
47+
size: 10Gi
48+
```
49+
50+
Models are pulled automatically by the otwld subchart's built-in init container. Change `ollama.ollama.models.pull` to use a different model — make sure `nl2dsl.env.OLLAMA_MODEL` matches.
51+
52+
### MedCAT
53+
54+
```yaml
55+
medcat:
56+
enabled: true
57+
env:
58+
APP_MEDCAT_MODEL_PACK: "/cat/models/examples/example-medcat-v2-model-pack.zip"
59+
```
60+
61+
To use a custom model pack, provide a download URL:
62+
63+
```yaml
64+
medcat:
65+
model:
66+
downloadUrl: "https://your-host/medcat_model_pack.zip"
67+
name: "medcat_model_pack.zip"
68+
```
69+
70+
### WebApp data volume
71+
72+
The WebApp requires a SNOMED data directory mounted at `/usr/src/app/server/data`. A PVC is provisioned automatically:
73+
74+
```yaml
75+
webapp:
76+
persistence:
77+
enabled: true
78+
size: 5Gi
79+
```
80+
81+
Populate the PVC with either:
82+
- `snomed_terms_data.tar.gz` — auto-extracted by the entrypoint on first startup, or
83+
- Pre-extracted files: `snomed_terms.json`, `cui_pt2ch.json`, and patient data files
84+
85+
To generate synthetic patient data on first startup (demo mode):
86+
87+
```yaml
88+
webapp:
89+
env:
90+
RANDOM_DATA: "true"
91+
```
92+
93+
### Ingress
94+
95+
```yaml
96+
ingress:
97+
enabled: true
98+
className: nginx
99+
hosts:
100+
- host: cohorter.example.com
101+
paths:
102+
- path: /
103+
pathType: ImplementationSpecific
104+
tls:
105+
- secretName: cohorter-tls
106+
hosts:
107+
- cohorter.example.com
108+
```
109+
110+
### Autoscaling (webapp only)
111+
112+
```yaml
113+
autoscaling:
114+
enabled: true
115+
minReplicas: 1
116+
maxReplicas: 3
117+
targetCPUUtilizationPercentage: 80
118+
```
119+
120+
## Uninstallation
121+
122+
```bash
123+
helm uninstall cogstack-cohorter
124+
```
125+
126+
## Support
127+
128+
For issues and questions, please visit the [CogStack GitHub repository](https://github.com/CogStack/cogstack-platform).
129+
130+
## Requirements
131+
132+
| Repository | Name | Version |
133+
|------------|------|---------|
134+
| https://otwld.github.io/ollama-helm/ | ollama(ollama) | >=0.1.0 |
135+
| oci://registry-1.docker.io/cogstacksystems | medcat(medcat-service-helm) | 0.0.1 |
136+
137+
## Values
138+
139+
| Key | Type | Default | Description |
140+
|-----|------|---------|-------------|
141+
| autoscaling.enabled | bool | `false` | |
142+
| autoscaling.maxReplicas | int | `3` | |
143+
| autoscaling.minReplicas | int | `1` | |
144+
| autoscaling.targetCPUUtilizationPercentage | int | `80` | |
145+
| fullnameOverride | string | `""` | |
146+
| global.imagePullSecrets | list | `[]` | |
147+
| ingress.annotations | object | `{}` | |
148+
| ingress.className | string | `""` | |
149+
| ingress.enabled | bool | `false` | |
150+
| ingress.hosts[0].host | string | `"cogstack-cohort.local"` | |
151+
| ingress.hosts[0].paths[0].path | string | `"/"` | |
152+
| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | |
153+
| ingress.tls | list | `[]` | |
154+
| medcat.enabled | bool | `true` | |
155+
| medcat.env.APP_ENABLE_METRICS | string | `"true"` | |
156+
| medcat.env.APP_MEDCAT_MODEL_PACK | string | `"/cat/models/examples/example-medcat-v2-model-pack.zip"` | |
157+
| medcat.image.tag | string | `"latest"` | |
158+
| medcat.resources | object | `{}` | |
159+
| medcat.service.port | int | `5000` | |
160+
| nameOverride | string | `""` | |
161+
| nl2dsl.affinity | object | `{}` | |
162+
| nl2dsl.enabled | bool | `true` | |
163+
| nl2dsl.env.ALLOW_ORIGINS | string | `"*"` | |
164+
| nl2dsl.env.OLLAMA_MODEL | string | `"gpt-oss:20b"` | |
165+
| nl2dsl.image.pullPolicy | string | `"IfNotPresent"` | |
166+
| nl2dsl.image.repository | string | `"cogstacksystems/cogstack-cohorter-nl2dsl"` | |
167+
| nl2dsl.image.tag | string | `"latest"` | |
168+
| nl2dsl.livenessProbe.httpGet.path | string | `"/"` | |
169+
| nl2dsl.livenessProbe.httpGet.port | string | `"http"` | |
170+
| nl2dsl.livenessProbe.initialDelaySeconds | int | `30` | |
171+
| nl2dsl.livenessProbe.periodSeconds | int | `10` | |
172+
| nl2dsl.nodeSelector | object | `{}` | |
173+
| nl2dsl.readinessProbe.httpGet.path | string | `"/"` | |
174+
| nl2dsl.readinessProbe.httpGet.port | string | `"http"` | |
175+
| nl2dsl.readinessProbe.initialDelaySeconds | int | `10` | |
176+
| nl2dsl.readinessProbe.periodSeconds | int | `5` | |
177+
| nl2dsl.replicaCount | int | `1` | |
178+
| nl2dsl.resources | object | `{}` | |
179+
| nl2dsl.service.port | int | `3002` | |
180+
| nl2dsl.service.type | string | `"ClusterIP"` | |
181+
| nl2dsl.tolerations | list | `[]` | |
182+
| ollama.enabled | bool | `true` | |
183+
| ollama.ollama.models.pull[0] | string | `"gpt-oss:20b"` | |
184+
| ollama.persistentVolume.enabled | bool | `true` | |
185+
| ollama.persistentVolume.size | string | `"10Gi"` | |
186+
| ollama.persistentVolume.storageClass | string | `""` | |
187+
| ollama.resources | object | `{}` | |
188+
| ollama.service.port | int | `11434` | |
189+
| ollama.service.type | string | `"ClusterIP"` | |
190+
| podAnnotations | object | `{}` | |
191+
| podLabels | object | `{}` | |
192+
| podSecurityContext | object | `{}` | |
193+
| securityContext | object | `{}` | |
194+
| serviceAccount.annotations | object | `{}` | |
195+
| serviceAccount.automount | bool | `true` | |
196+
| serviceAccount.create | bool | `true` | |
197+
| serviceAccount.name | string | `""` | |
198+
| webapp.affinity | object | `{}` | |
199+
| webapp.enabled | bool | `true` | |
200+
| webapp.env.RANDOM_DATA | string | `"false"` | |
201+
| webapp.image.pullPolicy | string | `"IfNotPresent"` | |
202+
| webapp.image.repository | string | `"cogstacksystems/cogstack-cohorter-webapp"` | |
203+
| webapp.image.tag | string | `"latest"` | |
204+
| webapp.livenessProbe.httpGet.path | string | `"/"` | |
205+
| webapp.livenessProbe.httpGet.port | string | `"http"` | |
206+
| webapp.livenessProbe.initialDelaySeconds | int | `60` | |
207+
| webapp.livenessProbe.periodSeconds | int | `15` | |
208+
| webapp.nodeSelector | object | `{}` | |
209+
| webapp.persistence.accessMode | string | `"ReadWriteOnce"` | |
210+
| webapp.persistence.enabled | bool | `true` | |
211+
| webapp.persistence.existingClaim | string | `""` | |
212+
| webapp.persistence.size | string | `"5Gi"` | |
213+
| webapp.persistence.storageClass | string | `""` | |
214+
| webapp.readinessProbe.httpGet.path | string | `"/"` | |
215+
| webapp.readinessProbe.httpGet.port | string | `"http"` | |
216+
| webapp.readinessProbe.initialDelaySeconds | int | `30` | |
217+
| webapp.readinessProbe.periodSeconds | int | `10` | |
218+
| webapp.replicaCount | int | `1` | |
219+
| webapp.resources | object | `{}` | |
220+
| webapp.service.port | int | `3000` | |
221+
| webapp.service.type | string | `"ClusterIP"` | |
222+
| webapp.tolerations | list | `[]` | |
223+
224+
----------------------------------------------
225+
Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2)

0 commit comments

Comments
 (0)