Docker-高級使用

前言

書接上文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版本演示,共有如下幾步。

  1. 新建主服務器實例3307端口
  2. 進入/mydir/mysql/master/conf目錄下新建my.cnf文件
  3. 修改完配置后重啟master實例
  4. 進入mysql-master容器
  5. master容器實例內創建數據同步用戶
  6. 新建從服務器實例3308
  7. 進入mydir/mysql/slave/conf目錄下新建my.cnf
  8. 修改完配置后重啟slave實例
  9. 在主數據庫中查看主從同步狀態
  10. 進入mysql-slave容器
  11. 在從數據庫中配置主從復制
  12. 在從數據庫中查看主從同步狀態
  13. 在從數據庫中開啟主從同步
  14. 查看從數據庫狀態發現已經同步
  15. 主從復制測試

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 STATUSSHOW SLAVE STATUS 等命令來查看復制相關的狀態。
  • ON *.*
    • ON關鍵字用于指定權限作用的范圍,*.* 表示權限適用于所有數據庫的所有表。也就是說,被授予權限的用戶在所有數據庫和表上都具備 REPLICATION SLAVEREPLICATION 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. 哈希取余分區
    2. 一致性哈希算法分區
    3. 哈希槽分區

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鍵值對時,首先計算keyhash值,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上面,不屬于當前節點,要手動切換到6383redis服務中去放值

  • 這樣的話,我們每次大概率都需要手動去切換,非常麻煩,那么我們可以在執行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、查看集群情況
  • 從下圖可以看到,我們的63874096個槽位了,并且是分了三段加在一起的[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 文檔

  • 我們生成鏡像共有兩種方式,正式開發中,我們一般都會使用第二種

    1. 一種是通過我們的docker commit命令,基于優化過的鏡像,重新打包為一個新鏡像
    2. 那么第二種就是通過Dockerfile文件,執行docker build命令,基于文件配置,生成一個新的鏡像
    3. 注意:必須要以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、案例講解

  • 下面,我們以MySQLDockerfile文件為例來講解該文件都用到了哪些命令,有什么含義:mysql Dockerfile

  • FROM <鏡像名:版本號>必須卸載文件最頂端,表示基于哪個鏡像修改構建新鏡像

    在這里插入圖片描述

  • RUN <命令行命令>,等同于在終端操作的shell命令,比如要下載vim功能,就寫RUN yum -y install vim

    在這里插入圖片描述

  • ENV <變量名> <值>:定義容器內的環境變量,在容器內,或者下文中都可以使用$變量名

    在這里插入圖片描述

  • VOLUME <容器內目錄>:定義掛載點,明確表示該目錄需要進行數據持久化,能讓使用該鏡像的人清楚知道哪些目錄的數據需要持久保存。

    在這里插入圖片描述

  • COPY <src> <dest>:將文件/目錄,拷貝到鏡像中文件系統的另一個目錄中

    在這里插入圖片描述

  • ENTRYPOINT <入口文件>:配置鏡像的入口文件,供exec -it進入容器

    在這里插入圖片描述

  • EXPOSE <端口>:指定容器內監聽的端口

    在這里插入圖片描述

  • CMD <默認命令>:容器啟動時的默認命令,如果在啟動的run 后面指定了啟動命令,那么就會被啟動命令替換,不執行DockerfileCMD的命令

    • centosCMDCMD ["/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、案例一:實現Ubuntuifconfig命令

  • 當我們從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目錄中

  1. 使用IDEA 或 Xftp工具連接服務器,將下載好的JDK文件放入

    1. 不知道怎么使用IDEA自帶工具連接的,可以查看:IDEA-不使用插件連接SSH、SFTP_idea ssh插件-CSDN博客
    2. 在這里插入圖片描述
  1. 連接好后,注意,使用這個工具,只能將左側項目中有的文件,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裝進去了,下面我們來一個接近真實項目的案例
    1. 我們自己寫一個SpringBoot項目,并且暴露一個接口
    2. 然后使用maven clearn package構建jar
    3. 然后在這個項目根目錄內新建Dockerfile文件,在IDEA編寫Dockerfile文件
    4. /target/下面的jar包和/Dockerfile文件一起移入服務器的/mydir/my-project/
    5. 最后進入目錄,使用build命令構建我們的鏡像

3.1、編寫項目及jar包生成

  1. 我們使用SpringBoot項目構建器創建一個基本的項目,然后編寫一個簡單的接口,項目端口設置為9999即可

    在這里插入圖片描述

  1. 然后在/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>
    
  2. 啟動項目,打開瀏覽器,訪問localhost:9999/getUser,返回信息正常即可

    在這里插入圖片描述

  1. 并且在項目所在目錄新建了/logs/app.log文件

    在這里插入圖片描述

  1. 使用maven,分別執行clean、package命令,將項目打包為jar

    在這里插入圖片描述

  1. 命令執行完后,可以在/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目錄中
  • 解決辦法:
    1. Dockerfile中添加RUN cd /app
    2. 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、在自己電腦上訪問接口

  • 由于我的容器IP192.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中網絡模式
    1. bridge為每一個容器分配、設置IP等,并將容器連接到一個docker0虛擬網橋,默認為該模式
    2. host:容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口
    3. none:容器有獨立的Network namespace,但并沒有對其進行任務網絡設置,比如分配veth pair和網橋鏈接,IP等
    4. 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容器本身占用資源極少,所以最好是將每個服務單獨的分割開來。
  • 正常我們的服務會有很多組件還有數據庫一起組成的,比如mysqlrediskafka、微服務模塊等,我們一個一個執行的話,很容易出錯,并且我們的服務和其他容器有可能有先后順序,比如先啟動依賴容器(比如:mysqlredis等),才能啟動我們的微服務
  • 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、使用

兩要素:

  1. 服務:一個個應用容器實例,比如訂單微服務、庫存微服務、mysql容器、nginx容器或者redis容器
  2. 工程:由一組關聯的應用容器組成的一個完整業務單元,在compose.yaml 或 compose.yml中定義

使用的三個步驟

  1. 編寫Dockerfile定義各個微服務應用并構建出對應的鏡像文件
  2. 使用compose.yml訂一個一個完整業務單元,安排好整體應用中的各個容器服務
  3. 最后執行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,否則頁面會出不來

  • 訪問頁面可以使用如下兩種方式

    1. 服務器內訪問:我們在虛擬機內部使用https://localhost:9443 或 https://127.0.0.1:9443
    2. 內網其他電腦訪問:https:// + 服務器IP + :9443即可
  • 我們首次訪問可能會出現如下界面,點擊高級->繼續訪問即可

    在這里插入圖片描述

2.2、創建賬號

  • 注意,Portainer初次啟動以后,要在5分鐘內完成賬號注冊,否則就要重啟容器,然后再重新注冊

  • 文檔地址:安裝 Portainer 后,我收到消息“出于安全目的,您的 Portainer 實例已超時”,我該如何解決這個問題?

    在這里插入圖片描述

在這里插入圖片描述

2.3、使用頁面

  • 頁面使用文檔:Home | Portainer Documentation

  • 注冊成功后,我們會進入如下頁面

    在這里插入圖片描述

2.4、查看Docker內部所有信息

  • 我們要先點擊右側那個localDocker,選擇我們的當前綁定的鏡像實例

  • 然后在左側,我們就會看到我們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等集成,可以加上對應配置將監控數據發往這些數據庫存儲起來。
      • 功能點主要有兩個
        1. 展示Host和容器兩個層次的監控數據
        2. 展示歷史變化數據
    • 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中的某個鏡像,單獨拉下來即可
  • 當我們按照上面文件啟動后,可以訪問如下三個地址,首次訪問可能會比較慢
    1. 瀏覽cAdvisor收集服務:http://宿主機ip:8080
    2. 瀏覽influxdb存儲服務:http://宿主機ip:8083
    3. 瀏覽grafana展現服務:http://宿主機ip:3000

2.1、cAdvisor

在這個頁面往下翻,可以看到簡單的統計圖,會顯示當前宿主機系統的情況,CPU、內存等信息

在這里插入圖片描述

在這里插入圖片描述

2.2、influxdb

  1. 進入頁面后,我們點擊右上角的設置(齒輪圖標),可以填寫賬號密碼
  2. 然后點擊右側Query Templates選擇需要的語句sql
  3. 輸入框回車,執行sql

在這里插入圖片描述

2.3、grafana

2.3.1、連接數據庫
  1. 頁面我們使用賬號:admin 密碼:admin登錄進去

  2. 左側Connections->Data sources,然后選擇InfluxDB

    在這里插入圖片描述

  1. 然后填寫數據庫信息,保存并測試即可

    在這里插入圖片描述

2.3.2、配置圖形化界面
  • 選擇左側的Dashboards菜單,點擊右側的create dashboard

  • 然后選擇我們剛剛配置的數據庫就來到了配置圖形頁面

  • 我這里配個簡單的圖形演示

    在這里插入圖片描述

  • 配置查詢的sql

    在這里插入圖片描述

  • 然后點擊右上角Save dashboard

  • 然后填寫圖形名稱

    在這里插入圖片描述

  • 保存成功后,我們即可刷新頁面,再次查看我們的圖形了

    在這里插入圖片描述

開發軟件中的Docker插件

  • 我這里以Idea開發工具中的Docker插件為例

  • 現在IDEA插件中一般都會自帶一個Docker插件,沒有的話自行安裝

    在這里插入圖片描述

  • 然后我們點擊左上角的File->Build,Execution,Deployment

    在這里插入圖片描述

  • 然后在右側點擊+號,選擇SSH連接我們的服務器

    在這里插入圖片描述

  • 然后在彈框中,填寫我們的服務器ip,賬號,密碼,測試連接

    在這里插入圖片描述

  • 最后我們點擊ok即可

  • 然后在下面的Services中可以看到Docker的狀態了,以及對Docker的一切操作

    在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903248.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903248.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903248.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot常用注解詳解:實例與核心概念

Spring Boot常用注解詳解&#xff1a;實例與核心概念 前言 Spring Boot作為Java領域最受歡迎的快速開發框架&#xff0c;其核心特性之一是通過注解&#xff08;Annotation&#xff09;簡化配置&#xff0c;提高開發效率。注解驅動開發模式讓開發者告別繁瑣的XML配置&#xff…

TRO再添新案 TME再拿下一熱門IP,涉及Paddington多個商標

4月2日和4月8日&#xff0c;TME律所代理Paddington & Company Ltd.對熱門IP Paddington Bear帕丁頓熊的多類商標發起維權&#xff0c;覆蓋文具、家居用品、毛絨玩具、紡織用品、游戲、電影、咖啡、填充玩具等領域。跨境賣家需立即排查店鋪內的相關產品&#xff01; 案件基…

經驗分享-上傳ios的ipa文件

.ipa格式的二進制文件&#xff0c;是打包后生成的文件&#xff0c;無論我們是放上去testflight測試還是正式上傳到app store&#xff0c;都需要先上傳到蘋果開發者中心的app store connect上的構建版本上。 在app store connect上&#xff0c;上傳構建版本的功能&#xff0c;它…

docker(3) -- 圖形界面

1. 前言 在wsl(8) – 圖形界面文章中介紹了wsl2默認是支持圖形界面的&#xff0c;現在我們嘗試下在docker中運行gui程序試試看。 2. x11-apps 啟動一個docker&#xff0c;安裝一些gui小程序&#xff0c;然后運行&#xff0c;發現會失敗。ubuntu_base詳見文章wsl(6) – 安裝d…

Docker容器跑定時任務腳本

最近搞了一個Docker容器跑腳本&#xff0c;想設置一個定時任務&#xff0c;每天8點運行一次&#xff0c;結果死活不成功。排查了一天&#xff0c;有一點當局者迷了&#xff0c;明明時間是對的&#xff0c;明明時區是對的&#xff0c;定時任務也是啟動的&#xff0c;它就是不執行…

【Linux】什么是完全限定域名

FQDN 是 “完全限定域名” (Fully Qualified Domain Name) 的縮寫。 FQDN 是一個互聯網上特定計算機或主機的完整且唯一的域名。它詳細說明了該主機在域名系統 (DNS) 層級結構中的確切位置。 一個 FQDN 通常由以下幾個部分組成&#xff0c;從左到右依次是&#xff1a; 主機名…

小結:BFD

*BFD&#xff08;雙向轉發檢測&#xff0c;Bidirectional Forwarding Detection&#xff09;是一種快速、輕量級的故障檢測機制&#xff0c;用于檢測網絡中兩點之間的連通性。它廣泛應用于各種場景 1. 檢測 IP 鏈路 應用場景&#xff1a; BFD 用于檢測兩臺設備之間的 IP 層連…

配置Spark歷史服務器,輕松查看任務記錄

在大數據處理中&#xff0c;Spark是一個強大的分布式計算框架。但當Spark服務重啟后&#xff0c;之前的運行記錄就會消失&#xff0c;給我們排查問題和分析任務執行情況帶來不便。這時&#xff0c;配置Spark歷史服務器就顯得尤為重要&#xff0c;它能幫助我們保存和查看歷史任務…

(六)RestAPI 毛子(外部導入打卡/游標分頁/Refit/Http resilience/批量提交/Quartz后臺任務/Hateoas Driven)

文章目錄 項目地址一、外部導入打卡功能1.1 創建實體1. Entry實體2. EntryImport實體3. 添加數據庫配置4. 創建表 1.2 創建DTOs1.3 創建GetEnties Controller 二、游標分頁2.1 創建所需要的DTOs1. 創建游標分頁的請求參數2. 創建CollectionResponse3. 添加游標編碼和解碼的DTO …

Node.js CSRF 保護指南:示例及啟用方法

解釋 CSRF 跨站請求偽造 (CSRF/XSRF) 是一種利用用戶權限劫持會話的攻擊。這種攻擊策略允許攻擊者通過誘騙用戶以攻擊者的名義提交惡意請求,從而繞過我們的安全措施。 CSRF 攻擊之所以可能發生,是因為兩個原因。首先,CSRF 攻擊利用了用戶無法辨別看似合法的 HTML 元素是否…

Flink介紹——實時計算核心論文之Dataflow論文總結

數據流處理的演變與 Dataflow 模型的革新 在大數據處理領域&#xff0c;流式數據處理系統的發展歷程充滿了創新與變革。從早期的 S4 到 Storm&#xff0c;再到 MillWheel&#xff0c;每一個系統都以其獨特的方式推動了技術的進步。S4 以其無中心架構和 PE&#xff08;Processi…

Arduino 入門學習筆記(五):KEY實驗

Arduino 入門學習筆記&#xff08;五&#xff09;&#xff1a;KEY實驗 開發板&#xff1a;正點原子ESP32S3 例程源碼在文章頂部可免費下載&#xff08;審核中…&#xff09; 1. GPIO 輸入功能使用 1.1 GPIO 輸入模式介紹 在上一文章中提及到 pinMode 函數&#xff0c; 要對…

Centos9安裝docker

1. 卸載docker 查看是否安裝了docker yum list | grep docker卸載老版本docker&#xff0c;拷貝自官網 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine卸載新版本…

Pgvector+R2R搭建RAG知識庫

背景 R2R是一個采用Python編寫的開源AI RAG框架項目&#xff0c;與PostgreSQL技術棧集成度高&#xff0c;運行需求資源少&#xff08;主要是本人的Macbook air m1內存只有8G&#xff09;的特點&#xff0c;對部署本地私有化化AI RAG應用友好。 Resource Recommendations Whe…

go中redis使用的簡單介紹

目錄 一、Redis 簡介 二、Go中Redis的使用 1. 安裝Go Redis包 2. 單機模式 連接示例 3. 哨兵模式 依賴 連接示例 三、Redis集群 1. 集群模式 集群部署 部署結構 使用redis-cli創建集群 連接示例 四、常用數據結構與操作 1. 字符串&#xff08;String&#xff0…

北京工業大學25計專上岸經驗分享

1.個人情況介紹 本科就讀于河北雙非&#xff0c;專業為計算機科學與技術&#xff0c;四級三次498&#xff0c;六級兩次460&#xff0c;拿過幾次校級獎學金&#xff0c;競賽經歷有藍橋杯國三、數學競賽省二。本科成績排名靠前&#xff0c;保研保7排8&#xff0c;遺憾選擇考研繼…

在 Ubuntu 24.04 系統上安裝和管理 Nginx

1、安裝Nginx 在Ubuntu 24.04系統上安裝Nginx&#xff0c;可以按照下面的步驟進行&#xff1a; 1.1、 更新系統軟件包列表 在安裝新軟件之前&#xff0c;需要先更新系統的軟件包列表&#xff0c;確保獲取到最新的軟件包信息。打開終端&#xff0c;執行以下命令&#xff1a; …

HarmonyOS4+NEXT星河版入門與項目實戰(26)-----版本控制與代碼托管

引言 隨著移動應用開發技術的不斷進步,華為推出的鴻蒙操作系統(HarmonyOS)以及其配套的集成開發環境DevEco Studio逐漸成為開發者關注的焦點。對于新手開發者來說,掌握版本控制和代碼托管不僅是提高工作效率的關鍵,也是團隊協作的重要基礎。本文將介紹如何在使用DevEco S…

利用Arcgis自己繪制shp文件

1.選擇自己想要創建的shp文件的位置 我是直接創建在連接文件夾中 2.右鍵-新建-shp 3.設置名稱、要素類型、空間參考 4、點擊創建要素 5、右側選擇圖層、創建面 6、開始繪制&#xff0c;雙擊任意位置結束繪制 之后可以改一下shp文件的名字

【C/C++】深入理解指針(六)

文章目錄 深入理解指針(六)1.sizeof和strlen的對比1.1 sizeof1.2 strlen1.3 sizeof和strlen的對? 2.數組和指針筆試題解析2.1 ?維數組2.2 字符數組代碼1&#xff1a;代碼2&#xff1a;代碼3&#xff1a;代碼4&#xff1a;代碼5&#xff1a;代碼6&#xff1a; 2.3 ?維數組 3.…