From cc89ce1e797b5bdcce8743e6ee932f8562273b0a Mon Sep 17 00:00:00 2001 From: Sugat Bajracharya Date: Wed, 24 Sep 2025 21:15:07 +0545 Subject: [PATCH 1/5] feat(#171): add kubernetes manifest files for deployment --- kubernetes/01-namespace.yaml | 6 + kubernetes/02-configmap.yaml | 20 ++ kubernetes/03-secrets.yaml | 41 ++++ kubernetes/04-persistent-volumes.yaml | 59 +++++ kubernetes/05-databases.yaml | 166 ++++++++++++++ kubernetes/06-openhim-core.yaml | 109 +++++++++ kubernetes/07-openhim-console.yaml | 72 ++++++ kubernetes/08-hapi-fhir.yaml | 85 +++++++ kubernetes/09-cht-services.yaml | 311 ++++++++++++++++++++++++++ kubernetes/10-mediator-services.yaml | 172 ++++++++++++++ start_local_kubernetes.sh | 41 ++++ 11 files changed, 1082 insertions(+) create mode 100644 kubernetes/01-namespace.yaml create mode 100644 kubernetes/02-configmap.yaml create mode 100644 kubernetes/03-secrets.yaml create mode 100644 kubernetes/04-persistent-volumes.yaml create mode 100644 kubernetes/05-databases.yaml create mode 100644 kubernetes/06-openhim-core.yaml create mode 100644 kubernetes/07-openhim-console.yaml create mode 100644 kubernetes/08-hapi-fhir.yaml create mode 100644 kubernetes/09-cht-services.yaml create mode 100644 kubernetes/10-mediator-services.yaml create mode 100755 start_local_kubernetes.sh diff --git a/kubernetes/01-namespace.yaml b/kubernetes/01-namespace.yaml new file mode 100644 index 00000000..8e9ba267 --- /dev/null +++ b/kubernetes/01-namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: health-interop + labels: + name: health-interop diff --git a/kubernetes/02-configmap.yaml b/kubernetes/02-configmap.yaml new file mode 100644 index 00000000..9a5e8296 --- /dev/null +++ b/kubernetes/02-configmap.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: openhim-console-config + namespace: health-interop +data: + default.json: | + { + "version": "1.10.0", + "minimumCoreVersion": "3.4.0", + "protocol": "https", + "host": "localhost", + "port": 8080, + "title": "Admin Console", + "footerTitle": "OpenHIM Administration Console", + "footerPoweredBy": "Powered by OpenHIM", + "loginBanner": "", + "mediatorLastHeartbeatWarningSeconds": 60, + "mediatorLastHeartbeatDangerSeconds": 120 + } diff --git a/kubernetes/03-secrets.yaml b/kubernetes/03-secrets.yaml new file mode 100644 index 00000000..c52c2a72 --- /dev/null +++ b/kubernetes/03-secrets.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Secret +metadata: + name: database-credentials + namespace: health-interop +type: Opaque +stringData: + couchdb-user: "admin" + couchdb-password: "password" + couchdb-secret: "secret" + postgres-user: "admin" + postgres-password: "instant101" + postgres-db: "hapi" +--- +apiVersion: v1 +kind: Secret +metadata: + name: openhim-credentials + namespace: health-interop +type: Opaque +stringData: + openhim-username: "root@openhim.org" + openhim-password: "openhim-password" + openhim-client-password: "interop-password" + openhim-user-password: "interop-password" +--- +apiVersion: v1 +kind: Secret +metadata: + name: mediator-credentials + namespace: health-interop +type: Opaque +stringData: + openhim-username: "interop@openhim.org" + openhim-password: "interop-password" + fhir-username: "interop-client" + fhir-password: "interop-password" + cht-username: "admin" + cht-password: "password" + openimis-username: "Admin" + openimis-password: "admin123" diff --git a/kubernetes/04-persistent-volumes.yaml b/kubernetes/04-persistent-volumes.yaml new file mode 100644 index 00000000..89eb1821 --- /dev/null +++ b/kubernetes/04-persistent-volumes.yaml @@ -0,0 +1,59 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: couchdb-data + namespace: health-interop +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cht-credentials + namespace: health-interop +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cht-ssl + namespace: health-interop +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: hapi-db-volume + namespace: health-interop +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mongo-data + namespace: health-interop +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/kubernetes/05-databases.yaml b/kubernetes/05-databases.yaml new file mode 100644 index 00000000..e6e2b785 --- /dev/null +++ b/kubernetes/05-databases.yaml @@ -0,0 +1,166 @@ +# MongoDB for OpenHIM +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongo + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: mongo + template: + metadata: + labels: + app: mongo + spec: + containers: + - name: mongo + image: mongo:4.2 + ports: + - containerPort: 27017 + volumeMounts: + - name: mongo-storage + mountPath: /data/db + volumes: + - name: mongo-storage + persistentVolumeClaim: + claimName: mongo-data +--- +apiVersion: v1 +kind: Service +metadata: + name: mongo + namespace: health-interop +spec: + selector: + app: mongo + ports: + - port: 27017 + targetPort: 27017 +--- +# PostgreSQL for HAPI FHIR +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hapi-db + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: hapi-db + template: + metadata: + labels: + app: hapi-db + spec: + containers: + - name: hapi-db + image: postgres:14.1 + env: + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: database-credentials + key: postgres-user + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: database-credentials + key: postgres-password + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: database-credentials + key: postgres-db + ports: + - containerPort: 5432 + volumeMounts: + - name: hapi-db-storage + mountPath: /var/lib/postgresql/data + volumes: + - name: hapi-db-storage + persistentVolumeClaim: + claimName: hapi-db-volume +--- +apiVersion: v1 +kind: Service +metadata: + name: hapi-db + namespace: health-interop +spec: + selector: + app: hapi-db + ports: + - port: 5432 + targetPort: 5432 +--- +# CouchDB for CHT +apiVersion: apps/v1 +kind: Deployment +metadata: + name: couchdb + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: couchdb + template: + metadata: + labels: + app: couchdb + spec: + containers: + - name: couchdb + image: public.ecr.aws/medic/cht-couchdb:4.1.0-alpha + env: + - name: COUCHDB_USER + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-user + - name: COUCHDB_PASSWORD + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-password + - name: COUCHDB_SECRET + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-secret + - name: COUCHDB_UUID + value: "CC0C3BA1-88EE-4AE3-BFD3-6E0EE56ED534" + - name: SVC_NAME + value: "couchdb" + - name: COUCHDB_LOG_LEVEL + value: "error" + ports: + - containerPort: 5984 + volumeMounts: + - name: couchdb-data-storage + mountPath: /opt/couchdb/data + - name: cht-credentials-storage + mountPath: /opt/couchdb/etc/local.d/ + volumes: + - name: couchdb-data-storage + persistentVolumeClaim: + claimName: couchdb-data + - name: cht-credentials-storage + persistentVolumeClaim: + claimName: cht-credentials + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: couchdb + namespace: health-interop +spec: + selector: + app: couchdb + ports: + - port: 5984 + targetPort: 5984 diff --git a/kubernetes/06-openhim-core.yaml b/kubernetes/06-openhim-core.yaml new file mode 100644 index 00000000..06b0587d --- /dev/null +++ b/kubernetes/06-openhim-core.yaml @@ -0,0 +1,109 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openhim-core + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: openhim-core + template: + metadata: + labels: + app: openhim-core + spec: + containers: + - name: openhim-core + image: jembi/openhim-core:7 + env: + - name: mongo_url + value: "mongodb://mongo/openhim" + - name: mongo_atnaUrl + value: "mongodb://mongo/openhim" + ports: + - containerPort: 8080 + - containerPort: 5000 + - containerPort: 5001 + - containerPort: 5050 + - containerPort: 5051 + - containerPort: 5052 + - containerPort: 7788 + readinessProbe: + httpGet: + path: /heartbeat + port: 8080 + scheme: HTTPS + initialDelaySeconds: 60 + periodSeconds: 20 + timeoutSeconds: 10 + failureThreshold: 5 + livenessProbe: + httpGet: + path: /heartbeat + port: 8080 + scheme: HTTPS + initialDelaySeconds: 120 + periodSeconds: 60 + timeoutSeconds: 10 + failureThreshold: 3 + initContainers: + - name: wait-for-mongo + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z mongo 27017; do echo waiting for mongo; sleep 2; done'] + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: openhim-core + namespace: health-interop +spec: + selector: + app: openhim-core + ports: + - name: api + port: 8080 + targetPort: 8080 + - name: router-http + port: 5000 + targetPort: 5000 + - name: router-https + port: 5001 + targetPort: 5001 + - name: router-tcp + port: 5050 + targetPort: 5050 + - name: router-tls + port: 5051 + targetPort: 5051 + - name: router-polling + port: 5052 + targetPort: 5052 + - name: tcp-adapter + port: 7788 + targetPort: 7788 +--- +# Expose OpenHIM Core API externally +apiVersion: v1 +kind: Service +metadata: + name: openhim-core-external + namespace: health-interop +spec: + type: NodePort + selector: + app: openhim-core + ports: + - name: api + port: 8080 + targetPort: 8080 + nodePort: 30080 + - name: router-http + port: 5000 + targetPort: 5000 + nodePort: 30000 + - name: router-https + port: 5001 + targetPort: 5001 + nodePort: 30001 diff --git a/kubernetes/07-openhim-console.yaml b/kubernetes/07-openhim-console.yaml new file mode 100644 index 00000000..a2acecd8 --- /dev/null +++ b/kubernetes/07-openhim-console.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: openhim-console + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: openhim-console + template: + metadata: + labels: + app: openhim-console + spec: + containers: + - name: openhim-console + image: jembi/openhim-console:1.14.4 + ports: + - containerPort: 80 + volumeMounts: + - name: console-config + mountPath: /usr/share/nginx/html/config/default.json + subPath: default.json + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 10 + periodSeconds: 5 + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 30 + periodSeconds: 30 + volumes: + - name: console-config + configMap: + name: openhim-console-config + initContainers: + - name: wait-for-openhim-core + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z openhim-core 8080; do echo waiting for openhim-core; sleep 2; done'] + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: openhim-console + namespace: health-interop +spec: + selector: + app: openhim-console + ports: + - port: 80 + targetPort: 80 +--- +# Expose OpenHIM Console externally +apiVersion: v1 +kind: Service +metadata: + name: openhim-console-external + namespace: health-interop +spec: + type: NodePort + selector: + app: openhim-console + ports: + - port: 80 + targetPort: 80 + nodePort: 30900 diff --git a/kubernetes/08-hapi-fhir.yaml b/kubernetes/08-hapi-fhir.yaml new file mode 100644 index 00000000..933c7c68 --- /dev/null +++ b/kubernetes/08-hapi-fhir.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hapi-fhir + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: hapi-fhir + template: + metadata: + labels: + app: hapi-fhir + spec: + containers: + - name: hapi-fhir + image: hapiproject/hapi:v5.5.1 + env: + - name: spring.datasource.url + value: "jdbc:postgresql://hapi-db:5432/hapi" + - name: spring.datasource.username + valueFrom: + secretKeyRef: + name: database-credentials + key: postgres-user + - name: spring.datasource.password + valueFrom: + secretKeyRef: + name: database-credentials + key: postgres-password + - name: spring.datasource.driverClassName + value: "org.postgresql.Driver" + - name: spring.jpa.properties.hibernate.dialect + value: "org.hibernate.dialect.PostgreSQL95Dialect" + - name: hapi.fhir.allow_external_references + value: "true" + - name: hapi.fhir.bulk_export_enabled + value: "true" + - name: hapi.fhir.subscription.resthook_enabled + value: "true" + - name: JAVA_TOOL_OPTIONS + value: "-Xmx2g" + - name: CATALINA_OPTS + value: "-Xmx2g" + ports: + - containerPort: 8080 + resources: + requests: + memory: "2Gi" + cpu: "500m" + limits: + memory: "3Gi" + cpu: "1000m" + readinessProbe: + httpGet: + path: /fhir/metadata + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 30 + timeoutSeconds: 10 + livenessProbe: + httpGet: + path: /fhir/metadata + port: 8080 + initialDelaySeconds: 120 + periodSeconds: 60 + timeoutSeconds: 10 + initContainers: + - name: wait-for-hapi-db + image: postgres:14.1 + command: ['sh', '-c', 'until pg_isready -h hapi-db -p 5432; do echo waiting for database; sleep 2; done'] + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: hapi-fhir + namespace: health-interop +spec: + selector: + app: hapi-fhir + ports: + - port: 8080 + targetPort: 8080 diff --git a/kubernetes/09-cht-services.yaml b/kubernetes/09-cht-services.yaml new file mode 100644 index 00000000..6d2bad2a --- /dev/null +++ b/kubernetes/09-cht-services.yaml @@ -0,0 +1,311 @@ +# HAProxy for CouchDB load balancing +apiVersion: apps/v1 +kind: Deployment +metadata: + name: haproxy + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: haproxy + template: + metadata: + labels: + app: haproxy + spec: + hostname: localhost + containers: + - name: haproxy + image: public.ecr.aws/medic/cht-haproxy:4.1.0-alpha + env: + - name: HAPROXY_IP + value: "0.0.0.0" + - name: COUCHDB_USER + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-user + - name: COUCHDB_PASSWORD + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-password + - name: COUCHDB_SERVERS + value: "couchdb" + - name: HAPROXY_PORT + value: "5984" + - name: HEALTHCHECK_ADDR + value: "healthcheck" + ports: + - containerPort: 5984 + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: haproxy + namespace: health-interop +spec: + selector: + app: haproxy + ports: + - port: 5984 + targetPort: 5984 +--- +# CHT HAProxy Healthcheck +apiVersion: apps/v1 +kind: Deployment +metadata: + name: healthcheck + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: healthcheck + template: + metadata: + labels: + app: healthcheck + spec: + containers: + - name: healthcheck + image: public.ecr.aws/medic/cht-haproxy-healthcheck:4.1.0-alpha + env: + - name: COUCHDB_SERVERS + value: "couchdb" + - name: COUCHDB_USER + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-user + - name: COUCHDB_PASSWORD + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-password + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: healthcheck + namespace: health-interop +spec: + selector: + app: healthcheck + ports: + - port: 80 + targetPort: 80 +--- +# CHT API +apiVersion: apps/v1 +kind: Deployment +metadata: + name: api + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: api + template: + metadata: + labels: + app: api + spec: + containers: + - name: api + image: public.ecr.aws/medic/cht-api:4.1.0-alpha + env: + - name: COUCH_URL + value: "http://admin:password@haproxy:5984/medic" + - name: BUILDS_URL + value: "https://staging.dev.medicmobile.org/_couch/builds_4" + - name: UPGRADE_SERVICE_URL + value: "http://localhost:5100" + - name: HOST + value: "0.0.0.0" + - name: HOSTNAME + value: "0.0.0.0" + - name: API_HOST + value: "0.0.0.0" + - name: BIND_ADDRESS + value: "0.0.0.0" + - name: API_PORT + value: "5988" + - name: PORT + value: "5988" + ports: + - containerPort: 5988 + readinessProbe: + httpGet: + path: /api/info + port: 5988 + initialDelaySeconds: 30 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /api/info + port: 5988 + initialDelaySeconds: 60 + periodSeconds: 30 + initContainers: + - name: wait-for-haproxy + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z haproxy 5984; do echo waiting for haproxy; sleep 2; done'] + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: api + namespace: health-interop +spec: + selector: + app: api + ports: + - port: 5988 + targetPort: 5988 +--- +# CHT Sentinel +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sentinel + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: sentinel + template: + metadata: + labels: + app: sentinel + spec: + containers: + - name: sentinel + image: public.ecr.aws/medic/cht-sentinel:4.1.0-alpha + env: + - name: COUCH_URL + value: "http://admin:password@haproxy:5984/medic" + - name: API_HOST + value: "api" + initContainers: + - name: wait-for-haproxy + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z haproxy 5984; do echo waiting for haproxy; sleep 2; done'] + restartPolicy: Always +--- +# CHT Nginx +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: public.ecr.aws/medic/cht-nginx:4.1.0-alpha + env: + - name: API_HOST + value: "api" + - name: API_PORT + value: "5988" + - name: CERTIFICATE_MODE + value: "SELF_SIGNED" + - name: SSL_CERT_FILE_PATH + value: "/etc/nginx/private/cert.pem" + - name: SSL_KEY_FILE_PATH + value: "/etc/nginx/private/key.pem" + - name: COMMON_NAME + value: "test-nginx.dev.medicmobile.org" + - name: EMAIL + value: "domains@medic.org" + - name: COUNTRY + value: "US" + - name: STATE + value: "California" + - name: LOCALITY + value: "San_Francisco" + - name: ORGANISATION + value: "medic" + - name: DEPARTMENT + value: "Information_Security" + ports: + - containerPort: 80 + - containerPort: 443 + volumeMounts: + - name: cht-ssl-storage + mountPath: /etc/nginx/private/ + readinessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 20 + periodSeconds: 10 + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 40 + periodSeconds: 30 + volumes: + - name: cht-ssl-storage + persistentVolumeClaim: + claimName: cht-ssl + initContainers: + - name: wait-for-api + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z api 5988; do echo waiting for api; sleep 2; done'] + - name: wait-for-haproxy + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z haproxy 5984; do echo waiting for haproxy; sleep 2; done'] + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx + namespace: health-interop +spec: + selector: + app: nginx + ports: + - name: http + port: 80 + targetPort: 80 + - name: https + port: 443 + targetPort: 443 +--- +# Expose CHT Nginx externally +apiVersion: v1 +kind: Service +metadata: + name: nginx-external + namespace: health-interop +spec: + type: NodePort + selector: + app: nginx + ports: + - name: http + port: 80 + targetPort: 80 + nodePort: 30080 + - name: https + port: 443 + targetPort: 443 + nodePort: 30443 diff --git a/kubernetes/10-mediator-services.yaml b/kubernetes/10-mediator-services.yaml new file mode 100644 index 00000000..600dd435 --- /dev/null +++ b/kubernetes/10-mediator-services.yaml @@ -0,0 +1,172 @@ +# Configurator - runs as a Job to set up initial configuration +apiVersion: batch/v1 +kind: Job +metadata: + name: configurator + namespace: health-interop +spec: + template: + spec: + containers: + - name: configurator + image: configurator:local + imagePullPolicy: Never + env: + - name: COUCHDB_USER + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-user + - name: COUCHDB_PASSWORD + valueFrom: + secretKeyRef: + name: database-credentials + key: couchdb-password + - name: OPENHIM_API_HOSTNAME + value: "openhim-core" + - name: OPENHIM_API_PORT + value: "8080" + - name: OPENHIM_PASSWORD + valueFrom: + secretKeyRef: + name: openhim-credentials + key: openhim-password + - name: OPENHIM_USERNAME + valueFrom: + secretKeyRef: + name: openhim-credentials + key: openhim-username + - name: OPENHIM_CLIENT_PASSWORD + valueFrom: + secretKeyRef: + name: openhim-credentials + key: openhim-client-password + - name: OPENHIM_USER_PASSWORD + valueFrom: + secretKeyRef: + name: openhim-credentials + key: openhim-user-password + initContainers: + - name: wait-for-openhim-core + image: busybox:1.35 + command: ['sh', '-c', 'until nc -z openhim-core 8080; do echo waiting for openhim-core; sleep 5; done'] + restartPolicy: OnFailure + backoffLimit: 3 +--- +# Mediator Service +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mediator + namespace: health-interop +spec: + replicas: 1 + selector: + matchLabels: + app: mediator + template: + metadata: + labels: + app: mediator + spec: + containers: + - name: mediator + image: mediator:local + imagePullPolicy: Never + ports: + - containerPort: 6000 + env: + - name: OPENHIM_USERNAME + valueFrom: + secretKeyRef: + name: mediator-credentials + key: openhim-username + - name: OPENHIM_PASSWORD + valueFrom: + secretKeyRef: + name: mediator-credentials + key: openhim-password + - name: OPENHIM_API_URL + value: "https://openhim-core:8080" + - name: PORT + value: "6000" + - name: FHIR_URL + value: "http://openhim-core:5001/fhir" + - name: FHIR_USERNAME + valueFrom: + secretKeyRef: + name: mediator-credentials + key: fhir-username + - name: FHIR_PASSWORD + valueFrom: + secretKeyRef: + name: mediator-credentials + key: fhir-password + - name: CHT_URL + value: "https://nginx" + - name: CHT_USERNAME + valueFrom: + secretKeyRef: + name: mediator-credentials + key: cht-username + - name: CHT_PASSWORD + valueFrom: + secretKeyRef: + name: mediator-credentials + key: cht-password + - name: OPENIMIS_API_URL + value: "https://openimis.s2.openimis.org" + - name: OPENIMIS_USERNAME + valueFrom: + secretKeyRef: + name: mediator-credentials + key: openimis-username + - name: OPENIMIS_PASSWORD + valueFrom: + secretKeyRef: + name: mediator-credentials + key: openimis-password + readinessProbe: + httpGet: + path: /health + port: 6000 + initialDelaySeconds: 30 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /health + port: 6000 + initialDelaySeconds: 60 + periodSeconds: 30 + initContainers: + - name: wait-for-configurator + image: busybox:1.35 + command: ['sh', '-c', 'echo "Configurator job completed, starting mediator"; sleep 5'] + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: mediator + namespace: health-interop +spec: + selector: + app: mediator + ports: + - port: 6000 + targetPort: 6000 +--- +# Expose Mediator externally for testing +apiVersion: v1 +kind: Service +metadata: + name: mediator-external + namespace: health-interop +spec: + type: NodePort + selector: + app: mediator + ports: + - port: 6000 + targetPort: 6000 + nodePort: 30600 diff --git a/start_local_kubernetes.sh b/start_local_kubernetes.sh new file mode 100755 index 00000000..02feb67a --- /dev/null +++ b/start_local_kubernetes.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Delete the previous cluster +kind delete cluster --name health-interop + +# Create a fresh cluster +kind create cluster --name health-interop + +# Reload your custom images +kind load docker-image configurator:local --name health-interop +kind load docker-image mediator:local --name health-interop + +# Deploy everything again (in order) +kubectl apply -f kubernetes/01-namespace.yaml +kubectl apply -f kubernetes/02-configmap.yaml +kubectl apply -f kubernetes/03-secrets.yaml +kubectl apply -f kubernetes/04-persistent-volumes.yaml +kubectl apply -f kubernetes/05-databases.yaml + +# Wait for databases to be ready, then continue +kubectl get pods -n health-interop -w + +# Once databases are running, deploy the rest +kubectl apply -f kubernetes/06-openhim-core.yaml +kubectl apply -f kubernetes/07-openhim-console.yaml +kubectl apply -f kubernetes/08-hapi-fhir.yaml +kubectl apply -f kubernetes/09-cht-services.yaml +kubectl apply -f kubernetes/10-mediator-services.yaml + +# OpenHIM Core - Management API (HTTPS) +kubectl port-forward svc/openhim-core 8080:8080 -n health-interop & + +# OpenHIM Core - HTTP Router (routes to mediators) +kubectl port-forward svc/openhim-core 5001:5001 -n health-interop & + +# OpenHIM Console - Management interface +kubectl port-forward svc/openhim-console 9000:80 -n health-interop & + +# CHT - Community Health Toolkit (via Nginx) +kubectl port-forward svc/nginx 8081:80 -n health-interop & +kubectl port-forward svc/nginx 8444:443 -n health-interop & From 919eb6055bad77ac993b7a31c83c81efdc6fbec6 Mon Sep 17 00:00:00 2001 From: Sugat Bajracharya Date: Fri, 17 Oct 2025 17:08:11 +0545 Subject: [PATCH 2/5] add support for helm charts and deployment in EKS --- charts/.helmignore | 23 +++ charts/Chart.yaml | 12 ++ charts/templates/01-namespace.yaml | 8 + .../templates}/02-configmap.yaml | 12 +- charts/templates/03-secrets.yaml | 41 +++++ charts/templates/04-persistent-volumes.yaml | 64 +++++++ .../templates}/05-databases.yaml | 45 +++-- .../templates}/06-openhim-core.yaml | 16 +- .../templates}/07-openhim-console.yaml | 16 +- .../templates}/08-hapi-fhir.yaml | 8 +- .../templates}/09-cht-services.yaml | 50 +++--- .../templates}/10-mediator-services.yaml | 24 +-- charts/templates/eks-cht-ingress.yaml | 38 ++++ .../eks-openhim-console-ingress.yaml | 36 ++++ .../templates/eks-openhim-core-ingress.yaml | 37 ++++ .../templates/eks-openhim-router-ingress.yaml | 41 +++++ charts/values-eks.yaml | 42 +++++ charts/values.yaml | 119 ++++++++++++ kubernetes/01-namespace.yaml | 6 - kubernetes/03-secrets.yaml | 41 ----- kubernetes/04-persistent-volumes.yaml | 59 ------ port-forward.sh | 16 ++ start_local_kubernetes.sh | 169 ++++++++++++++---- 23 files changed, 719 insertions(+), 204 deletions(-) create mode 100644 charts/.helmignore create mode 100644 charts/Chart.yaml create mode 100644 charts/templates/01-namespace.yaml rename {kubernetes => charts/templates}/02-configmap.yaml (58%) create mode 100644 charts/templates/03-secrets.yaml create mode 100644 charts/templates/04-persistent-volumes.yaml rename {kubernetes => charts/templates}/05-databases.yaml (66%) rename {kubernetes => charts/templates}/06-openhim-core.yaml (86%) rename {kubernetes => charts/templates}/07-openhim-console.yaml (78%) rename {kubernetes => charts/templates}/08-hapi-fhir.yaml (92%) rename {kubernetes => charts/templates}/09-cht-services.yaml (84%) rename {kubernetes => charts/templates}/10-mediator-services.yaml (87%) create mode 100644 charts/templates/eks-cht-ingress.yaml create mode 100644 charts/templates/eks-openhim-console-ingress.yaml create mode 100644 charts/templates/eks-openhim-core-ingress.yaml create mode 100644 charts/templates/eks-openhim-router-ingress.yaml create mode 100644 charts/values-eks.yaml create mode 100644 charts/values.yaml delete mode 100644 kubernetes/01-namespace.yaml delete mode 100644 kubernetes/03-secrets.yaml delete mode 100644 kubernetes/04-persistent-volumes.yaml create mode 100755 port-forward.sh diff --git a/charts/.helmignore b/charts/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/Chart.yaml b/charts/Chart.yaml new file mode 100644 index 00000000..68f68c1c --- /dev/null +++ b/charts/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: health-interop +description: A Helm chart for Health Interoperability Stack +type: application +version: 1.0.0 +appVersion: "1.0" +keywords: + - health + - interoperability + - openhim + - cht + - fhir diff --git a/charts/templates/01-namespace.yaml b/charts/templates/01-namespace.yaml new file mode 100644 index 00000000..91324fd1 --- /dev/null +++ b/charts/templates/01-namespace.yaml @@ -0,0 +1,8 @@ +{{- if .Values.createNamespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.namespace }} + labels: + name: {{ .Values.global.namespace }} +{{- end }} diff --git a/kubernetes/02-configmap.yaml b/charts/templates/02-configmap.yaml similarity index 58% rename from kubernetes/02-configmap.yaml rename to charts/templates/02-configmap.yaml index 9a5e8296..79ddc300 100644 --- a/kubernetes/02-configmap.yaml +++ b/charts/templates/02-configmap.yaml @@ -2,15 +2,21 @@ apiVersion: v1 kind: ConfigMap metadata: name: openhim-console-config - namespace: health-interop + namespace: {{ .Values.global.namespace }} data: default.json: | { "version": "1.10.0", "minimumCoreVersion": "3.4.0", +{{- if eq .Values.cluster_type "eks" }} "protocol": "https", - "host": "localhost", - "port": 8080, + "host": "{{ .Values.ingress.openhimCoreHost }}", + "port": 443, +{{- else }} + "protocol": "{{ .Values.openhim.console.config.protocol }}", + "host": "{{ .Values.openhim.console.config.host }}", + "port": {{ .Values.openhim.console.config.port }}, +{{- end }} "title": "Admin Console", "footerTitle": "OpenHIM Administration Console", "footerPoweredBy": "Powered by OpenHIM", diff --git a/charts/templates/03-secrets.yaml b/charts/templates/03-secrets.yaml new file mode 100644 index 00000000..d008b4eb --- /dev/null +++ b/charts/templates/03-secrets.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Secret +metadata: + name: database-credentials + namespace: {{ .Values.global.namespace }} +type: Opaque +stringData: + couchdb-user: {{ .Values.couchdb.credentials.username | quote }} + couchdb-password: {{ .Values.couchdb.credentials.password | quote }} + couchdb-secret: {{ .Values.couchdb.credentials.secret | quote }} + postgres-user: {{ .Values.postgresql.credentials.username | quote }} + postgres-password: {{ .Values.postgresql.credentials.password | quote }} + postgres-db: {{ .Values.postgresql.credentials.database | quote }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: openhim-credentials + namespace: {{ .Values.global.namespace }} +type: Opaque +stringData: + openhim-username: "root@openhim.org" + openhim-password: "openhim-password" + openhim-client-password: "interop-password" + openhim-user-password: "interop-password" +--- +apiVersion: v1 +kind: Secret +metadata: + name: mediator-credentials + namespace: {{ .Values.global.namespace }} +type: Opaque +stringData: + openhim-username: {{ .Values.mediator.credentials.openhimUsername | quote }} + openhim-password: {{ .Values.mediator.credentials.openhimPassword | quote }} + fhir-username: {{ .Values.mediator.credentials.fhirUsername | quote }} + fhir-password: {{ .Values.mediator.credentials.fhirPassword | quote }} + cht-username: {{ .Values.mediator.credentials.chtUsername | quote }} + cht-password: {{ .Values.mediator.credentials.chtPassword | quote }} + openimis-username: "Admin" + openimis-password: "admin123" diff --git a/charts/templates/04-persistent-volumes.yaml b/charts/templates/04-persistent-volumes.yaml new file mode 100644 index 00000000..12efb146 --- /dev/null +++ b/charts/templates/04-persistent-volumes.yaml @@ -0,0 +1,64 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: couchdb-data + namespace: {{ .Values.global.namespace }} +spec: + accessModes: + - ReadWriteOnce + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.couchdb.storage }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cht-credentials + namespace: {{ .Values.global.namespace }} +spec: + accessModes: + - ReadWriteOnce + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.persistence.chtCredentials }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: cht-ssl + namespace: {{ .Values.global.namespace }} +spec: + accessModes: + - ReadWriteOnce + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.persistence.chtSsl }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: hapi-db-volume + namespace: {{ .Values.global.namespace }} +spec: + accessModes: + - ReadWriteOnce + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.postgresql.storage }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mongo-data + namespace: {{ .Values.global.namespace }} +spec: + accessModes: + - ReadWriteOnce + storageClassName: {{ .Values.persistence.storageClass }} + resources: + requests: + storage: {{ .Values.mongodb.storage }} diff --git a/kubernetes/05-databases.yaml b/charts/templates/05-databases.yaml similarity index 66% rename from kubernetes/05-databases.yaml rename to charts/templates/05-databases.yaml index e6e2b785..b834c2ed 100644 --- a/kubernetes/05-databases.yaml +++ b/charts/templates/05-databases.yaml @@ -1,9 +1,9 @@ -# MongoDB for OpenHIM +# MongoDBefor OpenHIM apiVersion: apps/v1 kind: Deployment metadata: name: mongo - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: replicas: 1 selector: @@ -16,7 +16,14 @@ spec: spec: containers: - name: mongo - image: mongo:4.2 + image: {{ .Values.mongodb.image }} + resources: + requests: + memory: {{ .Values.mongodb.resources.requests.memory | quote }} + cpu: {{ .Values.mongodb.resources.requests.cpu | quote }} + limits: + memory: {{ .Values.mongodb.resources.limits.memory | quote }} + cpu: {{ .Values.mongodb.resources.limits.cpu | quote }} ports: - containerPort: 27017 volumeMounts: @@ -31,7 +38,7 @@ apiVersion: v1 kind: Service metadata: name: mongo - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: mongo @@ -44,7 +51,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: hapi-db - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: replicas: 1 selector: @@ -57,7 +64,14 @@ spec: spec: containers: - name: hapi-db - image: postgres:14.1 + image: {{ .Values.postgresql.image }} + resources: + requests: + memory: {{ .Values.postgresql.resources.requests.memory | quote }} + cpu: {{ .Values.postgresql.resources.requests.cpu | quote }} + limits: + memory: {{ .Values.postgresql.resources.limits.memory | quote }} + cpu: {{ .Values.postgresql.resources.limits.cpu | quote }} env: - name: POSTGRES_USER valueFrom: @@ -74,6 +88,8 @@ spec: secretKeyRef: name: database-credentials key: postgres-db + - name: PGDATA + value: /var/lib/postgresql/data/pgdata ports: - containerPort: 5432 volumeMounts: @@ -88,7 +104,7 @@ apiVersion: v1 kind: Service metadata: name: hapi-db - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: hapi-db @@ -101,7 +117,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: couchdb - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: replicas: 1 selector: @@ -114,7 +130,14 @@ spec: spec: containers: - name: couchdb - image: public.ecr.aws/medic/cht-couchdb:4.1.0-alpha + image: {{ .Values.couchdb.image }} + resources: + requests: + memory: {{ .Values.couchdb.resources.requests.memory | quote }} + cpu: {{ .Values.couchdb.resources.requests.cpu | quote }} + limits: + memory: {{ .Values.couchdb.resources.limits.memory | quote }} + cpu: {{ .Values.couchdb.resources.limits.cpu | quote }} env: - name: COUCHDB_USER valueFrom: @@ -132,7 +155,7 @@ spec: name: database-credentials key: couchdb-secret - name: COUCHDB_UUID - value: "CC0C3BA1-88EE-4AE3-BFD3-6E0EE56ED534" + value: {{ .Values.couchdb.credentials.uuid | quote }} - name: SVC_NAME value: "couchdb" - name: COUCHDB_LOG_LEVEL @@ -157,7 +180,7 @@ apiVersion: v1 kind: Service metadata: name: couchdb - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: couchdb diff --git a/kubernetes/06-openhim-core.yaml b/charts/templates/06-openhim-core.yaml similarity index 86% rename from kubernetes/06-openhim-core.yaml rename to charts/templates/06-openhim-core.yaml index 06b0587d..277074ea 100644 --- a/kubernetes/06-openhim-core.yaml +++ b/charts/templates/06-openhim-core.yaml @@ -2,9 +2,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: openhim-core - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.openhim.core.replicas }} selector: matchLabels: app: openhim-core @@ -15,7 +15,7 @@ spec: spec: containers: - name: openhim-core - image: jembi/openhim-core:7 + image: {{ .Values.openhim.core.image }} env: - name: mongo_url value: "mongodb://mongo/openhim" @@ -57,7 +57,7 @@ apiVersion: v1 kind: Service metadata: name: openhim-core - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: openhim-core @@ -85,11 +85,12 @@ spec: targetPort: 7788 --- # Expose OpenHIM Core API externally +{{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service metadata: name: openhim-core-external - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: type: NodePort selector: @@ -98,12 +99,11 @@ spec: - name: api port: 8080 targetPort: 8080 - nodePort: 30080 + nodePort: {{ .Values.services.nodePort.openhimCore | default 30081 }} - name: router-http port: 5000 targetPort: 5000 - nodePort: 30000 - name: router-https port: 5001 targetPort: 5001 - nodePort: 30001 +{{- end }} diff --git a/kubernetes/07-openhim-console.yaml b/charts/templates/07-openhim-console.yaml similarity index 78% rename from kubernetes/07-openhim-console.yaml rename to charts/templates/07-openhim-console.yaml index a2acecd8..e886feb5 100644 --- a/kubernetes/07-openhim-console.yaml +++ b/charts/templates/07-openhim-console.yaml @@ -2,9 +2,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: openhim-console - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.openhim.console.replicas }} selector: matchLabels: app: openhim-console @@ -15,7 +15,7 @@ spec: spec: containers: - name: openhim-console - image: jembi/openhim-console:1.14.4 + image: {{ .Values.openhim.console.image }} ports: - containerPort: 80 volumeMounts: @@ -48,7 +48,7 @@ apiVersion: v1 kind: Service metadata: name: openhim-console - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: openhim-console @@ -56,12 +56,13 @@ spec: - port: 80 targetPort: 80 --- -# Expose OpenHIM Console externally +# Expose OpenHIM Console externally (only for KIND) +{{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service metadata: name: openhim-console-external - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: type: NodePort selector: @@ -69,4 +70,5 @@ spec: ports: - port: 80 targetPort: 80 - nodePort: 30900 + nodePort: {{ .Values.services.nodePort.console }} +{{- end }} diff --git a/kubernetes/08-hapi-fhir.yaml b/charts/templates/08-hapi-fhir.yaml similarity index 92% rename from kubernetes/08-hapi-fhir.yaml rename to charts/templates/08-hapi-fhir.yaml index 933c7c68..fa6e934e 100644 --- a/kubernetes/08-hapi-fhir.yaml +++ b/charts/templates/08-hapi-fhir.yaml @@ -2,9 +2,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: hapi-fhir - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.hapiFhir.replicas }} selector: matchLabels: app: hapi-fhir @@ -15,7 +15,7 @@ spec: spec: containers: - name: hapi-fhir - image: hapiproject/hapi:v5.5.1 + image: {{ .Values.hapiFhir.image }} env: - name: spring.datasource.url value: "jdbc:postgresql://hapi-db:5432/hapi" @@ -76,7 +76,7 @@ apiVersion: v1 kind: Service metadata: name: hapi-fhir - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: hapi-fhir diff --git a/kubernetes/09-cht-services.yaml b/charts/templates/09-cht-services.yaml similarity index 84% rename from kubernetes/09-cht-services.yaml rename to charts/templates/09-cht-services.yaml index 6d2bad2a..9193601a 100644 --- a/kubernetes/09-cht-services.yaml +++ b/charts/templates/09-cht-services.yaml @@ -3,9 +3,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: haproxy - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.cht.haproxy.replicas }} selector: matchLabels: app: haproxy @@ -14,10 +14,9 @@ spec: labels: app: haproxy spec: - hostname: localhost containers: - name: haproxy - image: public.ecr.aws/medic/cht-haproxy:4.1.0-alpha + image: {{ .Values.cht.haproxy.image }} env: - name: HAPROXY_IP value: "0.0.0.0" @@ -45,7 +44,7 @@ apiVersion: v1 kind: Service metadata: name: haproxy - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: haproxy @@ -58,9 +57,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: healthcheck - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.cht.healthcheck.replicas }} selector: matchLabels: app: healthcheck @@ -71,7 +70,7 @@ spec: spec: containers: - name: healthcheck - image: public.ecr.aws/medic/cht-haproxy-healthcheck:4.1.0-alpha + image: {{ .Values.cht.healthcheck.image }} env: - name: COUCHDB_SERVERS value: "couchdb" @@ -91,7 +90,7 @@ apiVersion: v1 kind: Service metadata: name: healthcheck - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: healthcheck @@ -104,9 +103,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: api - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.cht.api.replicas }} selector: matchLabels: app: api @@ -115,9 +114,10 @@ spec: labels: app: api spec: + hostname: localhost containers: - name: api - image: public.ecr.aws/medic/cht-api:4.1.0-alpha + image: {{ .Values.cht.api.image }} env: - name: COUCH_URL value: "http://admin:password@haproxy:5984/medic" @@ -161,7 +161,7 @@ apiVersion: v1 kind: Service metadata: name: api - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: api @@ -174,9 +174,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: sentinel - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.cht.sentinel.replicas }} selector: matchLabels: app: sentinel @@ -187,7 +187,7 @@ spec: spec: containers: - name: sentinel - image: public.ecr.aws/medic/cht-sentinel:4.1.0-alpha + image: {{ .Values.cht.sentinel.image }} env: - name: COUCH_URL value: "http://admin:password@haproxy:5984/medic" @@ -204,9 +204,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: nginx - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.cht.nginx.replicas }} selector: matchLabels: app: nginx @@ -217,7 +217,7 @@ spec: spec: containers: - name: nginx - image: public.ecr.aws/medic/cht-nginx:4.1.0-alpha + image: {{ .Values.cht.nginx.image }} env: - name: API_HOST value: "api" @@ -278,7 +278,7 @@ apiVersion: v1 kind: Service metadata: name: nginx - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: nginx @@ -290,12 +290,13 @@ spec: port: 443 targetPort: 443 --- -# Expose CHT Nginx externally +# Expose CHT Nginx externally (only for KIND) +{{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service metadata: name: nginx-external - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: type: NodePort selector: @@ -304,8 +305,9 @@ spec: - name: http port: 80 targetPort: 80 - nodePort: 30080 + nodePort: {{ .Values.services.nodePort.nginx }} - name: https port: 443 targetPort: 443 - nodePort: 30443 + nodePort: {{ .Values.services.nodePort.nginxHttps }} +{{- end }} diff --git a/kubernetes/10-mediator-services.yaml b/charts/templates/10-mediator-services.yaml similarity index 87% rename from kubernetes/10-mediator-services.yaml rename to charts/templates/10-mediator-services.yaml index 600dd435..f107f279 100644 --- a/kubernetes/10-mediator-services.yaml +++ b/charts/templates/10-mediator-services.yaml @@ -3,14 +3,14 @@ apiVersion: batch/v1 kind: Job metadata: name: configurator - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: template: spec: containers: - name: configurator - image: configurator:local - imagePullPolicy: Never + image: {{ .Values.configurator.image }} + imagePullPolicy: {{ .Values.configurator.imagePullPolicy }} env: - name: COUCHDB_USER valueFrom: @@ -58,9 +58,9 @@ apiVersion: apps/v1 kind: Deployment metadata: name: mediator - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: - replicas: 1 + replicas: {{ .Values.mediator.replicas }} selector: matchLabels: app: mediator @@ -71,8 +71,8 @@ spec: spec: containers: - name: mediator - image: mediator:local - imagePullPolicy: Never + image: {{ .Values.mediator.image }} + imagePullPolicy: {{ .Values.mediator.imagePullPolicy }} ports: - containerPort: 6000 env: @@ -148,7 +148,7 @@ apiVersion: v1 kind: Service metadata: name: mediator - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: selector: app: mediator @@ -156,12 +156,13 @@ spec: - port: 6000 targetPort: 6000 --- -# Expose Mediator externally for testing +# Expose Mediator externally for testing (only for KIND) +{{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service metadata: name: mediator-external - namespace: health-interop + namespace: {{ .Values.global.namespace }} spec: type: NodePort selector: @@ -169,4 +170,5 @@ spec: ports: - port: 6000 targetPort: 6000 - nodePort: 30600 + nodePort: {{ .Values.services.nodePort.mediator }} +{{- end }} diff --git a/charts/templates/eks-cht-ingress.yaml b/charts/templates/eks-cht-ingress.yaml new file mode 100644 index 00000000..3be9cff7 --- /dev/null +++ b/charts/templates/eks-cht-ingress.yaml @@ -0,0 +1,38 @@ +{{- if eq .Values.cluster_type "eks" }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: cht-ingress + namespace: {{ .Values.global.namespace }} + annotations: + # ALB Configuration + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/tags: {{ .Values.ingress.annotations.tags }} + alb.ingress.kubernetes.io/group.name: {{ .Values.ingress.annotations.groupname }} + alb.ingress.kubernetes.io/target-type: ip + + # Backend uses HTTPS (nginx's self-signed cert) + alb.ingress.kubernetes.io/backend-protocol: HTTPS + alb.ingress.kubernetes.io/backend-protocol-version: HTTP1 + alb.ingress.kubernetes.io/healthcheck-path: / + alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS + + # SSL/TLS Configuration + alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.annotations.certificate }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]' + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01 +spec: + ingressClassName: alb + rules: + # ONLY CHT Application + - host: {{ .Values.ingress.chtHost }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx + port: + number: 443 +{{- end }} diff --git a/charts/templates/eks-openhim-console-ingress.yaml b/charts/templates/eks-openhim-console-ingress.yaml new file mode 100644 index 00000000..348ab484 --- /dev/null +++ b/charts/templates/eks-openhim-console-ingress.yaml @@ -0,0 +1,36 @@ +{{- if eq .Values.cluster_type "eks" }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: openhim-console-ingress + namespace: {{ .Values.global.namespace }} + annotations: + # ALB Configuration + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/tags: {{ .Values.ingress.annotations.tags }} + alb.ingress.kubernetes.io/group.name: {{ .Values.ingress.annotations.groupname }} + alb.ingress.kubernetes.io/target-type: ip + + # Backend uses HTTP + alb.ingress.kubernetes.io/backend-protocol: HTTP + alb.ingress.kubernetes.io/healthcheck-path: / + alb.ingress.kubernetes.io/healthcheck-protocol: HTTP + + # SSL/TLS Configuration + alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.annotations.certificate }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]' + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01 +spec: + ingressClassName: alb + rules: + - host: {{ .Values.ingress.openhimConsoleHost }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: openhim-console + port: + number: 80 +{{- end }} diff --git a/charts/templates/eks-openhim-core-ingress.yaml b/charts/templates/eks-openhim-core-ingress.yaml new file mode 100644 index 00000000..319c413b --- /dev/null +++ b/charts/templates/eks-openhim-core-ingress.yaml @@ -0,0 +1,37 @@ +{{- if eq .Values.cluster_type "eks" }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: openhim-core-ingress + namespace: {{ .Values.global.namespace }} + annotations: + # ALB Configuration + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/tags: {{ .Values.ingress.annotations.tags }} + alb.ingress.kubernetes.io/group.name: {{ .Values.ingress.annotations.groupname }} + alb.ingress.kubernetes.io/target-type: ip + + # Backend uses HTTPS (OpenHIM Core uses self-signed cert) + alb.ingress.kubernetes.io/backend-protocol: HTTPS + alb.ingress.kubernetes.io/backend-protocol-version: HTTP1 + alb.ingress.kubernetes.io/healthcheck-path: /heartbeat + alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS + + # SSL/TLS Configuration + alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.annotations.certificate }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]' + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01 +spec: + ingressClassName: alb + rules: + - host: {{ .Values.ingress.openhimCoreHost }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: openhim-core + port: + number: 8080 +{{- end }} diff --git a/charts/templates/eks-openhim-router-ingress.yaml b/charts/templates/eks-openhim-router-ingress.yaml new file mode 100644 index 00000000..bf716a17 --- /dev/null +++ b/charts/templates/eks-openhim-router-ingress.yaml @@ -0,0 +1,41 @@ +{{- if eq .Values.cluster_type "eks" }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: openhim-router-ingress + namespace: {{ .Values.global.namespace }} + annotations: + # ALB Configuration + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/tags: {{ .Values.ingress.annotations.tags }} + alb.ingress.kubernetes.io/group.name: {{ .Values.ingress.annotations.groupname }} + alb.ingress.kubernetes.io/target-type: ip + + # Backend uses HTTPS (OpenHIM Router uses self-signed cert) + alb.ingress.kubernetes.io/backend-protocol: HTTPS + alb.ingress.kubernetes.io/backend-protocol-version: HTTP1 + alb.ingress.kubernetes.io/healthcheck-path: / + alb.ingress.kubernetes.io/healthcheck-protocol: HTTPS + alb.ingress.kubernetes.io/healthcheck-interval-seconds: '30' + alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5' + alb.ingress.kubernetes.io/healthy-threshold-count: '2' + alb.ingress.kubernetes.io/unhealthy-threshold-count: '3' + + # SSL/TLS Configuration + alb.ingress.kubernetes.io/certificate-arn: {{ .Values.ingress.annotations.certificate }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]' + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-2017-01 +spec: + ingressClassName: alb + rules: + - host: {{ .Values.ingress.openhimRouterHost }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: openhim-core + port: + number: 5000 +{{- end }} diff --git a/charts/values-eks.yaml b/charts/values-eks.yaml new file mode 100644 index 00000000..11d4caaf --- /dev/null +++ b/charts/values-eks.yaml @@ -0,0 +1,42 @@ +global: + namespace: # Override namespace + +createNamespace: false + +persistence: + storageClass: # Override storage + +configurator: + image: 720541322708.dkr.ecr.eu-west-2.amazonaws.com/cht-interop/configurator:latest + imagePullPolicy: Always # Override pull policy + +mediator: + image: 720541322708.dkr.ecr.eu-west-2.amazonaws.com/cht-interop/mediator:latest + imagePullPolicy: Always + +service: + type: ClusterIP # Override service type + +ingress: + annotations: + groupname: "dev-cht-alb" + tags: "Environment=dev,Team=QA" + certificate: "arn:aws:iam::720541322708:server-certificate/2025-q4-wildcard-dev-medicmobile-org-letsencrypt" + # Ensure the host is not already taken. Valid characters for a subdomain are: + # a-z, 0-9, and - (but not as first or last character). + chtHost: "cht-interop.dev.medicmobile.org" # e.g. "mrjones.dev.medicmobile.org" + openhimConsoleHost: "openhim-cht-interop.dev.medicmobile.org" + openhimCoreHost: "openhim-api-cht-interop.dev.medicmobile.org" + openhimRouterHost: "openhim-router-cht-interop.dev.medicmobile.org" + hosted_zone_id: "Z3304WUAJTCM7P" + load_balancer: "dualstack.k8s-devchtalb-3eb0781cbb-694321496.eu-west-2.elb.amazonaws.com" + +cluster_type: "eks" + +resources: + requests: + memory: "512Mi" # Override resources + cpu: "250m" + limits: + memory: "2Gi" + cpu: "1000m" diff --git a/charts/values.yaml b/charts/values.yaml new file mode 100644 index 00000000..31bcf5ab --- /dev/null +++ b/charts/values.yaml @@ -0,0 +1,119 @@ +createNamespace: true # For template/01-namespace.yaml +cluster_type: "kind" # Default to KIND + +# Default values for health-interop +global: + namespace: cht-interop + +# Database configurations +couchdb: + image: public.ecr.aws/medic/cht-couchdb:4.1.0-alpha + storage: 10Gi + credentials: + username: admin + password: password + secret: secret + uuid: CC0C3BA1-88EE-4AE3-BFD3-6E0EE56ED534 + resources: + requests: + memory: "512Mi" + cpu: "250m" + limits: + memory: "2Gi" + cpu: "1000m" + +mongodb: + image: mongo:4.2 + storage: 5Gi + resources: + requests: + memory: "256Mi" + cpu: "200m" + limits: + memory: "1Gi" + cpu: "500m" + +postgresql: + image: postgres:14.1 + storage: 5Gi + credentials: + username: admin + password: instant101 + database: hapi + resources: + requests: + memory: "256Mi" + cpu: "200m" + limits: + memory: "1Gi" + cpu: "500m" + +# OpenHIM configuration +openhim: + core: + image: jembi/openhim-core:7 + replicas: 1 + console: + image: jembi/openhim-console:1.14.4 + replicas: 1 + config: + protocol: https + host: localhost + port: 8080 + +# CHT configuration +cht: + api: + image: public.ecr.aws/medic/cht-api:4.1.0-alpha + replicas: 1 + nginx: + image: public.ecr.aws/medic/cht-nginx:4.1.0-alpha + replicas: 1 + haproxy: + image: public.ecr.aws/medic/cht-haproxy:4.1.0-alpha + replicas: 1 + sentinel: + image: public.ecr.aws/medic/cht-sentinel:4.1.0-alpha + replicas: 1 + healthcheck: + image: public.ecr.aws/medic/cht-haproxy-healthcheck:4.1.0-alpha + replicas: 1 + +# HAPI FHIR configuration +hapiFhir: + image: hapiproject/hapi:v5.5.1 + replicas: 1 + +# Mediator configuration +mediator: + image: mediator:local + imagePullPolicy: Never + replicas: 1 + credentials: + openhimUsername: interop@openhim.org + openhimPassword: interop-password + fhirUsername: interop-client + fhirPassword: interop-password + chtUsername: admin + chtPassword: password + +# Configurator configuration +configurator: + image: configurator:local + imagePullPolicy: Never + +# Storage configuration +persistence: + storageClass: standard + chtCredentials: 1Gi + chtSsl: 1Gi + +# Service configuration +services: + nodePort: + nginx: 30080 + nginxHttps: 30443 + console: 30900 + mediator: 30600 + openhimCore: 30081 + diff --git a/kubernetes/01-namespace.yaml b/kubernetes/01-namespace.yaml deleted file mode 100644 index 8e9ba267..00000000 --- a/kubernetes/01-namespace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: health-interop - labels: - name: health-interop diff --git a/kubernetes/03-secrets.yaml b/kubernetes/03-secrets.yaml deleted file mode 100644 index c52c2a72..00000000 --- a/kubernetes/03-secrets.yaml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: database-credentials - namespace: health-interop -type: Opaque -stringData: - couchdb-user: "admin" - couchdb-password: "password" - couchdb-secret: "secret" - postgres-user: "admin" - postgres-password: "instant101" - postgres-db: "hapi" ---- -apiVersion: v1 -kind: Secret -metadata: - name: openhim-credentials - namespace: health-interop -type: Opaque -stringData: - openhim-username: "root@openhim.org" - openhim-password: "openhim-password" - openhim-client-password: "interop-password" - openhim-user-password: "interop-password" ---- -apiVersion: v1 -kind: Secret -metadata: - name: mediator-credentials - namespace: health-interop -type: Opaque -stringData: - openhim-username: "interop@openhim.org" - openhim-password: "interop-password" - fhir-username: "interop-client" - fhir-password: "interop-password" - cht-username: "admin" - cht-password: "password" - openimis-username: "Admin" - openimis-password: "admin123" diff --git a/kubernetes/04-persistent-volumes.yaml b/kubernetes/04-persistent-volumes.yaml deleted file mode 100644 index 89eb1821..00000000 --- a/kubernetes/04-persistent-volumes.yaml +++ /dev/null @@ -1,59 +0,0 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: couchdb-data - namespace: health-interop -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: cht-credentials - namespace: health-interop -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: cht-ssl - namespace: health-interop -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: hapi-db-volume - namespace: health-interop -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongo-data - namespace: health-interop -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi diff --git a/port-forward.sh b/port-forward.sh new file mode 100755 index 00000000..db47f48c --- /dev/null +++ b/port-forward.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +kubectl port-forward svc/openhim-core 8080:8080 -n health-interop > /dev/null 2>&1 & +kubectl port-forward svc/openhim-core 5001:5001 -n health-interop > /dev/null 2>&1 & +kubectl port-forward svc/openhim-console 9000:80 -n health-interop > /dev/null 2>&1 & +kubectl port-forward svc/api 5988:5988 -n health-interop > /dev/null 2>&1 & +kubectl port-forward svc/mediator 6000:6000 -n health-interop > /dev/null 2>&1 & + +echo "Port forwarding setup complete!" +echo "OpenHIM Console: http://localhost:9000" +echo "OpenHIM Core API: https://localhost:8080" +echo "OpenHIM Router: http://localhost:5001" +echo "CHT API: http://localhost:5988" +echo "Mediator: http://localhost:6000" +echo "" +echo "To stop all port forwards, run: pkill -f 'kubectl port-forward'" diff --git a/start_local_kubernetes.sh b/start_local_kubernetes.sh index 02feb67a..87421930 100755 --- a/start_local_kubernetes.sh +++ b/start_local_kubernetes.sh @@ -1,41 +1,150 @@ #!/bin/bash -# Delete the previous cluster -kind delete cluster --name health-interop +set -e # Exit on any error -# Create a fresh cluster -kind create cluster --name health-interop +echo "🚀 CHT Interoperability Stack Deployment" +echo "" -# Reload your custom images -kind load docker-image configurator:local --name health-interop -kind load docker-image mediator:local --name health-interop +# Check if cluster exists +CLUSTER_EXISTS=$(kind get clusters | grep -w "cht-interop" || echo "") -# Deploy everything again (in order) -kubectl apply -f kubernetes/01-namespace.yaml -kubectl apply -f kubernetes/02-configmap.yaml -kubectl apply -f kubernetes/03-secrets.yaml -kubectl apply -f kubernetes/04-persistent-volumes.yaml -kubectl apply -f kubernetes/05-databases.yaml +if [ -n "$CLUSTER_EXISTS" ]; then +  echo "⚠️  KIND cluster 'cht-interop' already exists." +  read -p "Do you want to delete and recreate it? (y/N): " -n 1 -r +  echo +  if [[ $REPLY =~ ^[Yy]$ ]]; then +    echo "Deleting existing KIND cluster..." +    kind delete cluster --name cht-interop +    CREATE_CLUSTER=true +  else +    echo "Keeping existing cluster..." +    CREATE_CLUSTER=false +  fi +else +  echo "No existing cluster found." +  CREATE_CLUSTER=true +fi -# Wait for databases to be ready, then continue -kubectl get pods -n health-interop -w +# Create cluster if needed +if [ "$CREATE_CLUSTER" = true ]; then +  echo "Creating fresh KIND cluster..." +  kind create cluster --name cht-interop +  if [ $? -ne 0 ]; then +    echo "❌ Failed to create KIND cluster" +    exit 1 +  fi +fi -# Once databases are running, deploy the rest -kubectl apply -f kubernetes/06-openhim-core.yaml -kubectl apply -f kubernetes/07-openhim-console.yaml -kubectl apply -f kubernetes/08-hapi-fhir.yaml -kubectl apply -f kubernetes/09-cht-services.yaml -kubectl apply -f kubernetes/10-mediator-services.yaml +# Build and load custom images +echo "" +echo "Building and loading custom images..." -# OpenHIM Core - Management API (HTTPS) -kubectl port-forward svc/openhim-core 8080:8080 -n health-interop & +# Build configurator +if [ -d "./configurator" ]; then +  echo "Building configurator image..." +  docker build -f configurator/Dockerfile -t configurator:local . +  if [ $? -ne 0 ]; then +    echo "❌ Failed to build configurator image" +    exit 1 +  fi +  kind load docker-image configurator:local --name cht-interop +else +  echo "⚠️  Configurator directory not found, skipping build" +fi -# OpenHIM Core - HTTP Router (routes to mediators) -kubectl port-forward svc/openhim-core 5001:5001 -n health-interop & +# Build mediator +if [ -d "./mediator" ]; then +  echo "Building mediator image..." +  docker build -t mediator:local ./mediator +  if [ $? -ne 0 ]; then +    echo "❌ Failed to build mediator image" +    exit 1 +  fi +  kind load docker-image mediator:local --name cht-interop +else +  echo "⚠️  Mediator directory not found, skipping build" +fi -# OpenHIM Console - Management interface -kubectl port-forward svc/openhim-console 9000:80 -n health-interop & +# Check if Helm release exists +RELEASE_EXISTS=$(helm list -n cht-interop | grep -w "cht-interop" || echo "") -# CHT - Community Health Toolkit (via Nginx) -kubectl port-forward svc/nginx 8081:80 -n health-interop & -kubectl port-forward svc/nginx 8444:443 -n health-interop & +if [ -n "$RELEASE_EXISTS" ]; then +  echo "" +  echo "Helm release 'cht-interop' already exists." +  read -p "Do you want to upgrade it? (Y/n): " -n 1 -r +  echo +  if [[ ! $REPLY =~ ^[Nn]$ ]]; then +    echo "Upgrading Helm release..." +    helm upgrade cht-interop ./charts +    if [ $? -ne 0 ]; then +      echo "❌ Failed to upgrade Helm release" +      exit 1 +    fi +  else +    echo "Skipping Helm deployment..." +  fi +else +  # Deploy using Helm +  echo "" +  echo "Deploying with Helm..." +  helm install cht-interop ./charts +  if [ $? -ne 0 ]; then +    echo "❌ Failed to install Helm release" +    exit 1 +  fi +fi + +# Wait for pods to be ready +echo "" +echo "Waiting for pods to be ready..." +echo "You can monitor progress with: kubectl get pods -n cht-interop -w" +echo "Or use K9s: k9s --context kind-cht-interop" + +# Wait for critical services with timeout +echo "" +echo "Waiting for databases to be ready..." +kubectl wait --for=condition=ready pod -l app=mongo -n cht-interop --timeout=300s || echo "⚠️  MongoDB not ready yet" +kubectl wait --for=condition=ready pod -l app=couchdb -n cht-interop --timeout=300s || echo "⚠️  CouchDB not ready yet" +kubectl wait --for=condition=ready pod -l app=hapi-db -n cht-interop --timeout=300s || echo "⚠️  PostgreSQL not ready yet" + +echo "Waiting for OpenHIM Core to be ready..." +kubectl wait --for=condition=ready pod -l app=openhim-core -n cht-interop --timeout=300s || echo "⚠️  OpenHIM Core not ready yet" + +echo "" +echo "✅ Deployment complete!" + +# Setup port forwarding +echo "" +echo "Setting up port forwarding..." + +# Kill any existing port forwards +pkill -f "kubectl port-forward.*cht-interop" 2>/dev/null || true + +kubectl port-forward svc/openhim-core 8080:8080 -n cht-interop >/dev/null 2>&1 & +kubectl port-forward svc/openhim-core 5001:5001 -n cht-interop >/dev/null 2>&1 & +kubectl port-forward svc/openhim-console 9000:80 -n cht-interop >/dev/null 2>&1 & +kubectl port-forward svc/api 5988:5988 -n cht-interop >/dev/null 2>&1 & +kubectl port-forward svc/mediator 6000:6000 -n cht-interop >/dev/null 2>&1 & + +sleep 2 # Give port forwards time to establish + +echo "" +echo "🎉 CHT Interoperability Stack is ready!" +echo "" +echo "📍 Access services at:" +echo "   OpenHIM Console: http://localhost:9000" +echo "   OpenHIM Core API: https://localhost:8080" +echo "   OpenHIM Router: http://localhost:5001" +echo "   CHT API: http://localhost:5988" +echo "   Mediator: http://localhost:6000" +echo "" +echo "🔑 Default credentials:" +echo "   OpenHIM: root@openhim.org / openhim-password" +echo "" +echo "🛠️  Useful commands:" +echo "   View pods: kubectl get pods -n cht-interop" +echo "   View logs: kubectl logs -n cht-interop" +echo "   Use K9s: k9s --context kind-cht-interop" +echo "   Stop port forwards: pkill -f 'kubectl port-forward'" +echo "   Helm status: helm status cht-interop -n cht-interop" +echo "" From 6af798b6a640e8a6800aed8da4fcbf338aa1963d Mon Sep 17 00:00:00 2001 From: Sugat Bajracharya Date: Fri, 7 Nov 2025 13:46:52 +0545 Subject: [PATCH 3/5] missed helm chart renaming --- charts/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/Chart.yaml b/charts/Chart.yaml index 68f68c1c..2ed480c6 100644 --- a/charts/Chart.yaml +++ b/charts/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -name: health-interop -description: A Helm chart for Health Interoperability Stack +name: cht-interop +description: A Helm chart for CHT Interoperability Stack type: application version: 1.0.0 appVersion: "1.0" From 2d6af1555ae8ffc1c5058501bcec94f638455dd6 Mon Sep 17 00:00:00 2001 From: Sugat Bajracharya Date: Tue, 20 Jan 2026 17:16:15 +0545 Subject: [PATCH 4/5] feedback changes and using node-port directly locally instead of port-forwarding due to reliability issues --- charts/templates/04-persistent-volumes.yaml | 4 + charts/templates/05-databases.yaml | 11 ++ charts/templates/06-openhim-core.yaml | 12 ++ charts/templates/07-openhim-console.yaml | 10 + charts/templates/08-hapi-fhir.yaml | 11 +- charts/templates/09-cht-services.yaml | 52 ++++++ charts/templates/10-mediator-services.yaml | 32 ++++ charts/templates/eks-cht-ingress.yaml | 2 +- charts/values-eks.yaml | 19 +- charts/values.yaml | 109 ++++++++++- port-forward.sh | 16 -- remove_local_kubernetes.sh | 45 +++++ start_local_kubernetes.sh | 193 ++++++++++---------- 13 files changed, 389 insertions(+), 127 deletions(-) delete mode 100755 port-forward.sh create mode 100755 remove_local_kubernetes.sh diff --git a/charts/templates/04-persistent-volumes.yaml b/charts/templates/04-persistent-volumes.yaml index 12efb146..9d76752b 100644 --- a/charts/templates/04-persistent-volumes.yaml +++ b/charts/templates/04-persistent-volumes.yaml @@ -1,3 +1,4 @@ +{{- if .Values.couchdb.enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: @@ -23,7 +24,9 @@ spec: resources: requests: storage: {{ .Values.persistence.chtCredentials }} +{{- end }} --- +{{- if .Values.cht.enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: @@ -36,6 +39,7 @@ spec: resources: requests: storage: {{ .Values.persistence.chtSsl }} +{{- end }} --- apiVersion: v1 kind: PersistentVolumeClaim diff --git a/charts/templates/05-databases.yaml b/charts/templates/05-databases.yaml index b834c2ed..9995327d 100644 --- a/charts/templates/05-databases.yaml +++ b/charts/templates/05-databases.yaml @@ -14,6 +14,7 @@ spec: labels: app: mongo spec: + automountServiceAccountToken: false containers: - name: mongo image: {{ .Values.mongodb.image }} @@ -21,9 +22,11 @@ spec: requests: memory: {{ .Values.mongodb.resources.requests.memory | quote }} cpu: {{ .Values.mongodb.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.mongodb.resources.requests "ephemeral-storage" | quote }} limits: memory: {{ .Values.mongodb.resources.limits.memory | quote }} cpu: {{ .Values.mongodb.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.mongodb.resources.limits "ephemeral-storage" | quote }} ports: - containerPort: 27017 volumeMounts: @@ -62,6 +65,7 @@ spec: labels: app: hapi-db spec: + automountServiceAccountToken: false containers: - name: hapi-db image: {{ .Values.postgresql.image }} @@ -69,9 +73,11 @@ spec: requests: memory: {{ .Values.postgresql.resources.requests.memory | quote }} cpu: {{ .Values.postgresql.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.postgresql.resources.requests "ephemeral-storage" | quote }} limits: memory: {{ .Values.postgresql.resources.limits.memory | quote }} cpu: {{ .Values.postgresql.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.postgresql.resources.limits "ephemeral-storage" | quote }} env: - name: POSTGRES_USER valueFrom: @@ -112,6 +118,7 @@ spec: - port: 5432 targetPort: 5432 --- +{{- if .Values.couchdb.enabled }} # CouchDB for CHT apiVersion: apps/v1 kind: Deployment @@ -128,6 +135,7 @@ spec: labels: app: couchdb spec: + automountServiceAccountToken: false containers: - name: couchdb image: {{ .Values.couchdb.image }} @@ -135,9 +143,11 @@ spec: requests: memory: {{ .Values.couchdb.resources.requests.memory | quote }} cpu: {{ .Values.couchdb.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.couchdb.resources.requests "ephemeral-storage" | quote }} limits: memory: {{ .Values.couchdb.resources.limits.memory | quote }} cpu: {{ .Values.couchdb.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.couchdb.resources.limits "ephemeral-storage" | quote }} env: - name: COUCHDB_USER valueFrom: @@ -187,3 +197,4 @@ spec: ports: - port: 5984 targetPort: 5984 +{{- end }} diff --git a/charts/templates/06-openhim-core.yaml b/charts/templates/06-openhim-core.yaml index 277074ea..f3600ccf 100644 --- a/charts/templates/06-openhim-core.yaml +++ b/charts/templates/06-openhim-core.yaml @@ -13,6 +13,7 @@ spec: labels: app: openhim-core spec: + automountServiceAccountToken: false containers: - name: openhim-core image: {{ .Values.openhim.core.image }} @@ -29,6 +30,15 @@ spec: - containerPort: 5051 - containerPort: 5052 - containerPort: 7788 + resources: + requests: + memory: {{ .Values.openhim.core.resources.requests.memory | quote }} + cpu: {{ .Values.openhim.core.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.openhim.core.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.openhim.core.resources.limits.memory | quote }} + cpu: {{ .Values.openhim.core.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.openhim.core.resources.limits "ephemeral-storage" | quote }} readinessProbe: httpGet: path: /heartbeat @@ -103,7 +113,9 @@ spec: - name: router-http port: 5000 targetPort: 5000 + nodePort: {{ .Values.services.nodePort.openhimRouterHttp | default 30500 }} - name: router-https port: 5001 targetPort: 5001 + nodePort: {{ .Values.services.nodePort.openhimRouterHttps | default 30501 }} {{- end }} diff --git a/charts/templates/07-openhim-console.yaml b/charts/templates/07-openhim-console.yaml index e886feb5..236158af 100644 --- a/charts/templates/07-openhim-console.yaml +++ b/charts/templates/07-openhim-console.yaml @@ -13,11 +13,21 @@ spec: labels: app: openhim-console spec: + automountServiceAccountToken: false containers: - name: openhim-console image: {{ .Values.openhim.console.image }} ports: - containerPort: 80 + resources: + requests: + memory: {{ .Values.openhim.console.resources.requests.memory | quote }} + cpu: {{ .Values.openhim.console.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.openhim.console.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.openhim.console.resources.limits.memory | quote }} + cpu: {{ .Values.openhim.console.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.openhim.console.resources.limits "ephemeral-storage" | quote }} volumeMounts: - name: console-config mountPath: /usr/share/nginx/html/config/default.json diff --git a/charts/templates/08-hapi-fhir.yaml b/charts/templates/08-hapi-fhir.yaml index fa6e934e..aaf3a1de 100644 --- a/charts/templates/08-hapi-fhir.yaml +++ b/charts/templates/08-hapi-fhir.yaml @@ -13,6 +13,7 @@ spec: labels: app: hapi-fhir spec: + automountServiceAccountToken: false containers: - name: hapi-fhir image: {{ .Values.hapiFhir.image }} @@ -47,11 +48,13 @@ spec: - containerPort: 8080 resources: requests: - memory: "2Gi" - cpu: "500m" + memory: {{ .Values.hapiFhir.resources.requests.memory | quote }} + cpu: {{ .Values.hapiFhir.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.hapiFhir.resources.requests "ephemeral-storage" | quote }} limits: - memory: "3Gi" - cpu: "1000m" + memory: {{ .Values.hapiFhir.resources.limits.memory | quote }} + cpu: {{ .Values.hapiFhir.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.hapiFhir.resources.limits "ephemeral-storage" | quote }} readinessProbe: httpGet: path: /fhir/metadata diff --git a/charts/templates/09-cht-services.yaml b/charts/templates/09-cht-services.yaml index 9193601a..e2a7a2b5 100644 --- a/charts/templates/09-cht-services.yaml +++ b/charts/templates/09-cht-services.yaml @@ -1,3 +1,4 @@ +{{- if .Values.cht.enabled }} # HAProxy for CouchDB load balancing apiVersion: apps/v1 kind: Deployment @@ -14,9 +15,19 @@ spec: labels: app: haproxy spec: + automountServiceAccountToken: false containers: - name: haproxy image: {{ .Values.cht.haproxy.image }} + resources: + requests: + memory: {{ .Values.cht.haproxy.resources.requests.memory | quote }} + cpu: {{ .Values.cht.haproxy.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.haproxy.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.cht.haproxy.resources.limits.memory | quote }} + cpu: {{ .Values.cht.haproxy.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.haproxy.resources.limits "ephemeral-storage" | quote }} env: - name: HAPROXY_IP value: "0.0.0.0" @@ -68,9 +79,19 @@ spec: labels: app: healthcheck spec: + automountServiceAccountToken: false containers: - name: healthcheck image: {{ .Values.cht.healthcheck.image }} + resources: + requests: + memory: {{ .Values.cht.healthcheck.resources.requests.memory | quote }} + cpu: {{ .Values.cht.healthcheck.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.healthcheck.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.cht.healthcheck.resources.limits.memory | quote }} + cpu: {{ .Values.cht.healthcheck.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.healthcheck.resources.limits "ephemeral-storage" | quote }} env: - name: COUCHDB_SERVERS value: "couchdb" @@ -114,10 +135,20 @@ spec: labels: app: api spec: + automountServiceAccountToken: false hostname: localhost containers: - name: api image: {{ .Values.cht.api.image }} + resources: + requests: + memory: {{ .Values.cht.api.resources.requests.memory | quote }} + cpu: {{ .Values.cht.api.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.api.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.cht.api.resources.limits.memory | quote }} + cpu: {{ .Values.cht.api.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.api.resources.limits "ephemeral-storage" | quote }} env: - name: COUCH_URL value: "http://admin:password@haproxy:5984/medic" @@ -185,9 +216,19 @@ spec: labels: app: sentinel spec: + automountServiceAccountToken: false containers: - name: sentinel image: {{ .Values.cht.sentinel.image }} + resources: + requests: + memory: {{ .Values.cht.sentinel.resources.requests.memory | quote }} + cpu: {{ .Values.cht.sentinel.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.sentinel.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.cht.sentinel.resources.limits.memory | quote }} + cpu: {{ .Values.cht.sentinel.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.sentinel.resources.limits "ephemeral-storage" | quote }} env: - name: COUCH_URL value: "http://admin:password@haproxy:5984/medic" @@ -215,9 +256,19 @@ spec: labels: app: nginx spec: + automountServiceAccountToken: false containers: - name: nginx image: {{ .Values.cht.nginx.image }} + resources: + requests: + memory: {{ .Values.cht.nginx.resources.requests.memory | quote }} + cpu: {{ .Values.cht.nginx.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.nginx.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.cht.nginx.resources.limits.memory | quote }} + cpu: {{ .Values.cht.nginx.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.cht.nginx.resources.limits "ephemeral-storage" | quote }} env: - name: API_HOST value: "api" @@ -311,3 +362,4 @@ spec: targetPort: 443 nodePort: {{ .Values.services.nodePort.nginxHttps }} {{- end }} +{{- end }} diff --git a/charts/templates/10-mediator-services.yaml b/charts/templates/10-mediator-services.yaml index f107f279..8df237da 100644 --- a/charts/templates/10-mediator-services.yaml +++ b/charts/templates/10-mediator-services.yaml @@ -7,10 +7,20 @@ metadata: spec: template: spec: + automountServiceAccountToken: false containers: - name: configurator image: {{ .Values.configurator.image }} imagePullPolicy: {{ .Values.configurator.imagePullPolicy }} + resources: + requests: + memory: {{ .Values.configurator.resources.requests.memory | quote }} + cpu: {{ .Values.configurator.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.configurator.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.configurator.resources.limits.memory | quote }} + cpu: {{ .Values.configurator.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.configurator.resources.limits "ephemeral-storage" | quote }} env: - name: COUCHDB_USER valueFrom: @@ -69,10 +79,20 @@ spec: labels: app: mediator spec: + automountServiceAccountToken: false containers: - name: mediator image: {{ .Values.mediator.image }} imagePullPolicy: {{ .Values.mediator.imagePullPolicy }} + resources: + requests: + memory: {{ .Values.mediator.resources.requests.memory | quote }} + cpu: {{ .Values.mediator.resources.requests.cpu | quote }} + ephemeral-storage: {{ index .Values.mediator.resources.requests "ephemeral-storage" | quote }} + limits: + memory: {{ .Values.mediator.resources.limits.memory | quote }} + cpu: {{ .Values.mediator.resources.limits.cpu | quote }} + ephemeral-storage: {{ index .Values.mediator.resources.limits "ephemeral-storage" | quote }} ports: - containerPort: 6000 env: @@ -103,17 +123,29 @@ spec: name: mediator-credentials key: fhir-password - name: CHT_URL + {{- if .Values.cht.enabled }} value: "https://nginx" + {{- else }} + value: {{ .Values.cht.external.url | quote }} + {{- end }} - name: CHT_USERNAME + {{- if .Values.cht.enabled }} valueFrom: secretKeyRef: name: mediator-credentials key: cht-username + {{- else }} + value: {{ .Values.cht.external.username | quote }} + {{- end }} - name: CHT_PASSWORD + {{- if .Values.cht.enabled }} valueFrom: secretKeyRef: name: mediator-credentials key: cht-password + {{- else }} + value: {{ .Values.cht.external.password | quote }} + {{- end }} - name: OPENIMIS_API_URL value: "https://openimis.s2.openimis.org" - name: OPENIMIS_USERNAME diff --git a/charts/templates/eks-cht-ingress.yaml b/charts/templates/eks-cht-ingress.yaml index 3be9cff7..442aa109 100644 --- a/charts/templates/eks-cht-ingress.yaml +++ b/charts/templates/eks-cht-ingress.yaml @@ -1,4 +1,4 @@ -{{- if eq .Values.cluster_type "eks" }} +{{- if and (eq .Values.cluster_type "eks") .Values.cht.enabled }} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: diff --git a/charts/values-eks.yaml b/charts/values-eks.yaml index 11d4caaf..bbde92b5 100644 --- a/charts/values-eks.yaml +++ b/charts/values-eks.yaml @@ -1,10 +1,10 @@ global: - namespace: # Override namespace + namespace: # Override namespace (e.g., "my-namespace") createNamespace: false persistence: - storageClass: # Override storage + storageClass: # Override storage (e.g., "gp2" for AWS) configurator: image: 720541322708.dkr.ecr.eu-west-2.amazonaws.com/cht-interop/configurator:latest @@ -21,7 +21,7 @@ ingress: annotations: groupname: "dev-cht-alb" tags: "Environment=dev,Team=QA" - certificate: "arn:aws:iam::720541322708:server-certificate/2025-q4-wildcard-dev-medicmobile-org-letsencrypt" + certificate: "arn:aws:iam::720541322708:server-certificate/2026-q1-wildcard-dev-medicmobile-org-letsencrypt" # Ensure the host is not already taken. Valid characters for a subdomain are: # a-z, 0-9, and - (but not as first or last character). chtHost: "cht-interop.dev.medicmobile.org" # e.g. "mrjones.dev.medicmobile.org" @@ -33,6 +33,19 @@ ingress: cluster_type: "eks" +# CHT and CouchDB configuration +# Set to false to use an external CHT instance (common for EKS deployments) +couchdb: + enabled: true + +cht: + enabled: true + # External CHT configuration (used when cht.enabled=false) + external: + url: "" # e.g., https://your-cht-instance.example.com + username: "" + password: "" + resources: requests: memory: "512Mi" # Override resources diff --git a/charts/values.yaml b/charts/values.yaml index 31bcf5ab..755b98a9 100644 --- a/charts/values.yaml +++ b/charts/values.yaml @@ -1,5 +1,5 @@ createNamespace: true # For template/01-namespace.yaml -cluster_type: "kind" # Default to KIND +cluster_type: "k3d" # Default to k3d for local development # Default values for health-interop global: @@ -7,6 +7,7 @@ global: # Database configurations couchdb: + enabled: true # Set to false to use external CHT/CouchDB image: public.ecr.aws/medic/cht-couchdb:4.1.0-alpha storage: 10Gi credentials: @@ -18,9 +19,11 @@ couchdb: requests: memory: "512Mi" cpu: "250m" + ephemeral-storage: "500Mi" limits: memory: "2Gi" cpu: "1000m" + ephemeral-storage: "2Gi" mongodb: image: mongo:4.2 @@ -29,9 +32,11 @@ mongodb: requests: memory: "256Mi" cpu: "200m" + ephemeral-storage: "256Mi" limits: memory: "1Gi" cpu: "500m" + ephemeral-storage: "1Gi" postgresql: image: postgres:14.1 @@ -44,18 +49,38 @@ postgresql: requests: memory: "256Mi" cpu: "200m" + ephemeral-storage: "256Mi" limits: memory: "1Gi" cpu: "500m" + ephemeral-storage: "1Gi" # OpenHIM configuration openhim: core: image: jembi/openhim-core:7 replicas: 1 + resources: + requests: + memory: "256Mi" + cpu: "100m" + ephemeral-storage: "100Mi" + limits: + memory: "512Mi" + cpu: "500m" + ephemeral-storage: "500Mi" console: image: jembi/openhim-console:1.14.4 replicas: 1 + resources: + requests: + memory: "64Mi" + cpu: "50m" + ephemeral-storage: "50Mi" + limits: + memory: "128Mi" + cpu: "200m" + ephemeral-storage: "200Mi" config: protocol: https host: localhost @@ -63,32 +88,101 @@ openhim: # CHT configuration cht: + enabled: true # Set to false to use external CHT instance + # External CHT configuration (used when cht.enabled=false) + external: + url: "" # e.g., https://external-cht.example.com + username: "" + password: "" api: image: public.ecr.aws/medic/cht-api:4.1.0-alpha replicas: 1 + resources: + requests: + memory: "256Mi" + cpu: "100m" + ephemeral-storage: "100Mi" + limits: + memory: "512Mi" + cpu: "500m" + ephemeral-storage: "500Mi" nginx: image: public.ecr.aws/medic/cht-nginx:4.1.0-alpha replicas: 1 + resources: + requests: + memory: "64Mi" + cpu: "50m" + ephemeral-storage: "50Mi" + limits: + memory: "256Mi" + cpu: "200m" + ephemeral-storage: "200Mi" haproxy: image: public.ecr.aws/medic/cht-haproxy:4.1.0-alpha replicas: 1 + resources: + requests: + memory: "64Mi" + cpu: "50m" + ephemeral-storage: "50Mi" + limits: + memory: "256Mi" + cpu: "200m" + ephemeral-storage: "200Mi" sentinel: image: public.ecr.aws/medic/cht-sentinel:4.1.0-alpha replicas: 1 + resources: + requests: + memory: "128Mi" + cpu: "100m" + ephemeral-storage: "100Mi" + limits: + memory: "256Mi" + cpu: "300m" + ephemeral-storage: "300Mi" healthcheck: image: public.ecr.aws/medic/cht-haproxy-healthcheck:4.1.0-alpha replicas: 1 + resources: + requests: + memory: "32Mi" + cpu: "25m" + ephemeral-storage: "50Mi" + limits: + memory: "64Mi" + cpu: "100m" + ephemeral-storage: "100Mi" # HAPI FHIR configuration hapiFhir: image: hapiproject/hapi:v5.5.1 replicas: 1 + resources: + requests: + memory: "2Gi" + cpu: "500m" + ephemeral-storage: "500Mi" + limits: + memory: "3Gi" + cpu: "1000m" + ephemeral-storage: "2Gi" # Mediator configuration mediator: image: mediator:local imagePullPolicy: Never replicas: 1 + resources: + requests: + memory: "128Mi" + cpu: "100m" + ephemeral-storage: "100Mi" + limits: + memory: "256Mi" + cpu: "300m" + ephemeral-storage: "300Mi" credentials: openhimUsername: interop@openhim.org openhimPassword: interop-password @@ -101,10 +195,19 @@ mediator: configurator: image: configurator:local imagePullPolicy: Never + resources: + requests: + memory: "128Mi" + cpu: "100m" + ephemeral-storage: "100Mi" + limits: + memory: "256Mi" + cpu: "300m" + ephemeral-storage: "300Mi" # Storage configuration persistence: - storageClass: standard + storageClass: local-path # k3d default storage class chtCredentials: 1Gi chtSsl: 1Gi @@ -116,4 +219,6 @@ services: console: 30900 mediator: 30600 openhimCore: 30081 + openhimRouterHttp: 30500 + openhimRouterHttps: 30501 diff --git a/port-forward.sh b/port-forward.sh deleted file mode 100755 index db47f48c..00000000 --- a/port-forward.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -kubectl port-forward svc/openhim-core 8080:8080 -n health-interop > /dev/null 2>&1 & -kubectl port-forward svc/openhim-core 5001:5001 -n health-interop > /dev/null 2>&1 & -kubectl port-forward svc/openhim-console 9000:80 -n health-interop > /dev/null 2>&1 & -kubectl port-forward svc/api 5988:5988 -n health-interop > /dev/null 2>&1 & -kubectl port-forward svc/mediator 6000:6000 -n health-interop > /dev/null 2>&1 & - -echo "Port forwarding setup complete!" -echo "OpenHIM Console: http://localhost:9000" -echo "OpenHIM Core API: https://localhost:8080" -echo "OpenHIM Router: http://localhost:5001" -echo "CHT API: http://localhost:5988" -echo "Mediator: http://localhost:6000" -echo "" -echo "To stop all port forwards, run: pkill -f 'kubectl port-forward'" diff --git a/remove_local_kubernetes.sh b/remove_local_kubernetes.sh new file mode 100755 index 00000000..d21cd6ca --- /dev/null +++ b/remove_local_kubernetes.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +set -e # Exit on any error + +echo "CHT Interoperability Stack Cleanup (k3d)" +echo "" + +# Check if cluster exists +CLUSTER_EXISTS=$(k3d cluster list | grep -w "cht-interop" || echo "") + +if [[ -z "$CLUSTER_EXISTS" ]]; then + echo "No k3d cluster 'cht-interop' found. Nothing to clean up." + exit 0 +fi + +echo "This will delete:" +echo " - k3d cluster 'cht-interop'" +echo " - All pods, services, and data in the cluster" +echo "" +read -p "Are you sure you want to proceed? (y/N): " -n 1 -r +echo + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Cleanup cancelled." + exit 0 +fi + +echo "" +echo "Deleting k3d cluster 'cht-interop'..." +k3d cluster delete cht-interop + +if [[ $? -eq 0 ]]; then + echo "" + echo "Cleanup complete!" + echo "" + echo "The following have been removed:" + echo " - k3d cluster 'cht-interop'" + echo " - All associated containers and volumes" + echo "" + echo "To redeploy, run: ./start_local_kubernetes.sh" +else + echo "" + echo "Failed to delete cluster" + exit 1 +fi diff --git a/start_local_kubernetes.sh b/start_local_kubernetes.sh index 87421930..288c31b1 100755 --- a/start_local_kubernetes.sh +++ b/start_local_kubernetes.sh @@ -2,37 +2,43 @@ set -e # Exit on any error -echo "🚀 CHT Interoperability Stack Deployment" +echo "CHT Interoperability Stack Deployment (k3d)" echo "" # Check if cluster exists -CLUSTER_EXISTS=$(kind get clusters | grep -w "cht-interop" || echo "") - -if [ -n "$CLUSTER_EXISTS" ]; then -  echo "⚠️  KIND cluster 'cht-interop' already exists." -  read -p "Do you want to delete and recreate it? (y/N): " -n 1 -r -  echo -  if [[ $REPLY =~ ^[Yy]$ ]]; then -    echo "Deleting existing KIND cluster..." -    kind delete cluster --name cht-interop -    CREATE_CLUSTER=true -  else -    echo "Keeping existing cluster..." -    CREATE_CLUSTER=false -  fi +CLUSTER_EXISTS=$(k3d cluster list | grep -w "cht-interop" || echo "") + +if [[ -n "$CLUSTER_EXISTS" ]]; then + echo "k3d cluster 'cht-interop' already exists." + read -p "Do you want to delete and recreate it? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "Deleting existing k3d cluster..." + k3d cluster delete cht-interop + CREATE_CLUSTER=true + else + echo "Keeping existing cluster..." + CREATE_CLUSTER=false + fi else -  echo "No existing cluster found." -  CREATE_CLUSTER=true + echo "No existing cluster found." + CREATE_CLUSTER=true fi # Create cluster if needed -if [ "$CREATE_CLUSTER" = true ]; then -  echo "Creating fresh KIND cluster..." -  kind create cluster --name cht-interop -  if [ $? -ne 0 ]; then -    echo "❌ Failed to create KIND cluster" -    exit 1 -  fi +if [[ "$CREATE_CLUSTER" == true ]]; then + echo "Creating fresh k3d cluster with port mappings..." + k3d cluster create cht-interop --agents 1 \ + --port "8080:30081@loadbalancer" \ + --port "9000:30900@loadbalancer" \ + --port "6000:30600@loadbalancer" \ + --port "5001:30501@loadbalancer" \ + --port "80:30080@loadbalancer" \ + --port "443:30443@loadbalancer" + if [[ $? -ne 0 ]]; then + echo "Failed to create k3d cluster" + exit 1 + fi fi # Build and load custom images @@ -40,111 +46,96 @@ echo "" echo "Building and loading custom images..." # Build configurator -if [ -d "./configurator" ]; then -  echo "Building configurator image..." -  docker build -f configurator/Dockerfile -t configurator:local . -  if [ $? -ne 0 ]; then -    echo "❌ Failed to build configurator image" -    exit 1 -  fi -  kind load docker-image configurator:local --name cht-interop +if [[ -d "./configurator" ]]; then + echo "Building configurator image..." + docker build -f configurator/Dockerfile -t configurator:local . + if [[ $? -ne 0 ]]; then + echo "Failed to build configurator image" + exit 1 + fi + k3d image import configurator:local -c cht-interop else -  echo "⚠️  Configurator directory not found, skipping build" + echo "Configurator directory not found, skipping build" fi # Build mediator -if [ -d "./mediator" ]; then -  echo "Building mediator image..." -  docker build -t mediator:local ./mediator -  if [ $? -ne 0 ]; then -    echo "❌ Failed to build mediator image" -    exit 1 -  fi -  kind load docker-image mediator:local --name cht-interop +if [[ -d "./mediator" ]]; then + echo "Building mediator image..." + docker build -t mediator:local ./mediator + if [[ $? -ne 0 ]]; then + echo "Failed to build mediator image" + exit 1 + fi + k3d image import mediator:local -c cht-interop else -  echo "⚠️  Mediator directory not found, skipping build" + echo "Mediator directory not found, skipping build" fi # Check if Helm release exists RELEASE_EXISTS=$(helm list -n cht-interop | grep -w "cht-interop" || echo "") -if [ -n "$RELEASE_EXISTS" ]; then -  echo "" -  echo "Helm release 'cht-interop' already exists." -  read -p "Do you want to upgrade it? (Y/n): " -n 1 -r -  echo -  if [[ ! $REPLY =~ ^[Nn]$ ]]; then -    echo "Upgrading Helm release..." -    helm upgrade cht-interop ./charts -    if [ $? -ne 0 ]; then -      echo "❌ Failed to upgrade Helm release" -      exit 1 -    fi -  else -    echo "Skipping Helm deployment..." -  fi +if [[ -n "$RELEASE_EXISTS" ]]; then + echo "" + echo "Helm release 'cht-interop' already exists." + read -p "Do you want to upgrade it? (Y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Nn]$ ]]; then + echo "Upgrading Helm release..." + helm upgrade cht-interop ./charts + if [[ $? -ne 0 ]]; then + echo "Failed to upgrade Helm release" + exit 1 + fi + else + echo "Skipping Helm deployment..." + fi else -  # Deploy using Helm -  echo "" -  echo "Deploying with Helm..." -  helm install cht-interop ./charts -  if [ $? -ne 0 ]; then -    echo "❌ Failed to install Helm release" -    exit 1 -  fi + # Deploy using Helm + echo "" + echo "Deploying with Helm..." + helm install cht-interop ./charts + if [[ $? -ne 0 ]]; then + echo "Failed to install Helm release" + exit 1 + fi fi # Wait for pods to be ready echo "" echo "Waiting for pods to be ready..." echo "You can monitor progress with: kubectl get pods -n cht-interop -w" -echo "Or use K9s: k9s --context kind-cht-interop" +echo "Or use K9s: k9s --context k3d-cht-interop" # Wait for critical services with timeout echo "" echo "Waiting for databases to be ready..." -kubectl wait --for=condition=ready pod -l app=mongo -n cht-interop --timeout=300s || echo "⚠️  MongoDB not ready yet" -kubectl wait --for=condition=ready pod -l app=couchdb -n cht-interop --timeout=300s || echo "⚠️  CouchDB not ready yet" -kubectl wait --for=condition=ready pod -l app=hapi-db -n cht-interop --timeout=300s || echo "⚠️  PostgreSQL not ready yet" +kubectl wait --for=condition=ready pod -l app=mongo -n cht-interop --timeout=300s || echo "MongoDB not ready yet" +kubectl wait --for=condition=ready pod -l app=couchdb -n cht-interop --timeout=300s || echo "CouchDB not ready yet" +kubectl wait --for=condition=ready pod -l app=hapi-db -n cht-interop --timeout=300s || echo "PostgreSQL not ready yet" echo "Waiting for OpenHIM Core to be ready..." -kubectl wait --for=condition=ready pod -l app=openhim-core -n cht-interop --timeout=300s || echo "⚠️  OpenHIM Core not ready yet" - -echo "" -echo "✅ Deployment complete!" +kubectl wait --for=condition=ready pod -l app=openhim-core -n cht-interop --timeout=300s || echo "OpenHIM Core not ready yet" -# Setup port forwarding echo "" -echo "Setting up port forwarding..." - -# Kill any existing port forwards -pkill -f "kubectl port-forward.*cht-interop" 2>/dev/null || true - -kubectl port-forward svc/openhim-core 8080:8080 -n cht-interop >/dev/null 2>&1 & -kubectl port-forward svc/openhim-core 5001:5001 -n cht-interop >/dev/null 2>&1 & -kubectl port-forward svc/openhim-console 9000:80 -n cht-interop >/dev/null 2>&1 & -kubectl port-forward svc/api 5988:5988 -n cht-interop >/dev/null 2>&1 & -kubectl port-forward svc/mediator 6000:6000 -n cht-interop >/dev/null 2>&1 & - -sleep 2 # Give port forwards time to establish +echo "Deployment complete!" echo "" -echo "🎉 CHT Interoperability Stack is ready!" +echo "CHT Interoperability Stack is ready!" echo "" -echo "📍 Access services at:" -echo "   OpenHIM Console: http://localhost:9000" -echo "   OpenHIM Core API: https://localhost:8080" -echo "   OpenHIM Router: http://localhost:5001" -echo "   CHT API: http://localhost:5988" -echo "   Mediator: http://localhost:6000" +echo "Access services at (via k3d port mappings - no port-forward needed):" +echo " OpenHIM Console: http://localhost:9000" +echo " OpenHIM Core API: https://localhost:8080" +echo " OpenHIM Router: https://localhost:5001" +echo " CHT: http://localhost:80 or https://localhost:443" +echo " Mediator: http://localhost:6000" echo "" -echo "🔑 Default credentials:" -echo "   OpenHIM: root@openhim.org / openhim-password" +echo "Default credentials:" +echo " OpenHIM: root@openhim.org / openhim-password" +echo " CHT: medic / password" echo "" -echo "🛠️  Useful commands:" -echo "   View pods: kubectl get pods -n cht-interop" -echo "   View logs: kubectl logs -n cht-interop" -echo "   Use K9s: k9s --context kind-cht-interop" -echo "   Stop port forwards: pkill -f 'kubectl port-forward'" -echo "   Helm status: helm status cht-interop -n cht-interop" +echo "Useful commands:" +echo " View pods: kubectl get pods -n cht-interop" +echo " View logs: kubectl logs -n cht-interop" +echo " Use K9s: k9s --context k3d-cht-interop" +echo " Helm status: helm status cht-interop" echo "" From c0599589d7b8107b71ec52585a4a906f7d75c3b1 Mon Sep 17 00:00:00 2001 From: Sugat Bajracharya Date: Tue, 20 Jan 2026 17:56:29 +0545 Subject: [PATCH 5/5] remove residue kind references --- charts/templates/07-openhim-console.yaml | 2 +- charts/templates/09-cht-services.yaml | 2 +- charts/templates/10-mediator-services.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/templates/07-openhim-console.yaml b/charts/templates/07-openhim-console.yaml index 236158af..d4fcfb7b 100644 --- a/charts/templates/07-openhim-console.yaml +++ b/charts/templates/07-openhim-console.yaml @@ -66,7 +66,7 @@ spec: - port: 80 targetPort: 80 --- -# Expose OpenHIM Console externally (only for KIND) +# Expose OpenHIM Console externally via NodePort (for local k3d development) {{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service diff --git a/charts/templates/09-cht-services.yaml b/charts/templates/09-cht-services.yaml index e2a7a2b5..8216837c 100644 --- a/charts/templates/09-cht-services.yaml +++ b/charts/templates/09-cht-services.yaml @@ -341,7 +341,7 @@ spec: port: 443 targetPort: 443 --- -# Expose CHT Nginx externally (only for KIND) +# Expose CHT Nginx externally via NodePort (for local k3d development) {{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service diff --git a/charts/templates/10-mediator-services.yaml b/charts/templates/10-mediator-services.yaml index 8df237da..72e094fb 100644 --- a/charts/templates/10-mediator-services.yaml +++ b/charts/templates/10-mediator-services.yaml @@ -188,7 +188,7 @@ spec: - port: 6000 targetPort: 6000 --- -# Expose Mediator externally for testing (only for KIND) +# Expose Mediator externally via NodePort (for local k3d development) {{- if ne .Values.cluster_type "eks" }} apiVersion: v1 kind: Service