跳过正文
  1. 博客文章/

使用 helm 在 Kubernetes 中部署 Nexus 私服

·1047 字·5 分钟·
Kubernetes DevOps Helm Nexus3 Kubernetes
Zayn
作者
Zayn
专注 Kubernetes、CI/CD、可观测性等云原生技术栈,记录生产环境中的实战经验与踩坑复盘。
目录

环境说明
#

  • helm version: v3.3.1
  • kubernetes: v1.17.9
  • nexus: 3.29.0

部署
#

准备 storageClass
#

必要 操作,可以选择手动创建 pvc & pv,如果想部署 nfsStorageClass 的话,请参考早期整理的 文档。此篇文档实战部署步骤中基于 nfsStorageClass 进行实现。如果是用于 生产环境 的话,还是建议使用 ssd 或 iops 较高的 磁盘 作为数据盘使用,数据盘管理方式可以使用 localPv or hostPath 绑定到对应节点进行运行。

使用 helm 进行安装
#

添加 helm 仓库
#

helm repo add stable https //charts.helm.sh/stable

helm repo update

设置部署 values.yaml 配置文件
#

可以执行下面命令进行查看 默认 模板部署文件,或点击此 链接 查看。

helm show values stable/sonatype-nexus

修改后,完整 values.yaml 文件展示

cat > prod-values.yaml << EOF
statefulset:  # 使用 statefulset 进行部署
  enabled: true

nexus:
  imageName: sonatype/nexus3
  imageTag: 3.30.1 
  imagePullPolicy: IfNotPresent
  env:
    - name: install4jAddVmParams
      value: "-Xms1200M -Xmx1200M -XX:MaxDirectMemorySize=2G -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
    - name: NEXUS_SECURITY_RANDOMPASSWORD
      value: "false"
    - name: TZ
      value: "Asia/Shanghai"
  resources: 
    limits:
     cpu: 4
     memory: 8192Mi
    requests:
     cpu: 250m
     memory: 4800Mi

persistence:
  enabled: true
  storageClass: "nfs-retain"
  storageSize: "100Gi"

service:
  name: nexus-service
  enabled: true
  serviceType: ClusterIP
  ports:
  - name: manage   # 此处为 service 对应暴露的端口, 如需暴露其他端口时,向下进行添加即可。
    targetPort: 8081
    port: 8081
  - name: docker-proxy
    targetPort: 8082
    port: 8082
  - name: docker-dev
    targetPort: 8083
    port: 8083
  - name: docker-qa  
    targetPort: 8084
    port: 8084
  - name: docker-prod
    targetPort: 8085
    port: 8085
  - name: docker-custom
    targetPort: 8086
    port: 8086
nexusProxy:
  enabled: false
EOF

创建部署应用
#

kubectl create ns nexus

helm upgrade --install nexus  -f ./prod-values.yaml  -n nexus stable/sonatype-nexus # 部署安装

image-20210523162416847

使用 traefik 将其暴露
#

traefik 部署安装使用,请参考 此篇文档

cat nexus-ingressroute.yaml 
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: nexus-mirror
  namespace: nexus
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`mirror.treesir.pub`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: nexus-service
      port: 8081

kubectl apply -f ./nexus-ingressroute.yaml 

image-20210523162902742

初始化U/P: admin: admin123

Docker 私服的配置与优化
#

此步骤文档,记录创建 customdevqaprod 环境的 docker 私服,并配置常见 docker proxy 类型私服,进行中间镜像的缓存进行使用。

仓库规划
#

docker 私服端口 使用规划
#

私服名称私服作用私服类型私服端口
docker-custom存放,自定义 push的 镜像,与项目环境无关hostd8086
idocker.io代理仓库 & custom 仓库的集合group8082
docker-dev存放与项目dev环境镜像hostd8083
docker-qa存放与项目qa环境镜像hostd8084
docker-prod存放与项目prod环境镜像hostd8085

docker 代理仓库列表
#

名称私服类型说明地址
docker-googleproxygoogle 公开镜像 (需扶墙)https://gcr.io
docker-k8sproxykubernetes 的官方 google 镜像源(需扶墙)https://k8s.gcr.io
docker-aliyunproxyaliyun 同步 docker 官方源 (存在部分镜像未同步问题)https://7bezldxe.mirror.aliyuncs.com
docker-officialproxydockerhub 官方镜像地址(限制带宽,触发条件:匿名用户100次,认证用户200次)https://registry-1.docker.io

私服创建
#

创建 hostd 类型私服
#

且示例创建 docker-custom , 其他仓库创建步骤是一样的,且需更具实际使用情况 更改 Deployment policy 策略 & 是否开启 匿名拉取镜像 即可,如在 prod 环境下,设置策略为 Disable redeploy ,即不允许对已存在的镜像做覆盖操作,push 时将提示错误。

  • 创建 docker 使用的 blob 存储

    建议对不同仓库类型的 私服做一下,blob存储的隔离 (可选)

    image-20210608120921089

  • 选择创建 hostd 类型 docker 私服

    image-20210608120857805

    image-20210608121148991

    image-20210608121249427

创建 proxy 类型代理私服
#

且示例创建 docker-official 私服,因官方对匿名用户做了拉取到100次后,将降低带宽的使用,我们可以在配置的过程中,为其添加用户认证来增加拉取限制。

  • 选择创建 proxy 类型 docker 私服

    image-20210608121818153

    image-20210608122129261

    image-20210608122321922

    image-20210608122431537

创建 group 类型私服
#

创建完成 对应 的 proxy 类型的私服后,就可以进行 group 类型私服, 一组仓库的集合的创建了。

  • 组集合列表,如下所示

    image-20210608122810520

  • 创建 group 组 idocker.io

    image-20210608122923180

    image-20210608123030930

    image-20210608123121924

配置 neuxs3 开启 使用 docker的认证管理
#

默认情况下,docker 认证在 neuxs3 中是没有被打开的,这里需要配置开启一下才行,不然会导致 执行 docker login 不成功。

image-20210610112948251

image-20210610113029463

image-20210610113048664

使用 ingress 对端口进行暴露
#

在使用 traefik 暴露的docker私服中,因默认开启了 443 端口的监听,此时 docker 私服将默认使用 websecure 入口上的 ingressroute 路由规则,如不添加对应证书的话,将导致 match 上的规则不被匹配

创建 tls 证书生成脚本
#

gen-cert.sh 证书签发脚本,如下所示:

#!/bin/bash
# scripts from https://www.jianshu.com/p/52fedb82ef53

usage()  
{  
    echo "Usage: $0 [-a [rsa|ecc]] [-d <domain>] [-n <name>] [-h]"  
    echo "  Options:"
    echo "    -a  algorithm.[rsa|ecc]"
    echo "    -d  domain.example: xxx.com,abc.org,*.abc.org"
    echo "    -n  server key name"   
    echo "    -h  help"  
    exit 1  
} 

srv_key_name="server"

while getopts "a:d:n:h" arg #选项后面的冒号表示该选项需要参数
do
    case $arg in
        a)
            alg=$OPTARG #算法
            ;;
        d)
            all_domain=$OPTARG #域名,逗号分隔
            ;;
        n)
            srv_key_name=$OPTARG #服务器证书名称
            ;;
        h)
            usage
            exit 0
            ;;
        ?)  #当有不认识的选项的时候arg为?
            usage
            exit 1
            ;;
    esac
done

domain="domain.com"
san="DNS:*.${domain},DNS:${domain}"
if [ -n "${all_domain}" ]; then
    #分割域名
    OLD_IFS="$IFS"  
    IFS="," 
    domain_array=($all_domain)
    IFS="$OLD_IFS"  

    domain_len=${#domain_array[@]} 
      
    domain=${domain_array[0]}
    san=""
    for ((i=0;i<domain_len;i++))
   {
    if [ $i = 0 ];then
        san="DNS:${domain_array[i]}"
    else
        san="${san},DNS:${domain_array[i]}"
    fi
   }
fi

ca_subj="/C=CN/ST=Hubei/L=Wuhan/O=MY/CN=MY CA"
server_subj="/C=CN/ST=Hubei/L=Wuhan/O=MY/CN=${domain}"
#其中C是Country,ST是state,L是local,O是Organization,OU是Organization Unit,CN是common name
days=14610 # 有效期40年
echo "san:${san}"

sdir="certs"
ca_key_file="${sdir}/ca.key"
ca_crt_file="${sdir}/ca.crt"
srv_key_file="${sdir}/${srv_key_name}.key"
srv_csr_file="${sdir}/${srv_key_name}.csr"
srv_crt_file="${sdir}/${srv_key_name}.crt"
srv_p12_file="${sdir}/${srv_key_name}.p12"
srv_fullchain_file="${sdir}/${srv_key_name}-fullchain.crt"
cfg_san_file="${sdir}/san.cnf"


#algorithm config
if [[ ${alg} = "rsa" ]] ; then
    rsa_len=2048
elif [[ ${alg} = "ecc" ]] ; then
    ecc_name=prime256v1
else 
    usage 
    exit 1
fi     #ifend

echo "algorithm:${alg}"

mkdir -p ${sdir}

if [ ! -f "${ca_key_file}" ]; then
    echo  "------------- gen ca key-----------------------"
    if [[ ${alg} = "rsa" ]] ; then
        openssl genrsa -out ${ca_key_file} ${rsa_len}
    elif [[ ${alg} = "ecc" ]] ; then
        openssl ecparam -out ${ca_key_file} -name ${ecc_name} -genkey
    fi     #ifend

    openssl req -new -x509 -days ${days} -key ${ca_key_file} -out ${ca_crt_file} -subj "${ca_subj}"
fi


if [ ! -f "${srv_key_file}" ]; then
    echo  "------------- gen server key-----------------------"
    if [[ ${alg} = "rsa" ]] ; then
        openssl genrsa -out ${srv_key_file} ${rsa_len}
    elif [[ ${alg} = "ecc" ]] ; then
        openssl ecparam -genkey -name ${ecc_name} -out ${srv_key_file}
    fi     #ifend

    openssl req -new  -sha256 -key ${srv_key_file} -out ${srv_csr_file} -subj "${server_subj}"

    printf "[ SAN ]\nauthorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE\nkeyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment\nsubjectAltName=${san}" > ${cfg_san_file}
    openssl x509 -req  -days ${days} -sha256 -CA ${ca_crt_file} -CAkey ${ca_key_file} -CAcreateserial -in ${srv_csr_file}  -out ${srv_crt_file} -extfile ${cfg_san_file} -extensions SAN
    cat ${srv_crt_file} ${ca_crt_file} > ${srv_fullchain_file}

    openssl pkcs12 -export -inkey ${srv_key_file} -in ${srv_crt_file} -CAfile ${ca_crt_file} -chain -out ${srv_p12_file}
fi

脚本使用用法

./gen-cert.sh -a 算法 -d 域名 -n 证书文件名

执行脚本生成 tls 证书文件
#

由于 traefik 在使用 secret 资源对象引用证书文件时,名称必须是 tls.crttls.key,这里我们在创建的时候就将名称设置为 tls

chmod a+x gen-cert.sh

./gen-cert.sh -a ecc -d idocker.io,*.idocker.io -n tls

ls certs/  # 在对应目录下,有如下文件即可
ca.crt  ca.key  ca.srl  san.cnf  tls.crt  tls.csr  tls-fullchain.crt  tls.key  tls.p12

将生成的证书,使用 secret 资源对象进行存储
#

kubectl create secret tls idocker-tls --cert=certs/tls.crt --key=certs/tls.key -n nexus

kubectl get secret idocker-tls -n nexus -o yaml 

image-20210608145341615

更新 traefik ingress 资源对象
#

最终,完整 nexus-ingressroute.yaml 配置文件如下所示:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: nexus-mirror
  namespace: nexus
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`mirror.treesir.pub`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: nexus-service
      port: 8081

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: nexus-idocker-http
  namespace: nexus
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`idocker.io`) || (Host(`idocker.io`) && Method(`GET`)) 
    kind: Rule
    services:
    - name: nexus-service
      port: 8082
  - match: (Host(`idocker.io`) && Path(`/v1/search`)) || (Host(`idocker.io`) && Method(`PUT`,`HEAD`,`POST`,`PATCH`))
    kind: Rule
    priority: 100  # 权重值提高,在执行 curl https://idocker.io/v1/search?q=nginx 时,确认路由至 dokcer-custom 私服中
    services:
    - name: nexus-service
      port: 8086
  - match: Host(`dev.idocker.io`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: nexus-service
      port: 8083
  - match: Host(`qa.idocker.io`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: nexus-service
      port: 8084
  - match: Host(`prod.idocker.io`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: nexus-service
      port: 8085
  tls:
    secretName: idocker-tls

---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
  namespace: nexus
spec:
  redirectScheme:
    scheme: https

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name:  nexus-idocker-https
  namespace: nexus
spec:
  entryPoints:
    - web
  routes:
  - match: HostRegexp(`idocker.io`, `{subdomain:[a-z]+}.idocker.io`)
    kind: Rule
    services:
    - name: nexus-service
      port: 8082
    middlewares: 
    - name: redirect-https

私服的使用
#

ingressroute 创建完成后,就是测试对应私服的使用了,直接拿来使用还不行,会提示证书报错,解决方法列表如下:

  • 将对应 CA 证书文件,复制到 /etc/docker/certs.d/idocker.io 目录即可,没有此目录则选择创建它

    mkdir -p /etc/docker/certs.d/idocker.io
    scp node1:/data/helm/nexus/certs/ca.crt /etc/docker/certs.d/idocker.io/
    
    mkdir -p /etc/docker/certs.d/qa.idocker.io
    cp /etc/docker/certs.d/idocker.io/ca.crt  /etc/docker/certs.d/qa.idocker.io/
    

    image-20210608160819915

由于,不支持对泛域名的一次认证,如多个子域名时,还需进行一个多次的 copy 操作。

  • 在对应 docker 配置中添加 --insecure-registry 参数,来忽略证书的校验,常见做法是:

    • 将配置项更改添加至 /etc/docker/daemon.json 配置文件中

      cat /etc/docker/daemon.json 
      {
          "insecure-registries": [
              "idocker.io",
              "dev.idocker.io",
              "qa.idocker.io",
              "prod.idocker.io"
          ]
      }
      
  • 或者是在 /usr/lib/systemd/system/docker.service 启动文件中的, ExecStart 配置项中添加启动参数

    ExecStart=/usr/bin/dockerd --insecure-registry idocker.io,dev.idocker.io...
    

参考文档
#

nexus 其他高级使用说明,请参考 此篇文档

https://doc.traefik.io/traefik/routing/routers/

https://www.jianshu.com/p/52fedb82ef53

Todo
#

相关文章

Kubernetes 部署企业级 Kafka 集群完整指南
·3156 字·15 分钟
Kafka Helm Kubernetes Zookeeper Kubernetes Streaming
Rancher 开启监控后,exporter/metrics 的添加说明 (二)
·1294 字·7 分钟
K8s DevOps Kubernetes Prometheus Rancher +5
Rancher 开启监控后的,阈值告警配置说明 (三)
·285 字·2 分钟
K8s DevOps Kubernetes Prometheus Rancher +5