前面做了那么多工作,現在終于到了創(chuàng )建Job這一步了,某種意義上,Jenkins的主要工作就是為了調度這些Job。Job的創(chuàng )建是有很大自由度的,也沒(méi)有誰(shuí)規定一定要創(chuàng )建成什么樣子才行。下面我會(huì )以實(shí)際使用中的幾個(gè)場(chǎng)景來(lái)舉例說(shuō)明。
需要注意的是:
Job名稱(chēng)千萬(wàn)不要用中文名稱(chēng)(不作死就不會(huì )死)。 創(chuàng )建Job名稱(chēng)時(shí)最好有個(gè)規劃,因為我們最后會(huì )通過(guò)正則匹配自動(dòng)將Job歸類(lèi),比如我喜歡 “項目前綴_一些說(shuō)明-Job類(lèi)型”這種方式。
先做一些準備活動(dòng) 為了方便我們后面的實(shí)驗,先找一臺虛擬機,在上面搭建一下git服務(wù)器和代碼質(zhì)量管理平臺(我這里使用的是sonar)。
搭建git服務(wù)器 因這部分不是我們的重點(diǎn),所以我打算搭建一個(gè)最簡(jiǎn)單的基于SSH的git服務(wù)器,假設這臺服務(wù)器IP為 172.16.12.83。
首選先從 https://github.com/git/git/tarball/master 下載git代碼,按照下面的步驟解壓并安裝。
[root@svr83 ~]# tar xzvf git-git-v1.8.4-474-g128a96c.tar.gz -C /usr/local/src/[root@svr83 ~]# cd /usr/local/src/git-git-128a96c/[root@svr83 git-git-128a96c]# autoconf && ./configure --prefix=/usr/[root@svr83 git-git-128a96c]# make && make install
創(chuàng )建一個(gè)git用戶(hù)并以登錄到這個(gè)git用戶(hù),然后在該用戶(hù)的家目錄下創(chuàng )建一個(gè) git_home 用于存放項目代碼(暫時(shí)先給git用戶(hù)設置密碼為git)。
[root@svr83 ~]# useradd git[root@svr83 ~]# passwd gitChanging password for user git.New UNIX password:BAD PASSWORD: it is WAY too shortRetype new UNIX password:passwd: all authentication tokens updated successfully.[root@svr83 ~]# su - git[git@svr83 ~]$ mkdir git_home
我們現在在 /tmp 下創(chuàng )建一個(gè)git 本地庫,比如叫 helloJava,然后向這個(gè)庫里提交一個(gè) readme.txt 文件(因為第一次使用git,還需要設置一下用戶(hù)名和郵件地址)。
[git@svr83 helloJava]$ git config --global user.email "bookong@gmail.com"[git@svr83 helloJava]$ git config --global user.name "jiangxu"[git@svr83 ~]$ mkdir /tmp/helloJava[git@svr83 ~]$ cd /tmp/helloJava/[git@svr83 helloJava]$ git init初始化空的 Git 版本庫于 /tmp/helloJava/.git/[git@svr83 helloJava]$ echo "hello java project" > readme.txt[git@svr83 helloJava]$ git add *[git@svr83 helloJava]$ git commit -m 'initial project'[master(根提交) d605f94] initial project1 file changed, 1 insertion(+)create mode 100644 readme.txt
將隱藏的 .git 目錄拷貝到 /home/git/git_home 下,并改名叫 helloJava.git 目錄。
[git@svr83 helloJava]$ cp -a .git/ /home/git/git_home/helloJava.git
我們在另一臺服務(wù)器上試著(zhù)clone出helloJava 項目。
[jenkins@svr82 test]$ git clone ssh://git@172.16.12.83/home/git/git_home/helloJava.git正克隆到 'helloJava'...The authenticity of host '172.16.12.83 (172.16.12.83)' can't be established.RSA key fingerprint is 50:51:8e:ad:e0:da:1d:61:fb:d0:97:c0:2b:46:65:83.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '172.16.12.83' (RSA) to the list of known hosts.git@172.16.12.83's password:remote: Counting objects: 3, done.remote: Total 3 (delta 0), reused 0 (delta 0)接收對象中: 100% (3/3), done.檢查連接... 完成[jenkins@svr82 test]$ cat helloJava/readme.txthello java project
簡(jiǎn)陋的 git 服務(wù)器搭建好了,足夠我們實(shí)驗用的了。
奴隸節點(diǎn)安裝git程序 之前的文章中,我們創(chuàng )建了兩個(gè)奴隸節點(diǎn),操作系統分表為 Win7 和 CentOS?,F在我們分表在上面安裝git軟件。CentOS這個(gè)節點(diǎn)的安裝方法上面已經(jīng)介紹了,只要再照做一遍就可以。Win7 下需要安裝 msysgit 軟件 http://msysgit.github.io/。
到 https://code.google.com/p/msysgit/downloads/list?q=full+installer+official+git 下載一個(gè)最新的程序,比如我下載的是 Git-1.8.4-preview20130916.exe,安裝時(shí)在下圖所示步驟里,選擇“Run Git from the Windows Command Prompt”,將git添加到PATH路徑中,其他都選默認值。
安裝后檢查一下
配置訪(fǎng)問(wèn)git服務(wù)器的憑據 還記得我們在上一集里配置了訪(fǎng)問(wèn)CentOS 奴隸節點(diǎn)的憑據嗎?
用相似的方法在git服務(wù)器上給git用戶(hù)添加一個(gè)公鑰(具體步驟就不重復了),然后將私鑰文件(id_rsa)分別拷貝到兩臺奴隸節點(diǎn)的當前用戶(hù)家目錄下的 .ssh 下(要注意在Linux系統下這個(gè)文件的權限必須是600)
搭建一個(gè)sonar服務(wù)器 為方便實(shí)驗,我們把sonar搭建在git服務(wù)器上(172.16.12.83)。
首選到 http://www.sonarqube.org/downloads/ 下載最新的SonarQube。
解壓到 /usr/local/ 下
[root@svr83 ~]# mv sonar-3.7.2.zip /usr/local/[root@svr83 ~]# cd /usr/local/[root@svr83 local]# unzip sonar-3.7.2.zip
雖然Sonar可以使用默認的H2嵌入數據庫,但Jenkins上的Sonar插件不支持,所以這里我們要安裝一個(gè)MySQL的數據庫
我們到下載一個(gè) MySQL,我下的是 MySQL-client-5.5.29-1.linux2.6.i386.rpm 和 MySQL-server-5.5.29-1.linux2.6.x86_64.rpm。
下載鏈接:http://dev.mysql.com/downloads/mysql/5.5.html#downloads
安裝這兩個(gè) RPM 包。
[root@svr83 sonar-3.7.2]# rpm -ivh MySQL-*
拷貝模版文件構造 my.cnf。
[root@svr83 sonar-3.7.2]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf
修改 my.cnf 內容
...[client]...default-character-set = utf8...[mysqld]...lower_case_table_names = 0...
啟動(dòng) mysql
[root@svr83 sonar-3.7.2]# service mysql start
進(jìn)入 mysql 客戶(hù)端創(chuàng )建默認的庫sonar,添加訪(fǎng)問(wèn)用戶(hù)(用戶(hù)名sonar,密碼sonar),并退出 mysql 客戶(hù)端。
[root@svr83 sonar-3.7.2]# mysqlmysql> grant all privileges on *.* to 'sonar'@'%' identified by 'sonar';mysql> grant all privileges on *.* to 'sonar'@'localhost' identified by 'sonar';mysql> flush privileges;mysql> quit
然后可以實(shí)驗一下用sonar用戶(hù)能否正常登錄:
[root@svr83 sonar-3.7.2]# mysql -h localhost -u sonar -p
修改 sonar 目錄下 conf/sonar.properties 文件,啟用 MySQL 相關(guān)設置
……#----- MySQL 5.x# Comment the embedded database and uncomment the following line to use MySQLsonar.jdbc.url: jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true……
啟動(dòng)sonar。
[root@svr83 linux-x86-64]# pwd/usr/local/sonar-3.7.2/bin/linux-x86-64[root@svr83 linux-x86-64]# ./sonar.sh startStarting sonar...Started sonar.
在瀏覽器中輸入 http://172.16.12.83:9000/ 看到 sonar 的界面。
創(chuàng )建一個(gè)用于健康檢查的Job 我們打算創(chuàng )建這樣一個(gè)Job,每十五分鐘檢查一次代碼庫,發(fā)現有提交動(dòng)作就觸發(fā)構建,編譯代碼并執行單元測試,它的目的是保證構建的完整性。在這個(gè)例子里,我們假設代碼是Java語(yǔ)言編寫(xiě),需要JDK 7來(lái)編譯,使用ant工具來(lái)編譯執行單元測試,需要在Win 7 系統上來(lái)做這一切。
首選我們先進(jìn)入Jenkins頁(yè)面中的“系統管理”→“系統設置”,找到 “JDK”部分,選擇“新增JDK”。
我們選擇讓Jenkins系統在需要的時(shí)候自動(dòng)安裝“Java SE Development Kit 7u40”。
注意最下面的錯誤提示,需要你輸入一個(gè)Oracle 賬號,點(diǎn)擊鏈接進(jìn)去,是一個(gè)需要輸入賬號和密碼的頁(yè)面(賬號可以到 https://login.oracle.com/mysso/signon.jsp 免費注冊)。
設置好JDK后,我們找到“Ant”部分,點(diǎn)擊“新增Ant”按鈕。也同樣設置在構建需要時(shí)自動(dòng)安裝Ant。
作為這一切后,點(diǎn)擊屏幕下方的“Save”按鈕保存配置。
然后我們寫(xiě)個(gè)簡(jiǎn)單的,用Ant編譯的Java小程序,javaAntSample 推送到之前搭建好的git服務(wù)器上(具體方法參考前面關(guān)于git服務(wù)器部分的說(shuō)明)。在這個(gè)程序的 build.xml 里,我們主要想執行 testrun 這個(gè) target,它會(huì )完成編譯并執行單元測試的工作,最后在項目根路徑下產(chǎn)JUnit單元測試的報告 TEST-sample.project1.AllTests.xml。
現在回到Jenkins的首頁(yè),點(diǎn)擊“新Job”。使用Ant編譯的話(huà)我們要選擇“構建一個(gè)自由風(fēng)格的軟件項目”;“任務(wù)名稱(chēng)”我寫(xiě)的是“project1_javaAntSample-auto”,這個(gè)名字里我想表達說(shuō)這個(gè)Job屬于“project1”項目,之后我建立視圖時(shí)會(huì )用正則匹配所有以“project1_”開(kāi)頭的項目;后面的“javaAntSample”希望我直接查看操作目錄時(shí)有比較直觀(guān)的提示,我希望用最后的“auto”標明這是一個(gè)做監控檢查的Job。當然你也可以采用其他的命名規則。
確定以后涉及的內容比較多,我一點(diǎn)一點(diǎn)來(lái)介紹。
首選“描述”這部分很好理解,當你點(diǎn)擊進(jìn)入某個(gè)Job查看詳情時(shí),會(huì )顯示在頁(yè)面的上方,這個(gè)部分可以在里面寫(xiě)HTML內容。
下面的“丟棄舊的構建”很重要,我們曾經(jīng)遇到過(guò)使用的太久后無(wú)用的發(fā)布包(比如WAR包)將磁盤(pán)空間耗盡的情況。我建議這里設置“發(fā)布包最大保留#個(gè)構建”設置為1。
后面的幾項我一般不做設置,但“Restrict where this project can be run”要設置希望構建的奴隸節點(diǎn),我們這里設置為 win。
“高級項目選項”這里,我一般只設置 “Display Name”,這里設置一個(gè)中文名稱(chēng)后,在Jenkins里顯示Job時(shí)優(yōu)先顯示這個(gè)值。
下面就到了“源碼管理”這部分了,選擇“Git”,填寫(xiě)倉庫的URL和希望簽出的分支名。
你可能注意到了,下面有一大串錯誤提示“Fail to connect to repository……”這個(gè)不用管它,因為Jenkins的主節點(diǎn)我們沒(méi)有配置訪(fǎng)問(wèn)git服務(wù)器的密鑰的原因。
如果你在Job執行時(shí)出現下面錯誤
點(diǎn)擊“高級”按鈕,我們在下面的地方隨便設置一下(可以設置一個(gè)管理員的郵箱)。
下面的“構建觸發(fā)器”部分,我們希望是每15分鐘檢查一次代碼庫,如果有變化,則觸發(fā)構建。
在下面的“構建”部分,點(diǎn)擊按鈕“增加構建步驟”,選擇“Invoke Ant”。
Ant的版本選擇我們一開(kāi)始在“系統設置”里指定的版本,第一次執行前它會(huì )自己下載?!癟argets”輸入“testrun”,這個(gè)值來(lái)自我們的build.xml文件中的定義。
在下面的“構建后操作”中,點(diǎn)擊“Add post-build action”按鈕,在列表中選擇“Publish JUnit test result report”。
由于我們的報告是輸出到項目根路徑下,所以我們這里直接填寫(xiě)XML文件名。
現在再次點(diǎn)擊“Add post-build action”按鈕,選擇“E-mail Notification”,添加失敗后的郵件提醒。這里不但可以設定固定通知的人,還可以自動(dòng)發(fā)郵件給疑似導致構建失敗的人。
如果你有時(shí)間就等待它自動(dòng)觸發(fā)構建,否則你可以點(diǎn)擊
直接觸發(fā)構建
這時(shí)候你執行Job的構建會(huì )發(fā)現一直停留在git簽出代碼階段,造成這個(gè)的原因是家目錄不正確,沒(méi)有找到私鑰的原因。我們可以有兩個(gè)方式解決。
解決Win7下無(wú)法簽出git代碼 方式一:修改Win7奴隸節點(diǎn)的設置 添加兩個(gè)環(huán)境變量“HOMEPATH”和“USERPROFILE”。
方法二:安裝插件 EnvInject Plugin 我們在插件管理頁(yè)面中,安裝插件“EnvInject Plugin”。
這時(shí)再修改Job的定義(在“參數化構建過(guò)程”下面會(huì )出現新的屬性“Prepare an environment for the run”。設置里面的“Properties Content”
最后執行結果 創(chuàng )建一個(gè)用于代碼質(zhì)量分析的Job 假如我們希望對代碼進(jìn)行靜態(tài)檢查,可以創(chuàng )建這種Job。最簡(jiǎn)單的方式就是與sonar進(jìn)行集成,sonar支持眾多語(yǔ)音的靜態(tài)檢查,包括:.NET($)、Android、C/C++($)、C++(社區版)、Java、JavaScript、PHP等等,其中后面帶($)表示收費版本,比如C/C++ 插件一年7000歐元。http://docs.codehaus.org/display/SONAR/Plugin+Library
使用前我們先安裝Sonar插件“Jenkins Sonar Plugin”
安裝好插件后,我們進(jìn)入“系統設置”頁(yè)面。
先找到“Sonar Runner”這里,點(diǎn)擊“新增 Sonar Runner”按鈕。
向下,找到“Maven”部分,新建一個(gè)Maven(就像前面創(chuàng )建的Ant一樣,需要時(shí)他會(huì )自動(dòng)安裝的)
再向下,找到“Sonar”部分,點(diǎn)擊“Add Sonar”按鈕。其中“Server URL”就是我們Sonar的訪(fǎng)問(wèn)URL“http://172.16.12.83:9000/”;Sonar默認賬號和密碼都是“admin”;數據庫部分的設置就是我們前面配置Sonar配置文件中寫(xiě)的MySQL相關(guān)設置。
前一個(gè)Job里,我們用Ant構建了一個(gè)Java項目,畢竟Ant已經(jīng)過(guò)時(shí)了,我們在這個(gè)Job試試用Maven構建一個(gè)項目,先創(chuàng )建一個(gè)用Maven構建的項目 javaMavenSample 推送到我們實(shí)驗用的git服務(wù)器上。Maven構建時(shí)除了pom.xml 外還有一個(gè)重要的配置是 settings.xml 文件,一般在這個(gè)文件中指定私服 nexus 的地址,一般情況下會(huì )要求將這個(gè)文件放在本地用戶(hù)家目錄下的 .m2 文件夾中。但對Jenkins來(lái)說(shuō)這樣可能造成一個(gè)構建干擾另一個(gè)構建的情況,所以我們將這個(gè) settings.xml 文件放在 javaMavenSample 項目的根目錄下一起提交。
現在創(chuàng )建一個(gè)新Job,名稱(chēng)就叫“project2_javaMavenSample-nightly”,類(lèi)型選擇“構建一個(gè)maven2/3項目”
其他的設置參考前面監控檢查的Job吧,這里只說(shuō)說(shuō)不一樣的地方。
觸發(fā)構建的日程表我們可以設置成“H 0 * * *”,表示每天晚上0點(diǎn)檢查代碼庫是否有更新。因為靜態(tài)檢查是一個(gè)極其消耗資源的緩慢過(guò)程,所以沒(méi)有必要在健康檢查中觸發(fā)。
Maven項目的Job會(huì )有一個(gè)“Build”部分?!癎oals and options”我們寫(xiě)“clean install”,點(diǎn)擊“高級”按鈕展開(kāi)高級屬性,在“Settings file”這里,選擇“Settings file in filesystem”,“File path”上可以寫(xiě)相對于Job工作區的相對路徑,這里我們直接寫(xiě)“settings.xml”,這樣代碼庫中隨項目一起提交的settings.xml就會(huì )生效。
在“構建后操作”這部分,點(diǎn)擊“Add post-build action”按鈕,添加“Sonar”,基本上安裝默認值就可以。
執行Job看一下。
成功后到我們的Sonar服務(wù)器上可以看到結果 http://172.16.12.83:9000/
創(chuàng )建自動(dòng)部署測試環(huán)境的Job 創(chuàng )建一個(gè)自動(dòng)部署到測試環(huán)境的Job有很多方法。
方法一:通過(guò)Deploy Plugin 安裝“Deploy Plugin”插件。這個(gè)插件支持 Tomcat 4.x/5.x/6.x/7.x、JBoss 3.x/4.x、Glassfish 2.x/3.x 的自動(dòng)部署。
你可以在設置Job的“構建后操作”部分添加“Deploy war/ear to container”
要注意的是,比如你自動(dòng)部署到 Tomcat 上,那么它的 webapps 目錄下 manager 需要保留,然后在 conf/tomcat-users.xml 文件中,添加如下內容
<role rolename="manager-gui"/><role rolename="manager-script"/><role rolename="manager-jmx"/><role rolename="manager-status"/><role rolename="manager"/><role rolename="admin"/><userusername="admin"password="admin"roles="manager-gui,manager-script,manager-jmx,manager-status, admin, manager"/>
方法二:通過(guò)腳本 這種方式更自由,你可以寫(xiě)好一個(gè)腳本來(lái)做你希望的事情,然后通過(guò)Jenkins來(lái)遠程啟動(dòng)這個(gè)腳本。
如果時(shí)執行Windows下的批處理,就選擇“Execute Windows batch command”,如果是bash腳本,就選擇“Execute shell”。
寫(xiě)腳本時(shí),有寫(xiě)Jenkins的內部變量你可以使用,比如我們這個(gè)實(shí)驗系統,有個(gè)頁(yè)面就是介紹這些內部變量的 http://ci.abc.com/jenkins/env-vars.html/。
創(chuàng )建一個(gè)做集成測試的Job 這一類(lèi)的Job一般是依賴(lài)某個(gè)Job(比如手動(dòng)部署測試環(huán)境)構建后啟動(dòng)構建。所以我們在配置Job屬性時(shí)配置:
展示報告 Jenkins 的插件已經(jīng)覆蓋了大部分的報告格式(測試報告、靜態(tài)檢查報告等),如果你使用了一個(gè)工具的報告格式是不常見(jiàn)。你可以嘗試把格式轉化為XUnit兼容的格式展示?;蛘呖梢詫蟾娈a(chǎn)生的XML文件結合 XLS文件通過(guò) “HTML Publisher Plugin” 插件來(lái)展示。
關(guān)于 XSL 展示 XML ,有興趣可以看看 http://www.ibm.com/developerworks/cn/xml/theme/x-xsl.html
交互風(fēng)格的Job 這是個(gè)有趣的功能,比如上面我們說(shuō)的用于自動(dòng)部署的Job,如果常規的構建方式,我們只能構建最新的代碼,如果我們希望能部署指定的某次提交到測試環(huán)境怎么辦呢?我們可以設置“參數化構建過(guò)程”來(lái)實(shí)現(參數化構建的本質(zhì)是在構建前讓你和Job有個(gè)交互過(guò)程,交互結果以環(huán)境變量方法參與到Job的構建)。
首選參考前文,在主節點(diǎn)上安裝git工具并且配置訪(fǎng)問(wèn)git服務(wù)器的私鑰(id_rsa)到 .ssh 目錄下。
編輯Job的屬性,找到“參數化構建過(guò)程”添加一個(gè)“Git Parameter”。
執行后發(fā)現并沒(méi)有列出git上的所有提交。
在“系統管理”→“System Log”中
查看“所有系統日志”得知,后臺報錯“No such file or directory”。我覺(jué)得這是Jenkins的一個(gè)Bug,我們配置Job是在奴隸節點(diǎn)上執行,它卻在主節點(diǎn)上查找目錄。關(guān)于這個(gè)問(wèn)題我們用另一個(gè)方法來(lái)解決,
我們欣賞一下在主節點(diǎn)構建的Job使用Git參數做參數化構建的效果。有一點(diǎn)要注意,這里雖然列出提交Id但不代表選擇后會(huì )簽出指定的這次提交代碼,它只是將你選擇的內容保存到你指定Name命名的環(huán)境變量里。 剛才說(shuō)的另一個(gè)方法需要安裝兩個(gè)插件“Extended Choice Parameter plugin”和“Extensible Choice Parameter plugin”他們可以擴展參數化構建過(guò)程。
我們在 Jenkins 服務(wù)器上創(chuàng )建一個(gè)目錄 /jenkins/tmp/,然后簽出 javaMavenSample 項目的代碼。
[root@svr80 ~]# mkdir /jenkins/tmp/[root@svr80 ~]# cd /jenkins/tmp/[root@svr80 tmp]# git clone ssh://git@172.16.12.83/home/git/git_home/javaMavenSample.git
在Jenkins的服務(wù)器上創(chuàng )建一個(gè) /jenkins/tools/ 目錄,然后在下面寫(xiě)一個(gè)腳本 genProject2Revision.sh,內容如下:
#!/bin/bashcd /jenkins/tmp/javaMavenSample/usr/bin/git pullecho "revision=\\" > /jenkins/tools/project2_revision.txt/usr/bin/git log --pretty=oneline | /bin/awk '{printf "%s,\\\n", $1}' >> /jenkins/tools/project2_revision.txt設置crontab 讓這個(gè)腳本每小時(shí)執行一次。
[root@svr80 tools]# crontab -l0 * * * * /jenkins/tools/genProject2Revision.sh
這樣我們每小時(shí)就會(huì )更新 project2_revision.txt 文件內容如下
現在設置Job,添加“Extended Choice Parameter”
再執行Job,可以選擇了
這里做的選擇只會(huì )將選擇內容保存到 GIT_COMMIT 環(huán)境變量里,要希望簽出選定的代碼,創(chuàng )建一個(gè)Pre-build setup。
目前這個(gè)測試項目的提交歷史如下
當我選擇中間的那次提交 ed8ec8bf4966cf41b859b5f60dd0fc96f5797af2 時(shí),執行結果如下:
當選擇最早的那次提交 2f65720bb717c4e62ae9d2e34d521689e30cd463 時(shí),執行結果如下,構建失敗的原因參考上面的提交歷史可知,那次提交時(shí) settings.xml 文件還未添加。
大小: 28.3 KB
大小: 7 KB
大小: 13.8 KB
大小: 12.9 KB
大小: 28 KB
大小: 26.1 KB
大小: 2.9 KB
大小: 12.4 KB
大小: 10 KB
大小: 9.1 KB
大小: 17.6 KB
大小: 9.8 KB
大小: 2.5 KB
大小: 7.4 KB
大小: 25.2 KB
大小: 24.8 KB
大小: 2.6 KB
大小: 12.5 KB
大小: 4.8 KB
大小: 7.2 KB
大小: 7.9 KB
大小: 6.9 KB
大小: 7.9 KB
大小: 1.5 KB
大小: 9.4 KB
大小: 44.4 KB
大小: 3 KB
大小: 12.9 KB
大小: 40.6 KB
大小: 81.8 KB
大小: 1.2 KB
大小: 12.8 KB
大小: 12 KB
大小: 33.7 KB
大小: 17.8 KB
大小: 39.2 KB
大小: 5.8 KB
大小: 17.4 KB
大小: 4.6 KB
大小: 17.4 KB
大小: 8.6 KB
大小: 5.3 KB
大小: 35.6 KB
大小: 8.6 KB
大小: 1.3 KB
大小: 7.6 KB
大小: 4.6 KB
大小: 5.3 KB
大小: 14.1 KB
大小: 5.8 KB
大小: 7.1 KB
大小: 7 KB
大小: 12.2 KB
大小: 4.5 KB
大小: 3.7 KB
大小: 6.2 KB
大小: 12.6 KB
大小: 16.2 KB查看圖