Docker image 映像檔的匯入與匯出:容器化離線部署的關鍵步驟

Docker 是一個 Open source 的容器化平台,可以輕鬆地打包、部署和運行你的應用程式。
Docker image (映像檔) 是該平台重要元件,它是一個輕量級、可執行、可快速打包的軟體包,不只是應用程式所需的執行檔,還包含運作環境和環境設定。

因為一些特殊需求,需要離線安裝 (offline install) 或者是有些時候你可能沒有一個可以使用私有 docker registry,
你可能會需要這些指令,因有常常忘記故筆記一下。

docker image 匯出

首先,先列出有什麼 images

$ docker image ls

這指令會列出所有你曾經用過的 images

找到你要的 images

然後用 docker save 來匯出 image

$ docker save myimage:latest | gzip > myimage_latest.tar.gz

docker image 匯入

在別台機器,使用 docker load 來匯入 image

docker load --input myimage_latest.tar.gz

備註:官方文件有說 docker load 除了可以直接輸入

  • *.tar 打包檔案(未壓縮)
  • *.tar.gz 壓縮檔案( gzip 壓縮格式)
  • *.tar.bz2 壓縮檔案( bzip2 壓縮格式)
  • *.tar.xz 壓縮檔案( xz 壓縮格式)

當然還是建議放在類似 Docker hub 這樣的 registry 比較好,
如果 docker hub 私有 registry 方案不符合需求,
三大雲端也有提供對應的服務,
有地端 (on-premise) 伺服器自建 docker registry 的方式
不過這個就是另外一個故事了

另外, Kubernetes (k8s) 就非常不建議用匯出匯入這種方式來做,
因為它是叢集自動部署的,你不知道它每次會部署在哪一台機器(除非你有特別指定),
如果你要做類似這樣匯入匯出,你需要在每一個 Node 都做匯出匯入,曠日費時,
建議還是架一個 docker registry 比較理想。

參考資料

用 OpenWRT 設定 VLAN 進行網路隔離 – 以 ASUS RT-AC58U 為例

在當今的數位時代,設定一個安全且專屬的家用網路變得越來越重要。透過使用開源軟體 OpenWRT,我們可以輕鬆地為家中的網路設備建立專屬的虛擬局域網(VLAN),以提供更高程度的安全性與隔離性。

在本篇文章中,我們將透過一個實作範例,詳細介紹如何設定 OpenWRT,將一台路由器切割成兩個 VLAN 區域,並讓這兩個區域互不影響。每個 VLAN 區域都會分到不同的 IP 網段,而且皆有對應的 Wifi 無線網路(2.4G 和 5G)可供使用。最後,我們也會確保每一個 VLAN 區域都能夠對外上網。

這篇文章適合具有基礎網路知識,且對於設定 VLAN 有興趣的讀者。我們將會帶領你逐步了解 VLAN 的基本概念,並實際操作如何在 OpenWRT 中進行設定。

我們用一些筆者自身有用過的機種來做設定範例,詳細探討其中設定值的差異,供大家學習。希望透過本篇文章,你可以瞭解如何透過 OpenWRT 來打造一個安全、專屬的家用網路環境。

那麼,就讓我們開始吧!


設定 VLAN 進行網路隔離 系列文:


範例環境說明

假設你的對外網路有一個光世代的盒子(小烏龜),
你透過 DHCP 配發 IP 的方式來上網

我們把一台路由器分成二個 VLAN 區域:

  • VLAN100 網段 192.168.10.0/24
  • VLAN200 網段 192.168.20.0/24

接孔對應:

  • 指定第一埠為 VLAN100
  • 指定第二埠為 VLAN200

示意圖如下

等效網路拓墣如下

等於是你在小烏龜這邊裝了一台 Switch,
底下各裝一台 Wifi Router 路由器,各自設定獨立的 IP 位址與網段,
實現完全隔離的網路。

而我們全部都在一台路由器就完成了這件事情,
一般的家用路由器沒辦法做到這樣的功能,
但 OpenWRT 可以,這也是它厲害的地方。

我們把範例情境做複雜一點,
假設我們家用區域很大,是個三層樓透天厝,ADSL 主線在一樓,
想要二樓與三樓都延伸以上雙 VLAN 的情境。要怎麼做?

  • 指定第四埠為 VLAN100VLAN200 的 trunk port
  • 多新增一台設定類似的路由器,我們暫稱它為子機
  • 多拉一條網路線,來連接母機與子機

示意圖變成如下:

等效網路拓墣如下

原本我們應該需要二台路由器、二條網路線、二台 Switch hub 來延伸這個完全隔離的網路,歸功於 VLAN 與 trunk port 的功能,我們使用二台路由器,一條網路線就可以做到一樣的事情了。


我們用華碩 ASUS RT-AC58U 來實作這個範例,
有因為硬體特性與原廠驅動設計問題,而步驟有一點點不同,
尤其這台較特別,需要另外說說

這次使用的版本為 OpenWrt 22.03.5 20134-515225c1e 供參考。

設定步驟

Step0. 觀察原有設定值

在開始設定之前,我們先觀察一下原有路由器的設定值,
據經驗,這部分不同機器還是會有些微差異,也記錄一下。

RT-AC58U 原有的設定值是這樣子

Network > Interface 頁面,Interfaces 頁籤

Network > Interface 頁面,Devices 頁籤

Network > Switch 的頁面

Network > Wireless 頁面

快速整理一下:

  • 有 Network > Switch 的頁面
  • 只有 eth1, eth2 二個 eth
  • 有一個 Bridge 介面
    • 預設綁定 VLAN 1 給 LAN 使用
    • 預設綁定 VLAN 2 給 WAN 使用
      (這段網頁管理介面沒有顯示,預設是隱藏的,這也是這台特別之處)

Step1. 修改原有 bridge 介面

到 Network > Switch 頁面

設定 VLAN ID,剛剛有提到這台 VLAN 2 是保留給 wan 使用的,而且它 預設在網頁管理介面是隱藏的
這部分我們等一下再來處理

VLAN ID CPU (eth0) LAN 1 LAN 2 LAN 3 LAN 4
100 t u off u t
200 t off u off t

到這邊只能按下「Save」存檔,不可按 Save & Apply,不然 會直接斷線!
然後到 Network > Interfaces 頁面,選擇預設的 lan 裝置

General Settings 部分

  • Protocol: Static address
  • IPv4 address: 192.168.10.1 (Edit)
  • IPv4 netmask: 255.255.255.0
  • Device: Switch VLAN: "eth0.100"

記得將 Device 調整為 Software VLAN: "eth0.100"
不然會整個連管理介面都連不上。

按 Save and Apply 套用設定

因為有修改路由器 IP,這個時候要更換瀏覽的網址。
http://192.168.1.1/ 要換成 http://192.168.10.1/ 然後重新登入。

Step 3. 設定第二個 VLAN

我們在 Network > Interfaces 的頁面中

按「Add New Interface…」按鈕,新增第二個介面

  • Name: lan200
  • Protocol: Static address
  • Device: Software VLAN: "eth0.200"

然後接續設定設定值

General Settings 區域

  • Protocol: Static address
  • IPv4 address: 192.168.20.1
  • IPv4 netmask: 255.255.255.0
  • Device: Switch VLAN: "eth0.200"

到 DHCP Server 頁籤,設定 DHCP 伺服器
(只有主要的那台路由器需要開,其他台必須關掉此設定值)

原本會顯示 No DHCP Server configured for this interface

按「Set up DHCP Server」按鈕啟動 DHCP 伺服器

DHCP Server > General Setup

  • Start: 2
  • Limit: 254

這邊設定的是 DHCP 伺服器發放 IP 位址的開始與結束區段,依需求修改
預設給 100 – 150,它可以是 2 – 254

Step4. 防火牆設定

(主要那台路由器需要設定,子機可以不用設定)

到 Network > Firewall 頁面

來到 Firewall – Zone Settings 頁面, General Settings 頁籤

依樣畫葫蘆,按 Add 新增一個區域

  • Name: lan200 (名字可以自己取)

  • Input: accept

  • Output: accept

  • Forward: accept

  • Covered networks: lan200 (Switch VLAN: "eth0.200")

Covered networks 為應用網路區域,這邊選擇前面設定的 lan200

  • Allow forward to destination zones:
    wanwan (Ethernet Adapter: "eth1") wan6 (Ethernet Adapter: "eth1")

轉送 (forward) 區域,這邊選擇 wan, wan6 即可。

第二個 VLAN 能不能正確上網就看這個設定了。

設定 Wi-Fi

這邊設定 Wi-Fi 步驟就相對簡單

這台它有二個頻段 2.4GHz 與 5GHz

分別設定為

  • SSID: OpenWRT_lan100

  • 設定您的密碼

  • 對應 VLAN100

  • SSID: OpenWRT_lan200

  • 設定您的密碼

  • 對應 VLAN200

  • SSID: OpenWRT_lan100_5G

  • 設定您的密碼

  • 對應 VLAN100

  • SSID: OpenWRT_lan200_5G

  • 設定您的密碼

  • 對應 VLAN200

這邊應該很直覺,注意不要選錯即可。


Wi-Fi 設定步驟如下:

到 Network > Wireless 頁面

在 radio0.network1 區域,修改原有的 2.4GHz Wi-Fi

General Setup

  • Operating frequency
  • Mode: N
  • Channel: 1 (2412 Mhz)
  • Width: 20 MHz

Interface Configuration
General Setup

  • Mode: Access Point
  • ESSID: OpenWRT_lan100
  • Network: lan (Switch VLAN: "eth0.100")

Interface Configuration
Wireless Security

  • Encryption: WPA2-PSK/WPA3-SAE Mixed Mode (strong security)
  • Key: (Your password)

這邊記得設定你的 Wi-Fi SSID 與密碼,注意不要選錯 vlan 介面


在 radio0.network1 區域,新增一個 2.4GHz 的 Wi-Fi

General Setup

  • Operating frequency
  • Mode: N
  • Channel: 1 (2412 Mhz)
  • Width: 20 MHz

Interface Configuration
General Setup

  • Mode: Access Point
  • ESSID: OpenWRT_lan200
  • Network: lan200 (Switch VLAN: "eth0.200")

Interface Configuration
Wireless Security

  • Encryption: WPA2-PSK/WPA3-SAE Mixed Mode (strong security)
  • Key: (Your password)

這邊記得設定你的 Wi-Fi SSID 與密碼,注意不要選錯 vlan 介面


在 radio1.network1 區域,新增一個 5GHz 的 Wi-Fi

General Setup

  • Operating frequency
  • Mode: AC
  • Channel: 36 (5180 Mhz)
  • Width: 80 MHz

Interface Configuration
General Setup

  • Mode: Access Point
  • ESSID: OpenWRT_lan100_5G
  • Network: lan (Switch VLAN: "eth0.100")

Interface Configuration
Wireless Security

  • Encryption: WPA2-PSK/WPA3-SAE Mixed Mode (strong security)
  • Key: (Your password)

這邊記得設定你的 Wi-Fi SSID 與密碼,注意不要選錯 vlan 介面


在 radio1.network1 區域,新增一個 5GHz 的 Wi-Fi

General Setup

  • Operating frequency
  • Mode: AC
  • Channel: 36 (5180 Mhz)
  • Width: 80 MHz

Interface Configuration
General Setup

  • Mode: Access Point
  • ESSID: OpenWRT_lan200_5G
  • Network: lan200 (Switch VLAN: "eth0.200")

Interface Configuration
Wireless Security

  • Encryption: WPA2-PSK/WPA3-SAE Mixed Mode (strong security)
  • Key: (Your password)

這邊記得設定你的 Wi-Fi SSID 與密碼,注意不要選錯 vlan 介面

Step 5. 修正 WAN 上網介面

這步驟算是 RT-AC58U 特有的步驟,
你會發現整個設定完畢卻無法辦法對外上網,這是正常的
因為剛剛有提到
這台 VLAN 2 是保留給 wan 使用的,而且它 預設在網頁管理介面是隱藏的
所以我們現在要來修正這件事情

使用 ssh 指令連線到路由器:

$ ssh [email protected]

(註:ssh 指令在 Windows powershell 有內建,或者用 putty 都可以)

我們需要直接修改 /etc/config/network 這個檔案

vi /etc/config/network

要比對一下設定檔,如果沒有這個段落的話,要手動加上這段

# this is the VLAN mapping for the internet port
config switch_vlan
    option device 'switch0'
    option vlan '1'
    option vid '2'
    option ports '0t 5'

然後重啟網路服務

$ /etc/init.d/network restart

然後測試,應該就可以連上網路了。

Step6. 連接第二台路由器(子機)

我們來實作示意圖上的第二台路由器

第二台(甚至以上)的路由器,設定跟前面非常類似,
唯有幾個需要確認:

  • DHCP Server 為關
  • 有線網路的對應網段與 VLAN 號碼,都要正確
  • Wi-Fi 帳號、密碼、對應網段與 VLAN 號碼,都要正確

然後將 trunk port 與 trunk port 用網路線,連接在一起,這樣就完成了。


文字介面設定參考

我保留了當初右上角系統透過介面自動產生的指令,供大家參考。
如果需要其他文章的話,才知道大概在講什麼。

基本上它就是用 uci 指令來做操作而已,所屬的設定檔案都已經列在註解上了,

# /etc/config/dhcp
uci del dhcp.lan.ra_slaac
uci set dhcp.lan.start='2'
uci set dhcp.lan.limit='254'
uci set dhcp.lan200=dhcp
uci set dhcp.lan200.interface='lan200'
uci set dhcp.lan200.start='100'
uci set dhcp.lan200.limit='150'
uci set dhcp.lan200.leasetime='12h'
uci set dhcp.lan200.start='2'
uci set dhcp.lan200.limit='254'

# /etc/config/firewall
uci add firewall zone # =cfg0edc81
uci set firewall.@zone[-1].name='lan200'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='ACCEPT'
uci add_list firewall.@zone[-1].network='lan200'
uci add firewall forwarding # =cfg0fad58
uci set firewall.@forwarding[-1].src='lan200'
uci set firewall.@forwarding[-1].dest='wan'

# /etc/config/network
uci add network switch_vlan # =cfg0b1ec7
uci set network.@switch_vlan[-1].device='switch0'
uci set network.@switch_vlan[-1].vlan='2'
uci set network.cfg0a1ec7.ports='0t 4 2 1t'
uci set network.cfg0a1ec7.vid='100'
uci set network.@switch_vlan[-1].ports='0t 3 1t'
uci set network.@switch_vlan[-1].vid='200'
uci set network.lan.device='eth0.100'
uci set network.lan.ipaddr='192.168.10.1'
uci set network.lan200=interface
uci set network.lan200.proto='static'
uci set network.lan200.device='eth0.200'
uci set network.lan200.ipaddr='192.168.20.1'
uci set network.lan200.netmask='255.255.255.0'
uci set network.lan200.type='bridge'

# /etc/config/wireless
uci set wireless.radio0.cell_density='0'
uci set wireless.default_radio0.ssid='OpenWrt_lan100'
uci set wireless.default_radio0.encryption='sae-mixed'
uci set wireless.default_radio0.key='YOUR_PASSWD'
uci del wireless.radio0.disabled
uci set wireless.wifinet2=wifi-iface
uci set wireless.wifinet2.device='radio0'
uci set wireless.wifinet2.mode='ap'
uci set wireless.wifinet2.ssid='OpenWrt_lan200'
uci set wireless.wifinet2.encryption='sae-mixed'
uci set wireless.wifinet2.key='YOUR_PASSWD'
uci set wireless.wifinet2.network='lan200'
uci set wireless.radio1.cell_density='0'
uci set wireless.default_radio1.ssid='OpenWrt_lan100_5G'
uci set wireless.default_radio1.encryption='sae-mixed'
uci set wireless.default_radio1.key='YOUR_PASSWD'
uci del wireless.radio1.disabled
uci set wireless.wifinet3=wifi-iface
uci set wireless.wifinet3.device='radio1'
uci set wireless.wifinet3.mode='ap'
uci set wireless.wifinet3.ssid='OpenWrt_lan200_5G'
uci set wireless.wifinet3.encryption='sae-mixed'
uci set wireless.wifinet3.key='YOUR_PASSWD'
uci set wireless.wifinet3.network='lan200'

用 OpenWRT 設定 VLAN 進行網路隔離 – 以 TOTOLINK-X500R 為例

在當今的數位時代,設定一個安全且專屬的家用網路變得越來越重要。透過使用開源軟體 OpenWRT,我們可以輕鬆地為家中的網路設備建立專屬的虛擬局域網(VLAN),以提供更高程度的安全性與隔離性。

在本篇文章中,我們將透過一個實作範例,詳細介紹如何設定 OpenWRT,將一台路由器切割成兩個 VLAN 區域,並讓這兩個區域互不影響。每個 VLAN 區域都會分到不同的 IP 網段,而且皆有對應的 Wifi 無線網路(2.4G 和 5G)可供使用。最後,我們也會確保每一個 VLAN 區域都能夠對外上網。

這篇文章適合具有基礎網路知識,且對於設定 VLAN 有興趣的讀者。我們將會帶領你逐步了解 VLAN 的基本概念,並實際操作如何在 OpenWRT 中進行設定。

我們用一些筆者自身有用過的機種來做設定範例,詳細探討其中設定值的差異,供大家學習。希望透過本篇文章,你可以瞭解如何透過 OpenWRT 來打造一個安全、專屬的家用網路環境。

那麼,就讓我們開始吧!


設定 VLAN 進行網路隔離 系列文:


範例環境說明

假設你的對外網路有一個光世代的盒子(小烏龜),
你透過 DHCP 配發 IP 的方式來上網

我們把一台路由器分成二個 VLAN 區域:

  • VLAN100 網段 192.168.10.0/24
  • VLAN200 網段 192.168.20.0/24

接孔對應:

  • 指定第一埠為 VLAN100
  • 指定第二埠為 VLAN200

示意圖如下:

等效網路拓墣如下:

等於是你在小烏龜這邊裝了一台 Switch,
底下各裝一台 Wifi Router 路由器,各自設定獨立的 IP 位址與網段,
實現完全隔離的網路。

而我們全部都在一台路由器就完成了這件事情,
一般的家用路由器沒辦法做到這樣的功能,
但 OpenWRT 可以,這也是它厲害的地方。

我們把範例情境做複雜一點,
假設我們家用區域很大,是個三層樓透天厝,ADSL 主線在一樓,
想要二樓與三樓都延伸以上雙 VLAN 的情境。要怎麼做?

  • 指定第四埠為 VLAN100VLAN200 的 trunk port
  • 多新增一台設定類似的路由器,我們暫稱它為子機
  • 多拉一條網路線,來連接母機與子機

示意圖變成如下:

等效網路拓墣如下:

看到這邊大家可能開始霧煞煞,可以先上下對照等效網路拓墣來看,
原本我們應該需要二台路由器、二條網路線、二台 Switch hub 來延伸這個完全隔離的網路,歸功於 VLAN 與 trunk port 的功能,我們使用二台路由器,一條網路線就可以做到一樣的事情了。


以下為設定步驟,這邊使用 TOTOLINK-X500R 刷入 OpenWRT 來實作以下的步驟,
有可能會因為硬體特性與原廠驅動設計問題,而步驟有一點點不同,
如果有比較特別的部份,可能另外寫一篇文章來解釋。

使用的版本為 OpenWRT 22.03.3 r20028-43d71ad93e 供參考。

設定步驟

Step0. 觀察原有設定值

在開始設定之前,我們先觀察一下原有路由器的設定值,
據經驗,這部分不同機器還是會有些微差異,也記錄一下。

TOTOLINK-X500R 原有的設定值是這樣子

Network > Interface 頁面,Interfaces 頁籤

Network > Interface 頁面,Devices 頁籤

br-lan 按下 「Configure…」按鈕的內容,

Bridge device: br-lan 視窗,General device options 頁籤

Bridge device: br-lan 視窗,Bridge VLAN filtering 頁籤

也附上 X500R 的產品背面圖

我們快速整理一下:

  • 沒有 Network > Switch 的頁面
  • eth1, eth2, eth3, eth4, eth5 ,對應到 5 個 Port
  • 有一個 Bridge 介面,
    • 綁定 eth1, eth2, eth3, eth4 為 LAN 的 Interface (介面)
  • 綁定 wan 為 WAN 的 Interface (介面)

接下來我們開始一步一步調整成我們要的範例情境。

Step1. 將原有 bridge 介面改為 VLAN 模式

先到 Network > Interface 頁面,選到 Devices 頁籤,

選到 br-lan 按下 「Configure…」按鈕,

直接到 Bridge VLAN filtering 頁籤,來做 VLAN 設定調整

勾選 Enable VLAN filtering

按下 Add 打入 VLAN ID,(例如:VLAN ID: 100 )
勾選 untagged 就是要應用上去的介面,畫面上會顯示一個 u
如果要走 trunk,再選擇 tagged

如有 CPU 的 Port 一律都選 trunk,這樣介面才看得到

複習一下範例情境:

  • VLAN ID: 100 應用在 Port 1, Port 3
  • VLAN ID: 200 應用在 Port 2
  • Port 4 走 VLAN ID: 100 與 VLAN ID: 200 的 trunk

所以變成這樣

VLAN ID lan1 lan2 lan3 lan4
100 u u t
200 u t

按了存檔 Save 了之後 不要馬上 Apply,不然 會直接斷線!
很重要講三次

到 Network > Interface 頁面 Interfaces 頁籤,

選擇預設的 LAN 按「Edit」按鈕

Interfaces » lan 的 General Settings 頁籤,

將 Device 調整為 Software VLAN: "br-lan.100"

再存檔 Apply

解釋:因為原本的單純的 bridge 介面,改跑成 VLAN 模式了,
以範例來說,原有的介面變成二個軟體 VLAN 介面
但路由器 IP 設定與 DHCP 設定沒有對應綁過去

原本的 bridge 介面不應該掛任何東西才正確

這邊的設定較重要,也是有沒有設定成功的關鍵。

註:先從本身連接的 VLAN 網段開始設定會比較順,
如果做錯了就整台重置吧。

Step2. 更換路由器 IP

為了符合範例的需求,我們更換一下目前連接路由器的 IP,

到 Network > Interface 頁面

General Settings 部分

  • IPv4 address: 192.168.10.1
  • IPv4 netmask: 255.255.255.0

將原本的 192.168.1.1 修改成 192.168.10.1

按 Save and Apply 套用設定,這個時候要更換瀏覽的網址。

http://192.168.1.1/ 要換成 http://192.168.10.1/ 然後重新登入。
這步應該對大家來說不困難。

Step3. 設定第二個 VLAN

我們依樣畫葫蘆在 Network > Interfaces 頁籤中,

按「Add New Interface…」按鈕,新增第二個介面

  • Name: LAN200
  • Protocol: Static address
  • Device: Software VLAN: "br-lan.200"

你就可以接續設定

General Settings

  • IPv4 address: 192.168.20.1
  • IPv4 netmask: 255.255.255.0

到 DHCP Server 頁籤,設定 DHCP 伺服器
(只有主要的那台路由器需要開,其他台必須關掉此設定值)

原本會顯示 No DHCP Server configured for this interface

按「Set up DHCP Server」按鈕啟動 DHCP 伺服器

DHCP Server > General Setup

  • Start: 2
  • Limit: 254

這邊設定的是 DHCP 伺服器發放 IP 位址的開始與結束區段,依需求修改
預設給 100 – 150,它可以是 2 – 254

還是重申:只有主要的那台路由器需要開,其他台必須關掉此設定值

Step4. 防火牆設定

(主要那台路由器需要設定,子機可以不用設定)

到 Network > Firewall 頁面

來到 Firewall – Zone Settings 頁面, General Settings 頁籤

依樣畫葫蘆,按 Add 新增一個區域

Firewall – Zone Settings 頁面, General Settings 頁籤

  • Name: lan200 (名字可以自己取)

  • Input: accept

  • Output: accept

  • Forward: accept

  • Covered networks: lan200 (Software VLAN: "br-lan.200")

Covered networks 為應用網路區域,這邊選擇前面設定的 lan200

  • Allow forward to destination zones: wan, wan6

轉送 (forward) 區域,這邊選擇 wan, wan6 即可。

第二個 VLAN 能不能正確上網就看這個設定了。

設定 Wi-Fi

這邊設定 Wi-Fi 步驟就相對簡單

這台它有二個頻段 2.4GHz 與 5GHz

分別設定為

  • SSID: OpenWRT_lan100

  • 設定您的密碼

  • 對應 VLAN100

  • SSID: OpenWRT_lan200

  • 設定您的密碼

  • 對應 VLAN200

  • SSID: OpenWRT_lan100_5G

  • 設定您的密碼

  • 對應 VLAN100

  • SSID: OpenWRT_lan200_5G

  • 設定您的密碼

  • 對應 VLAN200

這邊應該很直覺,注意不要選錯即可。

Step5. 連接第二台路由器(子機)

我們來實作示意圖上的第二台路由器

第二台(甚至以上)的路由器,設定跟前面非常類似,
唯有幾個需要確認:

  • DHCP Server 為關
  • 有線網路的對應網段與 VLAN 號碼,都要正確
  • Wi-Fi 帳號、密碼、對應網段與 VLAN 號碼,都要正確

然後將 trunk port 與 trunk port 用網路線,連接在一起,這樣就完成了。


文字介面設定參考

我保留了當初右上角系統透過介面自動產生的指令,供大家參考。
如果需要其他文章的話,才知道大概在講什麼。

基本上它就是用 uci 指令來做操作而已,所屬的設定檔案都已經列在註解上了,
這邊就不多做解釋,圖形介面都設定好了。

# /etc/config/dhcp
uci del dhcp.lan.ra_slaac
# /etc/config/network
uci add network bridge-vlan # =cfg07a1b0
uci set network.@bridge-vlan[-1].device='br-lan'
uci set network.@bridge-vlan[-1].vlan='100'
uci add_list network.@bridge-vlan[-1].ports='lan1'
uci add_list network.@bridge-vlan[-1].ports='lan3'
uci add_list network.@bridge-vlan[-1].ports='lan4:t'
uci add network bridge-vlan # =cfg08a1b0
uci set network.@bridge-vlan[-1].device='br-lan'
uci set network.@bridge-vlan[-1].vlan='200'
uci add_list network.@bridge-vlan[-1].ports='lan2'
uci add_list network.@bridge-vlan[-1].ports='lan4:t'
uci set network.lan.device='br-lan.100'

# /etc/config/dhcp
uci set dhcp.lan.start='2'
uci set dhcp.lan.limit='254'
uci set dhcp.lan200=dhcp
uci set dhcp.lan200.interface='lan200'
uci set dhcp.lan200.start='100'
uci set dhcp.lan200.limit='150'
uci set dhcp.lan200.leasetime='12h'
uci set dhcp.lan200.start='2'
uci set dhcp.lan200.limit='254'
# /etc/config/network
uci set network.lan.ipaddr='192.168.10.1'
uci set network.lan200=interface
uci set network.lan200.proto='static'
uci set network.lan200.device='br-lan.200'
uci set network.lan200.ipaddr='192.168.20.1'
uci set network.lan200.netmask='255.255.255.0'

# /etc/config/firewall
uci add firewall zone # =cfg0edc81
uci set firewall.@zone[-1].name='lan200'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='REJECT'
uci add_list firewall.@zone[-1].network='lan200'
uci add firewall forwarding # =cfg0fad58
uci set firewall.@forwarding[-1].src='lan200'
uci set firewall.@forwarding[-1].dest='wan'

# /etc/config/wireless
uci del wireless.radio0.disabled
uci set wireless.wifinet2=wifi-iface
uci set wireless.wifinet2.device='radio0'
uci set wireless.wifinet2.mode='ap'
uci set wireless.wifinet2.ssid='OpenWrt_lan200'
uci set wireless.wifinet2.encryption='sae-mixed'
uci set wireless.wifinet2.key='YOUR_PASSWD'
uci set wireless.wifinet2.network='lan200'
uci set wireless.radio0.cell_density='0'
uci set wireless.default_radio0.ssid='OpenWrt_lan100'
uci set wireless.default_radio0.encryption='sae-mixed'
uci set wireless.default_radio0.key='YOUR_PASSWD'
uci del wireless.radio1.disabled
uci set wireless.wifinet3=wifi-iface
uci set wireless.wifinet3.device='radio1'
uci set wireless.wifinet3.mode='ap'
uci set wireless.wifinet3.ssid='OpenWrt_lan200_5G'
uci set wireless.wifinet3.encryption='sae-mixed'
uci set wireless.wifinet3.key='YOUR_PASSWD'
uci set wireless.wifinet3.network='lan200'
uci set wireless.radio1.cell_density='0'
uci set wireless.default_radio1.ssid='OpenWrt_lan100_5G'
uci set wireless.default_radio1.encryption='sae-mixed'
uci set wireless.default_radio1.key='YOUR_PASSWD'

以上就是這次的內容,希望對大家有幫助。

刷 OpenWRT 韌體刷機記錄 – 華碩 ASUS RT-N16 路由器

查查部落格文章,原來我曾經有過 Asus RT-N10+Asus RT-N16 …等路由器。
這幾台其實可以相容 DD-WRT 與 Tomato 第三方韌體,
但現今,我還是會推薦使用 OpenWRT,功能多太多了。

因為華碩原廠開始用各種方式阻擋置換第三方韌體,熟悉的手感不見了,故記錄一下。

注意:刷機有風險,刷機前請詳閱說明書,刷壞了屬於個人行為,小弟也不負責。
刷機後很有可能失去保固,如果害怕弄壞就按左上角關閉本文吧!

開始之前,記得看文件

OpenWRT 的刷機指南
https://openwrt.org/toh/asus/rt-n16
找到對應的型號就開始吧,很多招都從這來的。

硬體概述

  • CPU: Broadcom BCM4718 480MHz
  • Flash: 32MB
  • RAM: 128MB
  • 2.4GHz Wi-Fi (b/g/n): 300Mbps
  • 5 ports Gigabit ethernet 10/100/1000 Mbps
  • USB 2.0 x 2

材料準備

  1. 去華碩 ASUS 官網下載 Firmware Restoration 韌體更新程式
    ASUS Firmware Restoration 版本 2.1.0.2

https://www.asus.com/tw/supportonly/rtn16/helpdesk_bios/

並在 Windows 電腦安裝起來。

  1. 下載該型號最初版的韌體 (Firmware)

ASUS RT-N16韌體版本 3.0.0.4.374.979 (2013/10/09)
https://www.asus.com/tw/supportonly/rtn16/helpdesk_bios/

這是該型號最初版的韌體。

  1. DD-WRT 的 INITIAL 中繼過渡韌體 (Firmware)

依據 DD-WRT 官方文件所說需要下載這一份 22118 K2.6_mini_RT-N16.trx 過渡韌體
https://download1.dd-wrt.com/dd-wrtv2/downloads/betas/2013/07-24-2013-r22118/broadcom_K26/dd-wrt.v24-22118_NEWD-2_K2.6_mini_RT-N16.trx

(過渡韌體檔名為 dd-wrt.v24-22118_NEWD-2_K2.6_mini_RT-N16.trx 供參考)

  1. OpenWRT 該型號的最新版韌體 (Firmware)

https://downloads.openwrt.org/releases/22.03.5/targets/bcm47xx/mips74k/openwrt-22.03.5-bcm47xx-mips74k-asus_rt-n16-squashfs.trx

(截稿至今,檔名為: openwrt-22.03.5-bcm47xx-mips74k-asus_rt-n16-squashfs.trx 僅供參考。)

安裝步驟

相關步驟筆記如下,可能寫得有點雜,請見諒。

因為新版韌體「 3.0.0.4.380.7378 (2017/04/26) 」的網頁介面有鎖非原廠韌體更新,故要先退版。

  1. 設定好電腦本機 IP: 192.168.1.2 子網路遮罩: 255.255.255.0
  2. 進入「救援模式 (Rescue mode)」(等下會敘述)
  3. 使用剛剛下載的 ASUS Firmware Restoration 韌體更新程式 刷機

這裡有二種選擇,

刷入最初版的韌體 (Firmware):3.0.0.4.374.979 (2013/10/09)

完成後會進入 原廠韌體介面,確認版號之後,直接從路由器管理介面,直接更新韌體,刷最新版 OpenWRT 韌體即可。

(截稿至今,檔名為: openwrt-22.03.5-bcm47xx-mips74k-asus_rt-n16-squashfs.trx 僅供參考。)

或者

刷入 DD-WRT 的 INITIAL 過渡韌體
dd-wrt.v24-22118_NEWD-2_K2.6_mini_RT-N16.trx 供參考)

完成後會進入 DD-WRT,但這個版本不能直接使用(所以才稱做中繼過渡韌體)
使用電腦 Firefox,透過這個過渡版本的路由器網頁管理介面
,刷最新版 OpenWRT 韌體即可。

(截稿至今,檔名為: openwrt-22.03.5-bcm47xx-mips74k-asus_rt-n16-squashfs.trx 僅供參考。)

救援模式 (Rescue mode)

新版韌體「 3.0.0.4.380.7378 (2017/04/26) 」的救援模式進入方式有改版,但如果你刷入了舊版韌體「3.0.0.4.374.979 (2013/10/09)」,救援模式進入方式會變成舊方式。

我二種方式都列出來供大家參考。

  • 舊版:路由器斷電後,按住 restore 鍵不放並插電,持續 5 秒,電源燈會變成慢閃 (2 秒亮一下)
  • 新版:路由器斷電後,然後按住紅色 WPS 按紐,然後插電,等到看到電源燈亮了 (大約 1 秒) 之後再按住 restore 直到電源燈慢閃 (2 秒亮一下)

如何判斷是否有進入救援模式?

如何判斷是否有進入救援模式?
我覺得電腦連接網路線,用 ping 最準。

設定好電腦本機 IP: 192.168.1.2 子網路遮罩: 255.255.255.0

用 ping 加上 -t 參數,變成連續 ping 模式

ping 192.168.1.1 -t

你會發現 TTL=64 (正常模式) 變為 TTL=100 (救援模式)

Reply from 192.168.1.1: bytes=32 time<1ms TTL=64
Reply from 192.168.1.1: bytes=32 time<1ms TTL=100

有變成 TTL=100 就代表成功進入救援模式了,有時候可能要多試幾次才會成功進去,就算進入救援模式了

幾個須注意的重點 (雷點)

  • 如果你的電腦處於複雜的網路環境,例如有裝 Hyper-V 虛擬機、 VMWare 虛擬機
    又有 WiFi 等等多個網路裝置
    把這些網路裝置先停用,把網路環境單純化

  • 救援模式的方式有偷偷改過,但如果刷舊版韌體會被改回來
    總而言之,可以先試試看舊版,如果不行再試試看新版方式

  • 過渡版 DD-WRT 網頁介面刷機的時候,Google Chrome 會出現 ERROR_EMPTY_RESPONSE 的離奇問題
    實測後用火狐 Firefox 就不會出現此問題,在這裡使用 Firefox。

希望整個流程對你有幫助。

參考資料

刷 OpenWRT 韌體刷機記錄 – 華碩 ASUS RT-AC58U 路由器

剛好拿到一台華碩 ASUS RT-AC58U AC1300 路由器,華碩硬體做得還不錯,很耐用。
雖然不是 WiFi 6,但 WiFi 5 AC1300 (400 + 867 Mbps) 可以勇一陣子,再戰十年。

這算是我第五台刷機的機器了,該有步驟的還是會講一下。

我個人很愛開源第三方韌體,從 DD-WRT 玩到 Tomato,直到 OpenWRT (LEDE) 橫空出世,可玩性就在這裡了。
OpenWRT 可以突破原廠限制,很多商用進階功能,直接下放到家用機種,穩定性也比原廠韌體高,這就是我刷機的原因。

注意:刷機有風險,刷機前請詳閱說明書,刷壞了屬於個人行為,小弟也不負責。
刷機後很有可能失去保固,如果害怕弄壞就按左上角關閉本文吧!

開始之前,記得看文件

OpenWRT 的刷機指南
https://openwrt.org/toh/asus/rt-ac58u
很多沒提到的細節都在這裡

硬體概述

  • CPU: Qualcomm Atheros IPQ4018 或 IPQ4019 717Mhz
  • Flash: 128MB
  • RAM: 128MB
  • 2.4GHz Wi-Fi (b/g/n): 400Mbps
  • 5GHz Wi-Fi (a/n/ac): 867Mbps
  • 5 ports Gigabit ethernet
  • USB 3.0 x 1

安裝方式

注意:刷機有風險,刷機前請詳閱說明書,刷壞了屬於個人行為,小弟也不負責。
刷機後很有可能失去保固,如果害怕弄壞就按左上角關閉本文吧!

刷機前請再三確認型號、硬體版號、國際版還是地區版,刷錯型號會直接變磚。

參考步驟為 OpenWRT 的刷機步驟

  1. 到 Zyxmon’s AC58U 網頁,下載我們的中繼韌體 (Firmware) XXX-squashfs-flash-factory.trx 檔案。

(截稿至今,檔名為: openwrt-r1834-0f04829-ipq806x-asus_rt-ac58u-squashfs-flash-factory.trx 僅供參考。)

  1. 瀏覽器鍵入 http://192.168.1.1/ 登入華碩的路由器管理介面

  2. 在 系統管理 Administration → 韌體更新 Firmware Upgrade
    (可能的頁面網址是 http://192.168.1.1/Advanced_FirmwareUpgrade_Content.asp
    上傳 XXX-squashfs-flash-factory.trx 檔案,重開機後會進入 OpenWRT (LEDE),不過這不要太高興,這個中繼版本有一些 Bug,沒辦法使用。

  3. 在終端機用指令打開 SSH
    (以下是用 Mac 做為連線,理論上 Windows 的 Powershell 也適用,或者使用 putty ,SSH 的連線方式就不贅述了。)

ssh [email protected]

依序鍵入以下指令:

# umount /mnt/ubi0_5
# ubirmvol /dev/ubi0 -N jffs2

意思大致為:刪除 jffs2 分割區,解除其保護機制。

  1. OpenWRT 網站 下載最新版更新版 OpenWRT 韌體,
    檔名 XXX-squashfs-sysupgrade.bin

(截稿至今,檔名為: openwrt-22.03.2-ipq40xx-generic-asus_rt-ac58u-squashfs-sysupgrade.bin 僅供參考。)

  1. 瀏覽器鍵入 http://192.168.1.1/ 到這個半殘中繼韌體的路由器管理介面,
    上傳韌體(可能的頁面網址是 http://192.168.1.1/cgi-bin/luci/admin/system/flashops),記得 Keep settings 的勾勾要拿掉,不要保留設定。

  2. 重開機就可以使用完整版 OpenWRT 了。

希望這篇文章對大家有幫助。

參考資料

關於 Kubernetes (K8S) 二個 Pod 與 Service 連線的一些細節

在 Kubernetes 的微服務架構中,了解 Pod 之間的連線細節是至關重要的一環。透過這篇文章的例子,深度探討 Kubernetes 的工作原理,讓讀者不僅理解 Pod 與 Service 之間的基本關聯,還能掌握其背後的機制與細節。我們將從 Pod 的概念和建立開始,進一步講解 Service 的角色和功能,並討論如何實現兩者間的連線。希望通過這篇文章,讀者能夠更具信心地運用 Kubernetes,無論是管理現有的微服務,還是設計新的應用架構。我們將嘗試將這些概念以最簡潔明了的方式呈現,使初學者和專業人士都能從中獲益。本文章帶你深入淺出,一窺 Kubernetes 的核心,理解與掌握 Pod 連線的關鍵知識。

範例需求

  • 建置二個 Deployment 而讓他們能夠內網互相溝通
  • 用一個 LoadBalancer 對應到其中一個 Deployment

配置範例

以下是一個 Kubernetes 配置範例,建立兩個 Deployment 並讓它們能夠內網互相溝通,以及一個 LoadBalancer 服務對應到其中一個 Deployment:

deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app-1
  template:
    metadata:
      labels:
        app: app-1
    spec:
      containers:
      - name: container-1
        image: j796160836/simple-test-http:latest
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app-2
  template:
    metadata:
      labels:
        app: app-2
    spec:
      containers:
      - name: container-2
        image: j796160836/simple-test-http:latest
        ports:
        - containerPort: 80

service.yml

apiVersion: v1
kind: Service
metadata:
  name: service-1
spec:
  selector:
    app: app-1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  name: service-2
spec:
  selector:
    app: app-2
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

這個範例中:

  1. 建立了兩個 Deployment,分別名為 deployment-1deployment-2。每個 Deployment 都有 2 個副本,分別使用標籤 app: app-1app: app-2

  2. deployment-1deployment-2 建立了兩個對應的 ClusterIP 服務,分別名為 service-1service-2。這兩個 ClusterIP 服務會將流量轉發到標籤為 app: app-1app: app-2 的 Pod。

  3. deployment-2 建立了一個名為 service-2 的 LoadBalancer 服務,將外部流量轉發到標籤為 app: app-2 的 Pod。

通過這個配置,兩個 Deployment 的 Pod 可以通過 ClusterIP 服務在內網進行通信,而 LoadBalancer 服務則允許外部流量來存取其中一個 Deployment 的 Pod。

備註:type: LoadBalancer 這個設定值只會在雲端服務
(例如:GCP (Google Cloud Platform) 裡面的 Google Kubernetes Engine (GKE) 、
AWS (Amazon Web Services) 的 Amazon Elastic Kubernetes Service (EKS)、
Microsoft 的 Azure Kubernetes Service (AKS))才會生效,
自行架設 on-premise 的 Kubernetes 叢集不會有動作,除非有另外做一些設定。

準備就緒,我們把它部署上來

$ kubectl apply -f deployment.yaml 

然後可以用 kubectl get pods 來查看 Pod 運作情形

$ kubectl get pods -n default
NAME                            READY   STATUS    RESTARTS   AGE
deployment-1-79c659f4ff-kkvgx   1/1     Running   0          112s
deployment-1-79c659f4ff-wf4kk   1/1     Running   0          112s
deployment-2-76d567869f-cgts7   1/1     Running   0          112s
deployment-2-76d567869f-fpqsm   1/1     Running   0          111s

別忘記部署 service

$ kubectl apply -f service.yaml 

我們使用 kubectl get services 來查看 services 的運作情況

$ kubectl get services -n default
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
service-1    ClusterIP      10.54.3.115   <none>          80/TCP           48s
service-2    LoadBalancer   10.54.3.33    34.xxx.xxx.123   80:32103/TCP     48s

筆記備註:
deployment 為一個部署計劃,裡面定義了 Pod spec,意指這個 Pod 樣板裡面有什麼 container。
replicas 標籤來定義這個樣板要跑幾個副本

通常一個 Pod 裡面只會有一個 container,在其他情況(例如需要 sidecar 的時候)才會一個 Pod 裡面有不只一個 container。


我的 app-2 要怎麼 ping 到 app-1 ?

想必你也跟我有一樣的問題, app-2 要怎麼 ping 到 app-1?讓我們一一解釋。

在 Kubernetes 集群中,你可以使用內部的 Service DNS 名稱來讓 app-2 的 Pod 連接到 app-1 的 Pod。在本例中,app-2 可以透過 service-1 服務名稱來存取 app-1

假設你的應用程式支持從環境變數讀取目標服務的 DNS 名稱,你可以在 deployment-2 的 Pod 模板中添加一個環境變數,指向 service-1 的 DNS 名稱,例如:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: app-2
  template:
    metadata:
      labels:
        app: app-2
    spec:
      containers:
      - name: container-2
        image: your-image-repo/image-2:latest
        ports:
        - containerPort: 80
        env:
        - name: APP_1_SERVICE_URL
          value: "http://service-1.default.svc.cluster.local:80"

這裡,我們為 container-2 添加了一個環境變數 APP_1_SERVICE_URL,其值為 http://service-1.default.svc.cluster.local:80。這個環境變數將被傳遞給 app-2 的應用程式,讓它可以連接到 app-1

在你的 app-2 應用程式中,你需要使用這個環境變數(例如,APP_1_SERVICE_URL)作為 app-1 服務的基礎 URL 進行連接。根據你的應用程式語言和框架,讀取環境變數的方法可能會有所不同。

例如,如果你的應用程式是用 Python 編寫的,你可以使用以下方式讀取環境變數:

import os

app_1_service_url = os.environ['APP_1_SERVICE_URL']

之後,你可以使用 app_1_service_url 作為 app-1 服務的基礎 URL 進行連接。

我們來做一個測試,嘗試把 container 裡面 console 掛進去看看

先列出 Pod,找到你要的 Pod

$ kubectl get pods -n default
NAME                            READY   STATUS    RESTARTS   AGE
deployment-1-79c659f4ff-kkvgx   1/1     Running   0          112s
deployment-1-79c659f4ff-wf4kk   1/1     Running   0          112s
deployment-2-76d567869f-cgts7   1/1     Running   0          112s
deployment-2-76d567869f-fpqsm   1/1     Running   0          111s

將 console 掛進去

$ kubectl exec -it -n my-namespace deployment-1-79c659f4ff-kkvgx -- /bin/bash

然後做 curl 瀏覽看看

root@deployment-1-79c659f4ff-kkvgx:/# curl service-2.my-namespace.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
....(後略)

可以成功連線!

關於內部 DNS 名稱

你或許會問: service-1.default.svc.cluster.local 是固定值嗎? 每次 deploy 會不會變更呢?

service-1.default.svc.cluster.local 是一個 Kubernetes 服務的內部 DNS 名稱。這個名稱是根據你的服務名稱和命名空間生成的。在本例中,服務名稱是 service-1,命名空間是 default

DNS 名稱的規則為 <service-name>.<namespace>.svc.cluster.local

這個 DNS 名稱在 Kubernetes 集群中是固定的,只要你不更改相應的服務名稱和命名空間。每次部署時,只要保持相同的服務名稱和命名空間,這個 DNS 名稱就不會變更。

在本例中,每次部署時,只要你保持服務名稱為 service-1 和命名空間為 default
那這個 service-1.default.svc.cluster.local 的 DNS 名稱就不會變更。

當然,如果你將服務名稱或命名空間更改為其他值,則對應的 DNS 名稱也會相應更改。在這種情況下,你需要在應用程式配置或部署文件中更新相應的 DNS 名稱。


Cleanup

做完實驗了,我們把剛剛建的這些東西都清掉(刪除),避免在雲端服務產生不必要的費用,這一步是很重要的。

$ kubectl delete deployments -n my-namespace deployment-1
deployment.apps "deployment-1" deleted

$ kubectl delete deployments -n my-namespace deployment-2
deployment.apps "deployment-2" deleted

$ kubectl delete services -n my-namespace service-1
service "service-1" deleted

$ kubectl delete services -n my-namespace service-2
service "service-2" deleted

依序把建立出來的 deployment、 service 給刪除

kubectl delete deployments <deployment>
kubectl delete services <services>
kubectl delete pods <pods>
kubectl delete daemonset <daemonset>

參考資料

https://sharegpt.com/c/feBhUAr

Kubernetes (K8S) 自建地端伺服器 (on-premise) 建置實錄

在當今的雲端時代,Kubernetes(簡稱 K8S)作為 Open source 的 container (容器) 編排平台,已經成為許多企業和開發者的首選。它為應用程式的部署、擴展和管理提供了一個強大且靈活的解決方案。
本篇文章將詳細介紹如何在地端 (On-premise, self-host) 伺服器上搭建 Kubernetes 環境,我們將介紹所有必要的步驟,包括環境設置、安裝必要的套件、建立節點與部署應用程式。這將是一個完整的實錄,讓讀者能夠透過這篇文章深入瞭解 K8S 的建置與運作。


若是測試環境,請使用 虛擬機 (Virtual machine, VM) 來建置,
你可以用你喜歡的虛擬機程式來架設,例如 VMWare Workstation, VirtualBox 都可以,我是使用 Promox VE 裡面的 VM 功能來完成。
測試穩定再架設實體機也不遲。

順帶一提,以下這個方式安裝方式為 Bare-metal (裸金屬、裸機)的安裝方式,
如果在其他教學有看到這樣的詞彙的話,可以意識過來。

安裝地圖

Docker 跟 Kubernetes (K8S) 發展至今,百家爭鳴,門派也很多,
安裝部署方式也不盡相同,為了避免初學者混肴,
先幫你預先選好各種所需要的元件:

作業系統

  • Ubuntu Linux 22.04.2 LTS (Jammy Jellyfish)

服務們

  • kubelet
  • Container 運行環境 (Container Runtime):docker
  • cgroup drivers: 確認為 systemd (cgroup drivers v2)
  • CRI (Container Runtime Interface):使用 cri-dockerd
  • CNI (Container Network Interface):使用 Flannel

指令們

  • kubectl
  • kubeadm

這篇主要關注在如何架設 Kubernetes 叢集,
除此之外,你還需要一個配合的共用儲存空間,叢集都可以存取到的儲存空間(檔案伺服器)
可以用 TrueNAS 架設一個。

虛擬機硬體建置

這邊是我 虛擬機 (VM) 的硬體部分建置設定

  • 2 CPU
  • 4GB Ram
  • 8GB Disk 以上,建議 10GB 較穩定

註:經過測試,不要用 Promox VE 裡的 LXC Container 功能架設,
會有非常多的問題,包含權限切不乾淨等。

到時候要建立三台 VM,一台 Control Node 跟二台 Worker Node ,這是最小叢集的配置。
可以先安裝一個母版,到時候用複製 VM 的方式來達成。

虛擬機作業系統 – Ubuntu

作業系統可以是不同的發行版,我這邊用 Ubuntu 來做三台虛擬機的作業系統。

Ubuntu 可從官網下載
https://releases.ubuntu.com/

截稿時的最新 LTS 版本為 Ubuntu 22.04.2 LTS (Jammy Jellyfish)

使用 Server install image (檔名:ubuntu-22.04.2-live-server-amd64.iso) 來安裝

只安裝 SSH Server 就好,其他都先不要。
然後選項裡面有個 docker 實測發現在後續的步驟會有一些問題,請不要偷懶勾上。

<每台都做> 關掉 swap

這步驟不分角色,三台都要做

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

根據 kubeadm 的安裝文件,他有特別指示

MUST disable swap in order for the kubelet to work properly.

必須要關掉 swap 才能正確運作。

所以我們用以下指令永久關閉 Swap

$ sudo sysctl -w vm.swappiness=0

暫時關閉 swap 可以用 swapoff 指令

$ sudo swapoff -a

確認 swap

sysctl 的方式來列出目前 swppiness 設定值

$ sysctl vm.swappiness

或者用列檔案方式列出

$ cat /proc/sys/vm/swappiness

<每台都做> 安裝 Docker

Docker 不分角色,三台都要裝

安裝文件:
https://docs.docker.com/engine/install/ubuntu/

小弟整理的一鍵安裝指令
(科技發展迅速,整理的安裝文件有可能會過時,如果有更新版,請參考官方文件)

$ sudo apt update -y && \
sudo apt install -y ca-certificates curl gnupg && \
sudo install -m 0755 -d /etc/apt/keyrings && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
sudo chmod a+r /etc/apt/keyrings/docker.gpg && \
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
sudo apt update -y && \
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 

修改 daemon.json 讓跳開預設網段
(如果沒有該檔案請自行新增之)

$ sudo vi /etc/docker/daemon.json

內容為

{
  "log-driver": "json-file",
  "log-opts": {
    "tag": "{{.Name}}",
    "max-size": "2m",
    "max-file": "2"
  },
  "default-address-pools": [
    {
      "base": "172.31.0.0/16",
      "size": 24
    }
  ],
  "bip": "172.7.0.1/16"
}

預設開機啟動

$ sudo systemctl enable docker && \
sudo systemctl start docker

驗證 Docker

可用 systemctl 指令查看是否有正常執行

$ sudo systemctl status docker

看看是否有 Running

可以用 docker ps 查看目前所有運行中的 container

$ docker ps

是否能夠正常顯示列表,若是初次安裝,列表是空的很正常。

Docker 版本

留下當時截稿的 Docker 版本給大家參考

# docker version
Client: Docker Engine - Community
 Version:           23.0.5
 API version:       1.42
 Go version:        go1.19.8
 Git commit:        bc4487a
 Built:             Wed Apr 26 16:21:07 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          23.0.5
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.8
  Git commit:       94d3ad6
  Built:            Wed Apr 26 16:21:07 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.20
  GitCommit:        2806fc1057397dbaeefbea0e4e17bddfbd388f38
 runc:
  Version:          1.1.5
  GitCommit:        v1.1.5-0-gf19387a
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

<每台都做> 安裝 kubeletkubeadmkubectl 三兄弟

安裝文件:
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

小弟整理的安裝指令

$ sudo apt update -y && \
sudo apt-get install -y apt-transport-https ca-certificates curl && \
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg && \
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list && \
sudo apt-get update -y && \
sudo apt-get install -y kubelet kubeadm kubectl && \
sudo apt-mark hold kubelet kubeadm kubectl

(科技發展迅速,整理的安裝文件有可能會過時,如果有更新版,請參考官方文件)

目前安裝的版本是 kubelet 1.27.1

<每台都做> 安裝 Container Runtime Interface (CRI) – cri-dockerd

這步驟不分角色,三台都要裝

https://kubernetes.io/docs/setup/production-environment/container-runtimes/

我們用 Docker Engine 推薦的 cri-dockerd

說明文件:
https://kubernetes.io/docs/tasks/administer-cluster/migrating-from-dockershim/migrate-dockershim-dockerd/#what-is-cri-dockerd

release 頁面找到最新版,並符合您的版本的執行檔,下載並安裝

以筆者為例,筆者用的是 Ubuntu 22.04.1 LTS (Jammy Jellyfish)
代號為 Jammy 當時最新版為 v0.3.0

所以找到了 cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb
這個檔案

下載安裝檔並解開安裝
(抱歉,這套件目前沒收錄在 apt-get 套件管理程式裡,沒辦法直接 apt install

$ wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.4/cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb && \
sudo dpkg -i cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb

然後請 systemctl 重新載入 daemon
最後啟動服務

$ systemctl daemon-reload && \
systemctl enable cri-docker.service && \
systemctl start cri-docker.service

如果找不到你的版本,可能要手動編譯並安裝

以下是官方文件提供的步驟
https://github.com/mirantis/cri-dockerd#build-and-install

驗證 cri-docker

可用 systemctl 指令確認是否有正常運行

systemctl status cri-docker.service

確認有 Running

裝完就會有 unix:///var/run/cri-dockerd.sock

複製虛擬機 (VM)

這邊步驟就是將單純的將 虛擬機 (VM) 複製二份成三台,並全部啟動。
以下分別闡述複製完要做的事情

重新產生 Machine-id

用以下指令重新產生 Machine-id

$ sudo rm /etc/machine-id && \
sudo systemd-machine-id-setup

修改 Hostname (主機名稱)

$ sudo vi /etc/hostname

分別改成對應的主機名稱

重新設定 ssh,產生全新的 known-host

sudo dpkg-reconfigure openssh-server

確認 Machine-id

sudo cat /sys/class/dmi/id/product_uuid

確認 Hostname

$ hostname

確認網卡 Mac address 位址

ip link

或者

ifconfig

都可以,如果沒有 ifconfig 指令要安裝 net-tools

apt install -y net-tools

https://superuser.com/questions/636924/regenerate-linux-host-fingerprint

如果有需要的話,可以用 dhclient 指令重新取 DHCP 的 IP
(基本上你重新產生 Machine-id 的話,就會視為別台電腦了)

$ sudo dhclient -r

<每台都做> 設定主機對應

叢集的三台機器做出來,還不知道彼此,
這邊用 /etc/hosts 檔案來讓主機們各自找到彼此

$ sudo vi /etc/hosts

根據每台主機的 IP 位址與主機名稱

192.168.1.100   k8s-ctrl
192.168.1.101   k8s-node1
192.168.1.102   k8s-node2

IP 位址在前,主機名稱在後,用 tab 分隔。

先整理好內容,再各自寫在每一台上面,每一台主機都會看到同一份資料。

確認 cgroup drivers 為 systemd

https://stackoverflow.com/questions/45708175/kubelet-failed-with-kubelet-cgroup-driver-cgroupfs-is-different-from-docker-c

直接講結論,目前最新使用的是 systemd (cgroup Version: 2)

查看 docker 的 cgroup

# docker info | grep -i cgroup

 Cgroup Driver: systemd
 Cgroup Version: 2
  cgroupns

查看 kubelet 的 cgroup

$ sudo cat /var/lib/kubelet/config.yaml | grep cgroup

cgroupDriver: systemd

可以確認是否為 systemd (cgroup Version: 2)

如果 docker 不為 systemd

可以在 daemon.json手動加上

$ sudo vi /etc/docker/daemon.json

這個段落

 "exec-opts": [
    "native.cgroupdriver=systemd"
  ],

重啟 docker

$ sudo systemctl restart docker

如果 kubelet 不為 systemd 就手動修改之

$ sudo vi /var/lib/kubelet/config.yaml

重啟 kubelet

$ sudo systemctl restart kubelet

<每台都做> 設定網路雜項值

根據文件:
https://kubernetes.io/docs/setup/production-environment/container-runtimes/#forwarding-ipv4-and-letting-iptables-see-bridged-traffic

這邊設定網路連線轉發 IPv4 位址並讓 iptables 查看橋接器的流量

用文件提供的指令操作,等等一句一句解釋:

$ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

請 Kubernetes (K8S) 引用載入 br_netfilteroverlay 二個核心模組

$ sudo modprobe overlay
$ sudo modprobe br_netfilter

啟用 br_netfilteroverlay 二個核心模組

$ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

設定轉發 IPv4 位址,讓 iptables 查看橋接器的流量

$ sudo sysctl --system

再不起重新啟動電腦情況下,套用設定值

檢查驗證

檢查 br_netfilteroverlay 二個核心模組有沒有被正確載入可以用以下二個指令

$ lsmod | grep br_netfilter
$ lsmod | grep overlay

檢查

  • net.bridge.bridge-nf-call-iptables
  • net.bridge.bridge-nf-call-ip6tables
  • net.ipv4.ip_forward 

這幾個系統變數是否有設定為 1,可以用 sysctl 指令來檢查:

$ sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

設定 Control plane node(控制平台) (舊名 Master node)

終於要來設定 Control plane (控制平台) 了,如果有其他教學看到 Master node 的話,
別擔心,指的是同一件事情。

利用 kubeadm init 指令來初始化,並代入這些參數:

$ sudo kubeadm init \
    --control-plane-endpoint=192.168.1.100 \
    --apiserver-advertise-address=192.168.1.100 \
    --node-name k8s-ctrl \
    --pod-network-cidr=10.244.0.0/16 \
    --cri-socket unix:///var/run/cri-dockerd.sock

參數說明

  • control-plane-endpoint
    指明 Control plane (控制平台) 是哪個網址,這邊設定好目前這台 IP 位址即可,假設為 192.168.1.100
    (這設定值可省略)
  • apiserver-advertise-address
    指明 API server 的廣播地址,預設就是 Control plane (控制平台) IP 位址,假設為 192.168.1.100
    (這設定值可省略)
  • node-name
    指明 Control plane (控制平台) 的名字,這裡跟主機名稱一致即可。
  • pod-network-cidr
    指明 pod 內部網路使用的網段,這邊因為配合 Flannel CNI,請保留 10.244.0.0/16 請不要修改
  • cri-socket
    指明使用的 CRI 使用 unix:///var/run/cri-dockerd.sock 這設定值 請不要修改

記錄一下運作的樣子

# kubeadm init --pod-network-cidr=10.244.0.0/16 --cri-socket unix:///var/run/cri-dockerd.sock

[init] Using Kubernetes version: v1.27.1
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W0503 18:35:29.693213    1321 images.go:80] could not find officially supported version of etcd for Kubernetes v1.27.1, falling back to the nearest etcd version (3.5.7-0)
W0503 18:35:46.627127    1321 checks.go:835] detected that the sandbox image "registry.k8s.io/pause:3.6" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.k8s.io/pause:3.9" as the CRI sandbox image.
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8s-ctrl kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.1.100]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8s-ctrl localhost] and IPs [192.168.1.100 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8s-ctrl localhost] and IPs [192.168.1.100 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
W0503 18:36:08.496065    1321 images.go:80] could not find officially supported version of etcd for Kubernetes v1.27.1, falling back to the nearest etcd version (3.5.7-0)
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 8.502958 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8s-ctrl as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node k8s-ctrl as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule]
[bootstrap-token] Using token: c1hnqs.c4imcnzqxqry62d0
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.100:6443 --token cxxxxs.c4xxxxxxxxxxxxd0 \
    --discovery-token-ca-cert-hash sha256:103d7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5b1b6

如果沒意外的話,完成之後會看到

Your Kubernetes control-plane has initialized successfully!

別太高興,設定還沒完,先把 kubeadm join 語句先存起來備用

然後依照步驟,
若是 root 使用者,

.bash_profile 或者 .zsh_profile 設定環境變數

$ export KUBECONFIG=/etc/kubernetes/admin.conf

若是一般使用者,請依照指令依序設定

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

註:加入 token 是有期限的,如果隔太久沒有整個步驟做完,
或者忘記了、被洗掉了,可以用指令重新生成加入指令

$ kubeadm token create --print-join-command

<Control plane 做> 安裝 Helm 套件管理程式

Helm 是 Kubernetes (k8s) 所使用的套件管理程式,
類似 apt-get 可以方便我們安裝元件,免去一點設定的雷

Helm 只要裝在 Control plane (舊名 Master node) 就可以了

安裝文件
https://helm.sh/docs/intro/install/

從 APT 安裝(推薦),可用小弟整理之一鍵安裝指令

$ curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null && \
sudo apt install apt-transport-https --yes && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list && \
sudo apt update -y && \
sudo apt install -y helm

(科技發展迅速,整理的安裝文件有可能會過時,如果有更新版,請參考官方文件)

也可從 Script 安裝

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \
chmod 700 get_helm.sh && \
./get_helm.sh

二者效果相同,擇一安裝即可。

<Control plane 做> 安裝 Flannel CNI

https://github.com/flannel-io/flannel

使用 Helm 安裝 Flannel,將之安裝在 kube-flannel 的 namespace,可用小弟整理之一鍵安裝指令

Flannel 只要在 Control plane (舊名 Master node) 上面下指令,就會部署到整個叢集。

可以使用以下整理之指令一鍵安裝

$ kubectl create ns kube-flannel && \
kubectl label --overwrite ns kube-flannel pod-security.kubernetes.io/enforce=privileged && \
helm repo add flannel https://flannel-io.github.io/flannel/ && \
helm install flannel --set podCidr="10.244.0.0/16" --namespace kube-flannel flannel/flannel

(科技發展迅速,整理的安裝文件有可能會過時,如果有更新版,請參考官方文件)

指令意思大致為:

  1. 建立一個 namespace (命名空間)名叫 kube-flannel
  2. 給定 kube-flannel 特權的權限
  3. 加入 repo 網址
  4. 用 helm 安裝 Flannel

設定 Worker node

這下終於可以設定 Worker node 了

還記得剛剛留下來的指令

kubeadm join 192.168.1.100:6443 --token cxxxxs.c4xxxxxxxxxxxxd0 \
    --discovery-token-ca-cert-hash sha256:103d7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5b1b6

什麼?忘記了?

可以用指令重新生成加入指令

$ kubeadm token create --print-join-command

出現 kubeadm join 指令之後,加上指明 cri-socket 就可以執行了

變成這樣

$ sudo kubeadm join 192.168.1.100:6443 
    --token cxxxxs.c4xxxxxxxxxxxxd0 \
    --discovery-token-ca-cert-hash sha256:103d7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5b1b6 \
    --cri-socket unix:///var/run/cri-dockerd.sock

記錄一下運作情形

$ kubeadm join 192.168.1.100:6443 
    --token cxxxxs.c4xxxxxxxxxxxxd0 \
    --discovery-token-ca-cert-hash sha256:103d7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5b1b6 \
    --cri-socket unix:///var/run/cri-dockerd.sock

[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

這樣就加入叢集了

重設整個叢集

如果整個叢集有其他問題,做爛了,可以用以下方法重新設定

進到每一台 node 裡面,利用 kubeadm reset 重置,記得代入 cri-socket

如下:

$ kubeadm reset -f --cri-socket unix:///var/run/cri-dockerd.sock

記錄一下運作情形

$ kubeadm reset -f --cri-socket unix:///var/run/cri-dockerd.sock

[preflight] Running pre-flight checks
W0507 02:43:32.160215    1264 removeetcdmember.go:106] [reset] No kubeadm config, using etcd pod spec to get data directory
[reset] Deleted contents of the etcd data directory: /var/lib/etcd
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
W0507 02:43:32.169757    1264 cleanupnode.go:134] [reset] Failed to evaluate the "/var/lib/kubelet" directory. Skipping its unmount and cleanup: lstat /var/lib/kubelet: no such file or directory
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]

The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d

The reset process does not reset or clean up iptables rules or IPVS tables.
If you wish to reset iptables, you must do so manually by using the "iptables" command.

If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.

The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.

它會提示你,有些防火牆規則並不會完全刪掉

可以刪掉 cni 資料夾來重置

$ rm -rf /etc/cni/net.d

對應文件:
https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-reset/

<Control plane 做> 測試檢查叢集

測試 Kubernetes 是否正常運作,
在 Control plane (控制平台) 裡可以用二個指令觀察一下:

取得所有的 Pods

kubectl get pods 指令取得 Pod,加上 -A 代表包含所有 namespace (命名空間)

以下指令就是取得所有的 Pods

$ kubectl get pods -A

取得所有的 pods

$ kubectl get pods -A

NAMESPACE      NAME                               READY   STATUS    RESTARTS   AGE
kube-flannel   kube-flannel-ds-8rtvc              1/1     Running   0          30s
kube-flannel   kube-flannel-ds-9w2vw              1/1     Running   0          30s
kube-flannel   kube-flannel-ds-jdndp              1/1     Running   0          30s
kube-system    coredns-5d78c9869d-df989           1/1     Running   0          4m20s
kube-system    coredns-5d78c9869d-s8ftg           1/1     Running   0          4m19s
kube-system    etcd-k8s-ctrl                      1/1     Running   0          4m35s
kube-system    kube-apiserver-k8s-ctrl            1/1     Running   0          4m33s
kube-system    kube-controller-manager-k8s-ctrl   1/1     Running   0          4m35s
kube-system    kube-proxy-2qrjj                   1/1     Running   0          4m19s
kube-system    kube-proxy-bpk94                   1/1     Running   0          3m51s
kube-system    kube-proxy-mgrjn                   1/1     Running   0          3m57s
kube-system    kube-scheduler-k8s-ctrl            1/1     Running   0          4m36s

你應該要看到:

  • kube-flannel 的若干個 Pod 為 Running
    (若是 Pending 或者 CrashLoopBackOff 可能要除錯)
  • kube-system (k8s 核心元件) 的二個 coredns 的 Pod 為 Running
    (若是 Pending 或者 CrashLoopBackOff 可能要除錯)
  • kube-system (k8s 核心元件) 的 etcdRunning
  • kube-system (k8s 核心元件) 的 kube-controller-manager 的 Pod 為 Running
  • kube-system (k8s 核心元件) 的 kube-apiserver 的 Pod 為 Running
  • kube-system (k8s 核心元件) 的 kube-scheduler 的 Pod 為 Running
  • kube-system (k8s 核心元件) 的若干個 kube-proxy 的 Pod 為 Running

當然,放在 kube-system 裡面的 Pod 屬於系統保留的,請勿更動修改。

取得所有 nodes (主機節點)

你可以用 kubectl get nodes -A 指令來取得所有運作的 nodes

$ kubectl get nodes -A

NAME        STATUS   ROLES           AGE     VERSION
k8s-ctrl    Ready    control-plane   4m40s   v1.27.1
k8s-node1   Ready    <none>          3m59s   v1.27.1
k8s-node2   Ready    <none>          3m53s   v1.27.1

你應該要看到你的叢集,三台都是 Ready

[教學] LibreNMS 串接 LINE 通知

在現代科技世界中,網路裝置監控與通知非常重要。LibreNMS 是一個開源的網路監控系統,可以用來監控網絡設備、伺服器…等。然而,對於一些使用者而言,LibreNMS 的通知設定可能會有一些小困難。我們將在這個系列文章中介紹幾種常用的通知方式:電子郵件、LINE、Telegram、GoogleChat…等。這些通知方式都可幫助使用者即時收到監視警報和報告,以便快速回應並保護他們的系統和網絡安全。

LibreNMS 系列文:

剛好工作會用到 LINE,所以把通知轉到 LINE 去,就讓我們看看要怎麼做吧!

抓下 Pull Request 的內容

目前截稿至今,目前還沒有人把 LINE 機器人通知功能的做進去,
小弟就順手貢獻程式碼,把這個功能加上 😎。

當然 LibreNMS 整套程式授權是 GPL,想當然爾貢獻的程式碼也是 GPL,歡迎大家使用。

只是官方還沒有允許 Pull Request 的內容,
如果覺得不錯,可以幫忙在原串留個言,加速系統演進。

https://github.com/librenms/librenms/pull/14802


也因為目前小弟貢獻的程式碼尚未被合併,預設這功能「沒有包含」在官方系統裡,
需要你手動抓檔案來補

檔案在此:
https://github.com/j796160836/librenms/blob/feature_line_messaging/LibreNMS/Alert/Transport/Linemessagingapi.php

按下 Raw 得到原始檔,然後另存新檔,存成 LineMessagingAPI.php

如果跟我一樣是使用 Docker 的話,
放在目錄中,修改 docker-compose.yml 把這個檔案用掛載的方式,
類似 Hot patch 的方式把它放進去

docker-compose.yml 的 LibreNMS 設定,裡頭的 volumes 區塊,加上一句:

- ./LineMessagingAPI.php:/opt/librenms/LibreNMS/Alert/Transport/Linemessagingapi.php

(注意大小寫!)

如果你是照個之前那篇文的方式架設的話,
變成類似底下的範例:

docker-compose.yml

version: '3.5'

services:
  web:
    image: jarischaefer/docker-librenms
    restart: always
    ports:
      - '80:80'
    volumes:
      - ./librenms_data/logs:/opt/librenms/logs
      - ./librenms_data/rrd:/opt/librenms/rrd
      # Add this line
      - ./LineMessagingAPI.php:/opt/librenms/LibreNMS/Alert/Transport/Linemessagingapi.php
    environment:
      APP_KEY: base64:NA......................................SdA=
      DB_HOST: librenms_database
      DB_USER: librenms
      DB_PASS: Tuq.........tai
      DB_NAME: librenms
      POLLERS: 16
      BASE_URL: http://192.168.1.2
      TZ: Asia/Taipei
    depends_on:
      - mysql
  mysql:
    image: mariadb:10.5
    container_name: librenms_database
    restart: always
    volumes:
      - ./librenms_data/mysql:/var/lib/mysql
      - ./LineMessagingAPI.php:/opt/librenms/LibreNMS/Alert/Transport/Linemessagingapi.ph
    environment:
      TZ: Asia/Taipei
      MYSQL_ROOT_PASSWORD: Cho.........lan
      MYSQL_USER: librenms
      MYSQL_PASSWORD: Tuq.........tai
      MYSQL_DATABASE: librenms

官方 docker 架設方式也雷同,就不贅述了。

設定 LINE 開發者帳號

1. 前往Line開發者網站並註冊帳戶

https://developers.line.biz/

使用您的真人帳號來進行註冊。

2. 新增一個 Channel (頻道)

  1. 如果你沒有 Provider (供應商),請先建立一個。

  1. 創建一個 Channel (頻道),選擇 Messaging API ,然後填寫表單。

一些必填欄位說明:

  • Channel type 頻道類型:Messaging API
  • Provider 供應商:(選擇您的 Provider (供應商))
  • Company or owner’s country or region 公司或擁有者的國家或地區:(選擇您的地區)
  • Channel name 頻道名稱:(預設它將是您的 LINE機器人的名稱,送出後無法編輯)
  • Channel description 頻道描述:(預設它將是您的 LINE 機器人的描述)
  • Category 類別:(選擇適當的類別)
  • Subcategory 子類別:(選擇適當的子類別)

然後按送出建立它。

  1. 到 Channel 的 "Messaging API" 頁籤,這裡列出了一些你需要注意的重要值。
  • Bot basic IDQR code 是您的 LINE 機器人的 ID 和 QR code。
  • Channel access token (long-lived),通行 token ,效力等同於密碼,這將在 LibreNMS 中使用,請妥善保管。

  1. 使用您的真實 LINE 帳號加你建立的 LINE機器人為好友。

3. 設置 webhook 以獲取「收件人ID」

這邊講的「收件人ID」是指,你未來希望系統要把訊息發送到哪裡
它可以是

  • 聊天群組(要抓取 groupID
  • 個人私訊(要抓取 userID

以下是獲取「收件人ID」的步驟。

使用以下 NodeJS 程式和 ngrok 轉送臨時 https 連線。
以下步驟是在 Mac 底下操作。Linux 也適用這些步驟。

LINE-bot-RecipientFetcher

抓取程式

git clone https://github.com/j796160836/LINE-bot-RecipientFetcher.git

切換到該資料夾

cd LINE-bot-RecipientFetcher

執行程式

$ node index.js

使用 ngrok 將該連接埠暴露到網路上

ngrok http 3000

到 Channel (頻道) 中的 "Messaging API" 頁籤,
將 Webhook URL 填寫 ngork 所產生的網址 https://<your ngrok domain>/webhook

4. 獲取「收件人ID」

如果您想讓 LINE 機器人向自己(或者目標發送對象)發送訊息,這是獲取 userID 的步驟。

  • 使用您的真實帳戶(或者目標發送對象)向您的 LINE 機器人發送訊息

範例資料:

{"type":"user","userId":"U527xxxxxxxxxxxxxxxxxxxxxxxxxc0ee"}

如果您想讓 LINE 機器人向一個群組發送訊息,這是獲取 groupID 的步驟。

  • 將您的LINE機器人添加到群組中
  • 使用您的真實帳戶在群組中發訊息

程式會把 groupID 印出來,這個就是收件人ID,請保管好。

範例資料:

{"type":"group","groupId":"Ce51xxxxxxxxxxxxxxxxxxxxxxxxxx6ef","userId":"U527xxxxxxxxxxxxxxxxxxxxxxxxxc0ee"} ```

LibreNMS 的通知設定

接下來回到 LibreNMS 繼續做設定。

1. 設定 Alert transport (通知管道)

Alerting > Alert Transports 頁面,新增一個 Alert transport (通知管道)。

  • Transport name 傳輸名稱:Line
  • Trsansport type 傳輸類型:Line Messanging API
  • Access token 存取權杖:(您的頻道存取權杖)
  • Recipient 收件人ID:_(填入剛剛抓的 userIDMARKDOWN_HASH2df121e268641afe58606b37a6e37a50MARKDOWNHASH )

2. 在 Alert rules (監控規則) 中掛上 Alert transport (通知管道)

Alerts > Alert rules 設定警告通知規則,

在想要通知的規則上按編輯,
(以預設通知 Device Down! Due to no ICMP response 為例)

Transports 的地方加上這個通知管道。

可以在 Alert rules 設定好通知的:

  • Max alert 通知數:最多要通知幾次
  • Delay 延遲:問題發生後,延遲多久再來通知,
    過濾掉時好時壞跳來跳去的情況
  • Interval 間隔:通知間隔,意指通知後隔多久再通知,該值會配合 Max alert 來使用。

例如:
Max alert: 3 / Delay: 30m / Interval: 5m
白話文就是:先延遲 30 分鐘再通知,通知共 3 次,每 5 分鐘通知一次

這邊可以依照需求來設定通知次數與頻繁度。

如果剛剛 Default Alert 有設定 ON 的話,應該所有規則都會出現才對。

測試

最後,你需要測試他們的通知設置是否正確。可以通過觸發警報或手動測試通知來完成這個步驟。

手動觸發測試

Alerts > Alert Transports 中,設定這個通知管道、通知方式。

就會收到測試訊息

以上,就是設定的所有內容,希望這個教學對您有幫助。

參考資料

[教學] 用 Gmail 來串接 LibreNMS 的 Email 通知

在現代科技世界中,網路裝置監控與通知非常重要。LibreNMS 是一個開源的網路監控系統,可以用來監控網絡設備、伺服器…等。然而,對於一些使用者而言,LibreNMS 的通知設定可能會有一些小困難。我們將在這個系列文章中介紹幾種常用的通知方式:電子郵件、LINE、Telegram、GoogleChat…等。這些通知方式都可幫助使用者即時收到監視警報和報告,以便快速回應並保護他們的系統和網絡安全。

LibreNMS 系列文:

這篇是利用 Gmail 來設定 電子郵件的通知方式

Gmail 建立應用程式密碼

首先,登入一個 Gmail 帳號,這個帳號未來會為系統寄件人。
你需要在 Google Gmail 中創建一個應用程式密碼。

到 Google 帳戶中的 「安全性」頁籤,

https://myaccount.google.com/security

在「登入 Google」的區段,有一個「應用程式密碼 App passwords」的選項

有件事情要先提醒,這必須要先開啟「兩步驟驗證 (Two-factor authentication (2FA))」,才會出現這個選項

它會重新驗證你的帳號,然後出現以下畫面:

Select the app and device you want to generate the app password for.

你可以直接選 Other (Custom name) 然後給定一個名字,按下產生後產生。

這邊要注意,「密碼只會出現一次」 請好好保存你的密碼。

LibreNMS 的通知設定

以下分為幾個步驟:

1. 設定發信方式

接下來,在 LibreNMS 的設定中,
到 Global settings 中,找到 Alert settings 選 Email options

打開 Enable email alerting 選項,
以下參考 Gmail 的 SMTP 的資訊設定,如果有修改,以官方文件為主。

  • Enable email alertingEnabled 開
  • From name:填入「寄件人」
    (例如:`"LibreNMS System")
  • From email address:填入「寄件人」的訊息
    (例如:"LibreNMS System" <[email protected]> ,這邊 E-mail 地址就填你剛剛設定的 Gmail 地址)
  • Use HTML emailsEnabled 開
  • How to deliver mailSMTP
  • SMTP Serversmtp.gmail.com
  • SMTP port setting587
  • EncryptionTLS
  • Auto TLS supportEnabled 開
  • SMTP authenticationEnabled 開
  • SMTP Auth username:填你剛剛設定的 Gmail 地址(例如: [email protected]
  • SMTP Auth password:填剛剛申請的「應用程式密碼」,不是你個人帳號的密碼唷

2. 建立通知管道 (Alert Transports)

然後,在 Alerts > Alert Transports 中,設定這個通知管道、通知方式。

按「Create alert transport」新增一個通知管道、通知方式

參數說明:

  • Transport name:取一個名字(例如:Email
  • Transport typeMail
  • Default Alert:是否為預設主要通知管道,這個依照你的需求來設定
  • Email:設定一個「收件人」,如果有發生警告,都會往他那邊寄信來通知
  • Include Graphs:是否包含圖片,這個保留預設 ON 即可

然後按「Save Transport」儲存

3. 在監控規則中掛上通知管道

最後在 Alerts > Alert rules 設定警告通知規則,

在想要通知的規則上按編輯,
(以預設通知 Device Down! Due to no ICMP response 為例)

Transports 的地方加上這個通知管道。

可以在 Alert rules 設定好通知的:

  • Max alert:最多要通知幾次
  • Delay:問題發生後,延遲多久再來通知,
    過濾掉時好時壞跳來跳去的情況
  • Interval:通知間隔,意指通知後隔多久再通知,該值會配合 Max alert 來使用。

例如:
Max alert: 3 / Delay: 30m / Interval: 5m
白話文就是:先延遲 30 分鐘再通知,通知共 3 次,每 5 分鐘通知一次

這邊可以依照需求來設定通知次數與頻繁度。

如果剛剛 Default Alert 有設定 ON 的話,應該所有規則都會出現才對。

測試

最後,你需要測試他們的通知設置是否正確。可以通過觸發警報或手動測試通知來完成這個步驟。

手動觸發測試

Alerts > Alert Transports 中,設定這個通知管道、通知方式。

旁邊有一個 打勾符號 可以按,按一下測試。
成功的話就會收到 Email 通知。

總結來說,這個教學文章向使用者展示了如何在 LibreNMS 中設置 Gmail 通知。這將使管理人能夠即時收到他們的監視警報和報告。這對於系統管理員和網絡工程師來說非常重要,因為它可以幫助他們及時處理問題,保護他們的系統和網絡的安全。

參考資料

[教學] 用 Docker 的 buildx 輕鬆多架構編譯 (multi-architecture build)

Docker 可以在程序層級上做為封裝系統環境的技術,並方便部署(或移轉)到別的機器上,
比起可以做到相同目標的 虛擬機 (VM) 比它輕量快速,近期成為熱門技術之一。
這麼好的技術還是有其相關限制的。例如: Docker image (映像檔) 仍受限於 CPU 架構 (architecture),
但標準的 Docker 的指令預設只能編譯一個 CPU 架構 (architecture)。

接下來要介紹算是某種新功能,新的 buildx 指令,讓 Docker 編譯製作 image (映像檔) 時,
能一次編譯各種你要的 CPU 架構的 image。


不知道您有沒有自己做過 Docker image 過?
我們複習一下標準的 Docker 編譯

原有的 docker build 流程

標準的 Docker 編譯如下:

$ docker build . -t MY_ACCOUNT/my-awesome-image:latest

相關說明:

  • . 點 (dot):代表當前目錄,也是預設名稱 Dockerfile 檔案名稱
  • -t 參數:給予 image 名字,如果要上傳到 Registry 倉庫的話,要改成對應名字
    例如: dockerHub 的格式 帳號 / 名稱,這個例子為: MY_ACCOUNT 帳號下的 my-awesome-image 套件,版本為 latest

再來就是用指令登入你的 dockerHub

$ docker login

輸入帳號與密碼

最後,上傳你的 image 到 Registry 倉庫

$ docker push MY_ACCOUNT/my-awesome-image:latest

但如今,宿主 (Host) 的 CPU 架構會因為你的使用伺服器環境的不同而不同
例如:你買了 Apple silicon (M1) 晶片,預設 CPU 架構跑 arm64
又例如:你想把你的 Docker 環境跑在樹莓派 (Raspberry Pi), CPU 架構跑 armv7 或者 arm64

各種情境,你可能會需要把你的 Docker 編譯模組換成能一次編輯多架構的。

新的 buildx 指令

要達成此目的,做法有二種,只講其中一種, docker buildx 指令

docker buildx 算是全新的指令,可以在官網去下載設定。

$ docker buildx version

查看是否有安裝,執行結果如下(我列出我的環境,你的可能會跟我不一樣):

$ docker version
Client:
 Cloud integration: v1.0.22
 Version:           20.10.13
 API version:       1.41
 Go version:        go1.16.15
 Git commit:        a224086
 Built:             Thu Mar 10 14:08:43 2022
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Desktop 4.6.0 (75818)
 Engine:
  Version:          20.10.13
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       906f57f
  Built:            Thu Mar 10 14:05:37 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.5.10
  GitCommit:        2a1d4dbdb2a1030dc5b01e96fb110a9d9f150ecc
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

查看有哪些架構可用

$ docker buildx inspect --bootstrap
Name:   mybuilder
Driver: docker-container

Nodes:
Name:      mybuilder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

以小弟的電腦來說,有這麼多,你也不一定要全部都使用。

我選了幾個常用的

  • linux/amd64:適合 x64 的環境(不管宿主主機是 linux 還是 Mac )
  • linux/arm64:適合 arm64 的環境(例如:Apple silicon (M1) 晶片)
  • linux/arm/v7:適合 arm 環境(例如:樹莓派)

接下來,我們建立一個 builder 並使用(初次安裝執行一次即可)

$ docker buildx create --use

(其實他是建立 builder 與 使用 builder 的簡化版,相關指令我列在下方)

建立 builder

$ docker buildx create --name mybuilder

使用該 builder

$ docker buildx use mybuilder

列出有哪些 builder

docker buildx ls

更新原有 build 指令

我們更新原有 build 指令

$ docker build . -t MY_ACCOUNT/my-awesome-image:latest

變成這樣

$ docker buildx build --load -t MY_ACCOUNT/my-awesome-image:latest --platform linux/amd64 .

(為了開發方便,我們先編譯一個平台架構)

效果二者一樣。

如果 Dockerfile 編好了,準備編譯並打包上傳 dockerhub 可以用以下指令:

$ docker buildx build --push -t MY_ACCOUNT/my-awesome-image:latest --platform linux/amd64,linux/arm64,linux/arm/v7 .

加個 --push 參數就可以在編譯完成的時候,一併做上傳。

瀏覽你的 dockerHub 帳號,會看到多種你選取的平台出現在 dockerHub 中。

小提醒:別使用 docker push 指令,截稿至今,它還不支援多架構映像檔上傳,它只會幫你上傳單一架構而已,
你也可以測試看看。

以上就是這次的內容,希望對大家有幫助。

參考資料