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)