Skip to main content

Pre-installation checks

This page lists the checks that an operator runs before installing Foundation4 in the production profile, with the command for each check and the result that confirms the check. The checks catch the problems that otherwise surface as a stalled Helm installation: missing permissions, unbound volume claims, image pull failures, database privileges and malformed secrets. Operators run the checks once per cluster and again after any change to the cluster, the registry or the database.

Scope and order​

Run the checks after steps 1 to 5 of Install on Kubernetes, which create the namespace, the image pull secret, the values file foundation4ai.values.yaml, the secrets file foundation4ai.secrets.env and the Secret foundation4ai-secrets. Run every command from the directory that holds the installation files. The test objects carry the label app.kubernetes.io/part-of: foundation4ai-checks, and the last section removes them.

Cluster access and permissions​

CheckCommandExpected result
Target clusterkubectl config current-contextThe context of the target cluster
Kubernetes versionkubectl versionServer Version 1.27 or later; a version with image volume support when models or packages are used
Node architecturekubectl get nodes -L kubernetes.io/archamd64 in the ARCH column of the nodes that run Foundation4
Namespace creationkubectl auth can-i create namespacesyes
Cluster roles for Prometheuskubectl auth can-i create clusterrolesyes
Cluster role bindings for Prometheuskubectl auth can-i create clusterrolebindingsyes
Secret reads during renderingkubectl -n foundation4ai auth can-i get secretsyes
Job logskubectl -n foundation4ai auth can-i get pods --subresource=logyes
Port forwardkubectl -n foundation4ai auth can-i create pods --subresource=portforwardyes
Pod securitykubectl get namespace foundation4ai --show-labelsNo pod-security.kubernetes.io/enforce=restricted label
Namespaced resourcesResource loop belowyes on every line

The resource loop checks each kind of object that the two releases create:

for r in pods secrets configmaps serviceaccounts services deployments statefulsets jobs \
persistentvolumeclaims poddisruptionbudgets horizontalpodautoscalers ingresses; do
printf '%s: ' "$r"
kubectl -n foundation4ai auth can-i create "$r"
done

Expected result: 12 lines, each ending in yes.

Workstation tools​

CheckCommandExpected result
Helm versionhelm version --shortA version that starts with v3.
Kustomizekubectl kustomize --helpThe help text of the kustomize subcommand
Secret generationopenssl version and uuidgenA version string and a universally unique identifier (UUID)
Recipe tools, when just is usedjust --version, kustomize version and yq --versionA version string from each tool

Storage and images​

CheckCommandExpected result
Default StorageClasskubectl get storageclassOne class marked (default), or a class named in the values for NATS JetStream and Prometheus
No placeholders in the values filegrep -n '<' foundation4ai.values.yamlNo output
Image tags setgrep -n -e serverImageTag: -e grpcImageTag: -e dashboardImageTag: foundation4ai.values.yaml3 lines, each with a tag
Pull secret typekubectl -n foundation4ai get secret <pull secret> -o jsonpath='{.type}'kubernetes.io/dockerconfigjson
Volume binding and image pullsInstallation testPod Succeeded and volume claim Bound
Registry token lifetimeThe registry's documentationTokens that do not expire, or a refresh mechanism, as described in Charts, images and installation bundle

Installation test​

The installation test requests a 10 GiB volume claim, the size of one NATS JetStream claim, and starts one container from each Foundation4 image. Save the following manifest as install-check.yaml, with the image repositories and tags from the values file. Remove the imagePullSecrets entry when the registry needs no credentials, and add storageClassName to the claim when the values name a storage class.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: install-check
namespace: foundation4ai
labels:
app.kubernetes.io/part-of: foundation4ai-checks
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: install-check
namespace: foundation4ai
labels:
app.kubernetes.io/part-of: foundation4ai-checks
spec:
restartPolicy: Never
imagePullSecrets:
- name: <pull secret>
containers:
- name: server
image: <api server repository>:<api server image tag>
command: ["df", "-h", "/check"]
volumeMounts:
- name: check
mountPath: /check
- name: grpc
image: <grpc service repository>:<grpc service image tag>
command: ["true"]
- name: dashboard
image: <dashboard repository>:<dashboard image tag>
command: ["true"]
volumes:
- name: check
persistentVolumeClaim:
claimName: install-check

Run the test:

kubectl apply -f install-check.yaml
kubectl -n foundation4ai wait --for=jsonpath='{.status.phase}'=Succeeded pod/install-check --timeout=300s
kubectl -n foundation4ai logs install-check -c server
kubectl -n foundation4ai get pvc install-check

Expected result: pod/install-check condition met, a df line for the file system mounted on /check, and the claim in Bound status. When the wait times out, kubectl -n foundation4ai describe pod install-check shows the cause: ErrImagePull or ImagePullBackOff for an image or credential problem, exec format error in a container log for an image built for another architecture, or an unbound claim for a storage problem.

For a mirrored registry, repeat the image test with the core release images listed in Charts, images and installation bundle. The core release images take pull credentials from separate values, so a successful test of the Foundation4 images does not cover the core release images.

Database​

The database checks apply to the production profile. The evaluation profile installs PostgreSQL from the bundled chart.

CheckCommandExpected result
Connection URL formatgrep -Ec '^POSTGRES_URL=postgres(ql)?://[A-Za-z0-9_.-]+:[A-Za-z0-9]+@[^/]+/[A-Za-z0-9_]+' foundation4ai.secrets.env1
Reachability, version and privilegesDatabase testPod Succeeded with the values described below

The URL check confirms a postgres:// URL with a user, a password of letters and digits only, a host and a database name. The charts write the URL into a configuration file without quoting or encoding, so other characters in the password can break the configuration.

Database test​

The database test runs psql inside the cluster with the URL from the Secret foundation4ai-secrets. The test uses the PostgreSQL image of the bundled chart, pgvector/pgvector:pg18-trixie, or the mirrored copy of that image. Save the following manifest as database-check.yaml:

apiVersion: v1
kind: Pod
metadata:
name: database-check
namespace: foundation4ai
labels:
app.kubernetes.io/part-of: foundation4ai-checks
spec:
restartPolicy: Never
containers:
- name: psql
image: pgvector/pgvector:pg18-trixie
env:
- name: POSTGRES_URL
valueFrom:
secretKeyRef:
name: foundation4ai-secrets
key: POSTGRES_URL
command: ["psql"]
args:
- "$(POSTGRES_URL)"
- "-x"
- "-c"
- "SELECT current_setting('server_version') AS server_version, (SELECT default_version FROM pg_available_extensions WHERE name = 'vector') AS vector_available, (SELECT extversion FROM pg_extension WHERE extname = 'vector') AS vector_installed, has_database_privilege(current_database(), 'CREATE') AS create_on_database, has_schema_privilege('public', 'CREATE') AS create_in_public, (SELECT rolsuper FROM pg_roles WHERE rolname = current_user) AS superuser"

Run the test:

kubectl apply -f database-check.yaml
kubectl -n foundation4ai wait --for=jsonpath='{.status.phase}'=Succeeded pod/database-check --timeout=120s
kubectl -n foundation4ai logs database-check

Expected result: pod/database-check condition met and one record. The values differ by installation; the following output meets every requirement:

-[ RECORD 1 ]------+-------
server_version | 18.1
vector_available | 0.8.1
vector_installed | 0.8.1
create_on_database | t
create_in_public | t
superuser | f

The fields are read as follows:

  • Server version. PostgreSQL 18, the version that the bundled chart and the Foundation4 test environment use.
  • Vector available. pgvector 0.8.0 or later is installed on the database server. An empty value means that the server has no pgvector package.
  • Vector installed. The extension exists in the database. An empty value is acceptable when the database user can create the extension, for example when superuser is t. Otherwise a database administrator runs CREATE EXTENSION vector; in the database before installation.
  • Create privileges. Both values are t, because Foundation4 creates the schemas public and embeddings and the tables in both.

When the pod ends in Failed status, the log shows the psql connection error. Database describes the database settings.

Secrets file​

The secrets file checks read foundation4ai.secrets.env and print counts, key names or unchanged template lines, never the new secret values.

CheckCommandExpected result
Template passwords replacedgrep -Fx -f foundation4ai.secrets.env.template foundation4ai.secrets.envNo line that starts with POSTGRES_SUPERUSER_PASSWORD, POSTGRES_PASSWORD or REDIS_PASSWORD
Hexadecimal passwordsgrep -Ec -e '^POSTGRES_SUPERUSER_PASSWORD=[0-9a-f]{48,}$' -e '^POSTGRES_PASSWORD=[0-9a-f]{48,}$' -e '^REDIS_PASSWORD=[0-9a-f]{48,}$' foundation4ai.secrets.env3
Master key identifier is a UUIDgrep -Ec '^FOUNDATION4AI_APP_MASTER_KEY=[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$' foundation4ai.secrets.env1
Master secret is hexadecimalgrep -Ec '^FOUNDATION4AI_APP_MASTER_SECRET=[0-9a-f]{48,}$' foundation4ai.secrets.env1
Application secret is a Fernet keygrep -Ec '^FOUNDATION4AI_APP_SECRET=[A-Za-z0-9_-]{43}=$' foundation4ai.secrets.env1
License value presentgrep -Ec '^FOUNDATION4AI_APP_LICENSE=.+' foundation4ai.secrets.env1, with pending until the license is received
Secret matches the filekubectl -n foundation4ai describe secret foundation4ai-secretsEvery key of the secrets file with a size in bytes, and no values

A Fernet key is 32 random bytes encoded in URL-safe Base64: 44 characters that end in =. The command openssl rand -base64 32 | tr '+/' '-_' produces a Fernet key. Secrets and keys describes each secret.

Ingress and Gateway API​

These checks apply when the values enable ingress or httpRoute.

CheckCommandExpected result
Ingress controllerkubectl get ingressclassThe class named in ingress.className
Gateway API resourceskubectl get crd httproutes.gateway.networking.k8s.ioThe resource definition is listed
Gatewaykubectl get gateways -AThe Gateway named in httpRoute.parentRefs
Transport Layer Security (TLS) certificate Secretkubectl -n foundation4ai get secret <tls secret> -o jsonpath='{.type}'kubernetes.io/tls

API and dashboard access describes both access methods.

Cleanup​

Remove the test objects before installing the releases:

kubectl -n foundation4ai delete pod,pvc -l app.kubernetes.io/part-of=foundation4ai-checks

Expected result: pod "install-check" deleted, pod "database-check" deleted and persistentvolumeclaim "install-check" deleted.