生產項目容器化改造(二)使用Jenkins任務部署Maven項目

構建jre1.8 tomcat8 基礎鏡像:

  • 登陸harbor主機,構建tomcat基礎鏡像,並上傳到harbor
cd /tmp
wget --no-check-certificate https://wget.XXXXXXX.com:10194/jre/server-jre-8u241-linux-x64.tar.gz
wget --no-check-certificate https://wget.XXXXXXX.com:10194/tomcat/apache-tomcat-8.5.51.tar.gz
vi Dockerfile
FROM centos:6
LABEL description="jdk1.8 and tomcat8"
# 時區調整
RUN /bin/cp -av /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 適應中文
ENV LC_ALL en_US.UTF-8
# 安裝unzip包和git包
RUN sed -i 's/gpgcheck=1/gpgcheck=0/g' /etc/yum.repos.d/*.repo && \
  yum -y install unzip git
# 部署jdk1.8
ENV JDK_TAR   server-jre-8u241-linux-x64.tar.gz
ENV JDK_FILE  jdk1.8.0_241
ENV JAVA_HOME /usr/local/java/java_1.8
ENV CLASSPATH ${JAVA_HOME}/lib:${JAVA_HOME}/jre/lib
ENV PATH      ${JAVA_HOME}/bin:${JAVA_HOME}/jre/bin:${PATH}
WORKDIR /usr/local/java
ADD ${JDK_TAR} .
RUN ln -s ${JDK_FILE} java_1.8 && \
    chown root: -R .
# 部署tomcat8
ENV TOM_TAR apache-tomcat-8.5.51.tar.gz
ENV TOM_FILE apache-tomcat-8.5.51
WORKDIR /usr/local/tomcat
ADD ${TOM_TAR} .
RUN ln -s ${TOM_FILE} tomcat8 && \
    chown root: -R .
# tomcat8 簡單優化調整
ENV OPTS "-Djava.security.egd=file:/dev/./urandom -Xms1256m -Xmx1512m"
ENV OPTS=${OPTS}" -XX:PermSize=50m -XX:MaxPermSize=70m"
ENV OPTS=${OPTS}" -XX:-UseGCOverheadLimit"
ENV OPTS2=${OPTS}" -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp"
RUN sed -i "s|cygwin=false|JAVA_OPTS=\"${OPTS}\"\n&|g" tomcat8/bin/catalina.sh && \
    sed -i "s|cygwin=false|# JAVA_OPTS=\"${OPTS2}\"\n&|g" tomcat8/bin/catalina.sh && \
    sed -i 's/Connector port="8080" protocol="HTTP\/1.1"/&\n \
               maxThreads="800" acceptCount="1000"\n \
               compression="on"\n \
               compressionMinSize="2048"\n \
               noCompressionUserAgents="gozilla,traviata"\n \
               compressableMimeType="text\/html,text\/xml,text\/javascript,text\/css,text\/plain"/g' tomcat8/conf/server.xml && \
    sed -i 's|${catalina.base}/logs|/web/logs|g' tomcat8/conf/logging.properties && \
    sed -i 's|appBase="webapps"|appBase="/web/project"|g' tomcat8/conf/server.xml && \
    sed -i 's|directory="logs"|directory="/web/logs/access"|g' tomcat8/conf/server.xml && \
    mkdir -pv /web/{profile,project/ROOT} && \
    echo "$(hostname) $(date +%F_%T)">/web/project/ROOT/index.html
EXPOSE 8080
CMD tomcat8/bin/catalina.sh run &> /web/logs/catalina.out

docker build -t harbor.vincent.com/library/tomcat8-j8 .
docker push harbor.vincent.com/library/tomcat8-j8

部署Jenkins模版任務,複製模版部署測試:

  • 網頁登陸jenkins,創建一個模版任務deploy-templete,類型爲pipeline, 丟棄舊構建選擇保留2個,添加groovy腳本如下:
#!groovy
pipeline{
  agent any
  environment{
    PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
    GitLab="gitlab"
    GitLabCredentialsId="gitlabcredentialsid"
    GitNS="gitns"
    GitName="gitname"
    GitSubPro="gitsubpro"
    GitSubProPort="gitsubproport"
    IPs="ips"
    Nginx="nginx"
    Harbor="harbor"
    LbNginx="lbnginx"
    LbNginxConf='lbnginxconf'
  }
  parameters{
    choice(
      name: 'Option',
      choices: 'Update\nRepublish\nRollback',
      description: '功能選擇,升級發佈、項目再發布,回滾發佈'
    )
    choice(
      name: 'Range',
      choices: 'Canary\nExcept\nALL\nips',
      description: '發佈範圍:單機發布,剩餘主機發布,全量發佈,單機發布'
    )
    choice(
      name: 'Interval',
      choices: '15\n30\n60\n120',
      description: '多機發布時的發佈間隔,單位秒'
    )
    /* 參數使用情形舉例:
    // ------- 金絲雀升級發佈,測試後,再發布到剩餘主機
    // Option=Update,Range=Canary,金絲雀升級發佈,默認發佈到第一個IP
    // Option=Republish,Range=Except,項目再發布到第一個IP之外的其他主機
    // ------- 全量升級發佈,不進行測試,直接發佈到全局主機
    // Option=Update,Range=ALL
    // ------- 指定IP升級發佈,測試,再發布到剩餘主機
    // Option=Update,Range=IP2,當指定的IP是第一個時,既是金絲雀發佈
    // Option=Republish,Range=IP3/IP4...,指定IP的再發布
    // ------- 指定IP再發布,當某個主機的項目包損壞時或者新添加了主機時
    // Option=Republish,Range=IP5
    // ------- 全量回滾
    // Option=Rollback,Range=ALL
    // ------- 金絲雀回滾發佈,測試後,剩餘主機回滾
    // Option=Rollback,Range=Canary
    // Option=Rollback,Range=Except
    // ------- 指定IP回滾
    // Option=Rollback,Range=IP2...
    // ------- 當Range=Except/ALL時,Interval 參數生效
    */
  }
  stages{
    stage("GitClone"){
      when { environment name: "Option", value: "Update"}
      steps{
        // 代碼下載
        sh 'git config --global http.sslVerify false'
        dir("${env.WORKSPACE}"){
          git branch: 'develop',
          // git branch: 'master',
          credentialsId: "${GitLabCredentialsId}",
          url:"${GitLab}/${GitNS}/${GitName}.git"
        }
      }
    }
    stage("ProjectBuild"){
      when { environment name: "Option", value: "Update"}
      steps{
        // 項目構建
        dir("${env.WORKSPACE}"){
          sh "source /etc/profile && mvn -Dmaven.test.skip=true clean package"
        }
      }
    }
    stage("ImageBuild"){
      when { environment name: "Option", value: "Update"}
      steps{
        // 項目包上傳包共享服務器,構建鏡像並存入harbor鏡像共享服務器
        sh "bash ${JENKINS_HOME}/script/warMoveAndClear.sh ${WORKSPACE} ${GitSubPro} ${Nginx} ${Harbor}"
      }
    }
    stage("PublishProject"){
      steps{
        sh "bash ${JENKINS_HOME}/script/mutiPublish.sh ${Option} ${env.Range} '${IPs}' ${Interval} ${GitSubPro} ${GitSubProPort} ${Harbor} ${LbNginx} ${LbNginxConf}"
        
      }
    }
  }
}

  • 在jenkins主機上部署任務所調用的腳本
su - deploy
mkdir -pv /var/lib/jenkins/script && cd /var/lib/jenkins/script
vi warMoveAndClear.sh
#!/bin/bash
source ~/.bash_profile
warPath=${1}
warProName=${2}
imageName=$(echo ${warProName}| tr '[A-Z]' '[a-z]')
Release=$(date +%Y%m%d.%H%M%S)
WarFile=${warProName}-${Release}.war
nginxRootPath=/usr/share/nginx/html
Nginx=${3}
Harbor=${4}
# 創建nginx相應目錄並存儲當前構建的war包
mkdir -p ${nginxRootPath}/${warProName}
cd ${warPath}/${warProName}/target/
find . -name "*.war" -type f -exec cp -a {} ${nginxRootPath}/${warProName}/${WarFile} \;
# 對歷史war包進行清理,保留3個war包
WarFileNumber=$(ls ${nginxRootPath}/${warProName}/*.war|wc -l)
if [ "${WarFileNumber}" -ge 3 ]
then
  StandFile=$(ls -t ${nginxRootPath}/${warProName}/*.war|head -3|tail -1)
  find ${nginxRootPath}/${warProName}/ -type f -name "*.war" -not -newer ${StandFile} -exec rm -f {} \;
fi
echo "[+] ############## $(date +%F_%T) 項目包${WarFile}存儲到nginx完成"
# 操縱harbor,構建鏡像並上傳
ssh root@${Harbor} "rm -rf /opt/${warProName} && mkdir -p /opt/${warProName}"
cat >/tmp/Dockerfile-${warProName}-${Release}<<EOF
FROM harbor.vincent.com/library/tomcat8-j8
WORKDIR /web/profile
ADD ${warProName}.tar.gz .
# git clone ...
WORKDIR /web/project
RUN rm -rf *
COPY ${WarFile} ROOT.war
EXPOSE 8080
CMD /usr/local/tomcat/tomcat8/bin/catalina.sh run &> /web/logs/catalina.out
EOF
echo "[+] ############## $(date +%F_%T) 同步Dockerfile到harbor"
scp /tmp/Dockerfile-${warProName}-${Release} root@${Harbor}:/opt/${warProName}/Dockerfile
rm -rf /tmp/Dockerfile-${warProName}-${Release}
echo "[+] ############## $(date +%F_%T) 下載profile"
ssh root@${Harbor} "cd /opt/${warProName} && wget ${Nginx}/profile/${warProName}.tar.gz -o /dev/null"
echo "[+] ############## $(date +%F_%T) 下載war包"
ssh root@${Harbor} "cd /opt/${warProName} && wget ${Nginx}/${warProName}/${WarFile} -o /dev/null"
echo "[+] ############## $(date +%F_%T) 構建鏡像"
ssh root@${Harbor} "cd /opt/${warProName} && docker build -t harbor.vincent.com/library/${imageName}:${Release} ."
echo "[+] ############## $(date +%F_%T) 鏡像上傳到harbor"
ssh root@${Harbor} "docker push harbor.vincent.com/library/${imageName}:${Release}"
echo "[+] ############## $(date +%F_%T) 本地鏡像清除"
ssh root@${Harbor} "docker rmi harbor.vincent.com/library/${imageName}:${Release}"
echo "[+] ############## $(date +%F_%T) 鏡像 harbor.vincent.com/library/${imageName}:${Release}存儲到harbor完成"
vi mutiPublish.sh
#!/bin/bash
source ~/.bash_profile
Option=${1}
Range=${2}
IPs=${3}
Interval=${4}
GitSubPro=${5}
imageName=$(echo ${GitSubPro}| tr '[A-Z]' '[a-z]')
GitSubProPort=${6}
Harbor=${7}
LbNginx=${8}
LbNginxConf=${9}
ImagePath="harbor.vincent.com/library"
# 獲取項目的鏡像tag列表
TagInfo=$(curl -s -k -X GET "https://${Harbor}/api/repositories/library%2F${imageName}/tags" \
  -H "accept: application/json" -H "X-Xsrftoken: GUXirgNTqmudkEPhJtOtl520yTRJz6RW" \
   | jq '.[].name'|sed 's/"//g')
Tag0=$(echo ${TagInfo}|awk '{print $(NF-0)}')
Tag1=$(echo ${TagInfo}|awk '{print $(NF-1)}')
Tag2=$(echo ${TagInfo}|awk '{print $(NF-2)}')
# 發佈類型判斷
case ${Option} in
  "Update")
    Image=${imageName}:${Tag0}
    ;;
  "Republish")
    Image=${imageName}:${Tag0}
    ;;
  "Rollback")
    Image=${imageName}:${Tag1}
    ;;
esac
# 發佈範圍判斷
case ${Range} in
  "Canary")
    ip=$(echo ${IPs}|awk '{print $1}')
    ;;
  "Except")
    ip=$(echo ${IPs}|awk '{for(i=2;i<=NF;i++) printf("%s ",$i)}')
    ;;
  "ALL")
    ip=${IPs}
    ;;
  *)
    ip=${Range}
    ;;
esac
# 最終發佈
echo "[+] ############## $(date +%F_%T) ${Option}發佈,使用鏡像:${ImagePath}/${Image},發佈IP爲:${ip}"
for i in ${ip}
do
  ssh root@${i} "echo -ne \"[+] ############## $(date +%F_%T) ${i} 發佈開始 \n\""
  # 需要配置deploy到LbNginx的root用戶的免密登陸
  # ssh root@${LbNginx} "sed -i 's/${i}:${GitSubProPort}/# ${i}:${GitSubProPort}/g' ${LbNginxConf}"
  # ssh root@${LbNginx} "systemctl reload nginx"
  # echo "[+] ############## $(date +%F_%T) ${GitSubPro}-${i}-${GitSubProPort} 負載下線,${Interval}秒後部署開始"
  # curl -s 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxxx' \
  #   -H "Content-Type: application/json" -d "{\"msgtype\": \"text\", \
  #        \"text\": {\"content\": \"${GitSubPro}-${i}-${GitSubProPort}:\n$(date +%F_%T) 負載下線,${Interval}秒後部署開始\"}}"
  # sleep ${Interval}
  ssh root@${i} "echo -ne \"[+] ############## $(date +%F_%T) 容器關閉 \" && docker stop ${imageName}-${i}-${GitSubProPort}"
  ssh root@${i} "echo -ne \"[+] ############## $(date +%F_%T) 容器刪除 \" && docker rm ${imageName}-${i}-${GitSubProPort}"
  ssh root@${i} "echo -ne \"[+] ############## $(date +%F_%T) 鏡像刪除 \n\" && for i in \$(docker image ls|grep ${imageName}|awk '{print \$3}');do docker rmi \$i &>/dev/null;done"
  ssh root@${i} "echo -ne \"[+] ############## $(date +%F_%T) 鏡像拉取 \n\" && docker pull ${ImagePath}/${Image} &>/dev/null"
  ssh root@${i} "echo -ne \"[+] ############## $(date +%F_%T) 容器啓動 \" && docker run -d --name=${imageName}-${i}-${GitSubProPort} -p ${GitSubProPort}:8080 -v /opt/logs/${imageName}-${i}-${GitSubProPort}:/web/logs -m 1512M -it ${ImagePath}/${Image}"
  echo "[+] ############## $(date +%F_%T) ${imageName}-${i}-${GitSubProPort} ${Option}發佈成功" #,${Interval}秒後負載上線"
  curl -s 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxxx' \
    -H "Content-Type: application/json" -d "{\"msgtype\": \"text\", \
         \"text\": {\"content\": \"${GitSubPro}-${i}-${GitSubProPort}:\n$(date +%F_%T) ${Option}發佈成功\"}}" #,${Interval}秒後負載上線\"}}"
  sleep ${Interval}
  # ssh root@${LbNginx} "sed -i 's/# ${i}:${GitSubProPort}/${i}:${GitSubProPort}/g' ${LbNginxConf}"
  # ssh root@${LbNginx} "systemctl reload nginx"
  # echo "[+] ############## $(date +%F_%T) ${GitSubPro}-${i} 負載上線"
  # curl -s 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxxxxxx' \
  #   -H "Content-Type: application/json" -d "{\"msgtype\": \"text\", \
  #        \"text\": {\"content\": \"${GitSubPro}-${i}-${GitSubProPort}:\n$(date +%F_%T) 負載上線\"}}"
done
  • 模版複製創建任務,構建發佈測試
su - deploy
gitns='vincent'
gitname='test'
gitsubpro='test-soaport'
gitsubproport='8081'
ips='192.168.1.171 192.168.1.172 192.168.1.173 192.168.1.174 192.168.1.175'
ipS='192.168.1.171\\n192.168.1.172\\n192.168.1.173\\n192.168.1.174\\n192.168.1.175'
gitlab='https://gitlab.vincent.com'
gitlabcredentialsid='https.gitlab.root.pass'
nginx='http://dockerjenkins:8080'
harbor='harbor.vincent.com'
lbnginx='lbnginx'
lbnginxconf='lbnginxconf'
cd /var/lib/jenkins/jobs/
cp -av deploy-templete ${gitsubpro}
sed -i "s|GitLab=\&quot;gitlab\&quot;|GitLab=\&quot;${gitlab}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|GitLabCredentialsId=\&quot;gitlabcredentialsid\&quot;|GitLabCredentialsId=\&quot;${gitlabcredentialsid}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|GitNS=\&quot;gitns\&quot;|GitNS=\&quot;${gitns}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|GitName=\&quot;gitname\&quot;|GitName=\&quot;${gitname}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|GitSubPro=\&quot;gitsubpro\&quot;|GitSubPro=\&quot;${gitsubpro}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|GitSubProPort=\&quot;gitsubproport\&quot;|GitSubProPort=\&quot;${gitsubproport}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|IPs=\&quot;ips\&quot;|IPs=\&quot;${ips}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|Nginx=\&quot;nginx\&quot;|Nginx=\&quot;${nginx}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|Harbor=\&quot;harbor\&quot;|Harbor=\&quot;${harbor}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|LbNginx=\&quot;lbnginx\&quot;|LbNginx=\&quot;${lbnginx}\&quot;|g" ${gitsubpro}/config.xml
sed -i "s|LbNginxConf=\&apos;lbnginxconf\&apos;|LbNginxConf=\&apos;${lbnginxconf}\&apos;|g" ${gitsubpro}/config.xml
sed -i "s|ips\&apos|${ipS}\&apos|g" ${gitsubpro}/config.xml
su - root /etc/init.d/jenkins restart
  • 項目做過配置分離,需要將相應的配置目錄profile打包上傳到nginx對應目錄:
cd /tmp
tar -czf test-soaport.tar.gz profile
mkdir -pv /usr/share/nginx/html/profile
mv -v test-soaport.tar.gz /usr/share/nginx/html/profile
  • 網頁登陸Jenkins,使用任務進行構建部署測試

[TOC]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章