Ansible部署Node.js

課程指數(shù)

難度指數(shù): 4星(滿星5星)
技術(shù)指數(shù): 5星(滿星5星)
理論指數(shù): 3星(滿星5星)
面向人群: 自動(dòng)化運(yùn)維&初中級(jí)運(yùn)維

分享目錄

1.1 添加額外的源 1
1.2 部署一個(gè)Node.js app 4
1.3 運(yùn)行一個(gè)Node.js app 6
1.4 Node.js app服務(wù)器總結(jié)。 7
1.5 問(wèn)題: 7

下面我們將要在我們的CentOS6.x服務(wù)器上配置Nodejs,啟動(dòng)一個(gè)簡(jiǎn)單的nodejs實(shí)例,這個(gè)服務(wù)器有很簡(jiǎn)單的架構(gòu)。

開(kāi)始了,首先創(chuàng)建一個(gè)playbook文件,我們盡量讓它保持簡(jiǎn)單。

---
- hosts: all
  tasks:

定義一些運(yùn)行這個(gè)playbook的主機(jī),然后下面列出一系列的tasks。

1.1 添加額外的源

在準(zhǔn)備應(yīng)用一個(gè)服務(wù)器的時(shí)候,為了確保指定些軟件包可以用或者在最新的版本,管理員經(jīng)常首先添加額外的源。
下面的腳本,我們想要添加EPEL和Remi源,以便于我們可以得到類似node.js的軟件包。如果使用shell腳本處理的話,如下所示。

 # 導(dǎo)入 Remi GPG 密鑰 – 請(qǐng)參閱: http://rpms.famillecollet.com/RPM-GPG-KEY-remi
wget http://rpms.famillecollet.com/RPM-GPG-KEY-remi \
 -O /etc/pki/rpm-gpg/RPM-GPG-KEY-remi
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-remi
 
# 安裝 Remi repo, Remi repo里面包含了很多的PHP擴(kuò)展
rpm -Uvh --quiet \
http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
 
# 安裝EPEL源
yum install epel-release
 
 # 安裝 Node.js (npm + 和它的依賴關(guān)系).
 yum --enablerepo=epel install npm

這個(gè)shell腳本用于導(dǎo)入EPEL和Remi的GPG keys,然后添加這源,最后安裝Nodejs。這對(duì)于簡(jiǎn)單的部署是沒(méi)有問(wèn)題的,但是運(yùn)行這么多命令是比較笨的方法,如果你的連接不小心斷開(kāi)了,那么你的腳本也會(huì)停止的。而如果這個(gè)時(shí)候,你的腳本剛準(zhǔn)備完成呢?

提示:如果你想跳過(guò)指定的步驟,你可以跳過(guò)添加GPG keys的步驟,只需要在運(yùn)行命令的時(shí)候加上—nogpgcheck.或者在Ansible中,yum模塊中設(shè)置disable_gpg_check參數(shù)為yes,但是最好還是添加GPG keys。使用GPG,你可以知道包的作者是誰(shuí),包有沒(méi)有修改稿,除非你知道你正在做什么,否則最好不要禁止GPG檢查。

Ansible讓事情變的更有健壯性,下面使用Ansible的案例顯得更加詳細(xì),它和上面的shell腳本有同樣的功能,但是更容易理解,更加結(jié)構(gòu)化。 下面使用了Ansible的變量和其它的一些有用的特性。接著上面的playbook,我們繼續(xù)往下寫(xiě)。

  tasks:
   - name: Import Remi GPG key
     rpm_key: "key={{ item }} state=present"
     with_items:
       - "http://rpms.famillecollet.com/RPM-GPG-KEY-remi"
   - name: Install Remi repo.
     command: "rpm -Uvh --force {{ item.href }} creates={{ item.creates }}"
     with_items:
       - href: "http://rpms.famillecollet.com/enterprise/remi-release-6.rpm"
         creates: "/etc/yum.repos.d/remi.repo"

   - name: Install epel repo
    yum: name=epel-release state=present

   - name: Stop the firewall
     service: name=iptables state=stopped
 
   - name: Install NodeJS and npm
     yum: name=npm state=present enablerepo=epel

我們看一下具體步驟。

  1. rpm_key 是一個(gè)的Ansible模塊用于從你的RPM數(shù)據(jù)庫(kù)中添加或移除GPG key。我們正在從Remi的源中導(dǎo)入一個(gè)key。
  2. 因?yàn)锳nsible沒(méi)有rpm命令,因此我們使用command模塊來(lái)使用rpm命令,這樣我們可以做其它的兩件事情。
    a) 使用creatse參數(shù)告訴Ansible什么時(shí)候不運(yùn)行這個(gè)命令,這個(gè)例子里,我們告訴Ansible,這個(gè)命令成功執(zhí)行后,將會(huì)創(chuàng)建那些文件。當(dāng)這個(gè)文件存在的時(shí)候,這個(gè)命令將不會(huì)運(yùn)行。
    b) 使用with_items定義一個(gè)URL和用于creates檢查的文件。
  3. yum負(fù)責(zé)安裝EPEL源。
  4. 因?yàn)檫@個(gè)服務(wù)器我們將用來(lái)做測(cè)試用,所以我們使用service模塊禁止系統(tǒng)防火墻,防止它干涉我們測(cè)試。
  5. yum安裝Node.js(同時(shí)安裝npm,Node’s package manager),我們使用enablerepo來(lái)指定在EPEL源中搜索它,當(dāng)然也可以使用disablerepo來(lái)指定不使用那個(gè)源(repository)。
  6. 因?yàn)镹PM現(xiàn)在被安裝了,我們使用Ansible 的npm模塊安裝Node.JS工具forever,forever來(lái)運(yùn)行我們的app,設(shè)置global為yes,告訴NPM安裝模塊在/usr/lib/node_modules位置,然后所有的用戶都可以使用它了。

我們已經(jīng)有一個(gè)Node.js app 服務(wù)器了,讓我們部署一個(gè)簡(jiǎn)單的Node.js app,在80端口響應(yīng)HTTP請(qǐng)求

1.2 部署一個(gè)Node.js app

這一步是在我們的服務(wù)器上部署簡(jiǎn)單的Node.js app。首先,通過(guò)創(chuàng)建一個(gè)新的文件夾,我們創(chuàng)建一個(gè)簡(jiǎn)單的Node.js app,這個(gè)文件夾和你上面的ymal文件處于相同的路徑下面。然后創(chuàng)建新的文件,app.js,在這個(gè)文件夾里面,編輯下面的文件

//app.js
// 加載express 模塊.
var express = require('express'),
app = express.createServer();
 
// 響應(yīng)”/”請(qǐng)求為 'Hello World'.
app.get('/', function(req, res){
        res.send('Hello World! Yunzhonge');
});
 
// 像一個(gè)真實(shí)服務(wù)器那樣監(jiān)聽(tīng)在80端口
app.listen(80);
console.log('Express server started successfully.')

不要擔(dān)心node.js的語(yǔ)法的和我們的案例。我們需要一個(gè)快速的部署案例,這個(gè)案例可以用Python,Perl,Java,PHP或者其他編程語(yǔ)言來(lái)寫(xiě),但是因?yàn)镹ode是非常簡(jiǎn)單的語(yǔ)言,運(yùn)行一個(gè)簡(jiǎn)單的輕量級(jí)的環(huán)境,它是一個(gè)非常不錯(cuò)的語(yǔ)言來(lái)測(cè)試你的服務(wù)器。

因?yàn)檫@個(gè)小app依賴于Express(一個(gè)簡(jiǎn)單的Node的HTTP框架),我們同樣需要通過(guò)一個(gè)package.json文件告訴NPM關(guān)于它的依賴關(guān)系,這個(gè)文件與app.js處于相同的路徑下面。

{
        "name": "examplenodeapp",
        "description": "Example Express Node.js app.",
        "author": "yunzhonghe",
        "dependencies": {
        "express": "3.x.x"
        },
        "engine": "node >= 0.10.6"
}

然后添加下面內(nèi)容到你的playbook里面,拷貝整個(gè)app到這個(gè)服務(wù)器,然后讓npm下載依賴的東西,(這里為express.)

   - name: Ensure Node.js app folder exists.
     file: "path={{ node_apps_location }} state=directory"
 
   - name: Copy example Node.js app to server.
     copy: "src=app dest={{ node_apps_location }}"
 
   - name: Install app dependencies defined in package.json.
     npm: "path={{ node_apps_location }}/app"
  1. 首先我們使用file模塊確保我們安裝的app目錄存在。{{ node_apps_location }}變量可以在vars部分定義,vars部分位于playbook的頂部。當(dāng)然也可以在inevntory中定義,也可以在運(yùn)行ansible-playbook的時(shí)候定義。
  2. 我們使用Ansible的copy模塊拷貝這整個(gè)app文件夾到測(cè)試服務(wù)器,copy模塊可以聰明的區(qū)分單一的文件和包含文件的目錄,然后在目錄中遞歸,就像rsync或scp。Ansible的copy模塊在單個(gè)文件或少量文件時(shí)候非常好用,但是如果你拷貝大量的文件,嵌套幾層的目錄,copy模塊就不能勝任。這種情形下,如果你想拷貝整個(gè)目錄,你最好考慮使用synchronize模塊,如果你想拷貝一個(gè)歸檔,然后展開(kāi)它,最好使用unarchive模塊。
  3. 第三步,我們使用npm模塊,這次除了app的路徑之外沒(méi)有額外的參數(shù)。這告訴NPM來(lái)解析package.json文件,然后確保所有的依賴關(guān)系都存在。
    已經(jīng)都完成了,最后一步是啟動(dòng)這個(gè)app

1.3 運(yùn)行一個(gè)Node.js app

我們現(xiàn)在使用forever來(lái)啟動(dòng)這個(gè)app。

   - name: Check list of running Node.js apps.
     command: forever list
     register: forever_list
     changed_when: false
 
   - name: Start example Node.js app.
     command: "forever start {{ node_apps_location }}/app/app.js"
     when: "forever_list.stdout.find('{{ node_apps_location }}/app/app.js') == -1"

在這個(gè)play中,我們做了兩件新的事情。

  1. register 創(chuàng)建了一個(gè)新的變量,forever_list,以便于下次task的時(shí)候使用用于判斷是否允運(yùn)行下一個(gè)命令。register用于保存命令的輸出包括標(biāo)準(zhǔn)輸出和錯(cuò)誤輸出,然后賦給變量名。
  2. changed_when告訴Ansible什么時(shí)候這個(gè)play會(huì)導(dǎo)致改變。在這里,forever list命令永遠(yuǎn)都不會(huì)導(dǎo)致服務(wù)器的改變,因?yàn)槲覀冎付薴alse。

第二個(gè)play實(shí)際上使用forever啟動(dòng)了這個(gè)app。我們可以啟動(dòng)這個(gè)app通過(guò)調(diào)用node {{ node_apps_location }}/app/app.js,不過(guò)這種方式更難控制。

Forever跟蹤它管理的Node app,然后我們使用Forever的list選項(xiàng),打印一系列的運(yùn)行app。我們第一次運(yùn)行這個(gè)playbook時(shí)候,這list明顯是空的,但是判斷為空之后就會(huì)運(yùn)行,如果app正在運(yùn)行,我們不會(huì)啟動(dòng)另外一個(gè)實(shí)例了,為了避免這種情形,我們使用when語(yǔ)句,指定,當(dāng)app的路徑不在forever list的輸出信息的時(shí)候,我們啟動(dòng)這個(gè)app。

1.4 Node.js app服務(wù)器總結(jié)。

在這時(shí)候上,你已經(jīng)完成了playbook,然后安裝一個(gè)簡(jiǎn)單的Node.js app,在80端口響應(yīng)HTTP請(qǐng)求。
為了運(yùn)行這個(gè)playbook在一個(gè)服務(wù)器上,使用下面的命令,傳遞node_apps_location變量通過(guò)命令

ansible-playbook --extra-vars="node_apps_location=/usr/local/opt/node"

當(dāng)服務(wù)器完成配置和部署服務(wù)器的時(shí)候,在瀏覽器中指定測(cè)試服務(wù)器的主機(jī)名查看效果

簡(jiǎn)單,但是有效,我們已經(jīng)在少于50行的YMAL文件中配置了一個(gè)Nodejs應(yīng)用服務(wù)器

到此結(jié)束,非常感謝朋友們的關(guān)注。

1.5 問(wèn)題:

問(wèn)題1:當(dāng)我在給100臺(tái)服務(wù)器進(jìn)行nodejs app部署的時(shí)候,到20臺(tái)中斷了,我再重新執(zhí)行,他是一個(gè)怎么個(gè)過(guò)程,前面已經(jīng)安裝的軟件包,進(jìn)行的配置的會(huì)重新的再進(jìn)行執(zhí)行一遍還是跳過(guò)呢?麻煩大牛解答
答:Ansible自身有冪等特性使其能有效保證所有操作的安全可靠性,針對(duì)執(zhí)行失敗的情況會(huì)自動(dòng)在家目錄下生成 對(duì)應(yīng)的錯(cuò)誤服務(wù)器列表 通過(guò) --limit 再次有針對(duì)性的完成剩余工作

問(wèn)題2: 請(qǐng)問(wèn)大俠的nodejs 是通過(guò)工具部署的? npm 好復(fù)雜啊
哈,npm的配置是一次性的,初始配置確認(rèn)比較耗時(shí)且麻煩,yum 或 npm 各有優(yōu)劣,視業(yè)務(wù)而定吧

問(wèn)題3: --extra-vars= 請(qǐng)問(wèn)企業(yè)中應(yīng)用的多嗎?
答:多,最少在我們的工作中一直有應(yīng)用,前幾期的分享大家應(yīng)該也有看到,這個(gè)參數(shù)應(yīng)用的很多。但官網(wǎng)介紹的卻一筆代過(guò)。還是建議大家多用

問(wèn)題4:當(dāng)我通過(guò)ansible執(zhí)行任務(wù)的過(guò)程中,會(huì)出現(xiàn)任務(wù)被長(zhǎng)時(shí)間卡主的原因,這一般需要重哪些地方排查呢
答:
很多朋友遇到這個(gè)問(wèn)題,一直有問(wèn),根據(jù)個(gè)人的經(jīng)驗(yàn)建議如下幾個(gè)方面排查:

  1. 確實(shí)當(dāng)前命令執(zhí)行時(shí)間不長(zhǎng),
  2. pong 檢測(cè)服務(wù)器存活
  3. 有些命令需連接外網(wǎng)下載更新耗時(shí)較長(zhǎng)的可檢查網(wǎng)絡(luò)寬帶情況
  4. -vvv 是非常好的排查方式
  5. 如若卻無(wú)解,/etc/ansible/ansible.cfg 中縮短操作執(zhí)行時(shí)長(zhǎng),等待最終結(jié)束嘗試
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Node.js是目前非常火熱的技術(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    Myselfyan閱讀 4,207評(píng)論 2 58
  • Node.js是目前非?;馃岬募夹g(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,737評(píng)論 2 41
  • 1 Node.js模塊的實(shí)現(xiàn) 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都著...
    zlx_2017閱讀 1,519評(píng)論 0 1
  • 1 Node.js模塊的實(shí)現(xiàn)# 之前在網(wǎng)上查閱了許多介紹Node.js的文章,可惜對(duì)于Node.js的模塊機(jī)制大都...
    七寸知架構(gòu)閱讀 2,164評(píng)論 1 50
  • 逆風(fēng)飛翔的小蕊閱讀 716評(píng)論 0 0

友情鏈接更多精彩內(nèi)容