diff --git a/.dockerignore b/.dockerignore index bca449c8d7c1..9a5efd58414c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -33,3 +33,6 @@ frontend/node_modules node_modules # travis vendor/bundle +# allow precompiled assets to be injected +!/public/assets +!/config/frontend_assets.manifest.json diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f9e1ab011854..8f5866444471 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -3,7 +3,7 @@ name: Docker on: # build dev daily schedule: - - cron: '20 2 * * *' # Daily at 02:20 + - cron: "20 2 * * *" # Daily at 02:20 push: tags: @@ -21,7 +21,7 @@ env: REGISTRY_IMAGE: openproject/openproject jobs: - extract_version: + setup: runs-on: ubuntu-latest steps: - name: Extract version @@ -36,6 +36,11 @@ jobs: elif [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then TAG_REF=${{ inputs.tag }} CHECKOUT_REF=${{ inputs.tag }} + + if [ -z "$TAG_REF" ]; then + TAG_REF=dev + CHECKOUT_REF=dev + fi else echo "Unsupported event" exit 1 @@ -50,75 +55,105 @@ jobs: echo "Version: $VERSION" echo "version=$VERSION" >> "$GITHUB_OUTPUT" echo "checkout_ref=$CHECKOUT_REF" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v4 + - name: Cache NPM + uses: runs-on/cache@v4 + with: + path: | + frontend/node_modules + node_modules + key: nodejs-x64-${{ hashFiles('**/package-lock.json') }} + restore-keys: nodejs-x64- + - name: Cache angular + uses: runs-on/cache@v4 + with: + path: frontend/.angular + key: angular-${{ github.ref }} + restore-keys: angular- + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: | + package-lock.json + frontend/package-lock.json + - name: Precompile assets + run: | + ./docker/prod/setup/precompile-assets.sh + cp config/frontend_assets.manifest.json public/assets/frontend_assets.manifest.json + - uses: actions/upload-artifact@v3 + with: + path: public/ + name: public-assets-${{ github.sha }} outputs: version: ${{ steps.extract_version.outputs.version }} checkout_ref: ${{ steps.extract_version.outputs.checkout_ref }} build: needs: - - extract_version + - setup if: github.repository == 'opf/openproject' - runs-on: runs-on,runner=32cpu-linux-x64,run-id=${{ github.run_id }} + runs-on: + labels: + - runs-on + - ssh=false + - run-id=${{ github.run_id }} + - ${{ matrix.runner }} strategy: matrix: include: - platform: linux/amd64 + bim_support: true target: slim + runner: runner=4cpu-linux-x64 - platform: linux/arm64/v8 + bim_support: false target: slim + runner: runner=4cpu-linux-arm64 - platform: linux/amd64 + bim_support: true target: all-in-one - - platform: linux/ppc64le + runner: runner=4cpu-linux-x64 + - platform: linux/arm64/v8 bim_support: false target: all-in-one - - platform: linux/arm64/v8 + runner: runner=4cpu-linux-arm64 + - platform: linux/ppc64le bim_support: false target: all-in-one + runner: runner=4cpu-linux-x64 steps: - - name: Extract version - id: extract_version - run: | - if [[ ${{ github.event_name }} == 'push' ]]; then - TAG_REF=${GITHUB_REF#refs/tags/} - CHECKOUT_REF=$GITHUB_REF - elif [[ ${{ github.event_name }} == 'schedule' ]]; then - TAG_REF=dev - CHECKOUT_REF=refs/heads/dev - elif [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then - TAG_REF=${{ inputs.tag }} - CHECKOUT_REF=${{ inputs.tag }} - else - echo "Unsupported event" - exit 1 - fi - - if [ -z "$TAG_REF" ] || [ -z "$CHECKOUT_REF" ]; then - echo "No TAG_REF or CHECKOUT_REF set. Aborting" - exit 1 - fi - - VERSION=${TAG_REF#v} - echo "Version: $VERSION" - echo "::set-output name=version::$VERSION" - echo "::set-output name=checkout_ref::$CHECKOUT_REF" - name: Checkout with: - ref: ${{ steps.extract_version.outputs.checkout_ref }} + ref: ${{ needs.setup.outputs.checkout_ref }} uses: actions/checkout@v4 - name: Prepare docker files run: | cp ./docker/prod/Dockerfile ./Dockerfile - - # Add build information - echo "${{ steps.extract_version.outputs.checkout_ref }}" > PRODUCT_VERSION - echo "https://github.com/opf/openproject/commits/${{ steps.extract_version.outputs.checkout_ref }}" > PRODUCT_URL + - name: Download precompiled public assets + uses: actions/download-artifact@v3 + with: + name: public-assets-${{ github.sha }} + path: public/ + - name: Setup precompiled assets + run: | + ls -al public/ + mv public/assets/frontend_assets.manifest.json config/frontend_assets.manifest.json + ls -al config/frontend_assets.manifest.json + - name: Add build information + run: | + echo "${{ needs.setup.outputs.checkout_ref }}" > PRODUCT_VERSION + echo "https://github.com/opf/openproject/commits/${{ needs.setup.outputs.checkout_ref }}" > PRODUCT_URL date -u +"%Y-%m-%dT%H:%M:%SZ" > RELEASE_DATE - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -132,7 +167,7 @@ jobs: org.opencontainers.image.documentation=https://www.openproject.org/docs/ org.opencontainers.image.vendor=OpenProject GmbH tags: | - type=semver,pattern={{version}},value=${{ needs.extract_version.outputs.version }} + type=semver,pattern={{version}},value=${{ needs.setup.outputs.version }} images: | ${{ env.REGISTRY_IMAGE }} - name: Build image @@ -148,6 +183,8 @@ jobs: load: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} + cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max - name: Test # We only test the native container. If that fails the builds for the others # will be cancelled as well. @@ -176,6 +213,8 @@ jobs: BIM_SUPPORT=${{ matrix.bim_support }} labels: ${{ steps.meta.outputs.labels }} outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true + cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }} + cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max - name: Export digest run: | mkdir -p /tmp/digests @@ -194,7 +233,7 @@ jobs: matrix: target: [slim, all-in-one] needs: - - extract_version + - setup - build steps: - name: Download digests @@ -209,7 +248,7 @@ jobs: if [ "$suffix" = "-all-in-one" ]; then suffix="" ; fi echo "suffix=$suffix" >> "$GITHUB_OUTPUT" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Docker meta id: meta uses: docker/metadata-action@v4 @@ -223,12 +262,12 @@ jobs: latest=false suffix=${{ steps.set_suffix.outputs.suffix }} tags: | - type=semver,pattern={{version}},value=${{ needs.extract_version.outputs.version }} - type=semver,pattern={{major}}.{{minor}},value=${{ needs.extract_version.outputs.version }} - type=semver,pattern={{major}},value=${{ needs.extract_version.outputs.version }} + type=semver,pattern={{version}},value=${{ needs.setup.outputs.version }} + type=semver,pattern={{major}}.{{minor}},value=${{ needs.setup.outputs.version }} + type=semver,pattern={{major}},value=${{ needs.setup.outputs.version }} type=raw,value=dev,priority=200,enable={{is_default_branch}} - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -241,7 +280,7 @@ jobs: run: | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} notify: - needs: [extract_version, build, merge] + needs: [setup, build, merge] if: ${{ always() && contains(needs.*.result, 'failure') }} uses: ./.github/workflows/email-notification.yml secrets: inherit diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 64bcc3c164b4..8fdced783c28 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -1,73 +1,18 @@ ARG RUBY_VERSION="3.3.1" -ARG NODE_VERSION="20.9.0" -ARG BUNDLER_VERSION="2.5.10" -ARG DEBIAN_FRONTEND=noninteractive +FROM ruby:${RUBY_VERSION}-bullseye as base +LABEL maintainer="operations@openproject.com" -# ------------------------------------- -# rubygems (private) -# ------------------------------------- -FROM ruby:${RUBY_VERSION}-bullseye as rubygems +ARG BUNDLER_VERSION="2.5.10" +ARG NODE_VERSION="20.9.0" +ARG BIM_SUPPORT=true +ENV DEBIAN_FRONTEND=noninteractive ENV BUNDLE_JOBS=8 ENV BUNDLE_RETRY=3 ENV BUNDLE_WITHOUT="development:test" - -WORKDIR /app - -RUN gem install bundler --version "$BUNDLER_VERSION" --no-document - -COPY Gemfile Gemfile.modules Gemfile.lock .ruby-version ./ -COPY modules ./modules -RUN bundle install - -# ------------------------------------- -# nodejs (private) -# ------------------------------------- -# Using docker image for node so that multi-arch is automatically taken care of -FROM node:${NODE_VERSION} as nodejs - -WORKDIR /app - -COPY package.json ./ -COPY frontend/package.json frontend/package-lock.json frontend/.npmrc ./frontend/ -RUN JOBS=8 npm install - -# ------------------------------------- -# assets (private) -# ------------------------------------- -FROM rubygems as assets - -COPY --from=nodejs /usr/local/bin/node /usr/local/bin/node -COPY --from=nodejs /usr/local/lib/node_modules /usr/local/lib/node_modules -COPY --from=nodejs /usr/local/include/node /usr/local/include/node -RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm - -WORKDIR /app - -COPY --from=nodejs /app/node_modules ./node_modules -COPY --from=nodejs /app/frontend/node_modules ./frontend/node_modules -COPY Rakefile . -COPY bin ./bin -COPY app ./app -COPY config ./config -COPY config/database.production.yml ./config/database.yml -COPY lib ./lib -COPY lib_static ./lib_static -COPY frontend ./frontend -COPY modules ./modules -COPY vendor ./vendor -COPY lookbook ./lookbook - -RUN --mount=type=cache,target=/app/frontend/.angular/cache,uid=1000,gid=1000 \ - SECRET_KEY_BASE=1 RAILS_ENV=production DATABASE_URL=nulldb://db \ - bin/rails openproject:plugins:register_frontend assets:precompile - -# ------------------------------------- -# base (private) -# ------------------------------------- -FROM ruby:${RUBY_VERSION}-slim-bullseye as base -LABEL maintainer="operations@openproject.com" +ENV BUNDLE_FROZEN=true # SYSTEM +ENV DOCKER=1 ENV APP_USER=app ENV APP_PATH=/app ENV APP_DATA_PATH=/var/openproject/assets @@ -90,6 +35,7 @@ ENV OPENPROJECT_EDITION=standard ENV OPENPROJECT_INSTALLATION__TYPE=docker ENV OPENPROJECT_ATTACHMENTS__STORAGE__PATH=$APP_DATA_PATH/files ENV OPENPROJECT_RAILS__CACHE__STORE=file_store +ENV OPENPROJECT_ANGULAR_UGLIFY=true RUN useradd -d /home/$APP_USER -m $APP_USER RUN mkdir -p $APP_PATH && chown $APP_USER:$APP_USER $APP_PATH @@ -97,47 +43,36 @@ RUN mkdir -p $APP_DATA_PATH && chown $APP_USER:$APP_USER $APP_DATA_PATH && chmod WORKDIR $APP_PATH -RUN --mount=type=cache,target=/var/cache/apt \ - apt-get update -qq \ - && apt-get install -yq --no-install-recommends \ - file \ - curl \ - gnupg2 \ - && curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ - && echo 'deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main' > /etc/apt/sources.list.d/pgdg.list \ - && apt-get update -qq \ - && apt-get install -yq --no-install-recommends \ - libpq5 \ - postgresql-client-$CURRENT_PGVERSION \ - postgresql-client-$NEXT_PGVERSION \ - libffi7 \ - unrtf tesseract-ocr poppler-utils catdoc imagemagick \ - && apt-get purge -y curl gnupg2 \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ - && truncate -s 0 /var/log/*log +# upgrade bundler +RUN gem install bundler --version "$BUNDLER_VERSION" --no-document -# ------------------------------------- -# slim (public) -# ------------------------------------- -FROM base as slim -COPY --chown=$APP_USER:$APP_USER --from=rubygems /usr/local/bundle /usr/local/bundle -COPY --chown=$APP_USER:$APP_USER --from=assets /app/public/assets /app/public/assets -COPY --chown=$APP_USER:$APP_USER --from=assets /app/config/frontend_assets.manifest.json /app/config/frontend_assets.manifest.json -COPY --chown=$APP_USER:$APP_USER . . -COPY --chown=$APP_USER:$APP_USER ./config/database.production.yml /app/config/database.yml -# Update Gemfile.lock in case a plugin has been added. It it hasn't, the file stays identical. -COPY --chown=$APP_USER:$APP_USER --from=rubygems /app/Gemfile.lock /app/ +# system dependencies, nodejs +COPY ./docker/prod/setup/preinstall-common.sh ./docker/prod/setup/preinstall-common.sh +RUN ./docker/prod/setup/preinstall-common.sh -ENV BUNDLE_FROZEN=true +# stuff required for gems +COPY Gemfile Gemfile.modules Gemfile.lock .ruby-version ./ +COPY modules ./modules +RUN bundle install + +COPY . . +RUN ./docker/prod/setup/precompile-assets.sh +RUN ./docker/prod/setup/postinstall-common.sh # We need this so puma is allowed to create the tmp/pids folder and # temporary upload files when running with a uid other than 1000 (app) # but with an allowed supplemental group (1000). RUN tmp_path=$APP_PATH/tmp; (mkdir -p $tmp_path || true) && chown $APP_USER:$APP_USER $tmp_path && chmod g+rw $tmp_path -USER $APP_USER +RUN cp ./config/database.production.yml config/database.yml RUN ln -s $APP_PATH/docker/prod/setup/.irbrc /home/$APP_USER/ +# ------------------------------------- +# slim (public) +# ------------------------------------- +FROM base as slim + +USER $APP_USER EXPOSE 8080 CMD ["./docker/prod/web"] VOLUME ["$APP_DATA_PATH"] @@ -146,61 +81,16 @@ VOLUME ["$APP_DATA_PATH"] # all-in-one (public) # ------------------------------------- FROM base as all-in-one -ARG DEBIAN_FRONTEND -ARG NODE_VERSION -ARG BUNDLER_VERSION -# Allow platform-specific additions. Valid values are: on-prem,saas,bahn -ARG PLATFORM=on-prem -# Use OAuth token in case private gems need to be fetched -ARG GITHUB_OAUTH_TOKEN -ARG BIM_SUPPORT=true -ARG GOSU_VERSION="1.17" -ARG OPENPROJECT_ANGULAR_UGLIFY=true ENV OPENPROJECT_RAILS__CACHE__STORE=memcache ENV DATABASE_URL=postgres://openproject:openproject@127.0.0.1/openproject ENV PGDATA=/var/openproject/pgdata -ENV PGBIN="/usr/lib/postgresql/$PGVERSION/bin" - -COPY docker/prod/setup ./docker/prod/setup -RUN ./docker/prod/setup/preinstall.sh +ARG GOSU_VERSION="1.17" -RUN dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \ - && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \ - && chmod +x /usr/local/bin/gosu \ - && gosu nobody true +RUN ./docker/prod/setup/postinstall-onprem.sh -# set irb default config for app (docker run -it ...) and root (docker exec -it ...) users -RUN ln -s /app/docker/prod/setup/.irbrc /home/$APP_USER/ RUN ln -s /app/docker/prod/setup/.irbrc /root/ -COPY Gemfile Gemfile.* .ruby-version ./ -COPY modules ./modules -COPY vendor ./vendor -# some gemspec files of plugins require files in there, notably OpenProject::Version -COPY lib ./lib - -RUN \ - bundle config set --local path 'vendor/bundle' && \ - bundle config set --local without 'test development' && \ - bundle install --quiet --no-cache --jobs=8 --retry=3 && \ - bundle config set deployment 'true' && \ - cp Gemfile.lock Gemfile.lock.bak && \ - rm -rf vendor/bundle/ruby/*/cache && \ - rm -rf vendor/bundle/ruby/*/gems/*/spec && \ - rm -rf vendor/bundle/ruby/*/gems/*/test - -# Finally, copy over the whole thing -COPY . . - -# Copy lock file again as the updated version was overriden by COPY just now -RUN cp Gemfile.lock.bak Gemfile.lock && rm Gemfile.lock.bak - -RUN ./docker/prod/setup/postinstall.sh - -# this has to happen after postinstall.sh since it uses a different database.yml -COPY config/database.production.yml ./config/database.yml - # Expose ports for apache and postgres EXPOSE 80 5432 @@ -211,4 +101,4 @@ VOLUME ["$PGDATA", "$APP_DATA_PATH"] ENTRYPOINT ["./docker/prod/entrypoint.sh"] # Set default command to launch the all-in-one configuration supervised by supervisord -CMD ["./docker/prod/supervisord"] +CMD ["./docker/prod/supervisord"] \ No newline at end of file diff --git a/docker/prod/setup/postinstall-common.sh b/docker/prod/setup/postinstall-common.sh index ead33f2ff9c3..3da98edb802a 100755 --- a/docker/prod/setup/postinstall-common.sh +++ b/docker/prod/setup/postinstall-common.sh @@ -1,50 +1,8 @@ #!/bin/bash +set -eox pipefail -set -e -set -o pipefail +# Ensure we can write in /tmp/op_uploaded_files (cf. #29112) +mkdir -p /tmp/op_uploaded_files/ && chown -R $APP_USER:$APP_USER /tmp/op_uploaded_files/ -pushd "${APP_PATH}/frontend" - -export NG_CLI_ANALYTICS=ci # so angular cli doesn't block waiting for user input - -# Installing frontend dependencies -npm install - -popd - -# Bundle assets - -su - postgres -c "$PGBIN/initdb -D /tmp/nulldb" -su - postgres -c "$PGBIN/pg_ctl -D /tmp/nulldb -l /dev/null -l /tmp/nulldb/log -w start" - -# give some more time for DB to start -sleep 5 - -echo "create database assets; create user assets with encrypted password 'p4ssw0rd'; grant all privileges on database assets to assets;" | su - postgres -c psql - -# dump schema -DATABASE_URL=postgres://assets:p4ssw0rd@127.0.0.1/assets RAILS_ENV=production bundle exec rake db:migrate db:schema:dump db:schema:cache:dump - -# this line requires superuser rights, which is not always available and doesn't matter anyway -sed -i '/^COMMENT ON EXTENSION/d' db/structure.sql - -# precompile assets -DATABASE_URL=postgres://assets:p4ssw0rd@127.0.0.1/assets RAILS_ENV=production bundle exec rake assets:precompile - -su - postgres -c "$PGBIN/pg_ctl -D /tmp/nulldb stop" - -rm -rf /tmp/nulldb - -# Remove sprockets cache -rm -rf "$APP_PATH/tmp/cache/assets" - -# Remove node_modules and entire frontend -rm -rf "$APP_PATH/node_modules/" "$APP_PATH/frontend/node_modules/" - -# Remove angular cache -rm -rf "$APP_PATH/frontend/.angular" - -# Clean cache in root -rm -rf /root/.npm - -rm -f "$APP_PATH/log/production.log" +# Remove any existing config/database.yml +rm -f ./config/database.yml \ No newline at end of file diff --git a/docker/prod/setup/preinstall-on-prem.sh b/docker/prod/setup/postinstall-onprem.sh similarity index 52% rename from docker/prod/setup/preinstall-on-prem.sh rename to docker/prod/setup/postinstall-onprem.sh index 95e6878dc330..ec4160ce7bde 100755 --- a/docker/prod/setup/preinstall-on-prem.sh +++ b/docker/prod/setup/postinstall-onprem.sh @@ -1,6 +1,6 @@ #!/bin/bash -set -e -set -o pipefail +set -eox pipefail + # postfix.postinst tries to generate a hostname based on /etc/resolv.conf, which # gets copied in to the docker environment from the host system. On systems @@ -14,10 +14,30 @@ if [ -f /run/.containerenv -o -f /.dockerenv ]; then mv /bin/x-hostname /bin/hostname fi +apt-get update -qq +# embed all-in-one additional software apt-get install -y \ + postgresql-$CURRENT_PGVERSION \ + postgresql-$NEXT_PGVERSION \ + memcached \ postfix \ apache2 \ - supervisor + supervisor \ + git subversion \ + wget + +# remove any existing cluster +service postgresql stop +rm -rf /var/lib/postgresql/{$CURRENT_PGVERSION,$NEXT_PGVERSION} a2enmod proxy proxy_http rm -f /etc/apache2/sites-enabled/000-default.conf + +# gosu +dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" +wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" +chmod +x /usr/local/bin/gosu +gosu nobody true + +rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +truncate -s 0 /var/log/*log diff --git a/docker/prod/setup/postinstall.sh b/docker/prod/setup/postinstall.sh deleted file mode 100755 index f1d9c75fd281..000000000000 --- a/docker/prod/setup/postinstall.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -display_error() { - echo " !--> ERROR on postinstall:" - tail -n 200 /tmp/dockerize.log - exit 1 -} - -echo " ---> POSTINSTALL" - -# Ensure we can write in /tmp/op_uploaded_files (cf. #29112) -mkdir -p /tmp/op_uploaded_files/ && chown -R $APP_USER:$APP_USER /tmp/op_uploaded_files/ - -rm -f ./config/database.yml - -if test -f ./docker/prod/setup/postinstall-$PLATFORM.sh ; then - echo " ---> Executing postinstall for $PLATFORM..." - ./docker/prod/setup/postinstall-$PLATFORM.sh -fi - -echo " ---> Precompiling assets. This will take a while..." -./docker/prod/setup/postinstall-common.sh - -echo " OK." diff --git a/docker/prod/setup/precompile-assets.sh b/docker/prod/setup/precompile-assets.sh new file mode 100755 index 000000000000..663b32b61034 --- /dev/null +++ b/docker/prod/setup/precompile-assets.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -exo pipefail + +if [ -f config/frontend_assets.manifest.json ]; then + echo "Assets have already been precompiled. Reusing." +else + echo "Assets need to be compiled" + JOBS=8 npm install + + SECRET_KEY_BASE=1 RAILS_ENV=production DATABASE_URL=nulldb://db \ + bin/rails openproject:plugins:register_frontend assets:precompile + + if [ "$DOCKER" = "1" ]; then + rm -rf /tmp/nulldb + # Remove sprockets cache + rm -rf "$APP_PATH/tmp/cache/assets" + # Remove node_modules and entire frontend + rm -rf "$APP_PATH/node_modules/" "$APP_PATH/frontend/node_modules/" + # Remove angular cache + rm -rf "$APP_PATH/frontend/.angular" + # Clean cache in root + rm -rf /root/.npm + rm -f "$APP_PATH/log/production.log" + fi +fi \ No newline at end of file diff --git a/docker/prod/setup/preinstall-common.sh b/docker/prod/setup/preinstall-common.sh index 3a9b092d43f8..ee5569141d3c 100755 --- a/docker/prod/setup/preinstall-common.sh +++ b/docker/prod/setup/preinstall-common.sh @@ -19,51 +19,56 @@ get_architecture() { return 0 } -set -e -set -o pipefail +set -exo pipefail ARCHITECTURE=$(get_architecture) apt-get update -qq -apt-get install -y git subversion wget curl gnupg2 apt-transport-https unzip build-essential libpq-dev libclang-dev +# make sure all dependencies are up to date +apt-get upgrade -y + +apt-get install -yq --no-install-recommends \ + file \ + curl \ + gnupg2 \ # install node + npm curl -s https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${ARCHITECTURE}.tar.gz | tar xzf - -C /usr/local --strip-components=1 -wget --quiet -O- https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - -echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main" > /etc/apt/sources.list.d/pgdg.list - -if [ ! "$BIM_SUPPORT" = "false" ]; then - # https://learn.microsoft.com/en-gb/dotnet/core/install/linux-debian#debian-11 - wget --quiet https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O /tmp/packages-microsoft-prod.deb && \ - dpkg -i /tmp/packages-microsoft-prod.deb && rm /tmp/packages-microsoft-prod.deb -fi +curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - +echo 'deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main' > /etc/apt/sources.list.d/pgdg.list apt-get update -qq -apt-get install -y \ - poppler-utils \ +apt-get install -yq --no-install-recommends \ + libpq-dev \ + postgresql-client-$CURRENT_PGVERSION \ + postgresql-client-$NEXT_PGVERSION \ + libpq5 \ + libffi7 \ unrtf \ tesseract-ocr \ + poppler-utils \ catdoc \ - postgresql-9.6 \ - postgresql-client-9.6 \ - postgresql-13 \ - postgresql-client-13 \ imagemagick \ - memcached + libclang-dev -# remove any existing cluster -service postgresql stop -rm -rf /var/lib/postgresql/{9.6,13} # Specifics for BIM edition if [ ! "$BIM_SUPPORT" = "false" ]; then + apt-get install -y wget unzip + + # https://learn.microsoft.com/en-gb/dotnet/core/install/linux-debian#debian-11 + wget --quiet https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O /tmp/packages-microsoft-prod.deb + dpkg -i /tmp/packages-microsoft-prod.deb + rm /tmp/packages-microsoft-prod.deb + + apt-get update -qq apt-get install -y dotnet-runtime-6.0 # required for BIM edition tmpdir=$(mktemp -d) cd $tmpdir # Install XKT converter - npm install @xeokit/xeokit-gltf-to-xkt@1.3.1 -g + npm install -g @xeokit/xeokit-gltf-to-xkt@1.3.1 # Install COLLADA2GLTF wget --quiet https://github.com/KhronosGroup/COLLADA2GLTF/releases/download/v2.1.5/COLLADA2GLTF-v2.1.5-linux.zip @@ -85,6 +90,8 @@ if [ ! "$BIM_SUPPORT" = "false" ]; then rm -rf $tmpdir fi -gem install bundler --version "$BUNDLER_VERSION" --no-document - id $APP_USER || useradd -d /home/$APP_USER -m $APP_USER + +rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +truncate -s 0 /var/log/*log + diff --git a/docker/prod/setup/preinstall.sh b/docker/prod/setup/preinstall.sh deleted file mode 100755 index 8a4fd099000f..000000000000 --- a/docker/prod/setup/preinstall.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -set -e -set -o pipefail - -echo " ---> PREINSTALL" - -display_error() { - echo " !--> ERROR on preinstall:" - tail -n 200 /tmp/dockerize.log - exit 1 -} - -echo " ---> Setting up common dependencies. This will take a while..." -./docker/prod/setup/preinstall-common.sh > /tmp/dockerize.log || display_error - -if test -f ./docker/prod/setup/preinstall-$PLATFORM.sh ; then - echo " ---> Executing preinstall for $PLATFORM..." - ./docker/prod/setup/preinstall-$PLATFORM.sh >/tmp/dockerize.log || display_error -fi - -apt-get clean -rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -truncate -s 0 /var/log/*log - -rm -f /tmp/dockerize.log -echo " OK."