Appendix: Background
Reference material for the FHIR Starter Project. The pages link here where it helps; you don’t need to read it from start to finish.
Kubernetes and Kustomize in Five Minutes
Your service runs in a Kubernetes cluster on your Mac, which OrbStack (or Docker Desktop) provides. You don’t need to know Kubernetes well for this guide, but these terms come up on almost every page.
Kubernetes
| Term | What it is in this guide |
|---|---|
Namespace |
A named group of objects in the cluster. Everything your local deployment creates is in the namespace |
Pod |
A running container: your service, WireMock, or cerner-mock. Kubernetes replaces a pod when its configuration changes, or when it crashes. |
Deployment |
Describes a pod: its image, its environment, and how many copies to run. Your deployments are |
Service |
A stable name and port for a deployment’s pods. Inside the cluster, your service reaches WireMock at |
ConfigMap |
A set of files or settings that a deployment mounts into its pods or turns into environment variables. Your WireMock stubs, cerner-mock data, and |
Readiness and liveness |
Kubernetes checks whether each pod has started and is still running, and sends it requests only while it is ready. Your service reports that at |
Port forwarding |
Makes a port in the cluster available on your Mac. |
The kubectl commands you are most likely to need:
kubectl get pods -n fhir-starter-service-test # what is running, and its status
kubectl logs -n fhir-starter-service-test deploy/wiremock # the log of a deployment's pod
kubectl describe pod -n fhir-starter-service-test <pod name> # why a pod doesn't start
kubectl port-forward -n fhir-starter-service-test svc/cerner-mock-v1 8090:8080
Kustomize
Kubernetes objects are described in YAML files. Kustomize builds the final YAML for an environment from shared pieces, so the files for your local cluster, staging, and production don’t repeat each other. Your kubernetes directory has three kinds of pieces:
-
base: the deployment and service of your own service, the same in every environment. -
components: optional pieces that an environment adds.components/devadds your local settings and test data; other teams' repositories provide components for WireMock and cerner-mock. -
One directory per environment, such as
dev-with-dependencies(your local cluster),sqa, orprod. Itskustomization.yamllists the base and components it uses. Skaffold deploysdev-with-dependenciesto your cluster.
A few things in the files you edit:
-
A component or resource can come from another repository, for example
https://coderepo.mobilehealth.va.gov/scm/dhsss/wiremock.git//kubernetes?ref=v3.13.2. Therefis the branch or tag to use, so you get a fixed version. -
The order of
componentsmatters: a component can only change objects that an earlier one created. That’s why WireMock comes before../components/dev, which adds your stubs to it. -
A
configMapGeneratorcreates a ConfigMap from files (files:) or from a properties file (envs:).behavior: createmakes a new ConfigMap;behavior: mergeadds settings to one that another piece created. Kustomize adds a hash of the contents to the ConfigMap’s name, so a change to a stub gives the ConfigMap a new name, and Kubernetes replaces the pods that use it. -
patcheschange objects that another piece created, for example to mount your stubs into the WireMock deployment. A patch finds its target bykindandmetadata.name, and merges its fields into it.
Before Skaffold deploys, scripts/localize.sh copies everything, including the pieces from other repositories, into kubernetes/localized; see The Kubernetes Files Skaffold Deploys. To see the YAML that Kustomize builds for your local cluster, run:
kustomize build kubernetes/localized/dev-with-dependencies/dev-with-dependencies
To learn more, see Skaffold and Kustomize Setup, the Kubernetes concepts, and the kustomization.yaml reference.
What setup.sh Does
The script works through 10 steps. Each question shows its default in brackets:
| Step | What the script does | What to answer |
|---|---|---|
1. Bitbucket/DTR and Jira project |
Sets the project the service belongs to. filegen uses it for the image paths |
Enter ( |
2. Git repository |
Notices that the service is inside your |
Enter ( |
3. filegen |
Generates the |
Enter for your user name and the Backstage system |
4–6. |
Adjusts |
Nothing to answer |
7. Dynatrace labels |
Sets the |
Enter ( |
8. Product owner |
Sets the product owner in |
Enter (leave it empty) |
9. Build |
Offers to build, deploy, and test the service |
Enter ( |
10. Commit |
Commits the files that the previous steps generated |
Enter ( |
Here is an abbreviated example of the output:
[2/10] Git repository The project directory is inside the git repository .../starter-project (origin: https://coderepo.mobilehealth.va.gov/scm/ckm/starter-project.git) Add fhir-starter-service to that repository instead of creating a repository for it? (y/n) [y]: Message of the initial commit [WIP: initial commit]: $ git add -A -- . $ git commit -q -m 'WIP: initial commit' -- . Done: Committed the generated project filegen reads the 'origin' remote only from a repository in the project directory, so it writes SET_ME instead of the Bitbucket project in catalog-info.yaml, mkdocs.yaml, and vv.yaml.
[3/10] Kubernetes, Skaffold, pipeline, and Backstage files (filegen) Backstage owner (your user name) [jdoe]: Backstage system (contract) [ckm]: filegen downloads its templates from coderepo. This can take a minute. $ ./mvnw -B -q gov.va.mobile.tools:ngss-filegen-maven-plugin:generate-kustomize-files ... Done: Generated the files
[4/10] skaffold.yaml for a single-module project Done: Removed 6 'project: fhir-starter-service' entries under 'jib:', and changed 1 'mvn -pl fhir-starter-service' to 'mvn -pl .' ... Finished setting up fhir-starter-service
Replace the remaining placeholders: metadata.yaml:10: # TODO: Document the settings of the service (see AppProperties and application.properties) ... vv.yaml:9:coderepo_project: "SET_ME" # coderepo project key
Setting Up a Service Without the Script
If you ever need to set up a generated service without the script, these are the equivalent manual steps:
-
Commit the generated project. The build reads git information, so a commit is required before the first Maven build:
git add . git commit -m "WIP: initial commit" -
Generate the Kubernetes, Skaffold, and other files with filegen. The full plugin name is required, because the
filegenprefix can resolve to another plugin:F=gov.va.mobile.tools:ngss-filegen-maven-plugin ./mvnw $F:generate-kustomize-files $F:generate-skaffold-file $F:init-vv-yaml $F:generate-jenkinsfile \ $F:generate-dibr-readme $F:init-backstage-files -Dbackstage.user=SET_ME -Dbackstage.contract=SET_ME -
filegen generates
skaffold.yamlfor a multi-module project. Inskaffold.yaml, remove everyproject: fhir-starter-serviceentry underjib:, and in thepost-sync-testprofile, changemvn -pl fhir-starter-service …tomvn -pl . …. -
Make the Skaffold scripts executable:
chmod +x ./scripts/* -
Add
SPRING_CLOUD_VAULT_ENABLED=falseafterSPRING_PROFILES_ACTIVE=devinkubernetes/components/dev/overrides.env. -
In
kubernetes/base/deployment.yaml, set themetadata:labels:DynatraceDeploymentNameandspec:template:metadata:labels:MAP-DHAS-ServiceNamelabels toMAP-DHAS-FSS-3443-fhir-starter-service-v1. -
Commit the generated files:
git add . git commit -m "Generated files added"
FHIR Server Properties
The Mobile Framework configures the FHIR server with va.mobile.fhir.server.* properties. These are the ones you are most likely to need; page 9 sets the server name and description:
| Property | Default | Description |
|---|---|---|
|
|
Path of the FHIR server, relative to the context path |
|
|
|
|
|
|
|
|
Indents JSON responses, which makes them easier to read |
|
None |
Page sizes of search results |
|
|
Logs every request with HAPI’s |