環境準備: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與開發版區別),可本身看我前一篇文件。