Docker學習筆記---通俗易懂

平遙發表於2021-05-06

Docker

簡介

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

Docker是基於 Go 語言開發的,是一個開源專案。

文件地址:https://docs.docker.com/

倉庫地址:https://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="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-8"
CENTOS_MANTISBT_PROJECT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

安裝:參考幫助文件 https://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 \
    https://download.docker.com/linux/centos/docker-ce.repo  #預設的是國外的十分慢
#阿里雲映象 (推薦使用)   
yum-config-manager \
    --add-repo \    
    http://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": ["https://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的所有命令

命令:官網地址 https://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:http://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

瀏覽器測試訪問:http://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後訪問測試:http://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="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
             http://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. 訪問http://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
https://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 暴漏已開放的埠即可!!

相關文章