Skip to content

Commit d27e86f

Browse files
authored
Merge pull request #4996 from tdonohue/port_4987_to_7x
[Port dspace-7_x] [Docker] Fix networking and startup issues with Docker Compose scripts. Update scripts to align with best practices
2 parents dc1724f + ea549c3 commit d27e86f

File tree

9 files changed

+183
-42
lines changed

9 files changed

+183
-42
lines changed

.github/workflows/docker.yml

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,117 @@ jobs:
5757
# Enable redeploy of sandbox & demo if the branch for this image matches the deployment branch of
5858
# these sites as specified in reusable-docker-build.xml
5959
REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }}
60-
REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }}
60+
REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }}
61+
62+
#################################################################################
63+
# Test Deployment via Docker to ensure newly built images are working properly
64+
#################################################################################
65+
docker-deploy:
66+
# Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace-angular'
67+
if: github.repository == 'dspace/dspace-angular'
68+
runs-on: ubuntu-latest
69+
# Must run after all major images are built
70+
needs: [dspace-angular, dspace-angular-dist]
71+
env:
72+
# Override default dspace.server.url & REST 'host' because backend starts at http://127.0.0.1:8080
73+
dspace__P__server__P__url: http://127.0.0.1:8080/server
74+
DSPACE_REST_HOST: 127.0.0.1
75+
# Override default dspace.ui.url to also use 127.0.0.1.
76+
dspace__P__ui__P__url: http://127.0.0.1:4000
77+
# Docker Registry to use for Docker compose scripts below.
78+
# If this is a PR, then we need to use docker.io (as the registry must be public),
79+
# Otherwise we default to ghcr.io to avoid aggressive rate limits at DockerHub.
80+
DOCKER_REGISTRY: ${{ github.event_name == 'pull_request' && 'docker.io' || 'ghcr.io' }}
81+
steps:
82+
# Checkout our codebase (to get access to Docker Compose scripts)
83+
- name: Checkout codebase
84+
uses: actions/checkout@v4
85+
# Download Docker image artifacts (which were just built by reusable-docker-build.yml)
86+
- name: Download Docker image artifacts
87+
uses: actions/download-artifact@v4
88+
with:
89+
# Download all amd64 Docker images (TAR files) into the /tmp/docker directory
90+
pattern: docker-image-*-linux-amd64
91+
path: /tmp/docker
92+
merge-multiple: true
93+
# Load each of the images into Docker by calling "docker image load" for each.
94+
# This ensures we are using the images just built & not any prior versions on DockerHub
95+
- name: Load all downloaded Docker images
96+
run: |
97+
find /tmp/docker -type f -name "*.tar" -exec docker image load --input "{}" \;
98+
docker image ls -a
99+
# Start backend using our compose script in the codebase.
100+
- name: Start backend in Docker
101+
run: |
102+
docker compose -f docker/docker-compose-rest.yml up -d
103+
sleep 10
104+
docker container ls
105+
# Create a test admin account. Load test data from a simple set of AIPs as defined in cli.ingest.yml
106+
- name: Load test data into Backend
107+
run: |
108+
docker compose -f docker/cli.yml run --rm dspace-cli create-administrator -e test@test.edu -f admin -l user -p admin -c en
109+
docker compose -f docker/cli.yml -f docker/cli.ingest.yml run --rm dspace-cli
110+
# Verify backend started successfully.
111+
# 1. Make sure root endpoint is responding (check for dspace.name defined in docker-compose.yml)
112+
# 2. Also check /collections endpoint to ensure the test data loaded properly (check for a collection name in AIPs)
113+
- name: Verify backend is responding properly
114+
run: |
115+
result=$(wget -O- -q http://127.0.0.1:8080/server/api)
116+
echo "$result"
117+
echo "$result" | grep -oE "\"DSpace Started with Docker Compose\""
118+
result=$(wget -O- -q http://127.0.0.1:8080/server/api/core/collections)
119+
echo "$result"
120+
echo "$result" | grep -oE "\"Dog in Yard\""
121+
# Start production frontend using our compose script in the codebase.
122+
- name: Start production frontend in Docker
123+
# Specify the GHCR copy of the production frontend, so that we use the newly built image
124+
env:
125+
DOCKER_REGISTRY: ghcr.io
126+
run: |
127+
docker compose -f docker/docker-compose-dist.yml up -d
128+
sleep 10
129+
docker container ls
130+
# Verify production frontend started successfully.
131+
# 1. Make sure /home path has "DSpace software" (this is in the footer of the page)
132+
# 2. Also check /community-list page lists one of the test Communities in the loaded test data
133+
- name: Verify production frontend is responding properly
134+
run: |
135+
result=$(wget -O- -q http://127.0.0.1:4000/home)
136+
echo "$result"
137+
echo "$result" | grep -oE "DSpace software"
138+
- name: Error logs of production frontend (if error in startup)
139+
if: ${{ failure() }}
140+
run: |
141+
docker compose -f docker/docker-compose-dist.yml logs
142+
# Now shutdown the production frontend image and startup the development frontend image
143+
- name: Shutdown production frontend
144+
run: |
145+
docker compose -f docker/docker-compose-dist.yml down
146+
sleep 10
147+
docker container ls
148+
- name: Startup development frontend
149+
# Specify the GHCR copy of the development frontend, so that we use the newly built image
150+
env:
151+
DOCKER_REGISTRY: ghcr.io
152+
run: |
153+
docker compose -f docker/docker-compose.yml up -d
154+
sleep 10
155+
docker container ls
156+
# Verify development frontend started successfully.
157+
# 1. First, keep requesting the frontend every 10 seconds to wait until its up. Timeout after 10 minutes.
158+
# 2. Once it's responding, check to see if the word "DSpace" appears.
159+
# We cannot check for anything more specific because development mode doesn't have SSR.
160+
- name: Verify development frontend is responding properly
161+
run: |
162+
timeout 10m wget --retry-connrefused -t 0 --waitretry=10 http://127.0.0.1:4000
163+
result=$(wget -O- -q http://127.0.0.1:4000)
164+
echo "$result"
165+
echo "$result" | grep -oE "DSpace"
166+
- name: Error logs of development frontend (if error in startup)
167+
if: ${{ failure() }}
168+
run: |
169+
docker compose -f docker/docker-compose.yml logs
170+
# Shutdown our containers
171+
- name: Shutdown running Docker containers
172+
run: |
173+
docker compose -f docker/docker-compose.yml -f docker/docker-compose-rest.yml down

Dockerfile

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
# This image will be published as dspace/dspace-angular
22
# See https://github.com/DSpace/dspace-angular/tree/main/docker for usage details
33

4-
FROM docker.io/node:18-alpine
4+
FROM docker.io/node:22-alpine
55

66
# Ensure Python and other build tools are available
77
# These are needed to install some node modules, especially on linux/arm64
88
RUN apk add --update python3 make g++ && rm -rf /var/cache/apk/*
99

1010
WORKDIR /app
11-
ADD . /app/
12-
EXPOSE 4000
11+
12+
# Copy over package files first, so this layer will only be rebuilt if those files change.
13+
COPY package.json yarn.lock ./
1314

1415
# We run yarn install with an increased network timeout (5min) to avoid "ESOCKETTIMEDOUT" errors from hub.docker.com
1516
# See, for example https://github.com/yarnpkg/yarn/issues/5540
1617
RUN yarn install --network-timeout 300000
1718

19+
# Add the rest of the source code
20+
COPY . /app/
21+
1822
# When running in dev mode, 4GB of memory is required to build & launch the app.
1923
# This default setting can be overridden as needed in your shell, via an env file or in docker-compose.
2024
# See Docker environment var precedence: https://docs.docker.com/compose/environment-variables/envvars-precedence/
2125
ENV NODE_OPTIONS="--max_old_space_size=4096"
2226

2327
# On startup, run in DEVELOPMENT mode (this defaults to live reloading enabled, etc).
24-
# Listen / accept connections from all IP addresses.
25-
# NOTE: At this time it is only possible to run Docker container in Production mode
26-
# if you have a public URL. See https://github.com/DSpace/dspace-angular/issues/1485
2728
ENV NODE_ENV=development
28-
CMD yarn serve --host 0.0.0.0
29+
30+
EXPOSE 4000
31+
32+
# On startup, run this command to start application in dev mode
33+
ENTRYPOINT [ "yarn", "serve" ]
34+
# By default set host to 0.0.0.0 to listen/accept connections from all IP addresses.
35+
# Poll for changes every 5 seconds (if any detected, app will rebuild/restart)
36+
CMD ["--host 0.0.0.0", "--poll 5000"]

Dockerfile.dist

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,46 @@
44
# Test build:
55
# docker build -f Dockerfile.dist -t dspace/dspace-angular:dspace-7_x-dist .
66

7-
FROM docker.io/node:18-alpine AS build
7+
# Step 1 - Build code for production
8+
FROM docker.io/node:22-alpine AS build
89

910
# Ensure Python and other build tools are available
1011
# These are needed to install some node modules, especially on linux/arm64
1112
RUN apk add --update python3 make g++ && rm -rf /var/cache/apk/*
1213

1314
WORKDIR /app
15+
16+
# Copy over package files first, so this layer will only be rebuilt if those files change.
1417
COPY package.json yarn.lock ./
1518
RUN yarn install --network-timeout 300000
1619

17-
ADD . /app/
20+
# Around 4GB of memory is required to build the app for production.
21+
# This default setting can be overridden as needed in your shell, via an env file or in docker-compose.
22+
# See Docker environment var precedence: https://docs.docker.com/compose/environment-variables/envvars-precedence/
23+
ENV NODE_OPTIONS="--max_old_space_size=4096"
24+
25+
COPY . /app/
1826
RUN yarn build:prod
1927

20-
FROM node:18-alpine
28+
# Step 2 - Start up UI via PM2
29+
FROM docker.io/node:22-alpine
30+
31+
# Install PM2
2132
RUN npm install --global pm2
2233

34+
# Copy pre-built code from build image
2335
COPY --chown=node:node --from=build /app/dist /app/dist
36+
# Copy configs and PM2 startup script from local machine
2437
COPY --chown=node:node config /app/config
2538
COPY --chown=node:node docker/dspace-ui.json /app/dspace-ui.json
2639

40+
# Start up UI in PM2 in production mode
2741
WORKDIR /app
2842
USER node
2943
ENV NODE_ENV=production
3044
EXPOSE 4000
31-
CMD pm2-runtime start dspace-ui.json --json
45+
46+
# On startup, run start the DSpace UI in PM2
47+
ENTRYPOINT [ "pm2-runtime", "start", "dspace-ui.json" ]
48+
# By default, pass param that specifies to use JSON format logs.
49+
CMD ["--json"]

docker/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ the Docker compose scripts in this 'docker' folder.
2020

2121
### Dockerfile
2222

23-
This Dockerfile is used to build a *development* DSpace 7 Angular UI image, published as 'dspace/dspace-angular'
23+
This Dockerfile is used to build a *development* mode DSpace Angular UI image, published as 'dspace/dspace-angular'. Because it uses development mode, this image supports "live reloading" of the user interface
24+
when local source code is modified.
2425

2526
```
2627
docker build -t dspace/dspace-angular:dspace-7_x .
@@ -35,7 +36,7 @@ docker push dspace/dspace-angular:dspace-7_x
3536

3637
### Dockerfile.dist
3738

38-
The `Dockerfile.dist` is used to generate a *production* build and runtime environment.
39+
The `Dockerfile.dist` is used to build a *production* mode DSpace Angular UI image, published as 'dspace/dspace-angular' with a `*-dist` tag. Because it uses production mode, this image supports Server Side Rendering (SSR).
3940

4041
```bash
4142
# build the latest image

docker/cli.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ networks:
1616
# Default to using network named 'dspacenet' from docker-compose-rest.yml.
1717
# Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet")
1818
# If COMPOSITE_PROJECT_NAME is missing, default value will be "docker" (name of folder this file is in)
19-
default:
19+
dspacenet:
2020
name: ${COMPOSE_PROJECT_NAME:-docker}_dspacenet
2121
external: true
2222
services:
@@ -34,13 +34,13 @@ services:
3434
db__P__url: 'jdbc:postgresql://dspacedb:5432/dspace'
3535
# solr.server: Ensure we are using the 'dspacesolr' image for Solr
3636
solr__P__server: http://dspacesolr:8983/solr
37+
networks:
38+
- dspacenet
3739
volumes:
3840
# Keep DSpace assetstore directory between reboots
3941
- assetstore:/dspace/assetstore
4042
entrypoint: /dspace/bin/dspace
4143
command: help
42-
tty: true
43-
stdin_open: true
4444

4545
volumes:
4646
assetstore:

docker/docker-compose-ci.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ services:
4141
ports:
4242
- published: 8080
4343
target: 8080
44-
stdin_open: true
45-
tty: true
4644
volumes:
4745
- assetstore:/dspace/assetstore
4846
# Ensure that the database is ready BEFORE starting tomcat
@@ -73,8 +71,6 @@ services:
7371
ports:
7472
- published: 5432
7573
target: 5432
76-
stdin_open: true
77-
tty: true
7874
volumes:
7975
# Keep Postgres data directory between reboots
8076
- pgdata:/pgdata
@@ -87,8 +83,6 @@ services:
8783
ports:
8884
- published: 8983
8985
target: 8983
90-
stdin_open: true
91-
tty: true
9286
working_dir: /var/solr/data
9387
volumes:
9488
# Keep Solr data directory between reboots

docker/docker-compose-dist.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
# Docker Compose for running the DSpace Angular UI dist build
1010
# for previewing with the DSpace Demo site backend
1111
networks:
12+
# Default to using network named 'dspacenet' from docker-compose.yml.
13+
# Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet")
1214
dspacenet:
15+
name: ${COMPOSE_PROJECT_NAME}_dspacenet
16+
external: true
1317
services:
1418
dspace-angular:
1519
container_name: dspace-angular
@@ -18,22 +22,18 @@ services:
1822
DSPACE_UI_HOST: dspace-angular
1923
DSPACE_UI_PORT: '4000'
2024
DSPACE_UI_NAMESPACE: /
21-
# NOTE: When running the UI in production mode (which the -dist image does),
22-
# these DSPACE_REST_* variables MUST point at a public, HTTPS URL.
23-
# This is because Server Side Rendering (SSR) currently requires a public URL,
24-
# see this bug: https://github.com/DSpace/dspace-angular/issues/1485
25-
DSPACE_REST_SSL: 'true'
26-
DSPACE_REST_HOST: demo.dspace.org
27-
DSPACE_REST_PORT: 443
25+
DSPACE_REST_SSL: 'false'
26+
DSPACE_REST_HOST: localhost
27+
DSPACE_REST_PORT: 8080
2828
DSPACE_REST_NAMESPACE: /server
29+
# Ensure SSR can use the 'dspace' Docker image directly (see docker-compose-rest.yml)
30+
DSPACE_REST_SSRBASEURL: http://dspace:8080/server
2931
image: "${DOCKER_REGISTRY:-docker.io}/${DOCKER_OWNER:-dspace}/dspace-angular:${DSPACE_VER:-dspace-7_x}-dist"
3032
build:
3133
context: ..
3234
dockerfile: Dockerfile.dist
3335
networks:
34-
dspacenet:
36+
- dspacenet
3537
ports:
3638
- published: 4000
3739
target: 4000
38-
stdin_open: true
39-
tty: true

docker/docker-compose-rest.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ networks:
1717
# Define a custom subnet for our DSpace network, so that we can easily trust requests from host to container.
1818
# If you customize this value, be sure to customize the 'proxies.trusted.ipranges' env variable below.
1919
- subnet: 172.23.0.0/16
20+
# Explicitly set external=false because this script creates the network.
21+
# NOTE: Because of how compose files are merged, this script should be specified LAST when passed
22+
# to "docker compose" for the network to be created properly.
23+
external: false
2024
services:
2125
# DSpace (backend) webapp container
2226
dspace:
@@ -31,6 +35,9 @@ services:
3135
# Uncomment to set a non-default value for dspace.server.url or dspace.ui.url
3236
# dspace__P__server__P__url: http://localhost:8080/server
3337
# dspace__P__ui__P__url: http://localhost:4000
38+
# Set SSR URL to the Docker container name so that UI can contact container directly in Production mode.
39+
# (This is necessary for docker-compose-dist.yml)
40+
dspace__P__server__P__ssr__P__url: http://dspace:8080/server
3441
dspace__P__name: 'DSpace Started with Docker Compose'
3542
# db.url: Ensure we are using the 'dspacedb' image for our database
3643
db__P__url: 'jdbc:postgresql://dspacedb:5432/dspace'
@@ -48,8 +55,6 @@ services:
4855
ports:
4956
- published: 8080
5057
target: 8080
51-
stdin_open: true
52-
tty: true
5358
volumes:
5459
- assetstore:/dspace/assetstore
5560
# Ensure that the database is ready BEFORE starting tomcat
@@ -76,8 +81,6 @@ services:
7681
ports:
7782
- published: 5432
7883
target: 5432
79-
stdin_open: true
80-
tty: true
8184
volumes:
8285
# Keep Postgres data directory between reboots
8386
- pgdata:/pgdata
@@ -90,8 +93,6 @@ services:
9093
ports:
9194
- published: 8983
9295
target: 8983
93-
stdin_open: true
94-
tty: true
9596
working_dir: /var/solr/data
9697
volumes:
9798
# Keep Solr data directory between reboots

0 commit comments

Comments
 (0)