CentOS 7.4 部署nodejs應用

本文以已 CentOS7.4 爲例(Ubuntu 相關命令大同小異)javascript

域名與 ECS 主機選擇

考慮因素:css

  1. 知名大廠商(考慮阿里雲,騰訊雲以及錢包)
  2. 國內(考慮訪問速度和以後的備案)
  3. 購買完成便可拿到公網 IP
  4. 服務器配置

ssh 登陸,鏈接服務器

# 登陸 公網IP
ssh root@110.110.120.114
 # 輸入密碼便可進入
 # 查看目錄
cd /
ls
 # 系統更新
yum update -y
複製代碼

node 安裝

安裝

# 下載源文件
wget https://nodejs.org/dist/v10.14.2/node-v10.14.2-linux-x64.tar.xz
# 解壓
tar xvf node-v10.14.2-linux-x64.tar.xz
# 解壓後刪除下載的源文件
rm -rf node-v10.14.2-linux-x64.tar.xz
# 移動文件位置 /usr/local/lib
mv node-v10.14.2-linux-x64 /usr/local/lib
# 把bin目錄添加到PATH環境中
export PATH=/usr/local/lib/node-v10.14.2-linux-x64/bin:$PATH
# # 建立軟鏈接 全局支持 node
# ln -s /usr/local/lib/node-v10.14.2-linux-x64/bin/node /usr/bin/node
# ln -s /usr/local/lib/node-v10.14.2-linux-x64/bin/npm /usr/bin/npm
# ln -s /usr/local/lib/node-v10.14.2-linux-x64/bin/npx /usr/bin/npx
 # 查看安裝信息,全局可用
node -v
npm -v
npm -v
複製代碼

測試 node 程序

  • 新建app.js
const http = require('http')

http
  .createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'application/json' })
    let data = {
      code: 0,
      msg: 'success'
    }
    res.end(JSON.stringify(data))
  })
  .listen(3001)

console.log('http server is listening at port 3001.')
複製代碼
  • 運行node app.js
{
  "code": 0,
  "msg": "success"
}
複製代碼

pm2 安裝

  1. 如何無縫重啓(故障恢復)
  2. node 進程如何管理
  • 安裝
npm install pm2 -g
 # 建立軟鏈接全局支持pm2
ln -s /usr/local/lib/node-v10.14.2-linux-x64/bin/pm2 /usr/local/bin/pm2
 # [查看 pm2 ls](https://github.com/Unitech/pm2)
pm2 list
複製代碼

pm2 啓動文件配置

  • 生成配置文件pm2 ecosystem
  • 配置文件修改與使用
  • 啓動
    • pm2 start ecosystem.config.js --env develop
  • 部署
    • pm2 deploy ecosystem.config.js --env production

mongodb 安裝

  • 安裝
# 軟件安裝位置:/usr/local/lib/mongodb
# 數據存放位置:/var/mongodb/data
# 日誌存放位置:/var/mongodb/logs
 # 下載
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.2.tgz
# 解壓
tar -zxvf mongodb-linux-x86_64-4.0.2.tgz
# 刪除下載源文件
rm -rf mongodb-linux-x86_64-4.0.2.tgz
# 重命名
mv mongodb-linux-x86_64-4.0.2 mongodb
# 設置環境變量,mongod,mongo命令全局生效
ln -s /usr/local/lib/mongodb/bin/mongo  /usr/local/bin/mongo
ln -s /usr/local/lib/mongodb/bin/mongod  /usr/local/bin/mongod

ln -s /usr/local/lib/mongodb/bin/mongoexport  /usr/local/bin/mongoexport
ln -s /usr/local/lib/mongodb/bin/mongoimport  /usr/local/bin/mongoimport

ln -s /usr/local/lib/mongodb/bin/mongodump  /usr/local/bin/mongodump
ln -s /usr/local/lib/mongodb/bin/mongorestore  /usr/local/bin/mongorestore
 # 建立數據和日誌存放目錄
mkdir /var/mongodb
mkdir /var/mongodb/data
mkdir /var/mongodb/logs
 # 添加配置文件啓動(/usr/local/lib/mongodb/conf/mongodb.conf)
cd /usr/local/lib/mongodb/
mkdir conf
cd conf
vi mongodb.conf
 # 端口號
port=27017
# 數據庫路徑
dbpath=/var/mongodb/data
# 日誌輸出文件路徑
logpath=/var/mongodb/logs/mongodb.log
pidfilepath=/var/mongodb/data/mongo.pid
# 設置後臺運行
fork=true
# 日誌輸出方式(追加)
logappend=true
# auth (添加管理員用戶再解開註釋))
# auth=true
 # 啓動(手動)
mongod -f /usr/local/lib/mongodb/conf/mongodb.conf
 # systemctl 啓動
# 在/lib/systemd/system/目錄下新建mongodb.service文件
cd  /lib/systemd/system/
vi mongodb.service
 # -------------------------------------------------------
[Unit]

Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/usr/local/lib/mongodb/bin/mongod --config /usr/local/lib/mongodb/conf/mongodb.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/usr/local/lib/mongodb/bin/mongod --shutdown --config /usr/local/lib/mongodb/conf/mongodb.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target
# -------------------------------------------------------
 # 設置權限
chmod 754 mongodb.service
 #啓動關閉服務,設置開機啓動
 # 可能會提示執行以下命名,執行便可
systemctl daemon-reload
 #啓動服務
systemctl start mongodb.service
#關閉服務
systemctl stop mongodb.service
#開機啓動
systemctl enable mongodb.service
 # 阿里雲配置安全組,以便客戶端(Robo 3T)鏈接線上服務器
# 修改mongodb.conf
# 遠程訪問地址
bind_ip=0.0.0.0
# 重啓mongdodb(根據本身設置的重啓方式重啓)便可
# 例:
#關閉服務
systemctl stop mongodb.service
#啓動服務
systemctl start mongodb.service
 # 查看mongodb佔用
ps -aef | grep mongo
pstree -p | grep mongo
pstree -p | grep mongod
複製代碼
# admin
db.createUser({ user: "duang", pwd:"2019", roles:[{ role: "userAdminAnyDatabase", db: "admin" }] })
 # 某個數據庫 //讀寫權限
db.createUser({ user: "duang", pwd:"2019", roles:[ { role: "readWrite", db: "card" }] })

複製代碼

mongodb 數據備份導入導出

# 導出
mongodump -h localhost:27017 -d card -o ./dump
 # 導入
mongorestore -h localhost:27017 -d card-test --dir ./dump/card
 # -h 設置服務器地址便可直接導出線上到本地
複製代碼
  • mongoexport, mongoimport
# 導出
mongoexport -d card -c users -o ./users.json
# 導入
mongoimport -d card -c users --file ./users.json
複製代碼

不要把 mongoimport,mongoexport 用於 生產環境的備份node

  • 由於 mongoimport,mongoexport 只是導入導出 JSON 格式數據
  • 沒法支持和保留全部的類型的數據
  • Mongo 內部完整的數據是用 BSON 格式去表示的,而 JSON 只是 BSON 的子集,因此有些數據格式,JSON 沒法表示出來

nginx 安裝、配置、域名綁定

注意阿里雲上須要配置安全組,否則端口沒法使用linux

安裝

# 安裝 nginx 卸載[yum -y remove nginx]
yum -y install nginx
# 啓動nginx
systemctl start nginx.service
# 訪問 默認端口 80
# 45.45.45.169:80
 # 配置 nginx
cd /etc/nginx/conf.d
# server {
# listen 3000; // 服務器地址:3000
# server_name localhost; // localhost 或者 域名
# root /home/html; // 靜態資源文件
# }
 # 如下爲nginx經常使用命令
# 啓動nginx服務
systemctl start nginx.service
# 中止nginx服務
systemctl stop nginx.service
# 重啓nginx服務
systemctl restart nginx.service
# 從新讀取nginx配置(這個最經常使用, 不用中止nginx服務就能使修改的配置生效)
systemctl reload nginx.service
複製代碼
  • 相關啓動命令也可以下
nginx -t   						#測試配置文件是否有語法錯誤
nginx -s reopen					#重啓Nginx
nginx -s reload					 #從新加載Nginx配置文件,而後以優雅的方式重啓Nginx
nginx -s stop  					#強制中止Nginx服務
nginx -s quit  						#優雅地中止Nginx服務(即處理完全部請求後再中止服務)
nginx -c [配置文件路徑]       #爲 Nginx 指定配置文件
複製代碼

配置靜態資源

/etc/nginx/conf.d目錄下建立 nginx 配置nginx

vim card-3000.confgit

server {
  listen  3000;
  server_name localhost;

  location / {
    root /home/card;
    index index.html index.htm;
  }
}
複製代碼

配置接口轉發

vim card-server-3001.conf 訪問api.abc.cn/card都轉發到3001端口github

server {
    listen 80;
    server_name api.abc.cn;

    location /card {
      # 容許跨域
      # add_header 'Access-Control-Allow-Origin' '*';
      # add_header 'Access-Control-Allow-Credentials' 'true';
      # add_header 'Access-Control-Allow-Methods' 'OPTION, POST, GET';
      # add_header 'Access-Control-Allow-Headers' 'X-Requested-With, Content-Type';

      # value for proxy_pass has to match upstream name
      proxy_pass http://127.0.0.1:3001;
      # proxy_redirect off;
    }
}
複製代碼
  • card 配置
server {
    listen 80;
    server_name api.abc.cn;

    location / {
      # 接口服務容許跨域配置
      # 是否容許請求帶有驗證信息
      add_header Access-Control-Allow-Credentials true;
      # 容許跨域訪問的域名,能夠是一個域的列表,空格隔開,也能夠是通配符*(不建議)
      add_header Access-Control-Allow-Origin  http://card.abc.cn;
      # 容許使用的請求方法,以逗號隔開,能夠用 *
      add_header Access-Control-Allow-Methods 'POST,GET,OPTIONS,PUT,DELETE';
      # 預檢命令的緩存,若是不緩存每次會發送兩次請求,單位爲秒。
      # 第一次是瀏覽器使用OPTIONS方法發起一個預檢請求,第二次纔是真正的異步請求
      add_header Access-Control-Max-Age 3600;

      # 容許腳本訪問的返回頭,在koa-cors也作了限制
      add_header Access-Control-Allow-Headers 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With';

      # 容許自定義的頭部,以逗號隔開,大小寫不敏感
      add_header Access-Control-Expose-Headers 'WWW-Authenticate,Server-Authorization';

      if ($request_method = 'OPTIONS') {
        add_header Access-Control-Allow-Origin "*";
        add_header Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS, DELETE";
        add_header Access-Control-Max-Age "3600";
        add_header Access-Control-Allow-Headers "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With";
        add_header Content-Type text/plain;
        return 200;
      }
    }
    location /card {
      # value for proxy_pass has to match upstream name
      proxy_pass http://127.0.0.1:3001;
    }
}
複製代碼
  • 隱藏版本號Response Headers -> Server: nginx/1.16.1web

    vi /etc/nginx/nginx.conf

    server_tokens off;
    複製代碼
  • 參考如下配置

# 開啓gzip 壓縮
gzip on;
# 設置gzip所需的http協議最低版本 (HTTP/1.1, HTTP/1.0)
gzip_http_version 1.1;
# 設置壓縮級別,壓縮級別越高壓縮時間越長 (1-9)
gzip_comp_level 4;
# 設置壓縮的最小字節數, 頁面Content-Length獲取
gzip_min_length 1000;
# 設置壓縮文件的類型 (text/html)
gzip_types text/plain application/javascript text/css;
複製代碼

知識拓展

linux 命令

# 拷貝
cp ./README.md ./copy/
# 拷貝並重命名
cp ./README.md ./copy/README.copy.md
 # 刪除
rm a.html
 # 移動
mv ./README.md ./copy/
# 移動並重命名
mv ./README.md ./copy/README.copy.md
# 重命名
mv ./README.md ./README.new.md
複製代碼

linux tar壓縮與解壓

  • tar
  • 壓縮率對比:xz > bzip2 > gzip
  • ls -lh能夠列出文件大小
參數:

-c :create 創建壓縮檔案的參數;

-x : 解壓縮壓縮檔案的參數;

-z : 是否須要用gzip壓縮;
  z     用於gzip壓縮:      filename.tar.gz
  j     用於bzip壓縮:      filename.tar.bz2
  J     用於xz壓縮:        filename.tar.xz

-v: 壓縮的過程當中顯示檔案;

-f: 置頂文檔名,在f後面當即接文件名,不能再加參數
複製代碼
  • 經常使用命令
# 將全部.jpg的文件打成一個名爲all.tar的包。
# -c是表示產生新的包 ,-f指定包的文件名。
tar -cf all.tar *.jpg
 # 將全部.gif的文件 增長 到all.tar的包裏面去。
# -r是表示增長文件的意思
tar -rf all.tar *.gif
 # 更新原來tar包all.tar中logo.gif文件,
# -u是表示更新文件的意思。
tar -uf all.tar logo.gif
 # 列出all.tar包中全部文件,
# -t是列出文件的意思
tar -tf all.tar
 # 解出all.tar包中全部文件,
# -x是解開的意思
tar -xf all.tar

複製代碼
# 壓縮
# 僅壓縮不打包,將images文件夾所有打包
tar -cvf /home/www/images.tar /home/www/images
# 打包並壓縮[以gzip壓縮方式]],將images文件夾所有打包並壓縮
tar -zcvf /home/www/images.tar.gz /home/www/images
 # 排除文件壓縮
tag -zcvf /home/www/images.tar.gz --exclude=/home/www/images/test /home/www/images
 # 解壓
# 解壓到/home/abc目錄
cd /home/abc
tar -zxvf /home/www/images.tar.gz
 # 解壓到指定目錄
tar -zxvf /home/www/images.tar.gz -C /home/abc

複製代碼

scp本地文件上傳服務器

上傳方式:

  1. 命令行上傳
  2. 客戶端軟件上傳
  3. git 同步
# 上傳-到指定目錄
scp ./card-server.tar.gz root@109.99.98.88:/home/card-server
 # 下載-到指定目錄
scp root@109.99.98.88:/home/card/card-server.tar.gz ./
複製代碼

shell 腳本編寫

數據庫備份

  • 定時任務,本地備份完同步到七牛雲存儲(nodejs 與 shell)
    • shell 執行打包壓縮
    • nodejs 調用
    • nodejs 實現上傳到七牛雲存儲
  • shell腳本 or node版本的shelljs庫
    • shell 執行 nodejs(或 nodejs 執行 shell)
  • crontab -e 定時任務(或 node-schedule 定時執行)
    # 定時備份:使用日期date+"%m-%d-%y" => 放在目錄/var/backups/01-20-16/中
    3 3 * * * mongodump --out /var/backups/mongobackups/`date +"%m-%d-%y"`;
    # 定時刪除:
    3 1 * * * find /var/backups/mongobackups/ -mtime +7 -exec rm -rf {} \;
    複製代碼
  • 具體實現方案以下

自動化部署,持續集成

webhook(gitee,github)

  • 資料參考

  • 同一服務多個 webhook

  • gitee-webhook-handler.js

    var http = require('http')
    var createHandler = require('gitee-webhook-handler')
    var handler = createHandler({ path: '/webhook', secret: '123456' })
    
    http
      .createServer(function(req, res) {
        handler(req, res, function(err) {
          res.statusCode = 404
          res.end('no such location')
        })
      })
      .listen(3200)
    
    handler.on('error', function(err) {
      console.error('Error:', err.message)
    })
    
    handler.on('Push Hook', function(event) {
      console.log(
        'Received a push event for %s to %s',
        event.payload.repository.name,
        event.payload.ref
      )
    })
    
    handler.on('Issue Hook', function(event) {
      console.log(
        'Received an issue event for %s action=%s: #%d %s',
        event.payload.repository.name,
        event.payload.action,
        event.payload.issue.number,
        event.payload.issue.title
      )
    })
    複製代碼
  • 一個服務,多個 webhook

    var http = require('http')
    var createHandler = require('node-github-webhook')
    var handler = createHandler([
      // 多個倉庫
      {
        path: '/app1',
        secret: 'CUSTOM'
      },
      {
        path: '/app2',
        secret: 'CUSTOM'
      }
    ])
    // var handler = createHandler({ path: '/webhook1', secret: 'secret1' }) // 單個倉庫
    
    http
      .createServer(function(req, res) {
        handler(req, res, function(err) {
          res.statusCode = 404
          res.end('no such location')
        })
      })
      .listen(7777)
    
    handler.on('error', function(err) {
      console.error('Error:', err.message)
    })
    
    handler.on('push', function(event) {
      console.log(
        'Received a push event for %s to %s',
        event.payload.repository.name,
        event.payload.ref
      )
      switch (event.path) {
        case '/app1':
          runCmd(
            'sh',
            ['./app1_deploy.sh', event.payload.repository.name],
            function(text) {
              console.log(text)
            }
          )
          break
        case '/app2':
          runCmd(
            'sh',
            ['./app2_deploy.sh', event.payload.repository.name],
            function(text) {
              console.log(text)
            }
          )
          break
        default:
          // 處理其餘
          break
      }
    })
    
    function runCmd(cmd, args, callback) {
      var spawn = require('child_process').spawn
      var child = spawn(cmd, args)
      var resp = ''
      child.stdout.on('data', function(buffer) {
        resp += buffer.toString()
      })
      child.stdout.on('end', function() {
        callback(resp)
      })
    }
    複製代碼
  • node 執行 shell 命令

    const { exec } = require('child_process')
    exec(`rm ./abc.tar.gzp`, err => {
      if (err) {
        return console.log(err)
      }
      console.log('ok???')
    })
    複製代碼

持續集成Travis_Ci

docker

SSL 證書

SSL 安裝-踩坑之旅

備案

推薦阿里雲手機端,備案較爲方便

參考資料

相關文章
相關標籤/搜索