2017/03 Chenxinphp
參考
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.htmlhtml
命令自動補全(不屬於docker內容)
安裝(僅支持較新的linux版本)java
yum install bash-completion
說明(能夠忽略)
最小化安裝centos7須要安裝一個 bash-completion 包,而後退出 bash,從新登陸便可.
bash-2.05及之後的版本提供了自動補齊的編程接口.
bash-completion的安裝已加入Centos7初始化腳本.node
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 xbzjmysql
網絡說明
因大陸訪問海外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-versionslinux
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.reponginx
b.正式安裝
yum install docker-ce
這裏會報依賴錯誤.能夠自行解決.或使用AWS自身的yum源(推薦)
yum install docker (aws只須要這一步就能夠了)git
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 #主要目錄github
安裝完成後的驗證
執行docker version
Client:
Version: 18.03.1-ce #這個是aws本身的版本,是18年03月作的AMI.web
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
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 指令(只對建立的容器有效)
一、運行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash -> 主機上的 /home/xqh/myimage 目錄中的內容關聯到 容器中設置了一個掛載點 /data.在容器仍是主機上操做它,都是徹底實時同步的(實際指向的物理空間徹底相同). 二、運行命令: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 物理機與運行中的容器 數據的覆蓋問題
以物理機器下的卷優先,以有數據的優先.
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參數來調整容器使用內存的大小.
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 run -it ubuntu /bin/bash 首先系統要有一個docker daemon的後臺進程在運行,當剛纔這行命令敲下時:
關閉流程
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功能)
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指令.大小寫不敏感(推薦大寫)
FROM nginx RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
鏡像構建上下文(Context)
docker build 命令最後有一個"."表示當前目錄,這裏是指明瞭上下文路徑(context的路徑),而非指明Dockerfile文件所在路徑.
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,以及會將其置於鏡像構建上下文目錄中。
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(基本爲網上內容)
目標:
總結(編寫Dockerfile須要注意的問題)
示例
最初示例
示例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/
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做爲標籤。
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
FROM node:7-alpine ADD . /app RUN cd /app && npm install CMD npm start
FROM node:7-alpine WORKDIR /app ADD . /app RUN npm install CMD ["npm", "start"]
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命令啓動的進程能夠取代腳本進程,所以全部的信號都會正常工做。
FROM node:7-alpine WORKDIR /app COPY . /app RUN npm install ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
FROM node:7-alpine WORKDIR /app COPY package.json /app RUN npm install COPY . /app ENTRYPOINT ["./entrypoint.sh"] CMD ["start"]
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"
...
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狀態。
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