Skip to content

Commit 63df9bb

Browse files
committed
feat: Enhance the docker image and docker build workflow for Kubernetes readiness with minimal image support
1 parent 698f938 commit 63df9bb

File tree

5 files changed

+284
-115
lines changed

5 files changed

+284
-115
lines changed

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

Lines changed: 200 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,186 @@ 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: ubuntu-latest
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+
- platform: linux/arm64
174+
name: linux-arm64
175+
health_wait_time: 260
176+
skip_on_draft_pr: true
177+
image_stage: publish
96178
steps:
97-
- run: |
98-
echo "Run docker test for platform ${{ matrix.platform }}"
99179
- name: Checkout
180+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
100181
uses: actions/checkout@v4
101182
with:
102183
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
184+
- name: Download image artifact
185+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
186+
uses: actions/download-artifact@v4
119187
with:
120-
platforms: ${{ matrix.platform }}
188+
name: image-${{ matrix.name }}-${{ matrix.image_stage }}-${{ needs.prepare_environment.outputs.dockerfile_hash }}-artifact
189+
path: ${{ runner.temp }}
121190
- name: Set up Docker Buildx
191+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
122192
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
193+
- name: Load image
194+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
130195
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
196+
docker load --input ${{ runner.temp }}/image-${{ matrix.name }}-${{ matrix.image_stage }}.tar
197+
- name: Get and save the UID
198+
run: |
199+
echo "UID=$(id -u)" >> $GITHUB_ENV
150200
- name: Start container from previously build image and wait for successful checks
201+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
151202
run: |
152203
mkdir -p $(pwd)/ors-docker/graphs $(pwd)/ors-docker/config $(pwd)/ors-docker/elevation_cache
153204
chown -R $UID $(pwd)/ors-docker/graphs $(pwd)/ors-docker/config $(pwd)/ors-docker $(pwd)/ors-docker/elevation_cache
@@ -158,16 +209,14 @@ jobs:
158209
sed -i "s|#logging.level.org.heigit: INFO|logging.level.org.heigit: DEBUG|" docker-compose.yml
159210
# Start the first build with the docker-compose setup
160211
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
212+
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 ${{ matrix.health_wait_time }} || (docker compose logs && exit 1)
164213
docker compose down
165214
# Set graphs data access to MMAPP
166215
sudo yq '.ors.engine.graphs_data_access = "MMAP"' -i $(pwd)/ors-docker/config/ors-config.yml
167216
# Start the container with the test image and the raw docker run command
168217
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 }}
169218
# 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 }}
219+
./.github/utils/url_check.sh 127.0.0.1 8080 /ors/v2/health 200 ${{ matrix.health_wait_time }}
171220
# Check for correct preflight settings to avoid CORS issues with ORIGIN wildcard from the example config
172221
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 10
173222
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.com" 200 10
@@ -177,14 +226,76 @@ jobs:
177226
docker restart ors-instance
178227
# Request preflight with https://example.com and https://example.org to see if it gets applied correctly
179228
# 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 }}
229+
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 ${{ matrix.health_wait_time }}
181230
# It should fail with http code 403 for https://example.com since the Origin is not covered.
182231
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.com" 403 10
183232
echo "Recreate the container to test if the graph can be properly read again"
184233
docker stop ors-instance
185234
docker container prune -f
186235
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 }}
187236
# 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 }}
237+
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.org" 200 ${{ matrix.health_wait_time }}
189238
# It should fail with http code 403 for https://example.com since the Origin is not covered.
190239
./.github/utils/cors_check.sh 127.0.0.1 8080 /ors/v2/isochrones/geojson "https://example.com" 403 10
240+
241+
minimal_image_tests:
242+
runs-on: ubuntu-latest
243+
needs:
244+
- prepare_environment
245+
- build_docker_images
246+
strategy:
247+
matrix:
248+
include:
249+
- platform: linux/amd64
250+
name: linux-amd64
251+
image_stage: minimal
252+
skip_on_draft_pr: false
253+
- platform: linux/arm64
254+
name: linux-arm64
255+
skip_on_draft_pr: true
256+
image_stage: minimal
257+
steps:
258+
- name: Checkout
259+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
260+
uses: actions/checkout@v4
261+
with:
262+
fetch-depth: 0
263+
- name: Download image artifact
264+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
265+
uses: actions/download-artifact@v4
266+
with:
267+
name: image-${{ matrix.name }}-${{ matrix.image_stage }}-${{ needs.prepare_environment.outputs.dockerfile_hash }}-artifact
268+
path: ${{ runner.temp }}
269+
- name: Load image
270+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
271+
run: |
272+
docker load --input ${{ runner.temp }}/image-linux-amd64-minimal.tar
273+
- name: Get and save the UID
274+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
275+
run: |
276+
echo "UID=$(id -u)" >> $GITHUB_ENV
277+
- name: Test minimal image with graph build
278+
if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true && matrix.skip_on_draft_pr) }}
279+
run: |
280+
mkdir -p $(pwd)/ors-docker/elevation_cache
281+
chown -R $UID $(pwd)/ors-docker/elevation_cache
282+
# Place cached elevation file
283+
cp ors-api/src/test/files/elevation/srtm_38_03.gh $(pwd)/ors-docker/elevation_cache
284+
# Start kubernetes image with graph build configured via environment variables
285+
docker run -it -d -p 8080:8082 \
286+
-u $UID:1000 \
287+
-v graphs:/home/ors/graphs \
288+
-v $(pwd)/ors-docker/elevation_cache:/home/ors/elevation_cache \
289+
-v $(pwd)/ors-api/src/test/files/heidelberg.test.pbf:/home/ors/files/heidelberg.test.pbf:ro \
290+
-e JAVA_OPTS="-server -Xmx8g" \
291+
-e server.port=8082 \
292+
-e logging.level.org.heigit=DEBUG \
293+
-e ors.engine.profile_default.build.source_file=/home/ors/files/heidelberg.test.pbf \
294+
-e ors.engine.profile_default.graph_path=/home/ors/graphs \
295+
-e ors.engine.graphs_data_access=MMAP \
296+
-e ors.engine.elevation.cache_path=/home/ors/elevation_cache \
297+
-e ors.engine.profiles.driving-car.enabled=true \
298+
--name ors-minimal-test \
299+
${{ needs.prepare_environment.outputs.test_minimal_image_name }}
300+
# Wait for graph build and health check (kubernetes image is non-interactive)
301+
./.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)