14
14
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
# See the License for the specific language governing permissions and
16
16
# limitations under the License.
17
- #
18
- # To transform into Brew-friendly Dockerfile:
19
- # 1. comment out lines with EXTERNAL_SOURCE_NESTED=. and CONTAINER_SOURCE=/opt/app-root/src
20
- # 2. uncomment lines with EXTERNAL_SOURCE_NESTED and CONTAINER_SOURCE pointing at $REMOTE_SOURCES and $REMOTE_SOURCES_DIR instead (Brew defines these paths)
21
- # 3. uncomment lines with RUN source .../cachito.env
22
- # 4. add Brew metadata
23
17
24
18
# Stage 1 - Build nodejs skeleton
25
19
# https://registry.access.redhat.com/ubi9/nodejs-22
26
20
FROM registry.access.redhat.com/ubi9/nodejs-22:9.5-1744136606 AS skeleton
27
21
# hadolint ignore=DL3002
28
22
USER 0
29
23
30
- # debug
31
- # RUN cat /cachi2/cachi2.env
32
-
33
24
# Install isolated-vm dependencies
34
25
# hadolint ignore=DL3041
35
26
RUN dnf install -q -y --allowerasing --nobest \
@@ -56,11 +47,10 @@ RUN dnf install -q -y --allowerasing --nobest \
56
47
python3-subscription-manager-rhsm python3-systemd python3-urllib3 readline redhat-release rootfiles rpm rpm-build-libs rpm-libs rpm-plugin-selinux rpm-sign-libs rsync scl-utils \
57
48
sed selinux-policy selinux-policy-targeted setup shadow-utils skopeo slirp4netns sqlite-libs subscription-manager subscription-manager-rhsm-certificates systemd systemd-libs \
58
49
systemd-pam systemd-rpm-macros tar tcl tpm2-tss tzdata unzip usermode util-linux util-linux-core vim-filesystem vim-minimal virt-what which xz xz-libs yajl yum zlib zlib-devel && \
59
-
50
+
60
51
# '(micro)dnf update -y' not allowed in Konflux+Cachi2: instead use renovate or https://github.com/konflux-ci/rpm-lockfile-prototype to update the rpms.lock.yaml file
61
52
dnf clean all
62
53
63
- # sources
64
54
ENV EXTERNAL_SOURCE_NESTED=.
65
55
ENV CONTAINER_SOURCE=/opt/app-root/src
66
56
@@ -85,7 +75,6 @@ COPY $EXTERNAL_SOURCE_NESTED/plugins/dynamic-plugins-info-backend/package.json .
85
75
COPY $EXTERNAL_SOURCE_NESTED/packages/backend/package.json ./packages/backend/package.json
86
76
COPY $EXTERNAL_SOURCE_NESTED/packages/app/package.json ./packages/app/package.json
87
77
COPY $EXTERNAL_SOURCE_NESTED/package.json ./package.json
88
- COPY $EXTERNAL_SOURCE_NESTED/e2e-tests/package.json ./e2e-tests/package.json
89
78
COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/_utils/package.json ./dynamic-plugins/_utils/package.json
90
79
COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-utils-dynamic/package.json ./dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-utils-dynamic/package.json
91
80
COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-http-request-dynamic/package.json ./dynamic-plugins/wrappers/roadiehq-scaffolder-backend-module-http-request-dynamic/package.json
@@ -168,53 +157,18 @@ COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin
168
157
COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins/wrappers/backstage-community-plugin-3scale-backend-dynamic/package.json ./dynamic-plugins/wrappers/backstage-community-plugin-3scale-backend-dynamic/package.json
169
158
# END COPY package.json files
170
159
171
- # Downstream only - debugging
172
- # RUN ls -la /cachi2/output/deps/yarn/*
173
-
174
- # Downstream only - enable offline node-gyp install from local headers - see artifacts.lock.yaml for tar.gz
175
- ENV NODE_HEADERS_VERSION="22.13.1"
176
- RUN mkdir -p ~/.cache/node-gyp/${NODE_HEADERS_VERSION}; \
177
- tar -xf /cachi2/output/deps/generic/node-v${NODE_HEADERS_VERSION}-headers.tar.gz --directory ~/.cache/node-gyp/${NODE_HEADERS_VERSION}/ --strip-components 1; \
178
- echo "11" > ~/.cache/node-gyp/${NODE_HEADERS_VERSION}/installVersion
179
-
180
- # Downstream only - enable offline playwright - see artifacts.lock.yaml for zip
181
- ENV CHROMIUM_VERSION="1155" \
182
- HEADLESS_VERSION="1155" \
183
- FFMPEG_VERSION="1011" \
184
- PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
185
- PLAYWRIGHT_BROWSERS_PATH=/cachi2/output/deps/generic/pw-browsers \
186
- CHROMIUM_DIR=$PLAYWRIGHT_BROWSERS_PATH/chromium-${CHROMIUM_VERSION} \
187
- HEADLESS_DIR=$PLAYWRIGHT_BROWSERS_PATH/chromium_headless_shell-${HEADLESS_VERSION} \
188
- FFMPEG_DIR=$PLAYWRIGHT_BROWSERS_PATH/ffmpeg-${FFMPEG_VERSION}
189
-
190
- # # python3 -m playwright install chromium firefox --dry-run
191
- # browser: chromium version 133.0.6943.16
192
- # Install location: /opt/app-root/src/.cache/ms-playwright/chromium-1155
193
- # Download url: https://cdn.playwright.dev/dbazure/download/playwright/builds/chromium/1155/chromium-linux.zip
194
- # browser: ffmpeg
195
- # Install location: /opt/app-root/src/.cache/ms-playwright/ffmpeg-1011
196
- # Download url: https://cdn.playwright.dev/dbazure/download/playwright/builds/ffmpeg/1011/ffmpeg-linux.zip
197
- # browser: chromium-headless-shell version 133.0.6943.16
198
- # Install location: /opt/app-root/src/.cache/ms-playwright/chromium_headless_shell-1155
199
- # Download url: https://cdn.playwright.dev/dbazure/download/playwright/builds/chromium/1155/chromium-headless-shell-linux.zip
200
- # browser: ffmpeg
201
- # Install location: /opt/app-root/src/.cache/ms-playwright/ffmpeg-1011
202
- # Download url: https://cdn.playwright.dev/dbazure/download/playwright/builds/ffmpeg/1011/ffmpeg-linux.zip
203
-
204
- RUN dnf install -q -y alsa-lib at-spi2-atk at-spi2-core atk cairo cups-libs libdrm libX11 libX11-xcb libXcomposite libXdamage libXext libXfixes libxkbcommon libXrandr mesa-libgbm nspr nss pango; \
205
- export PLAYWRIGHT_BROWSERS_PATH=$PLAYWRIGHT_BROWSERS_PATH/; \
206
- ls -la /cachi2/output/deps/generic/; \
207
- mkdir -p $CHROMIUM_DIR; unzip -q /cachi2/output/deps/generic/chromium-linux.zip -d $CHROMIUM_DIR/; touch $CHROMIUM_DIR/DEPENDENCIES_VALIDATED $CHROMIUM_DIR/INSTALLATION_COMPLETE; \
208
- mkdir -p $HEADLESS_DIR; unzip -q /cachi2/output/deps/generic/chromium-headless-shell-linux.zip -d $HEADLESS_DIR/; touch $HEADLESS_DIR/DEPENDENCIES_VALIDATED $HEADLESS_DIR/INSTALLATION_COMPLETE; \
209
- mkdir -p $FFMPEG_DIR; unzip -q /cachi2/output/deps/generic/ffmpeg-linux.zip -d $FFMPEG_DIR/; touch $FFMPEG_DIR/DEPENDENCIES_VALIDATED $FFMPEG_DIR/INSTALLATION_COMPLETE; \
210
- # echo "Chromium: "; ls -1 $CHROMIUM_DIR; \
211
- # echo "Chromium Headless Shell:"; ls -1 $HEADLESS_DIR; \
212
- # echo "ffmpeg:"; ls -1 $FFMPEG_DIR; \
213
- pip3 install playwright==1.49.1 && playwright --version
214
-
215
- # debugging
216
- # Redirect console output and errors to a log file to make this log shorter
217
- # RUN exec 3>&1 4>&2 1>> /tmp/build.log.txt 2>> /tmp/build.log.txt
160
+ # unpack headers from tarball (includes openssl headers not present in /usr/include/node) - see RHIDP-6755 for why we need this upstream
161
+ COPY $EXTERNAL_SOURCE_NESTED/.nvm/ .
162
+ RUN NODE_HEADERS_VERSION=$(node --version); echo "=== Install node headers $NODE_HEADERS_VERSION from tar.gz ===" ; \
163
+ if [[ ! -f releases/node-${NODE_HEADERS_VERSION}-headers.tar.gz ]]; then \
164
+ echo "[ERROR] Base image includes nodejs $NODE_HEADERS_VERSION but could not find releases/node-${NODE_HEADERS_VERSION}-headers.tar.gz to install!" ; \
165
+ echo "[ERROR] To fix, upload the node-${NODE_HEADERS_VERSION}-headers.tar.gz file into https://github.com/redhat-developer/rhdh/tree/main/.nvm/releases (or related branch)!" ; \
166
+ exit 1; \
167
+ fi; \
168
+ mkdir -p ~/.cache/node-gyp/${NODE_HEADERS_VERSION/v/}; \
169
+ tar -xf releases/node-${NODE_HEADERS_VERSION}-headers.tar.gz --directory ~/.cache/node-gyp/${NODE_HEADERS_VERSION/v/}/ --strip-components 1; \
170
+ echo "11" > ~/.cache/node-gyp/${NODE_HEADERS_VERSION/v/}/installVersion; \
171
+ rm -fr releases/node-${NODE_HEADERS_VERSION}-headers.tar.gz
218
172
219
173
# Increate timeout for yarn install
220
174
RUN "$YARN" config set httpTimeout 600000
@@ -224,8 +178,13 @@ RUN "$YARN" config set httpTimeout 600000
224
178
# export YARN_ENABLE_IMMUTABLE_CACHE=false
225
179
# export YARN_ENABLE_MIRROR=true
226
180
# export YARN_GLOBAL_FOLDER=/cachi2/output/deps/yarn
227
- RUN echo "=== YARN INSTALL ===" ; "$YARN" install --immutable | tee /tmp/yarn.install.log.txt 2>&1; \
228
- for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then echo; echo $d; echo "======" ; cat ${d}/build.log; fi; done
181
+ # RUN cat /cachi2/cachi2.env; echo; ls -la /cachi2/output/deps/yarn/*
182
+
183
+ RUN echo "=== YARN INSTALL ===" ; FAILED=0; "$YARN" install --immutable || true; \
184
+ for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then \
185
+ (( FAILED = FAILED + 1 )); echo; echo $d; echo "======" ; cat ${d}/build.log; \
186
+ fi; done; \
187
+ if [[ $FAILED -gt 0 ]]; then exit $FAILED; fi
229
188
230
189
# Stage 3 - Build packages
231
190
FROM deps AS build
@@ -246,26 +205,19 @@ RUN \
246
205
-e "s/(\" Last Commit\" : \" (.+)\" )/\1 , \" Build Time\" : \" $now\" /" && \
247
206
cat packages/app/src/build-metadata.json; echo
248
207
249
- RUN echo "=== YARN BUILD ===" ; "$YARN" build --filter=backend \
250
- >/tmp/yarn.build.log.txt 2>&1 \
251
- || { for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then echo; echo $d; echo "======" ; cat ${d}/build.log; fi; done }
208
+ RUN echo "=== YARN BUILD ===" ; "$YARN" build --filter=backend
252
209
253
- # >/tmp/yarn.export.dynamic.log.txt 2>&1
254
- RUN echo "=== EXPORT DYNAMIC PLUGINS (with --no-install) ===" ; "$YARN" export-dynamic --filter=./dynamic-plugins/wrappers/*; \
255
- for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then echo; echo $d; echo "======" ; cat ${d}/build.log; fi; done; \
256
- for d in $(find . -name yarn-install.log); do echo; echo "===== EXPORT DYNAMIC PLUGINS: $d =====>" ; cat ${d}; echo "<===== EXPORT DYNAMIC PLUGINS: $d =====" ; done;
210
+ RUN echo "=== EXPORT DYNAMIC PLUGINS (with --no-install) ===" ; FAILED=0; "$YARN" export-dynamic --filter=./dynamic-plugins/wrappers/* || true; \
211
+ for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then \
212
+ (( FAILED = FAILED + 1 )); echo; echo $d; echo "======" ; cat ${d}/build.log; \
213
+ fi; done; \
214
+ if [[ $FAILED -gt 0 ]]; then exit $FAILED; fi
257
215
258
- # Stan says we can omit this step - https://redhat-internal.slack.com/archives/C08A1KD7TNY/p1741805639019149?thread_ts=1741720088.366109&cid=C08A1KD7TNY
259
- # RUN echo "=== DIST-DYNAMIC YARN INSTALLS ==="; for f in $(find ./dynamic-plugins/wrappers/ -maxdepth 2 -type d -name dist-dynamic); do g=${f#*/wrappers/}; echo " > $g"; g=${g//\//_}; \
260
- # pushd $f >/dev/null; "$YARN" install --immutable >"/tmp/yarn.install.${g}.log.txt" 2>&1; popd >/dev/null; done
261
-
262
- # >/tmp/yarn.copy.dynamic.log.txt 2>&1
263
216
RUN echo "=== YARN COPY DYNAMIC PLUGINS in $(pwd) ===" ; "$YARN" copy-dynamic-plugins dist
264
- # RUN ls -la dynamic-plugins/*
217
+
265
218
# Downstream only - clean up dynamic plugins sources:
266
219
# Only keep the dist sub-folder in the dynamic-plugins folder
267
220
RUN echo "=== DELETE DYNAMIC PLUGINS/* (except dist/) from $(pwd) ===" ; find dynamic-plugins -maxdepth 1 -mindepth 1 -type d -not -name dist -exec rm -Rf {} \;
268
- # RUN ls -la dynamic-plugins/dist/*
269
221
270
222
# Stage 4 - Build the actual backend image and install production dependencies
271
223
FROM skeleton AS cleanup
@@ -278,21 +230,31 @@ COPY --from=build $CONTAINER_SOURCE/yarn.lock \
278
230
./
279
231
ENV TARBALL_PATH=.
280
232
281
- # Increate timeout for yarn install
282
- RUN "$YARN" config set httpTimeout 600000
283
-
284
233
RUN tar xzf "$TARBALL_PATH" /skeleton.tar.gz; tar xzf "$TARBALL_PATH" /bundle.tar.gz; \
285
234
rm -f "$TARBALL_PATH" /skeleton.tar.gz "$TARBALL_PATH" /bundle.tar.gz
286
235
287
236
# Copy app-config files needed in runtime
288
237
COPY $EXTERNAL_SOURCE_NESTED/app-config*.yaml ./
289
238
COPY $EXTERNAL_SOURCE_NESTED/dynamic-plugins.default.yaml ./
290
239
291
- # >/tmp/yarn.workspaces.focus.log.txt 2>&1
240
+ # Hackaround: create library symlinks to build: isolated-vm node-gyp better-sqlite cpu-features
241
+ # TODO is this still needed? maintaining it over time will be a chore if the .so files change
242
+ RUN echo "=== lib64 symlinks ===" ; \
243
+ for l in libbrotlidec.so.1 libbrotlienc.so.1 libbrotlicommon.so.1 libc.so.6 ld-linux-x86-64.so.2 libcrypto.so.3 libk5crypto.so.3 libz.so.1 libssl.so.3; do \
244
+ ln -s /usr/lib64/$l /usr/lib64/${l%.*} 2>/dev/null || true; \
245
+ ls -l /usr/lib64/${l%.*}; \
246
+ done
247
+
248
+ # Increate timeout for yarn install
249
+ RUN "$YARN" config set httpTimeout 600000
250
+
292
251
# Install production dependencies
293
252
# hadolint ignore=DL3059
294
- RUN "$YARN" workspaces focus --all --production \
295
- || { for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then echo; echo $d; echo "======" ; cat ${d}/build.log; fi; done }
253
+ RUN echo "=== YARN WORKSPACES FOCUS ===" ; FAILED=0; "$YARN" workspaces focus --all --production || true; \
254
+ for d in /tmp/xfs-*; do if [[ -f ${d}/build.log ]]; then \
255
+ (( FAILED = FAILED + 1 )); echo; echo $d; echo "======" ; cat ${d}/build.log; \
256
+ fi; done; \
257
+ if [[ $FAILED -gt 0 ]]; then exit $FAILED; fi
296
258
297
259
RUN \
298
260
# delete all the nested .npmrc files and set default values
@@ -316,30 +278,30 @@ done; if [[ $hadFail -gt 0 ]]; then exit $hadFail; fi
316
278
FROM registry.access.redhat.com/ubi9/nodejs-22-minimal:9.5-1742929466 AS runner
317
279
USER 0
318
280
319
- # sources
320
281
ENV EXTERNAL_SOURCE_NESTED=.
321
-
322
282
ENV CONTAINER_SOURCE=/opt/app-root/src
323
283
WORKDIR $CONTAINER_SOURCE/
324
284
325
- # Downstream only - install techdocs dependencies using cachito sources
326
- # Using cachi2 env vars:
285
+ # cachi2 env vars:
327
286
# export PIP_FIND_LINKS=/cachi2/output/deps/pip
328
287
# export PIP_NO_INDEX=true
288
+
289
+ # Install techdocs dependencies using requirements files
329
290
# hadolint ignore=DL3013,DL3041,SC2086
330
- COPY "$EXTERNAL_SOURCE_NESTED" /docker / ./docker
291
+ COPY "$EXTERNAL_SOURCE_NESTED" /python / ./python
331
292
RUN microdnf install -y python3.11 python3.11-pip python3.11-devel make cmake cpp gcc gcc-c++ skopeo 1>/dev/null 2>&1; \
332
293
alternatives --install /usr/bin/python python /usr/bin/python3.11 1 && \
333
294
alternatives --install /usr/bin/pip pip /usr/bin/pip3.11 1 && \
334
295
# fix ownership for pip install folder
335
296
mkdir -p /opt/app-root/src/.cache/pip && chown -R root:root /opt/app-root && \
336
297
# ls -ld /opt/ /opt/app-root /opt/app-root/src/ /opt/app-root/src/.cache /opt/app-root/src/.cache/pip || true; \
337
- pushd "$EXTERNAL_SOURCE_NESTED" /docker / >/dev/null && \
298
+ pushd "$EXTERNAL_SOURCE_NESTED" /python / >/dev/null && \
338
299
set -e; \
339
300
python3.11 -V; pip3.11 -V; \
340
301
pip install --no-cache-dir --upgrade pip setuptools pyyaml; \
341
302
pip install --no-cache-dir -r requirements.txt -r requirements-build.txt; mkdocs --version; \
342
303
popd >/dev/null; \
304
+ rm -fr python/; \
343
305
microdnf clean all
344
306
345
307
# Upstream only - copy from cleanup stage
@@ -363,12 +325,12 @@ RUN chmod -R a+r ./dynamic-plugins/ ./install-dynamic-plugins.py; \
363
325
# the container.
364
326
RUN ln -s /opt/app-root/src/packages/app/dist/index.html /opt/app-root/src/packages/app/dist/index.html.tmpl
365
327
366
- # Downstream only - fix for https://issues.redhat.com/browse/RHIDP-728 + some cleanup of unneeded files
367
- RUN mkdir /opt/app-root/src/.npm; chown -R 1001:1001 /opt/app-root/src/.npm; rm -fr docker/
328
+ # Fix for https://issues.redhat.com/browse/RHIDP-728
329
+ RUN mkdir -p /opt/app-root/src/.npm; chown -R 1001:1001 /opt/app-root/src/.npm
368
330
369
331
# The fix-permissions script is important when operating in environments that dynamically use a random UID at runtime, such as OpenShift.
370
332
# The upstream backstage image does not account for this and it causes the container to fail at runtime.
371
- # suppress warnings about dereferencing symlinks
333
+ # suppress warnings about dereferencing symlinks
372
334
RUN fix-permissions ./ 2>&1 | grep -v "chgrp: cannot dereference" || true
373
335
374
336
# Switch to nodejs user
0 commit comments