使用 Symfony 在 Docker 容器中恢复 PostgreSQL 数据库时出现问题

问题描述 投票:0回答:1

我正在开发一个 Symfony 应用程序来备份和恢复数据库。我的应用程序在 Symfony 服务器上运行良好,但在尝试将它与我的 dockerized 设置一起使用时遇到问题。

背景:

我有两个 PostgreSQL 数据库:主数据库名为“potter”,备份数据库名为“backup”。我可以成功创建这些数据库的转储并将 SQL 文件存储在我的 Apache-PHP 容器中,位置为

/var/www/var/dump/

当我尝试将主数据库恢复到备份时,只有当我在项目终端中执行以下命令时,它才能完美运行:

docker exec -it safebase-backup-1 psql -U user -d backup -f /var/www/var/dump/potter_dump_02-10-2024_14-05-08.sql

但是,当我在另一个上下文中(例如,从我的应用程序)运行相同的命令时,我收到以下错误:

命令“'docker''exec''-i''safebase-backup-1''psql''-U''用户''-d''备份''-f''/var/www/var/转储/potter_dump_02-10-2024_14-05-08.sql'”失败。工作目录:/var/www/public 错误:proc_open(): posix_spawn() 失败:没有这样的文件或目录。

问题:

  1. 为什么该命令在终端中有效,但从我的应用程序执行时失败?

     docker exec -it safebase-backup-1 psql -U user -d backup -f /var/www/var/dump/potter_dump_02-10-2024_14-05-08.sql
    
  2. 如何解决“proc_open(): posix_spawn() failed”错误?

任何帮助或建议将不胜感激!

谢谢!

我的代码:

恢复服务:

<?php
namespace App\Service;

use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class RestoreService
{
    public function restoreDatabase(string $fileName, string $databaseName): bool
    {
        $targetContainer = $this->getTargetContainer($databaseName);

        $restoreCommand = [
            'docker', 'exec', '-i', $targetContainer, 'psql', '-U', 'user', '-d', $databaseName, '-f', "/var/www/var/dump/$fileName"
        ];
        $this->executeProcess($restoreCommand);

        return true;
    }

    private function getTargetContainer(string $databaseName): string
    {
        switch ($databaseName) {
            case 'potter':
                return "safebase-database-1";
            case 'backup':
                return "safebase-backup-1";
            default:
                throw new \InvalidArgumentException("Database unknown : $databaseName");
        }
    }


    private function executeProcess(array $command): void
    {
        $process = new Process($command);
        $process->run();

        if (!$process->isSuccessful()) {
            throw new ProcessFailedException($process);
        }
    }
}

我的控制器:

 #[Route('/backlog/restore/{id}', name: 'app_backup_restore')]
    public function restoreForm(BackupLog $backupLog, ManagerRegistry $doctrine, Request $request): Response
    {
        $filePath = $backupLog->getFilePath();

        if (!file_exists($filePath)) {
            $this->addFlash('error', 'Le fichier de sauvegarde n\'existe pas.');
            return $this->redirectToRoute('app_backups');
        }

        $databases = ['potter', 'backup'];
        $form = $this->createForm(RestoreDatabaseType::class, null, ['databases' => $databases]);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $data = $form->getData();
            $databaseName = $data['database'];

            try {
                // Passer uniquement le nom du fichier à la méthode de restauration
                $this->restoreService->restoreDatabase(basename($filePath), $databaseName);
                $this->addFlash('success', 'La base de données a été restaurée avec succès.');
            } catch (\Exception $e) {
                $this->addFlash('error', 'Erreur lors de la restauration : ' . $e->getMessage());
            }

            return $this->redirectToRoute('app_backups');
        }

        return $this->render('backlog/restore.html.twig', [
            'form' => $form->createView(),
            'backupLog' => $backupLog,
        ]);
    }
postgresql docker symfony database-backups back
1个回答
0
投票

请勿将

docker exec
用于常规数据库操作。 这是不必要的,并且为调用者提供了对整个系统不受限制的根级别访问权限。

如果您只是尝试运行

psql
命令来恢复数据,那么我会完全删除子进程调用。 转储文件包含一系列重建数据库的 SQL 命令,您可以像运行任何其他 SQL 命令一样执行这些命令。 使用您的应用程序框架创建普通的数据库连接,读取转储文件的内容,并通过数据库连接执行它们。

如果你确实需要使用

psql
,那么我会直接在容器中运行它,而不是通过
docker exec
。 您需要确保它已安装在您的 Dockerfile 中

RUN apt-get update \
 && DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql-client

然后当您调用它时,通过

psql -h
(作为主机名)传递数据库容器名称,而不带
docker exec

$restoreCommand = [
  'psql', '-h', $targetContainer, '-U', 'user', '-d', $databaseName, '-f', "/var/www/var/dump/$fileName"
];

在这两种情况下,请注意转储文件需要位于应用程序容器中,而不是数据库容器中;

docker exec
路径要求它位于数据库容器中,而不是应用程序容器中。

此外,在这两种情况下,应用程序和数据库都需要位于同一 Docker 网络上。 如果您在同一个 Compose 文件中启动这两个文件,则会自动发生(我倾向于建议删除所有手动

networks:
设置);如果您使用手动
docker run
命令,您需要确保您已经
docker network create
网络是
docker run --net
两个容器都位于同一网络上。


正如我在第一段中提到的,如果您可以运行任何

docker
命令,那么您几乎可以轻松 root 整个主机系统。 容器通常没有可用的 Docker 套接字来避免这种可能性。 容器镜像通常也没有比运行特定应用程序所需的更多的软件或工具。

您的

posix_spawn() failed: No such file or directory
错误基本上可以翻译为“容器没有
docker
二进制文件”。 我会尽力避免使用这个。 上述任一路径(使用直接数据库连接或
psql
的本地副本)都可以在任何容器或非容器环境中工作。 如果您严重依赖
docker
CLI 工具,那么它无法在非容器环境、非特权用户或 Kubernetes 等非 Docker 容器环境中工作。

© www.soinside.com 2019 - 2024. All rights reserved.