Deploy Smartbox with Kubernetes

The guide covers only Smartbox mandatory components deployment in k8s

This guide shows how to deploy Smartbox in minimal configuration. One instance of PostgreSQL and a two instances of Aidbox (Sandbox and Portal).

To have a production-ready deployment there also should be:

  • Database and Aidbox replicas

  • Backups and restoring

  • Logging and rotations

  • Monitoring and Alerting

  • Expose Smartbox to the Internet

  • Issuing SSL certificates

This guide does not define exposing Smartbox to the Internet

Prerequisites

  • Kubernetes cluster is set up and running

  • kubectl utility is installed

  • Two Aidbox licenses are obtained

  • Email provider credentials are obtained

  • GCP connect credentials are obtained

Prebuilt k8s configuration

  1. Download the file

  2. Populate the missed ENVs

  3. Run the command kubectl apply -f smartbox.yaml

The smartbox.yaml is the k8s compiled templates configuration. The configuration components contained in the file are defined further in this guide

Smartbox mandatory ENVs

Common for Portal & Sandbox

  • PGUSER

  • PGPASSWORD

  • BOX_PROVIDER_DEFAULT_* values. See the documentation

Sandbox specific

  • PGDATABASE: sandbox

  • AIDBOX_LICENSE

  • AIDBOX_ADMIN_ID

  • AIDBOX_ADMIN_PASSWORD

  • AIDBOX_BASE_URL: http://sandbox

  • AIDBOX_ZEN_ENTRYPOINT: 'smartbox.dev-portal/box'

  • AIDBOX_CLIENT_ID: sandbox-client

  • AIDBOX_CLIENT_SECRET: sandbox-secret

  • BOX_AUTH_LOGIN__REDIRECT: "/"

Portal specific

  • PGDATABASE: smartbox

  • AIDBOX_LICENSE

  • AIDBOX_ADMIN_ID

  • AIDBOX_ADMIN_PASSWORD

  • AIDBOX_BASE_URL: http://smartbox

  • AIDBOX_CLIENT_ID: portal-client

  • AIDBOX_CLIENT_SECRET: portal-secret

  • BOX_SMARTBOX_SANDBOX__URL: http://sandbox

  • BOX_SMARTBOX_SANDBOX__ADMIN: admin

  • BOX_BULK__STORAGE_GCP_* values. See the documentation

BOX_SMARTBOX_SANDBOX__BASIC is deprecated. Use BOX_SMARTBOX_SANDBOX__ADMIN instead

All the available environment variables are defined here

Components templates

Database (PostgreSQL)

Smartbox (as an Aidbox configuration) requires an instance of running PostgreSQL. There should be two databases on a PostgreSQL cluster:

  • First is for Sandbox instance

  • Second is for Portal instance

Volume

Volume
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: aidboxdb-data
  namespace: smartbox
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Gi

ENVs

ConfigMap - ENVs
kind: ConfigMap
metadata:
  name: aidboxdb-envs
  namespace: smartbox
apiVersion: v1
data:
  POSTGRES_DB: postgres
  PGDATA: /data/pg
Secrets - ENVs
kind: Secret
apiVersion: v1
metadata:
  name: aidboxdb-envs
  namespace: smartbox
data:
  POSTGRES_USER: cG9zdGdyZXM=      # base64 encoded string postgres
  POSTGRES_PASSWORD: cG9zdGdyZXM=  # base64 encoded string postgres

Config

ConfigMap
kind: ConfigMap
apiVersion: v1
metadata:
  name: aidboxdb-config
  namespace: smartbox
data:
  postgres.conf: |-
    listen_addresses = '*'
    max_replication_slots = 30
    max_wal_senders = 30
    max_wal_size = '1GB'
    max_worker_processes = 128
    pg_stat_statements.max = 500
    pg_stat_statements.save = false
    pg_stat_statements.track = top
    pg_stat_statements.track_utility = true
    shared_buffers = '1GB'
    shared_preload_libraries = 'pg_stat_statements'
    synchronous_commit = off
    track_io_timing = on
    wal_level = logical
    wal_log_hints = on

StatefulSet

StatefulSet
kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: aidboxdb
  namespace: smartbox
spec:
  replicas: 1
  selector:
    matchLabels:
      service: aidboxdb
  serviceName: aidboxdb
  template:
    metadata:
      labels:
        service: aidboxdb
    spec:
      containers:
      - name: main
        imagePullPolicy: Always
        image: healthsamurai/aidboxdb:14.5
        volumeMounts:
        - name: db-data
          mountPath: /data
          subPath: pg
        - name: aidboxdb-config
          mountPath: /etc/configs
        - name: db-dshm
          mountPath: /dev/shm
        readinessProbe:
          exec:
            command:
            - bash
            - -c
            - psql -c 'SELECT 1'
          initialDelaySeconds: 10
          timeoutSeconds: 2
        envFrom:
        - configMapRef:
            name: aidboxdb-envs
        - secretRef:
            name: aidboxdb-envs
        ports:
        - containerPort: 5432
          protocol: TCP
        resources:
          requests:
            memory: 1Gi
      volumes:
      - name: db-data
        persistentVolumeClaim:
          claimName: aidboxdb-data
      - name: aidboxdb-config
        configMap:
          name: aidboxdb-config
      - name: db-dshm
        emptyDir:
          medium: Memory

Service

Service
kind: Service
apiVersion: v1
metadata:
  name: aidboxdb
  namespace: smartbox
spec:
  selector:
    service: aidboxdb
  ports:
  - protocol: TCP
    targetPort: 5432
    port: 5432

Sandbox

ENVs

kind: ConfigMap
apiVersion: v1
metadata:
  name: sandbox
  namespace: smartbox
data:
  BOX_ID: aidboxone
  AIDBOX_ZEN_ENTRYPOINT: 'smartbox.dev-portal/box'
  BOX_AUTH_LOGIN__REDIRECT: "/"
  PGHOST: aidboxdb
  PGDATABASE: sandbox
  AIDBOX_STDOUT_PRETTY: 'true'
  AIDBOX_PORT: '8080'
  AIDBOX_BASE_URL: 'http://sandbox'
  PGPORT: '5432'
  AIDBOX_FHIR_VERSION: 4.0.1
  BOX_PROVIDER_DEFAULT_TYPE: mailgun
Secret
apiVersion: v1
kind: Secret
metadata:
  name: sandbox
  namespace: smartbox
type: Opaque
data:
  PGUSER: cG9zdGdyZXM=                  # base64 encoded postgres
  PGPASSWORD: cG9zdGdyZXM=              # base64 encoded postgres
  AIDBOX_ADMIN_ID: YWRtaW4=             # base64 encoded admin
  AIDBOX_ADMIN_PASSWORD: cGFzc3dvcmQ=   # base64 encoded password
  AIDBOX_CLIENT_ID: cm9vdA==            # base64 encoded root
  AIDBOX_CLIENT_SECRET: c2VjcmV0        # base64 encoded secret

  AIDBOX_LICENSE:                       # your base64 encoded lincense

  # your base64 encoded email provider secrets
  BOX_PROVIDER_DEFAULT_URL:
  BOX_PROVIDER_DEFAULT_FROM:
  BOX_PROVIDER_DEFAULT_USERNAME:
  BOX_PROVIDER_DEFAULT_PASSWORD:

Service

kind: Service
apiVersion: v1
metadata:
  name: sandbox
  namespace: smartbox
spec:
  selector:
    service: sandbox
  ports:
  - protocol: TCP
    targetPort: 8080
    port: 80

Deployment

kind: Deployment
apiVersion: apps/v1
metadata:
  name: sandbox
  namespace: smartbox
spec:
  replicas: 1
  selector:
    matchLabels:
      service: sandbox
  template:
    metadata:
      labels:
        service: sandbox
    spec:
      containers:
      - readinessProbe:
          httpGet:
            scheme: HTTP
            path: /health
            port: 8080
          initialDelaySeconds: 20
          timeoutSeconds: 10
          periodSeconds: 10
          failureThreshold: 6
        envFrom:
        - configMapRef:
            name: sandbox
        - secretRef:
            name: sandbox
        name: main
        ports:
        - containerPort: 8080
          protocol: TCP
        livenessProbe:
          httpGet:
            scheme: HTTP
            path: /health
            port: 8080
          initialDelaySeconds: 20
          timeoutSeconds: 10
          periodSeconds: 10
          failureThreshold: 12
        imagePullPolicy: Always
        image: healthsamurai/smartbox:edge

Portal

ENVs

ConfigMap
kind: ConfigMap
apiVersion: v1
metadata:
  name: smartbox
  namespace: smartbox
data:
  BOX_INSTANCE_NAME: smartbox
  BOX_ID: aidboxone
  AIDBOX_ZEN_ENTRYPOINT: 'smartbox.portal/box'
  BOX_AUTH_LOGIN__REDIRECT: "/admin/portal"
  BOX_SMARTBOX_SANDBOX__URL: "http://sandbox"
  PGHOST: aidboxdb
  PGDATABASE: smartbox
  PGPORT: '5432'
  AIDBOX_STDOUT_PRETTY: 'true'
  AIDBOX_PORT: '8080'
  AIDBOX_FHIR_VERSION: 4.0.1
  AIDBOX_BASE_URL: 'http://smartbox'
  BOX_PROVIDER_DEFAULT_TYPE: mailgun
  BOX_BULK__STORAGE_BACKEND: gcp
  BOX_BULK__STORAGE_GCP_SERVICE__ACCOUNT: gcp-ac
Secret
apiVersion: v1
kind: Secret
metadata:
  name: smartbox
  namespace: smartbox
type: Opaque
data:
  PGUSER: cG9zdGdyZXM=                  # base64 encoded postgres
  PGPASSWORD: cG9zdGdyZXM=              # base64 encoded postgres
  AIDBOX_ADMIN_ID: YWRtaW4=             # base64 encoded admin
  AIDBOX_ADMIN_PASSWORD: cGFzc3dvcmQ=   # base64 encoded password
  AIDBOX_CLIENT_ID: cm9vdA==            # base64 encoded root
  AIDBOX_CLIENT_SECRET: c2VjcmV0        # base64 encoded secret
  
  BOX_SMARTBOX_SANDBOX__ADMIN: YWRtaW4= # base64 encoded admin
  
  AIDBOX_LICENSE:                       # your base64 encoded lincense
  
  # your base64 encoded email provider secrets
  BOX_PROVIDER_DEFAULT_URL:
  BOX_PROVIDER_DEFAULT_FROM:
  BOX_PROVIDER_DEFAULT_USERNAME:
  BOX_PROVIDER_DEFAULT_PASSWORD:

  # your base64 encoded GCP storage secrets
  BOX_BULK__STORAGE_GCP_SERVICE__ACCOUNT__EMAIL:
  BOX_BULK__STORAGE_GCP_SERVICE__ACCOUNT__PRIVATE__KEY:
  BOX_BULK__STORAGE_GCP_BUCKET:

Service

Service
kind: Service
apiVersion: v1
metadata:
  name: smartbox
  namespace: smartbox
spec:
  selector:
    service: smartbox
  ports:
  - protocol: TCP
    targetPort: 8080
    port: 80

Deployment

kind: Deployment
apiVersion: apps/v1
metadata:
  name: smartbox
  namespace: smartbox
spec:
  replicas: 1
  selector:
    matchLabels:
      service: smartbox
  template:
    metadata:
      labels:
        service: smartbox
    spec:
      containers:
      - readinessProbe:
          httpGet:
            scheme: HTTP
            path: /health
            port: 8080
          initialDelaySeconds: 20
          timeoutSeconds: 10
          periodSeconds: 10
          failureThreshold: 6
        envFrom:
        - configMapRef:
            name: smartbox
        - secretRef:
            name: smartbox
        name: main
        ports:
        - containerPort: 8080
          protocol: TCP
        livenessProbe:
          httpGet:
            scheme: HTTP
            path: /health
            port: 8080
          initialDelaySeconds: 20
          timeoutSeconds: 10
          periodSeconds: 10
          failureThreshold: 12
        imagePullPolicy: Always
        image: healthsamurai/smartbox:edge

Prepare a configuration file

To get a k8s configuration file:

  1. Populate the templates above

  2. Combine all the templates to the .yaml file separating the templates with --- lines

The beginning of the file should look like.

smartbox.yaml
---
kind: Namespace
apiVersion: v1
metadata:
  name: smartbox
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: aidboxdb-data
  namespace: smartbox
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
# ... other file content

Deploy Smartbox to your cluster

To deploy Smartbox run the command.

kubectl apply -f smartbox.yaml

The result should look like this.

namespace/smartbox created
persistentvolumeclaim/aidboxdb-data created
configmap/aidboxdb-envs created
secret/aidboxdb-envs created
configmap/aidboxdb-config created
statefulset.apps/aidboxdb created
service/aidboxdb created
configmap/sandbox created
secret/sandbox created
service/sandbox created
deployment.apps/sandbox created
configmap/smartbox created
secret/smartbox created
service/smartbox created
deployment.apps/smartbox created

To check if everything is working fine run the command.

kubectl get pods -n smartbox

There should be 3 running pods.

NAME                       READY   STATUS    RESTARTS      AGE
aidboxdb-0                 1/1     Running   1 (31s ago)   99m
sandbox-759d6b46fc-qwzwd   0/1     Running   1 (31s ago)   9m56s
smartbox-979b6dfbb-2bhkn   0/1     Running   1 (31s ago)   9m56s

Last updated