运行 Nexus 3 与 Docker 在 Kubernetes 集群中

Run Nexus 3 with Docker in a Kubernetes cluster

Kubernetes 中 运行 sonatype\nexus3 允许使用 Docker 存储库的最佳设置是什么?

目前我有一个基本设置:

如何绕过不允许多个端口的入口限制?

tl;博士

Nexus 需要通过 SSL 提供服务,否则 docker 将无法连接到它。这可以通过 k8s ingress + kube-lego for a Let's Encrypt 证书来实现。任何其他真实证书也可以使用。但是,为了通过一个入口(因此,一个端口)同时为 nexus UI 和 docker 注册表提供服务,需要在入口后面设置一个反向代理来检测 docker 用户代理和将请求转发给注册表。

                                                                             --(IF user agent docker) --> [nexus service]nexus:5000 --> docker registry
                                                                             |
[nexus ingress]nexus.example.com:80/ --> [proxy service]internal-proxy:80 -->|
                                                                             |
                                                                             --(ELSE                ) --> [nexus service]nexus:80   --> nexus UI

启动连接服务器

nexus-deployment.yaml 这使用了 azureFile 卷,但您可以使用任何卷。此外,由于显而易见的原因,未显示秘密。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nexus
  namespace: default

spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nexus
    spec:
      containers:
        - name: nexus
          image: sonatype/nexus3:3.3.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8081
            - containerPort: 5000
          volumeMounts:
            - name: nexus-data
              mountPath: /nexus-data
          resources:
            requests:
              cpu: 440m
              memory: 3.3Gi
            limits:
              cpu: 440m
              memory: 3.3Gi
      volumes:
        - name: nexus-data
          azureFile:
            secretName: azure-file-storage-secret
            shareName: nexus-data

添加运行状况和就绪探测器始终是个好主意,这样 kubernetes 就可以检测到应用何时宕机。点击 index.html 页面并不总是很好,所以我改用 REST API。这需要为具有 nx-script-*-browse 权限的用户添加授权 header。显然,您必须首先在没有探测的情况下启动系统来设置用户,然后再更新您的部署。

      readinessProbe:
        httpGet:
          path: /service/siesta/rest/v1/script
          port: 8081
          httpHeaders:
            - name: Authorization
              # The authorization token is simply the base64 encoding of the `healthprobe` user's credentials:
              # $ echo -n user:password | base64
              value: Basic dXNlcjpwYXNzd29yZA==
        initialDelaySeconds: 900
        timeoutSeconds: 60
      livenessProbe:
        httpGet:
          path: /service/siesta/rest/v1/script
          port: 8081
          httpHeaders:
            - name: Authorization
              value: Basic dXNlcjpwYXNzd29yZA==
        initialDelaySeconds: 900
        timeoutSeconds: 60

因为 nexus 有时需要很长时间才能启动,所以我使用了非常慷慨的初始延迟和超时。

nexus-service.yaml 为 UI 公开端口 80,为注册表公开端口 5000。这必须对应于通过 UI.

为注册表配置的端口
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nexus
  name: nexus
  namespace: default
  selfLink: /api/v1/namespaces/default/services/nexus

spec:
  ports:
  - name: http
    port: 80
    targetPort: 8081
  - name: docker
    port: 5000
    targetPort: 5000
  selector:
    app: nexus
  type: ClusterIP

启动反向代理(nginx)

proxy-configmap.yaml 添加nginx.conf作为ConfigMap数据卷。这包括用于检测 docker 用户代理的规则。这依赖于 kubernetes DNS 作为上游访问 nexus 服务。

apiVersion: v1
data:
  nginx.conf: |
    worker_processes auto;

    events {
        worker_connections 1024;
    }

    http {
        error_log /var/log/nginx/error.log warn;
        access_log  /dev/null;
        proxy_intercept_errors off;
        proxy_send_timeout 120;
        proxy_read_timeout 300;

        upstream nexus {
            server nexus:80;
        }

        upstream registry {
            server nexus:5000;
        }

        server {
            listen 80;
            server_name nexus.example.com;

            keepalive_timeout  5 5;
            proxy_buffering    off;

            # allow large uploads
            client_max_body_size 1G;

            location / {
            # redirect to docker registry
            if ($http_user_agent ~ docker ) {
                proxy_pass http://registry;
            }
            proxy_pass http://nexus;
            proxy_set_header Host $host;
            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 "https";
            }
        }
    }
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: internal-proxy-conf
  namespace: default
  selfLink: /api/v1/namespaces/default/configmaps/internal-proxy-conf

proxy-deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: internal-proxy
  namespace: default

spec:
  replicas: 1
  template:
    metadata:
      labels:
        proxy: internal
    spec:
      containers:
        - name: nginx
          image: nginx:1.11-alpine
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command: ["/usr/sbin/nginx","-s","quit"]
          volumeMounts:
            - name: internal-proxy-conf
              mountPath: /etc/nginx/
          env:
            # This is a workaround to easily force a restart by incrementing the value (numbers must be quoted)
            # NGINX needs to be restarted for configuration changes, especially DNS changes, to be detected
            - name: RESTART_
              value: "0"
      volumes:
        - name: internal-proxy-conf
          configMap:
            name: internal-proxy-conf
            items:
              - key: nginx.conf
                path: nginx.conf

proxy-service.yaml 代理特意为 ClusterIP 类型,因为入口会将流量转发给它。此示例中未使用端口 443。

kind: Service
apiVersion: v1
metadata:
  name: internal-proxy
  namespace: default

spec:
  selector:
    proxy: internal
  ports:
    - name: http
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 443
  type: ClusterIP

创建 Ingress

nexus-ingress.yaml 这一步假设你有一个 nginx 入口控制器。如果您有证书,则不需要入口,而是可以公开代理服务,但您将无法获得 kube-lego.

的自动化优势
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nexus
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    kubernetes.io/tls-acme: "true"

spec:
  tls:
    - hosts:
      - nexus.example.com
      secretName: nexus-tls
  rules:
    - host: nexus.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: internal-proxy
            servicePort: 80

我认为这可以通过使用 nginx ingress 来完成。通过为您的入口使用路径或子域。例如:

服务

apiVersion: v1
kind: Service
metadata:
  labels:
    app: nexus
  name: nexus
  namespace: default
  selfLink: /api/v1/namespaces/default/services/nexus

spec:
  ports:
  - name: http
    port: 80
    targetPort: 8081
  - name: docker
    port: 5000
    targetPort: 5000
  selector:
    app: nexus
  type: ClusterIP

入口

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nexus
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    kubernetes.io/tls-acme: "true"

spec:
  tls:
    - hosts:
        - nexus.example.com
        - docker.example.com
      secretName: nexus-tls
  rules:
    - host: nexus.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: nexus
            servicePort: 80
    - host: docker.example.com
      http:
        paths:
        - path: /
          backend:
            serviceName: nexus
            servicePort: 5000

此处 https://nexus.example.com 将带您访问 Nexus UI 以及在普通 HTTP 端口上运行的所有注册表功能。 https://docker.example.com:5000 将公开您的 docker 存储库。虽然这需要您使用两个不同的主机名,但它更明确一点并且不依赖于客户端正确设置用户代理。这也恰好是 Nexus Helm 图表使用的策略,如下所示:

https://github.com/kubernetes/charts/tree/master/stable/sonatype-nexus

使用 Helm 完成 Nexus 设置

这假设您的 nginx ingress 具有正确的 TLS 配置 运行 并且您的集群可以处理 Persistent Volume Claims:

安装 Nexus

使用 helm 在集群中安装 Nexus:

helm install stable/sonatype-nexus --name registry --namespace foo

注意:您可以使用此命令撤销安装:

helm del --purge registry

调整 Nexus 部署

使用 helm 安装 Nexus 后,您会发现 deployment 用于 Nexus。添加 containerPort: 5000 到它,就在已经存在的 containterPort 下面。

调整 Nexus 服务

您还需要将端口 5000 添加到 Nexus 服务。将其放在默认端口下方:

- port: 5000
  targetPort: 5000
  protocol: TCP
  name: docker 

Ingress 配置示例:

此配置将 https://registry.example.com 指向端口 8081 的 Nexus UI 并将 https://docker.exmaple.com 指向端口 [=18= 的 docker 服务].

注意:在我的例子中,端口 8081 是 Nexus 部署中提供的默认端口,您在上面的步骤中对其进行了编辑。如果您的安装使用另一个端口,请调整它。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-com-ingress
  namespace: foo
  annotations:
    kubernetes.io/ingress.class: nginx

spec:
  rules:

  # Provide the docker backend that is used for docker login.
  - host: docker.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: registry-sonatype-nexus
          servicePort: 5000

  # Provide the nexus backend that is used for the UI etc.
  - host: registry.exmaple.com
    http:
      paths:
      - path: /
        backend:
          serviceName: registry-sonatype-nexus
          servicePort: 8081

  tls:
  - secretName: example-com-tls
    hosts:
    - registry.example.com
    - docker.example.com

配置 Nexus

您现在应该可以在 https://registry.example.com 打开 Nexus UI。使用默认凭据登录。用户:admin 密码:admin123.

创建一个 docker 主机仓库并将 Repository Connector 下的 HTTP 设置为 5000 并禁用 Force Basic Authentication.

登录、打标签、推送图片

您现在应该能够使用 Nexus 登录凭据将您的 docker 客户端登录到注册表:

docker login docker.example.com

使用此模式标记和推送图像:

docker tag <image>:<tag> <nexus-hostname>/<namespace>/<image>:<tag>
docker push <nexus-hostname>/<namespace>/<image>:<tag>

例如:

docker tag myapp:1.0.0 docker.example.com/foo/myapp:1.0.0
docker push docker.example.com/foo/myapp:1.0.0