From 08a2f391fb5253249747100fbcfc37028fac9f8d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 29 Apr 2025 09:13:20 +0200 Subject: [PATCH] admin docker production with nginx, update workflow --- .github/workflows/test_admin_interface.yml | 42 +++++++---- admin/Dockerfile | 87 ++++++++++------------ admin/vite.config.js | 1 + docker-compose.yml | 6 +- nginx/serve.conf | 30 ++++++++ nginx/serveAdmin.conf | 29 ++++++++ package.json | 3 +- 7 files changed, 135 insertions(+), 63 deletions(-) create mode 100644 nginx/serve.conf create mode 100644 nginx/serveAdmin.conf diff --git a/.github/workflows/test_admin_interface.yml b/.github/workflows/test_admin_interface.yml index d57c78ef8..72b69356a 100644 --- a/.github/workflows/test_admin_interface.yml +++ b/.github/workflows/test_admin_interface.yml @@ -33,7 +33,7 @@ jobs: uses: actions/checkout@v3 - name: Admin Interface | Build 'test' image - run: docker build -f ./admin/Dockerfile --target test -t "gradido/admin:test" --build-arg NODE_ENV="test" . + run: docker build -f ./admin/Dockerfile --target production -t "gradido/admin:production" --build-arg NODE_ENV="production" --build-arg BUILD_COMMIT=$(git rev-parse HEAD) --build-arg BUILD_COMMIT_SHORT=$(git rev-parse --short HEAD) . unit_test: if: needs.files-changed.outputs.admin == 'true' @@ -41,44 +41,58 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: + - name: Set Node.js version + uses: actions/setup-node@v4 + with: + node-version: '18.20.7' + - name: Checkout code uses: actions/checkout@v3 + - name: Install turbo + run: yarn global add turbo@^2 + + - name: Prune admin with turbos help + run: turbo prune admin + + - name: install dependencies + run: cd out && yarn install --frozen-lockfile --production=false + - name: Admin Interface | Unit tests - run: cd admin && yarn global add node-gyp && yarn && yarn run test + id: test + run: | + turbo admin#test admin#lint + echo "success=$([ $? -eq 0 ] && echo true || echo false)" >> $GITHUB_OUTPUT lint: if: needs.files-changed.outputs.admin == 'true' name: Lint - Admin Interface - needs: files-changed + needs: [files-changed, unit_test] runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Admin Interface | Lint - run: cd admin && yarn global add node-gyp && yarn && yarn run lint + - name: Check result from previous step + run: if [ "${{ needs.unit_test.outputs.test-success }}" != "true" ]; then exit 1; fi stylelint: if: needs.files-changed.outputs.admin == 'true' name: Stylelint - Admin Interface - needs: files-changed + needs: [files-changed, unit_test] runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - - name: Admin Interface | Stylelint - run: cd admin && yarn global add node-gyp && yarn && yarn run stylelint + - name: Check result from previous step + run: if [ "${{ needs.unit_test.outputs.test-success }}" != "true" ]; then exit 1; fi locales: if: needs.files-changed.outputs.admin == 'true' name: Locales - Admin Interface - needs: files-changed + needs: [files-changed, unit_test] runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - - name: Admin Interface | Locales - run: cd admin && yarn global add node-gyp && yarn && yarn run locales + - name: Check result from previous step + run: if [ "${{ needs.unit_test.outputs.test-success }}" != "true" ]; then exit 1; fi \ No newline at end of file diff --git a/admin/Dockerfile b/admin/Dockerfile index 7d06b8251..76c98e905 100644 --- a/admin/Dockerfile +++ b/admin/Dockerfile @@ -1,7 +1,7 @@ ################################################################################## # BASE ########################################################################### ################################################################################## -FROM node:18.20-alpine3.20 as base +FROM node:18.20.7-alpine3.21 as base # ENVs (available in production aswell, can be overwritten by commandline or env file) ## DOCKER_WORKDIR would be a classical ARG, but that is not multi layer persistent - shame @@ -9,9 +9,12 @@ ENV DOCKER_WORKDIR="/app" ## We Cannot do `$(date -u +'%Y-%m-%dT%H:%M:%SZ')` here so we use unix timestamp=0 ENV BUILD_DATE="1970-01-01T00:00:00.00Z" ## We cannot do $(npm run version).${BUILD_NUMBER} here so we default to 0.0.0.0 -ENV BUILD_VERSION="0.0.0.0" -## We cannot do `$(git rev-parse --short HEAD)` here so we default to 0000000 -ENV BUILD_COMMIT_SHORT="0000000" +ARG BUILD_VERSION +ENV BUILD_VERSION=${BUILD_VERSION} +ARG BUILD_COMMIT +ENV BUILD_COMMIT=${BUILD_COMMIT} +ARG BUILD_COMMIT_SHORT +ENV BUILD_COMMIT_SHORT=${BUILD_COMMIT_SHORT} ## SET NODE_ENV ARG NODE_ENV="production" ## App relevant Envs @@ -42,67 +45,57 @@ EXPOSE ${PORT} RUN mkdir -p ${DOCKER_WORKDIR} WORKDIR ${DOCKER_WORKDIR} -RUN mkdir -p /config ################################################################################## -# DEVELOPMENT (Connected to the local environment, to reload on demand) ########## +# Base with turbo ################################################################ ################################################################################## -FROM base as development +FROM base as turbo-base -# We don't need to copy or build anything since we gonna bind to the -# local filesystem which will need a rebuild anyway - -# Run command -# (for development we need to execute yarn install since the -# node_modules are on another volume and need updating) -CMD /bin/sh -c "cd /config && yarn install && cd /app && yarn && yarn run dev" +RUN apk update && apk add --no-cache libc6-compat \ + && yarn global add turbo@^2 \ + && rm -rf /tmp/* ~/.cache node_modules/.cache \ + && yarn cache clean ################################################################################## -# BUILD (Does contain all files and is therefore bloated) ######################## +# BUILDER (create partly monorepo only with data needed by dht-node) ############# ################################################################################## -FROM base as build +FROM turbo-base as builder -# Copy everything -COPY ./admin/ . -# Copy everything from config -COPY ./config/ ../config/ +COPY --chown=app:app . . +RUN turbo prune admin --docker -# yarn install and build config -RUN cd ../config && yarn install --production=false --frozen-lockfile --non-interactive && yarn build - -# yarn install admin -RUN yarn install --production=false --frozen-lockfile --non-interactive - -# yarn build -RUN yarn run build +################################################################################## +# INSTALLER (create production image) ############################################## +################################################################################## +FROM turbo-base AS installer +# First install the dependencies (as they change less often) +COPY --chown=app:app --from=builder /app/out/json/ . +RUN yarn install --frozen-lockfile --production=false \ + && rm -rf /tmp/* ~/.cache node_modules/.cache \ + && yarn cache clean + +# Build the project +COPY --chown=app:app --from=builder /app/out/full/ . +RUN turbo build --env-mode=loose +RUN pwd && ls -lah && du -d1 -h + ################################################################################## # TEST ########################################################################### ################################################################################## -FROM build as test - -# Install Additional Software -RUN apk add --no-cache bash jq +FROM installer as test # Run command -CMD /bin/sh -c "yarn run dev" +CMD /bin/sh -c "turbo admin#test --env-mode=loose" ################################################################################## # PRODUCTION (Does contain only "binary"- and static-files to reduce image size) # ################################################################################## -FROM base as production +FROM nginx:alpine as production -# Copy "binary"-files from build image -COPY --from=build ${DOCKER_WORKDIR}/build ./build -COPY --from=build ${DOCKER_WORKDIR}/../config/build ../config/build -# We also copy the node_modules express and serve-static for the run script -COPY --from=build ${DOCKER_WORKDIR}/node_modules ./node_modules -# Copy static files -COPY --from=build ${DOCKER_WORKDIR}/public ./public -# Copy package.json for script definitions (lock file should not be needed) -COPY --from=build ${DOCKER_WORKDIR}/package.json ./package.json -# Copy run scripts run/ -COPY --from=build ${DOCKER_WORKDIR}/run ./run +# copy builded frontend files +COPY --from=installer /app/admin/build/ /usr/share/nginx/html/ + +# copy nginx config +COPY nginx/serveAdmin.conf /etc/nginx/conf.d/default.conf -# Run command -CMD /bin/sh -c "yarn run start" diff --git a/admin/vite.config.js b/admin/vite.config.js index dca1dc6d2..1499b2090 100644 --- a/admin/vite.config.js +++ b/admin/vite.config.js @@ -28,6 +28,7 @@ export default defineConfig(async ({ command }) => { } if (existsSync('../.git', constants.F_OK)) { CONFIG.BUILD_COMMIT = execSync('git rev-parse HEAD').toString().trim() + CONFIG.BUILD_COMMIT_SHORT = (CONFIG.BUILD_COMMIT ?? '0000000').slice(0, 7) } validate(schema, CONFIG) // make sure that all urls used in browser have the same protocol to prevent mixed content errors diff --git a/docker-compose.yml b/docker-compose.yml index d1e85aaa3..903e18a4f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,11 +44,15 @@ services: context: ./ dockerfile: ./admin/Dockerfile target: production + args: + BUILD_COMMIT: ${BUILD_COMMIT} + BUILD_COMMIT_SHORT: ${BUILD_COMMIT_SHORT} + BUILD_VERSION: ${BUILD_VERSION} networks: - external-net - internal-net ports: - - 8080:8080 + - 8080:80 environment: # Envs used in Dockerfile # - DOCKER_WORKDIR="/app" diff --git a/nginx/serve.conf b/nginx/serve.conf new file mode 100644 index 000000000..e793fbfba --- /dev/null +++ b/nginx/serve.conf @@ -0,0 +1,30 @@ +server { + listen 80; + server_name localhost; + + gzip_static on; + gzip on; + gzip_proxied any; + gzip_types + text/css + text/javascript + text/xml + text/plain + application/javascript + application/x-javascript + application/json; + + root /usr/share/nginx/html; + index index.html; + + location / { + #limit_req zone=frontend burst=40 nodelay; + #limit_conn addr 40; + root /usr/share/nginx/html/; + index index.html; + try_files $uri $uri/ /index.html = 404; + } + + # Optional: CORS Header (vorsichtig, je nach Bedarf) + add_header Access-Control-Allow-Origin *; +} \ No newline at end of file diff --git a/nginx/serveAdmin.conf b/nginx/serveAdmin.conf new file mode 100644 index 000000000..501366233 --- /dev/null +++ b/nginx/serveAdmin.conf @@ -0,0 +1,29 @@ +server { + listen 80; + server_name localhost; + + gzip_static on; + gzip on; + gzip_proxied any; + gzip_types + text/css + text/javascript + text/xml + text/plain + application/javascript + application/x-javascript + application/json; + + + location /admin { + #limit_req zone=frontend burst=30 nodelay; + #limit_conn addr 40; + rewrite ^/admin/(.*)$ /$1 break; + root /usr/share/nginx/html/; + index index.html; + try_files $uri $uri/ /index.html = 404; + } + + # Optional: CORS Header (vorsichtig, je nach Bedarf) + add_header Access-Control-Allow-Origin *; +} \ No newline at end of file diff --git a/package.json b/package.json index b97eba9f6..cc0694542 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ ], "scripts": { "release": "scripts/release.sh", - "installAll": "yarn && cd database && yarn && cd ../frontend && yarn && cd ../admin && yarn && cd ../backend && yarn && cd ../federation && yarn && cd ../dht-node && yarn && cd ../e2e-tests && yarn && cd .." + "installAll": "yarn && cd database && yarn && cd ../frontend && yarn && cd ../admin && yarn && cd ../backend && yarn && cd ../federation && yarn && cd ../dht-node && yarn && cd ../e2e-tests && yarn && cd ..", + "docker:admin": "docker build --progress=plain -f ./admin/Dockerfile --target production -t \"gradido/admin:latest\" --build-arg NODE_ENV=\"production\" --build-arg BUILD_COMMIT=$(git rev-parse HEAD) --build-arg BUILD_COMMIT_SHORT=$(git rev-parse --short HEAD) ." }, "dependencies": { "auto-changelog": "^2.4.0",