英文:
FTP upload file failed in Docker container
问题
我有一个使用 Apache Commons Net 库的 Spring Boot 应用程序。
我在 AWS EC2 上运行一个 FTP 服务器。
Filezilla 可以正常连接并上传文件。
本地应用程序可以正常连接并上传文件。
但当我使用 Docker 运行此应用程序时,应用程序可以成功连接到 FTP,但无法上传文件。
回复代码为:500。
Dockerfile:
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
请帮忙看看,我是否漏掉了任何步骤?
英文:
I have a spring boot app using library apache commons-net<br/>
I have a FTP server running on AWS EC2.<br/>
Filezilla connect and upload file normally.<br/>
Local app connect and upload file normally.<br/>
When i run this app using Docker, the app connect to ftp succeed,but it cannot upload file.<br/>
Reply code is: 500<br/><br/>
Dockerfile:
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"]
Image build command:
docker build -t aws-batch1 .
Image run command:
docker run aws-batch1
Code connect 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;
}
Code upload file:
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;
}
Log when upload on local successful:
uploadFile
CONNECT
replyCode: 230
connectFTPServer success
content: test
storeFile: true
ftpClient.getReplyCode(): 226
Log when upload on Docker failed:
uploadFile
CONNECT
replyCode: 230
connectFTPServer success
content: test
storeFile: false
ftpClient.getReplyCode(): 500
Please help me. Am I missing any steps?
UPDATE:Thanks @Metin
I have updated the code to connect to ftp client as below:
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;
}
and it works!
答案1
得分: 3
你可能想要阅读有关主动模式和被动模式 FTP 差异的内容:https://stackoverflow.com/questions/1699145/what-is-the-difference-between-active-and-passive-ftp
你应该得出结论,主动模式 FTP 不适用于容器化的 FTP 客户端,因为服务器会主动尝试初始化与 FTP 客户端的数据连接,而这对于容器来说是不可能的(除非容器使用网络:主机,但通常不希望如此)。
另一方面,使用被动模式 FTP,服务器将告诉你的 FTP 客户端下一个数据连接需要使用哪个端口。
英文:
You might want to read about the differences of active and passive mode ftp: https://stackoverflow.com/questions/1699145/what-is-the-difference-between-active-and-passive-ftp
You should come to the conclusion that active mode ftp is not suited for containerized ftp clients, due to the nature that the server activily tries to initate a data connection to the ftp client, which is not possible for a container (unless the container uses network: host, which is typicaly unwanted).
With passive mode ftp on the other hand, the server will tell your ftp client which port needs to be used for the next data connection.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论