프로젝트를 진행하다 보면 보안 및 인터넷 접속문제 등을 고려하여 사내망에 아티팩트 및 컨테이너 레포지토리를 구축 할 수 있다.
이번 포스트는 Nexus 컨테이너를 private subnet에 배치하여 사내망 레포지토리 서비스를 구축하는 과정이며, 구성도는 아래와 같다.
이 포스트에서는 단순히 private 서버 접속용으로 생성했으니, 퍼블릭 IP 접속만 가능하면 된다.
실무 환경에서는 Client VPN을 통해 private Nexus, Deploy 서버로 바로 접속 하거나
퍼블릭 IP를 제거한 Bastion VM을 통해 private 서버를 접속할 것이다.
넥서스를 사용하여 레포지토리를 구성하며, 포스트에서는 docker 컨테이너로 구현했다.
Dockerfile로 컨테이너 이미지를 빌드하며, 컨테이너 구동 시 필요한 스크립트 파일은 아래와 같다.
FROM sonatype/nexus3:3.32.0
USER root
RUN chown -R nexus:nexus ${NEXUS_HOME}/etc \
&& sed '/^application-port/s:$:\napplication-port-ssl=8443:' -i ${NEXUS_HOME}/etc/nexus-default.properties \
&& sed '/^nexus-args/s:$:,${jetty.etc}/jetty-https.xml:' -i ${NEXUS_HOME}/etc/nexus-default.properties \
&& rm -rf ${NEXUS_HOME}/etc/ssl && ln -s ${NEXUS_DATA}/etc/ssl ${NEXUS_HOME}/etc/ssl
COPY start.sh /usr/local/bin
USER nexus
EXPOSE 8443
CMD start.sh
#! /bin/bash
if [ ! -e "$NEXUS_DATA/etc/ssl/keystore.jks" ]; then
mkdir -p "$NEXUS_DATA/etc/ssl"
chmod go-rwx "$NEXUS_DATA/etc/ssl"
keytool -genkeypair -keystore $NEXUS_DATA/etc/ssl/keystore.jks -storepass password -keypass password \
-alias jetty -keyalg RSA -keysize 2048 -validity 5000 \
-dname "CN=*.${HOSTNAME}, OU=testOU, O=testO, L=Test, ST=Seoul, C=KR" \
-ext "SAN=DNS:${SAN_DNS}" -ext "BC=ca:true"
fi
sh -c ${SONATYPE_DIR}/start-nexus-repository-manager.sh
Dockerfile의 내용은 넥서스 3.32.0 버전을 사용하면서 HTTPS 접속을 활성화 하는 start.sh을 실행하면서 동작하기 때문에 Dockerfile, start.sh 파일이 같은 디렉터리에 위치해야 한다.
start.sh 파일은 도커 데몬이 실행할 수 있도록 아래와 같이 파일에 x권한을 추가 해야한다.
이미지 빌드가 완료되면 컨테이너를 아래와 같이 SAN_DNS를 지정하여 실행한다.
docker run -d -u root --net=host -e SAN_DNS=<Nexus VM의프라이빗IP DNS 이름> --name nexus -v ~/nexus-data:/nexus-data <이미지명>:<태그>
추후 Deploy VM에서 Nexus 연동이 필요하므로 Nexus VM 보안그룹에서 Deploy VM의 priv IP에 대한 아래 포트 접근을 허용한다.
Nexus 접속포트
-nexus 레포지토리 관리 페이지 접속 및 설정
이번 포스트에서는 NexusVM을 priv 서브넷에 구성했지만, 퍼블릭 IP를 통해 바로 접속한다.
하지만 실제로 구성도와 같이 내부망에 구성한 경우 VPN을 통해 접속 해야한다.
maven2 (proxy) 레포지토리 생성
docker (hosted) 레포지토리 생성
docker (proxy) 레포지토리 생성
-Nexus HTTPS 인증서 export
Nexus 컨테이너에서 레지스트리 로그인 용도로 사용할 인증서를 생성하고 아래 명령어로 컨테이너에 인증서를 적용한다
docker exec nexus keytool -printcert -sslserver 127.0.0.1:8443 -rfc | tee nexus.crt
외부에서 넥서스 레포지토리로 로그인 할때 로그인 인증서가 필요하다.
아래와 같이 nexus.crt 파일을 Nexus VM으로 import 하여 가능하다.
sudo cp -av nexus.crt /usr/local/share/ca-certificates/nexus.crt
sudo update-ca-certificates
도커 레지스트리에 로그인 할때도 기존 nexus.crt 파일이 필요하며 아래와 같이 인증서 파일명을 ca.crt로 지정하여 등록한다.
sudo mkdir /etc/docker/certs.d/<Nexus VM의프라이빗ip dns 이름>\:5443/ -p
sudo cp -av nexus.crt /etc/docker/certs.d/<Nexus VM의프라이빗ip dns
이름>\:5443/ca.crt
nexus.crt 파일을 넥서스에 접근할 VM, 도커 인증서 경로에 등록하면 아래와 같이 로그인 가능하다.
docker login -u <넥서스 사용자> -p '<비밀번호>' https://<NexusVM IP>:5001
docker login -u <넥서스 사용자> -p '<비밀번호>' https://<NexusVM IP>:5443
gradle 대신 gradlew를 사용하여 빌드하게 되면 인터넷을 통해 gradle 레포 파일을 다운로드 해야한다.
구성도 상의 Deploy VM은 인터넷 게이트웨이와 연결하지 않은 환경으로, 해당 VM에 한시적으로 인터넷 게이트웨이를 연결하여 gradle 패키지 설치 후 원상복구 한다.
-인증서 import
NexusVM에서 생성한 nexus.crt 파일을 Deploy VM에 복제하여 동일한 방법으로 적용 합니다.
sudo mkdir /etc/docker/certs.d/<Nexus VM의프라이빗ip dns 이름>\:5443/ -p
sudo cp -av nexus.crt /etc/docker/certs.d/<Nexus VM의프라이빗ip dns
이름>\:5443/ca.crt
Deploy VM에서 Docker Hub(Proxy) 로그인
docker login -u <넥서스 사용자> -p '<비밀번호>' https://<NexusVM IP>:5001
-oracle jdk 17버전 설치
gradle 7.4.2 버전을 사용하여 빌드하며, 자바는 oracle jdk 17버전으로 사용
-gradle 설정파일 (예시)
pluginManagement {
repositories {
maven {
url "http://<Nexus Private IP>:8081/repository/<nexus artifact repository Name>"
allowInsecureProtocol true
}
}
}
rootProject.name = 'test-docker-spring-boot'
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.1'
id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'com.google.cloud.tools.jib' version '3.3.1'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:2.7.1'
implementation 'org.springframework.boot:spring-boot-starter-web:2.7.1'
developmentOnly 'org.springframework.boot:spring-boot-devtools:2.7.1'
}
repositories {
maven {
url "http://<Nexus Private IP>:8081/repository/<nexus artifact repository Name>"
allowInsecureProtocol true
}
}
version = '0.0.1-SNAPSHOT'
description = 'test-docker-spring-boot'
group = 'com.test'
java.sourceCompatibility = JavaVersion.VERSION_11
jar {
enabled = false
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
jib {
from {
image = "<Nexus Private IP>:5443/<Nexus Repository Name>:<Image Tag Name>"
}
container {
entrypoint = ['java', '-Dspring.profiles.active=test', '-jar', 'test-docker-spring-boot-0.0.1-SNAPSHOT.jar']
jvmFlags = ['-Xms512m', '-Xmx512m', '-Xdebug', '-XshowSettings:vm', '-XX:+UnlockExperimentalVMOptions', '-XX:+UseContainerSupport']
ports = ['8080']
environment = [SPRING_OUTPUT_ANSI_ENABLED: "ALWAYS"]
labels = [version:project.version, name:project.name, group:project.group]
creationTime = 'USE_CURRENT_TIMESTAMP'
format = 'Docker'
}
extraDirectories {
paths {
path {
from = file('build/libs')
}
}
}
}
gradle과 jib을 사용하여 Nexus Custom Registry에 컨테이너 이미지 업로드
Nexus 관리 페이지에서 이미지 업로드 확인