以前曾經試過在VMware上安裝linux,再在linux上編譯openjdk8,但是每次都不順利,例如linux環境,預裝依賴軟件,openjdk源碼的選擇等環境都會遇到問題,一旦失敗再重新開始挺費時間的,現在用docker就省事多了,鏡像和容器的創建和刪除都比較簡單干凈,專心做好Dockerfile就行,下面我們一起來實踐一下吧。
本次實戰用到的所有文件,已經打包到github上,路徑是:https://github.com/zq2599/centos7_build_openjdk8 ,歡迎您來使用(git clone git@github.com:zq2599/centos7_build_openjdk8.git)
本次編譯實戰的基本步驟如下:
編寫的Dockerfile中要做的如下的事情:
- 安裝依賴的軟件;
- 把openjdk的源碼復制到鏡像中;
在編寫Dockerfile之前要做三個重要的選擇,如下:
- linux:我選擇了centos7,之前試過ubuntu16.04,但是在configure的時候提示"freetype"沒有安裝,我按照提示去裝了,再次configure的時候繼續提示"freetype"沒有安裝......(此問題現在還沒解決,如果您解決過相同問題,請您告訴一下解決方法,謝謝了!)
- openjdk源碼,這次要編譯的是openjdk8,源碼的下載地址在這里
- Bootstrap JDK:即編譯時要用到的JDK,下載了openjdk的源碼后,解壓開可以看到“README-builds.html”這個文件,里面有對Bootstrap JDK的描述:
看得出,需要安裝jdk7來編譯openjdk8的源碼;
OK,關鍵問題都已確認,即將開始Dockerfile制作,不過制作之前還有個小問題需要先想好:本次我打算把制作鏡像所需的Dockerfile和依賴文件都放到github上去,這樣做的好處有兩個:
- 讀者們從git上clone下來之后直接執行Docker build就能在本地構建鏡像;
- daocloud.io網站上支持通過執行github目錄的方式在線構建鏡像,后面我們會實踐在daocloud.io上構建鏡像並部署到騰訊雲或者阿里雲服務器上;
上傳到github時,除了Dockerfile,還要上傳的文件有兩個:jdk1.7和openjdk8源碼,都超過了100M,如下圖:
這就麻煩了,github上傳文件的時候,單個文件不能超過100M,否則push的時候會被服務器拒絕,解決這個問題有兩個辦法:
- 構建鏡像的時候不要把這兩個文件復制到鏡像中了,改為在Dockerfile中通過執行wget命令將這兩個文件分別下載到鏡像中,openjdk的下載路徑是http://www.java.net/download/openjdk/jdk8/promoted/b132/openjdk-8-src-b132-03_mar_2014.zip,而jdk1.7的下載路徑就難辦了,oracle上下載歷史版本的時候,是要做登錄操作的,這個在Dockerfile中難以實現,找到了一個下載地址https://mirror.its.sfu.ca/mirror/CentOS-Third-Party/NSG/common/x86_64/jdk-7u80-linux-x64.rpm,但是下載速度很慢,最少一個小時以上了,所以wget這種方法看似簡單,但下載文件耗時實在太長;
- 第二種方法比較簡單易用,就是在mac或者linux上先用split命令將文件分割成多個,再上傳到github上,在Dockerfile中有對應的命令將分割后的文件恢復成分割前的原文件,具體的分割命令如下:
split -b 50m jdk-7u71-linux-x64.rpm jdkrpm-
這個命令是將jdk-7u71-linux-x64.rpm分割成不超過50m的多個文件,分割后的文件以jdkrpm-作為文件名的前綴,如下圖:
opensdk的源碼用如下命令分割:
split -b 50m openjdk-8-src-b132-03_mar_2014.zip openjdksrc-
Dockerfile中,從分割文件恢復以上兩個原文件的命令為:
cat jdkrpm-* > jdk-7u71-linux-x64.rpm
cat openjdksrc-* > openjdk-8-src-b132-03_mar_2014.zip
以上就是兩種處理大文件的方法,本文用的是第二種,即先分割上傳到git,在Dockerfile中將已分割文件恢復成原文件再使用。
好了,前期的准備工作已經做完了,現在可以編寫Dockerfile文件了,整個文件中要做的事情列出如下:
- 安裝依賴軟件,例如libXtst-devel,libXt-devel等等,這些都是編譯前的configure命令要檢查的,檢查不過無法進行編譯;
- 把分割后的openjdk源碼復制到鏡像文件中,再合成,再解壓;
- 安裝jdk7,把分割后的安裝文件復制到鏡像中合成,然后安裝;
- 為了方便用戶進入容器后快速開始編譯,我們做了一個shell腳本start_make.sh,把這個腳本也要復制到鏡像中,內容如下:
#!/bin/bash
$WORK_PATH/$OPENJDK_SRC_DIR/configure
echo "start make"
cd $WORK_PATH/$OPENJDK_SRC_DIR
make all ZIP_DEBUGINFO_FILES=0 DISABLE_HOTSPOT_OS_VERSION_CHECK=OK
- 清理無用的文件,例如openjdk源碼的壓縮文件,jdk7的安裝文件等;
按照以上步驟,最終寫出的Dockerfile文件如下:
# Docker image of compile and build enviroment for openjdk8
# VERSION 0.0.1
# Author: bolingcavalry
#基礎鏡像使用centos7
FROM centos:centos7
#作者
MAINTAINER BolingCavalry <zq2599@gmail.com>
#定義工作目錄
ENV WORK_PATH /usr/local
#定義jdk1.7的文件名
ENV JDK_RPM_FILE jdk-7u71-linux-x64.rpm
#定義openJdk源碼的文件名
ENV OPENJDK_SRC_ZIP openjdk-8-src-b132-03_mar_2014.zip
#定義解壓縮后的文件名
ENV OPENJDK_SRC_DIR openjdk
#yum更新
RUN yum -y update
#安裝工具集
RUN yum -y groupinstall "Development Tools"
#安裝即將用到的軟件
RUN yum -y install unzip libXtst-devel libXt-devel libXrender-devel cups-devel freetype-devel alsa-lib-devel which
#把分割過的jdk1.7安裝文件復制到工作目錄
COPY ./jdkrpm-* $WORK_PATH/
#用本地分割過的文件恢復原有的jdk1.7的安裝文件
RUN cat $WORK_PATH/jdkrpm-* > $WORK_PATH/$JDK_RPM_FILE
#本地安裝jdk1.7
RUN yum -y localinstall $WORK_PATH/$JDK_RPM_FILE
#把分割過的openJdk8的源碼壓縮包復制到工作目錄
COPY ./openjdksrc-* $WORK_PATH/
#用本地分割過的文件恢復原有的openJdk8的源碼壓縮包
RUN cat $WORK_PATH/openjdksrc-* > $WORK_PATH/$OPENJDK_SRC_ZIP
#解壓縮源碼
RUN unzip $WORK_PATH/$OPENJDK_SRC_ZIP -d $WORK_PATH
#復制啟動編譯的shell
COPY ./start_make.sh $WORK_PATH/$OPENJDK_SRC_DIR/
#給執行文件增加可執行權限:configure文件
RUN chmod a+x $WORK_PATH/$OPENJDK_SRC_DIR/configure
#給執行文件增加可執行權限:啟動編譯文件
RUN chmod a+x $WORK_PATH/$OPENJDK_SRC_DIR/start_make.sh
#刪除分割文件
RUN rm $WORK_PATH/jdkrpm-*
#刪除分割文件
RUN rm $WORK_PATH/openjdksrc-*
#刪除jdk安裝包文件
RUN rm $WORK_PATH/$JDK_RPM_FILE
#刪除openJdk源碼壓縮文件
RUN rm $WORK_PATH/$OPENJDK_SRC_ZIP
至此,鏡像文件制作所需的材料都已經齊全了,如下圖:
現在讓我們開始制作鏡像吧,打開終端,進入Dockerfile所在目錄,執行命令
docker build -t bolingcavalryopenjdk:0.0.1 .
因為要在線安裝不少的軟件,所以可能耗時會略長,和網絡帶寬有關,我在住處用家庭網絡大概10分鍾左右構建成功,執行目錄docker images查看鏡像,新的鏡像文件已經生成了,如下圖:
現在啟動一個容器試試吧:
docker run --name=jdk001 -idt bolingcavalryopenjdk:0.0.1
容器已經啟動,再執行以下命令進入容器:
docker exec -it jdk001 /bin/bash
進去后,直接到/usr/local/openjdk目錄下,執行./start_make.sh,開始編譯了,整個過程的耗時和當前電腦的硬件配置有關,我用i7處理器的mac pro15大約要用20多分鍾,編譯結束后會有類似下圖的輸出:
這時候去/usr/local/openjdk目錄下看看,發現多了一個build目錄,這里面就是編譯好的結果,如下圖:
build目錄下只有一個linux-x86_64-normal-server-release目錄,再進去就能看到jdk目錄了,如下圖:
進入/usr/local/openjdk/build/linux-x86_64-normal-server-release/jdk/bin目錄,會發現里面有java文件,執行./java -version輸出如下:
新的jdk信息已經打印出來了,OpenJDK Runtime Enviroment信息已經說明了這是個最新構建的jdk環境。
至此我們的本次實戰就結束了,面對如此干凈的編譯環境和現成的源碼,讀者您是否有一種改動一番源碼的沖動,然后構建一個個性化的屬於自己的jdk,如果有興趣,敬請期待下一次實戰,我們一起分析,修改和調試openjdk源碼,打造一些個性化的小東東。