第40集企业级Nexus私服Maven仓库管理与CI/CD集成 | 字数总计: 5.9k | 阅读时长: 32分钟 | 阅读量:
1. Nexus私服概述 Nexus Repository Manager是Sonatype公司开发的企业级仓库管理工具,支持Maven、npm、Docker等多种包管理格式。在企业环境中,使用Nexus私服可以显著提升构建效率、保障依赖安全、实现统一管理。
1.1 核心优势
依赖缓存 : 减少对外网依赖的访问,提升构建速度
安全控制 : 统一管理依赖版本,避免安全漏洞
离线构建 : 支持内网环境下的项目构建
版本管理 : 统一管理企业内部组件版本
CI/CD集成 : 与持续集成工具无缝集成
1.2 技术架构 1 2 3 4 5 开发环境 → Maven/Gradle → Nexus私服 → 中央仓库 ↓ ↓ ↓ ↓ 本地构建 → 依赖下载 → 缓存管理 → 外部依赖 ↓ ↓ ↓ ↓ CI/CD → 自动化构建 → 版本发布 → 生产部署
2. Nexus安装与配置 2.1 Docker安装Nexus 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 version: '3.8' services: nexus: image: sonatype/nexus3:latest container_name: nexus3 restart: unless-stopped ports: - "8081:8081" - "8082:8082" volumes: - nexus-data:/nexus-data - ./nexus.properties:/opt/sonatype/nexus/etc/nexus.properties environment: - INSTALL4J_ADD_VM_PARAMS=-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g networks: - nexus-network volumes: nexus-data: driver: local networks: nexus-network: driver: bridge
2.2 Nexus配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 nexus.scripts.allowCreation =true nexus.security.randompassword =false nexus.datastore.enabled =true nexus.datastore.nexus.h2.cacheSize =256 nexus.security.userSource =default nexus.security.realms =NexusAuthenticatingRealm,NexusAuthorizingRealm,DockerToken nexus.threads.corePoolSize =8 nexus.threads.maxPoolSize =200 nexus.threads.keepAliveTime =60 nexus.log.level =INFO nexus.log.appenders =console,file nexus.log.file.path =/nexus-data/log/nexus.log
2.3 启动脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #!/bin/bash echo "启动Nexus私服..." if ! docker info > /dev/null 2>&1; then echo "Docker未运行,请先启动Docker" exit 1 fi mkdir -p ./nexus-data/logmkdir -p ./nexus-data/tmpmkdir -p ./nexus-data/cachechmod 777 ./nexus-datadocker-compose up -d echo "等待Nexus启动..." sleep 30if curl -s http://localhost:8081/service/rest/v1/status > /dev/null; then echo "Nexus启动成功!" echo "访问地址: http://localhost:8081" echo "默认用户名: admin" echo "默认密码: admin123" else echo "Nexus启动失败,请检查日志" docker-compose logs nexus fi
3. Maven仓库配置 3.1 仓库类型说明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class RepositoryTypes { public enum RepositoryType { HOSTED("hosted" , "托管仓库" , "存储内部开发的组件" ), PROXY("proxy" , "代理仓库" , "代理外部仓库,如Maven中央仓库" ), GROUP("group" , "组仓库" , "组合多个仓库,提供统一访问入口" ); private final String type; private final String name; private final String description; RepositoryType(String type, String name, String description) { this .type = type; this .name = name; this .description = description; } public String getType () { return type; } public String getName () { return name; } public String getDescription () { return description; } } public enum ReleasePolicy { RELEASE("Release" , "发布版本" , "存储稳定版本" ), SNAPSHOT("Snapshot" , "快照版本" , "存储开发版本" ), MIXED("Mixed" , "混合版本" , "同时存储发布和快照版本" ); private final String policy; private final String name; private final String description; ReleasePolicy(String policy, String name, String description) { this .policy = policy; this .name = name; this .description = description; } public String getPolicy () { return policy; } public String getName () { return name; } public String getDescription () { return description; } } }
3.2 仓库创建配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 @Component public class MavenRepositoryConfig { public RepositoryConfig createHostedRepository (String name, String policy) { return RepositoryConfig.builder() .name(name) .format("maven2" ) .type("hosted" ) .online(true ) .storage(StorageConfig.builder() .blobStoreName("default" ) .strictContentTypeValidation(true ) .writePolicy(policy) .build()) .maven(MavenConfig.builder() .versionPolicy(policy) .layoutPolicy("STRICT" ) .build()) .build(); } public RepositoryConfig createProxyRepository (String name, String remoteUrl) { return RepositoryConfig.builder() .name(name) .format("maven2" ) .type("proxy" ) .online(true ) .storage(StorageConfig.builder() .blobStoreName("default" ) .strictContentTypeValidation(true ) .build()) .proxy(ProxyConfig.builder() .remoteUrl(remoteUrl) .contentMaxAge(1440 ) .metadataMaxAge(1440 ) .build()) .negativeCache(NegativeCacheConfig.builder() .enabled(true ) .timeToLive(1440 ) .build()) .httpClient(HttpClientConfig.builder() .blocked(false ) .autoBlock(true ) .connection(ConnectionConfig.builder() .retries(3 ) .userAgentSuffix("Nexus-Proxy" ) .timeout(60 ) .build()) .build()) .maven(MavenConfig.builder() .versionPolicy("RELEASE" ) .layoutPolicy("STRICT" ) .build()) .build(); } public RepositoryConfig createGroupRepository (String name, List<String> memberRepositories) { return RepositoryConfig.builder() .name(name) .format("maven2" ) .type("group" ) .online(true ) .storage(StorageConfig.builder() .blobStoreName("default" ) .strictContentTypeValidation(true ) .build()) .group(GroupConfig.builder() .memberNames(memberRepositories) .build()) .build(); } } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class RepositoryConfig { private String name; private String format; private String type; private boolean online; private StorageConfig storage; private ProxyConfig proxy; private NegativeCacheConfig negativeCache; private HttpClientConfig httpClient; private MavenConfig maven; private GroupConfig group; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class StorageConfig { private String blobStoreName; private boolean strictContentTypeValidation; private String writePolicy; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ProxyConfig { private String remoteUrl; private int contentMaxAge; private int metadataMaxAge; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class NegativeCacheConfig { private boolean enabled; private int timeToLive; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class HttpClientConfig { private boolean blocked; private boolean autoBlock; private ConnectionConfig connection; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ConnectionConfig { private int retries; private String userAgentSuffix; private int timeout; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class MavenConfig { private String versionPolicy; private String layoutPolicy; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class GroupConfig { private List<String> memberNames; }
3.3 仓库管理服务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 @Service public class RepositoryManagementService { @Autowired private NexusApiClient nexusApiClient; public void createMavenRepositories () { try { RepositoryConfig mavenCentral = createProxyRepository( "maven-central" , "https://repo1.maven.org/maven2/" ); nexusApiClient.createRepository(mavenCentral); RepositoryConfig springReleases = createProxyRepository( "spring-releases" , "https://repo.spring.io/release/" ); nexusApiClient.createRepository(springReleases); RepositoryConfig springSnapshots = createProxyRepository( "spring-snapshots" , "https://repo.spring.io/snapshot/" ); nexusApiClient.createRepository(springSnapshots); RepositoryConfig internalReleases = createHostedRepository( "internal-releases" , "RELEASE" ); nexusApiClient.createRepository(internalReleases); RepositoryConfig internalSnapshots = createHostedRepository( "internal-snapshots" , "SNAPSHOT" ); nexusApiClient.createRepository(internalSnapshots); List<String> groupMembers = Arrays.asList( "maven-central" , "spring-releases" , "spring-snapshots" , "internal-releases" , "internal-snapshots" ); RepositoryConfig mavenPublic = createGroupRepository( "maven-public" , groupMembers ); nexusApiClient.createRepository(mavenPublic); System.out.println("Maven仓库创建完成" ); } catch (Exception e) { System.err.println("创建Maven仓库失败: " + e.getMessage()); e.printStackTrace(); } } private RepositoryConfig createProxyRepository (String name, String remoteUrl) { return RepositoryConfig.builder() .name(name) .format("maven2" ) .type("proxy" ) .online(true ) .storage(StorageConfig.builder() .blobStoreName("default" ) .strictContentTypeValidation(true ) .build()) .proxy(ProxyConfig.builder() .remoteUrl(remoteUrl) .contentMaxAge(1440 ) .metadataMaxAge(1440 ) .build()) .negativeCache(NegativeCacheConfig.builder() .enabled(true ) .timeToLive(1440 ) .build()) .httpClient(HttpClientConfig.builder() .blocked(false ) .autoBlock(true ) .connection(ConnectionConfig.builder() .retries(3 ) .userAgentSuffix("Nexus-Proxy" ) .timeout(60 ) .build()) .build()) .maven(MavenConfig.builder() .versionPolicy("RELEASE" ) .layoutPolicy("STRICT" ) .build()) .build(); } private RepositoryConfig createHostedRepository (String name, String policy) { return RepositoryConfig.builder() .name(name) .format("maven2" ) .type("hosted" ) .online(true ) .storage(StorageConfig.builder() .blobStoreName("default" ) .strictContentTypeValidation(true ) .writePolicy(policy) .build()) .maven(MavenConfig.builder() .versionPolicy(policy) .layoutPolicy("STRICT" ) .build()) .build(); } private RepositoryConfig createGroupRepository (String name, List<String> memberRepositories) { return RepositoryConfig.builder() .name(name) .format("maven2" ) .type("group" ) .online(true ) .storage(StorageConfig.builder() .blobStoreName("default" ) .strictContentTypeValidation(true ) .build()) .group(GroupConfig.builder() .memberNames(memberRepositories) .build()) .build(); } }
4. Maven客户端配置 4.1 settings.xml配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 <?xml version="1.0" encoding="UTF-8" ?> <settings xmlns ="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd" > <localRepository > ${user.home}/.m2/repository</localRepository > <interactiveMode > true</interactiveMode > <offline > false</offline > <pluginGroups > <pluginGroup > org.apache.maven.plugins</pluginGroup > <pluginGroup > org.codehaus.mojo</pluginGroup > </pluginGroups > <proxies > </proxies > <servers > <server > <id > nexus-releases</id > <username > admin</username > <password > admin123</password > </server > <server > <id > nexus-snapshots</id > <username > admin</username > <password > admin123</password > </server > <server > <id > nexus-public</id > <username > admin</username > <password > admin123</password > </server > </servers > <mirrors > <mirror > <id > nexus-public</id > <mirrorOf > central</mirrorOf > <name > Nexus Public Repository</name > <url > http://localhost:8081/repository/maven-public/</url > </mirror > </mirrors > <profiles > <profile > <id > development</id > <activation > <activeByDefault > true</activeByDefault > </activation > <properties > <maven.compiler.source > 11</maven.compiler.source > <maven.compiler.target > 11</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <repositories > <repository > <id > nexus-public</id > <name > Nexus Public Repository</name > <url > http://localhost:8081/repository/maven-public/</url > <releases > <enabled > true</enabled > <updatePolicy > daily</updatePolicy > </releases > <snapshots > <enabled > true</enabled > <updatePolicy > always</updatePolicy > </snapshots > </repository > </repositories > <pluginRepositories > <pluginRepository > <id > nexus-public</id > <name > Nexus Public Repository</name > <url > http://localhost:8081/repository/maven-public/</url > <releases > <enabled > true</enabled > <updatePolicy > daily</updatePolicy > </releases > <snapshots > <enabled > true</enabled > <updatePolicy > always</updatePolicy > </snapshots > </pluginRepository > </pluginRepositories > </profile > <profile > <id > production</id > <properties > <maven.compiler.source > 11</maven.compiler.source > <maven.compiler.target > 11</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <repositories > <repository > <id > nexus-releases</id > <name > Nexus Releases Repository</name > <url > http://localhost:8081/repository/internal-releases/</url > <releases > <enabled > true</enabled > <updatePolicy > never</updatePolicy > </releases > <snapshots > <enabled > false</enabled > </snapshots > </repository > </repositories > </profile > </profiles > <activeProfiles > <activeProfile > development</activeProfile > </activeProfiles > </settings >
4.2 pom.xml配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > com.example</groupId > <artifactId > nexus-demo</artifactId > <version > 1.0.0-SNAPSHOT</version > <packaging > jar</packaging > <name > Nexus Demo Project</name > <description > Nexus私服演示项目</description > <properties > <maven.compiler.source > 11</maven.compiler.source > <maven.compiler.target > 11</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <spring-boot.version > 2.7.0</spring-boot.version > </properties > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-dependencies</artifactId > <version > ${spring-boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > <version > ${spring-boot.version}</version > <executions > <execution > <goals > <goal > repackage</goal > </goals > </execution > </executions > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.1</version > <configuration > <source > 11</source > <target > 11</target > <encoding > UTF-8</encoding > </configuration > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-deploy-plugin</artifactId > <version > 2.8.2</version > <configuration > <skip > true</skip > </configuration > </plugin > </plugins > </build > <distributionManagement > <repository > <id > nexus-releases</id > <name > Nexus Releases Repository</name > <url > http://localhost:8081/repository/internal-releases/</url > </repository > <snapshotRepository > <id > nexus-snapshots</id > <name > Nexus Snapshots Repository</name > <url > http://localhost:8081/repository/internal-snapshots/</url > </snapshotRepository > </distributionManagement > <repositories > <repository > <id > nexus-public</id > <name > Nexus Public Repository</name > <url > http://localhost:8081/repository/maven-public/</url > <releases > <enabled > true</enabled > <updatePolicy > daily</updatePolicy > </releases > <snapshots > <enabled > true</enabled > <updatePolicy > always</updatePolicy > </snapshots > </repository > </repositories > <pluginRepositories > <pluginRepository > <id > nexus-public</id > <name > Nexus Public Repository</name > <url > http://localhost:8081/repository/maven-public/</url > <releases > <enabled > true</enabled > <updatePolicy > daily</updatePolicy > </releases > <snapshots > <enabled > true</enabled > <updatePolicy > always</updatePolicy > </snapshots > </pluginRepository > </pluginRepositories > </project >
5. 权限管理与安全 5.1 用户和角色管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 @Service public class NexusUserManagementService { @Autowired private NexusApiClient nexusApiClient; public void createUsers () { try { UserConfig developer = UserConfig.builder() .userId("developer" ) .firstName("Developer" ) .lastName("User" ) .emailAddress("developer@example.com" ) .password("developer123" ) .status("active" ) .roles(Arrays.asList("nx-developer" )) .build(); nexusApiClient.createUser(developer); UserConfig deployer = UserConfig.builder() .userId("deployer" ) .firstName("Deployer" ) .lastName("User" ) .emailAddress("deployer@example.com" ) .password("deployer123" ) .status("active" ) .roles(Arrays.asList("nx-deployment" )) .build(); nexusApiClient.createUser(deployer); UserConfig reader = UserConfig.builder() .userId("reader" ) .firstName("Reader" ) .lastName("User" ) .emailAddress("reader@example.com" ) .password("reader123" ) .status("active" ) .roles(Arrays.asList("nx-readonly" )) .build(); nexusApiClient.createUser(reader); System.out.println("用户创建完成" ); } catch (Exception e) { System.err.println("创建用户失败: " + e.getMessage()); e.printStackTrace(); } } public void createRoles () { try { RoleConfig developerRole = RoleConfig.builder() .id("nx-developer" ) .name("Developer" ) .description("开发者角色,可以下载和上传快照版本" ) .privileges(Arrays.asList( "nx-repository-view-maven2-*-read" , "nx-repository-view-maven2-*-browse" , "nx-repository-view-maven2-internal-snapshots-read" , "nx-repository-view-maven2-internal-snapshots-browse" , "nx-repository-view-maven2-internal-snapshots-add" , "nx-repository-view-maven2-internal-snapshots-edit" )) .roles(Arrays.asList("nx-anonymous" )) .build(); nexusApiClient.createRole(developerRole); RoleConfig deployerRole = RoleConfig.builder() .id("nx-deployment" ) .name("Deployment" ) .description("部署角色,可以上传发布版本" ) .privileges(Arrays.asList( "nx-repository-view-maven2-*-read" , "nx-repository-view-maven2-*-browse" , "nx-repository-view-maven2-internal-releases-read" , "nx-repository-view-maven2-internal-releases-browse" , "nx-repository-view-maven2-internal-releases-add" , "nx-repository-view-maven2-internal-releases-edit" )) .roles(Arrays.asList("nx-anonymous" )) .build(); nexusApiClient.createRole(deployerRole); RoleConfig readonlyRole = RoleConfig.builder() .id("nx-readonly" ) .name("Read Only" ) .description("只读角色,只能查看和下载" ) .privileges(Arrays.asList( "nx-repository-view-maven2-*-read" , "nx-repository-view-maven2-*-browse" )) .roles(Arrays.asList("nx-anonymous" )) .build(); nexusApiClient.createRole(readonlyRole); System.out.println("角色创建完成" ); } catch (Exception e) { System.err.println("创建角色失败: " + e.getMessage()); e.printStackTrace(); } } } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class UserConfig { private String userId; private String firstName; private String lastName; private String emailAddress; private String password; private String status; private List<String> roles; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class RoleConfig { private String id; private String name; private String description; private List<String> privileges; private List<String> roles; }
5.2 安全策略配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 @Service public class NexusSecurityConfigService { @Autowired private NexusApiClient nexusApiClient; public void configureSecurityPolicies () { try { createContentSelectors(); createPrivileges(); createSecurityPolicies(); System.out.println("安全策略配置完成" ); } catch (Exception e) { System.err.println("配置安全策略失败: " + e.getMessage()); e.printStackTrace(); } } private void createContentSelectors () { ContentSelectorConfig internalSelector = ContentSelectorConfig.builder() .name("internal-components" ) .description("内部组件选择器" ) .expression("format == 'maven2' and path =~ '^/com/example/.*'" ) .build(); nexusApiClient.createContentSelector(internalSelector); ContentSelectorConfig thirdPartySelector = ContentSelectorConfig.builder() .name("third-party-components" ) .description("第三方组件选择器" ) .expression("format == 'maven2' and path =~ '^/(org|com|net)/.*'" ) .build(); nexusApiClient.createContentSelector(thirdPartySelector); } private void createPrivileges () { PrivilegeConfig internalPrivilege = PrivilegeConfig.builder() .name("nx-repository-view-maven2-internal-*" ) .description("内部组件权限" ) .type("application" ) .properties(Map.of( "contentSelector" , "internal-components" , "repository" , "maven-public" , "actions" , "browse,read" )) .build(); nexusApiClient.createPrivilege(internalPrivilege); PrivilegeConfig thirdPartyPrivilege = PrivilegeConfig.builder() .name("nx-repository-view-maven2-third-party-*" ) .description("第三方组件权限" ) .type("application" ) .properties(Map.of( "contentSelector" , "third-party-components" , "repository" , "maven-public" , "actions" , "browse,read" )) .build(); nexusApiClient.createPrivilege(thirdPartyPrivilege); } private void createSecurityPolicies () { SecurityPolicyConfig internalPolicy = SecurityPolicyConfig.builder() .name("internal-components-policy" ) .description("内部组件安全策略" ) .contentSelectors(Arrays.asList("internal-components" )) .actions(Arrays.asList("browse" , "read" , "add" , "edit" )) .build(); nexusApiClient.createSecurityPolicy(internalPolicy); SecurityPolicyConfig thirdPartyPolicy = SecurityPolicyConfig.builder() .name("third-party-components-policy" ) .description("第三方组件安全策略" ) .contentSelectors(Arrays.asList("third-party-components" )) .actions(Arrays.asList("browse" , "read" )) .build(); nexusApiClient.createSecurityPolicy(thirdPartyPolicy); } } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ContentSelectorConfig { private String name; private String description; private String expression; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class PrivilegeConfig { private String name; private String description; private String type; private Map<String, String> properties; } @Data @Builder @NoArgsConstructor @AllArgsConstructor public class SecurityPolicyConfig { private String name; private String description; private List<String> contentSelectors; private List<String> actions; }
6. CI/CD集成 6.1 Jenkins集成配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 pipeline { agent any environment { NEXUS_URL = 'http://localhost:8081' NEXUS_REPOSITORY = 'internal-releases' NEXUS_CREDENTIALS = 'nexus-credentials' } stages { stage('Checkout' ) { steps { checkout scm } } stage('Build' ) { steps { sh 'mvn clean compile' } } stage('Test' ) { steps { sh 'mvn test' } post { always { junit 'target/surefire-reports/*.xml' } } } stage('Package' ) { steps { sh 'mvn package -DskipTests' } } stage('Deploy to Nexus' ) { steps { script { if (env.BRANCH_NAME == 'main' ) { sh 'mvn deploy -DskipTests' } else { sh 'mvn deploy -DskipTests -Dmaven.test.skip=true' } } } } stage('Docker Build' ) { steps { script { def image = docker.build("nexus-demo:${env.BUILD_NUMBER}" ) docker.withRegistry('http://localhost:8082' , 'nexus-docker-credentials' ) { image.push() image.push('latest' ) } } } } } post { always { cleanWs() } success { echo 'Pipeline executed successfully' } failure { echo 'Pipeline failed' } } }
6.2 GitHub Actions集成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 name: CI/CD Pipeline on: push: branches: [ main , develop ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up JDK 11 uses: actions/setup-java@v3 with: java-version: '11' distribution: 'temurin' - name: Cache Maven dependencies uses: actions/cache@v3 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Build with Maven run: mvn clean compile - name: Run tests run: mvn test - name: Package run: mvn package -DskipTests - name: Deploy to Nexus if: github.ref == 'refs/heads/main' run: mvn deploy -DskipTests env: NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} - name: Deploy Snapshot to Nexus if: github.ref == 'refs/heads/develop' run: mvn deploy -DskipTests -Dmaven.test.skip=true env: NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
6.3 Maven插件配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-deploy-plugin</artifactId > <version > 2.8.2</version > <configuration > <skip > false</skip > </configuration > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-release-plugin</artifactId > <version > 2.5.3</version > <configuration > <tagNameFormat > v@{project.version}</tagNameFormat > <releaseProfiles > release</releaseProfiles > <goals > deploy</goals > </configuration > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-source-plugin</artifactId > <version > 3.2.1</version > <executions > <execution > <id > attach-sources</id > <goals > <goal > jar</goal > </goals > </execution > </executions > </plugin > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-javadoc-plugin</artifactId > <version > 3.3.2</version > <executions > <execution > <id > attach-javadocs</id > <goals > <goal > jar</goal > </goals > </execution > </executions > </plugin > </plugins > </build >
7. 监控和维护 7.1 健康检查脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #!/bin/bash NEXUS_URL="http://localhost:8081" ADMIN_USER="admin" ADMIN_PASS="admin123" echo "开始Nexus健康检查..." echo "检查Nexus服务状态..." if curl -s -f "$NEXUS_URL /service/rest/v1/status" > /dev/null; then echo "✓ Nexus服务运行正常" else echo "✗ Nexus服务异常" exit 1 fi echo "检查仓库状态..." repositories=("maven-central" "spring-releases" "spring-snapshots" "internal-releases" "internal-snapshots" "maven-public" ) for repo in "${repositories[@]} " ; do if curl -s -f "$NEXUS_URL /service/rest/v1/repositories/$repo " > /dev/null; then echo "✓ 仓库 $repo 正常" else echo "✗ 仓库 $repo 异常" fi done echo "检查存储空间..." disk_usage=$(df -h /var/lib/docker/volumes/nexus_nexus-data | awk 'NR==2 {print $5}' | sed 's/%//' ) if [ "$disk_usage " -lt 80 ]; then echo "✓ 存储空间充足: ${disk_usage} %" else echo "⚠ 存储空间不足: ${disk_usage} %" fi echo "检查日志错误..." error_count=$(docker logs nexus3 2>&1 | grep -i error | wc -l) if [ "$error_count " -eq 0 ]; then echo "✓ 无错误日志" else echo "⚠ 发现 $error_count 个错误日志" fi echo "Nexus健康检查完成"
7.2 备份脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/bin/bash BACKUP_DIR="/backup/nexus" NEXUS_DATA_DIR="/var/lib/docker/volumes/nexus_nexus-data" DATE=$(date +%Y%m%d_%H%M%S) echo "开始Nexus备份..." mkdir -p "$BACKUP_DIR " echo "备份Nexus数据..." docker run --rm -v nexus_nexus-data:/data -v "$BACKUP_DIR " :/backup alpine tar czf "/backup/nexus-data-$DATE .tar.gz" -C /data . echo "备份配置文件..." cp -r ./nexus-data/etc "$BACKUP_DIR /nexus-config-$DATE " echo "清理旧备份..." find "$BACKUP_DIR " -name "nexus-data-*.tar.gz" -mtime +7 -delete find "$BACKUP_DIR " -name "nexus-config-*" -mtime +7 -exec rm -rf {} \; echo "Nexus备份完成: $BACKUP_DIR /nexus-data-$DATE .tar.gz"
7.3 监控配置 1 2 3 4 5 6 7 8 9 10 global: scrape_interval: 15s scrape_configs: - job_name: 'nexus' static_configs: - targets: ['localhost:8081' ] metrics_path: '/service/rest/v1/status' scrape_interval: 30s
8. 总结 通过Nexus私服的搭建和配置,我们成功构建了一个企业级的Maven仓库管理系统。关键特性包括:
8.1 核心优势
依赖管理 : 统一管理内部和外部依赖
安全控制 : 完善的用户权限和访问控制
性能提升 : 本地缓存减少网络依赖
CI/CD集成 : 与持续集成工具无缝集成
监控维护 : 完善的监控和备份机制
8.2 最佳实践
仓库规划 : 合理规划仓库类型和策略
权限管理 : 基于角色的权限控制
安全策略 : 内容选择器和安全策略
自动化 : CI/CD自动化部署
监控维护 : 定期健康检查和备份
这套Nexus私服方案不仅能够满足企业级Maven仓库管理的需求,还为其他包管理格式提供了扩展基础,是现代Java企业开发的重要基础设施。