Skip to main content

Install Patient Journey Intelligence on K3s

This guide installs Patient Journey Intelligence on one Linux server using K3s, a certified lightweight Kubernetes distribution. The release package sets K3s up for you, so you do not need an existing cluster. A server with 16 vCPU and 64 GiB of memory runs the ingestion services; 32 vCPU and 128 GiB runs all services. Everything runs inside your own infrastructure.

The guide is for operators and DevOps engineers who install Patient Journey Intelligence on a single-node Linux host, either a virtual machine or a bare-metal server. Review the common prerequisites and required release files first.


Scripts you run, in order​

You will run these scripts from the release package, in this order:

StepScriptRun it
1k3s-installer.shOnce per server, to set up Kubernetes.
2pj-app-installer.shOnce, to install Patient Journey Intelligence.
3setup_instance.shAfter installing, to size Patient Journey Intelligence for the server's memory.
4pj-app-updater.shFor every later release, to upgrade Patient Journey Intelligence.

All scripts must run as root or with sudo.


Before you begin​

Server requirements​

Choose the server size based on the services you plan to run:

WorkloadCPUMemory
Ingestion services (minimum)16 vCPU64 GiB
All services32 vCPU128 GiB

Other requirements:

ResourceMinimumNotes
Free disk on /var/lib80 GBk3s-installer.sh checks this and stops if there is less.
Operating systemLinux, such as Debian, Ubuntu, or RHELx86-64.
GPU (optional)NVIDIA GPUOnly needed to run the document processor or language model in GPU mode.

Network requirements​

  • Outbound: the server must reach the internet to download K3s, Helm, and the container images. For servers without internet access, see air-gapped installs.
  • Inbound: open port 80 for HTTP. Open port 443 if you use HTTPS.
  • DNS: HTTPS needs a DNS name, such as pji.example.com, that points to the server. Let's Encrypt must reach the server on port 80 to issue the certificate.

Tools on the server​

The installer and updater stop if curl, awk, or jq is missing. They also use openssl and tar. setup_instance.sh uses python3.

Ubuntu or Debian
sudo apt-get update
sudo apt-get install -y curl jq openssl tar python3 unzip
RHEL
sudo dnf install -y curl jq openssl tar python3 unzip

Install the AWS CLI to download the release package:

curl -sSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o awscliv2.zip
unzip -q awscliv2.zip
sudo ./aws/install
aws --version

K3s provides kubectl and crictl. k3s-installer.sh installs Helm.

What John Snow Labs provides​

  • The release version to install, for example 2.3.0.
  • AWS credentials that can read the release package.
  • Your license file, license.json.

Step 1: Download the release package​

Set the version you were given, then configure the AWS credentials from John Snow Labs:

export PJI_VERSION="2.3.0"
aws configure

aws configure asks for the access key ID, the secret access key, and a region. Use us-east-1.

Download the package:

aws s3 cp \
"s3://dev.johnsnowlabs.com/jsl-omop/artifacts/pj-app-${PJI_VERSION}.tar.gz" \
~/

Step 2: Unpack the release package​

The package unpacks its files directly into the target folder. Create a folder for this release first, so files from different releases never mix.

mkdir -p ~/pj-app-${PJI_VERSION}
tar -xzf ~/pj-app-${PJI_VERSION}.tar.gz -C ~/pj-app-${PJI_VERSION}
cd ~/pj-app-${PJI_VERSION}

Copy your license file into the same folder:

cp /path/to/license.json ./license.json

Check the contents:

ls -l
Expected files
instructions.md
jsl_create_secret
jsl_docker_pull
k3s-installer.sh
marketplace-installer.sh
packer/
pj-app-2.3.0.tgz
pj-app-installer.sh
pj-app-updater.sh
setup_instance.sh

A K3s install uses k3s-installer.sh, pj-app-installer.sh, setup_instance.sh, pj-app-updater.sh, the Helm chart pj-app-<version>.tgz, and the two helper programs jsl_create_secret and jsl_docker_pull. The other files are for AWS Marketplace and machine image builds.


Step 3: Set up K3s​

Run the K3s setup script once on a new server. It takes no options.

sudo ./k3s-installer.sh

The script does the following:

  1. Checks that /var/lib has at least 80 GB free. If not, it stops and tells you how much more space you need.
  2. Stops if K3s is already running on the server.
  3. On Red Hat Enterprise Linux, stops and turns off nm-cloud-setup if it is present.
  4. Sets the server hostname to k3s-pj and sets preserve_hostname: true in /etc/cloud/cloud.cfg.
  5. Installs K3s version v1.31.7+k3s1.
  6. Installs Helm version v3.16.4.
  7. Prints the installed Kubernetes and Helm versions.

Check that the node is ready. STATUS should show Ready:

sudo kubectl get nodes

Step 4: Install Patient Journey Intelligence​

Choose the command that matches your setup. Run it from the release folder. All options are described in Installer Options.

Option A: HTTPS with a DNS name​

Gets a certificate from Let's Encrypt.

sudo ./pj-app-installer.sh \
--host pji.example.com \
--namespace pji \
--license-file license.json \
--tls \
--install-cert-manager \
--acme-email admin@example.com \
--interactive-secrets

Option B: HTTP with a DNS name​

sudo ./pj-app-installer.sh \
--host pji.example.com \
--namespace pji \
--license-file license.json \
--interactive-secrets

Option C: HTTP without a DNS name​

If you leave out --host, the application has no host rule. The installer uses the server's public IP address, or its private IP address if no public one is found.

sudo ./pj-app-installer.sh \
--namespace pji \
--license-file license.json \
--interactive-secrets

API keys (optional)​

API keys are optional. In release 2.2.2, they are used only by:

  • the Data Curation Service, when it uses a custom language model
  • the terminology server

If you do not use these features, you can skip them. Press Enter at each prompt, or leave out --interactive-secrets.

note

The features that use these keys may change in later releases. Check the release notes for your version.

--interactive-secrets asks for each key in turn. To provide the keys without prompts, export them and run the installer with sudo -E so it can read them:

export OPENAI_API_KEY="sk-..."
export HUGGINGFACE_API_TOKEN="hf_..."
sudo -E ./pj-app-installer.sh --host pji.example.com --namespace pji --license-file license.json

See Environment Variables for every supported key.

Administrator password​

At the end, the installer prints Keycloak Admin Password. Store it in your password manager. You can read it again at any time:

sudo kubectl get secret pj-app-keycloak -n pji \
-o jsonpath='{.data.admin-password}' | base64 -d; echo

Step 5: Verify the installation​

Watch the services start. Press Ctrl+C when every pod shows Running or Completed.

sudo kubectl get pods -n pji -w

If you used HTTPS, check the certificate. READY should show True:

sudo kubectl get certificate -n pji

Open the application in a browser at https://pji.example.com, http://pji.example.com, or http://<server-ip>, depending on the option you chose.

If you did not pass --license-file, upload the license in the web interface after you sign in.


Step 6: Size Patient Journey Intelligence for the server​

setup_instance.sh tunes a running installation for the server's total memory. It:

  • Sets replica counts and resource limits for the language model, OCR, NLP, de-identification, database, terminology, and Elasticsearch services.
  • Sets the Elasticsearch memory.
  • Updates the pipeline settings in the shared configuration.
  • Saves Spark settings to the application database through the API.

It reads the namespace from your current kubectl context and finds the release, URLs, and credentials in the cluster.

Run it​

Run it from the release folder, so it can find the Helm chart. Point kubectl at the Patient Journey Intelligence namespace first:

sudo kubectl config set-context --current --namespace pji

Preview the settings without changing anything:

sudo bash ./setup_instance.sh 64 --dry-run

Apply them:

sudo bash ./setup_instance.sh 64

Replace 64 with the server's total memory in GB.

Arguments​

ArgumentRequiredDescription
<memory-in-GB>YesThe server's total memory in GB, as a whole number. It must be the first argument. Below 16, the script prints a warning and uses its minimum settings.
--dry-runNoPrint the capacity plan and the computed settings. Change nothing.
--skip-infraNoOnly save the Spark settings to the database. Do not change the Kubernetes services.
--skip-sparkNoOnly change the Kubernetes services. Do not save the Spark settings.

You cannot use --skip-infra and --skip-spark together.

Environment variables​

VariableDefaultDescription
KEYCLOAK_ADMIN_USERadminKeycloak administrator user name.
LOCAL_API_PORTa free portLocal port used to reach the API.
LOCAL_KC_PORTa free portLocal port used to reach Keycloak.
LOCAL_ES_PORTa free portLocal port used to reach Elasticsearch.

Keeping the settings after upgrades​

  • Helm chart found: if the release folder has the chart that matches the installed version, the script saves the settings in the installation, so they survive future upgrades. The script prints Chart found.
  • Helm chart not found: the script changes the running services directly and prints Chart file not found. These changes survive restarts, but the next upgrade overwrites them. Run setup_instance.sh again after each upgrade.

If saving the Spark settings fails, run it again with --skip-infra once the API is ready:

sudo bash ./setup_instance.sh 64 --skip-infra

Step 7: Upgrade to a new release​

Use the updater for every new release.

  1. Download and unpack the new release into its own folder, as in Step 1 and Step 2:

    export PJI_VERSION="2.4.0"
    aws s3 cp "s3://dev.johnsnowlabs.com/jsl-omop/artifacts/pj-app-${PJI_VERSION}.tar.gz" ~/
    mkdir -p ~/pj-app-${PJI_VERSION}
    tar -xzf ~/pj-app-${PJI_VERSION}.tar.gz -C ~/pj-app-${PJI_VERSION}
    cd ~/pj-app-${PJI_VERSION}
  2. Run the updater with the same host, namespace, release name, HTTPS options, and values files you used to install:

    sudo ./pj-app-updater.sh \
    --host pji.example.com \
    --namespace pji \
    --tls \
    --silent

Do not run k3s-installer.sh or pj-app-installer.sh again for an upgrade.

The updater does not remember every option

Always pass the same --host, --namespace, --release, --tls, and --values options you used at install time.

  • If you leave out --host, the updater removes the host rule, and the application is no longer reachable at that name.
  • If you leave out --tls, the application goes back to HTTP.

Updater Options shows which other options you must repeat.

Updater prompts​

ModeOptionWhat happens
DefaultnoneUses the API keys and administrator password already in the installation.
Interactive--interactive-secretsAsks for API keys and a new Keycloak administrator password. Press Enter to keep the current password.
Silent--silentSkips every prompt.

Update the license​

Copy the new license file into the release folder and pass it to the updater:

sudo ./pj-app-updater.sh \
--host pji.example.com \
--namespace pji \
--tls \
--license-file license.json \
--silent

Configure storage and HTTPS​

Use Single-node host directory when document artifacts need a predictable host path. That section includes the directory preparation command and the values-file installation and update commands.

For HTTPS, follow HTTPS And TLS. Keep the same namespace and environment values when upgrading.

When updating an HTTPS deployment, include --tls and any explicit issuer selection. Pass the same --values files and release name used during installation; the updater does not remember an omitted environment values file.


Common configurations​

These options work the same way with the installer and the updater.

Run the language model on a GPU​

sudo ./pj-app-installer.sh \
--host pji.example.com \
--namespace pji \
--slm-mode gpu \
--slm-gpu-count 1 \
--install-gpu-operator

--install-gpu-operator installs the NVIDIA GPU Operator for GPU workloads.

Larger Elasticsearch​

sudo ./pj-app-installer.sh \
--host pji.example.com \
--namespace pji \
--elasticsearch-profile=medium

Databricks​

To run pipeline jobs on Databricks, export the ECR password before you run the installer or the updater. Use sudo -E so the script can read it:

export ECR_PASSWORD=$(aws ecr get-login-password --region us-east-1)
sudo -E ./pj-app-installer.sh --host pji.example.com --namespace pji

The script then uses the Databricks de-identification, NLP pipeline, jobs, and custom NLP images from the ECR registry that match the release version.

Export ECR_PASSWORD before every update too:

export ECR_PASSWORD=$(aws ecr get-login-password --region us-east-1)
sudo -E ./pj-app-updater.sh --host pji.example.com --namespace pji --tls --silent

Optional services​

ServiceOption
Kibana--enable-kibana
NAACCR Edits60 API and NAACCR XML Service--enable-naaccr-services
Data Curation Service--enable-dcs --dcs-tag <tag>
Turn off the CPG Agent--disable-cpg-agent

Air-gapped installs​

Use --airgap when the server has no internet access. In this mode the scripts do not download images. They check that every image is already on the server and stop if one is missing.

k3s-installer.sh downloads K3s and Helm from the internet, so it cannot run on a server without internet access. Set up K3s and Helm before you start.

  1. Load every image the release needs into the K3s container runtime. Check them with:

    sudo k3s ctr images ls
  2. If the cluster does not already have the Elasticsearch operator, place eck-operator-3.4.0.tgz in the release folder, or set ECK_OPERATOR_CHART to its path. The image registry.johnsnowlabs.com/pj-app/eck-operator:3.4.0 must also be loaded.

  3. Install:

    sudo ./pj-app-installer.sh --airgap --host pji.example.com --namespace pji --license-file license.json
  4. Use --airgap on every update too.


More than one server​

This guide covers one server. On a K3s cluster with more than one node, pass --nfs to both the installer and the updater. It creates NFS-backed shared storage for the pipeline cache, so every node can use it. Without it, the pipeline cache uses storage that only one node can use.


Troubleshooting​

Message or problemWhat to do
Insufficient space in /var/libGrow the disk or the /var/lib volume, then run k3s-installer.sh again.
k3s is already Installed and RunningK3s is already set up. Continue with Step 4.
sed: can't read /etc/cloud/cloud.cfg from k3s-installer.shThe server does not use cloud-init. Create the file with echo "preserve_hostname: true" | sudo tee /etc/cloud/cloud.cfg, then run the script again.
Error: 'jq' not found in $PATHInstall the missing tool, as in tools on the server.
Missing chart: place pj-app-<version>.tgz in this directory.Run the script from the unpacked release folder.
Missing or non-executable binaryRun chmod +x jsl_create_secret jsl_docker_pull.
ERROR: TLS requires an FQDNPass a DNS name, not an IP address, with --host when you use --tls.
ERROR: --tls requires --host <FQDN>Add --host with your DNS name.
ERROR: --enable-dcs requires --dcs-tagAdd --dcs-tag <tag>.
Error: Could not read APP_URL from ConfigMap from setup_instance.shYour kubectl context points at the wrong namespace. Run sudo kubectl config set-context --current --namespace pji.
Application unreachable after an updateYou left out --host or --tls. Run the updater again with your original options.

Frequently asked questions​

A server with 16 vCPU and 64 GiB of memory runs the ingestion services, which is the minimum. Running all services needs 32 vCPU and 128 GiB. You also need at least 80 GB free on /var/lib; k3s-installer.sh checks this and stops if there is less. An NVIDIA GPU is optional and only needed to run the document processor or language model in GPU mode.

Yes. Use --airgap on the installer and on every later update. In this mode the scripts do not download images; they check that every image is already loaded in the K3s container runtime and stop if one is missing. Because k3s-installer.sh downloads K3s and Helm from the internet, set up K3s and Helm before you start.

Only for HTTPS or a friendly address. HTTPS needs a DNS name that points to the server, and Let's Encrypt must reach the server on port 80 to issue the certificate. You can install over HTTP with a DNS name, or over HTTP without one, using the options in Step 4.

Run k3s-installer.sh once per server to set up Kubernetes, pj-app-installer.sh once to install Patient Journey Intelligence, and setup_instance.sh after installing to size Patient Journey Intelligence for the server's memory. For every later release, run pj-app-updater.sh. All scripts must run as root or with sudo.

The updater was run without the options the installation uses. If you left out --host or --tls, run the updater again with your original options.

On a K3s cluster with more than one node, pass --nfs to both the installer and the updater. It creates NFS-backed shared storage for the pipeline cache so every node can use it. Without it, the pipeline cache uses storage that only one node can use.

Open port 80 for HTTP, and port 443 as well if you use HTTPS. Outbound internet access is required to download K3s, Helm, and the container images, unless you are running an air-gapped install.

Remove Patient Journey Intelligence​

This deletes data

These commands permanently delete the application and its data.

Remove the application only:

sudo kubectl delete namespace pji

Remove K3s and everything it stores:

sudo k3s-uninstall.sh

Installer and updater options​