diff --git a/.github/workflows/build-images.yaml b/.github/workflows/build-images.yaml new file mode 100644 index 0000000..89d492d --- /dev/null +++ b/.github/workflows/build-images.yaml @@ -0,0 +1,81 @@ +name: Build Container Images + +on: + push: + tags: + - "image/v*" + pull_request: + branches: [master] + +jobs: + build: + name: Build + runs-on: ubuntu-20.04 + steps: + - name: Docker meta + id: docker_meta + uses: crazy-max/ghaction-docker-meta@v1 + with: + images: | + ghcr.io/hapifhir/hapi + docker.io/hapiproject/hapi + tag-sha: false + tag-match: "v(.*)" + # waiting for https://github.com/crazy-max/ghaction-docker-meta/issues/13 for a cleaner solution + - name: Docker distroless meta + id: docker_distroless_meta + uses: crazy-max/ghaction-docker-meta@v1 + with: + images: | + ghcr.io/hapifhir/hapi + docker.io/hapiproject/hapi + tag-sha: false + tag-match: "v(.*)" + sep-tags: -distroless, + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + if: github.event_name != 'pull_request' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + if: github.event_name != 'pull_request' + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GHCR_TOKEN }} + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - name: Build and push + id: docker_build + uses: docker/build-push-action@v2 + with: + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} + - name: Build and push distroless + id: docker_build_distroless + uses: docker/build-push-action@v2 + with: + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.docker_distroless_meta.outputs.tags }}-distroless + labels: ${{ steps.docker_distroless_meta.outputs.labels }} + target: release-distroless + - name: Print image digests + run: | + echo ${{ steps.docker_build.outputs.digest }} + echo ${{ steps.docker_build_distroless.outputs.digest }} diff --git a/Dockerfile b/Dockerfile index a6699d5..64a6478 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,21 @@ RUN mvn -ntp dependency:go-offline COPY src/ /tmp/hapi-fhir-jpaserver-starter/src/ RUN mvn clean install -DskipTests +FROM build-hapi AS build-distroless +RUN mvn package spring-boot:repackage -Pboot +RUN mkdir /app && \ + cp /tmp/hapi-fhir-jpaserver-starter/target/ROOT.war /app/main.war + +FROM gcr.io/distroless/java-debian10:11 AS release-distroless +COPY --chown=nonroot:nonroot --from=build-distroless /app /app +EXPOSE 8080 +# 65532 is the nonroot user's uid +# used here instead of the name to allow Kubernetes to easily detect that the container +# is running as a non-root (uid != 0) user. +USER 65532:65532 +WORKDIR /app +CMD ["/app/main.war"] + FROM tomcat:9.0.38-jdk11-openjdk-slim-buster RUN mkdir -p /data/hapi/lucenefiles && chmod 775 /data/hapi/lucenefiles diff --git a/README.md b/README.md index 12fb454..95edfc7 100644 --- a/README.md +++ b/README.md @@ -322,7 +322,7 @@ Set `hapi.fhir.cql_enabled=true` in the [application.yaml](https://github.com/ha ## Enabling MDM (EMPI) -Set `hapi.fhir.mdm_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable MDM on this server. The MDM matching rules are configured in [mdm-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/mdm-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that MDM relies on subscriptions, so for MDM to work, subscriptions must be enabled. +Set `hapi.fhir.mdm_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable MDM on this server. The MDM matching rules are configured in [mdm-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/mdm-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that MDM relies on subscriptions, so for MDM to work, subscriptions must be enabled. ## Using Elasticsearch @@ -344,23 +344,14 @@ elasticsearch.schema_management_strategy=CREATE Set `hapi.fhir.lastn_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable the $lastn operation on this server. Note that the $lastn operation relies on Elasticsearch, so for $lastn to work, indexing must be enabled using Elasticsearch. -## Example of a Dockerfile based on distroless images (for lower footprint and improved security) +## Build the distroless variant of the image (for lower footprint and improved security) -```code -FROM maven:3.6.3-jdk-11-slim as build-hapi -WORKDIR /tmp/hapi-fhir-jpaserver-starter +The default Dockerfile contains a `release-distroless` stage to build a variant of the image +using the `gcr.io/distroless/java-debian10:11` base image: -COPY pom.xml . -RUN mvn -ntp dependency:go-offline - -COPY src/ /tmp/hapi-fhir-jpaserver-starter/src/ -RUN mvn clean package spring-boot:repackage -Pboot - -FROM gcr.io/distroless/java:11 - -COPY --from=build-hapi /tmp/hapi-fhir-jpaserver-starter/target/ROOT.war /app/main.war - -EXPOSE 8080 -WORKDIR /app -CMD ["main.war"] +```sh +docker build --target=release-distroless -t hapi-fhir:distroless . ``` + +Note that distroless images are also automatically build and pushed to the container registry, +see the `-distroless` suffix in the image tags. diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java b/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java index 082e3b4..2efe064 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java @@ -55,9 +55,13 @@ public class EnvironmentHelper { properties.putIfAbsent(AvailableSettings.USE_MINIMAL_PUTS, false); //Hibernate Search defaults - properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, true); + properties.putIfAbsent(HibernateOrmMapperSettings.ENABLED, false); if (Boolean.parseBoolean(String.valueOf(properties.get(HibernateOrmMapperSettings.ENABLED)))) { - properties.putIfAbsent(BackendSettings.backendKey(BackendSettings.TYPE), LuceneBackendSettings.TYPE_NAME); + if (isElasticsearchEnabled(environment)) { + properties.putIfAbsent(BackendSettings.backendKey(BackendSettings.TYPE), ElasticsearchBackendSettings.TYPE_NAME); + } else { + properties.putIfAbsent(BackendSettings.backendKey(BackendSettings.TYPE), LuceneBackendSettings.TYPE_NAME); + } if (properties.get(BackendSettings.backendKey(BackendSettings.TYPE)).equals(LuceneBackendSettings.TYPE_NAME)) { properties.putIfAbsent(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_TYPE), LocalFileSystemDirectoryProvider.NAME);