morgangraphics.ansible-role-nvm
Ansible角色:NVM
在Debian/Ubuntu、RHEL/CentOS系统和其他*nix系统上安装NVM和Node.js
Ansible跟SSH和(非)交互式Shell的奇怪组合使得用NVM和Ansible一起工作变得有点困难。可以参考这篇Stack Overflow帖子,了解一些人如何解决这个问题。
其他角色的不足之处
其他安装NVM和/或Node.js的Ansible角色存在一些不足。
他们使用apt-get或yum包管理器来安装Node.js。这通常意味着Node.js包的版本比Node.js仓库中可用的版本要旧。在某些情况下,这些包可能不是LTS版本,如果你需要在同一主机上运行多个Node.js版本,那就麻烦了。
他们通常以
root
用户安装NVM和Node.js(sudo su
或become: true
)。这可能增加与NPM插件管理相关的权限头痛,以及Node与nvm的功能,此外,还存在不必要的权限提升安全风险。你无法运行临时的nvm、npm、node、bash或Shell命令。
此角色与其他角色的不同之处
- 你可以通过wget、curl或git安装NVM。
- 你可以在自己的Ansible任务和剧本中像使用命令行一样使用NVM。
- 你可以安装任何版本或多个版本的Node.js。
- 不以root身份安装NVM或Node.js。
- 可以运行任意nvm、npm、node、bash或Shell命令,这可能消除需要单独的Node Ansible角色的需求。
要求
Ansible版本(ansible-core)2.16.0及以上。
:triangular_flag_on_post: 如果你需要支持较旧版本的Ansible,请参见legacy 1.5.X分支
请参见Ansible版本下文。
安装
- 将该仓库克隆到你的角色文件夹。
- 在你的
ansible.cfg
文件中将roles_path
变量指向角色文件夹,例如roles_path = ../ansible-roles/
。 - 在你的剧本中包含该角色。
:warning: 警告!
请勿以root身份运行此角色!(例如become: true|yes|1
)
原因有几点:
这是一个不必要的权限提升安全风险,你很可能不需要以
root_user
身份运行每个角色中的每个任务。如果出于某种原因,你确实需要以root_user
身份运行所有内容,请重新考虑该角色的功能以及它为什么需要所有内容的root访问权限。此角色在你运行NodeJS的相同上下文/ Shell/会话中安装nvm。你并不以
root
身份运行NodeJS。Ansible会将登录Shell的上下文更改为
root
,nvm将安装在root_user
的主目录中,例如/root/.bashrc
。这意味着如果你的主用户是vagrant、ec2-user、ubuntu等,该角色将无法正常工作!
错误示例 :thumbsdown:
- hosts: all
become: true # 这将以root_user身份运行所有任务,对于所有主机
become_method: sudo # 这将以root_user身份运行所有任务,对于所有主机
roles:
- role: ansible-role-nvm
nodejs_version: "8.16.0"
nvm_commands:
- "nvm exec default npm install"
- role: some-other-role
...
更好的示例 :thumbsup:
- hosts: all
roles:
- role: ansible-role-nvm
nodejs_version: "8.16.0"
nvm_commands:
- "nvm exec default npm install"
- role: some-other-role
...
become: true # 这仅在some-other-role中以root_user身份运行所有任务
become_method: sudo # 这仅在some-other-role中以root_user身份运行所有任务
最佳示例 :metal:
- hosts: all
roles:
- role: ansible-role-nvm
nodejs_version: "8.16.0"
nvm_commands:
- "nvm exec default npm install"
become: true # 这将更改登录上下文以使用下面的用户
become_user: ec2-user # 这将在EC2用户/默认用户的上下文中安装NVM。此用户必须存在于系统中!
- role: some-other-role
...
become: true # 这仅在some-other-role中以root_user身份运行所有任务
become_method: sudo # 这仅在some-other-role中以root_user身份运行所有任务
有关详细信息,请参见问题部分。
示例剧本
超简洁
按原样包含该角色,它将安装最新的LTS版本Node.js。
- hosts: all
roles:
- role: ansible-role-nvm
简单
包含该角色并指定要安装的Node.js的具体版本。
- hosts: all
roles:
- role: ansible-role-nvm
nodejs_version: "8.15.0"
更复杂
此示例展示了如何设置多个环境(开发/生产),每个环境具有不同的选项。生产设置利用nvm_commands
选项安装、构建和运行应用程序。该角色支持并利用Ansible变量语法,例如{{ variable_name }}
。
- hosts: dev
vars_files:
- vars/dev.yml
roles:
- role: ansible-role-nvm
nodejs_version: "{{ config.dev.nodejs.version }}"
- hosts: prod
vars_files:
- vars/prod.yml
roles:
- role: ansible-role-nvm
nvm_install: "curl"
nvm_dir: "/usr/local/nvm"
nvm_commands:
- "nvm install {{ config.prod.client-1.nodejs.version }}"
- "nvm alias default {{ config.prod.client-1.nodejs.version }}"
- "nvm exec default npm install"
- "nvm exec default npm run prod"
在同一主机上安装/运行/维护或升级多个版本的Node.js
默认情况下,Playbook中声明的第一个 Node.js版本将在第一次运行时自动别名为“默认”版本,无论之后安装的版本或运行角色的次数。对于在单台机器上安装多个Node.js版本,明确声明期望的“默认”版本非常重要。
存在两个预先存在的NVM别名default
(当前“活动”的Node.js版本)和system
(基础OS版本的Node.js)。
别名是NVM非常强大的功能,它是推荐的最佳实践来管理你的环境。
多重安装
- hosts: host-1
roles:
# 服务
- role: ansible-role-nvm
nodejs_version: "8.15.0" # <= 这将是Node.js的“默认”版本
# 应用程序
- role: ansible-role-nvm
nodejs_version: "10.15.0"
多重安装带默认
- hosts: host-2
roles:
# 服务
- role: ansible-role-nvm
nodejs_version: "8.15.0"
# 应用程序
- role: ansible-role-nvm
default: true
nodejs_version: "10.15.0" # <= 这现在是Node.js的“默认”版本
关于NVM命令的说明
NVM命令是此角色的一个非常强大的功能,它利用了NVM建立的基础。利用nvm_commands
可能完全消除需要单独的Node角色来管理你的Node应用程序的需求。
nvm run
和nvm exec
命令之间有区别。nvm run
功能上等同于node server.js
或node server
,用于调用JavaScript文件。
nvm exec
在子进程上下文中执行,功能上等同于npm run server
,其中server
是在package.json
文件的scripts部分中的键名称。
{
"name": "my_application",
"version": "0.1.0",
"private": true,
"scripts": {
"preserver": "npm run dbService &",
"server": "nodemon ./bin/www",
"build": "node build/build.js",
"dbService": "nodemon ./data-service/server.js --ignore node_modules/"
},
"dependencies": {
"..."
}
}
或
nvm exec
可以执行一些任意脚本文件,例如nvm exec hello-world.py
。
例如hello-world.py:
#!/usr/bin/env python
print('hello-world')
:warning: 必须包括脚本头,以便其正常工作
或
运行一些任意bash命令。
ls -al >> output.txt
nvm_commands
使得在同一主机上使用不同版本的Node.js设置Node应用程序和Node API层变得非常容易。
- hosts: host-1
roles:
# 服务
# 发生了什么?
# 1. 使用Node版本8.15.0运行服务JavaScript文件
# 警告:此时将其别名为Node.js的默认版本!!
# 因此我们需要明确指定正在使用的版本,因为
# 应用程序部分下面的默认Node.js版本会发生变化
- role: ansible-role-nvm
nodejs_version: "8.15.0"
nvm_commands:
- "nvm exec 8.15.0 npm run services"
# 应用程序
# 发生了什么?
# 1. 将Node.js的默认版本设置为10.15.0版本
# 2. 使用npm安装包依赖
# 3. 将环境设置为生产,运行构建JavaScript文件
# 4. 然后运行生产部署脚本
- role: ansible-role-nvm
nodejs_version: "10.15.0"
nvm_commands:
- "nvm alias webapp {{ nodejs_version }}" # <= 更改默认NVM版本(支持Ansible变量语法)
- "nvm exec webapp npm install" # 安装应用程序依赖
- "NODE_ENV=production nvm run webapp build" # 直接调用Node.js运行生产构建脚本
- "nvm exec webapp npm run prod" # 调用npm运行package.json文件中的生产脚本
另一个示例
- hosts: host-2
roles:
# 服务
# 发生了什么?
# 1. 创建一个版本8.15.0的别名,命名为service-default(支持Ansible变量语法)
# 2. 运行服务脚本
#
# ** 建议你给Node.js版本命名并相应引用 **
- role: ansible-role-nvm
nodejs_version: "8.15.0"
nvm_commands:
- "nvm alias service-default {{ nodejs_version }}" # <= (支持Ansible变量语法)
- "nvm exec service-default npm run services" # 在package.json文件中运行服务脚本
# 应用程序 - 不需要单独的Node.js Ansible角色
# 发生了什么?
# 1. 安装版本10.15.0的Node.js
# 2. 将Node.js的默认版本设置为10.15.0版本
# 3. 运行test.js脚本文件,直接调用Node.js
# 4. 然后运行生产部署bash脚本
- role: ansible-role-nvm
nodejs_version: "10.15.0"
nvm_commands:
- "nvm alias default 10.15.0" # <= 更改默认NVM版本
- "nvm exec default node test.js" # 直接调用Node.js运行测试脚本
- "nvm exec ./deploy.sh" # 运行任意bash脚本
你用来启动应用程序的命令行参数或在package.json文件中声明的命令脚本可以放入此角色的nvm_commands: []
部分中。
- hosts: host1
pre_tasks:
# test-user需要在系统上是一个真实用户,才能在其配置文件中安装nvm
- name: add new user
user:
name: "test-user"
become: true
roles:
- role: ansible-role-nvm
nodejs_version: "8.16.0"
nvm_profile: "/home/test-user/.bashrc"
nvm_commands:
- "whoami"
- "node --version"
- "nvm --version"
- "npm --version"
- "python3 -m hello"
become_user: test-user
become: true
注意事项
默认情况下,Playbook中列出的第一个版本将在第一次运行时自动别名为“默认”版本,无论之后安装的版本或运行角色的次数。第一个输入/安装的版本始终是默认的。 因此,如果你期望在剧本中后面声明的Node.js版本被设置为默认版本,请使用
default: true
或在nvm_commands
列表中明确设置,例如- "nvm alias default <YOUR_VERSION>"
。如果你明确声明了
default: true
作为角色变量以及- "nvm alias default <SOME_OTHER_VERSION>"
作为你的nvm_commands
的一部分,具有default: true
的版本将始终首先执行。这是因为我们需要Node.js在做其他事情之前可用。NVM是无状态的,如果你在一台机器上安装了多个版本的Node.js,你可能需要在脚本中运行
nvm use <VERSION>
来运行你希望/期待的Node.js版本。然而,强烈建议你根据需要命名你的版本并以此方式引用它们。请参见上面的示例。
问题
"nvm: command not found" 错误
这通常是由于在与nvm
和node
用户上下文不同的用户上下文中运行该角色。如果你在剧本中的所有角色上添加become: true
来解决由于权限问题引发的错误,那么该角色将以ROOT_USER
身份安装nvm
(通常在/root/.bashrc
中)。你很可能希望以默认用户,例如vagrant、ec2-user、ubuntu等身份运行nvm和node。 如果出于某种原因,你无法删除所有内容的become: true
,你只需为此角色指定become: true
和 become_user: ec2-user
,就可以解决become: true
问题。有关详细说明,请参见bash: nvm command not found。
"cannot find /usr/bin/python" 错误
这是由于默认运行Python 3的操作系统(例如Fedora)导致的。你需要在清单文件中或通过命令行指定Ansible python解释器变量:
[fedora1]
192.168.0.1 ansible_python_interpreter=/usr/bin/python3
[fedora2]
192.168.0.2
[fedora2:vars]
ansible_python_interpreter=/usr/bin/python3
或
ansible-playbook my-playbook.yml -e "ansible_python_interpreter=/usr/bin/python3"
glibc_2.28' not found (required by node)
你尝试在不支持安装的Node.js版本的操作系统上运行Node.js的一个版本。这不是NVM问题,也不是角色的问题。你需要升级操作系统或降级你试图安装的Node.js版本。
Ansible版本支持
ansible-core 2.16 +
Ansible在管理includes/imports方面发生了根本性变化。Ansible已从ansible-core中删除ansible.builtin.include
并用ansible.builtin.include_tasks
替换。不幸的是,Ansible无法将ansible.builtin.include
作用域设置为忽略旧版本等,因此我将此角色升级到完全支持ansible-core 2.16+。
如果你需要支持ansible-core 2.15及以下版本,请使用ansible-role-nvm-legacy分支。
ansible-core 2.15及以下版本
请使用legacy 1.5.X分支。
角色变量
可用变量列在下面,并附有默认值,请参见defaults/main.yml。
要安装的Node.js版本。最新的"LTS"版本是默认值,适用于大多数受支持的操作系统。
nodejs_version: "lts"
为了在用户手动维护服务器或工作站时安装NVM Bash自动完成(nvm <TAB>
)的便利方法。
autocomplete: false
从头开始安装NVM,删除所有与.nvm
(目录)有关的现有或先前引用,以及所有与系统中的配置文件条目相关的现有或先前引用,例如.bashrc
。
clean_install: false
clean_install: true
会grep查找/home
、/root
、/etc
和自定义安装目录
中的所有文件以查找参考,以及查找系统中的任何.nvm
文件夹。这相当于新机器设置,使用时请谨慎。
default: false
在维护/安装多个Node版本时设置默认Node版本。
NVM会自动将首个运行/安装的版本别名为“default”,这很可能是人们使用此角色的理由,但是这将允许在现有机器上安装/升级多个版本。
要运行的NVM命令列表。默认是空列表。
nvm_commands: []
NVM安装类型。选项包括wget、curl和git。
nvm_install: "wget"
NVM安装目录。
nvm_dir: ""
NVM将默认情况下在用户的主目录中安装
.nvm
目录,例如/home/vagrant/.nvm
。如果你希望将其放置到全局空间(不与特定用户帐户绑定),你可以通过更改此变量,例如将其更改为/opt/nvm
。此变量将尊重Ansible替换变量,例如{{ansible_env.HOME}}
。
NVM配置文件位置选项为.bashrc、.cshrc、.tcshrc、.zshrc。
nvm_profile: ".bashrc"
将从中获取nvm命令的登录SHELL配置文件的位置。需要考虑两个潜在的上下文:
全局,即每个登录用户都将访问nvm(这可能是你真正想要的)
例如
/etc/bash.bashrc
、/etc/profile
等。或
按用户的基础上与特定用户帐户绑定
例如
/home/vagrant/.bashrc
。*如果配置文件不存在,此角色将创建适当的配置文件。
如果你明确指定
nvm_profile: "/home/node-user/.bashrc"
,而node-user不是系统上的真实用户,则nvm将无法如你所预期那样工作。become、become_user和nvm_profile路径是相辅相成的。:warning: 请注意在Ubuntu系统上明确声明.profile或.bash_profile文件的局限性
https://askubuntu.com/a/969923详细说明。
https://kb.iu.edu/d/abdy展示每种Shell类型的选项。
NVM配置文件位置选项有:
BASH: .bashrc
CSH: /etc/csh.cshrc、.cshrc
TSCH: /etc/csh.cshrc、.tcshrc、.cshrc
ZSH: .zshrc
NVM源位置,即你自己托管的NVM的分支。
nvm_source: ""
要安装的NVM版本。
nvm_version: "0.39.7"
卸载NVM,将删除.nvm目录并清理位于{{ nvm_profile }}
变量路径(通常为$HOME/.bashrc)中的文件。
uninstall: False
依赖关系
无。
变更日志
2.0.0 请参见发布说明。
许可
MIT / BSD
作者信息
dm00000来自MORGANGRAPHICS, INC
此角色大量借鉴了Jeff Geerling的Node.js角色,后者是Ansible for DevOps的作者。
NVM installation for Linux
ansible-galaxy install morgangraphics.ansible-role-nvm