First stable version
This commit is contained in:
parent
17acb5582e
commit
4fea7fa1dc
|
@ -19,6 +19,6 @@ WORKDIR /docker-discover
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
RUN npm install --only=prod
|
RUN npm install --only=prod
|
||||||
|
|
||||||
COPY index.js config.json rproxy.handlebars ./
|
COPY index.js config.yml rproxy.handlebars ./
|
||||||
|
|
||||||
CMD ["pm2-runtime", "index.js"]
|
CMD ["pm2-runtime", "index.js"]
|
||||||
|
|
18
config.json
18
config.json
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"docker": {
|
|
||||||
"socketPath": "/var/run/docker.sock"
|
|
||||||
},
|
|
||||||
"rproxies": [
|
|
||||||
"rproxy1.local",
|
|
||||||
"rproxy2.local"
|
|
||||||
],
|
|
||||||
"sshAuth": {
|
|
||||||
"username": "root",
|
|
||||||
"privateKey": "/root/.ssh/id_rsa"
|
|
||||||
},
|
|
||||||
"proxyConf": "/etc/haproxy/haproxy.cfg",
|
|
||||||
"reloadCmd": "service haproxy reload",
|
|
||||||
"delay": 4,
|
|
||||||
"debug": false,
|
|
||||||
"events": ["service", "node"]
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
delay: 4
|
||||||
|
debug: true
|
||||||
|
events: [service, node]
|
||||||
|
docker:
|
||||||
|
socketPath: /var/run/docker.sock
|
||||||
|
rproxy:
|
||||||
|
hosts:
|
||||||
|
- rproxy1.local
|
||||||
|
- rproxy2.local
|
||||||
|
auth:
|
||||||
|
username: root,
|
||||||
|
privateKey: /root/.ssh/id_rsa
|
||||||
|
confPath: /etc/haproxy/haproxy.cfg
|
||||||
|
reloadCmd: service haproxy reload
|
|
@ -1,15 +1,15 @@
|
||||||
version: '3.7'
|
version: '3.7'
|
||||||
services:
|
services:
|
||||||
discover:
|
main:
|
||||||
image: registry.verdnatura.es/docker-discover
|
image: registry.verdnatura.es/docker-discover
|
||||||
build: .
|
build: .
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
NODE_ENV: production
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
configs:
|
configs:
|
||||||
- source: config
|
- source: config
|
||||||
target: /docker-discover/config.json
|
target: /docker-discover/config.yml
|
||||||
- source: template
|
- source: template
|
||||||
target: /docker-discover/rproxy.handlebars
|
target: /docker-discover/rproxy.handlebars
|
||||||
- source: ssh
|
- source: ssh
|
||||||
|
|
63
index.js
63
index.js
|
@ -1,30 +1,60 @@
|
||||||
|
require('require-yaml');
|
||||||
let Docker = require('dockerode');
|
let Docker = require('dockerode');
|
||||||
let handlebars = require('handlebars');
|
let handlebars = require('handlebars');
|
||||||
let ssh = require('node-ssh');
|
let ssh = require('node-ssh');
|
||||||
let fs = require('fs');
|
let fs = require('fs');
|
||||||
let conf = require('./config.json');
|
let conf = require('./config.yml');
|
||||||
|
|
||||||
let docker;
|
let docker;
|
||||||
let template;
|
let template;
|
||||||
|
let isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
async function updateProxy() {
|
async function updateProxy() {
|
||||||
console.log('Updating proxy configuration.');
|
console.log('Updating reverse proxy configuration.');
|
||||||
let data;
|
let info;
|
||||||
|
|
||||||
if (process.env.NODE_ENV != 'production') {
|
if (!isProduction) {
|
||||||
data = require('./test.json');
|
info = require('./test.json');
|
||||||
} else {
|
} else {
|
||||||
data = {
|
info = {
|
||||||
services: await docker.listServices(),
|
services: await docker.listServices(),
|
||||||
nodes: await docker.listNodes()
|
nodes: await docker.listNodes()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let services = [];
|
||||||
|
for (let serviceInfo of info.services) {
|
||||||
|
let ports = serviceInfo.Endpoint.Ports;
|
||||||
|
if (!Array.isArray(ports) || !ports.length) continue;
|
||||||
|
|
||||||
|
let name = serviceInfo.Spec.Name;
|
||||||
|
let match = name.match(/(.+)_main$/);
|
||||||
|
if (match) name = match[1];
|
||||||
|
|
||||||
|
let service = {
|
||||||
|
name,
|
||||||
|
port: ports[0].PublishedPort,
|
||||||
|
nodes: []
|
||||||
|
};
|
||||||
|
services.push(service);
|
||||||
|
|
||||||
|
for (let node of info.nodes) {
|
||||||
|
let address = node.ManagerStatus
|
||||||
|
? node.ManagerStatus.Addr.split(':')[0]
|
||||||
|
: node.Status.Addr;
|
||||||
|
|
||||||
|
service.nodes.push({
|
||||||
|
name: node.Description.Hostname,
|
||||||
|
endpoint: `${address}:${service.port}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let tmpConf = `/tmp/rproxy.${new Date().getTime()}`;
|
let tmpConf = `/tmp/rproxy.${new Date().getTime()}`;
|
||||||
let configString = template(data);
|
let configString = template({info, services});
|
||||||
fs.writeFileSync(tmpConf, configString);
|
fs.writeFileSync(tmpConf, configString);
|
||||||
|
|
||||||
if (conf.debug || process.env.NODE_ENV != 'production') {
|
if (conf.debug || !isProduction) {
|
||||||
let delimiter = '#'.repeat(80);
|
let delimiter = '#'.repeat(80);
|
||||||
console.log(delimiter);
|
console.log(delimiter);
|
||||||
console.log(configString);
|
console.log(configString);
|
||||||
|
@ -33,15 +63,18 @@ async function updateProxy() {
|
||||||
|
|
||||||
let files = {
|
let files = {
|
||||||
local: tmpConf,
|
local: tmpConf,
|
||||||
remote: conf.proxyConf
|
remote: conf.rproxy.confPath
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let host of conf.rproxies) {
|
for (let host of conf.rproxy.hosts) {
|
||||||
console.log(`Updating host: ${host}`);
|
console.log(`Updating host: ${host}`);
|
||||||
|
if (!isProduction) continue;
|
||||||
|
|
||||||
let sshClient = new ssh();
|
let sshClient = new ssh();
|
||||||
await sshClient.connect(Object.assign({host}, conf.sshAuth));
|
await sshClient.connect(Object.assign({host}, conf.rproxy.auth));
|
||||||
await sshClient.putFiles([files]);
|
await sshClient.putFiles([files]);
|
||||||
//await ssh.exec(conf.reloadCmd);
|
if (conf.rproxy.reloadCmd)
|
||||||
|
await ssh.exec(conf.rproxy.reloadCmd);
|
||||||
await sshClient.dispose();
|
await sshClient.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +86,7 @@ async function updateProxy() {
|
||||||
let timeoutId;
|
let timeoutId;
|
||||||
docker = new Docker(conf.docker);
|
docker = new Docker(conf.docker);
|
||||||
template = handlebars.compile(fs.readFileSync('rproxy.handlebars', 'utf8'));
|
template = handlebars.compile(fs.readFileSync('rproxy.handlebars', 'utf8'));
|
||||||
updateProxy();
|
await updateProxy();
|
||||||
|
|
||||||
console.log('Listenig for events.')
|
console.log('Listenig for events.')
|
||||||
docker.getEvents({}, (err, stream) => {
|
docker.getEvents({}, (err, stream) => {
|
||||||
|
@ -68,9 +101,9 @@ async function updateProxy() {
|
||||||
console.log(`Event: ${event.Type}: ${event.Action}`);
|
console.log(`Event: ${event.Type}: ${event.Action}`);
|
||||||
|
|
||||||
if (timeoutId) return;
|
if (timeoutId) return;
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(async () => {
|
||||||
timeoutId = null;
|
timeoutId = null;
|
||||||
updateProxy();
|
await updateProxy();
|
||||||
}, conf.delay * 1000);
|
}, conf.delay * 1000);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"name": "docker-discover",
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -20,6 +21,14 @@
|
||||||
"indent-string": "^4.0.0"
|
"indent-string": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"argparse": {
|
||||||
|
"version": "1.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||||
|
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||||
|
"requires": {
|
||||||
|
"sprintf-js": "~1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"asn1": {
|
"asn1": {
|
||||||
"version": "0.2.4",
|
"version": "0.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||||
|
@ -137,6 +146,11 @@
|
||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"esprima": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||||
|
},
|
||||||
"fs-constants": {
|
"fs-constants": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
|
@ -168,6 +182,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
},
|
},
|
||||||
|
"js-yaml": {
|
||||||
|
"version": "3.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||||
|
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||||
|
"requires": {
|
||||||
|
"argparse": "^1.0.7",
|
||||||
|
"esprima": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"jsonparse": {
|
"jsonparse": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
|
||||||
|
@ -252,6 +275,14 @@
|
||||||
"util-deprecate": "^1.0.1"
|
"util-deprecate": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"require-yaml": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-LhsY2RPDuqcqWk03O28Tjd0sMr0=",
|
||||||
|
"requires": {
|
||||||
|
"js-yaml": "^3.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
|
||||||
|
@ -298,6 +329,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
||||||
"integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY="
|
"integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY="
|
||||||
},
|
},
|
||||||
|
"sprintf-js": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||||
|
},
|
||||||
"ssh2": {
|
"ssh2": {
|
||||||
"version": "0.8.7",
|
"version": "0.8.7",
|
||||||
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.7.tgz",
|
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.7.tgz",
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitea.verdnatura.es/verdnatura/docker-discover"
|
"url": "https://gitea.verdnatura.es/verdnatura/docker-discover"
|
||||||
},
|
},
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dockerode": "^3.0.2",
|
"dockerode": "^3.0.2",
|
||||||
"handlebars": "^4.7.2",
|
"handlebars": "^4.7.2",
|
||||||
"node-ssh": "^7.0.0"
|
"node-ssh": "^7.0.0",
|
||||||
|
"require-yaml": "0.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
# Auto-generated backends
|
# Auto-generated backends
|
||||||
|
|
||||||
{{#each services}}
|
{{#each services}}
|
||||||
{{#if Endpoint.Ports.[0]}}
|
backend {{name}}
|
||||||
backend {{Spec.Name}}
|
{{#each nodes}}
|
||||||
{{#each ../nodes}}
|
server {{name}}({{endpoint}}) {{endpoint}} check
|
||||||
server {{Description.Hostname}}({{Status.Addr}}):{{../Endpoint.Ports.[0].PublishedPort}} {{Status.Addr}}:{{../Endpoint.Ports.[0].PublishedPort}} check
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
30
test.json
30
test.json
|
@ -1,33 +1,43 @@
|
||||||
{
|
{
|
||||||
"services": [
|
"services": [
|
||||||
{
|
{
|
||||||
"Spec": {"Name": "service1"},
|
"Spec": {"Name": "foo"},
|
||||||
"Endpoint": {
|
"Endpoint": {
|
||||||
"Ports": [
|
"Ports": [
|
||||||
{"PublishedPort": 10001}
|
{"PublishedPort": 10001}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"Spec": {"Name": "service2"},
|
"Spec": {"Name": "bar_main"},
|
||||||
"Endpoint": {
|
|
||||||
"Ports": []
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"Spec": {"Name": "service3"},
|
|
||||||
"Endpoint": {
|
"Endpoint": {
|
||||||
"Ports": [
|
"Ports": [
|
||||||
{"PublishedPort": 10003}
|
{"PublishedPort": 10003}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
"Spec": {"Name": "bar_foo"},
|
||||||
|
"Endpoint": {
|
||||||
|
"Ports": [
|
||||||
|
{"PublishedPort": 10003}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"Spec": {"Name": "baz"},
|
||||||
|
"Endpoint": {}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"Description": {"Hostname": "node1"},
|
"Description": {"Hostname": "fooNode"},
|
||||||
"Status": {"Addr": "10.0.0.1"}
|
"ManagerStatus": {"Addr": "10.0.0.1:2377"},
|
||||||
|
"Status": {"Addr": "0.0.0.0"}
|
||||||
}, {
|
}, {
|
||||||
"Description": {"Hostname": "node2"},
|
"Description": {"Hostname": "barNode"},
|
||||||
|
"ManagerStatus": {"Addr": "10.0.0.2:2377"},
|
||||||
"Status": {"Addr": "10.0.0.2"}
|
"Status": {"Addr": "10.0.0.2"}
|
||||||
|
}, {
|
||||||
|
"Description": {"Hostname": "bazNode"},
|
||||||
|
"Status": {"Addr": "10.0.0.3"}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Reference in New Issue