首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在码头集装箱之间运行pg_dump或pg_dumpall

如何在码头集装箱之间运行pg_dump或pg_dumpall
EN

Stack Overflow用户
提问于 2022-03-28 18:29:18
回答 2查看 595关注 0票数 0

我有一个nodejs应用程序,我有一个每天备份postgres数据库的例程,使用spawn运行db_dumpall。

问题是如何从容器执行命令到另一个容器。

我尝试过在两个容器中启用ssh,但我不能使用密码或公钥自动连接它们。

NODEJS功能:

代码语言:javascript
复制
    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')
            });
        })
    };

码头工人撰写文件:

代码语言:javascript
复制
  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:

代码语言:javascript
复制
 postgres:5432:lims:lims:lims
 // postgres is the docker compose network alias for the container

.env

代码语言:javascript
复制
PGPASSFILE=/usr/src/app/db/.pgpass 
//Using PGPASSFILE environment variable to pass the .pgpass file

2-我需要从nodejs派生进程--我尝试过不同的方法,但总是用代码1接收退出,并且看不到错误消息。

优先逼近

代码语言:javascript
复制
 const backupProcess = spawn('pg_dump', [
            `-h postgres`,
            `-U lims`,
            `-d lims`,
            `-f ./someFile.sql`
        ]);

第二次逼近

代码语言:javascript
复制
 const backupProcess = spawn('pg_dump', ['-c',
            `-h postgres -U lims -d lims-f ./someFile.sql`
        ]);
EN

回答 2

Stack Overflow用户

发布于 2022-03-29 00:13:09

一个容器不能在另一个容器中运行命令。同时,大多数关系数据库的设计使您可以通过TCP与它们进行通信;您可以从它的容器之外与数据库进行对话,并且您不需要特定于Docker的技巧来与其对话。

对于您的用例,重要的细节是pg_dumpall接受--host--port--username和类似的参数,并尊重标准PostgreSQL环境变量 (如$PGHOST$PGUSER )。这意味着,如果pg_dumpall与节点应用程序位于同一个映像中,那么您可以使用普通的node来运行它。

在Dockerfile中,您需要安装PostgreSQL命令行工具。默认的node映像基于Debian,因此如下所示

代码语言:javascript
复制
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容器中运行,但这可能不是问题。

代码语言:javascript
复制
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应用程序提供有关如何联系数据库容器的详细信息。您可以使用环境变量传递这些变量。

代码语言:javascript
复制
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
票数 1
EN

Stack Overflow用户

发布于 2022-03-28 18:49:19

你实际上可以,但这是可疑的,因为你应该让一个容器控制其他,意思是,如果受到损害,你可能会有麻烦。

有两种方法可以解决这个问题:1实际上可以,但这是可疑的,因为你应该让一个容器控制其他容器,这意味着如果受到损害,你可能会遇到麻烦。

有两种方法可以解决这个问题:

  1. 使用docker从主机上执行停靠器上的命令(例如,使用crontab )
  2. 您可以使用crontab守护进程将这个命令放入一个对接程序中,您只需在这个停靠程序中建立到您的DB的连接即可。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71652058

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档