feat: support docker swarm deployments

This commit is contained in:
Rainer Killinger
2022-05-09 13:51:14 +02:00
parent ac144095bf
commit 4bb46d8a06
5 changed files with 204 additions and 17 deletions

View File

@@ -30,6 +30,7 @@ process.on('unhandledRejection', async error => {
let containerHashCache = '';
let configHashCache = '';
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
/**
* Reads the container information from the docker socket and updates the nginx config if necessary
@@ -51,6 +52,8 @@ async function updateNginxConfig() {
// if containers changed -> write config file, reload nginx
if (containerHash !== containerHashCache || configHash !== configHashCache) {
Logger.log('Generating new NGINX configuration');
Logger.log('Waiting for Docker network to settle...');
await delay(10_000);
// render nginx config file
const nginxConfig = render(

View File

@@ -32,6 +32,9 @@ import {
/* eslint-disable unicorn/prefer-module */
/* eslint-disable unicorn/no-await-expression-member */
// eslint-disable-next-line @typescript-eslint/no-var-requires
const nodePortScanner = require('node-port-scanner');
/**
* Checks if a ContainerInfo matches a name and version regex
*
@@ -47,8 +50,11 @@ export function containerMatchesRegex(
return (
typeof container.Labels['stapps.version'] === 'string' &&
container.Labels['stapps.version'].match(versionRegex) !== null &&
typeof container.Labels['com.docker.compose.service'] === 'string' &&
container.Labels['com.docker.compose.service'] === name
((typeof container.Labels['com.docker.compose.service'] === 'string' &&
container.Labels['com.docker.compose.service'] === name) ||
(typeof container.Labels['com.docker.stack.namespace'] === 'string' &&
container.Labels['com.docker.swarm.service.name'] ===
`${container.Labels['com.docker.stack.namespace']}_${name}`))
);
}
@@ -62,14 +68,43 @@ export function containerMatchesRegex(
*/
export async function getGatewayOfStAppsBackend(container: Dockerode.ContainerInfo): Promise<string> {
if (container.Ports.length === 0) {
await Logger.error(`Container ${container.Id} does not advertise any port.
await Logger.error(`Container ${container.Names[0]} does not advertise any port.
Please expose a port if the container should be accessible by NGINX.`);
return '';
}
// ip:port
return `${container.Ports[0].IP}:${container.Ports[0].PublicPort}`;
// Basic Docker network
if (typeof container.Ports[0].IP !== 'undefined' && typeof container.Ports[0].PublicPort !== 'undefined') {
// ip:port
return `${container.Ports[0].IP}:${container.Ports[0].PublicPort}`;
}
// Docker Swarm network
if (
typeof container.NetworkSettings?.Networks?.ingress?.IPAddress !== 'undefined' &&
typeof container.Ports[0].PrivatePort !== 'undefined'
) {
const port = container.Ports[0].PrivatePort;
// Get a routable network connection
for (const network in container.NetworkSettings.Networks) {
const scan = await nodePortScanner(container.NetworkSettings.Networks[network].IPAddress, [port]);
if ((scan.ports.open as Array<number>).includes(port)) {
Logger.info(
`${container.Names[0]} reachable via ${container.NetworkSettings.Networks[network].IPAddress}:${port}`,
);
return `${container.NetworkSettings.Networks[network].IPAddress}:${port}`;
}
}
}
await Logger.error(
`Couldn't infer ${container.Names[0]} network reachability. It's possible your current Docker network setup isn't supported yet.`,
);
return '';
}
/**
@@ -91,6 +126,10 @@ export async function generateUpstreamMap(
let foundMatchingContainer = false;
// const backendContainer = containers.filter(container => container.Image.includes('backend'));
// // eslint-disable-next-line no-console
//console.log(JSON.stringify(backendContainer, undefined, 2));
// active versions
result += (
await Promise.all(
@@ -137,7 +176,7 @@ export async function generateUpstreamMap(
}
}
}
await Logger.error('No backend for version', activeVersionRegex, 'found');
Logger.warn('No backend for version', activeVersionRegex, 'found');
return ` \"~${activeVersionRegex}\" unavailable;\n`;
}),
@@ -149,7 +188,7 @@ export async function generateUpstreamMap(
.map(outdatedVersionRegex => {
return ` \"~${outdatedVersionRegex}\" outdated;`;
})
.join('');
.join('\n');
// eslint-disable-next-line prettier/prettier
result += '\n\}';