0%

搭建读高可用Nexus集群

一、架构

工作需要自己搭建维护一个Nexus集群,设计读高可用Nexus集群架构,参考[1]得到版本1架构设计如图1,版本2架构设计如图2,最终选用版本2架构设计,具体原因见“1.2、解决的问题及存在的问题”。

图1

图2

1.1、架构描述

1.1.1、版本1

设计有3个Nexus节点A,B,C,由于Nexus支持冷拷贝,因此通过冷拷贝进行A,B,C三个Nexus节点之间的同步,作者具体采用“rsync同步机制”作为同步实现。
节点A作为写入节点,Jenkins持续构建得到的包或者手动提交的包被写入到A,定时通过“rsync同步机制”保持B,C节点与A节点的同步,B,C节点作为读取节点,Maven客户端从B,C节点读取包数据。
为了获得读高可用,负载均衡和IP访问控制,在B,C节点与Maven客户端之间嵌入一个Nginx层。

1.1.2、版本2

设计有3个Nexus节点A,B,C,Jenkins持续构建得到的包或者手动提交的包写入时,重复写3份分别到A,B,C,读取A,B,C节点上包数据时通过Nginx反向代理,获得读高可用,负载均衡和IP访问控制。

1.2、解决的问题及存在的问题

1.2.1、版本1

以上架构设计解决问题如下:

  • 读取高可用
  • 数据丢失风险小

以上架构设计存在问题如下:

  • Jenkins存在单点故障风险
  • 写节点存在单点故障风险
  • Nginx存在单点故障风险
  • 虽然Nexus支持冷拷贝,但是冷拷贝后存在数据与Nexus进程内存数据不一致问题,导致不能实时同步,甚至导致不能正常运行,因此冷拷贝只适用于“冷拷贝,冷重启”场景,因此版本1架构设计存在致命缺陷

1.2.2、版本2

以上架构设计解决问题如下:

  • 读取高可用
  • 数据丢失风险小

以上架构设计存在问题如下:

  • Jenkins存在单点故障风险
  • Nginx存在单点故障风险

二、具体搭建

2.1、搭建Jenkins

在D上搭建Jenkins具体流程如下:

  1. 从官网下载最新的WAR包
  2. 执行java -jar jenkins.war --httpPort={自定义端口}命令运行Jenkins,使用“httpPort”选项配置自定义端口
  3. 访问“D:9091”,首次登录需要进行初始化配置,选择安装推荐插件,“admin”管理员用户的默认密码在“~/.jenkins/secrets/initialAdminPassword”文件内
  4. 可在“系统管理–>全局工具配置”下个性化配置JDK,Maven,Git等工具,否则使用默认配置

新建一个持续构建任务示例如下:

  1. 输入“任务名称”,选择“构建一个自由风格的软件项目”
  2. 在“源码管理”分栏下填写源码地址
  3. 在“构建触发器”分栏下选择构建触发逻辑类型,一般为“Poll SCM(定时查看源码是否有更新,如果有更新就进行一次构建)”,比如H/10 * * * *表示每隔10分钟查看源码是否有更新
  4. 在“构建环境”分栏下选择“Delete workspace before build starts”,避免旧构建结果对新构建的影响
  5. 在“构建”分栏下选择“Execute Shell”,输入构建命令,见构建命令示例1
  6. 在“构建后操作”分栏下选择“Archive the artifacts”,填写待打包资源的路径,比如target/*.jar

构建命令示例1

1
2
3
mvn deploy -Dmaven.test.skip=true -DaltDeploymentRepository=maven-releases::default::http://A:8081/repository/maven-releases/
mvn deploy -Dmaven.test.skip=true -DaltDeploymentRepository=maven-releases::default::http://B:8081/repository/maven-releases/
mvn deploy -Dmaven.test.skip=true -DaltDeploymentRepository=maven-releases::default::http://C:8081/repository/maven-releases/

2.2、搭建Nexus

具体选用Nexus OSS 3.6.0-02开源版本。

2.2.1、A节点

A节点具体搭建Nexus具体流程如下:

  1. 修改“bin/nexus”执行脚本中的INSTALL4J_JAVA_HOME_OVERRIDE变量,将其值设为1.8以上JDK的路径,执行bin/nexus start开启Nexus服务
  2. 开启的Nexus服务默认监听8081端口,通过A:8081进行访问,admin用户的默认密码为admin123
  3. Nexus的仓库有3种类型:“hosted,proxy,group”。“hosted”类型的仓库存储私人包;“proxy”类型的仓库代理远端仓库;“group”类型的仓库是组仓库,它管理多个仓库,访问它相当于访问该组下的所有仓库。Nexus默认配置有4个仓库:“maven-public(group类型),maven-releases(hosted类型),maven-snapshots(hosted类型),maven-central(proxy类型)”。“maven-central”默认代理官方Maven仓库(URL地址为:https://repo1.maven.org/maven2/),该代理仓库会缓存所代理的官方Maven仓库中的包,这样虽然会加快包获取速度,但是同时会大大增加硬盘占用大小,如果不需要可删除该代理仓库;Maven客户端直接使用“maven-public”组仓库即可,配置示例见配置示例1;“Release”版本的包发布到“maven-releases”仓库,配置示例见配置示例2;“Snapshot”版本的包发布到“maven-snapshots”仓库,配置示例见配置示例3

配置示例1

1
2
3
4
5
6
7
8
9
10
11
12
13
<repository>
<id>maven-public</id>
<name>Central Repository</name>
<url>http://A:8081/repository/maven-public/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>

配置示例2

1
2
3
4
5
6
7
8
9
10
11
12
13
# settings.xml
# 仓库的用户名和密码必须在settings.xml文件中配置,id属性作为唯一标识不一定需要是对应的仓库名称
<server>
<id>maven-releases</id>
<username>admin</username>
<password>admin123</password>
</server>

# 命令行
# 通过-D选项指定插件需要的系统变量
mvn deploy -Dmaven.test.skip=true -DaltDeploymentRepository=maven-releases::default::http://A:8081/repository/maven-releases/

mvn deploy:deploy-file -Dfile={待上传包路径} -DgroupId={包上传后的GroupId} -DartifactId={包上传后的ArtifactId} -Dversion={包上传后的版本号} -Dpackaging={包上传后的类型,一般为JAR} -DrepositoryId=maven-releases -Durl=http://A:8081/repository/maven-releases/

配置示例3

1
2
3
4
5
6
7
8
9
10
11
12
13
# settings.xml
# 仓库的用户名和密码必须在settings.xml文件中配置,id属性作为唯一标识不一定需要是对应的仓库名称
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>

# 命令行
# 通过-D选项指定插件需要的系统变量
mvn deploy -Dmaven.test.skip=true -DaltDeploymentRepository=maven-snapshots::default::http://A:8081/repository/maven-snapshots/

mvn deploy:deploy-file -Dfile={待上传包路径} -DgroupId={包上传后的GroupId} -DartifactId={包上传后的ArtifactId} -Dversion={包上传后的版本号} -Dpackaging={包上传后的类型,一般为JAR} -DrepositoryId=maven-snapshots -Durl=http://A:8081/repository/maven-snapshots/

备注:
上传到“maven-releases”仓库的JAR包“version”设置中禁止含有“SNAPSHOT”字符串;反之,上传到“maven-snapshots”仓库的JAR包“version”设置中必须含有“SNAPSHOT”字符串

2.2.2、B节点

B节点具体搭建Nexus具体流程如下:

  1. 修改“bin/nexus”执行脚本中的INSTALL4J_JAVA_HOME_OVERRIDE变量,将其值设为1.8以上JDK的路径
  2. 冷拷贝A节点上的Nexus数据目录“sonatype-work”
  3. 执行bin/nexus start开启Nexus服务

2.2.3、C节点

C节点具体搭建Nexus具体流程如下:

  1. 修改“bin/nexus”执行脚本中的INSTALL4J_JAVA_HOME_OVERRIDE变量,将其值设为1.8以上JDK的路径
  2. 冷拷贝A节点上的Nexus数据目录“sonatype-work”
  3. 执行bin/nexus start开启Nexus服务

2.3、搭建Nginx

具体选用Nginx-1.13.8版本,非root用户安装和使用Nginx。
参考[2],搭建Nginx具体流程如下:

  1. https://sourceforge.net/projects/pcre/files/pcre/下载最新的PCRE包,解压
  2. 解压Nginx包,进入解压后目录
  3. 执行./configure --prefix={Nginx安装到目录} --with-pcre={PCRE包路径} --without-http_gzip_module && make && make install命令,完成安装
  4. 进入安装到目录,配置“conf/nginx.conf”文件,需要注意的是,由于是非root用户使用Nginx,监听端口需要大于1024,一个示例配置见Nginx示例配置
  5. 进入安装到目录,执行sbin/nginx开启Nginx服务

Nginx示例配置

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
#user  nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;

events {
worker_connections 1024;
}

http {
upstream myapp1 {
#可以解决同一个会话的一系列请求被转发到不同服务器导致cookie获取异常的问题
ip_hash;

server A:8081;
server B:8081;
server C:8081;
}

server {
listen 8081;

location / {

allow 允许IP地址1;
allow 允许IP地址2;
allow 允许IP地址3;

deny all;

proxy_pass http://myapp1;
proxy_set_header Host $host:$server_port;
}
}
}

参考文献: [1]http://www.sonatype.org/nexus/2015/07/10/high-availability-ha-and-continuous-integration-ci-with-nexus-oss [2]https://gist.github.com/simonw/92481 [3]https://help.sonatype.com/display/NXRM3/Run+Behind+a+Reverse+Proxy [4]http://nginx.org/en/docs/http/load_balancing.html [5]https://ketao1989.github.io/2015/08/30/nginx-proxy-configure-and-sduty/ [6]http://www.cnblogs.com/xianyulaodi/p/6547807.html [7]https://serverfault.com/questions/598202/make-nginx-to-pass-hostname-of-the-upstream-when-reverseproxying [8]https://trac.nginx.org/nginx/ticket/501 [9]http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header [10]http://blog.51cto.com/1234567aaa/317802 [11]http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream [12]https://www.liaoxuefeng.com/article/001463233913442cdb2d1bd1b1b42e3b0b29eb1ba736c5e000
您的支持将鼓励我继续分享!