今日天气
  1. 博客/

使用 helm 在 Kubernetes 中部署 Nexus 私服

·2270 字·5 分钟· ·
k8s devops helm nexus3
Johny
作者
Johny
熟练的 云原生搬砖师
Table of Contents

环境说明
#

  • 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
#

相关文章

Rancher 开启监控后,exporter/metrics 的添加说明 (二)
·2662 字·6 分钟·
devops k8s prometheus rancher prometheus operator k8s kubekey exporter metrics
在 Kubernetes 中部署 nfs storageClass
·1026 字·3 分钟·
devops k8s storage-class nfs
Rancher 开启监控后的,阈值告警配置说明 (三)
·1032 字·3 分钟·
devops k8s prometheus alertmanage rancher prometheus operator k8s kubekey exporter
Rancher 开启监控,及生产应用的优化配置工作说明 (一)
·2785 字·6 分钟·
devops k8s prometheus rancher prometheus operator k8s kubekey exporter
使用 Confluentinc 在 Kubernetes 集群中部署 Kafka 集群
·1133 字·3 分钟·
k8s kafka zookeeper helm
初探 Traefik ingress gateway
·1594 字·4 分钟·
k8s devops traefik