Setup Notes - PathCloud
Environment: gcp-pathcloud-stage01
Setup Steps
GCP Digital Pathology - DICOM
PathCloud DICOM Configuration
Medplum FHIR Server Pre-requisites
Meplum Fhir Server in Cloud Run
PathCloud Load-balancer
Medplum Admin App in Cloud Run
PathCloud App
Viewers (Slim, OHIF)
Image Transformation Svc
DICOMCast Webhook Svc
DICOM Cast Bot
Practitioner Create Bot & Subscription
Sample Data in new Project (Giuseppe Gestalt)
Orthanc PACS Server
AI Studio Viewer & Server
GCP Digital Pathology
Follow Steps in IAC Playbook
Additional IAP Configuration for DICOM Proxy
- Enable or disable IAP depending on use-case. (Public/Anonymous Access versus Private/Authenticated Access)
Add User to "IAP-Secured Web App User" role
- manually configure initial users in IAP screen in Console
Enable CORS for IAP on DICOM-Proxy
- Click vertical elipse on right side of "default/dicom-proxy-service" row
- Click "Settings" and then Click "Enable HTTP Options"
Public DICOM Store & Proxy Configuration
- additional configuration for accessing DICOM. Currently using GCP Digital Pathology setup for initial config. May transition to use of Cloud Run DICOM-PROXY and "manual" setup of DICOM Store, BigQuery, PubSub, Service Accounts (082924)
Deploy DICOM-PROXY-Public to CloudRun
- Config is for PUBLIC Proxy (URL_PATH_PREFIX=/public01)
gcloud run deploy dicom-proxy-public01 \
--image=us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/dicom-proxy:latest \
--region=us-west2 --project=pathcloud-stage01 \
--port=8080 --allow-unauthenticated \
--memory 16G --cpu 4 --execution-environment=gen2 \
--cpu-boost --no-cpu-throttling \
--min-instances=1 --max-instances=100 --timeout=300 --concurrency=40 \
--service-account=dicom-proxy-k8s-sa@pathcloud-stage01.iam.gserviceaccount.com \
--set-env-vars "ORIGINS=*" \
--set-env-vars "VALIDATE_IAP=false" \
--set-env-vars "ENABLE_APPLICATION_DEFAULT_CREDENTIALS=true" \
--set-env-vars "REDIS_CACHE_HOST_IP=localhost" \
--set-env-vars "REDIS_CACHE_HOST_PORT=6379" \
--set-env-vars "ENABLE_DEBUG_FUNCTION_TIMING=true" \
--set-env-vars "URL_PATH_PREFIX=/public01" \
--set-env-vars "API_PORT_FLG=8080"
Create LB Backend and Network Endpoint Group (NEG)
- in console, create Backend and follow prompt for new NEG.
- use Cloud Run container NAME as convention for Backend and NEG name TODO - script creation of Backend and NEG
Disable Cloud CDN - can't use IAP if Cloud CDN is enabled
Create LB Route for backend to URL_PATH_PREFIX
- add Host Path and Rules (enables use of multiple proxies from same DNS host) DNS Host: dicom.stage01.gestaltcloud.com Path Matcher:
defaultService: projects/pathcloud-stage01/global/backendServices/dicom-proxy-public01-backend
name: path-matcher-7
routeRules:
- description: route-rule-public01
matchRules:
- prefixMatch: /public01
priority: 1
service: projects/pathcloud-stage01/global/backendServices/dicom-proxy-public01-backend
Enable IAP on Backend
- if Proxy is for Private Access then enable IAP (in this instance is public, so IAP disabled)
Configure BigQuery Instance for Public DICOM Store
- Copy table "slide-dicom-store-metadata" into a new dataset named: "dicom_pathology_public" (use Create Dataset option in copy)
- Delete all rows in copied table in new dataset
DELETE FROM `pathcloud-stage01.dicom_pathology_public.slide-dicom-store-metadata`
WHERE MediaStorageSOPClassUID IS NOT null
- Create view named:
slide-dicom-store-metadataView- copy query from same view in "dicom_pathology", run query, save sas View - Create view name:
pathcloud_slide-dicom-store-metadata_groupedView- copy query from same view in "dicom_pathology" (change dataset), run query, save as View
- name is used in DICOMCast SQL Query
- May need to add service account to new dataset permissions (click "Sharing", then "Permissions") If permission not added, will be notified in DICOM Store setup
Configure Pub/Sub Topic & Webhook ubscription for Public DICOM Store
- In Pub/Sub "Topics" create Topic ID = transformation-dicom-store-topic (need to create in DICOMStore setup wizard)
- In Pub/Sub "Subscriptions" create new subscription: Subscription ID: pathcloud-stage01-webhook-dicom-public-medplum-subscription Topic: pathcloud-stage01-webhook-dicom-public-medplum-subscription Delivery Type: Push Endpoint URL: https://pathcloud-webhook-dicom-pubsub-392114647566.us-west2.run.app (default URL of Webhook container)
Setup new DICOM Store (Public)
- use Console / Healthcare / Browser to create new DICOM store Name: slide-dicom-store-public
- select Streaming Configurations and select "slide-dicom-store-metadata" in "dicom_pathology_dataset"
- select Cloud Pub/Sub notifications - create new topic transformation-dicom-store-topic
Setup Project Pre-Requisites
Setup gcp digital pathology infrastructure
- https://gestaltdiagnostics.visualstudio.com/Gestalt%20PathCloud/_git/gcp-pathology-pathcloud
- Use
pathcloud-stage01Terraform code
Enable OAuth Client to Access IAP Resources
Links:
Scripts:
- create settings file
cat << EOF > oauth-iap-access-settings.txt
access_settings:
oauth_settings:
programmatic_clients: ["1053568465268-t2coh1p3ke4lrhu6o042squicec9toed.apps.googleusercontent.com"]
EOF
- Allowlist OAuth Client for IAP in PROJECT
gcloud iap settings set oauth-iap-access-settings.txt --project=pathcloud-stage01
Setup Medplum FHIR Server Pre-requisites
Install PostgreSQL instance in SQL services
Create storage bucket for config files: "apps-config"
Upload medplum db SQL script apps-config bucket Will use to create gold medplum db (previously exported from medplum-poc1 in gcp-pathology-poc1 project)
Import medplum db SQL script to new database in PostgreSQL called medplum-stag01 (password of db is G3st@lt)
Enable Cloud SQL Admin API (necessary for Cloud Run containers)
- https://console.cloud.google.com/apis/api/sqladmin.googleapis.com/metrics?project=pathcloud-stage01
Create pathcloud REDIS store
pathcloud-redis-stage01 gcloud redis instances create --project=pathcloud-stage01 pathcloud-redis-stage01 --tier=basic --size=4 --region=us-west2 --redis-version=redis_7_0 --network=projects/pathcloud-stage01/global/networks/default --zone=us-west2-a --connect-mode=DIRECT_PEERING --display-name="Pathcloud REDIS"
Configure SMTP Server for Medplum Config
- using Mailgun for SMTP relay. Limits 100 emails /day
- https://app.mailgun.com/ TODO - setup higher volume SMTP relay on SendGrid or Mailgun (090324)
Setup Medplum FHIR Server in Cloud Run
Configure new medplum config file (medplum.config.cloud.stage01.json)
- configure env (eg stage01) in urls
- configure db connection
- configure Redis IP address
Remove domain restricted sharing on project to enable public access to Cloud Run containers (need to do this in Cloud Console)
Add Cloud Run service account (eg service-392114647566@serverless-robot-prod.iam.gserviceaccount.com) to project with Artifact Registry that has selected container image
Create Bucket for medplum file storage (binary's)
gcloud storage buckets create gs://medplum-server-files-stage01 --location=us-west2
Create Bucket for medplum config storage
- need two buckets because can only volume mount a bucket at root of bucket
gcloud storage buckets create gs://medplum-server-config-stage01 --location=us-west2 - Name: medplum-server-config-stage01
Upload medplum config json
gcloud storage cp medplum.config.cloud.stage01.json gs://medplum-server-config-stage01
Build and Push medplum-fhir container image (Code)
- see README in app-containers/server-medplum-fhir directory Build Container
- Run inside
app-containers/server-medplum-fhir - Container with Medplum files and build inside (3 GB) docker build -f Dockerfile.medplum.code --tag us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/medplum-server-code:v4.0.2 ../../.
Push image to Artifact Registry docker push us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/medplum-server-code:v4.0.2
Deploy Cloud Run container
- change "file" arg to relevant medplum config
- need to use Medplum Server - Code image instead of DIST (issue with token, can't create Client App)
gcloud config set project pathcloud-stage01 && \
gcloud beta run deploy medplum-server --image us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/medplum-server-code:v4.0.2 --region=us-west2 --allow-unauthenticated \
--port 8103 --memory 4G \
--network default --subnet default \
--add-volume name=medplum-server-files,type=cloud-storage,bucket=medplum-server-files-stage01 \
--add-volume-mount volume=medplum-server-files,mount-path=/app/packages/server/binary \
--add-volume name=medplum-server-config,type=cloud-storage,bucket=medplum-server-config-stage01 \
--add-volume-mount volume=medplum-server-config,mount-path=/app/packages/server/config \
--add-cloudsql-instances pathcloud-stage01:us-west2:pathcloud-db-stage01 \
--command npm --args start,file:config/medplum.config.cloud.stage01.json
Setup PathCloud Load-balancer
Create new static IP address
gcloud compute addresses create pathcloud-stage01-lb-static-ip-address \
--network-tier=PREMIUM \
--ip-version=IPV4 \
--global
Create new GCP managed SSL Certificate
gcloud compute ssl-certificates create apps-stage01-ssl-v1 \
--description= \
--domains=fhir.stage01.gestaltcloud.com,apps.stage01.gestaltcloud.com,app.stage01.gestaltcloud.com,admin.stage01.gestaltcloud.com,pacs.stage01.gestaltcloud.com,ai.stage01.gestaltcloud.com,dicom.stage01.gestaltcloud.com,aistudio.stage01.gestaltcloud.com,viewer-public01.stage01.gestaltcloud.com \
--global
Create Network Endpoint Group connected to medplum-fhir-server in Cloud Run
TODO - create cli script for NEG
Create Backend for Medplum FHIR Server
TODO - create cli script for Backend Service
Initial setup and config of Load Balancer in project
New Loadbalancer in "Network Services"
Select following options:
- Type of load balancer: Application Load Balancer
- Public facing or internal: Public facing (external)
- Global or single region deployment: Best for global workloads
- Load balancer generation: Global external Application Load Balancer
Load Balancer Name: pathcloud-stage01-lb
Configure Frontend - http, https, configure static IP address, SSL Certificate
Setup Medplum Admin App in Cloud Run
- NOTE: configure env file before build to use Vite mode (in order to pass specific env file to build command)
Build container
-
Run inside
app-containers/app-admin -
Build from medplum src docker build -f Dockerfile --build-arg APP_ENV_PATH=.env.pathcloud-stage01.cloudrun --tag us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/stage01/app-admin:v4.0.2 ../../.
Test Container Locally
docker run --rm -p 3001:80 --name app-admin-container us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/stage01/app-admin:v4.0.2
Push image to Artifact Registry**
docker push us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/stage01/app-admin:v4.0.2
Deploy container to Cloud Run
gcloud config set project pathcloud-stage01 &&
gcloud run deploy pathcloud-admin-app --image us-west2-docker.pkg.dev/gcp-pathology-poc1/pathcloud/stage01/app-admin:v4.0.2 --port=80 --region=us-west2 --allow-unauthenticated --memory 4G
Load Balancer Setup
- configure Backend and Network Endpoint Group (NEG)
Configure Load Balancer Route
defaultService: projects/pathcloud-stage01/global/backendServices/pathcloud-admin-app-backend name: path-matcher-2