1. 常見命令

SpringCloud微服務技術棧.黑馬跟學(二)_mysql


SpringCloud微服務技術棧.黑馬跟學(二)_數據_02


SpringCloud微服務技術棧.黑馬跟學(二)_數據_03

# 第1步,去DockerHub查看nginx鏡像倉庫及相關信息
https://hub.docker.com/_/nginx

# 第2步,拉取Nginx鏡像
docker pull nginx

# 第3步,查看鏡像
docker images
# 結果如下:
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    605c77e624dd   16 months ago   141MB
mysql        latest    3218b38490ce   17 months ago   516MB

# 第4步,創建並允許Nginx容器
docker run -d --name nginx -p 80:80 nginx

# 第5步,查看運行中容器
docker ps
# 也可以加格式化方式訪問,格式會更加清爽
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第6步,訪問網頁,地址:http://虛擬機地址

# 第7步,停止容器
docker stop nginx

# 第8步,查看所有容器
docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第9步,再次啓動nginx容器
docker start nginx

# 第10步,再次查看容器
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

# 第11步,查看容器詳細信息
docker inspect nginx

# 第12步,進入容器,查看容器內目錄
docker exec -it nginx bash
# 或者,可以進入MySQL
docker exec -it mysql mysql -uroot -p

# 第13步,刪除容器
docker rm nginx
# 發現無法刪除,因為容器運行中,強制刪除容器
docker rm -f nginx

SpringCloud微服務技術棧.黑馬跟學(二)_數據_04


SpringCloud微服務技術棧.黑馬跟學(二)_mysql_05


SpringCloud微服務技術棧.黑馬跟學(二)_docker_06


SpringCloud微服務技術棧.黑馬跟學(二)_mysql_07

2. 命令別名

給常用Docker命令起別名,方便我們訪問:

# 修改/root/.bashrc文件
vi /root/.bashrc
內容如下:
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
alias dis='docker images'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

然後,執行命令使別名生效

source /root/.bashrc

3. 數據卷

容器是隔離環境,容器內程序的文件、配置、運行時產生的容器都在容器內部,我們要讀寫容器內的文件非常不方便。大家思考幾個問題:

  • 如果要升級MySQL版本,需要銷燬舊容器,那麼數據豈不是跟着被銷燬了?
  • MySQL、Nginx容器運行後,如果我要修改其中的某些配置該怎麼辦?
  • 我想要讓Nginx代理我的靜態資源怎麼辦?

因此,容器提供程序的運行環境,但是程序運行產生的數據、程序運行依賴的配置都應該與容器解耦。

SpringCloud微服務技術棧.黑馬跟學(二)_數據_08


鏡像容器中,只包含必備的系統函數,最小化系統環境,直接修改很不方便

3.1 什麼是數據卷

數據卷(volume)是一個虛擬目錄,是容器內目錄與宿主機目錄之間映射的橋樑。
以Nginx為例,我們知道Nginx中有兩個關鍵的目錄:

  • html:放置一些靜態資源
  • conf:放置配置文件
    如果我們要讓Nginx代理我們的靜態資源,最好是放到html目錄;如果我們要修改Nginx的配置,最好是找到conf下的nginx.conf文件。
    但遺憾的是,容器運行的Nginx所有的文件都在容器內部。所以我們必須利用數據卷將兩個目錄與宿主機目錄關聯,方便我們操作。如圖:



    教學演示環節:演示一下nginx的html目錄掛載
# 1.首先創建容器並指定數據卷,注意通過 -v 參數來指定數據卷
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx

# 2.然後查看數據卷
docker volume ls
# 結果
DRIVER    VOLUME NAME
local     29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f
local     html

# 3.查看數據卷詳情
docker volume inspect html
# 結果
[
    {
        "CreatedAt": "2024-05-17T19:57:08+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/html/_data",
        "Name": "html",
        "Options": null,
        "Scope": "local"
    }
]

# 4.查看/var/lib/docker/volumes/html/_data目錄
ll /var/lib/docker/volumes/html/_data
# 可以看到與nginx的html目錄內容一樣,結果如下:
總用量 8
-rw-r--r--. 1 root root 497 12月 28 2021 50x.html
-rw-r--r--. 1 root root 615 12月 28 2021 index.html

# 5.進入該目錄,並隨意修改index.html內容
cd /var/lib/docker/volumes/html/_data
vi index.html

# 6.打開頁面,查看效果

# 7.進入容器內部,查看/usr/share/nginx/html目錄內的文件是否變化
docker exec -it nginx bash

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_09

3.2 匿名數據卷

1.查看MySQL容器詳細信息

docker inspect mysql

關注其中.Config.Volumes部分和.Mounts部分

{
  "Config": {
    // ... 略
    "Volumes": {
      "/var/lib/mysql": {}
    }
    // ... 略
  }
}

可以發現這個容器聲明瞭一個本地目錄,需要掛載數據卷,但是數據卷未定義。這就是匿名卷。
然後,我們再看結果中的.Mounts部分:

{
  "Mounts": [
    {
      "Type": "volume",
      "Name": "29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f",
      "Source": "/var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data",
      "Destination": "/var/lib/mysql",
      "Driver": "local",
    }
  ]
}

可以發現,其中有幾個關鍵屬性:

  • Name:數據卷名稱。由於定義容器未設置容器名,這裏的就是匿名卷自動生成的名字,一串hash值。
  • Source:宿主機目錄
  • Destination : 容器內的目錄
    上述配置是將容器內的/var/lib/mysql這個目錄,與數據卷29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f掛載。於是在宿主機中就有了/var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data這個目錄。這就是匿名數據卷對應的目錄,其使用方式與普通數據卷沒有差別。

接下來,可以查看該目錄下的MySQL的data文件:

ls -l /var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data

注意:每一個不同的鏡像,將來創建容器後內部有哪些目錄可以掛載,可以參考DockerHub對應的頁面

4. 本地目錄掛載

可以發現,數據卷的目錄結構較深,如果我們去操作數據卷目錄會不太方便。在很多情況下,我們會直接將容器目錄與宿主機指定目錄掛載。掛載語法與數據卷類似:

# 掛載本地目錄
-v 本地目錄:容器內目錄
# 掛載本地文件
-v 本地文件:容器內文件

注意:本地目錄或文件必須以 / 或 ./開頭,如果直接以名字開頭,會被識別為數據卷名而非本地目錄名。

-v mysql:/var/lib/mysql # 會被識別為一個數據卷叫mysql,運行時會自動創建這個數據卷

-v ./mysql:/var/lib/mysql # 會被識別為當前目錄下的mysql目錄,運行時如果不存在會創建目錄

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_10


教學演示,刪除並重新創建mysql容器,並完成本地目錄掛載:

  • 掛載/root/mysql/data到容器內的/var/lib/mysql目錄
  • 掛載/root/mysql/init到容器內的/docker-entrypoint-initdb.d目錄(初始化的SQL腳本目錄)
  • 掛載/root/mysql/conf到容器內的/etc/mysql/conf.d目錄(這個是MySQL配置文件目錄)

在課前資料中已經準備好了mysql的init目錄和conf目錄:

SpringCloud微服務技術棧.黑馬跟學(二)_數據_11

以及對應的初始化SQL腳本和配置文件:

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_12

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_13


其中,hm.cnf主要是配置了MySQL的默認編碼,改為utf8mb4;而hmall.sql則是後面我們要用到的黑馬商城項目的初始化SQL腳本。

插入問題解決:

用xftp root連接時顯示ssh服務器拒絕了密碼,(密碼是對的)請重新連接。
產生這個錯誤的原因可能是:由於sshd的設置不允許root用户用密碼遠程登錄,修改/etc/ssh/sshd_config文件,但必須是安裝了openssh才會有這個文件,如果文件不存在,請檢查是否安裝了openssh。
1、輸入命令 :vim /etc/ssh/sshd_config
#Authentication:

LoginGraceTime 120

PermitRootLogin prohibit-password

StrictModes yes

改成如下:

#Authentication:

LoginGraceTime 120

PermitRootLogin yes

StrictModes yes

退出vim編輯後,輸入命令/etc/init.d/ssh restart
重啓ssh服務即可,如果還是不行則直接重啓一次系統即可。

我們直接將整個mysql目錄上傳至虛擬機的/root目錄下:

SpringCloud微服務技術棧.黑馬跟學(二)_docker_14


接下來,我們演示本地目錄掛載:

# 1.刪除原來的MySQL容器
docker rm -f mysql

# 2.進入root目錄
cd ~

# 3.創建並運行新mysql容器,掛載本地目錄
docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  -v ./mysql/data:/var/lib/mysql \
  -v ./mysql/conf:/etc/mysql/conf.d \
  -v ./mysql/init:/docker-entrypoint-initdb.d \
  mysql

# 4.查看root目錄,可以發現~/mysql/data目錄已經自動創建好了
ls -l mysql
# 結果:
總用量 4
drwxr-xr-x. 2 root    root   20 5月  19 15:11 conf
drwxr-xr-x. 7 polkitd root 4096 5月  19 15:11 data
drwxr-xr-x. 2 root    root   23 5月  19 15:11 init

# 查看data目錄,會發現裏面有大量數據庫數據,説明數據庫完成了初始化
ls -l data

# 5.查看MySQL容器內數據
# 5.1.進入MySQL
docker exec -it mysql mysql -uroot -p123
# 5.2.查看編碼表
show variables like "%char%";
# 5.3.結果,發現編碼是utf8mb4沒有問題
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8mb3                        |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+

# 6.查看數據
# 6.1.查看數據庫
show databases;
# 結果,hmall是黑馬商城數據庫
+--------------------+
| Database           |
+--------------------+
| hmall              |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
# 6.2.切換到hmall數據庫
use hmall;
# 6.3.查看錶
show tables;
# 結果:
+-----------------+
| Tables_in_hmall |
+-----------------+
| address         |
| cart            |
| item            |
| order           |
| order_detail    |
| order_logistics |
| pay_order       |
| user            |
+-----------------+
# 6.4.查看address表數據
+----+---------+----------+--------+----------+-------------+---------------+-----------+------------+-------+
| id | user_id | province | city   | town     | mobile      | street        | contact   | is_default | notes |
+----+---------+----------+--------+----------+-------------+---------------+-----------+------------+-------+
| 59 |       1 | 北京     | 北京   | 朝陽區    | 13900112222 | 金燕龍辦公樓   | 李佳誠    | 0          | NULL  |
| 60 |       1 | 北京     | 北京   | 朝陽區    | 13700221122 | 修正大廈       | 李佳紅    | 0          | NULL  |
| 61 |       1 | 上海     | 上海   | 浦東新區  | 13301212233 | 航頭鎮航頭路   | 李佳星    | 1          | NULL  |
| 63 |       1 | 廣東     | 佛山   | 永春      | 13301212233 | 永春武館       | 李曉龍    | 0          | NULL  |
+----+---------+----------+--------+----------+-------------+---------------+-----------+------------+-------+
4 rows in set (0.00 sec)

SpringCloud微服務技術棧.黑馬跟學(二)_數據_15

5. 自定義鏡像

前面我們一直在使用別人準備好的鏡像,那如果我要部署一個Java項目,把它打包為一個鏡像該怎麼做呢?

5.1 鏡像結構

要想自己構建鏡像,必須先了解鏡像的結構。

之前我們説過,鏡像之所以能讓我們快速跨操作系統部署應用而忽略其運行環境、配置,就是因為鏡像中包含了程序運行需要的系統函數庫、環境、配置、依賴。

因此,自定義鏡像本質就是依次準備好程序運行的基礎環境、依賴、應用本身、運行配置等文件,並且打包而成。

SpringCloud微服務技術棧.黑馬跟學(二)_docker_16

舉個例子,我們要從0部署一個Java應用,大概流程是這樣:

  • 準備一個linux服務(CentOS或者Ubuntu均可)
  • 安裝並配置JDK
  • 上傳Jar包
  • 運行jar包

那因此,我們打包鏡像也是分成這麼幾步:

  • 準備Linux運行環境(java項目並不需要完整的操作系統,僅僅是基礎運行環境即可)
  • 安裝並配置JDK
  • 拷貝jar包
  • 配置啓動腳本
    上述步驟中的每一次操作其實都是在生產一些文件(系統運行環境、函數庫、配置最終都是磁盤文件),所以鏡像就是一堆文件的集合。
    但需要注意的是,鏡像文件不是隨意堆放的,而是按照操作的步驟分層疊加而成,每一層形成的文件都會單獨打包並標記一個唯一id,稱為Layer(層)。這樣,如果我們構建時用到的某些層其他人已經制作過,就可以直接拷貝使用這些層,而不用重複製作。

例如,第一步中需要的Linux運行環境,通用性就很強,所以Docker官方就製作了這樣的只包含Linux運行環境的鏡像。我們在製作java鏡像時,就無需重複製作,直接使用Docker官方提供的CentOS或Ubuntu鏡像作為基礎鏡像。然後再搭建其它層即可,這樣逐層搭建,最終整個Java項目的鏡像結構如圖所示:

SpringCloud微服務技術棧.黑馬跟學(二)_docker_17

SpringCloud微服務技術棧.黑馬跟學(二)_docker_18

5.2 Dockerfile

由於製作鏡像的過程中,需要逐層處理和打包,比較複雜,所以Docker就提供了自動打包鏡像的功能。我們只需要將打包的過程,每一層要做的事情用固定的語法寫下來,交給Docker去執行即可。
而這種記錄鏡像結構的文件就稱為Dockerfile,其對應的語法可以參考官方文檔:
https://docs.docker.com/engine/reference/builder/

其中的語法比較多,比較常用的有:

SpringCloud微服務技術棧.黑馬跟學(二)_數據_19


例如,要基於Ubuntu鏡像來構建一個Java應用,其Dockerfile內容如下:

# 指定基礎鏡像
FROM ubuntu:16.04
# 配置環境變量,JDK的安裝目錄、容器內時區
ENV JAVA_DIR=/usr/local
ENV TZ=Asia/Shanghai
# 拷貝jdk和java項目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 設定時區
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 安裝JDK
RUN cd $JAVA_DIR \
 && tar -xf ./jdk8.tar.gz \
 && mv ./jdk1.8.0_144 ./java8
# 配置環境變量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 指定項目監聽的端口
EXPOSE 8080
# 入口,java項目的啓動命令
ENTRYPOINT ["java", "-jar", "/app.jar"]

同學們思考一下:以後我們會有很多很多java項目需要打包為鏡像,他們都需要Linux系統環境、JDK環境這兩層,只有上面的3層不同(因為jar包不同)。如果每次製作java鏡像都重複製作前兩層鏡像,是不是很麻煩。
所以,就有人提供了基礎的系統加JDK環境,我們在此基礎上製作java鏡像,就可以省去JDK的配置了:

# 基礎鏡像
FROM openjdk:11.0-jre-buster
# 設定時區
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷貝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

SpringCloud微服務技術棧.黑馬跟學(二)_docker_20

5.3 構建鏡像

當Dockerfile文件寫好以後,就可以利用命令來構建鏡像了。

在課前資料中,我們準備好了一個demo項目及對應的Dockerfile:

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_21


Dockerfile內容:

# 基礎鏡像
FROM openjdk:11.0-jre-buster
# 設定時區
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷貝jar包
COPY docker-demo.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

首先,我們將課前資料提供的docker-demo.jar包以及Dockerfile拷貝到虛擬機的/root/demo目錄:

SpringCloud微服務技術棧.黑馬跟學(二)_數據_22

然後,執行命令,構建鏡像:

# 進入鏡像目錄
cd /root/demo
# 開始構建
docker build -t docker-demo:1.0 .

命令説明:

  • docker build : 就是構建一個docker鏡像
  • -t docker-demo:1.0 :-t參數是指定鏡像的名稱(repository和tag)
  • . : 最後的點是指構建時Dockerfile所在路徑,由於我們進入了demo目錄,所以指定的是.代表當前目錄,也可以直接指定Dockerfile目錄:
# 直接指定Dockerfile目錄
docker build -t docker-demo:1.0 /root/demo

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_23


結果:

SpringCloud微服務技術棧.黑馬跟學(二)_docker_24

# 1.創建並運行容器
docker run -d --name dd -p 8080:8080 docker-demo:1.0

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_25


可以正常訪問

SpringCloud微服務技術棧.黑馬跟學(二)_docker_26


SpringCloud微服務技術棧.黑馬跟學(二)_mysql_27

6. 網絡

上節課我們創建了一個Java項目的容器,而Java項目往往需要訪問其它各種中間件,例如MySQL、Redis等。現在,我們的容器之間能否互相訪問呢?我們來測試一下

SpringCloud微服務技術棧.黑馬跟學(二)_數據_28

首先,我們查看下MySQL容器的詳細信息,重點關注其中的網絡IP地址:

# 1.用基本命令,尋找Networks.bridge.IPAddress屬性
docker inspect mysql
# 也可以使用format過濾結果
docker inspect --format='{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' mysql
# 得到IP地址如下:
172.17.0.2

# 2.然後通過命令進入dd容器
docker exec -it dd bash

# 3.在容器內,通過ping命令測試網絡
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.053 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.058 ms

發現可以互聯,沒有問題。

但是,容器的網絡IP其實是一個虛擬的IP,其值並不固定與某一個容器綁定,如果我們在開發時寫死某個IP,而在部署時很可能MySQL容器的IP會發生變化,連接會失敗。

所以,我們必須藉助於docker的網絡功能來解決這個問題,官方文檔:

https://docs.docker.com/engine/reference/commandline/network/

SpringCloud微服務技術棧.黑馬跟學(二)_mysql_29


教學演示:自定義網絡

# 1.首先通過命令創建一個網絡
docker network create hmall

# 2.然後查看網絡
docker network ls
# 結果:
NETWORK ID     NAME      DRIVER    SCOPE
639bc44d0a87   bridge    bridge    local
403f16ec62a2   hmall     bridge    local
0dc0f72a0fbb   host      host      local
cd8d3e8df47b   none      null      local
# 其中,除了hmall以外,其它都是默認的網絡

# 3.讓dd和mysql都加入該網絡,注意,在加入網絡時可以通過--alias給容器起別名
# 這樣該網絡內的其它容器可以用別名互相訪問!
# 3.1.mysql容器,指定別名為db,另外每一個容器都有一個別名是容器名
docker network connect hmall mysql --alias db
# 3.2.db容器,也就是我們的java項目
docker network connect hmall dd

# 4.進入dd容器,嘗試利用別名訪問db
# 4.1.進入容器
docker exec -it dd bash
# 4.2.用db別名訪問
ping db
# 結果
PING db (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.056 ms
# 4.3.用容器名訪問
ping mysql
# 結果:
PING mysql (172.18.0.2) 56(84) bytes of data.
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from mysql.hmall (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms

SpringCloud微服務技術棧.黑馬跟學(二)_docker_30


OK,現在無需記住IP地址也可以實現容器互聯了。

總結:

  • 在自定義網絡中,可以給容器起多個別名,默認的別名是容器名本身
  • 在同一個自定義網絡中的容器,可以通過別名互相訪問