Docker學習筆記—通俗易懂
- 2021 年 5 月 6 日
- 筆記
Docker
簡介
Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中,然後發佈到任何流行的 Linux或Windows 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口。
Docker是基於 Go 語言開發的,是一個開源項目。
文檔地址://docs.docker.com/
倉庫地址://hub.docker.com/
虛擬機技術缺點:模擬一個完整的操作系統,資源佔用多,步驟冗餘,啟動慢。
Docker 容器化技術:不是模擬的一個完整的操作系統。運行在宿主機的內核上。每個容器內是互相隔離的,互不影響。
DevOps:開發 運維。
應用更快的交付和部署。
傳統:安裝各種的jar包,打包發佈。
Docker :一鍵打包鏡像發佈,測試。
更便捷的升級和擴縮容,項目打包為一個鏡像,部署應用就和搭積木一樣。
更簡單的系統運維,容器化後,開發測試環境都是一致的。
更高效的計算資源利用,Docke是內核級的虛擬化,在一個物理機上可以運行很多的容器。
Docker安裝
Docker的基本組成
鏡像(image):
就好比是一個模板,可通過這個鏡像來創建容器服務,比如 tomcat 鏡像—>run—>tomcat01容器,通過這個鏡像可以創建多個容器(應用最終在容器中運行)。
容器(container):
Docker利用容器技術,獨立運行一個或一組應用,通過鏡像創建。
啟動,停止,刪除,基本命令。
倉庫(repository):
存放鏡像的地方。倉庫分為公有倉庫和私有倉庫。
安裝Docker
環境準備:
- 需要會Linux基礎
- Centos7
- 使用Xshell連接遠程服務器操作
- 已經購買雲服務器(以下使用阿里雲)
環境查看
#系統內核是3.0以上的
[root@zhourui /]# uname -r
4.18.0-193.28.1.el8_2.x86_64
#系統版本
[root@zhourui /]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="8 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="8"
PLATFORM_ID="platform:el8"
PRETTY_NAME="CentOS Linux 8 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:8"
HOME_URL="//www.centos.org/"
BUG_REPORT_URL="//bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"
安裝:參考幫助文檔 //docs.docker.com/engine/install/centos/
卸載舊的版本
#卸載
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
#需要的安裝包
yum install -y yum-utils
#設置鏡像的倉庫
yum-config-manager \
--add-repo \
//download.docker.com/linux/centos/docker-ce.repo #默認的是國外的十分慢
#阿里雲鏡像 (推薦使用)
yum-config-manager \
--add-repo \
//mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新yum軟件包索引
yun makecache fast
#安裝docker decker-ce社區版的 ee企業版
yum install docker-ce docker-ce-cli containerd.io
#啟動docker
systemctl start docker
#查看是否安裝成功
docker version
#啟動 hello-world
docker run hello-world
#查看下載的hello-world鏡像
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 weeks ago 13.3kB
#卸載docker
yum remove docker-ce docker-ce-cli containerd.io
#刪除資源
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
配置阿里雲鏡像加速
登錄阿里雲找到容器服務。
找到容器鏡像服務
配置使用
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["//tk46rux4.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
回顧helloworld流程
流程圖
工作原理
Docker是一個Client,Server結構的系統,Docker的守護進程運行在主機上,通過Socket從客戶端訪問。
DockerServer接收到DockerClient的指令,就會執行這個命令。
Docker為什麼比VNM快:
Docker有比虛擬機更少的抽象層。
Docker利用的是宿主機的內核,VM有自己的Guest OS。
新建一個容器的時候,Docker不需要像虛擬機一樣新建一個系統內核。利用宿主機的內核,提升了啟動速度和系統資源利用率。
Docker的常用命令
幫助命令
docker -version #顯示docker的版本信息
docker info #docker的詳細信息 鏡像和容器的數量
docker 命令 --help #萬能命令
docker --help #docker的所有命令
命令:官網地址 //docs.docker.com/reference/
鏡像命令
docker images:查看本機所有鏡像
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 weeks ago 13.3kB
#解釋
REPOSITORY 鏡像的倉庫源
TAG 鏡像的標籤
IMAGE ID 鏡像的 id
CREATED 鏡像的創建時間
SIZE 鏡像的大小
#可選項
-a, --all #顯示所有的鏡像
-q, --quiet #只顯示鏡像的id
docker search:搜索鏡像
[root@zhourui /]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10634 [OK]
mariadb MariaDB Server is a high performing open sou… 3990 [OK]
#可選項
--filter=STARS=3000 #搜索出來的就是stars大於等於3000的 -f簡寫
[root@zhourui /]# docker search mysql -f=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10634 [OK]
mariadb MariaDB Server is a high performing open sou… 3990 [OK]
docker pull:下載鏡像
#下載 docker pull 鏡像名 [:tag](可以選版本) 不寫版本默認latest最後一個
[root@zhourui /]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
a076a628af6f: Pull complete #分層下載 docker image核心 聯合文件系統
f6c208f3f991: Pull complete
88a9455a9165: Pull complete
406c9b8427c6: Pull complete
7c88599c0b25: Pull complete
25b5c6debdaf: Pull complete
43a5816f1617: Pull complete
1a8c919e89bf: Pull complete
9f3cf4bd1a07: Pull complete
80539cea118d: Pull complete
201b3cad54ce: Pull complete
944ba37e1c06: Pull complete
Digest: sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c #簽名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真實地址
# docker pull mysql
# 等價
# docker pull docker.io/library/mysql:latest
#指定版本下載
[root@zhourui /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
a076a628af6f: Already exists #共用
f6c208f3f991: Already exists
88a9455a9165: Already exists
406c9b8427c6: Already exists
7c88599c0b25: Already exists
25b5c6debdaf: Already exists
43a5816f1617: Already exists
1831ac1245f4: Pull complete
37677b8c1f79: Pull complete
27e4ac3b0f6e: Pull complete
7227baa8c445: Pull complete
Digest: sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d1165f221234 2 weeks ago 13.3kB
mysql 5.7 a70d36bc331a 2 months ago 449MB
mysql latest c8562eaf9d81 2 months ago 546MB
docker rmi:刪除鏡像
#刪除指定的容器 根據id
[root@zhourui /]# docker rmi -f c8562eaf9d81
#刪除多個鏡像
[root@zhourui /]# docker rmi -f id1 id2 id3
#刪除全部容器
[root@zhourui /]# docker rmi -f $(docker images -aq)
容器命令
我們有了鏡像才可以創建容器,下載一個CentOS鏡像來測試學習。
docker pull centos
新建容器並啟動
docker run (可選參數) image
#參數說明
--name=「Name」 #容器名字 tomcat01 tomcat01 來區分
-d #後台方式運行
-it #使用交互方式運行,進入容器查看內容
-p #指定容器的端口 -p 8080:8080
-p 主機端口:容器端口 (常用)
-p ip:主機端口:容器端口
-p 容器端口
容器端口(不寫-p)
-p #隨機指定端口
#啟動並進入容器
[root@zhourui /]# docker run -it centos /bin/bash
[root@b728c79b5448 /]# ls #查看容器內的centos 基礎版本 很多的命令不完善
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@b728c79b5448 /]# exit #退出命令
exit
[root@zhourui /]# ls
bin boot dev etc home lib lib64 media mnt opt patch proc root run sbin srv sys tmp usr var www
列出所有運行的容器
# docker ps
#列出所有在運行的容器
-a #列出歷史運行過的容器
-n=? #顯示最近創建的n個容器
-q #列出運行容器的id
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@zhourui /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b728c79b5448 centos "/bin/bash" 4 minutes ago Exited (0) 2 minutes ago relaxed_elbakyan
0ce52f9209e4 d1165f221234 "/hello" 5 hours ago Exited (0) 5 hours ago intelligent_mirzakhani
退出容器
exit #容器停止並退出
ctrl +P +Q #按住這三個鍵 容器不停止退出
[root@zhourui /]# docker run -it centos /bin/bash
[root@c9797d0b4ba8 /]# [root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9797d0b4ba8 centos "/bin/bash" About a minute ago Up About a minute inspiring_faraday
刪除容器
docker rm #刪指定id的容器 不能刪除正在運行的容器 強制刪除 rm -f
docker rm -f $(docker ps -aq) #刪除全部的容器
docker -a-q|xargs docker rm #刪除全部容器
啟動和停止容器的操作
docker start 容器id #啟動
docker restart 容器id #重啟
docker stop 容器id #停止容器
docker kill 容器id #強制停止
常用其它命令
後台啟動容器
# docker run -d 容器名 後台啟動
[root@zhourui /]# docker run -d centos
#運行docker ps 發現centos停止了
#docker容器使用後台運行,就必須有一個前台進程,docker發現沒有應用,就會自動停止
查看日誌
docker logs -f -t --tail 10 容器id #打印最近10條日誌
#編寫shell腳本
「while true;do echo zhourrrrr;sleep 1;done」
[root@zhourui /]# docker run -d centos /bin/bash -c "while true;do echo zhourrrr;sleep 1;done"
e79bac46e660abb781dcce7b0dbd3a3a896b573a104fdd9a15db0bbf5331341b
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e79bac46e660 centos "/bin/bash -c 'while…" 3 seconds ago Up 1 second jolly_sanderson
#顯示日誌
-tf #顯示日誌 t 時間
--tail number #最近的多少條數據
[root@zhourui /]# docker logs -f -t --tail 10 e79bac46e660
查看容器中的進程信息
docker top 容器id
[root@zhourui /]# docker top e79bac46e660
UID PID PPID C STIME TTY
root 227610 227588 0 22:36 ?
root 229020 227610 0 22:45 ?
查看鏡像源數據
docker inspect 容器id
[root@zhourui /]# docker inspect e79bac46e660
[
{
"Id": "e79bac46e660abb781dcce7b0dbd3a3a896b573a104fdd9a15db0bbf5331341b",
"Created": "2021-03-21T14:36:07.740342428Z",
"Path": "/bin/bash",
"Args": [
"-c",
"while true;do echo zhourrrr;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 227610,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-03-21T14:36:08.2053845Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
.........#省略...
}
}
進入當前正在運行的容器
#通常容器都是後台的方式運行的,需要進入容器修改一些配置
#命令
docker exec -it 容器id bashShell(bin/bash)
#測試
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
538cddb5e369 centos "bin/bash -c 'while …" 14 seconds ago Up 13 seconds quizzical_wing
[root@zhourui /]# docker exec -it 538cddb5e369 bin/bash
[root@538cddb5e369 /]#
[root@538cddb5e369 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@538cddb5e369 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 11:08 ? 00:00:00 bin/bash -c while true;do echo zzzzzrr;sleep 2;done
root 66 0 0 11:10 pts/0 00:00:00 bin/bash
root 131 1 0 11:12 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 2
root 132 66 0 11:12 pts/0 00:00:00 ps -ef
#方式二
docker attach 容器id
#測試
[root@zhourui /]# docker attach 538cddb5e369
zzzzzrr
zzzzzrr
zzzzzrr
zzzzzrr
#進去後是正在執行的當前代碼,想停止可以新開一個窗口 docker rm -f $(docker ps -aq)
# docker exec 進入後打開了一個新的終端,可以在裏面操作
# docker attach 進入容器正在執行的終端,不會啟動新的進程
從容器內拷貝文件到主機上
docker cp 容器id:容器內路徑 目的主機路徑
#測試
[root@zhourui /]# cd /home
[root@zhourui home]# ls
www zhour.java
[root@zhourui home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44e87620bf99 centos "/bin/bash" About a minute ago Up About a minute romantic_burnell
#進入容器
[root@zhourui home]# docker attach 44e87620bf99
[root@44e87620bf99 /]# cd /home
[root@44e87620bf99 home]# ls
#在容器內新建一個文件
[root@44e87620bf99 home]# touch zr.java
[root@44e87620bf99 home]# ls
zr.java
[root@44e87620bf99 home]# exit
exit
[root@zhourui home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@zhourui home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44e87620bf99 centos "/bin/bash" 3 minutes ago Exited (0) 6 seconds ago romantic_burnell
#將容器內的文件拷貝到主機上
[root@zhourui home]# docker cp 44e87620bf99:/home/zr.java /home
[root@zhourui home]# ls
www zhour.java zr.java
[root@zhourui home]#
#拷貝是一個手動過程,後面學習使用 -v 卷的技術,可以實現自動同步
小結
常用命令
練習部署
部署Nginx
-
搜索鏡像:docker search nginx
-
下載鏡像:docker pull nginx
-
運行測試:docker run -d –name nginx01 -p 3344:80 nginx (–name:起別名,-p 3344:80 3344是暴露的端口就是宿主機端口 80是nginx默認端口就是容器的端口)
[root@zhourui home]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest f6d0b4767a6c 2 months ago 133MB centos latest 300e315adb2f 3 months ago 209MB hello-world latest bf756fb1ae65 14 months ago 13.3kB #--name:起別名,-p 3344:80 3344是暴露的端口 80是nginx默認端口 [root@zhourui home]# docker run -d --name nginx01 -p 3344:80 nginx 56b36ad955ca7cf6d80708b20d7ffd1152a0ca974c312df45bfe9e31d0888e0b [root@zhourui home]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 56b36ad955ca nginx "/docker-entrypoint.…" 7 seconds ago Up 6 seconds 0.0.0.0:3344->80/tcp nginx01 [root@zhourui home]# curl localhost:3344 [root@zhourui home]# docker exec -it nginx01 bin/bash root@56b36ad955ca:/# whereis nginx nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx root@56b36ad955ca:/# cd /etc/nginx root@56b36ad955ca:/etc/nginx# ls conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf root@56b36ad955ca:/etc/nginx# #每次改動nginx的配置文件,都需要進入容器的內部修改,非常麻煩,後面學習數據卷的技術就可以在容器外部修改文件,容器內自動同步。
訪問自己服務器的nginx://39.105.48.232:3344/(前提是自己阿里雲服務器安全組中開啟了3344端口)
部署Tomcat
#docker hub 官方的使用
docker run -it --rm tomcat:9.0
#之前練習的啟動在後台,停止容器後,容器還在,可以查到。run -it --rm 一般用來測試,用完即刪除(容器刪除鏡像還在)
[root@zhourui /]# docker pull tomcat
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 040bdb29ab37 2 months ago 649MB
tomcat latest 040bdb29ab37 2 months ago 649MB
nginx latest f6d0b4767a6c 2 months ago 133MB
centos latest 300e315adb2f 3 months ago 209MB
hello-world latest bf756fb1ae65 14 months ago 13.3kB
[root@zhourui /]# docker run -d -p 3355:8080 --name tomcat01 tomcat
53197d7745a2d7f83f3a45b1f474a189eb7f496b0cf08c9a509a6c390680e347
[root@zhourui /]# curl localhost:3355
瀏覽器測試訪問://39.105.48.232:3355/(阿里雲安全組開啟端口),可以訪問但是顯示404。
#進入容器
[root@zhourui /]# docker exec -it tomcat01 /bin/bash
root@53197d7745a2:/usr/local/tomcat# ls
BUILDING.txt CONTRIBUTING.md LICENSE NOTICE README.md RELEASE-NOTES RUNNING.txt bin conf lib logs native-jni-lib temp webapps webapps.dist work
root@53197d7745a2:/usr/local/tomcat# cd webapps
root@53197d7745a2:/usr/local/tomcat/webapps# ls
root@53197d7745a2:/usr/local/tomcat/webapps#
#發現ll無法使用,ls-al可以使用,命令少了。webapps中是空的,默認的是最小的鏡像,不必要的被刪除了,保證的是最小可用環境。
如果想要訪問,可以複製webapps.dist目錄的內容到webapps中
root@53197d7745a2:/usr/local/tomcat/webapps# cd ..
root@53197d7745a2:/usr/local/tomcat# cd webapps.dist
root@53197d7745a2:/usr/local/tomcat/webapps.dist# ls
ROOT docs examples host-manager manager
root@53197d7745a2:/usr/local/tomcat/webapps.dist# cd ..
root@53197d7745a2:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@53197d7745a2:/usr/local/tomcat# cd webapps
root@53197d7745a2:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
root@53197d7745a2:/usr/local/tomcat/webapps#
再次刷新網頁訪問即可!
部署es+kibana
#es暴漏的端口十分多
#es十分耗內存
#es的數據一般需要放置到安全目錄,掛載。
#--net somenetwork 網絡配置
#啟動(啟動前停掉其它的容器,防止啟動不了)
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#docker stats 容器id 查看cpu的狀態
#啟動後 發現執行docker ps命令非常卡,因為內存快耗盡。
啟動後可以從寶塔上看到自己服務器的內存狀態。(也可以使用命令docker stats 容器id 查看cpu,內存的狀態)
停掉es
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
94c6cad2a01d elasticsearch:7.6.2 "/usr/local/bin/dock…" 5 minutes ago Up 5 minutes 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch
[root@zhourui /]# docker stop 94c6cad2a01d
94c6cad2a01d
這時查看服務器的狀態
再次啟動,增加內存的配置,修改配置文件,-e 環境配置修改。
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
可視化
- portainer(圖形化界面管理工具,提供一個面板供操作)
docker run -d -p 9222:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
- Rancher(CI/CD 持續集成/持續部署時使用)
啟動portainer後訪問測試://39.105.48.232:9222/,密碼可以隨意輸入。
進入後選擇local,點擊connect
可以看到鏡像,容器等
查看鏡像
Docker鏡像
鏡像是什麼:鏡像是一種輕量級的,可執行的獨立軟件包。用來打包軟件運行環境和基於運行環境開發的軟件,它包含運行某個軟件所需的所有內容,包括代碼,運行時,庫,環境變量和配置文件。
將應用直接打包為docker鏡像,就可以直接跑起來。
如何得到鏡像:
- 從倉庫下載
- 自己製作一個鏡像
Docker鏡像加載原理
UnionFS(聯合文件系統):Union文件系統(UnionFS)是一種分層,輕量級並且高性能的文件系統,它支持對文件系統的修改作為一次提交來一層層的疊加,同時可以將不同的目錄掛載到同一個虛擬文件系統下。Union文件系統是 docker 鏡像的基礎。鏡像可以通過分層來進行繼承,基於基礎鏡像(沒有父鏡像),可以製作具體的應用鏡像。
特性:一次同時加載多個文件系統,但從外面看起來,只能看到一個文件系統,聯合加載會把各層文件系統疊加起來,這樣最終的文件系統會包含所有底層的文件和目錄。
Docker鏡像加載原理:docker鏡像實際上是由一層一層的文件系統組成,這種層級的文件系統叫UnionFS(聯合文件系統)。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引導加載kernel,Linux剛啟動時會加載bootfs文件系統,在Docker鏡像的最底層是bootfs,這一層與我們典型的Linux/Unix系統是一樣的,包含boot加載和內核,當boot加載完之後整個內核都在內存中了,此時內存的使用權已由bootfs轉交給內核,此時系統也會卸載bootfs。
rootfs(root file system)在bootfs之上,包含的就是典型LInux系統中的 /dev,/proc,/bin,/etc等標準目錄和文件,rootfs就是各種不同的操作系統發行版,比如Ubantu,Centos等。
可以使用docker images看到Centos的鏡像非常小。
對於一個精簡的OS,rootfs可以很小,只需包含最基本的命令,工具和程序庫就可以了,因為底層直接用Host的kernel,自己只需提供rootfs就可以了,因此可見對於不同的Linux發行版,bootfs基本是一致的,rootfs會有差別,因此不同的發行版可以共用bootfs。
分層理解
下載一個鏡像,觀察日誌輸出,可以看到是一層一層的在下載(分層下載,提高了復用性)
使用docker inspect redis,可以看到RootFS
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:cb42413394c4059335228c137fe884ff3ab8946a014014309676c25e3ac86864",
"sha256:8e14cb7841faede6e42ab797f915c329c22f3b39026f8338c4c75de26e5d4e82",
"sha256:1450b8f0019c829e638ab5c1f3c2674d117517669e41dd2d0409a668e0807e96",
"sha256:f927192cc30cb53065dc266f78ff12dc06651d6eb84088e82be2d98ac47d42a0",
"sha256:a24a292d018421783c491bc72f6601908cb844b17427bac92f0a22f5fd809665",
"sha256:3480f9cdd491225670e9899786128ffe47054b0a5d54c48f6b10623d2f340632"
]
},
理解:所有的Docker鏡像都起始於一個基礎鏡像層,當進行修改或增加新的內容時,都會在當前的鏡像層上,創建新的鏡像層。在添加額外的鏡像層時,鏡像始終保持是當前所有鏡像的組合。
特點:
docker鏡像都是只讀的,當容器啟動時,一個新的可寫層被加載到鏡像的頂部。這一層通常是我們所說的容器層,容器之下都是鏡像層。
commit鏡像
docker commit #提交容器成為一個新的副本
#命令和git類似
docker commit -m=「提交描述信息」 -a=「作者」 容器id 目標鏡像名:[TAG]
測試
#啟動一個tomcat
docker run -it -p 8081:8080 tomcat
#在新的窗口進入tomcat
[root@zhourui /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS 1fd9b7b4cb3d tomcat "catalina.sh run" 28 seconds ago Up 27 seconds 0.0.0.0:8081->8080/tcp
[root@zhourui /]# docker exec -it 1fd9b7b4cb3d /bin/bash
#官方默認的tomcat的webapps下面沒有應用,自己拷貝
cp -r webapps.dist/* webapps
#提交自己的鏡像,以後使用修改過的鏡像即可
[root@zhourui /]# docker commit -a="zhourr" -m="add webapps" 1fd9b7b4cb3d tomcat02:1.0
sha256:1c7804b415ba38099178f63e48444aebec938252632defd16bb35acc71bdabab
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 1.0 1c7804b415ba 6 seconds ago 654MB
redis latest 621ceef7494a 2 months ago 104MB
tomcat 9.0 040bdb29ab37 2 months ago 649MB
tomcat latest 040bdb29ab37 2 months ago 649MB
nginx latest f6d0b4767a6c 2 months ago 133MB
centos latest 300e315adb2f 3 months ago 209MB
portainer/portainer latest 62771b0b9b09 8 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 12 months ago 791MB
hello-world latest bf756fb1ae65 14 months ago 13.3kB
[root@zhourui /]#
對容器進行修改後,想保存容器的狀態,通過commit來提交,下次就可以使用自己提交的這個鏡像了。就好比 vm 的快照功能。
容器數據卷
如果數據在容器中,那麼將容器刪除,數據就會丟失!需求,數據可持久化!!
MySQL容器刪除,數據丟失,需求,MySQL數據可以存儲在本地!!
容器之間可以有一個數據共享的技術。Docker容器中產生的數據,同步到本地。
這就是卷技術!將容器內的目錄,掛載到主機上。
數據持久化和同步操作,容器間也是可以數據共享的。
使用數據卷
方式一:使用命令來掛載 -v
docker -it -v主機內的目錄:容器內的目錄
#測試
[root@zhourui home]# docker run -it -v /home/zrtest:/home centos /bin/bash
#啟動後使用 docker inspect 容器id 查看
使用 docker inspect 容器id 查看
測試文件的同步
1.停止容器
2.修改宿主機上的文件
3.啟動容器,發現文件依舊是同步的
好處:以後修改只需要在本地修改即可,不需要進入容器!
部署MySQL
MySQL的數據持久化問題!
#獲取鏡像
docker pull mysql:5.7
#運行容器,數據掛載。安裝mysql需要配置密碼的,注意!
#官方測試連接方法
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#啟動MySQL
-d:後台運行
-p:端口映射
-v:數據卷掛載
-e:環境配置
--name:容器別名
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
#在本地連接上後創建一個test數據庫,查看映射路徑是否可以。
在本地使用Navicat測試連接
將容器刪除後
[root@zhourui data]# ls
auto.cnf ca.pem client-key.pem ibdata1 ib_logfile1 mysql private_key.pem server-cert.pem sys
ca-key.pem client-cert.pem ib_buffer_pool ib_logfile0 ibtmp1 performance_schema public_key.pem server-key.pem test
可以看到test數據庫還在,即掛載到本地的數據卷沒有丟失,這就實現了容器數據的持久化。
具名掛載和匿名掛載
#匿名掛載
-P(大寫P 隨機映射端口)
-v 容器內路徑
docker run -d -P --name nginx01 -v /etc/nginx nginx
#查看所有的卷的情況
[root@zhourui home]# docker volume ls
DRIVER VOLUME NAME
local 42a60ffb1a9dfcefffdf269e3a08fcb9172a082babe6ea19b864d5f679eb4361
local 93e2f2060025965b83b0433b95e29ac325c25fa8684b79a12617438ffe898941
local 271ccfa1da7814fa8fceb5b482ce86009f97e29c09dca69bcc594a0d8fabb92a
#匿名掛載:這裡-v的時候只寫了容器內的路徑,沒有寫容器外的路徑
#具名掛載
[root@zhourui home]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
3024685007a57eda45820c8c07920cea08b84b7847b86fd97f5f71f7100b8fbd
[root@zhourui home]# docker volume ls
DRIVER VOLUME NAME
local 42a60ffb1a9dfcefffdf269e3a08fcb9172a082babe6ea19b864d5f679eb4361
local 93e2f2060025965b83b0433b95e29ac325c25fa8684b79a12617438ffe898941
local 271ccfa1da7814fa8fceb5b482ce86009f97e29c09dca69bcc594a0d8fabb92a
local juming-nginx
[root@zhourui home]#
#通過-v 卷名:容器內名字
#查看卷
[root@zhourui home]# docker volume inspect juming-nginx
所有docker容器內的卷,在沒有指定目錄的情況下都是在 /var/lib/docker/volumes/xxxx/_data。
通過具名掛載可以方便的找到我們的卷,大多數情況下都是使用具名掛載。
#如何確定是具名掛載還是匿名掛載,還是指定路徑掛載
-v 容器內路徑 #匿名掛載
-v 卷名:容器內路徑 #具名掛載
-v /宿主機路徑:容器內路徑 #指定路徑掛載
拓展:
#通過-v 卷名:容器內路徑:ro或rw 改變讀寫權限
ro readonly #只讀
rw readwrite #可讀可寫
#一旦設置了容器權限,容器對掛載出來的文件就有限定了
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
#只要看到ro,就說明這個文件只能通過宿主機來操作,容器內部是無法操作的!
初識Dockerfile
Dockerfile就是用來構建 docker 鏡像的構建文件!命令腳本!
通過這個腳本可以生成鏡像。鏡像是一層一層的,腳本是一個個的命令,每個命令都是一層。
方式二:
[root@zhourui home]# pwd
/home
[root@zhourui home]# cd docker-test-volume/
[root@zhourui docker-test-volume]# pwd
/home/docker-test-volume
[root@zhourui docker-test-volume]# vim dockerfile #創建dockerfile
[root@zhourui docker-test-volume]# cat dockerfile #文件中添加以下內容後查看(文件中內容 指令(大寫) 參數)
#每個命令就是鏡像的一層
FROM centos
VOLUME ["volume01","volume02"] #匿名掛載
CMD echo "....end...."
CMD /bin/bash
[root@zhourui docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile -t zhour/centos:1.0 .
#啟動自己生成的容器
docker run -it 29e054de9dd4 /bin/bash
#在volume01中創建文件
[root@e224b7ebc0d7 volume01]# ls
[root@e224b7ebc0d7 volume01]# touch container.txt
[root@e224b7ebc0d7 volume01]# ls
container.txt
[root@e224b7ebc0d7 volume01]#
查看匿名卷掛載的路徑:docker inspect 容器id
進入掛載的路徑中查看
[root@zhourui /]# cd /var/lib/docker/volumes/f517ef934bb1d4376751cf0ec11608ed0fd287844436ba62cad973ce0f67dee8/_data
[root@zhourui _data]# ls
container.txt
[root@zhourui _data]#
可以看到文件已經同步!!
這種方式較常使用,通常用於構建自己的鏡像。
假設構建鏡像時沒有掛載卷,需要手動掛載,-v 卷名:容器內路徑。
數據卷容器
啟動三個容器
#創建docker01
[root@zhourui /]# docker run -it --name docker01 29e054de9dd4
[root@255f9d13bea7 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02
#創建docker02
[root@zhourui /]# docker run -it --name docker02 --volumes-from docker01 29e054de9dd4
[root@861b5d25a8ca /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01 volume02
#在docker01的volume01中創建文件
[root@zhourui /]# docker attach 255f9d13bea7
[root@255f9d13bea7 /]# cd volume01
[root@255f9d13bea7 volume01]# ls
[root@255f9d13bea7 volume01]# touch docker01
#進入docker02的volume01中查看
[root@861b5d25a8ca /]# cd volume01
[root@861b5d25a8ca volume01]# ls
docker01
#創建docker03並在volume01中增加docker03文件
[root@zhourui /]# docker run -it --name docker03 --volumes-from docker01 29e054de9dd4
[root@7a405584084a /]# cd volume01
[root@7a405584084a volume01]# ls
docker01
[root@7a405584084a volume01]# touch docker03
[root@7a405584084a volume01]# ls
docker01 docker03
#在docker01中查看volume01
[root@255f9d13bea7 volume01]# ls
docker01 docker03
[root@255f9d13bea7 volume01]#
通過 –volumes-from 可以實現容器間的數據共享!!
可以測試刪除掉 docker01 ,再去查看 docker02 和 docker03 ,數據仍然還在。
三個容器之間的文件是相互拷貝的,刪掉一個不會丟失數據。
應用:多個 MySQL 或者 Redis 之間實現數據共享!!
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
#可以實現兩個MySQL之間的數據同步
結論:容器之間配置信息的傳遞,數據卷容器的生命周期是一直持續到沒有容器使用為止。
通過 -v 將數據持久化到本地,本地的數據是不會刪除的。
DockerFile
DockerFile介紹
dockerfile是用來構建 docker 鏡像的文件。命令參數腳本。
構建步驟:
- 編寫一個 dockerfile 文件
- docker build 構建成為一個鏡像
- docker run 運行鏡像
- docker push 發佈鏡像(dockerHub,阿里雲鏡像倉庫)
查看官方 centos,點擊版本會跳轉至 GitHUb
很多的官方鏡像都是基礎包,一些功能沒有,我們就需要自己搭建。
DockerFile構建過程
基礎知識:
- 每個保留關鍵字(指令)必須是大寫字母。
- 只需順序從上到下。
-
, 表示注釋。
- 每個指令都會創建提交一個新的鏡像層。
docker 是面向開發的,發佈項目做鏡像,就需要編寫 dockerfile 文件。
Docker鏡像逐漸成為企業交付的標準。
dockerfile :構建文件,定義了一切所需的環境和源代碼。
dockerImage:通過 dockerfile 構建生成的鏡像,最終發佈和運行的產品。
docker 容器:容器是鏡像運行起來後提供服務的。
DockerFile指令
FROM #基礎鏡像,一切從這裡開始構建
MAINTAINER #鏡像是誰寫的
RUN #docker 鏡像構建的時候需要運行的命令
ADD #步驟:使用tomcat鏡像,tomcat壓縮包,就是添加的內容
WORKDIR #鏡像的工作目錄
VOLUME #掛載的目錄位置
EXPOSE #暴漏端口配置
CMD #指定這個容器啟動的時候要運行的命令,只有最後一個會生效,可被替代
ENTRYPOINT #指定這個容器啟動的時候要運行的命令,可以追加命令
ONBUILD #當構建一個被繼承的 dockerfile 這個時候會運行 ONBUILD 的指令,觸髮指令
COPY #類似add命令,將文件拷貝拷貝到目錄中
ENV #構建的時候設置環境變量
實戰測試
Docker Hub 中99%的鏡像都是由這個基礎鏡像 FROM scratch 來配置構建的
FROM scratch
ADD centos-8-x86_64.tar.xz /
LABEL \
org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20201204"
CMD ["/bin/bash"]
創建一個自己的 CentOS
#編寫 dockerfile 的文件
[root@zhourui home]# cd dockerfile/
[root@zhourui dockerfile]# ls
[root@zhourui dockerfile]# vim mydockerfile-centos
[root@zhourui dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER zhourr<813794474@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH #進去後的工作目錄,進去後 pwd 查看
RUN yum -y install vim #安裝 vim
RUN yum -y install net-tools #安裝後可以使用 ifconfig (不安裝只能用 ip add)
EXPOSE 80
CMD echo $MYPATH
CMD echo "...end..."
CMD /bin/bash
#通過這個文件構建鏡像
-f 構建文件路徑
-t 鏡像名:[tag]
最後有個 .
[root@zhourui dockerfile]# docker build -f mydockerfile-centos -t mycentos:0.1 .
...
Successfully built ddba7ccc7eee
Successfully tagged mycentos:0.1
#測試運行
docker run -it mycentos:0.1
默認的 centos 以下命令無法使用
[root@95c725dda358 /]# pwd
/
[root@95c725dda358 /]# vim
bash: vim: command not found
[root@95c725dda358 /]# ifconfig
bash: ifconfig: command not found
[root@95c725dda358 /]#
測試運行自己創建的鏡像這些命令就可以使用了。
我們可以列出本地鏡像的變更歷史 docker history 鏡像id
CMD和ENTRYPOINT的區別
CMD #指定這個容器啟動的時候要運行的命令,只有最後一個會生效,可被替代
ENTRYPOINT #指定這個容器啟動的時候要運行的命令,可以追加命令
測試 CMD
[root@zhourui dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
#構建鏡像
[root@zhourui dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
....
Successfully built a44c7103184f
Successfully tagged cmdtest:latest
# run 運行,可以看到 ls-a 命令生效
[root@zhourui dockerfile]# docker run a44c7103184f
.
..
.dockerenv
bin
dev
etc
home
lib
...
#追加一個 l ,希望返回 ls-al
[root@zhourui dockerfile]# docker run a44c7103184f -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
#此時報錯,因為使用CMD,-l替換了["ls","-a"],-l不是命令,所以報錯
#需要使用以下完整命令
[root@zhourui dockerfile]# docker run a44c7103184f ls -al
測試 ENTRYPOINT
[root@zhourui dockerfile]# vim dockerfile-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]
[root@zhourui dockerfile]# docker build -f dockerfile-entrypoint -t entrypointtest .
...
Successfully built 34773b8b0398
Successfully tagged entrypointtest:latest
[root@zhourui dockerfile]# docker run 34773b8b0398
.
..
.dockerenv
bin
dev
etc
home
lib
...
# 添加 -l,是可以直接追加到後面的,ls -a -l
[root@zhourui dockerfile]# docker run 34773b8b0398 -l
total 0
drwxr-xr-x 1 root root 6 Mar 27 14:51 .
drwxr-xr-x 1 root root 6 Mar 27 14:51 ..
-rwxr-xr-x 1 root root 0 Mar 27 14:51 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 340 Mar 27 14:51 dev
drwxr-xr-x 1 root root 66 Mar 27 14:51 etc
drwxr-xr-x 2 root root 6 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
Docker中很多命令都十分相似,需要去對比測試一下,才能發現其中的區別。
實戰 Tomcat鏡像
-
準備鏡像文件 tomcat 壓縮包,jdk壓縮包(放到home/zhour-tar目錄下)
-
編寫 Dockerfile 文件,官方命名:Dockerfile,build的時候會自動尋找這個文件,就不需要 -f 指定了。(在home/zhour-tar目錄下,vim Dockerfile),壓縮包會自動解壓。
FROM centos MAINTAINER zhourr<813794474@qq.com> COPY readme.txt /usr/local/read.txt ADD jdk-8u281-linux-x64.tar.gz /usr/local/ ADD apache-tomcat-9.0.44.tar.gz /usr/local/ RUN yum -y install vim ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0_281 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.44 ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.44 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin EXPOSE 8080 CMD /usr/local/apache-tomcat-9.0.44/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.44/bin/logs/catalina.out
-
構建鏡像
[root@zhourui zhour-tar]# ls apache-tomcat-9.0.44.tar.gz Dockerfile jdk-8u281-linux-x64.tar.gz readme.txt #構建 [root@zhourui zhour-tar]# docker build -t diytomcat .
-
啟動鏡像
[root@zhourui zhour-tar]# docker run -d -p 3030:8080 --name zhoutomcat -v /home/zhour-tar/test:/usr/local/apache-tomcat-9.0.44/webapps/test -v /home/zhour-tar/tomcatlogs/:/usr/local/apache-tomcat-9.0.44/logs diytomcat
-
訪問測試
-
發佈項目(配置了數據卷掛載,直接在容器外編寫項目就可以發佈了)在test中新建
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="//www.w3.org/2001/XMLSchema-instance" xmlns="//java.sun.com/xml/ns/javaee" xsi:schemaLocation="//java.sun.com/xml/ns/javaee //java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> </web-app>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello zhourrr!!</title> </head> <body> Hello World!<br/> <% System.out.println("----my tomcat test----"); %> </body> </html>
-
訪問//39.105.48.232:3030/test/
-
日誌查看,cd /home/zhour-tar/tomcatlogs。cat catalina.out
需要掌握 Dockersfile 的編寫!!
發佈鏡像
在 Docker Hub 上註冊賬號,在服務器登錄後就可以提交自己的鏡像了。
[root@zhourui tomcatlogs]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.
Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
登錄
[root@zhourui tomcatlogs]# docker login -u zhourui88
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
//docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
提交
[root@zhourui tomcatlogs]# docker push diytomcat
Using default tag: latest
The push refers to repository [docker.io/library/diytomcat]
e21bfbb06ee5: Preparing
145f6d70801c: Preparing
f3ba2f2219d6: Preparing
f83a7c49f1e3: Preparing
2653d992f4ef: Preparing
denied: requested access to the resource is denied #拒絕
#需要增加一個tag
[root@zhourui tomcatlogs]# docker tag ea84d80641b1 zhourui88/tomcat:1.0
#查看
[root@zhourui tomcatlogs]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
diytomcat latest ea84d80641b1 About an hour ago 640MB
zhourui88/tomcat 1.0 ea84d80641b1 About an hour ago 640MB
#提交
[root@zhourui tomcatlogs]# docker push zhourui88/tomcat:1.0
提交的時候鏡像也是按層級來提交的!
阿里雲服務器
-
登錄阿里雲
-
找到容器鏡像服務
-
創建命名空間
-
創建容器鏡像
-
點擊鏡像倉庫名 zhourui-test 瀏覽阿里雲
#登錄
[root@zhourui /]# sudo docker login --username=周銳822 registry.cn-beijing.aliyuncs.com
#提交到阿里雲,這裡沒有更改tag,顯示上傳成功,但是我沒有找到鏡像
[root@zhourui /]# docker push zhourui88/tomcat:1.0
The push refers to repository [docker.io/zhourui88/tomcat]
e21bfbb06ee5: Layer already exists
145f6d70801c: Layer already exists
f3ba2f2219d6: Pushing [==========> ] 77.66MB/356.6MB
f83a7c49f1e3: Layer already exists
#上傳阿里雲
[root@zhourui /]# sudo docker tag ea84d80641b1 registry.cn-beijing.aliyuncs.com/docker-zhourui/zhourui-test:1.0
[root@zhourui /]# docker images
REPOSITORY TAG IMAGE ID CREATED
diytomcat latest ea84d80641b1 3 hours ago
zhourui88/tomcat 1.0 ea84d80641b1 3 hours ago
registry.cn-beijing.aliyuncs.com/docker-zhourui/zhourui-test 1.0 ea84d80641b1 3 hours ago
[root@zhourui /]# docker push registry.cn-beijing.aliyuncs.com/docker-zhourui/zhourui-test:1.0
上傳後查看
小結
Docker網絡
理解 Dockers0
ip addr
#啟動容器
[root@zhourui /]# docker run -d -P --name tomcat01 tomcat
72dee6c91e3f593c69858191014b9d228c6494b0aa049cd1f620350c1c46cd56
#查看容器內部網絡地址 eth0@if123 ip地址 docker分配的
[root@zhourui /]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
#Linux去ping容器的內部
[root@zhourui /]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.045 ms
原理:我們每啟動一個 docker 容器,docker就會給docker容器分配一個ip,我們只要安裝了docker,就會有一個網卡docker0.
橋接模式,使用的技術是 evth-pair 技術
這時再輸入 ip addr,發現多了一個網卡
再啟動一個 tomcat02 發現又多了一個網卡 (docker run -d -P –name tomcat02 tomcat) ipaddr
查看tomcat02 ip addr
[root@zhourui /]# docker exec -it tomcat02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
124: eth0@if125: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以發現容器的網卡都是一對一對的,【122: eth0@if123】【124: eth0@if125】。
evth-pair:就是一對虛擬設備接口,它們都是成對出現的,一段連着協議,一段彼此相連。
所以,evth-pair就充當一個橋樑,連接各種虛擬網絡設備。
測試tomcat01和tomcat02之間能不能ping通:
[root@zhourui /]# docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.091 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.069 ms
#可以看到,容器之間是可以通信的
流程圖理解
tomcat01 和 tomcat02 是公用一個路由器 docker0 。
所有容器不指定網絡的情況下,都是 docker0 路由的,doker會給容器分配一個默認的可用 ip。
Docker使用的是 Linux 的橋接,宿主機中是 Docker 容器的網橋(Docker0)
Docker 中所有的網絡接口都是虛擬的,虛擬的轉發效率高。
只要刪除容器,對應的網橋就沒了。
docker network ls,docker network inspect (橋接network id)可以查看
–link
假設我們想通過容器的名字來ping,而不是通過ip,就需要使用 –link。
[root@zhourui /]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
#通過--link可以解決
[root@zhourui /]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
131bbb6e180687ff284ef2cabc78f4104dfc5d1018ee1e2f11a5b6e192bdc8bb
[root@zhourui /]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.101 ms
#反向ping
[root@zhourui /]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
docker network ls,docker network inspect (橋接network id)可以查看
–link 使用後,tomcat03在本地配置了tomcat02
[root@zhourui /]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 tomcat02 1fff64acaf04
172.17.0.4 131bbb6e1806
本質:在hosts的配置中增加了 tomcat02 的映射。
真實開發中,已經不建議使用 –link 了。
自定義網絡,不使用 docker0。docker0不支持容器名連接訪問。
自定義網絡
查看所有的docker網絡
[root@zhourui /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
25000c3be4a4 bridge bridge local #橋接
b518cb3beba9 host host local
bcd06ce03d47 none null local
網絡模式
bridge:橋接(docker默認)自己創建也使用 bridge 模式
none:不配置網絡
host:和宿主機共享網絡
container:容器內網絡聯通(局限性很大)
測試:
#直接啟動,默認是 --net bridge 的,
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
#docker0特點,默認,域名不能訪問,--link可以打通連接
#自定義網絡
# --driver bridge
# --subnet 192.168.0.0/16
# --gateway 192.168.0.1
[root@zhourui /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
6219f386e2bfc7f837554de2b011ec1d649d6eaafa617fcf4bdd2d8091cf82b2
[root@zhourui /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
25000c3be4a4 bridge bridge local
b518cb3beba9 host host local
6219f386e2bf mynet bridge local
bcd06ce03d47 none null local
查看自己的網絡:docker network inspect mynet
創建兩個容器,連上自己的網絡
[root@zhourui /]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
c638c0cee8dff978e60532b9a1ddac74f10a45bfb6b542bf3fd3079f69ec5515
[root@zhourui /]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
e9aee8d922b19af82f02e9e50b28a301ab10e7eb57828c454cb57b9ac5bdc0ae
[root@zhourui /]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "6219f386e2bfc7f837554de2b011ec1d649d6eaafa617fcf4bdd2d8091cf82b2",
"Created": "2021-03-28T17:29:39.571024726+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"c638c0cee8dff978e60532b9a1ddac74f10a45bfb6b542bf3fd3079f69ec5515": {
"Name": "tomcat-net-01",
"EndpointID": "6d4ac08b616e2e33e8fb7a3e8659b5a6ff2e381083572dbe202f7b8598347177",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"e9aee8d922b19af82f02e9e50b28a301ab10e7eb57828c454cb57b9ac5bdc0ae": {
"Name": "tomcat-net-02",
"EndpointID": "187733df51f17912e402211643ce7136cbb725d85a0c1045ef7e903471d9f878",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
#再次測試 ping 連接
[root@zhourui /]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.115 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 192.168.0.3: icmp_seq=3 ttl=64 time=0.068 ms
^C
--- 192.168.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 67ms
rtt min/avg/max/mdev = 0.067/0.083/0.115/0.023 ms
#不使用 --link。也可以ping名字了
[root@zhourui /]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.075 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.070 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.086 ms
自定義的網絡donker幫我們維護好了關係,推薦使用自定義的網絡。
應用:
redis:不同的集群使用不同的網絡,保證集群是安全和健康的(192.168.xxx.xxx)
mysql:不同的集群使用不同的網絡,保證集群是安全和健康的(192.182.xxx.xxx)
網絡聯通
創建兩個容器在默認的docker0網絡下
[root@zhourui /]# docker run -d -P --name tomcat01 tomcat
[root@zhourui /]# docker run -d -P --name tomcat02 tomcat
現在就有以下的四個容器在在 docker0 和 mynet 網絡下。怎樣去打通 tomcat01 連接到 mynet。
通過 –help 查看命令
測試打通 tomcat01 連接到 mynet
[root@zhourui /]# docker network connect mynet tomcat01
[root@zhourui /]# docker network inspect mynet
#打通之後,tomcat01被放到了 mynet 網絡下,
#一個容器兩個 ip 地址
測試
[root@zhourui /]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.092 ms
#反向也是可以ping通的
[root@zhourui /]# docker exec -it tomcat-net-01 ping tomcat01
PING tomcat01 (192.168.0.4) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.4): icmp_seq=1 ttl=64 time=0.118 ms
#tomcat02 是沒有連接上 mynet 的
[root@zhourui /]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
結論:如果需要跨網絡操作,就需要使用 docker network connect 網絡 容器名稱 來聯通!!
部署Redis集群
#創建redis的網絡
docker network create redis --subnet 172.38.0.0/16
#通過腳本創建6個redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf; \
#=====================================================================
#單個啟動
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
#創建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
[root@zhourui /]# docker exec -it redis-1 /bin/sh
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 1524f57c751c662847b24edb3cf4433e42e11dae 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 3d0a68b584e5935b6174d8b8e0603a14eb246393 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: cce404917b84b790cf39ac1f6dff85c1c080c9a1 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 2fb9e53fde60fb288e87a8bccf37f2d521c5f5be 172.38.0.14:6379
replicates cce404917b84b790cf39ac1f6dff85c1c080c9a1
S: d977bb4c2b2a45bbbeb74cc123bd87dba1acd257 172.38.0.15:6379
replicates 1524f57c751c662847b24edb3cf4433e42e11dae
S: 317ccf18aefe00a7a45820b6509bd8c9fc1f7097 172.38.0.16:6379
replicates 3d0a68b584e5935b6174d8b8e0603a14eb246393
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 1524f57c751c662847b24edb3cf4433e42e11dae 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: cce404917b84b790cf39ac1f6dff85c1c080c9a1 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 3d0a68b584e5935b6174d8b8e0603a14eb246393 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 317ccf18aefe00a7a45820b6509bd8c9fc1f7097 172.38.0.16:6379
slots: (0 slots) slave
replicates 3d0a68b584e5935b6174d8b8e0603a14eb246393
S: d977bb4c2b2a45bbbeb74cc123bd87dba1acd257 172.38.0.15:6379
slots: (0 slots) slave
replicates 1524f57c751c662847b24edb3cf4433e42e11dae
S: 2fb9e53fde60fb288e87a8bccf37f2d521c5f5be 172.38.0.14:6379
slots: (0 slots) slave
replicates cce404917b84b790cf39ac1f6dff85c1c080c9a1
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
/data # redis-cli -c
127.0.0.1:6379> cluster info
127.0.0.1:6379> cluster nodes
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
172.38.0.13:6379>
#新建窗口 docker stop redis-3
#獲取 a 的值
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
搭建redis集群完成!!
SpringBoot打包Dockers鏡像
-
構建一個SpringBoot項目
@RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "Hello zhour!"; } }
-
打包應用,package
-
編寫dockerfile
FROM java:8 COPY *.jar /app.jar CMD ["---server port 8080---"] EXPOSE 8080 ENTRYPOINT ["java","-jar","app.jar"]
-
構建鏡像(使用 ftp 將文件上傳至服務器)
[root@zhourui idea]# ls demo-docker-0.0.1-SNAPSHOT.jar Dockerfile [root@zhourui idea]# docker build -t boottestzr .
-
發佈運行
[root@zhourui idea]# docker run -d -P --name ideaboot-web boottestzr
-
訪問
如需瀏覽器訪問,阿里雲開發端口,或者運行時 -p 暴漏已開放的端口即可!!