How to disconnect a log stream when using `ssh://`?
Docker plans to remove the plain TCP / HTTP option so I'm migrating to SSH.
After I got Docker CLI working, I started looking into testcontainers-node, which uses dockerode under the hood. However while it was not complicated to get tests running, I started having dangling TCP issues where it prevented tests from exiting by themselves cleanly (https://github.com/testcontainers/testcontainers-node/issues/999).
I took some heap snapshots when jest hung, and it seems that this was caused by the SSH connection (ssh2 Channel) being held by the http core library internally.
More context can be found in the testcontainers-node issue, but I also managed to write up a minimal reproducer using dockerode directly:
import byline from "byline";
import Docker from "dockerode";
import { readFile } from "fs/promises";
const RYUK_IMAGE = "testcontainers/ryuk:0.11.0";
async function main() {
// This works
// const docker = new Docker({
// host: "foo.lan",
// port: 2375,
// protocol: "http",
// });
// This hangs
const privateKey = await readFile("/path/to/id_ed25519");
const docker = new Docker({
host: "foo.lan",
protocol: "ssh",
username: "docker-ssh",
sshOptions: {
privateKey,
},
});
const container = await docker.createContainer({
Image: RYUK_IMAGE,
name: "test-stream-ryuk",
HostConfig: {
AutoRemove: true,
Binds: ["/var/run/docker.sock:/var/run/docker.sock:rw"],
},
});
await container.start();
container.logs({ follow: true, stdout: true, stderr: true, tail: -1, since: 0 }).then(async (stream) => {
const lineProc = (line) => {
if (line.indexOf("Started") > 0) {
console.log("ryuk started");
stream.destroy();
}
};
byline(stream)
.on("data", lineProc)
.on("err", lineProc);
});
}
main();
Using HTTP (the commented out part), it prints ryuk started and then exits; using SSH, node often hangs after it prints ryuk started. Any idea why stream.destroy() doesn't seem to clean everything up when using SSH? Thank you.