前言
書接上文Docker-初級安裝及使用_用docker安裝doccano-CSDN博客,我們講解了
Docker
的基本操作,下面我們講解的是高級使用,請大家做好準備!
大家如果是從初級安裝使用過來的話,建議把之前鏡像和搭載的容器數據卷里面文件數據都清掉,再進行下面操作,不操作也可
如果刪除的話,記得也把
/etc/my.cnf
的數據庫文件一起刪掉find / -name my.cnf --查找rm $(find / -name my.cnf) --刪除
基于
docker(26.1.4)
版本演示
MySql主從搭建
有了
docker
以后,我們的主從搭建也會變得相當簡單,我們使用5.7
版本演示,共有如下幾步。
- 新建主服務器實例
3307
端口- 進入
/mydir/mysql/master/conf
目錄下新建my.cnf
文件- 修改完配置后重啟
master
實例- 進入
mysql-master
容器master
容器實例內創建數據同步用戶- 新建從服務器實例3308
- 進入
mydir/mysql/slave/conf
目錄下新建my.cnf
- 修改完配置后重啟
slave
實例- 在主數據庫中查看主從同步狀態
- 進入
mysql-slave
容器- 在從數據庫中配置主從復制
- 在從數據庫中查看主從同步狀態
- 在從數據庫中開啟主從同步
- 查看從數據庫狀態發現已經同步
- 主從復制測試
1.新建主服務器實例3307
端口
docker鏡像拉取我這里就不寫了,演示版本為
5.7
雖然我在
基礎篇
寫過好幾遍了,但是為了避免大家忘記,我這里從寫以下,同時回顧回顧。參數講解:
-d
:后臺啟動
-p 3307:3306
:宿主機3307
端口映射到容器內的3306
端口
--name mysql-master
:定義容器名稱為mysql-master
-v /mydir/mysql/master/log:/var/log/mysql
:搭建容器數據卷映射,將log
文件映射出來宿主機目錄中,:
前面為宿主機目錄地址,后面為容器目錄地址
-v /mydir/mysql/master/data:/var/lib/mysql
:搭建容器數據卷映射,將數據
文件映射出來宿主機目錄中
-v /mydir/mysql/master/conf:/etc/mysql
:搭建容器數據卷映射,將啟動配置文件
文件映射出來宿主機目錄中
-e MYSQL_ROOT_PASSWORD=admin
:設置環境變量,我這里是設置mysql
的密碼
mysql:5.7
:鏡像名:版本號如果大家啟動以后執行
ps
命令報如下錯了,就按照前言中的,把my.cnf
文件全部清掉mysqld failed while attempting to check config command was: mysqld --verbose --help --log-bin-index=/tmp/tmp.Im9pj3bIY7 mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 2 - No such file or directory) mysqld: [ERROR] Fatal error in defaults handling. Program aborted!
docker run -d -p 3307:3306 --name mysql-master -v /mydir/mysql/master/log:/var/log/mysql -v /mydir/mysql/master/data:/var/lib/mysql -v /mydir/mysql/master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=admin mysql:5.7
2.進入/mydir/mysql/master/conf
目錄下新建my.cnf
文件
[mysqld]
## 設置 server_id,同一局域網中需要唯一
server_id=1
## 指定不需要同步的數據庫名稱
binlog-ignore-db=mysql
## 開啟二進制日志功能 mall-mysql-bin表示日志名稱,例如,在一個服務器上運行多個 MySQL 實例,每個實例對應不同的業務系統(像商城系統、物流系統等)生成的二進制日志文件名稱就會類似 mall-mysql-bin.000001、mall-mysql-bin.000002 等,其中 .000001、.000002 是遞增的編號,用來區分不同的日志文件
log-bin=mall-mysql-bin
## 設置二進制日志使用內存大小(事務)
binlog_cache_size=1M
## 設置使用的二進制日志格式(mixed,statement,row)
binlog-format=mixed
## 二進制日志過期清理時間。默認值為0,表示不自動清理
expire_logs_days=7
## 跳過主從復制中遇到的所有錯誤或指定類型的錯誤,避免slave端復制終端。
## 如:1062錯誤是指一些主鍵重復,1032錯誤是因為主從數據庫數據不一致
slave_skip_errors=1062# 字符集設置
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
# 進入文件夾
cd /mydir/mysql/master/conf# 創建my.cnf文件,并寫入如上內容
vim my.cnf# 保存并退出
:wq
3.修改完配置后重啟master
實例
docker restart mysql-master
4.進入mysql-master
容器
# 進入容器
docker exec -it mysql-master /bin/bash# 打開mysql客戶端
mysql -uroot -p
# 輸入密碼 admin(啟動命令定義的)
5.master
容器實例內創建數據同步用戶
創建用戶命令
- 創建用戶
slave
,并指定密碼為123456
賦予權限命令
GRANT
關鍵字
GRANT
是 MySQL 中用于授予用戶特定權限的關鍵字。使用這個關鍵字可以指定用戶能夠執行的操作以及操作的范圍。- 權限列表
REPLICATION SLAVE
:此權限允許用戶連接到主服務器并接收二進制日志事件,是配置 MySQL 主從復制時從服務器必須具備的權限。從服務器借助該權限才能從主服務器獲取二進制日志,從而實現數據同步。REPLICATION CLIENT
:該權限允許用戶查看主服務器和從服務器的復制狀態信息。擁有此權限的用戶可以使用SHOW MASTER STATUS
和SHOW SLAVE STATUS
等命令來查看復制相關的狀態。ON *.*
ON
關鍵字用于指定權限作用的范圍,*.*
表示權限適用于所有數據庫的所有表。也就是說,被授予權限的用戶在所有數據庫和表上都具備REPLICATION SLAVE
和REPLICATION CLIENT
權限。TO 'slave'@'%'
'slave'
:這是要授予權限的用戶名,表明要為名為slave
的用戶授予指定的權限。'%'
:代表用戶可以從任意主機連接到 MySQL 服務器。如果將%
替換為具體的 IP 地址或主機名,那么該用戶就只能從指定的主機連接到 MySQL 服務器。
# 創建mysql從數據庫用戶
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
# 賦予用戶權限
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slave'@'%';
6.新建從服務器實例3308
docker run -d -p 3308:3306 --name mysql-slave -v /mydir/mysql/slave/log:/var/log/mysql -v /mydir/mysql/slave/data:/var/lib/mysql -v /mydir/mysql/slave/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=admin mysql:5.7
7.進入mydir/mysql/slave/conf
目錄下新建my.cnf
[mysqld]
## 設置 server_id,同一局域網中需要唯一
server_id=2
## 指定不需要同步的數據庫名稱
binlog-ignore-db=mysql
## 開啟二進制日志功能 mall-mysql-slave1-bin表示日志名稱,例如,在一個服務器上運行多個 MySQL 實例,每個實例對應不同的業務系統(像商城系統、物流系統等)生成的二進制日志文件名稱就會類似 mall-mysql-slave1-bin.000001、mall-mysql-slave1-bin.000002 等,其中 .000001、.000002 是遞增的編號,用來區分不同的日志文件
log-bin=mall-mysql-slave1-bin
## 設置二進制日志使用內存大小(事務)
binlog_cache_size=1M
## 設置使用的二進制日志格式(mixed,statement,row)
binlog-format=mixed
## 二進制日志過期清理時間。默認值為0,表示不自動清理
expire_logs_days=7
## 跳過主從復制中遇到的所有錯誤或指定類型的錯誤,避免slave端復制終端。
## 如:1062錯誤是指一些主鍵重復,1032錯誤是因為主從數據庫數據不一致
slave_skip_errors=1062
## relay_log配置中繼日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave將復制事件寫進自己的二進制日志
log_slave_updates=1
## slave設置為只讀(具有super權限的用戶除外)
read_only=1# 字符集設置
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
# 進入文件夾
cd /mydir/mysql/slave/conf# 創建my.cnf文件,并寫入如上內容
vim my.cnf# 保存并退出
:wq
8.修改完配置后重啟slave
實例
docker restart mysql-slave
9.在主數據庫中查看主從同步狀態
# 進入容器
docker exec -it mysql-master /bin/bash# 打開mysql客戶端
mysql -uroot -p
# 輸入密碼 admin(啟動命令定義的)# 查看binlog文件
show master status
10.進入mysql-slave
容器
docker exec -it mysql-slave bash# 進入mysql cli
mysql -uroot -p
# 輸入密碼,我這里是admin(啟動容器命令中有)
11.在從數據庫中配置主從復制
change master to master_host='宿主機ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='第九步圖片中File對應的值(我這里是 mall-mysql-bin.000001)', master_log_pos=第九步圖中Positon對應的值(我這里是 962), master_connect_retry=30;## 如下是我的命令,每個人ip、文件名、Postion可能不一樣,自行替換
change master to master_host='192.168.71.111', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=962, master_connect_retry=30;
12.在從數據庫中查看主從同步狀態
我這里列舉下圖幾個重要的講解
Master_Host
:主數據庫的IP地址Master_Port
:主數據庫的運行端口Master_User
:主數據庫創建的用于同步數據的用戶賬號Master_Log_File
:指定從數據庫要復制數據的日志文件,通過查看主數據的狀態,獲取File
參數Master_Log_Pos
:指定從數據庫從那個位置開始復制數據,通過查看主數據的狀態,獲取Position
參數Master_Connect_Retry
:連接失敗重試的時間間隔,單位為秒看見如下兩個屬性值都為
No
表示同步還未開始
# 以下命令在從數據庫中執行查看
show slave status \G;
13.在從數據庫中開啟主從同步
start slave;
14.查看從數據庫狀態發現已經同步
show slave status \G;
15.主從復制測試
## 主數據中 master
-- 創建庫
create database mydb;
-- 使用庫
use mydb;
-- 創建表
create table user(id int, name varchar(50));
-- 新建數據
insert into user values(1, 'zhang3');
-- 查詢數據
select * from user;## 從數據中 slave
# 使用庫
use mydb;
# 查詢數據
select * from user;
Redis主從搭建
- Redis主從搭建共有三套方案,下面我們會講到
- 哈希取余分區
- 一致性哈希算法分區
- 哈希槽分區
1、主從方案分析與選擇
1.1、哈希取余分區
- 假設我們3臺機器上構成一個集群,用戶每次讀寫操作都是根據公式:
hash(key) % N
個機器臺數,計算出哈希值,用來決定數據映射到哪一個節點上,存取數據都會使用這個算法- 好處:簡單,粗暴,實現起來容易,適合小廠使用
- 缺點:當進行擴容或縮容時,映射關系需要重新進行計算
Hash(key)/3
可能會變成Hash(key)/?
此時地址經過取余運算的結果將發生很大變化,根據公式獲取的服務器也會變的不可控
1.2、一致性哈希算法分區
圓環形成
一致性哈希算法必然有個
hash
函數并按照算法產生hash
值,這個算法的所有可能哈希值會構成一個全量集,這個集合可以成為一個hash
空間[0,2^32-1]
,這個是一個線性空間,但是在算法中,我們通過適當的邏輯控制將它的首尾相連(0=2^32),這樣讓它邏輯上形成了一個環形空間
集群映射
然后將集群中的各個
IP
節點映射到環上的某一個位置,將各個服務器使用Hash
進行一個哈希,具體可以選擇服務器的IP
或主機名作為關鍵字進行哈希,這樣每臺機器就能確定其在哈希環上的位置。假如4個節點
NodeA、B、C、D
,經過IP
地址的哈希函數計算(hash(ip)
),使用IP
地址哈希后再環空間的位置如下
鍵值存儲
當我們呢需要存儲一個
kv
鍵值對時,首先計算key
的hash
值,hash(key)
,將這個key
使用相同的函數Hash
計算出哈希值,并且頂此數據再環上的位置,從此位置沿環順時針"行走,第一臺遇到的服務器就是其應該定位到的服務器",并將該鍵值對存儲在該節點上
優缺點
優點:增加了容錯性,當刪除/停用一個節點時,不會影響其他節點的讀取。并且新增時一個節點影響的數據很少
缺點:當節點少時,很容易造成數據傾斜的問題
1.3、哈希槽分區
能干什么
- 可以解決上面的均勻分配的問題,在數據和節點之間又加入了一層,把這層成為哈希槽(slot),用于管理數據和節點之間的關系,現在就相當于節點上放的時槽,槽里放的時數據
- 槽解決的時粒度問題,相當于把粒度變大了,這樣便于數據移動
- 哈希解決的時映射問題,使用
key
的哈希值來計算所在的槽,便于數據分配多少個hash槽
- 一個集群只能有
16384
個槽,編號0-16383(0-2^14-1)
。這些槽會分配給集群中所有主節點,分配策略沒有要求。可以指定哪些編號的槽分配給哪個主節點。集群會記錄節點和槽的對應關系。解決了節點和槽的關系后,接下來就需要對key
求哈希值,然后對16834
取余,余數時幾,key
就落入對應的槽里。slot=CRC16(key) % 16384
。以槽位單位移動數據,因為槽的數目時固定的,處理起來比較容易,這樣數據移動問題就解決了Redis自帶的主從就是基于哈希槽分區的方式
Redis
集群中內置了16384
個哈希槽,redis
會根據節點數量大致均等的將哈希槽映射到不同的節點。當需要在Redis集群中放置一個key-value
時,redis
先對key
使用crc16
算法算出一個結果,然后把結果對16384
求余數,這樣每個key
都會對應一個編號在0-16383
之間的哈希槽,也就是映射到某個節點上
2、開始搭建
以下演示基于
Redis6.0.8
版本
2.1、關閉防火墻+啟動docker后臺服務
# 關閉防火墻
systemctl disable firewalld.service# 啟動docker
systemctl start docker
# 開機啟動docker
systemctl enable docker
2.2、新建6個redis容器實例
命令詳解如下
-d
:后臺啟動--name
:容器名稱--net host
:共用宿主機的IP和端口,后面講解Docker Network
會講解到--privileged=true
:開啟權限,方便容器數據卷搭建-v
:搭建容器數據卷,將數據目錄同步出來redis:6.0.0
:鏡像名:版本號--cluster-enabled yes
:開啟redis
集群--appendonly yes
:開啟持久化--port 6381
:redis端口號
docker run -d --name redis-node-1 --net host --privileged=true -v /mydir/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381docker run -d --name redis-node-2 --net host --privileged=true -v /mydir/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382docker run -d --name redis-node-3 --net host --privileged=true -v /mydir/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383docker run -d --name redis-node-4 --net host --privileged=true -v /mydir/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384docker run -d --name redis-node-5 --net host --privileged=true -v /mydir/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385docker run -d --name redis-node-6 --net host --privileged=true -v /mydir/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
2.3、進入容器redis-node-1
并為6臺機器構建集群關系
# 進入容器
docker exec -it redis-node-1 /bin/bash# 構建集群關系 將宿主機ip改為自己ip,--cluster-replicas 1表示為每個master創建一個slave節點
redis-cli --cluster create 宿主機ip:6381 宿主機ip:6382 宿主機ip:6383 宿主機ip:6384 宿主機ip:6385 宿主機ip:6386 --cluster-replicas 1# 下面是我自己的命令,你們自己改下ip即可
redis-cli --cluster create 192.168.71.111:6381 192.168.71.111:6382 192.168.71.111:6383 192.168.71.111:6384 192.168.71.111:6385 192.168.71.111:6386 --cluster-replicas 1
看到如下結果,代表配置成功
2.4、鏈接進入6381作為切入點,查看集群狀態
注意:需要先進入
redis-cli
才能執行命令(一、二):redis-cli -p 6381
命令一
cluster info
命令二
cluster nodes
命令三
# 需要先exit 退出redis-cli,處于容器內部執行如下命令
redis-cli --cluster check 自己ip:6381
2.5、整理生成的主從映射關系
根據上面的信息以及id對應關系,我們可以整理出來如下圖關系
3、讀寫路由增強:-c
我們使用命令
redis-cli -p 6381
進入服務,然后執行set k1 v1
,查看結果
上面報錯是說,根據算法算出來這個
k1
,占用的哈希槽應該在端口為6383
上面,不屬于當前節點,要手動切換到6383
的redis
服務中去放值這樣的話,我們每次大概率都需要手動去切換,非常麻煩,那么我們可以在執行
redis-cli
命令時,在后面添加-c
,這樣就會自動切換服務了redis-cli -p 6381 -c
- 看上圖可以發現,我們原本在
6381
的服務中,然后放入k1
,服務自動根據k1
算出來應該放入12706
的哈希槽中,這個哈希槽屬于端口為6383
的主節點上,那么就會自動給我們重定向到6383
的節點上,并且數據存入成功
4、主從容錯切換遷移
- 接下來,我們停掉主節點
6381
,然后進入6382
中查看當前集群狀態,從節點是否會代替主節點- 最后再啟動
6381
,查看它原來的身份是否會恢復
4.1、停掉6381
主節點,查看集群狀態
可以發現,原從節點
6384
成為了主節點,繼承了主節點的哈希槽分區
# 先停掉6381
docker stop redis-node-1# 進入6382
docker exec -it redis-node-2 /bin/bash# 以當前容器的 redis客戶端6382 為切入點,查看當前集群信息
redis-cli --cluster check 自己ip:6382
4.2、重啟6381節點,查看集群狀態
可以發現,
6384
還是主節點,原主節點6381
重連之后,成為了從節點
# 先從上面容器內部退出去,或者重新打開一個terminal
exit# 重啟 6381節點
docker restart redis-node-1# 再次 隨便進入一個節點內,查看當前集群信息
docker exec -it redis-node-2 /bin/bash# 這里
redis-cli --cluster check 自己ip:6382
5、主從擴容需求分析與演示
5.1、分析
- 主從擴容,我們就要先添加主節點,然后再添加從節點
- 既然要擴容,那么新增加進來的服務必然要分配哈希槽,但是我們前面已經分完了,那么怎么分配呢
- 注意:會從分配過的每個節點上,提取一部分出來,分配給新節點,如下圖所示
5.2、主節點添加演示
5.2.1、啟動新容器
docker run -d --name redis-node-7 --net host --privileged=true -v /mydir/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387docker run -d --name redis-node-8 --net host --privileged=true -v /mydir/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
5.2.2、將新的主節點加入集群
- 以下命令相當于,將
6387
加入6381
所在的集群中
# 進入節點node-7中
docker exec -it redis-node-7 /bin/bashredis-cli --cluster add-node 自己ip:6387 自己ip:6381
5.2.3、查看集群狀態
可以發現,端口
6387
已經加入成功,但是沒有從節點,并且沒有分配哈希槽
redis-cli --cluster check 自己ip:6382
5.2.4、分配哈希槽
redis-cli --cluster reshard 自己ip:6381
5.2.5、選擇要移動多少哈希槽
5.2.6、輸入待分配的節點ID
5.2.7、輸入從哪個節點拆分出來
下面要輸入從哪個節點拆分出來
4096
個槽給它,那么我們這里輸入all
,就是平均每個節點取出來一點給它
5.2.8、確定按照這樣分配
5.2.9、查看集群情況
- 從下圖可以看到,我們的
6387
有4096
個槽位了,并且是分了三段加在一起的[0-1364],[5461-6826],[10923-12287]
- 并且,原來節點的槽位分區也都發生了改變,下面的槽號,對應了
5.1小節
分析的圖
redis-cli --cluster check 自己ip:6382
5.3、從節點添加演示
5.3.1、命令
redis-cli --cluster add-node 你的ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主節點ID# 我這里是如下 命令,新主節點id上面是可以看到的
redis-cli --cluster add-node 192.168.71.111:6388 192.168.71.111:6387 --cluster-slave --cluster-master-id ab733301ab56ee869b1d46672b67c6b37ae6339b
5.3.2、查看集群狀態
redis-cli --cluster check 自己ip:6382
6、主從縮容需求與演示
6.1、分析
- 既然擴容的時候,我們是先新增主節點,然后再新增從節點,那么縮容我們就要先刪從節點,再刪主節點了
- 那么縮容以后,我們可以選擇還回去,或者都分配給某一個節點,下面我演示的為分配給某一個節點
- 其他情況可以自行一點一點分配(分配三次還回去),或者查看是否有批量分配命令
6.2、移除從節點
6.2.1、命令
redis-cli --cluster del-node 你的ip:從機端口 從機6388節點ID# 下面是我的命令,大家自行替換
redis-cli --cluster del-node 192.168.71.111:6388 55c5e1defef92e749ce6e65088f16edfaf78b7fd
6.2.2、再次查看集群狀態
# 自己改下ip
redis-cli --cluster check 192.168.71.111:6382
6.3、移除主節點
6.3.1、分配哈希槽命令
redis-cli --cluster reshard 你的ip:6381
6.3.2、輸入要移動的哈希槽數
6.3.3、指定要移動到哪個節點的Id
- 這里我們輸入
6384
節點的ID,將4096
個哈希槽全部給6384
服務- 因為我們上面演示過主從容錯切換遷移,
6381
服務是從節點了,6384
才是主節點
6.3.4、指定要從哪個節點移動
- 我們這里只指定
6387
端口的ID即可,全部移走
6.3.5、確定當前分配
6.3.6、然后查看集群狀態
可以發現,
6387
節點沒有再占用哈希槽了,并且6384
的槽位也增加了
# 自己改下ip
redis-cli --cluster check 192.168.71.111:6382
6.3.7、將6387
從集群刪除即可
redis-cli --cluster del-node 你的ip:主節點端口 主節點6387節點ID# 下面是我的命令,大家自行替換
redis-cli --cluster del-node 192.168.71.111:6387 ab733301ab56ee869b1d46672b67c6b37ae6339b
6.3.8、最后再查看當前集群狀態
# 自己改下ip
redis-cli --cluster check 192.168.71.111:6382
Dockerfile
Dockerfile
官網配置詳解:Dockerfile 參考 |Docker 文檔我們生成鏡像共有兩種方式,正式開發中,我們一般都會使用第二種
- 一種是通過我們的
docker commit
命令,基于優化過的鏡像,重新打包為一個新鏡像- 那么第二種就是通過
Dockerfile
文件,執行docker build
命令,基于文件配置,生成一個新的鏡像- 注意:必須要以
Dockerfile
命名,大小寫寫錯也不行!,還有文件內命令必須全大寫!!!當我們第一次在微服務中寫了
Dockerfile
后,那么后面所有的鏡像,我們只需要升級代碼,然后mvn package
打成jar/war
包后,其余Dockerfile
幾乎不用任何修改(除非你jar
包名修改了),就可以打成一個新的鏡像,供服務器使用Docker整體流程圖如下
Dockerfile
定義了一個進程需要的一切東西。Docerfile
設計的內容包括執行代碼或者是文件、環境變量、依賴包、運行時環境、動態鏈接庫、操作系統的發行版、服務進程和內核進程(當應用進程需要和系統服務和內核進程打交道,這是需要考慮如何設計namespace
的權限控制)等等
Docker
鏡像,在用Dockerfile
定義一個文件之后,docker build
時會產生一個Docker
鏡像,當運行Docker
鏡像時會真正開始提供服務
Docker
容器,容器時直接提供服務的
Dockerfile
常用命令如下
Dockerfile
命令說明 FROM 指定基礎鏡像,用于后續的指令構建,如果本地沒有安裝,那么會嘗試 pull
遠程倉庫的。MAINTAINER 指定 Dockerfile
的作者/維護者。LABEL 添加鏡像的元數據,使用鍵值對的形式。 RUN 在構建過程中在鏡像中執行命令。 CMD 指定容器創建時的默認命令。(可以被覆蓋) ENTRYPOINT 設置容器創建時的主要命令。(不可被覆蓋) EXPOSE 聲明容器運行時監聽的特定網絡端口。 ENV 在容器內部設置環境變量。 ADD 將文件、目錄或遠程URL復制到鏡像中。 COPY 將文件或目錄復制到鏡像中。 VOLUME 為容器創建掛載點或聲明卷。 WORKDIR 設置后續指令的工作目錄。 USER 指定后續指令的用戶上下文。 ARG 定義在構建過程中傳遞給構建器的變量,可使用 “docker build” 命令設置。 ONBUILD 當該鏡像被用作另一個構建過程的基礎時,添加觸發器。 STOPSIGNAL 設置發送給容器以退出的系統調用信號。 HEALTHCHECK 定義周期性檢查容器健康狀態的命令。 SHELL 覆蓋Docker中默認的shell,用于RUN、CMD和ENTRYPOINT指令。
1、案例講解
下面,我們以
MySQL
的Dockerfile
文件為例來講解該文件都用到了哪些命令,有什么含義:mysql Dockerfile
FROM <鏡像名:版本號>
,必須卸載文件最頂端,表示基于哪個鏡像修改構建新鏡像
RUN <命令行命令>
,等同于在終端操作的shell命令,比如要下載vim
功能,就寫RUN yum -y install vim
ENV <變量名> <值>
:定義容器內的環境變量,在容器內,或者下文中都可以使用$變量名
VOLUME <容器內目錄>
:定義掛載點,明確表示該目錄需要進行數據持久化,能讓使用該鏡像的人清楚知道哪些目錄的數據需要持久保存。
COPY <src> <dest>
:將文件/目錄,拷貝到鏡像中文件系統的另一個目錄中
ENTRYPOINT <入口文件>
:配置鏡像的入口文件,供exec -it
進入容器
EXPOSE <端口>
:指定容器內監聽的端口
CMD <默認命令>
:容器啟動時的默認命令,如果在啟動的run
后面指定了啟動命令,那么就會被啟動命令替換,不執行Dockerfile
中CMD
的命令
像
centos
的CMD
為CMD ["/bin/bash"]
比如在運行鏡像的時候命令為
docker run -exec -it centos bash
,這時候就會執行bash
命令,不是/bin/bash
除了上面這些還有一些常用的命令
WORKDIR <容器內目錄名>
:指定當使用exec -it
進入容器中,默認進入的文件位置,像我們進入Redis
中,默認會在/data
目錄中
1.1、ADD和COPY
- 兩個都是將文件
copy
到指定目錄中- 不同的是,
ADD
命令具有自動解壓的特性。如果<源路徑>
是一個壓縮文件(如.tar
、.tar.gz
、.xz
等),ADD
會自動將其解壓到<目標路徑>
1.2、RUN
RUN
命令有兩種寫法
RUN [OPTIONS] <command>
RUN [OPTIONS] ['<command>', ...]
- 比如下載vim命令,
- 寫法一:
RUN yum -y install vim
- 寫法二:
RUN ['yum', '-y', 'install', 'vim']
1.3、CMD和RUN區別
RUN
命令是在**構建鏡像時執行的**CMD
命令是在**運行鏡像時執行的**
1.4、ENTRYPOINT
命令格式
ENTRYPOINT ["executable", "param1", "param2"]
它也是用來指定一個容器啟動時要運行的命令,可以和
CMD
一起使用,一般是變參才會使用CMD。單獨使用
CMD
的話,當運行鏡像未在docker run xxxxxx 鏡像名:版本號
后面添加命令的話,后面就會自動加上CMD
命令一起用的話,
CMD
命令會放到ENTRYPOINT
后面,當作參數。我們以
Redis
為案例redis-dockerfile:
Dockerfile
為:
當我們執行
docker run -exec -it redis:6.0.8
的時候,實際會執行的是我們的命令 ENTRYPOINT配置的命令 CMD配置的命令:docker run -exec -it redis:6.0.8 docker-entrypoint.sh redis-server
當執行
docker run -exec -it redis:6.0.8 redis-server /etc/redis/redis.conf
的時候,實際會執行的是我們的命令 ENTRYPOINT配置的命令
2、案例一:實現Ubuntu
帶ifconfig
命令
- 當我們從
docker
倉庫中下載的ubuntu
中,是沒有ifconfig
命令的- 我們在
Docker 初級
的時候,演示過在ubuntu
中安裝vim
命令,并使用commit
重新創建了一個屬于我們的新鏡像。- 我們下面演示下,使用
Dockerfile
文件,構建新鏡像,實現在ubuntu
上,安裝ifconfig
命令
2.1、Dockerfile
- 我們首先進入
/mydir/myUbuntu
目錄中(沒有則創建),vim
命令新建文件,并編寫如下內容
# 新鏡像基于ubuntu鏡像 最新版
FROM ubuntu:latest# 更新軟件包列表
RUN apt update# 安裝 net-tools 包
RUN apt install net-tools# 測試定義變量
ENV MY_PATH /user/local# 測試使用變量,并在控制臺打印
CMD echo MY_PATH# 暴露主文件
CMD /bin/bash
2.2、執行命令
執行完命令后,可以發現,回根據文件內的內容,一步一步執行,并顯示執行進度。等所有命令執行完,那么就代表鏡像也創建成功了
# 注意:最后的.代表以當前目錄中的Dockerfile 來構建新鏡像,前提我們要在/mydir/myUbuntu中寫了文件,并且處于這個文件中
docker build -t 新鏡像名:版本號 .# 我這里命令是
docker build -t my-ubuntu:1.0.0 .
2.3、運行新鏡像并查看命令是否安裝成功
1.查看是否生成新鏡像
docker images
2.進入新鏡像中,然后查看ifconfig
命令
docker run -it my-ubuntu
3、案例二:實現my-ubuntu
帶Java8
- 上面,我們演示的是最簡單的步驟,下面,我們再來個稍微難點的
- 在
my-ubuntu
的基礎上,再安裝java8
3.1、本地下載JDK8
版本
下載地址:Java Archive Downloads - Java SE 8u211 and later | Oracle 中國
選擇這個即可
3.2、將jdk8
放入/mydir/my-ubuntu-java8
目錄中
使用
IDEA 或 Xftp
工具連接服務器,將下載好的JDK
文件放入
- 不知道怎么使用
IDEA
自帶工具連接的,可以查看:IDEA-不使用插件連接SSH、SFTP_idea ssh插件-CSDN博客
連接好后,注意,使用這個工具,只能將左側項目中有的文件,
ctrl+c、ctrl+v
進連接的服務器目錄中,拷貝文件夾中的文件不能直接粘貼進去
3.1、Dockerfile
下面,我們進入
/mydir/my-ubuntu-java8
目錄中,編寫Dockerfile
文件
# 基于上面創建的ubuntu
FROM my-ubuntu:1.0.0# 定義作者信息
MAINTAINER tcc<897113177@qq.com># 創建放置jdk的目錄
RUN mkdir -p /usr/local/java# 將宿主機內剛剛粘貼進去的jdk拷貝到容器目錄內,并解壓,前提是當前Dockerfile 和 jdk 是在同一目錄中,才能直接使用jdkxxx.tar.gz
ADD jdk-8u431-linux-x64.tar.gz /usr/local/java/#配置jdk的全局環境變量 注意,這里/java/后面要寫jdk解壓后的文件名,可以先在宿主機內解壓看看文件名
ENV JAVA_HOME /usr/local/java/jdk1.8.0_431
ENV JRE_HOME $JAVA_HOME/jre
ENV PATH $JAVA_HOME/bin:$PATHCMD /bin/bash
3.2、構建鏡像
docker build -t my-ubuntu:2.0.0 .
3.3、進入新構建的鏡像,驗證是否有java
# 查看新生成鏡像
docker images# 運行鏡像
docker run -it my-ubuntu:2.0.0 /bin/bash# 驗證java
java -version
4、案例三:實現部署我們的項目
- 上面,我們已經將jdk裝進去了,下面我們來一個接近真實項目的案例
- 我們自己寫一個
SpringBoot
項目,并且暴露一個接口- 然后使用
maven clearn package
構建jar
包- 然后在這個項目根目錄內新建
Dockerfile
文件,在IDEA
編寫Dockerfile
文件- 將
/target/
下面的jar
包和/Dockerfile
文件一起移入服務器的/mydir/my-project/
中- 最后進入目錄,使用
build
命令構建我們的鏡像
3.1、編寫項目及jar包生成
我們使用
SpringBoot
項目構建器創建一個基本的項目,然后編寫一個簡單的接口,項目端口設置為9999
即可
然后在
/src/main/resources/
目錄中新建logback-spring.xml
文件,這樣在我們請求接口的時候,就會在jar
包所在目錄中創建/logs/app.xxxx-xx-xx.log
日志文件,后面我們把它用Docker
掛載出來<?xml version="1.0" encoding="UTF-8"?> <configuration><!-- 控制臺輸出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 文件輸出 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 日志文件輸出的文件名 --><fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern><!-- 日志文件保留天數 --><maxHistory>30</maxHistory></rollingPolicy><encoder><charset>UTF-8</charset><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 根日志 --><root level="info"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /></root> </configuration>
啟動項目,打開瀏覽器,訪問
localhost:9999/getUser
,返回信息正常即可
并且在項目所在目錄新建了
/logs/app.log
文件
使用
maven
,分別執行clean、package
命令,將項目打包為jar
包
命令執行完后,可以在
/target
目錄查看
2.2、創建Dockerfile
文件并編寫內容
# 基于my-ubuntu2.0.0
FROM my-ubuntu:2.0.0# 作者
MAINTAINER tcc <897113177@qq.com># 定義日志目錄為掛載盤
VOLUME /log# 將當前目錄jar包,拷貝進容器的 /app/ 目錄下 并命名為 user-project.jar
ADD UserProject-0.0.1-SNAPSHOT.jar /app/user-project.jar# 啟動容器時運行
ENTRYPOINT ["java","-jar","/app/user-project.jar"]# 暴露端口作為微服務
EXPOSE 9999
2.3、將jar
包和Dockerfile
移入服務器內
- 連接服務器步驟就不說了
- 左邊
ctrl+c
,右邊創建目錄后ctrl+v
2.4、服務器進入目錄,構建鏡像
docker build -t user-project:1.0.0 .
2.5、運行鏡像
- 注意:由于我們配置的
logback-spring.xml
使用的是相對路徑,輸出日志文件的時候,就會在執行java -jar的工作窗口所處位置創建日志文件,我們上面創建的Dockerfile
文件由于默認就是在根目錄中,所以日志也會在根目錄的/logs目錄中- 解決辦法:
- 在
Dockerfile
中添加RUN cd /app
- 在
logback-spring.xml
配置文件名的時候使用絕對路徑
# 后臺運行容器,并掛載日志文件目錄
docker run -d --name user-project -p 9999:9999 -v /mydir/my-project/logs:/logs user-project:1.0.0
2.6、在自己電腦上訪問接口
- 由于我的容器
IP
為192.168.71.111
,所以我的請求地址為http://192.168.71.111:9999/getUser
,你們自行替換ip
2.7、查看掛載的日志
- 上面我們接口請求成功了,那么日志文件內肯定會記錄,我們啟動容器的時候也掛載了
- 我們按照啟動時配的掛載盤目錄
/mydir/my-project/logs
查看
5、虛懸鏡像
5.1、復現
- 在
Docker-初級
的時候,我們提到過虛懸鏡像,但是怎么來的我們沒說,這里就可以演示- 其實就是在首次構建使用
docker build
時,沒有使用-t xxx:xxx
指定鏡像名
5.2、查詢所有虛懸鏡像
docker image ls -f dangling=true
5.3、刪除所有虛懸鏡像
docker image prune
Docker Network容器網絡
- 上面我們有幾次提到過使用
--net
命令配置容器啟動時使用的網絡,下面我們開始講解如何使用- 使用網絡可以實現訪問其他容器可以直接使用 容器名,可以自動匹配到對應的容器IP
- docker默認有4中網絡模式
bridge
:為每一個容器分配、設置IP等,并將容器連接到一個docker0
虛擬網橋,默認為該模式host
:容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口none
:容器有獨立的Network namespace
,但并沒有對其進行任務網絡設置,比如分配veth pair
和網橋鏈接,IP等container
:新創建的容器不會創建自己的網卡和配置自己的IP,而是和一個指定的容器共享IP、端口等
1、命令
docker網絡命令全部都是由
docker network
開頭,可以使用docker network --help
查看所有命令,主要用的就是如下幾個
# 列出所有網絡
docker network ls# 新增網絡模式
docker network create test_network# 查看網絡源數據
docker network inspect test_network# 刪除網絡
docker network rm test_network
2、docker0網絡介紹
- 當我們啟動
docker
以后,使用ifconfig
命令,可以看到一個docker0
的網絡- docker0 網絡是 Docker 默認創建的虛擬網橋,以下是關于它的詳細介紹:
- 基本概念
- 網橋功能:docker0 作為一個網橋,連接了容器網絡與主機網絡,工作在數據鏈路層,使連接到它的容器之間以及容器與主機之間能夠進行通信,就像現實中的交換機將不同設備連接在一個局域網內一樣2。
- 默認網絡:當安裝并啟動 Docker 時,會自動創建 docker0 網橋及默認的橋接網絡。在沒有為容器指定網絡的情況下,新創建的容器會自動連接到 docker0 網絡23。
- 工作原理
- IP 地址分配:默認情況下,docker0 有一個與之關聯的子網,如 172.17.0.0/16,它可以分配此范圍內的 IP 地址給容器。Docker 主機的 IP 地址在 docker0 網橋上通常是 172.17.0.1,作為容器的默認網關2。
- 數據轉發:容器要與外部網絡通信時,流量會首先經過 docker0 的 IP 地址,由主機進一步處理和轉發。對于容器之間的通信,如果目標容器也連接在同一個 docker0 網橋上,數據可以直接在容器之間傳輸;如果目標容器在其他網絡或外部網絡,則數據會通過 docker0 網橋轉發到相應的網絡2。
- 網絡隔離:docker0 網橋提供了一定程度的網絡隔離,通過在主機上安裝規則,使得連接到不同網橋網絡的容器不能直接相互通信,保障了容器網絡的安全性和獨立性3。
3、網絡模式-bridge
網橋
Docker
啟動一個容器時,會根據Docker
網橋的網段分配給容器一個IP地址,成為Container-IP
,同時Docker
網橋時每個容器的默認網關。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP
直接通信docker run
的時候,如果沒有指定network
的話,默認使用的網橋模式就是bridge
,使用的就是docker0
- 網橋
docker0
創建一對對等虛擬設備接口,一個叫veth
,另一個叫eth0
,成對匹配
- 整個宿主機的網橋模式都是
docker0
,類似一個交換機有一堆接口,每個接口叫veth
,在本地主機和容器內分別創建一個虛擬接口,并讓他們彼此聯通(這樣一對接口叫veth pair
)- 每個容器實力內部也有一塊網卡,每個接口叫
eth0
docker0
上面的每個veth
匹配某個容器實力內部的eth0
,兩兩配對
3.1、驗證
- 下面,我們啟動三臺
billygoo/tomcat8-jdk8
容器,然后分別進入容器中,執行ifconfig
命令驗證billygoo/tomcat8-jdk8
:這個是可以不用修改webapps
文件夾的
# 啟動容器如果不指定網絡的話,默認就是bridge,可以手動添加 --network bridge 指定
docker run -d --name tomcat81 -p 8081:8080 billygoo/tomcat8-jdk8docker run -d --name tomcat82 -p 8082:8080 billygoo/tomcat8-jdk8
然后分別進入
tomcat81、tomcat82
容器
docker exec -it tomcat81 /bin/bashdocker exec -it tomcat82 /bin/bash
然后分別使用
ip addr
命令,查看網絡情況
最后,我們使用如下命令,查看容器內的網絡情況,可以發現容器有自己
ip
和網關
# 查詢 容器詳細信息,并且只展示最后20行
docker inspect tomcat81|tail -n 20
4、網絡模式-host
- 容器將不會獲得一個獨立的
Network Namespace
,而是和宿主機共用一個Network Namespace
。容器將不會虛擬出自己的網卡,而是使用宿主機的IP和端口- 注意:在啟動命令的時候,使用
-p
映射端口是無效的。端口號會以主機端口號為主,重復時則遞增
4.1、驗證
- 下面我們啟動一臺
billygoo/tomcat8-jdk8
- 然后進入容器內查看其網絡信息
# 我這里故意寫-p,執行會有警告,說 -p指令不生效的,但是不影響容器啟動,只是警告
docker run -d --network host -p 8083:8080 --name tomcat83 billygoo/tomcat8-jdk8
這時候我們執行
ip addr
命令,主機上是看不到容器對應的veth
網絡的,因為沒有使用網橋,和宿主機共用的
并且,我們在虛擬機內訪問
localhost:8083
是沒東西的,只有訪問localhost:8080
才會打開頁面。在虛擬機外則使用ip+:8080
。因為我們的-p
命令是無效的
然后我們進入容器,并且使用
ip addr
查看容器內網絡情況可以發現,網絡情況和宿主機是一模一樣的,代表了容器和宿主機共用的同一個網絡
docker exec -it tomcat83 /bin/bash
- 最后,我們使用如下命令,可以發現,容器內沒有自己的
ip和網關
,因為和宿主機共享的,并且網絡模式為host
# 查詢 容器詳細信息,并且只展示最后20行
docker inspect tomcat83|tail -n 20
5、網絡模式-none
- 禁用網絡功能,只有
lo
標識(就是127.0.0.1
表示本地回環)- 在
none
模式下,并不為Docker
容器進行任何網絡配置,也就是說,這個Docker
容器沒有網卡、IP、路由等信息,只有一個lo,需要我們自己為自己Docker
容器添加網卡、配置IP等- 以這種方式啟動的容器,只能內部自己訪問自己,外部無法訪問
5.1、驗證
docker run -d --network none -p 8084:8080 --name tomcat84 billygoo/tomcat8-jdk8
進入容器使用
ip addr
命令可以看到只有一個回環網絡
對容器使用如下命令也可以看到,該容器是沒有網絡的
docker inspect tomcat84|tail -n 20
5、網絡模式-container
- 新建的容器和已經存在的一個容器共享一個網絡ip配置,而不是和宿主機共享。
- 新床就的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口范圍等
- 同樣,兩個容器除了網絡方面,其他的如:文件系統、進程列表等還是隔離的
- 當被依賴的容器宕機了,那么依賴的容器則會失去網絡,只剩下自己的回環地址
- 這個案例我們就不再使用
tomcat
演示了,因為會共用同一個ip、端口,導致端口沖突。下面我們使用一個面相安全的輕型Linux
發版:Alpine
,各位先拉取最新的鏡像
# 注意:是使用 /bin/sh
docker run -it --name alpine1 alpine /bin/sh# 再打開一個窗口執行如下命令# 基于容器1的網絡創建
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
然后在兩個命令窗口中,分別執行
ip addr
,查看網絡,可以發現兩個網絡一模一樣
最后,我們停掉左邊的容器(被依賴的),再次查看右邊的網絡情況
5、自定義網絡(重要)
- 自定義網絡就是執行
docker netword create 網絡名
,自己創建的網絡- 創建的網絡默認也是==
bridge
網橋模式==- 但是,自己創建的網絡和默認自帶的網橋區別是自帶的網橋不能通過容器名,訪問容器內接口。而自己創建的網絡可以
- 自己創建的網絡內,會維護好一組一組的
容器名:容器IP
,而自帶的則不具備這種功能
5.1、驗證
我們先創建網絡
test_bridge
,可以發現新創建的網絡驅動也是bridge
# 創建網絡
docker network create test_bridge# 列出所有網絡
docker network ls
然后我們使用剛剛創建的網絡,啟動兩個
tomcat 85|86
容器來驗證
docker run -d --network test_bridge --name tomcat85 billygoo/tomcat8-jdk8docker run -d --network test_bridge --name tomcat86 billygoo/tomcat8-jdk8
我們各自進入容器內,然后互相
ping 容器名
,查看是否可以ping
通,符合我們的說法。至于使用默認的bridge
啟動的容器,互相ping
不通的案例,大家可以自行去嘗試。
docker exec -it tomcat85 /bin/bashdocker exec -it tomcat86 /bin/bash
Docker Compose容器編排
docker
建議我們每一個容器只運行一個服務,因為docker
容器本身占用資源極少,所以最好是將每個服務單獨的分割開來。- 正常我們的服務會有很多組件還有數據庫一起組成的,比如
mysql
、redis
、kafka
、微服務模塊等,我們一個一個執行的話,很容易出錯,并且我們的服務和其他容器有可能有先后順序,比如先啟動依賴容器(比如:mysql
、redis
等),才能啟動我們的微服務Docker
就提供了一種工具Docker Compost
容器編排的技術,讓我們通過寫一個文件,實現所有配置的容器一起啟動- 我們只需要在目錄中編寫
compose.yml 或 compose.yaml
文件即可,文件名稱不能改變- 官網地址:插件 |Docker 文檔
1、安裝
- 我這里是用的
CentOS 7
演示的,所以用下面這個命令
# 對于 Ubuntu 和 Debian,請運行:
apt-get update
apt-get install docker-compose-plugin# 對于基于 RPM 的發行版,請運行:
yum update
yum install docker-compose-plugin
2、驗證
docker compose version
3、卸載
# 要刪除 Docker Compose CLI 插件,請運行:
apt-get remove docker-compose-plugin# 基于 RPM 的發行版:
yum remove docker-compose-plugin
4、Compose
常用命令
下面的命令,會在后面第
5
章節演示
4.1、查看幫助
docker compose -h
4.2、啟動yml
內服務
# 也可以查看服務啟動時,每個服務的啟動日志報錯等
docker compose up
4.3、啟動所有yml
服務并后臺運行
docker compose up -d
4.4、停止并刪除yml
內容器、網絡、卷、鏡像
# 相當于 docker rm -f 容器名
docker compose down
4.5、進入容器實例內部
# 相當于 docker exec -it mydir-my-mysql-1 /bin/bash
docker compose exec yml里面的服務id <command命令>
4.6、展示當前yml
編排過的運行的所有容器
# 展示的不是所有容器,而是當前yml中配置的yml
docker compose ps
4.7、展示當前yml
編排過的容器進程
# 相當于 docker top 容器名
docker compose top
4.8、查看容器輸出日志
# 相當于 docker logs 容器名
docker compose logs yml里面的服務id
4.9、檢查配置
docker compose config
4.10、檢查配置,有問題才有輸出
docker compose config -q
4.11、重啟yml
內服務
# 相當于一鍵重啟yml配置中所有啟動的容器
docker compose restart
4.12、啟動yml
內服務
# 相當于一鍵啟動yml配置中所有停止的容器
docker compose start
4.13、停止yml
內服務
# 相當于一鍵停止yml配置中所有啟動的容器
docker compose stop
5、使用
兩要素:
- 服務:一個個應用容器實例,比如訂單微服務、庫存微服務、
mysql
容器、nginx
容器或者redis
容器- 工程:由一組關聯的應用容器組成的一個完整業務單元,在
compose.yaml 或 compose.yml
中定義使用的三個步驟
- 編寫
Dockerfile
定義各個微服務應用并構建出對應的鏡像文件- 使用
compose.yml
訂一個一個完整業務單元,安排好整體應用中的各個容器服務- 最后執行
docker compose up
命令,來啟動并運行整個應用程序,完成一鍵部署上線如下演示,我們使用
mysql、redis
以及我們之前演示Dockerfile
創建的user-project
微服務來掩飾
- 這里正常微服務都是依賴于
mysql、redis
的,但是我這里微服務圖省事,就不改了,假裝依賴一下吧。- 各位如果要自己修改微服務的話,可以使用之前講的
Docker Network
,在配置文件里把依賴mysql、reids
等第三方組件依賴,將IP
改為容器名嘗試
5.1、編寫compose.yml
文件
- 我們使用的鏡像以及版本為:
mysql:5.7、redis:6.0.8、user-project:1.0.0
,各位缺少哪個鏡像拉取一下,最后一個user-project
是你自己的微服務,使用Dockerfile
構建出來的鏡像- 下面我們編排的文件內的容器是有啟動的先后順序的
mysql、redis、user-project
,在容器內,我們只需要使用depends_on
標明我們的服務需要哪幾個其他服務的ID即可- 如下文件我們放到
/mydir/compose.yml
中即可- 如果直接粘貼進去會把所有命令前面都加一個
#
的話,把如下內容的注釋全部刪掉,再粘貼即可
# 容器列表,所有容器都配置再其中
services:# 相當于id,一個Compose中唯一user-project:# 鏡像名稱:版本號image: user-project:1.0.0# 容器名稱container_name: user-project# 端口號,使用 - xxx 表示數組形式,可以指定多個端口,我這里服務端口為9999ports:- "9999:9999"# 指定容器掛載卷,也是數組形式,可以配置多個volumes:- /mydir/my-project/logs:/logs# 指定容器使用的網絡配置,tcc_network會在文件最后面定義networks:- tcc_network# 指定該容器依賴的其服務的id,并不用于啟動命令中depends_on:- my-redis- my-mysql# 如下容器不指定容器名,那么生成的容器名為`目錄名-容器名-compose編排序號`,mydir-my-mysql-1my-mysql:image: mysql:5.7# 指定容器內的環境變量environment:# 用來設置 MySQL 數據庫的 root 用戶密碼MYSQL_ROOT_PASSWORD: 'admin'# 用于控制是否允許 MySQL 使用空密碼。把它設置為 no 表示不允許使用空密碼,以此增強數據庫的安全性。MYSQL_ALLOW_ENPTY_PASSWORD: 'no'# 指定在 MySQL 容器啟動時自動創建的數據庫名稱MYSQL_DATABASE: 'testdb'# 用于指定在 MySQL 容器啟動時自動創建的新用戶名稱MYSQL_USER: 'tcc'# 用于為 MYSQL_USER 指定的用戶設置密碼MYSQL_PASSWORD: 'tcc123'ports:- "3306:3306"volumes:- /mydir/mysql/log:/var/log/mysql- /mydir/mysql/data:/var/lib/mysql- /mydir/mysql/conf:/etc/mysql/conf.dnetworks:- tcc_network# 將默認認證插件設置為 mysql_native_password 解決外部無法訪問command: --default-authentication-plugin=mysql_native_password# my-redis:image: redis:6.0.8ports:- "6379:6379"volumes:- /mydir/redis/redis.conf:/etc/redis/redis.conf- /mydir/redis/data:/datanetworks:- tcc_networkcommand: redis-server /etc/redis/redis.conf# 相當于 docker network create tcc_network
networks:tcc_network:
5.2、運行yml
文件
# 注意,編寫完文件以后,最好先執行如下命令,校驗一下
docker compose config -q# 后臺運行
docker compose up -d
5.3、驗證
docker compose ps
進入
mysql
容器中查看是否默認創建了testdb
庫
# 進入my-mysql容器中 或者使用 docker exec -it 容器名 /bin/bash
docker compose exec my-mysql /bin/bash# 連接Mysql服務,打開客戶端
mysql -uroot -p# 輸入compose.yml定義的密碼# 顯示所有數據庫
show databases;
Portainer
安裝與使用(簡單版頁面管理)
- 官網:Kubernetes and Docker Container Management Software
Portainer
是一款輕量級的應用,它提供了圖形化界面,用于方便的管理Docker
環境,包括單機環境和集群環境- 在這個平臺上,我們能很方便的對
Docker
進行一切操作,包括監控容器使用情況。而不需要我們連接進入服務器去進行操作。重要的是,我們可以給登入網站的用戶權限限制,實現對操作可控制,減少誤操作
1、安裝命令
- 安裝地址:Install Portainer CE with Docker on Linux | Portainer Documentation
Portainer
也是放置在Docker
上的一個鏡像,我們通過拉取鏡像,運行即可- 特別命令解析,前面簡單的我就不說了
-p
:官網是監聽了8000、9443
兩個端口
8000
端口用于Portainer
服務器與Edge
代理之間的通信,支持對遠程節點的管理。9443
端口用于用戶通過Web
界面安全地訪問Portainer
管理控制臺,方便用戶進行日常的管理操作--restart=always
:指定容器跟隨Docker
啟動而自啟,意思就是,Docker
內部的開機自啟-v /var/run/docker.sock:/var/run/docker.sock
:宿主機的/var/run/docker.sock
文件掛載到容器內的/var/run/docker.sock
路徑。/var/run/docker.sock
是 Docker 守護進程的 Unix 套接字文件,通過掛載這個文件,容器就能和宿主機的 Docker 守護進程進行通信,進而管理宿主機上的 Docker 資源-v /mydir/portainer:/data
:將portainer
內部生成的數據同步到宿主機目錄中做備份portainer/portainer-ce:lts
:容器名portainer/portainer-ce
,版本號:lts
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /mydir/portainer:/data portainer/portainer-ce:lts
2、使用
2.1、登錄頁面
注意:訪問頁面時,必須使用
https
,不能使用http
,否則頁面會出不來訪問頁面可以使用如下兩種方式
- 服務器內訪問:我們在虛擬機內部使用
https://localhost:9443 或 https://127.0.0.1:9443
- 內網其他電腦訪問:
https:// + 服務器IP + :9443
即可我們首次訪問可能會出現如下界面,點擊高級->繼續訪問即可
2.2、創建賬號
注意,當
Portainer
初次啟動以后,要在5
分鐘內完成賬號注冊,否則就要重啟容器,然后再重新注冊文檔地址:安裝 Portainer 后,我收到消息“出于安全目的,您的 Portainer 實例已超時”,我該如何解決這個問題?
2.3、使用頁面
頁面使用文檔:Home | Portainer Documentation
注冊成功后,我們會進入如下頁面
2.4、查看Docker
內部所有信息
我們要先點擊右側那個
local
的Docker
,選擇我們的當前綁定的鏡像實例然后在左側,我們就會看到我們
Docker
內部的詳細信息了儀表盤內容,相當于我們的命令
docker system df
2.5、操作
- 我們不僅能觀察
Docker
內部的信息,還能進行我們之前大部分的操作,只需要點點按鈕即可- 我這里只演示對于
Containers
容器的操作,其他的按鈕跟我們之前代碼命令都大差不差,大家自行研究使用
CAdvisor
+InfluxDB
+Granfana
(GIA)監控系統
- 上面
Portainer
只是簡單的監控操作,下面這三個組件加起來可以實現對容器以及宿主機詳細的監控操作,適合生產系統的監控docker status
命令可以很方便的看到當前宿主機上所有容器的CPU
,內存以及網絡流量等數據,小公司基本夠用了。但是:docker status
統計結果只是當前宿主機的全部容器,數據資料是實時的,沒有地方存儲、沒有健康指標過線預警等功能- 三個組件功能如下:
CAdvisor
:監控收集
- 是一個容器資源監控工具,包括容器的內存,CPU,網絡IO,磁盤IO等監控,同時提供了一個
WEB
頁面用于查看容器的試試運行狀態。CAdvisor
默認存儲2分鐘的數據,而且只是針對單物理機。不過,CAdvisor
提供了很多數據集成接口,支持InfluxDB,Redis,Kafka,Elasticsearch
等集成,可以加上對應配置將監控數據發往這些數據庫存儲起來。- 功能點主要有兩個
- 展示
Host
和容器兩個層次的監控數據- 展示歷史變化數據
InfluxDB
:存儲數據
InfluxDB
使用GO
語言編寫的一個開源分布式時序、事件和指標數據庫,無需外部依賴。Cadvisor
默認只在本機保存最近2分鐘的數據,為了持久化存儲數據和統一收集展示監控數據,需要將數據存儲到InfluxDB
中。InfluxDB
是一個時序數據庫,專門用于存儲時序相關數據,很適合存儲CAdvisor
的數據。而且,CAdivisor
本身已經提供了InfluxDB
的繼承方法,在容器啟動時指定配置即可- 主要功能如下
- 基于時間序列,支持于時間有關的相關函數(如最大、最小、求和等)
- 可度量性:你可以實時對大量數據進行計算
- 基于事件:它支持任意的事件數據
Granfana
:展示圖表
Grafana
是一個開源的數據監控分析可視化平臺,支持多種數據源配置(支持的數據源包括InfluxDB,MySQL,Elasticsearch,OpenTSDB,Graphite等
和豐富的插件及模板功能,支持圖表權限控制和報警)- 主要功能如下
- 靈活豐富的圖形化選項
- 可以混合多種風格
- 支持白天和夜間模式
- 多個數據源
- 對于如下三個組件的演示,我這里只演示簡單的啟動以及登錄使用。更復雜使用自行查詢官網進行配置即可
1、Compose文件
- 下面,我們使用
Compose
來對這三個服務進行配置,然后一起啟動- 各位粘貼的話,記得先把里面注釋刪掉,不然可能粘貼進去錯亂
services:influxdb:container_name: influxdbimage: tutum/influxdb:latest# 跟隨docker啟動restart: alwaysnetworks:- cig_network# 預先創建一個名為cadvisor的數據庫environment:- PRE_CREATE_DB=cadvisorports:- "8083:8083"- "8086:8086"volumes:- /mydir/influxdb:/datacadvisor:container_name: cadvisorimage: google/cadvisornetworks:- cig_network# 配置啟動后連接上influx數據庫command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxdb:8086restart: alwaysports:- "8080:8080"volumes:- /:/rootfs:ro- /var/run:/var/run:ro- /sys:/sys:ro- /var/lib/docker/:/var/lib/docker:rodepends_on:- influxdbgrafana:container_name: grafanaimage: grafana/grafana# 使用root權限user: "root"restart: alwaysnetworks:- cig_networkports:- "3000:3000"volumes:- /mydir/grafana_data:/var/lib/grafana# 配置環境變量environment:- HTTP_USER=admin- HTTP_PASS=admin- INFLUXDB_HOST=influxdb- INFLUXDB_PORT=8086- INFLUXDB_NAME=cadvisor- INFLUXDB_USER=root- INFLUXDB_PASS=rootdepends_on:- influxdb# 創建網絡
networks:cig_network:
2、訪問并使用頁面
- 啟動上面的文件時間可能比較久,因為大概率要拉取鏡像,你本地沒有。如果一直拉不下來,建議單獨拉取
compose
中的某個鏡像,單獨拉下來即可- 當我們按照上面文件啟動后,可以訪問如下三個地址,首次訪問可能會比較慢
- 瀏覽
cAdvisor
收集服務:http://宿主機ip:8080
- 瀏覽
influxdb
存儲服務:http://宿主機ip:8083
- 瀏覽
grafana
展現服務:http://宿主機ip:3000
2.1、cAdvisor
在這個頁面往下翻,可以看到簡單的統計圖,會顯示當前宿主機系統的情況,CPU、內存等信息
2.2、influxdb
- 進入頁面后,我們點擊右上角的設置(齒輪圖標),可以填寫賬號密碼
- 然后點擊右側
Query Templates
選擇需要的語句sql
- 輸入框回車,執行
sql
2.3、grafana
2.3.1、連接數據庫
頁面我們使用
賬號:admin 密碼:admin
登錄進去左側
Connections->Data sources
,然后選擇InfluxDB
然后填寫數據庫信息,保存并測試即可
2.3.2、配置圖形化界面
選擇左側的
Dashboards
菜單,點擊右側的create dashboard
然后選擇我們剛剛配置的數據庫就來到了配置圖形頁面
我這里配個簡單的圖形演示
配置查詢的sql
然后點擊右上角
Save dashboard
然后填寫圖形名稱
保存成功后,我們即可刷新頁面,再次查看我們的圖形了
開發軟件中的Docker插件
我這里以
Idea
開發工具中的Docker
插件為例現在
IDEA
插件中一般都會自帶一個Docker
插件,沒有的話自行安裝
然后我們點擊左上角的
File->Build,Execution,Deployment
然后在右側點擊
+
號,選擇SSH
連接我們的服務器
然后在彈框中,填寫我們的服務器
ip
,賬號,密碼,測試連接
最后我們點擊
ok
即可然后在下面的
Services
中可以看到Docker
的狀態了,以及對Docker
的一切操作