node.js - Η διαδικασία Node μέσα σε docker έχει περιορισμένη μνήμη - πολύ κάτω από την διαθέσιμη


Έχω μια εφαρμογή Node που έχει δημιουργηθεί μέσα σε Docker. Όταν προσπαθώ να την μεταγλωττίσω μέσα στο container, εξαντλείται η μνήμη. Τρέχω docker-compose run api npm run build και λαμβάνω:

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
server |
server | Writing Node.js report to file: report.20200915.155423.48.0.001.json
server | <--- Last few GCs --->
server |
server | [48:0x557b183d4d20]     7413 ms: Scavenge 252.0 (254.4) -> 251.7 (254.9) MB, 1.9 / 0.0 ms  (average mu = 0.336, current mu = 0.325) allocation failure
server | [48:0x557b183d4d20]     7416 ms: Scavenge 252.4 (254.9) -> 251.9 (255.4) MB, 1.3 / 0.1 ms  (average mu = 0.336, current mu = 0.325) allocation failure
server | [48:0x557b183d4d20]     7425 ms: Scavenge 252.7 (255.4) -> 252.1 (256.4) MB, 7.5 / 0.0 ms  (average mu = 0.336, current mu = 0.325) allocation failure
server |
server |
server | <--- JS stacktrace --->
server |
server | ==== JS stack trace =========================================
server |
server |     0: ExitFrame [pc: 0x557b16d8e2e2]
server |     1: StubFrame [pc: 0x557b16d1dfa7]
server | Security context: 0x348fb7f9a299 <JSObject>
server |     2: createNodeArray(aka createNodeArray) [0xed8f52fff49] [/app/node_modules/typescript/lib/tsc.js:~15644] [pc=0x1e5b159af9a1](this=0x0138ef5004d1 <undefined>,0x2eff39aac181 <JSArray[1]>,82415,0x0138ef5004d1 <undefined>)
server |     3: parseStatement(aka parseStatement) [0x34818d601ef9] [/app/node_modules/typescript/lib/tsc.js...

Η μνήμη που έχει εκχωρηθεί στο docker είναι 12GB, μπορώ να το επιβεβαιώσω με docker stats:

2aeda754d6f8        graphql-services_api_run_30766f61adf8   0.00%               2.734MiB / 11.7GiB   0.02%               726B / 0B           0B / 0B             1

Η διαδικασία καταρρέει όταν πλησιάζει μόλις τα 500mb, που είναι τυπική χρήση μνήμης για τη μεταγλώττιση TypeScript:

cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.08%               444KiB / 11.7GiB     0.00%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   52.33%              28.81MiB / 11.7GiB   0.24%               746B / 0B           0B / 0B             19
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   52.33%              28.81MiB / 11.7GiB   0.24%               746B / 0B           0B / 0B             19
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   142.23%             118.7MiB / 11.7GiB   0.99%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   142.23%             118.7MiB / 11.7GiB   0.99%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   158.09%             228.6MiB / 11.7GiB   1.91%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   158.09%             228.6MiB / 11.7GiB   1.91%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   234.13%             337.4MiB / 11.7GiB   2.82%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   234.13%             337.4MiB / 11.7GiB   2.82%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   209.31%             348.4MiB / 11.7GiB   2.91%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   209.31%             348.4MiB / 11.7GiB   2.91%               746B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   24.58%              3.992MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   24.58%              3.992MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               3.828MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               3.828MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               3.527MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               3.527MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               3.504MiB / 11.7GiB   0.03%               746B / 0B           0B / 0B             1

Έχω παρατηρήσει ότι η χρήση της CPU εκτοξεύεται, αλλά όχι η μνήμη;

Έχω κάνει πάρα πολλές αναζητήσεις, αλλά σε όλες τις περιπτώσεις διαπίστωσα ότι η διαθέσιμη μνήμη για το docker ήταν περιορισμένη και η πρόταση ήταν να τη αυξήσω ή να καθορίσω το NODE_OPTIONS="--max-old-space-size όπως εδώ FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory στο ionic 3.

Η καθορισμός του NODE_OPTIONS="--max-old-space-size=512" κάνει τη δουλειά, αλλά δεν καταλαβαίνω γιατί χρειάζεται να το κάνω. Τρέχω το node 12.13 το οποίο έχει δυναμική κατανομή στοίβας. Για μνήμη ~ 12GB το μέγεθος της στοίβας θα έπρεπε να είναι πολύ μεγαλύτερο από τα απαιτούμενα 512.. Αν το φτιάξω έτσι, ποτέ δεν ξεπερνά το 5% ~ 600MB διαθέσιμης μνήμης:

cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.04%               2.344MiB / 11.7GiB   0.02%               956B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.04%               2.344MiB / 11.7GiB   0.02%               956B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   18.79%              19.18MiB / 11.7GiB   0.16%               956B / 0B           0B / 0B             12
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   18.79%              19.18MiB / 11.7GiB   0.16%               956B / 0B           0B / 0B             12
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   116.90%             84.32MiB / 11.7GiB   0.70%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   116.90%             84.32MiB / 11.7GiB   0.70%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   176.67%             188.2MiB / 11.7GiB   1.57%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   176.67%             188.2MiB / 11.7GiB   1.57%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   150.59%             329.9MiB / 11.7GiB   2.75%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   150.59%             329.9MiB / 11.7GiB   2.75%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   146.39%             417.2MiB / 11.7GiB   3.48%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   146.39%             417.2MiB / 11.7GiB   3.48%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   207.50%             507.9MiB / 11.7GiB   4.24%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   207.50%             507.9MiB / 11.7GiB   4.24%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   193.23%             567.1MiB / 11.7GiB   4.73%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   193.23%             567.1MiB / 11.7GiB   4.73%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   220.27%             567.6MiB / 11.7GiB   4.74%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   220.27%             567.6MiB / 11.7GiB   4.74%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   234.85%             598.1MiB / 11.7GiB   4.99%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   234.85%             598.1MiB / 11.7GiB   4.99%               956B / 0B           0B / 0B             30
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   218.03%             4.875MiB / 11.7GiB   0.04%               956B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   218.03%             4.875MiB / 11.7GiB   0.04%               956B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               4.77MiB / 11.7GiB    0.04%               956B / 0B           0B / 0B             1
cab79aa591a3        graphql-services_api_run_97f2b8f5c605   0.00%               4.77MiB / 11.7GiB    0.04%               956B / 0B           0B / 0B             1

Επιπλέον, αν απλώς κάνω docker-compose build, φαίνεται να λειτουργεί χωρίς προβλήματα, ακόμα και αν το αρχείο docker μου εκτελεί επίσης npm run build. Αυτό με οδηγεί στο να πιστεύω ότι το πρόβλημα είναι με το docker-compose run; Οποιαδήποτε συμβουλή θα ήταν πραγματικά χρήσιμη. Τα dockerfiles μου είναι παρακάτω.

Dockerfile

Base is just light node config with common tools to building
for building npm packages
FROM mhart/alpine-node:12.18.3 AS base

RUN apk add --no-cache gcc python perl-utils g++ make perl-dev tzdata openssh git curl perl-dbd-pg postgresql-client
RUN cpan App::cpanminus
RUN cpanm App::Sqitch --no-wget --notest --quiet
RUN rm -rf /root/.cpan


Build is the base with the installed npm packages
FROM base AS build

ENV TZ UTC

WORKDIR /app
COPY package.json package-lock.json ./

RUN npm ci


test creates the build for testing and can be used later for prod
FROM build AS test

WORKDIR /app

COPY . .

RUN chmod +x scripts/wait-for
RUN chmod +x scripts/restore_databases

THIS WORKS JUST FINE
When I ssh into the container after it gets built, I see the compiled code and can run it
RUN npm run build


dev adds an additional dependencies needed for container management
in our dev environment
FROM test AS dev
RUN apk add netcat-openbsd

WORKDIR /app


release builds from a lighter node image and copies stuff over
from tested build
FROM mhart/alpine-node:slim-12.18.3 AS release

ENV TZ UTC

WORKDIR /app

COPY --from=test /app/node_modules /app/build /app/db_changes ./
docker-compose.yml

version: '3.7'

volumes:
  pgdata:
      external: false
  databases:
      external: false

services:
    api:
      container_name: server
      build: 
        context: .
        target: dev
      env_file:
        - .env
      volumes:
        - ./src:/app/src
        - ./db_changes:/app/db_changes
        - ./db_install/logs:/app/logs
        - ./scripts:/app/scripts
        - ./package.json:/app/package.json
        - ./tsconfig.json:/app/tsconfig.json
        - ./jest.config.js:/app/jest.config.js
      ports:
        - 5000:5000
        - 5001:5001
        - 5002:5002
        - 5003:5003
      command: sh -c "chmod +x ./scripts/wait-for && ./scripts/wait-for db:5432 -- ${COMMAND:-npm run migrate && npm run dev}"

Εκτέλεση: docker-compose run api sh για να μπείτε στο περιβάλλον shell και στη συνέχεια npm run build προκαλεί OOM. Εκτέλεση NODE_OPTIONS="--max-old-space-size=512" npm run build μεταγλωττίζει επιτυχώς.

Docker version 19.03.12, build 48a66213fe
docker-compose version 1.27.2, build 18f557f9
node v12.18.3
typescript Version 3.8.3

Ευχαριστώ!