이전 포스팅에서 원하는 도커 이미지를 사용하여 Build 된 프로젝트 폴더를 AWS S3 Bucket에 올리기 쉽게 tar.gz(tgz) 파일로 압축하는 작업을 실행할 차례. apache에서 제공하는 commons-compress 라이브러리를 주입받아 사용한다.
Dependency injection
본인은 gadle build tool을 사용하고, commons-compress 1.3버전을 주입받아 사용하였다.
dependencies {
implementation group: 'org.apache.commons', name: 'commons-compress', version: '1.3'
}
Make CompressLib Class
compress 기능은 추후 다른 곳에서도 사용할 수 있기 때문에 compress 기능을 별도로 관리하는 CompressLib Class를 만들어 기능을 여기에 구현한다. 현재 만들고 있는 프로그램은 싱글 쓰레드로 구성되어 있기 때문에 모든 util, lib Class는 싱글턴 패턴으로 개발하여 인스턴스 생성에 따른 무분별한 hip 메모리 사용을 방지한다.
package mingyu.libraries;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class CompressLib {
private static CompressLib instance;
public static CompressLib getInstance() {
if (instance == null) {
synchronized (CompressLib.class) {
instance = new CompressLib();
}
}
return instance;
}
// compress(압축) 하기
public void compress(Path source) throws IOException {
if (!Files.isDirectory(source)) {
throw new IOException("Please provide a directory.");
}
// 압축 진행할 폴더 이름을 gzip 파일 폴더 이름으로 정한다
String tarFileName = source.getFileName().toString() + ".tar.gz";
try (OutputStream fOut = Files.newOutputStream(Paths.get(tarFileName));
BufferedOutputStream buffOut = new BufferedOutputStream(fOut);
GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(buffOut);
TarArchiveOutputStream tOut = new TarArchiveOutputStream(gzOut)) {
Files.walkFileTree(source, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attributes) {
// only copy files, no symbolic links
if (attributes.isSymbolicLink()) {
return FileVisitResult.CONTINUE;
}
// get filename
Path targetFile = source.relativize(file);
try {
TarArchiveEntry tarEntry = new TarArchiveEntry(
file.toFile(), targetFile.toString());
tOut.putArchiveEntry(tarEntry);
Files.copy(file, tOut);
tOut.closeArchiveEntry();
System.out.printf("file : %s%n", file);
} catch (IOException e) {
System.err.printf("Unable to tar.gz : %s%n%s%n", file, e);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
System.err.printf("Unable to tar.gz : %s%n%s%n", file, exc);
return FileVisitResult.CONTINUE;
}
});
tOut.finish();
}
}
}
Make ArchiveManager Class
위에서 구현한 CompressLib의 압축 기능을 실제로 사용하는 ArichiveManager Class를 만든다. 해당 클래스의 startArchive method에서 압축을 실행한다.
package mingyu.classes;
import mingyu.libraries.CompressLib;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.nio.file.Paths;
public class ArchiveManager {
private Logger logger;
private CompressLib compressLib;
public ArchiveManager() {
logger = LoggerFactory.getLogger("ArchiveManagerLogger");
compressLib = CompressLib.getInstance();
}
public void startArchive(String path) {
try {
Path source = Paths.get(path);
compressLib.compress(source);
} catch (Exception exception) {
logger.info("startArchive Error ::\n",exception.getMessage(),exception.getStackTrace());
}
}
}
Update BuilderManager Class
위의 ArchiveManager 객체를 생성해서 starArchive() method를 실행하는 문구를 추가하고 Run 작업을 실시한다.
public static void main(String[] args) throws Exception {
// args[0] : "git repository url" when use git pull command
// args[1] : "dockerRepo/dockerImage:tag" when use build
// args[2] : CI_COMMIT_BRANCH
String gitRepositoryURL = args[0];
String dockerRepositoryImage = args[1];
String gitCommitBranch = args[2];
BuilderManager builderManager = new BuilderManager(gitRepositoryURL, dockerRepositoryImage, gitCommitBranch);
// 해당 날짜 지정
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String dateTime = dateFormat.format(new Date());
// String sourceDirectoryPath = "/Users/mingyukim/tmp/build/source/" + dateTime;
// 최신 source code 다운로드
// builderManager.gitManager.sourceCodeDownload(dateTime, sourceDirectoryPath);
// 도커로 다운로드한 최신 source code build 하기;
// builderManager.dockerManager.startBuild(sourceDirectoryPath);
// build된 프로젝트 폴더 tar.gz 파일로 압축하기
// Test Folder
String sourceDirectoryPath = "/Users/mingyukim/tmp/build/source/20221228164126";
builderManager.archiveManager.startArchive(sourceDirectoryPath);
}
결과
해당 빌드된 폴더 ("/Users/mingyukim/tmp/build/source/20221228164126")의 내용이 tar.gz파일로 변환될 때 모든 내용이 잘 포함되었는지 출력하는 System.out.println 구문이 잘 출력되었고 BUILD SUCCESSFUL 까지 4초 걸렸으며 해당 tgz 파일이 잘 만들어지는 것 또한 확인이 가능했다.
Java로 만드는 Builder Program 포스팅은 여기서 마무리 짓겠다. 도커 이미지 만드는건 (2) Docker 구문에서 build & Push만 하면 되는것이기 때문에 별도로 진행하지 않았다.
CI/CD 구현에 있어서 파이프라인 구성을 최소화 하고 코스트를 아끼기 위해 거의 모든 처리 과정을 스스로 개발하며 재밌었다. 업무라고 생각되지 않았고 놀이라고 생각이 들어서 그런것일까?
Java로 더 많은 것들을 구현해보고 싶어졌다.
'Language > Java' 카테고리의 다른 글
Java로 Builder Program 만들기 (2) - Java로 Shell Script를 Controller하여 Docker로 Source Build하기 (0) | 2022.12.28 |
---|---|
Java로 Builder Program 만들기 (1) - Java JGit Library 사용해서 Git Controller하기 (0) | 2022.12.27 |
Java로 Firebase Cloude Message (Application Push) 구현하기 (0) | 2022.07.19 |
Java로 Data 암호화 및 복호화 하기 - AES256 (0) | 2022.06.27 |
Java로 Apache Kafka Consumer 구독 구현하기 (0) | 2022.06.20 |