±à¼ÍƼö: |
±¾ÎÄÖ÷Òª½éÉÜÁ˼¯Öл¯ÅäÖùÜÀí·þÎñ¹¦Äܵ㡢
Ö÷Ҫ˼· ¡¢Ö÷Òª¹¦ÄÜÉè¼ÆºÍʵÏÖ¡¢ ÌṩͳһµÄ¿Í»§¶Ë library¡¢library
Éè¼ÆµÈµÈÏà¹ØÄÚÈÝ¡£
±¾ÎÄÀ´×ÔÓÚÖªºõ£¬ÓÉ»ðÁú¹ûÈí¼þAnna±à¼¡¢ÍƼö¡£ |
|
¹¦Äܵã
Ê×ÏÈ£¬ÎÒÃÇÏÈÕûÀíһϼ¯Öл¯ÅäÖùÜÀíµÄÖ÷Òª feature£º
¿ÉÒԼǼ¡¢ÉóºËÅäÖõÄÐÞ¸Ä
Ö§³Ö¶àÖÖ»·¾³£¨Éú²ú¡¢²âÊÔ¡¢¿ª·¢¡¢ÑÝʾµÈµÈ£©
ÐÞ¸ÄÅäÖÃÖ®ºó£¬Ó¦ÓõÄÅäÖÃÄܹ»¼°Ê±µÃµ½¸üÐÂ
Ö÷Ҫ˼·
ÎÒÃǵÄÖ÷Ҫ˼·ÊÇ£º½«ÅäÖ÷þÎñÖ±½Óд³ÉÒ»¸ö¶ÀÁ¢µÄ webserver£¬webserver ¶ÔÍâÌṩ http
½Ó¿Ú£¬ÅäÖÃÖ±½ÓдÔÚ webserver µÄ´úÂëµ±ÖУ¬Ã¿´ÎÌá½»´úÂëʱͨ¹ý CI/CD ×Ô¶¯·¢²¼¡£
ÕâÑù×öµÄºÃ´¦ÊÇ£º
¿ÉÒÔÖ±½Óͨ¹ý git À´¼Ç¼¡¢ÉóºËÅäÖÃÊý¾ÝµÄÐ޸ģ¬Ã¿´ÎÓÐÈËÒªÐÞ¸ÄÅäÖÃʱ£¬Ö±½ÓÌá PR£¬leader
review ͨ¹ýÖ®ºóºÏ²¢µ½ master ·ÖÖ§
´úÂëºÏ²¢µ½ master ·ÖÖ§Ö®ºó£¬Í¨¹ý CI/CD ×Ô¶¯·¢²¼µ½ÏßÉÏ
¿ÉÄÜ´ó¼Ò»áÓÐÏÂÃæµÄһЩ¹ËÂÇ£º
²»Ó¦¸ÃÖ±½ÓÔÚ´úÂëµ±ÖÐÓ²±àÂë MySQL µÄÕ˺š¢ÃÜÂëÖ®ÀàµÄÃô¸ÐÊý¾Ý£¬ÕâÑùÊDz»°²È«µÄ
¼òµ¥Í¨¹ý http ½Ó¿ÚÀ´¶ÁÈ¡ÅäÖã¬Ð§Âʲ»¸ß
Õë¶ÔµÚÒ»¸öÎÊÌ⣬ÎÒÃÇËãÊÇʹÓÃÁ˵㠡°·´Ä£Ê½¡± °É¡£´úÂë¿Ï¶¨ÊÇҪȷ±£ÔÚ˽ÓдúÂë¿âµ±Öеģ¬ÄãÐèÒªÊÚȨ²ÅÄܹ»·ÃÎÊ´úÂë¿â£¬´ÓÕâ¸ö½Ç¶ÈÀ´Ëµ£¬Ö±½ÓÔÚ´úÂëÀïÃæÐ´ÅäÖÃÊý¾ÝÆäʵҲ²»ÊÇ´óÎÊÌâ£¬ÌØ±ðÊÇÔÚ²úÆ·Ñз¢³õÆÚ£¬Õâ¸öʱºòÍŶӹæÄ£Ò²²»´ó¡£¶øÇÒ£¬Ïñ
gitlab¡¢github ÕâÀàµÄ·þÎñ£¬±¾Éí¾ÍÓкܺõÄȨÏÞ¹ÜÀí»úÖÆ£¬¼ÓÉÏ git ±¾Éí¾ÍÊǰ汾¹ÜÀí¹¤¾ß£¬ÎªÊ²Ã´²»³ä·ÖʹÓÃÒ»ÏÂÄØ¡£
µÚ¶þ¸öÎÊÌâÄØ£¬ÆäʵºÍµÚÒ»¸öÒ»Ñù£º³õÆÚ£¬·þÎñѹÁ¦½ÏС£¬ÅäÖÃÊý¾Ý²»¸´ÔÓ£¬Í¨¹ý http ½Ó¿ÚÀ´¶ÁÈ¡ÅäÖã¬ÐÔÄÜÆäʵûÓдóÎÊÌâ¡£
ÕâÖÖ·½°¸µÄÒâÒå¾ÍÔÚÓÚ°ÑÕâ¸öÅäÖùÜÀíµÄ¿Ó¶ùÏÈÕ¼ÉÏ£¬È·±£¸÷¸ö·þÎñÊÇͨ¹ýͳһµÄ½Ó¿ÚÀ´¶ÁÈ¡ÅäÖõģ¬ÈÕºó¿ÉÒÔÂýÂýÓÅ»¯¡£
ʵ¼ù·¢ÏÖ£¬Ëæ×ŲúÆ·µü´ú£¬ÕâÖÖ·½°¸Äܹ»³ÖÐøµÄʱ¼ä»¹ÊÇͦ³¤µÄ£¬Í¶Èë³É±¾»¹ºÜС¡£
Ö÷Òª¹¦ÄÜÉè¼ÆºÍʵÏÖ
ÎÒÃÇ×Ô¼ºµÄÏîĿʹÓà Node.js ¿ª·¢µÄ£¬ËùÒÔÏÂÃæÒÔ Node.js ΪÀý£¬À´ËµÒ»Ï¾ßÌåÉè¼Æ¡£
Ê×ÏÈ£¬ËµÒ»Ï webserver µÄ½Ó¿ÚÉè¼Æ£¬½Ó¿ÚÒª¾¡¿ÉÄܼò»¯£¬ÎÒÃÇÖ»ÌṩÁËÒ»¸ö½Ó¿Ú£º
GET /api/profiles/:profile HTTP/1.1
profile ²ÎÊý±íʾÄãÏëÒªµÄ»·¾³£¬±ÈÈ磺
ÄãÏëÒª²âÊÔ»·¾³µÄÅäÖã¬Ó¦¸Ã·¢ËÍ GET /api/profiles/dev
Èç¹ûÏëҪͬÊ Jack µÄ±¾µØ¿ª·¢»·¾³ÅäÖã¬ÄãÓ¦¸Ã·¢ËÍ GET /api/profiles/jack-local-dev
·µ»ØµÄÊý¾Ý×ÔȻӦ¸ÃÊÇ json Êý¾Ý£¬±ÈÈçÏñÏÂÃæÕâÖÖ£º
{ "revision":
"5d41402abc4b2a76b9719d911017c592",
"config": { "debug": true,
"wechat": { "appId": "xxxx",
"secret": "xxxxx"
}, "mysql": { "host":
"localhost", "port": 3306
}
}
} |
revision ±íʾÅäÖõİ汾£¬config ¾ÍÊÇʵ¼ÊµÄÅäÖÃÊý¾ÝÀ²¡£
¸ù¾ÝÉÏÃæµÄÉè¼Æ£¬ÎÒÃÇµÄ webserver ·þÎñµÄ´úÂë¿â´ó¸ÅÊÇÏÂÃæÕâÑùµÄ£º
©À©¤©¤ Dockerfile
©À©¤©¤ README.md
©À©¤©¤ app.js
©¸©¤©¤ config
©À©¤©¤ dev.yml
©À©¤©¤ prod.yml
©¸©¤©¤ jack-local-dev.yml |
ÆäÖУº
ÓÐÒ»¸ö app.js £¬ÀïÃæ·â×°ÁË http ½Ó¿Ú
ÓÐÒ»¸ö config Îļþ¼Ð£¬ÀïÃæ·ÅÖò»Í¬»·¾³µÄÅäÖÃÎļþ¡£ÎÒÃÇÍÆ¼öʹÓà .yml Îļþ£¬.yml ÎļþдÆðÅäÖÃÆäʵ¸üÇåˬ£¬µ±È»
json Ò²¿ÉÒÔ
ÔÙÓÐÒ»¸ö Dockerfile ÓÃÓÚÅäÖþµÏñ´ò°üºÍ×Ô¶¯·¢²¼
ʵÏÖÕâÑùÒ»¸ö½Ó¿Ú£¬app.js µÄ´úÂëÒ²±È½Ï¼òµ¥£¬´ó¸Å¾ÍÏñÏÂÃæÕâÑù£º
const fs = require('fs');
const yaml = require('js-yaml');
const hash = require('object-hash');
const express = require('express');
const app = express();
app.get('/api/profiles/:profile', (req, res)
=> {
const path = `${__dirname}/config/$ {req.params.profile}.yml`
fs.readFile(path, {
"ecoding": "utf-8"
}, (e, content) => {
if (e) {
return res.status(500).json({
errorId: 'internal-server-error',
errorMsg: e.message
});
}
const config = yaml.safeLoad(content);
const revision = hash(config);
res.json({
config,
revision
});
});
}); app.get('/ping', (req, res) => res.send('pong')); const PORT = 8080;
app.listen(PORT, () => {
console.log('listening on port', PORT);
}); |
µ±È»ÄãÒ²¿ÉÒÔÔÚÉÏÃæ¼ÓһЩÐÔÄÜÉϵÄÓÅ»¯¹þ£¬ÌرðÊǼÓÔØ yaml ÎļþµÄ²¿·Ö¡£³ýÁ˶ÁÈ¡ yaml ÅäÖÃÎļþµÄÄÚÈÝÍ⣬ÀïÃæ»¹Í¨¹ý
object-hash À´¼ÆËãÁËÅäÖÃµÄ revision£¬·½±ã¿Í»§¶ËÀ´¼ì²éÅäÖÃÊý¾ÝµÄ°æ±¾¸üС£
ÌṩͳһµÄ¿Í»§¶Ë library
Ö÷ÌåÉè¼ÆºÍʵÏÖ¾ÍÊÇÉÏÃæËµµÄÕâЩÄÚÈÝÁË¡£²»¹ý£¬»¹ÓÐÒ»Ï×÷ºÜÖØÒª£¬¾ÍÊÇÌṩͳһµÄ¿Í»§¶Ë library¡£µ±´ó¼ÒʹÓÃͬÑùµÄ¿Í»§¶Ë
library À´¶ÁÈ¡ÅäÖõÄʱºò£¬ÅäÖùÜÀíµÄ¿Ó¶ù²ÅÄÜËãÕæÕýÕ¼ºÃ£¬ºóÃæ²Å·½±ãÌæ»»ÅäÖùÜÀí·þÎñµÄ¼¼Êõ·½°¸¡£
library Éè¼Æ
Ê×ÏÈ˵һÏÂÕâ¸ö library µÄ½Ó¿ÚÉè¼Æ°É
config.get(path)
Ìṩһ¸ö get ·½·¨£¬×¢Ò⣺
²ÎÊýÀïÃæÓ¦¸ÃÊÇÒ»¸ö path£¬×¼È·µÄ˵Ӧ¸ÃÊÇÒ»¸ö property path
Õâ¸ö·½·¨Ó¦¸ÃÊÇ Í¬²½Ö´ÐÐ µÄ£¬ËùÒÔÏÂÃæÎÒÌṩÁËÒ»¸ö sync ·½·¨£¬×¨ÃÅÓÃÀ´Í¬²½ÅäÖÃÊý¾Ý
¼ÙÉèÍêÕûµÄÅäÖÃÊý¾ÝÊÇÕâÑùµÄ£º
{
"mysql": {
"host": "111.111.11.11",
"port": 3306,
"username": "root",
"password": "123456"
},
"redis": {
"host": "111.111.11.12",
"port": 6379
},
"wechat": {
"appId": "wx888888888"
},
"secret": "foobar"
} |
ÄÇôͨ¹ý get ·½·¨Ó¦¸ÃÄܹ»×öµ½ÏÂÃæÕâЩÊÂÇ飺
config.get("mysql")
// => {"host": "111.111.11.11",
"port": 3306, ...} config.get("wechat.appId")
// => "wx888888888" config.get()
// => {"mysql": {...}, "wechat":
{...}, ...} |
Ò²¾ÍÊÇ˵£¬´ó¼Ò¿ÉÒÔͨ¹ý get ·½·¨Áé»îµÄ»ñÈ¡µ½ÅäÖÃÊý¾ÝµÄijһ²¿·Ö¡£Õâ¿éÎÒÃÇʹÓÃÁË object-path
Õâ¸öÄ£¿é¡£
config.sync(host, profile, token)
Ìṩһ¸ö sync ·½·¨£¬ÓÃÀ´³õʼ»°ºÍÂÖѵͬ²½ÅäÖÃÊý¾Ý
config.on(event, listener)
Ó¦¸ÃÌṩʼþ»Øµ÷½Ó¿Ú£¬ÓÃÀ´¼ì²âÊÇ·ñÓÐÊý¾Ý·¢Éú±ä»¯£¬Õâ¸ö½Ó¿ÚÔÚ Node.js ·þÎñÖÐÓÐÒ»¶¨Óô¦£¬ÆäËûµÄͬ²½µÄ¼¼Êõ¿ò¼ÜÓ¦¸Ã¾Í²»ÐèÒªÁË¡£
config.mock(object)
×îºó£¬Ó¦¸ÃÓÐÒ»¸ö mock ·½·¨£¬·½±ãÖ§³Ö×Ô¶¯»¯²âÊÔ
һЩ²¹³äÄÚÈÝ
ÕâÀïÏë²¹³ä˵Ã÷µÄÊÇ£¬¹ØÓÚ sync ·½·¨µÄһЩСÎÊÌâ¡£ÉÏÃæËµµ½ get ·½·¨Ó¦¸ÃÊÇÒ»¸öͬ²½·½·¨£¬±Ï¾¹Èç¹û¶ÁÈ¡ÅäÖÃÐÅÏ¢Ò²ÒªÒì²½µÄ»°£¬ÄǶԹ¤³ÌµÄÀ´Ëµ¸´ÔÓ¶È·´¶øÔö¼ÓÁË¡£
ËùÒÔÎÒ¶àÉè¼ÆÁËÒ»¸ö sync ·½·¨¡£ÔÚ Node.js ÏîÄ¿ÖУ¬Ó¦ÓÃÆô¶¯Ö®Ç°£¬Ó¦¸ÃÏȵ÷Óà sync
·½·¨£¬ÂÖѵͬ²½ÅäÖÃÊý¾Ý¡£ÕâÑù±£Ö¤ get ·½·¨±»µ÷ÓõÄʱºò£¬Ê¼ÖÕÊÇÄܹ»·µ»ØÊý¾ÝµÄ¡£
»¹ÓÐÒ»µã¾ÍÊÇ£¬sync ·½·¨±»µ÷ÓõÄʱºò£¬Ó¦¸ÃÏÈ·¢Ò»¸ö ͬ²½µÄ http ·½·¨À´»ñÈ¡Êý¾Ý£¬Õâ¿éÎÒÃÇʹÓÃÁË
sync-request À´ÊµÏÖ¡£
×îºó£¬²¹³äÒ»ÏÂÖ÷ÒªµÄʵÏÖ´úÂ룬¹©´ó¼Ò²Î¿¼£º
const EventEmitter
= require('events').EventEmitter;
const objectPath = require('object-path'); class Config {
constructor(interval) {
this.interval = interval || 5000;
this.emitter = new EventEmitter();
}
sync(host, profile, token) {
this.host = host;
this.profile = profile;
this.token = token; this.data = loadConfigSync(); // Ê×ÏÈͬ²½»ñÈ¡ÅäÖÃÊý¾Ý
setTimeOut(() => this.watch(), this.interval);
// Ö®ºó£¬¶¨Ê±ÂÖѵÊý¾Ý
}
get(path) {
return objectPath.get(this.data.config, path);
}
loadConfigSync() {
// Õⲿ·Ö´úÂë¾ÍÏÈÊ¡ÂÔÁË~
}
async loadConfigAsync() {
// Õⲿ·Ö´úÂë¾ÍÏÈÊ¡ÂÔÁË~
}
async watch() {
const result = await this.loadConfigAsync();
if (result.revision !== this.data.revision)
{
this.data = result;
this.emitter.emit('update', this.data.config);
}
setTimeout(() => this.watch(), this.interval);
}
} module.exports = new Config(); |
ʹÓÿͻ§¶Ë library µÄÒ»°ãÌ×·£º
// server.js
const config = require('config-module-name'); // 1. µ÷Óà sync ·½·¨¼ÓÔØÅäÖÃ
config.sync(process.env.CONFIG_HOST, process.env.CONFIG_PROFILE,
process.env.CONFIG_TOKEN); // 2. Æô¶¯Êµ¼ÊÏîÄ¿µÄ WebServer
const server = new WebServer();
server.serve(); |
Ôö¼ÓÅäÖø²¸Ç¹¦ÄÜ
ÉÏÃæµÄ webserver Éè¼Æ»¹ÊǼòµ¥ÁËһЩ£¬ÒòΪƽʱÎÒÃÇÅäÖ÷þÎñµÄʱºò£¬¾³£»áÓÐһϵÁÐͨÓõÄÅäÖ㬶øÃ¿¸ö»·¾³ÀïÃæ¿ÉÄܸ÷ÓÐһЩÉÙÁ¿ÌØÊâµÄÅäÖá£
ΪÁ˽â¾öÕâ¸öÎÊÌ⣬ÎÒÃÇÔÚÇ°ÃæµÄ·½°¸»ù´¡Ö®ÉÏ£¬¿ª·¢ÁËÒ»¸ö¼òµ¥µÄÅäÖø²¸Ç¹¦ÄÜ¡£ÎÒÃÇÊÇÕâô×öµÄ£º
ÔÚ config Îļþ¼Ðµ±ÖÐÌṩһ¸ö defaul.yml ÅäÖÃÎļþ£¬ÔÚÕâ¸öÎļþµ±ÖÐÈ¥±£´æÍ¨ÓõÄÅäÖÃÊý¾Ý
¼ÙÉ裬ÏÖÔÚÒª·ÃÎÊ dev »·¾³µÄÅäÖã¬webserver ¾Í°Ñ dev.yml ºÍ default.yml
ÅäÖÃÎļþ¶¼¶ÁÈ¡³öÀ´£¬½« dev.yml ºÍ default.yml ÖØºÏµÄ²¿·Ö merge µ½Ò»Æð£¬Õâ¿éÎÒÃÇʹÓõÄÒ»¸ö½Ð×ö
deepmerge µÄÄ£¿éÀ´ÊµÏÖµÄ
ÏÖÔÚ¾ÙÒ»¸öʵ¼ÊµÄÀý×Ó£¬¼ÙÉèÉú²ú£¨prod£©ºÍ¿ª·¢»·¾³£¨dev£©¾ÍÊý¾Ý¿âµÄÃû³Æ²»Í¬£¬Ã»ÓÐÔö¼ÓÅäÖø²¸Ç¹¦ÄÜ֮ǰ£¬ÅäÖÃÎļþÊÇÕâÑùµÄ£º
# prod.yml
mysql:
host: localhost
port: 3306
username: root
password: root
database: prod # dev.yml
mysql:
host: localhost
port: 3306
username: root
password: root
database: de |
Ôö¼ÓÁËÅäÖø²¸ÇµÄ¹¦ÄÜÖ®ºó£¬ÅäÖÃÎļþ±ä³ÉÁËÏÂÃæÕâ¸öÑù×Ó£º
# default.yml
mysql:
host: localhost
port: 3306
usrename: root
password: root # prod.yml
mysql:
database: prod # dev.yml
mysql:
database: dev |
ÔÚʵ¼ÊµÄÏîÄ¿µ±ÖУ¬Ôö¼ÓÅäÖø²¸ÇµÄÒ»¸ö×î´óºÃ´¦ÊÇ£¬ÓÐеÄͬʼÓÈëÏîĿʱ£¬ËûÐèÒªÔö¼ÓµÄÅäÖÃÄÚÈݾͻáÉٺܶ࣬¶ø²»ÐèҪȫÁ¿µÄ
copy Ò»·Ý±ðÈ˵ÄÅäÖÃÎļþ£¬Ö÷ÌåµÄÅäÖö¼¿ÉÒԷŵ½ default.yml ÎļþÖС£
°²È«ÎÊÌâ
Õâ¸ö·½°¸ÏÖÔÚ»¹ÓÐһЩÃ÷ÏԵݲȫÎÊÌ⣺
½Ó¿Ú·ÃÎÊûÓÐÔö¼Ó¼øÈ¨
ÓÐЩÊý¾Ý¾ÍÊDz»Ï£Íûдµ½´úÂëµ±ÖÐÈ¥£¬¸ÃÔõô°ì
¹ØÓÚ½Ó¿Ú¼øÈ¨£¬ÎÒÃǵĽâ¾ö·½°¸ÊÇÌṩһ¸ö token ÁÐ±í£¬token Êdz£Á¿µÄ UUID »òÕßËæ»ú×Ö·û´®¼´¿É¡£ÁíÍâÇ¿ÖÆÒªÇóʹÓÃ
https À´·ÃÎʽӿڣ¬²»ÒªÖ±½ÓÔÚǰ¶Ë¶ÁÈ¡ÅäÖá£
Èç¹ûÓÐЩÊý¾Ý¾ÍÊDz»Ï£Íûдµ½´úÂëµ±ÖÐÈ¥£¬¸ÄÔõô°ì£¿
ÎÒÃǽ¨ÒéÔö¼ÓÒ»¸ö»·¾³±äÁ¿×¢ÈëµÄ feature£¬±ÈÈçÅäÖÃÎļþ¸Äд³ÉÕâÑù£º
mysql:
password: ${MYSQL_PASSWORD}
|
½Ó¿ÚÔÚ·µ»ØÊý¾Ý֮ǰ£¬Ôö¼ÓÒ»µÀ¹¤Ðò£¬½«ÉÏÃæµÄ ${MYSQL_PASSWORD}
ÕâÀàµÄ±í´ïʽ½âÎö³öÀ´£¬È»ºó½«»·¾³±äÁ¿×¢Èë½øÈ¥¡£ÎÒÃÇĿǰÊÇʹÓÃÕýÔò±í´ïʽ¼òµ¥´Ö±©µÄ´¦ÀíµÄ£¬´ó¸Å¾ÍÊÇÕâÑù£º
const traverse
= require('traverse');
const delimeter = /\$\{(.+?)\}/g; function enjectEnv(config) {
return traverse(config).map(value => {
value.replace(delimeter, (match, p1) => {
return process.env[p1] || "";
})
})
} |
ͨ¹ýÕâÖÖ·½Ê½£¬Äã¾Í¿ÉÒÔͨ¹ý»·¾³±äÁ¿È¥ÅäÖÃһЩÃô¸ÐÐÅÏ¢ÁË¡£
×ܽá
×ܽáһϣ¬ÕâÑùÒ»¸ö·½°¸£¬Ö÷ÒªµÄ¹¤×÷£º
»ùÓÚ git ºÍ CI/CD ´î½¨ÅäÖ÷þÎñ
ÌṩͳһµÄ¿Í»§¶Ë library
À©Õ¹¹¦ÄÜ£¬Ôö¼ÓÅäÖø²¸Ç»úÖÆ
Ìṩ¼òµ¥µÄ½Ó¿Ú¼øÈ¨ºÍ»·¾³±äÁ¿×¢Èë
ÕâÑùÒ»¸ö·½°¸£¬ÆäʵÔÚ²úÆ·³õÆÚ½×¶ÎÓ¦¸Ã×ã¹»ºÃÓÃÁË¡£ÕâÖÖ·½°¸µÄºÃ´¦¾ÍÊÇ¿ìËÙÕ¼¿Ó£¬½«ÅäÖùÜÀí»úÖÆ¹Ì»¯ÏÂÀ´¡£ÕûÌ×·½°¸³ä·ÖʹÓÃÁË
git ºÍ CI/CD£¬Õû¸ö·þÎñÒ²ºÜÇá£¬ÍÆ¼ö´ó¼Ò³¢ÊÔÒ»ÏÂ~ |