본문 바로가기
IT.인터넷/Docker

Docker컨테이너에서 libreoffice (soffice)로 pdf변환 예제

by Mr-후 2023. 8. 5.
반응형

이 글은 다음 글 다음으로 연속해서 작성된 글이다. 

https://effectivecode.tistory.com/1729

 

Docker컨테이너에서 host(Linux) 명령어 사용하는 방법(pipe)

몇 일 동안 별별짓을 다했다. 왜? 모르니까. 접근은 간단하게 될 줄 알고 시작을 했는데, 막상 간단하지는 않았다. Docker로 서버를 구성했다는 점을 간과한 것이 가장 뼈아픈 실수다. libreoffice라는

effectivecode.tistory.com

 

위의 글의 내용대로 준비를 하고 이제 api에서는 프론트에서 업로드한 파일을 받아서 특정 폴더에 저장을 하고 

저장된 경로를 가지고 pdf로 변환을 하기 위해 쉘 스크립트를 실행해야 한다. 

실행 해야 할 스크립트의 위치는 docker 컨테이너와 볼륨으로 연결된 경로에 위치 해야한다. 
나의 경우 컨테이너 생성 시, 다음과 같이 볼륨을 마운트 하였다. 

/home/user1/data/files:/res

따라서, host에서는 /home/user1/data/files/안에 pdf_convert.sh이란 파일을 위치 시키면, 
컨테이너 입장에서 /res/pdf_convert.sh로 인식이 된다. 

대신 변환해야 할 파일의 경로는 /res로 시작하면 안된다. 왜냐면 이 경로는 host가 알 수 없기에 변환해야할 파일의 경로는 
다음과 같이 되어야 정상이다. /home/user1/data/files/변환할 파일명 

실제 pdf_convert.sh에서는 실행되는 명령은 host의 CLI명령이기 때문에 해당 CLI명령이 경로를 찾을 수 있어야 하기 때문이다. 

그럼 pdf_convert.sh의 파일 내용을 살펴 보자. 

#!/bin/sh

input_file=$1

extension="${input_file##*.}"

output_file="${input_file%.*}.pdf"

#스크립트가 있는 위치로 체인지 디렉토리
echo "cd /home/user1" > convert_pipe

#pipe명령을 읽어 들여 실행할 수 있도록 하기 위한 스크립트를 실행 
#여기까지 실행되고 나면 docker 컨테이너에서 보내는 명령어를 읽어 들일 준비가 끝. 

echo "sh ./pipe_run.sh" > convert_pipe

#실제 파일을 변환하는 명령어를 실행 
echo "soffice --headless --convert-to pdf --outdir "$(dirname "$output_file")" "$input_file"" > mypipe
if [ $? -ne 0 ]; then
    echo "FAIL"
    exit 1
fi

#변환된 파일을 경로를 출력
echo "$output_file"

 

이렇게 한 이유는 pipe_run.sh파일을 매번 실행해주지 않으면 다음 줄의 명령어를 보내도 읽어 들이지 않았다. 

그래서 꼼수를 쓴 것인데, 쉘스크립트를 잘 짜시는 분이라면 이 파일 하나에서 모두 해도 상관없을 것 같다. 

다음은 java spring boot의 코드 일부분이다. 

String SCRIPT_PATH = rootPath + "/pdf_convert.sh";
String input = "/home/user1/data/files" + "/" + datePath + "/" + filename;

try {
    // 쉘 스크립트를 실행합니다.
    // ProcessBuilder를 생성하여 쉘 스크립트의 경로와 인자를 전달합니다.
    ProcessBuilder processBuilder = new ProcessBuilder(SCRIPT_PATH, input);
    Process process = processBuilder.start();

    // 쉘 스크립트의 실행 결과를 읽어들입니다.
    // InputStreamReader와 BufferedReader를 사용하여 쉘 스크립트의 표준 출력을 읽어들입니다.
    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    String line;
    StringBuilder output = new StringBuilder();
    while ((line = reader.readLine()) != null) {
        output.append(line);
    }

    // 쉘 스크립트의 실행이 성공적으로 종료되었는지 확인합니다.
    // 쉘 스크립트의 실행이 성공적으로 종료되었다면 exit code는 0이 됩니다.
    int exitCode = process.waitFor();
    if (exitCode != 0) {
        throw new RuntimeException("Script execution failed with exit code: " + exitCode);
    }

    log.info("\n\n\n >> output : {}\n\n\n", output);

} catch (IOException e) {
    log.info("1. exception : {}",e.getLocalizedMessage());
    e.printStackTrace();
} catch (InterruptedException e) {
    log.info("2. exception : {}",e.getLocalizedMessage());
    throw new RuntimeException(e);
}

이게 챗GPT가 작성해준 클래스의 일부분이다. 경로만 바꿨을 뿐.... 

 

 

이 api를 호출할 때 파일을 업로드하면 

cd /host/user1 
sh ./pipe_run.sh 
soffice --headless ... 어쩌구 저쩌구 ~ 

하는 명령어가 실행되며, 파일이 변환된 걸 확인할 수 있다. 

 

끝. 

 

반응형