天天看點

docker1.12+swarmkit

部落客QQ:819594300

有什麼疑問的朋友可以聯系部落客,部落客會幫你們解答,謝謝支援!

docker1.12內建了swarmkit,使你可以不用安裝額外的軟體包, 使用簡單的指令啟動建立dockerswarm叢集。

如果你在運作 Docker 1.12時,你就可以原生建立一個 Swarm 叢集 .

內建了swarm叢集的安全特性, 內建了K-V存儲, 你現在不需要額外部署etcd或者consul。

在Docker1.12版本中,一個大的功能點是swarm叢集(基于swarmkit項目),通過Docker指令可以直接實作docker-engine互相發現,并組建成為一個容器叢集。

SwarmKit将節點分為兩類:

工作節點(Worker):負責通過執行器運作任務。SwarmKit的預設執行器為Docker容器執行器(Docker Container Executor)。

  (1)内建分布式存儲,不要額外的資料庫

  (2)支援Rolling update

  (3容器高可用

  (4)通過TLS保證了節點之間通訊的安全

管理節點(Manager):負責接收和響應使用者請求,将叢集狀态調節到最終狀态。在SwarmKit中,使用者可以動态調整節點的角色,即在Manager和Worker之間轉換。

如下圖所示,這是一個典型的master-slave的架構。每個節點都是運作着Docker Engine的Docker主機。一些節點有更高的權限,被稱為Manager。下面的節點是worker節點,接收來自manager組的任務訓示。

<a href="https://s2.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7cHRldVZAAHhoQJRbVs542.jpg" target="_blank"></a>

實驗:部署docker.12  Swarm

實驗環境:

這裡選擇三台主機運作Swarm,一台主機運作私有倉庫。

依次為:

node1  192.168.1.1

node2  192.168.1.2

node3  192.168.1.3

registry  192.168.1.4

虛拟機實驗環境:

<a href="https://s2.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7cKTDOgWAABzs4_KuJw467.jpg" target="_blank"></a>

實驗前準備工作:

1)配置ntp時間伺服器,確定三台node主機時間統一

2)配置好各自的IP位址

3)修改好各自的主機名

4)全部主機都關閉selinux

5)三台node主機開啟路由轉發功能

實驗步驟:

1)配置時間伺服器

<a href="https://s4.51cto.com/wyfs02/M02/8E/DC/wKioL1jN7czRibNaAAG0xXb4Vns454.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7dHiwjcGAAFI_d84VfQ284.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M00/8E/DE/wKiom1jN7dPjDMZQAAC9k88hekY673.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M01/8E/DE/wKiom1jN7dXD-1-CAADI9EacEig351.jpg" target="_blank"></a>

<a href="https://s2.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7eHREo6sAAEBjHl9WHg216.jpg" target="_blank"></a>

<a href="https://s4.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7eOB_tNDAAFNQNnTWBg772.jpg" target="_blank"></a>

<a href="https://s4.51cto.com/wyfs02/M02/8E/DC/wKioL1jN7ebRISRuAAFPLEGb3AY368.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7emgi3n4AADv3Tf4_vw432.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M00/8E/DE/wKiom1jN7evzrw-3AACTKMpQcLs234.jpg" target="_blank"></a>

同時,node3也同步node1的時間

<a href="https://s1.51cto.com/wyfs02/M01/8E/DE/wKiom1jN7e7QapZlAACL7VQq-x0376.jpg" target="_blank"></a>

至此時間伺服器配置完畢,三台node主機時間也已經全部同步了。

2)三台node主機全部需要修改hosts檔案,添加三台主機的ip位址和主機名的映射記錄。

<a href="https://s2.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7fSyaSw4AAC9iZZWDoI488.jpg" target="_blank"></a>

<a href="https://s2.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7fqxd4-JAADqo9bcuSQ593.jpg" target="_blank"></a>

<a href="https://s2.51cto.com/wyfs02/M01/8E/DE/wKiom1jN7fyiNALFAADnTC5WDcE344.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7gOh01DrAAGKzvjyGgg479.jpg" target="_blank"></a>

3)三台node主機防火牆開啟以下端口例外

說明:開啟主控端之間的端口 

TCP端口2377叢集管理端口

TCP與UDP端口7946節點之間通訊端口

TCP與UDP端口4789 overlay網絡通訊端口

<a href="https://s5.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7jLDJ4cKAAKNF9VWc50845.jpg" target="_blank"></a>

<a href="https://s4.51cto.com/wyfs02/M00/8E/DE/wKiom1jN7jvAZIdJAAKS37kmwD0130.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M02/8E/DC/wKioL1jN7lji15nJAALAHJ6tpQQ774.jpg" target="_blank"></a>

4)配置所有節點密鑰互信, 在node1可以免密碼登入各節點,隻在node1上執行

<a href="https://s4.51cto.com/wyfs02/M00/8E/DE/wKiom1jN7mDgpiN9AAJy5lCBWRA919.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7mexO8wHAALYSmr4Kps286.jpg" target="_blank"></a>

5)測試密鑰登入

<a href="https://s3.51cto.com/wyfs02/M01/8E/DE/wKiom1jN7m3QC2x5AAEeSHl5fAA252.jpg" target="_blank"></a>

6)安裝docker 1.12(按照docs.docker.com官網安裝),在所有節點上安裝docker 1.12

如果沒有docker1.12軟體,參照下面截圖的步驟:

<a href="https://s2.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7nDAdy-fAAF6HaoGmew533.jpg" target="_blank"></a>

我這裡已經有下載下傳好的docker1.12軟體,是以我不用上面的方法了,我直接rpm包安裝即可。(三台node主機都要安裝)

<a href="https://s2.51cto.com/wyfs02/M01/8E/DE/wKiom1jN7oSD57iSAAG3aC650j4974.jpg" target="_blank"></a>

<a href="https://s3.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7oeRrZ2OAAGDq32vtUs229.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7oryTD8gAAGOqOCfKeo253.jpg" target="_blank"></a>

7)三台node主機都啟動docker

<a href="https://s1.51cto.com/wyfs02/M02/8E/DC/wKioL1jN7o-Qur3ZAADB4roPbKM398.jpg" target="_blank"></a>

檢查docker版本

<a href="https://s1.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7pCjAuPTAADIQC836rs778.jpg" target="_blank"></a>

知識點說明:

docker1.12 Swarm 模式簡介

Docker Engine 1.12 內建了Swarm叢集工具.

主要使用三個新的指令行工具建立一個swarm叢集:

docker swarm 開啟swarm模式; 加入Swarm叢集; 配置叢集參數

docker node 查詢叢集節點資訊; 提升/移除一個管理節點; 管理swarm節點主機

docker service 建立管理 service

可以檢視docker --help

8)建立 Swarm叢集

在node1上初始化swram叢集:

(說明:初始化群集的意思就是建立群集)

注意 你隻需要在一個node1上初始化swarm叢集, 其他node加入這個叢集就行了, 是以以下指令隻需要在<code>node1</code>上運作.

<a href="https://s4.51cto.com/wyfs02/M00/8E/DE/wKiom1jN7qqwvOJ5AAGjyMKN0Bo737.jpg" target="_blank"></a>

--advertise-addr參數,後面跟你swarm叢集的通訊位址, 也就是node1的位址.

解釋:根據如上指令的提示:

我們的其他節點伺服器,以worker角色加入swarm叢集需要登入到伺服器運作如下指令:

<a href="https://s2.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7qvh5s_-AAB-bjOnldE825.jpg" target="_blank"></a>

以manager角色加入swarm叢集:

<a href="https://s1.51cto.com/wyfs02/M02/8E/DC/wKioL1jN7rLzBmC0AAB64FaS7wU002.jpg" target="_blank"></a>

檢視端口号監聽情況:

<a href="https://s2.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7rPQWp1dAACMjE1-RIM173.jpg" target="_blank"></a>

9)在node1上檢視群集資訊

<a href="https://s5.51cto.com/wyfs02/M00/8E/DE/wKiom1jN7vvgcAVuAAED5U9QlN4564.jpg" target="_blank"></a>

<a href="https://s4.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7xCgTFfbAAMxG0e63P0073.jpg" target="_blank"></a>

檢視swarm叢集node清單

<a href="https://s5.51cto.com/wyfs02/M02/8E/DC/wKioL1jN7xqyC1QsAAF96LpU9bo373.jpg" target="_blank"></a>

10)把其他節點加入叢集中:

在node1通過ssh, 在node2-node3上執行上面的加入叢集指令。

<a href="https://s4.51cto.com/wyfs02/M00/8E/DC/wKioL1jN7x_g9HezAAET5kgWAUE661.jpg" target="_blank"></a>

注: 如果你不記得上面提示的加入swarm叢集的指令和密鑰可以使用如下方式檢視worker節點和manager節點的加入指令:

<a href="https://s5.51cto.com/wyfs02/M01/8E/DE/wKiom1jN70vwBV6hAAFTq4hv04I421.jpg" target="_blank"></a>

再次檢查叢集節點清單, 我們可以看到所有的伺服器都已經加入swarm叢集了

<a href="https://s5.51cto.com/wyfs02/M01/8E/DC/wKioL1jN71OggEONAADri3_0C1Q606.jpg" target="_blank"></a>

不過現在叢集隻有一個manager節點node1, 為了swarm叢集的高可用,和避免單點故障. 我們希望建立多個manager節點叢集.

隻需要通過如下指令, 提升worker節點成manager節點:

<a href="https://s1.51cto.com/wyfs02/M00/8E/DC/wKioL1jN76CDjMMYAAGZ3FvCk8s413.jpg" target="_blank"></a>

檢視node2的docker  info

<a href="https://s1.51cto.com/wyfs02/M02/8E/DE/wKiom1jN76HDYIaXAACwLlGY4kk869.jpg" target="_blank"></a>

<a href="https://s3.51cto.com/wyfs02/M01/8E/DE/wKiom1jN76_SdBTCAAKXSzO063A901.jpg" target="_blank"></a>

說明:現在我們可以看到, 已經有2個manager節點了, 一個Leader節點, 一個Reachable節點. 現在你也可以在node2上面管理整個swarm叢集了。

以上我們的swarm叢集就搭建完畢了. 超級簡單。

習慣使用docker指令幫助:

docker&lt;command&gt; --help

總結:

docker swarm:叢集管理,子指令主要有下面幾個。

Docker swarm init指令用于初始化一個叢集

Docker swarm join指令用于加入一個現有叢集

Docker swarm leave指令由于離開叢集

附:node下線

有些時候需要維護一個節點,此時此節點可能會網絡斷開或者需要關機,造成節點上服務不可用。使用dockernode update --availability drain &lt;NODE-ID&gt;将節點下線,swarm會将目前節點上的容器關閉并在其他節點上啟動。當維護完成,需要上線是,将節點狀态修改為active狀态即可,指令如下:dockernode update --availability active &lt;NODE-ID&gt;

有了Docker Swarm叢集我們如何把我們的應用跑在Swarm叢集上呢?

很簡單, 基本上原來我們使用dockerrun的指令建立容器, 把前面替換成dockerservice create就行了。

建議搭建一個registry,為所的docker主機提供鏡像下載下傳,否則你需要在每個docker主機本地存在容器鏡像。

是以搭建一個私有倉庫,由私有倉庫提供所需要的鏡像。

11)配置registry私有倉裡

準備工作:

①關閉selinux

②開啟路由轉發

vi  /etc/sysctl.cof

添加net.ipv4.ip_forward=1

執行sysctl  -p使修改生效

③修改主機名叫docker.benet.com

安裝docker1.12,然後下載下傳registry2鏡像

#docker pull registry:2

#docker image

<a href="https://s3.51cto.com/wyfs02/M01/8E/DC/wKioL1jN77KQJvVBAAB-5HII8nQ845.jpg" target="_blank"></a>

附:registry1是python語言寫的,而現在registry2版本即docker distribution更加安全和快速,并且是用go語言寫的。

<a href="https://s3.51cto.com/wyfs02/M02/8E/DE/wKiom1jN77SxPEBBAAJmz-N3cuY194.jpg" target="_blank"></a>

12)所有主機都指向registry伺服器:并停止私有倉庫伺服器的docker服務,然後重載并啟動docker服務

<a href="https://s1.51cto.com/wyfs02/M02/8E/DC/wKioL1jN77XAjhDQAACufA5cgOk689.jpg" target="_blank"></a>

<a href="https://s1.51cto.com/wyfs02/M02/8E/DC/wKioL1jN77WSK1W7AABIuvrH9O8401.jpg" target="_blank"></a>

<a href="https://s3.51cto.com/wyfs02/M00/8E/DE/wKiom1jN77jQ3iOyAAFhq3wHKU8762.jpg" target="_blank"></a>

13)測試本地鏡像倉庫

有了本地鏡像倉庫registry, 現在我們推送一個測試鏡像到本機鏡像倉庫, 測試下registry服務.

測試:在node2主機上推送鏡像到registry

如果想把鏡像推送到本地registry.

需要先tag這個鏡像的名字成&lt;registry&gt;/&lt;image name&gt;:&lt;tag&gt;

<a href="https://s4.51cto.com/wyfs02/M00/8E/DC/wKioL1jN77uSLBRqAADRsB0o0Os372.jpg" target="_blank"></a>

檢視鏡像:

<a href="https://s3.51cto.com/wyfs02/M01/8E/DE/wKiom1jN772Ap2hQAACOMbNNH0U309.jpg" target="_blank"></a>

将tag後的鏡像上傳到registry.

<a href="https://s2.51cto.com/wyfs02/M00/8E/DE/wKiom1jN78CS3J4YAAFJWBmihzM587.jpg" target="_blank"></a>

push成功後, 可以調用registry API檢視 registry中的鏡像

<a href="https://s4.51cto.com/wyfs02/M00/8E/DC/wKioL1jN78HQhtPQAAEq3P8pIy0374.jpg" target="_blank"></a>

删除node3已有的所有的原來鏡像,我們來測試下載下傳

<a href="https://s2.51cto.com/wyfs02/M01/8E/DE/wKiom1jN78Khw5GOAADTssA4pAU002.jpg" target="_blank"></a>

在node3主機測試從registry下載下傳鏡像

<a href="https://s3.51cto.com/wyfs02/M01/8E/DC/wKioL1jN7-TDOeCzAAHWnExgeuU880.jpg" target="_blank"></a>

overlay網絡

解決了鏡像建構問題, 為了讓應用跑在swram叢集上,我們還需要解決容器間的網絡通路問題.

單台伺服器的時候我們應用所有的容器都跑在一台主機上, 是以容器之間的網絡是互通的. 現在我們的叢集有3台主機, 是以docker應用的服務會分布在這3台主機上.

如何保證不同主機上的容器網絡互通呢?

swarm叢集已經幫我們解決了這個問題了,就是隻用overlaynetwork.

在docker 1.12以前, swarm叢集需要一個額外的key-value存儲(consul, etcdetc). 來同步網絡配置, 保證所有容器在同一個網段中.

在docker1.12已經内置了這個存儲, 內建了overlaynetworks的支援.

注:swarm上預設已有一個名為ingress的overlay 網絡, 可以直接使用, 但本文會建立一個新的

為我們的docker應用建立一個名為dockercoins的overlay network

1)先檢視docker network清單

<a href="https://s5.51cto.com/wyfs02/M02/8E/DE/wKiom1jN7-XDAuTOAAESuocDcnE962.jpg" target="_blank"></a>

2)建立一個名為dockercoins的overlay network

(建立新的overlay network必須在管理節點,不可以在工作節點)

<a href="https://s5.51cto.com/wyfs02/M02/8E/DC/wKioL1jN8NzytJohAACBadKc3nI029.jpg" target="_blank"></a>

3)再次檢視docker network清單

<a href="https://s5.51cto.com/wyfs02/M00/8E/DE/wKiom1jN8ODzs_gXAAE2ddjwZUk769.jpg" target="_blank"></a>

在網絡清單中你可以看到dockercoins網絡的SCOPE是swarm, 表示該網絡在整個swarm叢集生效的, 其他一些網絡是local,表示本機網絡。

4)你隻需要在manager節點建立network,swarm叢集會自動處理配置到其他的節點,這時你可以檢視其他節點的network. dockercoins網絡已經都建立了。

<a href="https://s2.51cto.com/wyfs02/M02/8E/DC/wKioL1jN8OyAIK6DAAGH7NmataE326.jpg" target="_blank"></a>

注:一旦新的任務被指定給這個節點,Overlay網絡就會被按需建立。

<a href="https://s1.51cto.com/wyfs02/M00/8E/DC/wKioL1jN8PTj-lGtAAHppxDtFI8878.jpg" target="_blank"></a>

在swarm叢集上運作docker應用

概念解釋:service

Docker1.12 swarm引入了服務的概念,一個服務由多個任務組成,一個任務即一個運作的容器。

服務包括兩種類型:

複制服務(replicated services):類似 k8s 中複制集的概念,保持一定數量的相同任務在叢集中運作;

全局服務(global services):類似 k8s 中 daemon 的概念,每個工作節點上運作一個。

5)在manager上執行如下指令:

下面我們可以使用之前push到本地鏡像倉庫的鏡像啟動服務, 以centos:http為例:

<a href="https://s3.51cto.com/wyfs02/M00/8E/DC/wKioL1jN8QzjLrWcAACehcjFzto925.jpg" target="_blank"></a>

說明:docker service create指令建立一個 service.

--name标簽命名service為web。

--replicas标簽來聲明1個運作實體(即容器副本數)

注意, 我們啟動的鏡像名字

192.168.1.4:5000/centos:http使用我們本地鏡像倉庫的鏡像名稱, 這樣當主機上沒有這個鏡像時, 會自動到本地鏡像倉庫拉取鏡像。

6)使用docker service ls或者

docker service list檢視服務

<a href="https://s1.51cto.com/wyfs02/M01/8E/DE/wKiom1jN8Q2itir-AABo6pYRREk070.jpg" target="_blank"></a>

docker service  inspect指令使用者檢視service詳細資訊

<a href="https://s1.51cto.com/wyfs02/M01/8E/DE/wKiom1jN8Q6R8R9FAADRh59oWf4159.jpg" target="_blank"></a>

使用docker service  ps&lt;SERVICE-ID/NAME&gt;檢視服務運作在哪個節點上

<a href="https://s1.51cto.com/wyfs02/M01/8E/DC/wKioL1jN8RyxaQSdAACQ25grt_I516.jpg" target="_blank"></a>

可以看出web服務運作在了node2節點上。

7)現在你可以用浏覽器通路

http://192.168.1.1:8000 就能通路測試頁

<a href="https://s5.51cto.com/wyfs02/M01/8E/DC/wKioL1jN8R7Q3bQGAAHKxtoT0v8777.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M02/8E/DE/wKiom1jN8SKCxmoTAAG34n2uU_c188.jpg" target="_blank"></a>

<a href="https://s3.51cto.com/wyfs02/M02/8E/DC/wKioL1jN8SWg1cnsAAGvPd9b9PU629.jpg" target="_blank"></a>

<a href="https://s4.51cto.com/wyfs02/M00/8E/DE/wKiom1jN8Wjjt_L8AAGyasu5xQ4983.jpg" target="_blank"></a>

事實上, 你可以通路swarm叢集中的所有節點 192.168.1.2、192.168.1.3的8000端口, 都可以通路測試頁。(注:将firewall防火牆預設區域設定為trusted)

8)在manager上執行如下指令:

<a href="https://s1.51cto.com/wyfs02/M00/8E/DC/wKioL1jN8WixY1IOAADrk65-kmg379.jpg" target="_blank"></a>

--replicas标簽來聲明2個運作實體

檢視web2服務:

<a href="https://s2.51cto.com/wyfs02/M01/8E/DE/wKiom1jN8WqgEpSpAADFQ6TbJjw493.jpg" target="_blank"></a>

從上圖可以看到web2名稱的service有2個副本分别運作在node2和node3節點上。

9)在manager上執行建立全局服務

<a href="https://s4.51cto.com/wyfs02/M02/8E/DE/wKiom1jN8W_wjIFuAAEGNeBU9t4640.jpg" target="_blank"></a>

<a href="https://s4.51cto.com/wyfs02/M02/8E/DC/wKioL1jN8XCjaMjvAADdtkbkYQw097.jpg" target="_blank"></a>

從上圖可以看到服務web3在每個節點上都運作一個

10)下面我們擴充舊的服務,從下圖可以看到web service目前隻有一個副本

<a href="https://s3.51cto.com/wyfs02/M01/8E/DC/wKioL1jN8XeBwQ4PAAFmx-H69Uo354.jpg" target="_blank"></a>

11)縮減已有的服務的副本數,這裡将web服務縮減到2個副本

<a href="https://s2.51cto.com/wyfs02/M00/8E/DE/wKiom1jN8X7T5d65AAEASc7yWNM084.jpg" target="_blank"></a>

Swarm節點是自組織(self-organizing)和自修複(self-healing)的,什麼意思?隻要有節點或容器宕掉,swarmengine就會嘗試修複,下面我們來具體看一下

自修複(self-healing)

經過上面的操作之後,我們有以下3個節點:

<a href="https://s1.51cto.com/wyfs02/M00/8E/DC/wKioL1jN8YHRSjzdAAC2wNiltu8418.jpg" target="_blank"></a>

<a href="https://s5.51cto.com/wyfs02/M01/8E/DE/wKiom1jN8YTgbYlMAADQCl0O0lM115.jpg" target="_blank"></a>

上面一共運作着3個服務共7個任務(容器)

Node1節點上運作着容器2個容器。

<a href="https://s2.51cto.com/wyfs02/M02/8E/DE/wKiom1jN8YewqXLTAADInyIAtOw116.jpg" target="_blank"></a>

Node2節點上運作着容器2個容器

<a href="https://s3.51cto.com/wyfs02/M01/8E/DC/wKioL1jN8Yvgm6j7AAC_Kqef-7Q849.jpg" target="_blank"></a>

Node3節點上運作着容器3個容器

<a href="https://s5.51cto.com/wyfs02/M02/8E/DE/wKiom1jN8Y7Qz_lkAAD2ZoiTgBU353.jpg" target="_blank"></a>

現在我們讓node3上的容器都宕掉或部分宕掉

<a href="https://s2.51cto.com/wyfs02/M02/8E/DC/wKioL1jN8ZLCwhXoAAFEsW5bU0k015.jpg" target="_blank"></a>

一旦node3上所有容器停止,Docker就會試圖在相同的節點上啟動3個不同ID的容器。

這就是DockerSwarm Engine的self-healing(自修複)功能。

Self-Organizing(自組織)

現在我們讓node3整個宕掉(我直接吧node3關機了),node3上的容器會自動在其它節點上啟動。

在manager節點上執行docker  server ls看一下

<a href="https://s3.51cto.com/wyfs02/M00/8E/DE/wKiom1jN8ZjgxdwQAAE8sF5f1Qg071.jpg" target="_blank"></a>

從上圖可以看見沒了node3,但是依然還是3個服務,7個任務(容器)。

本文轉自Mr大表哥 部落格,原文連結: http://blog.51cto.com/zpf666/1908067    如需轉載請自行聯系原作者