Contents

Nexus

Nexus

参考:

官网:https://help.sonatype.com/repomanager3/

介绍

生产环境中,一般不会允许所有服务器都能访问公网,理想的情况是有几台服务器作为访问代理,同时作为缓存服务器。当服务器中有所需包时通过内网获取,如无则通过公网获取同时在本地保存。常用搭建私有yum源的方法是createrepo生成本地仓库,其它服务器通过http访问仓库。这种方法的弊端是如果当前仓库中没有所需软件包会导致安装失败,不会去其它源获取数据。Nexus是一个强大的仓库管理器,它极大地简化了自己内部仓库的维护和外部仓库的访问。

Nexus是一个强大的Maven仓库管理器,它极大地简化了本地内部仓库的维护和外部仓库的访问。 如果使用了公共的Maven仓库服务器,可以从Maven中央仓库下载所需要的构件(Artifact),但这通常不是一个好的做法。

正常做法是在本地架设一个Maven仓库服务器,即利用Nexus可以只在一个地方就能够完全控制访问和部署在你所维护仓库中的每个Artifact。 Nexus在代理远程仓库的同时维护本地仓库,以降低中央仓库的负荷,节省外网带宽和时间,Nexus就可以满足这样的需要。

Nexus是一套“开箱即用”的系统不需要数据库,它使用文件系统加Lucene来组织数据。

Nexus使用ExtJS来开发界面,利用Restlet来提供完整的REST APIs,通过m2eclipse与Eclipse集成使用。

Nexus支持WebDAV与LDAP安全身份认证。

Nexus还提供了强大的仓库管理功能,构件搜索功能,它基于REST,友好的UI是一个extjs的REST客户端,它占用较少的内存,基于简单文件系统而非数据库。

为什么要构建Nexus私服?

如果没有Nexus私服,我们所需的所有构件都需要通过maven的中央仓库和第三方的Maven仓库下载到本地,而一个团队中的所有人都重复的从maven仓库下载构件无疑加大了仓库的负载和浪费了外网带宽,如果网速慢的话,还会影响项目的进程。很多情况下项目的开发都是在内网进行的,连接不到maven仓库怎么办呢?开发的公共构件怎么让其它项目使用?这个时候我们不得不为自己的团队搭建属于自己的maven私服,这样既节省了网络带宽也会加速项目搭建的进程,当然前提条件就是你的私服中拥有项目所需的所有构件。

同时Nexus支持仓库有:AptBowerCocoaPodsCondaDockerGit LFSGoMavenNpmNuGetPyPiRawRubyGemsYum

二、安装

二进制安装

# 下载地址
https://help.sonatype.com/repomanager3/download

# 解压
tar zxf nexus-3.23.0-03-unix.tar.gz
mv nexus-3.23.0-03 sonatype-work /data
echo 'NEXUS_HOME="/data/nexus-3.23.0-03"' >> ~/.bashrc
echo 'run_as_user="root"' >> /data/nexus-3.23.0-03/bin/nexus.rc

# 配置systemd服务
$ vim /etc/systemd/system/nexus.service

[Unit]
Description=nexus service
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/data/nexus-3.23.0-03/bin/nexus start
ExecStop=/data/nexus-3.23.0-03/bin/nexus stop
User=root
Restart=on-abort

[Install]
WantedBy=multi-user.target

# 启动服务
systemctl start nexus
# 此处启动后,请耐心等待,netstat -tunlp 查看端口8081监听后继续

# 查看admin用户的密码
cat /data/sonatype-work/nexus3/admin.password

基于docker安装nexus

mkdir -p /data/nexus/data && chown -R 200 /data/nexus/data
docker run -d -p 8081:8081 --name nexus -v /data/nexus/data:/nexus-data sonatype/nexus3

docker-compose安装

mkdir -p /data/nexus/data && chown -R 200 /data/nexus/data

# docker-compose 
cat >docker-compose.yaml <<EOF
version: "3"
services:
  nexus3:
    image: sonatype/nexus3
    container_name: nexus3
    restart: always
    privileged: true
    environment:
      - TZ=Asia/Shanghai
    ports:
      - '8081:8081'
    volumes:
      - /data/nexus/data:/nexus-data
EOF

查看密码

管理员:admin
密码:cat /data/nexus/data/admin.passwor

nginx代理设置

upstream nexus-server{
    server 127.0.0.1:8081;
}

#server {
#    listen 80;
#    server_name mirrors.cccc.io;
#    location / {
#        return 301 https://xx.xx;
#    }

#    location ~ /.well-known {
#        root /tmp;
#    }
#}


server {
    listen 80;
    server_name nexus.local.com;
    client_max_body_size       1024m;
    client_body_buffer_size    128k;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_max_temp_file_size 0;
        proxy_pass http://nexus-server;
        

   	    proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;

        proxy_temp_file_write_size 64k;

        # Required for new HTTP-based CLI
        #proxy_http_version 1.1;
        #proxy_request_buffering off;
        #proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    	    
    }
    #ssl_certificate cert/xx.pem;
    #ssl_certificate_key cert/xx.key;

}

server {
    listen 80;
    server_name  mirrors.local.com ;
    client_max_body_size       1024m;
    client_body_buffer_size    128k;
    charset utf-8;
    location / {
        proxy_pass http://nexus.local.com/repository/;
        proxy_set_header Host nexus.local.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    access_log /var/log/nginx/mirrors.log;
    error_log /var/log/nginx/mirrors-error.log;
}

docker nginx

# compose.yaml
version: "3"
services:
  nexus3:
    image: sonatype/nexus3:3.67.1-java11
    container_name: nexus3
    restart: always
    privileged: true
    environment:
      - TZ=Asia/Shanghai
    ports:
      - '8081:8081'
    volumes:
      - /data/nexus:/nexus-data
      - /data/nexus-databackup:/nexus3-databackup

  nginx:
    container_name: nginx
    image: nginx
    restart: always
    privileged: true
    volumes:
      - "/etc/localtime:/etc/localtime:ro"
      - "${PWD}/ssl:/etc/nginx/cert_files"
      - "${PWD}/config:/etc/nginx/conf.d"
      - "/data/nginx/log:/var/log/nginx"
    network_mode: "host" 
    
    
# config/nexus.conf 
upstream nexus-local {
    server localhost:8081;
}
server {
    listen 80;
    server_name  nexus.local.com ;
    charset utf-8;
    client_max_body_size       100m;
    client_body_buffer_size    12800k;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;    
        proxy_pass http://nexus-local;
    }
    access_log /var/log/nginx/nexus.log;
    error_log /var/log/nginx/nexus-error.log;
}

server {
    listen 443 ssl;
    server_name  nexus.local.com ;
    charset utf-8;
    client_max_body_size       100m;
    client_body_buffer_size    12800k;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme; 
        proxy_pass http://nexus-local;
    }
    ssl_certificate /etc/nginx/cert_files/local.com.crt;
    ssl_certificate_key /etc/nginx/cert_files/local.com.key;
    access_log /var/log/nginx/nexus.log;
    error_log /var/log/nginx/nexus-error.log;
}

二、nexus仓库

Nexus 仓库按照类型(Type)区分,主要分为以下 3 个类型:

  • 代理仓库(proxy):主要用于代理缓存访问外网上其他公开的仓库,将每次从代理仓库拉取的制品缓存到nexus文件系统中,下次再拉取相同版本制品时就不需再次从外网拉取,起到代理访问缓存的功能。
  • 宿主仓库(hosted):类型的仓库主要用于存放各个项目组产出的、用于共享、不能放到公网上、私有的制品。有两种版本策略,一种是Snapshots版本策略类型的,对于相同版本制品的上传,nexus会自动追加时间戳加以区分;一种是Release版本策略类型的,对于相同的制品,要明确版本,不能存放相同版本。可以理解为snapshots仓库存放一些内容变更频繁的制品,这样不管上传还是使用时不用频繁变更版本号就能拉取到最新版本。而release仓库存放一些内容稳定变更少的制品,使用时指定好版本就行,无需经常变动。
  • 仓库组(group):主要用于组合其他仓库,统一对外使用方式。可设置组仓库组合其他仓库的顺序。例如组合顺序为先拉取maven格式aliyun代理仓库中的制品,如果其中没有想要的制品,再去拉取maven格式Central代理仓库中的制品。如果还没有,就去maven格式hosted类型仓库中拉取,直到遍历完所有的组合仓库。同时,拉取使用时不需要配置那么多的仓库地址,只需要配置group仓库地址就行。

group仓库可以包含proxy和hosted类型的仓库,并对外提供统一的服务

1、yum

1)创建 proxy 类型格式为 yum 的 repo

2)创建group类型的 repo,在 member repository 中增加proxy 类型的repo

3)yum 源配置 group的地址

2、npm

1)创建 proxy 类型的 repo

​ 创建proxy类型的repo,可以创建多个

# 官方地址
https://registry.npmjs.org/

# 阿里云地址
https://registry.npmmirror.com

# 腾讯
http://mirrors.cloud.tencent.com/npm/

# 华为
https://repo.huaweicloud.com/repository/npm/

# 南京大学
https://repo.nju.edu.cn/repository/npm/

2)创建group类型的 repo,在 member repository 中增加proxy 类型的repo

3) npm 配置 group的地址

# 配置 npm默认源
npm config set registry http://nexus.local.com/repository/npm

# 或者直接使用npm命令
npm install -y --registry=http://nexus.local.com/repository/npm/

3、pypi

1)创建 proxy 类型的 repo

​ 创建proxy类型的repo,可以创建多个

# 阿里云
https://mirrors.aliyun.com/pypi

# tuna
https://pypi.tuna.tsinghua.edu.cn

# huaweicloud
https://mirrors.huaweicloud.com/repository/pypi/

# nju
https://mirror.nju.edu.cn/pypi/web/

# sjtu
https://mirror.sjtu.edu.cn/pypi/web

2)创建group类型的 repo,在 member repository 中增加proxy 类型的repo

3)配置 group的地址

vim .pip/pip.conf
[global]
index-url = http://nexus.local.com/repository/pypi/simple
trusted-host = nexus.local.com
timeout = 120
# 不配置pip.conf直接使用
pip3 install redis   -i http://mirrors.local.com/pypi/simple --truste
d-host mirrors.local.com

4、maven

1)创建 proxy 类型的 repo

​ 创建proxy类型的repo,可以创建多个

# maven-central
https://maven.aliyun.com/repository/central

# maven-confluent
https://packages.confluent.io/maven/

2)创建group类型的 repo,在 member repository 中增加proxy 类型的repo

3)配置 group的地址

settings.xml

<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
                      https://maven.apache.org/xsd/settings-1.0.0.xsd">
    <localRepository>/usr/share/maven/ref/repository</localRepository>
    <mirrors>
        <mirror>
            <id>nexus</id>
            <name>nexus</name>
            <url>http://nexus.local.com/repository/maven/</url>
            <mirrorOf>*</mirrorOf>
        </mirror>
    </mirrors>
</settings>

5、apt

以debian仓库作为示例

1)创建 proxy 类型格式为 apt 的 repo,APT Settings —> Distribution 配置为 * ,Proxy —> Remote storage 配置为debian apt 源的地址

2)配置 proxy 的地址

# 示例:	
https://mirrors.ustc.edu.cn/debian/   
https://nexus.local.com/repositories/debian/

# 修改命令
sed -i 's+\w*.debian.org+nexus.local.com/repository+g' /etc/apt/sources.list

6、alpine

目前 nexus 官方暂时不支持配置 alpine proxy,但有社区开发了插件支持 alpine apk 代理

1)安装插件:到 https://central.sonatype.com/ 中搜索对应插件,并下载对应的 jar 包。下载后把 jar 包复制到nexus目录中的deploy目录里

https://sonatype-nexus-community.github.io/nexus-development-guides/plugin-install.html

# for docker 

wget https://repo1.maven.org/maven2/org/sonatype/nexus/plugins/nexus-repository-apk/0.0.26/nexus-repository-apk-0.0.26.jar 

docker cp nexus-repository-apk-0.0.26.jar nexus3:/opt/sonatype/nexus/deploy

2)创建 proxy 类型格式为 apk 的 repo,

3)配置 apk 源

sed -i 's+https://dl-cdn.alpinelinux.org+http://nexus.local.com/repository+g' /etc/apk/repositories

4)自定义镜像

wget https://repo1.maven.org/maven2/org/sonatype/nexus/plugins/nexus-repository-apk/0.0.26/nexus-repository-apk-0.0.26.jar 


# dockerfile
FROM sonatype/nexus3:3.68.1-java11

ADD nexus-repository-apk-0.0.26.jar /opt/sonatype/nexus/deploy/ 

7、docker

1)在nexus3 后台页面中创建一个repository,类型选择docker(proxy)

2)填入相关参数

  • Name:repo 名

  • Allow anonymous docker pull:允许未登录的用户拉取镜像,看自己情况勾选

  • Proxy-Remote storage:代理的docker 镜像源。可以填入docker 官方镜像源https://registry-1.docker.io

  • Proxy-Docker Index:选择 Use Docker Hub

  • Storage-Blob store:本地镜像存储的地址

  • HTTP-Authentication:选填,UsernamePassword 填入docker 官网的用户名和密码,填的话每天可以下载更多镜像(大概是这么个效果,但不填影响不大)

    点击Create repository创建

3)创建一个host repo

host repo 作为本地创建的镜像的存放地址,如果不想将镜像存到docker hub,就可以上传到这边。

a、在nexus3 后台页面中创建一个repository,类型选择docker(host)

b、填入相关参数

  • Name:repo 名

  • HTTP:用于推送到本repo 的http 端口,8082

  • Allow anonymous docker pull:允许未登录的用户拉取镜像,看自己情况勾选

  • Storage-Blob store:本地镜像存储的地址

  • Host-Deployment policy:上传镜像的规则

    • Allow redeploy:允许重传,一般选择这个即可
    • Disable redeploy:禁止重传

    点击Create repository创建

4)创建一个group repo

group repo 可以将多个其他repo 聚合起来,拉取镜像时直接选择group repo 即可。

  1. 在nexus3 后台页面中创建一个repository,类型选择docker(group)

  2. 填入相关参数

    • Name:repo 名
    • HTTP:用于下载镜像的http 端口,8083
    • Allow anonymous docker pull:允许未登录的用户拉取镜像,看自己情况勾选
    • Storage-Blob store:本地镜像存储的地址
    • Group-Menber repositiories:当前repo 包括的其他repo,将之前创建host repo 和proxy repo 加入右边的Members列表中(host repo 可以优先于proxy repo,以优先拉取本地上传的镜像)

    点击Create repository创建

5)启用Docker Bearer Token Realm以允许docker 登录nexus

​ a、进入nexus 后台管理页面,Security - Realms

​ b、将Docker Bearer Token Realm添加到右边Active栏内

​ c、保存

6)nginx配置文件

# web管理控制台
upstream nexus_web {
    server 10.0.0.5:8081;
}

# docker-group聚合仓库
upstream nexus_docker_get {
    server 10.0.0.5:8083;
}

# docker-hosted本地仓库
upstream nexus_docker_put {
    server 10.0.0.5:8082;

}

# HTTP 自动跳转 HTTPS
server {
    listen 80;
    # 设置docker代理使用的域名,你可以将 docker-registry.hellogitlab.com 替换成你的域名
    server_name docker.local.com;
    rewrite ^ https://$http_host$request_uri? permanent;
}

server {
    # 由于上面设置了HTTP 自动跳转 HTTPS,此处注释掉80端口
    # listen 80;
    listen 443 ssl;
    # 设置docker代理使用的域名,你可以将 docker-registry.hellogitlab.com 替换成你的域名
    server_name docker.local.com;
    # 设置日志文件,对应的日志格式使用main
    # main日志格式,在nginx.conf中log_format  main行定义过
    access_log /var/log/nginx/docker-registry.log main;
    error_log /var/log/nginx/docker-registry-error.log;
    # 证书
    ssl_certificate    /etc/nginx/cert_files/local.com.crt;
    ssl_certificate_key /etc/nginx/cert_files/local.com.key;
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:';
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # disable any limits to avoid HTTP 413 for large image uploads
    client_max_body_size 0;
    # required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
    chunked_transfer_encoding on;

    # 请求逻辑调整
    # 设置默认使用docker-group聚合仓库,即拉取镜像的情况多些
    set $upstream "nexus_docker_put";
    # 当请求是GET,也就是拉取镜像的时候,这里改为拉取代理,如此便解决了拉取和推送的端口统一
    if ( $request_method ~* 'GET') {
        set $upstream "nexus_docker_get";
    }    
    # 我测试的时候,docker-hosted本地仓库和docker-proxy代理仓库都支持搜索,所以将下面这段逻辑调整注释掉
    # 只有本地仓库才支持搜索,所以将搜索请求转发到本地仓库,否则出现 500 报错
    # if ($request_uri ~ '/search') {
    #    set $upstream "nexus_docker_put"; 
    # }

    index index.html index.htm index.php;
    location / {
        proxy_pass http://$upstream;
        proxy_set_header Host $host;
        proxy_connect_timeout 3600;
        proxy_send_timeout 3600;
        proxy_read_timeout 3600;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 直接使用以下配置【proxy_set_header X-Forwarded-Proto http; 】时,
        # 在尝试向仓库中push推送镜像时,就是docker login登陆成功了也会报以下认证异常
        # unauthorized: access to the requested resource is not authorized
        # proxy_set_header X-Forwarded-Proto http;
        # 修复docker push认证异常问题,将http替换成https即可
        proxy_set_header X-Forwarded-Proto https;
    }
}

配置docker registry-mirrors

  • harbor 也可以搭建 registry-mirrors
{
  "insecure-registries" : ["docker.local.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": [
      "https://docker.local.com"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  },
  "dns": ["119.29.29.29", "223.5.5.5"],
  "data-root": "/var/lib/docker"
}

重启docker服务,拉取镜像测试

  • 若遇到docker login denied ,则可以先 docker logout
[root@dev ~]# docker pull build/alpine:3.20
Error response from daemon: pull access denied for build/alpine, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
[root@dev ~]# docker logout 
Removing login credentials for https://index.docker.io/v1/
[root@dev ~]# docker pull build/alpine:3.20
3.20: Pulling from build/alpine
d25f557d7f31: Already exists 
Digest: sha256:216266c86fc4dcef5619930bd394245824c2af52fd21ba7c6fa0e618657d4c3b
Status: Downloaded newer image for build/alpine:3.20
docker.io/build/alpine:3.20

三、数据接入prometheus

grafana模板:

155563 https://grafana.com/grafana/dashboards/16459

neuxs 官方参考地址:

https://help.sonatype.com/repomanager3/nexus-repository-administration/support-features#SupportFeatures-Prometheus

配置文件模板

global:
  scrape_interval: 15s
  scrape_timeout: 10s
  evaluation_interval: 15s
alerting:
  alertmanagers:
  - static_configs:
    - targets: []
    scheme: http
    timeout: 10s
scrape_configs:
- job_name: nxrm
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /service/metrics/prometheus
  scheme: http
  basic_auth:
    username: admin
    password: admin123
  static_configs:
  - targets:
    - localhost:8081

四、数据清理

nexus的repo在删除多个目标后,会发现实际物理磁盘并没有释放出来,是因为在后台只是被标记为deletion,若要清理,需要创建一个task去清理。

1、创建一个定时任务,任务类型为Admin Compact Blobstore,然后填写定时任务详情

2、手动运行一下定时任务,task回慢慢清理blob的数据

五、主从同步

可以使用nexus proxy repo去实现主从同步,也可定时同步数据

#/bin/bash
# sync nexus data to bak server

# 限速 3MB/s
rsync --delete -avzP --bwlimit=3000 --chown=200:200 /data/nexus/  root@172.16.80.234:/data/nexus

备 nexus上的数据在启动服务的时候可能需要修改一下数据权限,具体操作需要观察一下nexus日志

chart数据同步

#!/usr/bin/env bash
src_repo=http://nexus.local.local.cc/repository/helm   
src_repo_name=local
dst_repo=http://nexus.local.cc/repository/helm   
dst_repo_name=newlocal

# add repo for helm 
#helm repo add ${src_repo_name} ${src_repo}
#helm repo add ${dst_repo_name} ${dst_repo}
#helm repo update

befor_time="20221104160208"
end_time="20230328093331"

user=ccccc
password=dddddd


project_list=$(helm search repo ${src_repo_name} |  awk '{print $1}' | grep -v NAME | awk -F '/' '{print $2}')

for project in ${project_list} ;do 
    version_list=$(helm search repo ${src_repo_name}/${project} -l  | awk '{print $2}')
    for version in ${version_list};do 
        if [[ ${version} -gt ${befor_time} ]];then 
            if [[ ${version} -lt ${end_time} ]];then
                
                helm fetch ${src_repo_name}/${project} --version ${version}
                helm nexus-push ${dst_repo_name}  ${project}-${version}.tgz  -u ${user} -p ${password}
            fi
        fi    

    done 
done

六、Terraform

目前 nexus 没有 api 提供去配置 cleanup policy,需要配置 nexus 运行运行 script ,使用groovy脚本进行添加

开启nexus 允许运行script

# nexus_dir/etc/nexus.properties
nexus.scripts.allowCreation=true

重启 nexus