Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 58 additions & 9 deletions docs/configuration/init-bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,37 @@ coverY: 0
Available since the 2411 release.
{% endhint %}

Init Bundle is a simple approach to creating configuration resources when starting Aidbox.
Init Bundle creates configuration resources when Aidbox starts.

It is equivalent to just executing [Bundle](../api/batch-transaction.md) in Aidbox using `POST /fhir`. There are some differences:
It is equivalent to executing [Bundle](../api/batch-transaction.md) in Aidbox using `POST /fhir`, with some differences:

1. It is executed before the internal HTTP server starts, and before the health check response.
2. Unsuccessful execution of the init bundle of type **transaction** prevents Aidbox from starting.
3. Unsuccessful execution of the init bundle of type **batch** triggers warnings in the log; Aidbox continues the startup process.
4. Aidbox startup will be interrupted if the specified file is unavailable or is not a valid bundle resource of transaction or batch type.
5. Only JSON format is supported.

## Why Init Bundle instead of a seed service

A common alternative is a self-written seed service: a sidecar, an init container, or a script that waits for Aidbox to boot and then `POST`s the configuration resources to `/fhir`. Init Bundle runs inside Aidbox before the HTTP server opens, which removes the problems that approach carries.

- **No race window.** A seed service `POST`s after Aidbox reports healthy, so the orchestrator can route traffic before the configuration lands. Init Bundle finishes before `/health` responds, so a green health check guarantees it applied.
- **Fail-fast on a bad bundle.** A failed transaction init bundle stops Aidbox from starting, so the orchestrator holds back traffic or rolls the deployment back. A failed seed service leaves Aidbox serving with missing configuration.
- **No bootstrap credentials.** A seed service needs a `Client` and `AccessPolicy` before it can write the ones you want to seed. Init Bundle runs before authentication serves, so it needs no external credentials.
- **Nothing extra to operate.** Init Bundle is one environment variable and one file, with no additional container or process to monitor and retry.

## Usage

Specify `BOX_INIT_BUNDLE` env. The value must be an URL.
Specify `BOX_INIT_BUNDLE` env. The value must be a URL.

```
BOX_INIT_BUNDLE=<URL>
```

Examples of URLs:

* `file:///tmp/bundle.json`
* `https://storage.googleapis.com/<BUCKET_NAME>/<OBJECT_NAME>`
- `file:///tmp/bundle.json`
- `https://storage.googleapis.com/<BUCKET_NAME>/<OBJECT_NAME>`

## Example

Expand Down Expand Up @@ -66,12 +75,53 @@ Aidbox will apply it if the `BOX_INIT_BUNDLE` is set to:
BOX_INIT_BUNDLE=file:///tmp/bundle.json
```

## Delivering the bundle to the pod

`BOX_INIT_BUNDLE` points at a `file://` path inside the container or an `https://` URL, so deploying an init bundle comes down to getting that file to the container. Common options:

| Method | How | Pros | Cons |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **Bake into a custom image** | `FROM healthsamurai/aidboxone`, `COPY bundle.json` into the image, set `BOX_INIT_BUNDLE=file:///…` | Immutable, versioned artifact; atomic deploy and rollback by image tag; no boot-time external dependency | Rebuild and push the image on every bundle change |
| **Mounted volume / ConfigMap** | Mount the file into the stock image (a Kubernetes `ConfigMap` or a volume); `BOX_INIT_BUNDLE=file://<mount>` | Stock image; change the bundle without rebuilding (GitOps-friendly) | A `ConfigMap` is text-only and limited to ~1 MiB, so large bundles hit the limit |
| **Init container / sidecar** | An init container builds or downloads the bundle into a shared volume that the Aidbox container reads via `file://` | Stock image; can fetch from private storage using the pod's identity | An extra container and its wiring to operate |
| **Remote URL (object storage)** | Upload the bundle to object storage (GCS, S3, Azure Blob); `BOX_INIT_BUNDLE=https://…` | Stock image; fully decoupled; per-environment is a different URL; versioned in the bucket | Startup depends on storage availability and access |

**Keep secrets out of the bundle.** A bundle baked into an image layer or served from a public URL exposes any secret it contains. Keep secrets out of the static bundle and inject them at container start. See [How to inject env variables into init bundle](../deployment-and-maintenance/deploy-aidbox/how-to-inject-env-variables-into-init-bundle.md).

**Fetching from private storage.** `BOX_INIT_BUNDLE` fetches an `https://` URL with a plain HTTP `GET` and does not authenticate with cloud IAM. For a private bucket, either put a pre-signed URL (S3 pre-signed URL, Azure SAS) in `BOX_INIT_BUNDLE`, or let an init container or a CSI volume driver (Azure Blob CSI or GCS FUSE with workload identity) fetch the object using the pod's identity and expose it to Aidbox as a `file://` path.

## Bundling a local FHIR package

If the init bundle installs a local FHIR package with [`$fhir-package-install`](../reference/package-registry-api.md), it references the package as a `.tgz` tarball on a `file://` path. That tarball is a second file, so it has to reach the container the same way the bundle does: bake it into the image, place it on the shared volume, or serve it from an `https://` URL. A `ConfigMap` is text-only and cannot hold it.

Add the install as a bundle entry that `POST`s the tarball path to `$fhir-package-install`:

```json
{
"request": {
"method": "POST",
"url": "$fhir-package-install"
},
"resource": {
"resourceType": "Parameters",
"parameter": [
{
"name": "package",
"valueString": "file:///tmp/ig/custom-ig.tgz"
}
]
}
}
```

Put this entry before the resources that depend on the package (profiles, custom types), so the package is loaded by the time they apply. For a full working setup, see the [init-bundle-from-directories example](https://github.com/Aidbox/examples/tree/main/aidbox-features/init-bundle-from-directories).

## Hints

1. First, check that Aidbox handles the Bundle as it should using `POST /fhir`. Try to post it several times to make sure it is idempotent. Then add it to `BOX_INIT_BUNDLE`.
2. Note that the [Aidbox format](../api/rest-api/other/aidbox-and-fhir-formats.md) is not supported.
3. Aidbox handles an `id` in the body of the POST request. That's why posting the resource with an id twice will cause an `duplicate key` error. Use [conditional create](../api/rest-api/crud/create.md) or [update](../api/rest-api/crud/update.md) for that.
4. Most resources support `PUT` for idempotent updates inside an init bundle. **Exception:** [`AidboxTopicDestination`](../modules/topic-based-subscriptions/aidbox-topic-based-subscriptions.md#updating-a-topicdestination) is immutable and rejects `PUT` / `PATCH` (also inside bundles). Use a [conditional create](../api/rest-api/crud/create.md) `POST` with `ifNoneExist=_id=<id>` so the entry is a no-op when the resource already exists and creates it on the first run:
4. Most resources support `PUT` for idempotent updates inside an init bundle. **Exception:** [`AidboxTopicDestination`](../modules/topic-based-subscriptions/aidbox-topic-based-subscriptions.md#updating-a-topicdestination) is immutable and rejects `PUT` / `PATCH` (also inside bundles). Use a [conditional create](../api/rest-api/crud/create.md) (`POST` with `ifNoneExist=_id=<id>`) so the entry is a no-op when the resource already exists and creates it on the first run:

```json
{
Expand All @@ -88,11 +138,10 @@ BOX_INIT_BUNDLE=file:///tmp/bundle.json
}
```

To change configuration of an already-created destination, delete it manually and let the next bundle run recreate it — see [Updating a TopicDestination](../modules/topic-based-subscriptions/aidbox-topic-based-subscriptions.md#updating-a-topicdestination).
To change configuration of an already-created destination, delete it manually and let the next bundle run recreate it. See [Updating a TopicDestination](../modules/topic-based-subscriptions/aidbox-topic-based-subscriptions.md#updating-a-topicdestination).

## See also


{% content-ref url="../deployment-and-maintenance/deploy-aidbox/how-to-inject-env-variables-into-init-bundle.md" %}
[how-to-inject-env-variables-into-init-bundle.md](../deployment-and-maintenance/deploy-aidbox/how-to-inject-env-variables-into-init-bundle.md)
{% endcontent-ref %}
Expand All @@ -101,4 +150,4 @@ BOX_INIT_BUNDLE=file:///tmp/bundle.json
{% endcontent-ref %}
{% content-ref url="../tutorials/artifact-registry-tutorials/upload-fhir-implementation-guide/how-to-load-fhir-ig-with-init-bundle.md" %}
[how-to-load-fhir-ig-with-init-bundle](../tutorials/artifact-registry-tutorials/upload-fhir-implementation-guide/how-to-load-fhir-ig-with-init-bundle.md)
{% endcontent-ref %}
{% endcontent-ref %}
Loading