基礎學習資料
Docker比較完整和詳細的指令? https://yeasy.gitbooks.io/docker_practice/network/port_mapping.html
Dockerfile 中的 CMD 與 ENTRYPOINT區(qū)別詳細說明清寇,建議看完通篇文章后再看 https://www.cnblogs.com/sparkdev/p/8461576.html
官方文檔https://docs.docker.com/engine/reference/builder/
docker的定位证舟,它本質(zhì)上是一個輕量級的虛擬機酗洒,但是實際應用中說是 進程的容器工具 更貼切。創(chuàng)建一個容器當做虛擬系統(tǒng)來使用凛忿,然后再里面部署多個應用程序澈灼,不是docker推薦的用法。因為docker的主要優(yōu)點是如下兩點
輕量級的資源隔離
簡潔一致的部署環(huán)境
為了盡量發(fā)揮優(yōu)點,所以應該每個容器運行一個應用叁熔,一般是只有一個進程委乌,單一功能。比如證券交易系統(tǒng)有資金者疤、交易福澡、用戶系統(tǒng),各對應一個項目驹马,應該部署到不同的容器。一個應用如果有多個進程除秀,盡量分開部署到不同容器實例糯累。如果應用要部署一個網(wǎng)關nginx做反向代理,部署到應用的容器里還勉強合理册踩。
接著要理解docker的重要概念
鏡像和容器
鏡像和容器的關系類似于虛擬機(比如VM或Virtual Box)的系統(tǒng)鏡像和系統(tǒng)實例泳姐,鏡像是容器的構(gòu)建基礎,容器是鏡像的實例暂吉∨置耄基于鏡像建立容器后可以做很多定制化的修改,而且也可以把修改后的容器再保存為新的鏡像慕的。
有兩種方式可以部署一個有自己的程序的docker容器阎肝,首先我們先做一些基礎操作
準備工作
首先根據(jù)上面的第一個資料鏈接安裝好docker,這部分不詳述肮街。
然后通過docker search openjdk指令搜索openjdk的公開鏡像风题,取第一個star最多的
接著通過 docker pull openjdk:8 將jdk版本為8的openjdk鏡像拉取到本地
通過指令docker images 可以查看到是否已經(jīng)拉取到鏡像
第一種方法
直接將項目文件放在鏡像里,然后每次構(gòu)建帶有最新項目文件的新的鏡像嫉父,并根據(jù)鏡像建立新的容器沛硅。
下面通過Dockerfile構(gòu)建定制鏡像,新建一個目錄绕辖,新建名為Dockerfile的文件摇肌,寫入定制化配置
示例:
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)有很多基礎鏡像仪际,包括redis围小、mysql、jdk弟头、openjdk吩抓,我們基于這些鏡像作進一步的定制化即可。
ENV 一行是配置時區(qū)為上海
Run是在鏡像里執(zhí)行指令赴恨,比如一些前置的指令建立文件夾疹娶,安裝工具等。比如用RUN apt-get update和RUN apt-get-y install vim可以安裝vim到鏡像里
COPY 是將主機目錄里的文件復制到鏡像中
EXPOSE 是聲明鏡像后期需要暴露的端口伦连,僅僅起到聲明作用
WORKDIR 設定后續(xù)指令工作目錄雨饺,因為鏡像構(gòu)建配置這里的指令都是無狀態(tài)的钳垮,無法繼承前一條指令的狀態(tài)如執(zhí)行目錄
CMD 設定啟動指令,有兩種方式额港,shell方式饺窿,如CMD top -a ;以及 exec方式移斩,如CMD? ["top”,”-a”] 肚医。兩者區(qū)別是最終在容器執(zhí)行的指令為 /bin/sh -c top -a 和 top -a。其中前者會導致sh才是容器的1號進程向瓷。
然后通過build指令構(gòu)建鏡像肠套,下面指令最后的點號是根據(jù)本目錄進行構(gòu)建的意思
docker build -t distribute-img .
執(zhí)行后通過docker images 發(fā)現(xiàn)得到了一個名為distribute-img的鏡像,如果是執(zhí)行成功猖任,執(zhí)行過程中會有一些中間容器生成你稚,并被刪掉,如果完全成功只會有鏡像不會有中間容器被留下來朱躺。
通過鏡像創(chuàng)建并啟動容器
docker run -d -p 28080:28080 -p 9001:9001 distribute-img
啟動成功后通過dockercontainer ls -a可以看到一個容器正在運行刁赖。這個容器的IMAGE是distribute-img ,command是 "/bin/sh -c 'java -c…”长搀,STATUS 是 Up xxx seconds宇弛,PORTS映射關系是0.0.0.0:9001->9001/tcp, 0.0.0.0:28080->28080/tcp。注意這個容器的配置方式會使得pid1 是sh而不是Java進程盈滴。
如果修改為如下的寫法涯肩,pid 1就會是java進程,住下這中用法指令的參數(shù)里不能有 $JAVA_HOME 這種環(huán)境變量,因為是沒辦法識別的巢钓。而且指令參數(shù)要劃分的很細病苗,是實際使用時如果將”cp部分寫成”-cp ./classes:./lib/*:/docker-java-home/lib/tools.jar:./test-classes",進程是不能正常起來的症汹。
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)生的推薦此種方式)
項目文件放在鏡像和容器外硫朦。
具體做法是在宿主機新建一個目錄,然后用run新建和啟動容器時將這個目錄掛載為數(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
主要是去除了移動程序文件進入鏡像并解壓的操作
然后通過build指令構(gòu)建鏡像
docker build -t distribute-img-volume1 .
通過鏡像創(chuàng)建并啟動容器,注意在這個步驟綁定了外部目錄作為數(shù)據(jù)盤
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
應用就運行起來了咬展,可以通過docker container ls -a查看
這個時候在宿主機或者容器里操作這個文件夾,任何變更都可以實時雙向體現(xiàn)瞒斩。
數(shù)據(jù)卷還有一種建立方式破婆,就是先建立一個獨立的docker數(shù)據(jù)卷,然后在docker run指令掛載到新建的容器胸囱,這種方式比較復雜祷舀,在建立獨立數(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
啟動已有容器
docker container start CONTAINER_ID
對于不做修改直接建立容器無法持續(xù)運行的鏡像比如openjdk,可以通過如下指令建立容器觀察其結(jié)構(gòu)裳扯,openjdk:8是鏡像的名字版本
docker run -it openjdk:8? /bin/bash
已經(jīng)啟動的容器直接進入容器的shell
docker exec -it CONTAINER_ID bash
查看數(shù)據(jù)卷列表
docker volume ls
Java程序的資源控制
docker run指令建立啟動容器時可以通過 --cpus 1 -m 1G 控制cpu和內(nèi)存資源抛丽,但是容器里的jvm在10之前還是會只感知到宿主機的資源限制,所以需要jdk10之前要做一些額外的jvm配置參數(shù)饰豺。詳細資料如下
http://www.concurrent.work/docker/java/jvm/gc/pitfalls-about-running-java-inside-container/
建立獨立數(shù)據(jù)卷
建立數(shù)據(jù)卷時用下面的命令構(gòu)建一個數(shù)據(jù)卷亿鲜,但這個指令無法指定數(shù)據(jù)卷的掛載位置,不太好用冤吨。
docker volume create distribute_volume1
用下面的指令查看數(shù)據(jù)卷信息蒿柳,發(fā)現(xiàn)有個配置是 "Mountpoint": "/var/lib/docker/volumes/distribute_volume1/_data”,但這個目錄無法在宿主機直接訪問,不存在锅很,即是數(shù)據(jù)卷掛在到機器中并且在里面建立了文件還是沒東西其馏,后面需要進一步了解這種用法
docker volume inspect distribute_volume1
總結(jié)
以上是Docker的本地用法,兩種方式里面爆安,如果程序是無狀態(tài)的,推薦使用第一種方式仔引,每次修改后重新構(gòu)建鏡像發(fā)布扔仓;而程序會產(chǎn)生本地日志和文件的,推薦用第二種方法咖耘。Docker的使用對開發(fā)和運維人員工作量有一定增加翘簇,很多無docker時很簡單的操作會麻煩很多。它優(yōu)勢在于大規(guī)模分布式部署和管理應用儿倒,隔離應用并管理資源使用版保。Docker實際使用中還需要有一些額外工具的輔助,比如Kubernetes或者Docker Compose等快速分部署的工具夫否,在后續(xù)的文章中再做詳細介紹彻犁。