Sftp 文件上传无法与 Docker 容器中的 Apache MINA SSHD 和 JIMFS 一起使用

发布于 2025-01-14 06:46:00 字数 3351 浏览 3 评论 0原文

我正在处理一个棘手的问题:

出于测试目的,我使用 Apache Mina SSHD 和 JIMFS 来模拟远程 sftp 服务器 - 仅在本地和测试环境中。从未投入生产。

在我的 Spring Boot 应用程序中,我在应用程序启动期间启动 Apache Mina sshd。我使用 jimfs(尝试过 unix 和 osX)为 FileSystemFactory 创建了一个虚拟文件系统。 我的业务代码在生产环境中调用远程 sftp 服务器,而在测试环境中,它会调用本地主机上的 mina sshd 服务器。 它除了将文件上传到 sftp 服务器之外什么也不做。

这在我的本地机器上运行得很好,但是当我在测试环境(docker 容器)中运行它时,我收到“文件或目录未找到”错误消息。

com.jcraft.jsch.SftpException: No such file or directory
    at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873)
    at com.jcraft.jsch.ChannelSftp._put(ChannelSftp.java:594)
    at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:475)
    at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:365)
    at our.service.core.client.sftp.SftpClient.upload(SftpClient.java:89)

在应用程序启动期间创建 JIMFS 文件系统:

public class MockSftpServerInitializer implements ApplicationListener<ApplicationReadyEvent> {

  @Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    
    SshServer sshd = SshServer.setUpDefaultServer();

    sshd.setHost("localhost");
    sshd.setPort(1234);
    sshd.setCommandFactory(new ScpCommandFactory());
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("host-key.ser")));
    sshd.setPublickeyAuthenticator(getPublickeyAuthenticator());
    sshd.setFileSystemFactory(getInMemoryFileSystemFactory());
    List<NamedFactory<Command>> sftpCommandFactory = new ArrayList<>();
    sftpCommandFactory.add(new SftpSubsystemFactory());
    sshd.setSubsystemFactories(sftpCommandFactory);
    
    try {
      sshd.start();
    } catch (Exception e) {
      throw new RuntimeException("Unable to start sshd", e);
    }
  }
  
  private FileSystemFactory getInMemoryFileSystemFactory() {
    return session -> getInMemoryFileSystem();
  }

  private FileSystem getInMemoryFileSystem() {
    return Jimfs.newFileSystem(
        Configuration.osX()
            .toBuilder()
            .setWorkingDirectory("/")
            .setMaxSize(1024*1024*4)
            .setDefaultAttributeValue("posix:permissions", "rwxrw-rw-")
            .setAttributeViews("basic", "owner", "posix", "unix", "acl", "user")
            .build());
  }
  

}

文件上传:

public class SftpClient {

  public boolean upload(String source, String destination) {

    Session session = null;
    ChannelSftp sftpChannel = null;

    try {
      sftpProvider.addIdentity("Identity", privateKey.getBytes(), publicKey.getBytes(), null);
      session = sftpProvider.getSession(username, host, port);
      session.setConfig("StrictHostKeyChecking", "no");

      session.connect();

      Channel channel = session.openChannel("sftp");
      channel.connect();

      sftpChannel = (ChannelSftp) channel;
      sftpChannel.put(source, destination);

      log.info("Successful upload of file {} to SFTP server {}.", source, host);

      return true;
    } catch (SftpException | JSchException ex) {
      log.error("Failed upload of file {} to SFTP server {}.", source, host);
      log.error("{}", ex);
      return false;
    } finally {
      if (sftpChannel != null) {
        sftpChannel.disconnect();
      }
      if (session != null) {
        session.disconnect();
      }
    }
  }
}

我很感激任何关于为什么它在本地工作但在我们的 docker 容器中工作的提示。

I'm dealing with a tough one:

For testing purposes I use Apache Mina SSHD and JIMFS to mock a remote sftp server - only locally and in test environment. Never in production.

In my Spring Boot application I start a Apache Mina sshd during application startup. I create a virtual filesystem with jimfs (tried unix and osX) for the FileSystemFactory.
My business code calls a remote sftp server in production and in test environment it calls the mina sshd server on localhost instead.
It does nothing else than uploading a file to the sftp server.

This works very well on my machine locally but i get a "file or directory not found" error message when I run this in our test environment (a docker container).

com.jcraft.jsch.SftpException: No such file or directory
    at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2873)
    at com.jcraft.jsch.ChannelSftp._put(ChannelSftp.java:594)
    at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:475)
    at com.jcraft.jsch.ChannelSftp.put(ChannelSftp.java:365)
    at our.service.core.client.sftp.SftpClient.upload(SftpClient.java:89)

Creation of JIMFS file system during Application startup:

public class MockSftpServerInitializer implements ApplicationListener<ApplicationReadyEvent> {

  @Override
  public void onApplicationEvent(ApplicationReadyEvent event) {
    
    SshServer sshd = SshServer.setUpDefaultServer();

    sshd.setHost("localhost");
    sshd.setPort(1234);
    sshd.setCommandFactory(new ScpCommandFactory());
    sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File("host-key.ser")));
    sshd.setPublickeyAuthenticator(getPublickeyAuthenticator());
    sshd.setFileSystemFactory(getInMemoryFileSystemFactory());
    List<NamedFactory<Command>> sftpCommandFactory = new ArrayList<>();
    sftpCommandFactory.add(new SftpSubsystemFactory());
    sshd.setSubsystemFactories(sftpCommandFactory);
    
    try {
      sshd.start();
    } catch (Exception e) {
      throw new RuntimeException("Unable to start sshd", e);
    }
  }
  
  private FileSystemFactory getInMemoryFileSystemFactory() {
    return session -> getInMemoryFileSystem();
  }

  private FileSystem getInMemoryFileSystem() {
    return Jimfs.newFileSystem(
        Configuration.osX()
            .toBuilder()
            .setWorkingDirectory("/")
            .setMaxSize(1024*1024*4)
            .setDefaultAttributeValue("posix:permissions", "rwxrw-rw-")
            .setAttributeViews("basic", "owner", "posix", "unix", "acl", "user")
            .build());
  }
  

}

File upload:

public class SftpClient {

  public boolean upload(String source, String destination) {

    Session session = null;
    ChannelSftp sftpChannel = null;

    try {
      sftpProvider.addIdentity("Identity", privateKey.getBytes(), publicKey.getBytes(), null);
      session = sftpProvider.getSession(username, host, port);
      session.setConfig("StrictHostKeyChecking", "no");

      session.connect();

      Channel channel = session.openChannel("sftp");
      channel.connect();

      sftpChannel = (ChannelSftp) channel;
      sftpChannel.put(source, destination);

      log.info("Successful upload of file {} to SFTP server {}.", source, host);

      return true;
    } catch (SftpException | JSchException ex) {
      log.error("Failed upload of file {} to SFTP server {}.", source, host);
      log.error("{}", ex);
      return false;
    } finally {
      if (sftpChannel != null) {
        sftpChannel.disconnect();
      }
      if (session != null) {
        session.disconnect();
      }
    }
  }
}

I'm grateful for any hint on why this works locally but not in our docker container.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文