Docker詳解(上)

Docker 學習

  • Docker概述
  • Docker安裝
  • Docker命令
    • 鏡像命令
    • 容器命令
    • 操作命令
  • Docker鏡像
  • 容器數據卷
  • DockerFile
  • Docker網路原理
  • IDEA整合Docker
  • Docker Compose
  • Docker Swarm
  • CI/CD Jenkins

Docker概述

Docker為什麼出現?

一款產品:開發 –> 上線 兩套環境!應用環境,應用配置!

開發 –> 運維 問題:我在我的電腦上可以運行!版本更新,導致服務不可用!對於運維來說,考驗就十分大!

環境配置是十分的麻煩,每一個機器都要部署環境(集群Redis、ES、Hadoop……)!費時費力。

發布一個項目(jar + (Redis MySQL jdk ES)),項目能不能都帶上環境安裝打包!

之前在伺服器配置一個應用環境 Redis MySQL jdk ES Hadoop,配置十分麻煩,不能夠跨平台。

Windows,最後發布到Linux!

傳統:開發 jar,運維來做!

現在:開發打包部署上線,一套流程做完!

Java –> apk –> 發布(應用商店) –> 張三使用apk –> 安裝即可用!

Java –> jar(環境) –> 打包項目帶上環境(鏡像) –> (Docker倉庫:商店) –> 下載我們發布的鏡像 –> 直接運行即可!

Docker給以上的問題,提出了解決方案!

Docker的思想就來自於集裝箱!

JRE –> 多個應用(埠衝突) –> 原來都是交叉的!

隔離:Docker核心思想:打包裝箱!每個箱子是互相隔離的。

水果 生化武器

Docker 通過隔離機制,可以將伺服器利用到極致!

本質:所有的技術都是因為出現了一些問題,我們需要去解決,才去學習!

Docker的歷史

2010年,幾個搞IT的年輕人,就在美國成立了一家dotCloud

做一些pass的雲計算服務!LXC 有關的容器技術!

他們將自己的技術(容器化技術)命名 就是 Docker!

Docker 剛剛誕生的時候,沒有引起行業的注意!dotCloud,就活不下去!

開源

開放源程式碼!

2013年,Docker開源!

Docker越來越多的人發現了Docker的優點!火了,Docker 每個月都會更新一個版本!

2014年4月9日,Docker1.0發布!

Docker為什麼這麼火?十分的輕巧!

在容器技術出來之前,我們都是使用虛擬機技術!

虛擬機:在Windows中裝一個VMware,通過這個軟體我們可以虛擬出來一台或者多台電腦!十分笨重!

虛擬機也是屬於虛擬化技術,Docker 容器技術,也是一種 虛擬化技術!

vm : linux centos原生鏡像(一個電腦!) 隔離,需要開啟多個虛擬機! 幾個G 幾分鐘
docker : 隔離,鏡像(最核心的環境 4m + jdk + mysql)十分的小巧,運行鏡像就可以了!小巧! 幾個M KB 秒級啟動!

到現在,所有開發人員都必須要會Docker!

聊聊Docker

Docker基於Go語言開發的!開源項目!

官網://www.docker.com/

文檔地址://docs.docker.com/ Docker的文檔是超級詳細的!

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

Docker能幹嘛

之前的虛擬機技術!

虛擬機技術缺點:

  1. 資源佔用十分多

  2. 冗餘步驟多

  3. 啟動很慢!

容器化技術

容器化技術不是模擬的一個完整的作業系統

比較Docker 和 虛擬機技術的不同:

  • 傳統虛擬機,虛擬出一套硬體,運行一個完整的作業系統,然後在這個系統上安裝和運行軟體
  • 容器內的應用直接運行在宿主機的內核,容器是沒有自己的內核的,也沒有虛擬我們的硬體,所以就輕便了
  • 每個容器間是互相隔離的,每個容器內都有一個屬於自己的文件系統,互不影響。

DevOps(開發、運維)

應用更快速的交付和部署

傳統:一堆幫助文檔,安裝程式

Docker:打包鏡像,發布測試,一鍵運行

更便捷的升級和擴縮容

使用了Docker之後,我們部署應用就和搭積木一樣!

項目打包為一個鏡像,擴展 伺服器A!伺服器B

更簡單的系統運維

在容器化之後,我們的開發、測試環境都是高度一致的。

更高效的計算資源利用

Docker 是內核級別的虛擬化,可以在物理機上可以運行很多的容器實例!伺服器的性能可以被壓榨到極致。

Docker 安裝

Docker的基本組成

鏡像(image):

docker鏡像就像一個模板,可以通過這個模板來創建服務,tomcat鏡像 ==> run ==> tomcat01容器(提供服務),通過這個鏡像可以創建多個容器(最終服務運行或者項目運行就是在容器中的)。

容器(container):

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

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

目前可以把這個容器理解為就是一個簡易的linux系統

倉庫(repository):

倉庫就是存放鏡像的地方!

倉庫分為公有倉庫和私有倉庫!

Docker Hub(默認是國外的)

阿里雲…都有容器伺服器(配置鏡像加速!)

安裝Docker

環境準備

  1. 需要會一點點的Linux基礎
  2. CentOS 7
  3. 我們使用Xshell連接遠程伺服器進行操作!

環境查看

# 系統內核是 3.10 以上的
# 系統版本

安裝

幫助文檔:

# 1、卸載舊的版本
sudo apt-get remove docker docker-engine docker.io containerd runc

# 2、需要的安裝包
yum install -y yum-utils

# 3、設置鏡像的倉庫
yum-config-manager --add-repo //mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 阿里雲

# 更新yum軟體包索引
yum makecache fast

# 4、安裝docker  docker-ce 社區版  ee 企業版
yum install docker-ce docker-ce-cli containerd.io

# 5、啟動docker
systemctl start docker

# 6、使用docker version 查看是否安裝成功

# 7、hello-world
docker run hello-world

# 8、查看一下下載的這個 hello-world 鏡像
[root@ls-Cwj2oH9C /]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   9 months ago   13.3kB

了解:卸載docker

# 1、卸載依賴
yum remove docker-ce docker-ce-cli containerd.io

# 2、刪除資源
rm -rf /var/lib/docker

# /var/lib/docker  docker的默認工作路徑!

阿里雲鏡像加速

  1. 登錄阿里雲找到容器服務

  2. 找到鏡像加速的地址

  3. 配置使用

    sudo mkdir -p /etc/docker
    
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["//veotnqhz.mirror.aliyuncs.com"]
    }
    EOF
    
    sudo systemctl daemon-reload
    
    sudo systemctl restart docker
    

回顧HelloWorld流程

底層原理

Docker是怎麼工作的?

Docker是一個Client – Server 結構的系統,Docker的守護進程運行在主機上。通過Socket從客戶端訪問!

DockerServer接收到 Docker – Client 的指令,就會執行這個命令!

Docker 為什麼比 VM 快?

  1. Docker有著比虛擬機更少的抽象層

  2. Docker利用的是宿主機的內核,vm需要的是Guest OS。

    所以說,新建一個容器的時候,docker不需要像虛擬機一樣重新載入一個作業系統內核,避免引導操作。虛擬機是載入Guest OS,分鐘級別的,而docker是利用宿主機的作業系統,省略了這個複雜的過程,秒級!

之後學習完畢所有的命令,再回過頭來看這段理論,就會很清晰!

Docker的常用命令

幫助命令

docker version     # 顯示docker的版本資訊
docker info        # 顯示docker的系統資訊,包括鏡像和容器的數量
docker 命令 --help  # 幫助命令

幫助文檔的地址://docs.docker.com/engine/reference/commandline/docker/

鏡像命令

docker images 查看所有本地的主機上的鏡像

[root@ls-Cwj2oH9C /]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   9 months ago   13.3kB

# 解釋
REPOSITORY  鏡像的倉庫源
TAG         鏡像的標籤
IMAGE ID    鏡像的id
CREATED     鏡像的創建時間
SIZE        鏡像的大小

# 可選項
  -a,--all          # 列出所有鏡像
  -q,--quiet        # 只顯示鏡像的id

docker search 搜索鏡像

[root@ls-Cwj2oH9C /]# docker search mysql
NAME                           DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                          MySQL is a widely used, open-source relation…   12821     [OK]       
mariadb                        MariaDB Server is a high performing open sou…   4918      [OK]       
percona                        Percona Server is a fork of the MySQL relati…   580       [OK]       
phpmyadmin                     phpMyAdmin - A web interface for MySQL and M…   564       [OK]      

# 可選項,通過搜索來過濾
  --filter=STARS=3000  # 搜索出來的鏡像就是STARS大於3000的
[root@ls-Cwj2oH9C ~]# docker search mysql --filter=STARS=3000
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   12821     [OK]       
mariadb   MariaDB Server is a high performing open sou…   4918      [OK]       
[root@ls-Cwj2oH9C ~]# docker search mysql --filter=STARS=5000
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   12821     [OK]         

docker pull 下載鏡像

# 下載鏡像 docker pull 鏡像名[:tag]
[root@ls-Cwj2oH9C /]# docker pull mysql
Using default tag: latest    # 如果不寫 tag,默認就是latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete  # 分層下載,docker image的核心 聯合文件系統
93619dbc5b36: Pull complete 
99da31dd6142: Pull complete 
626033c43d70: Pull complete 
37d5d7efb64e: Pull complete 
ac563158d721: Pull complete 
d2ba16033dad: Pull complete 
688ba7d5c01a: Pull complete 
00e060b6d11d: Pull complete 
1c04857f594f: Pull complete 
4d7cfa90e6ea: Pull complete 
e0431212d27d: Pull complete 
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709  # 簽名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest  # 真實地址

# 等價於它
docker pull mysql
docker pull docker.io/library/mysql:latest

# 指定版本下載
[root@ls-Cwj2oH9C /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists 
93619dbc5b36: Already exists 
99da31dd6142: Already exists 
626033c43d70: Already exists 
37d5d7efb64e: Already exists 
ac563158d721: Already exists 
d2ba16033dad: Already exists 
0ceb82207cd7: Pull complete 
37f2405cae96: Pull complete 
e2482e017e53: Pull complete 
70deed891d42: Pull complete 
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

docker rmi 刪除鏡像!

[root@ls-Cwj2oH9C /]# docker rmi -f 鏡像id  # 刪除指定的鏡像
[root@ls-Cwj2oH9C /]# docker rmi -f 鏡像id 鏡像id 鏡像id 鏡像id  # 刪除多個鏡像
[root@ls-Cwj2oH9C /]# docker rmi -f $(docker images -aq)  # 刪除全部的鏡像

容器命令

說明:我們有了鏡像才可以創建容器,linux,下載一個 centos 鏡像來測試學習

docker pull centos

新建容器並啟動

docker run [可選參數] image

# 參數說明
--name="Name"    容器名字  tomcat01  tomcat02,用來區分容器
-d               後台方式運行
-it              使用交互方式運行,進入容器查看內容
-p               指定容器的埠  -p  8080:8080
    -p ip:主機埠:容器埠
    -p 主機埠:容器埠 (常用)
    -p 容器埠
    容器埠
-p                隨機指定埠

# 測試,啟動並進入容器
[root@ls-Cwj2oH9C ~]# docker run -it centos /bin/bash
[root@26c5b40b2e60 /]# ls  # 查看容器內的centos,基礎版本,很多命令都是不完善的!
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

# 從容器中退回主機
[root@c103dbc1d4d4 /]# exit
exit
[root@ls-Cwj2oH9C ~]# cd /
[root@ls-Cwj2oH9C /]# ls
bin   dev  home  lib64       media  opt   root  sbin  sys  usr
boot  etc  lib   lost+found  mnt    proc  run   srv   tmp  var

列出所有的運行的容器

# docker ps 命令
    # 列出當前正在運行的容器
-a  # 列出當前正在運行的容器+帶出歷史運行過的容器
-n=?  # 顯示最近創建的容器

[root@ls-Cwj2oH9C /]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@ls-Cwj2oH9C /]# docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED          STATUS                          PORTS     NAMES
c103dbc1d4d4   centos         "/bin/bash"   57 seconds ago   Exited (0) 50 seconds ago                 busy_ramanujan
26c5b40b2e60   centos         "/bin/bash"   11 minutes ago   Exited (0) About a minute ago             thirsty_brahmagupta
1aba774b8be5   feb5d9fea6a5   "/hello"      4 hours ago      Exited (0) 4 hours ago                    quizzical_turing
[root@ls-Cwj2oH9C /]# docker ps -aq
c103dbc1d4d4
26c5b40b2e60
1aba774b8be5

退出容器

exit    # 直接容器停止並退出
Ctrl + P + Q    # 容器不停止退出

刪除容器

docker rm 容器id                 # 刪除指定的容器,不能刪除正在運行的容器,如果要強制刪除 rm -f
docker rm -f $(docker ps -aq)    # 刪除所有的容器
docker ps -a -q|xargs docker rm  # 刪除所有的容器

啟動和停止容器的操作

docker start 容器id    # 啟動容器
docker restart 容器id  # 重啟容器
docker stop 容器id     # 停止當前正在運行的容器
docker kill 容器id     # 強制停止當前容器

常用其他命令

後台啟動容器

# 命令 docker run -d 鏡像名!
[root@ls-Cwj2oH9C /]# docker run -d centos
d3ebfe17b9c02d91f4f45bc9405b6713b7098e9c2f1229cd6523b46f85531c03

# 問題docker ps,發現 centos 停止了

# 常見的坑:docker 容器使用後台運行,就必須要有一個前台進程,docker發現沒有應用,就會自動停止
# nginx,容器啟動後,發現自己沒有提供服務,就會立刻停止,就是沒有程式了

查看日誌

docker logs -f -t --tail 10 容器  沒有日誌

# 自己編寫一段shell腳本
[root@ls-Cwj2oH9C /]# docker run -d centos /bin/sh -c "while true;do echo kuangshen;sleep 1;done"
be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de

# [root@ls-Cwj2oH9C /]# docker ps
CONTAINER ID   IMAGE
be09e0fd41c7   centos
d2ae011f21b8   centos

# 顯示日誌
 -tf            # 顯示日誌
 --tail number  # 要顯示的日誌條數
[root@ls-Cwj2oH9C /]# docker logs -tf --tail 10 be09e0fd41c7

查看容器中進程資訊 ps

# 命令 docker top 容器id
[root@ls-Cwj2oH9C /]# docker top be09e0fd41c7
UID                 PID                 PPID                C                   STIME     
root                23558               23538               0                   15:53     
root                25465               23558               0                   16:09     

查看鏡像的元數據

# 命令
docker inspect 容器id

# 測試
[root@ls-Cwj2oH9C /]# docker inspect be09e0fd41c7
[
    {
        "Id": "be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de",
        "Created": "2022-07-05T07:53:54.627754682Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true;do echo kuangshen;sleep 1;done"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 23558,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2022-07-05T07:53:54.913270812Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
        "ResolvConfPath": "/var/lib/docker/containers/be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de/hostname",
        "HostsPath": "/var/lib/docker/containers/be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de/hosts",
        "LogPath": "/var/lib/docker/containers/be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de/be09e0fd41c70e5d114b5c2534acba6ae97a3a12e1b4d0d603077b83c76697de-json.log",
        "Name": "/vigilant_tu",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/1a375808cf6a2eff0ce527432ddf9fd9b2c5519b1a71b9c6a5931104f24e55ed-init/diff:/var/lib/docker/overlay2/652792c86aac30ea5e1860169ae46b72da12c74efde67ea5aaba90a396e5989f/diff",
                "MergedDir": "/var/lib/docker/overlay2/1a375808cf6a2eff0ce527432ddf9fd9b2c5519b1a71b9c6a5931104f24e55ed/merged",
                "UpperDir": "/var/lib/docker/overlay2/1a375808cf6a2eff0ce527432ddf9fd9b2c5519b1a71b9c6a5931104f24e55ed/diff",
                "WorkDir": "/var/lib/docker/overlay2/1a375808cf6a2eff0ce527432ddf9fd9b2c5519b1a71b9c6a5931104f24e55ed/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "be09e0fd41c7",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "while true;do echo kuangshen;sleep 1;done"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "4b2ab1f2e949baa34edcfd36e72e6ed4a80c5f5381f6183b30ee6d9e73e39e44",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/4b2ab1f2e949",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "83295610dca0bd58cf285f6e7238eaae06749bf30433a75ee9d126dd6f92c25f",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.3",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:03",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "4181a198dd37ad281366217d8321f1ca65fd69f9139e73c0a7fc460afc58fa28",
                    "EndpointID": "83295610dca0bd58cf285f6e7238eaae06749bf30433a75ee9d126dd6f92c25f",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }
        }
    }
]

進入當前正在運行的容器

# 我們通常容器都是使用後台方式運行的,需要進入容器,修改一些配置

# 命令
docker exec -it 容器id bashShell

# 測試
[root@ls-Cwj2oH9C /]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
be09e0fd41c7   centos    "/bin/sh -c 'while t…"   32 minutes ago   Up 32 minutes             vigilant_tu
d2ae011f21b8   centos    "/bin/bash"              45 minutes ago   Up 45 minutes             mystifying_tereshkova
[root@ls-Cwj2oH9C /]# docker exec -it be09e0fd41c7 /bin/bash
[root@be09e0fd41c7 /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
[root@be09e0fd41c7 /]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 07:53 ?        00:00:01 /bin/sh -c while true;do echo kuangshen;sleep 1;don
root      4191     0  0 09:03 pts/0    00:00:00 /bin/bash
root      4214     1  0 09:03 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /
root      4215  4191  0 09:03 pts/0    00:00:00 ps -ef

# 方式二
docker attach 容器id
# 測試
[root@ls-Cwj2oH9C /]# docker attach be09e0fd41c7
正在執行當前的程式碼...

# docker exec      # 進入容器後開啟一個新的終端,可以在裡面操作(常用)
# docker attach    # 進入容器正在執行的終端,不會啟動新的進程!

從容器內拷貝文件到主機上

docker cp 容器id:容器內路徑  目的主機路徑

# 查看當前主機目錄下
[root@ls-Cwj2oH9C home]# ls
kuangshen.java
[root@ls-Cwj2oH9C home]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
17c1f83eeda6   centos    "/bin/bash"              32 seconds ago   Up 31 seconds             relaxed_spence
be09e0fd41c7   centos    "/bin/sh -c 'while t…"   2 hours ago      Up 2 hours                vigilant_tu
d2ae011f21b8   centos    "/bin/bash"              2 hours ago      Up 2 hours                mystifying_tereshkova

# 進入docker容器內部
[root@ls-Cwj2oH9C home]# docker attach 17c1f83eeda6
[root@17c1f83eeda6 /]# cd /home
[root@17c1f83eeda6 home]# ls
# 在容器內新建一個文件
[root@17c1f83eeda6 home]# touch test.java
[root@17c1f83eeda6 home]# exit
exit
[root@ls-Cwj2oH9C home]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED       STATUS       PORTS     NAMES
be09e0fd41c7   centos    "/bin/sh -c 'while t…"   2 hours ago   Up 2 hours             vigilant_tu
d2ae011f21b8   centos    "/bin/bash"              2 hours ago   Up 2 hours             mystifying_tereshkova
[root@ls-Cwj2oH9C home]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS                     PORTS     NAMES
17c1f83eeda6   centos    "/bin/bash"              2 minutes ago   Exited (0) 7 seconds ago             relaxed_spence
be09e0fd41c7   centos    "/bin/sh -c 'while t…"   2 hours ago     Up 2 hours                           vigilant_tu
d2ae011f21b8   centos    "/bin/bash"              2 hours ago     Up 2 hours                           mystifying_tereshkova
d3ebfe17b9c0   centos    "/bin/bash"              3 hours ago     Exited (0) 3 hours ago               gifted_joliot

# 將這個文件拷貝出來到主機上
[root@ls-Cwj2oH9C home]# docker cp 17c1f83eeda6:/home/test.java /home
[root@ls-Cwj2oH9C home]# ls
kuangshen.java  test.java
[root@ls-Cwj2oH9C home]# 

# 拷貝是一個手動過程,未來我們使用 -v 卷的技術,可以實現,自動同步

小結

attach :                  	##進入指定運行對象
	[root@VM-0-9-centos ~]# docker attach 96763bc9ea4e 
build : 					##通過Dockerfile訂製鏡像
commit : 					##提交當前容器為新的鏡像
cp : 						##拷貝指定文件或目錄到主機
	[root@VM-0-9-centos ~]# docker cp 96763bc9ea4e:/home/test.java /home/test_docker_cp/
create :					##創建新的容器,類似於run,但是不啟動容器
	[root@VM-0-9-centos ~]# docker create centos /bin/bash 
diff:						##查看docker容器變化
events:						##從docker獲取實時容器事件
exec: 						##進入已經啟動的容器運行指令
	[root@VM-0-9-centos ~]# docker exec -it f170a9b28775 /bin/bash
export: 					##到處容器的內容歸為一個tar文檔
history:					##展示一個鏡像形成歷史
images:						##列出系統當前鏡像
	[root@VM-0-9-centos ~]# docker images -a
import:						## 從tar包中內容中創建一個新的文件系統
info:						## 查看系統詳細資訊
	[root@VM-0-9-centos ~]# docker info
inspect:					## 查看容器詳細資訊
	[root@VM-0-9-centos ~]# docker inspect f170a9b28775
kill: 						## 強制結束指定容器
load:						## 從一個tar包中載入一個鏡像
login:						## 註冊或者登錄一個docker源伺服器
logout:						## 登出
logs:  						## 輸出當前容器日誌資訊
	docker logs -tf 容器id 			 
	docker logs --tail number 容器id #num為要顯示的日誌條數

port:						## 查看映射埠對應容器內部的源埠
pasue: 						## 暫停容器
ps:							## 列出容器列表
	docker ps     #運行中列表  
	docker ps -a  #所有容器列表
pull: 						## 從docker源鏡像拉取指定鏡像
	docker pull mysql	#默認拉取最新版本mysql
push:						## 推送指定鏡像或庫鏡像至docker源伺服器
restart: 					## 重啟正在運行的容器
rm: 						## 移除一個或者多個容器
	docker rm -f $(docker ps -aq)	#移除所有容器
rmi:						## 移除一個或者多個鏡像
run:						## 創建一個容器並運行內容
	docker run -it centos /bin/bash
save: 						## 保存一個鏡像為一個tar包
search: 					## 在docker	hub中搜索鏡像
	docker search mysql						#搜索所有mysql鏡像
	docker search mysql --filter=STARS=3000 #搜索收藏數大於3000的鏡像
start:						## 啟動容器
	docker start [id]
stop:						## 停止容器
	docker stop [id]
tag:						## 給源伺服器中鏡像設置標籤
top:						## 查看容器中運行的進程資訊
unpause:					## 取消暫停容器
version:  					## 查看docker版本號
	docker version
wait:						## 截取容器停止時的退出狀態值

docker的命令十分多,上面我們學習的那些都是最常用的容器和鏡像的命令,之後我們還會學習很多命令!

作業練習

Docker 安裝 Nginx

# 1、搜索鏡像  search  建議大家去docker hub搜索,可以看到幫助文檔
# 2、下載鏡像  pull
# 3、運行測試
[root@ls-Cwj2oH9C home]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   6 months ago   141MB
centos       latest    5d0da3dc9764   9 months ago   231MB

# -d 後台運行
# --name 給容器命名
# -p 宿主機埠:容器內部埠
[root@ls-Cwj2oH9C home]# docker run -d --name nginx01 -p 3344:80 nginx
fb127ee2c6ba61f9e42c8664673494314122e48017df0875342fbeed80b81e60
[root@ls-Cwj2oH9C home]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                                   NAMES
fb127ee2c6ba   nginx     "/docker-entrypoint.…"   4 seconds ago   Up 4 seconds   0.0.0.0:3344->80/tcp, :::3344->80/tcp   nginx01
be09e0fd41c7   centos    "/bin/sh -c 'while t…"   3 hours ago     Up 3 hours                                             vigilant_tu
d2ae011f21b8   centos    "/bin/bash"              3 hours ago     Up 3 hours                                             mystifying_tereshkova
[root@ls-Cwj2oH9C home]# curl localhost:3344

# 進入容器
[root@ls-Cwj2oH9C home]# docker exec -it nginx01 /bin/bash
root@fb127ee2c6ba:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@fb127ee2c6ba:/# cd /etc/nginx
root@fb127ee2c6ba:/etc/nginx# ls
conf.d	fastcgi_params	mime.types  modules  nginx.conf  scgi_params  uwsgi_params
root@fb127ee2c6ba:/etc/nginx# 

埠暴露的概念

思考問題:我們每次改動nginx配置文件,都需要進入容器內部,十分的麻煩,我們要是可以在容器外部提供一個映射路徑,達到在容器修改文件名,容器內部就可以自動修改 -v 數據卷!

作業:docker來裝一個tomcat

# 官方的使用
docker run -it --rm tomcat:9.0

# 我們之前的啟動都是後台,停止了容器之後,容器還是可以查到  docker run -it --rm,一般用來測試,用完就刪除

# 下載再啟動
docker pull tomcat

# 啟動運行
docker run -d -p 3355:8080 --name tomcat01 tomcat

# 測試訪問沒有問題

# 進入容器
[root@ls-Cwj2oH9C /]# docker exec -it tomcat01 /bin/bash

# 發現問題:1、linux命令少了  2、沒有webapps  默認是最小的鏡像,所有不必要的都剔除掉。
# 保證最小可運行的環境

思考問題:我們以後要部署項目,如果每次都要進入容器是不是十分麻煩?我們要是可以在容器外部提供一個映射路徑,webapps,我們在外部放置項目,就自動同步到內部就好了!

作業:部署 es + kibana

# es 暴露的埠很多!
# es 十分的耗記憶體
# es 的數據一般需要放置到安全目錄!掛載
# --net somenetwork ? 網路配置

# 啟動 elasticsearch
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:latest

# 啟動了 linux就卡住了  docker stats 查看cpu的狀態

# es 是十分耗記憶體的 2.182GiB  1核2G根本跑不動,會卡死,2核4G起步可以運行!

# 查看 docker stats

# 測試一下es是否成功了
[root@ls-Cwj2oH9C /]# curl localhost:9200
{
  "name" : "7QxbBIY",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "wUTOoYcpSZaSKV4VALlxeQ",
  "version" : {
    "number" : "5.6.8",
    "build_hash" : "688ecce",
    "build_date" : "2018-02-16T16:46:30.010Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.1"
  },
  "tagline" : "You Know, for Search"
}

# 趕緊關閉,增加記憶體的限制!

# 關閉es,增加記憶體的限制,修改配置文件  -e  環境配置修改
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:latest

# 查看 docker stats

[root@ls-Cwj2oH9C /]# curl localhost:9200
{
  "name" : "FnQQV4P",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "-M8PzTiLTVCNeZ2AZND1Ig",
  "version" : {
    "number" : "5.6.8",
    "build_hash" : "688ecce",
    "build_date" : "2018-02-16T16:46:30.010Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.1"
  },
  "tagline" : "You Know, for Search"
}

作業:使用kibana連接elasticsearch?思考網路如何才能連接過去!

可視化

  • portainer(先用這個)

  • Rancher(CI/CD(Continuous Intergration/Continuous Delpoy)持續集成/持續部署再用)

什麼是portainer?

Docker圖形化介面管理工具!提供一個後檯面板供我們操作!

docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

訪問測試://182.61.20.38:8088/

通過它來訪問了:

管理員登錄後選擇Local Docker後的主介面,注意:管理員只有一個

點擊local docker進入後的面板,可以查看容器、鏡像、卷、網路等的詳細資訊

可視化面板平時不會使用,測試使用即可!

Docker鏡像詳解

鏡像是什麼

鏡像是一種輕量級、可執行的獨立軟體包,用來打包軟體運行環境和基於運行環境開發的軟體,它包含運行某個軟體所需的所有內容,包括程式碼、運行時庫、環境變數和配置文件。

所有的應用,直接打包docker鏡像,就可以直接跑起來!

如何得到鏡像:

  • 從遠程倉庫下載
  • 朋友拷貝給你
  • 自己製作一個鏡像 DockerFile

Docker鏡像載入原理

UnionFS(聯合文件系統)

我們下載的時候看到的一層層就是這個!

UnionFS(聯合文件系統):Union文件系統(UnionFS)是一種分層、輕量級並且高性能的文件系統,它支援對文件系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下(unite several directories into a single virtual filesystem)。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就是各種不同的作業系統發行版,比如Ubuntu,Centos等等。

平時我們安裝進虛擬機的CentOS都是好幾個G,為什麼Docker這裡才200M?

對於一個精簡的OS,rootfs可以很小,只需要包含最基本的命令,工具和程式庫就可以了,因為底層直接用Host的kernel,自己只需要提供rootfs就可以了,由此可見對於不同的linux發行版,rootfs會有差別,因此不同的發行版可以公用bootfs。

虛擬機是分鐘級別,容器是秒級!

分層理解

分層的鏡像

我們可以去下載一個鏡像,注意觀察下載的日誌輸出,可以看到是一層一層的在下載!

思考:為什麼Docker鏡像要採用這種分層的結構呢?

最大的好處,莫過於是資源共享了!比如有多個鏡像都從相同的Base鏡像構建而來,那麼宿主機只需在磁碟上保留一份base鏡像,同時記憶體中也只需要載入一份base鏡像,這樣就可以為所有的容器服務了,而且鏡像的每一層都可以被分享。

查看鏡像分層的方式可以通過 docker image inspect 命令!

[root@ls-Cwj2oH9C ~]# docker image inspect redis:latest
[
    // ......
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:08249ce7456a1c0613eafe868aed936a284ed9f1d6144f7d2d08c514974a2af9",
                "sha256:5659b3a1146e8bdda814e4ad825e107088057e8578c83b758ad6aab93700d067",
                "sha256:cf3ae502d7faa4e90c159cc42b63b46a6be04864fe9d04fb0939e2b0c8b1f7c7",
                "sha256:4ca33072d02630d1d55ada52c3bde95a1ffe02ae60da9ef147c836db444f7a0f",
                "sha256:58bcc523fc9281a3a7033280804e841d1fcec71cbd6359c643c7e06a90efb34c",
                "sha256:be56018ff4790f7f1d96f500e9757c27979c37e476e21a2932746b4654955806"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

理解:

所有的Docker鏡像都起始於一個基礎鏡像層,當進行修改或增加新的內容時,就會在當前鏡像層之上,創建新的鏡像層。

舉一個簡單的例子,假如基於Ubuntu Linux 16.04 創建一個新的鏡像,這就是新鏡像的第一層;如果在該鏡像中添加Python包,就會在基礎鏡像之上創建第二個鏡像層;如果繼續添加一個安全修補程式,就會創建第三個鏡像層。

該鏡像當前已經包含3個鏡像層,如下圖所示(這只是一個用於演示的很簡單的例子)。

在添加額外的鏡像層的同時,鏡像始終保持是當前所有鏡像的組合,理解這一點非常重要。下圖舉了一個簡單的例子,每個鏡像層包含 3 個文件,而鏡像包含了來自兩個鏡像層的 6 個文件。

上圖中的鏡像層跟之前圖中的略有區別,主要目的是便於展示文件。

下圖中展示了一個稍微複雜的三層鏡像,在外部看來整個鏡像只有 6 個文件,這是因為最上層中的文件7是文件5的一個更新版本。

這種情況下,上層鏡像層中的文件覆蓋了底層鏡像層中的文件。這樣就使得文件的更新版本作為一個新鏡像層添加到鏡像當中。

Docker通過存儲引擎(新版本採用快照機制)的方式實現鏡像層堆棧,並保證多鏡像層對外展示為統一的文件系統。

Linux上可用的存儲引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顧名思義,每種存儲引擎都基於Linux中對應的文件系統或者塊設備技術,並且每種存儲引擎都有其獨有的性能特點。

Docker在Windows上僅支援windowsfilter一種存儲引擎,該引擎基於NTFS文件系統之上實現了分層和CoW。下圖展示了與系統顯示相同的三層鏡像。所有鏡像層堆疊併合並,對外提供統一的視圖。

特點

Docker鏡像都是只讀的,當容器啟動時,一個新的可寫層被載入到鏡像的頂部!

這一層就是我們通常說的容器層,容器之下的都叫鏡像層!

如何提交一個自己的鏡像

commit鏡像

docker commit 提交容器成為一個新的副本

# 命令和git原理類似
docker commit -m="提交的描述資訊" -a="作者" 容器id 目標鏡像名:[TAG]

實戰測試

# 啟動一個默認的tomcat

# 發現這個默認的tomcat 是沒有webapps應用,鏡像的原因,官方的鏡像默認 webapps下面是沒有文件的!

# 我自己拷貝進去了基本的文件
[root@ls-Cwj2oH9C ~]# docker exec -it 11cdc75c9c6e /bin/bash
root@11cdc75c9c6e:/usr/local/tomcat# ls
BUILDING.txt	 LICENSE  README.md	 RUNNING.txt  conf  logs	    temp     webapps.dist
CONTRIBUTING.md  NOTICE   RELEASE-NOTES  bin	      lib   native-jni-lib  webapps  work
root@11cdc75c9c6e:/usr/local/tomcat# cp -r webapps.dist/* webapps

# 將我們操作過的容器通過commit提交為一個鏡像!我們以後就使用我們修改過的鏡像即可,這就是我們自己的一個修改的鏡像

學習方式:理解概念,進行實踐,最後實踐和理論相結合!

如果想要保存當前容器的狀態,就可以通過commit來提交,獲得一個鏡像
就像我們之前學習的VM快照功能!

到了這裡才算是入門Docker!

容器數據卷

什麼是容器數據卷

docker理念回顧

將應用和環境打包成一個鏡像!

數據?如果數據都在容器中,那麼我們容器刪除,數據就會丟失! 需求:數據可以持久化

MySQL,容器刪了,刪庫跑路! 需求:MySQL數據可以存儲在本地!

容器之間可以有一個數據共享的技術!Docker容器中產生的數據,同步到本地!

這就是卷技術!目錄的掛載,將我們容器內的目錄,掛載到Linux上面!

總結一句話:容器的持久化和同步操作!容器間也是可以數據共享的!

使用數據卷

方式一:直接使用命令來掛載 -v

docker run -it -v 主機目錄:容器內目錄

# 測試
[root@ls-Cwj2oH9C ~]# docker run -it -v /home/ceshi:/home centos /bin/bash

# 啟動起來之後,我們可以通過 docker inspect 容器id

測試文件的同步

再來測試:

  1. 停止容器
  2. 宿主機上修改文件
  3. 啟動容器
  4. 容器內的數據依舊是同步的

好處:我們以後修改只需要在本地修改即可,容器內會自動同步!

實戰:安裝MySQL

思考:MySQL的數據持久化的問題!

# 獲取鏡像
[root@ls-Cwj2oH9C ~]# 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 容器名字
[root@ls-Cwj2oH9C ~]# 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

# 啟動成功之後,我們在本地使用Navicat來連接測試一下(sqlyog反覆嘗試都連不上,Navicat一次成功!)
# Navicat 連接到伺服器的3310 --- 3310和容器內的3306映射,這個時候我們就可以連接上了!

# 在本地測試創建一個資料庫test,查看一下我們映射的路徑是否ok!

# 假如我們將容器刪除
[root@ls-Cwj2oH9C ~]# docker rm -f mysql01

發現,我們掛載到本地的數據卷依舊沒有丟失,這就實現了容器數據持久化功能!

具名和匿名掛載

# 匿名掛載
-v 容器內路徑!
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的volume的情況
[root@ls-Cwj2oH9C ~]# docker volume ls
DRIVER    VOLUME NAME
local     33a9eda0390dd6b15259dbf0fb1b5828f19bfb8f7e09c5467863862b839f1879
local     b3e57bea4d55bfb0f3cb6640ec6f6518f424218e204826c14a220c910def5a31
local     dd326255ea9dfbf32350012c3d61ec0991a1f0c52f694bab76b2c322c0f60f62
local     f8f8c5df2175bf49695d6799c38b64b8843dce08889bdc0fc869749ac239bee4
local     f57aac3e8dc17710ab8a1151ea48ff97354849624a9478ea4fa7a58e1fd3dec2

# 這裡發現,這種就是匿名掛載,我們在 -v 只寫了容器內的路徑,沒有寫容器外的路徑!

# 具名掛載
[root@ls-Cwj2oH9C home]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
a2a98f1b0f43c47c44ee4d2f6b5047d9ffa1c182e674b8238ad377af13ee188b
[root@ls-Cwj2oH9C home]# docker volume ls
DRIVER    VOLUME NAME
local     33a9eda0390dd6b15259dbf0fb1b5828f19bfb8f7e09c5467863862b839f1879
local     b3e57bea4d55bfb0f3cb6640ec6f6518f424218e204826c14a220c910def5a31
local     dd326255ea9dfbf32350012c3d61ec0991a1f0c52f694bab76b2c322c0f60f62
local     f8f8c5df2175bf49695d6799c38b64b8843dce08889bdc0fc869749ac239bee4
local     f57aac3e8dc17710ab8a1151ea48ff97354849624a9478ea4fa7a58e1fd3dec2
local     juming-nginx

# 通過 -v 卷名:容器內路徑
# 查看一下這個卷

所有的docker容器內的卷,沒有指定目錄的情況下都是在/var/lib/docker/volumes/xxxx/_data

我們通過具名掛載可以方便的找到我們的一個卷,大多數情況下都在使用具名掛載

# 如何確定是具名掛載還是匿名掛載,還是指定路徑掛載!
-v 容器內路徑  # 匿名掛載
-v 卷名:容器內路徑  # 具名掛載
-v /宿主機路徑:容器內路徑  # 指定路徑掛載!

拓展:

# pwd 顯示當前文件路徑
# 通過 -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 只要看到ro就說明這個路徑只能通過宿主機來操作,容器內部是無法操作的!

初始DockerFile

DockerFile就是用來構建docker鏡像的構建文件!命令腳本!先體驗一下!

通過這個腳本可以生成鏡像,鏡像是一層一層的,腳本就是一個個的命令,每個命令都是一層!

# 創建一個dockerfile文件,名字可以隨機 建議 Dockerfile
# 文件中的內容 指令(大寫) 參數
FROM centos

VOLUME ["volume01","volume02"]    # 匿名掛載

CMD echo "----end----"
CMD /bin/bash

# 這裡的每個命令,就是鏡像的一層!

# 啟動自己寫的容器

這個卷和外部一定有一個同步的目錄!匿名掛載,只寫了容器內的目錄!

查看一下卷掛載的路徑

測試一下剛才的文件是否同步出去了!

這種方式我們未來使用的十分多,因為我們通常會構建自己的鏡像!

假設構建鏡像的時候沒有掛載卷,要手動鏡像掛載 -v 卷名 : 容器內路徑!

數據卷容器

多個mysql同步數據!

# 啟動3個容器,通過我們剛才自己的鏡像啟動

# 測試,可以刪除docker01,查看一下docker02和docker03是否還可以訪問這個文件
# 測試依舊可以訪問

多個mysql實現數據共享

[root@ls-Cwj2oH9C ~]# 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
[root@ls-Cwj2oH9C ~]# 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 mysql02 --volumes-from mysql01 mysql:5.7

結論:

容器之間配置資訊的傳遞,數據卷容器的生命周期一直持續到沒有容器使用為止。

但是一旦持久化到了本地,這個時候,本地的數據是不會刪除的!

DockerFile

DockerFile介紹

DockerFile是用來構建docker鏡像的文件!命令參數腳本!

構建步驟:

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

查看一下官方是怎麼做的?

發現官方的鏡像都是基礎包,很多功能沒有,我們通常會自己搭建自己的鏡像!

官方既然可以製作鏡像,那麼我們也可以!

DockerFile構建過程

基礎知識:

  1. 每個保留關鍵字(指令)都是必須是大寫字母
  2. 執行從上到下順序執行
  3. # 表示注釋
  4. 每一個指令都會創建提交一個新的鏡像層,並提交!

DockerFile是面向開發的,我們以後要發布項目,做鏡像,就需要編寫dockerfile文件,這個文件十分簡單!

Docker鏡像逐漸成為企業交付的標準,必須要掌握!

步驟:開發,部署,運維。。。缺一不可!

DockerFile:構建文件,定義了一切的步驟,源程式碼

DockerImages:通過DockerFile構建生成的鏡像,最終發布和運行的產品!

Docker容器:容器就是鏡像運行起來提供服務的

DockerFile的指令

以前的話我們就是使用別人的,現在我們知道了這些指令後,我們來練習自己寫一個鏡像!

FROM        # 基礎鏡像,一切從這裡開始構建
MAINTAINER  # 鏡像是誰寫的,姓名+郵箱
RUN         # 鏡像構建的時候需要運行的命令
ADD         # 步驟,tomcat鏡像,這個tomcat壓縮包!添加內容
WORKDIR     # 鏡像的工作目錄
VOLUME      # 掛載的目錄
EXPOSE      # 暴露埠配置
CMD         # 指定這個容器啟動的時候要運行的命令,只有最後一個會生效,可被替代
ENTRYPOINT  # 指定這個容器啟動的時候要運行的命令,可以追加命令
ONBUILD     # 當構建一個被繼承的 DockerFile 這個時候就會運行 ONBUILD 的指令,觸髮指令
COPY        # 類似ADD,將我們的文件拷貝到鏡像中
ENV         # 構建的時候設置環境變數!

實戰測試

Docker Hub中99%鏡像都是從這個基礎鏡像過來的 FROM scratch,然後配置需要的軟體和配置來進行構建

創建一個自己的centos

創建出錯可以查看我的部落格中遇到的錯誤一欄中的相關內容進行解決!

# 1 編寫Dockerfile的文件
[root@ls-Cwj2oH9C dockerfile]# cat mydockerfile-centos
FROM centos:7.9.2009
MAINTAINER wydilearn<[email protected]>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum install vim
RUN yum install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash

# 2 通過這個文件構建鏡像
# 命令 docker build -f dockerfile文件路徑 -t 鏡像名:[tag]
Successfully built 4ca77dadd64f
Successfully tagged mycentos:7.9.2009

# 3 測試運行

對比:之前的原生centos

工作目錄默認是根目錄,沒有vim、ifconfig等命令

我們增加之後的鏡像:

我們可以列出本地鏡像的變更歷史

我們平時拿到一個鏡像,可以研究一下它是怎麼做的了!

CMD 和 ENTRYPOINT 區別

CMD            # 指定這個容器啟動的時候要運行的命令,只有最後一個會生效,可被替代
ENTRYPOINT     # 指定這個容器啟動的時候要運行的命令,可以追加命令

測試cmd

# 編寫 dockerfile 文件
[root@ls-Cwj2oH9C dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

# 構建鏡像
[root@ls-Cwj2oH9C dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .

# run運行,發現我們的ls -a 命令生效
[root@ls-Cwj2oH9C dockerfile]# docker run 08f5a6379ff7
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
lib
lib64

# 想追加一個命令 -l  ls -al
[root@ls-Cwj2oH9C dockerfile]# docker run 08f5a6379ff7 -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled 

# CMD的情況下 -l 替換了CMD ["ls","-a"]命令,-l 不是命令所以報錯!

測試 ENTRYPOINT

[root@ls-Cwj2oH9C dockerfile]# vim dockerfile-cmd-entrypoint
FROM centos:7.9.2009
ENTRYPOINT ["ls","-a"]

[root@ls-Cwj2oH9C dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM centos:7.9.2009
 ---> eeb6ee3f44bd
Step 2/2 : ENTRYPOINT ["ls","-a"]
 ---> Running in a11a899f08f4
Removing intermediate container a11a899f08f4
 ---> db46b6b11456
Successfully built db46b6b11456
Successfully tagged entrypoint-test:latest
[root@ls-Cwj2oH9C dockerfile]# docker run d74cdaf8abb6
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

# 我們的追加命令,是直接拼接在我們的 ENTRYPOINT 命令的後面!
[root@ls-Cwj2oH9C dockerfile]# docker run d74cdaf8abb6 -l
total 64
drwxr-xr-x   1 root root  4096 Jul 12 08:56 .
drwxr-xr-x   1 root root  4096 Jul 12 08:56 ..
-rwxr-xr-x   1 root root     0 Jul 12 08:56 .dockerenv
-rw-r--r--   1 root root 12114 Nov 13  2020 anaconda-post.log
lrwxrwxrwx   1 root root     7 Nov 13  2020 bin -> usr/bin
drwxr-xr-x   5 root root   340 Jul 12 08:56 dev
drwxr-xr-x   1 root root  4096 Jul 12 08:56 etc
drwxr-xr-x   2 root root  4096 Apr 11  2018 home
lrwxrwxrwx   1 root root     7 Nov 13  2020 lib -> usr/lib
lrwxrwxrwx   1 root root     9 Nov 13  2020 lib64 -> usr/lib64
drwxr-xr-x   2 root root  4096 Apr 11  2018 media
drwxr-xr-x   2 root root  4096 Apr 11  2018 mnt
drwxr-xr-x   2 root root  4096 Apr 11  2018 opt
dr-xr-xr-x 173 root root     0 Jul 12 08:56 proc
dr-xr-x---   2 root root  4096 Nov 13  2020 root
drwxr-xr-x  11 root root  4096 Nov 13  2020 run
lrwxrwxrwx   1 root root     8 Nov 13  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root  4096 Apr 11  2018 srv
dr-xr-xr-x  13 root root     0 Jul  9 02:03 sys
drwxrwxrwt   7 root root  4096 Nov 13  2020 tmp
drwxr-xr-x  13 root root  4096 Nov 13  2020 usr
drwxr-xr-x  18 root root  4096 Nov 13  2020 var

Dockerfile中很多命令都十分的相似,我們需要了解它們的區別,我們最好的學習就是對比他們然後測試效果!

實戰:Tomcat鏡像

  1. 準備鏡像文件 tomcat 壓縮包,jdk的壓縮包!

  2. 編寫dockerfile文件,官方命名 Dockerfile ,build 會自動尋找這個文件,就不需要 -f 指定了!

    FROM centos:7.9.2009
    MAINTAINER wydilearn<[email protected]>
    
    COPY readme.txt /usr/local/readme.txt
    
    ADD jdk-8u333-linux-x64.tar /usr/local/
    ADD apache-tomcat-10.0.22.tar.gz /usr/local/
    
    RUN yum -y install vim
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    ENV JAVA_HOME /usr/local/jdk1.8.0_333
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.22
    ENV CATALINA_BASE /usr/local/apache-tomcat-10.0.22
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    
    EXPOSE 8080
    
    CMD /usr/local/apache-tomcat-10.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-10.0.22/bin
    /logs/catalina.out
    
  3. 構建鏡像

    # docker build -t diytomcat .
    
  4. 啟動鏡像

  5. 訪問測試

  6. 發布項目(由於做了卷掛載,我們直接在本地編寫項目就可以發布了!)

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
             xmlns="//java.sun.com/xml/ns/javaee"
             xmlns:web="//java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             xsi:schemaLocation="//java.sun.com/xml/ns/javaee
                                 //java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             id="WebApp_ID" version="2.5">
    
    </web-app>
    
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>hello,kuangshen</title>
    </head>
    <body>
    Hello World!<br/>
    <%
    System.out.println("----my test web logs----");
    %>
    </body>
    </html>
    

發現:項目部署成功,可以直接訪問ok!

我們以後開發的步驟:需要掌握Dockerfile的編寫!我們之後的一切都是使用docker鏡像來發布運行!

發布自己的鏡像

DockerHub

  1. 地址 //hub.docker.com/ 註冊自己的帳號!

  2. 確定這個帳號可以登錄

  3. 在我們的伺服器上提交自己的鏡像

    [root@ls-Cwj2oH9C 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
    
  4. 登錄完畢後就可以提交鏡像了,就是一步 docker push

    # 給自己要發布的鏡像增加一個 tag
    [root@ls-Cwj2oH9C tomcat]# docker tag 52f83276fc08 wydilearn/diytomcat:1.0
    
    # docker push上去即可!自己發布的鏡像盡量帶上版本號
    [root@ls-Cwj2oH9C tomcat]# docker push wydilearn/diytomcat:1.0
    The push refers to repository [docker.io/wydilearn/diytomcat]
    3c40fff9f2ee: Pushed 
    fc3bd8b32ed0: Pushed 
    f8c82bfdcfb9: Pushed 
    a5760cf5dc3b: Pushed 
    174f56854903: Mounted from library/centos 
    1.0: digest: sha256:e0fae8f6383fdbf05a1fc89676fd7696949fc16d378f698a60918cb16a0fabb9 size: 1373
    

    提交的時候也是按照鏡像的層級來進行提交的。

發布到阿里雲鏡像服務上

  1. 登錄阿里雲

  2. 找到容器鏡像服務

  3. 創建命名空間

  4. 創建容器鏡像

  5. 瀏覽阿里雲

阿里雲容器鏡像就參考官方地址!

小結

Docker 網路

理解Docker0

清空所有環境

測試

三個網路

# 問題:docker 是如何處理容器網路訪問的?

[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat01 tomcat

# 查看容器的內部網路地址 ip addr,發現容器啟動的時候會得到一個 eth0@if2763 IP地址,docker分配的!
[root@ls-Cwj2oH9C /]# docker exec -it 232419b4b0ff /bin/bash  # 進入容器安裝兩個命令
root@232419b4b0ff:/usr/local/tomcat# apt update && apt install -y iproute2
root@232419b4b0ff:/usr/local/tomcat# apt install iputils-ping
root@232419b4b0ff:/usr/local/tomcat# 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
2762: eth0@if2763: <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@ls-Cwj2oH9C /]# 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.047 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.044 ms

# linux可以ping通容器內部

原理

  1. 我們每啟動一個docker容器,docker就會給docker容器分配一個IP,我們只要安裝了docker,就會有一個網卡 docker0

    橋接模式,使用的技術是 evth-pair 技術!

    再次測試ip addr

  2. 再啟動一個容器測試,發現又多了一對網卡!

    # 我們發現這個容器帶來網卡,都是一對一對的
    # evth-pair 就是一堆的虛擬設備介面,他們都是成對出現的,一端連著協議,一端彼此相連
    # 正因為有這個特性,evth-pair充當一個橋樑,連接各種虛擬網路設備
    # OpenStac,Docker容器之間的連接,OVS的連接,都是使用evth-pair技術
    
  3. 我們來測試下tomcat01和tomcat02是否可以ping通!

    # 進入tomcat02
    [root@ls-Cwj2oH9C /]# docker exec -it tomcat02 /bin/bash
    root@fde1226260aa:/usr/local/tomcat# apt update && apt install -y iproute2
    root@fde1226260aa:/usr/local/tomcat# apt install iputils-ping
    root@fde1226260aa:/usr/local/tomcat# 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.087 ms
    64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.071 ms
    

    結論:容器和容器之間是可以互相ping通的!

繪製一個網路模型圖:

結論:tomcat01 和 tomcat02 是共用的一個路由器,docker0。

所有的容器不指定網路的情況下,都是 docker0 路由的,docker會給我們的容器分配一個默認的可用IP

小結

Docker中的所有網路介面都是虛擬的。虛擬的轉發效率高!

只要容器刪除,對應的一對網橋就沒了!

思考一個場景,我們編寫了一個微服務,database url=ip:,項目不重啟資料庫ip換掉了,我們希望可以處理這個問題,可以通過名字來進行訪問容器?

[root@ls-Cwj2oH9C ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known

# 如何可以解決呢?
# 通過--link 就可以解決網路連通問題
[root@ls-Cwj2oH9C ~]# docker run -it -d -P --name tomcat03 --link tomcat02 tomcat
371f584079471c6b8934c5ee961d741dba06884e0e85135bd0d224f685f0d6ca
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat03 /bin/bash
root@371f58407947:/usr/local/tomcat# apt update && apt install -y iproute2
root@371f58407947:/usr/local/tomcat# apt install iputils-ping
root@371f58407947:/usr/local/tomcat# 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.111 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.062 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.061 ms

探究:inspect!

其實這個tomcat03就是在本地配置了tomcat02配置

# 查看 hosts 配置,在這裡原理髮現!
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat03 /bin/bash
root@371f58407947:/usr/local/tomcat# 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 fde1226260aa
172.17.0.4	371f58407947

本質探究:–link 就是在hosts配置中增加了一個 172.17.0.3 tomcat02 fde1226260aa

我們現在用Docker,已經不建議使用 –link 了!

自定義網路!不使用docker0!

docker0的問題:它不支援容器名連接訪問!

自定義網路

查看所有的docker網路

網路模式

bridge:橋接模式 docker(默認,自己創建也使用 bridge 橋接模式)

none:不配置網路

host:和宿主機共享網路

container:容器內網路連通!(用的較少!局限很大)

三種常見網路模式(補充)

bridged(橋接模式)

虛擬機和宿主電腦處於同等地位,虛擬機就像是一台真實主機一樣存在於區域網中

NAT(網路地址轉換模式)

宿主電腦相當於一台開啟了DHCP功能的路由器,而虛擬機則是內網中的一台真實主機

host-only(僅主機模式)

相當於虛擬機通過雙絞線和宿主電腦直連,而宿主電腦不提供任何路由服務。因此在Host-only模式下,虛擬機可以和宿主電腦互相訪問,但是虛擬機無法訪問外部網路。

測試

# 我們直接啟動的命令 --net bridge,而這個就是我們的docker0
[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat01 tomcat
[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat01 --net bridge tomcat

# docker0特點,默認,域名不能訪問,--link可以打通連接!

# 我們可以自定義一個網路!
# --driver bridge
# --subnet 192.168.0.0/16  192.168.0.2 192.168.255.255
# --gateway 192.168.0.1
[root@ls-Cwj2oH9C /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
c82c2708387b95f0d932ae395fe0dc1d3182d38a47b820584c66e39219541eb4
[root@ls-Cwj2oH9C /]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
1340a553ba22   bridge    bridge    local
6f12b7793243   host      host      local
c82c2708387b   mynet     bridge    local
2581ba94b5d9   none      null      local

我們自己的網路就創建好了!

[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
e1d698bdf7bd90daf158e00e7f3c69785590198b477e1b45ef0fb2f6d2dd8ed6
[root@ls-Cwj2oH9C /]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
685b7164f606200c809c81858a291374171ed2ddf77e30e24f94fbbbbcdbe2e1
[root@ls-Cwj2oH9C /]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "c82c2708387b95f0d932ae395fe0dc1d3182d38a47b820584c66e39219541eb4",
        "Created": "2022-07-16T17:38:25.818266785+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": {
            "685b7164f606200c809c81858a291374171ed2ddf77e30e24f94fbbbbcdbe2e1": {
                "Name": "tomcat-net-02",
                "EndpointID": "7a3ac62a87388c10907bee1b83800d28968caf47160bec9999c3921a3e5183ff",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "e1d698bdf7bd90daf158e00e7f3c69785590198b477e1b45ef0fb2f6d2dd8ed6": {
                "Name": "tomcat-net-01",
                "EndpointID": "ea12cb9879b8d6801eabd3510e67e3a546888723ea743eedaec5274cca080ff0",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# 再次測試ping連接
[root@ls-Cwj2oH9C ~]# 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.085 ms
64 bytes from 192.168.0.3: icmp_seq=2 ttl=64 time=0.070 ms

# 現在不使用--link也可以ping名字了!
[root@ls-Cwj2oH9C ~]# 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.055 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.063 ms

我們自定義的網路docker都已經幫我們維護好了對應的關係,推薦我們平時這樣使用網路!

好處:

redis – 不同的集群使用不同的網路,保證集群是安全和健康的

mysql – 不同的集群使用不同的網路,保證集群是安全和健康的

網路連通

# 測試打通 tomcat01 - mynet

# 連通之後就是將 tomcat01 放到了 mynet 網路下

# 一個容器兩個ip地址!

# 阿里雲服務:公網ip  私網ip

# 01 連通ok
[root@ls-Cwj2oH9C ~]# 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.072 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.070 ms

# 02 是依舊打不通的
[root@ls-Cwj2oH9C ~]# docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

結論:假設要跨網路操作別人,就需要使用 docker network connect 連通!

實戰:部署Redis集群

shell腳本

# 創建網卡
[root@ls-Cwj2oH9C /]# docker network create redis --subnet 172.38.0.0/16

# 通過腳本創建六個redis配置
[root@ls-Cwj2oH9C /]# 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

[root@ls-Cwj2oH9C 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

[root@ls-Cwj2oH9C 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

[root@ls-Cwj2oH9C 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

[root@ls-Cwj2oH9C conf]# docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
> -v /mydata/redis/node-4/data:/data \
> -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

[root@ls-Cwj2oH9C conf]# docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
> -v /mydata/redis/node-5/data:/data \
> -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

[root@ls-Cwj2oH9C conf]# docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
> -v /mydata/redis/node-6/data:/data \
> -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
> -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

# 任意進入一個reids容器,注意使用 /bin/sh 而不是 /bin/bash
[root@ls-Cwj2oH9C conf]# 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:6
379 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: f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 3ab93307a4de5df775702779665ca4583abe5210 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: abe4ba6a98b5fe967d952ffc06060d7c07474821 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: ca57da80daea08a065f5add0a607edde9d11e7eb 172.38.0.14:6379
   replicates abe4ba6a98b5fe967d952ffc06060d7c07474821
S: e9664d81440a18689a1d8cd00f7a191f78f0979c 172.38.0.15:6379
   replicates f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2
S: f972b8b774941d383a26ab31cc337c5017657ba0 172.38.0.16:6379
   replicates 3ab93307a4de5df775702779665ca4583abe5210
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: f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: abe4ba6a98b5fe967d952ffc06060d7c07474821 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: ca57da80daea08a065f5add0a607edde9d11e7eb 172.38.0.14:6379
   slots: (0 slots) slave
   replicates abe4ba6a98b5fe967d952ffc06060d7c07474821
S: f972b8b774941d383a26ab31cc337c5017657ba0 172.38.0.16:6379
   slots: (0 slots) slave
   replicates 3ab93307a4de5df775702779665ca4583abe5210
S: e9664d81440a18689a1d8cd00f7a191f78f0979c 172.38.0.15:6379
   slots: (0 slots) slave
   replicates f142bdcc5c5d7ac81eb70d91da9987b71a79d2e2
M: 3ab93307a4de5df775702779665ca4583abe5210 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
[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

[root@ls-Cwj2oH9C ~]# docker stop redis-3
redis-3

127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"

docker搭建redis集群完成!

我們使用了docker之後,所有的技術都會慢慢的變得簡單起來!

SpringBoot微服務打包Docker鏡像

  1. 構建springboot項目

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

  3. 編寫dockerfile

    FROM java:8
    
    COPY *.jar /app.jar
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java","-jar","/app.jar"]
    
  4. 構建鏡像

    [root@ls-Cwj2oH9C home]# mkdir idea
    [root@ls-Cwj2oH9C home]# cd idea
    [root@ls-Cwj2oH9C idea]# ls
    demo1-0.0.1-SNAPSHOT.jar  Dockerfile
    [root@ls-Cwj2oH9C idea]# docker build -t wydilearn .
    
  5. 發布運行!

    [root@ls-Cwj2oH9C idea]# docker run -d -P --name wydilearn-springboot-web wydilearn
    cd4d8f37d9e980af091eceac6ef30f51b9291fc415c53457285353881e19f84b
    [root@ls-Cwj2oH9C idea]# docker ps
    CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS          PORTS                                         NAMES
    cd4d8f37d9e9   wydilearn   "java -jar /app.jar …"   37 seconds ago   Up 36 seconds   0.0.0.0:49163->8080/tcp, :::49163->8080/tcp   wydilearn-springboot-web
    [root@ls-Cwj2oH9C idea]# curl localhost:49163
    {"timestamp":"2022-07-17T04:04:03.880+00:00","status":404,"error":"Not Found","path":"/"}
    [root@ls-Cwj2oH9C idea]# curl localhost:49163/hello
    

以後我們使用了Docker之後,給別人交付的就是一個鏡像即可!

到了這裡我們已經完全夠用了Docker!

未完待續。。。

Tags: