본문 바로가기

Log

Nexus Repository 도입하기

sonatype Nexus3 설치하고 리포지토리 생성하기

최근에 프로젝트에 Nexus Repository를 도입하였다. 프로젝트는 멀티 모듈 프로젝트로, 각 기능별로 독립적으로 동작하는 여러 독립 모듈들이 존재한다.

 

Nexus 도입 목적

  • 라이브러리와 외부 의존성 관리의 중앙화
  • 빌드 속도와 안정성 향상

Docker Compose로 Nexus3 실행하기

로컬 환경에서 테스트하기 위하여 도커를 사용하였다. 

다음과 같이 compose.yaml 파일을 생성하였다.

version: '3'
services:
  nexus_oss:
    image: sonatypecommunity/nexus3
    container_name: nexus3
    ports:
      - 8085:8081
    restart: always
    volumes:
      - nexus_data:/nexus-data
volumes:
  nexus_data:
  • 이 Docker Compose 파일은 Sonatype Nexus Repository 를 설정하고 실행한다. nexus_oss 서비스는 sonatypecommunity/nexus3 이미지를 사용하며, 호스트의 포트 8085를 컨테이너의 포트 8081에 매핑한다. Nexus 데이터는 nexus_data 볼륨에 저장된다.
  • nexus는 기본 포트로 8081을 이용하여 서비스를 수행한다.
  • 도커 컴포즈 파일을 실행하여 nexus를 시작한다. yaml 파일이 위치한 경로에서 터미널 실행 후 docker-compose up 명령어를 입력한다.
  • 명령어를 실행하면 필요한 이미지를 자동으로 다운로드하고, 컨테이너를 실행한다.

 

Admin 계정으로 로그인하기

Nexus3 접근하기

컨테이너가 실행되면 Nexus3에 접근할 수 있다.

웹브라우저에서 Nexus3 UI에 접근하면 초기 설정을 진행할 수 있다.

Admin 계정으로 로그인하기

  • 기본 사용자 이름: admin
  • 비밀번호 : nexus 설치 디렉토리의 admin.password 파일에 최초 비밀번호가 저장되어 있다.
    • → /nexus-data/admin.password 파일에서 확인 가능
    • 터미널에서 확인하려면 docker exec nexus3 cat /nexus-data/admin.password 입력

 

비밀번호 재설정

 

 

로그인 이후 바로 비밀번호 재설정을 진행한다.

 

익명 접근 설정

 

  • Configure Anonymous Access에서는 익명 접근에 대한 허용 여부를 물어본다.
  • Disable anonymous access를 선택하여 자격 증명이 있는 사용자만이 접근할 수 있도록 설정하였다.

 

Repository 생성하기

일반적으로 Spring 개발 환경에서 Maven 의존성 라이브러리 관리를 위해 2가지 리포지토리를 생성한다.

  • snapshot: 스냅샷은 개발 과정에서 사용되는 리포지토리이다.
  • release: 실제 배포 버전의 라이브러리가 존재하는 리포지토리이다. 일반적으로 릴리즈는 redeploy가 되지 않도록 설정한다. 이는 실행환경에서의 안정적인 라이브러리 사용을 위해 필요한 설정이다.

리포지토리 생성

  • 상단 메뉴의 톱니바퀴를 클릭하고, Repositories 메뉴를 선택한 뒤 Create repository 버튼을 눌러 리포지토리를 생성한다.
  • 리포지토리 타입은 proxy, group, hosted 가 있다.
    • proxy: 외부 리포지토리를 프록시 해준다. 즉, 내부 시스템에서 외부에 직접 접근하지 못하는 환경을 구성할때 프록시를 주로 사용한다.
    • group: 여러 리포지토리를 그루핑한다.
    • hosted: 실제 현재 nexus에서 라이브러리를 제공한다. 주로 자체 개발한 라이브러리를 서비스할때 hosted 리포지토리를 설정한다.
     

  • 여기서 ‘maven2(hosted) 타입으로 2개를 생성할 것이다.

Release 리포지토리 생성

  • 리포지토리 생성 화면에서 다음과 같이 입력한다.
    • Name: xxx-release
    • Version policy: Release
    • Deployment policy: Disable redeploy
  • 이름은 적절하게 설정하고, 나머지는 default로 둔다.

Snapshot 리포지토리 생성

  • 스냅샷 리포지토리도 다음과 같이 입력한다.
    • Name: xxx-snapshot
    • Version policy: Snapshot
    • Deployment policy: Allow redeploy
  • 이름을 적절하게 설정하고, Release 버전과 version policy와 Deployment policy 설정이 다름에 유의한다.

여기까지 진행하면 두 개의 리포지토리를 생성하였다.

사용자 생성 및 권한 부여

Role 생성

  • 톱니바퀴의 Security > Roles에서 롤을 생성할 수 있다.
  • 롤은 어떤 리포지토리에 접근할 수 있는지에 대한 정책을 설정하는 것이다.

User 생성

  • Security > Users에서 사용자를 생성할 수 있다.
  • 사용자를 생성하여 위에서 만든 Role을 부여할 수 있다.

 

Nexus에 라이브러리 배포 및 사용하기

(참고: 프로젝트는 빌드 툴으로 gradle kotlin을 사용한다.)

 

라이브러리 배포하기

프로젝트에 Nexus Repository URL과 인증 정보 추가

라이브러리의 배포와 사용을 위해 gradle.kts 스크립트 작성이 필요하다.

이때 사용할 URL과 인증 정보를 루트 경로의 gradle.properties 파일에 작성해 두었다.

NEXUS.SNAPSHOT_URL=http://localhost:8085/repository/xxx-snapshot/
NEXUS.RELEASE_URL=http://localhost:8085/repository/xxx-release/
NEXUS.USER_NAME=admin
NEXUS.PASSWORD=xxx

 

라이브러리로 발행할 모듈의 gradle.properties 파일에 group 정보 추가

  • 모듈을 Nexus Repository로 배포할 때 필요한 정보를 모듈의 gradle.properties에 추가한다.
  • application.name
  • application.version
  • application.group

예:

application.name=modules-test
application.version=1.0.0
application.group=kr.co.example.modules.test

이는 추후 implementation의 내부 경로 작성에 다음과 같이 사용된다.

implementation(”${application group 경로}:${application name}:${application version}”)

예 : implementation("kr.co.example.modules.test:modules-test:1.0.0")

(혹은 application.group의 경우 루트 경로에 정의해 두고 모듈별로 공용으로 사용해도 된다.)

 

라이브러리 발행을 위한 빌드 스크립트 작성

  • 빌드 스크립트는 발행 대상 모듈의 build.gradle.kts에서 다음 내용이 들어가도록 작성한다.
plugins {
    `maven-publish`
    // maven-publish 플러그인은 프로젝트를 Maven 리포지토리에 배포할 수 있게 한다.
}

publishing {
// publishing 블록은 프로젝트를 다양한 아웃풋 형식(예: JAR, WAR, ZIP)으로 패키징하고,
// 이를 원격 저장소에 배포하는 데 사용되는 설정을 정의한다.

    publications {
        // publications 블록에서는 배포할 아티팩트를 정의
        create<MavenPublication>("mavenJava") { // Maven 형식으로 아티팩트 배포
            from(components["java"]) // Java 컴포넌트를 가져와 배포할 아티팩트로 설정
            groupId = findProperty("application.group") as String
            artifactId = findProperty("application.name") as String
            version = findProperty("application.version") as String
        }
    }

    repositories {
        // repositories 블록에서는 아티팩트를 배포할 원격 저장소를 정의
        maven {
            if (findProperty("application.version").toString().endsWith("-SNAPSHOT")) {
                // 버전이 "-SNAPSHOT"으로 끝나는지 확인하여 스냅샷 저장소와 릴리스 저장소를 구분
                name = "snapshots"
                url = uri(findProperty("NEXUS.SNAPSHOT_URL") as String)
            } else {
                name = "releases"
                url = uri(findProperty("NEXUS.RELEASE_URL") as String)
            }
            credentials {
                username = findProperty("NEXUS.USER_NAME") as String
                password = findProperty("NEXUS.PASSWORD") as String
            }
            isAllowInsecureProtocol = true
            // Http 허용
        }
    }
}
  • 그런데 우리 프로젝트의 경우 여러 모듈에서 이 빌드 스크립트가 필요하기에, buildSrc 디렉토리에 위 내용을 별도의 파일로 작성하였다.
  • buildSrc 디렉토리는 빌드 스크립트의 공통 코드와 플러그인 코드를 모듈화하고 재사용하기 위해 사용된다. 이 디렉토리는 프로젝트의 루트 디렉토리에 위치하고, Gradle은 이 디렉토리를 자동으로 빌드 경로에 추가한다.
    • buildSrc 디렉토리에 작성된 코드는 Gradle 빌드 스크립트에서 공통으로 사용될 수 있으며, 이를 통해 반복되는 코드나 복잡한 로직을 모듈화하여 재사용 가능
    • Gradle 플러그인을 작성하여 buildSrc 디렉토리에 저장할 수 있다. 이렇게 작성된 플러그인은 프로젝트 내의 모든 빌드 스크립트에서 사용할 수 있다.
  • 라이브러리 발행이 필요한 곳에서는 이 플러그인만 추가하면 된다.
  • isAllowInsecureProtocol = true 설정은 Https가 아닌 Http 같은 보안되지 않은 프로토콜을 허용하는 옵션으로, Https 환경에서 사용 시 설정을 제거해준다.

 

참고: https://docs.gradle.org/current/userguide/custom_plugins.html

 

Understanding Plugins

A convention plugin is typically a precompiled script plugin that configures existing core and community plugins with your own conventions (i.e. default values) such as setting the Java version by using java.toolchain.languageVersion = JavaLanguageVersion.

docs.gradle.org

 

 

라이브러리 발행하기

  • 라이브러리를 NexusRepository에 발행하려면 배포하려는 모듈의 build.gradle.kts에서 위에서 저장한 라이브러리 발행 플러그인을 포함한다.
  • 예를 들어, 위의 라이브러리 발행 빌드 스크립트를 ‘nexus-repository-publish.gradle.kts’로 저장했다고 했을 때 모듈의 build.gradle.kts 에 다음과 같이 플러그인을 추가한다.
plugins {
    id("nexus-repository-publish")
}
  • 발행을 하려면 Gradle 탭의 해당 모듈에서 Tasks → publishing -> publish 를 실행한다.
  • application.version 의 버전 설정에 따라 release 혹은 snapshot 리포지토리로 발행된다.
    • application.version에 SNAPSHOT이라는 접미사가 붙으면 snapshot 리포지토리로 발행된다. 스냅샷 리포지토리는 같은 버전을 여러 번 발행할 수 있다.
      • 예 : application.version=1.0.0-SNAPSHOT
    • 그 이외에는 release 리포지토리로 발행된다. release 버전은 재발행이 안 되므로 한번 발행한 버전을 다시 발행하려 하면 오류가 발생한다.
      • 예 : application.version=1.0.0

등록된 라이브러리 사용하기

리포지토리 등록하기

  • 우선 Nexus Repository를 프로젝트에 추가해야 한다.
  • Nexus Repository를 사용할 곳의 build.gradle.kts 파일의 repositories {} 내부에 다음 내용을 추가하여 원격 저장소로부터 라이브러리를 가져오도록 한다.
repositories {
    // Nexus repository
    val nexusUrls = listOf(
        findProperty("NEXUS.RELEASE_URL") as String,
        findProperty("NEXUS.SNAPSHOT_URL") as String
    )

    nexusUrls.forEach { repoUrl ->
        maven {
            url = uri(repoUrl)
            credentials {
                username = findProperty("NEXUS.USER_NAME") as String
                password = findProperty("NEXUS.PASSWORD") as String
            }
            isAllowInsecureProtocol = true
        }
    }
}

 

의존성 라이브러리 추가하기

  • 우리 프로젝트에서는 모든 의존성을 Gradle Version Catalog로 관리하며, 이는 libs.versions.toml 파일에 정리되어 있다.
  • 따라서 라이브러리 의존성 추가 시 libs.versions.toml 파일의 [versions], [bundles], [libraries] 섹션에 순차적으로 추가해야 한다.

(참고 : gradle version catalog https://docs.gradle.org/current/userguide/platforms.html )

 

예: libs.versions.toml 파일

[versions]
modules-test = "1.0.0"

[bundles]
test-bundle = ["spring-boot-starter-web", "spring-boot-starter-aop", "modules-test"]

[libraries]
modules-test = { module = "kr.co.example.modules.test:modules-test", version.ref = "modules-test" }

 

번들을 의존하는 곳에서는 다음과 같은 의존성을 가진다.

dependencies {
    implementation(libs.bundles.test.bundle)
}

 

toml 파일을 사용하지 않는 프로젝트에서는 간단하게 이렇게 의존성을 추가하면 된다.

implementation("kr.co.example.modules.test:modules-test:1.0.0")