FTP 在 Docker 容器中上传文件失败
FTP upload file failed in Docker container
我有一个 spring 启动应用程序使用库 apache commons-net
我在 AWS EC2 上有一个 FTP 服务器 运行ning。
Filezilla 正常连接和上传文件。
本地应用程序连接和上传文件正常。
当我 运行 这个应用程序使用 Docker 时,应用程序连接到 ftp 成功,但它无法上传文件。
回复码是:500
Docker文件:
FROM openjdk:11
RUN mkdir /app
COPY build/libs/aws-batch1-1.0.0.jar /app/aws-batch1.jar
ENTRYPOINT ["java","-jar","/app/aws-batch1.jar","Test"]
映像构建命令:
docker build -t aws-batch1 .
图片运行命令:
docker run aws-batch1
代码连接FTP:
private boolean connectFTPServer() throws IOException {
LOGGER.info("CONNECT");
boolean flg = true;
try {
ftpClient.connect(FTP_SERVER_ADDRESS, FTP_SERVER_PORT_NUMBER);
ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
} catch (IOException e) {
LOGGER.error("CONNECT FAILED", e);
flg = false;
}
int replyCode = ftpClient.getReplyCode();
LOGGER.info("replyCode: " + replyCode);
if (!FTPReply.isPositiveCompletion(replyCode)) {
flg = false;
}
if (!flg) {
throw new IOException();
}
return flg;
}
代码上传文件:
public boolean uploadFile(byte[] content, String fileName)
throws IOException {
boolean flg = false;
LOGGER.info("uploadFile");
if (connectFTPServer()) {
LOGGER.info("connectFTPServer success");
LOGGER.info("content: " + new String(content));
try (InputStream is = new ByteArrayInputStream(content)) {
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
boolean storeFile = ftpClient.storeFile(fileName, is);
LOGGER.info("storeFile: " + storeFile);
LOGGER.info("ftpClient.getReplyCode(): " + ftpClient.getReplyCode());
flg = storeFile &&
ftpClient.getReplyCode() ==
FTPReply.CLOSING_DATA_CONNECTION;
if (!flg) {
throw new IOException("FTP error");
}
} finally {
closeConnectionFTPClient();
}
}
return flg;
}
本地上传成功时记录:
uploadFile
CONNECT
replyCode: 230
connectFTPServer success
content: test
storeFile: true
ftpClient.getReplyCode(): 226
在 Docker 上传失败时记录:
uploadFile
CONNECT
replyCode: 230
connectFTPServer success
content: test
storeFile: false
ftpClient.getReplyCode(): 500
请帮助我。我是否遗漏了任何步骤?
更新:谢谢@Metin
我已经更新了连接到 ftp 客户端的代码,如下所示:
private boolean connectFTPServer() throws IOException {
LOGGER.info("CONNECT");
boolean flg = true;
try {
ftpClient.connect(FTP_SERVER_ADDRESS, FTP_SERVER_PORT_NUMBER);
ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
ftpClient.enterLocalPassiveMode();
} catch (IOException e) {
LOGGER.error("CONNECT FAILED", e);
flg = false;
}
int replyCode = ftpClient.getReplyCode();
LOGGER.info("replyCode: " + replyCode);
if (!FTPReply.isPositiveCompletion(replyCode)) {
flg = false;
}
if (!flg) {
throw new IOException();
}
return flg;
}
而且有效!
您可能想了解主动模式和被动模式的区别ftp:What is the difference between active and passive FTP?
您应该得出这样的结论:主动模式 ftp 不适合容器化 ftp 客户端,因为服务器主动尝试启动与 ftp 客户端,这对容器来说是不可能的(除非容器使用网络:主机,这通常是不需要的)。
另一方面,使用被动模式ftp,服务器会告诉您的ftp客户端下一个数据连接需要使用哪个端口。
我有一个 spring 启动应用程序使用库 apache commons-net
我在 AWS EC2 上有一个 FTP 服务器 运行ning。
Filezilla 正常连接和上传文件。
本地应用程序连接和上传文件正常。
当我 运行 这个应用程序使用 Docker 时,应用程序连接到 ftp 成功,但它无法上传文件。
回复码是:500
Docker文件:
FROM openjdk:11
RUN mkdir /app
COPY build/libs/aws-batch1-1.0.0.jar /app/aws-batch1.jar
ENTRYPOINT ["java","-jar","/app/aws-batch1.jar","Test"]
映像构建命令:
docker build -t aws-batch1 .
图片运行命令:
docker run aws-batch1
代码连接FTP:
private boolean connectFTPServer() throws IOException {
LOGGER.info("CONNECT");
boolean flg = true;
try {
ftpClient.connect(FTP_SERVER_ADDRESS, FTP_SERVER_PORT_NUMBER);
ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
} catch (IOException e) {
LOGGER.error("CONNECT FAILED", e);
flg = false;
}
int replyCode = ftpClient.getReplyCode();
LOGGER.info("replyCode: " + replyCode);
if (!FTPReply.isPositiveCompletion(replyCode)) {
flg = false;
}
if (!flg) {
throw new IOException();
}
return flg;
}
代码上传文件:
public boolean uploadFile(byte[] content, String fileName)
throws IOException {
boolean flg = false;
LOGGER.info("uploadFile");
if (connectFTPServer()) {
LOGGER.info("connectFTPServer success");
LOGGER.info("content: " + new String(content));
try (InputStream is = new ByteArrayInputStream(content)) {
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
boolean storeFile = ftpClient.storeFile(fileName, is);
LOGGER.info("storeFile: " + storeFile);
LOGGER.info("ftpClient.getReplyCode(): " + ftpClient.getReplyCode());
flg = storeFile &&
ftpClient.getReplyCode() ==
FTPReply.CLOSING_DATA_CONNECTION;
if (!flg) {
throw new IOException("FTP error");
}
} finally {
closeConnectionFTPClient();
}
}
return flg;
}
本地上传成功时记录:
uploadFile
CONNECT
replyCode: 230
connectFTPServer success
content: test
storeFile: true
ftpClient.getReplyCode(): 226
在 Docker 上传失败时记录:
uploadFile
CONNECT
replyCode: 230
connectFTPServer success
content: test
storeFile: false
ftpClient.getReplyCode(): 500
请帮助我。我是否遗漏了任何步骤?
更新:谢谢@Metin 我已经更新了连接到 ftp 客户端的代码,如下所示:
private boolean connectFTPServer() throws IOException {
LOGGER.info("CONNECT");
boolean flg = true;
try {
ftpClient.connect(FTP_SERVER_ADDRESS, FTP_SERVER_PORT_NUMBER);
ftpClient.login(FTP_USERNAME, FTP_PASSWORD);
ftpClient.enterLocalPassiveMode();
} catch (IOException e) {
LOGGER.error("CONNECT FAILED", e);
flg = false;
}
int replyCode = ftpClient.getReplyCode();
LOGGER.info("replyCode: " + replyCode);
if (!FTPReply.isPositiveCompletion(replyCode)) {
flg = false;
}
if (!flg) {
throw new IOException();
}
return flg;
}
而且有效!
您可能想了解主动模式和被动模式的区别ftp:What is the difference between active and passive FTP?
您应该得出这样的结论:主动模式 ftp 不适合容器化 ftp 客户端,因为服务器主动尝试启动与 ftp 客户端,这对容器来说是不可能的(除非容器使用网络:主机,这通常是不需要的)。
另一方面,使用被动模式ftp,服务器会告诉您的ftp客户端下一个数据连接需要使用哪个端口。