First stable version

This commit is contained in:
Juan Ferrer 2020-01-28 14:57:24 +01:00
parent 17acb5582e
commit 4fea7fa1dc
9 changed files with 128 additions and 55 deletions

View File

@ -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"]

View File

@ -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"]
}

14
config.yml Normal file
View File

@ -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

View File

@ -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

View File

@ -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);
}) })
}); });

36
package-lock.json generated
View File

@ -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",

View File

@ -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"
} }
} }

View File

@ -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}}

View File

@ -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"}
} }
] ]
} }