基礎(chǔ)學(xué)習(xí)資料
Docker比較完整和詳細(xì)的指令? https://yeasy.gitbooks.io/docker_practice/network/port_mapping.html
Dockerfile 中的 CMD 與 ENTRYPOINT區(qū)別詳細(xì)說(shuō)明,建議看完通篇文章后再看 https://www.cnblogs.com/sparkdev/p/8461576.html
官方文檔https://docs.docker.com/engine/reference/builder/
docker的定位,它本質(zhì)上是一個(gè)輕量級(jí)的虛擬機(jī),但是實(shí)際應(yīng)用中說(shuō)是 進(jìn)程的容器工具 更貼切。創(chuàng)建一個(gè)容器當(dāng)做虛擬系統(tǒng)來(lái)使用,然后再里面部署多個(gè)應(yīng)用程序,不是docker推薦的用法。因?yàn)閐ocker的主要優(yōu)點(diǎn)是如下兩點(diǎn)
輕量級(jí)的資源隔離
簡(jiǎn)潔一致的部署環(huán)境
為了盡量發(fā)揮優(yōu)點(diǎn),所以應(yīng)該每個(gè)容器運(yùn)行一個(gè)應(yīng)用,一般是只有一個(gè)進(jìn)程,單一功能。比如證券交易系統(tǒng)有資金、交易、用戶系統(tǒng),各對(duì)應(yīng)一個(gè)項(xiàng)目,應(yīng)該部署到不同的容器。一個(gè)應(yīng)用如果有多個(gè)進(jìn)程,盡量分開(kāi)部署到不同容器實(shí)例。如果應(yīng)用要部署一個(gè)網(wǎng)關(guān)nginx做反向代理,部署到應(yīng)用的容器里還勉強(qiáng)合理。
接著要理解docker的重要概念
鏡像和容器
鏡像和容器的關(guān)系類似于虛擬機(jī)(比如VM或Virtual Box)的系統(tǒng)鏡像和系統(tǒng)實(shí)例,鏡像是容器的構(gòu)建基礎(chǔ),容器是鏡像的實(shí)例?;阽R像建立容器后可以做很多定制化的修改,而且也可以把修改后的容器再保存為新的鏡像。
有兩種方式可以部署一個(gè)有自己的程序的docker容器,首先我們先做一些基礎(chǔ)操作
準(zhǔn)備工作
首先根據(jù)上面的第一個(gè)資料鏈接安裝好docker,這部分不詳述。
然后通過(guò)docker search openjdk指令搜索openjdk的公開(kāi)鏡像,取第一個(gè)star最多的
接著通過(guò) docker pull openjdk:8 將jdk版本為8的openjdk鏡像拉取到本地
通過(guò)指令docker images 可以查看到是否已經(jīng)拉取到鏡像
第一種方法
直接將項(xiàng)目文件放在鏡像里,然后每次構(gòu)建帶有最新項(xiàng)目文件的新的鏡像,并根據(jù)鏡像建立新的容器。
下面通過(guò)Dockerfile構(gòu)建定制鏡像,新建一個(gè)目錄,新建名為Dockerfile的文件,寫(xiě)入定制化配置
示例:
FROM openjdk:8
ENV TZ=Asia/Shanghai
COPY distribute-all.zip /home/
RUN cd /home/ && unzip distribute-all.zip
EXPOSE 28080 9001
WORKDIR /home/distribute/
CMD java -cp ./classes:./lib/*:$JAVA_HOME/lib/tools.jar:./test-classes com.dd.http.server.WebServer --config config-test.json --env test distribute > /dev/null 2>&1
FROM指的是基于什么鏡像做配置,官方已經(jīng)有很多基礎(chǔ)鏡像,包括redis、mysql、jdk、openjdk,我們基于這些鏡像作進(jìn)一步的定制化即可。
ENV 一行是配置時(shí)區(qū)為上海
Run是在鏡像里執(zhí)行指令,比如一些前置的指令建立文件夾,安裝工具等。比如用RUN apt-get update和RUN apt-get-y install vim可以安裝vim到鏡像里
COPY 是將主機(jī)目錄里的文件復(fù)制到鏡像中
EXPOSE 是聲明鏡像后期需要暴露的端口,僅僅起到聲明作用
WORKDIR 設(shè)定后續(xù)指令工作目錄,因?yàn)殓R像構(gòu)建配置這里的指令都是無(wú)狀態(tài)的,無(wú)法繼承前一條指令的狀態(tài)如執(zhí)行目錄
CMD 設(shè)定啟動(dòng)指令,有兩種方式,shell方式,如CMD top -a ;以及 exec方式,如CMD? ["top”,”-a”] 。兩者區(qū)別是最終在容器執(zhí)行的指令為 /bin/sh -c top -a 和 top -a。其中前者會(huì)導(dǎo)致sh才是容器的1號(hào)進(jìn)程。
然后通過(guò)build指令構(gòu)建鏡像,下面指令最后的點(diǎn)號(hào)是根據(jù)本目錄進(jìn)行構(gòu)建的意思
docker build -t distribute-img .
執(zhí)行后通過(guò)docker images 發(fā)現(xiàn)得到了一個(gè)名為distribute-img的鏡像,如果是執(zhí)行成功,執(zhí)行過(guò)程中會(huì)有一些中間容器生成,并被刪掉,如果完全成功只會(huì)有鏡像不會(huì)有中間容器被留下來(lái)。
通過(guò)鏡像創(chuàng)建并啟動(dòng)容器
docker run -d -p 28080:28080 -p 9001:9001 distribute-img
啟動(dòng)成功后通過(guò)dockercontainer ls -a可以看到一個(gè)容器正在運(yùn)行。這個(gè)容器的IMAGE是distribute-img ,command是 "/bin/sh -c 'java -c…”,STATUS 是 Up xxx seconds,PORTS映射關(guān)系是0.0.0.0:9001->9001/tcp, 0.0.0.0:28080->28080/tcp。注意這個(gè)容器的配置方式會(huì)使得pid1 是sh而不是Java進(jìn)程。
如果修改為如下的寫(xiě)法,pid 1就會(huì)是java進(jìn)程,住下這中用法指令的參數(shù)里不能有 $JAVA_HOME 這種環(huán)境變量,因?yàn)槭菦](méi)辦法識(shí)別的。而且指令參數(shù)要?jiǎng)澐值暮芗?xì),是實(shí)際使用時(shí)如果將”cp部分寫(xiě)成”-cp ./classes:./lib/*:/docker-java-home/lib/tools.jar:./test-classes",進(jìn)程是不能正常起來(lái)的。
CMD ["java","-cp","./classes:./lib/*:/docker-java-home/lib/tools.jar:./test-classes","com.dd.http.server.WebServer","--config","config-test.json","--env","test","distribute","> /dev/null","2>&1"]
第二種方法(有本地日志以及文件產(chǎn)生的推薦此種方式)
項(xiàng)目文件放在鏡像和容器外。
具體做法是在宿主機(jī)新建一個(gè)目錄,然后用run新建和啟動(dòng)容器時(shí)將這個(gè)目錄掛載為數(shù)據(jù)卷。
首先修改第一種方法中的Dockerfile改為如下
FROM openjdk:8
ENV TZ=Asia/Shanghai
EXPOSE 28080 9001
WORKDIR /home/volume/distribute/
CMD java -cp ./classes:./lib/*:$JAVA_HOME/lib/tools.jar:./test-classes com.dd.http.server.WebServer --config config-test.json --env test distribute > /dev/null 2>&1
主要是去除了移動(dòng)程序文件進(jìn)入鏡像并解壓的操作
然后通過(guò)build指令構(gòu)建鏡像
docker build -t distribute-img-volume1 .
通過(guò)鏡像創(chuàng)建并啟動(dòng)容器,注意在這個(gè)步驟綁定了外部目錄作為數(shù)據(jù)盤(pán)
docker run -d -p 28080:28080 -p 9001:9001? --mount type=bind,source=/Users/workandstudy/14_docker/01_distribute_volume1/volume,target=/home/volume distribute-img-volume1
應(yīng)用就運(yùn)行起來(lái)了,可以通過(guò)docker container ls -a查看
這個(gè)時(shí)候在宿主機(jī)或者容器里操作這個(gè)文件夾,任何變更都可以實(shí)時(shí)雙向體現(xiàn)。
數(shù)據(jù)卷還有一種建立方式,就是先建立一個(gè)獨(dú)立的docker數(shù)據(jù)卷,然后在docker run指令掛載到新建的容器,這種方式比較復(fù)雜,在建立獨(dú)立數(shù)據(jù)卷部分以后再做探討。
上述操作用到的主要指令
搜索公版鏡像,如搜索openjdk的公版鏡像
docker search openjdk
查看容器列表
docker container ls -a
查看容器的操作日志
docker logs -t --since="2018-02-08T13:23:37" --until "2018-02-09T12:23:37” CONTAINER_ID
docker logs -t --since="2018-02-08T13:23:37" CONTAINER_ID
啟動(dòng)已有容器
docker container start CONTAINER_ID
對(duì)于不做修改直接建立容器無(wú)法持續(xù)運(yùn)行的鏡像比如openjdk,可以通過(guò)如下指令建立容器觀察其結(jié)構(gòu),openjdk:8是鏡像的名字版本
docker run -it openjdk:8? /bin/bash
已經(jīng)啟動(dòng)的容器直接進(jìn)入容器的shell
docker exec -it CONTAINER_ID bash
查看數(shù)據(jù)卷列表
docker volume ls
Java程序的資源控制
docker run指令建立啟動(dòng)容器時(shí)可以通過(guò) --cpus 1 -m 1G 控制cpu和內(nèi)存資源,但是容器里的jvm在10之前還是會(huì)只感知到宿主機(jī)的資源限制,所以需要jdk10之前要做一些額外的jvm配置參數(shù)。詳細(xì)資料如下
http://www.concurrent.work/docker/java/jvm/gc/pitfalls-about-running-java-inside-container/
建立獨(dú)立數(shù)據(jù)卷
建立數(shù)據(jù)卷時(shí)用下面的命令構(gòu)建一個(gè)數(shù)據(jù)卷,但這個(gè)指令無(wú)法指定數(shù)據(jù)卷的掛載位置,不太好用。
docker volume create distribute_volume1
用下面的指令查看數(shù)據(jù)卷信息,發(fā)現(xiàn)有個(gè)配置是 "Mountpoint": "/var/lib/docker/volumes/distribute_volume1/_data”,但這個(gè)目錄無(wú)法在宿主機(jī)直接訪問(wèn),不存在,即是數(shù)據(jù)卷掛在到機(jī)器中并且在里面建立了文件還是沒(méi)東西,后面需要進(jìn)一步了解這種用法
docker volume inspect distribute_volume1
總結(jié)
以上是Docker的本地用法,兩種方式里面,如果程序是無(wú)狀態(tài)的,推薦使用第一種方式,每次修改后重新構(gòu)建鏡像發(fā)布;而程序會(huì)產(chǎn)生本地日志和文件的,推薦用第二種方法。Docker的使用對(duì)開(kāi)發(fā)和運(yùn)維人員工作量有一定增加,很多無(wú)docker時(shí)很簡(jiǎn)單的操作會(huì)麻煩很多。它優(yōu)勢(shì)在于大規(guī)模分布式部署和管理應(yīng)用,隔離應(yīng)用并管理資源使用。Docker實(shí)際使用中還需要有一些額外工具的輔助,比如Kubernetes或者Docker Compose等快速分部署的工具,在后續(xù)的文章中再做詳細(xì)介紹。