­

Docker學習筆記—通俗易懂

Docker

簡介

Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中,然後發佈到任何流行的 LinuxWindows 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口。

Docker是基於 Go 語言開發的,是一個開源項目。

文檔地址://docs.docker.com/

倉庫地址://hub.docker.com/

虛擬機技術缺點:模擬一個完整的操作系統,資源佔用多,步驟冗餘,啟動慢。

Docker 容器化技術:不是模擬的一個完整的操作系統。運行在宿主機的內核上。每個容器內是互相隔離的,互不影響。

DevOps:開發 運維。

應用更快的交付和部署。

傳統:安裝各種的jar包,打包發佈。

Docker :一鍵打包鏡像發佈,測試。

更便捷的升級和擴縮容,項目打包為一個鏡像,部署應用就和搭積木一樣。

更簡單的系統運維,容器化後,開發測試環境都是一致的。

更高效的計算資源利用,Docke是內核級的虛擬化,在一個物理機上可以運行很多的容器。

Docker安裝

Docker的基本組成

鏡像(image):

就好比是一個模板,可通過這個鏡像來創建容器服務,比如 tomcat 鏡像—>run—>tomcat01容器,通過這個鏡像可以創建多個容器(應用最終在容器中運行)。

容器(container):

Docker利用容器技術,獨立運行一個或一組應用,通過鏡像創建。

啟動,停止,刪除,基本命令。

倉庫(repository):

存放鏡像的地方。倉庫分為公有倉庫和私有倉庫。

安裝Docker

環境準備:

  1. 需要會Linux基礎
  2. Centos7
  3. 使用Xshell連接遠程服務器操作
  4. 已經購買雲服務器(以下使用阿里雲)

環境查看

#系統內核是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

  1. 搜索鏡像:docker search nginx

  2. 下載鏡像:docker pull nginx

  3. 運行測試: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 鏡像的文件。命令參數腳本。

構建步驟:

  1. 編寫一個 dockerfile 文件
  2. docker build 構建成為一個鏡像
  3. docker run 運行鏡像
  4. docker push 發佈鏡像(dockerHub,阿里雲鏡像倉庫)

查看官方 centos,點擊版本會跳轉至 GitHUb

很多的官方鏡像都是基礎包,一些功能沒有,我們就需要自己搭建。

DockerFile構建過程

基礎知識:

  1. 每個保留關鍵字(指令)必須是大寫字母。
  2. 只需順序從上到下。
  3. , 表示注釋。

  4. 每個指令都會創建提交一個新的鏡像層。

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鏡像

  1. 準備鏡像文件 tomcat 壓縮包,jdk壓縮包(放到home/zhour-tar目錄下)

  2. 編寫 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
    
    
  3. 構建鏡像

    [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 .
    
    
  4. 啟動鏡像

    [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
    
    
  5. 訪問測試

  6. 發佈項目(配置了數據卷掛載,直接在容器外編寫項目就可以發佈了)在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>
    
  7. 訪問//39.105.48.232:3030/test/

  8. 日誌查看,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

提交的時候鏡像也是按層級來提交的!

阿里雲服務器

  1. 登錄阿里雲

  2. 找到容器鏡像服務

  3. 創建命名空間

  4. 創建容器鏡像

  5. 點擊鏡像倉庫名 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)可以查看

假設我們想通過容器的名字來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鏡像

  1. 構建一個SpringBoot項目

    @RestController
    public class HelloController {
        @RequestMapping("/hello")
        public String hello(){
    
            return "Hello zhour!";
        }
    }
    
  2. 打包應用,package

  3. 編寫dockerfile

    FROM java:8
    
    COPY *.jar /app.jar
    
    CMD ["---server port 8080---"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java","-jar","app.jar"]
    
  4. 構建鏡像(使用 ftp 將文件上傳至服務器)

    [root@zhourui idea]# ls
    demo-docker-0.0.1-SNAPSHOT.jar  Dockerfile
    [root@zhourui idea]# docker build -t boottestzr .
    
    
  5. 發佈運行

    [root@zhourui idea]# docker run -d -P --name ideaboot-web boottestzr
    
  6. 訪問

如需瀏覽器訪問,阿里雲開發端口,或者運行時 -p 暴漏已開放的端口即可!!