本篇原創發佈於 Flex 的我的博客:點擊跳轉java
在沒有 docker 前,項目轉測試是比較麻煩的一件事。首先會化較長的時間搭建測試環境,而後在測試過程當中又常常出現測試說是 bug,開發說沒法復現的狀況,致使撕逼。mysql
本篇記錄瞭如何將一個 java 應用部署到 docker 中。主要講述瞭如下幾個部分:linux
項目架構以下:nginx
本系統中有三個主要模塊 OMS,DAS 和一個 Eureka 註冊中心。其中 OMS 和 DAS 使用有 activemq 消息隊列,來進行大量數據的交互而後各自使用一個 mysql 數據庫存儲主要的業務數據。使用 elastricsearch 存儲超大量的數據。sql
本項目在 windows 部署時是將其做爲三個部分來進行安裝的--ENV 環境包(保護 mysql,es 等),OMS 產品包,DAS 產品包。因此最初個人設想是一個容器中裝 ENV 環境包所需的全部軟件,一個容器裝 DAS,一個容器裝 OMS。而後再實踐的過程當中愈來愈感受不對勁,環境配置比較複雜,並且也有種把容器當虛擬機用的感受,一點沒有簡化的感受。docker
遂停下了操做,開始學習一波 docker 究竟是怎麼用的。用租房子來作比喻:數據庫
使用 docker 推薦操做是一個進程放到一個容器中,作到更好的隔離性,同時也更容易進行管理。下面來使用容器技術部署咱們應用。仍是分爲三部分,可是每一個進程使用一個容器,作到 0 配置啓動容器。ubuntu
在此默認已經會安裝 docker,且瞭解基本操做。如不瞭解的先看這兩篇:安裝,基本使用windows
環境包中諸如 elastricsearch,mysql 這樣的數據存儲工具,須要知足以下兩個要求:tomcat
使用容器部署 mysql 過程以下:
docker pull mysql:5.7.24
因爲 mysql 是用來存數據的,數據不管什麼狀況都不能丟失,因此數據存在容器外部,經過映射操做,映射到容器內部,參數以下:
# 將宿主機的路徑,映射到容器內部。這個路徑既能夠是文件夾,也能夠是文件 -v hostPath:containerPath
顯然咱們經過這個桉樹將外部的數據文件夾,配置文件映射到容器中。最後啓動這個容器的命令以下:
# 假設在宿主機中數據存放路徑爲/opt/mysql/data,配置文件路徑爲:/opt/mysql/my.cnf docker run --name=mysql -itd -p 3308:3306 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /opt/mysql/data:/var/lib/mysql -v /opt/mysql/my.cnf:/etc/mysql/my.cnf -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.25
注意:若是 mysql 版本爲 8.x,還須要映射容器中的/var/lib/mysql-files 目錄,不然啓動會報錯
下面介紹具體參數含義:
可能大家會問爲何要映射/etc/timezone
和/etc/timezone
,這是爲了讓容器的時間和時區與宿主機保持一致。默認狀況下容器爲 UTC 標準時間。/etc/timezone
讓容器時間,時區和宿主機一致。可是若是不映射/etc/timezone
java 應用中的時區仍是錯的,雖然使用date -R
命令查看時間和時區都正常。
es 和 activeMQ 都依賴 java 的運行環境,因此有兩種部署方式:
這裏以第二種方式爲例進行說明。
這裏不從 docker hub 中拉取鏡像,經過 dockerfile 來製做一個自定義的鏡像。因爲只須要一個 java 運行環境,因此只要將一個 jre 運行環境加入到一個基礎 linux 鏡像中便可(這裏選擇 ubuntu)。製做過程以下:
首先建立一個文件夾dockerFileTest
存放依賴和 dockerfile 文件。
而後將下載加壓後的 jre 運行環境放到dockerFileTest/jre
目錄下。
接着在 dockerFileTest 目錄中建立 Dockerfile 文件,內容以下:
#說明基礎鏡像,默認:latest FROM ubuntu #將當前路徑下的jre文件夾複製到新鏡像下的/opt/jre路徑 COPY jre /opt/jre #設置環境變量 ENV JAVA_HOME=/opt/jre CLASSPATH=/opt/jre/lib PATH=$PATH:/opt/jre/bin
最後經過``命令生成新鏡像 jre:v1
下載好 es,假設存放在/root/es1 中,經過如下命令建立一個 es 容器:
docker run --name=es1 -itd -p 9200:9200 -p 9300:9300 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/es1:/opt/es -w /opt/es jre:v1 ./bin/elasticsearch -Des.insecure.allow.root=true
參數含義以下:
上面的命令以 es1 爲容器名,映射 9200,9300 到宿主機端口,以./bin/'elasticearch -Des.insecure.allow.root=true
建立 es 容器。最後加的參數爲了讓 es 可以以 root 在容器中啓動。
將以前的 es1 複製一份命名爲 es2 做爲節點 2。要讓兩個 es 節點構成 es 集羣,須要讓節點間可以進行通訊,這裏使用--link
參數來讓 es2 可以連上 es1 構成集羣。--link
用法以下:
--link containerName[:alias]
es2 啓動命令以下:
docker run --name=es2 -itd -p 9201:9200 -p 9301:9300 --link es1 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/es2:/opt/es -w /opt/es jre:v1 ./bin/elasticsearch -Des.insecure.allow.root=true
而後就能在 es2 中經過 es1 的容器名訪問到 es1(實際是在 es2 的 host 中增長了一條記錄,將 es1 指向 es1 的 IP,該 IP 是 docker 的虛擬網卡分配的 IP)。
可是使用--link 有一些侷限,經過該參數聯通的容器必須存在。所以該參數只能用在 B 依賴 A 的狀況,若是同時 A 也依賴 B(也就是 A,B 要可以相互訪問到),這種狀況下就不能經過 link 來實現了,緣由你們應該可以想到。。。
在容器中啓動 activeMQ 與啓動 es 稍有不一樣。activeMQ 默認是後臺啓動的,啓動完成後啓動程序就會退出,所以若是直接以./bin/activemq start
(假設當前目錄在 activemq 中),啓動容器會發如今 activemq 啓動成功後容器就中止運行了。會出現這種狀況是由於容器中啓動的第一個進程結束後,容器就會被docker關閉掉
。因此呢咱們只需讓第一個進程不結束就好了,所以須要咱們編寫一個啓動腳原本啓動 activemq 並監測運行狀況,一旦 activemq 進程掛掉,就結束啓動腳本,不然一直運行。啓動腳本代碼以下:
#!/bin/bash #使用sh腳本啓動activemq,而後定時判斷服務是否被關閉,關閉後退出腳本,不然一致循環。 #爲避免docker容器在active自帶的啓動腳本運行結束後就關閉容器了。 #獲取啓動pid out=`./bin/activemq start` echo "$out" pid=`echo $out | grep -Eo "pid '[0-9]+'" | grep -Eo "[0-9]+"` echo "當前mq進程pid爲:${pid}" if [ ${#pid} = 0 ]; then echo "啓動失敗" exit 0 fi while true; do num=`ps -e | grep -cwE "$pid"` if [ $num = 0 ]; then echo "進程異常關閉" exit 0 fi sleep 1 done
而後以該腳本做爲啓動腳原本啓動容器便可。啓動命令以下:(假設 activemq 目錄爲/opt/activemq,啓動腳本路徑爲/opt/activemq/start.sh)
docker run --name=activemq -itd -p 8161:8161 -p 61616:61616 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/activemq:/opt/activemq -w /opt/activemq jre:v1 /bin/bash ./start.sh
仍是使用以前製做的 jar 鏡像來啓動 java 應用,這裏以部署 jar 包爲例,若是部署 war 包則須要在 tomcat 鏡像上部署。特別注意下容器的時間和時區設置,不然 java 程序中沒法獲取到正確的時間和時區。這裏經過映射宿主機的 localtime 和 timezone 文件來讓容器時間和時區與宿主機相同。啓動命令以下:
# 啓動oms docker run -itd --name=oms -p 8082:9090 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/oms.jar:/opt/oms.jar -w /opt --link es1 --link activemq --link oms-mysql --link eureka-server jre:v1 java -jar oms.jar # 啓動das docker run -itd --name=das -p 8083:9099 -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone -v /root/das.jar:/opt/oms -w /opt --link es1 --link activemq --link oms-mysql --link eureka-server jre:v1 java -jar das.jar
本篇只是記錄瞭如何使用一容器一進程
的方式來部署 java 應用.
PS:不推薦這麼直接手擼命令,建議使用 docker-compose
本篇原創發佈於 Flex 的我的博客:點擊跳轉