一、docker 基礎(chǔ)操作
搜索鏡像: 這種方法只能用于官方鏡像庫(kù)
例如搜索基于 Centos 操作系統(tǒng)的鏡像
[root@root ~]# docker search centos
查看完整鏡像的信息:
[root@root ~]# docker inspect id名稱
拉取鏡像
[root@root ~]# docker pull centos
查看本地鏡像
[root@root ~]# docker image list
查看鏡像詳情
[root@root ~]# docker image inspect 鏡像id
刪除鏡像
刪除一個(gè)或多個(gè),多個(gè)之間用空格隔開,可以使用鏡像名稱或id
[root@root ~]# docker rmi daocloud.io/library/mysql
強(qiáng)制刪除:--force
如果鏡像正在被使用中可以使用--force強(qiáng)制刪除
[root@root ~]# docker rmi docker.io/ubuntu:latest --force
刪除所有鏡像
[root@root ~]# docker rmi $(docker images -q)
只查看所有鏡像的id
[root@root ~]# docker images -q
Docker容器管理
創(chuàng)建新容器但不啟動(dòng)
[root@root ~]# docker create -it daocloud.io/library/centos:8 /bin/bash
創(chuàng)建并運(yùn)行一個(gè)新Docker 容器
同一個(gè)鏡像可以啟動(dòng)多個(gè)容器,每次執(zhí)行run子命令都會(huì)運(yùn)行一個(gè)全新的容器
[root@root ~]# docker run -it --restart=always centos /bin/bash
如果執(zhí)行成功,說(shuō)明CentOS 容器已經(jīng)被啟動(dòng),并且應(yīng)該已經(jīng)得到了 bash 提示符。
-i
捕獲標(biāo)準(zhǔn)輸入輸出
-t
分配一個(gè)終端或控制臺(tái)
--restart=always
容器隨docker engine自啟動(dòng),因?yàn)樵谥貑ocker的時(shí)候默認(rèn)容器都會(huì)被關(guān)閉
也適用于create選項(xiàng)
--rm
默認(rèn)情況下,每個(gè)容器在退出時(shí),它的文件系統(tǒng)也會(huì)保存下來(lái),這樣一方面調(diào)試會(huì)方便些,因?yàn)槟憧梢酝ㄟ^查看日志等方式來(lái)確定最終狀態(tài)。另一方面,也可以保存容器所產(chǎn)生的數(shù)據(jù)。
但是當(dāng)你僅僅需要短暫的運(yùn)行一個(gè)容器,并且這些數(shù)據(jù)不需要保存,你可能就希望Docker能在容器結(jié)束時(shí)自動(dòng)清理其所產(chǎn)生的數(shù)據(jù)。這個(gè)時(shí)候就需要--rm參數(shù)了。注意:--rm 和 -d不能共用
容器名稱
--name= Assign a name to the container
--為容器分配一個(gè)名字,如果沒有指定,docker會(huì)自動(dòng)分配一個(gè)隨機(jī)名稱
是docker run子命令的參數(shù)
docker run -it --restart=always --name +你創(chuàng)建命名的名稱 centos /bin/bash
如果只想斷開和容器的連接而不關(guān)閉容器:
快捷鍵:ctrl+p+q
進(jìn)入容器3種方式:
docker exec -it 容器id /bin/bash
docker attach 容器id bin/bash
查看容器:
只查看運(yùn)行狀態(tài)的容器:
[root@root ~]#docker ps
-a 查看所有容器
[root@root ~]#docker ps -a
只查看所有容器id:
[root@root ~]# docker ps -a -q
容器里在安裝ip或ifconfig命令之前,查看網(wǎng)卡IP顯示容器IP地址和端口號(hào),如果輸出是空的說(shuō)明沒有配置IP地址(不同的Docker容器可以通過此IP地址互相訪問)
[root@root ~]# docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器id
啟動(dòng)容器
[root@root ~]# docker start name
關(guān)閉容器:
[root@root ~]# docker stop name
[root@root ~]# docker kill name --強(qiáng)制終止容器
殺死所有running狀態(tài)的容器
[root@root ~]# docker kill $(docker ps -q)
stop和kill的區(qū)別
docker stop命令給容器中的進(jìn)程發(fā)送SIGTERM信號(hào),默認(rèn)行為是會(huì)導(dǎo)致容器退出,當(dāng)然,容器內(nèi)程序可以捕獲該信號(hào)并自行處理,例如可以選擇忽略。而docker kill則是給容器的進(jìn)程發(fā)送SIGKILL信號(hào),該信號(hào)將會(huì)使容器必然退出。
刪除容器
[root@root ~]# docker rm 容器id或名稱
要?jiǎng)h除一個(gè)運(yùn)行中的容器,添加 -f 參數(shù)
根據(jù)格式刪除所有容器:
[root@root ~]# docker rm $(docker ps -qf status=exited)
重啟容器:
[root@root ~]#docker restart name
暫停容器:
pause --暫停容器內(nèi)的所有進(jìn)程,
通過docker stats可以觀察到此時(shí)的資源使用情況是固定不變的,通過docker logs -f也觀察不到日志的進(jìn)一步輸出。
恢復(fù)容器:
unpause --恢復(fù)容器內(nèi)暫停的進(jìn)程,與pause參數(shù)相對(duì)應(yīng)
[root@root ~]# docker start infallible_ramanujan
這里的名字是狀態(tài)里面NAMES列列出的名字,這種方式同樣會(huì)讓容器運(yùn)行在后臺(tái)
讓容器運(yùn)行在后臺(tái):
如果在docker run后面追加-d=true或者-d,那么容器將會(huì)運(yùn)行在后臺(tái)模式。此時(shí)所有I/O數(shù)據(jù)只能通過網(wǎng)絡(luò)資源或者共享卷組來(lái)進(jìn)行交互。因?yàn)槿萜鞑辉俦O(jiān)聽你執(zhí)行docker run的這個(gè)終端命令行窗口。但你可以通過執(zhí)行
docker attach來(lái)重新附著到該容器的回話中。
注:
容器運(yùn)行在后臺(tái)模式下,是不能使用--rm選項(xiàng)的(老版本是這樣,新版本已經(jīng)可以同時(shí)生效)
[root@root ~]#docker run -d IMAGE[:TAG] 命令
[root@root ~]#docker logs container_id [root@root ~]#打印該容器的輸出
[root@root ~]# docker run -it -d --name mytest docker.io/centos /bin/sh -c "while true; do echo hello world; sleep 2; done"
37738fe3d6f9ef26152cb25018df9528a89e7a07355493020e72f147a291cd17
[root@root ~]# docker logs mytest
hello world
hello world
docker attach container_id #附加該容器的標(biāo)準(zhǔn)輸出到當(dāng)前命令行
[root@root ~]# docker attach mytest
hello world
hello world
.......
此時(shí),ctrl+d等同于exit命令,按ctrl+p+q可以退出到宿主機(jī),而保持container仍然在運(yùn)行
rename
Rename a container
stats
Display a live stream of container(s) resource usage statistics
--動(dòng)態(tài)顯示容器的資源消耗情況,包括:CPU、內(nèi)存、網(wǎng)絡(luò)I/O
port
List port mappings or a specific mapping for the CONTAINER
--輸出容器端口與宿主機(jī)端口的映射情況
[root@root ~]# docker port blog
80/tcp -> 0.0.0.0:80
容器blog的內(nèi)部端口80映射到宿主機(jī)的80端口,這樣可通過宿主機(jī)的80端口查看容器blog提供的服務(wù)
連接容器:
方法1.attach
[root@root ~]# docker attach 容器id //前提是容器創(chuàng)建時(shí)必須指定了交互shell
方法2.exec
通過exec命令可以創(chuàng)建兩種任務(wù):后臺(tái)型任務(wù)和交互型任務(wù)
交互型任務(wù):
[root@root ~]# docker exec -it 容器id /bin/bash
root@68656158eb8e:/ ls
后臺(tái)型任務(wù):
[root@root ~]# docker exec 容器id touch /testfile
監(jiān)控容器的運(yùn)行:
可以使用logs、top、events、wait這些子命令
logs:
使用logs命令查看守護(hù)式容器
可以通過使用docker logs命令來(lái)查看容器的運(yùn)行日志,其中--tail選項(xiàng)可以指定查看最后幾條日志,而-t選項(xiàng)則可以對(duì)日志條目附加時(shí)間戳。使用-f選項(xiàng)可以跟蹤日志的輸出,直到手動(dòng)停止。
[root@root ~]# docker logs App_Container //不同終端操作
[root@root ~]# docker logs -f App_Container
top:
顯示一個(gè)運(yùn)行的容器里面的進(jìn)程信息
[root@qroot ~]# docker top birdben/ubuntu:v1
events
Get real time events from the server
實(shí)時(shí)輸出Docker服務(wù)器端的事件,包括容器的創(chuàng)建,啟動(dòng),關(guān)閉等。
[root@root ~]# docker start loving_meninsky
loving_meninsky
[root@root ~]# docker events //不同終端操作
2017-07-08T16:39:23.177664994+08:00 network connect
df15746d60ffaad2d15db0854a696d6e49fdfcedc7cfd8504a8aac51a43de6d4
(container=50a0449d7729f94046baf0fe5a1ce2119742261bb3ce8c3c98f35c80458e3e7a,
name=bridge, type=bridge)
2017-07-08T16:39:23.356162529+08:00 container start
50a0449d7729f94046baf0fe5a1ce2119742261bb3ce8c3c98f35c80458e3e7a (image=ubuntu,
name=loving_meninsky)
wait(X)
Block until a container stops, then print its exit code
--捕捉容器停止時(shí)的退出碼
執(zhí)行此命令后,該命令會(huì)"hang"在當(dāng)前終端,直到容器停止,此時(shí),會(huì)打印出容器的退出碼
[root@root ~]# docker wait 01d8aa //不同終端操作
137
diff
查看容器內(nèi)發(fā)生改變的文件,以elated_lovelace容器為例
root@68656158eb8e:
touch c.txt
用diff查看:
包括文件的創(chuàng)建、刪除和文件內(nèi)容的改變都能看到
[root@root ~]# docker diff 容器名稱
A /c.txt
C對(duì)應(yīng)的文件內(nèi)容的改變,A對(duì)應(yīng)的均是文件或者目錄的創(chuàng)建刪除
[root@root ~]# docker diff 7287
A /a.txt
C /etc
C /etc/passwd
A /run
A /run/secrets
宿主機(jī)和容器之間相互Copy文件
cp的用法如下:
docker cp [OPTIONS] CONTAINER:PATH LOCALPATH
docker cp [OPTIONS] LOCALPATH CONTAINER:PATH
如:容器mysql中/usr/local/bin/存在docker-entrypoint.sh文件,可如下方式copy到宿主機(jī)
[root@root ~]# docker cp mysql:/usr/local/bin/docker-entrypoint.sh /root
修改完畢后,將該文件重新copy回容器
[root@root ~]# docker cp /root/docker-entrypoint.sh mysql:/usr/local/bin/
二、Docker容器鏡像制作
1、容器文件系統(tǒng)打包
將容器的文件系統(tǒng)打包成tar文件,也就是把正在運(yùn)行的容器直接導(dǎo)出為tar包的鏡像文件
有兩種方式(elated_lovelace為容器名)
第一種:[root@root ~]# docker export -o elated_lovelace.tar elated_lovelace
第二種:[root@root ~]# docker export 容器名稱 > 鏡像.tar
導(dǎo)入鏡像歸檔文件到其他宿主機(jī)
[root@root ~]# docker import elated_lovelace.tar elated_lovelace:v1
注意:
如果導(dǎo)入鏡像時(shí)沒有起名字,隨后可以單獨(dú)起名字(沒有名字和tag),可以手動(dòng)加tag
[root@root ~]# docker tag 鏡像ID mycentos:7
2、通過容器創(chuàng)建本地鏡像
方案:
?使用 docker commit 指令,把一個(gè)正在運(yùn)行的容器,直接提交為一個(gè)鏡像。commit 是提交的意思,類似告訴svn服務(wù)器我要生成一個(gè)新的版本。
例:在容器內(nèi)部新建了一個(gè)文件
#進(jìn)入容器操作:
[root@qfedu.com ~]# docker exec -it 4ddf4638572d /bin/sh
root@4ddf4638572d# touch test.txt
root@4ddf4638572d# exit
#將這個(gè)新建的文件提交到鏡像中保存
[root@qfedu.com ~]# docker commit 4ddf4638572d wing/helloworld:v2
(添加了作者及注釋內(nèi)容,生產(chǎn)時(shí)需要加上)
[root@qfedu.com ~]# docker commit -m "my images version1" -a "wing" 108a85b1ed99 daocloud.io/ubuntu:v2
sha256:ffa8a185ee526a9b0d8772740231448a25855031f25c61c1b63077220469b057
-m 添加注釋
-a 作者
108a85b1ed99 容器環(huán)境id
daocloud.io/ubuntu:v2 鏡像名稱:hub的名稱/鏡像名稱:tag
-p,–pause=true 提交時(shí)暫停容器運(yùn)行
3、通過Dockerfile創(chuàng)建鏡像
docker build命令用于根據(jù)給定的Dockerfile和上下文以構(gòu)建Docker鏡像.
查找docker容器映射的端口:docker port 容器名/容器ID
save沒有直接修改的情況下可以把鏡像保存到本地(不需要運(yùn)行成容器);export不能直接對(duì)鏡像保存必須是鏡像運(yùn)行成容器的情況下才能保存;
save和load搭配使用;export和import搭配使用;其中export是直接可以保存到本地,而commit不能直接保存到本地,需要通過save保存到本地。
Dockerfile默認(rèn)放到/docker目錄下,名字默認(rèn)就叫Dockerfile
Dockerfile優(yōu)化之一:盡量把RUN合并到一行。
docker build語(yǔ)法:
docker build [OPTIONS] <PATH | URL | ->
例: docker build -t centos:v2 .
在Dockerfile文件中寫入指令,每一條指令都會(huì)更新鏡像的信息例如:
[root@qfedu.com ~]# vim Dockerfile
[root@qfedu.com ~]# This is a comment
FROM daocloud.io/library/centos:7
MAINTAINER wing wing@qfedu.com
RUN 命令1;命令2;命令3
RUN 命令
格式說(shuō)明**
? 每行命令都是以 INSTRUCTION statement 形式,就是命令+ 清單的模式。命令要大寫,"#"是注解。
? FROM 命令是告訴docker 我們的鏡像什么。
? MAINTAINER 是描述 鏡像的創(chuàng)建人。
? RUN 命令是在鏡像內(nèi)部執(zhí)行。就是說(shuō)他后面的命令應(yīng)該是針對(duì)鏡像可以運(yùn)行的命令。
創(chuàng)建鏡像
[root@root ~]# docker build -t centos:v2 .
docker build 是docker創(chuàng)建鏡像的命令
-t 鏡像名稱
"." 上下文目錄,如果不用-f指定Dockerfile文件的位置和名稱,默認(rèn)會(huì)從上下文目錄也就是這里指定的當(dāng)前目錄查找。
創(chuàng)建完成后,用這個(gè)鏡像運(yùn)行容器
[root@root ~]# docker run -it centos:v2 /bin/bash
4、Dockerfile實(shí)例01:容器化Python的Flask應(yīng)用
目標(biāo):
用 Docker 部署一個(gè)用 Python 編寫的 Web 應(yīng)用。
應(yīng)用代碼部分:
? 代碼功能:如果當(dāng)前環(huán)境中有"NAME"這個(gè)環(huán)境變量,就把它打印在"Hello"后,否則就打印"Hello world",最后再打印出當(dāng)前環(huán)境的 hostname。
[root@root ~]# mkdir python_app
[root@root ~]# cd python_app
[root@root ~]# \vim app.py
from flask import Flask
import socket
import os
app = Flask(__name__)
@app.route('/')
def hello():
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
應(yīng)用依賴:
定義在同目錄下的 requirements.txt 文件里,內(nèi)容如下:
[root@root ~]# vim requirements.txt
Flask
編寫Dockerfile
[root@qfedu.com ~]# vim Dockerfile
FROM python:2.7-slim
WORKDIR /app
ADD . /app
RUN pip install --trusted-host pypi.python.org -r requirements.txt
EXPOSE 80
ENV NAME World
CMD ["python", "app.py"]
Dockerfile文件說(shuō)明
FROM python:2.7-slim
使用官方提供的 Python 開發(fā)鏡像作為基礎(chǔ)鏡像
指定"python:2.7-slim"這個(gè)官方維護(hù)的基礎(chǔ)鏡像,從而免去安裝 Python 等語(yǔ)言環(huán)境的操作。否則,這一段就得這么寫了:
FROM ubuntu:latest
RUN apt-get update -y
RUN apt-get install -y python-pip python-dev build-essential
WORKDIR /app
將工作目錄切換為 /app,意思是在這一句之后,Dockerfile 后面的操作都以這一句指定的 /app 目錄作為當(dāng)前目錄。
ADD . /app
將當(dāng)前目錄下的所有內(nèi)容復(fù)制到 /app 下,Dockerfile 里的原語(yǔ)并不都是指對(duì)容器內(nèi)部的操作。比如 ADD,指的是把當(dāng)前目錄(即 Dockerfile 所在的目錄)里的文件,復(fù)制到指定容器內(nèi)的目錄當(dāng)中。
RUN pip install --trusted-host pypi.python.org -r requirements.txt
使用 pip 命令安裝這個(gè)應(yīng)用所需要的依賴
EXPOSE 80 //允許外界訪問容器的 80 端口
ENV NAME World //設(shè)置環(huán)境變量
CMD ["python", "app.py"]
設(shè)置容器進(jìn)程為:python app.py,即:這個(gè) Python 應(yīng)用的啟動(dòng)命令
這里app.py 的實(shí)際路徑是 /app/app.py。CMD ["python", "app.py"] 等價(jià)于 "docker run python app.py"。
在使用 Dockerfile 時(shí),可能還會(huì)看到一個(gè)叫作 ENTRYPOINT 的原語(yǔ)。它和 CMD 都是 Docker 容器進(jìn)程啟動(dòng)所必需的參數(shù),完整執(zhí)行格式是:"ENTRYPOINT CMD"。
但是,默認(rèn),Docker 會(huì)提供一個(gè)隱含的 ENTRYPOINT,即:/bin/sh -c。所以,在不指定 ENTRYPOINT 時(shí),比如在這個(gè)例子里,實(shí)際上運(yùn)行在容器里的完整進(jìn)程是:/bin/sh -c "python app.py",即 CMD 的內(nèi)容就是 ENTRYPOINT 的參數(shù)。
基于以上原因,后面會(huì)統(tǒng)一稱 Docker 容器的啟動(dòng)進(jìn)程為 ENTRYPOINT,而不是 CMD。
/bin/bash -c 'pwd' 與pwd 結(jié)果一樣 完整的終端命令
現(xiàn)在目錄結(jié)構(gòu):
[root@qfedu.com ~]# ls
Dockerfile app.py requirements.txt
構(gòu)建鏡像
[root@qfedu.com ~]# docker build -t helloworld .
-t 給這個(gè)鏡像加一個(gè) Tag
Dockerfile 中的每個(gè)原語(yǔ)執(zhí)行后,都會(huì)生成一個(gè)對(duì)應(yīng)的鏡像層。即使原語(yǔ)本身并沒有明顯地修改文件的操作(比如,ENV 原語(yǔ)),它對(duì)應(yīng)的層也會(huì)存在。只不過在外界看來(lái),這個(gè)層是空的。
查看結(jié)果:
[root@root ~]# docker image ls
REPOSITORY TAG IMAGE ID
helloworld latest 653287cdf998
啟動(dòng)容器
[root@root ~]# docker run -p 4000:80 helloworld
鏡像名 helloworld 后面,什么都不用寫,因?yàn)樵?Dockerfile 中已經(jīng)指定了 CMD。
否則,就得把進(jìn)程的啟動(dòng)命令加在后面:
[root@root ~]# docker run -p 4000:80 helloworld python app.py
查看容器
[root@root ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED
4ddf4638572d helloworld "python app.py" 10 seconds ago
進(jìn)入容器
[root@qfedu.com ~]# docker exec -it b69 /bin/bash
訪問容器內(nèi)應(yīng)用
[root@qfedu.com ~]# curl http://localhost:4000
結(jié)果如下:
<h3>Hello World!</h3><b>Hostname:</b> 4ddf4638572d