From 5d909e8ca0df5689c0feaf9f3606c65b678a1858 Mon Sep 17 00:00:00 2001 From: Brian Walsh Date: Thu, 23 Jan 2025 05:47:30 -0800 Subject: [PATCH 1/4] adds k8s --- .env-k8s-sample | 13 +++++++++ README-hapi-k8s.md | 54 +++++++++++++++++++++++++++++++++++++ create_hapi_k8s.sh | 31 +++++++++++++++++++++ create_hapi_k8s_postgres.sh | 29 ++++++++++++++++++++ deploy_hapi_k8s.sh | 44 ++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 .env-k8s-sample create mode 100644 README-hapi-k8s.md create mode 100755 create_hapi_k8s.sh create mode 100755 create_hapi_k8s_postgres.sh create mode 100755 deploy_hapi_k8s.sh diff --git a/.env-k8s-sample b/.env-k8s-sample new file mode 100644 index 0000000..3e5ddaa --- /dev/null +++ b/.env-k8s-sample @@ -0,0 +1,13 @@ +PROJECT_ID="ncpi-rti-p01-007-ohsu" +REGION="us-central1" # Choose your preferred region +CLUSTER_NAME="my-hapi-fhir-cluster" +NUM_NODES=3 # Adjust as needed + +ZONE="" +NAMESPACE="fhir" +CLOUD_SQL_INSTANCE="" +DATABASE_NAME="" +DATABASE_USER="" +DATABASE_PASSWORD="" +CHART_REPO="https://hapifhir.github.io/hapi-fhir-jpaserver-starter/" +CHART_NAME="hapi-fhir-jpaserver" diff --git a/README-hapi-k8s.md b/README-hapi-k8s.md new file mode 100644 index 0000000..41e2750 --- /dev/null +++ b/README-hapi-k8s.md @@ -0,0 +1,54 @@ +# Deploying HAPI FHIR JPA Server on GKE with Cloud SQL + +This script deploys the HAPI FHIR JPA server starter on a Google Kubernetes Engine (GKE) cluster using Cloud SQL for PostgreSQL as the database. + +## Prerequisites + +* A Google Cloud project with billing enabled. +* A GKE cluster created. +* A Cloud SQL for PostgreSQL instance created. +* A service account with the necessary permissions to access Cloud SQL. +* `kubectl` and `helm` installed and configured. +* The `hapi-fhir-jpaserver` Helm chart added to your Helm repositories. (If using the repo from examples, make sure its added) + +Before running: + +* Install gcloud: Ensure the Google Cloud SDK is installed and configured with the correct credentials for your project ( ncpi-rti-p01-007-ohsu ). +* Enable Kubernetes Engine API: Make sure the Kubernetes Engine API is enabled in your project. +* Choose a Region: Select an appropriate region ( REGION ) for your cluster. Consider latency and availability requirements. +* Node Count: Adjust NUM_NODES based on your application's resource needs. Start small and scale up as needed. + +* Important Considerations: + +* Networking: This script uses the default VPC network. For more complex networking scenarios (e.g., private clusters), you'll need to specify additional network parameters. +* Node Pools: This script uses cluster autoscaling. For more fine-grained control over node configuration (machine type, etc.), you'll need to explicitly create node pools using gcloud container node-pools create . +* Security: Consider adding appropriate security settings (e.g., IP allowlisting, Kubernetes Roles and RBAC) to secure your cluster. + +After running this script successfully, you can use gcloud container clusters get-credentials to authenticate with your newly created cluster. Remember to always review the Google Cloud documentation for best practices and more advanced configuration options. + +## Configuration + +Before running the script, update the `deploy_hapi_fhir.sh` script with your project-specific values: + +* `PROJECT_ID`: Your Google Cloud project ID. +* `CLUSTER_NAME`: The name of your GKE cluster. +* `ZONE`: The zone of your GKE cluster. +* `NAMESPACE`: The Kubernetes namespace for the deployment (default: `fhir`). +* `CLOUD_SQL_INSTANCE`: The connection name of your Cloud SQL instance. +* `DATABASE_NAME`: The name of your PostgreSQL database. +* `DATABASE_USER`: The username for your PostgreSQL database. +* `DATABASE_PASSWORD`: The password for your PostgreSQL database. + + +## Deployment + +Run the script: `./deploy_hapi_k8s.sh`. + + +## Verification + +After the script completes, verify the deployment: + +```bash +kubectl get pods -n fhir +``` diff --git a/create_hapi_k8s.sh b/create_hapi_k8s.sh new file mode 100755 index 0000000..74f4998 --- /dev/null +++ b/create_hapi_k8s.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# --- Configuration --- +# see .env-k8s-sample file +#PROJECT_ID="ncpi-rti-p01-007-ohsu" +#REGION="us-central1" # Choose your preferred region +#CLUSTER_NAME="my-hapi-fhir-cluster" +#NUM_NODES=3 # Adjust as needed + + +# --- Create GKE Cluster --- + +gcloud container clusters create "${CLUSTER_NAME}" \ + --project="${PROJECT_ID}" \ + --region="${REGION}" \ + --cluster-autoscaling \ + --min-nodes=1 \ + --max-nodes="${NUM_NODES}" + + +# --- Check Cluster Status --- + +echo "Checking cluster status..." +gcloud container clusters describe "${CLUSTER_NAME}" \ + --project="${PROJECT_ID}" \ + --region="${REGION}" + + +echo "Cluster creation complete. You can now connect to your cluster using:" +echo "gcloud container clusters get-credentials ${CLUSTER_NAME} --region ${REGION} --project ${PROJECT_ID}" + diff --git a/create_hapi_k8s_postgres.sh b/create_hapi_k8s_postgres.sh new file mode 100755 index 0000000..be42ca7 --- /dev/null +++ b/create_hapi_k8s_postgres.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Load environment variables from .env-k8s-sample +source .env-k8s-sample + +# Check if required environment variables are set +: "${CLOUD_SQL_INSTANCE:?Need to set CLOUD_SQL_INSTANCE}" +: "${DATABASE_NAME:?Need to set DATABASE_NAME}" +: "${DATABASE_PASSWORD:?Need to set DATABASE_PASSWORD}" + +# 1. Authentication (if necessary) +gcloud auth application-default login + +# 2. Create Cloud SQL instance +gcloud sql instances create ${CLOUD_SQL_INSTANCE} \ + --database-version=POSTGRES_14 \ + --region=us-central1 \ + --tier=db-n1-standard-1 \ + --activation-policy=ALWAYS \ + --database-flags="cloudsql.iam_authentication=on" #Consider Private IP for better security + +# 3. Create a database within the instance +gcloud sql databases create ${DATABASE_NAME} --instance=${CLOUD_SQL_INSTANCE} + +# 4. Connect to the instance and create a user (replace with your actual password) +gcloud sql connect ${CLOUD_SQL_INSTANCE} --user=postgres --execute="CREATE USER hapi_user WITH PASSWORD '${DATABASE_PASSWORD}'; GRANT ALL PRIVILEGES ON DATABASE ${DATABASE_NAME} TO hapi_user;" + +# 5. Check instance status +gcloud sql instances describe ${CLOUD_SQL_INSTANCE} diff --git a/deploy_hapi_k8s.sh b/deploy_hapi_k8s.sh new file mode 100755 index 0000000..f2c7bb8 --- /dev/null +++ b/deploy_hapi_k8s.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Load environment variables from .env-k8s-sample +source .env-k8s-sample + +# Check if required environment variables are set +: "${PROJECT_ID:?Need to set PROJECT_ID}" +: "${CLUSTER_NAME:?Need to set CLUSTER_NAME}" +: "${ZONE:?Need to set ZONE}" +: "${NAMESPACE:?Need to set NAMESPACE}" +: "${CLOUD_SQL_INSTANCE:?Need to set CLOUD_SQL_INSTANCE}" +: "${DATABASE_NAME:?Need to set DATABASE_NAME}" +: "${DATABASE_USER:?Need to set DATABASE_USER}" +: "${DATABASE_PASSWORD:?Need to set DATABASE_PASSWORD}" +: "${CHART_REPO:?Need to set CHART_REPO}" +: "${CHART_NAME:?Need to set CHART_NAME}" + +# --- Functions --- + +create_secret() { + local secret_name="$1" + local key="$2" + local value="$3" + kubectl create secret generic "$secret_name" --from-literal="$key=$value" -n "$NAMESPACE" || true +} + +deploy_chart() { + helm install "$CHART_NAME" "$CHART_REPO/$CHART_NAME" \ + -n "$NAMESPACE" \ + --set spring.datasource.url="jdbc:postgresql://${CLOUD_SQL_INSTANCE}:5432/${DATABASE_NAME}" \ + --set spring.datasource.username="${DATABASE_USER}" \ + --set spring.datasource.password=$(kubectl get secret cloud-sql-credentials -o jsonpath="{.data.password}" -n "$NAMESPACE" | base64 --decode) +} + +# --- Main Script --- + +# Create Kubernetes secrets for Cloud SQL credentials +create_secret cloud-sql-credentials password "${DATABASE_PASSWORD}" + +# Deploy the Helm chart +deploy_chart + +echo "Deployment complete. Check the pods' status using:" +echo "kubectl get pods -n $NAMESPACE" \ No newline at end of file From f520b42fc1879fd6b779c43a6bf6b1fc5f4b1f98 Mon Sep 17 00:00:00 2001 From: Brian Walsh Date: Thu, 23 Jan 2025 21:27:34 -0800 Subject: [PATCH 2/4] PR feedback --- .env-k8s-sample | 3 +++ create_hapi_k8s.sh | 14 ++++++++++---- create_hapi_k8s_postgres.sh | 34 ++++++++++++++++++++++++++-------- deploy_hapi_k8s.sh | 6 ++++-- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/.env-k8s-sample b/.env-k8s-sample index 3e5ddaa..c149f14 100644 --- a/.env-k8s-sample +++ b/.env-k8s-sample @@ -11,3 +11,6 @@ DATABASE_USER="" DATABASE_PASSWORD="" CHART_REPO="https://hapifhir.github.io/hapi-fhir-jpaserver-starter/" CHART_NAME="hapi-fhir-jpaserver" +# Machine Type for the Cloud SQL (Postgres) instance +DATABASE_TIER="db-custom-1-3840" +DATABASE_VERSION=POSTGRES_14 \ No newline at end of file diff --git a/create_hapi_k8s.sh b/create_hapi_k8s.sh index 74f4998..da42678 100755 --- a/create_hapi_k8s.sh +++ b/create_hapi_k8s.sh @@ -1,11 +1,17 @@ #!/bin/bash +# https://bertvv.github.io/cheat-sheets/Bash.html#writing-robust-scripts-and-debugging +set -euo pipefail + +# Check if required environment variables are set +# See .env-k8s-sample + # --- Configuration --- # see .env-k8s-sample file -#PROJECT_ID="ncpi-rti-p01-007-ohsu" -#REGION="us-central1" # Choose your preferred region -#CLUSTER_NAME="my-hapi-fhir-cluster" -#NUM_NODES=3 # Adjust as needed +: "${PROJECT_ID:?Need to set PROJECT_ID}" +: "${REGION:?Need to set REGION}" +: "${CLUSTER_NAME:?Need to set CLUSTER_NAME}" +: "${NUM_NODES:?Need to set NUM_NODES}" # --- Create GKE Cluster --- diff --git a/create_hapi_k8s_postgres.sh b/create_hapi_k8s_postgres.sh index be42ca7..c3b2363 100755 --- a/create_hapi_k8s_postgres.sh +++ b/create_hapi_k8s_postgres.sh @@ -1,29 +1,47 @@ #!/bin/bash -# Load environment variables from .env-k8s-sample -source .env-k8s-sample +# https://bertvv.github.io/cheat-sheets/Bash.html#writing-robust-scripts-and-debugging +set -euo pipefail + # Check if required environment variables are set +# See .env-k8s-sample : "${CLOUD_SQL_INSTANCE:?Need to set CLOUD_SQL_INSTANCE}" : "${DATABASE_NAME:?Need to set DATABASE_NAME}" : "${DATABASE_PASSWORD:?Need to set DATABASE_PASSWORD}" +: "${DATABASE_TIER:?Need to set DATABASE_TIER}" +: "${DATABASE_VERSION:?Need to set DATABASE_VERSION}" + +Possibility of only logging in if user is not already authenticated (avoids browser opening every debugging run)? # 1. Authentication (if necessary) -gcloud auth application-default login +# Skip logging in if user is already authenticated +# ref: https://stackoverflow.com/a/78138012/7656815 +if gcloud projects list &> /dev/null; then + echo "User is authenticated with gdcloud" +else + echo "Logging in with gcould auth application-default login..." + gcloud auth application-default login +fi # 2. Create Cloud SQL instance gcloud sql instances create ${CLOUD_SQL_INSTANCE} \ - --database-version=POSTGRES_14 \ + --database-version=${DATABASE_VERSION} \ --region=us-central1 \ - --tier=db-n1-standard-1 \ + --tier=${DATABASE_TIER} \ --activation-policy=ALWAYS \ --database-flags="cloudsql.iam_authentication=on" #Consider Private IP for better security # 3. Create a database within the instance gcloud sql databases create ${DATABASE_NAME} --instance=${CLOUD_SQL_INSTANCE} -# 4. Connect to the instance and create a user (replace with your actual password) -gcloud sql connect ${CLOUD_SQL_INSTANCE} --user=postgres --execute="CREATE USER hapi_user WITH PASSWORD '${DATABASE_PASSWORD}'; GRANT ALL PRIVILEGES ON DATABASE ${DATABASE_NAME} TO hapi_user;" +# 4. Create a user +gcloud sql users create hapi_user --instance=${CLOUD_SQL_INSTANCE} --password=${DATABASE_PASSWORD} + +# 5. Connect to the instance and grant privileges +gcloud sql connect ${CLOUD_SQL_INSTANCE} --user=postgres < Date: Thu, 23 Jan 2025 21:54:40 -0800 Subject: [PATCH 3/4] adds ingress adds ingress --- .env-k8s-sample | 11 ++++- create_hapi_k8s_ingress.sh | 96 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 create_hapi_k8s_ingress.sh diff --git a/.env-k8s-sample b/.env-k8s-sample index c149f14..1254231 100644 --- a/.env-k8s-sample +++ b/.env-k8s-sample @@ -4,13 +4,20 @@ CLUSTER_NAME="my-hapi-fhir-cluster" NUM_NODES=3 # Adjust as needed ZONE="" -NAMESPACE="fhir" +NAMESPACE="fhir" # helm namespace CLOUD_SQL_INSTANCE="" DATABASE_NAME="" DATABASE_USER="" DATABASE_PASSWORD="" CHART_REPO="https://hapifhir.github.io/hapi-fhir-jpaserver-starter/" CHART_NAME="hapi-fhir-jpaserver" + # Machine Type for the Cloud SQL (Postgres) instance DATABASE_TIER="db-custom-1-3840" -DATABASE_VERSION=POSTGRES_14 \ No newline at end of file +DATABASE_VERSION=POSTGRES_14 + +# ingress, letsencrypt +NAMESPACE="fhir" +EMAIL="your-email@example.com" +DOMAIN1="hapi.example.com" +DOMAIN2="google-fhir.example.com" diff --git a/create_hapi_k8s_ingress.sh b/create_hapi_k8s_ingress.sh new file mode 100644 index 0000000..807fcd6 --- /dev/null +++ b/create_hapi_k8s_ingress.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# https://bertvv.github.io/cheat-sheets/Bash.html#writing-robust-scripts-and-debugging +set -euo pipefail + +# Check if required environment variables are set +# See .env-k8s-sample + +# --- Configuration --- +# see .env-k8s-sample file +: "${NAMESPACE:?Need to set NAMESPACE}" +: "${EMAIL:?Need to set EMAIL}" +: "${DOMAIN1:?Need to set DOMAIN1}" +: "${DOMAIN2:?Need to set DOMAIN2}" + +# Create the namespace +kubectl create namespace $NAMESPACE + +# Install cert-manager +helm repo add jetstack https://charts.jetstack.io +helm repo update +kubectl create namespace cert-manager +helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.11.0 --set installCRDs=true + +# Create the ClusterIssuer +cat < Date: Thu, 23 Jan 2025 22:04:45 -0800 Subject: [PATCH 4/4] adds service account to ingress --- create_hapi_k8s_ingress.sh | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/create_hapi_k8s_ingress.sh b/create_hapi_k8s_ingress.sh index 807fcd6..d29277b 100644 --- a/create_hapi_k8s_ingress.sh +++ b/create_hapi_k8s_ingress.sh @@ -93,4 +93,68 @@ spec: - protocol: TCP port: 80 targetPort: 8080 +EOF + +# Create the ServiceAccount for google-fhir-proxy +cat <