Я пишу функцию Azure на Java для копирования больших двоичных объектов между учетными записями хранения в одном клиенте без предварительной загрузки их в память. Я наткнулся на этот пост , в котором предлагалось использовать для этого AzCopy. Я скачал двоичный файл AzCopy из этого места и добавил его в корневой каталог функции перед созданием образа Docker. Ниже приведен мой код для вызова двоичного файла azcopy в Java, он отлично работает локально, но ничего не делает, когда функция развернута в Kubernetes. Не уверен, проблема ли это в двоичном файле или в среде, поскольку функция развертывается в Kubernets, а не в функциональном приложении.
Источником и местом назначения являются URL-адреса с временными токенами SAS.
ProcessBuilder processBuilder = new ProcessBuilder(azCopyBinaryLocation, "copy", source, destination);
Process process = processBuilder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append("\n");
sb.append(line);
}
context.getLogger().info("Logs: "+sb.toString()); //print logs in console
Я не уверен, что я на правильном пути, например, следует ли мне использовать azcopy или вместо этого попытаться использовать Java SDK, для SDK я не уверен, загружает ли blob APIs содержимое в память перед копированием в другую учетную запись хранения, если это так, то это будет быть медленным и требовательным к памяти, чего я хочу избежать любой ценой. Я ищу вариант, который использует магистраль Azure так же, как azcopy.
Я использовал метод copyfromurl
для копирования файла из одного хранилища в другое.
Ниже приведенный код работал у меня.
Я использовал то же имя в качестве имени файла назначения. если вы хотите изменить имя файла, вы можете использовать любое имя файла.
При использовании
getBlobUrl
вstorage account => Configuration
должно быть включено разрешение анонимного доступа к BLOB-объектам. если нет, нужно использоватьSAS_url
.
package com.function;
import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import com.microsoft.azure.functions.*;
import com.azure.identity.*;;
public class HttpTriggerJava1 {
@FunctionName("HttpTriggerJava1")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
//Source Account
String sourceContainerName = "source";
String blobName = "oldfile.txt";
BlobServiceClient sourceServiceClient = new BlobServiceClientBuilder().credential(new DefaultAzureCredentialBuilder().build()).endpoint("https://storage29aug.blob.core.windows.net").buildClient();
BlobContainerClient sourceContainerClient = sourceServiceClient.getBlobContainerClient(sourceContainerName);
BlobClient sourceBlobClient = sourceContainerClient.getBlobClient(blobName);
//Destination Account
String destinationContainerName = "destination";
BlobServiceClient destinationServiceClient = new BlobServiceClientBuilder().credential(new DefaultAzureCredentialBuilder().build()).endpoint("https://destinationstorage29aug.blob.core.windows.net").buildClient();
BlobContainerClient destinationContainerClient = destinationServiceClient.getBlobContainerClient(destinationContainerName);
BlobClient destinatiBlobClient = destinationContainerClient.getBlobClient(blobName);
destinatiBlobClient.copyFromUrl(sourceBlobClient.getBlobUrl());
return request.createResponseBuilder(HttpStatus.OK).body("blob copied successfully").build();
}
}
pom.xml
:
<dependencies>
<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
<version>12.27.1</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.13.2</version>
</dependency>
</dependencies>
OUTPUT
:@Сэнди, я еще не пробовал работать с большим файлом.
Проблема заключалась в том, что AZCOPY_LOG_LOCATION и AZCOPY_JOB_PLAN_LOCATION отсутствовали в переменных среды, установка необходимых переменных через значение docker ENV устранила проблему.
Окончательный файл докера выглядит так
# Use a base image with the necessary dependencies
FROM mcr.microsoft.com/azure-functions/java:4-java17
# Install dependencies for azcopy
RUN apt-get update && apt-get install -y wget
# Download and install azcopy
RUN wget https://aka.ms/downloadazcopy-v10-linux -O azcopy.tar.gz && \
tar -xvf azcopy.tar.gz && \
cp ./azcopy_linux_amd64_*/azcopy /usr/bin/ && \
chmod +x /usr/bin/azcopy && \
rm -rf azcopy.tar.gz azcopy_linux_amd64_*
COPY ./target ./package
RUN mkdir -p /home/site/wwwroot && \
cd /package/azure-functions/ && \
cd $(ls -d */|head -n 1) && \
cp -a . /home/site/wwwroot && \
groupadd appuser -g 2000 && \
useradd -r -M -s /sbin/nologin -g appuser -c appuser appuser -u 1000 && \
mkdir -p /home/appuser/.local && \
chown -R appuser:appuser /azure-functions-host && \
chown -R appuser:appuser /home/appuser/.local
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true \
ASPNETCORE_URLS=http://+:8080 \
FUNCTIONS_WORKER_RUNTIME=java \
JAVA_OPTS = "--add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
RUN mkdir -p /home/site/wwwroot/log_files && \
chown -R appuser:appuser /home/site/wwwroot/log_files && \
chmod 777 /home/site/wwwroot/log_files
ENV AZCOPY_LOG_LOCATION=/home/site/wwwroot/log_files
ENV AZCOPY_JOB_PLAN_LOCATION=/home/site/wwwroot/log_files
# Switch to the user
USER appuser
# Expose the port
EXPOSE 8080
и Java-код
File azCopyPath = new File("/usr/bin/azcopy");
ProcessBuilder processBuilder = new ProcessBuilder(azCopyPath.getAbsolutePath(), "copy", sourceFileSasUrl, destinationFileSasUrl);
Process process = processBuilder.start();
Спасибо @vivek. Пробовали ли вы это с большими файлами, сколько времени занимает копирование больших файлов (например, 1 гигабайт) между учетными записями хранения?