Jenkins-安装

安装

创建Role RoleBinding

kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-blue
  namespace: kube-ops
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins-blue
subjects:
- kind: ServiceAccount
  name: jenkins-blue
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: jenkins-blue
  namespace: kube-ops
rules:
- apiGroups:
  - extensions
  - apps
  resources:
  - deployments
  verbs:
  - create
  - delete
  - get
  - list
  - watch
  - patch
  - update
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - create
  - delete
  - get
  - list
  - watch
  - patch
  - update
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - pods/exec
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - pods/log
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - get
EOF

创建serviceAccount,并创建sa的sercret

kubectl apply -f - <<EOF
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
  name: jenkins-blue
  namespace: kube-ops
secrets:
- name: jenkins-blue
---
apiVersion: v1
kind: Secret
metadata:
  name: jenkins-blue
  namespace: kube-ops
  annotations:
    kubernetes.io/service-account.name: "jenkins-blue"
type: kubernetes.io/service-account-token
EOF

创建configmaps

kubectl apply -f - <<EOF
apiVersion: v1
data:
  addJavaAppStart.sh: >
    #!/bin/sh


    echo "获取包依赖关系: "

    mvn dependency:tree -D outputFile=/pipeline-stage-share/dependency_tree.txt
    -D outputType=dot -D includes=cn.axzo.*


    echo ' 

    #!/bin/bash


    # Copyright 2019-2039 AXZO Co. Ltd.

    # Licensed under the Apache License, Version 2.0 (the "License");

    # you may not use this file except in compliance with the License.

    # You may obtain a copy of the License at


    #      http://www.apache.org/licenses/LICENSE-2.0

    #

    # Unless required by applicable law or agreed to in writing, software

    # distributed under the License is distributed on an "AS IS" BASIS,

    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

    # See the License for the specific language governing permissions and

    # limitations under the License.

    artifact=\$1


    if [[ \$# -le 0 ]]; then
      echo "Usage: \$0 example.jar"
      exit 255
    fi


    readonly megabytes=1048576

    # shellcheck disable=SC2004


    # jvm堆内存占容器内存上限的比例, 如果没有设置, 则默认为60%

    if [ "\${JVM_MEM_PERCENT}" == "" ]; then
      JVM_MEM_PERCENT="60"
    fi


    # jvm堆内存数值计算, 如果容器内存上限没有设置, 则堆内存直接设置为1024m

    if [ "\${MY_MEMORY_LIMIT}" == "" ]; then
      heapmem="1024m"
    else
      heapmem=\$(printf "%sm" \$(((\$MY_MEMORY_LIMIT / \$megabytes) * \$JVM_MEM_PERCENT / 100)))
    fi


    # jvm堆内存精细化设置, 会覆盖前面的jvm堆内存设置, 并添加非堆内存的设置

    if [ x"\${JVM_MEM_HEAP}" != x ]; then
      heapmem=\${JVM_MEM_HEAP}
    fi

    if [ "\${JVM_MEM_DIRECT}" == "" ]; then
      directmem="512m"
    else
      directmem=\${JVM_MEM_DIRECT}
    fi

    if [ "\${JVM_MEM_METASPACE}" == "" ]; then
      metaspacemem="512m"
    else
      metaspacemem=\${JVM_MEM_METASPACE}
    fi


    if [ "\${JVM_OCCUPANCY_PERCENT}" == "" ]; then
      jvm_occupancy_percent="50"
    else
      jvm_occupancy_percent=\${JVM_OCCUPANCY_PERCENT}
    fi


    if [ "\${JVM_NEWSIZE_PERCENT}" == "" ]; then
      jvm_newsize_percent="60"
    else
      jvm_newsize_percent=\${JVM_NEWSIZE_PERCENT}
    fi


    export COLLECTOR="-XX:+UseG1GC -XX:ConcGCThreads=4
    -XX:+UnlockExperimentalVMOptions
    -XX:G1MaxNewSizePercent=\${jvm_newsize_percent}
    -XX:InitiatingHeapOccupancyPercent=\${jvm_occupancy_percent}
    -XX:G1HeapRegionSize=4M -XX:MaxTenuringThreshold=15 -XX:ParallelGCThreads=8"

    export LOGGER="-Xloggc:/tmp/gc.log -XX:+PrintGCDetails
    -XX:+PrintGCDateStamps"

    export HEAP="-Xmx\${heapmem} -Xms\${heapmem}"

    export NON_HEAP="-XX:MaxDirectMemorySize=\${directmem}
    -XX:MaxMetaspaceSize=\${metaspacemem}"

    export DUMP="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump/"

    export MON="-XX:NativeMemoryTracking=detail"


    JAVA_OPTS="\$JAVA_OPTS \${JAVA_HEAP:-\${HEAP}}"

    JAVA_OPTS="\$JAVA_OPTS \${JAVA_NON_HEAP:-\${NON_HEAP}}"

    JAVA_OPTS="\$JAVA_OPTS \${JAVA_GC:-\${COLLECTOR}}"

    JAVA_OPTS="\$JAVA_OPTS \${JAVA_LOGS:-\${LOGGER}}"

    JAVA_OPTS="\$JAVA_OPTS \${JAVA_DUMP:-\${DUMP}}"

    JAVA_OPTS="\$JAVA_OPTS \${JAVA_MON:-\${MON}}"


    # prometheus jmx agent加载, 主动开启才加载,默认不加载

    if [ "\${PROMETHEUS_JMX_AGENT}" == "true" ]; then
      JAVA_OPTS="\$JAVA_OPTS -javaagent:/mnt/jvm-agent/prometheus-javaagent/jmx_prometheus_javaagent-0.20.0.jar=12345:/mnt/jvm-agent/prometheus-javaagent/config.yaml"
    fi


    # tingyun agent加载, 主动开启才加载,默认不加载

    if [ "\${TINGYUN_JMX_AGENT}" == "true" ]; then
      JAVA_OPTS="\$JAVA_OPTS -javaagent:/mnt/skywalking-es7/agent/tingyun/tingyun-agent-java.jar -Dtingyun.app_name=\${MY_PROJECT_NAME}"
    fi


    # 其他JVM_AGENT设置, 可能会与前面的agent设置重复

    JAVA_OPTS="\$JAVA_OPTS \${JVM_AGENT}"


    # 其他JVM追加设置, 可能会与前面的设置重复

    JAVA_OPTS="\$JAVA_OPTS \${JVM_EXT_ARG}"


    # 其他固定的JAVA_OPTS

    JAVA_OPTS="\$JAVA_OPTS -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai"

    JAVA_OPTS="\$JAVA_OPTS -jar \${artifact}"


    echo "starting appliction \${artifact%????}"

    echo "running command: java \$JAVA_OPTS"

    eval "exec java \$JAVA_OPTS"


    ' > axzo_java_app_startup.sh


    JarFile=`echo \${ENTRYPOINT} | awk -F , '{print \$NF}'`

    JarFile=`echo \${JarFile} | sed 's/"//g'`


    echo "\n" >> Dockerfile


    # 注入MY_PROJECT_NAME环境变量

    echo "env MY_PROJECT_NAME \${ProjectName}" >> Dockerfile


    # 注入启动脚本并使用此脚本为容器启动脚本,覆盖Dockerfile中原有的ENTRYPOINT

    echo "ADD axzo_java_app_startup.sh /axzo_java_app_startup.sh" >> Dockerfile

    echo "ADD dependency_tree.txt /dependency_tree.txt" >> Dockerfile

    echo "ENTRYPOINT sh /axzo_java_app_startup.sh \${JarFile}" >> Dockerfile


    cat Dockerfile
  mvDockerBuildDep.py: |-
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    import sys
    import subprocess
    import os
    import re
    import json
    import requests
    import hashlib

    def runCommand(commandStr):
        r = subprocess.getstatusoutput(commandStr)
        if r[0] == 0:
            print(r[1])
            return r[1]
        else:
            print(r[1])
            return False

    if not os.path.exists("Dockerfile"):
        print("No Dockerfile found,quit.")
        sys.exit(0)
    if not os.path.exists("dockerBuildOnly"):
        os.mkdir("dockerBuildOnly")

    # java类应用计算包依赖
    axzoDepList = []
    if os.path.exists("/pipeline-stage-share/dependency_tree.txt"):
        for line in open("/pipeline-stage-share/dependency_tree.txt","r"):
            try:
                if re.search(" -> ",line):
                    depLeftGroupId = line.strip().split(" -> ")[0].split("\"")[1].split(":")[0]
                    depLeftArtifactId = line.strip().split(" -> ")[0].split("\"")[1].split(":")[1]

                    depRightGroupId = line.strip().split(" -> ")[1].split("\"")[1].split(":")[0]
                    depRightArtifactId = line.strip().split(" -> ")[1].split("\"")[1].split(":")[1]
                    
                    if depLeftGroupId.startswith("cn.axzo") and depRightGroupId.startswith("cn.axzo"):
                        #print(line.strip())

                        depRight = "{}:{}".format(depRightGroupId,depRightArtifactId)
                        # print(depRight)
                        if depRight not in axzoDepList:
                            axzoDepList.append(depRight)      
            except:
                continue

    # 查询依赖包的版本信息
    with open("/pipeline-stage-share/dependency_tree.txt","w+") as f:
        for axzoDep in axzoDepList:
            if os.getenv("targetEnv") in ["axzo-pro","axzo-live"] or os.getenv("targetEnv").endswith("-prod"):
                repository = "axzo-master"
            else:
                repository = os.getenv("targetEnv")
            url = "https://nexus.axzo.cn/service/rest/v1/search?repository={}&group={}&name={}&sort=version&direction=desc".format(repository,axzoDep.split(":")[0],axzoDep.split(":")[1])
            headers = {
                'content-type': 'application/json',
                'Accept': 'application/json;charset=utf-8'
            }
            try:
                r = requests.get(url=url, headers=headers)
                # print(r.text)
                r_json = json.loads(r.text)
                for i in r_json["items"]:
                    print("{}.{}: {}".format(axzoDep.split(":")[0],axzoDep.split(":")[1],i["version"]))
                    f.write("{}.{}: {}\n".format(axzoDep.split(":")[0],axzoDep.split(":")[1],i["version"]))
                    f.flush()
                    break
            except:
                # traceback.print_exc()
                continue

    # 计算依赖清单md5值
    if os.path.exists("/pipeline-stage-share/dependency_tree.txt"):
        with open("/pipeline-stage-share/dependency_tree.txt", 'rb') as fp:
            data = fp.read()
        file_md5= hashlib.md5(data).hexdigest()

        with open("/pipeline-stage-share/dependency_tree.txt.md5sum","w") as f:
            f.write(file_md5)
            f.flush()
        commandStr = "cat /pipeline-stage-share/dependency_tree.txt > dependency_tree.txt"
        runCommand(commandStr)
        

    depFiles = []
    for line in open("Dockerfile"):
        line = line.strip()
        if line.startswith("COPY") or line.startswith("ADD"):
            lineWords = line.split()
            del lineWords[0]
            del lineWords[-1]
            for depFile in lineWords:
                depFile = depFile.strip("/")
                depFiles.append(depFile)
    depFiles.append("Dockerfile")

    for depFile in depFiles:
        if not os.path.exists(depFile):
            print("Not found: {}".format(depFile))
            sys.exit(1)
        commandStr = "cp --parents -raf {} dockerBuildOnly/".format(depFile)
        print(commandStr)
        r = runCommand(commandStr)
        if r == False:
            sys.exit(1)



    sys.exit(0)
  pomTrack.py: >
    #! /usr/bin/env python

    # -*- coding: utf-8 -*-


    import xml.etree.ElementTree as et

    import sys

    import json

    import os

    import traceback

    import requests


    envName = sys.argv[1]



    def pomTrack(xmlFile,module):
        global deploy_list
        global my_group_id
        deploy_list[module] = {}
        deploy_list[module]["pom"] = xmlFile

        dependency_list_by_pom[xmlFile] = []
        if not os.path.exists(xmlFile):
            print("Not found: ",xmlFile)
            return True
        try:
            tree = et.parse(xmlFile)
            #print(tree)
        except:
            traceback.print_exc()
            return False
        # print(xmlFile)
        root = tree.getroot()
        #print(thisXml.attrib)
        for i in root:
            if i.tag.endswith("name"):
                deploy_list[module]["name"] = i.text
                break
        for i in root:
            if i.tag.endswith("artifactId"):
                deploy_list[module]["artifactId"] = i.text
                break
        for i in root:
            if i.tag.endswith("groupId"):
                my_group_id = i.text
                deploy_list[module]["groupId"] = i.text
                break
        for i in root:
            if i.tag.endswith("packaging"):
                deploy_list[module]["packaging"] = i.text
                break
        for i in root:
            if i.tag.endswith("version"):
                deploy_list[module]["version"] = i.text
                break
        if "groupId" not in deploy_list[module].keys():
            deploy_list[module]["groupId"] = my_group_id
        
        
        for i in root:
            if i.tag.endswith("dependencies"):
                #print("\tdependencies:")
                for j in i:
                    if j.tag.endswith("dependency"):
                        isDepAxzo = False
                        thisMap = {}
                        for k in j:
                            thisMap[k.tag.replace('{http://maven.apache.org/POM/4.0.0}',"")] = k.text
                            if k.tag.replace('{http://maven.apache.org/POM/4.0.0}',"") == "groupId" and k.text.startswith("cn.axzo."):
                                if k.text not in dependency_list.keys():
                                    dependency_list[k.text] = []
                                isDepAxzo = True
                        if isDepAxzo:
                            for k in j:
                                if k.tag.replace('{http://maven.apache.org/POM/4.0.0}',"") == "groupId" and k.text.startswith("cn.axzo."):
                                    dependency_list_by_pom[xmlFile].append(thisMap)
                                    if thisMap["artifactId"] not in dependency_list[k.text]:
                                        dependency_list[k.text].append(thisMap["artifactId"])
                break
        for i in root:
            if i.tag.endswith("modules"):
                for j in i:
                    if j.tag.endswith("module"):
                        xmlFileName = xmlFile.split("/")[-1]
                        moduleXmlFile = "{}/pom.xml".format(xmlFile.replace(xmlFileName,j.text))
                        pomTrack(moduleXmlFile,j.text)

    my_group_id = "None"

    deploy_list = {}

    dependency_list = {}

    dependency_list_by_pom = {}

    pomTrack("./pom.xml","root")       



    # print(json.dumps(deploy_list,sort_keys=True, indent=4,
    ensure_ascii=False))

    # print(json.dumps(dependency_list,sort_keys=True, indent=4,
    ensure_ascii=False))


    print("依赖清单:")

    for k,v in dependency_list.items():
        for x in v:
            if envName in ["axzo-pro","axzo-live"] or envName.endswith("-prod"):
                repository = "axzo-master"
            else:
                repository = envName
            url = "https://nexus.axzo.cn/service/rest/v1/search?repository={}&group={}&name={}&sort=version&direction=desc".format(repository,k,x)
            headers = {
                'content-type': 'application/json',
                'Accept': 'application/json;charset=utf-8'
            }
            try:
                r = requests.get(url=url, headers=headers)
                # print(r.text)
                r_json = json.loads(r.text)
                for i in r_json["items"]:
                    print("{}.{}: {}".format(k,x,i["version"]))
                    break
            except:
                # traceback.print_exc()
                continue
    #print(json.dumps(dependency_list_by_pom,sort_keys=True, indent=4,
    ensure_ascii=False))


    # sys.exit(0)
kind: ConfigMap
metadata:
  name: jenkins-scripts
  namespace: kube-ops
EOF

创建secrets

kubectl apply -f - <<EOF
apiVersion: v1
data:
  git-credentials: xxxx
kind: Secret
metadata:
  name: jenkins-secret
  namespace: kube-ops
type: Opaque
EOF

创建PVC

kubectl apply -f - <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jenkins-1223
  namespace: kube-ops
  annotations:
    volume.beta.kubernetes.io/storage-provisioner: everest-csi-provisioner
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Gi
  storageClassName: sfsturbo-k8s-ops
  volumeMode: Filesystem
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: maven
  namespace: kube-ops
  annotations:
    volume.beta.kubernetes.io/storage-provisioner: everest-csi-provisioner
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 550Gi
  storageClassName: sfsturbo-k8s-ops
  volumeMode: Filesystem
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jnlp-data
  namespace: kube-ops
  annotations:
    volume.beta.kubernetes.io/storage-provisioner: everest-csi-provisioner
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 550Gi
  storageClassName: sfsturbo-k8s-ops
  volumeMode: Filesystem
EOF

创建deploy service

kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    name: jenkins-new
  name: jenkins-new
  namespace: kube-ops
spec:
  progressDeadlineSeconds: 600
  replicas: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      name: jenkins-new
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        name: jenkins-new
      name: jenkins-new
    spec:
      automountServiceAccountToken: true
      containers:
        - env:
            - name: JAVA_OPTS
              value: >-
                -Xmx16g -Xms16g -XshowSettings:vm
                -Dhudson.slaves.NodeProvisioner.initialDelay=0
                -Dhudson.slaves.NodeProvisioner.MARGIN=50
                -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85
                -Duser.timezone=Asia/Shanghai
            - name: LIMITS_MEMORY
              valueFrom:
                resourceFieldRef:
                  divisor: '0'
                  resource: limits.memory
          image: 'harbor.axzo.cn/devops/jenkins:2.375.1-lts'
          imagePullPolicy: IfNotPresent
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /login
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 30
            periodSeconds: 5
            successThreshold: 1
            timeoutSeconds: 2
          name: jenkins-new
          ports:
            - containerPort: 8080
              name: 8080tcp2
              protocol: TCP
            - containerPort: 50000
              name: 50000tcp2
              protocol: TCP
          securityContext:
            privileged: true
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /etc/localtime
              name: tz-config
            - mountPath: /var/jenkins_home
              name: jenkins-1223
      dnsPolicy: ClusterFirst
      hostAliases:
        - hostnames:
            - harbor.axzo.cn
          ip: 172.16.2.25
      imagePullSecrets:
        - name: harbor
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        fsGroup: 1000
      serviceAccount: jenkins-blue
      serviceAccountName: jenkins-blue
      terminationGracePeriodSeconds: 10
      volumes:
        - hostPath:
            path: /usr/share/zoneinfo/Asia/Shanghai
          name: tz-config
        - name: jenkins-1223
          persistentVolumeClaim:
            claimName: jenkins-1223
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins-new
  namespace: kube-ops
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
    - name: agent
      port: 50000
      protocol: TCP
      targetPort: 50000
  selector:
    name: jenkins-new
  type: NodePort
EOF