分享生产项目DevOps CICD流水线解决方案
  T5Bv8I9TIFQW 2023年11月02日 53 0

一、前言

每家互联网业务迭代更新都会有自己的一套DevOps 发布上线技术架构体系,不管是采用什么工具都离不开编译、打包、发布、部署这几个步骤,随着互联网快速的发展,为了满足企业业务上线需求,大批的技术人员都研发出各种有意思的开源工具,像我们熟知的Jenkins、Spug等,都为我们互联网公司业务上线发版带来很多便利,那么接下来我将会给大家介绍一下,适用于Kubernetes环境的一套CICD技术架构解决方案

二、技术架构介绍

如下图所示,项目业务都是运行在Kubernetes集群环境中,然后基于Jenkins Pipline去更新迭代我们的业务镜像版本发布至Kubernetes,服务上线完毕之后,运维会授权给指定的研发人员授权Kubesphere权限从而管理维护Kubernetes集群中各个业务模版

分享生产项目DevOps CICD流水线解决方案_Jenkins

三、DevOps平台建设

3.1、CICD流程剖析:

  1. 根据自己企业内部Git仓库(gitlab、gitee、gitea)上管理创建对应的服务项目
  2. 配置Jenkins集成Kubernetes集群,后期Jenkins的Slave将会在Kubernetes集群上动态创建Slave任务;
  3. Jenkins创建对应的前后端任务(job),集成该项目的Git地址和Kubernetes集群
  4. 开发人员将本地的代码push到GIt上
  5. 若配置由钩子,那么研发人员没次推送(Push)代码会自动触发Jenkins构建,如果没有配置钩子,需要手动在Jnekins上手动构建job任务
  6. Jenkins会控制Kubernetes(基于Kubernetes插件)创建Jnekins Slave(以Pod形式出现)
  7. Jenkins Slave会根据流水线(Pipline)定义的流程步骤执行构建
  8. 通过Dockerfile生成我们想要的Docker镜像
  9. 将生成的镜像推送(Push)至(Harbor)私有镜像仓库(或者其他镜像仓库)
  10. Jenkins再次控制Kubernetes进行最新的镜像部署
  11. 整套流水线结束之后就会自动删除Jenkins salve任务

3.2、Jenkins安装部署

安装Docker-ce服务

这里我们Jnekins是通过docker启的,采用bitnami的镜像

yum安装docker依赖的环境
# yum install -y yum-utils device-mapper-persistent-data lvm2
添加docker repo源
# yum-config-manager --add-repo https://mirrors.aliyun.com/docker- ce/linux/centos/docker-ce.repo
# sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo
yum安装docker-ce19.x版本的docker服务
# yum install docker-ce-19.03.* docker-ce-cli-19.03.* -y 
# systemctl daemon-reload && systemctl enable --now docker

启动Jenkins镜像

docker run运行jenkins服务,并配置管理员账号密码为admin/admin123

#docker run -d --name=jenkins --restart=always -e JENKINS_PASSWORD=admin123 -e JENKINS_USERNAME=admin -e JENKINS_HTTP_PORT_NUMBER=8080 -p 8080:8080 -p 50000:50000 -v /data/jenkins_data:/bitnami/jenkins -v /usr/bin/docker:/usr/bin/docker -v /run/docker.sock:/run/docker.sock -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime  -e JAVA_OPTS=-Duser.timezone=Asia/Shanghai bitnami/jenkins:2.332.2-debian-10-r4
Ps:8080端口为Jenkins web界面端口,50000是jnlp使用的端口,后期Jenkins Slave需要使用50000端口和Jenkins主节点通信
Jenkins安装完成之后即可通过 Jenkins 宿主机的 IP+8080 即可访问 Jenkins服务

分享生产项目DevOps CICD流水线解决方案_Jenkins_02

Jenkins所需插件安装

配置插件站点源

https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

分享生产项目DevOps CICD流水线解决方案_docker_03

安装下面列出来的Jenkins插件

Git
Git Parameter
Git Pipeline for Blue Ocean
GitLab
Credentials
Credentials Binding
Blue Ocean
Blue Ocean Pipeline Editor
Blue Ocean Core JS
Pipeline SCM API for Blue Ocean
Dashboard for Blue Ocean
Build With Parameters
Dynamic Extended Choice Parameter Plug-In Dynamic Parameter Plug-in
Extended Choice Parameter
List Git Branches Parameter
Pipeline
Pipeline: Declarative
Kubernetes
Kubernetes CLI
Kubernetes Credentials
安装中文插件
Localization Support Plugin
Localization: Chinese (Simplified)
SSH Agent
SSH Pipeline Steps
安装获取用户、时间变量插件
build user vars plugin
Build Timestamp Plugin
Qy Wechat Notification
Groovy Postbuild
Post build task

3.3、GitLab安装部署

git平台可以根据自己企业内部现有的进行测试,如果没有,可以选择Gitlab,如果有则忽略该步骤

GitLab 国内源下载 GitLab 的安装包
https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/
将下载好的rpm包,上传至服务器,之后通过rpm进行解压安装即可
## yum install gitlab-ce-14.2.3-ce.0.el7.x86_64.rpm -y
#vim /etc/gitlab/gitlab.rb

将 external_url 更改为自己的发布地址,可以是服务器的 IP,也可以是一个可被解析的域名

分享生产项目DevOps CICD流水线解决方案_Jenkins_04

另外这里我们不需要用到Prometheus监控,这里直接选择关闭即可

分享生产项目DevOps CICD流水线解决方案_git_05

更改完配置文件之后需要重新加载配置文件

#gitlab-ctl reconfigure

加载配置完成之后,可以看到下面信息

Notes:
Default admin account has been configured with following details: Username: root
Password: You didn't opt-in to print initial root password to STDOUT. Password stored to /etc/gitlab/initial_root_password. This file will be
cleaned up in first reconfigure run after 24 hours.
NOTE: Because these credentials might be present in your log files in plain text, it is highly recommended to reset the password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your- root-password.
    gitlab Reconfigured!


之后可以通过浏览器访问 GitLab,账号 root,默认密码在/etc/gitlab/initial_root_password

分享生产项目DevOps CICD流水线解决方案_Jenkins_06

创建一个项目分组测试

组名根据自己实际情况而定,我这里直接命名为kubernetes

分享生产项目DevOps CICD流水线解决方案_Jenkins_07

分享生产项目DevOps CICD流水线解决方案_docker_08

在kubernetes组下面创建一个Project

分享生产项目DevOps CICD流水线解决方案_Jenkins_09

选择创建一个空的项目

分享生产项目DevOps CICD流水线解决方案_docker_10

输入项目名称,然后点击 Create project 即可

分享生产项目DevOps CICD流水线解决方案_git_11

之后进入到jenkins容器里面生成可以将Jenkins 服务器的 key 导入到 GitLab,首先生成密钥(如有可以无需生成):
#ssh-keygen -t rsa -C "YOUR_EMAIL@ADDRESS.COM"
查看jenkins生成的密钥对,将公钥放到GitLab中即可
# cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC44ni3FivVXHkGcJ3E1bk3mugx6e8aDqKR1MPQP0idb0XG RQp3kNJ244pypRoj/w1OIBWtb5Pj3fT8rxGaW/bzyAHpeAWsmXYtZdZ3q/kbzPfp1yHcjG0RrWs9 Fb1LPohHdsoV+FOqaAlO73kXOJUem/BSbeGmQVCP5toQbO0NaHPBqGE3V5dPJxscEqzsFmlrH/Wh M+bF3gWlc7AiO4SySFM2tJ7gUMsMXhB1F5kaT1vZPcn1BF4SNvDrHv0bt+uMcYXAAKTmUUdZcpG2 tBA8izVblnZPHgIS0Xyu+kGfkxMZFzoGhJXgUkTlwNC3qruBNNcKf7BXB/wd5f+vS+Xl root@k8s-master01

在 GitLab 找到 Profile

分享生产项目DevOps CICD流水线解决方案_docker_12

之后在 SSH Keys 添加公钥

分享生产项目DevOps CICD流水线解决方案_Jenkins_13

添加后就可以在 Jenkins 服务器拉取代码

#yum install git -y 如果没有git可直接yum安装即可,如果有忽略即可
根据自己的git验证jenkins容器内是否正常push/pull仓库代码
# git clone git@YOUR_GITLAB_ADDRESS:kubernetes/test-project.git
创建几个文件,然后提交测试:
# ls
test-project
# cd test-project/
# ls
README.md
# echo "# Frist Commit For DevOps" > first.md # ls
first.md README.md
# git add .
# git commit -am "first commit"
[main a327add] first commit
create mode 100644 first.md
# git push origin main
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 302 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0)
To git@YOUR_GITLAB_ADDRESS:kubernetes/test-project.git b64564e..a327add main -> main

提交之后在 GitLab 即可看到该文件

分享生产项目DevOps CICD流水线解决方案_git_14

3.4、Harbor安装部署

这里附上Github下载地址,可以通过该链接有选择性的下载Harbor离线包,并上传至Harbor服务器

https://github.com/goharbor/harbor/releases

由于Harbor是采用docker-compose一键部署,因此Harbor服务器也需要安装docker

# yum install -y yum-utils device-mapper-persistent-data lvm2
# yum-config-manager --add-repo https://mirrors.aliyun.com/docker- ce/linux/centos/docker-ce.repo
# sed -i -e '/mirrors.cloud.aliyuncs.com/d' -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo
# yum install docker-ce-19.03.* docker-ce-cli-19.03.* -y # systemctl daemon-reload && systemctl enable --now docker

安装完成后,将下载的Harbor离线包解压并载入harbor镜像

#wget https://github.com/goharbor/harbor/releases/download/v2.8.4/harbor-online-installer-v2.8.4.tgz
#tar  zxvf harbor-online-installer-v2.8.4.tgz 
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/common.sh
harbor/harbor.yml.tmpl
安装docker-compose
#curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:16 --:--:--     0
100 12.1M  100 12.1M    0     0  17116      0  0:12:24  0:12:24 --:--:-- 16516
#chmod +x /usr/local/bin/docker-compose 
#docker-compose -v 
docker-compose version 1.29.2, build 5becea4c

根据自己业务需求修改harbor.yml文件

分享生产项目DevOps CICD流水线解决方案_docker_15

[harbor]# cp harbor.yml.tmpl harbor.yml
[harbor]# ./prepare 
[harbor]# ./install.sh

分享生产项目DevOps CICD流水线解决方案_docker_16

分享生产项目DevOps CICD流水线解决方案_Jenkins_17

设置开机自启动
#/usr/local/bin/docker-compose -f /root/harbor/docker-compose.yml up -d
修改dockes客户端仓库名称
#vim /etc/docker/daemon.json
{
  "log-opts": {
    "max-size": "5m",
    "max-file":"3"
  },
  "exec-opts": ["native.cgroupdriver=systemd"],
  "insecure-registries":["10.10.203.165:8930"]
}

分享生产项目DevOps CICD流水线解决方案_docker_18

四、Jenkins 凭据Credentials配置

Harbor账号密码、Git的私钥、Kubernetes的证书均使用Jenkins的Credentials管理

1.配置Kubernetes证书凭据

  • 首先需要找到集群中kubeconfig,一般都是kubectl节点的 ~/.kube/config 文件,或者是kubeconfig环境变量所指定的文件,
查看k8s证书文件
#cat ~/.kube/config或者kubectl config view --raw -o json
获取/root/.kube/config中certificate-authority-data的内容并转化成base64 encoded文件
#echo "certificate-authority-data | base64 -d >ca.crt
获取/root/.kube/config中client-certificate-data的内容并转化成base64 encoded文件
#echo "client-certificate-data" | base64 -d >client.crt
获取/root/.kube/config中client-key-data"的内容并转化成base64 encoded文件
#echo "client-key-data" | base64 -d >client.key
根据上述生成的三个文件生成一个PKCS12格式的客户端证书文件
#openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt

也可以通过高级玩法获取我们想要的values信息

安装jq工具
#wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
#chmod +x ./jq
#cp jq /usr/bin
提取CA证书
#kubectl config view --raw -o json|jq '.clusters[].cluster."certificate-authority-data"' |tr -d '"'|base64 -d> ca.cert
提取客户端证书
#kubectl config view --raw -o json|jq '.users[].user."client-certificate-data"' |tr -d '"'|base64 -d > client.cert
提取客户端证书密钥
#kubectl config view --raw -o json|jq '.users[].user."client-key-data"'|tr -d '"'|base64 -d > client.key
根据上述生成的三个文件生成一个PKCS12格式的客户端证书文件
#openssl pkcs12 -export -out ./cert.pfx -inkey ./client.key -in ./client.crt -certfile ./ca.crt
Enter Export Password:
Verifying - Enter Export Password:

注意生成证书的时候,一定要填写密码,后面会用到

分享生产项目DevOps CICD流水线解决方案_git_19

分享生产项目DevOps CICD流水线解决方案_Jenkins_20

将生成的cert.pfx文件上传至Jenkins凭据中即可

分享生产项目DevOps CICD流水线解决方案_Jenkins_21

分享生产项目DevOps CICD流水线解决方案_git_22

分享生产项目DevOps CICD流水线解决方案_Jenkins_23

系统管理->全局安全配置->代理-TCP port for inbound agents

这里已经要指定50000端口号,否则Jenkins Salve链接Kubernetes集群API报错

分享生产项目DevOps CICD流水线解决方案_Jenkins_24

系统管理->节点管理->Configure Clouds

如下图所示,配置Jenkins链接k8s相关集群信息配置

分享生产项目DevOps CICD流水线解决方案_docker_25

分享生产项目DevOps CICD流水线解决方案_Jenkins_26

完成后点击测试链接即可

2.配置GitLab 凭据

点击Add Credentials, 因为这里我们做了ssh免密,类型选择SSH Username with private key即可,

也可以选择类型为Username with password也可以

分享生产项目DevOps CICD流水线解决方案_git_27

Ps:Username:用户名,无强制性
Private Kety:Jenkins容器内部的私钥,一般位于~/.ssh/id_rsa

3.配置Harbor仓库凭据

这里我们Harbor凭据选择类型为Username with password.通过 Jenkins 凭证管理 Harbor 的账号密码

分享生产项目DevOps CICD流水线解决方案_docker_28

分享生产项目DevOps CICD流水线解决方案_Jenkins_29

➢Username:Harbor或者其它平台的用户名;
➢ Password:Harbor或者其它平台的密码; 
➢ ID:该凭证的ID;
➢ Description:证书的描述。

五、创建后端应用Java服务实例

1.准备工作

在节点上打上我们的节点标签
#kubectl label node k8s-node01 jenkins-build=true
登陆到标签节点创建缓存目录
#ssh k8s-node02
创建构建工作目录,每次构建编译的产物文件都会放置在该目录下
#mkdir /opt/workspace -p 
授予足够的目录权限
#chown 777 -R /opt/workspace/
创建项目命名空间
#kubectl create ns tongrentang
创建secret资源对象
kubectl create secret docker-registry harborkey --docker-server=CHANGE_HERE_FOR_YOUR_HARBOR_ADDRESS --docker-username=admin --docker- password=Harbor12345 --docker-email=mail@kubeasy.com -n tongrentang

2.定义Jekinsfile流水线脚本

定义后端Java服务Pipeline Jenkinsfile

#vim Jenkinsfile
pipeline {
  agent {
    kubernetes {
      cloud 'produce-kubernetes' #这里指定Jenkins配置好的Configure Clouds名称
      slaveConnectTimeout 1200   #配置连接超时时间
      workspaceVolume hostPathWorkspaceVolume(hostPath: "/opt/workspace", readOnly: false)
      yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
      image: 'registry.cn-beijing.aliyuncs.com/devops-tols/jnlp-slave:latest' #指定jnlp镜像
      name: jnlp
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
          readOnly: false
    - command:
        - "cat"
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
      image: "registry.cn-beijing.aliyuncs.com/devops-tols/maven:3.5.3" #指定maven镜像地址
      imagePullPolicy: "IfNotPresent"
      name: "build"
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
        - mountPath: "/root/.m2/"
          name: "cachedir"
          readOnly: false
    - command:
        - "cat"
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
      image: "registry.cn-beijing.aliyuncs.com/devops-tols/kubectl:self-1.17" #指定kubectl镜像
      imagePullPolicy: "IfNotPresent"
      name: "kubectl"
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
          readOnly: false
    - command:
        - "cat"
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
      image: "registry.cn-beijing.aliyuncs.com/devops-tols/docker-git:1.19-git"
      imagePullPolicy: "IfNotPresent"
      name: "docker"
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "localtime"
          readOnly: false
        - mountPath: "/var/run/docker.sock"
          name: "dockersock"
          readOnly: false
  restartPolicy: "Never"
  nodeSelector:
    jenkins-build: "true" #匹配node标签 部署pod
  securityContext: {}
  volumes:
    - hostPath:
        path: "/var/run/docker.sock"
      name: "dockersock"
    - hostPath:
        path: "/usr/share/zoneinfo/Asia/Shanghai"
      name: "localtime"
    - name: "cachedir"
      hostPath:
        path: "/opt/m2"
'''
    }
}
  stages {
    stage('Pulling Code') {
      parallel {
        stage('Pulling Code by Jenkins') {
          when {
            expression {
              env.gitlabBranch == null
            }

          }
          steps {
            git(changelog: true, poll: true, url: 'https://Your GIT address/server/tcm-parent.git', branch: "${BRANCH}", credentialsId: 'GITEA_ACCOUNT')
            script {
              COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
              TAG = BUILD_TAG + '-' + COMMIT_ID
              println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"

            }

          }
        }

        stage('Pulling Code by trigger') {
          when {
            expression {
              env.gitlabBranch != null
            }

          }
          steps {
            git(url: 'https://Your GIT address/server/tcm-parent.git', branch: env.gitlabBranch, changelog: true, poll: true, credentialsId: 'GITEA_ACCOUNT')
            script {
              COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
              TAG = BUILD_TAG + '-' + COMMIT_ID
              println "Current branch is ${env.gitlabBranch}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
            }

          }
        }

      }
    }

    stage('Building') {
      steps {
        container(name: 'build') {
            sh """
            mvn clean package -Dmaven.test.skip=true -Ptest
            ls tcm-web/tcm-web-patient/target/*
            """
        }
      }
    }

    stage('Docker build for creating image') {
      environment {
        HARBOR_USER = credentials('HARBOR_ACCOUNT')
    }
      steps {
        container(name: 'docker') {
          sh """
          echo ${HARBOR_USER_USR} ${HARBOR_USER_PSW} ${TAG}
          pwd
          ls *
          mkdir -p repo/${IMAGE_NAME}
          cp tcm-web/tcm-web-patient/target/**.jar repo/${IMAGE_NAME}
          sed -i "s/\r//" tcm-web/tcm-web-patient/start.sh
          cp tcm-web/tcm-web-patient/start.sh  repo/${IMAGE_NAME}
          cp tcm-web/tcm-web-patient/Dockerfile  repo/${IMAGE_NAME}
          cd repo/${IMAGE_NAME}
          ls *
          docker version
          docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} .
          docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}
          docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG}
          """
        }
      }
    }

    stage('Deploying to K8s') {
      environment {
        MY_KUBECONFIG = credentials('k8s-kubeconfig')
    }
      steps {
          container(name: 'kubectl'){
           sh """
           /usr/local/bin/kubectl --kubeconfig $MY_KUBECONFIG set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} -n $NAMESPACE
           """
        }
      }
    }

  }
  environment {
    COMMIT_ID = ""
    HARBOR_ADDRESS = "Your harbor warehouse address" #指定你的镜像仓库地址
    REGISTRY_DIR = "trt-master" #指定仓库命名空间
    IMAGE_NAME = "tcm-web-patient" #指定你的服务名称
    NAMESPACE = "tongrentang" #指定kubernetes命名空间
    TAG = ""
  }
  parameters {
    gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
    //下面是根据业务需求可以固定master分支进行构建
    //string(defaultValue: 'master', description: 'Branch for build and deploy', name: 'BRANCH')
  }
}

3.定义Kubernetes资源

这里我们定义一个deployment的资源类型,

基于Yaml形式部署一个Java资源
#vim tcm-web-patient.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: tcm-web-patient #定义deployment标签,和流水线版本部署环节set -l一致
  name: tcm-web-patient  #Deployment 名称
  namespace: tongrentang  #命名空间
spec:
  replicas: 1	#Pod副本
  selector:
    matchLabels:
      app: tcm-web-patient
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  template:
    metadata: #定义资源的元数据信息,比如资源的名称,namespace,标签等信息
      creationTimestamp: null # 表示该资源的创建时间戳尚未被创建,当创建一个资源时,kubernetes会自动分配一个创建时间戳
      labels:
        app: tcm-web-patient #pod的标签
    spec:
      affinity: #定义亲和力配置,用于指定Pod的调度规则
        podAntiAffinity: #pod反亲和力
          preferredDuringSchedulingIgnoredDuringExecution: #定义一个优先级较高的反亲和力规则
          - podAffinityTerm: #定义了一个Pod亲亲和性条件,用于选择与之匹配的pod
              labelSelector:  #定义了标签选择器,用于选择具体特定标签的Pod
                matchExpressions: #定义了匹配表达式,通过Key和operator指定匹配条件
                - key: app #表示匹配的标签键为"app"的Pod
                  operator: In #表示匹配操作为“In”,即匹配标签值在指定的列表中
                  values:
                  - auth-be #表示要匹配的标签值是"auth-be"
              topologyKey: kubernetes.io/hostname #表示使用节点主机名作为拓扑键,用于根据节点进行反亲和力调度
            weight: 100 #表示该反亲和性规则的权重为100,即比其他规则更具有优先级
#上述反亲和性规则:这样的配置可以确保在调度该Pod时,尽量避免与具有标签 app=auth-be 的其他Pod调度在同一节点上。
      containers: 
      - env:
        - name: TZ
          value: Asia/Shanghai
        - name: LANG 
          value: C.UTF-8
        image: nginx #此处使用nginx镜像作为原始镜像,通过 Jenkins 构建并发版后,就会被替换成Java应用的镜像
        imagePullPolicy: IfNotPresent #镜像拉取规则, 表示本地存在则使用本地镜像,不拉取
        lifecycle: {} #生命周期
        livenessProbe: #存活探针(通过检测容器内部程序响应是否正常来决定是否重启)
          failureThreshold: 2 #最大失败次数(检测失败两次就表示该容器不健康,就会尝试重启)
          initialDelaySeconds: 30 #延迟的时间s(表示延迟30秒后开始进行存活探测。这个参数用于等待容器启动并初始化完成。)
          periodSeconds: 10  #探测间隔时间 (表示每隔10s就会探测一次)
          successThreshold: 1 #表示连续探测成功一次,容器就会被认为是健康状态
          tcpSocket:	#字段定义了一个TCP Socket探测容器内部程序响应是否正常
            port: 80 #探测的目标端口是80
          timeoutSeconds: 2 #探测超时时间2秒,如果超过这个时间,仍然还没有收到响应,那么探测将被认为是失败的
        name: auth-be
        ports:
        - containerPort: 80
          name: web
          protocol: TCP
        readinessProbe: #就绪探针(通过确定容器是否就绪,决定是否接受请求)
          failureThreshold: 2 #最大失败次数(探测失败两次就表示未就绪,此时就会尝试切断流量)
          initialDelaySeconds: 30 #延迟时间(表示延迟30秒后开始进行就绪探测。这个参数用于等待容器启动并初始化完成。)
          periodSeconds: 10 #探测间隔时间(表示每隔10s就会开始探测一次)
          successThreshold: 1  #表示连续探测成功一次,容器就会被认为是就绪状态,开始接受流量请求,
          tcpSocket: #字段定义了一个TCP Socket探测方式,用于检测容器内部程序是否就绪
            port: 80 
          timeoutSeconds: 2 #探测超时2秒,如果超过该时间,仍然没有响应,那认为是失败的
        resources: #资源限制
          limits: #最大限制
            cpu: 994m
            memory: 1170Mi
          requests: #最小请求
            cpu: 10m
            memory: 55Mi 
      dnsPolicy: ClusterFirst 
      imagePullSecrets:
      - name: harborkey #指定harbor仓库的认证密钥文件(secret)
      restartPolicy: Always 
      securityContext: {} 
      serviceAccountName: default
#kubectl apply -f tcm-web-patient.yaml

4.定义java服务启动脚本

该脚本需要放置Git项目上,和Jenkinsfile保持同级目录

#vim  start.sh
#!/bin/sh
echo -------------------------------------------
echo start server
echo -------------------------------------------
# JAVA_HOME
#export JAVA_HOME=/data/jdk
# 设置项目代码路径
export _EXECJAVA="$JAVA_HOME/bin/java"

JAVA_OPTS="-XX:+UseContainerSupport -XX:InitialRAMPercentage=40.0 -XX:MinRAMPercentage=20.0 -XX:MaxRAMPercentage=80.0  -XX:-UseAdaptiveSizePolicy"
#jar包 名称
JAR_NAME=`ls /data/webserver/*jar`

# 启动类
$_EXECJAVA $JAVA_OPTS -jar -Dspring.profiles.active=test -Xms512m -Xmx512m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:+PrintReferenceGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintCommandLineFlags -XX:+PrintFlagsFinal -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=45 -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gclogs   $JAR_NAME

5.定义Dockerfile

该资源同样要与Jenkinsfile 文件保持统计目录

#vim Dockerfile
FROM registry.cn-beijing.aliyuncs.com/devops-tols/openjdk:8-jre-alpine
MAINTAINER bixiaoyu@bjca.org.cn

#ENV TZ=Asia/Shanghai
RUN mkdir /data/webserver -p

ENV LANG en_US.UTF-8
ADD start.sh /data/webserver/
RUN chmod +x /data/webserver/start.sh

#COPY agent /data/agent
ADD *.jar /data/webserver/
#RUN apk add --update ttf-dejavu fontconfig

EXPOSE 9300

ENTRYPOINT ["/data/webserver/start.sh"]

下图是公司内部gitea环境,三个资源一定要在同级目录

分享生产项目DevOps CICD流水线解决方案_git_30

6.创建Jenkins job任务

资源准备就绪之后只需要在jenkins创建任务即可

分享生产项目DevOps CICD流水线解决方案_git_31

分享生产项目DevOps CICD流水线解决方案_docker_32

分享生产项目DevOps CICD流水线解决方案_Jenkins_33

7.控制台输出信息详解

构建日志上部分为创建 Pod 的日志,可以看到 Pod 为 Agent 指定的 Pod:

分享生产项目DevOps CICD流水线解决方案_docker_34

分享生产项目DevOps CICD流水线解决方案_Jenkins_35

分享生产项目DevOps CICD流水线解决方案_docker_36

分享生产项目DevOps CICD流水线解决方案_docker_37

分享生产项目DevOps CICD流水线解决方案_git_38

分享生产项目DevOps CICD流水线解决方案_docker_39

分享生产项目DevOps CICD流水线解决方案_Jenkins_40

验证流程

分享生产项目DevOps CICD流水线解决方案_docker_41

END!

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  wwLZeziuqjLR   2023年12月11日   30   0   0 Dockercentos
  MCWYWqSAMsot   2023年12月11日   31   0   0 Docker
  DnoStTHsc0vp   2023年12月11日   24   0   0 Docker
  wwLZeziuqjLR   2023年12月08日   99   0   0 Dockercentosbash
T5Bv8I9TIFQW