6

I have an app that I deploy through Gitlab. To deploy it to the production server I use a script in deploy_production. Basically enter via ssh, remove node_modules do a pull, an install and build:

image: node:latest

before_script:
  - apt-get update -qq
  - apt-get install -qq git
  - 'which ssh-agent || ( apt-get install -qq openssh-client )'
  - eval $(ssh-agent -s)
  - ssh-add <(echo "$K8S_SECRET_SSH_PRIVATE_KEY" | base64 -d)
  - mkdir -p ~/.ssh
  - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

stages:
  - install
  - build
  - deploy_production

cache:
  paths:
    - node_modules/

install:
  stage: install
  script:
    - npm install
  artifacts:
    paths:
      - node_modules/


build:
  stage: build
  script:
    - npm build

deploy_production:
  stage: deploy_production
  only:
    - master
  script:
    - ssh example@example.com "export NPM_TOKEN=${NPM_TOKEN} && cd www/myproject && rm -rf node_modules dist/* && git pull && npm ci && npm run prod"

But my problem uses node 11.5, and in the production server there is a node 8 by default. On that server we have installed nvm to trigger the correct node version, but the issue is that the gitlab-ci script is not able to access nvm. No matter what we do, it wont work.

Some options we have tried —without the breaklines—:

- ssh myuser@example.com "cd www/myproject
&& export NPM_TOKEN=${NPM_TOKEN}
&& export NVM_DIR='$HOME/.nvm' && . '$NVM_DIR/nvm.sh' --no-use
&& eval '[ -f .nvmrc ] && nvm install || nvm install stable'
&& nvm use --delete-prefix
&& rm -rf node_modules dist/*
&& git pull && node -v
&& npm ci && npm run prod"

Returns:

Warning: Permanently added 'myserver.com,x.x.x.x' (ECDSA) to the list of known hosts.
bash: /nvm.sh: No such file or directory

Or if I try to install nvm:

- ssh myuser@example.com "cd www/myproject
&& export NPM_TOKEN=${NPM_TOKEN}
&& wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash
&& export NVM_DIR='$HOME/.nvm' && . '$NVM_DIR/nvm.sh' --no-use
&& eval '[ -f .nvmrc ] && nvm install || nvm install stable'
&& nvm use --delete-prefix
&& rm -rf node_modules dist/*
&& git pull
&& node -v
&& npm ci
&& npm run prod"

Returns:

=> nvm is already installed in /home/myuser/.nvm, trying to update using git
=> => Compressing and cleaning up git repository
=> nvm source string already in /home/myuser/.bashrc
=> bash_completion source string already in /home/myuser/.bashrc
nvm is not compatible with the npm config "prefix" option: currently set to "/usr/home/myuser/.nvm/versions/node/v11.5.0"
Run `npm config delete prefix` or `nvm use --delete-prefix v11.5.0 --silent` to unset it.
=> 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
bash: /nvm.sh: No such file or directory

If I check the .bashrc:

- ssh myuser@exmple.com "cat .bashrc"

I get:

[…] lots of stuff
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

And if I do:

- ssh myuser@exmple.com "echo $NVM_DIR"

I get nothing.

So it looks like, even when gitlab-ci is entering the server via ssh, can't see the environment variables. And if I try to save them, they wont be saved.

Does anyone know how to use nvm with ssh in a gitlab-ci script?

Emille C.
  • 562
  • 1
  • 7
  • 23

2 Answers2

2

In my case these lines works:

variables: # variables for dind
  DOCKER_REGISTRY_DOMAIN: "registry.digitalocean.com"
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""
  DOCKER_DRIVER: overlay2

image: docker:latest

services:
  - docker:dind

task:
  image: archlinux:latest # image on arch in this example
  script:
    - pacman -Sy wget --noconfirm # install wget
    - wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.38.0/install.sh | bash #install nvm
    - export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" --no-use #load nvm
    - eval "[ -f .nvmrc ] && nvm install || nvm install 14" #install node
    - node --version
    - npm --version

You can find latest version in repository

https://github.com/nvm-sh/nvm

More about "docker in docker"

https://docs.gitlab.com/ee/ci/docker/using_docker_build.html

Daniel
  • 7,684
  • 7
  • 52
  • 76
1

This is a slight improvement over the above authors handy one which ensures that the nvm installed version is globally accessible without having to remember to source the .bashrc or calling the other nvm source command before each occurrence and is a reusable script template you can use

Credit for that snippet symlink: https://stackoverflow.com/a/40078875/1621381

I just combined the two things and its perfect now.

# Global defaults
variables:
  NODE_VERSION: "16.14.2"

# reusable nvm snippet
.setup-nvm-template: &setup-nvm
- wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 
- export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" --no-use
- eval "[ -f .nvmrc ] && nvm install || nvm install ${NODE_VERSION}"
- node --version
- npm --version
- sudo ln -s "$NVM_DIR/versions/node/$(nvm version)/bin/node" "/usr/local/bin/node"
- sudo ln -s "$NVM_DIR/versions/node/$(nvm version)/bin/npm" "/usr/local/bin/npm"

Then in the pre job or other job you can use via the alias - *setup-nvm

.install-deps-template: &install-deps
  before_script:
  - export TZ=EDT
  - ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
  - export DEBIAN_FRONTEND=noninteractive
  - apt update -qq && apt install -qq -y --no-install-recommends apt-transport-https curl file gcc git
  - export LANG=en_US.UTF-8 ; export LANGUAGE=en_US:en ; export LC_ALL=en_US.UTF-8
  - *setup-nvm

Make it easy to keep using and just pin exact version without alot of effort

Mike R
  • 679
  • 7
  • 13