本文很長很長,可是句句乾貨,點贊關注收藏後有驚喜在文末等你html
現有混合雲平臺的場景下,即有線下和線上的環境,又有測試與正式的場景,並且結合了Docker,致使打包內容有所區分,且服務的發佈流程複雜起來,手工打包須要在編譯階段就要根據環境處處更改配置,所以純手工發佈增長了實施的難度,須要一個統一的適應各類環境部署的方案。前端
基於微服務的發佈流程vue
手動/自動構建 -> Jenkins 調度 K8S API ->動態生成 Jenkins Slave pod -> Slave pod 拉取 Git 代碼/編譯/打包鏡像 ->推送到鏡像倉庫 Harbor -> Slave工做完成,Pod 自動銷燬 ->部署到測試或生產 Kubernetes(K8S)平臺。java
上面是理想情況下的將服務編譯打包成鏡像上傳到鏡像庫後部署到Kubernetes平臺的一個流程,但問題是:node
咱們有線上線下平臺,代碼在線下GitLab,是出不了外網的,所以線上K8S集羣沒法拉取代碼編譯。git
Jenkins的master所在服務器是CentOS6.5,沒有Docker環境,也沒有在K8S集羣服務器內,所以沒法直接執行docker build鏡像和 kubectl apply 發佈服務到K8S集羣。程序員
Jenkins的slave節點都是沒法訪問外網的,線上服務須要Pinpoint而線下環境暫時不須要啓用Pinpoint,不然一直報錯,所以須要根據選擇的環境動態的構建Dockerfile,並且要求整個發佈流程可選擇。web
就上面現實問題,咱們將發佈流程簡化:面試
關鍵點:spring
Docker鏡像的打包使用com.spotify的docker-maven-plugin插件結合Dockerfile,調用遠程服務器的Docker環境生成鏡像。
K8S服務部署採用的是ssh方式,將Deployment文件上傳到K8S集羣服務器,而後執行部署命令。
如何利用Dockerfile打包鏡像
以前也是用com.spotify的docker-maven-plugin插件來打包鏡像並推送到私有鏡像倉庫,但問題是沒法根據環境寫條件判斷,如動態選擇是否須要啓動pinpoint,線上線下庫地址動態更換,致使鏡像名前綴也是要動態變化的,此時直接配置沒法知足,須要結合Dockerfile來實現。
先更改pom文件,指定本項目的Dockerfile文件地址,默認是放在項目根目錄下:
<plugin><groupId>com.spotify</groupId><artifactId>docker-maven-plugin</artifactId><version>1.2.0</version><configuration><!--覆蓋相同標籤鏡像--><forceTags>true</forceTags><!-- 與maven配置文件settings.xml一致 --><serverId>nexus-releases</serverId><!--私有倉庫地址 --><registryUrl>https://${docker.repostory}</registryUrl><!--遠程Docker地址 --><dockerHost>http://10.3.87.210:2375</dockerHost><!-- 注意imageName必定要是符合正則[a-z0-9-_.]的,不然構建不會成功 --><!--指定鏡像名稱 倉庫/鏡像名:標籤--><imageName>${docker.repostory}/${project.artifactId}:${project.version}</imageName><dockerDirectory>${project.basedir}</dockerDirectory><resources><resource><!-- 指定要複製的目錄路徑,這裏是當前目錄 --><!-- 將打包文件放入dockerDirectory指定的位置 --><targetPath>/app/</targetPath><!-- 指定要複製的根目錄,這裏是target目錄 --><directory>${project.build.directory}</directory><!-- 指定須要拷貝的文件,這裏指最後生成的jar包 --><include>${project.build.finalName}.jar</include></resource></resources></configuration></plugin>
<registryUrl>https://${docker.repostory}</registryUrl>
指定遠程倉庫地址,在主項目的<properties>中指定,這裏默認線上倉庫<docker.repostory>39.95.40.97:5000</docker.repostory>
<dockerHost>http://10.3.87.210:2375</dockerHost>
指定Docker鏡像打包服務器,這裏指定線下服務器。
<imageName>${docker.repostory}/${project.artifactId}:${project.version}</imageName>
指定鏡像名稱 倉庫/鏡像名:標籤
<dockerDirectory>${project.basedir}</dockerDirectory>
指定Dockerfile文件地址,此處指定項目根目錄
Dockerfile內容
FROM join:0.2
MAINTAINER {description} Join
ADD /app/{artifactId}-{version}.jar /app/
ENTRYPOINT ["java", "-Xmx512m","-Dspring.profiles.active={active}",{jarparam} "-jar", "/app/{artifactId}-{version}.jar"]
基礎鏡像用join:0.2,裏面包含了pinpoint和監控jvm的promethus客戶端包。
Jarparam會在Jenkins中動態替換運行時參數,active 指定當前運行環境,這裏可能有人提議根據項目yml文件中指定內容自動匹配,由於要考慮到若是自動匹配 更換線上線下環境就須要更改yml配置文件後又要上傳到gitlab,如此沒有必要多作一步,直接在Jenkins中看成參數指定最爲便捷。
此處Dockerfile是通用模板,若是有特殊內容添加,可自行更改,此時的模板須要在Jenkins運行時替換參數後纔有用,若是想直接在本機運行打包,可手動替換參數內容後運行:
clean package -DskipTests docker:build
推送
clean package -DskipTests docker:build -DpushImage
Jenkins發佈流程
利用Jenkins的pipeline構建流水線
Pipeline也就是構建流水線,對於程序員來講,最好的解釋是:使用代碼來控制項目的構建、測試、部署等。使用它的好處有不少,包括但不限於:
l 使用Pipeline能夠很是靈活的控制整個構建過程;
l 能夠清楚的知道每一個構建階段使用的時間,方便構建的優化;
l 構建出錯,使用stageView能夠快速定位出錯的階段;
l 一個job能夠搞定整個構建,方便管理和維護等。
Pipeline 支持兩種語法,聲明式和腳本式。這兩種方法都支持構建持續交付流水線,均可以經過 web UI 或 Jenkinsfile 文件來定義 Pipeline(一般認爲建立 Jenkinsfile 文件並上傳到源代碼控制倉庫是最佳實踐)
Jenkinsfile 就是一個包含對 Jenkins Pipeline 定義的文本文件,會上傳到版本控制中。下面的 Pipeline 實現了基本的 3 段持續交付流水線。
聲明式 Pipeline:
// Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
對應的腳本式 Pipeline:
// Jenkinsfile (Scripted Pipeline)
node {
stage('Build') {
echo 'Building....'
}
stage('Test') {
echo 'Building....'
}
stage('Deploy') {
echo 'Deploying....'
}
}
注意,全部的 Pipeline 都會有這三個相同的 stage,能夠在全部項目的一開始就定義好它們。下面演示在 Jenkins 的測試安裝中建立和執行一個簡單的 Pipeline。
假設項目已經設置好了源代碼控制倉庫,而且已經按照入門章節的描述在 Jenkins 中定義好了 Pipeline。
使用文本編輯器(最好支持 Groovy 語法高亮顯示),在項目根目錄中建立 Jenkinsfile。
上面的聲明式 Pipeline 示例包含了實現一個持續交付流水線所需的最少步驟。必選指令 agent 指示 Jenkins 爲 Pipeline 分配執行程序和工做空間。沒有 agent 指令的話,聲明式 Pipeline 無效,沒法作任何工做!默認狀況下 agent 指令會確保源代碼倉庫已經檢出,而且可用於後續步驟。
stage 和 step 指令在聲明式 Pipeline 中也是必須的,用於指示 Jenkins 執行什麼及在哪一個 stage 中執行。
對於腳本式 Pipeline 的更高級用法,上面的示例節點是相當重要的第一步,由於它爲 Pipeline 分配了一個執行程序和工做空間。若是沒有 node,Pipeline 不能作任何工做!在 node 內,業務的第一階段是檢出此項目的源代碼。因爲 Jenkinsfile 是直接從源代碼控制中提取的,所以 Pipeline 提供了一種快速簡單的方法來訪問源代碼的正確版本:
// Jenkinsfile (Scripted Pipeline)
node {
checkout scm
/* .. snip .. */
}
這個 checkout 步驟會從源代碼控制中檢查代碼,scm 是特殊變量,它指示運行檢出步驟,複製觸發了此次 Pipeline 運行的指定版本。
最終的流程樣式:
通常用聲明式來構建流水,實際操做過程當中仍是發現腳本式構建更順手,並且Groovy語言更方便查資料,所以下面以腳本構建爲主演示一個流程。
1.新建任務
2.填寫任務名和描述,因爲防止構建歷史太多,只保留3個。
3.添加構建時全局構建參數,用來構建流程動態選擇環境,這裏有兩種方式,一種是直接在頁面上添加,以下圖,一種是在Jenkinsfile中添加(第一次構建時不會出現選項,第二次構建纔會出現,所以首次構建須要試構建,暫停再刷新頁面纔會有選擇框),兩種最張效果同樣,這裏爲了方便採用Jenkinsfile來添加全局參數。
Jenkinsfile中添加
properties([
parameters([string(name: 'PORT', defaultValue: '7082', description: '程序運行端口'),choice(name: 'ACTIVE_TYPE', choices: ['dev', 'prd', 'local'], description: '程序打包環境'),choice(name: 'ENV_TYPE', choices: ['online', 'offline'], description: '線上、仍是線下環境'),booleanParam(name: 'ON_PINPOINT', defaultValue: true, description: '是否添加Pinpoint監控'),booleanParam(name: 'ON_PROMETHEUS', defaultValue: true, description: '是否添加Prometheus監控'),string(name: 'EMAIL', defaultValue: '104@qq.com', description: '打包結果通知')])
])
4.選擇源碼代碼庫:
須要添加認證,將Jenkins的ssh祕鑰添加到GitLab的頁面中,且須要將此處gitlab中joint用戶添加到須要拉取代碼的項目中才有權限拉取代碼。
Jenkinsfile位置放在項目的根目錄。
5. Jenkinsfile中指定maven目錄地址
MVNHOME = '/opt/maven354'
爲防止手工填寫項目名和版本號等一系列信息,所以直接讀取pom文件中要編譯項目的這些信息給全局變量:
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}"
根據選擇的線上環境仍是線下環境,替換鏡像倉庫ip
if (params.ENV_TYPE == 'offline' || params.ENV_TYPE == null) {
sh "sed -i 's#39.95.40.97:7806#10.3.87.51:8080#g' pom.xml"
image = "10.3.87.51:8080/${artifactId}:${version}"
}
6.編譯
利用maven構建,利用上面的內容先替換掉Dockerfile、Deployment中的變量,再根據選擇的條件是否啓用pinpoint和promethus,最後編譯。
def jarparam=''
def pinname = artifactId
if( pinname.length() > 23) {
pinname = artifactId.substring(0,23)
}
//添加pinpointif(params.ON_PINPOINT) {
jarparam ='"-javaagent:/app/pinpoint-agent/pinpoint-bootstrap-1.8.0.jar","-Dpinpoint.agentId={pinname}", "-Dpinpoint.applicationName={pinname}",'}//添加prometheusif(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' 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 "'${MVNHOME}/bin/mvn' -DskipTests clean package"
須要注意的是pinpoint的pinpoint.applicationName不能操做24個字符,不然啓用不成功,所以超過的直接截斷。
Department文件詳情看後文。
跳過測試編譯打包 '${MVNHOME}/bin/mvn' -DskipTests clean package 須要在Jenkins服務器安裝maven環境,還有指定maven的jar包私有倉庫地址。
7. Docker打包
前提是上一步指定pom文件中的鏡像倉庫和Dockerfile中的內容是替換後的完整內容。
sh "'${MVNHOME}/bin/mvn' docker:build"
8. 推送鏡像
sh "'${MVNHOME}/bin/mvn' docker:push"
如何發佈服務到K8S集羣
前面幾步已經將項目打包並生成了鏡像並推送到了私有倉庫,下面就是部署服務到K8S集羣。
先看看Department.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:
containers:
- name: {artifactId}
image: {image}
# IfNotPresent\Always imagePullPolicy: Always
ports:
- name: prometheusjmx
containerPort: 1234 livenessProbe: #kubernetes認爲該pod是存活的,不存活則須要重啓 httpGet:
path: /health
port: {port}
scheme: HTTP
initialDelaySeconds: 60## 設置爲系統徹底啓動起來所需的最大時間+若干秒timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 readinessProbe: #kubernetes認爲該pod是啓動成功的 httpGet:
path: /health
port: {port}
scheme: HTTP
initialDelaySeconds: 40## 設置爲系統徹底啓動起來所需的最少時間timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 env:
- name: eureka-server
value: "eureka-server.default.svc.cluster.local"- name: eureka-server-replica
value: "eureka-server-replica.default.svc.cluster.local" resources:
# 5%的CPU時間和700MiB的內存 requests:# cpu: 50m memory: 700Mi
# 最多容許它使用 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
volumes:
- name: logs-volume
hostPath:
# 宿主機上的目錄path: /logs
- name: host-time
hostPath:
path: /etc/localtime
- name: host-timezone
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
- name: pinpoint-config
configMap:
name: pinpoint-config
# 運行在指定標籤的節點,前提是先給節點打標 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}
ports:
- name: tcp-{port}-{port}
protocol: TCP
port: {port}
targetPort: {port}
裏面的變量會在前面幾步自動替換掉。
添加了prometheus收集jvm的內容:
prometheus.io.jmx: "true"
prometheus.io.jmx.port: "1234"
containerPort: 1234
將pinpoint的配置內容pinpoint.config用configMap 保存,方便更改內容。
其它內容不在此詳解,可自行google。
網上資料通常發佈服務都是直接kubectl deploy,這種狀況只適用於jenkins的服務器已包含在K8S服務器集羣中。第二種狀況是在K8S集羣服務器裏面生成Jenkins的一個slave節點,而後在pipeline裏面設置node(「k8s」){ ……} 裏面發佈,具體方法自行google。
這裏爲了不麻煩,採用直接SSH到K8S服務器集羣的方案發布服務。
配置sshagent
SSH Agent Plugin :sshagent方法支持,用於上傳構建產物到目標服務器,使用詳情見:
https://wiki.jenkins.io/display/JENKINS/SSH+Agent+Plugin
在Jenkins插件庫搜索後直接下載安裝(須要連外網環境),生產環境已安裝,直接使用。
使用:
sshagent(credentials: ['deploy_ssh_key_23']) {
sh "scp -P 2222 -r Deployment.yaml root@39.95.40.97:/docker/yaml/Deployment-${artifactId}.yaml"
sh "ssh -p 2222 root@39.95.40.97 'kubectl apply -f /docker/yaml/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'"
}
先用ssh遠程到K8S集羣中的服務器,將Deployment文件上傳,而後再遠程執行kubectl apply發佈服務。
爲了不誤操做,在發佈前作了發佈確認提示判斷。
timeout(time: 10, unit: 'MINUTES') {
input '確認要部署嗎?'
}
以上流程已完成整個流程,而後能夠去K8S環境去看服務是否有正常運行。
關於測試
上面的過程沒有加入代碼測試、代碼質量分析SonarQube、發佈後服務測試的階段(Selenium是一套完整的Web應用程序測試系統http://www.51testing.com/zhuanti/selenium.html),後續能夠接入。
如何進行多模塊如何構建
不少項目採用的是多模塊構成,所以每一個項目配置和發佈要求不同,須要單獨編譯到部署,因此每一個模塊都須要獨立的Dockerfile和Deployment文件,Jenkinsfile通用一份,而後在發佈時自動彈出模塊列表,選擇須要發佈的模塊進行編譯發佈。
//須要處理的項目多項目時先進入子項目
projectwk ="."mainpom = readMavenPom file:'pom.xml'//存在多個模塊時,選擇其中一個進行編譯if(mainpom.modules.size() > 0 ) {
echo "項目擁有模塊==${mainpom.modules}" timeout(time: 10, unit:'MINUTES') {
defselproj = input message:'請選擇須要處理的項目', parameters: [choice(choices: mainpom.modules, description:'請選擇須要處理的項目', name:'selproj')] //, submitterParameter:'project' projectwk = selproj
echo "選擇項目=${projectwk}" }
}
讀取主項目的pom中的modules判斷是否包含多個模塊,供用戶選擇。
而後根據選擇的模塊進行編譯,dir進入選擇的模塊讀取信息並編譯。
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}"}
完整的Jenkinsfile
properties([
parameters([string(name: 'PORT', defaultValue:'7082', description:'程序運行端口'),choice(name:'ACTIVE_TYPE', choices: ['dev','prd','local'], description:'程序打包環境'),choice(name:'ENV_TYPE', choices: ['online','offline'], description:'線上、仍是線下環境'),booleanParam(name:'ON_PINPOINT', defaultValue: true, description:'是否添加Pinpoint監控'),booleanParam(name:'ON_PROMETHEUS', defaultValue: true, description:'是否添加Prometheus監控'),string(name:'EMAIL', defaultValue:'1041126478@qq.com', description:'打包結果通知')])
])
node {
stage('Prepare') {
echo "1.Prepare Stage" MVNHOME ='/opt/maven354'//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') {
defselproj = input message:'請選擇須要處理的項目', parameters: [choice(choices: mainpom.modules, description:'請選擇須要處理的項目', name:'selproj')] //, submitterParameter:'project' projectwk = selproj
echo "選擇項目=${projectwk}" }
}
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}" }
script {
GIT_TAG = sh(returnStdout: true, script:'/usr/local/git/bin/git rev-parse --short HEAD').trim()
echo "GIT_TAG== ${GIT_TAG}" }
image ="192.168.4.2:5000/${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 ="10.3.80.50:5000/${artifactId}:${version}" }
}
if(mainpom.modules.size() > 0 ) {
stage('編譯總項目') {
sh "'${MVNHOME}/bin/mvn' -DskipTests clean install" }
}
dir("${projectwk}") {
stage('編譯模塊') {
echo "2.編譯模塊 ${artifactId}"defjarparam=''defpinname = 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' 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 "'${MVNHOME}/bin/mvn' -DskipTests clean package" stash includes: 'target/*.jar', name:'app' }
stage('Docker打包') {
echo "3.Docker打包" unstash 'app' sh "'${MVNHOME}/bin/mvn' docker:build" }
stage('推送鏡像') {
echo "4.Push Docker Image Stage" sh "'${MVNHOME}/bin/mvn' docker:push" }
timeout(time: 10, unit:'MINUTES') {
input '確認要部署嗎?' }
stage('發佈') {
if(params.ENV_TYPE =='offline'|| params.ENV_TYPE == null) {
sshagent(credentials: ['deploy_ssh_key_34']) {
sh "scp -r Deployment.yaml root@10.2.85.30:/docker/yaml/Deployment-${artifactId}.yaml" sh "ssh root@10.2.85.30 'kubectl apply -f /docker/yaml/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@39.95.40.97:/docker/yaml/Deployment-${artifactId}.yaml" sh "ssh -p 22 root@39.95.40.97 'kubectl apply -f /docker/yaml/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'" }
}
echo "發佈完成" }
}
stage('通知負責人'){// emailext body:"構建項目:${description}\r\n構建完成", subject:'構建結果通知【成功】', to:"${EMAIL}" echo "構建項目:${description}\r\n構建完成" }
}
將Jenkinsfile文件放在項目根目錄,而後將源碼都上傳到GitLab。
打開BlueOcean,這是Jenkins新出的美化頁面。
選擇本身的項目。
進入後點擊運行,其中會彈出框選擇發佈參數(這裏須要手工填寫發佈的端口,因爲採用配置中心化,端口沒法自動讀取)。
進入查看流程狀態,失敗會有相應的提示:
顯示發佈服務
在K8S內查看部署的服務啓動狀況。
Jenkinsfile Pipeline
還能夠進入項目後,有個流水線語法:
選擇想要的功能,生成:
Jenkins還可用做發佈Vue前端項目,具體內容可參考 Jenkins自動化構建vue項目而後發佈到遠程服務器 文檔。
Jenkins要發佈Net服務須要有一臺windows的Jenkins slave,還須要在此節點上安裝編譯器MSBuild框架,Git框架、更改服務器上的IIS權限等功能,最後文件分發到其它windows服務器,過程比較繁瑣,若無發佈審覈建議直接經過VS自帶發佈功能發佈程序。
文末驚喜:天天都會分享技術文章,同時免費分享Java技術教程,習題資料,面試真題,須要的朋友呢能夠在關注我後私信我
來源:知乎
做者:白天不懂夜的黑
原文:https://zhuanlan.zhihu.com/p/73651000