spring cloud+maven+rancher2+Kubernetes(k8s)+git+jenkins+pipeline+docker實現打包自動部署

環境準備:java

rancher2.3管理的k8s環境(本身搭)node

jenkins(可以使用docker搭建,也可直接安裝,若是k8s的不是特別熟悉不建議使用helm安裝jenkins,不少配置不方便改。我是用的docker搭建的,但要記錄掛載docker命令。建議直接在主機上安裝,可避免發佈是的ssh免key的問題git

阿里鏡像倉庫(本身可註冊阿里雲帳號就有了免費的)spring

maven的本地nexus代理服務器(方便公司內部的jar管理)docker

 

1.maven打包並docker編譯發佈我使用的是:json

<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.2.0</version>

此插件已有代替:dockerfile-maven-plugin,不過我沒用這個,由於我本機開發機並無裝docker客戶端之類的軟件,而這個好像是要求本機至少得有docker客戶端環境,還得配置docker環境變量。因此我沒有使用。這樣本機也能夠直接使用maven打包docker build:push代碼到阿里倉庫。方便開發環境應用升級。bootstrap

使用此docker-maven-plugin發現一個bug:api

因爲我拿的是docker安裝的jenkins,啓動容器前沒有掛載docker命令,然後我又依賴此容器,從新生成了鏡像,後來也把阿里鏡像倉庫的登錄認證信息給加入到用戶根目錄下(就是docker的config.json放到/root/.docker/下,不知道百度)後,致使docker-maven-plugin插件裏的serverId與此config.json衝突,沒法把鏡像推送到阿里鏡像倉庫。服務器

也調了我2天,逼的我拿源碼來研究了都。最後發現問題所在。app

解決方法:

如何要直接使用docker命令時,直接使用pipeline指定用戶也密碼。而後我是用pipeline部署的。

 

2.首先在項目根目錄(注意不是maven的模塊目錄)下放置jenkinsfile如圖:

jenkinsfile內容參照:

properties([
	parameters([
		string(name: 'PORT', defaultValue: '1111', description: '程序運行端口'),
		choice(name: 'ACTIVE_TYPE', choices: ['local', 'dev', 'test', 'prod'], description: '程序打包環境'),
		choice(name: 'ENV_TYPE', choices: ['offline', 'online'], description: '仍是線下、線上環境'),
		booleanParam(name: 'All_COMPILE', defaultValue: false, description: '是否須要從新編譯全模塊'),
		booleanParam(name: 'DEPLOYMENT', defaultValue: true, description: '是否部署'),
		booleanParam(name: 'ON_PINPOINT', defaultValue: false, description: '是否添加Pinpoint監控'),
		booleanParam(name: 'ON_PROMETHEUS', defaultValue: false, description: '是否添加Prometheus監控'),
		string(name: 'EMAIL', defaultValue: '******@tintinhealth.com', description: '打包結果通知')

	])
])
node {

	stage('Prepare') {


		echo "1.Prepare Stage"

		def MVNHOME = tool 'maven-3.6.3'
		// 再把變量加入到環境變量中
		//env.PATH = "${jdk77}/bin:${MVNHOME}/bin:${env.PATH}"
		env.PATH = "${MVNHOME}/bin:${env.PATH}"
		MVNCONFIG= '/var/jenkins_home/maven/settings.xml'


		//echo "UUID=${UUID.randomUUID().toString()}"

		checkout scm

		//須要處理的項目多項目時先進入子項目

		projectwk = "."

		mainpom = readMavenPom file: 'pom.xml'

		repostory = "${mainpom.properties['docker.repostory']}"

		//存在多個模塊時,選擇其中一個進行編譯

		//        if(mainpom.modules.size() > 0 ) {

		//          echo "項目擁有模塊==${mainpom.modules}"

		//         timeout(time: 10, unit: 'MINUTES') {

		//            def selproj = input message: '請選擇須要處理的項目', parameters: [choice(choices: mainpom.modules, description: '請選擇須要處理的項目', name: 'selproj')] //, submitterParameter: 'project'

		//            projectwk = selproj

		//           echo "選擇項目=${projectwk}"

		//          }



		//        }
		projectwk="${JOB_NAME}"

		dir("${projectwk}") {

			pom = readMavenPom file: 'pom.xml'

			echo "group: ${pom.groupId}, artifactId: ${pom.artifactId}, version: ${pom.version} ,description: ${pom.description}"

			artifactId = "${pom.artifactId}"

			version = "${pom.version}"

			description = "${pom.description}"

		}
		if(version == 'null'){
			version = "${mainpom.version}"
			echo "使用父version:${version}"
		}

		script {

			GIT_TAG = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()

			echo "GIT_TAG== ${GIT_TAG}"

		}

		image = "registry.cn-hangzhou.aliyuncs.com/ddyk/${artifactId}:${version}"

		//    if (params.ENV_TYPE == 'offline' || params.ENV_TYPE == null) {

		//sh "sed -i 's#39.95.40.97:5000#10.3.80.50:5000#g' pom.xml"

		//      image = "registry.cn-hangzhou.aliyuncs.com/ddyk/${artifactId}:${version}"

		//     }

	}

	if(params.All_COMPILE){

		if(mainpom.modules.size() > 0 ) {

			stage('編譯總項目') {

				sh "mvn -s ${MVNCONFIG} -DskipTests clean install"

			}

		}
	}

	dir("${projectwk}") {

		stage('編譯模塊') {

			echo "2.編譯模塊 ${artifactId}"

			def jarparam=''

			def pinname = artifactId

			if( pinname.length() > 23) {

				pinname = artifactId.substring(0,23)

			}

			//添加pinpoint

			if(params.ON_PINPOINT) {

				jarparam = '"-javaagent:/app/pinpoint-agent/pinpoint-bootstrap-1.8.0.jar","-Dpinpoint.agentId={pinname}", "-Dpinpoint.applicationName={pinname}",'

			}

			//添加prometheus

			if(params.ON_PROMETHEUS) {

				jarparam = jarparam + '"-javaagent:/app/prometheus/jmx_prometheus_javaagent-0.11.0.jar=1234:/app/prometheus/jmx.yaml",'

			}

			sh "sed -i 's#{jarparam}#${jarparam}#g;s#{port}#${params.PORT}#g' Dockerfile"

			sh "sed -i 's#{description}#${description}#g;s#{artifactId}#${artifactId}#g;s#{version}#${version}#g;s#{active}#${params.ACTIVE_TYPE}#g;s#{pinname}#${pinname}#g' Dockerfile"

			sh "sed -i 's#{artifactId}#${artifactId}#g;s#{version}#${version}#g;s#{port}#${params.PORT}#g;s#{image}#${image}#g' Deployment.yaml"

			sh "mvn -s ${MVNCONFIG} -DskipTests clean package"

			stash includes: 'target/*.jar', name: 'app'

		}

		stage('Docker打包') {

			echo "3.Docker打包"

			unstash 'app'

			sh "mvn -s ${MVNCONFIG}  docker:build"

		}

		stage('推送鏡像') {

			echo "4.Push Docker Image Stage"

			sh "mvn -s ${MVNCONFIG}  docker:push"

		}

		//        timeout(time: 10, unit: 'MINUTES') {

		//            input '確認要部署嗎?'

		//         }

		if(params.DEPLOYMENT){
			stage('發佈') {


				if (params.ENV_TYPE == 'offline' || params.ENV_TYPE == null) {

					sshagent(credentials: ['deploy_ssh_key_dev']) {

						sh "scp -r Deployment.yaml root@192.168.1.108:/home/sam/devops/kubernetes/manifests/workTools/ddyk/Deployment-${artifactId}.yaml"

						sh "ssh root@192.168.1.108 'kubectl apply -f /home/sam/devops/kubernetes/manifests/workTools/ddyk/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'"

					}

				} else {

					sshagent(credentials: ['deploy_ssh_key_238']) {

						sh "scp -P 22 -r Deployment.yaml root@192.168.1.108:/home/sam/devops/kubernetes/manifests/workTools/ddyk/Deployment-${artifactId}.yaml"

						sh "ssh -p 22 root@192.168.1.108 'kubectl apply -f /home/sam/devops/kubernetes/manifests/workTools/ddyk/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'"

					}

				}

				echo "發佈完成"

			}
		}

	}

	stage('通知負責人'){

		//    emailext body: "構建項目:${artifactId}\r\n構建完成", subject: '構建結果通知【成功】', to: "${EMAIL}"

		//        echo "構建項目:${description}\r\n構建完成"
		echo "構建項目:${artifactId}\r\n構建完成"

	}

}

以上內容可本身根據須要更改刪除。

3.maven模塊下放以下文件:

Dockerfile內容參照說明:

FROM openjdk:8-alpine

MAINTAINER ddyk gsj "*****@tintinhealth.com"
ENV WORK_PATH /app
#ENV APP_NAME @project.build.finalName@.@project.packaging@

EXPOSE 9108
#統一時區
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime

COPY /app/message-service*.jar $WORK_PATH/app.jar

WORKDIR $WORK_PATH

ENTRYPOINT ["java", "-Xmx512m","-Dspring.profiles.active={active}","-Dserver.port={port}",{jarparam} "-jar", "/app/app.jar"]

Deployment.yaml內容參照:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {artifactId}
  namespace: default
  labels:
    app: {artifactId}
    version: {version}
spec:
  selector:
    matchLabels:
      app: {artifactId}
  replicas: 1
  template:
    metadata:
      labels:
        app: {artifactId}
      annotations:
        prometheus.io.jmx: "true"
        prometheus.io.jmx.port: "1234"
    spec:
      hostAliases:
        - ip: "172.20.246.2"
          hostnames:
            - "node-1"
        - ip: "172.20.246.3"
          hostnames:
            - "node-2"
      containers:
        - name: {artifactId}
          image: {image}
          # IfNotPresent\Always
          imagePullPolicy: Always
          ports:
            - name: prometheusjmx
              containerPort: 1234
          livenessProbe: #kubernetes認爲該pod是存活的,不存活則須要重啓
            httpGet:
              path: /actuator/health
              port: {port}
              scheme: HTTP
            initialDelaySeconds: 60 ## 設置爲系統徹底啓動起來所需的最大時間+若干秒
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 5
          readinessProbe: #kubernetes認爲該pod是啓動成功的
            httpGet:
              path: /actuator/health
              port: {port}
              scheme: HTTP
            initialDelaySeconds: 40 ## 設置爲系統徹底啓動起來所需的最少時間
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 5
          env:
            - name: register-eureka
              value: "register-eureka.default.svc.cluster.local"
            - name: register-eureka-replica
              value: "register-eureka-replica.default.svc.cluster.local"
          resources:
            # 5%的CPU時間和700MiB的內存
            requests:
              #            cpu: 50m
              memory: 250Mi
            # 最多容許它使用
            limits:
              #            cpu: 100m
              memory: 1000Mi
          # 指定在容器中掛載路徑
          volumeMounts:
            - name: logs-volume
              mountPath: /logs
            - name: host-time
              mountPath: /etc/localtime
              readOnly: true
            - name: host-timezone
              mountPath: /etc/timezone
              readOnly: true
#            - name: pinpoint-config
#              mountPath: /app/pinpoint-agent/pinpoint.config
      imagePullSecrets:
      - name: registrykey-m2-1
      volumes:
        - name: logs-volume
          hostPath:
            # 宿主機上的目錄
            path: /logs
        - name: host-time
          hostPath:
            path: /etc/localtime
        - name: host-timezone
          hostPath:
            path: /usr/share/zoneinfo/Asia/Shanghai
#
        # 運行在指定標籤的節點,前提是先給節點打標  kubectl label nodes 192.168.0.113 edgenode=flow
#      nodeSelector:
#        edgenode: flow
---
apiVersion: v1
kind: Service
metadata:
  name: {artifactId}
  namespace: default
  labels:
    app: {artifactId}
    version: {version}
spec:
  selector:
    app: {artifactId}
#  type: NodePort
  ports:
    - name: tcp-{port}-{port}
      protocol: TCP
      port: {port}
      targetPort: {port}
#      nodePort: 31111

注意:prometheus我還沒用上,大家能夠自行修改部署文件調試。

關於register-eureka的部署:服務名與register-eureka同樣。

 

注意事項:jenkins中建的項目名要和maven的模塊名同樣,否則須要修改jenkinsfile文件的部署相關的腳本 。

有不懂的歡迎諮詢,其實這套部署主要就是這些個腳本文件。

對了,自動部署(git提交代碼後自動觸發)只能實如今開發環境,由於畢竟程序沒有能通知何時發送正式環境(當前也能夠根據版本判斷加release與開發版區別),可本身看我前一篇文件。

相關文章
相關標籤/搜索