Docker 外掛的開發,本質上是建立一個與 Docker Engine 互動的外接程式。這些外掛通常使用 Go 語言編寫,並透過 Unix Socket 或 TCP 埠與 Docker 通訊。外掛的註冊需要在特定目錄下建立 .sock、.spec 或 .json 檔案,其中 .json 檔案包含更詳細的外掛資訊,例如名稱、地址和 TLS 組態。為了確保外掛在 Docker 之前啟動,可以使用 systemd 建立服務檔案。當 Docker 呼叫外掛時,它會傳送 /Plugin.Activate 請求,外掛則需要傳回 JSON 格式的回應,宣告其功能。
除了 Docker 外掛開發外,本文還介紹了使用 Puppet 自動化 Docker 基礎設施。Puppet 作為一個組態管理工具,能簡化伺服器組態和維護,特別是在多伺服器環境下,可以確保組態一致性,減少錯誤並提高效率。文章以佈署 WordPress 為例,展示瞭如何使用 Puppet 組態 Docker 映像檔、容器、連線埠和環境變數。更進一步,文章還提到了使用 Puppet Master 管理多個 Docker 節點的架構,讓讀者對 Puppet 在 Docker 自動化中的應用有更全面的理解。
建立自己的 Docker 外掛
Docker 外掛是擴充套件 Docker Engine 功能的外接程式。在本章中,我們將探討如何建立自己的 Docker 外掛。
瞭解外掛
到目前為止,我們已經瞭解到所有安裝的外掛實際上與 Docker 本身沒有直接關係。那麼,什麼是外掛呢?Docker 將外掛描述為「Docker 外掛是新增 Docker Engine 功能的外接擴充套件」。
外掛的共同點
我們觀察到的所有外掛都有一些共同的特點:
- 它們都有指令碼和二進位制檔案,這些檔案都是在 Docker 之外執行的。
- 大多數外掛都是用與 Docker 相同的語言編寫的,例如 Go 語言。
| 外掛名稱 | 程式語言 |
|---|---|
| Convoy | Go |
| REX-Ray | Go |
| Flocker | Python |
| Weave | Go |
建立自己的外掛
大多數 Docker 服務都是用 Go 語言編寫的,只有 Flocker 是用 Python 編寫的。Go 語言具有表達力強、簡潔、乾淨和高效的特點。其並發機制使得編寫充分利用多核和網路機器的程式變得容易。
發現(Discovery)
通常,外掛會安裝在與 Docker 二進位制檔案相同的宿主機上。我們可以透過在特定目錄下建立檔案來向 Docker 註冊我們的外掛,例如 /run/docker/plugins、/etc/docker/plugins 或 /usr/lib/docker/plugins。
對於我們的 mobyfs 外掛,我們需要建立以下檔案之一:
mobyfs.sock(Unix 通訊端檔案)mobyfs.specmobyfs.json
如果使用 .spec 檔案,則只需包含一個指向 TCP 主機和埠或本地通訊端檔案的 URL。例如:
tcp://192.168.1.1:8080
tcp://localhost:8080
unix:///other.sock
如果使用 .json 檔案,則需要包含外掛的詳細資訊,例如:
{
"Name": "mobyfs",
"Addr": "https://192.168.1.1:8080",
"TLSConfig": {
"InsecureSkipVerify": false,
"CAFile": "/usr/shared/docker/certs/example-ca.pem",
"CertFile": "/usr/shared/docker/certs/example-cert.pem",
"KeyFile": "/usr/shared/docker/certs/example-key.pem"
}
}
啟動順序(Startup Order)
理想情況下,外掛服務應該在 Docker 之前啟動。如果宿主機上安裝了 systemd,可以透過建立一個 systemd 服務檔案來實作這一點。
[Unit]
Description=mobyfs
Before=docker.service
[Service]
EnvironmentFile=/etc/mobyfs/mobyfs.env
ExecStart=/usr/bin/mobyfs start -p 8080
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
[Install]
WantedBy=docker.service
啟用(Activation)
一旦外掛服務啟動,我們需要讓 Docker 知道應該將請求傳送到哪裡。對於我們的 mobyfs 卷外掛,可以執行以下命令:
docker run -ti -v volumename:/data --volume-driver=mobyfs russmckendrick/base bash
這將掛載 volumename 捲到容器內的 /data 目錄。
API 呼叫(API Calls)
一旦外掛被呼叫,Docker 守護程式將使用 RPC 風格的 JSON over HTTP 向外掛服務發出 POST 請求。外掛服務必須實作一個 HTTP 伺服器並繫結到指定的通訊端或埠。
第一個請求是 /Plugin.Activate,外掛服務必須回應其中一個有效的回應。例如,對於 mobyfs 卷外掛,回應如下:
{
"Implements": ["VolumeDriver"]
}
程式碼範例與解析
以下是一個簡單的 Go 語言程式碼範例,用於建立一個 HTTP 伺服器並回應 Docker 的 /Plugin.Activate 請求:
package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
response := map[string]interface{}{
"Implements": []string{"VolumeDriver"},
}
json.NewEncoder(w).Encode(response)
})
fmt.Println("Server is listening on port 8080")
http.ListenAndServe(":8080", nil)
}
內容解密:
此程式碼建立了一個簡單的 HTTP 伺服器,監聽在 8080 埠。當收到 /Plugin.Activate 請求時,它會傳回一個 JSON 物件,表明該外掛實作了 VolumeDriver 介面。這是 Docker 外掛啟用流程中的關鍵一步。
使用第三方工具擴充基礎架構
在第2章「介紹第一方工具」中,我們探討了Docker提供的工具,用於擴充核心Docker引擎的功能。在本章中,我們將研究擴充Docker組態管理和建置及啟動容器方式的第三方工具。我們將要討論的工具有:
- Puppet:http://puppetlabs.com/
- Ansible:http://www.ansible.com/docker/
- Vagrant:https://docs.vagrantup.com/v2/docker/
- Packer:https://www.packer.io/docs/builders/docker.html
- Jenkins:https://jenkins-ci.org/content/jenkins-and-docker/
對於每個工具,我們將探討如何安裝、組態和使用它們與Docker一起使用。在我們研究如何使用這些工具之前,讓我們先討論為什麼要使用它們。
為什麼使用這些工具?
到目前為止,我們一直在研究使用主要Docker客戶端或由Docker和其他第三方提供的工具來支援主要Docker客戶端的工具。有一段時間,這些工具現在具有的一些功能在Docker支援產品中並不存在。例如,如果你想啟動一個Docker主機,你不能直接使用Docker Machine,而是必須使用像Vagrant這樣的工具來啟動虛擬機器(本地或雲端),然後使用bash指令碼、Puppet或Ansible安裝Docker。
Puppet化一切
在「容器化一切」的梗圖開始頻繁出現在人們的演講中之前:
人們對Puppet也有同樣的說法。那麼,什麼是Puppet?為什麼要在所有事情上使用它?
Puppet Labs,Puppet的製造商,將Puppet描述為:
「使用Puppet,您可以定義IT基礎架構的狀態,Puppet會自動強制執行所需的狀態。Puppet自動化軟體交付過程的每個步驟,從實體和虛擬機器的組態到協調和報告;從早期程式碼開發到測試、生產發布和更新。」
在像Puppet這樣的工具出現之前,作為系統管理員的工作有時會是一個非常繁瑣的過程:如果你不是在排查問題,就是在編寫自己的指令碼來引導伺服器,或者更糟糕的是,從內部wiki複製和貼上命令來安裝軟體堆積疊並進行組態。
使用Puppet進行自動化
Puppet是一種組態管理工具,可以幫助您自動化IT基礎架構的管理。它允許您定義基礎架構的所需狀態,並確保實際狀態與所需狀態一致。
Puppet的工作原理
Puppet使用一種稱為「宣告式組態」的概念,您可以在其中定義基礎架構的所需狀態。然後,Puppet會自動強制執行所需的狀態。
以下是Puppet工作原理的高階概述:
- 您定義基礎架構的所需狀態,使用Puppet的DSL(領域特定語言)或JSON/YAML組態檔案。
- Puppet將您的組態推播到您的節點(伺服器、虛擬機器等)。
- Puppet的代理程式在您的節點上執行,並強制執行所需的狀態。
使用Puppet的好處
使用Puppet可以帶來多種好處,包括:
- 提高一致性:Puppet可確保您的基礎架構的一致性,無論是單個伺服器還是數千個伺服器。
- 減少錯誤:透過自動化任務,Puppet可以減少人為錯誤的可能性。
- 提高效率:Puppet可以節省您在管理和維護基礎架構上的時間和精力。
# Puppet程式碼範例
node 'example.com' {
package { 'httpd':
ensure => installed,
}
service { 'httpd':
ensure => running,
enable => true,
}
}
內容解密:
這段Puppet程式碼定義了一個名為example.com的節點,並確保httpd套件已安裝且httpd服務正在執行。這是Puppet宣告式組態的一個簡單範例。
圖表翻譯: 此圖示展示了Puppet的工作流程。Puppet Master將組態推播到Puppet Agent,然後Agent在節點上執行組態。節點將其狀態報告給Agent,Agent再將狀態報告給Master。
使用Puppet管理Docker容器
在伺服器管理中,保持組態的一致性至關重要。隨著伺服器數量的增加,管理和維護這些伺服器變得越來越複雜。Puppet是一種組態管理工具,可以幫助管理員定義伺服器的組態,並確保這些組態被正確地應用和維護。
為何需要Puppet
在沒有Puppet的情況下,管理多台伺服器需要手動執行相同的組態變更,或編寫指令碼來同步這些變更。這不僅耗時,而且容易出錯。Puppet可以幫助管理員定義伺服器的組態,並自動將這些組態應用到多台伺服器上。
例如,如果你有多台伺服器執行PHP網站,你需要確保這些伺服器的NGINX或Apache組態、PHP版本和模組都相同。使用Puppet,你可以定義一個組態檔案,確保所有伺服器都符合這些要求。
package { 'php' :
ensure => '5.6',
}
這段程式碼確保了PHP套件被安裝,並且版本是5.6。
Docker與Puppet的結合
在Docker的早期版本中,Puppet被用來管理和啟動Docker容器。雖然現在有Docker Machine、Docker Compose和Docker Swarm等工具,但是Puppet仍然可以用來管理Docker主機和容器。
安裝Vagrant和啟動虛擬機器
首先,你需要安裝Vagrant。Vagrant是一個虛擬機器管理工具,可以幫助你快速啟動和管理虛擬機器。
mkdir ubuntu && cd ubuntu/
vagrant init ubuntu/trusty64; vagrant up --provider VirtualBox
安裝Puppet代理
接下來,你需要在虛擬機器中安裝Puppet代理。
vagrant ssh
sudo su -
curl -fsS https://raw.githubusercontent.com/russmckendrick/puppet-install/master/ubuntu | bash
安裝Docker模組
安裝完Puppet代理後,你需要安裝Docker模組。
puppet module install garethr-docker
編寫Puppet組態檔案
在本地機器上,建立一個名為docker.pp的檔案,內容如下:
include 'docker'
docker::image { 'russmckendrick/base': }
docker::run { 'helloworld':
image => 'russmckendrick/base',
command => '/bin/sh -c "while true; do echo hello world; sleep 1; done"',
}
套用Puppet組態
回到虛擬機器中,執行以下命令來套用Puppet組態:
puppet apply /vagrant/docker.pp
驗證結果
執行完上述命令後,你可以驗證Docker是否已經安裝,以及容器是否已經啟動。
docker --version
docker images
docker ps
docker attach helloworld
再次套用Puppet組態
你可以再次執行puppet apply /vagrant/docker.pp來檢視Puppet如何處理已經套用的組態。
內容解密:
- 安裝Vagrant和啟動虛擬機器:使用Vagrant快速啟動和管理虛擬機器。
- 安裝Puppet代理:在虛擬機器中安裝Puppet代理,以便能夠執行Puppet組態。
- 安裝Docker模組:安裝Docker模組,以便能夠使用Puppet管理Docker容器。
- 編寫Puppet組態檔案:編寫Puppet組態檔案,以定義Docker容器的佈署和管理。
- 套用Puppet組態:執行Puppet組態,以自動化Docker容器的佈署和管理。
- 驗證結果:驗證Docker是否已經安裝,以及容器是否已經啟動。
- 再次套用Puppet組態:再次執行Puppet組態,以檢視Puppet如何處理已經套用的組態。
圖表翻譯:
此圖示展示了使用Puppet管理Docker容器的流程。 圖表翻譯: 此圖表展示了使用Puppet管理Docker容器的步驟,包括安裝Vagrant、啟動虛擬機器、安裝Puppet代理、安裝Docker模組、編寫Puppet組態檔案、套用Puppet組態、驗證結果和再次套用Puppet組態。
使用 Puppet 擴充套件 Docker 基礎設施
佈署 WordPress 與 Puppet
首先,我們需要移除現有的虛擬機器並建立一個更複雜的組態。輸入以下命令以銷毀虛擬機器:
vagrant destroy
然後,在 ubuntu 資料夾中的 Vagrantfile 檔案內容替換為:
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.network "private_network", ip: "192.168.33.10"
HOSTNAME = 'docker'
DOMAIN = 'media-glass.es'
Vagrant.require_version '>= 1.7.0'
config.ssh.insert_key = false
config.vm.host_name = HOSTNAME + '.' + DOMAIN
config.vm.provider "VirtualBox" do |v|
v.memory = 2024
v.cpus = 2
end
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = "2024"
v.vmx["numvcpus"] = "2"
end
$script = <<SCRIPT
sudo sh -c 'curl -fsS https://raw.githubusercontent.com/russmckendrick/puppet-install/master/ubuntu | bash'
sudo puppet module install garethr-docker
SCRIPT
config.vm.provision "shell",
inline: $script
end
內容解密:
- 這段
Vagrantfile組態了虛擬機器的基本設定,包括使用ubuntu/trusty64映象、設定私有網路 IP 為192.168.33.10。 - 組態了虛擬機器的主機名稱、記憶體和 CPU 資源。
- 使用 shell provision 安裝 Puppet 和 Docker Puppet 模組。
接下來,在 ubuntu 資料夾中建立一個名為 wordpress.pp 的 Puppet 清單檔案,內容如下:
include 'docker'
docker::image { 'wordpress': }
docker::image { 'mysql': }
docker::run { 'wordpress':
image => 'wordpress',
ports => ['80:80'],
links => ['mysql:mysql'],
}
docker::run { 'mysql':
image => 'mysql',
env => ['MYSQL_ROOT_PASSWORD=password', 'FOO2=BAR2'],
}
內容解密:
- 這段 Puppet 清單定義了 Docker 的映像檔和容器。
- 使用
docker::image資源下載 WordPress 和 MySQL 的映像檔。 - 使用
docker::run資源啟動 WordPress 和 MySQL 容器,並組態連線埠和環境變數。
完成後,執行 vagrant up 和 vagrant ssh,然後應用 Puppet 清單:
sudo puppet apply /vagrant/wordpress.pp
更進階的 Puppet 範例
Puppet 的真正強大之處在於使用 Puppet Master 伺服器來管理多個節點。以下是一個範例架構圖:
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Docker外掛開發與Puppet自動化佈署
package "Docker 架構" {
actor "開發者" as dev
package "Docker Engine" {
component [Docker Daemon] as daemon
component [Docker CLI] as cli
component [REST API] as api
}
package "容器運行時" {
component [containerd] as containerd
component [runc] as runc
}
package "儲存" {
database [Images] as images
database [Volumes] as volumes
database [Networks] as networks
}
cloud "Registry" as registry
}
dev --> cli : 命令操作
cli --> api : API 呼叫
api --> daemon : 處理請求
daemon --> containerd : 容器管理
containerd --> runc : 執行容器
daemon --> images : 映像檔管理
daemon --> registry : 拉取/推送
daemon --> volumes : 資料持久化
daemon --> networks : 網路配置
@enduml圖表翻譯: 此圖示展示了一個 Puppet Master 控制四個 Docker 節點的架構。
在這個範例中,可以使用 Puppet 管理每個節點上的 Docker 和 Weave。Puppet Agent 每隔一段時間會向 Puppet Master 回報並套用組態。