6 項目部署 nginx/pm2/docker

課程⽬目標

  • Nginxhtml

    • 靜態資源location
    • 動態數據請求proxy
    • 負載均衡
  • 了了解cluster原理理
  • 掌握pm2部署NodeJS服務

參考⽂文檔

使⽤用pm2+nginx部koa2(https)https://www.zhaofinger.com/de...前端

課程內容

cluster模塊

⽂件上傳服務器器

  • scp (最原始)nginx

    scp docker-compose.yml root@47.98.252.43:/root/source/ #⽂件
    scp -r mini-01 root@47.98.252.43:/root/source/ #⽂件夾
  • git (實際⼯工做中)
  • deploy插件 (debug)

PM2的應⽤

  • 內建負載均衡(使⽤用Node cluster 集羣模塊、⼦子進程,能夠參考樸靈的《深⼊入淺出node.js》⼀一書第九章)
  • 線程守護,keep alive
  • 0秒停機重載,維護升級的時候不不須要停機.
  • 如今 Linux (stable) & MacOSx (stable) & Windows (stable).多平臺⽀支持
  • 停⽌止不不穩定的進程(避免⽆無限循環)
  • 控制檯檢測https://id.keymetrics.io/api/...
  • 提供 HTTP API

配置

npm install -g pm2
pm2 start app.js --watch -i 2
// watch 監聽⽂文件變化
// -i 啓動多少個實例例
pm2 stop all
pm2 list
pm2 start app.js -i max # 根據機器器CPU核數,開啓對應數⽬目的進程,那麼每次都要執行這個命令不是很麻煩?

配置process.yml

apps:
    - script : app.js
    instances: 2
    watch : true
    env :
    NODE_ENV: production
  • 啓動配置git

    pm2 start process.yml
  • Keymetrics在線監控 https://id.keymetrics.io/api/...github

    pm2 link 8hxvp4bfrftvwxn uis7ndy58fvuf7l TARO-SAMPLE
  • pm2設置爲開機啓動web

    pm2 startup

Nginx 反向代理理 + 前端打包Dist

安裝

yum install nginx
-----
apt update
apt install nginx

添加靜態路路由

# /etc/nginx/sites\-enable/taro  
server {  
    listen 80;  
    server\_name taro.josephxia.com;  
    location / {  
        root /root/source/taro\-node/dist;  
        index index.html index.htm;  
    }  
}
# 驗證Nginx配置
nginx -t
# 從新啓動Nginx
service restart nginx

nginx -s reload
\# /etc/nginx/sites\-enable  
\# taro  
server {  
    listen 80;  
    server_name taro.josephxia.com;  
    location / {  
        root /root/source/taro-node/dist;  
        index index.html index.htm;  
    }  
    location ~ \\.(gif|jpg|png)$ {  
        root /root/source/taro-node/server/static;  
    }  
    location /api {  
        proxy\_pass http://127.0.0.1:3000;  
        proxy\_redirect off;  
        proxy\_set\_header Host $host;  
        proxy\_set\_header X\-Real\-IP $remote\_addr;  
        proxy\_set\_header X\-Forwarded\-For $proxy\_add\_x\_forwarded\_for;  
    }  
}
# 查看配置⽂文件位置
nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
#重啓
service nginx restart

Docker

概念

  • 操做系統層⾯面的虛擬化技術
  • 隔離的進程獨⽴立於宿主和其它的隔離的進程 - 容器器
  • GO語⾔言開發

特色

  • ⾼高效的利利⽤用系統資源
  • 快速的啓動時間
  • ⼀一致的運⾏行行環境
  • 持續交付和部署
  • 更更輕鬆的遷移

對⽐比傳統虛擬機總結

特性 容器 虛擬機
啓動 秒級 分鐘級
硬盤使⽤用 通常爲 MB 通常爲 GB
性能 接近原⽣生 弱於
系統⽀支持量量 單機⽀支持上千個容器器 ⼀通常⼏幾⼗十個

三個核⼼心概念

  • 鏡像
  • 容器
  • 倉庫

Docker基本使⽤用

  • 構建⼀一個Nginx服務器器
  1. 拉取官⽅方鏡像mongodb

    # 拉取官⽅方鏡像
    docker pull nginx
    # 查看
    docker images nginx
    # 啓動鏡像
    mkdir www
    echo 'hello docker!!' >> www/index.html
    # 啓動
    # www⽬目錄⾥裏里⾯面放⼀一個index.html
    docker run -p 80:80 -v $PWD/www:/usr/share/nginx/html -d nginx
    # 查看進程
    docker ps
    docker ps -a // 查看所有
    # 僞終端 ff6容器器的uuid
    # -t 選項讓Docker分配⼀一個僞終端(pseudo-tty)並綁定到容器器的標準輸⼊入上,
    # -i 則讓容器器的標準輸⼊入保持打開
    docker exec -it ff6 /bin/bash
    # 停⽌止
    docker stop ff6
    # 刪除鏡像
    docker rm ff6

Dockerfile定製鏡像

#Dockerfile
FROM nginx:latest
RUN echo '<h1>Hello, Kaikeba!</h1>' > /usr/share/nginx/html/index.html
# 定製鏡像
docker build -t mynginx .
# 運⾏行行
# -d 守護態運⾏行行
docker run -p 80:80 -d mynginx

定製⼀一個程序NodeJS鏡像

npm init -y
npm i koa -s
// package.json  
{  
    "name": "myappp",  
    "version": "1.0.0",  
    "main": "app.js",  
    "scripts": {  
        "test": "echo \\"Error: no test specified\\" && exit 1"  },  
    "keywords": \[\],  
    "author": "",  
    "license": "ISC",  
    "description": "myappp",  
    "dependencies": {  
        "koa": "^2.7.0"  
  }  
}
// app.js  
const Koa \= require('koa')  
const app \= new Koa()  
app.use(ctx \=> {  
    Math.random() \> 0.8 ? abc() : ''  
  ctx.body \= 'Hello Docker'  
})  
app.listen(3000, () \=> {  
    console.log('app started at http://localhost:3000/')  
})
#Dockerfile
#制定node鏡像的版本
FROM node:10-alpine
#移動當前⽬目錄下⾯面的⽂文件到app⽬目錄下
ADD . /app/
#進⼊入到app⽬目錄下⾯面,相似cd
WORKDIR /app
#安裝依賴
RUN npm install
#對外暴暴露露的端⼝口
EXPOSE 3000
#程序啓動腳本
CMD ["node", "app.js"]
# 定製鏡像
docker build -t mynode .
# 運⾏行行
docker run -p 3000:3000 -d mynode

Pm2 - 利⽤多核資源

# .dockerignore
node_modules
// process.yml  
{  
    "apps": [{  
    "name": "app-name",  
    "script": "app.js",  
    "instances": 2,  
    "env": {  
        "production": true  
  }  
}\]  
}
# Dockerfile
FROM keymetrics/pm2:latest-alpine
WORKDIR /usr/src/app
ADD . /usr/src/app
RUN npm config set registry https://registry.npm.taobao.org/ && \
npm i
EXPOSE 3000
#pm2在docker中使⽤用命令爲pm2-docker
CMD ["pm2-runtime", "start", "process.yml"]
# 定製鏡像
docker build -t mypm2 .
# 運⾏行行
docker run -p 3000:3000 -d mypm2

Docker-Compose

#docker-compose.yml
app-pm2:
container_name: app-pm2
#構建容器器
build: .
# volumes:
# - .:/usr/src/app
ports:
- "3000:3000"
// 強制從新構建並啓
# --force-recreate 強制重建容器器
# --build 強制編譯
docker-compose up -d --force-recreate --build
#docker-compose.yml
version: '3.1'
services:
    nginx:
        image: nginx:kaikeba
        ports:- 80:80

# 運⾏
docker-compose up
# 後臺運行
docker-compose up -d
部署Mongo + MongoExpress
#docker-compose.yml
version: '3.1'
services:
    mongo:
        image: mongo
        restart: always
        ports:- 27017:27017
    mongo-express:
        image: mongo-express
        restart: always
        ports:- 8081:8081
代碼中添加Mongoose調⽤用
// mongoose.js
const mongoose = require("mongoose");
// 1.鏈接
mongoose.connect("mongodb://mongo:27017/test", { useNewUrlParser: true });
const conn = mongoose.connection;
conn.on("error", () => console.error("鏈接數據庫失敗"));
// app.js
const mongoose = require('mongoose');
mongoose.connect('mongodb://mongo:27017/test', {useNewUrlParser: true});
const Cat = mongoose.model('Cat', { name: String });
Cat.deleteMany({})
const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));

app.use(async ctx => {
    ctx.body = await Cat.find()
})

Github WebHook實現CI持續集成

  • 啓動NodeJS監聽
var http \= require('http')  
var createHandler \= require('github-webhook-handler');  
var handler \= createHandler({path: '/webhooks', secret: 'myHashSecret'})  
  
// 上⾯面的 secret 保持和 GitHub 後臺設置的⼀一致  
function run\_cmd(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)  
    });  
}  
  
http.createServer(function (req, res) {  
    handler(req, res, function (err) {  
        res.statusCode \= 404  
  res.end('no such location')  
    })  
}).listen(3000)  
  
handler.on('error', function (err) {  
    console.error('Error:', err.message)  
})  
  
handler.on('\*', function (event) {  
    console.log('Received \*', event.payload.action);  
// run\_cmd('sh', \['./deploy-dev.sh'\], function(text){  
  console.log(text)  
})  
  
handler.on('push', function (event) {  
    console.log('Received a push event for %s to %s',  
        event.payload.repository.name,  
        event.payload.ref);  
// 分⽀支判斷  
  if (event.payload.ref \=== 'refs/heads/master') {  
        console.log('deploy master..')  
    }  
// run\_cmd('sh', \['./deploy-dev.sh'\], function(text){  
  console.log(text)  
})  
  
handler.on('issues', function (event) {  
    console.log('Received an issue event for % action=%s: #%d %s',  
        event.payload.repository.name,  
        event.payload.action,  
        event.payload.issue.number,  
        event.payload.issue.title)  
})
相關文章
相關標籤/搜索