2017
Jan
17

我平均一年只會寫兩次 Java ,因為寫的頻率很低,每次輪到 Java 的工作時,總是找不到合適的環境來開發,後來我使用 Docker 的技術,將 Java + Maven 環境設定寫成 Docker 專用的 Dockerfile ,以後只要碰到 Java 的專案,就只要打開 Docker container 就行了。

下面就是我使用的 Dockerfile ,重點要記得 mount ~/.m2 這個目錄,因為 Maven 會下載 Java libraries 到 ~/.m2 這個目錄, Docker container 每次執行都會是一個全新乾淨的環境,所有下載過的 Java libraries 都會消失,你應該不想每次 compile 都要重新下載 Java libraries 吧。

Dockerfile for mvn
  1. FROM openjdk:8-jdk
  2.  
  3. ARG MAVEN_VERSION=3.3.9
  4. ARG USER_HOME_DIR="/root"
  5.  
  6. RUN apt-get update
  7. RUN apt-get install build-essential -y
  8. RUN ln -sf /usr/bin/make /usr/bin/gmake
  9. RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
  10. && curl -fsSL http://apache.osuosl.org/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz \
  11. | tar -xzC /usr/share/maven --strip-components=1 \
  12. && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
  13.  
  14. ENV MAVEN_HOME /usr/share/maven
  15. ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
  16.  
  17. VOLUME ["/usr/src/mymaven", "/root/.m2"]

使用 docker build -t my/my-mvn . 建立好 docker image 後,執行下面這個執令就能夠執行 Maven 了,這個指令在 Mac 上是可以運作的,請把帳號改成你自已的。

docker run -it --rm -v /Users/account/.m2:/root/.m2 -v /my_dev/maven/project:/usr/src/mymaven -w /usr/src/mymaven my/my-mvn mvn compile

這個指令的 -v /Users/account/.m2:/root/.m2 -v /Users/account/.m2:/root/.m2 ,就是要 mount ~/.m2 這個目錄,這樣每次下載 Java Libraries 就會存在實體機的 ~/.m2 ,而不是存在 docker container , 另外 -v /my_dev/maven/project:/usr/src/mymaven 這個是指我 Java 程式碼的路徑,我把程式碼掛載到 /usr/src/mymaven 這個目錄, "-w /usr/src/mymaven" :指定切換到 /usr/src/mymaven 這個目錄下。

mount 目錄到 Docker machine

如果你的 docker engine 是安裝在 linux 環境,那麼操作上是沒什麼問題,若是使用 Mac 或 Windows ,那麼你要先把本機的目錄掛載到 Docker machine 上,只有個人目錄不用特別手動掛載,像我平常習慣的程式開發路徑都放在 /dev 下, 所以我得先把 /dev 掛載到 docker machine 的 /dev ,Mac mount 的執令如下:

VBoxManage sharedfolder add default --name /dev --hostpath /dev --automount

Windows 要下這樣的指令:

/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe sharedfolder add default --name /dev --hostpath 'd:\dev' --automount

設定 alias

每次都打這麼長的指令,而且還要手動修改路徑,當然是不行的,我們可以簡單的寫一個 alias ,簡化指令, 請在 ~/.alias 這個檔案加入下面的設定。

.alias
  1. alias mvn="mvn_fn"
  2.  
  3.  
  4. function mvn_fn() {
  5. command=" $@ "
  6. pwd=`pwd`
  7. owner=`whoami`
  8. if [ `uname` = "Darwin" ]; then
  9. HOME="/Users/$owner"
  10. else
  11. HOME="/home/$owner"
  12. fi
  13. command="docker run -it --rm -v $HOME/.m2:/root/.m2 -v $(pwd):/usr/src/mymaven -w /usr/src/mymaven my/my-mvn $command"
  14. echo $command
  15. $command
  16. }

這個 alias 會自動找出你當前的目錄,並將這個目錄 mount 到 /usr/src/mymaven 如此我們就不用手動輸入程式碼目錄,你只要換掉到 Maven pom.xml 的目錄,執行 mvn mvn compile 就行了,第一個 mvn 是我們的 alias ,告訴 docker 啟動 Maven container ,第二個 mvn compile 才是真的執行 mvn 指令,如果你想要用 Java compile 程式,那麼可以輸入 mvn javac xxx.java

執行兩行指令

有時候,我們會需要執行二行以上的指令,例如先 mvn compile 再 mvn test ,而 docker 沒辦法讓我們這樣做(有可能是我自已不會), 我的做法是的 , 我將指令寫在 Makefile 裡 ,然後用 mvn gmake targe 來執行就好了。

Example
  1. run:
  2. mvn compile
  3. mvn test
Example
  1. $ mvn gmake run
  2. docker run -it --rm -v /Users/account/.m2:/root/.m2 -v /my_test/maven/proj:/usr/src/mymaven -w /us
  3. r/src/mymaven my/my-mvn gmake run
  4. mvn compile
  5. [INFO] Scanning for projects...
  6. [INFO]
  7. [INFO] ------------------------------------------------------------------------
  8. [INFO] Building maven 1.0-SNAPSHOT
  9. [INFO] ------------------------------------------------------------------------
  10. [INFO]
  11. [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven ---
  12. [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
  13. [INFO] Copying 116 resources
  14. [INFO]
  15. [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven ---
  16. [INFO] Nothing to compile - all classes are up to date
  17. [INFO] ------------------------------------------------------------------------
  18. [INFO] BUILD SUCCESS
  19. [INFO] ------------------------------------------------------------------------
  20. [INFO] Total time: 9.219 s
  21. [INFO] Finished at: 2017-01-19T16:30:19+00:00
  22. [INFO] Final Memory: 7M/17M
  23. [INFO] ------------------------------------------------------------------------
  24. mvn exec:java -Dexec.mainClass="com.dungame.Main"[INFO] ------------------------------------------------------------------------
  25. [INFO] BUILD SUCCESS
  26. [INFO] ------------------------------------------------------------------------
  27. [INFO] Total time: 9.219 s
  28. [INFO] Finished at: 2017-01-19T16:30:19+00:00
  29. [INFO] Final Memory: 7M/17M
  30. [INFO] ------------------------------------------------------------------------
  31. mvn exec:java -Dexec.mainClass="com.dungame.Main"
  32. [INFO] Scanning for projects...
  33. [INFO]
  34. [INFO] ------------------------------------------------------------------------
  35. [INFO] Building maven 1.0-SNAPSHOT
  36. [INFO] ------------------------------------------------------------------------
  37. [INFO]
  38. [INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ maven ---
  39. Hello World!2
  40. [INFO] ------------------------------------------------------------------------
  41. [INFO] BUILD SUCCESS
  42. [INFO] ------------------------------------------------------------------------
  43. [INFO] Total time: 3.924 s
  44. [INFO] Finished at: 2017-01-19T16:30:25+00:00
  45. [INFO] Final Memory: 8M/19M
  46. [INFO] ------------------------------------------------------------------------

回應 (Leave a comment)