Skip to content

Commit 2b58e07

Browse files
authored
feat: Kubernetes ready minimal image (#2183)
2 parents 698f938 + 035fcd5 commit 2b58e07

File tree

5 files changed

+288
-115
lines changed

5 files changed

+288
-115
lines changed

.github/workflows/docker-build-and-test.yml

Lines changed: 204 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88

99
env:
1010
TEST_IMAGE_NAME: 'local/openrouteservice:test'
11+
TEST_minimal_IMAGE_NAME: 'local/openrouteservice:test-minimal'
1112
BUILD_PLATFORMS: 'linux/amd64,linux/arm64'
1213

1314

@@ -18,136 +19,188 @@ jobs:
1819
runs-on: ubuntu-latest
1920
outputs:
2021
test_image_name: ${{ env.TEST_IMAGE_NAME }}
22+
test_minimal_image_name: ${{ env.TEST_minimal_IMAGE_NAME }}
2123
build_platforms: ${{ env.BUILD_PLATFORMS }}
24+
dockerfile_hash: ${{ steps.dockerfile-hash.outputs.hash }}
2225
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
- name: Generate Dockerfile hash
29+
id: dockerfile-hash
30+
run: |
31+
HASH=$(sha256sum Dockerfile | cut -d' ' -f1 | cut -c1-8)
32+
echo "hash=$HASH" >> $GITHUB_OUTPUT
2333
- run: |
2434
echo "Publish environment variables"
35+
prepare_maven_dependencies:
36+
name: Prepare Maven dependencies for ${{ matrix.name }}
37+
runs-on: ${{ matrix.runner }}
38+
needs:
39+
- prepare_environment
40+
strategy:
41+
matrix:
42+
include:
43+
- platform: linux/amd64
44+
name: linux-amd64
45+
runner: ubuntu-latest
46+
- platform: linux/arm64
47+
name: linux-arm64
48+
runner: ubuntu-24.04-arm
49+
steps:
50+
- name: Checkout
51+
uses: actions/checkout@v4
52+
with:
53+
fetch-depth: 0
54+
- name: Set up JDK 21
55+
uses: actions/setup-java@v4
56+
id: setup-java
57+
with:
58+
distribution: 'temurin'
59+
java-version: '21'
60+
cache: 'maven'
61+
- name: Download Maven dependencies
62+
if: steps.setup-java.outputs.cache-hit != 'true'
63+
run: |
64+
./mvnw package -q dependency:resolve dependency:resolve-plugins -Dmaven.test.skip=true > /dev/null || true
2565
build_docker_images:
26-
name: Build the docker images
27-
runs-on: ubuntu-latest
66+
name: Build ${{ matrix.image_stage }} for ${{ matrix.name }}
67+
runs-on: ${{ matrix.runner }}
2868
needs:
2969
- prepare_environment
70+
- prepare_maven_dependencies
71+
strategy:
72+
matrix:
73+
include:
74+
- platform: linux/amd64
75+
name: linux-amd64
76+
runner: ubuntu-latest
77+
image_stage: publish
78+
skip_on_draft_pr: false
79+
tags: ${{ needs.prepare_environment.outputs.test_image_name }}
80+
- platform: linux/arm64
81+
name: linux-arm64
82+
runner: ubuntu-24.04-arm
83+
image_stage: publish
84+
skip_on_draft_pr: true
85+
tags: ${{ needs.prepare_environment.outputs.test_image_name }}
86+
- platform: linux/amd64
87+
name: linux-amd64
88+
runner: ubuntu-latest
89+
image_stage: minimal
90+
skip_on_draft_pr: false
91+
tags: ${{ needs.prepare_environment.outputs.test_minimal_image_name }}
92+
- platform: linux/arm64
93+
name: linux-arm64
94+
runner: ubuntu-24.04-arm
95+
image_stage: minimal
96+
skip_on_draft_pr: true
97+
tags: ${{ needs.prepare_environment.outputs.test_minimal_image_name }}
3098
steps:
3199
- name: Checkout
100+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
32101
uses: actions/checkout@v4
33102
with:
34103
fetch-depth: 0
35104
- name: Get and save the UID
105+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
36106
run: |
37107
echo "UID=$(id -u)" >> $GITHUB_ENV
38-
- name: Set up QEMU
39-
uses: docker/setup-qemu-action@v3
40-
with:
41-
platforms: ${{ needs.prepare_environment.outputs.build_platforms }}
42108
- name: Set up Docker Buildx
109+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
43110
uses: docker/setup-buildx-action@v3
44-
- name: Set up JDK 17
45-
id: setup-java
111+
id: setup-buildx
112+
- name: Set up JDK 21
113+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
46114
uses: actions/setup-java@v4
115+
id: setup-java
47116
with:
48117
distribution: 'temurin'
49-
java-version: '17'
50-
- name: Cache Maven packages
51-
uses: actions/cache@v4
52-
with:
53-
path: ~/.m2
54-
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
55-
restore-keys: ${{ runner.os }}-m2
56-
- name: Prepare the maven cache dependencies
118+
java-version: '21'
119+
cache: 'maven'
120+
- name: Prepare Dockerfile for Maven cache
121+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
57122
run: |
58-
echo "Sync the maven dependencies"
59-
./mvnw package -Dmaven.test.skip=true -B dependency:go-offline dependency:resolve-plugins dependency:resolve -q
60-
# Replace all RUN ./mvnw with RUN --mount=type=cache,target=/root/.m2 ./mvnw
61-
sed -i 's/RUN \.\/mvnw /RUN --mount=type=cache,target=\/root\/.m2 \.\/mvnw /g' Dockerfile
62-
- name: inject maven-build-cache into docker
63-
uses: reproducible-containers/[email protected]
123+
sed -i "s|RUN \./mvnw |RUN --mount=type=cache,target=/root/.m2/repository ./mvnw |g" Dockerfile
124+
- name: Inject Maven cache into Docker build
125+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
126+
uses: 'reproducible-containers/buildkit-cache-dance@5b81f4d29dc8397a7d341dba3aeecc7ec54d6361' # v3.3.0
64127
with:
128+
builder: ${{ steps.setup-buildx.outputs.name }}
129+
dockerfile: Dockerfile
130+
skip-extraction: ${{ steps.setup-java.outputs.cache-hit }}
65131
cache-map: |
66132
{
67-
"/home/runner/.m2": "/root/.m2"
133+
"/home/runner/.m2/repository": "/root/.m2/repository"
68134
}
69-
- name: Build image for platforms ${{ needs.prepare_environment.outputs.build_platforms }}
135+
- name: Build ${{ matrix.image_stage }} image stage for ${{ matrix.name }}
70136
uses: docker/build-push-action@v6
137+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
71138
with:
72139
context: .
140+
build-args: MAVEN_OPTS=-Dmaven.repo.local=/root/.m2/repository
141+
target: ${{ matrix.image_stage }}
73142
push: false
74143
load: false
75-
tags: ${{ needs.prepare_environment.outputs.test_image_name }}
76-
platforms: "${{ needs.prepare_environment.outputs.build_platforms }}"
144+
tags: ${{ matrix.tags }}
145+
platforms: "${{ matrix.platform }}"
77146
cache-from: type=gha
78147
cache-to: type=gha,mode=max
79-
run_docker_image_tests:
80-
name: Run & test ${{ matrix.platform }}
81-
runs-on: ${{ matrix.image }}
148+
outputs: type=docker,dest=${{ runner.temp }}/image-${{ matrix.name }}-${{ matrix.image_stage }}.tar
149+
- name: Upload image artifact
150+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
151+
uses: actions/upload-artifact@v4
152+
with:
153+
name: image-${{ matrix.name }}-${{ matrix.image_stage }}-${{ needs.prepare_environment.outputs.dockerfile_hash }}-artifact
154+
path: ${{ runner.temp }}/image-${{ matrix.name }}-${{ matrix.image_stage }}.tar
155+
retention-days: 1
156+
if-no-files-found: error
157+
compression-level: 0
158+
overwrite: true
159+
docker_image_tests:
160+
name: Test ${{ matrix.name }} - publish image
161+
runs-on: ${{ matrix.runner }}
82162
needs:
83163
- prepare_environment
84164
- build_docker_images
85165
strategy:
86166
matrix:
87-
platform: [ linux/amd64,linux/arm64 ]
88-
image: [ ubuntu-latest ]
89-
# linux/arm64 is emulated with qemu and takes ages to build the graph.
90-
# Only run linux/arm64 tests on ready PR and main.
91-
isDraftPR:
92-
- ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true }}
93-
exclude:
94-
- isDraftPR: true
95-
platform: linux/arm64
167+
include:
168+
- platform: linux/amd64
169+
name: linux-amd64
170+
health_wait_time: 260
171+
image_stage: publish
172+
skip_on_draft_pr: false
173+
runner: ubuntu-latest
174+
- platform: linux/arm64
175+
name: linux-arm64
176+
health_wait_time: 260
177+
skip_on_draft_pr: true
178+
image_stage: publish
179+
runner: ubuntu-24.04-arm
96180
steps:
97-
- run: |
98-
echo "Run docker test for platform ${{ matrix.platform }}"
99181
- name: Checkout
182+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
100183
uses: actions/checkout@v4
101184
with:
102185
fetch-depth: 0
103-
- name: Get and save the UID
104-
run: |
105-
echo "UID=$(id -u)" >> $GITHUB_ENV
106-
- name: Set the wait time for arm64
107-
run: |
108-
if [[ "${{ matrix.platform }}" == 'linux/arm64' ]]; then
109-
# arm64 is emulated and takes longer to build the graph
110-
echo "Set HEALTH_WAIT_TIME to 600 for arm64"
111-
echo "HEALTH_WAIT_TIME=600" >> $GITHUB_ENV
112-
else
113-
echo "Set HEALTH_WAIT_TIME to 260 for non-arm64"
114-
echo "HEALTH_WAIT_TIME=260" >> $GITHUB_ENV
115-
fi
116-
- name: Set up QEMU for ${{ matrix.platform }}
117-
if: ${{ matrix.platform == 'linux/arm64' }}
118-
uses: docker/setup-qemu-action@v3
186+
- name: Download image artifact
187+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
188+
uses: actions/download-artifact@v4
119189
with:
120-
platforms: ${{ matrix.platform }}
190+
name: image-${{ matrix.name }}-${{ matrix.image_stage }}-${{ needs.prepare_environment.outputs.dockerfile_hash }}-artifact
191+
path: ${{ runner.temp }}
121192
- name: Set up Docker Buildx
193+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
122194
uses: docker/setup-buildx-action@v3
123-
- name: Cache Maven packages
124-
uses: actions/cache@v4
125-
with:
126-
path: ~/.m2
127-
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
128-
restore-keys: ${{ runner.os }}-m2
129-
- name: Prepare the maven cache dependencies
195+
- name: Load image
196+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
130197
run: |
131-
# Replace all RUN ./mvnw with RUN --mount=type=cache,target=/root/.m2 ./mvnw
132-
sed -i 's/RUN \.\/mvnw /RUN --mount=type=cache,target=\/root\/.m2 \.\/mvnw /g' Dockerfile
133-
- name: inject maven-build-cache into docker
134-
uses: reproducible-containers/[email protected]
135-
with:
136-
cache-map: |
137-
{
138-
"/home/runner/.m2": "/root/.m2"
139-
}
140-
- name: Build image
141-
uses: docker/build-push-action@v6
142-
with:
143-
context: .
144-
build-args: UID=${{ env.UID }}
145-
push: false
146-
load: true
147-
tags: ${{ needs.prepare_environment.outputs.test_image_name }}
148-
platforms: "${{ matrix.platform }}"
149-
cache-from: type=gha
198+
docker load --input ${{ runner.temp }}/image-${{ matrix.name }}-${{ matrix.image_stage }}.tar
199+
- name: Get and save the UID
200+
run: |
201+
echo "UID=$(id -u)" >> $GITHUB_ENV
150202
- name: Start container from previously build image and wait for successful checks
203+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
151204
run: |
152205
mkdir -p $(pwd)/ors-docker/graphs $(pwd)/ors-docker/config $(pwd)/ors-docker/elevation_cache
153206
chown -R $UID $(pwd)/ors-docker/graphs $(pwd)/ors-docker/config $(pwd)/ors-docker $(pwd)/ors-docker/elevation_cache
@@ -158,16 +211,14 @@ jobs:
158211
sed -i "s|#logging.level.org.heigit: INFO|logging.level.org.heigit: DEBUG|" docker-compose.yml
159212
# Start the first build with the docker-compose setup
160213
docker compose up -d
161-
# Check for health to turn 200 after the graphs are build and spring-boot completely started
162-
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 ${{ env.HEALTH_WAIT_TIME }}
163-
# Stop the compose setup and continue with docker run
214+
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 ${{ matrix.health_wait_time }} || (docker compose logs && exit 1)
164215
docker compose down
165216
# Set graphs data access to MMAPP
166217
sudo yq '.ors.engine.graphs_data_access = "MMAP"' -i $(pwd)/ors-docker/config/ors-config.yml
167218
# Start the container with the test image and the raw docker run command
168219
docker run -it -d -p 8080:8082 -v $(pwd)/ors-docker/graphs:/home/ors/graphs -v $(pwd)/ors-docker/config:/home/ors/config -v $(pwd)/ors-api/src/test/files/elevation:/home/ors/elevation_cache --name ors-instance ${{ needs.prepare_environment.outputs.test_image_name }}
169220
# Check for health to turn 200 after the graphs are build and spring-boot completely started
170-
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 ${{ env.HEALTH_WAIT_TIME }}
221+
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 ${{ matrix.health_wait_time }}
171222
# Check for correct preflight settings to avoid CORS issues with ORIGIN wildcard from the example config
172223
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 10
173224
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.com" 200 10
@@ -177,14 +228,78 @@ jobs:
177228
docker restart ors-instance
178229
# Request preflight with https://example.com and https://example.org to see if it gets applied correctly
179230
# If matrix platform is arm64, the health check will take longer
180-
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 ${{ env.HEALTH_WAIT_TIME }}
231+
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 ${{ matrix.health_wait_time }}
181232
# It should fail with http code 403 for https://example.com since the Origin is not covered.
182233
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.com" 403 10
183234
echo "Recreate the container to test if the graph can be properly read again"
184235
docker stop ors-instance
185236
docker container prune -f
186237
docker run -it -d -p 8080:8082 -v $(pwd)/ors-docker/graphs:/home/ors/graphs -v $(pwd)/ors-docker/config:/home/ors/config -e ors.cors.allowed_origins=https://example.org --name ors-instance ${{ needs.prepare_environment.outputs.test_image_name }}
187238
# Request preflight with https://example.com and https://example.org to see if it gets applied correctly
188-
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 ${{ env.HEALTH_WAIT_TIME }}
239+
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 ${{ matrix.health_wait_time }}
189240
# It should fail with http code 403 for https://example.com since the Origin is not covered.
190241
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.com" 403 10
242+
243+
minimal_image_tests:
244+
runs-on: ${{ matrix.runner }}
245+
needs:
246+
- prepare_environment
247+
- build_docker_images
248+
strategy:
249+
matrix:
250+
include:
251+
- platform: linux/amd64
252+
name: linux-amd64
253+
image_stage: minimal
254+
skip_on_draft_pr: false
255+
runner: ubuntu-latest
256+
- platform: linux/arm64
257+
name: linux-arm64
258+
skip_on_draft_pr: true
259+
image_stage: minimal
260+
runner: ubuntu-24.04-arm
261+
steps:
262+
- name: Checkout
263+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
264+
uses: actions/checkout@v4
265+
with:
266+
fetch-depth: 0
267+
- name: Download image artifact
268+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
269+
uses: actions/download-artifact@v4
270+
with:
271+
name: image-${{ matrix.name }}-${{ matrix.image_stage }}-${{ needs.prepare_environment.outputs.dockerfile_hash }}-artifact
272+
path: ${{ runner.temp }}
273+
- name: Load image
274+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
275+
run: |
276+
docker load --input ${{ runner.temp }}/image-${{ matrix.name }}-${{ matrix.image_stage }}.tar
277+
- name: Get and save the UID
278+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
279+
run: |
280+
echo "UID=$(id -u)" >> $GITHUB_ENV
281+
- name: Test minimal image with graph build
282+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
283+
run: |
284+
mkdir -p $(pwd)/ors-docker/elevation_cache
285+
chown -R $UID $(pwd)/ors-docker/elevation_cache
286+
# Place cached elevation file
287+
cp ors-api/src/test/files/elevation/srtm_38_03.gh $(pwd)/ors-docker/elevation_cache
288+
# Start kubernetes image with graph build configured via environment variables
289+
docker run -it -d -p 8080:8082 \
290+
-u $UID:1000 \
291+
-v graphs:/home/ors/graphs \
292+
-v $(pwd)/ors-docker/elevation_cache:/home/ors/elevation_cache \
293+
-v $(pwd)/ors-api/src/test/files/heidelberg.test.pbf:/home/ors/files/heidelberg.test.pbf:ro \
294+
-e JAVA_OPTS="-server -Xmx8g" \
295+
-e server.port=8082 \
296+
-e logging.level.org.heigit=DEBUG \
297+
-e ors.engine.profile_default.build.source_file=/home/ors/files/heidelberg.test.pbf \
298+
-e ors.engine.profile_default.graph_path=/home/ors/graphs \
299+
-e ors.engine.graphs_data_access=MMAP \
300+
-e ors.engine.elevation.cache_path=/home/ors/elevation_cache \
301+
-e ors.engine.profiles.driving-car.enabled=true \
302+
--name ors-minimal-test \
303+
${{ needs.prepare_environment.outputs.test_minimal_image_name }}
304+
# Wait for graph build and health check (kubernetes image is non-interactive)
305+
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 60 || (docker logs ors-minimal-test && exit 1)

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Releasing is documented in RELEASE.md
3333
- type-specific filtering for mapping point features to graph edges ([#2156](https://github.com/GIScience/openrouteservice/pull/2156))
3434
- documentation on the matching endpoint ([#2156](https://github.com/GIScience/openrouteservice/pull/2156))
3535
- PostgreSQL-backed feature store with scheduled synchronization for dynamic routing data updates ([#2156](https://github.com/GIScience/openrouteservice/pull/2156))
36+
- Enhance the docker image and docker build workflow for Kubernetes readiness with minimal image support ([#2183](https://github.com/GIScience/openrouteservice/pull/2183))
3637

3738
### Changed
3839
- enhanced status endpoint to expose dynamic data statistics and feature store metrics ([#2156](https://github.com/GIScience/openrouteservice/pull/2156))

0 commit comments

Comments
 (0)