2

我有一个运行 Jenkins Pod 的 Kubernetes 集群,该集群为 Metallb 设置了服务。目前,当我尝试在loadBalancerIP集群外部访问 pod 时,我无法做到。我还有一个kube-verify在集群上运行的 pod,它的服务也使用 Metallb。当我尝试在我的集群之外击中那个 pod 时,我可以毫无问题地击中它。

当我将 Jenkins pod 的服务切换为类型NodePort时,它可以工作,但是一旦我将其切换回类型LoadBalancer,它就会停止工作。Jenkins pod 和工作kube-verifypod 都在同一个节点上运行。

集群详细信息:主节点正在运行并以无线方式连接到我的路由器。在主节点上,我设置了 dnsmasq 以及将连接从无线端口转发到以太网端口的 iptable 规则。每个节点通过以太网通过交换机连接在一起。Metallb 在 layer2 模式下设置,地址池与主节点无线端口的 IP 地址位于同一子网中。kube-proxy设置为使用和strictArp模式ipvs

詹金斯清单:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
---
apiVersion: v1
kind: Secret
metadata:
  name: jenkins-secret
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
type: Opaque
data:
  jenkins-admin-password: ***************
  jenkins-admin-user: ********
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: jenkins
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
data:
  jenkins.yaml: |-
    jenkins:
      authorizationStrategy:
        loggedInUsersCanDoAnything:
          allowAnonymousRead: false
      securityRealm:
        local:
          allowsSignup: false
          enableCaptcha: false
          users:
          - id: "${jenkins-admin-username}"
            name: "Jenkins Admin"
            password: "${jenkins-admin-password}"
      disableRememberMe: false
      mode: NORMAL
      numExecutors: 0
      labelString: ""
      projectNamingStrategy: "standard"
      markupFormatter:
        plainText
      clouds:
      - kubernetes:
          containerCapStr: "10"
          defaultsProviderTemplate: "jenkins-base"
          connectTimeout: "5"
          readTimeout: 15
          jenkinsUrl: "jenkins-ui:8080"
          jenkinsTunnel: "jenkins-discover:50000"
          maxRequestsPerHostStr: "32"
          name: "kubernetes"
          serverUrl: "https://kubernetes"
          podLabels:
          - key: "jenkins/jenkins-agent"
            value: "true"
          templates:
            - name: "default"
          #id: eeb122dab57104444f5bf23ca29f3550fbc187b9d7a51036ea513e2a99fecf0f
              containers:
              - name: "jnlp"
                alwaysPullImage: false
                args: "^${computer.jnlpmac} ^${computer.name}"
                command: ""
                envVars:
                - envVar:
                    key: "JENKINS_URL"
                    value: "jenkins-ui:8080"
                image: "jenkins/inbound-agent:4.11-1"
                ttyEnabled: false
                workingDir: "/home/jenkins/agent"
              idleMinutes: 0
              instanceCap: 2147483647
              label: "jenkins-agent"
              nodeUsageMode: "NORMAL"
              podRetention: Never
              showRawYaml: true
              serviceAccount: "jenkins-sa"
              slaveConnectTimeoutStr: "100"
              yamlMergeStrategy: override
      crumbIssuer:
        standard:
          excludeClientIPFromCrumb: true
    security:
      apiToken:
        creationOfLegacyTokenEnabled: false
        tokenGenerationOnCreationEnabled: false
        usageStatisticsEnabled: true
    unclassified:
      location:
        adminAddress:
        url: jenkins-ui:8080
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins-pv-volume
  labels:
    type: local
spec:
  storageClassName: local-storage
  claimRef:
    name: jenkins-pv-claim
    namespace: devops-tools
  capacity:
    storage: 16Gi
  accessModes:
    - ReadWriteMany
  local:
    path: /mnt
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - heine-cluster1
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pv-claim
  namespace: devops-tools
  labels:
    app: jenkins
    version: v1
    tier: backend
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 8Gi
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-cr
rules:
- apiGroups: [""]
  resources: ["*"]
  verbs: ["*"]
---
# This role is used to allow Jenkins scheduling of agents via Kubernetes plugin. 
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: jenkins-role-schedule-agents
  namespace: devops-tools
  labels:
    app: jenkins
    version: v1
    tier: backend
rules:
- apiGroups: [""]
  resources: ["pods", "pods/exec", "pods/log", "persistentvolumeclaims", "events"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["pods", "pods/exec", "persistentvolumeclaims"]
  verbs: ["create", "delete", "deletecollection", "patch", "update"]
---
# The sidecar container which is responsible for reloading configuration changes
# needs permissions to watch ConfigMaps
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: jenkins-casc-reload
  namespace: devops-tools
  labels:
    app: jenkins
    version: v1
    tier: backend
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-crb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins-cr
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: "devops-tools"
---
# We bind the role to the Jenkins service account. The role binding is created in the namespace
# where the agents are supposed to run.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-schedule-agents
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins-role-schedule-agents
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: "devops-tools"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-watch-configmaps
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins-casc-reload
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: "devops-tools"
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
  annotations:
    metallb.universe.tf/address-pool: default
spec:
  type: LoadBalancer
  loadBalancerIP: 172.16.1.5
  ports:
  - name: ui
    port: 8080
    targetPort: 8080
  externalTrafficPolicy: Local
  selector:
    app: jenkins
---
apiVersion: v1
kind: Service
metadata: 
  name: jenkins-agent
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
spec:
  ports:
  - name: agents
    port: 50000
    targetPort: 50000
  selector:
    app: jenkins 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins
  namespace: "devops-tools"
  labels:
    app: jenkins
    version: v1
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
        version: v1
        tier: backend
      annotations:
        checksum/config: c0daf24e0ec4e4cb59c8a66305181a17249770b37283ca8948e189a58e29a4a5
    spec:
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
        runAsNonRoot: true
      containers:
        - name: jenkins
          image: "heineza/jenkins-master:2.323-jdk11-1"
          imagePullPolicy: Always
          args: [ "--httpPort=8080"]
          env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: JAVA_OPTS
            value: -Djenkins.install.runSetupWizard=false -Dorg.apache.commons.jelly.tags.fmt.timeZone=America/Chicago
          - name: JENKINS_SLAVE_AGENT_PORT
            value: "50000"
          ports:
          - containerPort: 8080
            name: ui
          - containerPort: 50000
            name: agents
          resources:
            limits:
              cpu: 2000m
              memory: 4096Mi
            requests:
              cpu: 50m
              memory: 256Mi
          volumeMounts:
          - mountPath: /var/jenkins_home
            name: jenkins-home
            readOnly: false
          - name: jenkins-config
            mountPath: /var/jenkins_home/jenkins.yaml
          - name: admin-secret
            mountPath: /run/secrets/jenkins-admin-username
            subPath: jenkins-admin-user
            readOnly: true
          - name: admin-secret
            mountPath: /run/secrets/jenkins-admin-password
            subPath: jenkins-admin-password
            readOnly: true
      serviceAccountName: "jenkins-sa"
      volumes:
        - name: jenkins-cache
          emptyDir: {}
        - name: jenkins-home
          persistentVolumeClaim:
            claimName: jenkins-pv-claim
        - name: jenkins-config
          configMap: 
            name: jenkins
        - name: admin-secret
          secret:
            secretName: jenkins-secret

此 Jenkins 清单是 Jenkins helm-chart 生成的修改版本。我编辑了我的秘密,但在实际清单中有base64编码字符串。此外,我在部署中创建和使用的 docker 镜像使用 Jenkins 2.323-jdk11 镜像作为基础镜像,并且我刚刚安装了一些用于 Configuration as Code、kubernetes 和 Git 的插件。使用 Metallb 时,什么可能会阻止 Jenkins pod 在我的集群外部访问?

4

1 回答 1

0

MetalLB 默认不允许重复使用/共享相同的 LoadBalancerIP 地址。

根据MetalLB 文档

MetalLB 尊重该spec.loadBalancerIP参数,因此如果您希望使用特定地址设置您的服务,您可以通过设置该参数来请求它。

如果 MetalLB不拥有请求的地址,或者该地址被其他服务使用,则分配将失败,MetalLB 将记录一个可见的警告事件kubectl describe service <service name>[1]

如果您需要在单个 IP 上提供服务,您可以启用选择性 IP 共享。为此,您必须将metallb.universe.tf/allow-shared-ip注释添加到服务中。

注释的值是“共享密钥”。服务可以在以下情况下共享 IP 地址:

  • 他们都有相同的共享密钥。
  • 他们要求使用不同的端口(例如,一个为 tcp/80,另一个为 tcp/443)。
  • 它们都使用 Cluster 外部流量策略,或者它们都指向 完全相同 的一组 pod(即 pod 选择器是相同的)。 [2]

更新

我成功地测试了您的设置,但有一个细微差别 - 我需要删除:externalTrafficPolicy: Local从 Jenkins 服务规范。

试试这个解决方案,如果还是不行,那就是你的集群环境有问题。

于 2021-12-31T12:24:26.257 回答