Search code examples
djangoamazon-web-servicesamazon-elastic-beanstalkamazon-linux-2django-pipeline

How to install Node Packages for an Elastic Beanstalk Python 3.7 Project Running on 64bit Amazon Linux 2?


I am using a Django package named django-pipeline to compress js and css files.

When I deploy my project, I run Django's collectstatic command, from .ebextensions folder:

01_django.config:

container_commands:
    ...
    07_collectstatic:
        command: "source /var/app/venv/*/bin/activate && python3 manage.py collectstatic --noinput"

The problem is, django-pipeline uses compressor libraries that require Node.

I have copied two libraries (cssmin and terser) from my node_modules directory locally to my static directory.

static
|_vendor
|___|.bin
|_____|cssmin
|_____|cssmin.cmd
|_____|terser
|_____|terser.cmd
|___|cssmin
|_____|...
|___|terser
|_____|...

Secondly, I have the following setin on the Pipeline to tell the pipeline where the binaries exist:

PIPELINE_CONFIG.update({
    'CSSMIN_BINARY': os.path.join(BASE_DIR, "static", "vendor", ".bin", "cssmin"),
    'TERSER_BINARY': os.path.join(BASE_DIR, "static", "vendor", ".bin", "terser"),
})

The Error

2021-09-14 05:00:58,513 P4080 [INFO] ============================================================
2021-09-14 05:00:58,513 P4080 [INFO] Command 07_collectstatic
2021-09-14 05:00:59,502 P4080 [INFO] -----------------------Command Output-----------------------
2021-09-14 05:00:59,503 P4080 [INFO]    Traceback (most recent call last):
2021-09-14 05:00:59,503 P4080 [INFO]      File "manage.py", line 21, in <module>
2021-09-14 05:00:59,503 P4080 [INFO]        main()
2021-09-14 05:00:59,503 P4080 [INFO]      File "manage.py", line 17, in main
2021-09-14 05:00:59,503 P4080 [INFO]        execute_from_command_line(sys.argv)
2021-09-14 05:00:59,503 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
2021-09-14 05:00:59,503 P4080 [INFO]        utility.execute()
2021-09-14 05:00:59,503 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/django/core/management/__init__.py", line 413, in execute
2021-09-14 05:00:59,503 P4080 [INFO]        self.fetch_command(subcommand).run_from_argv(self.argv)
2021-09-14 05:00:59,503 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/django/core/management/base.py", line 354, in run_from_argv
2021-09-14 05:00:59,503 P4080 [INFO]        self.execute(*args, **cmd_options)
2021-09-14 05:00:59,503 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/django/core/management/base.py", line 398, in execute
2021-09-14 05:00:59,503 P4080 [INFO]        output = self.handle(*args, **options)
2021-09-14 05:00:59,503 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 187, in handle
2021-09-14 05:00:59,503 P4080 [INFO]        collected = self.collect()
2021-09-14 05:00:59,503 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 128, in collect
2021-09-14 05:00:59,503 P4080 [INFO]        for original_path, processed_path, processed in processor:
2021-09-14 05:00:59,504 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/pipeline/storage.py", line 30, in post_process
2021-09-14 05:00:59,504 P4080 [INFO]        packager.pack_stylesheets(package)
2021-09-14 05:00:59,504 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/pipeline/packager.py", line 98, in pack_stylesheets
2021-09-14 05:00:59,504 P4080 [INFO]        variant=package.variant, **kwargs)
2021-09-14 05:00:59,504 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/pipeline/packager.py", line 116, in pack
2021-09-14 05:00:59,504 P4080 [INFO]        content = compress(paths, **kwargs)
2021-09-14 05:00:59,504 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/pipeline/compressors/__init__.py", line 75, in compress_css
2021-09-14 05:00:59,504 P4080 [INFO]        css = getattr(compressor(verbose=self.verbose), 'compress_css')(css)
2021-09-14 05:00:59,504 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/pipeline/compressors/cssmin.py", line 8, in compress_css
2021-09-14 05:00:59,504 P4080 [INFO]        return self.execute_command(command, css)
2021-09-14 05:00:59,504 P4080 [INFO]      File "/var/app/venv/staging-LQM1lest/lib/python3.7/site-packages/pipeline/compressors/__init__.py", line 250, in execute_command
2021-09-14 05:00:59,504 P4080 [INFO]        raise CompressorError(stderr)
2021-09-14 05:00:59,504 P4080 [INFO]    pipeline.exceptions.CompressorError: b'/var/app/staging/static/vendor/.bin/cssmin: line 12: node: command not found\n'
2021-09-14 05:00:59,504 P4080 [INFO] ------------------------------------------------------------
2021-09-14 05:00:59,504 P4080 [ERROR] Exited with error code 1

My Question

How do I install node within a Python 3.7 Elastic Beanstalk environment so this collectstatic command will work?

Edit #1

I tried:

commands:
  05_install node:
    command: |
      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
      . ~/.nvm/nvm.sh
      nvm install node

It returns the same error:

pipeline.exceptions.CompressorError: b'/var/app/staging/static/vendor/.bin/cssmin: line 12: node: command not found\n'

This is what the cssmin file where the error is coming from looks like:

#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")

case `uname` in
    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac

if [ -x "$basedir/node" ]; then
  "$basedir/node"  "$basedir/../cssmin/bin/cssmin" "$@"
  ret=$?
else 
  node  "$basedir/../cssmin/bin/cssmin" "$@" <----------- line 12
  ret=$?
fi
exit $ret

I have tried prebuild hooks:

#!/bin/bash

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
source /root/.nvm/nvm.sh
nvm install node
export NVM_DIR="/root/.nvm"
node -e "console.log('Running Node.js ' + process.version)"

The result of prebuild hooks, in eb-hooks.log from Elastic Beanstalk:

2021/09/14 15:13:59.896274 [INFO] => nvm is already installed in /root/.nvm, trying to update the script

=> nvm source string already in /root/.bashrc
=> bash_completion source string already in /root/.bashrc
=> You currently have modules installed globally with `npm`. These will no
=> longer be linked to the active version of Node when you install a new node
=> with `nvm`; and they may (depending on how you construct your `$PATH`)
=> override the binaries of modules installed with `nvm`:

/root/.nvm/versions/node/v16.9.1/lib
+-- [email protected]
=> If you wish to uninstall them at a later point (or re-install them under your
=> `nvm` Nodes), you can remove them from the system Node as follows:

     $ nvm use system
     $ npm uninstall -g a_module

=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
Now using node v16.9.1 (npm v7.21.1)
Running Node.js v16.9.1

The output above shows that node installs, but my collectstatic container command still fails with the inability to find node.

After it fails, I can SSH into the instance and see the environment variables for locating nvm exist:

declare -x NVM_BIN="/root/.nvm/versions/node/v16.9.1/bin"
declare -x NVM_CD_FLAGS=""
declare -x NVM_DIR="/root/.nvm"

I got an interesting output when I ran which node in container_commands:

2021-09-14 16:40:46,512 P8087 [INFO]    which: no node in (/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin)
2021-09-14 16:40:46,512 P8087 [INFO] ------------------------------------------------------------
2021-09-14 16:40:46,512 P8087 [ERROR] Exited with error code 1

It seems like node is not on the system path in that moment?


Solution

  • You can use commands and do the following:

    UPDATE:

    commands:
        05_install node:
            command: |
              curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash -
              yum install -y nodejs