我有一个nodejs应用程序,我有一个每天备份postgres数据库的例程,使用spawn运行db_dumpall。
问题是如何从容器执行命令到另一个容器。
我尝试过在两个容器中启用ssh,但我不能使用密码或公钥自动连接它们。
NODEJS功能:
const backupDB = (path: string) => {
return new Promise((resolve, reject) => {
const backupProcess = spawn('bash', ['-c', `docker exec ${dbOptions.container} pg_dumpall -U ${dbOptions.user} > ${path}`]);
// THIS WORKS WELL IF I EXECUTE THIS FUNTION OUTSIDE THE CONTAINER
backupProcess.on('exit', (code, signal) => {
resolve(code)
if (code)
console.log('Backup process exited with code ', code);
else if (signal)
console.error('Backup process was killed with singal ', signal);
else
console.log('Successfully backedup the database')
});
backupProcess.on('error', (error) => {
console.log(error)
resolve('Ocurrió un error al hacer el backup de la base de datos')
});
})
};码头工人撰写文件:
nodejs-server:
image: nodejs-server
build:
context: ../backend_apollo_server_express
dockerfile: Dockerfile
ports:
- "4000:4000"
environment:
- PROTOCOL=http://
- HOST=localhost
- PORT=4000
- JWT_SECRET=appsecret321
- JWT_EXPIRESIN=300
- WORKER_POOL_ENABLED=0
- DB_NAME=lims
- DB_USER=lims
- DB_PASSWORD=lims
- CONTAINER_NAME=frontend_postgres_1
- DB_SCHEMA=public
- "DATABASE_URL=postgresql://lims:lims@postgres/lims?schema=public"
depends_on:
- postgres
volumes:
- ../backend_apollo_server_express:/usr/src/app
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
- app-volume:/root/.ssh
postgres:
container_name: db_postgres
command: sh -c "service ssh start && runuser -u postgres postgres"
image: postgresc
build:
context: ../backend_apollo_server_express
dockerfile: Dockerfile.database
environment:
- "POSTGRES_USER=lims"
- "POSTGRES_PASSWORD=lims"
volumes:
- /home/javier/lims/dockerVolumes/db:/var/lib/postgresql/data
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
- app-volume:/usr/src/shared-volume
ports:
- 5434:5432
volumes:
app-volume:编辑13/04/2022:
我正在实施@David方法来解决这个问题,但是我发现了两个问题。
1- pg_dump和pg_dumpall不接受密码作为参数,所以我必须使用.pgpass。问题是psql和pg_dump不需要密码就能正常工作,但是pg_dumpall仍然要求密码,我不知道为什么。
.pgpass:
postgres:5432:lims:lims:lims
// postgres is the docker compose network alias for the container.env
PGPASSFILE=/usr/src/app/db/.pgpass
//Using PGPASSFILE environment variable to pass the .pgpass file2-我需要从nodejs派生进程--我尝试过不同的方法,但总是用代码1接收退出,并且看不到错误消息。
优先逼近
const backupProcess = spawn('pg_dump', [
`-h postgres`,
`-U lims`,
`-d lims`,
`-f ./someFile.sql`
]);第二次逼近
const backupProcess = spawn('pg_dump', ['-c',
`-h postgres -U lims -d lims-f ./someFile.sql`
]);发布于 2022-03-29 00:13:09
一个容器不能在另一个容器中运行命令。同时,大多数关系数据库的设计使您可以通过TCP与它们进行通信;您可以从它的容器之外与数据库进行对话,并且您不需要特定于Docker的技巧来与其对话。
对于您的用例,重要的细节是pg_dumpall接受--host、--port、--username和类似的参数,并尊重标准PostgreSQL环境变量 (如$PGHOST和$PGUSER )。这意味着,如果pg_dumpall与节点应用程序位于同一个映像中,那么您可以使用普通的node来运行它。
在Dockerfile中,您需要安装PostgreSQL命令行工具。默认的node映像基于Debian,因此如下所示
FROM node:16
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends --assume-yes \
postgresql-client
WORKDIR /app
COPY package*.json ./
...当您要运行它时,您只需将pg_dumpall作为子进程运行即可。您不需要docker exec、ssh连接或其他任何东西。请注意,这将在Node容器中运行,但这可能不是问题。
import { open } from 'fs/promises';
import { spawn } from 'child_process';
import { Writable } from 'stream';
const runPgDumpall = async (stream: Writable) => {
const subprocess = spawn('pg_dumpall', [], {
stdio: ['inherit', stream, 'inherit']
});
return new Promise((resolve, reject) => {
subprocess.on('exit', (code, signal) => resolve(code));
subprocess.on('error', err => reject(err));
});
};
const backupDB = async (path: string) => {
const fh = await open(path, 'w');
const stream = fh.createWriteStream();
try {
return await runPgDumpall(stream);
} finally {
stream.end();
}
}最后,在docker-compose.yml文件中,您需要向Node应用程序提供有关如何联系数据库容器的详细信息。您可以使用环境变量传递这些变量。
version: '3.8'
services:
nodejs-server:
build: ../backend_apollo_server_express
environment:
- PGHOST=postgres
- PGUSER=lims
- PGPASSWORD=lims
postgres:
image: 'postgres:13'
environment:
- POSTGRES_USER=lims
- POSTGRES_PASSWORD=lims
volumes:
- /home/javier/lims/dockerVolumes/db:/var/lib/postgresql/data发布于 2022-03-28 18:49:19
你实际上可以,但这是可疑的,因为你应该让一个容器控制其他,意思是,如果受到损害,你可能会有麻烦。
有两种方法可以解决这个问题:1实际上可以,但这是可疑的,因为你应该让一个容器控制其他容器,这意味着如果受到损害,你可能会遇到麻烦。
有两种方法可以解决这个问题:
https://stackoverflow.com/questions/71652058
复制相似问题