云時代【6】—— 鏡像 與 容器
- 四、Docker
- (三)鏡像 與 容器
- 1. 鏡像
- (1)定義
- (2)相關指令
- (3)實戰演習
- 鏡像容器基本操作
- 離線遷移鏡像
- 鏡像的壓縮與共享
- 2. 容器
- (1)定義
- (2)容器的生命周期
- (3)基本指令
- 與容器交互
- 容器的資源使用
- 容器與宿主機
- 容器與鏡像
- (4)實戰演習
- A. 實際操作案例
- B. MySQL 與 Redis的容器化安裝
- C. Java 程序的容器制作
- D. 容器資源更新
四、Docker
(三)鏡像 與 容器
1. 鏡像
(1)定義
鏡像 的作用可以看成:納戒 + 模板。 鏡像”模板“很好理解,它指的是:鏡像可以被快速復制(拉取);而鏡像”納戒“的本質是: **Union FS**
聯合文件系統。
它可以將幾層目錄掛載到一起,形成一個虛擬文件系統。每一層文件系統我們叫做一層 layer
。聯合文件系統可以對每一層文件系統設置三種權限:只讀**(readonly)**
、讀寫**(readwrite)**
和寫出**(whiteout-able)**
,但是** ****docker**
鏡像中每一層文件系統都是只讀的。 構建鏡像的時候,從一個最基本的操作系統開始,每個構建的操作都相當于做一層的修改,增加了一層文件系統。一層層往上疊加,上層的修改會覆蓋底層該位置的可見性。當你使用的時候,你只會看到一個完全的整體,你不知道里面有幾層,也不清楚每一層所做的修改是什么。
理解了鏡像”納戒“的本質是聯合文件系統之后,我們就能很好的理解鏡像的優缺點了。
-
優點:
- 屏蔽了環境的差異
- 分層的存儲:可以充分利用共享層(減少存儲空間的占用)
- 快速分發(只添加缺失的層)
-
缺點:
- 鏡像添加的依賴占用機器的空間
- 尋找文件只能一層一層找,會帶來一定的性能損失
(2)相關指令
docker rmi [鏡像]:[版本]
docker rmi 'IMAGE ID'# --no-prune 不移除該鏡像的過程鏡像
docker run -it --name mybusybox busybox:1.35.0 sh
docker rmi busybox:1.35.0 # error
docker rmi -f busybox:1.35.0 # 但是強制刪除也沒必要,可以先刪除容器,再刪除鏡像
docker save -o xxx.tar [鏡像]:[版本]# 下圖大小沒有發生變化主要原因是:打了同一個鏡像!(IMAGE ID相同)
docker load -i xxx.tar
docker load -i xxx.tar -q
# -q 是安靜模式(不顯示進度條)
docker history [鏡像]:[版本號]# --no-trunc 不做截斷(顯示全部信息)
# 該層鏡像不被任何一層鏡像使用
docker image prune# -a 刪除全部不被容器使用的鏡像
(3)實戰演習
鏡像容器基本操作
docker search busybox
docker pull busybox:1.36.0
docker images busybox# 查看鏡像的下載位置
cd /data/var/lib/docker # 在 /etc/docker/daemon.json
cd overlay2
cat repositories.json# 查看鏡像的詳細信息
docker image inspect busybox:1.36.0
# 查看鏡像的分層
docker history busybox:1.36.0# 給鏡像打標簽
docker tag busybox:1.36.0 lllzxx/fortest:v1.36.0
docker push lllzxx/fortest:v1.36.0 -a# 查看登錄站點
cat /root/.docker/config.json# 拉取鏡像
docker pull lllzxx/fortest:v1.36.0# 運行容器
docker run -it -d --name mybusybox -h myweb -e myenv=test lllzxx:v1.36.0 sh
ifconfig
exit# 查看所有容器
docker ps -a# 刪除鏡像
docker rmi lllzxx/fortest:v1.36.0
docker rm 'IAMGE ID' # 刪除容器
離線遷移鏡像
# A服務器
docker pull lllzxx/fortest:v1.36.0
cd /data/lllzxx
docker images
docker save -o mybusybox.tar lllzxx/fortest:v1.36.0# B服務器
docker version # 檢查是否安裝Docker,沒有則安裝
mkdir -p /data/lllzxx
cd /data/lllzxx
ll# A服務器
scp mybusybox.tar root@IP:/data/lllzxx # 需要輸入密碼# B服務器
ll
docker load -i mybusybox.tar
docker images
docker run -it lllzxx/fortest:v1.36.0 sh
ifconfig
ping www.baidu.com
exit
鏡像的壓縮與共享
docker images nginx
docker pull [鏡像]:[版本號]
# 查看遠端和本地的大小是否一樣?
# 不一樣。遠端:①節省存儲空間 ②減少網絡帶寬
# 如果遠端的鏡像是相同的,只是不同別名的話并不會真正上傳,只會標示出不同鏡像
2. 容器
(1)定義
容器是鏡像的運行實體。鏡像是靜態的只讀文件,而是容器帶有運行時需要的可寫文件層,并且容器中的進程屬于運行狀態。容器本質上是主機運行的一個進程,但是該進程被進行了各種各樣的限制,無法看到主機的進程、環境變量、網絡等信息。
注:不同角度理解會對容器做出不同定義,其他角度見”云時代【1】“。
(2)容器的生命周期
(3)基本指令
docker create --name mywebs1 -p 8080:80 nginx:1.23.4 # 創建容器(擰鑰匙)
docker ps -a | grep mywebs1
docker start mywebs1 # 啟動容器(踩油門)
docker ps -a | grep mywebs1
docker container inspect mywebs2docker container inspect -s mywebs2 # -s 顯示總的文件大小
docker stop mywebs2 # 停止-踩剎車
# 使用 stop 超時也會殺死容器docker start mywebs2 # 開啟-踩油門
docker ps -a | grep mywebs2docker logs -f -n 5 mywebs2docker restart mywebs2docker restart -s 9 mywebs2
docker kill mywebs2
docker wait mywebs3
docker run -d --name mywebs3 nginx:1.23.4
docker ps -a
docker stop mywebs3
docker container prune
docker ps -a
docker rm -f [容器名] # -f 強制刪除運行中的容器# 重新 docker run 的話,名稱和端口相同也不會沖突
docker logs mywebs2# -f 跟蹤日志輸出
# -since="2099-01-01"
# -n x 多少條數據
與容器交互
docker attach mywebs2# 使用 ctrl + c 之后會直接退出容器(熄火)docker attach --sig-proxy=false mywebs2
# --sig-proxy 使用 ctrl + c 之后不會退出容器
docker exec -it mywebs2 bash
docker exec -it -d mywebs2 nginx -V # 在后臺運行容器docker exec -it -e mynginx=lllzxx mywebs2 bash # 設置容器的環境變量docker exec -it mywebs2 cat /etc/passwd
docker exec -it -u nginx mywebs2 nginx -v # 指定用戶docker exec -it -w /etc mywebs2 bash # 指定工作目錄
容器的資源使用
docker top mywebs2 docker top mywebs2 aux # aux 能夠查看資源使用情況
docker pause mywebs3
docker unpause mywebs3
docker stats -a --no-stream --no-trunc mywebs2# -a 所有容器(停止的也打印)
# --format 打印模式,默認是表格,可以使用json
# --no-stream 不實時更新
# --no-trunc 不截斷輸出
docker stats --format json
docker rename [舊名字] [新名字]
free -m
docker stats mywebs2
docker update --memory 500m --memory-swap 500m mywebs2
docker stats mywebs2# 一般來說都是會在創建容器的時候就規劃好的
容器與宿主機
docker port mywebs2 docker port mywebs2 80/tcp # 使用tcp協議的
docker cp mywebs2:/usr/share/nginx/html/index.html .
# .表示當前目錄,即當前工作目錄。
# ..表示父目錄,即當前目錄的上一級目錄。docker cp ./index.html mywebs2:/usr/share/nginx/html/index.html/
mkdir -p /data/lllzxx/textexport # -p 是遞歸地創建目錄
cd /data/lllzxx/textexport
ls -l
docker export -o myweb3.tar mywebs3
docker import -m '將文件轉回為鏡像' mywebs3.tar mywebs3:v1.0 # 與 save 和 load 相比會丟失信息
# A服務器
docker pull lllzxx/fortest:v1.36.0
cd /data/lllzxx
docker images
docker save -o mybusybox.tar lllzxx/fortest:v1.36.0# B服務器
docker version # 檢查是否安裝Docker,沒有則安裝
mkdir -p /data/lllzxx
cd /data/lllzxx
ll# A服務器
scp mybusybox.tar root@IP:/data/lllzxx # 需要輸入密碼# B服務器
ll
docker load -i mybusybox.tar
docker images
docker run -it lllzxx/fortest:v1.36.0 sh
ifconfig
ping www.baidu.com
exit
docker exec -it mywebs2 bash
echo "Hello World!" > /test.html
ls -ldocker diff mywebs2
容器與鏡像
docker images
docker run -d --name mywebsforcommit nginx:1.23.4
docker ps | grep mywebsforcommit
docker images mywebsforcommit
docker commit mywebsforcommit mywebsforcommit:v1.0 # docker commit [容器] [鏡像名]:[版本號]
docker images mywebsforcommit
docker exec -it mywebsforcommit bash
echo "Hello World!" > /testforcommit.txt
ls -l
exit
docker diff mywebsforcommit
docker commit mywebsforcommit mywebsforcommit:v2.0
docker run -it --rm mywebsforcommit:v2.0 bash
ls -l
cat testforcommit.txt
exit
docker commit -a 'lzxx' -m 'create by lzxx' -p mywebsforcommit mywebsforcommit:v3.0# -a 指定創建者
# -m 描述信息
# -p 創建鏡像時停止
docker commit -a 'lzxx' -m 'create by lzxx' -c 'CMD ["tail","-f","/etc/hosts"]' -p mywebsforcommit mywebsforcommit:v4.0
docker images mywebsforcommit
docker run -d --rm --name mywebsforcommit2 mywebsforcommit:v4.0
docker ps --no-trunc | grep mywebsforcommit
(4)實戰演習
A. 實際操作案例
docker images nginx
docker run -d --name mynginx01 -p 8101:80 nginx:1.22.0
docker ps
docker container inspet mynginx01
docker logs -f -n 10 mynginx01
docker rm mynginx01
docker stop mynginx01
docker ps -a | grep mynginx01
docker create --name mynginx02 -p 8102:80 nginx:1.22.0
docker ps -a | grep mynginx02
docker start mynginx02
docker ps -a | grep mynginx02docker kill mynginx02
docker ps -a | grep mynginx02
docker start mynginx02
docker ps -a | grep mynginx02docker stop mynginx02
docker ps -a | grep mynginx02
docker start mynginx02
docker ps -a | grep mynginx02docker ps -a | grep mynginx02
docker restart mynginx02
docker ps -a | grep mynginx02docker pause mynginx02
docker ps -a | grep mynginx02
docker unpause mynginx02
docker ps -a | grep mynginx02
# 批量過濾
# ps : Process Status,即進程狀態。
docker ps -a
docker stop mywebs1 mywebs2
docker ps
docker ps -f name=mywebs1
docker ps -f status=exited
docker ps -f ancestor=nginx:1.23.4
docker ps -q# 批量操作
docker stop `docker ps -q`
docker ps -a
# A-1.attached模式--該模式是在前臺運行,按 ctrl + c 就會退出容器,會簡化開發的過程,但不能用于生產
docker run --name mynginx03 -p 8103:80 nginx:1.22.0
docker ps | mynginx03# A-2.detached模式--在后臺運行
docker run -d --name myngine04 -p 8104:80 nginx:1.22.0
docker ps | mynginx04
exit # 斷開連接
docker ps | mynginx04 # 依舊在運行
docker logs -f mynginx04# B.attach 會把 attached模式 轉為 detached模式
docker attach mynginx04
ctrl + c
docker ps -a | mynginx04 # C.interactive模式
# C-1.創建一個可交互的容器
docker run -it --name mynginx05 -p 8105:80 nginx:1.22.0 bash
ls /
cat /etc/*release*
nginx -v
nginx # 正式啟動nginx
ctrl + c # 沒有影響
exit # shell退出,也意味著:容器退出
# C-2.與后臺運行的容器交互
docker run -it -d --name mynginx06 -p 8106:80 nginx:1.22.0
docker exec -it mynginx06 bash
curl 127.0.0.1
exit # shell退出,但容器依然正常運行
# 容器內部沒有vim編輯器
docker run -it -d --name mynginx07 -p 8107:80 nginx:1.22.0
docker exec -it mynginx07 bash
cd /usr/share/nginx/html
ls -l
cat index.html
vi index.html # refuse
exitmkdir -p /data/lllzxx/testcp
cd /data/lllzxx/testcp
ls -l
docker cp mynginx07:/usr/share/nginx/html/index.html .
vi index.html
docker cp ./index.html mynginx07:/usr/share/nginx/html/docker exec -it mynginx07 bash
cd /usr/share/nginx/html
cat index.html# 注意:cp 不支持容器與容器之間的拷貝
docker run -it --rm --name mynginx08 -p 8108:80 nginx:1.22.0 bash
nginx -v
exit
docker ps -a | grep mynginx08 # 查找不到docker run -d --rm --name mynginx08 -p 8108:80 nginx:1.22.0 # 一停止就刪除
docker ps | grep mynginx08
docker stop mynginx08
docker ps -a | grep mynginx08 # 同樣查找不到
# restart:
# no-不重啟(默認);on-failure:3 指定重啟次數;
# always-總是重啟;unless-stopped-中途退出也重啟
docker run -d --name mynginx09 -p 8109:80 --restart=always nginx:1.22.0
docker exec -it mynginx09 bash
nginx -s quit # 停止nginx服務
docker ps | mynginx09 # 發生重啟docker stop mynginx09 # 無法再次拉起
docker run -it --rm -e MYTEST1=1 -e MYTEST2=2 nginx:1.22.0 bash
env | grep MYTEST
exit# 通過配置文件 設置環境變量
mkdir -p /data/lllzxx/mytestenv
cd /data/lllzxx/mytestenv
vi myenv.txt
docker run -it --rm --env-file=./myenv.txt nginx:1.22.0 bash
env | grep MYTEST
docker run --rm busybox ifconfig # 查看容器的
docker run --rm --net host busybox ifconfig # 使用宿主機的網絡,查看宿主機的
# A服務器
docker run -d --name mynginx10 -p 8110:80 nginx:1.22.0
docker ps
docker exec -it mynginx10
cd /usr/share/nginx/html/
echo "Hello World" > index.html
cat index.html
exit
mkdir -p /data/lllzxx/testtar
cd /data/lllzxx/testtar
docker export -o mynginx10.tar mynginx10
ls -l# B服務器
mkdir -p /data/lllzxx/testtar
cd /data/lllzxx/testtar# A服務器
scp mynginx10.tar root@IP:/data/lllzxx/testtar # scp 在跨云的時候會有速度限制# B服務器
docker import mynginx10.tar mynginx10:v10.0
docker images mynginex10
docker run -d --name mynginx10 -p 8010:80 mynginx10:v10.0 # refuse:CMD丟失。
docker inspect mynginx10:v10.0 # 還有很多其他源數據丟失
docker run -d --name mynginx10 -p 8010:80 nginx -g "daemon off" mynginx10:v10.0
docker save
與 docker export
的區別可看下方文章:
docker save與docker export的區別_docker版本不同導致save-CSDN博客
docker run -d --name mynginx11 -p 8011:80 nginx:1.22.0
docker logs -f mynginx11# 流的重定向
docker logs mynginx11 > info.log 2>err.log # info.log 是標準信息流;err.log 是標準錯誤流# 直接看Docker后臺的目錄
cd /data/var/lib/docker/containers
ls
docker ps
cd xxxxxxx
ls
cat xxxxx-json.log
docker run -d --name mynginx12 -p 8012:80 nginx:1.22.0
docker stats mynginx12 # 整個容器總的資源占用
docker top mynginx12 aux # 容器中具體進程占用的資源
B. MySQL 與 Redis的容器化安裝
docker run --name mysql -e MYSQL_ROOT_PASSWORD=lzxx@mysql -p 8201:3306 -d mysql:5.7
docker images
docker ps | grep mysql
docker exec -it mysql bash
mysql -u root -p # lzxx@mysql
exit # 退出 MySQL
exit # 退出 容器
docekr run --name redis -d -p 8300:6379 redis:7
docker ps | grep redis
docker exec -it redis bash
redis-cli
set sellcount 1
get sellcount
exit # 退出Redis
exit # 退出容器
C. Java 程序的容器制作
docker pull ubuntu:22.04
docker images | grep ubuntu
docker run -it --name myjava -p 8080:80 ubuntu:22.07 bash
# 使用中科大源拉取鏡像,記得更新緩存
apt search jdk
apt-get install java-1.8.0-openjdk.x86_64 -y
java -version
exitmkdir -p /data/lllzxx/myapp
cd /data/lllzxx/myapp
# 上傳 .jar 包 :scp mynginx10.tar root@IP:/data/lllzxx/testtar
ls -l
docker cp ./myapp.jar myjava:/docker exec -it myjava bash
ls /
java -jar myapp.jar
# 訪問地址:IP:8080/hello/docker
exit # 現在是以前臺方式運行,可以寫 run 指令,也可以寫 DockerFile
D. 容器資源更新
# A窗口
docker pull java:8
docker run -it --name myjava2 java:8 bash# B窗口
cd /data/lllzxx/myapp
ls -l
docker cp myapp.java myjava2:/# A窗口
ls -l
java -jar myapp.jar# C窗口
docker stats myjava2# D窗口
docker update -m 200m --memory-swap 200m myjava2 # 兩者一樣即只能使用物理內存而不能使用交換內存# A窗口
ctrl + c# D窗口
docker update -m 10m --memory-swap 10m myjava2# A窗口
java -jar myapp.jar # OOM-Kill 因為申請的內存太多了,無法給這么多資源
# A窗口
docker run -it --name myjava3 java:8 bash# B窗口
docker stats myjava3# A窗口
for i in `seq 1 $(cat /proc/cpuinfo |grep "physical id" |wc -l)`
dodd if=/dev/zero of=/dev/null &
done
#說明:
#cat /proc/cpuinfo |grep “physical id” | wc -l 可以獲得 CPU 的個數,我們將其表示為 N
#seq 1 N 用來生成1到N之間的數字
#for i in seq 1 N; 就是循環執行命令,從1到N
#dd if=/dev/zero of=/dev/null 執行 dd 命令, 輸出到/dev/null, 實際上只占用 CPU, 沒有 IO 操作
#由于連續執行N個(N是 CPU 個數)的 dd 命令, 且使用率為 100%, 這時調度器會調度每個 dd 命令在不同的 CPU 上處理,最終就實現所有CPU占用率 100%# C窗口
docker update --cpu-quota 分子 --cpu-period 分母 myjava3