diff --git a/deployment/helm/pathling/Chart.yaml b/deployment/helm/pathling/Chart.yaml
new file mode 100644
index 0000000000..980d38c58d
--- /dev/null
+++ b/deployment/helm/pathling/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v2
+name: pathling
+description: A Helm chart for Pathling Server
+type: application
+version: 1.0.0
diff --git a/deployment/helm/pathling/templates/deployment.yaml b/deployment/helm/pathling/templates/deployment.yaml
new file mode 100644
index 0000000000..66b0ad15f6
--- /dev/null
+++ b/deployment/helm/pathling/templates/deployment.yaml
@@ -0,0 +1,87 @@
+kind: Deployment
+apiVersion: apps/v1
+metadata:
+ name: pathling-deployment
+spec:
+ selector:
+ matchLabels:
+ app: pathling-server
+ template:
+ metadata:
+ labels:
+ app: pathling-server
+ spec:
+ containers:
+ - name: pathling-server
+ image: {{ .Values.pathling.image | quote }}
+ imagePullPolicy: {{ .Values.pathling.deployment.imagePullPolicy }}
+ ports:
+ - containerPort: 8080
+ - containerPort: 8081
+ - containerPort: 4040
+ - containerPort: 7077
+ - containerPort: 7078
+ resources:
+ requests: {{ toJson .Values.pathling.resources.requests }}
+ limits: {{ toJson .Values.pathling.resources.limits }}
+ startupProbe:
+ httpGet:
+ path: /actuator/health/liveness
+ port: 8081
+ periodSeconds: 5
+ failureThreshold: 36
+ livenessProbe:
+ httpGet:
+ path: /actuator/health/liveness
+ port: 8081
+ periodSeconds: 5
+ failureThreshold: 12
+ readinessProbe:
+ httpGet:
+ path: /actuator/health/readiness
+ port: 8081
+ periodSeconds: 5
+ failureThreshold: 3
+ volumeMounts: {{ toJson .Values.pathling.volumeMounts }}
+ {{- if gt (add (len .Values.pathling.config) (len .Values.pathling.secretConfig)) 0 }}
+ env:
+ - name: JAVA_TOOL_OPTIONS
+ value: {{ printf "-Xmx%s %s" .Values.pathling.resources.maxHeapSize .Values.pathling.additionalJavaOptions }}
+ - name: spark.driver.host
+ value: pathling-driver
+ - name: spark.driver.port
+ value: "7077"
+ - name: spark.blockManager.port
+ value: "7078"
+ - name: spark.driver.bindAddress
+ value: 0.0.0.0
+ {{- range $configKey, $configValue := .Values.pathling.config }}
+ - name: {{ $configKey }}
+ value: {{ $configValue | quote }}
+ {{- end }}
+ {{- range $configKey, $configValue := .Values.pathling.secretConfig }}
+ - name: {{ $configKey }}
+ valueFrom:
+ secretKeyRef:
+ name: pathling-secrets
+ key: {{ $configKey }}
+ {{- end }}
+ {{- end }}
+ volumes: {{ toJson .Values.pathling.volumes }}
+ serviceAccountName: {{ .Values.pathling.serviceAccount }}
+ imagePullSecrets: {{ toJson .Values.pathling.imagePullSecrets }}
+ tolerations: {{ toJson .Values.pathling.tolerations }}
+ affinity: {{ toJson .Values.pathling.affinity }}
+ strategy:
+ type: {{ .Values.pathling.deployment.strategy }}
+{{- if gt (len .Values.pathling.secretConfig) 0 }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: pathling-secrets
+data:
+ {{- range $configKey, $configValue := .Values.pathling.secretConfig }}
+ {{ $configKey }}: {{ $configValue | b64enc }}
+ {{- end }}
+{{- end }}
diff --git a/deployment/helm/pathling/templates/role-binding.yaml b/deployment/helm/pathling/templates/role-binding.yaml
new file mode 100644
index 0000000000..b0ab41c73d
--- /dev/null
+++ b/deployment/helm/pathling/templates/role-binding.yaml
@@ -0,0 +1,11 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: spark-role-binding
+subjects:
+ - kind: ServiceAccount
+ name: spark-service-account
+roleRef:
+ kind: Role
+ name: spark-role
+ apiGroup: rbac.authorization.k8s.io
diff --git a/deployment/helm/pathling/templates/role.yaml b/deployment/helm/pathling/templates/role.yaml
new file mode 100644
index 0000000000..e5072dc652
--- /dev/null
+++ b/deployment/helm/pathling/templates/role.yaml
@@ -0,0 +1,14 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: spark-role
+rules:
+ - apiGroups: [""]
+ resources: ["pods", "services", "configmaps"]
+ verbs: ["create", "get", "list", "watch", "delete"]
+ - apiGroups: [""]
+ resources: ["pods/log"]
+ verbs: ["get", "list", "watch"]
+ - apiGroups: [""]
+ resources: ["pods"]
+ verbs: ["watch"]
diff --git a/deployment/helm/pathling/templates/service-account.yaml b/deployment/helm/pathling/templates/service-account.yaml
new file mode 100644
index 0000000000..eec7df016d
--- /dev/null
+++ b/deployment/helm/pathling/templates/service-account.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: spark-service-account
diff --git a/deployment/helm/pathling/templates/service.yaml b/deployment/helm/pathling/templates/service.yaml
new file mode 100644
index 0000000000..0f8bf0a94c
--- /dev/null
+++ b/deployment/helm/pathling/templates/service.yaml
@@ -0,0 +1,52 @@
+kind: Service
+apiVersion: v1
+metadata:
+ name: pathling-fhir
+spec:
+ type: ClusterIP
+ ports:
+ - port: 8080
+ targetPort: 8080
+ selector:
+ app: pathling-server
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: pathling-management
+spec:
+ type: ClusterIP
+ ports:
+ - port: 8081
+ targetPort: 8081
+ selector:
+ app: pathling-server
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: pathling-spark-ui
+spec:
+ type: ClusterIP
+ ports:
+ - port: 4040
+ targetPort: 4040
+ selector:
+ app: pathling-server
+---
+kind: Service
+apiVersion: v1
+metadata:
+ name: pathling-driver
+spec:
+ type: ClusterIP
+ ports:
+ - name: driver
+ port: 7077
+ targetPort: 7077
+ - name: block-manager
+ port: 7078
+ targetPort: 7078
+ selector:
+ app: pathling-server
+ publishNotReadyAddresses: true
diff --git a/deployment/helm/pathling/values.yaml b/deployment/helm/pathling/values.yaml
new file mode 100644
index 0000000000..6d69fb4b56
--- /dev/null
+++ b/deployment/helm/pathling/values.yaml
@@ -0,0 +1,21 @@
+pathling:
+ image: aehrc/pathling:latest
+ resources:
+ requests:
+ cpu: 2
+ memory: 4G
+ limits:
+ memory: 4G
+ maxHeapSize: 2800m
+ additionalJavaOptions: -Duser.timezone=UTC
+ deployment:
+ strategy: Recreate
+ imagePullPolicy: Always
+ volumes: [ ]
+ volumeMounts: [ ]
+ serviceAccount: ~
+ imagePullSecrets: [ ]
+ tolerations: [ ]
+ affinity: ~
+ config: { }
+ secretConfig: { }
diff --git a/fhir-server/pom.xml b/fhir-server/pom.xml
index ad1dbd2d04..ead722907d 100644
--- a/fhir-server/pom.xml
+++ b/fhir-server/pom.xml
@@ -388,8 +388,21 @@
8080
8081
4040
+ 7077
+
+ /usr/bin/entrypoint.sh
+
+
+ src/main/jib
+
+
+ /usr/bin/entrypoint.sh
+ 755
+
+
+
diff --git a/fhir-server/src/main/jib/usr/bin/entrypoint.sh b/fhir-server/src/main/jib/usr/bin/entrypoint.sh
new file mode 100644
index 0000000000..3de424cb6a
--- /dev/null
+++ b/fhir-server/src/main/jib/usr/bin/entrypoint.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+#
+# Copyright 2023 Commonwealth Scientific and Industrial Research
+# Organisation (CSIRO) ABN 41 687 119 230.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Modified from the Kubernetes Docker image entrypoint script:
+# https://github.com/apache/spark/blob/v3.3.2/resource-managers/kubernetes/docker/src/main/dockerfiles/spark/entrypoint.sh
+
+set -xe
+
+case "$1" in
+ # If the command is "executor", run the container as a Kubernetes executor.
+ executor)
+ env | grep SPARK_JAVA_OPT_ | sort -t_ -k4 -n | sed 's/[^=]*=\(.*\)/\1/g' > /tmp/java_opts.txt
+ readarray -t SPARK_EXECUTOR_JAVA_OPTS < /tmp/java_opts.txt
+ CMD=(
+ java
+ "${SPARK_EXECUTOR_JAVA_OPTS[@]}"
+ -Xms$SPARK_EXECUTOR_MEMORY
+ -Xmx$SPARK_EXECUTOR_MEMORY
+ -cp @/app/jib-classpath-file
+ org.apache.spark.scheduler.cluster.k8s.KubernetesExecutorBackend
+ --driver-url $SPARK_DRIVER_URL
+ --executor-id $SPARK_EXECUTOR_ID
+ --cores $SPARK_EXECUTOR_CORES
+ --app-id $SPARK_APPLICATION_ID
+ --hostname $SPARK_EXECUTOR_POD_IP
+ --resourceProfileId $SPARK_RESOURCE_PROFILE_ID
+ --podName $SPARK_EXECUTOR_POD_NAME
+ )
+ ;;
+
+ # If the command is anything else, run the FHIR server.
+ *)
+ CMD=(
+ java
+ -cp @/app/jib-classpath-file
+ au.csiro.pathling.PathlingServer
+ )
+ ;;
+esac
+
+exec "${CMD[@]}"