前段時間在我廠卷爺?shù)闹笇聦ocker在我的實際項目中落地,最近幾個小demo都盡量熟悉docker的使用,希望通過這篇文章分享我截止目前的使用經(jīng)驗(如有不準確的表述,歡迎幫我指出)。本文的主要內(nèi)容是關于Java應用程序的docker化,首先簡單介紹了docker和docker-compose,然后利用兩個案例進行實踐說明。
簡單說說Docker,現(xiàn)在云計算領域火得一塌糊涂的就是它了吧。Docker的出現(xiàn)是為了解決PaaS的問題:運行環(huán)境與具體的語言版本、項目路徑強關聯(lián),因此干脆利用lxc技術進行資源隔離,構造出跟隨應用發(fā)布的運行環(huán)境,這樣就解決了語言版本的限制問題。PaaS的出現(xiàn)是為了讓運維人員不需要管理一臺虛擬機,IaaS的出現(xiàn)是為了讓運維人員不需要管理物理機。云計算,說到底都是倆字——運維。
云計算領域的技術分為虛擬化技術和資源管理兩個方面,正好對應我們今天要講的兩個工具:Docker和docker-compose。Docker的主要概念有:容器、鏡像、倉庫;docker-compose是fig的后續(xù)版本,負責將多個docker服務整合起來,對外提供一致服務。
1. Spring Boot應用的docker化
首先看Spring Boot應用程序的docker化,由于Spring Boot內(nèi)嵌了tomcat、Jetty等容器,因此我們對docker鏡像的要求就是需要java運行環(huán)境。我的應用代碼的的Dockerfile文件如下:
#基礎鏡像:倉庫是java,標簽用8u66-jdk
FROM java:8u66-jdk
#當前鏡像的維護者和聯(lián)系方式
MAINTAINER duqi duqi@example.com
#將打包好的spring程序拷貝到容器中的指定位置
ADD target/bookpub-0.0.1-SNAPSHOT.jar /opt/bookpub-0.0.1-SNAPSHOT.jar
#容器對外暴露8080端口
EXPOSE 8080
#容器啟動后需要執(zhí)行的命令
CMD java -Djava.security.egd=file:/dev/./urandom -jar /opt/bookpub-0.0.1-SNAPSHOT.jar
因為目前的示例程序比較簡單,這個dockerfile并沒有在將應用程序的數(shù)據(jù)存放在宿主機上。如果你的應用程序需要寫文件系統(tǒng),例如日志,最好利用VOLUME /tmp
命令,這個命令的效果是:在宿主機的/var/lib/docker目錄下創(chuàng)建一個臨時文件并把它鏈接到容器中的/tmp目錄。
把這個Dockerfile放在項目的根目錄下即可,后續(xù)通過docker-compose build
統(tǒng)一構建:基礎鏡像是只讀的,然后會在該基礎鏡像上增加新的可寫層來供我們使用,因此java鏡像只需要下載一次。
docker-compose是用來做docker服務編排,參看《Docker從入門到實踐》中的解釋:
Compose 項目目前在 Github 上進行維護,目前最新版本是 1.2.0。Compose 定位是“defining and running complex applications with Docker”,前身是 Fig,兼容 Fig 的模板文件。
Dockerfile 可以讓用戶管理一個單獨的應用容器;而 Compose 則允許用戶在一個模板(YAML 格式)中定義一組相關聯(lián)的應用容器(被稱為一個 project,即項目),例如一個 Web 服務容器再加上后端的數(shù)據(jù)庫服務容器等。
單個docker用起來確實沒什么用,docker技術的關鍵在于持續(xù)交付,通過與jekins的結合,可以實現(xiàn)這樣的效果:開發(fā)人員提交push,然后jekins就自動構建并測試剛提交的代碼,這就是我理解的持續(xù)交付。
2. spring boot + redis + mongodb
在這個項目中,我啟動三個容器:web、redis和mongodb,然后將web與redis連接,web與mongodb連接。首先要進行redis和mongodb的docker化,redis鏡像的Dockerfile內(nèi)容是:
FROM ubuntu:14.04
RUN apt-get update
RUN apt-get -y install redis-server
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
Mongodb鏡像的Dockerfile內(nèi)容是,docker官方給了mongodb的docker化教程,我直接拿來用了,參見Dockerizing MongoDB:
# Format: FROM repository[:version]
FROM ubuntu:14.04
# Format: MAINTAINER Name <email@addr.ess>
MAINTAINER duqi duqi@example.com
# Installation:
# Import MongoDB public GPG key AND create a MongoDB list file
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
RUN echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-3.0.list
# Update apt-get sources AND install MongoDB
RUN apt-get update && apt-get install -y mongodb-org
# Create the MongoDB data directory
RUN mkdir -p /data/db
# Expose port 27017 from the container to the host
EXPOSE 27017
# Set usr/bin/mongod as the dockerized entry-point application
ENTRYPOINT ["/usr/bin/mongod"]```
使用docker-compose編排三個服務,具體的模板文件如下:
web:
build: .
ports:
- "49161:8080"
links: - redis
- mongodb
redis:
image: duqi/redis
ports:
- "6379:6379"
mongodb:
image: duqi/mongodb
ports:
- "27017:27017"
架構比較簡單,第一個區(qū)塊的build,表示docker中的命令“docker build .”,用于構建web鏡像;ports這塊表示將容器的8080端口與宿主機(IP地址是:192.168.99.100)的49161對應。因為現(xiàn)在docker不支持原生的osx,因此在mac下使用docker,實際上是在mac上的一臺虛擬機(docker-machine)上使用docker,這臺機器的地址就是192.168.99.100。參見:[在mac下使用docker](https://docs.docker.com/v1.8/installation/mac/)
links表示要連接的服務,redis與下方的redis區(qū)塊對應、mongodb與下方的mongodb區(qū)塊對應。redis和mongodb類似,首先說明要使用的鏡像,然后規(guī)定端口映射。
那么,如何運行呢?
1. 命令`docker-compose build`,表示構建web服務,目前我用得比較土,就是編譯jar之后還需要重新更新docker,優(yōu)雅點不應該這樣。

2. 命令`docker-compose up`,表示啟動web服務,可以看到mongodb、redis和web依次啟動,啟動后用`docker ps`查看當前的運行容器。

特別注意,在配置文件中寫redis和mongodb的url時,要用虛擬機的地址,即192.168.99.100。例如,redis的一個配置應該為:spring.redis.host=192.168.99.100。
## 3. spring boot + mysql
拉取mysql鏡像的指令是:`docker run --name db001 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=admin -d mysql:5.7`,表示啟動的docker容器名字是db001,登錄密碼一定要設定, -d表示設置Mysql版本。
我的docker-compose模板文件是:
web:
build: .
ports:
- "49161:8080"
links: - mysql
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: admin
MYSQL_DATABASE: springbootcookbook
ports:
- "3306:3306"
主要內(nèi)容跟之前的類似,主要講下mysql部分,通過environement來設置進入mysql容器后的環(huán)境變量,即連接數(shù)據(jù)庫的密碼MYSQL_ROOT_PASSWORD,使用的數(shù)據(jù)庫名稱MSYQL_DATABASE等等。
一直想寫這篇文章做個總結,寫來發(fā)現(xiàn)還是有點薄,對于docker我還需要系統(tǒng)得學習,不過,針對上面的例子,我都是親自實踐過的,大家有什么問題可以與我聯(lián)系。
## 參考資料
1. [Docker從入門到實踐](https://www.gitbook.com/book/yeasy/docker_practice/details)
2. [Docker - Initialize mysql database with schema](http://stackoverflow.com/questions/29145370/docker-initialize-mysql-database-with-schema)
3. [使用Docker搭建基礎的mysql應用](http://blog.csdn.net/smallfish1983/article/details/40080305)
4. [Spring Boot with docker](https://spring.io/guides/gs/spring-boot-docker/)
***
本號專注于后端技術、JVM問題排查和優(yōu)化、Java面試題、個人成長和自我管理等主題,為讀者提供一線開發(fā)者的工作和成長經(jīng)驗,期待你能在這里有所收獲。
