Docker-核心筆記(含Dockerfile,Compose)
2017/03 Chenxin
參考
https://yeasy.gitbooks.io/docker_practice Docker入門與實踐 電子書,截止201807一直在更新.
http://guide.daocloud.io/dcs/daocloud-services-9152632.html Docker加速器
https://blog.csdn.net/S_gy_Zetrov/article/details/78161154 入門
http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html
http://www.ruanyifeng.com/blog/2018/02/docker-wordpress-tutorial.html
命令自動補全(不屬於docker內容)
安裝(僅支持較新的linux版本)
yum install bash-completion
說明(可以忽略)
最小化安裝centos7需要安裝一個 bash-completion 包,然后退出 bash,重新登錄即可.
bash-2.05及以后的版本提供了自動補齊的編程接口.
bash-completion的安裝已加入Centos7初始化腳本.
常用指令匯總
yum install docker # 安裝
docker version
docker info
docker search centos
docker pull centos:latest
docker image ls --all
docker image rmi image_id # 刪除
docker image save image_id -o centosvim.tar # 輸出一個tar格式的
docker image load -i centosvim.tar # 載入一個tar格式的
docker image tag image_id centosvim:1.0
docker image inspect image_id #獲取鏡像元數據
docker container ls --all
docker container attach container_id # ctrl+p, ctrl+q 將容器推到后台后,推薦使用exec方式進入,防止退出的時候錯誤的將容器終止了(Ctrl+d)
docker container exec -it container_id /bin/bash # 推薦
docker container exec -it --user root container_id /bin/bash #登陸容器,並成為root
docker container run -it --name container_name image_id /bin/bash #啟動一個容器
docker container run -d -p 1022:80 foo/live /bin/bash #物理機的1022映射到docker的80;
docker container run -d -p 127.0.0.2:8080:80 --rm --name wordpress --env WORDPRESS_DB_PASSWORD=123456 --link wordpressdb:mysql --volume "$PWD/wordpress":/var/www/html wordpress
docker container run -p 1022:80 -it centos:lastest /bin/bash
docker container port container_id
docker container inspect container_id #獲取容器元數據
docker container cp container_id:[/path/to/file] /local/path/dir/
docker container commit -m "centos with vim" -a "chenxin" container_id chenxin/centos:vim
docker container rm container_id
docker container prune #刪除所有處於stop狀態的container
docker container stats container_id #顯示當前運行的這個容器資源占用情況(CPU/MEM/NET/IO/PIDS)
docker container top container_id #顯示容器中當前運行的pid信息
docker container start container_id
docker container stop container_id
ctrl+p ctrl+q # 容器正常運行,用戶臨時退出bash
exit / ctrl+d # 用戶退出,可能導致容器stop
docker diff container_id # 查看容器存儲層改動記錄
docker history image_id # 查看image內的歷史記錄(每層改動情況)
docker build -t xbzj . # 使用Dockerfile構建鏡像
用戶權限
普通用戶執行docker指令需要的權限
xbzj賬號執行 docker search java
報錯Got permission denied while trying to connect to the Docker daemon socket at ...permission denied
將xbzj加入到docker用戶組就可以了: usermod -G docker xbzj
安裝部署/目錄說明/啟停方式
網絡說明
因大陸訪問海外download.docker.com存在網絡問題.可以使用rpm方式安裝.之后可以使用大陸第三方提供的Docker庫(比如阿里雲,或daocloud)
AWS上本身有docker庫,可以直接yum安裝.如果增加yum源安裝官網版本,需要解決一些依賴問題.
建議采取yum方式安裝(AWS默認的yum源)
docker分為社區版(ce)和企業版(ee收費)
官方安裝文檔 https://docs.docker.com/install/linux/docker-ce/centos/#uninstall-old-versions
yum安裝方式
a.配置yum倉庫(aws不需此步驟)
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
ls /etc/yum.repos.d/
amzn-main.repo docker-ce.repo
b.正式安裝
yum install docker-ce
這里會報依賴錯誤.可以自行解決.或使用AWS自身的yum源(推薦)
yum install docker (aws只需要這一步就可以了)
rpm安裝方式
https://download.docker.com/linux/centos/7/x86_64/stable/Packages/
https://download.docker.com/
rpm安裝完成后,執行rpm -ql docker
/etc/rc.d/init.d/docker #啟動關停狀態查看腳本
/etc/sysconfig/docker #配置文件,可以配置docker的一些目錄信息和日志信息
/etc/sysconfig/docker-storage #文件配置
/etc/udev/rules.d/80-docker.rules
/usr/bin/docker
/usr/bin/docker-containerd
/usr/bin/docker-containerd-shim
/usr/bin/docker-ctr
/usr/bin/docker-init
/usr/bin/docker-proxy
/usr/bin/docker-runc
/usr/bin/dockerd
/usr/share/bash-completion/docker
/usr/share/vim/vimfiles/syntax/dockerfile.vim
/var/lib/docker #主要目錄
安裝完成后的驗證
執行docker version
Client:
Version: 18.03.1-ce #這個是aws自己的版本,是18年03月做的AMI.
docker主要目錄說明
ls /var/lib/docker/
builder containerd containers image network overlay2 plugins runtimes swarm tmp trust volumes
/var/lib/docker/devicemapper/devicemapper/data #用來存儲相關的存儲池數據
/var/lib/docker/devicemapper/devicemapper/metadata #用來存儲相關的元數據。
/var/lib/docker/devicemapper/metadata/ #用來存儲 device_id、大小、以及傳輸_id、初始化信息
/var/lib/docker/devicemapper/mnt #用來存儲掛載信息
/var/lib/docker/container/ #用來存儲容器信息
/var/lib/docker/graph/ #用來存儲鏡像中間件及本身詳細信息和大小 、以及依賴信息
/var/lib/docker/repositores-devicemapper #用來存儲鏡像基本信息
/var/lib/docker/tmp #docker臨時目錄
/var/lib/docker/trust #docker信任目錄
/var/lib/docker/volumes #docker卷目錄
docker啟停
service docker start 或者 systemctl start docker
鏡像與源站說明
查詢鏡像
docker search centos
拉取
docker pull centos
或者
docker pull centos:latest
會默認放到/var/lib/docker/overlay2/目錄,進入查看如下:
ls /var/lib/docker/overlay2/00...28/diff
bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
目錄和文件內容跟我們安裝系統后的相同(連日志都有了).
鏡像源地址
a.查看鏡像源地址
docker info
b.修改鏡像源地址(2種方式)
1.增加或修改/etc/docker/daemon.json (18.03版本后就沒有這個文件了aws的centos18.03版本.只能新增.1.13版本有這個文件centos7yum安裝)
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]
}
2.修改或新增 /etc/sysconfig/docker,在OPTIONS變量后追加參數
OPTIONS="--default-ulimit nofile=1024:4096 --registry-mirror=https://docker.mirrors.ustc.edu.cn"
修改完成后,重啟docker.經過測試,以上2個地址都可用.
Docker國內源
a.國內源
Docker 官方中國區 https://registry.docker-cn.com
中國科技大學 https://docker.mirrors.ustc.edu.cn
網易 http://hub-mirror.c.163.com
阿里雲 https://pee6w651.mirror.aliyuncs.com
默認docker源: Registry: https://index.docker.io/v1/
b.加速器
需要注冊的加速器使用說明:
登陸阿里雲docker的registry:(需要先注冊阿里雲賬號,在容器鏡像服務里配置registry密碼.將生成的鏡像url復制到docker配置文件里,類似:https://2r6ncmdxli.mirror.aliyuncs.com 的地址.
docker login --username=chenxin6676 registry.cn-shanghai.aliyuncs.com
之后在本地可以push鏡像到阿里雲.
查看docker鏡像版本
查看docker鏡像的版本號TAG,從遠程倉庫拉取自己想要版本的鏡像.需要在docker hub查看
地址如下:https://hub.docker.com/r/library/
進入之后,在頁面左上角搜索框搜索.
點擊 詳情->TAG.
docker pull java:latest
docker指令使用說明
1 查看本地鏡像
docker image ls --all
2 容器啟動參數
docker container run -it --name test image_id /bin/bash
具有自動抓取 image 的功能.如果發現本地沒有指定的 image 文件,就會從倉庫自動抓取.
-t 選項讓Docker分配一個偽終端(pseudo-tty)並綁定到容器的標准輸入上
-i 則讓容器的標准輸入保持打開
--name test:容器的名字叫做test.
docker container run --rm --name wordpress --volume "$PWD/":/var/www/html php:5.6-apache
--rm:停止運行后,自動刪除容器文件.
--volume "$PWD/":/var/www/html:將宿主機當前目錄($PWD變量內容)映射到容器的/var/www/html.
php:5.6-apache : 來源鏡像
docker container run -d --rm --name wordpressdb --env MYSQL_ROOT_PASSWORD=123456 --env MYSQL_DATABASE=wordpress mysql:5.7
-d:容器啟動后,在后台運行.
--env MYSQL_ROOT_PASSWORD=123456:向容器進程傳入一個環境變量MYSQL_ROOT_PASSWORD,該變量會被用作 MySQL 的根密碼.
--env MYSQL_DATABASE=wordpress:向容器進程傳入一個環境變量MYSQL_DATABASE,容器里面的MySQL會根據該變量創建一個數據庫wordpress
mysql:5.7 : 來源鏡像
docker container run -d -p 127.0.0.2:8080:80 --rm --name wordpress --env WORDPRESS_DB_PASSWORD=123456 --link wordpressdb:mysql --volume "$PWD/wordpress":/var/www/html wordpress
-p 127.0.0.2:8080:80:物理機127.0.0.2的8080映射到器的 80 端口.
--link wordpressdb:mysql,表示 wordpress 容器要連到(先前創建的)wordpressdb容器,冒號表示該容器的別名是mysql.
瀏覽器訪問物理機127.0.0.2:8080就能看到 WordPress 的安裝提示了.而且,你在wordpress子目錄下的每次修改,都會反映到容器里面.
最后,終止上面這兩個容器(--rm,容器文件會自動刪除): docker container stop wordpress wordpressdb
docker container run -d -p 10.0.0.10:8080:80 --volume /home/admin/www/:/usr/local/apache2/htdocs --name apache httpd 或者
docker container run -d -p 8080:80 --volume ...xxx...
以上使用一個httpd的鏡像創建一個apache的容器
docker啟動容器的時候,可以指定容器的IP地址,但需要額外配置網絡模式,具體請參考網上資料https://blog.csdn.net/sbxwy/article/details/78962809 .
3 detach容器
如果想讓容器一直運行,而不是停止,可以使用快捷鍵 ctrl+p ctrl+q 退出,此時容器的狀態為Up.
4 attach進入到這個容器
exec方式進入(run的時候沒有指定 -it /bin/bash的)容器
docker container exec -it [containerID] /bin/bash
如果docker run命令運行容器的時候,沒有使用-it參數,就要用這個命令進入容器.一旦進入了容器,就可以在容器的 Shell 執行命令了.
docker container attach container_id # 不推薦此方式.推薦exec方式,因為attach完,直接ctrl+d,容器狀態會變成exited.而exec不會.
5 終止容器(多種方式)
在容器內,使用 exit,命令退出,則容器的狀態處於Exit,而不是后台運行.
或者 docker container stop [containID]
或者 docker container kill [containID]
6 查看當前運行的容器/已停止的容器
docker container ls 同 docker ps (查看正在run中的容器)
docker container ls --all 同 docker ps -a 查看所有容器,包括停止的(Exited狀態)
docker container rm `docker container ls -aq` 只列出docker container的id,並刪除掉所有container.
7 啟動、停止、重啟容器
docker container start ca5b2982c795 #[containID]
docker container stop ca5b2982c795
docker container restart ca5b2982c795
docker stop $(docker ps -aq) 停止所有的容器
8 與宿主機間對拷文件
docker container cp [containID]:[/path/to/file] /local/path/dir/ # 拷貝容器內文件到物理機上
9 commit指令
commit利用container創建image.
應用場合,比如被入侵后保存現場等。但是,不要使用 docker commit 定制鏡像,定制鏡像應該使用 Dockerfile 來完成。
docker container commit -m "centos with vim" -a "chenxin" container_id chenxin/centos:vim
-m指定說明信息;
-a指定用戶信息;
ca5b2982c795代表容器的id;
chenxin/centos:vim指定目標鏡像的用戶名、倉庫名和 tag 信息.
查看我們剛剛創建鏡像對應生成的文件
/var/lib/docker/image/overlay2/imagedb/metadata/sha256/38...348/ 這里是lastUpdated和parent的2個文本文件說明(起源於哪個鏡像).
/var/lib/docker/image/overlay2/imagedb/content/sha256/38...348 這個文本文件詳細說明了這個鏡像的配置信息
10 刪除 容器/鏡像
刪除單個容器 docker container rm [containerID] (非運行狀態的才允許刪除,否則請先docker stop/kill)
刪除全部容器 docker container rm `docker container ls -aq` 或 docker container rm `docker ps -aq`
刪除單個鏡像 docker image rmi image_id
刪除所有鏡像 docker image rmi `docker image ls -aq`
刪除所有在 mongo:3.2 之前的鏡像:docker image rmi $(docker image ls -q -f before=mongo:3.2) # -f為filter.
刪除一個運行中的容器,可以添加 -f 參數 docker container rm -f myweb
刪除所有處於終止狀態的容器 docker container prune
docker rm : 刪除一個或多個 容器
docker rmi : 刪除一個或多個 鏡像
docker prune: 用來刪除不再使用的 docker 對象
11 將image導出后再導入其他裝了docker的機器
docker image save image_id -o centosvim.tar #如何將自己的image硬拷貝
docker image load -i centosvim.tar #將tar文件拷貝到其他機器后,執行導入image
docker image tag 38f309423638 centosvim:1.0 #上面的REPOSITORY/TAG都是none,那么可以tag
12 push自己的image到第三方倉庫(aws)
a.將自己的image給push到docker官方的hub
這里需要到官方注冊賬號才行.需要先登錄 docker login;然后 docker push chenxin/centos:vim .這樣以后可以通過自己的賬號可以從官網pull下來自己的image.
b.將image給push到aws的ECR(ERS)
docker build -t xbzj . # 首先本地構建鏡像,以xbzj為例
aws ecr get-login --no-include-email --region ap-southeast-1 #執行awscli指令獲取登陸ECR命令
docker login -u AWS -p eyJwY...M30= https://61..9551.dkr.ecr.a..t-1.amazonaws.com #根據上條命令輸出登陸token,登陸完成.
docker tag xbzj:latest 61..51.dkr.ecr.ap-southeast-1.amazonaws.com/xbzj:latest #對image打TAG
docker push 615..51.dkr.ecr.ap-southeast-1.amazonaws.com/xbzj:latest #將本地image給PUSH到ECR
13 端口映射NAT
docker啟動服務,開啟端口,如何映像到外部的IP和端口,從而對外提供服務(2種方式).
容器中啟動的服務,可以通過宿主機直接訪問(route物理機會看到172.17.0.0的路由docker0),但外部機器無法訪問,那么就需要將docker端口映射到宿主機端口上.
查看物理機路由表,執行
# route
Destination Gateway Genmask Flags Metric Ref Use Iface
172.17.0.0 * 255.255.0.0 U 0 0 0 docker0
2種方式,如下:
1.通過容器指令(推薦)
docker container run -d -p 1022:80 foo/live /bin/bash #物理機的1022映射到docker的80;
docker container run -p 1022:80 -it centos:lastest /bin/bash #將物理機的1022端口映射docker的80端口
docker container run -d -p 10.0.0.10:1022:80 --volume /home/admin/www/:/usr/local/apache2/htdocs --name apache httpd # 指定了映射到哪個物理網卡
docker container run -d -P image_id #這里的大寫P,會將物理機隨機1個端口映射到Dockfile文件EXPOSE聲明的端口上.
2.通過iptables的映射
docker inspect container_id |grep IPAddress ->172.17.0.2
iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination 172.17.0.2:8000 # 將物理機的8001映射到容器的8000.
進入docker container里,啟動httpd服務,並netstat檢查:/usr/sbin/httpd
檢查物理機端口開放:
tcp 0 0 :::8000 :::* LISTEN 14066/docker-proxy
14 容器的 volume 子命令 (或 -v)
docker專門提供了volume子命令來操作數據卷:
create 創建數據卷
inspect 顯示數據卷的詳細信息
ls 列出所有的數據卷
prune 刪除所有未使用的 volumes,並且有 -f 選項
rm 刪除一個或多個未使用的 volumes,並且有 -f 選項
15 關於容器和鏡像的掛載卷說明
一.通過docker run命令.在docker run后的 -v 指令(只對創建的容器有效)
1、運行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash -> 主機上的 /home/xqh/myimage 目錄中的內容關聯到 容器中設置了一個掛載點 /data.在容器還是主機上操作它,都是完全實時同步的(實際指向的物理空間完全相同).
2、運行命令:docker run --name test1 -it -v /data ubuntu /bin/bash ->docker會自動綁定主機上的一個目錄到容器的/data上。(其目的不是讓在主機上修改,而是讓多個容器共享。)
二.通過dockerfile創建鏡像聲明的掛載點.
通過dockerfile的 VOLUME 方式對鏡像有效.(在鏡像中創建掛載點).與容器-v參數相比,有一個區別是,通過 VOLUME 指令創建的掛載點,無法指定主機上對應的目錄,是自動生成的。
FROM ubuntu
MAINTAINER hello1
VOLUME ["/data1","/data2"]
上面的dockfile文件通過VOLUME指令指定了兩個掛載點 /data1 和 /data2. 如果用此鏡像創建容器,則容器中的/data1和/data2是隨機掛載的物理主機上的目錄.
三.容器共享卷(掛載點) --volumes-from (會將原容器的dockerfile中聲明的數據卷共享到自己這個容器上來,以便保持這個目錄與原容器的一致)
docker run --name test1 -it myimage /bin/bash #myimage是用前面的dockerfile文件構建的鏡像。 這樣容器test1就有了 /data1 和 /data2兩個掛載點。
下面我們創建其他容器可以和test1共享 /data1 和 /data2卷 ,在 docker run中使用 --volumes-from標記,如:
來源不同鏡像,如:docker run --name test2 -it --volumes-from test1 ubuntu /bin/bash
來源相同鏡像,如:docker run --name test3 -it --volumes-from test1 myimage /bin/bash
上面的三個容器 test1 , test2 , test3 均有 /data1 和 /data2 兩個目錄,且目錄中內容是共享的,任何一個容器修改了內容,別的容器都能獲取到。
四.最佳實踐:數據容器
如果多個容器需要共享數據(如持久化數據庫、配置文件或者數據文件等),可以考慮創建一個特定的數據容器,該容器有1個或多個卷。其它容器通過--volumes-from 來共享這個數據容器的卷。
因為容器的卷本質上對應主機上的目錄,所以這個數據容器也不需要啟動。如: docker run --name dbdata myimage echo "data container"
說明:有個卷,容器之間的數據共享比較方便,但也有很多問題需要解決,如權限控制、數據的備份、卷的刪除等。這些內容以后介紹。
16 對比 mount 掛載數據卷 方式 的說明
之前我們使用 --volume(-v) 選項來掛載數據卷,現在 docker 提供了更強大的 --mount 選項來管理數據卷。mount 選項可以通過逗號分隔的多個鍵值對一次提供多個配置項,因此 mount 選項可以提供比 volume 選項更詳細的配置。使用 mount 選項的常用配置如下:
type 指定掛載方式,我們這里用到的是 volume,其實還可以有 bind 和 tmpfs。
volume-driver 指定掛載數據卷的驅動程序,默認值是 local。
source 指定掛載源,對於一個命名的數據卷,這里應該指定這個數據卷的名稱.在使用時可以寫source,也可以簡寫為 src
destination 指定掛載的數據在容器中的路徑。在使用時可以寫 destination,也可以簡寫為 dst 或 target。
readonly 指定掛載的數據為只讀。
volume-opt 可以指定多次,用來提供更多的 mount 相關的配置。
下面我們看個具體的例子:
$ docker volume create hello
$ docker run -id --mount type=volume,source=hello,target=/world ubuntu /bin/bash
我們創建了名稱為 hello 的數據卷,然后把它掛在到容器中的 /world 目錄。通過 inspect 命令查看容器的詳情中的 "Mounts" 信息可以驗證.
使用 volume driver 把數據存儲到其它地方
除了默認的把數據卷中的數據存儲在宿主機,docker 還允許我們通過指定 volume driver 的方式把數據卷中的數據存儲在其它的地方,比如 AWS 的 S3。
簡單起見,我們接下來的 demo 演示如何通過 vieux/sshfs 驅動把數據卷的存儲在其它的主機上。
docker 默認是不安裝 vieux/sshfs 插件的,我們可以通過下面的命令進行安裝:
$ docker plugin install --grant-all-permissions vieux/sshfs
然后通過 vieux/sshfs 驅動創建數據卷,並指定遠程主機的登錄用戶名、密碼和數據存放目錄:
docker volume create --driver vieux/sshfs \
-o sshcmd=nick@10.32.2.134:/home/nick/sshvolume \
-o password=yourpassword \
mysshvolume
注意,請確保你指定的遠程主機上的掛載點目錄是存在的(demo 中是 /home/nick/sshvolume 目錄),否則在啟動容器時會報錯。
最后在啟動容器時指定掛載這個數據卷:
docker run -id \
--name testcon \
--mount type=volume,volume-driver=vieux/sshfs,source=mysshvolume,target=/world \
ubuntu /bin/bash
這就搞定了,你在容器中 /world 目錄下操作的文件都存儲在遠程主機的 /home/nick/sshvolume 目錄中。進入容器 testcon 然后在 /world 目錄中創建一個文件,然后打開遠程主機的 /home/nick/sshvolume 目錄進行查看,你新建的文件是不是已經出現在那里了!
17 物理機與運行中的容器 數據的覆蓋問題
以物理機器下的卷優先,以有數據的優先.
- 如果掛載一個空的數據卷到容器中的一個非空目錄中,那么這個目錄下的文件會被復制到數據卷中。
- 如果掛載一個非空的數據卷到容器中的一個目錄中,如果容器目錄中原先有數據,那么容器中原始數據會被隱藏掉.
這兩個規則都非常重要,靈活利用第一個規則可以幫助我們初始化數據卷(物理設備)中的內容。掌握第二個規則可以保證掛載數據卷后的數據總是你期望的結果。
在 Dockerfile 中添加數據卷(鏡像里的數據卷聲明)(請參考本筆記 "Dockerfile編寫" )
18 查看輸出和日志(重要,常用)
docker container logs [container-id/names] # 獲取容器的輸出信息(類似控制台輸出等)
docker container logs service-match|tail -n 100
19 控制容器占用系統資源(CPU,內存)
docker create 或者 docker run 的時候
-c|–cpu-shares[=0]參數來調整同期使用CPU的權重.
-m|–memory參數來調整容器使用內存的大小.
如何創建docker的私有倉庫 即 Docker Registry 搭建
1.從官方pull一個registery的鏡像,通過該鏡像與物理機本地文件做好 --volume
2.修改物理機的鏡像源站地址
可以參考
https://cloud.tencent.com/developer/article/1015137
https://juejin.im/post/5a4ac6806fb9a045104ad7c8
其他概念
倉庫(Repository) 是存放一組關聯鏡像的集合,比如同一個應用的不同版本的鏡像,
注冊服務器(Registry) 是存放實際的鏡像的地方,
注冊索引(Index) 則負責維護用戶的賬號,權限,搜索,標簽等管理。
注冊服務器利用注冊索引來實現認證等管理。
如何啟動容器后,服務進程自啟動
構建鏡像
FROM centos-base:latestMAINTAINER artemus717@gmail.com
ENTRYPOINT ["/config/bootstrap.sh"]
CMD ["/bin/bash"]
此處指定了ENTRYPOINT、CMD命令.CMD命令為bash,我們構建的鏡像一定是有bash進程的,有問題可以直接進行排查.
准備bootstrap.sh
在容器內部,編寫腳本,腳本內容直接復制
mkdir /config
mkdir /config/init
vi /config/bootstrap.sh
chmod 755 /config/bootstrap.sh
問題
在你的Dockerfile中
RUN service mysql restart && /tmp/setup.sh
首先,docker鏡像不快照您的運行進程,您的RUN命令只是在docker構建階段運行,您需要指定命令運行時容器開始使用CMD或ENTRYPOINT命令,如 CMD mysql start
其次Docker容器需要進程(最后一個命令)保持運行,否則容器將退出.因此正常的服務mysql啟動命令不能直接在Dockerfile中使用
解決方案:為了保持進程正常運行:
通常方式Dockerfile
使用service命令,並附加非end命令后,像tail -F,如下:
CMD service mysql start && tail -F /var/log/mysql/error.log
或使用前台命令來執行此操作,如下:
CMD /usr/bin/mysqld_safe
能否將腳本放到/etc/rc.local 來實現呢?經過測試,貌似不行,原因應該是執行完后,自動退出了當前shell進程.
docker啟動流程/關閉流程/狀態說明
啟動流程
docker run -it ubuntu /bin/bash 首先系統要有一個docker daemon的后台進程在運行,當剛才這行命令敲下時:
- 檢查本地是否存在指定的鏡像,不存在就從公有倉庫下載
- 利用鏡像創建並啟動一個容器.
- 分配一個文件系統,並在只讀的鏡像層外面掛載一層可讀寫層
- 從宿主主機配置的網橋接口中橋接一個虛擬接口到容器中去
- 從地址池配置一個 ip 地址給容器
- 執行用戶指定的應用程序
- 執行完畢后容器被終止
最后,我們就得到了一個ubuntu的虛擬機,然后就可以進行各種操作了.
關閉流程
docker stop (默認會10秒超時后再kill)或直接docker kill(直接kill -9) .stop的話,會保持現場到磁盤,優雅的關閉.
容器狀態說明
Up 正在運行 Exited 已經停止 Created 已創建未運行
關於持久化
持久化涉及到的外掛數據卷(有狀態,緊耦合類的應用)
默認不掛載外部存儲,則數據會和容器同生共死(違背了計算和數據分離原則),為容器的遷移或者故障恢復制造了麻煩。
所以一般采用-v參數掛外部卷.rm掉舊容器再重新run一個,把-v的卷掛回去就恢復了。
另外-v可以掛多個物理磁盤或者外部存儲,也解決了io瓶頸的問題。
一般設置Volume的場景:
配置文件目錄,數據文件目錄,重要的日至文件目錄.
容器中安裝軟件
- 安裝軟件
需要先apt-get update,這個命令的作用是:同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,這樣才能獲取到最新的軟件包.否則安裝的時候會提示:E: Unable to locate package xxx(如vim)
vim 安裝 apt-get install vim
net-tools工具包 (含netstat route ifconfig mii-tool arp 等) apt-get install net-tools
procps工具包 (含 ps free ) apt-get install procps
rcconf (類似ntsyv,圖形界面配置服務) apt-get install rcconf
update-rc.d (debian默認已安裝,功能類似chkconfig)
iputils-ping (ping功能)
Dockerfile 編寫
201807 Chenxin
參考
docker從入門到實踐(一直更新): https://yeasy.gitbooks.io/docker_practice/image/build.html
Dockerfile實踐: https://www.cnblogs.com/jsonhc/p/7767669.html
xbzj的Dockerfile文件,請參見"k8s筆記內容".
Dockerfile 定制鏡像原理說明
dockerfile概念說明
在空目錄中,創建Dockerfile文件.Dockerfile指令.大小寫不敏感(推薦大寫)
- 示例-Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
- 構建-Dockerfile
docker build -t nginx:v3 . # 這里的"."就是context(鏡像構建上下文) -t指明創建的鏡像名稱
鏡像構建上下文(Context)
docker build 命令最后有一個"."表示當前目錄,這里是指明了上下文路徑(context的路徑),而非指明Dockerfile文件所在路徑.
- docker build 的工作原理
Docker 在運行時分為 Docker 引擎(服務端守護進程)和客戶端工具。Docker 的引擎提供了一組 REST API,被稱為 Docker Remote API,而如 docker 命令這樣的客戶端工具,則是通過這組 API 與 Docker 引擎交互,從而完成各種功能。因此,雖然表面上我們好像是在本機執行各種 docker 功能,但實際上,一切都是使用的遠程調用形式在服務端(Docker 引擎)完成。也因為這種 C/S 設計,讓我們操作遠程服務器的 Docker 引擎變得簡單.
當我們進行鏡像構建的時候,並非所有定制都會通過 RUN 指令完成,經常會需要將一些本地文件復制進鏡像,比如通過 COPY 指令、ADD 指令等。而 docker build 命令構建鏡像,其實並非在本地構建,而是在服務端,也就是 Docker 引擎中構建的。那么在這種C/S的架構中,如何才能讓服務端獲得本地文件呢?
這就引入了上下文的概念。當構建的時候,用戶會指定構建鏡像上下文的路徑,docker build 命令得知這個路徑后,會將路徑下的所有內容打包,然后上傳給 Docker 引擎。這樣 Docker 引擎收到這個上下文包后,展開就會獲得構建鏡像所需的一切文件。
如果在 Dockerfile 中這么寫: COPY ./package.json /app/
這是復制 上下文(context) 目錄下的 package.json。因此,COPY 這類指令中的源文件的路徑都是相對路徑。如果真的需要那些並不在context目錄下的文件,應該將它們復制到context目錄中去。
如果觀察 docker build 輸出,我們其實已經看到了這個發送上下文的過程:
$ docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB ...
一般,應該將 Dockerfile 置於一個空目錄下,或者項目根目錄下。如果該目錄下沒有所需文件,那么應該把所需文件復制一份過來。如果目錄下有些文件不希望構建時傳給 Docker 引擎,那么可以用".dockerignore"(剔除文件列表,不傳遞給 Docker 引擎).
那么為什么會有人誤以為"."是指定 Dockerfile 所在目錄呢?在默認情況下,如果不額外指定 Dockerfile 的話,會將上下文目錄下的名為 Dockerfile 的文件作為 Dockerfile。實際上 Dockerfile 的文件名並不要求必須為 Dockerfile,且並不要求必須位於上下文目錄中,比如可以用
-f ../docker-file.txt
參數指定某個文件作為 Dockerfile。
當然,一般大家習慣性的會使用默認的文件名 Dockerfile,以及會將其置於鏡像構建上下文目錄中。
Dockerfile指令說明
FROM
指定基礎鏡像
LABEL
可選的
RUN
執行命令.制作image過程中執行的事項.每執行1次RUN,就會構建1個臨時image.
其格式有兩種:
* shell 格式:RUN <命令>,就像直接在命令行中輸入的命令一樣.RUN <cmd> 這個會當作/bin/sh -c “cmd” 運行。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
* exec 格式:RUN ["可執行文件", "參數1", "參數2"],這更像是函數調用中的格式。
RUN ["executable", "arg1", .. ],Docker把他當作json的順序來解析,因此必須使用雙引號,而且executable需要完整路徑.
Dockerfile 中每一個指令都會建立一層.很多初學者制作出很臃腫的鏡像原因之一,就是忘記了每一層構建的最后沒有清理掉無關文件.
CMD
執行指令或傳遞參數
執行container時候的默認啟動命令.可能會被覆蓋(比如,當運行container的時候聲明了command,則不再用image中的CMD定義的命令)
一個Dockerfile中定義多個CMD的時候,只有最后一個才會起作用.
CMD定義的三種方式:
CMD <cmd> 這個會當作/bin/sh -c "cmd"來執行 # shell方式
CMD ["executable","arg1",....] # 推薦exec方式
CMD ["arg1","arg2"],這個時候CMD作為ENTRYPOINT的參數
對容器而言,啟動程序就是啟動容器應用進程. 容器就是為了主進程而存在的,主進程退出,容器就失去了存在的意義,從而退出,不會關心輔助進程.
而使用 service nginx start 命令,則是希望用 upstart 方式以后台守護進程形式啟動 nginx 服務。而剛才說了 CMD service nginx start 會被理解為 CMD [ "sh", "-c", "service nginx start"],因此主進程實際上是 sh。那么當 service nginx start 命令結束后,sh 也就結束了,sh 作為主進程退出了,自然就會令容器退出。
正確的做法是直接執行 nginx 可執行文件,並且要求以前台形式運行。比如:
CMD ["nginx", "-g", "daemon off;"]
EXPOSE
聲明端口 EXPOSE <端口1> [<端口2>...]
聲明運行時容器提供服務端口,這只是一個聲明,在運行時並不會因為這個聲明應用就會開啟這個端口的服務。此聲明有兩個好處
1.幫助使用者理解服務的守護端口,以便配置映射.
2.啟動容器時,指定 docker run -P 時,會將EXPOSE 端口映射到物理機的隨機端口.
ENTRYPOINT
當定義了ENTRYPOINT以后,CMD只能夠作為參數進行傳遞.
有2種定義方式:
1.ENTRYPOINT ["executable","arg1","arg2"] (推薦) CMD可以通過json的方式來定義entrypoint的參數,在運行容器的時候可以通過CMD的方式傳遞參數.執行的程序的pid為1.
2.ENTRYPOINT cmd param1 param2 (shell form) 相當於/bin/bash -c "cmd"命令.bash的pid為1.會屏蔽掉docker run時后面加的命令和CMD里的參數.不常用.
示例,第一種,比如:
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
把可能需要變動的參數寫到CMD里面。然后你可以在docker run里指定參數,這樣CMD里的參數(這里是-c)就會被覆蓋掉,而ENTRYPOINT里的不會被覆蓋。
ENTRYPOINT更像是一個可執行程序,而CMD是隨時都可能被覆蓋的命令或傳參.
COPY & ADD
不建議用ADD.
類似於直接在bash里執行的指令是 docker container cp [containID]:[/path/to/file] /local/path/dir/ (容器文件拷貝到物理機).
把host上的文件或者目錄(源文件必須在context路徑下)復制到image中.如果目錄不存在會在復制文件前先行創建缺失目錄.
不建議使用ADD(因為語義模糊,且沒必要)
ADD相對COPY多的功能(支持URL),當src為網絡URL的情況下,ADD指令可以把它下載到dest的指定位置.ADD相對COPY多的功能,能夠進行自動解壓壓縮包.
ENV
ENV
后面的其它指令,如 RUN,還是運行時的應用,都可以直接使用這里定義的環境變量。
WORKDIR
用來改變工作目錄.
比如:
RUN cd /app
RUN echo "hello" > world.txt
這樣做根本不會生成/app/world.txt文件.原因是,每一個 RUN 都是啟動一個容器、執行命令、然后提交存儲層文件變更。第一層 RUN cd /app 的執行僅僅是當前進程的工作目錄變更,一個內存上的變化而已,其結果不會造成任何文件變更。而到第二層的時候,啟動的是一個全新的容器,跟第一層的容器更完全沒關系,自然不可能繼承前一層構建過程中的內存變化。
因此如果需要改變以后各層的工作目錄的位置,那么應該使用 WORKDIR 指令。
USER
改變之后層的執行 RUN, CMD 以及 ENTRYPOINT 這類命令的身份.
擴展知識: 如果以 root 執行的腳本,在執行期間希望改變身份,比如希望以某個已經建立好的用戶來運行某個服務進程,不要使用 su 或者 sudo,這些都需要比較麻煩的配置,而且在 TTY 缺失的環境下經常出錯。建議使用 gosu。
#建立 redis 用戶,並使用 gosu 換另一個用戶執行命令
RUN groupadd -r redis && useradd -r -g redis redis
#下載 gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \
&& chmod +x /usr/local/bin/gosu \
&& gosu nobody true
#設置 CMD,並以另外的用戶執行
CMD [ "exec", "gosu", "redis", "redis-server" ] #exec的說明,執行shell腳本三種方式的區別( sh,bash,xxx.sh / source,. / exec ) 見<<shell bash 技巧說明>>筆記.
VOLUME
Dockerfile中的VOLUME使每次運行一個新的container時,都會為其自動創建一個匿名的volume,並掛載到container指定的目錄里.
應用場景: 用來創建一個在image之外的mount point,可以用來在多個container之間實現數據共享(通過--volumes-from嗎?).
運行使用json array的方式定義多個volume.
VOLUME ["/var/data1","/var/data2"] .
或者plain text的情況下定義多個VOLUME指令.
示例,cat Dockerfile
FROM nginx
#VOLUME ["/home/admin/test"] 或 #VOLUME ["/home/admin/test","home/admin/mynginx"] 或
VOLUME /home/admin/test
在docker container run xxx 的時候,會創建一個匿名volume.比如,物理機上的/var/lib/docker/volumes/99b2...d1/_data -> 容器內的/home/admin/test .
在 Dockerfile 中添加數據卷
在 Dockerfile 中我們可以使用 VOLUME 指令向容器添加數據卷:
VOLUME /data # 這里只跟容器有關,因為為了匹配不同物理機卷環境,所以物理機卷必是匿名卷.
在使用 docker build 命令生成鏡像並且以該鏡像啟動容器時會掛載一個主機數據卷到容器 /data 目錄。根據我們已知的數據覆蓋規則,如果鏡像中存在 /data 目錄,鏡像中的/data目錄的內容將全部被復制到宿主機中對應的目錄中(匿名目錄),並且根據容器中的文件設置合適的權限和所有者。假設在docker run 的時候,添加 -v /data:/data(前一個是物理主機目錄,且有數據,后一個是新啟動容器目錄) ,會發生什么呢?應該會以物理機數據優先吧.
注意,VOLUME 指令不能掛載主機中指定的目錄。這是為了保證 Dockerfile 的一致性,因為不能保證所有的宿主機都有對應的目錄。
在實際的使用中,這里還有一個陷阱需要大家注意:在 Dockerfile 中使用 VOLUME 指令之后的代碼,如果嘗試對這個數據卷進行修改,這些修改都不會生效!下面是一個這樣的例子:
FROM ubuntu
RUN useradd nick
VOLUME /data # 其實把VOLUME當做聲明就可以了,不實際創建卷.這樣理解.
RUN touch /data/test.txt
RUN chown -R nick:nick /data
通過這個 Dockerfile 創建鏡像並啟動容器后,該容器中存在用戶 nick,並且能夠看到 /data 目錄掛載的數據卷。但是 /data 目錄內並沒有文件 test.txt,更別說 test.txt 文件的所有者屬性了。要解釋這個現象需要我們了解通過 Dockerfile 創建鏡像的過程:
Dockerfile 中除了 FROM 指令的每一行都是基於上一行生成的臨時鏡像運行一個容器,執行一條指令並執行類似 docker commit 的命令得到一個新的鏡像。這條類似 docker commit 的命令不會對掛載的數據卷進行保存。
所以上面的 Dockerfile 最后兩行執行時,都會在一個臨時的容器上掛載 /data,並對這個臨時的數據卷進行操作,但是這一行指令執行並提交后,這個臨時的數據卷並沒有被保存。因而我們最終通過鏡像創建的容器所掛載的數據卷是沒有被最后兩條指令操作過的。我們姑且叫它 "Dockerfile 中數據卷的初始化問題"。
下面的寫法可以解決 Dockerfile 中數據卷的初始化問題:
FROM ubuntu
RUN useradd nick
RUN mkdir /data && touch /data/test.txt # 創建了/data目錄
RUN chown -R nick:nick /data
VOLUME /data # 在聲明前,鏡像里已經有/data目錄了,那么會將目錄以及內容復制到啟動的容器匿名目錄里(對應容器的/data目錄).
通過這個 Dockerfile 創建鏡像並啟動容器后,數據卷的初始化是符合預期的。這是由於在掛載數據卷時,/data 已經存在,/data 中的文件以及它們的權限和所有者設置會被復制到數據卷中(被復制到物理主機的匿名卷中,對應的就是新啟動的容器的/data目錄)。
還有另外一種方法可以解決 Dockerfile 中數據卷的初始化問題。就是利用 CMD 指令和 ENTRYPOINT 指令的執行特點:與 RUN 指令在鏡像構建過程中執行不同,CMD 指令和 ENTRYPOINT 指令是在容器啟動時執行。因此使用下面的 Dockerfile 也可以達到對數據卷的初始化目的:
FROM ubuntu
RUN useradd nick
VOLUME /data
CMD touch /data/test.txt && chown -R nick:nick /data && /bin/bash
HEALTHCHECK
健康檢查
ONBUILD:略
如何編寫最佳的Dockerfile(基本為網上內容)
目標:
- 更快的構建速度
- 更小的Docker鏡像大小
- 更少的Docker鏡像層
- 充分利用鏡像緩存
- 增加Dockerfile可讀性
- 讓Docker容器使用起來更簡單
總結(編寫Dockerfile需要注意的問題)
- 編寫.dockerignore文件
- 容器只運行單個應用
- 將多個RUN指令合並為一個
- 基礎鏡像的標簽不要用latest
- 每個RUN指令后刪除多余文件
- 選擇合適的基礎鏡像(alpine版本最好)
- 設置WORKDIR和CMD
- 使用ENTRYPOINT (可選)
- 在entrypoint腳本中使用exec
- COPY與ADD優先使用前者
- 合理調整COPY與RUN的順序
- 設置默認的環境變量,映射端口和數據卷
- 使用LABEL設置鏡像元數據
- 添加HEALTHCHECK
示例
最初示例
示例Dockerfile犯了幾乎所有的錯.假設我們需要使用Docker運行一個Node.js應用,下面就是它的Dockerfile(CMD指令太復雜了,所以我簡化了,它是錯誤的,僅供參考)。
FROM ubuntu
ADD . /app
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y nodejs ssh mysql
RUN cd /app && npm install
# this should start three processes, mysql and ssh
# in the background and node app in foreground
# isn't it beautifully terrible? <3
CMD mysql & sshd & npm start #這里是錯誤的
構建鏡像:
docker build -t wtf .
這里先給出最終示例(對比):
FROM node:7-alpine
ENV PROJECT_DIR=/app
WORKDIR $PROJECT_DIR
COPY package.json $PROJECT_DIR
RUN npm install
COPY . $PROJECT_DIR
ENV MEDIA_DIR=/media \
NODE_ENV=production \
APP_PORT=3000
VOLUME $MEDIA_DIR
EXPOSE $APP_PORT
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
將最初示例逐步進行優化的過程
-
編寫.dockerignore文件
構建鏡像時,Docker需要先准備context ,將所有需要的文件收集到進程中。默認的context包含Dockerfile目錄中的所有文件,但是實際上,我們並不需要.git目錄,node_modules目錄等內容。示例如下:
.git/
node_modules/ -
容器只運行單個應用
因此,我建議大家為每個應用構建單獨的Docker鏡像,然后使用 Docker Compose 運行多個Docker容器。
現在,我從Dockerfile中刪除一些不需要的安裝包,另外,SSH可以用docker exec替代。示例如下:
FROM ubuntu
ADD . /app
RUN apt-get update
RUN apt-get upgrade -y
# we should remove ssh and mysql, and use
# separate container for database
RUN apt-get install -y nodejs # ssh mysql
RUN cd /app && npm install
CMD npm start
-
將多個RUN指令合並為一個
Docker鏡像是分層的.Docker鏡像類似於洋蔥。它們都有很多層。為了修改內層,則需要將外面的層都刪掉。記住這一點的話,其他內容就很好理解了。
現在,我們將所有的RUN指令合並為一個。
記住一點,我們只能將變化頻率一樣的指令合並在一起。將node.js安裝與npm模塊安裝放在一起的話,則每次修改源代碼,都需要重新安裝node.js,這顯然不合適. -
基礎鏡像的標簽不要用latest
當鏡像沒有指定標簽時,將默認使用latest 標簽。當鏡像更新時,latest標簽會指向不同的鏡像,這時構建鏡像有可能失敗。
示例Dockerfile應該使用16.04作為標簽。 -
每個RUN指令后刪除多余文件
假設我們更新了apt-get源,下載,解壓並安裝了一些軟件包,它們都保存在/var/lib/apt/lists/目錄中。但是,運行應用時Docker鏡像中並不需要這些文件。我們最好將它們刪除,因為它會使Docker鏡像變大。
示例Dockerfile中,我們可以刪除/var/lib/apt/lists/目錄中的文件(它們是由apt-get update生成的)。
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y nodejs \
# added lines
&& rm -rf /var/lib/apt/lists/*
ADD . /app
RUN cd /app && npm install
CMD npm start
- 選擇合適的基礎鏡像(alpine版本最好)
在示例中,我們選擇了ubuntu作為基礎鏡像。但是我們只需要運行node程序,有必要使用一個通用的基礎鏡像嗎?node鏡像應該是更好的選擇。
FROM node
...
更好的選擇是alpine版本的node鏡像。alpine是一個極小化的Linux發行版,只有4MB,這讓它非常適合作為基礎鏡像。
FROM node:7-alpine
ADD . /app
RUN cd /app && npm install
CMD npm start
- 設置WORKDIR和 CMD
WORKDIR指令可以設置默認目錄,也就是運行RUN / CMD / ENTRYPOINT指令的地方。
CMD指令可以設置容器創建時執行的默認命令。另外,你應該將命令寫在一個數組中,數組中每個元素為命令的每個單詞.
FROM node:7-alpine
WORKDIR /app
ADD . /app
RUN npm install
CMD ["npm", "start"]
- 使用ENTRYPOINT (可選)
ENTRYPOINT指令並不是必須的,因為它會增加復雜度。
ENTRYPOINT可以是一個腳本,會默認執行。它通常用於構建可執行的Docker鏡像。
示例Dockerfile:
FROM node:7-alpine
WORKDIR /app
ADD . /app
RUN npm install
ENTRYPOINT ["./entrypoint.sh"] #該腳本可以接受dev,start,*等參數.
CMD ["start"]
可以使用如下命令運行該鏡像:
# 運行開發版本 docker run our-app dev
# 運行生產版本 docker run our-app start
# 運行bash版本 docker run -it our-app /bin/bash
-
在entrypoint腳本中使用exec
在前文的entrypoint腳本中,我使用了exec命令運行node應用。不使用exec的話,我們則不能順利地關閉容器,因為SIGTERM信號會被bash腳本進程吞沒。exec命令啟動的進程可以取代腳本進程,因此所有的信號都會正常工作。 -
COPY與ADD優先使用前者
COPY指令非常簡單,僅用於將文件拷貝到鏡像中。ADD相對來講復雜一些,可以用於下載遠程文件以及解壓壓縮包.
FROM node:7-alpine
WORKDIR /app
COPY . /app
RUN npm install
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
- 合理調整COPY與RUN的順序
我們應該把變化最少的部分放在Dockerfile的前面,這樣可以充分利用鏡像緩存。
示例中,源代碼會經常變化,則每次構建鏡像時都需要重新安裝NPM模塊,這顯然不是我們希望看到的。因此我們可以先拷貝package.json,然后安裝NPM模塊,最后才拷貝其余的源代碼。這樣的話,即使源代碼變化,也不需要重新安裝NPM模塊。
FROM node:7-alpine
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
- 設置默認的環境變量,映射端口和數據卷(相對於上面的11項,這里比較完整歸納了上面遇到的問題)
運行Docker容器時很可能需要一些環境變量。在Dockerfile設置默認的環境變量是一種很好的方式。
另外,我們應該在Dockerfile中設置映射端口和數據卷。
示例如下:
FROM node:7-alpine
ENV PROJECT_DIR=/app
WORKDIR $PROJECT_DIR
COPY package.json $PROJECT_DIR
RUN npm install
COPY . $PROJECT_DIR
ENV MEDIA_DIR=/media \
NODE_ENV=production \
APP_PORT=3000
VOLUME $MEDIA_DIR
EXPOSE $APP_PORT
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
ENV指令指定的環境變量在容器中可以使用。如果你只是需要指定構建鏡像時的變量,你可以使用ARG指令。
-
使用LABEL設置鏡像元數據
使用LABEL指令,可以為鏡像設置元數據,例如鏡像創建者或者鏡像說明。
舊版的Dockerfile語法使用MAINTAINER指令指定鏡像創建者,但是它已經被棄用了。
有時,一些外部程序需要用到鏡像的元數據,例如nvidia-docker需要用到com.nvidia.volumes.needed。
示例如下:
FROM node:7-alpine
LABEL maintainer "jakub.skalecki@example.com"
... -
添加HEALTHCHECK
運行容器時,可以指定--restart always選項。這樣的話,容器崩潰時,Docker守護進程(docker daemon)會重啟容器。對於需要長時間運行的容器,這個選項非常有用。但是,如果容器的確在運行,但是不可(陷入死循環,配置錯誤)用怎么辦?使用HEALTHCHECK指令可以讓Docker周期性的檢查容器的健康狀況。我們只需要指定一個命令,如果一切正常的話返回0,否則返回1。
示例如下:
FROM node:7-alpine
LABEL maintainer "jakub.skalecki@example.com"
...
EXPOSE $APP_PORT
HEALTHCHECK CMD curl --fail http://localhost:$APP_PORT || exit 1
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
當請求失敗時,curl --fail 命令返回非0狀態。
docker compose 單主機容器編排
20180728 Chenxin
Docker是容器技術的核心、基礎.
Docker Compose是一個基於Docker的單主機容器編排工具,功能並不像Docker Swarm和Kubernetes是基於Dcoker的跨主機的容器管理平台那么豐富。
這個也挺常用的,將一組服務的多個docker一起管理.具體需要深入研究
你說多服務?好吧那就寫個docker-compose.file吧。 嗯哼? 你說集群部署 來來來, 有Kubernetes、Mesos,Fleet和Swarm 任君挑選
https://docs.docker.com/compose/
https://blog.csdn.net/pushiqiang/article/details/78682323
https://www.cnblogs.com/neptunemoon/p/6512121.html
Compose 中有兩個重要的概念:
服務 (service):一個應用的容器,實際上可以包括若干運行相同鏡像的容器實例。
項目 (project):由一組關聯的應用容器組成的一個完整業務單元,在 docker-compose.yml 文件中定義。
Compose 的默認管理對象是項目,通過子命令對項目中的一組容器進行便捷地生命周期管理。
安裝:
pip install docker-compose 如果報錯,添加參數 --ignore-installed docker-compose