diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..de86122ce24 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +.github +node_modules +dist diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index ceb24e9681e..4911527128d 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -9,6 +9,14 @@ jobs: packages: write uses: ./.github/workflows/container.yml + production-container: + permissions: + contents: read + id-token: write # Required to exchange for AWS credentials using OIDC + uses: ./.github/workflows/container-production.yml + secrets: + GU_RIFF_RAFF_ROLE_ARN: ${{ secrets.GU_RIFF_RAFF_ROLE_ARN }} + prettier: uses: ./.github/workflows/prettier.yml diff --git a/.github/workflows/container-production.yml b/.github/workflows/container-production.yml new file mode 100644 index 00000000000..0ecf3611a2f --- /dev/null +++ b/.github/workflows/container-production.yml @@ -0,0 +1,46 @@ +name: Production container +on: + workflow_call: + secrets: + GU_RIFF_RAFF_ROLE_ARN: + required: true + outputs: + imageDigest: + description: 'The digest of the generated container image' + value: ${{ jobs.build-production-image.outputs.imageDigest }} +jobs: + facts: + runs-on: ubuntu-slim + permissions: {} # This job doesn't need any permissions. Explicitly set it to an empty object to avoid inheriting any default permissions of the workflow. + outputs: + branchName: ${{ steps.get-build-facts.outputs.branchName }} + buildNumber: ${{ steps.get-build-facts.outputs.buildNumber }} + commitSha: ${{ steps.get-build-facts.outputs.commitSha }} + steps: + - uses: guardian/actions-build-facts@v0.0.1 + id: get-build-facts + + build-production-image: + runs-on: ubuntu-latest + needs: + - facts + permissions: + contents: read + id-token: write # Required to exchange for AWS credentials using OIDC + outputs: + imageDigest: ${{ steps.publish-image.outputs.imageDigest }} + steps: + - uses: actions/checkout@v6.0.2 + - name: Add commit hash for PRout + working-directory: dotcom-rendering + run: echo 'export const GIT_COMMIT_HASH = "${{ needs.facts.outputs.commitSha }}";' > src/server/prout.ts + - name: Build image + run: docker buildx build -f Production.dockerfile -t ${{ github.repository }}:latest . + - name: Publish Image + uses: guardian/actions-publish-image@v0.0.2 + id: publish-image + with: + roleArn: ${{ secrets.GU_RIFF_RAFF_ROLE_ARN }} + branchName: ${{ needs.facts.outputs.branchName }} + buildNumber: ${{ needs.facts.outputs.buildNumber }} + commitSha: ${{ needs.facts.outputs.commitSha }} diff --git a/Production.dockerfile b/Production.dockerfile new file mode 100644 index 00000000000..c31c688555c --- /dev/null +++ b/Production.dockerfile @@ -0,0 +1,34 @@ +FROM dhi.io/node:24-alpine3.23-dev AS base +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME/bin:$PATH" +RUN corepack enable +COPY . /app +WORKDIR /app + +# Install dependencies as a separate step to take advantage of Docker's caching. +# Leverage a cache mount to /pnpm/store to speed up subsequent builds. +FROM base AS dependencies +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +WORKDIR /app/dotcom-rendering +ENV PATH="node_modules/.bin:$PATH" +ENV NODE_ENV=production + +# Build the application +FROM dependencies AS builder +RUN webpack --config webpack/webpack.config.js --progress +RUN node scripts/islands/island-descriptions.mjs + +# Finally, create the production image with only the necessary files +FROM dhi.io/node:24-alpine3.23 AS application +WORKDIR /app +COPY --from=builder --chown=node:node /app/dotcom-rendering/dist /app + +# Disable logging with Log4js as console logs will be forwarded to Central ELK with a sidecar +# TODO Maintain metrics +ENV DISABLE_LOGGING_AND_METRICS=true +ENV NODE_ENV=production + +# Expose the port that the application listens on +EXPOSE 9000 + +CMD ["node", "/app/server.js"] diff --git a/scripts/postinstall.sh b/scripts/postinstall.sh index feede7c03f7..fae29ac04a3 100755 --- a/scripts/postinstall.sh +++ b/scripts/postinstall.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # Automatically copy over required settings for vscode if [ ! -f .vscode/settings.json ] ;