一. Docker
1.1 docker安裝
安裝相關(guān)依賴
sudo yum install -y yum-utils device-mapper-persistent-data lvm2國內(nèi)源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安裝docker
sudo yum -y install docker-ce服務(wù)自啟動(dòng)
systemctl enable docker設(shè)置阿里云鏡像
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://a05qb3lx.mirror.aliyuncs.com"]
}
EOF啟動(dòng)服務(wù)
sudo systemctl daemon-reload
sudo systemctl restart docker
1.2 docker常用命令
查看所有docker容器
docker ps -a啟動(dòng)新容器
docker run -d --name (指定容器名字) -p (端口):(端口) -v (數(shù)據(jù)路徑):(數(shù)據(jù)路徑) (鏡像名):(版本)進(jìn)入容器內(nèi)部
docker exec -it (容器名字) /bin/bash查看容器的日志
docker logs (容器名字)
二. Jenkins
2.1 jenkins安裝
拉取鏡像
docker pull jesusperales/jenkins-docker-run-inside啟動(dòng)鏡像
docker run --name jenkins -d -p 8080:8080 -p 50000:50000 -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):$(which docker) --add-host updates.jenkins-ci.org:(nginx所在節(jié)點(diǎn)的ip地址) jesusperales/jenkins-docker-run-inside訪問服務(wù)
http://ip:8080
生產(chǎn)項(xiàng)目中還需要將配置文件(-v /root/jenkins/conf/config.xml:/var/jenkins_home/config.xml),項(xiàng)目文件等掛載到宿主機(jī)上恶迈。
2.2 參數(shù)介紹
①-p 8080:8080 jenkins通訊端口署咽。
②-p 50000:50000 基于JNLP的Jenkins代理通過TCP端口50000與Jenkins主站進(jìn)行通信,即可以通過瀏覽器直接執(zhí)行java應(yīng)用程序遂赠。
③-v /var/run/docker.sock:/var/run/docker.sock 用于docker客戶端與守護(hù)進(jìn)程通訊
④-v $(which docker):$(which docker) docker指令腳本
⑤--add-host updates.jenkins-ci.org:192.168.32.128 添加本地DNS域名解析
2.3 配置
修改權(quán)限
因?yàn)槟J(rèn)是jenkins用戶登錄,需要添加docker權(quán)限
docker exec -it jenkins /bin/bash
sudo groupadd docker
sudo usermod -aG docker jenkins
sudo cat /etc/group
sudo chmod a+rw /var/run/docker.sock配置maven倉庫為阿里云倉庫
將容器中的配置文件settings.xml復(fù)制到宿主機(jī)
docker cp jenkins:/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/mvn3.5.0/conf/settings.xml ~/將<mirror></mirrors>標(biāo)簽內(nèi)容該為如下配置
<mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror> </mirrors>
將在宿主機(jī)修改完成后的配置文件settings.xml覆蓋回容器中
docker cp jenkins:/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/mvn3.5.0/conf ~/settings.xml
2.4 存在的問題
jenkins需要安裝大量的第三方插件晌杰,但是所有的數(shù)據(jù)源都是指向國外倉庫跷睦,導(dǎo)致國內(nèi)下載插件緩慢甚至大量失敗,因此需要配置國內(nèi)的鏡像源肋演。
方式一:修改鏡像源的url地址(因?yàn)閖enkins會通過數(shù)字簽名驗(yàn)證鏡像源是否有效抑诸,所以這個(gè)方法不可靠):
①$ cd {你的Jenkins工作目錄}/updates #進(jìn)入更新配置位置
②$ vim default.json
在vim中替換官方鏡像源為清華鏡像源
1)http://updates.jenkins-ci.org/download/ 替換為 https://mirrors.tuna.tsinghua.edu.cn/jenkins
2)/http://www.google.com/ 替換為 https://www.baidu.com
或通過sed命令替換
$ sed -i 's/http://updates.jenkins-ci.org/download/https://mirrors.tuna.tsinghua.edu.cn/jenkins/g' default.json && sed -i 's/http://www.google.com/https://www.baidu.com/g' default.json
方式二:將請求引向nginx烂琴,通過nginx進(jìn)行代理,重定向到清華鏡像源蜕乡,具體見第三章奸绷。
三. Nginx
3.1 nginx安裝
拉取鏡像
docker pull jesusperales/jenkins-docker-run-inside啟動(dòng)鏡像
docker run -d -p 80:80 -p 81:81 -p 82:82 -v /root/nginx/html:/usr/share/nginx/html -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf -v /root/nginx/conf.d:/etc/nginx/conf.d -v /root/nginx/log:/var/log/nginx --name nginx nginx
3.2 配置文件
將請求引向nginx,重定向到清華鏡像源
https://blog.csdn.net/scc95599/article/details/104656973
①添加本地DNS域名解析updates.jenkins-ci.org
echo '127.0.0.1 updates.jenkins-ci.org' >> /etc/hosts②創(chuàng)建文件
vim ~/root/nginx/conf.d/jenkins_redirect.conf
添加如下配置內(nèi)容server { listen 80; server_name updates.jenkins-ci.org; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location /download/plugins { proxy_next_upstream http_502 http_504 error timeout invalid_header; proxy_set_header Host mirrors.tuna.tsinghua.edu.cn; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Accept-Encoding ""; proxy_set_header Accept-Language "zh-CN"; rewrite /download/plugins/(.*) /jenkins/plugins/$1 break; proxy_pass https://mirrors.tuna.tsinghua.edu.cn; } location /pub/jenkins/plugins { proxy_next_upstream http_502 http_504 error timeout invalid_header; proxy_set_header Host mirrors.tuna.tsinghua.edu.cn; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Accept-Encoding ""; proxy_set_header Accept-Language "zh-CN"; rewrite /pub/jenkins/plugins/(.*) /jenkins/plugins/$1 break; proxy_pass https://mirrors.tuna.tsinghua.edu.cn; } # location / { # root /usr/share/nginx/html; # index index.html index.htm; # } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } access_log /var/log/nginx/mirrors.access.log; error_log /var/log/nginx/mirrors.error.log; }
四. Pipeline腳本
4.1 自動(dòng)化部署腳本
方式一:通過賬號密碼遠(yuǎn)程登錄
pipeline {
agent any
//系統(tǒng)參數(shù)配置
options{
buildDiscarder(logRotator(numToKeepStr:'2')) //持久化工件和控制臺輸出层玲,規(guī)定pipeline運(yùn)行的最大個(gè)數(shù)
disableConcurrentBuilds() //設(shè)置pipeline不能并行運(yùn)行号醉,放置同時(shí)訪問共享資源。
skipDefaultCheckout() //跳過默認(rèn)設(shè)置的代碼check out
skipStagesAfterUnstable() //一旦構(gòu)建狀態(tài)變成unstable不穩(wěn)定狀態(tài)称簿,跳過該階段
timeout(time:1,unit:'HOURS') //設(shè)置該pipeline運(yùn)行的超時(shí)時(shí)間扣癣,超時(shí)的pipeline會自動(dòng)被終止
timestamps() //為控制臺輸出增加時(shí)間戳
}
//變量定義
environment {
CREDENTIALSID = 'smartcook'
GIT_URL = 'http://gitlab.iotmars.com/backend/smartcook/smartcook.git'
BRANCH = 'dev'
ALIYUN_NAMESPACE = 'wecook'
ALIYUN_REPOSITORY = 'menu-center-dev'
IMAGE_VERSION = '0.0.1-SNAPSHOT'
DOCKER_CONTAINER_NAME = 'smartcook'
REMOTE_SERVER_IP = '192.168.32.128'
REMOTE_SERVER_NAME = 'localhost.localdomain'
REMOTE_SERVER_CREDENTIALSID = 'server_128'
REMOTE_REPOSITORY_CREDENTIALSID = 'hxr_aliyun'
SERVER_PORT = '8002'
EMAIL = '792965772@qq.com'
}
//定義工具
triggers {
GenericTrigger (
genericVariables: [
[key: 'ref',value: '$.ref']
],
causeString: 'Triggered on $ref',
token: 'Smartcook_Menu-Center',
printContributedVariables: true,
printPostContent: true,
silentResponse: false,
regexpFilterText: '$ref',
regexpFilterExpression: "refs/heads/dev"
)
}
stages {
//1.拉取源碼
stage('Git Checkout'){
steps {
retry(3){
git (
branch:"${BRANCH}" ,
credentialsId:"${CREDENTIALSID}" ,
url: "${GIT_URL}" ,
changelog: true
)
}
}
}
//2.編譯成jar包
stage('Maven Build') {
steps {
retry(3){
sh "mvn -Dmaven.test.failure.ignore=true clean package"
}
}
}
//3.構(gòu)建鏡像并上傳到阿里云鏡像倉庫
stage('Build and Push Image'){
steps{
withCredentials([usernamePassword(credentialsId: 'hxr_aliyun', passwordVariable: 'password', usernameVariable: 'username')]) {
script{
out=sh(script:"ls ./Dockerfile",returnStatus:true)
println out
if( out == 2 ){
println "創(chuàng)建默認(rèn)Dockerfile"
sh '''
cat << EOF > Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD ./target/*.jar app.jar
EXPOSE ${SERVER_PORT}
ENTRYPOINT ["java","-Xmx200m","-Xms200m","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EOF
'''
}
retry(3){
sh """
docker build -t ${DOCKER_CONTAINER_NAME} .
sudo docker login --username=${username} --password=${password} registry.cn-hangzhou.aliyuncs.com
sudo docker tag ${DOCKER_CONTAINER_NAME} registry.cn-hangzhou.aliyuncs.com/${ALIYUN_NAMESPACE}/${ALIYUN_REPOSITORY}:${IMAGE_VERSION}
sudo docker push registry.cn-hangzhou.aliyuncs.com/${ALIYUN_NAMESPACE}/${ALIYUN_REPOSITORY}:${IMAGE_VERSION}
"""
}
}
}
}
}
//4.拉取鏡像并啟動(dòng)
stage('Pull Image and Run'){
steps{
retry(3){
script{
withCredentials([usernamePassword(credentialsId: REMOTE_SERVER_CREDENTIALSID, passwordVariable: 'password', usernameVariable: 'username')]) {
def remote = [:]
remote.name = REMOTE_SERVER_NAME
remote.host = REMOTE_SERVER_IP
remote.user = username
remote.password = password
remote.allowAnyHosts = true
withCredentials([usernamePassword(credentialsId: REMOTE_REPOSITORY_CREDENTIALSID, passwordVariable: 'password', usernameVariable: 'username')]) {
//從阿里云鏡像倉庫中拉取鏡像并啟動(dòng)
sshCommand remote: remote, command: "sudo docker login --username=\"${username}\" --password=\"${password}\" registry.cn-hangzhou.aliyuncs.com"
sshCommand remote: remote, command: "sudo docker pull registry.cn-hangzhou.aliyuncs.com/\"${ALIYUN_NAMESPACE}\"/\"${ALIYUN_REPOSITORY}\":\"${IMAGE_VERSION}\""
sshCommand remote: remote, command: "docker stop \"${DOCKER_CONTAINER_NAME}\" || true"
sshCommand remote: remote, command: "docker rm \"${DOCKER_CONTAINER_NAME}\" || true"
sshCommand remote: remote, command: "docker run -it -d -p \"${SERVER_PORT}\":\"${SERVER_PORT}\" --name \"${DOCKER_CONTAINER_NAME}\" registry.cn-hangzhou.aliyuncs.com/\"${ALIYUN_NAMESPACE}\"/\"${ALIYUN_REPOSITORY}\":\"${IMAGE_VERSION}\""
}
}
}
}
}
}
}
post {
always {
echo 'This will always run'
script{
currentBuild.description = "\n always"
}
deleteDir() /* clean up our workspace */
//archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
//junit 'build/reports/**/*.xml'
//TODO 添加郵箱服務(wù)
}
success {
println("success!!!!!!!")
script{
currentBuild.description = "\n success"
}
//mail to: "${EMAIL}",
// subject: "Success Pipeline: ${currentBuild.fullDisplayName}",
// body: "Success with ${env.BUILD_URL}" /*該構(gòu)建的url地址*/
}
failure {
echo 'This will run only if failed'
script{
currentBuild.description = "\n failure"
}
//mail to: "${EMAIL}",
// subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
// body: "Something is wrong with ${env.BUILD_URL}" /*該構(gòu)建的url地址*/
}
}
}
方式二:通過設(shè)置私鑰憑證的方式遠(yuǎn)程登錄
如果不會寫流水線語法,有兩種解決方式:
- 可以訪問官網(wǎng)https://support.cloudbees.com/hc/en-us/articles/203802500-Injecting-Secrets-into-Jenkins-Build-Jobs#inpipelines查看如何生成withCredentials的pipeline寫法憨降。
- 也可以在項(xiàng)目中點(diǎn)擊
流水線語法
來訪問片段生成器父虑,如下圖所示。
image.png
pipeline {
agent any
options{
buildDiscarder(logRotator(numToKeepStr:'2')) //持久化工件和控制臺輸出授药,規(guī)定pipeline運(yùn)行的最大個(gè)數(shù)
disableConcurrentBuilds() //設(shè)置pipeline不能并行運(yùn)行士嚎,放置同時(shí)訪問共享資源。
skipDefaultCheckout() //跳過默認(rèn)設(shè)置的代碼check out
skipStagesAfterUnstable() //一旦構(gòu)建狀態(tài)變成unstable不穩(wěn)定狀態(tài)悔叽,跳過該階段
timeout(time:1,unit:'HOURS') //設(shè)置該pipeline運(yùn)行的超時(shí)時(shí)間莱衩,超時(shí)的pipeline會自動(dòng)被終止
timestamps() //為控制臺輸出增加時(shí)間戳
}
environment {
CREDENTIALSID = 'CJsGitlab'
GIT_URL = 'http://gitlab.iotmars.com/backend/duerosbots.git'
BRANCH = 'master'
ALIYUN_NAMESPACE = 'wecook'
ALIYUN_REPOSITORY = 'menu-center-dev'
IMAGE_VERSION = '0.0.1-SNAPSHOT'
DOCKER_CONTAINER_NAME = 'duerosbots'
REMOTE_SERVER_IP = '121.41.68.248'
REMOTE_SERVER_NAME = 'iotmars.ecs.area.h03'
REMOTE_SERVER_CREDENTIALSID = 'server_aliyun_248'
REMOTE_REPOSITORY_CREDENTIALSID = 'hxr_aliyun'
SERVER_PORT = '8090'
EMAIL = '792965772@qq.com'
}
//定義工具
tools {
maven "mvn3.5.0"
}
//定義遠(yuǎn)程觸發(fā)器
triggers {
GenericTrigger (
genericVariables: [
[key: 'ref',value: '$.ref']
],
causeString: 'Triggered on $ref',
token: 'Smartcook_Menu-Center',
printContributedVariables: true,
printPostContent: true,
silentResponse: false,
regexpFilterText: '$ref',
regexpFilterExpression: "refs/heads/dev"
)
}
stages {
stage('Git Checkout'){
steps {
retry(3){
//1.拉取源碼
git (
branch:"${BRANCH}" ,
credentialsId:"${CREDENTIALSID}" ,
url: "${GIT_URL}" ,
changelog: true
)
}
}
}
stage('Maven Build') {
steps {
//2.編譯成jar包
retry(3){
sh "mvn -Dmaven.test.failure.ignore=true clean package"
}
}
}
stage('Build and Push Image'){
steps{
//3.構(gòu)建鏡像
withCredentials([usernamePassword(credentialsId: REMOTE_REPOSITORY_CREDENTIALSID, passwordVariable: 'password', usernameVariable: 'username')]) {
script{
//判斷路徑下是否有dockerfile文件,沒有則創(chuàng)建默認(rèn)的dockerfile
out=sh(script:"ls ./Dockerfile",returnStatus:true)
println out
if( out == 2 ){
println "創(chuàng)建默認(rèn)Dockerfile"
sh '''
cat << EOF > Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD ./target/*.jar app.jar
EXPOSE ${SERVER_PORT}
ENTRYPOINT ["java","-Xmx200m","-Xms200m","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EOF
'''
}
retry(3){
sh """
docker build -t ${DOCKER_CONTAINER_NAME} .
sudo docker login --username=${username} --password=${password} registry.cn-hangzhou.aliyuncs.com
sudo docker tag ${DOCKER_CONTAINER_NAME} registry.cn-hangzhou.aliyuncs.com/${ALIYUN_NAMESPACE}/${ALIYUN_REPOSITORY}:${IMAGE_VERSION}
sudo docker push registry.cn-hangzhou.aliyuncs.com/${ALIYUN_NAMESPACE}/${ALIYUN_REPOSITORY}:${IMAGE_VERSION}
"""
}
}
}
}
}
stage('Pull Image and Run'){
steps{
retry(3){
script{
//通過私鑰登錄到遠(yuǎn)程服務(wù)器
withCredentials([sshUserPrivateKey(credentialsId: REMOTE_SERVER_CREDENTIALSID, keyFileVariable: 'keyFile', passphraseVariable: 'passphrase', usernameVariable: 'username')]) {
def remote = [:]
remote.name = REMOTE_SERVER_NAME
remote.host = REMOTE_SERVER_IP
remote.user = username
remote.identityFile = keyFile
remote.port = 22
remote.allowAnyHosts = true
withCredentials([usernamePassword(credentialsId: REMOTE_REPOSITORY_CREDENTIALSID, passwordVariable: 'password', usernameVariable: 'username')]) {
//4.拉取鏡像并啟動(dòng)
sshCommand remote: remote, command: "sudo docker login --username=\"${username}\" --password=\"${password}\" registry.cn-hangzhou.aliyuncs.com"
sshCommand remote: remote, command: "sudo docker pull registry.cn-hangzhou.aliyuncs.com/\"${ALIYUN_NAMESPACE}\"/\"${ALIYUN_REPOSITORY}\":\"${IMAGE_VERSION}\""
sshCommand remote: remote, command: "docker stop \"${DOCKER_CONTAINER_NAME}\" || true"
sshCommand remote: remote, command: "docker rm \"${DOCKER_CONTAINER_NAME}\" || true"
sshCommand remote: remote, command: "docker run -it -d -p \"${SERVER_PORT}\":\"${SERVER_PORT}\" --name \"${DOCKER_CONTAINER_NAME}\" registry.cn-hangzhou.aliyuncs.com/\"${ALIYUN_NAMESPACE}\"/\"${ALIYUN_REPOSITORY}\":\"${IMAGE_VERSION}\""
}
}
}
}
}
}
}
post {
always {
echo 'This will always run'
script{
currentBuild.description = "\n always"
}
deleteDir() /* clean up our workspace */
//archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
//junit 'build/reports/**/*.xml'
//TODO 添加郵箱服務(wù)
}
success {
println("success!!!!!!!")
script{
currentBuild.description = "\n success"
}
//mail to: "${EMAIL}",
// subject: "Success Pipeline: ${currentBuild.fullDisplayName}",
// body: "Success with ${env.BUILD_URL}" /*該構(gòu)建的url地址*/
}
failure {
echo 'This will run only if failed'
script{
currentBuild.description = "\n failure"
}
//mail to: "${EMAIL}",
// subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
// body: "Something is wrong with ${env.BUILD_URL}" /*該構(gòu)建的url地址*/
}
}
}
方式三:通過私鑰文件遠(yuǎn)程登錄(將pem文件放到j(luò)enkins容器中)
pipeline {
agent any
options{
buildDiscarder(logRotator(numToKeepStr:'2')) //持久化工件和控制臺輸出娇澎,規(guī)定pipeline運(yùn)行的最大個(gè)數(shù)
disableConcurrentBuilds() //設(shè)置pipeline不能并行運(yùn)行笨蚁,放置同時(shí)訪問共享資源。
skipDefaultCheckout() //跳過默認(rèn)設(shè)置的代碼check out
skipStagesAfterUnstable() //一旦構(gòu)建狀態(tài)變成unstable不穩(wěn)定狀態(tài)趟庄,跳過該階段
timeout(time:1,unit:'HOURS') //設(shè)置該pipeline運(yùn)行的超時(shí)時(shí)間括细,超時(shí)的pipeline會自動(dòng)被終止
timestamps() //為控制臺輸出增加時(shí)間戳
}
environment {
CREDENTIALSID = 'CJsGitlab'
GIT_URL = 'http://gitlab.iotmars.com/backend/duerosbots.git'
BRANCH = 'master'
ALIYUN_NAMESPACE = 'wecook'
ALIYUN_REPOSITORY = 'menu-center-dev'
IMAGE_VERSION = '0.0.1-SNAPSHOT'
DOCKER_CONTAINER_NAME = 'duerosbots'
REMOTE_SERVER_IP = '121.41.68.248'
REMOTE_SERVER_NAME = 'iotmars.ecs.area.h03'
REMOTE_SERVER_CREDENTIALSID = 'server_128'
REMOTE_SERVER_USERNAME = 'root'
REMOTE_SERVER_IDENTITYFILE = '/home/jenkins/.ssh/M20200509_162337marssenger.pem'
REMOTE_REPOSITORY_CREDENTIALSID = 'hxr_aliyun'
SERVER_PORT = '8090'
EMAIL = '792965772@qq.com'
}
//定義工具
tools {
maven "mvn3.5.0"
}
//定義遠(yuǎn)程觸發(fā)器
triggers {
GenericTrigger (
genericVariables: [
[key: 'ref',value: '$.ref']
],
causeString: 'Triggered on $ref',
token: 'Smartcook_Menu-Center',
printContributedVariables: true,
printPostContent: true,
silentResponse: false,
regexpFilterText: '$ref',
regexpFilterExpression: "refs/heads/dev"
)
}
stages {
stage('Git Checkout'){
steps {
retry(3){
//1.拉取源碼
git (
branch:"${BRANCH}" ,
credentialsId:"${CREDENTIALSID}" ,
url: "${GIT_URL}" ,
changelog: true
)
}
}
}
stage('Maven Build') {
steps {
//2.編譯成jar包
retry(3){
sh "mvn -Dmaven.test.failure.ignore=true clean package"
}
}
}
stage('Build and Push Image'){
steps{
//3.構(gòu)建鏡像
withCredentials([usernamePassword(credentialsId: 'hxr_aliyun', passwordVariable: 'password', usernameVariable: 'username')]) {
script{
out=sh(script:"ls ./Dockerfile",returnStatus:true)
println out
if( out == 2 ){
println "創(chuàng)建默認(rèn)Dockerfile"
sh '''
cat << EOF > Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD ./target/*.jar app.jar
EXPOSE ${SERVER_PORT}
ENTRYPOINT ["java","-Xmx200m","-Xms200m","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
EOF
'''
}
retry(3){
sh """
docker build -t ${DOCKER_CONTAINER_NAME} .
sudo docker login --username=${username} --password=${password} registry.cn-hangzhou.aliyuncs.com
sudo docker tag ${DOCKER_CONTAINER_NAME} registry.cn-hangzhou.aliyuncs.com/${ALIYUN_NAMESPACE}/${ALIYUN_REPOSITORY}:${IMAGE_VERSION}
sudo docker push registry.cn-hangzhou.aliyuncs.com/${ALIYUN_NAMESPACE}/${ALIYUN_REPOSITORY}:${IMAGE_VERSION}
"""
}
}
}
}
}
stage('Pull Image and Run'){
steps{
retry(3){
script{
def remote = [:]
remote.name = REMOTE_SERVER_NAME
remote.host = REMOTE_SERVER_IP
remote.user = REMOTE_SERVER_USERNAME
remote.port = 22
remote.identityFile = '/home/jenkins/.ssh/M20200509_162337marssenger.pem'
remote.allowAnyHosts = true
withCredentials([usernamePassword(credentialsId: REMOTE_REPOSITORY_CREDENTIALSID, passwordVariable: 'password', usernameVariable: 'username')]) {
//4.拉取鏡像并啟動(dòng)
sshCommand remote: remote, command: "sudo docker login --username=\"${username}\" --password=\"${password}\" registry.cn-hangzhou.aliyuncs.com"
sshCommand remote: remote, command: "sudo docker pull registry.cn-hangzhou.aliyuncs.com/\"${ALIYUN_NAMESPACE}\"/\"${ALIYUN_REPOSITORY}\":\"${IMAGE_VERSION}\""
sshCommand remote: remote, command: "docker stop \"${DOCKER_CONTAINER_NAME}\" || true"
sshCommand remote: remote, command: "docker rm \"${DOCKER_CONTAINER_NAME}\" || true"
sshCommand remote: remote, command: "docker run -it -d -p \"${SERVER_PORT}\":\"${SERVER_PORT}\" --name \"${DOCKER_CONTAINER_NAME}\" registry.cn-hangzhou.aliyuncs.com/\"${ALIYUN_NAMESPACE}\"/\"${ALIYUN_REPOSITORY}\":\"${IMAGE_VERSION}\""
}
}
}
}
}
}
post {
always {
echo 'This will always run'
script{
currentBuild.description = "\n always"
}
deleteDir() /* clean up our workspace */
//archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
//junit 'build/reports/**/*.xml'
//TODO 添加郵箱服務(wù)
}
success {
println("success!!!!!!!")
script{
currentBuild.description = "\n success"
}
//mail to: "${EMAIL}",
// subject: "Success Pipeline: ${currentBuild.fullDisplayName}",
// body: "Success with ${env.BUILD_URL}" /*該構(gòu)建的url地址*/
}
failure {
echo 'This will run only if failed'
script{
currentBuild.description = "\n failure"
}
//mail to: "${EMAIL}",
// subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
// body: "Something is wrong with ${env.BUILD_URL}" /*該構(gòu)建的url地址*/
}
}
}
4.2 pipeline腳本設(shè)置
4.2.1 腳本路徑為配置文件在倉庫中的路徑
4.2.2 配置鉤子程序
需要安裝插件Generic Webhook Trigger
在gitlab的項(xiàng)目settings=>Integrations中設(shè)置jenkins項(xiàng)目的url:
http://192.168.32.128:8080/generic-webhook-trigger/invoke?token=Smartcook_Menu-Center
token需要和腳本中的TRIGGER_TOKEN對應(yīng)
triggers {
GenericTrigger (
genericVariables: [
[key: 'ref',value: '$.ref']
],
causeString: 'Triggered on $ref',
token: 'Smartcook_Menu-Center',
printContributedVariables: true,
printPostContent: true,
silentResponse: false,
regexpFilterText: '$ref',
regexpFilterExpression: "refs/heads/dev"
)
}
可以指定前置任務(wù)完成后觸發(fā)
triggers { upstream(upstreamProjects: 'Smartcook_Register-Center', threshold: hudson.model.Result.SUCCESS) }
4.3 郵箱服務(wù)設(shè)置
4.3.1 系統(tǒng)配置
①下載插件Email Extension Plugin
②在系統(tǒng)配置中設(shè)置系統(tǒng)管理員郵箱
③在系統(tǒng)配置的Extended E-mail Notification中進(jìn)行設(shè)置
User Name必須與系統(tǒng)管理員郵箱一致,Password是獲取的郵箱第三方登錄授權(quán)碼戚啥。
4.3.2 郵件腳本(一般添加在pipeline腳本的always{}中)
emailext body: '''<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次構(gòu)建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0"
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td>(本郵件是程序自動(dòng)下發(fā)的奋单,請勿回復(fù)!)</td>
</tr>
<tr>
<td><h2>
<font color="#0000FF">構(gòu)建結(jié)果 - ${BUILD_STATUS}</font>
</h2></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">構(gòu)建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>項(xiàng)目名稱 : ${PROJECT_NAME}</li>
<li>構(gòu)建編號 : 第${BUILD_NUMBER}次構(gòu)建</li>
<li>SVN 版本: ${SVN_REVISION}</li>
<li>觸發(fā)原因: ${CAUSE}</li>
<li>構(gòu)建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>構(gòu)建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目錄 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>項(xiàng)目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
</td>
</tr>
<tr>
<td><b><font color="#0B610B">Changes Since Last
Successful Build:</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>歷史變更記錄 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat=" %p"}
</td>
</tr>
<tr>
<td><b>Failed Test Results</b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td><pre
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
<br /></td>
</tr>
<tr>
<td><b><font color="#0B610B">構(gòu)建日志 (最后 100行):</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<!-- <tr>
<td>Test Logs (if test has ran): <a
href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
<br />
<br />
</td>
</tr> -->
<tr>
<td><textarea cols="80" rows="30" readonly="readonly"
style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea>
</td>
</tr>
</table>
</body>
</html>''', subject: '${BUILD_STATUS} - ${PROJECT_NAME} - Build # ${BUILD_NUMBER} !', to: "${EMAIL}"
全局郵件變量解釋
${FILE,path="PATH"} 包括指定文件(路徑)的含量相對于工作空間根目錄
path文件路徑猫十,好比你用jenkins+git览濒,他執(zhí)行Pipeline的時(shí)候,找文件的路徑就是從拉下來的代碼開始
${BUILD_NUMBER} 當(dāng)前構(gòu)建的編號
${JOB_DESCRIPTION} 項(xiàng)目描述
${SVN_REVISION} svn版本號拖云。還支持Subversion插件出口的SVN_REVISION_n版本
${CAUSE} 顯示誰贷笛、通過什么渠道觸發(fā)這次構(gòu)建
${CHANGES } -顯示上一次構(gòu)建之后的變化
${BUILD_ID}顯示當(dāng)前構(gòu)建生成的ID
${PROJECT_NAME} 顯示項(xiàng)目的全名
${PROJECT_DISPLAY_NAME} 顯示項(xiàng)目的顯示名稱
${JENKINS_URL} 顯示Jenkins服務(wù)器的url地址
${BUILD_LOG_MULTILINE_REGEX}按正則表達(dá)式匹配并顯示構(gòu)建日志。
${BUILD_LOG} 最終構(gòu)建日志宙项。
${PROJECT_URL} 顯示項(xiàng)目的URL地址昨忆。
${BUILD_STATUS} -顯示當(dāng)前構(gòu)建的狀態(tài)(失敗、成功等等)
${BUILD_URL} -顯示當(dāng)前構(gòu)建的URL地址杉允。
${CHANGES_SINCE_LAST_SUCCESS} -顯示上一次成功構(gòu)建之后的變化邑贴。
${CHANGES_SINCE_LAST_UNSTABLE} -顯示顯示上一次不穩(wěn)固或者成功的構(gòu)建之后的變化。
${FAILED_TESTS} -如果有失敗的測試叔磷,顯示這些失敗的單元測試信息拢驾。
${JENKINS_URL} -顯示Jenkins服務(wù)器的地址。(你能在“系統(tǒng)配置”頁改變它)改基。
${PROJECT_URL} -顯示項(xiàng)目的URL繁疤。
${SVN_REVISION} -顯示SVN的版本號。
${TEST_COUNTS} -顯示測試的數(shù)量秕狰。
五稠腊、使用LDAP進(jìn)行登陸認(rèn)證
進(jìn)入Manage Jenkins -> Configure Global Security ,在訪問控制中選擇LDAP鸣哀,配置如下架忌。用戶的權(quán)限控制可以通過Manage and Assign Roles來實(shí)現(xiàn)。
需要注意的是我衬,一旦使用LDAP叹放,那么原來的管理員賬戶會失效,需要再指定一個(gè)LDAP中的用戶給其管理員權(quán)限挠羔,否則LDAP中的全部用戶都沒有任何權(quán)限井仰。
如果不幸的事發(fā)生,那么有兩個(gè)方法來獲取管理員權(quán)限:
①LDAP中創(chuàng)建一個(gè)與原管理員賬號同名的用戶破加,那么該用戶就是超級管理員俱恶。
②修改jenkins的配置文件了,該配置文件在docker中的位置是 /var/jenkins_home/config_cp.xml范舀,修改內(nèi)容如下:<securityRealm class="hudson.security.HudsonPrivateSecurityRealm"> <disableSignup>false</disableSignup> <enableCaptcha>false</enableCaptcha> </securityRealm>
修改完成后使用原來的管理員賬戶進(jìn)行登陸合是,重新保存一下LDAP配置,并給一個(gè)用戶超級管理員角色即可尿背。
以上都完成后端仰,可以使用Test LDAP Settings按鈕進(jìn)行用戶登陸測試,user為uid田藐,password為對應(yīng)的用戶密碼荔烧。