Docker部署微服務(wù)
場(chǎng)景介紹
我們使用Docker完成一個(gè)微服務(wù)的搭建過程
整體架構(gòu)如下

使用多個(gè)微服務(wù)進(jìn)行項(xiàng)目部署測(cè)試
整體服務(wù)說明
我們總共涉及到三個(gè)微服務(wù)以及兩個(gè)中間件
| 服務(wù)名稱 | 描述 |
|---|---|
| mysql | 數(shù)據(jù)庫(kù)服務(wù) |
| nacos | 注冊(cè)中心 |
| learn-docker-gateway | 網(wǎng)關(guān)服務(wù) |
| learn-docker-web | API接口服務(wù) |
| learn-docker-storage | 存儲(chǔ)服務(wù) |
配置文件提取
因?yàn)槲覀冊(cè)陂_發(fā)中需要頻繁修改
application.yml文件我們將配置項(xiàng)配置到pom文件中打包時(shí)自動(dòng)打到配置文件,這樣可以用一個(gè)pom文件控制多個(gè)不同的服務(wù)的配置文件項(xiàng)的修改
pom文件定義屬性
我們需要在總
pom文件定義全局配置,例如nacos、mysql等配置
<properties>
<mysql.addr>192.168.64.153:3306</mysql.addr>
<nacos.addr>192.168.64.153:8848</nacos.addr>
</properties>
配置編譯選項(xiàng)
在子項(xiàng)目的pom文件的
build構(gòu)建配置中使用<filtering>true</filtering>配置,這樣就可以將我們的總pom中的配置編譯進(jìn)配置文件了
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
配置文件配置
在子項(xiàng)目的
application.yml配置文件中注意使用@xxx@占位符來配置編譯占位配置,下面的配置就是用了@@占位符編譯后會(huì)將pom中的配置編譯到配置文件中
server:
port: @project.server.prot@
spring:
application:
name: learn-docker-storage
######################### 數(shù)據(jù)源連接池的配置信息 #################
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://@db.addr@/employees?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
initialSize: 10
minIdle: 20
maxActive: 100
maxWait: 60000
#### nacos 配置#######
cloud:
nacos:
server-addr: @nacos.addr@
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.heima.module.p
編譯測(cè)試
配置完后編譯項(xiàng)目后,可以進(jìn)入target目錄下查看編譯后的配置文件

我們看到maven已經(jīng)幫我們將配置編譯進(jìn)了配置文件中了
安裝MySQL
MySQL簡(jiǎn)介
MySQL 是世界上最受歡迎的開源數(shù)據(jù)庫(kù)。憑借其可靠性、易用性和性能,MySQL 已成為 Web 應(yīng)用程序的數(shù)據(jù)庫(kù)優(yōu)先選擇。
查找MySQL鏡像
我們可以使用 docker search 鏡像名稱,命令來搜索鏡像
docker search mysql

參數(shù)解釋
搜索出來的有這么多鏡像,怎么選擇呢
NAME: 鏡像倉(cāng)庫(kù)源的名稱
DESCRIPTION: 鏡像的描述
OFFICIAL: 是否 docker 官方發(fā)布
stars: 類似 Github 里面的 star,表示點(diǎn)贊、喜歡的意思。
AUTOMATED: 自動(dòng)構(gòu)建。
根據(jù)參數(shù),我們一般選擇 官方發(fā)布的,并且stars多的。
下載鏡像
可以使用
docker pull 鏡像名稱來拉取鏡像,我們選擇了第一個(gè)Mysql的鏡像,我們把它給拉取下來
docker pull mysql

注意事項(xiàng)
- 如果不寫版本號(hào)默認(rèn)拉取最新的版本好
latest。 - 拉取的時(shí)候是多個(gè)層一起拉取的,這樣可用讓其他鏡像復(fù)用分層
- 如果拉取的鏡像不寫倉(cāng)庫(kù)地址默認(rèn)就是
docker.io/library/
下載指定版本的鏡像
我們上面下載的鏡像不符合我們的預(yù)期,我們需要Mysql5.7的鏡像
查找指定鏡像
可以登錄 https://hub.docker.com 地址搜索鏡像

輸入需要搜索的鏡像名稱,并選擇對(duì)應(yīng)鏡像名稱

選擇
tag標(biāo)簽,這個(gè)就是版本的信息

找到符合的版本 的mysql鏡像,這里我們選擇
5.7.33

下載指定版本鏡像
剛才我們已經(jīng)找到了
5.7.33版本的Mysql的鏡像,我們使用docker pull命令下載,鏡像后面跟的是tag也就是版本名稱
docker pull mysql:5.7.34

我們發(fā)現(xiàn),我們的新拉取的mysql鏡像共用了 部分分層
查看鏡像
安裝完鏡像后,我們需要看一下我們的本地鏡像,使用
docker images可用查看本地鏡像
docker images

這里有兩個(gè)鏡像,一個(gè)是最新版本的一個(gè)是我們剛才下載的
5.7.33版本的
MySQL配置
配置MySQL忽略大小寫
創(chuàng)建MySQL掛載目錄,等會(huì)會(huì)解釋什么是掛載路徑
# 創(chuàng)建MySQL配置的文件夾
mkdir -p /tmp/etc/mysql
# 編輯my.cnf配置文件
vi /tmp/etc/mysql/my.cnf
配置MySQL忽略大小寫,在我們創(chuàng)建的MySQL配置文件掛載點(diǎn)的目錄的my.cnf文件加入如下內(nèi)容
[mysqld]
lower_case_table_names=1
創(chuàng)建MySQL數(shù)據(jù)目錄
因?yàn)槟J(rèn)MySQL啟動(dòng)后他的文件是在容器中的,如果我們刪除容器,數(shù)據(jù)也將會(huì)消失,我們需要將數(shù)據(jù)掛載出來。
#創(chuàng)建mysql存儲(chǔ)的目錄
mkdir -p /tmp/data/mysql
啟動(dòng)MySql
使用
docker run啟動(dòng)容器
docker run -d -p 3306:3306 -v /tmp/etc/mysql:/etc/mysql/mysql.conf.d/ -v /tmp/data/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql mysql:5.7.34

到這里MySQL已經(jīng)后臺(tái)運(yùn)行了
參數(shù)解釋
- -d:是指容器后臺(tái)運(yùn)行,如果不加
-d,當(dāng)用戶斷開客戶端時(shí)容器會(huì)結(jié)束運(yùn)行 - -p:將容器的3306端口映射到主機(jī)的3306端口,用來暴漏端口的
- -v:這個(gè)命令是用來掛載目錄的,將本地目錄掛載到容器中,這樣容器操作的就是本地目錄
- -e:這個(gè)命令是配置環(huán)境參數(shù)的,這里
MYSQL_ROOT_PASSWORD=root指的是用root用戶運(yùn)行mysql,可以登錄Docker容器通過ENV命令查看 - --name:這個(gè)命令是配置Mysql的容器名稱的,如果不配置,默認(rèn)是隨機(jī)生成的名字
檢查MySQL運(yùn)行狀態(tài)
現(xiàn)在并不能確認(rèn)MySQL的運(yùn)行狀態(tài),我們需要去看下
查看容器運(yùn)行狀態(tài)
使用
docker ps可以看到運(yùn)行中的容器
docker ps
執(zhí)行命令后,我們看到mysql的服務(wù)已經(jīng)起來了

查看MySQL運(yùn)行日志
現(xiàn)在MySQL容器起來了,并不代表MySQL已經(jīng)成功啟動(dòng),我們需要使用
docker logs命令查看MySQL的日志
docker logs -f mysql
該命令可以查看容器日志
-f是追蹤打印日志,可以看到MySQL已經(jīng)啟動(dòng)了

客戶端連接MySQL
因?yàn)槲覀円呀?jīng)暴漏端口了,可以使用客戶端工具連接MySQL

檢查配置的大小寫參數(shù)是否生效
SHOW VARIABLES LIKE '%case_table%';

查看容器掛載的配置文件
可以通過
docker exec -ti mysql /bin/bash命令登錄容器,檢查掛載的配置文件情況
# 登錄容器
docker exec -ti mysql /bin/bash
該命令含義是在mysql容器中以

我們可以看到我們修改的配置文件已經(jīng)被掛載到了docker內(nèi)部,這里面用到了exec命令,主要是在deocker容器中運(yùn)行命令,下面我們介紹下
命令格式
主要是在deocker容器中運(yùn)行命令
docker exec [options] container command [arg...]
命令參數(shù)
| 名稱 | 簡(jiǎn)寫 | 描述 |
|---|---|---|
| --detach | -d | 后臺(tái)運(yùn)行模式,在后臺(tái)執(zhí)行命令相關(guān)命令 |
| --detach-keys | 覆蓋容器后臺(tái)運(yùn)行的一些參數(shù)信息 | |
| --env | -e | 設(shè)置環(huán)境變量 |
| --interactive | -i | 展示容器輸入信息STDIN |
| --privileged | 為命令提供一些擴(kuò)展權(quán)限 | |
| --tty | -t | 命令行交互模式 |
| --user | -u | 設(shè)置用戶名(format: <name|uid>[:<group|gid>]) |
| --workdir | -w | 指定容器內(nèi)的目錄 |
查看掛載的數(shù)據(jù)文件
可以看下掛載的數(shù)據(jù)文件是否存在
cd /tmp/data/mysql/ && ll

我們看到數(shù)據(jù)文件已經(jīng)寫入了
MySQL準(zhǔn)備數(shù)據(jù)
MySql需要導(dǎo)入一些數(shù)據(jù)用來操作,我們用MySQL官方提供的數(shù)據(jù)庫(kù)來操作
下載并導(dǎo)入數(shù)據(jù)
下載MySQL測(cè)試數(shù)據(jù)庫(kù)
到測(cè)試數(shù)據(jù)官網(wǎng) 下載數(shù)據(jù)庫(kù)文件

直接導(dǎo)入無法導(dǎo)入,需要編輯
employees.sql文件的一些地方
set storage_engine = InnoDB;修改為:set default_storage_engine = InnoDB;select CONCAT('storage engine: ', @@storage_engine) as INFO;修改為:select CONCAT('storage engine: ', @@default_storage_engine) as INFO;
.....
set default_storage_engine = InnoDB;
-- set storage_engine = MyISAM;
-- set storage_engine = Falcon;
-- set storage_engine = PBXT;
-- set storage_engine = Maria;
select CONCAT('storage engine: ',@@default_storage_engine) as INFO;
.....
導(dǎo)入測(cè)試數(shù)據(jù)
下載解壓后,在本地執(zhí)行命令導(dǎo)入到mysql服務(wù)器
mysql -uroot -h192.168.64.152 -p < employees.sql

客戶端檢查數(shù)據(jù)
在登陸客戶端就能看到數(shù)據(jù)庫(kù)以及表了

安裝部署nacos
Nacos是阿里巴巴開源的一款支持服務(wù)注冊(cè)與發(fā)現(xiàn),配置管理以及微服務(wù)管理的組件。用來取代以前常用的注冊(cè)中心(zookeeper , eureka等等),以及配置中心(spring cloud config等等)。Nacos是集成了注冊(cè)中心和配置中心的功能,做到了二合一。
直接運(yùn)行服務(wù)
可以直接用docker 啟動(dòng)服務(wù),鏡像不存在會(huì)自動(dòng)拉取
docker run -d -p 8848:8848 --name nacos --env MODE=standalone nacos/nacos-server

運(yùn)行容器后可以稍等下,等待nacos啟動(dòng)成功,受環(huán)境限制啟動(dòng)可能有些慢
登錄頁(yè)面測(cè)試
可以登錄服務(wù)器測(cè)試以下
用戶名:nacos 密碼:nacos

微服務(wù)打包鏡像
我們準(zhǔn)備將一個(gè)微服務(wù)打包成Docker鏡像,在各種服務(wù)器中進(jìn)行運(yùn)行,改為服務(wù)支持進(jìn)行查詢用戶信息
提前說明
因?yàn)槲覀儎傞_始進(jìn)行學(xué)習(xí)Docker,先從單個(gè)微服務(wù)開始學(xué)習(xí),我們就先部署
learn-docker-storage服務(wù),后面隨著課程的深入在慢慢增加其他的微服務(wù)

訪問測(cè)試
在idea中運(yùn)行
learn-docker-storage,

我們配置的端口是8003,我們可以直接訪問
http://localhost:8003/storage/employe/findByID/10001

打包上傳微服務(wù)
將
learn-docker-storage服務(wù)打包后上傳到服務(wù)器
注意配置項(xiàng)
這里需要檢查下maven配置的編譯屬性是否正確
<mysql.addr>192.168.64.153:3306</mysql.addr>
<nacos.addr>192.168.64.153:8848</nacos.addr>
我們發(fā)現(xiàn)是我們?nèi)萜髦袉?dòng)的地址
上傳打包后的微服務(wù)
將target目錄中打包完成的微服務(wù)上傳到服務(wù)器

創(chuàng)建DockerFile
Dockerfile 是一個(gè)用來構(gòu)建鏡像的文本文件,文本內(nèi)容包含了一條條構(gòu)建鏡像所需的指令和說明。
創(chuàng)建一個(gè)Dockerfile文件
vi Dockerfile
具體內(nèi)容如下
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD learn-docker-storage-1.0-SNAPSHOT.jar app.jar
EXPOSE 8003
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
命令解釋
FORM:定制的鏡像都是基于 FROM 的鏡像,這里的 openjdk 就是定制需要的基礎(chǔ)鏡像,后續(xù)操作都是基于openjdk
VOLUME:掛載一個(gè)數(shù)據(jù)卷,這里因?yàn)闆]有名稱,所以是一個(gè)默認(rèn)的數(shù)據(jù)卷(后面詳細(xì)解釋)
ADD:添加一層鏡像到當(dāng)前鏡像,這里就是添加SpringBootTest鏡像到當(dāng)前層,并改名app.jar
EXPOSE:暴漏端口,因?yàn)槲覀兊淖约旱亩丝谑?080,所以我們暴漏8080
ENTRYPOINT:設(shè)定容器啟動(dòng)時(shí)第一個(gè)運(yùn)行的命令及其參數(shù),這里就是容器以啟動(dòng)就執(zhí)行 java -jar /app.jar
打包鏡像
寫好DockerFile后就需要用
docker build命令來構(gòu)建我們的鏡像了,這樣就可以將我們的微服務(wù)打包成一個(gè)鏡像了
構(gòu)建命令格式
構(gòu)建一個(gè)鏡像需要使用以下命令
docker bulid -t 倉(cāng)庫(kù)名/鏡像名:tag .
參數(shù)解釋
-
-t: 鏡像的名字及標(biāo)簽,一般命名規(guī)則是 倉(cāng)庫(kù)名/鏡像名:tag,
- 倉(cāng)庫(kù)名:一般是私服或者dockerhub等地址,如果忽略默認(rèn)就是dockerhub的地址
docker.io.library/ - 鏡像名稱:就是我們的自己的服務(wù)名稱,可以隨意命名
- tag:就是我們的版本號(hào)
- 倉(cāng)庫(kù)名:一般是私服或者dockerhub等地址,如果忽略默認(rèn)就是dockerhub的地址
-
.:這個(gè)
.表示當(dāng)前目錄,這實(shí)際上是在指定上下文的目錄是當(dāng)前目錄,docker build命令會(huì)將該目錄下的內(nèi)容打包交給 Docker 引擎以幫助構(gòu)建鏡像。
實(shí)戰(zhàn)操作
一般來說,應(yīng)該會(huì)將 `Dockerfile` 置于一個(gè)空目錄下,或者項(xiàng)目根目錄下,如果該目錄下沒有所需文件,那么應(yīng)該把所需文件復(fù)制一份過來。
一般大家習(xí)慣性的會(huì)使用默認(rèn)的文件名 `Dockerfile`,以及會(huì)將其置于鏡像構(gòu)建上下文目錄中。
當(dāng)前目錄的結(jié)構(gòu)如下

構(gòu)建鏡像
進(jìn)入Dockerfile的目錄,通過如下命令構(gòu)建鏡像
docker build -t learn-docker-storage:0.0.1 .
構(gòu)建完成如果出現(xiàn)
Successfully說明已經(jīng)構(gòu)建成功了,

查看我們構(gòu)建的鏡像
使用
docker images命令查看我們構(gòu)建完成的鏡像
docker images
我們可以看到我們的鏡像就在第一個(gè)位置

運(yùn)行鏡像
剛才已經(jīng)打包完成了鏡像,現(xiàn)在我們運(yùn)行我們自己的鏡像
# 運(yùn)行容器
docker run -d -p 8003:8003 learn-docker-storage:0.0.1
# 查看運(yùn)行中的容器
docker ps

參數(shù)最后的
learn-docker-storage:0.0.1是鏡像的名稱,如果啟動(dòng)容器可以使用鏡像名稱或者鏡像ID
參數(shù)解釋
-d:后臺(tái)運(yùn)行
-p:映射端口,將宿主機(jī)的8080端口映射到docker內(nèi)部的8080端口上
查看啟動(dòng)日志
使用
docker logs 容器ID來查看啟動(dòng)日志
docker logs -f 74c239792266

嘗試訪問服務(wù)
通過
curl命令來訪問服務(wù)
curl http://192.168.64.153:8003/storage/employe/findByID/10001 | python -m json.tool

我們發(fā)現(xiàn)服務(wù)調(diào)用成功了,我們基本實(shí)現(xiàn)了微服務(wù)改造為docker方式并運(yùn)行
刪除容器
要?jiǎng)h除一個(gè)容器首先需要將一個(gè)容器停止掉
停止容器
我們要把剛才運(yùn)行的容器停止掉,使用
docker stop 容器ID停止一個(gè)容器
docker stop 3752f7088a04

停止容器后,我們?cè)谕ㄟ^進(jìn)程查看是看不到容器的,但是容器還是存在我們的服務(wù)中的
查看全部容器
通過
docker ps只能看到運(yùn)行中的容器,但是我們停止的容器是看不到的,可以加上-a查看所有的容器
docker ps -a

我們可以看到 加上
-a參數(shù)可以看到剛才已經(jīng)停止掉的容器
啟動(dòng)停止的容器
想要啟動(dòng)一個(gè)停止的容器可以使用
docker start 容器ID
docker start 3752f7088a04

這樣就把剛才已經(jīng)停止的容器啟動(dòng)了
刪除容器
已經(jīng)停止的容器可以使用
docker rm 容器ID刪除容器,但是對(duì)于運(yùn)行中的容器可以加上-f參數(shù)強(qiáng)制刪除
docker rm -f 3752f7088a04

這樣可以將一個(gè)運(yùn)行的容器強(qiáng)制刪除,如果停止的容器可以通過通過
docker rm刪除
docker rm 3752f7088a04
這個(gè)時(shí)候就把容器給刪除掉了
日志掛載優(yōu)化
存儲(chǔ)卷優(yōu)化
什么是存儲(chǔ)卷
“卷”是容器上的一個(gè)或多個(gè)“目錄”,此類目錄可繞過聯(lián)合文件系統(tǒng),與宿主機(jī)上的某個(gè)目錄“綁定(關(guān)聯(lián))”;

在Docker中,要想實(shí)現(xiàn)數(shù)據(jù)的持久化(所謂Docker的數(shù)據(jù)持久化即**數(shù)據(jù)不隨著Container的結(jié)束而結(jié)束**),需要將數(shù)據(jù)從宿主機(jī)掛載到容器中。
Docker管理宿主機(jī)文件系統(tǒng)的一部分,默認(rèn)位于 /var/lib/docker/volumes 目錄中;(**最常用的方式**)
存儲(chǔ)卷優(yōu)化寫入速度
Docker鏡像由多個(gè)只讀層疊加而成,啟動(dòng)容器時(shí),docker會(huì)加載只讀鏡像層并在鏡像棧頂部加一個(gè)讀寫層;

如果運(yùn)行中的容器修改了現(xiàn)有的一個(gè)已經(jīng)存在的文件,那該文件將會(huì)從讀寫層下面的只讀層復(fù)制到讀寫層,該文件版本仍然存在,只是已經(jīng)被讀寫層中該文件的副本所隱藏,此即“**寫時(shí)復(fù)制(COW)”機(jī)制**。

為了避免這種情況,構(gòu)建Dockerfile的時(shí)候應(yīng)該加入一個(gè)存儲(chǔ)卷
Dockerfile增加存儲(chǔ)卷
增加存儲(chǔ)卷
編寫Dockerfile增加存儲(chǔ)卷,增加日志存儲(chǔ)卷
/logs,這會(huì)是一個(gè)匿名存儲(chǔ)卷
FROM openjdk:8-jdk-alpine
VOLUME /tmp /logs
ADD learn-docker-storage-1.0-SNAPSHOT.jar app.jar
EXPOSE 8003
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
構(gòu)建鏡像
因?yàn)槲覀冊(cè)瓉硪呀?jīng)構(gòu)建了鏡像,這次使用版本號(hào)是
0.0.2
#構(gòu)建鏡像
docker build -t learn-docker-storage:0.0.2 .
# 查看鏡像列表
docker images

運(yùn)行容器
通過run命令運(yùn)行容器
# 運(yùn)行容器
docker run -d -p 8003:8003 learn-docker-storage:0.0.2
# 查看運(yùn)行中的容器
docker ps

查看存儲(chǔ)卷
通過
docker volume ls可以看到存儲(chǔ)卷
docker volume ls

查看容器信息
我們發(fā)現(xiàn)都是匿名的存儲(chǔ)卷,如何來確定都是那個(gè)呢,可以通過
docker inspect 容器ID來查看存儲(chǔ)新鮮
docker inspect 2041965c3e87|grep Mounts -A20

通過這個(gè)命令可以看到數(shù)據(jù)卷的名稱以及宿主機(jī)的存儲(chǔ)路徑,我們可以直接到宿主機(jī)打印日志
# 進(jìn)入文件掛載目錄
cd /var/lib/docker/volumes/d35de1b7e4631908b05635db4c1f114ab3aafbdf25a9843c068696e66a779c75/_data
# 輸出日志
tail -f learn-docker-storage.log

這樣就看到了我們的日志文件
驗(yàn)證存儲(chǔ)卷
刪除容器檢查存儲(chǔ)卷釋放消失
# 查看運(yùn)行的容器列表
docker ps
#刪除容器
docker rm -f 2041965c3e87
#查看所有的容器列表(運(yùn)行+停止)
docker ps -a

我們看到容器已經(jīng)被刪除了,檢查我們的存儲(chǔ)卷
docker volume ls

發(fā)現(xiàn)存儲(chǔ)卷還存在,數(shù)據(jù)還是存在的,并且數(shù)據(jù)也存在
# 查看存儲(chǔ)卷列表
docker volume ls
# 查看存儲(chǔ)卷詳情
docker inspect 296ccc64d919e86bb8329bf6b08447c2ea6a118458d3fcb86d5c7c9a3177dfe0

重新運(yùn)行鏡像啟動(dòng)一個(gè)新的容器
# 運(yùn)行容器
docker run -d -p 8080:8080 e1222496c69f
# 查看運(yùn)行中的容器
docker ps

啟動(dòng)容器后查看存儲(chǔ)卷列表
# 查看存儲(chǔ)卷列表
docker volume ls

我們發(fā)現(xiàn)有創(chuàng)建了兩個(gè)存儲(chǔ)卷,查看容器詳情
docker inspect 2041965c3e87|grep Mounts -A20

我們發(fā)現(xiàn)新啟動(dòng)的容器新開了一個(gè)匿名存儲(chǔ)卷
bind掛載共享存儲(chǔ)
什么是bind
Bind mounts模式和Volumes非常相似,不同點(diǎn)在于Bind mounts模式是將宿主機(jī)上的任意文件或文件夾掛載到容器,而Volumes本質(zhì)上是將Docker服務(wù)管理的一塊區(qū)域(默認(rèn)是/var/lib/docker/volumes下的文件夾)掛載到容器。
共享存儲(chǔ)
經(jīng)過上面的測(cè)試,我們發(fā)現(xiàn)每一個(gè)容器都是單獨(dú)用一個(gè)存儲(chǔ)卷,用于臨時(shí)文件沒有問題的,但是如果要讓容器都用同一個(gè)存儲(chǔ)路徑怎么辦呢,這個(gè)時(shí)候就用到了 bind掛載了,可以使用
-v進(jìn)行掛載掛載剛才的存儲(chǔ)卷。
# 級(jí)聯(lián)創(chuàng)建文件夾
mkdir -p /tmp/data/logs
# 運(yùn)行容器,指定掛載路徑
docker run -d -v /tmp/data/logs:/logs \
-p 8003:8003 --name learn-docker-storage \
learn-docker-storage:0.0.2
這里面
--name是指定docker容器的名稱,我們操作容器就可以使用名稱進(jìn)行操作了

然后使用
docker inspect命令來檢查容器詳情
docker inspect learn-docker-storage|grep Mounts -A20

我們發(fā)現(xiàn)掛載日志的掛載方式已經(jīng)變了,由原來的volume變?yōu)榱薭ind,并且掛載路徑變?yōu)榱宋覀冏约憾x的路徑,進(jìn)入目錄查看
# 進(jìn)入目錄并瀏覽目錄文件
cd /tmp/data/logs/&&ll
# 打印日志詳情
tail -f learn-docker-storage.log

驗(yàn)證共享存儲(chǔ)
我們也按照上面步驟驗(yàn)證下bind方式掛載的存儲(chǔ),先刪除容器,檢查日志文件是否存在
# 停止并刪除容器
docker rm -f learn-docker-storage
# 查看容器已經(jīng)被刪除了
docker ps -a
# 進(jìn)入日志掛載路徑查看日志是否村咋
cd /tmp/data/logs/&&ll
我們發(fā)現(xiàn)容器被刪除但是日志文件還存在本地

啟動(dòng)一個(gè)新的容器
# 運(yùn)行容器,指定掛載路徑
docker run -d -v /tmp/data/logs:/logs \
-p 8003:8003 --name learn-docker-storage \
learn-docker-storage:0.0.2
# 查看日志文件
cat learn-docker-storage.log
我們發(fā)現(xiàn)新的容器的日志文件追加進(jìn)來了

我們發(fā)現(xiàn)日志已經(jīng)追加,我們讓不同的容器掛載同一個(gè)目錄了
volume和bind的區(qū)別
對(duì)于多個(gè)容器需要共享訪問同一數(shù)據(jù)目錄,或者需要持久化容器內(nèi)數(shù)據(jù)(如數(shù)據(jù)庫(kù))時(shí),我們都是采用掛載目錄形式(bind mounts),將宿主機(jī)的某一目錄掛載到容器內(nèi)的指定目錄,這種方式能解決問題,但這種方式也一直有一些缺點(diǎn)
- 容器在不同的服務(wù)器部署需要根據(jù)實(shí)際磁盤掛載目錄修改路徑
- 不同操作系統(tǒng)的文件和目錄權(quán)限會(huì)搞得你昏頭轉(zhuǎn)向,火冒三丈 ?
bind mount和volume其實(shí)都是利用宿主機(jī)的文件系統(tǒng),不同之處在于volume是docker自身管理的目錄中的子目錄,所以不存在權(quán)限引發(fā)的掛載的問題,并且目錄路徑是docker自身管理的,所以也不需要在不同的服務(wù)器上指定不同的路徑,你不需要關(guān)心路徑。

清理volume掛載
volume掛載方式,會(huì)生成很多匿名的目錄,我們可以找到對(duì)應(yīng)的沒有使用的volume進(jìn)行刪除
docker volume ls

通過查看我們發(fā)現(xiàn)里面,有很多的volume,我們可以找到?jīng)]有用的刪除
docker volume rm volume_name

還可以通過命令將沒有引用的全部volume清除掉,但是這個(gè)命令很危險(xiǎn)
docker volume prune

這樣就將我們服務(wù)器上無效的volume清除掉了
網(wǎng)絡(luò)優(yōu)化
Docker網(wǎng)絡(luò)原理
Docker使用Linux橋接,在宿主機(jī)虛擬一個(gè)Docker容器網(wǎng)橋(docker0),Docker啟動(dòng)一個(gè)容器時(shí)會(huì)根據(jù)Docker網(wǎng)橋的網(wǎng)段分配給容器一個(gè)IP地址,稱為Container-IP,同時(shí)Docker網(wǎng)橋是每個(gè)容器的默認(rèn)網(wǎng)關(guān)。因?yàn)樵谕凰拗鳈C(jī)內(nèi)的容器都接入同一個(gè)網(wǎng)橋,這樣容器之間就能夠通過容器的Container-IP直接通信。
Docker網(wǎng)橋是宿主機(jī)虛擬出來的,并不是真實(shí)存在的網(wǎng)絡(luò)設(shè)備,外部網(wǎng)絡(luò)是無法尋址到的,這也意味著外部網(wǎng)絡(luò)無法通過直接Container-IP訪問到容器。如果容器希望外部訪問能夠訪問到,可以通過映射容器端口到宿主主機(jī)(端口映射),即docker run創(chuàng)建容器時(shí)候通過 -p 或 -P 參數(shù)來啟用,訪問容器的時(shí)候就通過[宿主機(jī)IP]:[容器端口]訪問容器。
Docker網(wǎng)絡(luò)模式
| Docker網(wǎng)絡(luò)模式 | 配置 | 說明 |
|---|---|---|
| host模式 | –net=host | 容器和宿主機(jī)共享Network namespace。 |
| container模式 | –net=container:NAME_or_ID | 容器和另外一個(gè)容器共享Network namespace。 kubernetes中的pod就是多個(gè)容器共享一個(gè)Network namespace。 |
| none模式 | –net=none | 容器有獨(dú)立的Network namespace,但并沒有對(duì)其進(jìn)行任何網(wǎng)絡(luò)設(shè)置,如分配veth pair 和網(wǎng)橋連接,配置IP等。 |
| overlay模式 | -- driver overlay | Docker跨主機(jī)通信模式,使用分布式計(jì)算機(jī)架構(gòu)后需要使用overlay網(wǎng)絡(luò)模式 |
| bridge模式 | –net=bridge | (默認(rèn)為該模式) |
host模式
如果啟動(dòng)容器的時(shí)候使用host模式,那么這個(gè)容器將不會(huì)獲得一個(gè)獨(dú)立的Network Namespace,而是和宿主機(jī)共用一個(gè)Network Namespace。容器將不會(huì)虛擬出自己的網(wǎng)卡,配置自己的IP等,而是使用宿主機(jī)的IP和端口。但是,容器的其他方面,如文件系統(tǒng)、進(jìn)程列表等還是和宿主機(jī)隔離的。
使用host模式的容器可以直接使用宿主機(jī)的IP地址與外界通信,容器內(nèi)部的服務(wù)端口也可以使用宿主機(jī)的端口,不需要進(jìn)行NAT,host最大的優(yōu)勢(shì)就是網(wǎng)絡(luò)性能比較好,但是docker host上已經(jīng)使用的端口就不能再用了,網(wǎng)絡(luò)的隔離性不好。
Host模式如下圖所示

container模式
這個(gè)模式指定新創(chuàng)建的容器和已經(jīng)存在的一個(gè)容器共享一個(gè) Network Namespace,而不是和宿主機(jī)共享。新創(chuàng)建的容器不會(huì)創(chuàng)建自己的網(wǎng)卡,配置自己的 IP,而是和一個(gè)指定的容器共享 IP、端口范圍等。同樣,兩個(gè)容器除了網(wǎng)絡(luò)方面,其他的如文件系統(tǒng)、進(jìn)程列表等還是隔離的。兩個(gè)容器的進(jìn)程可以通過 lo 網(wǎng)卡設(shè)備通信。
Container模式示意圖
none模式
使用none模式,Docker容器擁有自己的Network Namespace,但是,并不為Docker容器進(jìn)行任何網(wǎng)絡(luò)配置。也就是說,這個(gè)Docker容器沒有網(wǎng)卡、IP、路由等信息。需要我們自己為Docker容器添加網(wǎng)卡、配置IP等。
這種網(wǎng)絡(luò)模式下容器只有l(wèi)o回環(huán)網(wǎng)絡(luò),沒有其他網(wǎng)卡。none模式可以在容器創(chuàng)建時(shí)通過--network=none來指定。這種類型的網(wǎng)絡(luò)沒有辦法聯(lián)網(wǎng),封閉的網(wǎng)絡(luò)能很好的保證容器的安全性。
None模式示意圖
overlay模式
容器在兩個(gè)跨主機(jī)進(jìn)行通信的時(shí)候,是使用overlay network這個(gè)網(wǎng)絡(luò)模式進(jìn)行通信,如果使用host也可以實(shí)現(xiàn)跨主機(jī)進(jìn)行通信,直接使用這個(gè)物理的ip地址就可以進(jìn)行通信。overlay它會(huì)虛擬出一個(gè)網(wǎng)絡(luò)比如10.0.9.3這個(gè)ip地址,在這個(gè)overlay網(wǎng)絡(luò)模式里面,有一個(gè)類似于服務(wù)網(wǎng)關(guān)的地址,然后把這個(gè)包轉(zhuǎn)發(fā)到物理服務(wù)器這個(gè)地址,最終通過路由和交換,到達(dá)另一個(gè)服務(wù)器的ip地址。
bridge模式
當(dāng)Docker進(jìn)程啟動(dòng)時(shí),會(huì)在主機(jī)上創(chuàng)建一個(gè)名為docker0的虛擬網(wǎng)橋,此主機(jī)上啟動(dòng)的Docker容器會(huì)連接到這個(gè)虛擬網(wǎng)橋上。虛擬網(wǎng)橋的工作方式和物理交換機(jī)類似,這樣主機(jī)上的所有容器就通過交換機(jī)連在了一個(gè)二層網(wǎng)絡(luò)中。
從docker0子網(wǎng)中分配一個(gè)IP給容器使用,并設(shè)置docker0的IP地址為容器的默認(rèn)網(wǎng)關(guān)。在主機(jī)上創(chuàng)建一對(duì)虛擬網(wǎng)卡veth pair設(shè)備,Docker將veth pair設(shè)備的一端放在新創(chuàng)建的容器中,并命名為eth0(容器的網(wǎng)卡),另一端放在主機(jī)中,以vethxxx這樣類似的名字命名,并將這個(gè)網(wǎng)絡(luò)設(shè)備加入到docker0網(wǎng)橋中??梢酝ㄟ^brctl show命令查看。
bridge模式是docker的默認(rèn)網(wǎng)絡(luò)模式,不寫--net參數(shù),就是bridge模式。使用docker run -p時(shí),docker實(shí)際是在iptables做了DNAT規(guī)則,實(shí)現(xiàn)端口轉(zhuǎn)發(fā)功能。可以使用iptables -t nat -vnL查看。
bridge模式如下圖所示

我們的網(wǎng)絡(luò)結(jié)構(gòu)
下圖是我們自己的網(wǎng)絡(luò)結(jié)構(gòu),我們是通過宿主機(jī)訪問Mysql容器的,剛才我們學(xué)過,默認(rèn)Docker已經(jīng)接入了一個(gè)名字叫
bridge的橋接網(wǎng)絡(luò)

我們可以讓我們的網(wǎng)絡(luò)直接接入橋接網(wǎng)絡(luò),例如下圖

創(chuàng)建網(wǎng)絡(luò)
查看網(wǎng)絡(luò)列表
可以通過
docker network ls命令查看網(wǎng)絡(luò)列表
# 查看網(wǎng)絡(luò)列表
docker network ls

上面就是容器默認(rèn)幾種網(wǎng)絡(luò)
創(chuàng)建一個(gè)橋接網(wǎng)絡(luò)
默認(rèn)容器啟動(dòng)會(huì)自動(dòng)默認(rèn)接入
bridge的橋接網(wǎng)絡(luò),為了區(qū)分我們的服務(wù)也防止各種網(wǎng)絡(luò)問題,我們創(chuàng)建一個(gè)專用網(wǎng)絡(luò),可以通過docker network create 網(wǎng)絡(luò)名稱來創(chuàng)建一個(gè)默認(rèn)的橋接網(wǎng)絡(luò)
# 創(chuàng)建一個(gè)橋接網(wǎng)絡(luò)
docker network create learn-docker-network
# 查看網(wǎng)絡(luò)列表
docker network ls

服務(wù)接入網(wǎng)絡(luò)
停止并刪除原有容器
停止和刪除我們的微服務(wù)以及mysql服務(wù)
# 刪除當(dāng)前運(yùn)行中的容器
docker rm -f learn-docker-storage nacos mysql

創(chuàng)建MySQL
因?yàn)槲覀兊奈⒎?wù)依賴MySQL先啟動(dòng)MySQL并接入網(wǎng)絡(luò),因?yàn)镸ySQL不需要通過宿主機(jī)訪問,所有也不需要映射端口了,--network 是配置接入哪一個(gè)網(wǎng)絡(luò)
docker run -d \
-v /tmp/etc/mysql:/etc/mysql/mysql.conf.d/ \
-v /tmp/data/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
--name mysql --network=learn-docker-network \
mysql:5.7.34

這樣我們就把我們的MySQL服務(wù)啟動(dòng)起來了并且加入了learn-docker-network的網(wǎng)絡(luò)
創(chuàng)建Nacos
我們的nacos是需要暴漏端口的,因?yàn)槲覀冃枰獠磕軌蚩吹絥acos頁(yè)面,但是我們也需要我們的nacos連接到當(dāng)前網(wǎng)絡(luò)
docker run -d -p 8848:8848 \
--network=learn-docker-network \
--name nacos --env MODE=standalone \
nacos/nacos-server

查看網(wǎng)絡(luò)詳情
可以通過
docker network inspect 網(wǎng)絡(luò)名稱可以查看當(dāng)前的網(wǎng)絡(luò)的詳細(xì)信息
docker network inspect learn-docker-network|grep Containers -A 20

修改微服務(wù)配置
因?yàn)樾枰褂米远x網(wǎng)絡(luò)訪問mysql容器以及nacos容器,需要修改微服務(wù)數(shù)據(jù)庫(kù)連接地址,
docker 網(wǎng)絡(luò)訪問 可以通過IP或者通過服務(wù)名稱都是可以的,這里我們通過**服務(wù)名稱訪問**,因?yàn)槲覀兪褂昧薽aven打包的方式,我們只需要將pom文件修改就可以
<properties>
<mysql.addr>mysql:3306</mysql.addr>
<nacos.addr>nacos:8848</nacos.addr>
</properties>
修改完成后進(jìn)行編譯項(xiàng)目

這里將數(shù)據(jù)庫(kù)連接地址改為mysql容器的服務(wù)名稱
mysql,nacos的連接地址變?yōu)榱?code>nacos
重新打包服務(wù)
將打包的文件上傳服務(wù)器后按照上面步驟同上面打包,打包版本為 0.0.3
docker build -t learn-docker-storage:0.0.3 .

創(chuàng)建微服務(wù)
下面就按部就班的創(chuàng)建微服務(wù)就可以,只是注意需要加入網(wǎng)絡(luò),這里這個(gè)端口需要映射外網(wǎng)訪問
docker run -d \
-v /tmp/data/logs:/logs \
-p 8003:8003 \
--name learn-docker-storage \
--network=learn-docker-network \
learn-docker-storage:0.0.3

測(cè)試微服務(wù)
到現(xiàn)在微服務(wù)已經(jīng)啟動(dòng),我們嘗試訪問以下
curl http://192.168.64.153:8003/storage/employe/findByID/10001 | python -m json.tool

訪問測(cè)試數(shù)據(jù)沒有問題,到現(xiàn)在我們服務(wù)已經(jīng)搭建完成,并且使用網(wǎng)絡(luò)進(jìn)行了優(yōu)化
本文由育博學(xué)谷狂野架構(gòu)師發(fā)布
如果本文對(duì)您有幫助,歡迎關(guān)注和點(diǎn)贊;如果您有任何建議也可留言評(píng)論或私信,您的支持是我堅(jiān)持創(chuàng)作的動(dòng)力
轉(zhuǎn)載請(qǐng)注明出處!