CICD Day8、Pipeline实现网站项目的自动发布

为了更好的理解Pipeline脚本和cicd流程,本次将使用一个java语言开发的用户信息管理系统进行实践

  • 项目源代码的仓库的地址为
http://172.16.99.82:88/root/java-web-demo.git

1 Pipeline脚本基本结构

  • 我们将Pipeline脚本的构建过程分为拉取代码、代码编译、构建镜像、部署到K8s集群、反馈5个阶段。如下图所示
    image

  • 各阶段的任务如下:

1、拉取代码阶段

  • 从代码仓库拉取最新代码
  • 根据选择的分支拉取对应的代码版本

2、代码编译阶段

  • 执行代码编译工作
  • 生成可部署的文件

3、构建镜像阶段

  • 编写Dockerfile
  • 构建镜像
  • 推送镜像到镜像仓库

4、部署到k8s集群阶段

  • 编写资源配置
  • kubectl执行部署和更新操作

5、反馈阶段

  • 发送通知到钉钉群或邮箱告知执行结果
  • 综上所述,Pipeline脚本结构如下
pipeline {
  agent {
    kubernetes {
      yaml '''
        apiVersion: v1
        kind: Pod
        spec:
          containers:
          - name: jnlp
            image: uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21
            args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']
      '''
    }
  }
  stages {
    stage('拉取代码') {
      steps {
         echo "拉取代码..."
      }
    }
    stage('代码编译') {
      steps {
         echo "代码编译..."
      }
    }
    stage('构建镜像') {
      steps {
         echo "构建镜像..."
      }
    }
    stage('部署到k8s集群') {
      steps {
         echo "部署到k8s集群..."
      }
    }
    post {
       always {
          echo "构建完成"
       }
       success {
          echo "构建成功"
       }
       failure {
          echo "构建失败"
       }
    }
  }
}

2、拉取代码阶段

  • 拉取代码步骤可以通过片段生成器生成,在生成器中选择checkout: Check out from version control,输入仓库地址、访问凭据和构建分支。具体配置如下图所示:
    image
  • 将生成的Pipeline代码片段复制到Pipeline中,如下所示
    stage('拉取代码') {
      steps {
         checkout scmGit(branches: [[name: '*/dev']], extensions: [], userRemoteConfigs: [[credentialsId: '0b376781-1e95-417f-9fae-aec4deb7f966', url: 'http://172.16.99.82:88/root/java-web-demo.git']])
      }
    }
  为了让用户在触发构建时可以选择并动态获取分支,这里使用Git Parameter,该Parameter由Git Parameter插件提供,该插件需要额外安装。这个步骤可以通过声明式指令生成器生成,在生成器中选择parameters: Parameter,然后添加Git Parameter,输入名称、描述、参数类型和默认分支。
  • 具体配置如下图所示
    image
  • 将生成的代码片段复制到Pipeline中,如下图所示
  parameters {
      gitParameter branch: '', branchFilter: '.*', defaultValue: 'dev', description: '请选择构建的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'
  }
  stages {
    stage('拉取代码') {
      steps {
         checkout scmGit(branches: [[name: "${params.Branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: '0b376781-1e95-417f-9fae-aec4deb7f966', url: 'http://172.16.99.82:88/root/java-web-demo.git']])
      }
    }
  }

同时,将scmGit中的分支名称*/dev 设置为${params.Branch},以便根据用户选择的分支名称拉取代码

3、代码编译阶段

  这个java web项目使用Maven工具进行项目管理。因此,在这个阶段需要执行 mvn clean package命令进行代码编译和构建,该命令执行完成后将生成一个可部署的jar文件。将该命令放置在代码编译阶段中,如下所示
    stage('代码编译') {
      steps {
         sh 'mvn clean package'
      }
    }
  • 这个时候会引发一个问题:mvn命令是否可以顺利执行?

  • 答案是否定的,因为这个命令会在代理pod中执行,而代理pod是由uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21镜像构建的,该镜像仅运行代理程序,并没有提供Maven环境

  • 为了解决这个文件,需要确保代理pod中具备Maven环境,这可以通过以下两种方法实现:

    • (1) 基于uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21镜像构建一个包含Maven环境的镜像,并使用该镜像创建代理pod
    • (2) 在代理pod中添加一个具有Maven环境的容器,在构建步骤中使用container()指令切换到该容器,并在容器中执行mvn命令
      这里采用第二种方法,它具有很高的灵活性,易于扩展代理pod的功能
  • 在pod中添加一个名为maven的容器,并通过maven:3.2.3-jdk-8镜像创建该容器,配置如下:

apiVersion: v1
kind: Pod
spec:
  containers:
  - name: jnlp
    image: uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21
    args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']
  - name: maven
    image: uhub.service.ucloud.cn/librarys/maven:3.2.3-jdk-8
    command:
    - cat
    tty: true
  • 在构建步骤中使用container()指令切换到该容器,并在该容器中执行mvn命令,配置如下
    stage('代码编译') {
      steps {
         container('maven') {
           sh 'mvn clean package'
         }
      }
    }

4、构建镜像阶段

mvn命令执行完成后,生成jar文件被放置在target目录下,文件名为web-demo-0.1.0.jar。这个构建镜像阶段生成Dockerfile文件,将该文件构建到jdk环境镜像中,并将其推送到Harbor镜像仓库,配置如下:

    stage('构建镜像') {
      steps {
         sh """
         echo '
           FROM uhub.service.ucloud.cn/librarys/8-jdk-alpine:latest
           COPY ./target/*.jar /app/java-web-demo.jar
           EXPOSE 8080
           CMD java -jar /app/java-web-demo.jar
         ' > Dockerfile
         # 使用构建编号作为镜像标签号
         image=172.16.99.82/java-web-demo/java-web-demo:$BUILD_NUMBER
         docker build -t \${image} .
         docker login -uadmin -p'qq1092279986' 172.16.99.82
         docker push \${image}
       """
      }
    }

这是也会面临与上一个阶段相同的问题:代理pod中没有Docker环境,无法执行Docker命令。解决这个问题的思路还是一样,在pod中添加一个名为docker的容器,该容器使用docker镜像创建,配置如下:

        apiVersion: v1
        kind: Pod
        spec:
          containers:
          - name: jnlp
            image: uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21
            args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']
          - name: maven
            image: uhub.service.ucloud.cn/librarys/maven:3.2.3-jdk-8
            command:
            - cat
            tty: true
          - name: docker
            image: docker:latest
            command:
            - cat
            tty: true
            volumeMounts:
            - mountPath: /var/run/docker.sock
              name: sock
           volumes:
           - name: sock
             hostPath:
               path: /var/run/docker.sock

需要注意的是,docker容器仅包含了Docker命令,并非一个完整的Docker容器运行时环境。因此,还需要将节点上的UNIX套接字文件/var/run/docker.sock挂载到容器中,以便与节点上的Docker容器运行时进行交互,执行与Docker相关的命令

在构建步骤中使用container()指令切换到该容器,并在该容器中执行Docker命令,配置如下:

    stage('构建镜像') {
      steps {
        container('docker') {
          sh """
          echo '
            FROM uhub.service.ucloud.cn/librarys/8-jdk-alpine:latest
            COPY ./target/*.jar /app/java-web-demo.jar
            EXPOSE 8080
            CMD java -jar /app/java-web-demo.jar
          ' > Dockerfile
          # 使用构建编号作为镜像标签号
          image=172.16.99.82/java-web-demo/java-web-demo:$BUILD_NUMBER
          docker build -t \${image} .
          docker login -uadmin -p'qq1092279986' 172.16.99.82
          docker push \${image}
        """
        }
      }
    }

需要注意的是,docker login命令使用明文传递密码,这会导致密码显示在控制台输出中,存在密码泄露的风险。为了提高安全性,可以使用withCredentials语句将凭据中的慢慢安全地注入构建过程中。使用片段生成器生成代码片段,配置如下图所示:
image

我们需要先将Harbor用户名和密码保存到Jenkins凭据中并选中它们,然后生成以下代码片段:

withCredentials([usernamePassword(credentialsId: '3a1837fa-8189-4f83-b5b1-ab53d38e151a', passwordVariable: '', usernameVariable: '')]) {
    // some block
}

withCredentials为凭据ID3a1837fa-8189-4f83-b5b1-ab53d38e151a中的用户名和密码分别设置环境变量username和password,这两个环境变量只能在该块内被引用。然后将用户名和密码传递给Docker命令,配置如下:

      steps {
        container('docker') {
          withCredentials([usernamePassword(credentialsId: '3a1837fa-8189-4f83-b5b1-ab53d38e151a', passwordVariable: 'password', usernameVariable: 'username')])
          sh """
          echo '
            FROM uhub.service.ucloud.cn/librarys/8-jdk-alpine:latest
            COPY ./target/*.jar /app/java-web-demo.jar
            EXPOSE 8080
            CMD java -jar /app/java-web-demo.jar
          ' > Dockerfile
          # 使用构建编号作为镜像标签号
          image=172.16.99.82/java-web-demo/java-web-demo:$BUILD_NUMBER
          docker build -t \${image} .
          docker login -u ${username} -p ${password} 172.16.99.82
          docker push \${image}
        """
        }
      }

5、部署到k8s集群阶段

  • 为应用程序定义Deployment、Service和Ingress资源配置,并将它们统一保存在k8s-deploy.yaml文件中,内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-web-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: java-web-demo
  template:
    metadata:
      labels:
        app: java-web-demo
    spec:
      imagePullSecrets:
      - name: private-registry-auth
      containers:
      - name: web
        image: 172.16.99.82/java-web-demo/web:1
---
apiVersion: v1
kind: Service
metadata:
  name: java-web-demo
spec:
  selector:
    app: java-web-demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: java-web-demo
spec:
  ingressClassName: nginx
  rules:
  - host: web-demo.suyajun.cn
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: java-web-demo
            port:
              number: 80
  • 然后使用kubectl apply -f k8s-deploy.yaml 命令完成应用程序的部署,但在当前环境中,存在以下问题:
    • (1)代理pod中没有kubectl环境,还需要按照之前的方式,在pod中添加一个kubectl容器,在步骤中使用container()指令切换到该容器,并在容器中执行kubectl命令。但还没有资源文件k8s-deploy.yaml,无法执行kubectl apply -f 命令
    • (2)假设kubectl能读取到资源文件,但pod中没有kubeconfig认证文件,kubectl无法与kubernetes集群交互
    • (3)假设成功执行kubectl apply -f k8s-deploy.yaml命令。但镜像标签每次构建都会发生变化,该如何将标签动态的修改为正确的标签呢
  • 问题(1) 的解决方法是,将资源文件k8s-deploy.yaml提交到代码仓库,以便与项目代码一起进行版本管理。这样,在源代码目录也可以访问资源文件。在pod中添加一个名为kubectl的容器,使用bitnami/kubectl:1.28.4镜像创建,配置如下:
        apiVersion: v1
        kind: Pod
        spec:
          containers:
          - name: jnlp
            image: uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21
            args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']
          - name: kubectl
            image: uhub.service.ucloud.cn/librarys/kubectl:1.28.4
            command:
            - cat
            tty: true
            securityContext:
              runAsUser: 0
         ...
  • 问题(2)的解决方法是,将kubectl使用的kubeconfig认证文件以Secret file类型保存到Jenkins凭据中,然后通过withCredentials语句将凭据安全注入构建过程中。使用片段生成器生成代码片段,配置如下:
    image
    ** 将生成的代码片段复制到Pipeline中,配置如下:**
    stage('部署到k8s集群') {
      steps {
        container(kubectl)
          withCredentials([file(credentialsId: 'c6eba4ce-82bd-43ba-ad7b-276678ae0dc3', variable: 'KUBECONFIG')])
            sh """
               sed -i -r "s#(image: ).*#\1172.16.99.82/java-web-demo/java-web-demo:$BUILD_NUMBER#" k8s-deploy.yaml
               kubectl apply -f k8s-deploy.yaml
            """
      }
    }

6、反馈阶段

  • Pipeline流程执行完成后,Jenkins将其结果发送邮件,以通知相关负责人。Jenkins发送邮件的功能是由Email Extension插件提供的,需要额外安装该插件
    image
  • 首先配置邮件通知:Manage Jenkins》System》Extended E-mail Notification,配置如下:
    • SMTP server:SMTP 服务器的域名。这里使用的是163个人邮箱,163的SMTP服务器域名是smtp.163.com
    • SMTP Port:SMTP服务器的端口号,通常是25(非加密)或465(加密),这里填写465端口。
    • Credentials:选择登录SMTP服务器的凭据。单击Add按钮添加凭据,选择Username with password作为凭据类型,输入用户名和授权码,既邮箱账号和授权码,完成凭据的添加,然后选择该凭据
    • Default user e-mail suffix:默认的发件邮箱后缀,这里输入@163.com
    • Default Content Type:默认内容类型,可以是纯文本、HTML等,这里设置为HTML,以支持更丰富的邮件内容格式
      邮件通知配置如下所示
      image

然后,在post部分添加发送邮件的步骤,配置如下:

    post {
       always {
          echo "构建完成"
       }
       success {
          echo "构建成功"
          emailext {
            subject: "构建成功: 项目 '${JOB_NAME} [${BUILD_NUMBER}]'",
            body: """
                <p>构建成功, 项目 '${JOB_NAME} [${BUILD_NUMBER}]'</p>
                <p>构建代码分支: ${Branch}</p>
                <p>构建程序时间: ${currentBuild.durationString} </p>
                <p>详情信息查看控制台输出: <a href="${BUILD_URL}"> ${JOB_NAME} [${BUILD_NUMBER}]</a>
              """,
            to: "1092279986@qq.com,333@qq.com",
            from: "baojingtongzhi@163.com"
          }
       }
       failure {
          echo "构建失败"
          emailext {
            subject: "构建失败: 项目 '${JOB_NAME} [${BUILD_NUMBER}]'",
            body: """
                <p>构建失败, 项目 '${JOB_NAME} [${BUILD_NUMBER}]'</p>
                <p>构建代码分支: ${Branch}</p>
                <p>构建程序时间: ${currentBuild.durationString} </p>
                <p>详情信息查看控制台输出: <a href="${BUILD_URL}"> ${JOB_NAME} [${BUILD_NUMBER}]</a>
              """,
            to: "1092279986@qq.com,333@qq.com",
            from: "baojingtongzhi@163.com"
          }
       }
    }
  • 在上述配置中,emailext步骤用于在Pipeline执行成功或失败时执行执行发送邮件通知。字段含义如下
    • subject:定义邮件主机
    • body:定义邮件正文,采用HTML格式
    • to:指定收件人的邮箱,多个邮箱地址以逗号分隔
      为了丰富邮件内容,在邮件中引用了多个Jenkins内置变量,以获取相关构建信息

7、验证与测试

  • 为了提高代码的可维护性和灵活性,将Pipeline脚本中的可修改的数据设置为环境变量,并在environment块内定义该环境变量,如仓库地址、凭据ID等。
  • 完整的Pipeline脚本如下
pipeline {
  agent {
    kubernetes {
      yaml '''
        apiVersion: v1
        kind: Pod
        spec:
          containers:
          - name: jnlp
            image: uhub.service.ucloud.cn/librarys/jenkins/inbound-agent:latest-jdk21
            args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']
          - name: kubectl
            image: uhub.service.ucloud.cn/librarys/kubectl:1.28.4
            command:
            - cat
            tty: true
            securityContext:
              runAsUser: 0
          - name: maven
            image: uhub.service.ucloud.cn/librarys/maven:3.2.3-jdk-8
            command:
              - cat
            tty: true
          - name: docker
            image: uhub.service.ucloud.cn/librarys/docker:latest
            command:
            - cat
            tty: true
            volumeMounts:
            - mountPath: /var/run/docker.sock
              name: sock
            - mountPath: /etc/docker/daemon.json
              name: daemonfile
              readOnly: true
          volumes:
          - name: sock
            hostPath:
              path: /var/run/docker.sock
          - name: daemonfile
            hostPath:
            path: /etc/docker/daemon.json
            type: File
      '''
    }
  }
  environment {
    kubectl = '/opt/bitnami/kubectl/bin/kubectl'
    gitlab_repo_url = 'http://192.168.31.189:88/root/java-web-demo.git'
    gitlab_credentials_id = 'c8a6ec74-5c3e-4c4a-8793-a5dee2e35892'
    harbor_registry = '192.168.31.189'
    harbor_credentials_id = '75c69904-9dd8-4b4c-877a-45dc6145d2ba'
    harbor_image = '${harbor_registry}/java-web-demo/java-web-demo'
    k8s_kubeconfig_id = '5608b5a2-9ce8-4afc-9f97-7ad0a10a51ab'
    mail_notification_reciplents = 'suyajun1993@163.com, suyajun.1993@qq.com'
  }
  parameters {
      gitParameter branch: '', branchFilter: '.*', defaultValue: 'dev', description: '请选择构建的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'
  }
  stages {
    stage('拉取代码') {
      steps {
         checkout scmGit(branches: [[name: "${params.Branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${gitlab_credentials_id}", url: "${gitlab_repo_url}"]])
      }
    }
    stage('代码编译') {
      steps {
         container('maven') {
           sh """
              echo  "nameserver 8.8.8.8\nnameserver 8.8.4.4" > /etc/resolv.conf && cat
              # 配置阿里云maven仓库,提高依赖文件下载速度
              sed -i "s#<mirrors>#<mirrors>\
              <mirror>\
                <id>aliyunmaven</id>\
                <url>https://maven.aliyun.com/repository/public</url>\
                <mirrorOf>*</mirrorOf>\
              </mirror>#" /usr/share/maven/conf/settings.xml

              mvn clean package
           """
         }
      }
    }
    stage('构建镜像') {
      steps {
        container('docker') {
          withCredentials([usernamePassword(credentialsId: "${harbor_credentials_id}", passwordVariable: 'password', usernameVariable: 'username')]) {
          sh """
          # 使用构建编号作为镜像标签号
          image=${harbor_image}:${BUILD_NUMBER}
          # 根据当前目录中的Dockerfile文件构建镜像
          docker build -t \${image} .
          # 推送镜像之前登录Harbor仓库
          docker login -u ${username} -p '${password}' ${harbor_registry}
          # 推送镜像到Harbor镜像仓库
          docker push \${image}
          
        """
          }
        }
      }
    }
    stage('部署到k8s集群') {
      steps {
        container('kubectl') {
          withCredentials([file(credentialsId: "${k8s_kubeconfig_id}", variable: 'KUBECONFIG')]) {
          sh """
          echo "睡着啦"
          sed -i -r "s#(image: )(.*)#\\1${harbor_image}:${BUILD_NUMBER}#" k8s-deploy.yaml
          ${kubectl} apply -f k8s-deploy.yaml
          sleep 3
          ${kubectl} get pod,service,ingress
        """
          }
        }
      }
    }
  }
  post {
     always {
        echo "构建完成"
     }
     success {
        echo "构建成功"
        emailext (
          subject: "构建成功: 项目 '${JOB_NAME} [${BUILD_NUMBER}]'",
          body: """
              <p>构建成功, 项目 '${JOB_NAME} [${BUILD_NUMBER}]'</p>
              <p>构建代码分支: ${Branch}</p>
              <p>构建程序时间: ${currentBuild.durationString} </p>
              <p>详情信息查看控制台输出: <a href="${BUILD_URL}">${JOB_NAME} [${BUILD_NUMBER}]</a>
            """,
          to: "${mail_notification_reciplents}",
          from: "suyajun1993@163.com"
        )
     }
     failure {
        echo "构建失败"
        emailext (
          subject: "构建失败: 项目 '${JOB_NAME} [${BUILD_NUMBER}]'",
          body: """
              <p>构建失败, 项目 '${JOB_NAME} [${BUILD_NUMBER}]'</p>
              <p>构建代码分支: ${Branch}</p>
              <p>构建程序时间: ${currentBuild.durationString}</p>
              <p>详情信息查看控制台输出: <a href="${BUILD_URL}">${JOB_NAME} [${BUILD_NUMBER}]</a>
            """,
          to: "${mail_notification_reciplents}",
          from: "suyajun1993@163.com"
        )
     }
  }
}

  • 创建一个名为java-web-demo的Pipeline类型项目,将上述脚本放置到Pipeline脚本编辑框中,然后单击项目的Build now按钮触发构建。同时,在项目中可以实时查看每个阶段的执行结果和耗时,步骤视图如下所示
    image

  • 最后会发送邮件通知,邮件内容如下
    image

8、问题处理

8.1 镜像拉取失败

8.1.1 问题详情

  • 有的时候会遇到很奇怪的问题。比如我们通过jenkins发布代码的时候,发现发布成功后,有的pod会提示拉取镜像失败,如下所示
[root@h-k8s-master-181 ~]# kubectl get pod -A -o wide|grep java
default                java-web-demo-77995b987c-l57qw               0/1     ImagePullBackOff   0               2m48s   10.244.102.36    h-k8s-node02-183   <none>           <none>
[root@h-k8s-master-181 ~]# kubectl describe pod java-web-demo-77995b987c-l57qw
......
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason                  Age                    From               Message
  ----     ------                  ----                   ----               -------
  Normal   Scheduled               5m44s                  default-scheduler  Successfully assigned default/java-web-demo-77995b987c-l57qw to h-k8s-node02-183
  Warning  Failed                  4m25s (x6 over 5m44s)  kubelet            Error: ImagePullBackOff
  Normal   Pulling                 4m10s (x4 over 5m44s)  kubelet            Pulling image "192.168.31.189/java-web-demo/java-web-demo:17"
  Warning  Failed                  4m10s (x4 over 5m44s)  kubelet            Failed to pull image "192.168.31.189/java-web-demo/java-web-demo:17": Error response from daemon: unauthorized: unauthorized to access repository: java-web-demo/java-web-demo, action: pull: unauthorized to access repository: java-web-demo/java-web-demo, action: pull
  • 但是我们到对应的node节点上docker pull 192.168.31.189/java-web-demo/java-web-demo:17是没问题的。

8.1.2 解决方法

  • 我们需要到kubernetes Master节点上生成秘钥Secret并在pod中使用

1、生成秘钥Secret

 kubectl create secret docker-registry harborsecret \
--docker-server=192.168.31.189 \
--docker-username=admin \
--docker-password=YOUR_UHUB_PASSWORD
镜像仓库中关于账号与密码的信息是配置在Kuernetes中的Secret资源中,可以创建一个docker-registry类型的Secret保存账号密码;使用以下命令创建Secret,注意将其中的大写字母值替换为你自己的信息;

harborsecret:Secret资源名称,改为自己定义名称;这里以harborsecret为例
192.168.31.189 是自己搭建的仓库,请调整为自己的仓库域名;
admin:镜像仓库登陆账号
YOUR_UHUB_PASSWORD:镜像仓库登陆账号对应的密码

2、查看生成的秘钥信息

[root@h-k8s-master-181 ~]# kubectl get secret
NAME           TYPE                             DATA   AGE
harborsecret   kubernetes.io/dockerconfigjson   1      57m

3、在Pod中使用

[root@h-cicd-189 java-web-demo]# cat k8s-deploy.yaml
apiVersion: apps/v1
kind: Deployment
...
    spec:
      containers:
      - name: web
        image: 172.16.99.82/java-web-demo/web:1
      imagePullSecrets:
        - name: harborsecret

参考文档

https://docs.ucloud.cn/uk8s/dockerhub/using_uhub_in_uk8s
posted @ 2025-01-08 18:46  Hello_worlds  阅读(104)  评论(0)    收藏  举报