1. 程式人生 > >【Jenkins學習 】解決jenkins執行磁碟滿的問題

【Jenkins學習 】解決jenkins執行磁碟滿的問題

一、背景

今天有同事編譯Jenkins的相關Jobs的時候,出現了編譯成功,但是輸出產物失敗的情況,如下圖所示:
這裡寫圖片描述

Caused by:java.io.IOException: No space left on device
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:345)
    at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java
:1793) at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769) at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744) at hudson.util.IOUtils.copy(IOTuils.java:40) at hudson.FilePath.readFromTar(FilePath.java:2318) ....13 more Cause by:java.util.concurrent.ExecutionException:java.io
.IOException:This archives contains unclosed entries. ...12 more Cause by:java.io.IOException:This archives contains unclosed entries. ...

看上面圖的描述就是Jenkins伺服器上的磁碟空間已經不足,導致輸出產物失敗的情況出現。

二、排查問題

好吧,我登入Jenkins的伺服器,去檢視下磁碟空間,發現Jenkins儲存的磁碟 /data 已經百分百使用完畢。
這裡寫圖片描述

oot@codesrv1:/data/.jenkins/jobs# pwd
/data/.jenkins/jobs
root@codesrv1
:/data/.jenkins/jobs# df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda3 48750348 44294000 2014928 96% / udev 3886836 4 3886832 1% /dev tmpfs 1558256 260 1557996 1% /run none 5120 0 5120 0% /run/lock none 3895636 0 3895636 0% /run/shm /dev/sda1 9738232 255456 8994536 3% /boot /dev/sda5 236267580 236267580 0 100% /data /dev/sdb1 314197776 5271856 293197332 2% /data1

查看了下 /data/.jenkins/jobs 目錄下 所有的Jenkins jobs的佔用情況

root@codesrv1:/data/.jenkins/jobs# du -ah --max-depth=1

使用如上命令,檢視所有的Jenkins jobs的磁碟佔用情況。

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

查看了大部分的Jenkins Jobs,發現IOS開發人員所擁有的IOS相關的Jenkins任務,隨隨便便都佔用1G以上的磁碟。

進入一個IOS的Jenkins任務,名為 iOS_Trunk 的Jenkins任務去檢視磁碟佔用情況

root@codesrv1:/data/.jenkins/jobs/iOS_Trunk/builds# pwd 
/data/.jenkins/jobs/iOS_Trunk/builds
root@codesrv1:/data/.jenkins/jobs/iOS_Trunk/builds# du -ah --max-depth=1
46M ./802
1.5M    ./826
0   ./lastFailedBuild
176M    ./825
166M    ./827
137M    ./810
0   ./lastUnstableBuild
137M    ./797
137M    ./819
176M    ./824
137M    ./800
36K ./822
126M    ./804
137M    ./794
137M    ./803
137M    ./795
137M    ./814
166M    ./828
137M    ./785
137M    ./806
137M    ./805
126M    ./793
0   ./legacyIds
126M    ./798
137M    ./799
126M    ./821
137M    ./783
137M    ./784
126M    ./801
137M    ./809
44K ./817
16K ./787
137M    ./796
137M    ./786
40K ./789
126M    ./813
126M    ./815
126M    ./780
126M    ./790
137M    ./807
0   ./lastUnsuccessfulBuild
0   ./lastSuccessfulBuild
137M    ./811
137M    ./788
24M ./792
176M    ./823
137M    ./820
137M    ./791
0   ./lastStableBuild
137M    ./781
126M    ./808
16K ./816
127M    ./818
178M    ./829
137M    ./812
20K ./782
5.7G    .
root@codesrv1:/data/.jenkins/jobs/iOS_Trunk/builds#

這裡寫圖片描述

這裡寫圖片描述

發現這個iOS_Trunk的Jenkins任務,每一次編譯的常務都有100多Mb,然後保留了大概50次的編譯產物,所以關這一個Jenkins任務就佔用了5.7G。可怕啊!

去檢視下 這個Jenkins的配置情況,如下圖所示:

這裡寫圖片描述

如上圖所示,IOS的每個任務都是 保持構建的最大個數 設定為了50,那就代表著每一個IOS的任務理論上最多都佔用5個多G的磁碟空間。

而其他的Android的Jenkins任務的配置如下圖所示:

這裡寫圖片描述

Android相關的Jenkins任務都是預設最多保留3天的構建產物,這樣就可以節省磁碟。

三、解決問題

第一步、自動丟棄構建歷史資料

把以前構建過的過時歷史資料自動清除掉,保留最近更新的天數和個數。
這裡寫圖片描述

修改策略為

  • 保持構建的天數 3
  • 保持構建的最大個數 20

當然這個策略可以根據自己的專案實際情況來定。

第二步、關於以前有些Jenkins Job被刪除但是WorkSpace沒有被清理的問題

正常的刪除Jenkins Job的流程是 先清理工作空間 然後再刪除掉Jenkins Job
這裡寫圖片描述

但是有很多同事以前直接就刪除Jenkins Job,並沒有先清理工作空間,這樣會導致有些被刪除的Jenkins Job原來的工作空間一直存在佔用的磁碟。

摘要: jenkins cleanup workspace after job removal
如果Jenkins使用的Master-Slave多節點架構,刪除Jenkins JOB後,相應JOB的slave節點的workspace不會被刪除

所以需要自行處理,於是用指令碼實現該功能

具體思路是:

遍歷jenkins節點的workspace,根據路徑解析獲得jenkins job name
如果該job不存在(通過python jenkinsapi實現),則刪除相應的workspace
暫不考慮自定義的workspace
需要在jenkins每個節點上進行處理(可以在jenkins上建立job,將job繫結到相應slave上;也可以在相應slave上直接執行指令碼)
相關的Python指令碼如下:

# -*- coding: utf-8 -*-
import os
import shutil
import logging

from jenkinsapi.jenkins import Jenkins

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__file__)


def get_jenkins_instance():
    jenkins_url = "http://jenkins.example.com"
    jenkins_username = "username"
    jenkins_password = "password"
    return Jenkins(jenkins_url, username=jenkins_username, password=jenkins_password)


def clean_workspace():
    jenkins_instance = get_jenkins_instance()

    jenkins_workspace_path = "/opt/JENKINS_HOME/workspace/"

    for dirpath, dirnames, filenames in os.walk(jenkins_workspace_path):
        if dirpath == jenkins_workspace_path:
            for dirname in dirnames:
                jenkins_job_name = dirname
                # 如果job被刪除,則清理相應的workspace
                if not jenkins_instance.has_job(jenkins_job_name):
                    logger.info("removing workspace dir of job:%s" % dirname)
                    shutil.rmtree(os.path.join(dirpath, dirname))


if __name__ == "__main__":
    clean_workspace()

這個指令碼暫時沒有去執行,因為將IOS所有的Jenkins任務的丟棄舊的構建的策略修改之後,目前磁碟空間完全足夠使用!目前經過一輪清理,已經有84G的剩餘可以可以使用。

這裡寫圖片描述

而且該指令碼目前暫時不敢去使用,待我在測試的Jenkins伺服器上測試之後再應用到正式的Jenkins伺服器。

如果要使用,請讀者將程式碼中的相關引數改為自己的Jenkins伺服器配置的引數再執行。jenkins_url 、jenkins_username、jenkins_password 、jenkins_workspace_path這幾個引數都得修改為真實的引數。

這裡寫圖片描述

如果覺得本文對您有所幫助,歡迎您掃碼下圖所示的支付寶和微信支付二維碼對本文進行隨意打賞。您的支援將鼓勵我繼續創作!

這裡寫圖片描述