├── 2019
├── container
│ ├── day2.html
│ ├── day2.md
│ ├── day3.html
│ ├── day3.md
│ ├── day4.html
│ └── day4.md
├── device-plugin
│ ├── day23.html
│ ├── day23.md
│ ├── day24.html
│ ├── day24.md
│ ├── day25.html
│ ├── day25.md
│ ├── day26.html
│ └── day26.md
├── extension
│ ├── day27.html
│ ├── day27.md
│ ├── day28.html
│ └── day28.md
├── network
│ ├── day10.html
│ ├── day10.md
│ ├── day11.html
│ ├── day11.md
│ ├── day12.html
│ ├── day12.md
│ ├── day13.html
│ ├── day13.md
│ ├── day14.html
│ ├── day14.md
│ ├── day15.html
│ ├── day15.md
│ ├── day16.html
│ ├── day16.md
│ ├── day17.html
│ └── day17.md
├── overview
│ ├── day1.html
│ └── day1.md
├── runtime
│ ├── day5.html
│ ├── day5.md
│ ├── day6.html
│ ├── day6.md
│ ├── day7.html
│ ├── day7.md
│ ├── day8.html
│ ├── day8.md
│ ├── day9.html
│ └── day9.md
├── security
│ ├── day29.html
│ └── day29.md
├── storage
│ ├── day18.html
│ ├── day18.md
│ ├── day19.html
│ ├── day19.md
│ ├── day20.html
│ ├── day20.md
│ ├── day21.html
│ ├── day21.md
│ ├── day22.html
│ └── day22.md
└── summary
│ ├── day30.html
│ └── day30.md
├── 2020
├── application
│ ├── Day2.md
│ ├── Day3.md
│ ├── Day4.md
│ ├── day2.html
│ ├── day3.html
│ └── day4.html
├── cd
│ ├── day13.html
│ ├── day13.md
│ ├── day14.html
│ ├── day14.md
│ ├── day15.html
│ └── day15.md
├── ci
│ ├── day10.html
│ ├── day10.md
│ ├── day11.html
│ ├── day11.md
│ ├── day12.html
│ ├── day12.md
│ ├── day9.html
│ └── day9.md
├── gitops
│ ├── day16.html
│ ├── day16.md
│ ├── day17.html
│ ├── day17.md
│ ├── day18.html
│ └── day18.md
├── local
│ ├── Day5.md
│ ├── Day6.md
│ ├── Day7.md
│ ├── Day8.md
│ ├── day5.html
│ ├── day6.html
│ ├── day7.html
│ └── day8.html
├── overview
│ ├── day1.html
│ └── day1.md
├── plugin
│ ├── day26.html
│ ├── day26.md
│ ├── day27.html
│ ├── day27.md
│ ├── day28.html
│ └── day28.md
├── registry
│ ├── day19.html
│ ├── day19.md
│ ├── day20.html
│ ├── day20.md
│ ├── day21.html
│ ├── day21.md
│ ├── day22.html
│ └── day22.md
├── resources
│ └── day30.md
├── secret
│ ├── day23.html
│ ├── day23.md
│ ├── day24.html
│ ├── day24.md
│ ├── day25.html
│ └── day25.md
└── summary
│ ├── day29.html
│ └── day29.md
├── 2021
├── day1.html
├── day1.md
├── day10.html
├── day10.md
├── day11.html
├── day11.md
├── day12.html
├── day12.md
├── day13.html
├── day13.md
├── day14.html
├── day14.md
├── day15.html
├── day15.md
├── day16.html
├── day16.md
├── day17.html
├── day17.md
├── day18.html
├── day18.md
├── day19.html
├── day19.md
├── day2.html
├── day2.md
├── day20.html
├── day20.md
├── day21.html
├── day21.md
├── day22.html
├── day22.md
├── day23.html
├── day23.md
├── day24.html
├── day24.md
├── day25.html
├── day25.md
├── day26.html
├── day26.md
├── day27.html
├── day27.md
├── day28.html
├── day28.md
├── day29.html
├── day29.md
├── day3.html
├── day3.md
├── day30.html
├── day30.md
├── day4.html
├── day4.md
├── day5.html
├── day5.md
├── day6.html
├── day6.md
├── day7.html
├── day7.md
├── day8.html
├── day8.md
├── day9.html
├── day9.md
└── terraform
│ └── main.tf
├── .gitignore
├── CNAME
├── Makefile
├── README.md
├── SUMMARY.md
├── gitbook
├── fonts
│ └── fontawesome
│ │ ├── FontAwesome.otf
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.svg
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
├── gitbook-plugin-fontsettings
│ ├── fontsettings.js
│ └── website.css
├── gitbook-plugin-highlight
│ ├── ebook.css
│ └── website.css
├── gitbook-plugin-lunr
│ ├── lunr.min.js
│ └── search-lunr.js
├── gitbook-plugin-search
│ ├── lunr.min.js
│ ├── search-engine.js
│ ├── search.css
│ └── search.js
├── gitbook-plugin-sharing
│ └── buttons.js
├── gitbook.js
├── images
│ ├── apple-touch-icon-precomposed-152.png
│ └── favicon.ico
├── style.css
└── theme.js
├── gulpfile.js
├── index.html
├── package-lock.json
├── package.json
├── search_index.json
└── sitemap.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | yarn.lock
3 | .publish
4 | _book/*
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/2019/container/day4.md:
--------------------------------------------------------------------------------
1 | [Day4] 淺談 Container 實現原理, 以 Docker 為例(III)
2 | ==================================================
3 |
4 | > 本文同步刊登於 [hwchiu.com - 淺談 Container 設計原理(III)](https://www.hwchiu.com/container-design-iii.html)
5 |
6 | 2020 IT邦幫忙鐵人賽 Kubernetes 原理分析系列文章
7 |
8 | - [kubernetes 探討](https://ithelp.ithome.com.tw/articles/10215384/)
9 | - [Container & Open Container Initiative](https://ithelp.ithome.com.tw/articles/10216215/)
10 | - [Container Runtime Interface](https://ithelp.ithome.com.tw/articles/10218127)
11 | - [Container Network Interface](https://ithelp.ithome.com.tw/articles/10220626)
12 | - [Container Storage Interface](https://ithelp.ithome.com.tw/articles/10224183)
13 | - Device Plugin
14 | - Container Security
15 |
16 | 有興趣的讀者歡迎到我的網站 https://hwchiu.com 閱讀其他技術文章,有任何錯誤或是討論歡迎直接留言或寄信討論
17 |
18 | # 前言
19 |
20 | 前一天的文章中,我們探討了如何透過現有的工具來創造出滿足 `OCI` 標準的 `Container` 並且稍微介紹了一下 `Docker` 內的架構,理解一下 `Docker Client`, `Docker Engine`, `Containerd` 以及 `Containered-shim`
21 |
22 | 相對於前幾天都在觀察 `OCP` 以及 `Docker` 創建容器的過程,今天則是會更細部的針對底層資源進行研究,譬如 `Networking` 與 `Storage`.
23 |
24 | 在前述的文章中有提到`Linux` 環境中是透過了 `Namespace` 來提供各式各種不同資源隔離,而其中有兩個之後再 `kubernetes` 中也會頻繁出現的分別是 `Networking` 以及 `Storage`.
25 |
26 | 所以今天的文章就要來探討一些關於上述兩種資源是如何完成隔離化的。
27 |
28 | # Networking
29 | ## Namespace
30 | `Network` namespace 本身隔離了 `Network Stack`, 這意味包含了 `interface`, `ip address`, `iptagbles`, `route` 等各式各樣跟網路有關的資源都被隔離。
31 |
32 |
33 |
34 | 接下來我們可以做一個簡單的操作來看看,再操作上我們都會使用 `ip netns` 的指令來使用
35 |
36 | ```bash=
37 | #create network namespace ns1
38 | ip netns add ns1
39 | ##exec in ns1
40 | ip netns exec ns1 bash
41 | #check interface
42 | ifconfig -a
43 | ```
44 |
45 | 這時候你應該會看到類似下面的畫面。
46 |
47 | ```bash=
48 | lo: flags=8 mtu 65536
49 | loop txqueuelen 1000 (Local Loopback)
50 | RX packets 0 bytes 0 (0.0 B)
51 | RX errors 0 dropped 0 overruns 0 frame 0
52 | TX packets 0 bytes 0 (0.0 B)
53 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
54 | ```
55 |
56 | 因為該新創建的 `network namespace` 是完全空的,所以裡面除了最基本的 `loopback` 之外不會有任何其他的網卡。
57 |
58 | 此外,這時候前往 `/var/run/netns` 你會觀察到有一個名為 `ns1` 的檔案,上述`ip netns` 相關的指令則會根據這個檔案進行處理。
59 |
60 |
61 | # docker
62 | 接下來嘗試創建一個 `docker container`, 並且觀察看看是否有辦法透過 `ip netns` 的方式來觀察該 `container`.
63 |
64 | ```bash=
65 | sudo docker run -d hwchiu/netutils
66 | ```
67 |
68 | 這時候按照上述的方法去觀察
69 | ```bash=
70 | sudo ip netns ls
71 | sudo ls /var/run/netns
72 | ```
73 | 會發現完全沒有看到其他的資訊,依然只有先前創立的 `ns1`,原因是
74 | `docker` 創建 `network namespace` 後會將該檔案從 `/var/run/netns/` 中移除,所以導致沒有辦法用 `ip netns` 相關的指令去檢視。
75 |
76 | 但是其實這些檔案一直都在系統之中,畢竟系統要運行,資訊也必須存在,所以我們可以透過一些方法把該檔案重新找回來,最後重新放回 `/var/run/netns` 中,最後就可以透過 `ip netns` 的方式來操作。
77 |
78 | 0. 先取得待觀察之 `container` 的 `containerID`
79 | 2. 先取得該 `Container Process` 於 `Host` 上的 `PID`
80 | 3. 前往該 `PID` 於 `/proc/xxxx/ns` 底下找到所有的 `namespace`
81 | 4. 將上述發現的 `namespace` 建立連結到 `/var/run/ns`
82 | 5. 可以使用 `ip netns` 等指令來操作
83 |
84 | ```bash=
85 | sudo docker ps
86 | ```
87 |
88 | ```bash
89 | hwchiu@k8s-dev:/var/run$ sudo docker ps
90 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
91 | 2be547d81b69 hwchiu/netutils "/bin/bash ./entrypo…" 6 minutes ago Up 6 minutes priceless_cray
92 | ```
93 |
94 | ```bash=
95 | container_id=2be547d81b69
96 | pid=$(sudo docker inspect -f '{{.State.Pid}}' ${container_id})
97 | sudo ln -sfT /proc/$pid/ns/net /var/run/netns/${container_id}
98 | sudo ls /proc/19265/ns
99 | sudo ls /proc/19265/ns/
100 | sudo ip netns ls
101 | sudo ip netns exec ${container_id} ifconfig
102 | ```
103 |
104 | 這時候你應該會看到類似下面的輸出
105 |
106 | ```bash=
107 | eth0: flags=4163 mtu 1500
108 | inet 172.18.0.2 netmask 255.255.0.0 broadcast 172.18.255.255
109 | ether 02:42:ac:12:00:02 txqueuelen 0 (Ethernet)
110 | RX packets 14 bytes 1116 (1.1 KB)
111 | RX errors 0 dropped 0 overruns 0 frame 0
112 | TX packets 0 bytes 0 (0.0 B)
113 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
114 |
115 | lo: flags=73 mtu 65536
116 | inet 127.0.0.1 netmask 255.0.0.0
117 | loop txqueuelen 1000 (Local Loopback)
118 | RX packets 0 bytes 0 (0.0 B)
119 | RX errors 0 dropped 0 overruns 0 frame 0
120 | TX packets 0 bytes 0 (0.0 B)
121 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
122 |
123 | ```
124 |
125 | 這時候可以嘗試使用 `docker` 系列的指令來觀察看到的資訊是否一致
126 |
127 | ```bash=
128 | sudo docker exec -it ${container_id} bash
129 | ifconfig
130 | ```
131 |
132 | 理論上我們先前透過 `ip netns` 操作的對象就是該 `container` 的 `network namespace`, 所以看到的資訊必須要一致且一樣的。
133 |
134 | 除了這個基本概念之外,在 `docker` 與 `kubernetes` 裡面都有一個網路選項是 `net=hostnetwork`, 這個的意思就是`請不要創建額外的 network namespace`,請使用與 `host` 相同的 `network namespace`. 這個情物下,你就可以在 `container` 內外都看到相同的網路資源 `NIC, Route, IP, IPtables..etc`
135 |
136 |
137 | # Storage
138 |
139 | 常常使用 `docker` 的人一定對於 `volume mount` 這個概念不陌生,不論是 `docker volume` 更上層的抽象化或是單純運行時期掛載上去的 `docker run -v xxx:xxx` 等都能夠用來解決部分的 `Container` 內的需要的儲存問題
140 |
141 | 於 `linux` 底下,通常我們都會使用 `mount` 來處理檔案的掛載問題
142 |
143 | 首先我們先啟動一個簡單的 `Container` 來掛載一個外部的資料夾到 `Container` 內使用
144 |
145 | ```bash=
146 | sudo docker run -d -v /home/:/outside-home hwchiu/netutils
147 | ```
148 |
149 | 這時候透過本機的指令去檢查 `host mount namespace` 會完全看不到跟 `/home` 有關的任何資料
150 |
151 | ```bash=
152 | mount | grep home
153 | sudo cat /proc/self/mountinfo | grep home
154 | ```
155 |
156 | 這是因為該容器的 `mount` 相關資訊也都被 `mount namespace` 隔離了,就如同 `networking` 一樣,我們其實也可以在該 `container process` 的相關檔案中找到該資訊
157 | ```bash=
158 | #change the id to your container id
159 | container_id=b9428568d3ff
160 | pid=$(sudo docker inspect -f '{{.State.Pid}}' ${container_id})
161 | sudo cat /proc/$pid/mountinfo | grep home
162 | sudo docker exec $container_id cat /proc/self/mountinfo | grep home
163 | ```
164 |
165 | 這時候就會看到相關的資訊,譬如
166 |
167 | ```bash=
168 | 478 459 8:1 /home /outside-home rw,relatime - ext4 /dev/sda1 rw,data=ordered
169 | ```
170 |
171 | 反過來說,如果今天你知道目標的 `ContainerID`,你就可以透過類似的方式找到當初創建該 `Container` 時設定的相關 `Mount` 資訊
172 |
173 | `Mount` 相關的概念非常龐大也非常複雜,我非常推薦有興趣的可以把[這篇文章](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt)看完。
174 | 除了基本的 `mount` 的使用方法外,其實在 `kubernetes` 裡面還有一個 `mount propagation` 的設定可以使用,但是這個設定其實本身背後的概念並不簡單,一般的使用者基本上都不會碰到這個設定,但是一旦遇到的時候就會需要了。
175 |
176 | 此外對於 `Container` 來說,我們也可以觀察到其實 `Contianer` 本身不太去管到底怎麼跟外界的 `Storage` 串連的, 一切就是依賴 `Mount Namespace` 將這些儲存空間掛進去,至於你要採用什麼檔案系統,背後有什麼備援機制,都是 `host` 本身去管理, `Container` 本身不處理。
177 |
178 |
179 | # Summary
180 | 今天透過一些基本的 `linux` 工具帶大家稍微過了一下 `docker container` 底下關於 `networking` 以及 `storage` 的一些冷知識,跟大家分享平常在使用 `docker container` 時到底背後有哪些機制撐起了這複雜的 `container` 系統,同時藉由理解這些資訊,未來想要做更進一步的除錯也都可以有其他的工作來幫忙輔助ㄡ
181 |
182 | 除了 `networking` 以及 `mount` 外,還有其他的如 `user`, `uts` 等不同的 `namespace` 幫忙隔離其餘的系統資源以完成所謂的 `container` 虛擬化。
183 | 有興趣的人都可以針對其他的資源去研究看看要如何再 `host` 端存取相關的資訊並且學習更多底層的實作。
184 |
185 | # Reference
186 | - http://man7.org/linux/man-pages/man5/proc.5.html
187 |
--------------------------------------------------------------------------------
/2019/device-plugin/day23.md:
--------------------------------------------------------------------------------
1 | [Day23] Device Plugin
2 | =====================
3 |
4 | > 本文同步刊登於 [hwchiu.com - Device Plugin](https://www.hwchiu.com/k8s-device-plugin.html)
5 |
6 | 2020 IT邦幫忙鐵人賽 Kubernetes 原理分析系列文章
7 |
8 | - [kubernetes 探討](https://ithelp.ithome.com.tw/articles/10215384/)
9 | - [Container & Open Container Initiative](https://ithelp.ithome.com.tw/articles/10216215)
10 | - [Container Runtime Interface](https://ithelp.ithome.com.tw/articles/10218127)
11 | - [Container Network Interface](https://ithelp.ithome.com.tw/articles/10220626)
12 | - [Container Storage Interface](https://ithelp.ithome.com.tw/articles/10224183)
13 | - Device Plugin
14 |
15 |
16 | 有興趣的讀者歡迎到我的網站 https://hwchiu.com 閱讀其他技術文章,有任何錯誤或是討論歡迎直接留言或寄信討論
17 |
18 | # 前言
19 |
20 | 探討完畢運算,網路,儲存三大資源的標準介面 **CRI, CNI, CSI** 之後,接下來要探討的是另外一個可以擴充 **kubernetes** 本身功能的框架 **device plugin**。
21 |
22 | 這邊接下來都會使用 **框架** 來形容,是因為 **device plugin** 本身就是 **kubernetes** 自行實作且專屬於 **kubernetes** 使用的。 不同於上述的 **CRI,CNI,CSI** 這類型的標準其本身是獨立設計,不把 **kubernetes** 當作唯一的使用者,因此設計上就會盡可能彈性與抽象。
23 |
24 | 而 **device plugin** 框架作為 **kubernetes** 單獨使用,因此之後介紹的開發過程以及運作過程就會與 **kubernetes**,準確的說 **kubelet** 息息相關
25 |
26 | # 開發理由
27 |
28 | **device plugin** 開發出來的理由與之前提過的各種標準雷同,都是為了將程式碼分離,提供第三方解決方案提供者更靈活與彈性的開發流程,同時如果可以避開 **kubernetes** 本身邏輯的程式碼,專注於自身解決方案去開發的話又更好不過了。
29 |
30 | 早期的 **kubernetes** 針對運算資源的分配時的資源選擇,只有 **CPU** 以及 **Memory** 兩個最基本的硬體資源可以使用。然而除了這兩種資源之外,過往的各種系統應用場景也發展出了根據不同特性與需求的 **device**。 譬如
31 | 1. GPU
32 | 2. FPGA
33 | 3. Smart NIC
34 | 4. ...等
35 |
36 | 為了能夠提供一個更加方便的方式讓這些 **device** 被加入到 **kubernetes** 的操作邏輯中且能夠讓運算資源**Pod** 可以根據輕易地使用這些 **device**,更重要的是這些第三方解決方案提供者能夠用最簡單的方式來完成這一連串的概念。 於是 **device plugin** 框架因應而生。
37 |
38 | 該框架希望能夠讓第三方解決方案提供者專注於下列的功能就好,其餘與 **kubernetes** 的整合與使用就交由框架本身處理。
39 | 1. 確認相關 **device** 的資訊,譬如數量以及狀態
40 | 2. 讓該 **device** 有能夠被 **containers** 存取
41 | 3. 定期確認這些 **devices** 的資訊,譬如是否可用,是否運作正常
42 |
43 | 對於使用者來說,希望可以讓整個使用流程簡單且輕鬆
44 | 1. 部署 **device plugin** 解決方案的 **Pod** 去處理這些狀態
45 | 譬如 kubectl create -f http://vendor.com/device-plugin-daemonset.yaml
46 | 2. 部署運算資源的時候,可以透過 **node selector** 的方式去描述該運算資源需要多少個 **device** 來使用
47 | 譬如每個 **node** 上面都會被打上 **vendor-domain/vendor-device** 類似的標籤,這時候就可以透過這些標籤告訴 **scheduler** 要如何挑選符合資格的節點並且透過 **device plugin** 來掛載相關的資源到 **Pod** 裡面。
48 |
49 | # 使用情境
50 | 什麼情況下使用者會想要使用 **device plugin** ? 官方列舉了三個情境
51 | 1. 想要使用特別的 **device** 裝置是官方沒有內建支援的,譬如 **GPU**, **InfiniBand**, **FPGE** 等
52 | 2. 可以再不撰寫任何 **kubernetes** 相關程式碼的情況下直接使用這些 **devices**
53 | 3. 希望有一個一致且相容的解決方案可以讓使用者於不同的 **kubernetes** 叢集中都能夠順利的使用這些跟硬體有關的 **devices**。
54 |
55 | 我認為這三種情境就已經充分描述的所有可能使用的情境,事實上大多數人的會使用這些的確是因為業務需求,使用情境而需要這些特別的 **devices**。
56 |
57 |
58 |
59 | # 現存解決方案
60 |
61 | 如同前述的標準一樣,通常負責維護的相關文件中都會記載目前有被收錄的解決方案,當然也有許多沒有被收錄的,因為這些紀錄並不是官方主動去收集,而是解決方案必須要自己發送請求將自己的解決方案加入到官方的文件之中,所以有些解決方案沒有申請的話就不會顯示於官方資料中。
62 |
63 | 根據目前[官方文件](https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/#examples) 的記載,目前有被收錄的 **device plugin** 如下
64 |
65 | - The AMD GPU device plugin
66 | - The Intel device plugins for Intel GPU, FPGA and QuickAssist devices
67 | - The KubeVirt device plugins for hardware-assisted virtualization
68 | - The NVIDIA GPU device plugin
69 | - The NVIDIA GPU device plugin for Container-Optimized OS
70 | - The RDMA device plugin
71 | - The Solarflare device plugin
72 | - The SR-IOV Network device plugin
73 | - The Xilinx FPGA device plugins for Xilinx FPGA devices
74 |
75 | 看過去就是滿滿特殊用途的 **device**,其中我覺得 **GPU** 應該是近期最熱門的選項,隨者 **AI** 科技的發展,愈來愈多人踏入該領域並且嘗試各式各樣的操作,而 **GPU** 作為強力計算的基本需求,同時考慮到現在 **kubernetes** 這麼熱門,是否有辦法把這兩者結合打造出一個基於 **AI** 開發或是應用環境的 **kubernetes** 叢集也是一個有趣的方向。
76 |
77 | 之後的篇章會挑幾個有趣的 **plugin** 跟大家介紹一下其用途及用法。
78 |
79 |
80 | # 使用流程
81 |
82 | 接下來根據[官方開發文件](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/device-plugin.md#vendor-story),我們可以看一下一個使用情境以及用法會長怎麼樣,
83 |
84 | ## 開發者
85 |
86 | 對於開發者來說,基於 **gRPC** 的介面去實現相關功能(詳細的部分下篇文章會探討),譬如說
87 |
88 | ```golang=
89 | service DevicePlugin {
90 | // returns a stream of []Device
91 | rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}
92 | rpc Allocate(AllocateRequest) returns (AllocateResponse) {}
93 | }
94 | ```
95 |
96 | 開發者基於這些介面去開發一個應用程式,該程式滿足上述的介面的功能,譬如回報當前 **device** 的狀態,根據需求去分配可用的 **device**。
97 |
98 | 接者開發者將該應用程式部署到 **kubernetes** 叢集之中,並且透過 **unix socket** 的方式與 **kubelet** 溝通,該路徑通常是 **/var/lib/kubelet/device-plugins/**,這個路徑跟之前研究 **CSI** 時候所觀察到的路徑非常類似,都是給 **kubelet** 使用的。
99 |
100 | 一但 **device plugin** 部署到節點之中,主動透過 gRPC 通知 **kubelet** 目前有新的 **device plugin** 安裝到系統中,並且準備註冊,一但這個步驟完畢後,整個 kubernetes 叢集中就知道這個 **device plugin** 的存在,並且使用者就可以開始使用了。
101 |
102 | 舉例來說,假設該開發者開了一個 **hwchiu/test-dev** 的 **device**,則下來都可以透過 **kubelet** 去查看每個節點上 **hwchiu/test-dev** 此 **device** 的總共數量以及當前可用數量。
103 |
104 | ## 使用者
105 |
106 | 對於使用者來說,使用起來的方式非常簡單,就是於 **Pod** 格式中透過 **resources** 的方式去定義需要什麼 **device** 且需要多少個
107 |
108 | ```yaml=
109 | apiVersion: v1
110 | kind: Pod
111 | metadata:
112 | name: hwchiu-test-dev-pod
113 | spec:
114 | containers:
115 | - name: test-pod
116 | image: hwchiu/netutils:latest
117 | workingDir: /root
118 | resources:
119 | limits:
120 | hwchiu/test-dev: 1 # requesting a devivce
121 | ```
122 |
123 | 當使用者提交上述的資源描述到 kubernetes 之中時,kubernetes scheduler 搭配 kubelet 就會去詢問所有節點上的 **device plugin**,透過上述的 **gRPC** 介面去詢問當前有多少個可用 **device** 並且找出所有符合該需求的節點。
124 | 當 **schedukler** 選定節點之後,就會再度透過該節點的 **kubelet** 透過 **gRPC** 去戳相關的 **device plugin** 應用程式去創立一個資源供目標的 **Pod** 使用。
125 |
126 | 整理一下流程就是:
127 | 1. Pod資源請求
128 | 2. Scheduler 搭配 kubelet 去尋找所有符合需求的 節點
129 | 3. Scheduler 選定一個節點部署
130 | 4. 該節點的 kubelet 呼叫 **device plugin** 解決方案去分配需求數量的 **device plugin** 供 **Pod** 使用。
131 |
132 | 當然當 **pod** 結束之後會有相對應的函式可以被呼叫來進行資源回收。
133 |
134 | # Summary
135 |
136 | 本篇文章簡單簡述了一下關於 **Device Plugin** 的概念,並且簡單敘述了一下工作流程,
137 | 下一篇文章會針對 **device plugin** 本身的運作原理跟架構進行更仔細的討論。
138 |
139 | # 參考
140 | - https://medium.com/kokster/kubernetes-mount-propagation-5306c36a4a2d
141 | - https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/device-plugin.md
142 |
--------------------------------------------------------------------------------
/2019/overview/day1.md:
--------------------------------------------------------------------------------
1 | [Day1] 淺談 Kubernetes 設計原理
2 | =============================
3 |
4 | > 本文同步刊登於 [hwchiu.com - 淺談 Kubernetes 設計原理](https://www.hwchiu.com/kubernetes-design.html)
5 |
6 | 2020 IT邦幫忙鐵人賽 Kubernetes 原理分析系列文章
7 |
8 | - [kubernetes 探討](https://ithelp.ithome.com.tw/articles/10215384/)
9 | - [Container & Open Container Initiative](https://ithelp.ithome.com.tw/articles/10216215/)
10 | - [Container Runtime Interface](https://ithelp.ithome.com.tw/articles/10218127)
11 | - [Container Network Interface](https://ithelp.ithome.com.tw/articles/10220626)
12 | - [Container Storage Interface](https://ithelp.ithome.com.tw/articles/10224183)
13 | - Device Plugin
14 | - Container Security
15 |
16 | 有興趣的讀者歡迎到我的網站 https://hwchiu.com 閱讀其他技術文章,有任何錯誤或是討論歡迎直接留言或寄信討論
17 |
18 | # 前言
19 | `Kubernetes` 作為近年來討論度最高的容器管理平台,從自行架設,使用公有雲相關服務甚至到尋求第三方廠商解決方案都已經是日常可見的作法。
20 |
21 | 使用場景來看,各式各樣的場景都在思考與評估是否有機會將 `kubernetes` 納入其應用範圍,從架設服務器提供服務,配合 GPU 進行大量運算使用甚至將 `kubernetes` 與 5G網路產業結合。 各式各樣的需求不停的發出,而 `kubernetes` 是否能夠滿足這些所有的需求則是一個需要好好思考的問題。
22 |
23 | 為了評估到底 `kubernetes` 能不能適用於各種使用情境,我們必須先知道什麼是
24 | `kubernetes` 的極限,我認為透過學習其實作原理與設計理念能夠提供一個基本的能力去評估到底 `kubernetes` 能不能滿足所需。
25 |
26 | 接下來的 30 天內,我會針對 `kubernetes` 內幾個最大的特點也是所有使用情境最需要考慮的幾個方向來探討,如下
27 |
28 | - 運算單元
29 | - 網路架設與連線
30 | - 儲存空間
31 | - 其他特殊裝置
32 |
33 | 藉由學習這些不同面向功能的實作原理與設計開發理念,我們都能夠有更好的立足點去評估到底 `kubernetes` 是否能夠滿足目前所需,甚至說若需要進行第三方開發改善時,該怎麼下手。
34 |
35 |
36 | # 架構
37 |
38 | `Kubernetes` 作為一個開放原始碼的專案,其所有原始碼都可以在 [Github](https://github.com/kubernetes/kubernetes) 看到,同時也可以在看來自世界各地的使用者與開發者如何合作一起開發這個巨大的專案。
39 |
40 | 對於一個成熟的開源軟體來說,通常都會有所謂的 Release 版本週期,並不是每個開發的新功能都可以很準時的被安排在下一個版本釋出,同時也意味有時候希望某些新功能可以順利的使用,都要等到下個 Release 週期釋出,否則就要自己透過版本控制的方法去 `build/compile` 來使用最新的功能。
41 |
42 | 基於以上的軟體開發流程情況,可以試想一下一個情境。
43 | 今天某開發者開發了一個有趣的功能,吸引很多使用者都想要趕快嚐鮮使用,然後基於上述的理由,該功能要先經過整體的程式碼評估與測試,最後合併。接者還要等上一段時間產生一個正式公開的建置版本,這一切跑完可能都是數天,數週,甚至數個月後的事情。
44 |
45 | 而對於 `Kubernetes` 來說,所謂的 `容器管理平台` 其涉略的領域實在太多,對於 `kubernetes` 的眾多開發者來說,要能夠完全掌握這些不同領域的技術與概念其實也是很困難的事情。
46 |
47 | 舉例來說
48 | 今天有一個熱心的開發者想要讓 `Kubernetes` 支援 `GPU` 的運算,於是提交了相關的程式碼改動, 如果 `kubernetes` 的維護者對於 `GPU` 的運作原理不夠掌握是否有辦法幫他進行程式碼的審查?
49 |
50 | 同時加上 `kubernetes` `release` 週期的規則,會使得這些由來自世界各地貢獻者的結晶沒有辦法很即時的被一般使用者與測試。
51 |
52 | 整個運作流程如下圖
53 | 
54 |
55 |
56 | 為了使得整體的開發流程更加順暢,如果能夠針對架構比較需要彈性的功能進行架構改造,將介面與實作給獨立出來各自運作。此架構中, `kubernetes` 只要設計介面,並且專注於本身與介面的溝通與整合,第三方的開發者則是專注於開發應用,只要該應用符合介面標準即可。
57 |
58 | 這種狀況下,第三方的開發者可以自行決定其軟體/產品的 `release` 週期,不需要與 `kubernetes` 本身掛鉤。不但能夠讓整個平台的擴充功能開發更佳流暢,同時使用者也可以更方便地去嘗試各種不同的底層實現。
59 |
60 |
61 | 改良後的架構可參考下圖,`kubernetes` 與其他各自的解決方案可以有自己的開發週期
62 | 與流程,彼此之間透過事先定義好的介面進行溝通,如此一來就可以提升整體開發的
63 | 流暢度。
64 | 
65 |
66 | 接下來的29天,會帶領讀者一起探討這些介面的設計以及各種不同應用的實作。
67 | 包含了
68 | - 基於運算單元的 `CRI (Container Runtime Interface)`,
69 | - 提供平台容器網路連接能力的 `CNI(Container Network Interface)`,
70 | - 提供儲存能力供容器使用的 `CSI (Container Storage Interface)`
71 | - 以及可以掛載各式各樣系統裝置的 `Device Plugin`.
72 |
--------------------------------------------------------------------------------
/2019/summary/day30.md:
--------------------------------------------------------------------------------
1 | [Day30] Summary
2 | ===============
3 |
4 | 2020 IT邦幫忙鐵人賽 Kubernetes 原理分析系列文章
5 |
6 | - [kubernetes 探討](https://ithelp.ithome.com.tw/articles/10215384/)
7 | - [Container & Open Container Initiative](https://ithelp.ithome.com.tw/articles/10216215)
8 | - [Container Runtime Interface](https://ithelp.ithome.com.tw/articles/10218127)
9 | - [Container Network Interface](https://ithelp.ithome.com.tw/articles/10220626)
10 | - [Container Storage Interface](https://ithelp.ithome.com.tw/articles/10224183)
11 | - [Device Plugin](https://ithelp.ithome.com.tw/articles/10226060)
12 |
13 |
14 | 有興趣的讀者歡迎到我的網站 https://hwchiu.com 閱讀其他技術文章,有任何錯誤或是討論歡迎直接留言或寄信討論
15 |
16 | # 感想
17 |
18 | 本篇為鐵人賽的最後一篇,本篇基本上沒有什麼要探討的了,主要是回顧一下這三十天以來的所有文章以及想要跟社群大眾分享的重點
19 |
20 | 從2012左右開始引起一波虛擬化熱潮的 OpenStack 開始,人們開始討論架構的改變,虛擬化帶來的優缺點,基於虛擬機器產生的部署環境開始落地於各種場景之中,不論是研究,測試或是真的商用.
21 |
22 | 然而在OpenStack出現之前,其實虛擬化的技術早就蓬勃發展,譬如 chroot, jail, lxc 甚至各式各樣的虛擬機器解決方案.
23 |
24 | 而 OpenStack 的出現,帶來的不單純只是一個虛擬化的範例,而是一整個解決方案,裡面滿滿的不同元件,基於不同的功能一起搭建出完整的解決方案。
25 | 我認為也是這一點才使得整個專案可以如此吸人目光與吸引熱潮,還在世界各地的使用者都思緒這如何使用這個 虛擬化叢集管理工具來管理大量的虛擬機器並且提供更有效的管理效率,良好的服務品質
26 |
27 | 然而軟體世界就是有趣,永遠都無法滿足眾人,隨著 docker 專案的興起,基於容器的虛擬化解決方案也開始吸引了一波目光,容器與虛擬機器的比較從來沒有停過,輕巧快速簡單等特色吸引了大眾的眼球。
28 |
29 | 就如同 OpenStack 帶來的叢集管理功能,容器方面是否也有基於多節點的管理工具?
30 | Docker Swam, Mesos 等諸多的專案都為了這些方向發展,直到 kubernetes 的出現,我個人認為其幾乎打趴了先前的所有管理工具,幾乎一統了基於容器的叢集管理平台解決方案。
31 |
32 | 綜觀發展歷程,解決方案一直推陳出新,虛擬機器與容器共存,不同平台互相整合已提供更完善的解決方案。
33 | 對於使用者來說,看到的反而是一直出現的新專案,每個專案發展的速度比大部分使用學習速度還要快上超級多,根本追都追不上。
34 |
35 | 但是仔細想想,底層的容器技術早就存在已久,從隔離的 **namespace**, 網路的 **iptables/ipvs**, 儲存系統的 **mount,file system**, 系統的 **device** 等技術早就行之有年甚至成熟。
36 | 對於 **kubernetes** 來說就是如何把這些存在的功能與平台進行整合,讓使用者使用起來更為方便。
37 |
38 | 我自己的想法是除了學習新功能如何使用之外,其實多花點時間瞭解所有底層的運作原理並不會吃虧,目前看起來都還是過去那些基礎功能不停的轉換使用,而這些東西也是最為苦悶但是卻最為重要的基底。
39 |
40 | 一旦瞭解更多的底層原理,其實看到任何的新功能的時候都可以開始思考,這個功能可能怎麼完成的? 如果是我來做我會怎麼做,接者開始驗證自己的想法,藉由這種思考後學習的辦法其實更可以幫助你理解其實做的概念與理由。
41 |
42 | 很多時候實作上不一定會有註解,甚至文件都只是描述其功能,沒有描述為什麼,這時候如果有相關的經驗與概念,對於思考上都會有很大的幫助。
43 |
44 | 最後再次重申,學習底層原理,學習閱讀原始碼,都能夠為你帶來很大的好處與進步,這些知識也許短時間之內不能幫你解決問題,但就如同歷久彌新般的內功,你遲早會愛上他的>
45 |
46 |
47 | # 相關資料
48 |
49 | 這次 30 天的所有文章都放到 [GitHub](https://github.com/hwchiu/ithome-2020ironman) 上面了,
50 |
51 | # 社群推廣
52 |
53 | 最後跟來跟大家推廣一下台灣在地社群, [Cloud Native Taiwan User Group](https://www.facebook.com/groups/cloudnative.tw/)
54 |
55 | 每個月都會定期有 meetup 來探討各式各樣的議題,有從使用者角度出發的,也有從底層開發出發的,歡迎大家有興趣可以加入社群一起討論。
56 |
57 | [Telegram](https://t.me/cntug)
58 |
59 | [Meetup](https://www.meetup.com/CloudNative-Taiwan/)
60 |
61 | [每次 Meetup 投影片紀錄](https://github.com/cloud-native-taiwan/meetups)
62 |
63 | [演講相關範例程式碼與相關文章](https://github.com/cloud-native-taiwan/kourse)
64 |
65 | [徵才相關](https://github.com/cloud-native-taiwan/jobs)
66 |
--------------------------------------------------------------------------------
/2020/application/Day2.md:
--------------------------------------------------------------------------------
1 | Day 2 - Kubernetes 物件管理
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 所有接觸及使用過 Kuberntees 的玩家一定都知道如何透過 Yaml 來管理 Kubernetes 內滿滿的物件與應用程式
11 |
12 | Kubernetes 內的眾多資源,譬如 Deployment/Pod/ConfigMap/Ingress/Service... 等全部都可以透過 YAML 的方式來管理及部署
13 |
14 | 我認為這也是最簡單且最直覺的作法,官方的所有文件都是基於 YAML 為範例來介紹如何玩轉 Kubernetes
15 |
16 | 舉例來說,下列的 [官方文件](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/) 則分享了五種管理 Kubernetes 物件的方式,這五種方式其實分成兩大類, Imperative 與 Declarative 兩種概念
17 |
18 | 根據這兩種概念底下又可以分成不同的實作方式,其中最簡單的一個問題就是,你能不能說出 `kubectl apply` 以及 `kubectl create` 這兩者的差異
19 |
20 | 想要理解這兩者差異,非常推薦閱讀官方文件 [Kubernetes Object Management](https://kubernetes.io/docs/concepts/overview/working-with-objects/object-management/) 來學習,裡面有非常詳細的介紹與比較
21 |
22 |
23 |
24 | 回到本文來,到底什麼是應用程式? 筆者認為一個應用程式則是包含了該服務會用到的所有物件資源,譬如 Deployment + Service + ConfigMap
25 |
26 | 因此下文所講述的應用程式其實背後含義就是多個 Kubernetes 物件
27 |
28 | 對於一個應用程式來說,如果要將其部署到 Kuberentes 裡面,我認為有下列的議題可以探討
29 |
30 | 1. 該應用程式是否需要散播給其他使用者使用,其他使用者屬於相同單位還是世界任意使用者
31 | 2. 該應用程式是否需要版本控制來提供不同版本的需求?
32 | 3. 該應用程式是否會需要不同環境而有不同的設定?
33 |
34 |
35 |
36 | ### 分享與散佈
37 |
38 | 今天一個應用程式如果有需要給外部使用,譬如可以透過類似 `apt install` 的方式來外部安裝,這種情況下我們會需要一些方式來包裝
39 |
40 | 應用程式,所謂的包裝除了原本所需要的眾多 Kubernetes 物件外,可能也會牽扯到下列議題
41 |
42 | 1. 文件系統,如何讓外部使用者可以清楚地知道該怎麼使用,以及使用上有什麼要注意的部分
43 | 2. 依賴性系統,如果該應用程式本身又依賴其他應用程式,這種情況下要如何讓使用者可以順利安裝全部所需的資源物件
44 | 3. 一套發布系統,可以讓開發者跟使用者都方便去上傳/下載這些應用程式
45 |
46 | ### 版本控制
47 |
48 | 版本控制的議題相對單純,今天一個程式開發本身就會有版本的變化,其所需要的 Kuberentes 物件資源是不是也會有版本的差異?
49 |
50 | 譬如 1.0.0 版本需要 ConfigMap 而 2.0.0 則移除了這個限制,所以今天 Kubernetes 的應用程式,本身是否也可以有版本控制的概念來控
51 |
52 | 管,這樣使用上時就可以更有彈性的去選擇所需要的版本
53 |
54 | ### 客製化
55 |
56 | 客製化的議題也是單純,對於 Kubernetes 的物件資源來說,針對不同的使用環境,會需要不同的設定檔案,譬如同樣一個 Kubernetes
57 |
58 | Service, 有些環境覺得使用 ClusterIP 就可以,有些環境會需要使用 NodePort 來存取,甚至有些會使用 LoadBalancer
59 |
60 | 所以今天應用程式是否有辦法讓使用者很方便的去進行客製化的設定,最簡單的做法也許就是一個環境一大包設定檔案,但是這樣建置起
61 |
62 | 來非常沒有效率,同時維護上也會有眾多問題
63 |
64 |
65 |
66 | ## 解決方案
67 |
68 | 看了上面這些議題之後,接下來要思考的就是到底有什麼方式可以處理上述這些議題?
69 |
70 | 如果使用最原生的 Yaml ,是否能完成上述的要求?
71 |
72 | 這個答案我認為可以,雖然麻煩但是有效。
73 |
74 | 事實上也滿多服務都透過 Yaml 配上 Git 的方式來散佈其應用程式,使用者根據不同的 URL 來安裝不同的 Yaml 檔案,同時如果有需求就
75 |
76 | 自己直接修改該 Yaml 來滿足,譬如一個知名的 CNI Flannel 就是透過這種方式,將 Yaml 的內容全部寫到一個檔案中,然後透過 Github
77 |
78 | 來維護不同版本,使用者根據不同的 URL 來安裝不同版本的 Flannel。
79 |
80 | 如果不想要走原生 Yaml 檔案,那可以怎麼做?
81 |
82 | 相關的開源專案滿多的,我認為主流有兩套,分別是 Helm 以及 Kustomize,這兩套解決方法都用不同的設計思維來讓解決上述問題(部
83 |
84 | 分,非全部),就我個人認為,目前除了 Helm 以外,還沒有任何一套開源專案可以滿足 `分享與散佈` 的需求,然而 Helm 於某些情況下又
85 |
86 | 受到大家的厭惡,輾轉改用 Kustomize 來部署,這中間的取捨沒有絕對,完全是根據應用場景選擇
87 |
88 | 整個 Kubernetes 生態系的概念也是這樣,沒有一個絕對的解決方案,每個方案都有適合自己的應用場景,最困難的點一直都是如何分析
89 |
90 | 自己的使用情境並且找到合適的解決方案
91 |
92 | 整個系列文中我們都會使用 Helm 作為我們的應用程式安裝解決方案,如果對 Kustomize 有興趣的朋友,歡迎自己閱讀官方文件學習怎
93 |
94 | 麼使用
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/2020/application/Day3.md:
--------------------------------------------------------------------------------
1 | Day 3 - Helm 介紹
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 上篇文章探討了關於 Kubernetes 內應用程式的包裝方式,提到了一些相關的議題,包含了如何散佈安裝檔案,同時支援不同版本的選擇,以及客製化的選項。
11 |
12 | 因此本篇我們將來介紹 Helm3 這個工具,同時也會介紹 Helm 是如何實現上述所提過的各種議題
13 |
14 |
15 |
16 | ## Helm
17 |
18 | 根據官方敘述, Helm 是一個管理 Kubernetes 應用程式的套件,透過 Helm Charts 這套系統,可以幫助開發者打包,安裝,升級相關的 Kubernetes 應用程式。
19 |
20 | 此外, Helm Charts 本身也被設計得很容易去創造,版本控制,分享以及發佈,所以透過 Helm Charts 就可以避免到處 Copy-and-Paste 各式各樣的 Yaml。
21 |
22 | Helm 本身也是一個開源專案,而且也是 [CNCF](https://cncf.io/) 內的畢業專案,目前是由 [Helm 社群](https://github.com/helm/community) 進行維護
23 |
24 | > Helm helps you manage Kubernetes applications — Helm Charts help you define, install, and upgrade even the most complex Kubernetes application.
25 | >
26 | > Charts are easy to create, version, share, and publish — so start using Helm and stop the copy-and-paste.
27 | >
28 | > Helm is a graduated project in the [CNCF](https://cncf.io/) and is maintained by the [Helm community](https://github.com/helm/community).
29 |
30 |
31 |
32 |
33 |
34 | Helm 的架構概念非常簡單,就是將整包 Kubernetes 的所有資源物件再疊加一層抽象層,這個抽象層是給 Helm 工具使用的,Helm 的工具會有自己的方式去解讀這個抽象層,最後產生出最後的 Kubernetes 資源物件然後安裝到 Kubernetes 裡面
35 |
36 | ## Purpose
37 |
38 | Helm 將所有 Kubernetes 的應用程式都統稱為 `Charts`.
39 |
40 | Helm 的工具會將這些 Charts 打包成 **tgz** 的檔案,接下來可以可以透過 Helm Charts Server 的方式將這個 **tgz** 的檔案給散佈出去,讓其
41 |
42 | 他使用者可以方便地取得這些已經打包好的應用程式(Charts)。
43 |
44 | 此外, Helm 的工具也可以直接針對這些 Charts 所描述的應用程式去安裝到/解除於 Kubernetes 叢集中
45 |
46 | 對於安裝到 Kubernetes 中的應用程式, Helm 稱其為 `Release`
47 |
48 | 而 Chart 到 Release 中間有一個客製化的概念,稱為 Config,透過這個 config 可以產生出適應不同環境的 Kubernetes Yaml
49 |
50 |
51 |
52 | 這三者如下圖所示,每個 Charts 搭配不同環境的設定檔案最後會產生出一個唯一的 Release 物件,而該物件就代表者該應用程式於 Kubernetes 內的實體
53 |
54 | 
55 |
56 |
57 |
58 |
59 |
60 | ## 客製化
61 |
62 | 為了滿足客製化的需求,希望開發者可以簡單的設計 Charts,使用者又可以簡單的客製化使用,這部分 Helm 採用的是 Go Template 的方式來進行 Yaml 的客製化,舉例來說
63 |
64 | 下面一個常見的 Service Yaml 檔案,內容全部都寫死
65 |
66 | ```
67 | apiVersion: v1
68 | kind: Service
69 | metadata:
70 | name: example
71 | labels:
72 | app: example
73 | spec:
74 | type: ClusterIP
75 | ports:
76 | - port: 80
77 | targetPort: http
78 | protocol: TCP
79 | name: http
80 | selector:
81 | app.kubernetes.io/name: example
82 | app.kubernetes.io/instance: example
83 | ```
84 |
85 | 這種情況下使用者就沒有辦法客製化需求,譬如需要的 Port(80),或是不同類型 (ClusterIP/NodePort)
86 |
87 | Helm 針對這種情況引入了 Go Template,使得 Yaml 檔案的樣子可能會變成如下圖
88 |
89 | ```yaml=
90 | apiVersion: v1
91 | kind: Service
92 | metadata:
93 | name: {{ include "example.fullname" . }}
94 | labels:
95 | {{ include "example.labels" . | indent 4 }}
96 | spec:
97 | type: {{ .Values.service.type }}
98 | ports:
99 | - port: {{ .Values.service.port }}
100 | targetPort: http
101 | protocol: TCP
102 | name: http
103 | selector:
104 | app.kubernetes.io/name: {{ include "example.name" . }}
105 | app.kubernetes.io/instance: {{ .Release.Name }}
106 | ```
107 |
108 | 可以看到上述的採用大量的 `{{}}` 的格式來進行變數的替換,使用者再使用該 Charts 的時候會對上述的變數進行設定,而這些變數最後在渲染這些 Template 檔案的時候就會給替換掉最後產生出真正的 Yaml 檔案。
109 |
110 | 舉例來說,第一個使用者安裝的時候輸入 `service.type: ClusterIP` 就會產生出一個使用 `ClusterIP` 的 Service,而若輸入的是 `service.type:NodePort` 則會產生使用 `NodePort` 的 Service.
111 |
112 |
113 |
114 | 為了方便使用者去使用,開發者設計的時候可以準備一套預設值放到一個名為 `values.yaml` 的檔案裡面,使用者可以直接修改該檔案或是使用別的檔案來替換所有的變數
115 |
116 |
117 |
118 | 這種 Go Template 的方式的確可以讓 Yaml 變得很彈性,可以讓使用者針對不同情境傳入不同的數值,但是我認為他也帶來的更多的複雜性,因為這些 Template 的用法十分多元,從基本的變數替換,到 FOR 迴圈, IF 判斷條件等都可以使用。
119 | 對於 Helm 用法不理解的人初次看到這些滿滿被 `{{}}` 入侵的 Yaml加上一堆不確定是幹嘛用的關鍵字,其實會難以入手,沒有花更多時間去理解的情況下,可能就只會使用而沒有辦法成為一個開發者去設計一個好的 Helm Chart
120 |
121 |
122 |
123 | ## 散播與發佈
124 |
125 | 當開發者準備好一個 Helm Charts 的檔案時候,就可以透過打包的方式將其上傳到官方或是自行維護的 Helm Chart 伺服器
126 |
127 | 一個使用範例如下(參考自官網)
128 |
129 | ```bash
130 | $ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
131 | $ helm search repo stable
132 | NAME CHART VERSION APP VERSION DESCRIPTION
133 | stable/acs-engine-autoscaler 2.2.2 2.1.1 DEPRECATED Scales worker nodes within agent pools
134 | stable/aerospike 0.2.8 v4.5.0.5 A Helm chart for Aerospike in Kubernetes
135 | stable/airflow 4.1.0 1.10.4 Airflow is a platform to programmatically autho...
136 | stable/ambassador 4.1.0 0.81.0 A Helm chart for Datawire Ambassador
137 | ...
138 |
139 | ```
140 |
141 | 上述指令代表的意思是我想要將 `https://kubernetes-charts.storage.googleapis.com/` 這個 Helm Charts 的伺服器加入到本地 `Helm` 指令的來源之一,並且嘗試搜尋上面任何有 `stable` 字眼的 Helm Chart
142 |
143 |
144 |
145 | 下列指令則可以嘗試安裝 `stable/mysql` 這個 Helm Chart 到 Kubernetes 中,產生的 Release 名稱為 `smiling-penguin`
146 |
147 | 這邊要注意的是 Helm 本身會需要存取 Kubernetes 叢集,所以也是使用 KUBECONFIG 等方式來設定存取權限
148 |
149 | ```bash
150 | $ helm install stable/mysql --generate-name
151 | Released smiling-penguin
152 | ```
153 |
154 |
155 |
156 | 最後可以透過 `Helm ls` 的指令來觀看目前安裝於叢集內的 Helm Release.
157 |
158 | ```bash
159 | $ helm ls
160 | NAME VERSION UPDATED STATUS CHART
161 | smiling-penguin 1 Wed Sep 28 12:59:46 2016 DEPLOYED mysql-0.1.0
162 | ```
163 |
164 |
165 |
166 | ## Helm v2 v.s Helm v3
167 |
168 | Helm 目前流通的版本有 Helm v2 以及 Helm v3,使用起來差別不會非常誇張,但是如果是新上手的朋友強烈建議直接上 Helm v3,而不要使用 Helm v2,否則後來還要處理更新搬移的問題。
169 |
170 | 官方網站就有專門一個頁面在介紹如何從 Helm2 搬移至 Helm3, [Migrating Helm v2 to v3](https://helm.sh/docs/topics/v2_v3_migration/), 有興趣的人可以點進去看更多詳細的介紹。
171 |
172 | 下面來列一下 [v3 以及 v2 最大的差異](https://v3.helm.sh/docs/faq/#changes-since-helm-2)
173 |
174 | 1. Tiller 的移除,過往使用 Helm v2 的時候,還要在系統內先行安裝一個叫做 Tiller 的伺服器,同時也要對其設定一些權限,安裝起來麻煩,同時也有潛在的安全性問題。 Helm v3 基本上整個架構變得更乾淨,只需要一個 Helm 指令即可
175 | 2. Helm Chart 裡面相關的 apiVersion 需要跳號,從 v1 跳到 v2,才會宣告該 Helm Chart 是屬於 Helm v3.
176 | 3. 更新應用程式的策略, v3 使用的是三方比對來進行測試,將會使用 `過往狀態`, `當前運作狀態` 以及 `期望狀態` 來比對,最後產生更新後的內容
177 | 4. OCI 的支援,這個是我覺得最有趣的功能,未來 Helm Chart 打包後的格式可以遵循 OCI (Open Contaianer Initiative) 的格式,這意味者我們未來將有機會使用 Container Registry 來存放 Helm Chart, 只需要一個伺服器就可以同時滿足 Container Image 以及 Helm Chart,如果有興趣的人可以嘗試使用 Harbor 這套 Contaienr Registry 的解決方案來體驗看看這個功能
178 |
179 | > 想要知道更多關於 OCI 的介紹,可以參考這篇[文章](https://www.hwchiu.com/container-design-i.html)
180 |
181 | 5. Helm 一些子指令的新增與移除
182 |
183 |
184 |
185 | 基本上修改的細部內容非常多,有興趣的建議參考上述官方連結去看看修改細節,可以更加瞭解 Helm3.
186 |
187 |
188 |
189 |
--------------------------------------------------------------------------------
/2020/cd/day13.md:
--------------------------------------------------------------------------------
1 | Day13 - CD 系統的選擇議題
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 前面幾篇文章我們在探討 CI 與 Kubernetes 的整合,當 CI 完成,一切準備就緒後,下一件事情就是 CD,如何將開發者修改後的結果透過 pipeline 系統給推入到 Kubernetes 叢集中
11 |
12 |
13 |
14 | 這過程中有非常多的議題可以探討,舉例來說
15 |
16 | 1. 要使用 Pipeline 系統加上客製化腳本來部署,來是使用專門處理 CD 過程的軟體
17 | 2. 要用什麼工具來管理 Kubernetes 應用程式,對於不同環境所需要的客製化參數,要如何準備並且部署到遠方 Kubernetes
18 |
19 | 3. 要如何實現藍綠部署,金絲雀部署等
20 | 4. 如果環境中有機密資訊,譬如資料庫密碼等,要如何於 CD 過程中準備與部署
21 |
22 |
23 |
24 | 上述每個問題的坑都很深,我們接下來的文章會盡量探討每個層面的細節以及有什麼樣的開源軟體可以處理。
25 |
26 |
27 |
28 | # CNCF 技術雷達
29 |
30 | 本篇文章我們先來探討第一個問題,到底系統該怎麼選擇? 我們先來看看由 `CNCF End User Techonlogy Radar` 所發佈的 [CD 調查報告](https://radar.cncf.io/2020-06-continuous-delivery), 其中我們擷取一張重點圖片即可
31 |
32 | > 想看完整報告的解析版本可以參考[CNCF Continuous Delivery 使用者調查報告](https://www.hwchiu.com/cncf-tech-radar-cd.html)
33 |
34 | 
35 |
36 | 這張圖片是根據 CNCF 的使用者廠商投票回報,大家在 CD 的過程中會使用哪些工具,對這些工具是否推薦大家去使用
37 |
38 | 雷達圖片由內到外,代表推薦程度,愈靠近圓心代表推薦程度愈高
39 |
40 |
41 |
42 | ## 應用工具包裝與部署
43 |
44 | 首先,雷達圖片中有三個工具在描述上述的問題 (2),分別是 `Helm`, `Kustomize`,`jsonnet`,剛好推薦信心也是按照這個排序
45 |
46 | 最多廠商選擇使用 `Helm` ,再來是 `Kustomize` 以及 `jsonnet`。
47 |
48 | 我個人的經驗會根據情況使用 `Helm` 以及 `Kustomize`,比較不會使用 `jsonnet`,覺得帶來的效益跟並不是很大,
49 |
50 |
51 |
52 | ## 部署平台/策略選擇
53 |
54 | 再來上圖中剩下的技術都跟 CD 部署有關,其中 `Flux` 以及 `ArgoCD` 這兩個主要是主打 GitOps 的部署工具,本身沒有任何流水線的設計,完完全全就是針對部署去設計的,之後也會有章節再探討 GitOps 的概念與示範。
55 |
56 | 剩下的平台基本是都有提供 Pipeline 系統來處理,這部分有開源軟體,也有 SaaS 軟體,這之中包含了
57 |
58 | 1. CircleCI
59 | 2. GitLab
60 | 3. Jenkins
61 | 4. Jenkins X
62 | 5. Github Action
63 | 6. TeamCity
64 | 7. TravisCI
65 |
66 |
67 |
68 | 從使用者廠商回報的結果來看, CircleCI 以及 Gitlab 比較有明確的共識,推薦大家使用,其他的內容包含
69 |
70 | 1. Github Action 擁有完全正面的回饋,只是正式使用的數量還不夠多
71 |
72 | 2. Jenkins 則是一面倒,擁有數量不少的推薦數量,但是也有最高票的強烈不推薦票
73 |
74 | 眾多人的意見表示,對舊有系統來說 Jenkins 已經運行的很好了,但是對於全新的系統會願意嘗試不同的系統,而非使用 Jenkins。
75 |
76 |
77 |
78 | 所以針對 (1) 到底該怎麼選擇? 這部分我認為目前有兩個主流,一個就是透過 Pipeline 系統直接與 Kubernetes 叢集互動,另外一個則是透過 GItOps 的概念讓 Kubernetes 叢集自己更新,不仰賴額外的 Pipeline 系統。
79 |
80 | 接下來我們這兩種概念都會去探討,並且介紹這兩種概念下可能的部署流程會長怎樣。
81 |
82 |
83 |
84 | # 部署策略
85 |
86 | 這部分要探討的主要是部署過程中,你要如何將新的應用部署到生產環境,同時對系統以及使用者造成的影響最少,這部分有不少的流派在跑,譬如說
87 |
88 | 1. Recreate
89 | 這是個最簡單的策略,將舊版本全部移除,接者部署新版本。這種策略下的 downtime 取決於舊版本移除的時間以及新版本的部署時間
90 |
91 | 2. Ramped
92 | 透過 one by one 的替換策略,每次都會部署一個新版本的實體,透過 load-balancer 確認該新版本實體可以接受到網路流量且正常運作後,就會把舊版本的一份實體移除,反覆執行直到舊版本全部結束。
93 |
94 | 3. Blue/Green
95 | 相對於 Ramped 部署, BG 部署則是一口氣部署全部的新版本實體,譬如 3 份副本,部署完畢且測試完成後,一口氣將所有流量導向新版本,並且移除舊版本。
96 |
97 | 4. Canary
98 | Canary 強調的是逐步切換的概念,首先一口氣部署全部的新版本實體,接下來透過 load-balancer 的方式與權重的設定,慢慢的將流量從舊版本導向新版本,譬如 90%:10% -> 80%:20% -> 50%:50% -> 10%:90% -> 0%:100% 這樣的進展
99 |
100 | 5. A/B testing
101 | 這種部署策略更大的應用是商業上的判斷,最常見的就是針對不同使用者給予不同的介面,譬如 Facebook 每次升級新版本的時候,都會有一部分的使用者開始使用新版本,而剩下的依然使用舊版本。其運作邏輯跟上述的 Canary 部署雷同。
102 |
103 | 6. Shadow
104 | 這個版本的部署也是新部署版本的全部實體,接下來針對所有流向舊版本的流量都複製一份,將其送到新版本去跑,當一切都沒有問題後才會移除舊版本。
105 |
106 |
107 |
108 | 更多詳細的介紹可以參閱這篇文章 [Six Strategies for Applications Deployment](https://thenewstack.io/deployment-strategies/)
109 |
110 | 實際上這些策略跟你使用的 CD 工具會有很大的關係,礙於每個工具的技術與架構,並不是上述所有策略都可以輕鬆的於任何架構中實現
111 |
112 |
113 |
114 | # 機密資料控管
115 |
116 | 最後一個要探討的問題就是機密資料管理,舉例來說,今天要部署一款新的應用程式到 Kuberntes 叢集中,而該應用程式需要知道資料庫的帳號密碼,假設今天使用的是 `Helm` 的方式來部署。
117 |
118 | 雖然 Helm 有提供 `--set`, `values.yaml` 的方式來客製化內容,但是要如何在 CD 的過程中取得這些機密資料並且部署到 Kubernetes 內,同時又不希望有任何的地方可以看到這些機密資料的明碼。
119 |
120 | 這部分之後的章節會再來仔細探討相關議題以及一些解決方案
121 |
122 |
--------------------------------------------------------------------------------
/2020/cd/day14.md:
--------------------------------------------------------------------------------
1 | Day 14 - CD 與 Kubernetes 的整合
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 上篇文章中我們探討了 CD 過程的各種議題,而本篇文章則會開始探討 CD 與 Kubernetes 的部署整合
11 |
12 | 這邊要特別強調的是 CI 跟 CD 兩件事情本來就不需要一定在一起,最簡單的情況下就是將 CI 與 CD 兩個步驟整合到同一個 pipeline 系統
13 |
14 | 上。但是有時候會希望透過手動部署,但是部署中間的過程希望自動化,所以會透過手動觸發 CD 的流程來達成自動部署。
15 |
16 |
17 |
18 | 此外, CI 與 CD 使用的流水線系統也不一定要用同一套系統,就如同前一篇文章提到專門針對 CD 這個步驟去列出相關的工具。
19 |
20 | 以下將會列出四種用法,這四種用法可以分成兩大類
21 |
22 | 1. Push Mode
23 | 2. Pull Mode
24 |
25 | 其中 Push Mode 的概念是由我們的 CD Pipeline 主動將新的應用程式推到遠方的 Kubernetes Cluster 內
26 |
27 | 然而 Pull Mode 的概念是由 Kuberentes 主動去更新,藉由監聽遠方目標的變化來確保是否要自動更新版本
28 |
29 |
30 |
31 | # CI/CD pipeline (Push)
32 |
33 | 
34 |
35 |
36 |
37 | 第一個是我認為最直接且直觀,我們把 CI/CD 兩個流程都放到同一個 Pipeline 系統內,其設計上也相對簡單
38 |
39 | 1. 當 CI 流程結束後,接下來就跑下個步驟,這個步驟包含
40 | a. 準備相關執行檔案
41 | b. 透過相關工具部署到遠方的 Kubernetes
42 | 2. 這種架構下,因為要存取遠方的 kubernetes,也是會需要將 KUBECONFIG 這個檔案放到 Pipeline 系統中,所以使用上要特別注意
43 | 安全性的問題,避免別人存取到這個 KUBECONFIG,否則攻擊者可以控制你的 Kubernetes 叢集
44 |
45 |
46 |
47 | # 人員觸發 (Push)
48 |
49 | 
50 |
51 |
52 |
53 | 這種架構下,我們將 CI pipeline 與 CD pipeline 給分開執行,這兩套 pipeline 要不要使用同一套系統無所謂,至少 Job 是分開的。
54 |
55 | 叢集管理員或是其他有權限的人可以透過直接執行當前的 `CD pipeline` 來觸發自動化部屬。這種的好處在於,對於一些正式的生產環境
56 |
57 | 下,太過於自動的部署不一定是完全好的,有時候會需要一些人為介入的確認,確認一切都沒有問題後才會繼續執行自動部署。
58 |
59 | 因此這個架構下可能的一個流程是
60 |
61 | 1. 透過 CI pipeline 通過測試以及產生出最後要使用的 Image 檔案
62 | 2. 部署團隊與 PM 等經過確認,公告更新時間後在手動觸發自動部署的工作來完成部署
63 | 3. 如同前面部署,這邊也會需要將 Kubernetes 存取所需要的 KUBECONFIG 放到 CD pipeline 內,所以也是有安全性的問題需要注意
64 |
65 |
66 |
67 | # Container Image 觸發 (Push)
68 |
69 | 
70 |
71 |
72 |
73 | 這是另外一種不同的架構,我們將人為觸發的部分提供了一個新的選擇,當 Container Registry 本身發現有新版本的 Container Image 更新時,會透過不同的方式通知遠方的 CD pipeline 去觸發自動更新。
74 |
75 | 這個使用方法會依賴你使用的 Container Registry 是否有支援這種的架構,譬如 Harbor 這個開源專案就有支援,當 image 更新後可以透過 webhook 的方式將訊息打到遠方。而遠方的 CD pipeline 如果也有這種機制可以透過 webhook 來觸發的話,就可以實作上面的機制。
76 |
77 | 由於是透過 container registry 所觸發的工作,所以這種架構可以支援更多的觸發方式,譬如管理員今天緊急需求,手動推動新版的 Container Image 到遠方 Registry,這樣也能夠觸發
78 |
79 | 因為跟前述架構完全類似,所以 KUBECONFIG 也是會放到環境之中,必須要有安全性的考量。
80 |
81 | # Pull Mode
82 |
83 | 
84 |
85 |
86 |
87 | 最後我們來看另外一種不同的架構,這種架構下我們就不會從 Pipeline 系統中主動地將新版應用程式推到 Kubernetes 中,相反的是我們的 Kubernetes 內會有一個 Controller,這個 Controller 會自己去判斷是否要更新這些應用程式,譬如說當遠方的 Contaienr Image 有新版更新時,就會自動抓取新的 Image 並且更新到系統之中。
88 |
89 | 這種架構下,我們不需要一個 CD Piepline 來維護這些事情,此外,因為沒有主動與 Kubernetes 溝通的需求,所以也不需要把 KUBECONFIG 給放到外部系統 (CD Pipeline) 中,算是減少了一個可能的安全性隱憂。
90 |
91 | 當然這種架構下,整個部署的流程都必須依賴 Controller 的邏輯來處理,如果今天有任何客製化的需求就變成全部都讓 Controller 來處理,可能要自行修改開源軟體,或是依賴對方更新,相較於完全使用 CD Pipeline 處理來說,彈性會比較低,擴充性也比較低,同時整個架構的極限都會被侷限在 Controller 本身的能力。
92 |
93 |
94 |
95 | 最後要說的是,以上介紹的架構沒有一個是完美的,都只是一個參考架構,真正適合的架構還是取決於使用者團隊,透過理解不同部署方
96 |
97 | 式所帶來的優缺點,評估哪些優勢我團隊需要,哪些缺點是團隊可以接受,不可以接受,最後綜合評量後取捨出一套適合團隊工作的方式。
98 |
99 |
--------------------------------------------------------------------------------
/2020/cd/day15.md:
--------------------------------------------------------------------------------
1 | Day15 - CD 之 Pull Mode 介紹: Keel
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 上篇文章中,我們探討了不同類型的部署架構,今天我們就針對最後一種 Pull 的方式來進行一個介紹,同時使用開源專案 keel 來展示一
11 |
12 | 下這種模式下的操作過程與結果
13 |
14 |
15 |
16 | 本文中的圖片都節錄自 [Keel官網](https://github.com/keel-hq/keel)
17 |
18 | # 介紹
19 |
20 | [Keel](https://github.com/keel-hq/keel) 的官網介紹如下
21 |
22 | > # Keel - automated Kubernetes deployments for the rest of us
23 |
24 |
25 |
26 | Keel 是一款 CD 部署的工具,其實作方式除了我們介紹的 Pull Mode 之外,他也支援 Push Mode 的方式,讓 Container Registry 主動通知 Keel 去進行自動部署。
27 |
28 |
29 |
30 | 下圖是一個最快理解 Keel 的運作流程,該圖片有五個步驟,分別是
31 |
32 | 1. 修改程式碼推到 Github
33 | 2. 透過 CI pipeline 來產生最後的 Container Image,並且把 Container Image 給推到遠方 Registry
34 | 3. Container Registry 知道有新版出現後,透過 relay 的方式把 web hook 的資訊往下傳遞
35 | 4. 當 Webhook 最終到達 Keel 的 Controller 後, Keel 根據設定來準備更新相關資源
36 | 5. 將差異性更新到 Kubernetes 內
37 |
38 | 
39 |
40 | 上述的運作方式跟我們前篇提到的 Pull-Mode 不太一樣,因為還是透過 webhook 的方式主動通知 Keel 去更新,但是 Keel 本身也有提供別的機制來實現不同的架構,如同其官方內的文章介紹
41 |
42 | >Polling
43 |
44 | Since only the owners of docker registries can control webhooks - it's often convenient to use polling. Be aware that registries can be rate limited so it's a good practice to set up reasonable polling intervals. While configuration for each provider can be slightly different - each provider has to accept several polling parameters:
45 |
46 | 如圖上篇文章所說,不是每個 container registry 都能去控管 web hooks 的架構,我們等等的示範中會使用 docker registry 配上 Polling 的機制來實現這種稍微被動一點的更新
47 |
48 | 此外,相對於 Push mode, Pull 則是透過定期詢問的方式去確認有沒有新版本,因此更新的速度上可能會比 webhook 還來得慢一點。
49 |
50 |
51 |
52 | 下圖是比較完整的架構,用來敘述 Keel 整個專案的架構
53 |
54 | 
55 |
56 |
57 |
58 | 整個架構圖非常簡單,首先右邊代表的是 Keel Controller 以及控管的 Kubernetes Cluster,其中可以 Keel 下方還有 Helm 的標誌,這意
59 |
60 | 味者 Keel 對於應用程式可以支援原生的 Yaml 也可以支援用 Helm 控管的應用程式
61 |
62 |
63 |
64 | 左邊有三個框架,最上面代表的是 KEEL 支援的 Kubernetes 版本,不論是官方原生, Rancher 或者 Openshift 都支援。
65 |
66 | 下面則是所支援的 Container Registry 版本,譬如是 Quay, Harbor, Docker 或是其他公有雲的 Cloud Registry。
67 |
68 | 最下面則是一些通知系統,包含 Slack, Mattermost, Hipchat 等,此外 keel 還可以支援審核機制,當要部署的時候會發通知到 slack 等系統,需要有人按下同意後,才會繼續執行後續的動作。
69 |
70 | 有更多的興趣可以參閱[官方網站](https://keel.sh/docs/#introduction)
71 |
72 |
73 |
74 | # 安裝
75 |
76 | 安裝方面提供兩種做法,可以透過 `helm` 去安裝或是直接透過 `kubectl` 安裝原生 yaml 檔案
77 |
78 | ```bash
79 | $ helm repo add keel https://charts.keel.sh
80 | "keel" has been added to your repositories
81 | $ helm repo update
82 | Hang tight while we grab the latest from your chart repositories...
83 | ...Successfully got an update from the "keel" chart repository
84 | Update Complete. ⎈Happy Helming!⎈
85 | $ helm upgrade --install keel --namespace=kube-system keel/keel
86 | Release "keel" does not exist. Installing it now.
87 | NAME: keel
88 | LAST DEPLOYED: Sun Sep 13 03:28:06 2020
89 | NAMESPACE: kube-system
90 | STATUS: deployed
91 | REVISION: 1
92 | TEST SUITE: None
93 | NOTES:
94 | 1. The keel is getting provisioned in your cluster. After a few minutes, you can run the following to verify.
95 |
96 | To verify that keel has started, run:
97 |
98 | kubectl --namespace=kube-system get pods -l "app=keel"
99 | ```
100 |
101 | 到這邊完畢我們就將 Keel Controller 安裝到 Kubernetes 叢集內了,接下來就來試試看如何使用 Keel 來完成自動部署
102 |
103 | # 示範
104 |
105 | 接下來的示範流程如下
106 |
107 | 1. 透過 Deployment 準備一個自己準備的 Container Image
108 | 2. 讓 Keel 幫忙部署該應用程式
109 | 3. 手動於別的畫面更新 Container Image
110 | 4. 觀察 Keel 的 log 以及 Kubernetes 狀況,確認該 container 有更新
111 |
112 |
113 |
114 | 首先,因為 Keel 本身沒有額外的 CRD 去告訴 Keel 到底哪些應用程式想要被 Keel 控管,因此控制的方式就是在應用程式的 Yaml 內增加 label,然後 Keel 的 controller 就會去監聽所有有設定這些規則的應用程式,再根據應用程式的內容來決定如何更新
115 |
116 | 下面是一個簡單的 deployment 的範例,該範例中我們於 metadata.labels 裡面增加兩個關於 keel 的敘述
117 |
118 | ```yaml
119 | apiVersion: apps/v1
120 | kind: Deployment
121 | metadata:
122 | name: ithome
123 | namespace: default
124 | labels:
125 | name: "ithome"
126 | keel.sh/policy: all
127 | keel.sh/trigger: poll
128 | spec:
129 | replicas: 3
130 | selector:
131 | matchLabels:
132 | app: ithome
133 | template:
134 | metadata:
135 | name: ithome
136 | labels:
137 | app: ithome
138 | spec:
139 | containers:
140 | - image: hwchiu/netutils:3.4.5
141 | name: ithome
142 | ```
143 |
144 |
145 |
146 | 1. keel.sh/policy:
147 | 這邊描述怎樣的 image tag 的變化是認可為有新版,keel 會希望image tag的版本都可以根據 SemVer 的方式使用 $major.$minor.$patch 來描述。 而今天我們使用 `all` 的含義是三者有任何一個版本更新,我們就會更新,預設會使用最新的版本。
148 | 2. keel.sh/trigger
149 | 這邊描述我們不使用 webhook 的方式,而是改用去定期詢問遠方 image 是否有更新
150 |
151 |
152 |
153 | 接下來我們就來部署看看
154 |
155 | ```bash
156 | $ kubectl apply -f deployment.yaml
157 | $ kubectl get deployment ithome -o jsonpath='{.spec.template.spec.containers[0].image}'
158 | hwchiu/netutils:3.4.5
159 | ```
160 |
161 | 接下來開啟其他視窗,嘗試部署一個全新的 image tag, 其版本必須大於 3.4.5,譬如我們使用 4.5.6 試試看
162 |
163 | ```bash
164 | $ docekr push hwchiu/netutils:4.5.6
165 | ....
166 | Successfully tagged hwchiu/netutils:4.5.6
167 | The push refers to repository [docker.io/hwchiu/netutils]
168 | de527d59ee7c: Layer already exists
169 | 0c98ba7dbe5c: Layer already exists
170 | 64d2e4aaa54c: Layer already exists
171 | 0d3833376c2f: Layer already exists
172 | 4a048ea09024: Layer already exists
173 | b592b5433bbf: Layer already exists
174 | 4.5.6: digest: sha256:f2956ee6b5aafb43ec22aeeda10cfd20b92b3d01d9048908a25ef4430671b8a3 size: 1569
175 | $ kubectl get deployment ithome -o jsonpath='{.spec.template.spec.containers[0].image}'
176 | hwchiu/netutils:4.5.6
177 | ```
178 |
179 | 不久後就可以觀察到系統上的 image 已經被改變了,此時去觀察中間層的 replicaset,就可以看到有 `4.5.6` 的出現
180 |
181 | ```bash
182 | $ kubectl get rs -o wide
183 | NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
184 | ithome-7d44545847 3 3 3 2m49s ithome hwchiu/netutils:4.5.6 app=ithome,pod-template-hash=7d44545847
185 | ithome-7d5fb6757f 0 0 0 12m ithome hwchiu/netutils:3.4.5 app=ithome,pod-template-hash=7d5fb6757f
186 | ```
187 |
188 |
189 |
190 | 透過這樣的 Demo 過程,我們算是跑了一個基本的 Pull Mode 的更新,我們透過 Container Image 版本的更新來自動更新 Kubernetes 內部資源的狀態,這中間沒有牽扯到任何 CD Pipeline 的運作。
191 |
192 | 實際上這種運作模式後來也有一種更好的架構,稱為 GitOps,下篇開始我們就來認真學習一下 GitOps 的概念!
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/2020/ci/day10.md:
--------------------------------------------------------------------------------
1 | Day 10 - CI 與 Kubernetes 的整合
2 | ===============================
3 |
4 |
5 |
6 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
7 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)https://www.facebook.com/technologynoteniu)
9 |
10 |
11 |
12 | 上文中我們介紹了流水線系統的取捨,最後也決定要使用 GitHub Action 來使用,而接下來這篇文章則要介紹到底於該 Pipeline 系統中,如果我們的應用程式跟 Kubernetes 有整合,又希望 CI 系統可以幫忙測試,那系統該怎麼做?
13 |
14 |
15 |
16 | 這篇文章的前提就是,我們的應用程式本身需要 Kubernetes 來進行測試,至於要如何測試之後的文章會跟大家介紹,今天就專注於探討如果需要 Kubernetes 來測試,那我們的 Pipeline(GIthub Action) 系統要怎麼使用,以及有什麼相關點要注意
17 |
18 |
19 |
20 | # 架構
21 |
22 | 首先,我們的應用程式需要一個 Kubernetes 來測試,這個 Kubernetes 則有兩種架構
23 |
24 | 1. 遠方架設一個固定的 Kubernetes 叢集供 CI 流水線測試
25 |
26 | 2. CI 架構中動態產生 Kubernetes 叢集來給你測試
27 |
28 |
29 |
30 | 這兩種架構都有各自的優缺點,現在來看一下彼此的差異
31 |
32 |
33 |
34 | ## 遠方固定一個 Kubernetes 叢集
35 |
36 |
37 |
38 | 架構概念如下,這情境下會有一個遠方的 Kubernetes 叢集,我們希望所有的 CI 測試都會使用這個遠方的 Kuberentes 叢集。
39 |
40 | 同時,我們系統中會有兩個 Job(假設多個開發者同時開發,各自的修改都會觸發 Pipeline 去執行),每個 Job 中都會有很多個 Stage 要執
41 |
42 | 行,其中最重要的 `Testing` 我們會希望將應用程式部署到 Kubernetes 內去測試。
43 |
44 | 
45 |
46 |
47 |
48 | 這種狀況下就會有一些問題產生,譬如
49 |
50 | 1. 每次的測試是否有完整的清理資源,確保系統資源測試前後一致(我認為這是很重要的一點,任何的測試都不應該殘留資源於系統上,導致二次測試失敗)
51 | 2. 如果有多個工作同時要使用該 Kubernetes,是否會有衝突? 雖然可以透過 namespace 來區分,但是 Kubernetes 內有些資源是沒有 namespace 概念的,譬如 PV
52 | 3. 為了讓 Pipeline 有能力存取 Kubernetes,勢必要把 KUBECONFIG 等資訊存放到 pipeline 系統中,這對很多人來說是個安全性的隱憂,畢竟只要讓 KUBECONFIG 流出去,其他人就有能力操控你的 Kubernetes,如果權限弄得不好甚至可以搞壞整個 Kubernetes 叢集。
53 |
54 | 這種架構的好處就是, pipeline 系統內只要專注處理如何測試,這些 pipeline 到底是運行在 VM 或是 Container 上都沒有關係,只要能夠透過 kubectl/helm 等指令存取遠方 Kubernetes 叢集即可。
55 |
56 | 此外,如果測試過程中發現任何錯誤,我們都可以直接到遠方的 Kubernetes 去檢查失敗後的環境,來釐清到底為什麼會測試失敗
57 |
58 | ## CI 過程動態產生 Kubernetes 叢集
59 |
60 |
61 |
62 | 這種架構與上述不同,主要的差異是該 Kubernetes 叢集並非固定的,而是於 pipeline 過程中動態產生
63 |
64 | 
65 |
66 | 這種架構下來我們來看看到底有什麼樣的好壞
67 |
68 | 1. 由於 Kuberentes 都是獨立產生,每個 Job 都會有自己的 Kubernetes,所以彼此環境不衝突,甚至也不用擔心資源沒有清理乾淨,因為每次測試都是全新的環境
69 | 2. 也因為 Kubernetes 是獨立且動態的, KUBECONFIG 是動態產生,所以不用擔心會有額外的安全性問題
70 |
71 |
72 |
73 | 但是這種架構下也會有其他的缺點
74 |
75 | 1. 如果今天測試失敗時,可能這個 Kubernetes Cluster 就被移除了,導致沒有相關的環境可以用來釐清出錯的原因,變得更難除錯
76 | 2. 有些測試需要一些前置作業,這些前置作業會不會不好處理,譬如需要一個額外的檔案系統,額外的環境架設
77 | 3. pipeline 環境中要思考如何架設 Kuberentes,如果你的 pipeline 環境是基於 docker, 那就要思考如何在 docker上創建 kubernetes,這部分還要考慮使用的 pipeline 系統有沒有辦法做到這些事情。
78 |
79 |
80 |
81 | 這兩種架構各自有其優缺點,並沒有絕對的對錯,接下來我們會嘗試使用第二種架構,於 GitHub Action 中去創建一個 Kuberentres Clsuter,並且透過 Kubectl 指令來確認該 Kubernetes 叢集是運作正常的
82 |
83 |
84 |
85 |
86 |
87 | ## GitHub Action & Kubernetes
88 |
89 | Github Action 中有非常豐富的 Plugin,其實可以查到有非常多的 action 再幫忙創建 Kubernetes 叢集,譬如
90 |
91 | 1.[action-k3s](https://github.com/marketplace/actions/actions-k3s)
92 |
93 | 2.[kind](https://github.com/marketplace/actions/kind-kubernetes-in-docker-action)
94 |
95 | 3.[setup-minikube](https://github.com/marketplace/actions/setup-minikube)
96 |
97 |
98 |
99 | 可以直接到 [Github Action Marketplace](https://github.com/marketplace) 去搜尋就可以看到滿多跟 Kubernetes 相關的範例。
100 |
101 | 由於之前的章節中我們介紹過用 KIND 與 K3D 來部署本地的 Kubernetes,那這次我們就嘗試使用 K3S 來部署看看 Kubernetes。
102 |
103 |
104 |
105 | ## 使用
106 |
107 | 這邊不會介紹太多關於 GitHub Action 的詳細用法,有興趣可以參考官網教學,其實非常簡單,每個 GitHub Repo 只要準備一個檔案就可以設定。
108 |
109 | 於專案中的下列資料夾中 `.github/workflows` ,準備一個名為 `main.yml` 的檔案,其內容如下
110 |
111 | ```yaml
112 | # This is a basic workflow to help you get started with Actions
113 |
114 | name: CI
115 |
116 | # Controls when the action will run. Triggers the workflow on push or pull request
117 | # events but only for the master branch
118 | on:
119 | push:
120 | branches: [ master ]
121 | pull_request:
122 | branches: [ master ]
123 |
124 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
125 | jobs:
126 | # This workflow contains a single job called "build"
127 | build:
128 | # The type of runner that the job will run on
129 | runs-on: ubuntu-latest
130 |
131 | # Steps represent a sequence of tasks that will be executed as part of the job
132 | steps:
133 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
134 | - uses: actions/checkout@v2
135 | - uses: debianmaster/actions-k3s@master
136 | id: k3s
137 | with:
138 | version: 'v1.18.2-k3s1'
139 | - run: |
140 | kubectl get nodes
141 | kubectl version
142 | ```
143 |
144 | 基本就是一個最基本的 GitHub Action 範例,只是最後我們改成使用 `k3s` 的 `GitHub Action` ,根據 [action-k3s](https://github.com/marketplace/actions/actions-k3s) 的描述,我們只要指定 `k3s` 的版本就可以獲得對應的 Kubernetes 版本,因此我們指定 `v.18.2-k3s1`。
145 |
146 | 最後我們補上兩個指令 `kubectl get nodes` 以及 `kubectl version` 來確保我們有在 GitHub Action 中獲得一個 Kubernetes 叢集並且可以操控。
147 |
148 | 這邊要注意的`GitHub Action`預設都是提供 `Virtual Machine` 供所有測試任務使用,所以我們可以相對簡單的於這個 VM 上面去運行相關的操作。反之如果今天提供的是 Container 為基底的環境,那要在上面再次安裝 Kubernetes 就不是這麼簡單了。
149 |
150 |
151 |
152 | ## 執行過程
153 |
154 | 下圖是執行過程,可以看到最上面是執行 `actions-k3s` 的內容,透過 `docker` 指令創建相關的 `k3s` Cluster,最後透過 `kubectl` 來觀看相關的內容,包含節點資訓以及對應的版本
155 |
156 | 
157 |
158 | 到這邊為止我們就有辦法於 GitHub Action 中動態創立 Kubernetes 叢集了,如果有什麼測試都可以把這些部分整合到 GitHub action 中了。
--------------------------------------------------------------------------------
/2020/ci/day12.md:
--------------------------------------------------------------------------------
1 | Day 12 - CI Pipeline x Kubernetes 結論
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 過去幾天我們探討了關於 Pipeline 的架構, CI 過程中 Kubernetes 的設計,以及 Yaml 相關的測試方式,今天這篇文章就來針對這些內容進行一些心得總結
11 |
12 |
13 |
14 | 一開始我們先用一張圖片來介紹可能的 pipeline 架構(此架構只是一個可能性,不是唯一,每個團隊需要運行的架構都不盡相同,沒有最好的架構只有最適合自己環境的架構)
15 |
16 | 
17 |
18 | 這張架構中,我們首先要先選擇一套自己喜歡的 Pipeline 系統,這套系統可能是自架,也可能是 SaaS 服務,這中間的取捨條件非常多,
19 |
20 | 不論是成本考量,維護考量,擴充靈活性等,每個細項都需要團隊經過評估討論後決定
21 |
22 | 接下來於該 Pipeline 中我們會設定相關的 Job 來處理我們的工作,目前我們都只專注於 CI 方面的工作,因此上述的區塊都跟測試相關,
23 |
24 | 主要用來驗證與確保每次開發者的程式碼修正有通過團隊的一些測試要求。
25 |
26 | 這邊的架構其實非常多變,譬如 Git Repo 的設計,是否要將應用程式與 Yamls 放一起
27 |
28 | 1. 放一起的架構下,就變成整條 pipeine 的測試中要同時包含程式碼的測試,以及 Yaml 的測試,會比較類似上述的架構
29 | 2. 如果分開放,則有些測試就可以分開,譬如 Yaml Repo 就只需要針對 Yaml 進行測試,甚至配上一些整合測試確保部署後功能沒有問題。當然應用程式本身可以依靠程式語言的測試框架進行基本測試,接者搭配一些整合測試即可。
30 |
31 |
32 |
33 | Yaml 測試方面前一天的文章有探討一些工具的使用與介紹,這些工具的用法與面向都不相同,甚至裡面要測試的檔案也不一定只有
34 |
35 | Kubernetes 可以使用,所以多方測試總是會有幫助的
36 |
37 | 一切通過之後可以開始建置相關的 Container Image,並且準備將其送到測試用的 Kubernetes 叢集中,這邊要特別注意的環節就是
38 |
39 | Image Tag 的處理。假設前述過程中產生的 Image Tag 是 `5b1f94025b2`,那後續測試的過程要有能力把這個 `5b1f94025b2` 給傳遞到
40 |
41 | 相關的 Yaml 裡面,這樣才可以確保 Kubernetes 內使用的是這個剛建置好的 Container Image.
42 |
43 | 如果使用的是 Helm 來部署的話,我們可以透過 `--set image.tag=5b1f94025b2` 之類的方式來修改 image tag,如果是使用原生的 Yaml 檔案,可能就要利用 sed 等指令來修改,這部分腳本的撰寫要特別小心。
44 |
45 | 當一切都測試完畢後就可以將最後的 Image Tag 給推上去成為一個經過測試認可的 Image。
46 |
47 |
48 |
49 | 那上述的流程有沒有哪些部分可以改善或是引入不同的工具來提升效率呢?
50 |
51 | 事實上是可以的,我們可以嘗試引入之前介紹過的本地開發工作 `skaffold` 來幫我們處理建置 Image 及將 Image 推到 Kubernetes 叢集內的這段過程,其架構如下。
52 |
53 |
54 |
55 |
56 |
57 | 
58 |
59 |
60 |
61 | 於 Skaffold 的設定檔案中我們可以設定測試用的指令,將我們運行整合測試的指令整合進去,就可以把 Build Image 到測試這過程全部
62 |
63 | 讓 Skaffold 來搞定,同時藉由 Skaffold 的幫忙,我們就不需要自己去處理修改 Image Tag 的這個過程,一切讓 Skaffold 去修改對應的
64 |
65 | image tag, 不論是 Helm, Kustomize 或是原生 Yaml 都能搞定。
66 |
67 | 結論來說,我認為現在一個簡單的 CI 流水線內其實會引入各式各樣的開源軟體來幫忙處理,每個軟體都有自己擅長與不擅長的地方,很
68 |
69 | 多時候就算找不到相關的開源軟體我們都可以秉持 `給我一個 bash, 我給你全世界` 的概念來自行處理。但是有時候要去思考一下到底現在
70 |
71 | 團隊最要緊的任務是什麼,哪個工作是公司最需要的,有時候架構上的完美不一定是商業上的完美,這部分的取捨往往需要一些溝通與協
72 |
73 | 調,來找到一個公司開心,工程師開心,大家開心的節奏。
74 |
75 |
--------------------------------------------------------------------------------
/2020/ci/day9.md:
--------------------------------------------------------------------------------
1 | Day 9 - Pipeline System 介紹
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 昨天我們介紹了本地開發的一個開源工具, Skaffold,如何透過 Skaffold 來提升本地開發的效率
11 |
12 | 根據我們一開始展現的 CI/CD 世界圖,我們已經探索完畢 `Local Developement Environment` 的相關議題
13 |
14 | 
15 |
16 |
17 |
18 | 接下來我們要來探討 CI/CD Pipline 的設計,這部分牽扯到諸多議題,第一個最基本的問題就是, Pipeline 系統要選擇哪一套
19 |
20 | 目前開源軟體超級多,選擇上其實非常困難,譬如有 GitLab, Jenkins, CircleCI, TravisCI, TeamCity, GithubAction...等
21 |
22 | 所以今天這個章節,我們就來聊聊有哪些 Pipeline 系統可以使用,以及在選擇上有哪些點可以考慮
23 |
24 |
25 |
26 | 我認為在選擇上,有一些可以考慮
27 |
28 | 1. 服務的部署模式,是自架部署還是使用 SaaS 服務
29 | 2. 該系統有哪些吸引人的特色
30 |
31 |
32 |
33 | 接下來我們就來看看這幾點中有什麼細節可以討論
34 |
35 |
36 |
37 | ## 部署模式
38 |
39 | 部署模式上基本上就是兩大塊,自架服務或是SaaS服務,這兩種類型我認為他們的好壞優點有
40 |
41 | ### 自架服務
42 |
43 | 優點:
44 |
45 | 1. 彈性,擴展性佳,可以根據各種需求去修正,甚至有機會透過修改原始碼來滿足客製化需求
46 | 2. 使用上限制比較少
47 |
48 | 缺點:
49 |
50 | 1. 要自己維護伺服器,包含了運算資源,儲存資源,網路資源甚至可能連硬體都要處理。
51 |
52 | 2. 第三方整合不一定有,需要自己研究跟處理,甚至還要自己撰寫程式碼來完成
53 | 3. 發現問題時不一定有太多支援可以尋求,會變成要花更多時間在處理這些問題而非賺錢的商業邏輯
54 |
55 | ### SaaS
56 |
57 | 優點:
58 |
59 | 1. 使用起來簡單,不用擔心底層基礎架設,譬如硬體資源,網路資源,儲存資源以及運算資源
60 | 2. 付費情況下會有比較好的支援服務可以尋求,發生問題時可以讓對方幫忙處理
61 |
62 | 缺點:
63 |
64 | 1. 限制多,需要花更多的錢來獲得更好的服務與使用條件
65 | 2. 支援的平台與支援的語言完全受限於廠商,沒有辦法擴充
66 | 3. 彈性與擴充性比較低,一切都依賴廠商去開發
67 |
68 |
69 |
70 | 大部分的 SaaS 都會提供免費版本的功能讓使用者使用,但是部分功能都會有所限制,想要解除這些限制就要付費,透過付錢來取得更好的使用品質,至些功能可能有
71 |
72 | 1. 可以有多少個並行的工作
73 | 2. 一段時間內可以跑多少時間的工作,譬如每個月只能跑 10 小時的工作
74 | 3. 每個 job 能夠支援的 Timeout 上限
75 | 4. 支援哪些平台與機器類型,譬如是否可以支援 Docker 或是 VM, 平台除了常見的 Linux 之外是否也支援 Winodws/OSX/iOS/Andorid 等平台。
76 |
77 |
78 |
79 | 此外,對於這些 Piepline 系統來說,自架跟 SaaS 並不是二擇一,很多情況下,這些系統除了提供 SaaS 的服務外,也有提供自架服務
80 |
81 | 這種情況下就可以讓使用者決定到底要使用自架服務或是 SaaS,譬如先透過 SaaS 去使用評估看看,覺得喜歡看考慮自架或是反過來
82 |
83 | 一開始先自架來用看看,如果喜歡但是覺得維護麻煩,覺得改用 SaaS 更可以省時省力。
84 |
85 |
86 |
87 | ## 特色
88 |
89 | 每個不同的 Piepline 系統都會有不同的特性,這些特性不一定每個環境都需要,所以選擇上還是根據自己的需求去選擇
90 |
91 | 我個人的經驗下,可能會有這些特性(包含但不侷限)
92 |
93 | 1. 通知系統。當工作成功或是失敗的時候,能不能把這些結果通知出去,讓管理員有辦法被動知道這些工作的結果
94 |
95 | 2. 專案的追蹤與問題管理,譬如是否該系統能夠把這些每個工作都跟一些 Issue Tracking 整合,譬如 Jira
96 |
97 | 3. 使用者權限整合,是否可以跟已知常用的系統整合,譬如 LDAP/Windows AD/Google Suite/Crowd/OpenID
98 |
99 | 4. 流水線的工作內容是否可以用程式碼的方式來保存,類似 Pipeline as a Code
100 |
101 | 5. 使用工具與閱覽工具有哪些,是否有好用的 UI 或是工具可以使用
102 |
103 | 6. 除錯與文件的完整性,使用上是否能夠找到詳細的文件來使用,發生問題時是否容易找到詢問的管道
104 |
105 | 7. Secret 這種機密資訊的管理與使用是否有支援,譬如 db password 等
106 |
107 |
108 |
109 | 要找到一套系統完全支持上述所有功能且都要好用穩定不會出錯其實不可能,最困難的還是去評估每個系統以及其特性,看看有哪些特性
110 |
111 | 是你們一定要有,哪些可以妥協不一定要有的
112 |
113 |
114 |
115 | ## 工具的選擇
116 |
117 | 就如同最上面所述的,市面上有非常多 Piepline 系統可以選擇,每個都有各自的優點與使用,接下來的文章為了讓整體操作簡單與順利,會採取使用 SaaS 服務的 Piepline 系統,並且基於免費版本來使用
118 |
119 | 這些選擇中有 CircieCI, TravisCI 甚至是 Github 本身的 Github Action.
120 |
121 | 由於我們的專案都很習慣放在 GitHub 上,我們就來使用 GitHub Action 作為後續的操作環境!
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/2020/gitops/day16.md:
--------------------------------------------------------------------------------
1 | Day 16 - GitOps 的介紹
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 |
11 |
12 | 之前章節我們介紹過關於 CD 的種種議題,同時也有提到 `CNCF End User Technology Radar` 關於 CD 的使用者報告內,有兩個關於 GitOps 的軟體,其中一個就是 Flux 而另外一個則是 ArgoCD。
13 |
14 | 其中 Flux 還是報告中被個使用者廠商推薦為推薦使用的專案技術,那到底是什麼是 GItOps
15 |
16 | 本篇文章就來跟大家介紹到底什麼是 GitOps 以及這個概念相對於過往的 CD pipeline 使用起來有什麼差異
17 |
18 |
19 |
20 | # 介紹
21 |
22 | GitOps 的概念源自於 `weaveworks` 於 2017 所提出的一個想法,希望透過 GitOps 帶來一個針對 Cloud Native 的全新 CD 方式
23 |
24 | 這個概念中,希望可以使用大家已經熟悉且穩定的工具來搭建出一套良好的 CD 方式,這兩個工具就是
25 |
26 | 1. Git
27 | 2. 任何好用的 Continuous Delivery 工具
28 |
29 |
30 |
31 | # 核心概念
32 |
33 | GitOps 的核心概念不會太難,分別是
34 |
35 | 1. Git 作為單一來源
36 | 2. 狀態同步
37 | 3. 更新方式單一來源
38 |
39 | ## Git 作為單一來源
40 |
41 | GitOps 中強調,所有的資源描述檔案,都集中放於 Git,不論是原生的 Yaml,Kustomize 或是 Helm。 這些內容都要放到 Git 裡面
42 |
43 | 同時也只能有這個來源,當有人問起你這個 Kubernetes 資源的描述檔案在哪裡,唯一的答案就是 Git 身上
44 |
45 | 透過使用 Git 帶來一些好處
46 |
47 | 1. 任何檔案的變化都可以使用 Git History 來觀察,藉此追蹤每個版本的差異
48 | 2. 如果有任何修改有問題,想要修復的話,都可以透過 Git 的指令操作,譬如 Revert, 或是再次修正
49 |
50 | > 你要用哪一套 Git 其實沒差,其實概念源自於 VCS 版本控制系統
51 |
52 | 此外, Git 中所放置的資源描述檔案都希望是基於 Declarative 的概念,一種宣告式描述希望狀態的格式,擁有這個要求才可以滿足第二個核心概念
53 |
54 | ## 狀態同步
55 |
56 | 第二個核心概念是完全建築在第一個概念的實現,要先完成第一個核心狀態的建置,接下來才可以處理這個
57 |
58 | 探討這個概念前,我們要先定義兩個資源狀態
59 |
60 | 1. 使用者渴望的資源狀態
61 | 這個狀態指的是 Git 內所維護的狀態,譬如使用者希望我的 Deployment 有 3 個副本,同時 image 的版本是 1.2.4。
62 | 這也是為什麼前述有說 Git 專案內要使用的是 Declarative 的格式,透過這類型的概念來描述開發者渴望的狀態
63 | 2. 正在運行的實際狀態
64 | 這個狀態指的是目標資源目前於 Kubernetes(舉例)內運行的狀態,譬如當前運行的 Deployment 有 2 個副本,使用的 image 版本是 1.2.3
65 |
66 | GitOps 會希望有一個代理人(Controller),這個代理人權責很重,他左邊觀看(1)的渴望狀態,同時右邊監控(2)系統上的運行狀態
67 |
68 | 這個代理人的最終目標就是要確保 (1) 與 (2) 的狀態一致,大部分的情況下都是把 (1) 的狀態給覆蓋到系統內,讓(2)最後會成為(1)所描述的樣子。
69 |
70 | > 部分情況下,管理人員會直接使用一些工具來直接對運行的 Kuberentes 資源進行修改,譬如 kubectl patch, kubectl edit 等工具來修改其運行狀態。一但這種事情發生,就會導致最初描述這些資源的 Yaml 檔案與運行狀態不一致
71 |
72 |
73 |
74 | ## 更新方式單一來源
75 |
76 | 最後要講的則是 GitOps 的更新方式,鑑於前面兩個核心概念的組合,所有的更新都要從 Git 出發
77 |
78 | 舉例來說,我今天想要更新 Deployment 的 image tag, 我就針對該檔案進行修改,並且遞交一個修正的 Git Commit.
79 |
80 | 當一切都合併完畢後, `GitOps` 內的代理人接下來就會負責將 Git 上面的狀態資源給同步到目標的 Kubernetes 叢集中,藉此更新 Kubernetes 內的資源。
81 |
82 | 這種方式帶來幾個好處
83 |
84 | 1. Git Commit 是唯一的更新來源,禁止其他人透過 kubectl 等工具直接對 Kubernetes 進行部署與修改。這樣當問題發生的時候也比較好追蹤問題來源與除錯
85 | 2. 今天版本有問題想要進行退版的時候,可以直接對 Git 進行版本的處理,譬如修正,退版等。只要 Git 這邊搞定,後續就等待代理人將 Kubernetes 叢集內的狀態修正成符合 GIt 上面的格式
86 | 3. 就算今天有任何繞過規則,手動對 Kubernetes 內的資源進行手動修改,這些修改都可以被代理人追蹤,可以自動更新回去,迫使所有運行資源都要與 Git 所描述的一致
87 |
88 |
89 |
90 | 上述三個核心概念組建出 GitOps 的操作模式,然而這邊都只是概念上的敘述,下一篇會再用圖片跟大家介紹 Kuberentes 架構下的 GitOps 實作方式,當然實作方式也是百百種,不同的開源作案做法也都不一樣。
91 |
92 |
93 |
94 | # 缺點
95 |
96 | 當然每個技術都不可能完美無瑕沒有任何缺失,接下來將列舉一些別人於 GitOps 實戰中遇到的痛點以及一些領悟,由於內文過長,對於詳細內容有興趣以參閱 [GitOps 帶來的痛點與反思](https://www.hwchiu.com/gitops-bad-and-ugly.html) 內的分析與介紹。
97 |
98 | 以下列舉文章內的缺點
99 |
100 | 1. 不適合使用於程式化的更新
101 | 2. Git Repo 增長帶來的問題
102 |
103 | 3. 缺乏視覺化
104 | 4. Secret 的管理問題依然沒有解決
105 | 5. 缺少檔案資源的驗證性
106 |
107 |
108 |
109 | 最後,其實 GitOps 的概念並沒有侷限於 Kubernetes 身上,畢竟 GitOps 就是一個概念,不是一個實作的規格,用任何的工具都有辦法
110 |
111 | 打造出符合這個核心概念的工作流程,甚至目標部署不是 Kubernetes 也沒有問題。
--------------------------------------------------------------------------------
/2020/gitops/day17.md:
--------------------------------------------------------------------------------
1 | Day 17 - GitOps 與 Kubernetes 的整合
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 |
11 |
12 | 上篇文章我們探討了 GitOps 的概念,但是概念歸概念,實作歸實作,有時候實作出來的結果跟概念不會完全一致,因此最後的使用方式與優缺點還是要看實作的細節。
13 |
14 | 今天我們就來看看 GItOps 這個概念要怎麼與 Kubernetes 整合。
15 |
16 | 首先,前述 GitOps 的概念中,我們提到一個代理人程式,這個程式要能夠管理左看 Git Repo, 右看 Kubernetes ,那由於這個程式本身要能夠有能力去讀取 Kubernetes 內的資源狀態,同時也要有能力對其修改,勢必要獲得一些操控權限。
17 |
18 | 設想一個情境,如果今天這個代理人程式其座落於 Kubernetes 外,我們終究還是要為他準備一份 KUBECONFIG,這樣其實也是會增加安全性的風險,但是如果把這個程式放到 Kubernetes 裡面,讓其擁有存取 Kubernetes 能力的部分就相對好解決,這樣可以減少一些安全性的風險。
19 |
20 |
21 |
22 | # 程式碼架構
23 |
24 | GitOps 的架構下,因為都會把資源的狀態檔案都放在 Git,所以這時候就會有一些不同的做法,舉例來說
25 |
26 | 1. 應用程式原始碼以及相關的 Yaml 放一起
27 | 2. 應用程式原始碼以及相關的 Yaml 分開到不同的 Repo 去放
28 |
29 | GitOps 的原則我認為採用 (2) 是比較好實現的,因為我們可以很明確地將應用程式與部署資源給分開,這兩個 Repo 所維護跟控管的團隊也有所不同。同時 Yaml Repo 內的所有更動跟只會跟部署資源的狀態有關,這樣對於維護,追蹤任何變動,甚至要退版等需求都比較好實現。
30 |
31 | 如果將程式碼跟相關 Yaml 放在同樣一個 Repo 內,那想要針對部署狀況進行退版,就有可能也會導致程式碼本身功能也一併被退版,這就不是期望的結果。
32 |
33 | 不過這邊所提的都只是一些各自的特性與優缺點,沒有一個絕對的解決方案跟絕對的正確與否,還是要根據 GitOps 的實作方式以及團隊的習慣方式去選擇。
34 |
35 | 接下來的架構圖都會基於 (2) 的方式去介紹
36 |
37 |
38 |
39 | # 架構一
40 |
41 | 我們用下面的架構圖來看一下一個 GitOps 與 Kubernetes 整合範例一
42 |
43 | 這個架構下,我們會在 Kubernetes 內安裝一個 Controller,也就是前文所提的代理人程式,這個程式本身要有辦法與遠方的 Git(Yaml) Repo 溝通。
44 |
45 | 接下來其運作流程可能是
46 |
47 | 1. 開發者對 Git(Application) Repo 產生修改,這份修改觸發了相關的 CI Pipeline ,這過程中經歷過測試等階段,最後將相關的 Image 給推到遠方的 Container Registry。
48 | 2. 系統管理者針對 Git(Yaml) Repo 產生修改,這份修改觸發了相關的 CI Pipeline, 這過程中會針對 Yaml 本身的格式與內容進行測試,確保沒有任何出錯。
49 | 3. 當 Git(Yaml) Repo 通過 CI Pipeline 而合併程式碼後,接下來 Kubernetes 內的 Controller 會知道 Git(Yaml) Repo 有更新
50 | 1. 一種是 Git 那邊透過 Webhook 的方式告訴 Controller
51 | 2. 一種是 Controller 定期輪詢後得到這個結果
52 | 4. 同步 Git(Yaml) Repo 裡面的狀態描述檔案與 Kubernetes 叢集內的狀態,確保目前運行狀態與 Git 內的檔案描述一致
53 | 5. 如果今天不想要 (3) 這個步驟的自動化,也可以由管理員經過確認後,手動要求 Controller 去同步 Git 並更新
54 |
55 |
56 |
57 |
58 |
59 | 
60 |
61 | 上述的架構聽起來運作起來都滿順暢,但是對於開發者的叢集來說(假設開發者會有一個遠方的 Kubernetes 用來測試功能)可能會不便利,只要這些更新非常頻繁,那就意味者要一直不停的去修改 Git Yaml Repo 的內容,雖然一切都按照概念在運行,但是操作起來可能會覺得效率不一定更好。
62 |
63 | 因此也會有人將上述的一些架構整合,譬如當 Image 推向到遠方 Container Registry 後,利用程式化的功能於 CI Pipeline 的最後階段自動的對 `Git(Yaml) Code Changed` 去送一筆 Commit 並自動觸發後面的 Controller 同步行為。
64 |
65 | GitOps 的概念很活,很多種做法都可以,並沒有要求一定要怎麼實作才可以稱為 GitOps,最重要的是你們的工作流程是否可以達到如同 GitOps 所宣稱的效果,就算不走 GitOps,只要可以增加開發跟部署的效率,減少問題就是一個適合的架構。
66 |
67 |
68 |
69 | # 架構二
70 |
71 | 接下來我們來看一下另外一種參考架構,這種架構希望可以解決 Contaienr Image 頻繁更新的問題,因此 Controller 本身又會多了監聽 Container Registry 的能力。
72 |
73 | 當 Controller 發現有新的版本的時候,只要這個版本號碼有符合規則,就會把新的版本資訊給套用到 Kubernetes 裡面。
74 |
75 | 但是因為 GitOps 的原則是希望以 Git 作為單一檔案來源,如果這樣做就會破壞這個規則,因此這時候 Controller 就要根據當前 Image Tag 的變化,把變化內容給寫回到 Git(Yaml) Repo 之中。
76 |
77 | 這也是為什麼下圖中 Controller 要對 Git(Yaml) Repo 進行更新與撰寫新 Commit 的原因。
78 |
79 | 也因為這個原因,我們的 Controller 也必須要對該 Git(Yaml) Repo 擁有讀寫的能力,這方面對於系統又會增加一些設定要處理
80 |
81 |
82 |
83 | 
84 |
85 |
86 |
87 | 以上兩種架構並不是互斥,是可以同時存在的,功能面方面就讓各位自己取捨,哪種功能我們需要,帶來的利弊誰比較大。
88 |
89 | 下一篇我們將帶來其中一個開源專案 ArgoCD 的介紹,看看 ArgoCD 如何實踐 GitOps 的原則
90 |
91 |
--------------------------------------------------------------------------------
/2020/local/Day5.md:
--------------------------------------------------------------------------------
1 | Day 5 - 淺談本地部署 Kubernetes 的各類選擇
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 接下來幾天我們將開始探討對於一個本地開發者來說,要怎麼搭建一個 Kubernetes 來使用
11 |
12 | 探討這個議題之前,我們要先來問一個問題是
13 |
14 | 我們本地開發者,真的需要一個 Kuberntees 嗎? 這個是必要的嗎?
15 |
16 | 我認為這個答案是非必要,並不是所有的本地開發者都需要有一個獨立的 Kubernetes 叢集來使用,但是如果有符合下列需求之一,就會需要創建一個本地的 Kubernetes 叢集
17 |
18 | 1. 開發的應用程式與 Kubernetes 息息相關,譬如該應用程式會用到 Kubernetes API,這類型應用程式需要部署到 Kubernetes 內才可以發揮其功用
19 | 2. 開發的應用程式需要用到一些 Kubernetes 的資源才能夠看出差異,譬如想確認 Kubernetes HPA 發生時應用程式是否能夠如預期運作。這類型的應用程式也會需要有個本地的 Kubernetes 叢集才測試
20 | 3. 開發人員本身是公司的基礎設施維運人員,譬如要設計 Jenkins 與 Kubernetes 的連動測試,可能會需要在本地先進行相關測試之後才會正式上到公司環境。好處可能是可以先不用開雲端機器,可以先省錢,都用VM來測試相關功能
21 | 4. 開發的應用程式有很多依賴性,譬如需要 redis, kafaka, memcached 等,這種情況下如果 `也許` 有個本地的 Kuberentes 會比較方便
22 |
23 |
24 |
25 | 除了上述理由之外(一定還有其他情境,我沒有辦法列舉全部),我認為剩下的情境應該都可以透過 docker/docker-compose 來完成建置相關環境供開發者測試。 (4) 的條件我認為比較彈性,假如依賴的服務都可以用 docker-compose 直接建立,那其實也不需要有個 Kuberentes,但是如果這些服務本身有一些設定而且 Kubernetes Yaml/Helm 都已經準備好, 整體部署與設定所花費的時間比重新研究如何轉移到 Docker-compose 上還來得輕量與快速,那其實也可以考慮就直接上 Kubernetes。
26 |
27 | 如果你今天深思熟慮後,確認真的有需要於本地測試 Kuberntes 的需求,我們就可以來思考,對於一個開發者,我希望可以怎麼使用這個本地的 Kubernetes。
28 |
29 | 對我個人來說,我希望這套解決方案能夠有下列特性
30 |
31 | 1. 容易設定與架設,最好幾個按鈕就好
32 | 2. 能夠都用指令完成,不需要有任何 UI 介入
33 | 3. 能夠模擬多節點最好
34 | 4. 最好能夠把上述的一切都包成一個腳本,一個命令建置完畢
35 |
36 |
37 |
38 | 接下來我們來看一下四套不同的開源軟體, Kubeadm, Minikube, KIND, K3D 這四套的基本介紹,下一章節我們則會從中挑選一些來進行安裝示範
39 |
40 |
41 |
42 | ## Kubeadm
43 |
44 | Kubeadm 是由官方維護的開源專案,我認為是非常簡單的一個測試方式,其本身會透過 systemd 的方式維護 Kubelet 之後再透過 container 的方式叫起 controller/scheduler/kube-proxy 等 Kubernetes 核心元件。
45 |
46 | 使用方面 Kubeadm 本身不算困難使用,可以透過指令列的方式來創建一切所需資源,唯一要注意的是安裝完畢之後還需要人為手動安裝 CNI 的解決方案整個 Kubernetes 才算是安裝完畢。
47 |
48 | Kubeadm 本身也支援架設多節點的叢集,只是在使用上沒有這麼方便,需要先創建 Master 節點,並且產生相對應的 token/key,接下來其他節點使用 kubeadm 的指令加入到已經創建的叢集中。
49 |
50 | 總體來說, Kubeadm 能夠滿足上述要求,但是實作上會稍嫌麻煩,特別是多節點的情況下還要處理 Token/key 的資訊,此外 CNI 的安裝也需要自己處理,但是作為一個單節點的測試環境也算是容易上手且堪用
51 |
52 | ## Minikube
53 |
54 | Minikube 也是由官方維護的專案,其本身的架構一開始是依賴於 VM (虛擬機器) 來幫使用者創建一個全新測試的 Kubernetes 叢集,任何平台的開發者都可以輕鬆只用,因為背後都會幫你起一個全新的 VM 。當 VM 起來之後,其會透過 kubeadm 的方式幫忙建立與設定 Kubernetes 叢集,並且幫你把 CNI 等指令都安裝完成。
55 |
56 | 除了依賴 VM 之外,其也有提供不同底層實作,譬如 `none` 就可以直接在該機器上透過 kubeadm 來建立,基本上整個架構會變得跟 kubeadm 非常類似,比較大的差異是 CNI 也會一併幫你安裝完成。
57 |
58 | 此外 Mnikube 本身也有一些屬於自己的套件,可以把一些功能整包裝進去,對於這個功能我的想法是不好也不壞,不壞的地方在於提供一個環境讓使用者去測試功能,著實方便,不好的地方在於可能會讓使用者以為這些功能都是 Kubernetes 本來就有的,反而會有所誤解,甚至對於其背後使用原理都不太清楚就草草學習完畢。
59 |
60 |
61 |
62 | 總體來說, Minikube 也可以滿足上述的部分要求,多節點的部分可能就會跑起來多個 VM 來建立,消耗的資源會相對多一點。
63 |
64 |
65 |
66 | ## KIND
67 |
68 | KIND 的全名是 Kubernetes In Docker,顧名思義就是把 Kubernetes 的節點都用 Docker 的方式叫起來運行,每一個 Docker Container 就是一個 Kubernetes 節點,可以充當 Worker 也可以充當 Master.
69 |
70 | 使用方面非常簡單,使用 KIND 的指令搭配一個設定檔案就可以輕鬆地建立起 Kubernetes 叢集,由於全部的操作都是由 KIND 完成,所以要建立多節點的方式也非常簡單,只要設定檔案中描述需要多少節點以及各自什麼身份,接下來就一個指令搞定全部,連 CNI 方面都不需要處理, KIND 會自行搞定
71 |
72 |
73 |
74 | 總體來說, KIND 可以滿足上述所有需求,多節點的部分則是用 Docker 來管理,因此在資源與啟動速度方面都有良好的效果,搭配 Vagrant 的方式就可以輕鬆打包一個多節點的 VM 環境供測試者開發,著實方便。
75 |
76 | ## K3D
77 |
78 | K3D 是由 Rancher 所開發 K3S 的 Docker 版本, K3S 是一個輕量級的 Kubernetes 平台,本身適合用在一些低運算資源系統上
79 |
80 | 而 K3D 直接將 K3S 給移植到 Docker 之中,讓使用者可以更方便的創建一個 K3S 叢集。
81 |
82 | 使用方便也是很簡單,整個主要架構都在 `k3d` 這個執行檔案上面,使用該指令搭配不同的參數就可以快速地建立起多節點的 Kubernetes Cluster,此外也可以透過指令動態增加節點,使用上也是非常方便。
83 |
84 | 與KIND一樣, CNI 的部分也會一併被處理,所以使用者真的只需要一個指令就可以處理好所有的事情,總體來說, K3D 可以滿足上述所有要求,優點基本上跟 KIND 完全類似,搭配上 Vagrant 真的可以輕鬆地建立起多節點的模擬環境。
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/2020/local/Day7.md:
--------------------------------------------------------------------------------
1 | Day 7 - 本地開發 Kubernetes 應用程式流程
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 前篇介紹了如何透過 `k3d` 以及 `kind` 等不同工具來架設一個本地的 Kubernetes 叢集,當然除了這些工具外,最初介紹的 Kubeadm/Minikube 也都可以使用,工具的選擇往往沒有最好,只有適合當下的工作流程與環境而已,隨者時間改變,很多工具可能也會變得不適用,所以困難的地方還是在於如何抓分析出目前的情境,從眾多工具中挑選一個適合的。
11 |
12 |
13 |
14 | 有了 Kubernetes 叢集之後,我們接下來看一下對一個需要 Kubernetes 的本地開發者來說,他的工作流程可能會長什麼樣子
15 |
16 | 首先由於 Kubernetes 預設的情況下是一個容器管理平台,裡面的運算資源都必須要容器化,本文我們都假設我們使用 Docker 作為我們的容器解決方案。
17 |
18 | > 實際上透過 CRI 的更動,要讓 Kubernetes 支援 Virtual Machine 也是可以的, Docker 只是容器化的選項之一,切換成別的容器解決方案都是選項
19 |
20 |
21 |
22 | # 工作流程
23 |
24 | 為了讓應用程式可以部署到 Kubernetes 裡面,開發者準備下列步驟將應用程式給部屬進去
25 |
26 | 1. 修改應用程式原始碼
27 | 2. 借助 Dockerfile 的幫助產生一個 Docker Container Image
28 | 3. 部署新版本應用程式到 Kubernetes
29 | 4. Kubernetes 根據新版本的 Docker Container Image 來產生新的運算資源
30 |
31 |
32 |
33 | 這四個步驟中比較需要探討的流程是 (4), 到底 Kubernetes 要如何獲取這個新版本的 Docker Container Image.
34 |
35 | 最簡單的做法就是準備一個遠方的 Container Registry,每次(2)完畢後,都將該 Container Image 給推到遠方 Container Registry
36 |
37 | 功能面上完全沒有問題,唯一的問題就是等待時間,畢竟時間就是金錢,就是一個開發者的成本。
38 |
39 | 對於一些高達數 GB 的 Container Image, 每次測試都要送到遠方,接者本地的 Kubernetes Cluster 再抓取下來,實際上會非常花費時間也沒有效率。
40 |
41 | 因此接下來探討兩種不同的作法與架構來看看如何改善這塊工作流程
42 |
43 |
44 |
45 | ## Kubeadm
46 |
47 | 如果今天採用的是 Kubeadm 這個部署方式,由於 Kubadm 預設創立的是一個單節點的 Kubernetes 叢集,這種情況下只要開發者跟 Kubernetes 是同一台機器,那基本上 Docker Container Image 就可以共用。
48 |
49 | 架構如下圖所示
50 |
51 | 
52 |
53 | 開發者產生的 Container Image 可以直接給同台機器上面的 Kubernetes 使用,開發者唯一要處理的就只有部署過程中 (Yaml/Helm) 所描述的 Image Name 而已。
54 |
55 |
56 |
57 | 上述的便利性是建立在開發者使用的環境與 Kubeadm 架設的環境是同個機器上,如果 Kubeadm 本身也建立多節點叢集,那這種便利性就不存在,必須要用額外的方法來處理。
58 |
59 |
60 |
61 | ## KIND/K3D
62 |
63 | 如果今天採用的是 KIND/K3D 這類型基於 Docker 而部署的 Kubernetes 架構,那整個架構就會有點不同,如下圖。
64 |
65 | 
66 |
67 |
68 |
69 | 當開發者建立起 Container Image 後,這些 Image 是屬於本地端,然而 KIND/K3D 的環境都是基於 Docker,這意味者如果要在 KIND/K3D 的環境中跑起開發者的 Container Image, 勢必要把這些 Contaienr Image 給複製到 Kubernetes Node 中,也就是那些 Docker,所以其實背後使用到的是 Docker in Docker 的技術,基於 Docker 所創建立的 Kubernests 裡面再根據 Docker Image 去創建 Pod(Containers)。
70 |
71 |
72 |
73 | 這部分如果使用的是 `KIND` 指令的話,其本身有特別提供一個功能來幫助使用者把本地端的 Image 給快速地送到 `KIND` 建立的叢集裡面
74 |
75 | ```bash
76 | $ kind load
77 | Loads images into node from an archive or image on host
78 |
79 | Usage:
80 | kind load [command]
81 |
82 | Available Commands:
83 | docker-image Loads docker image from host into nodes
84 | image-archive Loads docker image from archive into nodes
85 |
86 | Flags:
87 | -h, --help help for load
88 |
89 | Global Flags:
90 | --loglevel string DEPRECATED: see -v instead
91 | -q, --quiet silence all stderr output
92 | -v, --verbosity int32 info log verbosity
93 |
94 | Use "kind load [command] --help" for more information about a command.
95 | ```
96 |
97 | 可以看到 kind 支援兩種格式的 container image, 一種是直接從當前節點已知的 comtainer image,另外一種則是從被打包壓縮過的 image 格式。 KIND 可以將這兩種格式的 container 給送到 KIND 裡面。
98 |
99 |
100 |
101 | 首先,我們先來觀察一下預設情況下, KIND 架構中的 `docker` 有哪些 `contaienr image`
102 |
103 | ```bash
104 | $ docker exec -it kind-worker crictl image
105 | IMAGE TAG IMAGE ID SIZE
106 | docker.io/kindest/kindnetd 0.5.4 2186a1a396deb 113MB
107 | docker.io/rancher/local-path-provisioner v0.0.11 9d12f9848b99f 36.5MB
108 | k8s.gcr.io/coredns 1.6.5 70f311871ae12 41.7MB
109 | k8s.gcr.io/debian-base v2.0.0 9bd6154724425 53.9MB
110 | k8s.gcr.io/etcd 3.4.3-0 303ce5db0e90d 290MB
111 | k8s.gcr.io/kube-apiserver v1.17.0 134ad2332e042 144MB
112 | k8s.gcr.io/kube-controller-manager v1.17.0 7818d75a7d002 131MB
113 | k8s.gcr.io/kube-proxy v1.17.0 551eaeb500fda 132MB
114 | k8s.gcr.io/kube-scheduler v1.17.0 09a204f38b41d 112MB
115 | k8s.gcr.io/pause 3.1 da86e6ba6ca19 746kB
116 | ```
117 |
118 | 這邊要特別注意的是, KIND 其實並不是在 docker 內使用 dockerd 作為 Kubernetes 的 container runtime,而是採用 containerd ,因此系統上並沒有 `docker` 指令可以使用,取而代之的是我們要使用 `crictl` (container runtime interface control) 這個指令來觀察 container 的資訊。
119 |
120 | 透過 `crictl image` 可以觀察到預設情況下有的都是 `kubernetes` 會使用到的 container image 以及二個由 KIND 所安裝的 image, `kindnetd`(CNI) 以及 `local-path-provisioner` (storageclass for hostpath).
121 |
122 |
123 |
124 | 接下來假設本機上面有一個 `postgres:10.8` 的 container image, 我們透過 `kind load` 的指令將其傳送到 `KIND` 叢集裡面
125 |
126 | ```bash=
127 | $ kind load docker-image postgres:10.8
128 | Image: "postgres:10.8" with ID "sha256:83986f6d271a23ee6200ee7857d1c1c8504febdb3550ea31be2cc387e200055e" not present on node "kind-worker2"
129 | Image: "postgres:10.8" with ID "sha256:83986f6d271a23ee6200ee7857d1c1c8504febdb3550ea31be2cc387e200055e" not present on node "kind-control-plane"
130 | Image: "postgres:10.8" with ID "sha256:83986f6d271a23ee6200ee7857d1c1c8504febdb3550ea31be2cc387e200055e" not present on node "kind-worker"
131 | ```
132 |
133 | 上述的指令描述說,因為系統上目前不存在,所以要開始複製,當一切就緒後再次透過 `crictl` 指令來觀察,就可以看到這時候 `postgres:10.8` 這個 container image 已經放進去了。
134 |
135 | ```bash
136 | $ docker exec -it kind-worker crictl image
137 | IMAGE TAG IMAGE ID SIZE
138 | docker.io/kindest/kindnetd 0.5.4 2186a1a396deb 113MB
139 | docker.io/library/postgres 10.8 83986f6d271a2 237MB
140 | docker.io/rancher/local-path-provisioner v0.0.11 9d12f9848b99f 36.5MB
141 | k8s.gcr.io/coredns 1.6.5 70f311871ae12 41.7MB
142 | k8s.gcr.io/debian-base v2.0.0 9bd6154724425 53.9MB
143 | k8s.gcr.io/etcd 3.4.3-0 303ce5db0e90d 290MB
144 | k8s.gcr.io/kube-apiserver v1.17.0 134ad2332e042 144MB
145 | k8s.gcr.io/kube-controller-manager v1.17.0 7818d75a7d002 131MB
146 | k8s.gcr.io/kube-proxy v1.17.0 551eaeb500fda 132MB
147 | k8s.gcr.io/kube-scheduler v1.17.0 09a204f38b41d 112MB
148 | k8s.gcr.io/pause 3.1 da86e6ba6ca19 746kB
149 | ```
150 |
151 |
152 |
153 | 透過上述的流程我們就可以很順利的將本地開發的 Image 給快速的載入到 KIND 建立的 Kubernetes 叢集中,又不需要將 Container Image 給傳送到遠方 Registry 花費如此冗長的傳輸時間,整個開發效率上會提升不少。
154 |
155 |
--------------------------------------------------------------------------------
/2020/overview/day1.md:
--------------------------------------------------------------------------------
1 | Day 1 - DevOps 與 Kubernetes 的愛恨情仇
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 這次的鐵人賽的題目則著重於 Kubernetes 與 DevOps 之間的關係, DevOps 這詞發展多年以來,似乎成為一個顯學
11 | 每間公司都會朗朗上口需要招聘專門負責 DevOps 的人,工作內容百百種,實在讓人難以一言就斷定到底什麼是 DevOps。
12 |
13 | 本次系列文則不會針對 DevOps 去進行細部探討,到底 DevOps 的日常生活中可能會有哪些事情要處理,相反的
14 | 本系列文主要會針對 `CI/CD` 的流程去探討,看看當 CI/CD 與 Kubernetes 整合的過程中,要怎麼處理
15 |
16 | 舉例來說,一個最大的差別就是當所有應用程式都容器化後,要如何透過 `CI/CD` 流水線將新版本部署到 Kubernetes 之中
17 | 這中間有哪些議題可以探討,針對不同議題有哪些解決方案可以使用,以及這些解決方案彼此的優缺點
18 |
19 | 下圖是一個參考流程,從開發階段到部署階段中, Kubernetes 可能會扮演哪些角色,而 `CI/CD` 流水線則會跟哪些角色有所互動
20 |
21 | 
22 |
23 |
24 |
25 | 上次的流程中有非常多的環節可以探討,每個環節中都有不同的解決方案與取捨,這些歡節包含
26 |
27 | 1. Kubernetes 內的應用程式該如何包裝? 原生 Yaml 還是 Helm?
28 | 2. 本地開發者需要 Kubernetes 來測試 Kubernetes 嗎?
29 | 3. CI 流水線系統要選擇哪一套? 流水線工作要如何被觸發?
30 | 4. CI 流水線過程中,需要 Kubernetes 來測試應用程式嗎 ?
31 | 5. Container Registry 要使用雲端服務還是要自架,自架的話該怎麼使用以及如何與 Kubernetes 整合
32 | 6. CD 流水線系統要選擇哪一套? 流水線工作要如何被觸發?
33 | 7. CD 流水線過程中,要怎麼將應用程式更新到遠方 Kubernetes? 雲端架構或是地端架構會有什麼差異
34 | 8. CD 更新過程中,如果有機密資料,該怎麼處理
35 |
36 |
37 |
38 | 接下來的章節會針對上述環節進行介紹,每個環節都會透過下述流程來介紹
39 |
40 | 1. 概念介紹
41 | 2. 相關專案介紹
42 | 3. 使用範例
43 |
44 |
45 |
46 | 再次強調,上面的流程圖不是一個唯一的流程圖,而是一個範例,真正的運作流程都會根據不同的環境與需求而有所差異
47 | 但是選擇跟設計解決方案的思路則是不變的,透過培養思考的能力,才能夠遇到任何環境都有辦法構建出一套符合的解決流程。
--------------------------------------------------------------------------------
/2020/registry/day19.md:
--------------------------------------------------------------------------------
1 | Day 19 - Container Registry 的介紹及需求
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 |
11 |
12 | 本篇開始要來介紹一些 CI/CD 過程中都一定會用到的一個元件, Container Registry
13 |
14 | Container Registry 顧名思義就是用來保存 Container Image 的一個倉庫,我認為 Container Registry 也有一些有趣的議題可以探討,譬如說
15 |
16 | 1. 要使用 SaaS 服務還是自己架設
17 | 2. 是否支持 Private registry
18 | 3. 多人合作下是否支持權限控管
19 | 4. 是否有 web hook 可以與後續的 pipeline 或是其他系統連動
20 | 5. 跟 Git 等相關專案是否有自動連動與處理
21 | 6. 是否支援弱點掃描,可以用來檢查當前 Registry 內的 image 是否有潛在安全性的問題
22 |
23 |
24 |
25 | 上述的每個議題也都滿有趣的,我們可以先來聊聊 (1) 這個議題到底有什麼要探討的地方
26 |
27 | 我認為近8年大部分踏入容器化世界的開發者或使用者,第一個接觸的解決方案基本上都是 Docker Container,後續開始使用時通常都會使用 Docker Hub 這個由 Docker 所提供的 Container Registry 作為第一個接觸的 Contaienr Registry 解決方案。
28 |
29 | Docker Hub 使用起來,我認為算是非常方便,特別是跟 GitHub/Bitbucket 的連動非常輕鬆設定,通常只要在專案內準備一個 Dockerfile 的檔案,就可以讓 Docker Hub 自動地幫你部署相關的 Image 並且存放到 Docker Hub 上。
30 |
31 | 這種情況下對於一些要準備自己 Image 的開發者來說非常便利,都不需要額外的 CI Pipeline 系統來處理,只要將程式碼合併,等待一段時間後相關的 Image 就出現了。
32 |
33 | 然而隨者專案的擴大,使用環境的改變, Docker Hub 並不一定可以適合所有情境
34 |
35 | 舉例來說,很多落地的工作環境中,會基於保密,機密等安全性要求,不希望運行的 Contianer Image 放置雲端,這時候就會思考是否有辦法自架一個本地端的 Container Registry。
36 |
37 | 此外更多的情境是網路問題,因為 Container Image 的容量說大不大,說小不小,幾百 MB 到幾 GB 都有,如果遇到網路速度瓶頸問題,就會發生抓一個 Image 花上長時間等待。 這部分的問題其實常常看到,舉例來說
38 |
39 | [Extremely Slow Image Pulls](https://github.com/docker/hub-feedback/issues/1675)
40 |
41 | [hub-feedback issue about slow](https://github.com/docker/hub-feedback/issues?q=is%3Aissue+is%3Aopen+slow)
42 |
43 | 這些連結都可以看到滿滿的關於下載速度的問題,有時候還會牽扯到 docker hub CDN 的問題,問題發生的時候還真的什麼都不能做,只能祈禱 docker hub 快點修復。
44 |
45 |
46 |
47 | # Docker Hub 方案比較
48 |
49 | 此外,部分工作團隊也會有一些 contaienr image 的需求,但是又不想要公開相關的內容,這時候會需要 private registry 的支援,可惜的是對於 Docker Hub 來說,這部分會取決於方案的選擇,譬如下圖的[方案比較](https://www.docker.com/pricing)
50 |
51 |
52 |
53 | 免費方案只能有一個 Private,付費又會取決於你是個人用戶還是一個團隊,對於團隊來說,其價格還會根據使用者數量而有所增加,
54 |
55 | 所以如果今天團隊內會希望根據架構有不同的權限控管,因此使用者的數量可能會有不少的時候,整個成本又會大幅度增加。
56 |
57 | 
58 |
59 |
60 |
61 | 總總考量之下,自架 Container Registry 的需求就會逐漸出現,不論是為了成本,為了功能或是其他因素, SaaS 與 自架的選擇從來沒有
62 |
63 | 停止過,就如同之前探討 pipeline 系統一樣,每個系統都會有 SaaS 與自架的需求比較,但是哪一種比較適合貴團隊就沒有答案
64 |
65 | 此外,不同的開源專案提供的 container registry 的功能也都不盡相同,這種情況下就需要有人去針對每套軟體進行評估,找出一套適合自己團隊的服務,或是最後轉回使用 SaaS 商用解決方案都有可能。
66 |
67 |
68 |
69 | # DockerHub 使用者條款
70 |
71 | 最後要提的是,使用 SaaS 服務也不是就沒有完全痛點,譬如 2020 八月份 Docker Hub 的[使用者條款更新](https://www.docker.com/legal/docker-terms-service),該更新中有幾個更動令很多無付費使用者都在思考該怎麼處理,是否要轉換到其他的 SaaS 服務或是都要改成自架來處理。主要更新有
72 |
73 | 1. 當一個 Image repository 六個月內沒有任何動作(push/pull),則該 image repository 會被自動刪除
74 | 2. 針對無認證用戶或是免費版本用戶有下載量的限制。
75 | 1. 無認證用戶每六小時只能 Pull Image 100 次
76 | 2. 認證的免費用戶每六小時只能 pull 200 次
77 |
78 | 對於很多使用者或是開發者來說,這兩個問題都會造成一些使用上的困擾,特別是 (2) 的限制,因此不少人開始思考要如何於不花錢的情況下解決這些問題,譬如 [avoiding the docker hub retention limit](https://poweruser.blog/avoiding-the-docker-hub-retention-limit-e18cdcacdfde), 或是轉戰到其他的 SaaS。
79 |
80 | 只能說天下沒有白吃的午餐,享受免費方案的同時,也要多注意所謂的使用者條款,如果發現這些條款的修正會影響自己的使用情境,可能就要開始考慮搬移,自架或是付費等選擇
81 |
82 | 接下來的文章,我們就會探討自架 Contaienr Registry 的各種選擇與示範,最後會在展示如何將自架 Contianer Registry 與 Kubernetes 結合,讓你的 Kubernetes 叢集能夠接受 Docker Hub 以外的 Contaeinr Registry.
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/2020/registry/day20.md:
--------------------------------------------------------------------------------
1 | Day 20 - Container Registry 的方案介紹
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 本篇文章要來跟大家分享其他 Contaienr Registry 的選擇及相關議題,這些議題包含(包含但不限於)
11 |
12 | 1. 使用者登入權限控管與整合
13 |
14 | 2. 硬碟空間處理機制
15 |
16 | > Registry 的空間處理問題非常重要,處理不好很容易造成使用者沒有辦法繼續推送 Image
17 |
18 | 3. UI 介面的操作
19 | 4. 潛在漏洞與安全性檢查
20 | 5. SSL 憑證的支援性
21 |
22 | 此外這邊要特別注意,自架 Container Registry 不一定是免費的,有時候自架的會需要有相關授權等花費。 SaaS 不一定要錢,只是免費的通常都會有一些限定
23 |
24 | 接下來我們就來看一下方案介紹與比較
25 |
26 | # Docker Registry 2.0
27 |
28 | Docker Registry 2.0 是由 `Docker` 所維護的開源專案,提供開發者一個自架 Docker Registry 的選項,使用上非常簡單,透過 Docker Container 的方式就可以輕鬆創建出一個 docker registry 2.0 的服務器。
29 |
30 | 舉例來說,下列指令就可以創建完畢
31 |
32 | ```bash
33 | $ docker run -d -p 5000:5000 --restart always --name registry registry:2
34 | ```
35 |
36 | 不過我個人對於 docker registry 沒有很愛,主要是其預設情況下並沒有提供任何 UI 的支援,一切的操控都只能透過 docker 指令或是 curl 等指令來處理,對於多人控管以及操作上非常不便利。
37 |
38 | 網路上也有相關的專案,譬如 [docker-registry-ui](https://github.com/Joxit/docker-registry-ui) 這些第三方專案在幫忙實作 UI,讓使用者有一個比較好的方式可以管理,但是這種情況下會變成 UI 與 Server 兩個程式是由不同的維護團隊在維護,功能上的整合, Issue 的問題等都不一定夠順暢,所以如果不是為了本地簡單測試的情況下,我通常不會採用 Docker Registry 作為一個長期的解決方案。
39 |
40 | 儲存方面, [Customize the storage location](https://docs.docker.com/registry/deploying/#support-for-lets-encrypt) 以及 [Customize the stoage back-end](https://docs.docker.com/registry/deploying/#customize-the-storage-back-end) 等來自官方的文章再介紹相關的設定
41 |
42 | 對於外部存取的話,其也有支援 [Let's Encrypt](https://docs.docker.com/registry/configuration/#letsencrypt) 等機制,讓其自動幫你 renew 快過期的憑證,使用上相對方便。
43 |
44 | 權限認證方面我認為功能比較少,滿多的認證方式都需要自行透過額外的伺服器幫忙處理,可以參考 [restricting-access](https://docs.docker.com/registry/deploying/#restricting-access) 或是 [reverse proxy + SSL + LDAP for Docker Registry](https://medium.com/@two.oes/reverse-proxy-ssl-ldap-for-docker-registry-805539daaa94)
45 |
46 | # Harbor
47 |
48 | Harbor 是由 VMWare 所開源的 Container Registry 專案,我認為 Harbor 一個很值得推薦的原因是該專案是 [CNCF 畢業專案](https://www.cncf.io/projects/),要成為 CNCF 畢業專案必須要滿足一些條件,雖然沒有一個專案可以完美的適合所有情形,但是就社群使用程度與社群貢獻程度來看, Harbor 算是滿優良的,這部分至少可以證明其本身是不少使用者在使用,而不是一個乏人問津的專案。
49 |
50 | Harbor 的目標很簡單,源自期[官網](https://goharbor.io/)的介紹
51 |
52 | > Our mission is to be the trusted cloud native repository for Kubernetes
53 |
54 | Harbor 本身使用上不會太困難,可以透更 docker-compose 的方式去安裝,同時本身也有提供簡單的 UI 供使用操作,
55 |
56 | 詳細的架構可以參考這個 [Architecture Overview of Harbor](https://github.com/goharbor/harbor/wiki/Architecture-Overview-of-Harbor), 大概條列一下幾個重點功能
57 |
58 | 1. 登入授權方式支援 LDAP/AD 以及 OIDC(OpenID Connect),基本上銜接到 OIDC 就可以支援超多種登入,譬如 google, microsoft, saml, github, gitlab 等眾多方式都有機會整合進來
59 | 2. Harbor v2.0 架構大改,成為一個 OCI (Open Container Initiative) 相容的 Artifacct Registry, 這意味者 Harbor 不單純只是一個 Container Image Registry,而是只要符合 OCI 檔案格式的產物都可以存放,影響最大的就是 Helm3 的打包內容。 未來是有機會透過一個 Harbor 來同時維護 Container Image 以及 Helm Charts
60 | 3. 支援不同的潛在安全性掃描引擎
61 | 4. 本身可跟其他知名的 Container Registry 進行連動,譬如複製,或是中繼轉發都可以
62 | 5. 除此之外還有很多特性,有興趣的點選上方連結瞭解更多
63 |
64 | 
65 |
66 |
67 |
68 | # Cloud Provider Registry
69 |
70 | 三大公有雲 Azure, AWS, GCP 都有針對自己的平台提供基於雲端的 Container Registry,使用這些 Registry 的好處就是他們與自家的運算平台都會有良好的整合,同時服務方面也會有比較好的支援。
71 |
72 | 當然這些 SaaS 服務本身都會有免費與收費版本,就拿 [AWS(ECR)](https://aws.amazon.com/ecr/pricing/) 為範例,一開始會有一個嚐鮮方案,大概是每個月有 500GB 的容量使用,但是接下來更多的容量就會開始計費,計費的方式則是用(1)容量計費,每多少 GB 多少錢,(2)流量計費,流量的價錢是一個區間價格,使用愈高後的單位平均價格愈低。
73 |
74 | 
75 |
76 | 就如同之前提過,使用 SaaS 服務有很多的優點,包含不需要自行維護伺服器,從軟體到硬體都可以全部交由服務供應商去處理,自己只要專心處理應用的邏輯即可,但是成本考量就是一個需要注意的事項。
77 |
78 |
79 |
80 | # Others
81 |
82 | 除此之外還有不少專案有提供 Self-Hosted 的服務,譬如由 SUSE 所維護的開源專案 [Portus](http://port.us.org/) ,其專注整合 Docker Registry 並提供友善的介面與更多進階的功能,譬如 LDAP 控管,更進階的搜尋等。
83 |
84 | > ### [Portus](https://github.com/SUSE/Portus) is an open source authorization service and user interface for the next generation Docker Registry.
85 |
86 | 不過觀察該專案的[Github](https://github.com/SUSE/Portus) 顯示已經數個月沒有更新,甚至其最新的 Issue 都在探討是否該專案已經被放棄,[Is Portus no longer being worked on](https://github.com/SUSE/Portus/issues/2313), 有其他網友發現 SUSE 後來開了一個新的專案 [harbor-helm](https://github.com/SUSE/registry/tree/master/harbor-helm),大膽猜測可能 SUSE 也在研究採用 Harbor 作為其容器管理平台而放棄自主研發的 Portus。
87 |
88 | 如果本身已經是使用 Gitlab 的團隊,可以考慮直接使用 [GItlab Container Registry](https://docs.gitlab.com/ee/administration/packages/container_registry.html#enable-the-container-registry),其直接整合 Gitlab 與 Docker Registry 提供了良好的介面讓你控管 Container Registry,好處是可以將程式碼的管理與 Image 的管理都同時透過 Gitlab 來整合。
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/2020/resources/day30.md:
--------------------------------------------------------------------------------
1 | Day 30 - 相關資源分享
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 最後則是來跟大家介紹一些個人的資源以及台灣相關社群分享,我認為參加社群是一個滿不錯的學習方式,因為每個人的時間有限,一天只有 24 小時,如果有看過 [CNCF landscap](https://landscape.cncf.io/selected=weave-scope) 就知道, CNCF 內滿坑滿的領域,而領域內都有超多專案。
11 |
12 | 一個人的力量根本沒有辦法看完全部,如果今天有人願意免費分享一些踩雷經驗,也許是你有用過的軟體,你可以互相學習看看是否能夠把什麼經驗融入到自己的工作環境。如果是沒有用過的軟體,就當作有人快速幫你介紹一輪,讓你至少對該軟體會有一個印象。
13 |
14 | 
15 |
16 |
17 |
18 | 所以這邊跟大家介紹一個台灣在地社團, [Cloud Native Taiwan User Group](https://www.facebook.com/groups/cloudnative.tw)(CNTUG), 基本上每個月都會有一場線下社群活動,歡迎有興趣的人可以關注該社團
19 |
20 | Facebook 連結: [Cloud Native Taiwan User Group](https://www.facebook.com/groups/cloudnative.tw)
21 |
22 | Telegram 連結: https://t.me/cntug
23 |
24 | Meetups 連結: https://www.meetup.com/CloudNative-Taiwan
25 |
26 | Github 投影片連結: https://github.com/cloud-native-taiwan/meetups
27 |
28 |
29 |
30 | 我個人則有相關的技術資源
31 |
32 | Blog: https://www.hwchiu.com/
33 |
34 | 線上演講影片: https://www.youtube.com/channel/UCoYY8K9fbfDtTY7m68UCATA/videos
35 |
36 | 個人技術推廣頁面: https://www.facebook.com/technologynoteniu
37 |
38 | Telegram 技術推播頻道: https://t.me/technologynote
39 |
40 | 去年 ITHOME 參賽文章: https://www.hwchiu.com/tags/ITHOME/page/3/
41 |
42 | > 主要探討 Kubernetes 底層的各種實作介面,從 CRI/CNI/CSI 聊到 Device Plugin
--------------------------------------------------------------------------------
/2020/secret/day23.md:
--------------------------------------------------------------------------------
1 | Day 23 - Secret 的部署問題與參考解法(上)
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 本篇文章要來探討 CI/CD 部署的最後一個環節,來探討機密資訊的部署問題。
11 |
12 | CI/CD pipeline 的設計,讓管理員可以手動觸發這些部署工作流,或是透過其他機制去觸發,最後都可以讓 pipeline 自動化的去完成 CI
13 |
14 | 與 CD 的動作。
15 |
16 | 然而就是這些自動化的步驟,帶來了一些額外的隱憂,對於一個基於自動化運行的程式,要如何將機密資訊,如應用程式帳號密碼,存取
17 |
18 | 的 Key/Token 給套入到每個環節,又不希望這些資訊外流實屬一個挑戰。同時也要避免這些機密資訊被存放到 log 之中,盡可能地減少
19 |
20 | 任何會曝光這些機密資訊的機會。
21 |
22 | 此外,除了 pipeline 系統的架構外,如何包裝應用程式也會是一個問題,譬如使用原生的 Yaml, Kustomize 或是 Helm,不同的工具都有不同的解法。
23 |
24 |
25 |
26 | 就我個人的瞭解,至少有三種參考架構可以解決這些問題(不一定完美,但是可以稍微處理)
27 |
28 |
29 |
30 | # 前提
31 |
32 | 開始探討架構前,我們先來假設幾個部署情境,接下來的架構都會去思考是否可以滿足這個應用
33 |
34 | ### Helm
35 |
36 | 試想一個範例,我們的應用程式由 Helm 組成,會透過讀取檔案(Kubernetes Secret)的方式來獲取遠方資料庫的密碼。
37 |
38 | 今天要透過 Helm 部署這個應用程式的時候,我們會透過準備自己的 values.yaml 或是透過 `--set dbpassword=xxx` 等方式來客製化這個 secret 檔案,最後把全部的內容送到 Kubernetes 裡面。
39 |
40 | ### 原生 Yaml
41 |
42 | 如果是原生 Yaml 的情況下,我們沒有 `--set` 這類型的東西可以使用,變成我們要透過腳本的方式自行實現類似 Go-Template 的方法,或是動態產生一個 Secret 來使用。這部分不會太困難,只是就會讓人覺得有沒有更好的解決方案
43 |
44 | ### Kustomize
45 |
46 | 基本上 Kustomize 是基於 overlay 的概念去組合出最後的 Yaml 檔案,所以作法跟原生 Yaml非常類似,好加在 Kustomize 本身有提供 `secretGenerator` 的語法,讓你更輕鬆的產生 Kubernetes Secret 物件檔案
47 |
48 | ```bash
49 | cat <<'EOF' > ./kustomization.yaml
50 | secretGenerator:
51 | - name: mysecrets
52 | envs:
53 | - foo.env
54 | files:
55 | - longsecret.txt
56 | literals:
57 | - FRUIT=apple
58 | - VEGETABLE=carrot
59 | EOF
60 | ```
61 |
62 |
63 |
64 | # Pipeline System
65 |
66 | 第一種架構是 Pipeline 系統本身有提供一些機密資訊的保護,譬如 Jenkins, Github Action, CircleCI..等。 系統中有一塊特別的資訊,讓使用者可以填入想要的 key:value 的數值,然後於 Pipeline 運作過程中,可以透過一些該平台限定的語法來取得。舉例來說
67 |
68 |
69 |
70 | ### Github Action
71 |
72 | 使用者先在專案列表中,把你想要用到的 key:value 加進去,接下來於 Github Action workflow 中使用 `{{ secrets.xxxxx }} `的方式可以取出這些數值,然後這類型的數值再運行的 log 中會被系統給過濾掉,以 `****` 的方式呈現。
73 |
74 | ```yaml
75 | steps:
76 | - name: Hello world action
77 | with: # Set the secret as an input
78 | super_secret: ${{ secrets.SuperSecret }}
79 | env: # Or as an environment variable
80 | super_secret: ${{ secrets.SuperSecret }}
81 | ```
82 |
83 | 其他的如 Jenkins/CircleCI 等不同系統都有一樣的機制可以使用,但是這種用法對於我們的 Kubernetes 應用程式來說要怎麼整合?
84 |
85 |
86 |
87 | 接下來我們嘗試將上述三種情境套入到這個架構中,看看會怎麼執行
88 |
89 | ### Helm
90 |
91 | 1. CI/CD pipeline 運行到後面階段後,從系統中取出資料庫的帳號密碼,假設這個變數叫做 `$password`
92 | 2. 接下來要透過 `helm` 的方式來安裝我們的應用程式,因此會執行 `helm upgrade --install --set dbpassword=$password .` 等類似這樣的指令產生出最後的 secret 以及 pod,然後一起部署到 Kubernetes 裡面
93 |
94 | ### Kustomize
95 |
96 | 1. CI/CD pipeline 運行到後面階段後,從系統中取出資料庫的帳號密碼,假設這個變數叫做 `$password`
97 | 2. 接下來透過腳本的方式,產生對應的 `secretGenerator` 寫入到相關的 Yaml 之中,之後呼叫 `kubectl -k` 以及 `kustomize ` 這兩個指令最後去部署
98 |
99 | ### 原生 Yaml
100 |
101 | 1. CI/CD pipeline 運行到後面階段後,從系統中取出資料庫的帳號密碼,假設這個變數叫做 `$password`
102 | 2. 接下來透過 `kubectl create secret ...... -o yaml` 的方式產生對應的 Yaml 檔案,然後跟剩餘的內容一起部署到 kubernetes 內部
103 |
104 |
105 |
106 | 這樣的流程看起來似乎沒有問題,但是我認為有幾個地方要注意
107 |
108 | 1. 假設今天應用程式需要用到的機密資訊很多,譬如 db_table, db_username, db_password, 甚至一些連接其他服務的帳號密碼,可能需要設定的東西就會非常多,變成你的 pipeline 那邊的設定變得非常多,同時大部分的 pipeline 系統都不會讓你編輯,有要修改就要整條換掉,同時通常也不會顯示明碼給你。
109 | 2. 呈上,當你要使用一個 pipeline 系統對應多個環境,譬如 dev/QA/staging/production 等多環境,你上述的變數量就會直接翻倍,然後那邊的數量就愈來愈多
110 | 3. 上述 `helm upgrade --install ...` 的部分一定是於 shell 去執行,這時候如果有些應用程式需要的機密資料本身就有雙引號,單引號等討人厭字元,就要特別注意跳脫的問題。我過往還遇過某些機密資訊本身是由一個 JSON 檔案組成的,裡面可說是雙引號滿天下,這時候的處理就變得非常頭疼
111 | 4. 今天這個作法是將機密資訊於 pipeline 系統來處理,但是如果採用的 GitOps 的做法,那就不會有 CD pipeline,因此這種解法也不可行。
112 | 5. 如果今天因為一些需求,需要替換整個 pipeline 系統,那管理人員會覺得很崩潰,因為整個系統要大搬移。
113 |
114 |
115 |
116 | 整個流程如下圖
117 |
118 | 
119 |
120 |
121 |
122 | 今天我們就先探討這個架構,下一篇文章我們再來探討別的架構會如何解決這個問題
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/2020/secret/day24.md:
--------------------------------------------------------------------------------
1 | Day 24 - Secret 的部署問題與參考解法(下)
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 前篇文章中我們探討了 CI/CD 自動化部屬中機密資訊的保存與使用議題,介紹了第一種透過 Pipeline 架構本身來處理問題,同時也探討了潛在的隱憂,而今天這篇我們將繼續從不同的架構下繼續探討解決方案
11 |
12 |
13 |
14 | 開始之前,我們先複習一下,我們會有三個使用情境, `Helm`, `原生 Yaml` 以及 `Kustomize`
15 |
16 | # Centralized Management
17 |
18 | 這種架構會有一個 Secret 的管理者,這個管理者所在的位置影響不太大,主要問題是取決於什麼時間點使用這個管理者。
19 |
20 | 相較於上一篇的架構,將這個 secret 管理者從 pipeline 系統抽離的一個好處就是我們把存取機密資訊的用法與 pipeline 系統脫離,因此未來如果需要轉換到不同平台,所花費的時間與成本會少很多,因為大部分的東西都可以共用。
21 |
22 | 今天這個架構的重點是,我們將產生 secret 的發生地點往後延遲,從本來的 pipeline 系統推遲到 kubernetes 內部,當應用程式真正要部署的時候才會去動態產生這些 secret 的檔案。
23 |
24 | 上述是一個概念,但是實作上可以有不同做法,舉一個範例就是,Pod 本身先賦予相關的權限能力,讓其有能力跟 Secret 管理者溝通,然後部署 Pod 的時候要去描述說 `資料庫的密碼放在什麼地方,什麼路徑`,接下來 Pod 把這些資訊拿去問給 Secret 管理者,然後管理者回覆這些資訊。
25 |
26 | 也可以有不同做法是 Pod 本身其實不知道後面是接什麼系統,總之他相信會有人給他一些設定檔案,然後我們有額外的其他應用程式,或是 sidecar container 會幫忙去問 secret 管理者,問完後就產生出最後的設定檔案給應用程式使用。
27 |
28 | 後者的做法比前者更好,因為對於應用程式來說,我們隱藏了背後的運作細節,這使得開發者比較容易本地端開發,用一個簡單的設定檔案就可以建立環境,同時未來要遷移到不同系統時,要改變的只有維護團隊以及那些 sidecar 的運作模式,應用程式本身邏輯都不需要更動。
29 |
30 |
31 |
32 | 接下來我們嘗試將上述三種情境套入到這個架構中,看看會怎麼執行
33 |
34 | ### Helm
35 |
36 | 1. 一開始 Helm 裡面就要準備好相關的設定檔案,包含帳號密碼要用什麼東西問等,這部分取決於實作的需求
37 | 2. CI/CD pipeline 運行到後面階段後,沒有什麼事情要特別處理,因此直接透過 `helm upgrade --install ...` 的方式部署到 kubernetes內部
38 | 3. 當應用程式部署進去後,應用程式或是 sidecar 就會根據當前的設定去詢問需要的機密資訊,最後產生相對應的檔案給應用程式讀取
39 |
40 | ### Kustomize/Yaml
41 |
42 | 1. 基本上這兩者的做法一樣,其實也跟 Helm 差不多,因為不需要於 pipeline 系統中動態取得這些機密資訊,所以這個步驟也不太需要客製化。
43 | 2. 一切的運作邏輯跟 Helm 一樣,只要確保部署進去的資源能夠與 secret 管理者溝通即可。
44 |
45 |
46 |
47 | 這種架構下帶來的好處有
48 |
49 | 1. 因為與 pipeline 的部分都抽離了,所以 GItOps 就有機會實現
50 | 2. 大部分機密資訊的保存與管理都跟 pipeline 系統無關,要抽換容易
51 | 3. 這類型 secret 管理者的介面跟操作能力都比 pipeline 系統提供的介面強超級多,用起來相對彈性
52 | 4. 使用上與設計上稍嫌複雜,同時 secret 管理者的存活要自己負責,如果要設計 HA 的架構就要花一些心思去探索
53 |
54 |
55 |
56 | 
57 |
58 |
59 |
60 | # Centralized Management(ii)
61 |
62 | 這種架構是上一種的不同實作方式,就如同所說的其實 secret manager 位置放在哪邊不是重點,重點是什麼時間點去呼叫來取得資訊。
63 |
64 | 如果今天我們依然還是在 Pipeline 系統中去取得這些資訊,那基本上我們還是會得到跟第一篇架構一樣的結果。
65 |
66 | 由於這類型的服務本身也需要一些 token/key 才可以存取,而現在存取的時間點是 pipeline 系統上,所以我們只要利用 pipeline 系統本
67 |
68 | 身的管理機制去管理這些 token/key 即可。剩下應用程式所需要的機密資訊就跟遠方的 secret manager 去獲取即可。
69 |
70 |
71 |
72 | 但是這邊有一個要特別注意的地方,因為我們的 secret 管理者現在已經搬移到系統外面,所以 pipeline 系統對於你的各種操作都沒有辦
73 |
74 | 法辨認哪些東西是機密,哪些不是機密,因此 log 檔案會有機會將你的操作內容全部記錄下來,包含你的帳號與密碼。 這部分要特別小
75 |
76 | 心,避免這些資訊遺漏否則可能會釀成大禍。
77 |
78 |
79 |
80 | 之前提到的三個情境再這個架構下的實作方法大同小異,這邊就不再贅述,相關的隱憂基本上也都存在,只有搬移平台部分會是相對順
81 |
82 | 利,因為所有的存取方式與內容都與 pipeline 系統抽離。
83 |
84 |
85 |
86 | 
87 |
88 |
89 |
90 |
91 |
92 | # Encrption/Decryption
93 |
94 | 最後一個架構的做法是透過加解密的方式來記錄這些資訊,過往我們會擔心 Kubernetes Secret 的資訊是因為其本身只有 base64 編碼,並不是加密,因此實際上就是沒有安全性可言。
95 |
96 | 那如果我們有辦法把它變成加密後的結果,是否就會更有信心的放到 Yaml 上面,直接使用 Git 保存?
97 |
98 | 這個架構就是基於這樣的想法,其運作流程如下(概念,實作不一定)
99 |
100 | 1. Kubernetes 中要安裝一個 Controller,這個 Controller 會準備 key,這把 key 會用來加密跟解密
101 | 2. Kubernetes 中新增一個全新的物件,譬如叫做 Encrypted Secret,代表被加密後的 secret 資料。
102 | 3. 叢集管理者使用那把 key 將機密資料加密,得到加密後的結果,並且把這個結果寫到 EncryptedSecret 的 Yaml 中
103 | 4. 當未來這個 EncryptedSecret 被部署到叢集之中,該 Controller 就會偵測到,並且使用 key 去解密
104 | 5. 解密成功後就會把解密的內容產生一個 Secret ,這時候應用程式就可以去讀取來使用
105 |
106 |
107 |
108 | 簡單來說,上述的流程也是把取得機密內容的時間點延後到 Kubernetes 內部,只是他的做法是一開始加密,直到進入 Kubernetes 後就將其解密,最後得到真正資訊。
109 |
110 |
111 |
112 | 接下來我們嘗試將上述三種情境套入到這個架構中,看看會怎麼執行
113 |
114 | ### Helm
115 |
116 | 1. 一開始 Helm 裡面就要先透過 key 去加密,準備好一個 Encrypted Secret 的物件
117 | 2. CI/CD pipeline 運行到後面階段後,沒有什麼事情要特別處理,因此直接透過 `helm upgrade --install ...` 的方式部署到 kubernetes內部
118 | 3. 當應用程式部署進去後,該 controller 偵測到 Encrypted Secret 的出現,就會幫其解密,解密後產生對應的 secret 物件,然後應用程式去讀取
119 |
120 | ### Kustomize/Yaml
121 |
122 | 1. 基本上這兩者的做法一樣,其實也跟 Helm 差不多,因為不需要於 pipeline 系統中動態取得這些機密資訊,所以這個步驟也不太需要客製化。
123 | 2. 一切的運作邏輯跟 Helm 一樣,只要確保部署進去的資源能夠與 secret 管理者溝通即可。
124 |
125 |
126 |
127 | 這種架構帶來的好壞處有
128 |
129 | 1. 本身也不需要 CD pipeline 的參與,所以 GitOps 的概念可以實現
130 | 2. 如同上述架構一樣, Controller 的生命尤為重要,要保護好他的生命以及相關的 key
131 | 3. 機密資訊都直接存放到 Git 上面,每次要修改都要有對應權限的人去產生加密後的結果,有可能會讓工作效率比較低,但是安全性更高
132 |
133 | 
134 |
135 |
136 |
137 | 到這邊為止我們探討了數種可能的解決方式與架構,下一篇我們將實際操作一個範例來展示其用法
138 |
--------------------------------------------------------------------------------
/2020/summary/day29.md:
--------------------------------------------------------------------------------
1 | Day 29 - Summary
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
6 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
7 |
8 |
9 |
10 | 過去的 28 篇文章我們從頭到尾探討了以下這張圖片的種種議題,包含了
11 |
12 | 1. 如何管理 Kubernetes 應用程式,Helm/Kustomize/原生 Yaml
13 |
14 | 2. 本地開發者如果有 Kubernetes 使用的需求,那可以怎麼做
15 |
16 | 3. Pipeline 該怎麼選擇, SaaS 與自架各自的優劣
17 |
18 | 4. CI Pipeline 可以怎麼做,如果有 Kubernetes 的需求,那可以怎麼設計
19 |
20 | 5. CI pipeline 要如何對 Kubenretes 應用程式進行測試, Yaml 可以測試針對語法,語意等進行測試
21 |
22 | 6. CD pipeline 有哪一些做法,配上 Kubernetes 之後有哪些參考作法
23 |
24 | 7. GitOps 是什麼,相對於過往的部署方式,有什麼優劣
25 |
26 | 8. GitOps 與 Kubernetes 的整合,有哪些解決方案可以使用
27 |
28 | 9. Container Registry 的選擇,SaaS 與自架各自的優劣
29 |
30 | 10. 自架的 Container Registry 要怎麼與 Kubernetes 整合,有哪些點要注意
31 |
32 | 11. Secret 機密資訊於自動部署上要怎處理
33 |
34 | 12. Secret 機密部署與 Kubernetes 要如何處理
35 |
36 |
37 |
38 | 
39 |
40 | 事實上,上面每個議題都有跳不完的坑,每個議題都有好多的解決方案,不論是開源解決方案,或是商業付費方案,每個都有不同的場景,以及不同的時機去使用。
41 |
42 | 踏入一個新技術想要嘗試導入時,往往最困難的就是要如何在包山包海的選擇中,挑出一個最後的答案。
43 |
44 | 這部分吃的除了是技術的洞察力,透過觀察不同軟體的架構來判斷問題外,還有對於自己團隊工作流程的掌握力,一時之間選不出來的時
45 |
46 | 候,可能還需要針對不同專案進行嘗試,透過實際操作去觀察實際運用的情況,再加以輔佐來進行判斷。
47 |
48 | 就如同 CNCF End User Technology Radar 關於 Continuouse Delivery 調查報告中所說,很多人使用 Jenkins 是因為舊系統已經正在使用,實在是沒有什麼理由硬要把它拔掉,優劣權衡之後就決定舊系統繼續使用 Jenkins,但是對於很多全新的專案,因為是全新的環境,
49 |
50 | 就可以開始嘗試不同的解決方法。
51 |
52 | 該文章也提到,很多公司都嘗試過至少10個以上的解決方案在評估,最後就收斂到 3-4 個繼續穩定使用的專案,幾乎沒有公司是一個專案打天下,甚至很多大公司發現解決方案解決不了問題的時候,就會自己動手實作符合自己工作情境的軟體,甚至將其開源貢獻。
--------------------------------------------------------------------------------
/2021/day1.md:
--------------------------------------------------------------------------------
1 | Day 1 - 淺談 Kubernetes 的架設與管理
2 | =================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 |
13 | # Kubernetes
14 | 近年來 Kubernetes 的聲勢水漲船高,愈來愈多的產業與團隊都在思考是否要引入 Kubernetes 來取代舊有的部署平台。
15 | 導入 Kubernetes 自然而來就會產生兩個需要討論的問題
16 | 1. 團隊目前的環境需要使用 Kubernetes 嗎?
17 | 2. 如果需要使用 Kubernetes,該使用哪一套 Kubernetes ?
18 |
19 | 第一個問題看似簡單,其實非常困難,每個團隊原先的部署流程都是獨一無二且完全不同的,因此導入 Kubernetes 到底能夠帶來什麼樣的改變?
20 | 這類型的改變可能有
21 | 1. 團隊是否已經透過容器部署應用程式,如果沒有,那想要直接導入 Kubernetes 會是一個非常痛苦的過程,畢竟 Kubernetes 跟單純 Docker Container 的使用方式有非常大的差異,部署及管理的方式也困難很多
22 | 2. 團隊目前是採用公有雲的環境來部署還是自行維護機房? 三大公有雲基本上都有提供非常多的功能來提供使用者去部署應用程式,有些團隊單純依賴這些服務而不使用 Kubernetes,結果來看整體的運作流程也非常順暢
23 | 3. 團隊人員是否有足夠的技術與知識來使用 Kubernetes? 如果沒有則導入 Kubernetes 也會是一個很大的過渡期,訓練既有人員或是招聘新員工對公司來說都會有成本增加的考量。
24 | 4. 既有工作流程再導入 Kubernetes 之後是否會變輕鬆? 這部分可以再細分多個小節
25 | a. 團隊的服務是否已經有針對不同流量的水平擴展計畫?
26 | b. 網路流量要如何有效地處理,是否有 Load-Balancer 之類的可以自動地將流量導向後方服務?
27 | c. 開發跟維運人員要如何更新版本測試
28 |
29 | 所以作為團隊的領導者,切記不要跟風,千萬不要因為 kubernetes 是潮流就貿然採用 Kubernetes,我認為一個可以參考的做法是
30 | 1. 讓團隊中一個熟悉既有運作模式跟架構的員工去學習 Kubernetes
31 | 2. 找出團隊目前維運上的痛點
32 | 3. 比較 Kubernetes 如何解決維運上的痛點,這些痛點帶來的改善是否直得期待
33 | 4. 如果評估後認為轉換有價值,從小服務開始導入來測試,不要一口氣直接轉換
34 | 5. 也要注意混合過程中,部分服務是k8s,部分服務是原先架構的情況下會不會有什麼問題出現
35 |
36 | 假設今天決定想要導入 Kubernetes,則接下來談談如何管理與架設團隊的 Kubernetes 叢集
37 |
38 | # 如何管理 Kubernetes
39 |
40 | Kubernetes 本身是個開源專案,既然是個開源專案就意味使用者是有機會直接使用其開源版本的內容來架設屬於自己的 Kubernetes 叢集。
41 | 但是 Kubernetes 本身架構不算簡單,部署雖然容易但是長期的維護與除錯這部分需要仰賴對於 Kubernetes 的理解與經驗,特別是要與眾多服務進行整合時,整個難度又更高。
42 | 因此自然而然也會衍生出系統整合商的生意模式,提供一個更好使用且有技術支援的 Kubernetes 平台。
43 | 除此之外,公有雲本身也都有基於 Kubernetes 提供託管 Kubernetes 叢集的服務,譬如 Azure(AKS), GCP(GKE), AWS(EKS) 等,這類型的服務也都是要額外收費的。
44 |
45 | 我認為 Kubernetes 平台如何部署與架設,可以用下列的方式去分類
46 | 1. 如果團隊打算使用地端(on-premises)環境
47 | a. 直接於 bare-metal 的機器上使用開源專案來架設所有環境,譬如 K8s,必要時還可以先架設 VM
48 | b. 找尋相關的系統整合商,請對方提供整體的解決方案,從機器到 k8s 叢集等
49 | 2. 如果團隊打算使用雲端環境
50 | a. 直接使用雲端的 Kubernetes 服務
51 | b. 使用雲端的 VM 作為主體,上面使用開源專案幫忙架設 Kubernetes 並管理
52 | c. 找尋相關的系統整合商,請對方提供整體的解決方案,包含使用哪套雲端環境,如何架設 k8s 叢集等
53 |
54 | 不考慮人力的情況下,基本上1(a),2(b)的價格會是相對低的,畢竟你付錢取得機器,後續的架設與管理都要自行處理,其餘三個選項都會有額外的金錢成本來購買相對應的服務。
55 | 除了成本外還需要考慮到所謂的技術支援。技術支援本身也是需要錢的,團隊如果本身沒有辦法培養熟悉 Kubernetes 的人才,也許用錢買服務是相對簡單的方式。
56 | 這也是採用開源專案的一個痛點,畢竟純開源專案的情況下,遇到問題都需要仰賴團隊的工程師自行想辦法解決。
57 |
58 | 談了這麼多種變化,本次系列文沒有辦法針對所有可能都去探討與分析,處而代之的則是從開源的角度出發,去探討如果想要自行管理與維護整個 Kubernetes 叢集的話會有什麼選擇。
59 | 接下來將使用開源專案 Rancher 作為管理多套 Kubernetes 叢集的平台,Rancher 能夠針對上述的 1(a), 2(a,b) 等三個類別去處理,提供了一個友善且強大的管理介面,讓團隊可以輕鬆的去架設與管理多套 Kubernetes 叢集。
60 |
--------------------------------------------------------------------------------
/2021/day12.md:
--------------------------------------------------------------------------------
1 | Day 12 - Rancher 專案管理指南 - Project 概念介紹
2 | ============================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 | 前幾篇文章探討了如何透過 Rancher 操作與管理 Kubernetes 叢集,不論是直接抓取 Kubeconfig 或是使用網頁上的 web terminal 來操作,此外也探討了 Rancher 整合的應用程式,特別是最重要的 Monitoring 該如何使用。
14 |
15 | 有了上述的概念後,使用者已經可以順利的操作 Kubernetes 來部署各種服務。
16 | 不過 Rancher 想做的事情可沒有這麼簡單, Rancher 希望能夠強化 Kubernetes 讓其更佳適合給多位使用者共同使用了。
17 | 對於這種多租戶的概念, Kubernetes 提供了 namespace 的機制來達到資源隔離,不過 namespace 普遍上被認為是個輕量級的隔離技術,畢竟 namespace 主要是邏輯層面的隔離,底層的運算與網路資源基本上還是共用的。
18 |
19 | 就算是 RKE 也沒有辦法完全顛覆 namespace 讓其變成真正的隔離技術,畢竟 CPU/Memory/Network 等相關資源因為 Container 的關係本來就很難切割,要達到如 VM 般真正隔離還不是這麼容易。
20 | 不過 Rancher 還是有別的方向可以去發展與強化,就是如何讓 Kubernetes 變得更適合一個團隊使用,如果該團隊內有數個不同的專案,這些專案要如何共同的使用一套 Kubernetes 叢集同時又可以有一個清楚且清晰的管理方式。
21 |
22 | # Project
23 | Rancher 提出了一個名為 project 的概念,Project 是基於 Kubernetes Namespace 的實作的抽象管理概念,每個 Project 可以包含多個 namespace,同時 project 也會與 Rancher 內部的使用者權限機制整合。
24 |
25 | 從架構層面來看
26 | 1. Rancher 管理了多套 Kubernetes 叢集
27 | 2. Kubernetes 叢集管理多個 Project
28 | 3. Project 擁有多個 namespace.
29 |
30 | 如同前面探討的, Kubernetes 原生提供的 namespace 機制是個輕量級虛擬化概念,所有 kubernetes 內的機制也都是以 namespace 為基礎去設計的,這意味者如果你今天要透過 RBAC 設定權限等操作你都需要針對 namespace 去仔細設計。但是 Rancher 認為一個產品專案可能不會只使用一個 namespace,而是會使用多個 namespace 來區隔不同的應用程式。
31 | 這種情況下你就必須要要針對每個 namespace 一個一個的去重複設定,從結果來說一樣可以達到效果,但是操作起來就是不停重複相同的動作。
32 |
33 | 透過 Rancher Project 的整合,叢集管理者可以達到
34 | 1. 整合使用者群組權限,一口氣讓特定群組/使用者的人針對多個 namespace 去設定 RBAC
35 | 2. 針對 Project 為單位去進行資源控管,一口氣設定多個 namespace 內 CPU/Memory 的使用量
36 | 3. 套用 Pod Security Policy 到多個 namespace 中
37 |
38 | 因此實際上管理 Kubernetes 叢集就變成有兩種方式
39 | 1. 完全忽略 Rancher 提供的 Project 功能,直接就如同其他 Kubernetes 版本一樣去操作
40 | 2. 使用 Rancher 所設計的 Project 來管理
41 |
42 | Rancher 會開發 Project 勢必有其好處,但是要不要使用就是另外一回事情,因為這個技術與概念是只有 Rancher 才有的,如果今天團隊同時擁有多套不同的 Kubernetes 叢集,有些用 Rancher 管理,有些沒有。
43 | 這種情況下也許不要使用 Rancher 工具而是採用盡可能原生統一的工具來管理會更好,因為可以避免團隊中使用的工具有太多的客製化行為,造成開發與維護都不容易。相反的使用所有 Kubernetes 發行版本都有的工具與管理方式反而有機會降低工具的複雜性。
44 | 所以到底要不要使用這類型的工具反而是見仁見智,請依據每個團隊需求去思考。
45 |
46 | 接下來就來看一下到底如何使用 Rancher Project 概念。
47 |
48 | # 操作
49 | Project 因為是用來簡化同時操作多個 namespace 的一種概念,因此管理上會跟 namespace 放在一起。
50 | Rancher 畫面上方的 Projects/Namespaces 就是用來管理這類型概念的,點選進去會看到類似下圖的版面。
51 |
52 | 
53 |
54 | 因為 Project 包含多個 namespace,所以版面中都是以 Project 為主,列出該 Project 底下有哪些 namespace,
55 | Rancher 內的任何 Kubernetes 叢集預設都會有兩個 Projects,System 與 Default
56 | System 內會放置任何跟 Rancher 以及 Kubernetes 有關的 namespace,譬如 cattle-system, fleet-system, kube-system, kube-public 等
57 |
58 | Default 是預設的 Project,預設對應到 default 這個 namespace。
59 | 任何不是透過 Rancher 創立的 namespace 都不會加入到任何已知的 project 底下,因此圖片中最上方可以看到一堆 namespace,而這些 namespace 都不屬於任何一個 project。
60 |
61 | 因此要使用 project 的話就需要把這些 namespace 給搬移到對應的 project 底下。
62 | 圖中右上方有一個按鈕可以創立新的 Project,點下去可以看到如下畫面
63 |
64 | 
65 |
66 | 創立一個 Project 有四個資訊需要輸入,分別是
67 | 1. 使用者權限
68 | 2. Project 資源控管
69 | 3. Container 資源控管
70 | 4. Labels/Annotation.
71 |
72 | 使用者權限可以控制屬於什麼樣的使用者/群組可以對這個 Project 有什麼樣的操作。
73 | Project 與 Container 的資源控管之後會有一篇來介紹
74 | 創立完 Project 之後就可以回到最外層的介面,將已經存在的 namespace 給掛到 project 底下
75 |
76 | 
77 |
78 | 譬如上述範例就將 cis-operator-system, longhorn-system 這兩個 namespace 給分配到剛剛創立的 project 底下。
79 |
80 | 
81 |
82 | 之後重新進入到該 Project 去編輯,嘗試將 QA 使用群組加入到該 Project 底下,讓其變成 Project Owner,代表擁有完整權限。
83 |
84 | 
85 |
86 | 創造完畢後,就可以透過 UI 切換到不同的 project,如上圖所示,可以看到 ithome-dev 叢集底下有三個 Project,其中有兩個是預設的,一個是剛剛前述創立的。
87 |
88 | 
89 |
90 | 切換到該 Project 之後,觀察當前的 URL 可以觀察到兩個有趣的ID,c-xxxx/p-xxxxx 會分別對應到 clusterID 以及 project ID,因此之後只要看到任何 ID 是 c-xxx 開頭的,基本上都是 Rancher 所創立的,跟 Cluster 有關,而 p-xxxx 開頭的則是跟 Project 有關,每個 Project 都勢必屬於某個 Cluster。
91 |
92 | 有了 ProjectID 之後,仿造之前透過 kubectl 去觀察使用者權限的方式,這次繼續觀察前述加入的 QA 群組會有什麼變化。
93 |
94 | 
95 |
96 | 從上述指令中可以看到 QA 群組對應到一個新的 ClusterRole,叫做 p-p6xrd-namespaces-edit,其中 p-p6xrd 就是對應到前述創立的 project,而 edit 代表則是擁有 owner 般的權限,能夠去編輯任何資源。
97 |
98 | 接者更詳細的去看一下該 ClusterRole 的內容
99 |
100 | 
101 |
102 | 可以看到該 ClusterRole 針對設定的兩個 namespace 都給予了 "*" 的動詞權限,基本上就是讓該使用者能夠如管理者般去使用這兩個 namespace。
103 |
104 |
105 | 除了上述的權限外,當切換到 Project 的頁面時,就可以看到從 Rancher 中去看到該 Project 底下 namespaces 內的相關 Kubernetes 物件資源,譬如下圖
106 |
107 | 
108 |
109 | Workloads 就是最基本的運算單元,譬如 Pod, Deployment, Job, DaemonSet..等
110 | 而 Config(ConfigMap), Secrets 可以看到整個叢集內的相關資源,此外 secret 透過網頁的可以直接看到透過 base64 解密後的結果。
111 |
112 | 註: Pipelines 請忽略他, v2.5 之後 Rancher 會主推使用 GitOps 的方式來部署,因此過往 pipeline 的方式這邊就不介紹了。
113 |
114 | 以 workloads 為範例,點進去後可以更詳細的去看當前系統中有哪些 workloads。
115 |
116 | 
117 |
118 | 每個 workloads 旁邊都有一個選項可以打開,打開後會看到如上的選擇,這邊就有很多功能可以使用,譬如
119 | 1. Add a Sidecar,可以幫忙加入一個 sidecar contaienr 進去
120 | 2. Rollback 到之前版本
121 | 3. Redeploy 重新部署
122 | 4. 取得該 Pod 的 shell (如果該 workloads 底下有多種 pod,則不建議這邊使用這個功能)
123 |
124 | 基本上這些功能都可以透過 kubectl 來達到,網頁只是把 kubectl 要用的指令給簡化,讓他更輕鬆操作。
125 | 上述的範例 test 是使用 deployment 去部署的,點進去該 deployment 可以看到更詳細 pods 的資訊,如下
126 |
127 | 
128 |
129 | 該畫面中就可以看到每個 Pod 的資訊,包含 Pod 的名稱,部署到哪個節點,同時也可以透過 UI 去執行該 Pod 的 shell 或是觀看相關 log。
130 |
131 | 以上就介紹了關於 Project 的基本概念。 Project 是 Rancher 內的最基本單位,因此要透過 Rancher 的 UI 去管理叢集內的各種部署資源則必須要先準備好相關的 Project,並且設定好每個 Project 對應的 namespace 以及使用者權限。
132 |
133 | 當然 Rancher Project 不是一個一定要使用的功能,因為也是有團隊單純只是依賴 Rancher 去部署 Kubernetes 叢集,而繼續使用本來的方式來管理與部署 Kubernetes 叢集,畢竟現在有很多種不同的專案可以提供 Kubernetes 內的資源狀況。一切都還是以團隊需求為主。
134 |
--------------------------------------------------------------------------------
/2021/day13.md:
--------------------------------------------------------------------------------
1 | Day 13 - Rancher 專案管理指南 - 資源控管
2 | ====================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前篇文章探討為什麼需要 Project 這樣的概念,透過 Project 能夠帶來什麼樣的好處,然而前篇文章只有帶到簡單的操作以及如何使用透過 Rancher 的 UI 來檢視 Project 內的各種 Kubernetes 物件。
15 |
16 | 本篇文章將介紹我認為 Project 最好也最方便的功能, Resource Quotas 與 Container Default Resource Limit 到底是什麼以及如何使用。
17 |
18 | # 資源控管介紹
19 |
20 | 熟悉 Kubernetes 的讀者應該都知道資源控管是一個非常困難的問題,其根本原因是 Container 本身的實作方式導致資源控管不太容器。
21 | 很多人使用資源控管最常遇到的問題有
22 | 1. 不知道該怎麼設定 Resources Limit, CPU/Memory 到底要用哪種? 三種內建的 QoS 型態有哪些? 有哪些影響?
23 | 2. 設定好了 Limit/Request 後結果運作不如預期,或是某些情況下應用程式效能大幅度降低等
24 |
25 | 第一點是最容易遇到的,畢竟要如何有效地去分配容器使用的 CPU/Memory 是個很困難的問題,特別是第一次踏入到容器化的團隊對於這個問題會有更大的疑惑,不確定該怎麼用。
26 | 第二個問題則是部分的 Linux Kernel 版本實作 Container 的資源控管與限制上會有一些 bug,可能會導致你的應用程式被不預期的 throttle,導致效能變得很低。
27 |
28 | 本篇文章不太探討這兩個問題,反而是探討最基本的概念,畢竟上述兩個概念跟 Rancher 沒太大關係,反而是比較進階使用與除錯的內容。
29 |
30 | Kubernetes 中針對 CPU/Memory 等系統資源有兩種限制,稱為 Request 與 Limit。
31 | Request 代表的是要求多少,而 Limit 代表的是最多可以使用多少。
32 | 這些資源是以 Container 為基本單位,而 Pod 本身是由多個 Container 組成的,所以 CPU/Memory 的計算上就相對繁瑣。
33 |
34 | Kubernetes 本身有一個特別的物件稱為 ResourceQuota,透過該物件可以針對特定 namespace 去限定該 namespace 內所有 Container 的資源上限。譬如可以設定 default namespace 最多只能用 10顆 vCPU,超過的話就沒有辦法繼續部署。
35 |
36 | Rancher 的 Project 本身就是一個管理多 namespace 的抽象概念,接下來看一下 Project 中有哪些關於 Resource 的管理。
37 |
38 | # 操作
39 | 為了方便操作,先將 default namespace 給加入到之前創立的 Project 中,加進去後當前 project 中有三個 namespace,如下圖。
40 |
41 | 
42 |
43 | 接者編輯該 Project 去設定 Resource 相關的資訊,如下圖
44 |
45 | 
46 |
47 | Project 中有兩種概念要設定,第一種是 Resource Quota,第二個是 Container Default Resource Limit.
48 | Resource Quota 是更高階層的概念,是用來控管整個 Project 能夠使用的 CPU/Memory 用量。
49 | 由於 Project 是由多個 namespaces 所組成的,所以設定上還要去設定每個 namespace 的用量,如上述範例就是設定
50 | 整個 Project 可以使用 100個 vCPU,而每個 namespace 最多可以使用 10 vCPU。
51 | 但是因為 namespace 本身就是使用 kubernetes ResourceQuota 來實作,而這個功能本身會有一個限制就是。
52 | 一但該 namespace 本身設定了 ResourceQuota,則所有部署到該 namespace 的容器都必須要明確的寫出 CPU/Memory 用量。
53 |
54 | 這個概念也滿容易理解的,畢竟你要去計算 namespace 的使用上限,那 namespace 內的每個 container 都需要有 CPU/Memory 等相關設定,否則不能計算。
55 | 如果你的容器沒有去設定的話,你的服務會沒有辦法部署,會卡到 Scheduler 那個層級,連 Pending 都不會有。
56 | 但是如果要求每個容器部署的時候都要設定 CPU/Memory 其實會有點煩人,為了讓這個操作更簡單,Project 底下還有 Container Default Resource Limit 的設定。
57 | 該設定只要打開,所有部署到該 namespace 內的 Container 都會自動的補上這些設定。
58 | 如上圖的概念就是,每個 Container 部署時就會被補上 CPU(Request): 3顆, CPU(Limit): 6顆
59 |
60 | 這邊有一個東西要特別注意,Project 設定的 Container Default Resource Limit 本身有一個使用限制,如果 namespace 是再設定 Resource Quota 前就已經加入到 Project 的話,設定的數字並不會自動地套用到所有的 namespace 上。
61 | 反過來說,設定好這些資訊後,所有新創立的 namespace 都會自動沿用這些設定,但是設定前的 namespace 需要手動設定。
62 |
63 | 所以這時候必須要回到 namespace 上去重新設定,如下圖
64 |
65 | 
66 |
67 | namespace 的編輯頁面就可以重新設定該 namespace 上的資訊,特別是 Container Default Resource Limit。
68 | 當這邊重新設定完畢後,就可以到系統中去看相關的物件
69 |
70 | 首先 Project 設定好 Resource Quota 後,Kubernetes 就會針對每個 namespace 都產生一個對應的 Quota 來設定,如下
71 |
72 | 
73 |
74 | 因為設定每個 namespace 的 CPU 上限是 10顆,而該 project 總共有三個 namespace,所以系統中這三個 namespace 都產生了對應的 quota,而這些 quota 的設定都是 10顆 CPU。
75 |
76 | 其中 default namespace 的標示是 5025m/10 代表目前已經用了 5.025顆 CPU,而系統上限是 10顆。
77 |
78 | 
79 |
80 | 這時候將 default namespace 內的 pod 都清空,接者重新再看一次該 quota 物件就會發現 used 的數值從 5025m 到 0。
81 |
82 | 
83 |
84 | 由於上述 default namespace 中設定 CPU 預設補上 0.1顆 CPU (Request/Limit),所以 Kubernetes 會創造相關的物件 Limits
85 |
86 | 
87 | 
88 |
89 | 從上述物件可以觀察到該 LimitRange 設定了 100m 的 CPU。
90 |
91 | 最後嘗試部署一個簡單的 deployment 來測試此功能看看,使用一個完全沒有標示任何 Resource 的 deployment,內容如下。
92 |
93 | 
94 | 
95 |
96 | 該物件部署到叢集後,透過 kubectl describe 去查看一下這些 Pod 的狀態,可以看到其 Resource 被自動的補上 Limits/Requests: 100m。
97 |
98 | 
99 |
100 | Resource 的管理一直以來都不容易, Rancher 透過 Project 的管理方式讓團隊可以更容易的去管理多 namespace 之間的資源用量,同時也可以透過這個機制要求所有要部署的 container 都要去設定資源用量來確保不會有容器使用過多的資源。
101 |
--------------------------------------------------------------------------------
/2021/day14.md:
--------------------------------------------------------------------------------
1 | Day 14 - Rancher - 其他事項
2 | ==========================
3 |
4 |
5 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
6 |
7 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
8 |
9 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
10 |
11 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
12 |
13 | # 前言
14 |
15 | 過去十多篇文章從從三個不同角度來探討如何使用 Rancher,包含系統管理員,叢集管理員到專案管理員,不同層級專注的角度不同,因此使用上也有不同的功能可以用。
16 |
17 | 本篇文章將探討 Rancher 一些其他的注意事項。
18 |
19 | # 清除節點
20 |
21 | 之前文章探討過三種不同安裝 Kubernetes 的方式,其中一種方式是運行 docker command 在現有的節點上將該節點加入到 RKE 叢集中。
22 |
23 | 但是如果今天有需求想將該節點從 RKE 中移除該怎麼辦?
24 |
25 | 
26 |
27 | Cluster Manager 中可以直接到 Cluster 頁面將該節點從 RKE 中移除,但是要注意的是,這邊的移除代表的只是將該節點從 RKE 移除,該節點上可能會有一些因為加入 RKE 而產生的檔案依然存在節點上。
28 |
29 | 假設今天有需求又要將該節點重新加入回到 RKE 中的話,如果上次移除時沒有妥善地去刪除那些檔案的話,第二次運行 docker command 去加入 RKE 叢集有非常大的機率會失敗,因為節點中有太多之前的產物存在。
30 |
31 | 官網有特別撰寫一篇文章探討如果要清除這些產物的話,有哪些資源要處理,詳細版本可以參閱 [Removing Kubernetes Components from Nodes](https://rancher.com/docs/rancher/v2.5/en/cluster-admin/cleaning-cluster-nodes/)
32 |
33 | 這邊列舉一下一個清除節點正確步驟
34 | 1. 從 Rancher UI 移除該節點
35 | 2. 重啟該節點,確保所有放到暫存資料夾的檔案都會消失
36 | 3. Docker 相關資料
37 | 4. Mount 相關資訊都要 umount
38 | 5. 移除資料夾
39 | 6. 移除多的網卡
40 | 7. 移除多的 iptables 規則
41 | 8. 再次重開機
42 |
43 | 第三點移除 docker 相關資料,官方列出三個指令,分別移除 container, volume 以及 image。
44 | ```bash
45 | docker rm -f $(docker ps -qa)
46 | docker rmi -f $(docker images -q)
47 | docker volume rm $(docker volume ls -q)
48 | ```
49 |
50 | 如果該節點接下來又要重新加入到 Rancher 中,建議不需要執行 docker rmi 的步驟,之前的 image 可以重新使用不需要重新抓取,這樣可以省一些時間。
51 |
52 | 第四點的 mount 部分要注意的是,官文文件沒有特別使用 sudo 的指令於範例中,代表其假設你會使用 root 身份執行,因此如果不是使用 root 的話記得要在 umount 指令中補上 sudo
53 |
54 | ```bash
55 | for mount in $(mount | grep tmpfs | grep '/var/lib/kubelet' | awk '{ print $3 }') /var/lib/kubelet /var/lib/rancher; do sudo umount $mount; done
56 | ```
57 |
58 |
59 | 第五點跟第四點一樣,但是第五點非常重要,因為系統上有太多的資料夾都含有過往 RKE 叢集的資料,所以第五步一定要確保需要執行才可以將資料清除。
60 |
61 | ```bash=
62 | sudo rm -rf /etc/ceph \
63 | /etc/cni \
64 | /etc/kubernetes \
65 | /opt/cni \
66 | /opt/rke \
67 | /run/secrets/kubernetes.io \
68 | /run/calico \
69 | /run/flannel \
70 | /var/lib/calico \
71 | /var/lib/etcd \
72 | /var/lib/cni \
73 | /var/lib/kubelet \
74 | /var/lib/rancher/rke/log \
75 | /var/log/containers \
76 | /var/log/kube-audit \
77 | /var/log/pods \
78 | /var/run/calico
79 | ```
80 |
81 |
82 | 第六跟第七這兩步驟並不一定要處理,因為這些資訊都是節點加入到 Kubernetes 後被動態創建的,基本上重開機就不會有這些資訊,只要確保節點重新開機後沒有繼續成為 Kubernetes 的節點,那相關的虛擬網卡跟 iptables 規則也就不會被產生。
83 |
84 | 要注意的是官方文件中的所有步驟不一定都會有東西可以刪除,主要會取決於叢集內的設定,不同的設定可能會有不同的結果,譬如採用不同的 CNI,其產生的 iptables 規則與虛擬網卡就會有所不同。
85 |
86 | # 離線安裝
87 | 雖然雲端環境方便存取,但是很多產業與環境可能會需要於一個沒有對外網路的環境下去安裝 Kubernetes 叢集,這種情況下如果想要使用 Rancher 的話就要探討如何達到離線安裝。
88 |
89 | Rancher 講到離線安裝有兩種含義,一種是
90 | 1. Rancher 本身的離線安裝
91 | 2. Rancher 以離線安裝的方式幫忙創建 RKE 叢集
92 |
93 | 上述兩種方式其實都還是仰賴各式各樣的 container image 來處理,所以處理的方法一致,就是要安裝一個 container registry 並且將會需要使用的 container image 都事先匯入到該 container registry 中,接者安裝時要讓系統知道去哪下載相關的 container image 即可。
94 |
95 | 官網有數篇文章探討這種類型下的安裝該怎麼處理,有興趣的也可以參考 [Air Gapped Helm CLI Install](https://rancher.com/docs/rancher/v2.5/en/installation/other-installation-methods/air-gap/)
96 |
97 | 由於安裝 Rancher 本身有很多方式,譬如多節點的 RKE 或是單節的 Docker 安裝,以下簡述一下如何用 Docker 達成單節點的離線安裝。
98 | 1. 架設一個 Private Container Registry
99 | 2. 透過 Rancher 準備好的腳本去下載並打包 Rancher 會用到的所有 Container Image
100 | 3. 把第二步驟產生 Container Image 檔案給匯入到 Private Container Registry
101 | 4. 運行修改過後的 Docker 來安裝 Rancher.
102 |
103 | 第一點這邊有幾點要注意
104 | a. 可以使用 container registry v2 或是使用 harbor
105 | b. 一定要幫該 container registry 準備好一個憑證,這樣使用上會比較方便,不用太多地方要去處理 invalid certificate 的用法。憑證的部分可以自簽 CA 或是由一個已知信任 CA 簽署的。
106 | c. image 的容量大概需要 28 GB 左右,因此準備環境時要注意空間
107 |
108 | 第二跟第三點直接參閱官網的方式,先到 GitHub 的 Release Page 找到目標版本,接者下載下列三個檔案
109 | 1. rancher-images.txt
110 | 2. rancher-save.images.sh
111 | 3. rancher-load-images.sh
112 |
113 | 第二個腳本會負責去下載 rancher-images.txt 中描述的檔案並且打包成一個 tar 檔案,系統中會同時存放 container image 以及 tar 檔,所以最好確保空間有 60GB 以上的足夠空間。
114 | 第三個腳本會將該 tar 檔案的內容上傳到目標 container registry。
115 |
116 | 這一切都準備完畢後,就可以執行 docker 指令,可以參閱[Docker Install Commands](https://rancher.com/docs/rancher/v2.5/en/installation/other-installation-methods/air-gap/install-rancher/docker-install-commands/)
117 |
118 | 一個範例如下
119 | ```bash=
120 | docker run -d --restart=unless-stopped \
121 | -p 80:80 -p 443:443 \
122 | -v /mysite/fullchain.pem:/etc/rancher/ssl/cert.pem \
123 | -v /mysite/previkey.pem>:/etc/rancher/ssl/key.pem \
124 | -e CATTLE_SYSTEM_DEFAULT_REGISTRY=test.hwchiu.com \ # Set a default private registry to be used in Rancher
125 | -e CATTLE_SYSTEM_CATALOG=bundled \ # Use the packaged Rancher system charts
126 | --privileged
127 | registry.hwchiu.com/rancher/rancher:v2.5.9 \
128 | --no-cacerts
129 | ```
130 |
131 | 請特別注意上述的參數,不同的憑證方式會傳入的資訊不同,自簽的方式還要額外把 CA_CERTS 給丟進去。
132 |
--------------------------------------------------------------------------------
/2021/day17.md:
--------------------------------------------------------------------------------
1 | Day 17 - 應用程式部署 - 淺談 Rancher 的應用程式管理
2 | ==============================================
3 |
4 |
5 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
6 |
7 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
8 |
9 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
10 |
11 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
12 |
13 | # 概念探討
14 | Rancher 作為一個 Kubernetes 管理平台,提供不同的方式將 Kubernetes 叢集給匯入到 Rancher 管理平台中,不論是已經創立的 Kubernetes 或是先透過 Rancher 創造 RKE 接者匯入到 Rancher 中。
15 |
16 | 但是 Kubernetes 終究只是一個容器管理平台,前述介紹的各種機制或是 Rancher 整合的功能都是輔助 Kubernetes 的維護,對於團隊最重要的還是產品本身,產品可能是由數個應用程式所組合而成,而每個應用程式可能對應到 Kubernetes 內又是多種不同的物件,譬如 Deployment, Service, StorageClass 等。
17 | 接下來會使用應用程式這個詞來代表多個 Kubernetes 內的資源集合。
18 |
19 | 過往探討到部署應用程式到 Kubernetes 叢集內基本上會分成兩個方向來探討
20 | 1. 如何定義與管理應用程式供團隊使用
21 | 2. 部署應用程式給到 Kubernetes 叢集的流程
22 |
23 | # 定義與管理應用程式
24 |
25 | Kubernetes 的物件基本上可以透過兩種格式來表達,分別是 JSON 與 YAML,不過目前主流還是以 YAML 為主。
26 | 這意味這一個最簡單管理應用程式的方式就是使用一堆 YAML 檔案,檔案內則是各種 Kubernetes 的物件。
27 |
28 | 這些應用程式本身還需要考慮到下列使用情境
29 | 1. 該應用程式會不會需要跨團隊使用
30 | 2. 該應用程式是否需要針對不同環境有不同的參數
31 | 3. 該應用程式本身有沒有其他相依性,譬如部署 A 應用程式會需要先部署 B 應用程式
32 | 4. ...等
33 |
34 | 上述的這些使用情境是真實存在的,而為了解決這些問題,大部分情況下都不會使用純 YAML 檔案來管理應用程式,譬如想要讓一個 Service 針對不同環境有不同設定就不太好處理,除了準備多個幾乎一樣的檔案外幾乎沒有辦法。
35 | 目前主流的管理方式有 Helm, Kustomize,其餘的還有 ksonnet 等。
36 | 不同解決方案都採用不同的形式來管理與部署應用程式,舉例來說
37 | 使用 Helm 的使用者可以採用下列不同方式來安裝應用程式
38 | 1. helm install
39 | 2. helm template | kubectl apply -
40 |
41 | 而使用 kustomize 的使用者則可以使用
42 | 1. kustomize ...
43 | 2. kubectl -k ...
44 |
45 | 因為 kubectl 目前已經內建 kustomize 的功能,所以直接使用 kustomize 指定或是 kubectl 都可以。
46 | 當團隊選擇好如何管理與部署這些應用程式後,下一個問題就是如何部署這些 Helm/Kustomize 物件到 Kubernetes 叢集。
47 |
48 | # 部署流程
49 | 基本上所有的部署都以自動化為目標去探討,當然這並不代表手動部署就沒有其價值,畢竟在自動化部署有足夠的信心前,團隊也必定會經歷過各式各樣的手動部署,甚至很多自動化的撰寫與開發也是都仰賴手動部署的經驗。
50 |
51 | 從 Rancher 的角度來看,自動化部署有三種不同的方式
52 | 1. Kubeconfig
53 | 2. Rancher Catalog
54 | 3. Rancher Fleet
55 |
56 | 下面稍微探討一下這三者的概念與差異。
57 |
58 | # Kubeconfig
59 | 一個操作 Kubernetes 最簡單的概念就是直接使用 kubectl/helm 等指令進行控制,而 Rancher 也有針對每個帳戶提供可存取 Kubernetes 叢集所要使用的 KUBECONFIG。
60 |
61 | 假設團隊已經完成 CI/CD 的相關流程,就可以於該流程中透過該 KUBECONFIG 來得到存取該 Kubernetes 的權限,接者使用 Helm/Kubectl 等功能來部署應用程式到叢集中。
62 |
63 | 基本上使用這種方式沒有什麼大問題,畢竟 RKE 也是一個 Kubernetes 叢集,所以如果團隊已經有現存的解決方案是透過這種類型部署的話,繼續使用這種方式沒有任何問題。
64 |
65 | # Rancher Catalog
66 |
67 | Rancher 本身有一個名為 catalog 的機制用來管理要部署到 Rancher 內的應用程式,這些應用程式必須要基於 Helm 來管理。
68 |
69 | 其底層背後也是將 Helm 與 Helm values 轉換為 YAML 檔案然後送到 Kubernetes 中。
70 | 這種作法跟第一種最大的差異就是,所有的安裝與管理中間都多了一層 Rancher Catalog 的管理。
71 |
72 | CI/CD 流程要存取時就不是針對 Kubernetes 叢集去使用,也不需要取得 KUBECONFIG。
73 | 相反的需要取得 Rancher API Token,讓你 CI/CD 內的腳本有能力去呼叫 Rancher,要求 Rancher 去幫忙創建,管理,刪除不同的 Catalog。
74 |
75 | 這種方式只限定於 Rancher 管理的叢集,所以如果團隊中不是每個叢集都用 Rancher 管理,那這種方式就不推薦使用,否則只會讓系統混亂。
76 |
77 | # Rancher Fleet
78 | Rancher Fleet 是 Rancher v2.5 正式推出的功能,其替代了過往的 Rancher pipeline(前述文章沒有探討,因為基本上要被淘汰了)的部署方式。
79 |
80 | Fleet 是一個基於 GitOps 策略的大規模 Kubernetes 應用部署解決方案,基於 Rancher 的架構使得 Fleet 可以很輕鬆的存取所有 Rancher 控管的 Kubernetes 叢集,同時 GitOps 的方式讓開發者可以簡單的一口氣將應用程式更新到多個 Kubernetes 叢集。
81 |
82 | 接下來的文章就會從 Rancher Catalog 出發,接者探討 GitOps 與 Rancher Fleet 的使用方式。
83 |
--------------------------------------------------------------------------------
/2021/day18.md:
--------------------------------------------------------------------------------
1 | Day 18 - Rancher Catalog(v2.0~v2.4) 介紹
2 | =======================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # Rancher Application
13 |
14 | Rancher v2.5 是一個非常重要的里程碑,有很多功能於這個版本進入了 v2 下一個里程碑,本章節要探討的應用程式部署實際上也有這個轉變。
15 |
16 | Rancher Catalog 是 Rancher v2.0 ~ v2.4 版本最主要的部署方式,而 v2.5 則改成 Cluster Explorer 內的 App&Marketplace 的方式。
17 | 也可以將這個差異說成由 Cluster Manager 轉換成 Cluster Explorer。
18 |
19 | 那為什麼這個已經要被廢除的功能還需要來介紹?
20 | 主要是我自己針對 v2.5 的使用經驗來看,我認為部署應用程式用 Cluster Manager 看起來還是比較簡潔有力,相反的 Cluster Explorer 內的機制沒有好到會讓人覺得替換過去有加分效果。
21 |
22 | 所以接下來就針對這兩個機制分享一下使用方式。
23 |
24 | # Rancher Catalog
25 |
26 | Rancher Catalog 的核心概念分成兩個
27 |
28 | 1. 如何取得 Kubernetes 應用程式,這部分的資訊狀態就稱為 Catalog
29 | 2. 將 Catalog 中描述的應用程式給實體化安裝到 Kubernetes 中
30 |
31 | Catalog 的核心精神就是要去哪邊取得 Kubernetes 應用程式,Catalog 支援兩種格式
32 | 1. Git 專案,底層概念就是能夠透過 git clone 執行的專案都可以
33 | 2. Helm Server,說到底 Helm Server 就是一個 HTTP Server,這部分可以自行實作或是使用 chartmuseum 等專案來實作。
34 |
35 | 由於 Helm 本身還有版本差別, Helm v2 或是 Helm v3,因此使用上需要標注到底使用哪版本。
36 |
37 | Catalog 也支援 Private Server,不過這邊只支援使用帳號密碼的方式去存取。使用權限方面 Catalog 也分成全 Rancher 系統或是每個 Kubernetes 叢集獨立設定。
38 |
39 | 首先如下圖,切換到 Global 這個範圍,接者可以於 Tools 中找到 Catalog 這個選項。
40 |
41 | 
42 |
43 | 或是如下圖,切換到 ithome-dev 這個叢集中,也可以看到 Tools 中有 Catalog 的範圍。
44 |
45 | 
46 |
47 | 這邊我們使用 Kubernetes Dashboard 這個專案作為一個示範,該專案的 Helm Chart 可以經由 https://kubernetes.github.io/dashboard 這個 Helm Server 去存取。
48 |
49 | 這類型的伺服器預設都沒有 index.html,所以存取會得到 404 是正常的,想要存取相關內容可以使用下列方式去存取 https://kubernetes.github.io/dashboard/index.yaml,這也是 helm 指令去抓取相關資源的辦法,可以知道該 Server 上會有多少 Helm Charts 以及對應的版本有哪些。
50 |
51 | 點選右上方的 Add Catalog 就可以看到如下的設定視窗
52 |
53 | 
54 |
55 | 該畫面中我們填入上述資訊,如果是 Git 專案的位置還可以輸入 branch,但是因為我們是 Helm Server,所以 Branch 的資訊就沒有設定的意義。
56 | 最後順便設定該 Helm Server 是基於 Helm v3 來使用的。
57 |
58 | 
59 |
60 | 創建完畢後就意味 Rancher 已經可以透過這個 Catalog 去得到遠方當前有哪些 應用程式以及擁有哪些版本,但是這並不代表 Rancher 已經知道。
61 | 一種做法就是等 Rancher 預設的同步機制慢慢等或是直接點選 Refresh 讓 Rancher 直接同步該 Catalog 的資訊。
62 |
63 | 一種常見的情境就是你的 CI/CD 流程更新了 Helm Chart,推進一個版本,結果 Rancher 還不知道,這時候就可以 refresh 強制更新。
64 |
65 | 創建 Catalog 完畢後,下一件事情就是要從 Catalog 中找到一個可以用的應用程式,並且選擇該應用程式的版本,如果是 Helm 描述的應用程式還可以透過 values.yaml 的概念去客製化應用程式。
66 |
67 | 應用程式的安裝是屬於最底層架構的,因此是跟 Project 綁定,從左上方切換到之前創立的 myApplication project,並且切換到到畫面上方的 app 頁面中。
68 |
69 | 
70 |
71 | 該頁面的右上方有兩個按鈕,其中 Manage Catalog 會切回到該專案專屬的 Catalog 頁面,因此 Catalog 本身實際上有三種權限,(Global, Cluster, Project).
72 | 右邊的 Launch 意味者要創立一個應用程式。
73 | 點進去後會看到如下方的圖
74 |
75 | 
76 |
77 | 圖中最上方顯示的就是前述創立的 Catalog,該 Helm Server 中只有一個應用程式名為 kubernetes-dashboard
78 |
79 | 下面則是一些系統預設的 catalog,譬如 helm3-library,該 helm server 中則有非常多不同的應用程式。
80 | 其中這些預設提供的 helm chart 還會被標上 partner 的字樣。
81 |
82 | 點選 kubernetes-dashboard 後就會進入到設定該應用程式的畫面。
83 |
84 | 
85 |
86 | 畫面上會先根據 Helm Chart 本身的描述設定去介紹該 Helm Charts 的使用方式
87 |
88 | 
89 |
90 |
91 | 接下來就要針對該應用程式去設定,該設定包含了
92 | 1. 該應用程式安裝的名稱
93 | 2. 該 Helm Chart 要用什麼版本,範例中選擇了 4.5.0
94 | 3. 該服務要安裝到哪個 Kubernetes namespace 中
95 | 4. 最下面稱為 Answer 的概念其實就是 Helm Chart values,這邊可以透過 key/value 的方式一個一個輸入,或是使用 Edit as YAML 直接輸入都可以
96 |
97 | 預設情況下我們不進行任何調整,然後直接安裝即可。
98 |
99 | 
100 |
101 | 安裝完畢後就可以於外面的 App 頁面看到應用程式的樣子,其包含了
102 | 1. 應用程式的名稱
103 | 2. 當前使用版本,如果有新版則會提示可以更新
104 | 3. 狀態是否正常
105 | 4. 有多少運行的 Pod
106 | 5. 是否有透過 service 需要被外部存取的服務
107 |
108 | 點選該名稱可以切換到更詳細的列表去看看到底該應用程式包含的 Kubernetes 資源狀態,譬如 Deployment, Service, Configmap 等
109 |
110 | 
111 |
112 | 如果該資源有透過 Service 提供存取的話, Rancher 會自動的幫該物件創建一個 Endpoint,就如同 Grafana/Monitoring 那樣,可以使用 API Server 的轉發來往內部存取。
113 | 譬如途中可以看到有產生一個 Endpoint,該位置就是基於 Rancher 的位置後面補上 cluster/namespace/service 等相關資訊來進行處理。
114 |
115 | 
116 |
117 | 這類型的資訊也會於最外層的 App 介面中直接呈現,所以如果直接點選的話就可以很順利地打該 Kubernetes Dashboard 這個應用程式。
118 |
119 | 
120 | 
121 |
122 | 最後也可以透過 Kubectl 等工具觀察一下目標 namespace 是否有相關的資源,可以看到有 deployment/service 等資源
123 |
124 | 
125 |
126 | 透過 Rancher Catalog 的機制就可以使用 Rancher 的介面來管理與存取這些服務,使用上會稍微簡單一些。既然都可以透過 UI 點選那就有很大的機會可以透過 Terraform 來實現上述的操作。
127 |
128 | 接下來示範如何透過 Terraform 來完成上述的所有操作,整個操作會分成幾個步驟
129 | 1. 先透過 data 資料取得已經創立的 Project ID
130 | 2. 創立 Catalog
131 | 3. 創立 Namespace
132 | 4. 創立 App
133 |
134 | ```
135 | data "rancher2_project" "system" {
136 | cluster_id = "c-z8j6q"
137 | name = "myApplication"
138 | }
139 | resource "rancher2_catalog" "dashboard-global" {
140 | name = "dashboard-terraform"
141 | url = "https://kubernetes.github.io/dashboard/"
142 | version = "helm_v3"
143 | }
144 | resource "rancher2_namespace" "dashboard" {
145 | name = "dashboard-terraform"
146 | project_id = data.rancher2_project.system.id
147 | }
148 | resource "rancher2_app" "dashboard" {
149 | catalog_name = "dashboard-terraform"
150 | name = "dashboard-terraform"
151 | project_id = data.rancher2_project.system.id
152 | template_name = "kubernetes-dashboard"
153 | template_version = "4.5.0"
154 | target_namespace = rancher2_namespace.dashboard.id
155 | depends_on = [rancher2_namespace.dashboard, ncher2_catalog.dashboard-global]
156 | }
157 | ```
158 |
159 | 上述做的事情基本上跟 UI 是完全一樣,創造一個 Catalog,輸入對應的 URL 並且指名為 Helm v3 的版本。
160 | 然後接者創立 Namespace,因為使用 namespace,所以要先利用前述的 data 取得目標 project 的 ID,這樣就可以把這個 namespace 掛到特定的 project 底下。
161 |
162 | 最後透過 catalog 名稱, Template 的名稱與版本來創造 App。
163 | 準備完畢後透過 Terraform Apply 就可以於網頁看到 App 被創造完畢了。
164 |
165 | 
166 |
167 | 透過 Terraform 的整合,其實可以更有效率的用 CI/CD 系統來管理 Rancher 上的應用程式,如果應用程式本身需要透過 Helm 來進行客製化,這部分也都可以透過 Terraform 內的參數來達成,所以可以更容易的來管理 K8s 內的應用程式,有任何需求想要離開時,就修改 Terraform 上的設定,然後部署即可。
168 |
--------------------------------------------------------------------------------
/2021/day19.md:
--------------------------------------------------------------------------------
1 | Day 19 - Rancher App(v2.5) 介紹
2 | ==============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前篇文章介紹了 Rancher(v2.0 ~ v2.4) 中主打的應用程式管理系統, Catalog,所有的 Catalog 都必須要於 Cluster Manager 的介面中去管理。
15 |
16 | 而 Rancher v2.5 開始主打 Cluster Explorer 的介面,該介面中又推行了另外一套應用程式管理系統,稱為 App & Marketplace。
17 |
18 | 事實上前述的章節就已經有透過這個新的系統來安裝 Monitoring 的相關資源,因此現在 Rancher 都已經使用這個新的機制來提供各種整合服務,因此後續的新功能與維護也都會基於這個新的機制。
19 |
20 | 使用上我認為兩者還是有些差異,因此對於一個 Rancher 的使用者來說最好兩者都有碰過,稍微理解一下其之間的差異,這樣使用上會更有能力去判斷到底要使用哪一種。
21 |
22 | # Rancher App
23 | 新版的應用程式架構基本上跟前述的沒有不同,不過名詞上整個大改,相關名詞變得與 Helm 生態系更佳貼近,譬如舊版使用 Catalog 來描述去哪邊抓取 Helm 相關的應用程式,新版本則是直接貼切的稱為 Helm Repo。
24 |
25 | Cluster Explorer 的狀態下,左上方點選到 Apps & Marketplace 就可以進入到新版的系統架構,
26 |
27 | 該架構中左方有三個類別,其中第二個 Charts Repositories 就是新版的 Catalog,畫面如下。
28 |
29 | 
30 |
31 | 預設系統上有兩個 Chart Repo,其中之前安裝的 Monitoring 就是來自於這邊。
32 | 接者點選右上方的 Create 就會看到新版的創立畫面
33 |
34 | 
35 |
36 | 新版本的創建畫面更加簡潔與簡單,首先可以透過 target 來選擇到底要使用 Git 還是 HTTP 來存取,針對 Private Helm Repo 這次則提供了兩種驗證方式,譬如 SSH Key 與 HTTP Basic 兩種方式。
37 |
38 | 創造完畢後就可以於系統上看到新建立的 Helm Repo,系統預設的兩個 Helm Repo 都是基於 Git 去處理,而本篇文章新創立的則是 HTTP。
39 |
40 | 
41 |
42 | 有了 Helm Repo 後,下一步就是要創造應用程式,切換到 Charts 的介面就可以看到如下的畫面。
43 |
44 | 
45 |
46 | 畫面中上方顯示了目前擁有的 Helm Repo 有哪些,這邊可以透過勾選的方式來過濾想要顯示的 Helm Repo
47 | 只有單純勾選 dashboard 後就可以看到 kubernetes-dashboard 這個 Helm Chart。
48 |
49 | 
50 |
51 | 點選該 kubernetes-dashboard 後進入到新版的安裝設定介面,該畫面中相對於舊版的 Catalog 來說畫面更為簡潔有力。
52 | 畫面中,最上方包含了 App 的名稱,該使用的 Helm Chart 版本,範例使用了 4.5.0。
53 |
54 | 接者下方則是安裝的 namespace ,這些選擇都與舊版的介面差不多。
55 | 最下方則列出不同的類別,包含
56 | 1. Values
57 | 2. Helm README
58 | 3. Helm Deploy Options
59 |
60 | 
61 |
62 | Rancher 新版 App 捨棄了舊版 Answer 的叫法,同時也完全使用 YAML 的格式來設定 values,而不是透過 UI 一行一行慢慢設定。
63 |
64 | 註: 事實上舊版的 UI 的設定方式其實有滿多問題,某些情況還真的不能設定,透過檔案還是相對簡單與方便。
65 |
66 | 
67 |
68 | 下面的 Helm Deploy Options 有不同的部署選項,譬如
69 | 1. 要不要執行 Helm Hooks
70 | 2. 部署 Helm 時要不要設定 Timeout,多久的時間沒有成功部署就會判定失敗
71 |
72 | 
73 |
74 | 一切設定完畢後就可以開始安裝,安裝畫面跟 Monitoring 的經驗類似,都會彈出一個 Terminal 畫面來顯示安裝過程。
75 | 畫面最下方則是顯示了到底系統是使用什麼指令來安裝 Helm Chart,安裝完畢可以用左上的按鈕離開畫面。
76 |
77 | 
78 |
79 | 接者移動到 Installed Charts 可以找到前述安裝的 App,外面提供的 Active 資源數量則是代表所有 Kubernetes 的資源,不單單只是舊版所顯示的 Pod 而已。
80 |
81 | 
82 |
83 |
84 | 新版跟舊版的 App 最大的差異我認為就是 Endpoint 的顯示,舊版的 Catalog 會很好心地將 Endpoint 呈現出來讓使用者可以輕鬆存取這些服務,但是新版卻不會。
85 | 要注意的是這些存取實際上是透過 Kubernetes API 去轉發的,所以其實這項功能並不需要 Rancher 特別幫你的應用程式處理什麼,因此如果知道相關的規則,還是可以透過自行撰寫 URL 來存取相關服務網頁,如下。
86 |
87 | 
88 | 
89 |
90 |
91 | 透過 UI 觀察新版應用程式後,接下來就示範如何透過 Terraform 來管理這種新版本的 Application。
92 |
93 | Rancher 於 Terraform 中的實作是將 Catalog 與 App 的概念分開,新的概念都會補上 _v2 於相關的資源類型後面,譬如
94 | catalog_v2, app_v2。
95 |
96 | 這個範例中的作法跟前述一樣
97 | 1. 取得 project 的 ID(此處省略)
98 | 2. 透過 catalog_v2 創造 Helm Repo
99 | 3. 創造要使用的 namespace
100 | 4. 接者使用 app_v2 創造 App
101 |
102 | Terraform 的程式碼非常簡單,如下
103 | ```bash
104 | resource "rancher2_catalog_v2" "dashboard-global-app" {
105 | name = "dashboard-terraform"
106 | cluster_id = "c-z8j6q"
107 | url = "https://kubernetes.github.io/dashboard/"
108 | }
109 | resource "rancher2_namespace" "dashboard-app" {
110 | name = "dashboard-terraform-app"
111 | project_id = data.rancher2_project.system.id
112 | }
113 | resource "rancher2_app_v2" "dashboard-app" {
114 | cluster_id = "c-z8j6q"
115 | name = "k8s-dashboard-app-terraform"
116 | namespace = rancher2_namespace.dashboard-app.id
117 | repo_name = "dashboard-terraform"
118 | chart_name = "kubernetes-dashboard"
119 | chart_version = "4.5.0"
120 | depends_on = [rancher2_namespace.dashboard-app, rancher2_catalog_v2.dashboard-global-app]
121 | }
122 | ```
123 |
124 | 其實透過觀察 v2 版本的 API 就可以觀察出來 v2 的改動很多,譬如
125 | 1. catalog_v2 (Helm Repo) 移除了關於 Scope 的選項,現在所有的 Helm Repo 都是以 Cluster 為單位,不再細分 Global, Cluster, Project.
126 | 2. app_v2 (App) 安裝部分差異最多,特別是 Key 的部分跟貼近 Helm Chart 使用的名詞,使用上會更容易理解每個名詞的使用。
127 | 譬如使用 chart_name, chart_version 取代過往的 template, template_version,同時使用 repo_name 取代 catalog_name。
128 | 不過如果都要使用 repo_name 了,其實直接捨棄 catalog_v2 直接創造一個新的物件 helm_repo 我認為會更佳直覺一些。
129 |
130 | 另外 App 移除了對於 Project 的使用,反而是跟 Cluster 有關,變成 App 都是以 Cluster 為基本單位。
131 |
132 | 當 Terraform 順利執行後,就可以於 App 頁面觀察到前述描述的應用程式被順利的部署起來了,如下圖。
133 |
134 | 
135 |
136 | 到這邊可能會感覺到有點混淆,似乎使用 Cluster Explorer 就再也沒有 Project 的概念了,因此我認為 Rancher v2.6 後續還有很多東西要等,短時間內 Cluster Explorer 沒有辦法完全取代 Cluster Manager 的介面操作,但是部分功能 (Monitoring) 又已經完全轉移到 Cluster Explorer,這會造就管理者可能會兩個功能 (Cluster Explorer/Manager) 都會各自使用一部分的功能。
137 |
138 | 期許 Rancher 能夠將這些概念都同步過去才有辦法真正的移除 Cluster Manager,或是更可以直接的說過往的某些概念於新版後都不再需要。
139 |
--------------------------------------------------------------------------------
/2021/day2.md:
--------------------------------------------------------------------------------
1 | Day 2 - 何謂 Rancher
2 | ====================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # Rancher
13 |
14 | Rancher 是一個由 Rancher Labs 的公司所維護的 Kubernetes 相關開源專案,Rancher Lab 於 2020 年底被 Suse 據傳已 600萬 ~ 700萬美金左右收購,因此如果目前搜尋
15 | Rancher 相關的資源有時候會看到跟 Suse 這間公司有關的消息就不要太意外。
16 |
17 | 簡單來說,Rancher 是一個 Kubernetes 管理平台,希望能夠讓團隊用更簡單及有效率的方式去管理各式各樣的 Kubernetes 叢集,其支援幾種不同方式
18 | 1. Rancher 自行維護的 Kubernetes 版本,Rancher Kubernetes Engine(RKE)
19 | 2. 各大公有雲所提供的 Kubernetes 服務,如 AKS, EKS 以及 GKE
20 | 3. 任何使用者自己創建的 Kubernetes 叢集
21 |
22 | 除了上述 Kubernetes 叢集外, Rancher 也支援眾多公有雲平台來簡化整個部署流程,譬如可以讓公有雲自動創建 VM 並且於 VM 上創建 RKE 叢集,而且這些 VM
23 | 還可以根據不同的需求設定不同的能力,譬如某些節點設定 4c8g(4vCPU, 8G Memory),某些給予 16c32g,同時有些專門當 worker,有些可以當 etcd/control plan等不同角色。
24 |
25 | 註: 不同來源的 Kubernetes 叢集功能上會有些許差異,詳細可以參閱[官網介紹](https://rancher.com/docs/rancher/v2.5/en/overview/),RKE 跟 EKS/GKE 於 2.5.8 版本則擁有全部的操作能力,但是 AKS 或是其他使用者自行架設的 Kubernetes 叢集會有些功能沒辦法使用。
26 |
27 | 有些人會好奇,如果自己都已經有方式去架設跟管理自己的 Kubernetes 叢集,那為什麼還需要使用 Rancher 的管理平台?
28 | 就如同 Kubernetes 一樣,要不要導入 Rancher 也是要評估的,我認為符合下列情況的團隊其實並不一定要使用 Rancher,譬如
29 | 1. 雲端環境直接採用 Kubernetes 服務,如 EKS/AKS/GKE
30 | 2. 直接尋找系統整合商購買 Kubernetes 服務
31 | 3. 沒有地端(On-premises)環境需求
32 | 4. 公司不太想要使用開源專案,希望專案都要有人員提供技術服務
33 |
34 | 如果團隊都沒有符合上述需求時,其實可以評估看看是否要導入 Rancher
35 | 導入的第一個問題就是導入 Rancher 能夠帶來什麼好處?,為什麼要使用 Rancher?
36 |
37 |
38 |
39 | 我個人認為 Rancher 對於團隊帶來的好處有
40 | 1. 很輕鬆地去架設一套 RKE 的環境,雖然本身是 Rancher 所維護的版本,但是大部分情況跟原生 Kubernetes 使用起來沒有差異。
41 | 2. 如果團隊同時有地端跟雲端的混合環境,可以透過 Rancher 方便管理多套 Kubernetes
42 | 3. 如果今天地端環境本身擁有網路防火牆限制,導致想要從外部使用 Kubectl 來存取與管理該地端上的 Kubernetes 叢集會有困難時,使用 Rancher 能夠輕鬆地處理這個問題。
43 | 4. Rancher 提供的 Dashboard 提供滿多訊息,可以一目明瞭目前所有 Kubernetes 叢集的健康狀態,非工程人員也可以容易閱讀
44 | 5. Rancher 本身支援不同的認證機制,可以跟團隊本身使用的認證服務整合,直接透過現有的狀態來認證與授權,管理上非常方便
45 |
46 | 有了上述功能後,來看一下從[官方](https://rancher.com/docs/rancher/v2.5/en/overview/)所節錄的架構圖,來看看導入 Rancher 後對於整個團隊有什麼變化?
47 |
48 | 
49 |
50 | 上圖分成三個部分,左邊代表 DevOps Team,中間是 Rancher 管理平台,右邊則是公司的 IT Team.
51 | Rancher平台(中間)
52 | 1. Rancher 本身管理多套 Kubernetes 叢集,譬如圖中的 GKE/EKS,甚至可以跟 VMware 整合,將 RKE 安裝到產生的 VM 上
53 | 2. 如果已經跟公有雲平台串接完畢(API),則可以透過 Rancher 的介面自動創立相關 VM 並且直接再上面創建 RKE 叢集,因此可以很方便根據需求創立 Dev/Staging/QA/Prod 等不同用途的 Kubernetes 叢集
54 |
55 | IT Team(右邊)
56 | 1. IT Team 對於公司內的環境會有比較不同的需求,譬如帳號認證授權,安全政策等
57 | 2. IT 直接將 Rancher 與團隊內的身份機制整合,可以讓每個不同的 Kubernetes 都擁有不同的存取權限,譬如 QA Team 的人只擁有 QA 叢集的完全存取權限,而 Dev Team 的人可以存取 Dev 叢集,DevOps Team 的人則可以對所有叢集都有權限。
58 | 3. 可以直接於 Rancher 本身設定相關的安全政策,這些安全政策會直接套用到所有託管的 Kubernetes 叢集內。
59 | 4. Rancher 其實也有實作 Terraform 的介面,所以 IT Team 是可以直接透過 Terraform 使用 Infrastructure as Code 的概念來維護 Rancher,這樣就可以很簡單與快速的維護與創建各種叢集。
60 |
61 | DevOps Team(左邊)
62 | 1. DevOps Team 使用 IT Team 設定好的身份帳號來存取相關 Kubernetes 叢集
63 | 2. Rancher 也提供 KUBECONFIG 供使用者透過 kubectl/helm 等工具使用,也可以將此資訊整合到 CI/CD 流程來達成自動部署。
64 | 3. Rancher 也提供應用程式部署的相關機制讓使用者可以方便地管理 Kubernetes 上的應用
65 | 4. Rancher 整合的 Monitoring/Logging/Alert 功能讓使用者用起來很簡單。
66 | 5. Rancher Fleet 使用 GitOps 的方式簡化了部署流程,使用者只需要更新 Git Repo 就可以順利更新自己的應用程式,甚至本身對於 Kubernetes 底層不太熟悉都能夠順利部署進去
67 |
68 | 當然上述架構只是一個範例,實際上更有可能是 DevOps Team 而非 IT Team 需要維護 Rancher 本身,這部分完全是取決於團隊的分工與組成。
69 |
70 | # 版本選擇
71 | 目前主流的 Rancher 版本是 v2.5 系列,如果還沒有使用過 Rancher 的讀者建議都直接使用 v2.5 系列版本,主要是 v2.5 相對於前版有很多重大修改,譬如
72 | 1. Monitoring 功能的改進,v2.5 以前是用 Rancher 自行整合的 Prometheus/Grafana,所以使用者要客製化上會相對麻煩。 v2.5 整個架構都改成基於 Prometheus Operator 的做法,因此如果本來就熟悉 Prometheus Operator 的使用者可以更容易的使用 Rancher Monitoring 來加上自己想要的功能。
73 | 2. Rancher 的 UI 也有大幅度的改動,過往瀏覽觀察 Cluster 的介面稱為 Cluster Manager,而新版的 Cluster Explorer 將會是未來維護的主要功能
74 | 3. 整合 Rancher Fleet 來提供基於 GitOps 的部署方式,之後的章節會詳細介紹如何使用 Rancher Fleet 來管理多叢集的應用程式
75 | 4. 提升與 AWS EKS 的整合,可以將已經創立的 EKS 直接整合到 Rancher 讓管理員用一個 Rancher 去管理多個 Kubernetes
76 |
77 | 目前 v2.6 版本還在積極開發中,目前已知 2.6 也在努力提升與 AKS/GKE 的整合。
78 | 同時 Rancher v2.5 之後 Rancher 本身的安裝方式也都轉移到 Helm3,因此如果需要從舊版 Rancher 轉移到新版 Rancher 時,有可能會遇到 Helm 轉移的問題
79 | 所以新的使用者都強烈建議直上 v2.5,而不要再嘗試舊版了。
80 |
81 | 下篇文章將詳細介紹 Rancher 的架構,看完該架構會更加理解到底 Rancher 扮演何種角色。
--------------------------------------------------------------------------------
/2021/day20.md:
--------------------------------------------------------------------------------
1 | Day 20 - 初探 GitOps 的概念
2 | =========================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前述文章探討了應用程式部署的基本思路,從 Rancher 管理的叢集出發有至少三種不同的部署方式,分別為
15 | 1. 直接取得 Kubeconfig 獲得對 Kubernetes 叢集操作的權限
16 | 2. 使用 Rancher 內的應用程式機制(Catalog or App & Marketplace) 來安,並可透過 Terraform 來達到 Infrastructure as Code 的狀態。
17 | 3. 使用 GitOps 的方式來管理 Kubernetes 應用程式
18 |
19 | 本篇文章開始將探討何謂 GitOps 以及 GitOps 能夠帶來的好處,並且最後將基於 Rancher FLeet 去進行一系列 GitOps 解決方案的
20 | 示範。
21 |
22 | # GitOps
23 |
24 | 就如同 DevOps 是由 DEV + OPS 兩種概念結合而成, GitOps 的原意來自於 Git 以及 OPS,目的是希望以 Git 上的資料為基底去驅動 Ops 相關的操作。
25 |
26 | 該詞源自於 2017 年由 Weave Works 所提出,GitOps 本身並沒有一個非常標準的定義與實作方式,就如同 DevOps 的文化一樣, 不同人使用 GitOps 的方式都不同,但是基本上都會遵循一個大致上的文化。
27 |
28 | GitOps 的精神就是以 Git 作為唯一的資料來源,所有的應用程式部署都只能依賴這份 Git 上內容去變化。
29 | 基於這種精神,下列行為都希望盡量減少甚至避免。
30 | 1. 直接透過 KUBECONNFIG 對叢集直接使用 Helm/Kubectl 去進行操作
31 | 2. 透過其他機制(Rancher Catalog/App) 去對叢集進行應用程式的管理
32 |
33 | 當 Git 作為一個唯一的資料來源時,整個部署可以帶來下列的好處
34 | 1. Git 本身的管理控制提供了應用程式的稽核機制,透過 Git 機制可以知道誰於什麼時間點什麼時間點帶來了什麼樣的改變。
35 | 2. 需要退版的時候,可以使用 Git Revert 的方式來退版 Git 內容,因此應用程式也會退版
36 | 3. 可以透過 Git 的方式(Branch, tag) 等本身機制來管理不同環境的應用程式
37 | 4. 由於 Git 本身都會使用 Pull Request/Git Review 等機制來管理程式碼管理,因此該機制可以套用到應用程式管理上。
38 |
39 | 這邊要注意的是, GitOps 本身的並沒有特別限制只能使用於 Kubernetes 環境之中,只是當初 Weave work 講出這名詞時是基於 Kubernetes 的環境來探討,因此後續比較多的解決方案也都是跟 Kubernetes 有關,但是這並不代表 GitOps 只能使用於 Kubernetes 內,任何的使用環境只要有基於 Git/Ops 的理念,基本上都可以想辦法實作 GitOps.
40 |
41 | 但是 GitOps 到底要如何實作? 要如何將 Git 的更動給同步到應用程式的部署則沒有任何規範與標準,目前主要有兩種主流,以下都是一種示範介紹,實務上實作時可以有更多不同的變化。
42 | 1. 專屬 CI/CD 流水線
43 | 2. 獨立 Controller
44 |
45 | 接下來以 Kubernetes 為背景來探討一下可能的解法。
46 |
47 | # 專屬 CI/CD 流水線
48 |
49 | 這種架構下會創立一個專屬的 CI/CD Pipeline, 該 Pipeline 的觸發條件就是 Git 專案發生變化之時。
50 | 所以 Pipeline 中會去抓取觸發當下的 Git 內容,接者從該內容中判別當前有哪些檔案被修改,從這些被修改的檔案去判別是哪些應用程式有修改,接者針對被影響的應用程式去進行更新。
51 |
52 | 以 Kubernetes 來說,通常就是指 CI/CD Pipeline 中要先獲得 KUBECONFIG 的權限,如果使用的是 Rancher,則可以使用 Rancher API Token。
53 | 當系統要更新應用程式時,就可以透過這些權限將 Kubernetes 內的應用程式進行更新。
54 |
55 | 這種架構基本上跟傳統大家熟悉的 CD 流程自動化看起來沒有什麼不同,不過 GitOps 會更加強調以 Git 為本,所以會希望只有該 CI/CD Pipeline 能夠有機會去更新應用程式,這也意味任何使用者直接透過 KUBECONFIG 對 Kubernetes 操作這件事情是不被允許的。
56 |
57 | 所以 GitOps 不單單是一個工具與解決方案,也是一個文化。
58 |
59 | # 獨立 Controller
60 | 第二個解決方式是目前 Kubernetes 生態中的常見作法,該作法必須要於 Kubernetes 內部署一個 Controller,該 Controller 本身基於一種狀態檢查的無限迴圈去運行,一個簡單的運作邏輯如下。
61 | 1. 檢查目標 Git 專案內的檔案狀態
62 | 2. 檢查當前 Kubernetes 叢集內的應用程式狀態
63 | 3. 如果(2)的狀態與(1)不同,就更新叢集內的狀態讓其與(1)相同
64 |
65 | 一句話來說的話,該 Controller 就是用來確保 Git 專案所描述的狀態與目標環境的現行狀態一致。
66 |
67 | 為了完成上述流程,該 Controller 需要有一些相關權限
68 | 1. 能夠讀取 Git 專案的權限
69 | 2. 能夠讀取 Kubernetes 內部狀態的權限
70 | 3. 能夠更新 Kubernetes 應用程式的權限
71 |
72 | 由於該 Controller 會部署到 Kubernetes 內部,所以(2+3)的權限問題不會太困難,可以透過 RBAC 下的 Service Account 來處理。
73 | (1)的部分如果是公開 Git 專案則沒有太多問題,私人的話就要有存取的 Credential 資訊。
74 |
75 | 以下是一個基於 Controller 架構的部署示範
76 | 1) 先行部署 Controller 到 Kubernetes 叢集內
77 | 2) 設定目標 Git 專案與目標 k8s 叢集/namespace 等資訊。
78 | 3) 開發者針對 Git 專案進行修改。
79 | 4) Controller 偵測到 Git 專案有變動
80 | 5) 獲取目前 Git 狀態
81 | 6) 獲取目前 叢集內的應用程式狀態
82 | 7) 如果(5),(6)不一樣,則將(5)的內容更新到叢集中
83 | 8) 反覆執行 (4~7) 步驟。
84 |
85 | 到這邊為止探討了關於 GitOps 的基本概念,接下來就會數個知名的開源專案去進行探討
86 |
--------------------------------------------------------------------------------
/2021/day21.md:
--------------------------------------------------------------------------------
1 | Day 21 - GitOps 解決方案比較
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前篇文章探討了基本的 GitOps 概念,GitOps 本身沒有嚴謹明確的實作與定義,所以任何宣稱符合 GitOps 工作流程的解決方案其實作方式與使用方有可能並不相同。
15 |
16 | 本文將探討數個常見的 GitOps 解決方案,針對其基本概念進行研究,一旦對這些解決方案都有了基本認知後,就可以更快的理解 Rancher Fleet 這套由 Rancher v2.5 後主推的 GitOps 解決方案是什麼,該怎麼使用。
17 |
18 | # KubeStack
19 | GitOps 並不是專屬於 Kubernetes 的產物,任何架構與專案都有機會採用 GitOps 的概念來實作。
20 | KubeStack 是目前極為少數非 Kubernetes 應用程式的 GitOps 解決方案,官網宣稱是一個專注於 Infrastructure 的 GitOps 框架。該架構基於 Terraform 去發展,因此 KubeStack 的使用者實際上還是撰寫 Terraform ,使用 Terraform 的語言。 KubeStack 針對 Terraform 發展了兩套不同的 Terraform Module,分別是 Cluster Module 以及 Cluster Service Module。
21 |
22 | Cluster Module 讓使用者可以方便的去管理 Kubernetes 叢集,該叢集可以很輕鬆的去指定想要建立於哪種雲端架構上,透過 KubeStack 使用者也可以很容易的針對不同地區不管雲端架構來搭建多套的 Kubernetes 叢集。
23 | 其實整體概念滿類似 Rancher 的,只不過這邊是依賴 Terraform 來管理與多個雲端架構的整合,同時 Kubernetes 叢集也會採用原生版本或是 Kubernetes 管理服務的版本。
24 |
25 | Cluster Service Module 目的是用來創造 Kubernetes 相關資源,所以使用上會先透過 Cluster Module 創建 Kubernetes 叢集,接者透過 Cluster Service Module 部署相關服務。
26 | Cluster Service Module 的目的並不是部署各種團隊的商業邏輯服務,相反的,其目的是則是部署前置作業,任何真正部署前需要用到的服務都會透過這個 Module 來處理。預設情況下 KubeStack 有提供 Catalog 清單來提供預設提供的服務,包含了
27 | 1. ArgoCD/Flux
28 | 2. Cert-Manager
29 | 3. Sealed Secrets
30 | 4. Nginx Ingress
31 | 5. Tekton
32 | 6. PostgreSQL Operator
33 | 7. Prometheus Operator
34 |
35 | 而前述兩個則是針對 kubernetes 應用程式的 GitOps 解決方案。
36 |
37 | KubeStack 的使用方式是採用前述探討的第一種實作,團隊需要準備一個專屬的 CI/CD Pipeline,其內透過呼叫 Terraform 的方式來完成整個更新的流程,對於 KubeStack 有興趣的可以參閱其官網。
38 |
39 |
40 | # ArgoCD/Flux
41 | 探討到開源且針對 Kubernetes 應用程式部署的解決方案時,目前最知名的莫過於 ArgoCD 以及 Flux。
42 |
43 | ArgoCD 本身的生態系非常豐富,該品牌底下有各式各樣不同的專案,專注於不同功能,而這些功能又有機會彼此互相整合,譬如
44 | 1. ArgoCD
45 | 2. Argo Workflow
46 | 3. Argo RollOut
47 |
48 | ArgoCD 是專注於 GitOps 的解決方案, Argo Workflow 是套 Multi-Stage 的 pipeline 解決方案,而 Argo Rollout 則是希望能夠針對 Kubernetes 提供不同策略的部署方式,譬如藍綠部署,金絲雀部署等,這些都是 Kubernetes 原生不方便實作的策略。
49 |
50 | ArgoCD 採用的是第二種實作方式,需要於 Kubernetes 內安裝 ArgoCD 解決方案,該解決方案大致上會於叢集內安裝
51 | 1. Argo API Server
52 | 2. Argo Controller
53 | 3. Dex Server
54 | 4. Repository Service
55 |
56 | 以下架構圖來自於[官方網站](https://argo-cd.readthedocs.io/en/stable/)
57 | 
58 |
59 | Argo Controller/Repository Service 是整個 GitOps 的核心功能,能夠偵測 Git 專案的變動並且基於這些變動去比較當前 Kubernetes 內的即時狀態是否符合 Git 內的期望狀態,並且嘗試更新以符合需求。
60 | Argo API Server 則是提供一層 API 介面,讓外界使用者可以使用不同方式來操作 ArgoCD 解決方案,譬如 CLI, WebUI 等。
61 |
62 | ArgoCD 安裝完畢後就會提供一個方式去存取其管理網頁,大部分的使用者都會透過該管理網頁來操作整個 ArgoCD,該介面的操作符合不同需求的使用者,譬如 PM 想要理解當前專案部署狀態或是開發者想要透過網頁來進行一些部署操作都可以透過該網頁完成。
63 | 為了讓 ArgoCD 可以更容易的支援不同帳戶的登入與權限管理,其底層會預先安裝 Dex 這套 OpenID Connector 的解決方案,使用者可以滿容易地將 LDAP/OAuth/Github 等帳號群組與 ArgoCD 整合,接者透過群組的方式來進行權限控管。
64 |
65 | 應用程式的客製化也支援不少,譬如原生的 YAML,Helm, Kustomize 等,這意味者大部分的 kubernetes 應用程式都可以透過 ArgoCD 來部署。
66 |
67 | ArgoCD 大部分的使用者一開始都會使用其 UI 進行操作與設定,但是這種方式基本上與 Rancher 有一樣的問題
68 | 1. UI 提供的功能遠少於 API 本身,UI 不能 100% 發揮 ArgoCD 的功能
69 | 2. 設定不易保存,不容易快速複製一份一樣的 ArgoCD 解決方案,特別是當有災難還原需求時。
70 |
71 | 舉例來說,ArgoCD 可以管理多套 Kubernetes 叢集,這意味你可以於叢集(A)中安裝 ArgoCD,透過其管理叢集B,C,D。
72 | 管理的功能都可以透過網頁的方式來操作,但是要如何讓 ArgoCD 有能力去存取叢集 B,C,D,相關設定則沒辨法透過網頁操作,必須要透過 CLI 或是修改最初部署 ArgoCD時的 YAML 檔案。
73 |
74 | ArgoCD 實際上於 Kubernetes 內新增了不少 CRD(Custom Resource Definition),使用者於網頁上的所有設定都會被轉換為一個又一個的 Kubernetes 物件,而且 ArgoCD 本身的部署也是一個又一個 YAML 檔案,因此實務上解決設定不易保存的方式就是 「讓 ArgoCD 透過 GitOps 的方式來管理 ArgoCD」
75 |
76 | 該工作流程如下(範例)
77 | 1. 將所有對 ArgoCD 的設定與操作以 YAML 的形式保存於一個 Git 專案中
78 | 2. 使用官方 Helm 的方式去安裝最乾淨的 ArgoCD
79 | 3. 於 ArgoCD 的網頁上新增一個應用程式,該應用程式目標是來自(1)的 Git 專案
80 | 4. ArgoCD 會將(1)內的 Git 內容都部署到 Kubernetes 中
81 | 5. ArgoCD 網頁上就會慢慢看到所有之前設定的內容
82 |
83 | 如果對於 ArgoCD 有興趣的讀者可以參考我開設的線上課程[kubernetes 實作手冊: GitOps 版控整合篇
84 | ](https://hiskio.com/courses/490/about?promo_code=R3Y9O2E),該課程中會實際走過一次 ArgoCD 內的各種操作與注意事項,並且最後也會探討 ArgoCD 與 Argo Rollout 如何整合讓部署團隊可以用金絲雀等方式來部署應用程式。
85 |
86 | 下篇文章就會回到 Rancher 專案身上,來探討 Rancher Fleet 是什麼,其基本元件有哪些,接者會詳細的介紹 Rancher Fleet 的用法。
--------------------------------------------------------------------------------
/2021/day22.md:
--------------------------------------------------------------------------------
1 | Day 22 - Rancher Fleet 架構介紹
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 | 前篇文章探討了 ArgoCD 與 KubeStack 這兩套截然不同的 GitOps 解決方案,可以觀察到 GitOps 就是一個文化與精神,實際的操作與部署方式取決於不同解決方案。
14 |
15 | Rancher 本身作為一個 Kubernetes 管理平台,不但可以管理已經存在的 Kubernetes 叢集更可以動態的於不同架構上創建 RKE 叢集。
16 | 基於這些功能的基礎上,Rancher 要實作 GitOps 似乎會簡單一些,畢竟連 Kubernetes 都可以創建了,要部署一些 Controller 到叢集內也不是什麼困難的事情,因此本篇文章就來仔細探討 Rancher Fleet 這套 Rancher 推出的 GitOps 解決方案。
17 |
18 | # Rancher Fleet
19 |
20 | Rancher Fleet 是 Rancher 於 v2.5 後正式推出的應用程式安裝功能,該安裝方式不同於 Catalog 以及 v2.5 的 App 專注於單一應用安裝,而是更強調如何透過 GitOps 來進行大規模部署。
21 |
22 | Fleet 的設計初衷就是希望提供一個大規模的 GitOps 解決方案,大規模可以是大量的 Kubernetes 叢集或是大量的應用程式部署。為了滿足這個目標, Fleet 架構設計上就是追求輕量與簡單,畢竟 Rancher 擁有另外一套針對物聯網環境的輕量級 Kubernetes 叢集,K3s。 因此 Fleet 也希望能夠針對 K3s 這種輕量級環境來使用。
23 |
24 | Fleet 支援三種不同的格式,分別是原生YAML, Helm 以及 Kustomize,其中最特別的是這些格式還可以互些組合,這意味者使用者可以透過 Helm + Kustomize 來客製化你的應用程式,之後會有文章針對這些使用情境來介紹這類型的用途及好處。
25 |
26 | Fleet 的內部邏輯會將所有的應用程式動態的轉為使用 Helm 去安裝與部署,因此使用者除了透過 Rancher Fleet 之外也可以透過 Helm 的方式去觀察與管理這些應用程式,簡單來說 Fleet 希望可以讓透過使用者簡單的安裝大規模的應用程式,同時又提供一個良好的介面讓使用者可以管理這些應用程式。
27 |
28 |
29 | 下圖來自於[官方網站](http://fleet.rancher.io/concepts/),該圖呈現了 Fleet 的基本架構與使用概念。圖中有非常多的專有名詞,瞭解這些名詞會對我們使用 Fleet 有非常大的幫助,因此接下來針對這張圖進行詳細介紹。
30 |
31 | 
32 |
33 | Fleet 與大部分的 Operator 實作方式一樣,都是透過 Kubernetes CRD 來自定義相關資源,並且搭配一個主要的 Controller 來處理這些資源的變化,最終提供 GitOPs 的功能,因此圖上看到的大部分名詞實際上都可以到 Kubernetes 內找到一個對應的 CRD 資源。
34 |
35 | Fleet Manager/Fleet Controller:
36 |
37 | 由於 Fleet 是一個可以管理多個 Kubernetes 叢集的解決方案,其採取的是 Manager/Agent 的架構,所以架構中會有一個 Kubernetes 叢集其扮演者 Fleet Manager 的概念,而被管理的 Kubernetes 叢集則是所謂的 Fleet Agent
38 | 上圖中的 Fleet Controller Cluster 就是一個擁有 Fleet Manager 的 Kubernetes 叢集,底下三個 Cluster Group 代表的是其裡面的所有 Kubernetes 叢集都是 Fleet Agent
39 |
40 | Fleet Manager 的概念中,實際上會部署一個名為 Fleet Controller 的 Kubernetes Pod,該服務要負責處理 Fleet Agent 註冊的資訊,同時也要協調多個 Fleet Agent 當前的部署狀態最後呈現到 UI 中供管理者使用。
41 |
42 | Fleet Agent:
43 |
44 | 每一個想要被管理的 Kubernetes 叢集都被視為 Fleet Agent,實際上需要安裝一個名為 Fleet Agent 的 Kubernetes Pod 到叢集中,該 Agent 會負責跟 Fleet Manager 溝通並且註冊,確保該叢集之後可以順利地被 Fleet Manager 給管理。
45 |
46 | Single/Multi Cluster Style:
47 |
48 | Fleet 的官方網站提及兩種不同的部署模式,分別是 Single Cluster Style 以及 Multi Cluster Style
49 | Single Cluster Style 主要是測試使用,該架構下會於一個 Kubernetes 叢集中同時安裝 Fleet Agent 與 Fleet Controller,這樣就可以於一個 Kubernetes 叢集中去體驗看看 Rancher Fleet 帶來的基本部署功能。
50 | 不過實務上因為會有更多的叢集要管,因此都會採用 Multi Cluster Style,該架構如同上圖所示,會有一個集中的 Kubernetes 叢集作為 Fleet Manager,而所有要被管理的 Kubernetes 叢集都會作為 Fleet Agent.
51 |
52 | GitRepo:
53 |
54 | Fleet 中會有一個名為 GitRepo 的物件專門用來代表各種 Git 的存取資訊,Fleet Manager 會負責去監控欲部署的 Git 專案,接者將這些專案的內容與差異性給部署到被視為 Fleet Agent 的 Kubernetes 叢集。
55 |
56 | Bundle
57 |
58 | Bundle 可以說是整個 Fleet 中最重要也是最基本的資源,其代表的是一個又一個要被部署的應用程式。
59 | 當 Fleet Manager 去掃描 GitRepo 時,就會針對該 GitRepo 中的各種檔案(YAML, Helm, Kustomize) 等
60 | 產生多個 Bundle 物件。
61 | Bundle 是由一堆 Kubernetes 物件組成的,基本上也就是前篇所探討的應用程式。舉例來說,今天 Git 專案中透過 Helm 的方式描述了三種應用程式,Fleet Manager 掃描該 GitRepo 後就會產生出對應的三個 Bundle 物件。接者 Fleet Manager 就會將該 Bundle 給轉送到要部署該應用程式的 Fleet Agent 叢集,最後 Fleet Agent 就會將這些 Bundle 動態的轉成 Helm Chart 並且部署到 Kubernetes 叢集。
62 |
63 | 從上方的架構圖來看,可以看到中間的 Fleet Cluster 本身會連接 Git 專案,並且針對這些專案產生出一個又一個 Bundle 資源(Bundle Definition),接者這些 Bundle 就會被傳送到需要部署的 Kubernetes 叢集,該叢集上的 Fleet Agent 就會負責處理這些 Bundle,譬如補上針對自身叢集的客製化設定,最後部署到叢集內。
64 | 所以可以看到上圖左下方的 Kubernetes 叢集內使用的是 (Bundle with Cluster Specific Configuration) 的字眼,代表這些真正部署到該叢集內的 Bundle 都是由最基本的 Bundle 檔案配上每個叢集的客製化內容。
65 |
66 | 為了讓 Fleet 能夠盡可能地去管理不同架構的 Kubernetes 叢集, Fleet 跟 Rancher 本身的設計非常類似,都是採取 Agent Pull 的方式。該模式代表的是 Fleet Controller 不會主動的去跟 Fleet Agent 進行連線,而是由 Fleet Agent 主動的去建立連線。
67 | 這種架構的好處就是被管理的 Kubernetes 叢集可以將整個網路給隱藏到 NAT 後面,只要確保底層環境有 SNAT 的功能網路可以對外即可。
--------------------------------------------------------------------------------
/2021/day23.md:
--------------------------------------------------------------------------------
1 | Day 23 - Rancher Fleet 環境架設與介紹
2 | ==================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | ---
13 |
14 | # 前言
15 | 前述文章探討了關於 Rancher Fleet 的基本架構與概念介紹,瞭解到 Rancher Fleet 本身是個主從式的架構。環境中會有一個 Kubernetes 叢集專門用來部署 Fleet Controller 作為 Fleet Manager,而所有要被託管的 Kubernetes 叢集都必須要部署一個 Fleet Agent 來連接 Fleet Manager。
16 |
17 | 本篇文章將針對實際部署情況去觀察。
18 |
19 | # 安裝
20 |
21 | [官方網站](http://fleet.rancher.io/multi-cluster-install/) 有列出非常詳細的安裝步驟,針對 Fleet Manager 安裝要用到的憑證與除錯方式,如何使用 Helm 安裝 CRD 與 Fleet Controller 都有介紹。
22 | 當 Fleet Manager 安裝與設定完畢後,接下來就可以參考 [Cluster Registration Overview](http://fleet.rancher.io/cluster-overview/) 這篇官方文章來學習如何將一個 Kubernetes 叢集作為 Fleet Agent 加入到 Fleet Manager 的管理中。
23 |
24 | 不過這邊要特別注意的是,以上所提的安裝方式都是針對純 Fleet 解決方案時才需要考慮的部分,因為 Fleet 是 Rancher 開發與維護的,因此任何由 Rancher 管理與創建的 Kubernetes 叢集都已經內建 Fleet Agent,大幅度簡化使用者的安裝方式。
25 |
26 | 當初安裝 Rancher 時會先準備一個 Kubernetes 叢集專門用來負責 Rancher 本身的維運,其他所有的叢集都會透過這個 Rancher 去創建與維護,Rancher Fleet 會採用相同的架構與方式去處理。專門用來部署 Rancher 的 Kubernetes 叢集會被安裝 Fleet Controller。
27 |
28 | 基於以上兩點,只要所有叢集都是由 Rancher 去創建與管理的, Fleet 就不需要自己手動安裝,Fleet Manager 與 Fleet Agent 都會自動的被安裝與部署到相關叢集中。
29 |
30 | # 觀察
31 |
32 | 前述所述,用來安裝 Rancher 服務的 Kubernetes 叢集本身也會安裝 Fleet Controller,這部分可以到 Apps 的頁面去看到底有哪些應用程式被安裝到叢集中。同時透過畫面中提供的 kubectl 指令去觀察 fleet-system namespace 中安裝的 Pod,如下圖。
33 |
34 | 
35 |
36 | 可以觀察到 local 也就是部署 Rancher 的 Kubernetes 叢集有部署三個 Pod,其中 fleet-controller 以及 gitjob 兩個 pod 是針對 fleet manager 而部署的 Pod,而 fleet-agent 則是給 fleet-agent 使用的。
37 |
38 | 此架構意味者管理者可以透過該 Fleet 來管理 local 這套 Kubernetes 叢集。
39 | 之前提到 Fleet 與大部分的 Operator 有相同的開發流程,所以會使用一個 Kubernetes Controller 配上很多預先設定的 CRD 物件,所以透過 kubectl get crd 就可以看到 local 叢集上有各式各樣關於 Fleet 的 CRD。
40 |
41 | 接下來觀察要被管理的 Kubernetes 叢集,譬如給 Dev 使用的叢集,這時候使用相同的方式去觀察該叢集內安裝的資源,可以觀察到 fleet-system 內只有安裝一個 Pod,該 Pod 就是扮演 Fleet Agent 的角色,讓該叢集能夠順利的 Fleet Manager 溝通,範例如下。
42 |
43 | 
44 |
45 | 確認完畢之後就可以移動到 Rancher Fleet 的專屬頁面,移動的方式很簡單,不論當前是處於哪個叢集,點選左上方就可以找到一個名為 Continuous Delivery 的選項,點進去就會進入到 Rancher Fleet 的畫面。
46 |
47 | 
48 |
49 | 進去畫面中後會看到如下的畫面,畫面中有非常多的新東西,接下來針對這些新東西慢慢探索
50 |
51 | 
52 |
53 | 首先畫面最上方有一個下拉式選單可以選擇,該選單會列出所有可以使用的 Fleet Workspace,那到底什麼是 workspace 呢?
54 |
55 | Fleet workspace 是一個管理單位,就如同大部分專案的 workspace 概念一樣,每個 workspace 都會有自己獨立的 GitRepo, Group, Bundle 等概念。
56 | 一個實務上的上作法會創立多種不同的 workspace,譬如 dev, qa 及 prod。
57 |
58 | 每個 workspace 內都可包含多個不同的 cluster 與其他的資源。
59 |
60 | 預設的情況下有兩個 workspace,分別是 fleet-local 以及 fleet-default. 所有剛加入到 Rancher 的叢集都會被加入到 fleet-default 這個 workspace 中。
61 |
62 | 畫面左邊有六個不同的資源
63 |
64 | Git Repos:
65 | Git Repos 內的資源是告訴 Fleet 希望追蹤哪些 Git 專案,該 Git 專案中哪些資料夾的哪些檔案要讓 Fleet 幫忙管理與安裝。
66 |
67 | 因為 Fleet 什麼都還沒有安裝與設定,所以 Git Repo 內目前是空空的,沒有任何要被安裝的應用程式。
68 |
69 | Clusters/Cluster Groups:
70 | 這邊顯示的是該 workspace 中有多少個 cluster,目前的環境中先前創立三個不同的 Kubernetes 叢集,而這些叢集預設都會被放入到 fleet-default workspace 內的 group。
71 |
72 | 假設 cluster 數量過多,還可以透過 Cluster Group 的概念來簡化操作,將相容用途的 cluster 用群組的方式來簡化之後的操作。
73 |
74 | 
75 |
76 | Workspace:
77 | Workspace 可以看到目前系統有多少個 workspace,可以看到系統中有 fleet-default 以及 fleet-local,同時也會顯示這些 workspace 中目前管理多少個 cluster 。
78 |
79 | 
80 |
81 | Bundles:
82 | 之前提過 Bundle 是 Fleet controller 掃過 GitRepo 專案後會產生的安裝資源檔案。
83 | 可以當前的範例非常奇妙,沒有任何 Git Repo 的內容卻擁有這些 Bundle 檔案,主要是因為這三個 Bundle 是非常奇妙與特殊的 Bundle,仔細看的話可以觀察到這些 Bundle 的名稱都是 Fleet-agent-c-xxxx,這些 bundle 是用來安裝 fleet-agent 到目前 Rancher 下的所有 Kubernetes 叢集。
84 | 這些安裝是 Rancher 內建強迫的,所以使用上會稍微跟正常用法有點不同。
85 |
86 | 
87 |
88 | ClusterRegistrationTokens:
89 | 最後一個則是 Cluster(Fleet Agent) 要加入到 Fleet Manager 使用的 Token,不過因為目前的叢集全部都是由 Rancher 去管理與創造的,所以不需要參考官網自行安裝,因此 Rancher 會走比較特別的方式來將 Rancher 管理的叢集給加入到 Fleet manager 中,因此這邊就是空的。
90 |
91 |
92 | 此外透過 Cluster 內的操作,可以將該 workspace 下的 cluster 給移轉到其他的 workspace,所以之後根據需求創立不同的 workspace 後,就可以透過這個方式將 cluster 給移轉到屬於該用途的 workspace。
93 |
94 | 
95 |
96 | 到這邊為止,稍微看了一下關於 Fleet 介面的操作與基本概念,下一篇就會正式嘗試透過 Git Repo 這個物件來管理試試看 GitOps 的玩法,此外因為 Fleet 內的操作基本上都可以轉化為 Kubernetes 的 CRD 物件,所以很多 UI 的設定都可以使用 YAML 來管理,透過這個概念就可以達到跟 ArgoCD 一樣的想法,用 GitOps 來管理 Fleet 本身。
97 |
--------------------------------------------------------------------------------
/2021/day25.md:
--------------------------------------------------------------------------------
1 | Day 25 - Rancher Fleet.yaml 檔案探討
2 | ===================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 | 前篇文章用很簡易的方式去探討如何使用 Fleet 的 GitOps 概念來管理資源,最後面用一個非常簡易的 Deployment 物件來展示如何讓 Fleet 將該資源部署到三個叢集中。
14 |
15 | 實務上使用的情境會更加複雜,譬如說
16 | 1. 應用程式來源不同,有的是純 YAML 檔案,有的是透過 Helm 包裝,有的是透過 Kustomize 去包裝
17 | 2. 希望針對不同叢集有不同客製化,以 Helm 來說可能不同的叢集要給不同的 values.yaml
18 |
19 | 因此接下來的文章就會針對上述兩個概念來探討,到底於 Fleet 中要如何滿足上述要求。
20 |
21 | # GitRepo 掃描方式
22 |
23 | Fleet 中要先準備 GitRepo 的物件,該物件中會描述
24 | 1. Git URL
25 | 2. 檔案的路徑來源
26 |
27 | 準備好該 GitRepo 物件後, Fleet 就會去掃描該 Git 專案並且掃描底下的路徑,接者從裡面找出可以使用的 Kubernetes 資源檔案。
28 |
29 | 實際上 Fleet 的運作邏輯更加複雜,因為 Fleet 支援下列幾種變化
30 | 1. 原生 YAML 檔案
31 | 2. Helm Chart
32 | 3. Kustomize
33 |
34 | 這三種變化大抵上可以分成五種不同的檔案來源,分別是
35 | 1. Chart.yaml
36 | 2. kustomization.yaml
37 | 3. fleet.yaml
38 | 4. *.yaml
39 | 5. overlays/{name}
40 |
41 | Helm Chart 本身又分成兩種部署方式,分別是
42 | 1. 使用遠方的 Helm Server
43 | 2. 將 Helm Chart 直接放到 Git 專案中,所以專案內會有 charts.yaml, templates 等檔案。
44 |
45 | 將上述的概念整合請來大抵上就是
46 |
47 | 1. 當路徑上有 Chart.yaml 檔案時,Fleet 就會認為要使用 Helm Chart 的概念去部署
48 | 2. 當路徑上有 kustomization.yaml 檔案時, Fleet 就會認為要使用 Kustomize 的方式來部署應用程式
49 | 3. 當路徑上有 fleet.yaml 檔案時, Fleet 會依照該檔案中的作法去部署,實務上都會使用 fleet.yaml 去描述部署的策略
50 | 4. 當路徑上沒有 Chart.yaml 與 kustomization.yaml 時,Fleet 就會使用最直覺的 Kubernetes 資源去部署
51 | 5. overlays/{name} 這是針對(4)情況使用的客製化部署,是專門針對純 Kubernetes 資源的客製化。
52 |
53 | 前篇文章只有準備一個 deployment.yaml,所以就會踩到 (4) 這種部署方式。實務上最常使用的就是 fleet.yaml,fleet.yaml 可以直覺去呈現每個應用程式針對不同叢集的客製化設定,同時還可以做到混合的效果,譬如單純使用 Helm Chart, 單獨使用 Kustomize,或是先 Helm Chart 再 Kustomize 的混合部署。
54 |
55 | 所以可以知道 Fleet.yaml 可以是整個 Fleet 部署的重要精靈與靈魂,所有的應用程式都需要準備一個 fleet.yaml
56 |
57 | # Fleet.yaml
58 |
59 | Fleet.yaml 是一個用來控制 Fleet 如何去處理當前資料夾下的 YAML 檔案,該用什麼方式處理以及不同的叢集應該要如何客製化。
60 | 每一個 fleet.yaml 都會被產生一個對應的 Fleet Bundle 物件,所以通常會將 fleet.yaml 放到每個應用程式的最上層路徑。
61 |
62 | Fleet.Yaml 的詳細內容如下,接下來根據每個欄位介紹一下
63 |
64 | ```YAML=
65 |
66 | defaultNamespace: default
67 |
68 | namespace: default
69 |
70 | kustomize:
71 | dir: ./kustomize
72 |
73 | helm:
74 | chart: ./chart
75 | repo: https://charts.rancher.io
76 | releaseName: my-release
77 | constraint
78 | version: 0.1.0
79 | during
80 | values:
81 | any-custom: value
82 | valuesFiles:
83 | - values1.yaml
84 | - values2.yaml
85 | force: false
86 |
87 | paused: false
88 |
89 | rolloutStrategy:
90 | maxUnavailable: 15%
91 | maxUnavailablePartitions: 20%
92 | autoPartitionSize: 10%
93 | partitions:
94 | - name: canary
95 | maxUnavailable: 10%
96 | clusterSelector:
97 | matchLabels:
98 | env: prod
99 | clusterGroup: agroup
100 | clusterGroupSelector: agroup
101 |
102 | targetCustomizations:
103 | - name: prod
104 | namespace: newvalue
105 | kustomize: {}
106 | helm: {}
107 | yaml:
108 | overlays:
109 | - custom2
110 | - custom3
111 | specified,
112 | clusterSelector:
113 | matchLabels:
114 | env: prod
115 | clusterGroupSelector:
116 | matchLabels:
117 | region: us-east
118 | clusterGroup: group1
119 | ```
120 |
121 | defaultNamespace/namespace
122 | defaultNamespace 代表的是如果 Kubernetes YAML 資源沒有標示 namespace 的話,會自動的被部署到這個 defaultNamespace 所指向的位置。
123 |
124 | namespace 則是強迫將所有資源給安裝到某個 namespace 中,要特別注意的是如果目標 namespace 中已經有重複的資源的話,安裝可能會失敗,這點跟正常的 kubernetes 資源一樣。
125 |
126 | kustomize:
127 | 熟悉 kustomize 的朋友一定都知道 kustomize 習慣上都會透過一個又一個資料夾搭配 kustomization.yaml 來客製化資源,對於 Fleet 來說給予一個相對的資料夾位置, Fleet 就會嘗試尋找該資料夾底下的 kustomization.yaml 並且客製化。
128 |
129 | helm:
130 | Helm Chart 本身有兩種使用方式,一種是讀取遠方 Helm Server 上面的物件,一種是本地的 Helm 物件,因此 helm 格式內就有 chart/repo 等不同欄位要交互使用。
131 | 之後的文章都會有這些的使用範例,所以這邊就不詳細列出使用方式。
132 |
133 | 如果採用的是 helm server 的話,還可以指名想要安裝的版本,同時可以透過兩種不同的方式來客製化,一種是直接使用 values:.... 的格式來撰寫,這種方式適合少量客製化的需求,當客製化的數量過多時就推薦使用第二種 valuesFiles 的方式來載入客製化內容。
134 |
135 | pause:
136 | Pause 的用途是讓 Fleet 單純做版本掃描確認有新版本,但是不會幫忙更新 Kubernetes 內的資源,管理人員需要自己手動從 UI 去點選 force update 來更新。
137 | 預設情況下都是 false,就代表 Fleet 不但會確認新舊差異也會幫忙更新資源。
138 |
139 | rolloutStrategy:
140 | Fleet 的用途是管理大量叢集的部署,因此其提供的 rolloutStrategy 的選項來客製化叢集間的更新策略,基本上跟 Kubernetes Deployment 的更新策略非常雷同,同時間可以有多少個 Cluster 可以處於更新的狀態,
141 |
142 | 這個欄位中主要分成兩大類
143 | 1. 如何將 Group 分類,稱為 Partition
144 | 2. 如何針對所有的 Group/Partition 去設定更新的比率
145 |
146 | targetCustomizations:
147 | 這個欄位是整個 Fleet.yaml 最重要的部分
148 | 前述的 Helm/Kustomization 代表的是如何渲染當前路徑底下的 Kubernetes YAML 檔案。
149 | 而 targetCustomizations 則是要如何針對不同的 Kubernetes 叢集進行二次客製化
150 |
151 | 重要的是下方三個選項,如何選擇一個 Cluster,有三種不同方式
152 | 1. clusterSelector
153 | 2. clusterGroupSelector
154 | 3. clusterGroup
155 |
156 | 其中(2)/(3)兩個都是針對 Cluster Group 直接處理,所以如果有相同類似的 Cluster 就可以直接群組起來進行處理,不然就要使用第一種方式透過 selector 的方式去處理。
157 | clusterSelector 的方式跟 Kubernetes 內大部分的資源處理一樣,都是透過 Label 的方式去處理。
158 | Label 可以於 UI 方面透過點選的方式去加入這些 label,當然也可以透過 Terraform 去創建 RKE Cluster 的時候一起給予 Label。
159 |
160 | 從網頁要給予 Label 的話,就點選到 Cluster 頁面,找到目標的 Cluster ,點選 Edit Config/Edit YAML 都可以。
161 |
162 | 
163 |
164 | 接者於畫面中去填寫想要使用的 Label,這些 Label 就可以於 fleet.yaml 去客製化選擇。
165 |
166 | 
167 |
168 |
169 | 如果想要嘗試 Cluster Group 的話也可以嘗試將不同的 Cluster 給群組起來,之後的範例都可以嘗試看看。
170 |
171 | 
172 |
173 | # 簡單範例
174 | 以下範例節錄自[官網範例](https://github.com/rancher/fleet-examples/blob/master/multi-cluster/helm-external/fleet.yaml)
175 |
176 | ```yaml=
177 | namespace: fleet-mc-helm-external-example
178 | helm:
179 | chart: https://github.com/rancher/fleet-examples/releases/download/example/guestbook-0.0.0.tgz
180 | targetCustomizations:
181 | - name: dev
182 | helm:
183 | values:
184 | replication: false
185 | clusterSelector:
186 | matchLabels:
187 | env: dev
188 |
189 | - name: test
190 | helm:
191 | values:
192 | replicas: 3
193 | clusterSelector:
194 | matchLabels:
195 | env: test
196 |
197 | - name: prod
198 | helm:
199 | values:
200 | serviceType: LoadBalancer
201 | replicas: 3
202 | clusterSelector:
203 | matchLabels:
204 | env: prod
205 | ```
206 |
207 | 上述的 fleet.yaml 非常直覺
208 | 1. 使用 遠方的 Helm Chart 檔案作為目標來源
209 | 2. 使用 env 作為 label 來挑選三個不同的 cluster
210 | 3. 每個 cluster 使用時都會設定不同的 value 內容。
211 |
212 | 下篇文章就會嘗試使用這些概念來實際部署應用程式
--------------------------------------------------------------------------------
/2021/day26.md:
--------------------------------------------------------------------------------
1 | Day 26 - Rancher Fleet Kubernetes 應用程式部署
2 | ============================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前篇文章探討了 Fleet.yaml 的基本概念,而本篇文章就會針對各種不同的情境來示範如何使用 fleet.yaml 來達到客製化的需求。
15 |
16 | 本篇所有 YAML 範例都來自於[官方範例](https://github.com/rancher/fleet-examples)。
17 |
18 | # Overlay
19 | 第一個要示範的情境是使用純 Kubernetes YAML 為基礎的客製化,因為純 Kubernetes YAML 沒有辦法達到類似 Helm/Kustomize 的內容客製化,所以能夠提供的變化有限,頂多只能做到不同檔案的資源部署。
20 |
21 | 假設今天總共有四種資源,該四種資源為
22 | 1. Deployment A
23 | 2. Service A
24 | 3. Deployment B
25 | 4. Service B
26 |
27 | 希望達到的客製化為
28 | Dev 叢集安裝
29 | 1. Deployment A
30 | 2. Service A
31 |
32 | IT 叢集安裝
33 | 1. Deployment A
34 | 2. Service A
35 | 3. Deployment B
36 |
37 | QA 叢集安裝
38 | 1. Deployment A
39 | 2. Service A
40 | 3. Deployment B
41 | 4. Service B
42 |
43 | 前述有提過,對於純 YAML 來說,Fleet 提供一個名為 overlay 的資料夾來客製化,因此先於專案中的 app 底下創建一個 basic_overlay 的資料夾。
44 |
45 | 由於 deployment A 這個資源三個叢集都需要,所以可以放到最外層,讓所有叢集共享,只需要針對(2)/(3)/(4) 進行客製化即可。
46 |
47 | 客製化的作法很簡單,於 overlays 底下創建不同的資料夾,然後於資料夾中放置想要客製化的檔案即可。
48 | 這時候的架構應該會長得很類似下圖
49 |
50 | ```bash=
51 | ╰─$ tree .
52 | .
53 | ├── fleet.yaml
54 | ├── frontend-deployment.yaml
55 | └── overlays
56 | ├── dev
57 | │ └── frontend-service.yaml
58 | ├── it
59 | │ ├── frontend-service.yaml
60 | │ └── redis-master-deployment.yaml
61 | └── qa
62 | ├── frontend-service.yaml
63 | ├── redis-master-deployment.yaml
64 | └── redis-master-service.yaml
65 | ```
66 |
67 | 這邊先忽略 fleet.yaml 的內容,仔細看剩下的內容。
68 | frontend-deployment 就是 deployment A 的服務,而 overlays 底下的資料夾對應了三個不同的叢集,每個叢集內都放置更多的資源。
69 | 譬如 dev 底下多了 frontend-service,就是所謂的 Service A
70 | it 相較於 dev 又新增了 redis-master-deployment.yaml, 也就是 Deployment B
71 | qa 相較於 it 又新增了 redis-master-service.yaml, 也就是 service B
72 |
73 | 這些檔案都準備完畢後,接下來要做的就是準備一個 fleet.yaml 的檔案,讓 Fleet 要針對不同叢集讀取不同環境。
74 |
75 | 前述提到 Fleet.yaml 中會透過 label 的方式來選擇目標叢集,沒有特別設定的情況下,每個叢集會有一些預設的 label 可以使用。切換到該叢集並且以 YAML 方式瀏覽就可以觀察到這些預設 label.
76 |
77 | 
78 |
79 | 上圖中呈現了三種 label,其中第一種是比較適合人類閱讀的,該 label 呈現了叢集的名稱,key 為 management.cattle.io/cluster-display-name
80 | 所以接下來 fleet.yaml 中就可以透過這個 label 來比對不同的 cluster。
81 |
82 | ```
83 | namespace: basicoverlay
84 | targetCustomizations:
85 | - name: dev
86 | clusterSelector:
87 | matchLabels:
88 | management.cattle.io/cluster-display-name: ithome-dev
89 | yaml:
90 | overlays:
91 | - dev
92 |
93 | - name: it
94 | clusterSelector:
95 | matchLabels:
96 | management.cattle.io/cluster-display-name: rke-it
97 | yaml:
98 | overlays:
99 | - it
100 |
101 | - name: qa
102 | clusterSelector:
103 | matchLabels:
104 | management.cattle.io/cluster-display-name: rke-qa
105 | yaml:
106 | overlays:
107 | - qa
108 | ```
109 |
110 | 上述是一個 Fleet.yaml 的範例,該 Fleet.yaml 希望將所有資源都安裝到 basicoverlay 這個 namespace 中。
111 |
112 | 接者於 targetCustomizations 的物件中,針對三個不同環境撰寫不同的 clusterSelector。
113 | 範例中使用 cluster-name 來比對,符合 ithome-dev 使用 overlays 這個語法來讀取特定的環境,將 overlays/dev 中的資料夾一併納入部署。
114 | 剩下兩個環境如法炮製,一切都準備完畢之後,最後修改 repo/prod/app-basic.yaml 以及 repo/testing/app/app-basic.yaml 讓其知道要掃描 app/basic_overlay 這個路徑。
115 |
116 | ```bash=
117 | ╰─$ cat repos/prod/app-basic.yaml
118 | kind: GitRepo
119 | apiVersion: fleet.cattle.io/v1alpha1
120 | metadata:
121 | name: prod-app
122 | namespace: prod
123 | spec:
124 | repo: https://github.com/hwchiu/fleet_demo.git
125 | branch: master
126 | paths:
127 | - app/basic
128 | - app/basic_overlay
129 | targets:
130 | - clusterSelector: {}
131 | ╰─$ cat repos/prod/app-basic.yaml
132 | kind: GitRepo
133 | apiVersion: fleet.cattle.io/v1alpha1
134 | metadata:
135 | name: prod-app
136 | namespace: prod
137 | spec:
138 | repo: https://github.com/hwchiu/fleet_demo.git
139 | branch: master
140 | paths:
141 | - app/basic
142 | - app/basic_overlay
143 | targets:
144 | - clusterSelector: {}
145 | ```
146 |
147 |
148 | 一切準備完畢後就將修改給推到遠方的 Git 專案,然後靜靜等者 Fleet 開始處理。
149 | 當 Testing workspace 底下的 GitRepo 呈現 Active 後就代表環境已經部署完畢了。
150 |
151 | 
152 |
153 | 這時候點選進去可以看到更為詳細的內容,因為 Fleet 還是一個非常嶄新的專案,我認為其還有很多值得改近的地方,譬如當前的 UI 就會將 Fleet.yaml 中描述的所有資源都一起放進來,而不是針對叢集客製化的資源去顯示,這一點會容易混淆人。希望下一個版本 (v0.3.6) 有機會修復。
154 |
155 | 
156 |
157 | 一切完畢後透過 kubectl 去觀察三個叢集下 basicoverlay 內的資源變化
158 |
159 | dev 的叢集可以看到只有 deployment A 配上 service A 的資源
160 |
161 | 
162 |
163 | it 叢集除了 dev 叢集的資源外,還多了 deployment B 也就是 redis-master 的 Pod.
164 |
165 | 
166 |
167 | qa 叢集則最完整,擁有 Deployment(A,B) 以及 Service (A,B)
168 |
169 | 
170 |
171 | 下篇文章將針對 Kustomize 的範例介紹
--------------------------------------------------------------------------------
/2021/day28.md:
--------------------------------------------------------------------------------
1 | Day 28 - Rancher Fleet Helm 應用程式部署
2 | ======================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 | 前篇文章探討了基於 Kustomize 的客製化行為,另外一個常見的應用程式處理方式就是 Helm, Helm 採用的是基於 template 的方式來動態渲染出一個可用的 YAML。
14 | 本篇文章就會探討兩種不同使用 Helm 的方式。
15 |
16 | 本篇所有 YAML 範例都來自於[官方範例](https://github.com/rancher/fleet-examples)。
17 |
18 | # 本地 Helm Chart
19 | Helm Chart 基於 go-template 的方式來客製化 Yaml 內的數值,這意味者 Helm Chart 本身所擁有的 YAML 其實大部分情況下都不是一個合法 YAML,都需要讓 Helm 動態的將相關數值給填入到 Helm YAML 中來產生最後的檔案內容。
20 |
21 | 下方是一個 Helm YAML 的範例
22 |
23 | ```yaml=
24 | apiVersion: apps/v1
25 | kind: Deployment
26 | metadata:
27 | name: frontend
28 | spec:
29 | selector:
30 | matchLabels:
31 | app: guestbook
32 | tier: frontend
33 | replicas: {{ .Values.replicas }}
34 | template:
35 | metadata:
36 | labels:
37 | app: guestbook
38 | tier: frontend
39 | spec:
40 | containers:
41 | - name: php-redis
42 | image: gcr.io/google-samples/gb-frontend:v4
43 | resources:
44 | requests:
45 | cpu: 100m
46 | memory: 100Mi
47 | ports:
48 | - containerPort: 80
49 |
50 | ```
51 |
52 | 可以看到 replicas 的部分抽出來,變成一個 template 的格式,搭配下方的 values.yaml
53 | ```yaml=
54 | replicas: 1
55 | ```
56 | Helm 就會動態的將 replicas 的數值給填入到上方的 template 來產生最終要送到 Kubernetes 內的 YAML 物件。
57 |
58 | 有了基本概念之後,就可以來看看如何透過 Fleet 來管理 Helm 的應用程式。
59 |
60 | 這次的應用程式會直接使用 Helm 內建的範例應用程式,透過 helm create $name 就可以創建出來
61 | 所以移動到 app 資料夾底下,輸入 helm create helm 即可
62 | ```bash=
63 | ╰─$ helm create helm
64 | Creating helm
65 | ╰─$ tree helm
66 | helm
67 | ├── Chart.yaml
68 | ├── charts
69 | ├── templates
70 | │ ├── NOTES.txt
71 | │ ├── _helpers.tpl
72 | │ ├── deployment.yaml
73 | │ ├── hpa.yaml
74 | │ ├── ingress.yaml
75 | │ ├── service.yaml
76 | │ ├── serviceaccount.yaml
77 | │ └── tests
78 | │ └── test-connection.yaml
79 | └── values.yaml
80 | ```
81 |
82 | 該 Helm 的範例應用程式會部署一個 nginx 的應用程式,並且為其配上一個 service + ingress 的服務。
83 |
84 | 這次希望透過 Fleet 為兩個不同的 workspace 去部署不同的環境,意味者 testing workspace 底下的兩個叢集(dev/qa) 採用一組設定,而 prod workspace 底下的 it 叢集採用另外一組設定。
85 |
86 | 修改的部分採取簡單好理解即可
87 | 針對 testing 的環境
88 | 1. replica 設定為 2 份,
89 |
90 | prod 的環境
91 | 1. replica 為 3
92 | 2. 開啟 Ingress 物件
93 |
94 | 為了完成這件事情針對 workspace 下多個 cluster 統一設定,必須要先完成下列之一
95 | 1. 將群組給 group 起來
96 | 2. 給叢集有對應的 Label
97 |
98 | 因此先到 UI 部分將 Prod Workspace 底下的 cluster (rke-it) 給予一個 env=prod 的 Label.
99 |
100 | 
101 |
102 | 接者到 testing workspace 底下創建一組 Cluster Group,創建 Cluster Group 的時候可以根據條件去抓到符合條件的 Cluster,預設情況下沒有設定的話就是全抓。
103 | 系統還會告訴你目前有多少個 Cluster 符合當前的 Selector,以我們的環境來說該 workspace 底下有兩個不同的 cluster。
104 |
105 | 
106 |
107 | 一切準備就緒後就來準備 Fleet.yaml
108 |
109 | ```bash=
110 | ╰─$ cat fleet.yaml
111 | namespace: helminternal
112 | targetCustomizations:
113 | - name: prod
114 | helm:
115 | values:
116 | replicaCount: 3
117 | ingress:
118 | enabled: true
119 | hosts:
120 | - host: rancher.hwchiu.com
121 | paths:
122 | - /testing
123 | clusterSelector:
124 | matchLabels:
125 | env: prod
126 |
127 | - name: test
128 | helm:
129 | values:
130 | replicaCount: 2
131 | clusterGroup: testing-group
132 | ```
133 |
134 | 因為 Fleet 會自己偵測若路徑中有 Chart.yaml 檔案的話,就會使用 Helm 的方式去處理,所以不需要特別於 Fleet.yaml 中去描述需要使用 Helm。
135 | 這次的範例會安裝到 helminternal 這個 namespace 中,接者底下針對兩種不同的客製化。
136 | 如果 cluster 本身含有 env:prod 這種標籤的話,就會將其的複本數量設定為 3 個,並且將 ingress 給設定為 enable,為了讓 Ingress 物件可以順利創立,需要針對 hosts 底下的物件也給予設定,這邊隨便寫就好,目的只是測試 ingress 物件的部署。
137 |
138 | 另外一個則是直接使用 testing-group 這個 cluster group,對其底下的所有 cluster 都設定副本數為 2 。
139 |
140 | 記得也要對 repo/*/app-basic.yaml 兩個檔案去增加 app/helm 的路徑,這樣 GitRepo 才知道也要去掃描 app/helm 的路徑。
141 |
142 | 一切都部署完畢後,使用 kubectl 去觀察部署的資源,可以觀察到 rke-it 這個屬於 prod workspace 的叢集被部署了三個副本的 deployment 外加一個 ingress 資源。
143 |
144 | 
145 |
146 | 至於 testing workspace 下的兩個叢集的部署資源都一致,都只有兩個副本的 deployment,沒有任何 ingress 物件。
147 |
148 | 
149 | 
150 |
151 | # 遠方 Helm Chart
152 | 實務上並不是所有部署到團隊中的 Helm Chart 都是由團隊自行維護的,更多情況下可能是使用外部別人包裝好的 Helm Chart,譬如 Prometheus-operator 等。
153 |
154 | 這種情況下專案的路徑內就是透過 fleet.yaml 來描述要使用哪個遠方的 Helm Chart 以及要如何客製化。
155 |
156 | 這邊直接使用[官方 Helm-External的範例](https://github.com/rancher/fleet-examples/blob/master/multi-cluster/helm-external/fleet.yaml) 來操作。
157 |
158 | 首先先於 app 資料夾底下創建一個 helm-external 的資料夾,因為這次不需要準備 Helm Chart 的內容,所以直接準備一個 fleet.yaml 的檔案即可。
159 |
160 | fleet.yaml 內容如下
161 | ```bash=
162 | ╰─$ cat fleet.yaml
163 | namespace: helmexternal
164 | helm:
165 | chart: https://github.com/rancher/fleet-examples/releases/download/example/guestbook-0.0.0.tgz
166 | targetCustomizations:
167 | - name: prod
168 | helm:
169 | valuesFiles:
170 | - prod_values.yaml
171 | clusterSelector:
172 | matchLabels:
173 | env: prod
174 |
175 | - name: test
176 | helm:
177 | valuesFiles:
178 | - testing_values.yaml
179 | clusterGroup: testing-group
180 | ```
181 |
182 | 如果要使用遠方的 Helm Chart,總共有兩種不同的寫法,一種是參考上述直接於 chart 中描述完整的下載路徑。
183 | 針對一般的 Helm Chart Server 來說會更常使用下列這種形式
184 | ```yaml
185 | helm:
186 | repo: https://charts.rancher.io
187 | chart: rancher-monitoring
188 | version: 9.4.202
189 | ```
190 |
191 | 這種形式更加容易理解要去哪個 Helm Chart 抓取哪個版本的 Helm Chart 應用程式。
192 |
193 | 接者這次的 fleet.yaml 要採用不同的方式去進行客製化,當 Helm Values 的客製化非常多的時候,有可能會使得 fleet.yaml 變得冗長與複雜,這時候可以透過 valuesFiles 的方式,將不同環境用到的 values 內容給獨立撰寫成檔案,然後於 fleet.yaml 中將該檔案給讀取即可。
194 |
195 | ```bash=
196 | ╰─$ cat prod_values.yaml
197 | serviceType: NodePort
198 | replicas: 3
199 | ╰─$ cat testing_values.yaml
200 | serviceType: ClusterIP
201 | replicas: 2
202 | ```
203 |
204 | 上述兩個設定檔案就是針對不同副本去處理,同時 prod 環境下會將 service 給轉換為 NodePort 類型。
205 | 一切完畢後記得修改 repo/*/app-basic.yaml 內的路徑。
206 | 注意的是這邊的 replica/serviceType 只會影響 Helm 裏面的 frontend deployment/service,純粹是對方 helm chart 的設計。
207 |
208 | 部署完畢後透過 kubectl 觀察部署的狀況
209 |
210 | 可以觀察到 prod workspace 底下的 rke-it 叢集內的確將 frontend 的 replica 設定成 3個,同時 frontend 的 service 也變成 NodePort
211 |
212 | 
213 |
214 | 而剩下兩個叢集也符合預期的是一個兩副本的 deployment 與 ClusterIP
215 |
216 | 
217 | 
218 |
219 | 下篇文章將來探討 fleet 最有趣的玩法,Helm + Kustomize 兩者結合一起運行。
--------------------------------------------------------------------------------
/2021/day29.md:
--------------------------------------------------------------------------------
1 | Day 29 - Rancher Fleet Helm + Kustomize 應用程式部署
2 | =================================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 | 前篇文章探討了基於 Helm 的客製化行為,透過兩種不同方式來部署 Helm 的應用程式,透過 Helm Values 的設定可以讓管理人員更容易的去設定與處理不同的設定。
14 |
15 | 實務上如果採用的是遠方 Helm Chart Server 的部署方式,還是有機會遇到綁手綁腳的問題,譬如想要針對某些欄位客製化,但是該 Helm Chart 卻沒有定義等
16 | 這時候就可以補上 Kustomize 來進行二次處理,應用程式先透過 Helm 進行第一層處理,接者透過 Kustomize 進行二次處理,幫忙 Patch 一些不能透過 values.yaml 控制的欄位。
17 |
18 | 本篇所有 YAML 範例都來自於[官方範例](https://github.com/rancher/fleet-examples)。
19 |
20 | # Helm + Kustomize
21 |
22 | 使用遠方 Helm Chart 來部署應用程式的人可能都會有下列的經驗
23 | 1. Helm Values 沒有提供自己想要的欄位
24 | 2. 如果該 Helm Chart 裡面需要 secret 的物件,需要自己額外部署,沒有辦法跟該 Helm Chart 融為一體。
25 |
26 | 不同問題會有不同解決方法,譬如
27 | 1. 嘗試針對該 Helm Charts 提交 PR 去增加更多的 values 欄位可以使用。這種情況的解法比較漂亮,但是要花比較長的時間來處理程式碼的合併與審核。
28 | 2. 複製遠方的 Helm Chart 到本地環境中,手動修改欄位符合自己需求,沒有將修改推回遠方的 upstream.
29 | 3. 團隊內創造一個全新的 Helm Chart,該 Helm Chart 透過 requirement 的概念來使用本來要用的 Helm Chart,接者於自己的環境中補上其他資源。
30 |
31 | 如果 Helm Values 沒有提供自己想要的欄位,那(1)/(2) 這兩種解法都可以處理,畢竟都有能力針對本來的 Helm YAML 進行改寫。
32 | 但是如果今天的需求是想要加入一些全新的 YAML 檔案,譬如上述的 Secret 物件,那(1)/(2)/(3) 三種方法都可以採用。
33 |
34 | 第一個方法需要花時間將修改合併到 upstream 的專案,而第二個方法其實維護起來很麻煩,因為每次遠方有任何版本更新時都要重新檢查。第三個方法又不能針對 values 的方式去客製化。
35 |
36 | Fleet 中提供了一個有效的方式來解決這個困境,就是 Helm + Kustomize 的組合技
37 | 透過 Helm 進行第一次的渲染,接者透過 Kustomize 的方式可以達到
38 | 1. 動態增加不同的 Kubernetes 物件
39 | 2. 透過 Kustomize 的 Patch 方式可以動態修改欄位
40 |
41 | 因此上述的情境問題就可以完美解決。
42 |
43 | 註: Kustomize 今年的新版本也嘗試提供 Helm 的支援,讓你可以透過 Kustomize 的方式去部署 Helm 的應用程式,詳細可以參考 [kustomization of a helm chart
44 | ](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/chart.md)
45 |
46 | 本次的範例繼續使用前篇文章的 Helm Chart,使用 Rancher 提供的 guestbook 作為遠方的 Helm Chart 檔案,接者透過 Kustomize 的方式來動態修改欄位與增加資源。
47 |
48 | 這次的環境部署要求如下。
49 | 預設情況下先透過 Helm Values 將 frontend 的副本數調高為 3
50 |
51 | dev 叢集:
52 | 1. 將 serviceType 改成 LoadBalancer
53 |
54 | it 叢集:
55 | 1. 將 redis-slave 的副本數改成 0 (預設是2)
56 |
57 | qa 叢集:
58 | 1. 新增一個基於 nginx 的 deployment
59 |
60 | 有了這些概念後,就來準備相關的檔案,這次於 app 底下創建名為 helm_kustomize 的資料夾,並且於裡面先準備一個 fleet.yaml 的檔案。
61 |
62 | ```yaml=
63 | ╰─$ cat fleet.yaml
64 | namespace: helmkustomize
65 | helm:
66 | chart: https://github.com/rancher/fleet-examples/releases/download/example/guestbook-0.0.0.tgz
67 | values:
68 | replicas: 3
69 | targetCustomizations:
70 | - name: dev
71 | clusterSelector:
72 | matchLabels:
73 | management.cattle.io/cluster-display-name: ithome-dev
74 | kustomize:
75 | dir: overlays/dev
76 |
77 | - name: it
78 | clusterSelector:
79 | matchLabels:
80 | management.cattle.io/cluster-display-name: rke-it
81 | kustomize:
82 | dir: overlays/it
83 |
84 | - name: qa
85 | clusterSelector:
86 | matchLabels:
87 | management.cattle.io/cluster-display-name: rke-qa
88 | kustomize:
89 | dir: overlays/qa
90 | ```
91 |
92 | 上述的 fleet.yaml 中首先透過 helm chart 去抓取遠方的 helm chart server,接者透過 values 的方式將 frontend 的副本數設定為三個。
93 |
94 | 接下來是叢集客製化的部分,每個叢集這次採用叢集名稱作為比對的方式,接者使用 kustomize 的方式去 overlays 底下的資料夾來客製化。
95 |
96 | ```bash
97 | ╰─$ tree .
98 | .
99 | ├── dev
100 | │ ├── frontend-service.yaml
101 | │ └── kustomization.yaml
102 | ├── it
103 | │ ├── kustomization.yaml
104 | │ └── redis-slave-deployment.yaml
105 | └── qa
106 | ├── deployment.taml
107 | └── kustomization.yaml
108 |
109 | ```
110 |
111 | ```bash=
112 | ╰─$ cat dev/frontend-service.yaml
113 | kind: Service
114 | apiVersion: v1
115 | metadata:
116 | name: frontend
117 | spec:
118 | type: LoadBalancer
119 | ╰─$ cat dev/kustomization.yaml
120 | patches:
121 | - frontend-service.yaml
122 |
123 |
124 | ╰─$ cat it/kustomization.yaml
125 | patches:
126 | - redis-slave-deployment.yaml
127 | ╰─$ cat it/redis-slave-deployment.yaml
128 | kind: Deployment
129 | apiVersion: apps/v1
130 | metadata:
131 | name: redis-slave
132 | spec:
133 | replicas: 0
134 |
135 |
136 | ╰─$ cat qa/deployment.yaml
137 | apiVersion: apps/v1
138 | kind: Deployment
139 | metadata:
140 | name: test
141 | labels:
142 | app: nginx
143 | spec:
144 | replicas: 3
145 | selector:
146 | matchLabels:
147 | app: nginx
148 | template:
149 | metadata:
150 | labels:
151 | app: nginx
152 | spec:
153 | containers:
154 | - name: nginx-server
155 | image: nginx
156 |
157 | ╰─$ cat qa/kustomization.yaml
158 | resources::
159 | - deployment.yaml
160 | ```
161 |
162 | 準備好這些檔案並且修改 repo/*/app-basic.yaml 後,就可以將修改給推到遠方的 Git 專案,接者等待 Fleet 來幫忙處理部署。
163 |
164 | 使用 kubectl 工具觀察
165 |
166 | Dev 的環境可以觀察到
167 | 1. Frontend 的 replica 是三個副本
168 | 2. Service 的類型改成 LoadBalancer
169 |
170 | 
171 |
172 | IT 的環境可以觀察到
173 | 1. Frontend 的 replica 是三個副本
174 | 2. redis-slave 的 replica 變成 0
175 |
176 | 
177 |
178 |
179 | QA 的環境可以觀察到
180 | 1. Frontend 的 replica 是三個副本
181 | 2. 新的一個 Deployment 叫做 test,有三個副本。
182 |
183 | 
184 |
185 | 可以發現環境中的部署條件都有如先前所述,算是成功的透過 Helm + Kustomize 的方式來調整應用程式。
186 |
187 |
188 | Fleet 本身發展的時間不算久,因此 UI 上有時候會有一些額外的 Bug,這些除了看官方文件外剩下都要看 Github 上的 issue 來找問題。
189 |
190 | 此外 Fleet 於 08/28/2021 正式推出 v0.3.6 版本,不過因為如果想要單純使用 Rancher 來使用的話,那這樣就必須要等待新版本的 Rancher 一起推出才可以直接享用新版本的整合。
--------------------------------------------------------------------------------
/2021/day3.md:
--------------------------------------------------------------------------------
1 | Day 3 - Rancher 架構與安裝方式介紹
2 | ===============================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 | 前篇文章探討了 Rancher 的基本概念與 Rancher 帶來的好處,本章節則要探討 Rancher 的架構
14 | 對其架構瞭解愈深,未來使用時要除錯就會更知道要從什麼角度去偵錯同時部署時也比較會有些基本概念為什麼官方會有不同的部署方式。
15 |
16 | 由於 Rancher 本身是一個管理 Kubernetes 的平台,同時又要提供 UI 介面給使用者管理,因此其本身就是由多個內部元件組成的,如下圖(該圖節錄自[官方網站](https://rancher.com/docs/rancher/v2.5/en/overview/architecture/#rancher-server-architecture))
17 |
18 | 註: 此為 v2.5 的架構
19 |
20 | 
21 |
22 | 從官方的架構圖中可以觀察到, Rancher 本身除了 API Server 作為整體邏輯處理之外,還有額外的元件譬如
23 | 1. Cluster Controller
24 | 2. Authentication Proxy
25 | 3. etcd
26 |
27 | 其中 Cluster Controller 可以用來控制不同類型的 Kubernetes Cluster,不論是透過 Rancher 所架設的 RKE 或是其他如 EKS/AKS 等。
28 | 這邊要特別注意的,任何要給 Rancher 給控管的 Kubernetes Cluster 都會必須要於其叢集中安裝一個 Cluster Agent。 Rancher 要透過 Agent 的幫忙才可以達到統一控管的效用。
29 |
30 | API Server 方面本身面對的 Client 很多,有使用 UI 瀏覽的,有使用 CLI 操作,甚至連 Kubernetes API 也都是由 API 處理的。
31 | 這邊解釋一下為什麼 Kubernetes API 需要走 Rancher API Server,試想一個純地端的網路環境,如果使用者想要透過 kubectl/helm 等指令去存取該 Kubernetes,這意味者該地端環境需要將 API Server 的 6443 port 給放出來,同時還要準備好相關憑證等。如果該 Kubernetes Cluster 是由 Rancher 所創立的,那 Rancher 可以透過與 Agent 的溝通過程來交換這些 Kubernetes API 的操作,這意味者使用者只要對 Rancher API Server 發送 Kubernetes API 等相關的指令,這些最後都會被 Rancher API Server 給轉發到底下 Kubernetes Cluster 的 API Server。這樣地端環境也不需要開啟 6443 port,只要本身叢集內的 Agent 有跟 Rancher API Server 有保持連線即可。使用上大幅度簡化整個操作流程。
32 | 最後提醒的是此功能並非一定要使用,針對 RKE 叢集也是有辦法不經由 Rancher 而直接存取 Kubernetes 。
33 |
34 | 上述的架構圖也清楚的告訴使用者,要架設一個 Rancher 服務要準備上述這些元件,而官方網站本身則提供的數種不同的安裝方式,而這些方式又會分成兩大類,單一節點或是多節點。
35 | 單一節點的安裝方式適合測試使用,而生產環境下會建議採用多節點的方式去部署 Rancher Server,畢竟 Rancher 本身是管理多套 Kubernetes 叢集的服務,因此本身最好要有 HA 的機制去確保不會因為單一節點損毀而導致後面一連串的錯誤。
36 |
37 | 下圖節錄自[官方網站](https://rancher.com/docs/rancher/v2.5/en/overview/architecture-recommendations/)
38 |
39 | 
40 |
41 | 該架構圖呈現了兩種不同模式下的架構,最大的差別就只是 Rancher Server 本身到底如何被外界存取以及 Rancher Server 有無 HA 等特性。
42 |
43 | 單一節點的安裝非常簡單,只要使用 docker 指令就可以很輕鬆的起一個 Rancher Server,不過要特別注意的是透過這種方法部署的 Rancher 不建議當作生產環境,最好只是拿來測試即可。
44 | 其原理其實是透過一個 docker container 起 Rancher 服務,服務內會用 RKE 創建一個單一節點的 Kubernetes 節點,該節點內會把 Rancher 的服務都部署到該 Kubernetes 內。
45 |
46 | 多節點安裝的安裝概念很簡單,就是把 Rancher 的服務安裝到一個 Kubernetes 叢集內即可, Rancher 本身提供 Helm 的安裝方式,所以熟悉 Helm 指令就可以輕鬆的安裝一套 Rancher 到 Kubernetes 叢集內。
47 | 官方文件提供了不同種 Kubernetes 叢集的安裝方式,包含
48 | 1. RKE (使用 RKE 指令先行創建一個 K8S 叢集,再用 Helm 把 Rancher 安裝進去)
49 | 2. EKS
50 | 3. GKE
51 | 4. K3s (輕量級 RKE,針對 IoT 等環境設計的 Kubernetes 版本)
52 | 5. RKE2 (針對美國安全相關部門所開發更為安全性的 RKE 版本)
53 |
54 | 除了上述所描述的一些安裝方式外, Rancher 也跟 AWS 有相關整合,能夠透過 CloudFormation 的方式透過 EKS 部署 Rancher 服務,詳細的可以參閱[Rancher on the AWS Cloud
55 | Quick Start Reference Deployment](https://aws-quickstart.github.io/quickstart-eks-rancher/)
56 |
57 | 最後為了讓整體的安裝更加簡化,Rancher 於 v2.5.4 後釋出了一個實驗的新安裝方式,稱為 RancherD
58 | 該服務會先創建一個 RKE2 的叢集,並且使用 Helm 將相關服務都安裝到該 RKE2 叢集中。
59 |
60 | 最後要注意的是,不論是哪種安裝方式,都需要針對 SSL 憑證去進行處理,這部分可以用 Rancher 自行簽署,自行準備或是透過 Let's Encrypt 來取得都可以,所以安裝時也需要對 SSL 有點概念會比較好,能的話最好有一個屬於自已的域名來方便測試。
61 | 單一節點的 Docker Container 部署方式有可能會遇到 RKE 內部 k8s 服務憑證過期的問題,如果遇到可以參閱下列解決方式處理 [Rancher container restarting every 12 seconds, expired certificates](https://github.com/rancher/rancher/issues/26984#issuecomment-712233261)
62 |
63 | 下一篇文章便會嘗試透過 RKE + Helm 的方式來看看如何架設 Rancher
--------------------------------------------------------------------------------
/2021/day30.md:
--------------------------------------------------------------------------------
1 | Day 30 - Summary
2 | ================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | Rancher x Fleet 系列文到此告一個段落,這系列文中探討四大概念,包含
13 | 1. Rancher 基本知識
14 | 2. Rancher 管理指南
15 | 3. Rancher 應用程式部署
16 | 4. GitOps 部署
17 |
18 | # Rancher 基本知識
19 | Kubernetes 作為一個容器管理平台,這幾年的聲勢不減反升,愈來愈多的團隊想要嘗試導入 Kubernetes 來替換應用程式部署的底層架構。Kubernetes 不是萬靈丹,並不是所有的情境與環境都適合使用 Kubernetes,但是一旦經過評估確認想要使用 Kubernetes 後就會面臨到下一個重大問題,就是該 Kubernetes 叢集要怎麼安裝與管理?
20 |
21 | 從 On-Premise 到雲端環境,從手工架設到使用付費 Kubernetes 服務都是選項之一,這種情況下團隊需要花更多心力與時間去思考到底要走哪一個方式,畢竟每個方式都有不同的優缺點。
22 |
23 | Rancher Labs 是一個針對 Kubernetes 生態系開發許多工具的強大團隊,譬如
24 | 1. Rancher Kubernetes Engine (RKE): 客製化的 Kubernetes 環境
25 | 2. K3s: 輕量級的 Kubernetes 叢集,適合物聯網環境
26 | 3. Fleet: 針對 Kubernetes 的 GitOps 解決方案
27 | 4. Longhorn: 持久性儲存的解決方案
28 |
29 | 除了可以將現存的 Kubernetes 叢集讓 Rancher 託管,更多的使用方式是讓 Rancher 直接創造基於 RKE 版本的 Kubernetes 叢集,因為 RKE 叢集才可以真正發揮 Rancher 內的所有功能。
30 |
31 | 官方文章有專門的文章 [Best Practices Guide](https://rancher.com/docs/rancher/v2.5/en/best-practices/) 探討如何針對生產環境部署一個最適當的 Rancher,接者如何透過這套 Rancher 來託管與創建不同的 Kubernetes 叢集。
32 |
33 | 透過 docker 可以很輕鬆的部署一個 Rancher,該環境非常適合測試與評估使用,但是如果要將 Rancher 給導入到正式環境的話,就會希望能夠透過一套 RKE 叢集來維護 Rancher 服務。
34 |
35 | # Rancher 管理
36 |
37 | Rancher 本身是個 Kubernetes 管理平台,因此其系統架構的設計有非常多層級的概念
38 | 1. 管理 Rancher 服務本身的功能
39 | 2. 管理 Kubernetes 叢集本身的功能
40 | 3. 管理 Kubernetes Project 的功能
41 |
42 | 有了這些基本概念後去閱讀官方文件就會更加理解到底官方文件的編排與含義。
43 | 此外,Rancher 基於 RBAC 的方式針對不同的使用者可以設定不同的權限。
44 | 使用者的認證除了預設的內建資料庫外,也支援不同的外部服務,如 Azure/GSuite/Keycloak 等不同機制
45 | 因此使用 Rancher 時也要特別注意 RBAC 的設定,避免所有 Rancher 的使用者都共享一套 admin 的帳號來操作。
46 |
47 | # IaC
48 | Rancher 本身除了透過 UI 大量操作外,也可以透過 Terraform/Pulumi 這些 IaC 工具來設定,因此一個比較好的模式是推薦使用這類型的工具來操作與管理 Rancher 本身,同時將這些操作與系統中的 CI/CD pipeline 給結合,這樣所有的變更可會更加透明且也能夠透過 CI/CD 的入口當作 Single Source of Truth 的概念
49 |
50 | # 應用程式部署
51 |
52 | 透過 Rancher 準備好一套可用的 Kubernetes(RKE) 叢集後,接下來可以透過很多種方式去管理叢集上的應用程式。
53 | 譬如直接取得 Kubernetes 的 KUBECONFIG,擁有該檔案的任何人都可以直接使用 helm/kubectl 等指令進行操作來安裝各種 Kubernetes 的資源到目標叢集內。
54 |
55 | 如果想要妥善利用 Rancher 的設計的話,就可以考慮使用 Rancher 內的機制 (Catalog/App) 來安裝應用程式,透過 Rancher 的機制來安裝應用程式會於 UI 方面有更好的呈現與整合,同時使用上可以避免 Kubeconfig 的匯出,可以統一都使用 Rancher API Token 進行存取即可。
56 |
57 | 如果對於這種手動部署感到厭煩的,也可以嘗試看看 Rancher v2.5 正式推出的 GitOps 解決方案, Rancher Fleet。
58 | 透過 Rancher Fleet 的幫助,管理者可以講所有要部署的資源都存放到一個 Git 專案,同時 Fleet 支援數種不同的應用程式客製化。
59 | 除了常見的 Helm 及 Kustomize 外, Fleet 還支援將 Helm 與 Kustomize 一起使用,針對使用外部 Helm Chart 的情境特別好用。
60 |
61 | 不過 Rancher Fleet 目前還在茁壯發展中,因此使用上難免會遇到一些 Bug,這部分都非常歡迎直接到官方 Github 去回報問題,透過社群的幫忙官方才更有機會將這些問題給修復。
62 |
--------------------------------------------------------------------------------
/2021/day6.md:
--------------------------------------------------------------------------------
1 | Day 6 - Rancher 系統管理指南 - 使用者登入管理
2 | ========================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 |
13 | # 前言
14 | 前篇文章透過 rke / helm 成功的搭建了一個 Rancher 服務,並且於第一次登入時按照系統要求創建了一組給 admin 使用的密碼,並且使用該 admin 的帳號觀察到了第一組創建被 Rancher 管理的 Kubernetes 叢集。
15 |
16 | 複習: 該 K8s 叢集並不是 Rancher 創造的,而是我們事先透過 rke 創造用來部署 Rancher 服務的 k8s 叢集。
17 |
18 | 對於 IT 管理人員來說,看到一個新的服務通常腦中會閃過的就是該服務的使用者管理權限該怎麼處理? 最直觀也簡單的方式就是透過該服務創建眾多的本地使用者,每個使用者給予不同的權限與帳號密碼。但是這種使用方式實務上會有太多問題
19 | 1. 團隊內員工通常不喜歡每一個服務都有獨立的密碼,最好能夠用一套密碼去存取公司內所有服務
20 | 2. 員工數量過多時,通常團隊也很懶得幫每個員工都獨立創造一份帳號密碼,更常發生的事情是一套帳號密碼多人共同使用。
21 | 3. 多人共同使用的問題就是會喪失了稽核性,沒有辦法知道是誰於什麼時間點進行什麼操作,未來要除錯與找問題時非常困難
22 | 4. 如果權限還想要用群組來管理時,整個要處理的事情就變得又多又複雜
23 | 5. 由於帳號密碼都是服務本地管理,這意味團隊內的帳號密碼是分散式的架構,因此有人想要改密碼就需要到所有系統去改密碼,這部分也是非常不人性化,特別如果員工離職時,要是有服務忘了刪除可能會造成離職員工還有能力去存取公司服務。
24 |
25 | 因此大部分的 IT 都不喜歡使用本地帳號,更喜歡使用混合模式來達到靈活的權限管理。
26 | 1. 服務想辦法整合外部的帳號密碼系統,常見的如 Windows AD, LDAP, GSuite, SMAL, OpenID, Crowd 等。
27 | 2. 每個服務都維持一個本地使用者,該使用者是管理員的身份,作為一個緊急備案,當外部帳號密碼系統出問題導致不能使用時,就必須要用本地使用者來存取。
28 |
29 | 混合模式的架構下,所有員工的帳號與密碼都採用集中式管理,任何第三方服務都要與該帳號系統整合,因此
30 | 1. 員工只需要維護一套帳號密碼即可登入團隊內所有服務,如果員工需要改密碼,也只需要改一個地方即可
31 | 2. IT 人員可以統一管理群組,每個第三方服務針對群組去進行權限控管即可。
32 | 3. 這種架構下不會有共享帳號密碼的問題,每個使用者登入任何系統都會有相關的日誌,未來除錯也方便
33 |
34 | 因此本篇文章就來探討 Rancher 提供何種使用者登入與權限控管,系統管理員架設維護時可以如何友善的去設定 Rancher
35 |
36 | # Authorization 授權
37 |
38 | Rancher 的世界中將權限分成三大塊,由大到小分別是
39 | 1. Global Permission
40 | 2. Cluster Role
41 | 3. Project Role
42 |
43 | 其中 Cluster/Project 這個概念要到後面章節探討如何用 Rancher 去架設與管理 Kubernetes 叢集時才會提到,因此這邊先專注於第一項,也就是 Global Permission。
44 |
45 | Global Permission 代表的是 Rancher 服務本身的權限,本身跟任何 Kubernetes 叢集則是沒有關係。
46 | Rancher 本身採用 RBAC (Role-Based Access Control) 的概念來控制使用者的權限,每個使用者會依據其使用者名稱或是所屬的群組被對應到不同Role。
47 |
48 | Global Permission 預設提供多種身份,每個身份都有不同的權限,以下圖來看(Security->Roles)
49 | 
50 |
51 | 圖中是預設的不同 Role,每個 Role 都有各自的權限,同時還可以去設定說當一個新的外部使用者登入時,應該要賦予何種 Role
52 | 權限部分是採取疊加狀態的,因此設計 Role 的時候都是以 "該 Role 可以針對什麼 API 執行什麼指令",沒有描述到的就預設當作不允許。
53 | 因此 Role 是可以互相疊加來達到更為彈性的狀態,當然預設 Role 也可以有多個。
54 |
55 | 註: 本圖片並不是最原始的 Rancher 設定,預設狀態有被我修改過,請以自己的環境為主。
56 |
57 |
58 | Role 這麼多種對於初次接觸 Kubernetes 與 Rancher 的管理員來說實在太複雜與太困難,因此 Rancher 又針對這些 Role 提供了四種好記的名稱,任何使用者與群組都可以基於這四種 Role 為基礎去添加不同的 Role 來達到靈活權限。
59 |
60 | 這四種好記的 Role 分別為
61 |
62 | 1. Administration
63 | 超級管理員,基本上什麼都可以操作,第一次登入時所使用的 admin 帳號就屬於這個權限
64 |
65 | 2. Restricted Admin
66 | 能力近乎於超級管理員,唯一不能管理的就是 Rancher 本身所在的 kubernetes 叢集,也就是前篇文章看到的 local 叢集。
67 |
68 | 3. Standard User: 可以透過 Rancher 創建 Kubernetes 叢集 並且使用的使用者,大部分情況下可以讓非管理員角色獲得這個權限,不過因為創建過多的 Kubernetes 叢集有可能會造成成本提高,所以賦予權限時也要注意到底什麼樣的人可以擁有創造 kubernetes 叢集的權限。
69 |
70 | 4. User-Base: 基本上就是一個 read-only 的使用者,同時因為本身權限很低,能夠看到的資訊非常少,更精準的來說就是一個只能登入的使用者。
71 |
72 | # Authentication 認證
73 |
74 | 前述探討如何分配權限,接下來要探討的就是要如何幫使用者進行帳號密碼的驗證,這部分 Rancher 除了本地使用者之外也支援了各式各樣的第三方服務,譬如
75 | 1. Microsoft Active Directory
76 | 2. GitHub
77 | 3. Microsoft Azure AD
78 | 4. FreeIPA
79 | 5. OpenLDAP
80 | 6. Microsoft AD FS
81 | 7. PingIdentity
82 | 8. Keycloak
83 | 9. Okta
84 | 10. Google OAuth
85 | 11. Shibboleth
86 |
87 | Rancher v2.6 的其中一個目標就是支援基於 OIDC 的 Keycloak ,因此如果團隊使用的是基於 OIDC 的 Keycloak 服務,讀者不仿可以期待一下 v2.6 的新功能。
88 |
89 | 使用者可以於 security->authentication 頁面看到如下的設定頁面
90 | 
91 |
92 | [官方網站中](https://rancher.com/docs/rancher/v2.5/en/admin-settings/authentication/)有針對上述每個類別都提供一份詳細的教學文件,要注意的是因為 Rancher 版本過多,所以網頁本身的內容有可能你會找到的是舊的版本,因此閱讀網頁時請確保你當前看到的版本設定方式與你使用的版本一致。
93 |
94 | 預設情況下,管理者只能針對一個外部的服務進行認證轉移,不過這只是因為 UI 本身的設定與操作限制,如果今天想要導入多套機制的話是可以從 Rancher API 方面去進行設定,對於這功能有需求的可以參考這個 Github Issue [Feature Request - enabling multiple authentication methods simultaneously #24323
95 | ](https://github.com/rancher/rancher/issues/24323)
96 |
97 | # 實戰演練
98 | 上述探討完了關於 Rancher 基本的權限管理機制後,接下來我們就來實際試試看到底用起來的感覺如何。
99 | 由於整個機器都是使用 Azure 來架設的,因此第三方服務我就選擇了 Azure AD 作為背後的使用者權限,之後的系列文章也都會基於這個設定去控制不同的使用者權限。
100 |
101 |
102 | 下圖是一個想要達到的設定狀況
103 | 
104 |
105 | Rancher 本身擁有一開始設定的本地使用者之外,還要可以跟 Azure AD 銜接
106 | 而 Azure AD 中所有使用者都會分為三個群組,分別是
107 | 1. IT
108 | 2. QA
109 | 3. DEV
110 |
111 | 我希望 IT 群組的使用者可以獲得 Admin 的權限,也就是所謂整個 Rancher 的管理員。
112 | 而 QA/DEV 目前都先暫時給予一個 User-Base 的權限,也就是只能單純登入然後實際上什麼都不能做。
113 | 這兩個群組必須要等到後面探討如何讓 Rancher 創建叢集時才會再度給予不同的權限,因此本篇文章先專注於 Rancher 與 AD 的整合。
114 |
115 | 本篇文章不會探討 Azure AD 的使用方式與概念,因此我已經於我的環境中創建了相關的使用者以及相關的群組。
116 |
117 | 整合方面分成兩大部分處理
118 | 1. Azure AD 與 Rancher 的整合
119 | 2. Rancher 內的 Roles 設定
120 |
121 | Azure AD 的部分可以參考[官方教學](https://rancher.com/docs/rancher/v2.5/en/admin-settings/authentication/azure-ad/),裡面有非常詳細的步驟告知要如何去 Azure 內設定,這邊要特別注意就是千萬不要看錯版本,以及最後填寫 Azure Endpoints 資訊時版本不要寫錯。
122 |
123 | 下圖是 Rancher 內的設定,其中 Endpoints 部分要特別小心
124 | 
125 | 1. Graph 要使用 https://graph.windows.net/ 而不是使用 Azure UI 內顯示的 https://graph.microsoft.com
126 | 2. Token/Authorization 這兩個要注意使用的是 OAUTH 2.0 (V1) 而不是 V2
127 |
128 | 下圖是 Azure 方面的設定,所以使用時要使用 V1 的節點而不是 V2,否則整合時候會遇到各種 invalid version 的 internal error.
129 | 
130 |
131 | 當這一切整合完畢後重新登入到 Rancher 的畫面,應該要可以看到如下圖的畫面
132 | 
133 |
134 | 畫面中告知 Rancher 的登入這時候分成兩種方式,分別是透過 Azure AD 以及使用本地使用者登入。
135 |
136 | # 權限控制
137 |
138 | 當與 Azure AD 整合完畢後,首先要先透過本地使用者進行權限設定,因為本地使用者本身也是 Admin 的關係,因此可以輕鬆地去修改 Rancher。
139 |
140 | 如同前面所提,希望整體權限可以是
141 | 1. IT 群組的人為超級使用者
142 | 2. DEV/QA 群組的人為只能登入的使用者 (User-Base)。
143 |
144 | 同時這邊也要注意,因為 Rancher 的使用者與群組兩個權限是可以分別設定且疊加的,因此設定的時候必須要這樣執行
145 | 1. 將所有第一次登入的外部使用者的預設使用者都改為 (User-Base)
146 | 2. 撰寫群組的相關規則,針對 IT/DEV/QA 進行處理。
147 |
148 | 預設情況下, Rancher 會讓所有第一次登入的使用者都給予 Standard-User 的權限,也就是能夠創建 k8s 叢集,這部分與我們的需求不同。
149 |
150 | 所以第一步驟,移動到 security->roles 裡面去修改預設使用者身份,取消 User 並且增加 User-Base
151 | 
152 |
153 | 第二步驟則是移動到 security-groups 內去針對不同 Group 進行設定
154 |
155 | 針對 IT 群組,給予 Administrator 的權限
156 | 
157 |
158 | 針對 Dev 群組給予 User-Base 的權限
159 | 
160 |
161 | 最後看起來會如下
162 | 
163 |
164 | 到這邊為止,我們做了兩件事情
165 | 1. 所有新登入的使用者都會被賦予 User-Base 的權限
166 | 2. 當使用者登入時,會針對其群組添加不同權限
167 | 如果是 IT,則會添加 Administrator 的權限,因此 IT 群組內的人就會擁有 User-Base + Administrator 的權限
168 | 如果是 DEV/QA 的群組,則會添加 Base-User 的權限,因此該群組內的人就會擁有 User-Base + User-Base 的權限,基本上還是 User-Base。
169 |
170 | 設定完畢後就可以到登入頁面使用事先創立好的使用者來登入。
171 |
172 | 當使用 Dev 群組的使用者登入時,沒有辦法看到任何 Cluster
173 | 
174 |
175 | 相反的如果使用 IT 群組的使用者登入時,則因為屬於 Administrator 的權限,因此可以看到系統上的 RKE 叢集。
176 | 
177 |
178 |
179 | 本篇文章探討了基本權限控管的概念並且展示了使用 Azure AD 後的使用範例,一旦瞭解基礎知識後,接下來就是好好研究 Rancher 內有哪些功能會使用到,哪些不會,針對這部分權限去進行設定,如果系統預設的 Role 覺得不夠好用時,可以自行創立不同的 Roles 來符合自己的需求,並且使用使用者與群組的概念來達到靈活的設定。
180 |
181 | 下篇文章將會使用 IT 的角色來看看到底 Rancher 上還有什麼設定是橫跨所有 Kubernetes 叢集,以及這些設定又能夠對整個系統帶來什麼樣的好處。
182 |
--------------------------------------------------------------------------------
/2021/day7.md:
--------------------------------------------------------------------------------
1 | Day 7 - Rancher 系統管理指南 - RKE Template
2 | =========================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前篇文章探討如何透過 Rancher 整合既有的帳號管理系統,同時如何使用 Rancher 提供的 RBAC 來為不同的使用者與群組設定不同的權限。
15 | 本文將繼續探討從 Rancher 管理人員角度來看還有哪些功能是執得注意與使用的。
16 |
17 |
18 |
19 | # 系統設定
20 | 當今天透過認證與RBAC等功能完成權限控管後,下一個部分要探討的就是團隊的運作流程。
21 | Rancher 作為一個 Kubernetes 管理平台,最大的一個特色就是能夠輕鬆地於各種架構下去安裝一個 Kubernetes 叢集並且管理它,
22 | 雖然到現在為止我們還沒有正式的示範如何創建叢集,但是可以先由下圖看一下大概 Rancher 支援哪些不同類型的架構
23 |
24 | 
25 |
26 | 圖中分成四種不同類型,這四種類型又可以分成兩大類
27 | 1. 已經存在的 Kubernetes 叢集,請 Rancher 幫忙管理。
28 | 2. 請 Rancher 幫忙創建一個全新的 Kubernetes 叢集並且順便管理。
29 |
30 | 圖中第一個類型就屬於第一大類,這部分目前整合比較好的有 EKS 與 GKE
31 | 這意味者如果你有已經運行的 EKS/GKE 叢集,是有機會讓 Rancher 幫忙管理,讓團隊可以使用一個共同的介面(Rancher)來管理所有的 Kubernetes 叢集。
32 |
33 | 圖中剩下的(2,3,4)都屬於第二大類,只是這三大類的安裝方式有些不同,分別是
34 | 1. 使用者要事先準備好節點, Rancher 會於這些節點上去創建 RKE 叢集
35 | 2. Rancher 會透過 API 要求服務供應商去動態創建 VM,並且創建 VM 後會自動的建立起 RKE 叢集
36 | 3. 針對部分有提供 Kubernetes 服務的業者, Rancher 也可以直接透過 API 去使用這些 Kubernetes 服務(AKS/EKS/GKE) 並且把 Rancher Agent 安裝進去,接者就可以透過 Rancher 頁面去管理。
37 |
38 | 這邊點選第三類別的 Azure 作為一個範例來看一下,透過 RKE 安裝 Kubernetes 會有什麼樣的資訊需要填寫
39 | 
40 |
41 | 首先上圖看到關於 Cluster Options 下有四大項,這四大項裡面都問題都跟 Kubernetes 叢集,更精準的說是 RKE 有關
42 |
43 | 
44 |
45 | 首先第一個類別就是 Kubernetes 的基本資訊,包含了
46 | 1. RKE 的版本,版本跟 Kubernetes 版本是一致走向的。
47 | 2. CNI 使用哪套,目前有 Flannel, Calico 以及 Canal。
48 | 3. CNI 需不需要額外設定 MTU
49 | 4. 該環境要不要啟用一些 Cloud Provider 的功能,要的話還要填入一些機密資訊
50 |
51 | 
52 |
53 | 往下看還有更多選項可以用,譬如該 RKE 創建時,所有用到的 Registry 是否要從一個 Private Registry 來抓取,這功能對某些團隊來說會非常有用,因為部分團隊會希望用到的所有 Container Image 都要有一份備份以免哪天 quay, docker.io 等出現問題導致整個安裝失敗。
54 |
55 | 因此如果團隊事先將 RKE 用到的 Container Image 都複製一份到自己團隊的 private container registry 的話,就可以打開這個功能讓 Rancher 知道去哪邊抓 Image。
56 |
57 | 後續則是更多的進階選項,譬如説
58 | 1. RKE 中預設要不要安裝 Nginx 作為 Ingress Controller?
59 | 2. 系統中的 NodePort 用到的範圍多少?
60 | 3. 是否要導入一組預設的 PodSecurityPolicy 來限制叢集內所有Pod的安全性規則
61 | 4. Docker 有沒有特別指定的版本
62 | 5. etcd 要如何備份,要本地備份還是要透過 s3 將 etcd 上傳
63 | 6. 要不要定期透過 CIS 進行安全性相關的掃描?
64 |
65 | 可以看到上述的設定其實滿多的,如果每次創建一個叢集都要一直輸入一樣的資訊難免會出錯,同時有一些設定 IT 人員會有不同的顧慮與要求。為了讓團隊內的所有 RKE 叢集都可以符合團隊的需求,Rancher 就有提供基於全面系統地 RKE Template.
66 |
67 | # RKE Template
68 | RKE Template 的概念就是讓系統人員與安全人員針對需求去規範 Kubernetes 的要求,所有使用者都必須要使用這個事先創立的 RKE Template 來創立 RKE 叢集。
69 | 透過這個方式有幾個好處
70 | 1. 使用者創立的所有 RKE 叢集都可以符合團隊需求
71 | 2. 使用者使用 Template 去創建 RKE 的話就可以省略那些不確定該怎麼填寫的資訊,簡化整個創造步驟
72 | 3. Template 本身也是一個物件,所以 Rancher 前述提到的權限控管就可以針對 Template 去進行設定,譬如 DEV/QA 人員只能使用已經創建的 Template 來創立 RKE 叢集
73 |
74 | 以下是一些常見使用 RKE Template 的使用範例
75 | 1. 系統管理人員強迫要求所有新創立的 RKE 叢集都只能使用事先創立好的 RKE Template
76 | 2. 系統管理人員創建不同限制的 RKE Template,針對不同的使用者與群組給予不同的 RKE Template
77 | 3. RKE Template 本身是有版本的概念,所以如果今天公司資安團隊希望調整資安方面的使用,只需要更新 RKE Template 即可。所有使用到的使用者再進行 RKE Template 更新的動作即可
78 |
79 | 此外 RKE Template 內所有的設定都有一個覆蓋的概念存在,創建該 RKE Template 時可以決定該設定是否能夠被使用者覆蓋,這對於某些很重要的設定來說非常有用。
80 |
81 | 以下是一個 RKE Template 創建的方式 (Tools->Template 進入)
82 |
83 | 
84 |
85 | 圖中最上方代表的是該 RKE Template 的名稱與版本,同時每個 RKE Template 有很多個版本,更新的時候可以選擇當前版本是否要作為當前 Template 的預設版本。
86 |
87 | 中間部分則是到底誰可以使用這個 RKE Template,裡面可以針對使用者與群組去設定身份總共分成兩個身份,分別是 User 以及 Owner。
88 |
89 | 1. Owner: 符合這個身份的使用者可以執行 更新/刪除/分享 這些關於 RKE Template 的設定,概念來說就是這個 RKE Template 的擁有者。
90 | 2. User: 簡單來說就是使用這個 RKE Template 的人,使用者再創建 RKE 叢集的時候可以從這些 Template 中去選擇想要使用的 Template。
91 |
92 |
93 | 最下面的部分跟前述探討安裝 RKE 要使用的權限都差不多,唯一要注意的是每個選項旁邊都有一個 "Allow user override?" 的選項,只要該選項沒有打開,那使用者(User)使用時就不能覆蓋這些設定。
94 |
95 | # 實驗
96 | 接下來針對 RKE Template 進行一個實驗,該實驗想到達到以下目的。
97 |
98 | 1. IT 管理員創建一個 RKE Template,並且設定 DEV 群組的使用者可以使用
99 | 2. DEV 群組的使用者可以創建 Cluster,但是被強迫只能使用 RKE Template 創造,並不是自己填寫任何資訊。
100 |
101 | 為了達到這個目的,我們有三個步驟要做,分別是
102 | 1. 透過 Rancher 的設定,強迫所有創建 RKE 叢集一定要使用 RKE Template,不得自行填寫資訊。
103 | 2. 創造一個 RKE Template,並且設定 DEV 群組的人是使用者,同時該 RKE Template 內讓 Kubernetes 版本是一個可以被使用者覆蓋的設定。
104 | 3. 登入 DEV 使用者嘗試創造 RKE 叢集,看看上述設定是否可以達到我們的需求。
105 |
106 |
107 | 首先到首頁上方的 Setting,進去後搜尋 template-enforcement 就會找到類似下列這張圖片的樣子
108 | 
109 |
110 | 預設狀況下,該設定是 False,透過旁邊的選項把它改成 True,該選項一打開後,所有新的 RKE 叢集都只能透過 RKE Template 來創建。
111 |
112 | 接者用 IT 人員登入作為一個系統管理員,創建一個如下的 RKE Template
113 |
114 | 
115 |
116 | 中間部分表示任何屬於 DEV 群組的人都可以使用這個 RKE Template,同時該 RKE Template 允許使用者去修改 Kubernetes 版本,其餘部分都採用 RKE Template 的設定。
117 |
118 | 最後用 DEV 的身份登入 Rancher 並且嘗試創造一個 RKE 叢集。
119 | 從下述畫面可以觀察到一些變化
120 |
121 | 
122 |
123 | 1. RKE Template 相關選項 "Use an existing RKE Template and revision" 被強迫打勾,這意味使用者一定要使用 RKE Template
124 | 2. 選擇了前述創造的 RKE Template 後就可以看到之前創造好的設定
125 | 3. 只有 Kubernetes 的版本是可以調整的,其餘部分如 CNI 等都是不能選擇的。
126 |
127 | 註: 當透過 RKE Template 賦予權限給予 DEV 群組後, 群組那邊的設定會被修改,這時候的 DEV 群組會被自動加上 "Creating new Clusters" 這個權限,範例如下
128 |
129 | 
130 |
131 | 透過上述的範例操作成功地達到預期目標的設定,讓團隊內所有需要創建 RKE 叢集的使用者都必須要使用事先創造好的 RKE Template 來確保所有叢集都可以符合團隊內的需求。
--------------------------------------------------------------------------------
/2021/day8.md:
--------------------------------------------------------------------------------
1 | Day 8 - Rancher 叢集管理指南 - 架設 K8s(上)
2 | ========================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前述文章探討的都是基於一個系統管理員的角度下,可以如何使用 Rancher 這個管理平台來符合整個團隊的需求,譬如 RKE Template 以及最重要的使用者登入與權限控管。
15 | 當 Rancher 系統有了妥善的規劃與設定後,下一步就是踏入到 Rancher 最重要的功能,也就是 Kubernetes 管理。
16 |
17 | 前篇文章探討 RKE Template 的時候有介紹過 Rancher 有四種新增 Kubernetes 叢集的方式,第一種是將已經存在的 EKS/GKE 等叢集直接匯入到 Rancher 中,而剩下三種是根據不同架構來產生一個全新的 RKE 叢集並且匯入到 Rancher 中。
18 |
19 | 這三種架構以目前的環境架構如下圖所示
20 |
21 | 
22 |
23 | Rancher 有三種方式可以架設 RKE,從右到左分別是
24 | 1. 透過 API 請求 Azure 幫忙創建 AKS,並且把 Rancher 相關的 agent 安裝到該 AKS 中
25 | 2. 透過 API 請求 Azure 創造 VM 叢集,接者於這些 VM 上安裝 RKE 叢集
26 | 3. 直接於已經存在的節點上搭建一套 RKE 叢集
27 |
28 | 接下來就示範這三種用法有何不同,以及當 RKE 叢集創建出來後該如何使用
29 |
30 | # 環境實驗
31 | 三種環境中,我認為相對複雜的是第二種,如何請求 Azure 創建 VM 並且安裝 RKE 叢集。
32 | 所以先從這個較為複雜的情況開始探討,掌握這個概念後後續兩個(1)(3)都較為簡單,使用上也就不會有太多問題。
33 |
34 | 第二種的安裝模式將其仔細攤開來看,其實有幾個重點需要完成
35 | 1. 選擇一個想要使用的 Service Provider
36 | 2. 準備好該 Service Provider 溝通用的設定,譬如帳號密碼, Token 等
37 | 3. 規劃需要準備多少台 VM,每個 VM 要用何種規模(CPU/Memory),該機器要扮演 Kubernetes 什麼角色
38 | 4. 規劃 RKE 的設定
39 |
40 | # Service Provider
41 |
42 | 第一點是選擇一個想要使用的 Service Provider,由於之前的環境都是基於 Azure 去使用,因此我接下來的範例都會基於 Azure 去架設。
43 |
44 | 下圖是一個 Rancher 預設支援的 Service Provider,包含了 AWS, Azure, DigitalOcean, Linode 以及 vSphere.
45 |
46 | 
47 |
48 | 實際上 Rancher 內部有一個名為 Node Driver 的資源專門用來管理目前支援哪些 Service Provider,該資源是屬於系統層級,也就是整個 Rancher 環境共享的。
49 |
50 | Driver (Tools->Driver) 頁面中顯示了兩種不同的 Driver,分別是 Cluster Driver 以及 Node Drivers.
51 |
52 | 預設的 Node Driver 狀態如下,可以看到 Driver 分成兩種狀態,分別是 Active 以及 Inactive,而上圖中顯示的 AWS/Azure/Digital/Linode/vSphere 都屬於 Active。
53 |
54 | 
55 |
56 | 嘗試將上述所有 Inactive 的 Drive 都 active 後,這時候重新回去 Cluster 創建頁面看,就可以發現目前支援的 Service Provider 變得超級多。
57 |
58 | 
59 |
60 | 所以如果團隊使用的 Service Provider 沒有被 Rancher 預設支援的話,別忘記到 Driver 處去看看有沒有,也許只是屬於 Inactive 的狀態而已。
61 |
62 | # Access Credentials
63 |
64 | 選擇 Service Provider(Azure) 後的下一個步驟就是要想辦法讓 Rancher 跟 Azure 有辦法溝通,基本上 Service Provider 都會提供相關的資訊供使用者使用。
65 |
66 | 這邊試想一下,這種帳號密碼資訊的東西如果每次創建時都要一直重複輸入其實也是相對煩人的,所以如果有一個類似 RKE Template 概念的物件,就能夠讓使用者更為方便的去使用。
67 | 譬如使用者只需要事先設定一次,接下來每次要使用到的時候都去參考事先設定好的帳號密碼資訊即可。
68 |
69 | Rancher 實際上也有提供這類型的機制,稱為 Cloud Credentials,其設定頁面位於個人使用者底下,
70 |
71 | 
72 |
73 | 接者點選創建一個 Cloud Credential 並且將 Cloud Credential Type 設定為 Azure 後就會出現 Azure 應該要輸入的相關資訊,對於熟悉 Azure 的讀者來說這三個設定應該不會太陌生,基本上 Rancher 官方都有針對這些類別提供簡單的教學文件。
74 |
75 | 
76 |
77 | 一切準備就緒後就可以創建一個基於 Azure 的 Cloud Credential 了。未來其他操作如果需要 Azure 相關的帳號密碼時,就不需要一直重複輸入,而是可以直接使用這組事先創建好的連接資訊。
78 |
79 | # VMs
80 |
81 | 當 Rancher 準備好如何跟 Service Provider(Azure) 溝通後,下一個要做的就是使用者要去思考,希望這個創建的 RKE 叢集有多少個節點以及相關設定。這些節點都會是由 Rancher 要求 Azure 動態創立的,每個節點都需要下列資訊
82 |
83 |
84 | 1. 節點的 VM 規模,多少 CPU,多少 Memory
85 | 2. 該 VM 要用什麼樣的 Image,什麼樣的版本,登入角色要用什麼名稱,有沒有 Cloud-Init 要運行
86 | 3. 每個 Service Provider 專屬設定
87 | 4. 該節點於 Kubernetes 內扮演的角色,角色又可以分成三種
88 | a. etcd: 扮演 etcd 的角色,要注意的是 etcd 的數量必須是奇數
89 | b. control plane: Kubernetes Control Plane 相關的元件,包含 API Server, Controller, Scheduler 等
90 | c. worker: 單純的角色,可以接受 Control Plane 的命令將 Pod 部署到該節點上。
91 |
92 | 從上述的資訊可以觀察到,要創建一個 RKE 資訊光節點這邊要輸入的資訊就不少,所以如果每次創建 RKE 叢集都要一直重複輸入上列這些資訊,其實帶來的麻煩不下 Credential 與 K8s 本身。
93 |
94 | 這個問題 Rancher 也有想到,其提供了一個名為 Node Template 的物件讓使用者可以去設定 VM 的資訊,同時為了讓整個操作更加彈性與靈活,上述四個步驟其實分成兩大類
95 | 1. VM 本身的設定 (1~3)
96 | 2. 該 VM 怎麼被 RKE 使用 (4)
97 |
98 | Node Template 要解決的是第一大類的問題,讓 VM 本身的設定可以重複利用,不需要每次輸入。
99 | 使用者要創立ㄧ個新的 RKE 叢集時,可以直接使用創造好的 NodeTemplate 設定 VM 資訊,接者根據當前需求決定該節點應該要以何種身份於 RKE 叢集中使用。
100 |
101 | Node Template 與 Cloud Credential 一樣,都可以於使用者底下的頁面去設定。
102 | 進入到頁面後可以看到目前支援的 Service Provider,因為先前有將所有 Node Driver 都打開,所以這邊的選擇就非常的多。
103 |
104 | 
105 |
106 | 當選擇為 Azure 後,底下的 Account Access 就會出現之前創立的 Cloud Credential。
107 | 如果想要創建新的也可以於這個頁面直接創立該 Cloud Credential。
108 |
109 | 
110 | 
111 |
112 | 接者下列就是滿滿的 VM 設定,這邊的設定內容都跟該 Service Provider 有關 可以看到
113 | 1. image 預設是 canonical:UbuntuServer:18.04-LTS:latest,
114 | 2. Size 是 Standard_D2_v2
115 | 3. SSH 的使用者名稱是誰
116 | 4. 硬碟空間預設是 30GB
117 |
118 | 上述還有非常多的設定,除非對這些選項都非常熟悉,不然大部分情況下都可以採取預設選項
119 | 一切就緒後給予該 Node Template 一個名稱並且儲存。
120 |
121 | 實務上通常會針對不同大小的機器創建不同的 Node Template 並且給予名稱時有一個區別,這樣之後使用者要使用時就會比較清楚當前的 Node Template 會創造出什麼樣的機器。
122 |
123 | 這邊示範一下創建兩個 Node Template 並且給予不同的名稱
124 | 
125 |
126 | # RKE
127 | 一切資訊都準備完畢後,接者就可以回到 Cluster 的頁面去創造一個基於 Azure 的 RKE 叢集。
128 |
129 | 
130 | 上圖紅匡處則是本文章重點處理的部分,也就是所謂的 Node Template。
131 | 對於 RKE 叢集來說,會先透過 Node Template 來定義一個 Node Pool,每個 Node Pool 需要定義下列資訊
132 | 1. 該 Node Pool 名稱
133 | 2. Pool 內有多少節點
134 | 3. 該 Node Pool 要基於哪個 Node Template 來創造
135 | 4. 本身要扮演什麼身份
136 |
137 | 同時 UI 也會提醒你每個身份應該要有多少個節點,譬如 etcd 要維持奇數, Control Plane/Worker 至少都要有一個節點。
138 |
139 | 決定好叢集身份後,下一件事情就是權限,到底誰有權限去使用這個 RKE 叢集,預設情況下有兩種身份,分別是
140 | 1. Cluster Owner: 該使用者擁有對該叢集的所有操控權,包含裡面的各種資源
141 | 2. Cluster Member: 可以讀取觀看各種相關資源,寫的部分是針對底下的專案去操作,沒有辦法對 Cluster 本身進行太多操作,這部分之後會探討叢集內的專案概念時會更加理解。
142 |
143 | 一切準備就緒就給他點選創立,接者就是慢慢等他處理,整個過程會相對漫長,因為需要從 VM 開始創立,接者才去創建 RKE 叢集。
144 | 當畫面顯示如下時,就代表者相關叢集已經創建完畢了。
145 |
146 | 
147 |
148 | 這邊可以看到,跟之前用來存放 Rancher 的 RKE 不同,這個新創的 RKE 叢集其 Provider 標示為 Azure。
149 |
150 | 同時我的 Azure VM 中也真的產生出三個新的VM,這些 VM 的名稱與規格都與之前設定的完全一樣。
151 |
152 | 
153 |
154 | 下一章節會繼續介紹另外兩種不同的安裝方式,並且會基於這三種不同方式安裝三個不同類型的叢集,之後探討到 Rancher Fleet 這個 GitOps 的概念時,就會使用 GitOps 來部署應用程式到這三個不同的叢集。
155 |
--------------------------------------------------------------------------------
/2021/day9.md:
--------------------------------------------------------------------------------
1 | Day 9 - Rancher 叢集管理指南 - 架設 K8s(下)
2 | ========================================
3 |
4 | 本文將於賽後同步刊登於筆者[部落格](https://hwchiu.com/)
5 |
6 | 有興趣學習更多 Kubernetes/DevOps/Linux 相關的資源的讀者,歡迎前往閱讀
7 |
8 | 更多相關科技的技術分享,歡迎追蹤 [矽谷牛的耕田筆記](https://www.facebook.com/technologynoteniu)
9 |
10 | 對於 Kubernetes 與 Linux Network 有興趣的可以參閱筆者的[線上課程](https://course.hwchiu.com/)
11 |
12 | # 前言
13 |
14 | 前篇文章探討了 Rancher 其中一種安裝 Kubernetes(RKE) 的方式,該方式會先透過 API 請求 Service Provider(Azure) 幫忙創建相關的 VM,接者於這些 VM 上面搭建一個符合需求的 RKE 叢集。
15 |
16 | 為了讓簡化整個設定過程,我們學到了如何透過 Cloud Credential 以及 Node Template 兩種方式來事先解決繁瑣的操作,接者真正創建 RKE 叢集時則使用 Node Template 與 RKE Template 兩個方式讓整個創建過程變得很簡單,不需要填入太多資訊,只需要利用這兩個 Template 的內容加上自行設計要多少個 VM 節點,這些節點要屬於什麼身份以及該叢集最後要給哪個使用者/群組使用即可。
17 |
18 | 本篇文章將繼續把剩下兩種安裝方式給走一遍,三種安裝方式都玩過後會對 Rancher 的能力有更多的瞭解,同時也會為之後 Rancher Fleet 的使用先行搭建環境。
19 |
20 | 之前探討使用者管理與部署時於系統中創建了三種不同群組的使用者,包含了 DEV, QA 以及 IT。而這兩個章節探討的三種部署方式其實剛好就會剛好拿來搭配這些不同的使用者,期望透過不同方式搭造出來的三套 RKE 叢集本身權限控管上就有不同的設定。
21 |
22 | 目標狀況是三套叢集擁有的權限如下
23 | 1. DEV 叢集 -> IT & DEV 可以使用
24 | 2. QA 叢集 -> IT & QA 可以使用
25 | 3. IT 叢集 -> IT 可以使用
26 |
27 | 基本上因為 IT 群組的使用者會被視為系統管理員,因此本身就有能力可以存取其他叢集,所以創建時只需要針對 DEV 以及 QA 兩個叢集去設計。
28 | 實務上到底會如何設計取決於團隊人數與分工狀況,這邊的設計單純只是一個權限控管的示範,並不代表真實應用就需要這樣做。
29 |
30 |
31 | # Existing Cluster
32 |
33 | 前篇文章探討的是動態創建 VM 並且於搭建 RKE 叢集,與之相反的另外一種架設方式就是於一個已經存在的節點上去搭建 RKE 叢集。
34 |
35 | 這個安裝方式大部分都會用於地端環境,部分使用者的地端環境沒有 vSphere/Openstack 等專案可以幫忙自動創建 VM,這種情況下一台又一台的 bare-metal 機器就會採用這種方式來安裝。
36 |
37 | 我先於我的 Azure 環境中創建兩個 VM,想要用這兩個 VM 搭建一個屬於 QA 群組使用者的 RKE 叢集
38 |
39 | 
40 |
41 | 上圖中標示為 qa-rke{1,2} 的機器就是為了這個情況手動創建起來的。
42 | 準備好了相關 VM 之後,就切換到 Rancher 的介面去創建一個 RKE 叢集。
43 |
44 | 
45 |
46 | 介面中選擇非常簡單,只有一個 Existing Nodes 可以選擇,點進去後可以看到類似下方頁面
47 |
48 | 
49 |
50 | 與之前的安裝方式不同,這邊沒有所謂的 Node Pool 的概念,畢竟是要安裝到一個已存在的節點,所以沒有 Node Pool 需要設定也是合理的。
51 | 這邊我將該叢集分配給 QA 群組的使用者,令其為 Owner,擁有整個叢集的管理權限,同時下方繼續使用先前設定好的 RKE 叢集。
52 |
53 | 一切完畢後點選 Next 到下一個頁面,該頁面才是真正安裝的方式
54 |
55 | 
56 |
57 | 該介面有三個地方要注意
58 | 1. 最下方是安裝的指令,實際上是到該節點上透過 Docker 的方式去運行一個 Rancher Agent 的容器,該容器會想辦法跟安裝 RKE 並且跟遠方的 Rancher 註冊以方便被管理
59 | 2. 最上方兩個區塊都是用來調整該節點到底要於 RKE 叢集中扮演什麼角色,這些變動都會影響下方 Docker 指令
60 | 3. 就如同先前安裝一樣,這邊也需要選擇當前節點到底要當 ETCD/Control Plane/Worker 等
61 | 4. Show advanced options 選項打開可以看到的是 Labels/Taints 等相關設定
62 |
63 | 我透過上述介面設定了兩種介面,分別是
64 | 1. 單純的 worker
65 | 2. 全包,同時兼任 worker/etcd/controlplane
66 |
67 | 接者複製這些 docker 指令到事先準備好的 VM 上去執行
68 |
69 | 
70 |
71 |
72 |
73 | 到兩個機器上貼上指令後,就慢慢的等 Rancher 將整個 RKE 架設起來。
74 |
75 | 可以看到透過這種方式創建的叢集,其 Provider 會被設定成 Custom,跟之前創立的 Azure 有所需別。
76 |
77 | 
78 |
79 | 點選該叢集名稱進去後,切換到節點區塊可以看到兩台機器正在建立中,這邊要特別注意,節點的 hostname 必須要不同,如果 hostname 一致的話會讓 Rancher 搞混,所以使用 bare-metal 機器建立時千萬要注意 hostname 不要衝突。
80 |
81 | 
82 |
83 | 一切結束後,就可以於最外層的介面看到三個已經建立的叢集,一個是用來維護 Rancher 本身,兩個則是給不同群組的 RKE 叢集。
84 |
85 | 
86 |
87 | # Managed Kubernetes Service
88 | 接者來看最後一個安裝方式,這個方式想要直接透過 Rancher 去創造 AKS 這種 Kubernetes 服務,並且安裝完畢後將 Rancher 的相關服務部署進去,這樣 Rancher 才有辦法控管這類型的叢集。
89 |
90 | 回到叢集安裝畫面,這時候針對最下面的服務,預設情況下這邊的選擇比較少,但是如果有到 Tools->Driver 去將 Cluster Driver 給打開的話,這邊就會出現更多的 Service Provider 可以選擇。
91 |
92 | 
93 |
94 | 根據我的環境,我選擇了 Azure AKS,點選進去後就可以看到如下圖的設定頁面
95 |
96 | 
97 |
98 | 進到畫面後的第一個選項就是 Azure 相關的認證資訊,這邊我認為是 Rancher 還沒有做得很完善的部分,先前創建 Node Template 時使用的 Cloud Credential 這邊沒有辦法二次使用,變成每次創建一個 AKS 叢集時都要重新輸入一次相關的資訊,這部分我認為還是有點不方便。
99 | 不過仔細觀察需要的資訊有些許不同,創造 Node Template 時不需要 Tenant ID,但是使用 AKS 卻需要。有可能因為這些設定不同導致 Cloud Credential 這邊就沒有辦法很輕鬆的共用。
100 | 不過作為使用者也是希望未來能夠簡化這些操作,否則每次創建都要翻找算是有點麻煩。
101 |
102 | 
103 |
104 | 通過存取資訊驗證後,就可以來到設定頁面,因為這個是 AKS 叢集,因此並沒有辦法使用 RKE Template 來客製化內容,所有的設定內容都是跟 AKS 有關,因此不同的 K8S 服務提供的操作選項就不同。
105 |
106 | 
107 |
108 | 一切準備就緒後,就可以看到最外層的叢集列表多出了一個全新的 Kubernetes 叢集,其 Provider 則是 Azure AKS。
109 |
110 | 
111 |
112 | 此時觀看 Azure AKS 的頁面可以發現到也多了一個正在創建中的 AKS 叢集,名稱 c-xxxx 就是 Rancher 創造的證明,每個 Rancher 管理的 Kubernetes 叢集都會有一個內部ID,都是 c-xxxx 的形式。
113 |
114 | 等待一段時間待節點全部產生完畢,就可以看到一個擁有三個節點的 AKS 叢集被創建了
115 |
116 | 
117 |
118 | 最後到外層叢集介面可以看到目前有四個 K8S 叢集被 Rancher 管理,其中一個是管理 Rancher 本身,剩下三個則是新創立的 K8s 叢集。同時這三個叢集都分配給不同群組的使用者使用。
119 |
120 | 
121 |
122 |
123 | 如果這時候用 QA 使用者登入,就只會看到一個叢集,整個運作的確有符合當初的設計。
124 | 
125 |
126 |
127 | 叢集都創立完畢後,下一章節將來探討如何使用 Rancher 的介面來管理 Kubernetes,以及 Rancher 介面還提供了哪些好用的功能可以讓叢集管理員更加方便的去操作叢集。
128 |
--------------------------------------------------------------------------------
/2021/terraform/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | rancher2 = {
4 | source = "rancher/rancher2"
5 | version = "1.17.0"
6 | }
7 | }
8 | }
9 |
10 | provider "rancher2" {
11 | api_url = "https://rancher.hwchiu.com"
12 | access_key = "xxxxxxxx"
13 | secret_key = "xxxxxxxxxxxxxxxxxxxxxxx"
14 | }
15 |
16 | resource "rancher2_cluster_template" "foo" {
17 | name = "ithome_terraforn"
18 | template_revisions {
19 | name = "V1"
20 | cluster_config {
21 | rke_config {
22 | network {
23 | plugin = "canal"
24 | }
25 | services {
26 | etcd {
27 | creation = "6h"
28 | retention = "24h"
29 | }
30 | }
31 | upgrade_strategy {
32 | drain = true
33 | max_unavailable_worker = "20%"
34 | }
35 | }
36 | }
37 | default = true
38 | }
39 | description = "Terraform cluster template foo"
40 | }
41 |
42 | data "rancher2_project" "system" {
43 | cluster_id = "c-z8j6q"
44 | name = "myApplication"
45 | }
46 |
47 | resource "rancher2_catalog" "dashboard-global" {
48 | name = "dashboard-terraform"
49 | url = "https://kubernetes.github.io/dashboard/"
50 | version = "helm_v3"
51 | }
52 |
53 | resource "rancher2_namespace" "dashboard" {
54 | name = "dashboard-terraform"
55 | project_id = data.rancher2_project.system.id
56 | }
57 |
58 | resource "rancher2_app" "dashboard" {
59 | catalog_name = "dashboard-terraform"
60 | name = "dashboard-terraform"
61 | project_id = data.rancher2_project.system.id
62 | template_name = "kubernetes-dashboard"
63 | template_version = "4.5.0"
64 | target_namespace = rancher2_namespace.dashboard.id
65 | depends_on = [rancher2_namespace.dashboard, rancher2_catalog.dashboard-global]
66 | }
67 |
68 | resource "rancher2_catalog_v2" "dashboard-global-app" {
69 | name = "dashboard-terraform"
70 | cluster_id = "c-z8j6q"
71 | url = "https://kubernetes.github.io/dashboard/"
72 | }
73 |
74 | resource "rancher2_namespace" "dashboard-app" {
75 | name = "dashboard-terraform-app"
76 | project_id = data.rancher2_project.system.id
77 | }
78 |
79 | resource "rancher2_app_v2" "dashboard-app" {
80 | cluster_id = "c-z8j6q"
81 | name = "k8s-dashboard-app-terraform"
82 | namespace = rancher2_namespace.dashboard-app.id
83 | repo_name = "dashboard-terraform"
84 | chart_name = "kubernetes-dashboard"
85 | chart_version = "4.5.0"
86 | depends_on = [rancher2_namespace.dashboard-app, rancher2_catalog_v2.dashboard-global-app]
87 | }
88 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | ithome.hwchiu.com
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | gitbook build
3 | cp -R _book/* .
4 | git clean -fx _book
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ITHOME 鐵人 30 的文章原始檔案
2 | ==================================
3 |
4 | 本書用來記錄 ITHOME 相關文章的原始檔案,有興趣可以參考下列連結獲得更多資訊
5 |
6 | - [筆者部落格](https://www.hwchiu.com)
7 | - [活動推廣粉絲頁](https://www.facebook.com/technologynoteniu)
8 | - [Telegram 推播頻道](https://t.me/technologynote)
9 | - [線上影片 - Youtube](https://www.youtube.com/watch?v=1n2JsOIiHP8&list=TLPQMDYwOTIwMjA3DiY-FQiX7g&index=1)
10 | - [線上活動 - Meetups](https://www.meetup.com/CloudNative-Taiwan/events)
11 | - [投影片 - Slideshare](https://www.slideshare.net/hongweiqiu/presentations)
12 | - [筆者線上課程](https://www.hwchiu.com/course)
13 | - [Cloud Native Taiwan User Group](https://www.facebook.com/groups/cloudnative.tw)
14 |
15 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Summary
2 |
3 | * 2019 鐵人賽
4 | * [Kubernetes 設計原理](2019/overview/day1.md)
5 | * Container 介紹
6 | * [淺談 Container 實現原理- 上](2019/container/day2.md)
7 | * [淺談 Container 實現原理- 中](2019/container/day3.md)
8 | * [淺談 Container 實現原理- 下](2019/container/day4.md)
9 | * Container Runtime Interface(CRI)
10 | * [Kubernetes & CRI (I)](2019/runtime/day5.md)
11 | * [Kubernetes & CRI (II)](2019/runtime/day6.md)
12 | * [Container Runtime - CRI-O](2019/runtime/day7.md)
13 | * [Container Runtime - Security Container](2019/runtime/day8.md)
14 | * [Container Runtime - Virtual Machine](2019/runtime/day9.md)
15 | * Container Network Interface(CNI)
16 | * [Container Network Interface 介紹](2019/network/day10.md)
17 | * [kubernetes 與 CNI 的互動](2019/network/day11.md)
18 | * [使用 golang 開發第一個 CNI 程式](2019/network/day12.md)
19 | * [初探 CNI 的 IP 分配問題 (IPAM)](2019/network/day13.md)
20 | * [CNI - Flannel - 安裝設定篇](2019/network/day14.md)
21 | * [CNI - Flannel - IP 管理篇](2019/network/day15.md)
22 | * [CNI - Flannel - VXLAN 封包運作篇](2019/network/day16.md)
23 | * [CNI 閒談](2019/network/day17.md)
24 | * Container Storage Interface(CSI)
25 | * [Container Storage Interface 基本介紹](2019/storage/day18.md)
26 | * [Container Storage Interface 標準介紹](2019/storage/day19.md)
27 | * [Container Storage Interface 與 kubernetes](2019/storage/day20.md)
28 | * [Container Storage Interface(CSI) - NFS 初體驗](2019/storage/day21.md)
29 | * [CSI 雜談](2019/storage/day22.md)
30 | * Device Plugin
31 | * [Device Plugin Introduction](2019/device-plugin/day23.md)
32 | * [Device Plugin - Kubernetes](2019/device-plugin/day24.md)
33 | * [RDMA](2019/device-plugin/day25.md)
34 | * [SR-IOV](2019/device-plugin/day26.md)
35 | * Miscellaneous
36 | * [Operator Pattern](2019/extension/day27.md)
37 | * [Service Catalog](2019/extension/day28.md)
38 | * [Security](2019/security/day29.md)
39 | * [總結](2019/summary/day30.md)
40 |
41 |
42 |
43 | * 2020 鐵人賽
44 | * [DevOps 與 Kubernetes 的愛恨情仇](2020/overview/day1.md)
45 | * Kubernetes 物件管理與部署
46 | * [Kubernetes 物件管理簡介](2020/application/day2.md)
47 | * [Helm 的介紹](2020/application/day3.md)
48 | * [Helm 的使用範例](2020/application/day4.md)
49 | * Kubernetes 本地開發之道
50 | * [淺談本地部署 Kubernetes 的各類選擇](2020/local/day5.md)
51 | * [K3D與KIND 的部署示範](2020/local/day6.md)
52 | * [本地開發 Kubernetes 應用程式](2020/local/day7.md)
53 | * [Skaffold 本地開發與測試](2020/local/day8.md)
54 | * CI 流水線介紹
55 | * [Pipeline System 介紹](2020/ci/day9.md)
56 | * [CI 與 Kubernetes 的整合](2020/ci/day10.md)
57 | * [Kubernetrs 應用測試](2020/ci/day11.md)
58 | * [CI Pipeline x Kubernetes 結論](2020/ci/day12.md)
59 | * CD 流水線介紹
60 | * [CD 系統的選擇議題](2020/cd/day13.md)
61 | * [CD 與 Kubernetes 的整合](2020/cd/day14.md)
62 | * [CD 之 Pull Mode 介紹: Keel](2020/cd/day15.md)
63 | * GitOps 的部署概念
64 | * [GitOps 的介紹](2020/gitops/day16.md)
65 | * [GitOps 與 Kubernetes 的整合](2020/gitops/day17.md)
66 | * [GitOps - ArgoCD 介紹](2020/gitops/day18.md)
67 | * Private Registry
68 | * [Container Registry 的介紹及需求](2020/registry/day19.md)
69 | * [自架 Registry 的方案介紹](2020/registry/day20.md)
70 | * [自架 Registry - Harbor](2020/registry/day21.md)
71 | * [自架 Registry 與 Kubernetes 的整合](2020/registry/day22.md)
72 | * Secret 的議題
73 | * [Secret 的部署問題與參考解法(上)](2020/secret/day23.md)
74 | * [Secret 的部署問題與參考解法(下)](2020/secret/day24.md)
75 | * [Secret 使用範例: sealed-secrets](2020/secret/day25.md)
76 | * 番外篇
77 | * [kubectl plugin 介紹](2020/plugin/day26.md)
78 | * [Kubernetes plugin 範例](2020/plugin/day27.md)
79 | * [Kubernetes 第三方好用工具介紹](2020/plugin/day28.md)
80 | * [Summary](2020/summary/day29.md)
81 | * [各類資源分享](2020/summary/day30.md)
82 |
83 | * 2021 鐵人賽
84 | * Rancher 基本知識
85 | * [淺談 Kubernetes 的架設與管理](2021/day1.md)
86 | * [何謂 Rancher](2021/day2.md)
87 | * [Rancher 架構與安裝方式介紹](2021/day3.md)
88 | * [透過 RKE 架設第一套 Rancher(上)](2021/day4.md)
89 | * [透過 RKE 架設第一套 Rancher(下)](2021/day5.md)
90 | * Rancher 系統管理指南
91 | * [系統管理指南 - 使用者登入管理](2021/day6.md)
92 | * [系統管理指南 - RKE Template](2021/day7.md)
93 | * Rancher 叢集管理指南
94 | * [架設 K8s(上)](2021/day8.md)
95 | * [架設 K8s(下)](2021/day9.md)
96 | * [RKE 管理與操作](2021/day10.md)
97 | * [Monitoring 介紹](2021/day11.md)
98 | * Rancher 專案管理指南
99 | * [Project 基本概念介紹](2021/day12.md)
100 | * [Resource Quota 介紹](2021/day13.md)
101 | * Rancher 雜談
102 | * [其他事項](2021/day14.md)
103 | * [Rancher & Infrastructure as Code](2021/day15.md)
104 | * [Rancher 指令工具的操作](2021/day16.md)
105 | * Rancher 應用程式部署
106 | * [淺談 Rancher 的應用程式管理](2021/day17.md)
107 | * [Rancher Catalog 介紹(v2.0~v2.4)](2021/day18.md)
108 | * [Rancher App & Marketplace 介紹(v2.5)](2021/day19.md)
109 | * GitOps 部署
110 | * [淺談 GitOps ](2021/day20.md)
111 | * [GitOps 解決方案比較](2021/day21.md)
112 | * [Rancher Fleet 介紹](2021/day22.md)
113 | * [Fleet 環境架設與介紹](2021/day23.md)
114 | * [Fleet 玩轉第一個 GitOps](2021/day24.md)
115 | * [Fleet.yaml 檔案探討](2021/day25.md)
116 | * [Fleet Kubernetes 應用程式部署](2021/day26.md)
117 | * [Fleet Kustomize 應用程式部署](2021/day27.md)
118 | * [Fleet Helm 應用程式部署](2021/day28.md)
119 | * [Fleet Helm + Kustomize 應用程式部署](2021/day29.md)
120 | * [Summary](2021/day30.md)
--------------------------------------------------------------------------------
/gitbook/fonts/fontawesome/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/fonts/fontawesome/FontAwesome.otf
--------------------------------------------------------------------------------
/gitbook/fonts/fontawesome/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/fonts/fontawesome/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/gitbook/fonts/fontawesome/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/fonts/fontawesome/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/gitbook/fonts/fontawesome/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/fonts/fontawesome/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/gitbook/fonts/fontawesome/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/fonts/fontawesome/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/gitbook/gitbook-plugin-highlight/ebook.css:
--------------------------------------------------------------------------------
1 | pre,
2 | code {
3 | /* http://jmblog.github.io/color-themes-for-highlightjs */
4 | /* Tomorrow Comment */
5 | /* Tomorrow Red */
6 | /* Tomorrow Orange */
7 | /* Tomorrow Yellow */
8 | /* Tomorrow Green */
9 | /* Tomorrow Aqua */
10 | /* Tomorrow Blue */
11 | /* Tomorrow Purple */
12 | }
13 | pre .hljs-comment,
14 | code .hljs-comment,
15 | pre .hljs-title,
16 | code .hljs-title {
17 | color: #8e908c;
18 | }
19 | pre .hljs-variable,
20 | code .hljs-variable,
21 | pre .hljs-attribute,
22 | code .hljs-attribute,
23 | pre .hljs-tag,
24 | code .hljs-tag,
25 | pre .hljs-regexp,
26 | code .hljs-regexp,
27 | pre .hljs-deletion,
28 | code .hljs-deletion,
29 | pre .ruby .hljs-constant,
30 | code .ruby .hljs-constant,
31 | pre .xml .hljs-tag .hljs-title,
32 | code .xml .hljs-tag .hljs-title,
33 | pre .xml .hljs-pi,
34 | code .xml .hljs-pi,
35 | pre .xml .hljs-doctype,
36 | code .xml .hljs-doctype,
37 | pre .html .hljs-doctype,
38 | code .html .hljs-doctype,
39 | pre .css .hljs-id,
40 | code .css .hljs-id,
41 | pre .css .hljs-class,
42 | code .css .hljs-class,
43 | pre .css .hljs-pseudo,
44 | code .css .hljs-pseudo {
45 | color: #c82829;
46 | }
47 | pre .hljs-number,
48 | code .hljs-number,
49 | pre .hljs-preprocessor,
50 | code .hljs-preprocessor,
51 | pre .hljs-pragma,
52 | code .hljs-pragma,
53 | pre .hljs-built_in,
54 | code .hljs-built_in,
55 | pre .hljs-literal,
56 | code .hljs-literal,
57 | pre .hljs-params,
58 | code .hljs-params,
59 | pre .hljs-constant,
60 | code .hljs-constant {
61 | color: #f5871f;
62 | }
63 | pre .ruby .hljs-class .hljs-title,
64 | code .ruby .hljs-class .hljs-title,
65 | pre .css .hljs-rules .hljs-attribute,
66 | code .css .hljs-rules .hljs-attribute {
67 | color: #eab700;
68 | }
69 | pre .hljs-string,
70 | code .hljs-string,
71 | pre .hljs-value,
72 | code .hljs-value,
73 | pre .hljs-inheritance,
74 | code .hljs-inheritance,
75 | pre .hljs-header,
76 | code .hljs-header,
77 | pre .hljs-addition,
78 | code .hljs-addition,
79 | pre .ruby .hljs-symbol,
80 | code .ruby .hljs-symbol,
81 | pre .xml .hljs-cdata,
82 | code .xml .hljs-cdata {
83 | color: #718c00;
84 | }
85 | pre .css .hljs-hexcolor,
86 | code .css .hljs-hexcolor {
87 | color: #3e999f;
88 | }
89 | pre .hljs-function,
90 | code .hljs-function,
91 | pre .python .hljs-decorator,
92 | code .python .hljs-decorator,
93 | pre .python .hljs-title,
94 | code .python .hljs-title,
95 | pre .ruby .hljs-function .hljs-title,
96 | code .ruby .hljs-function .hljs-title,
97 | pre .ruby .hljs-title .hljs-keyword,
98 | code .ruby .hljs-title .hljs-keyword,
99 | pre .perl .hljs-sub,
100 | code .perl .hljs-sub,
101 | pre .javascript .hljs-title,
102 | code .javascript .hljs-title,
103 | pre .coffeescript .hljs-title,
104 | code .coffeescript .hljs-title {
105 | color: #4271ae;
106 | }
107 | pre .hljs-keyword,
108 | code .hljs-keyword,
109 | pre .javascript .hljs-function,
110 | code .javascript .hljs-function {
111 | color: #8959a8;
112 | }
113 | pre .hljs,
114 | code .hljs {
115 | display: block;
116 | background: white;
117 | color: #4d4d4c;
118 | padding: 0.5em;
119 | }
120 | pre .coffeescript .javascript,
121 | code .coffeescript .javascript,
122 | pre .javascript .xml,
123 | code .javascript .xml,
124 | pre .tex .hljs-formula,
125 | code .tex .hljs-formula,
126 | pre .xml .javascript,
127 | code .xml .javascript,
128 | pre .xml .vbscript,
129 | code .xml .vbscript,
130 | pre .xml .css,
131 | code .xml .css,
132 | pre .xml .hljs-cdata,
133 | code .xml .hljs-cdata {
134 | opacity: 0.5;
135 | }
136 |
--------------------------------------------------------------------------------
/gitbook/gitbook-plugin-lunr/search-lunr.js:
--------------------------------------------------------------------------------
1 | require([
2 | 'gitbook',
3 | 'jquery'
4 | ], function(gitbook, $) {
5 | // Define global search engine
6 | function LunrSearchEngine() {
7 | this.index = null;
8 | this.store = {};
9 | this.name = 'LunrSearchEngine';
10 | }
11 |
12 | // Initialize lunr by fetching the search index
13 | LunrSearchEngine.prototype.init = function() {
14 | var that = this;
15 | var d = $.Deferred();
16 |
17 | $.getJSON(gitbook.state.basePath+'/search_index.json')
18 | .then(function(data) {
19 | // eslint-disable-next-line no-undef
20 | that.index = lunr.Index.load(data.index);
21 | that.store = data.store;
22 | d.resolve();
23 | });
24 |
25 | return d.promise();
26 | };
27 |
28 | // Search for a term and return results
29 | LunrSearchEngine.prototype.search = function(q, offset, length) {
30 | var that = this;
31 | var results = [];
32 |
33 | if (this.index) {
34 | results = $.map(this.index.search(q), function(result) {
35 | var doc = that.store[result.ref];
36 |
37 | return {
38 | title: doc.title,
39 | url: doc.url,
40 | body: doc.summary || doc.body
41 | };
42 | });
43 | }
44 |
45 | return $.Deferred().resolve({
46 | query: q,
47 | results: results.slice(0, length),
48 | count: results.length
49 | }).promise();
50 | };
51 |
52 | // Set gitbook research
53 | gitbook.events.bind('start', function(e, config) {
54 | var engine = gitbook.search.getEngine();
55 | if (!engine) {
56 | gitbook.search.setEngine(LunrSearchEngine, config);
57 | }
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/gitbook/gitbook-plugin-search/search-engine.js:
--------------------------------------------------------------------------------
1 | require([
2 | 'gitbook',
3 | 'jquery'
4 | ], function(gitbook, $) {
5 | // Global search objects
6 | var engine = null;
7 | var initialized = false;
8 |
9 | // Set a new search engine
10 | function setEngine(Engine, config) {
11 | initialized = false;
12 | engine = new Engine(config);
13 |
14 | init(config);
15 | }
16 |
17 | // Initialize search engine with config
18 | function init(config) {
19 | if (!engine) throw new Error('No engine set for research. Set an engine using gitbook.research.setEngine(Engine).');
20 |
21 | return engine.init(config)
22 | .then(function() {
23 | initialized = true;
24 | gitbook.events.trigger('search.ready');
25 | });
26 | }
27 |
28 | // Launch search for query q
29 | function query(q, offset, length) {
30 | if (!initialized) throw new Error('Search has not been initialized');
31 | return engine.search(q, offset, length);
32 | }
33 |
34 | // Get stats about search
35 | function getEngine() {
36 | return engine? engine.name : null;
37 | }
38 |
39 | function isInitialized() {
40 | return initialized;
41 | }
42 |
43 | // Initialize gitbook.search
44 | gitbook.search = {
45 | setEngine: setEngine,
46 | getEngine: getEngine,
47 | query: query,
48 | isInitialized: isInitialized
49 | };
50 | });
--------------------------------------------------------------------------------
/gitbook/gitbook-plugin-search/search.css:
--------------------------------------------------------------------------------
1 | /*
2 | This CSS only styled the search results section, not the search input
3 | It defines the basic interraction to hide content when displaying results, etc
4 | */
5 | #book-search-results .search-results {
6 | display: none;
7 | }
8 | #book-search-results .search-results ul.search-results-list {
9 | list-style-type: none;
10 | padding-left: 0;
11 | }
12 | #book-search-results .search-results ul.search-results-list li {
13 | margin-bottom: 1.5rem;
14 | padding-bottom: 0.5rem;
15 | /* Highlight results */
16 | }
17 | #book-search-results .search-results ul.search-results-list li p em {
18 | background-color: rgba(255, 220, 0, 0.4);
19 | font-style: normal;
20 | }
21 | #book-search-results .search-results .no-results {
22 | display: none;
23 | }
24 | #book-search-results.open .search-results {
25 | display: block;
26 | }
27 | #book-search-results.open .search-noresults {
28 | display: none;
29 | }
30 | #book-search-results.no-results .search-results .has-results {
31 | display: none;
32 | }
33 | #book-search-results.no-results .search-results .no-results {
34 | display: block;
35 | }
36 |
--------------------------------------------------------------------------------
/gitbook/gitbook-plugin-sharing/buttons.js:
--------------------------------------------------------------------------------
1 | require(['gitbook', 'jquery'], function(gitbook, $) {
2 | var SITES = {
3 | 'facebook': {
4 | 'label': 'Facebook',
5 | 'icon': 'fa fa-facebook',
6 | 'onClick': function(e) {
7 | e.preventDefault();
8 | window.open('http://www.facebook.com/sharer/sharer.php?s=100&p[url]='+encodeURIComponent(location.href));
9 | }
10 | },
11 | 'twitter': {
12 | 'label': 'Twitter',
13 | 'icon': 'fa fa-twitter',
14 | 'onClick': function(e) {
15 | e.preventDefault();
16 | window.open('http://twitter.com/home?status='+encodeURIComponent(document.title+' '+location.href));
17 | }
18 | },
19 | 'google': {
20 | 'label': 'Google+',
21 | 'icon': 'fa fa-google-plus',
22 | 'onClick': function(e) {
23 | e.preventDefault();
24 | window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href));
25 | }
26 | },
27 | 'weibo': {
28 | 'label': 'Weibo',
29 | 'icon': 'fa fa-weibo',
30 | 'onClick': function(e) {
31 | e.preventDefault();
32 | window.open('http://service.weibo.com/share/share.php?content=utf-8&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title));
33 | }
34 | },
35 | 'instapaper': {
36 | 'label': 'Instapaper',
37 | 'icon': 'fa fa-instapaper',
38 | 'onClick': function(e) {
39 | e.preventDefault();
40 | window.open('http://www.instapaper.com/text?u='+encodeURIComponent(location.href));
41 | }
42 | },
43 | 'vk': {
44 | 'label': 'VK',
45 | 'icon': 'fa fa-vk',
46 | 'onClick': function(e) {
47 | e.preventDefault();
48 | window.open('http://vkontakte.ru/share.php?url='+encodeURIComponent(location.href));
49 | }
50 | }
51 | };
52 |
53 |
54 |
55 | gitbook.events.bind('start', function(e, config) {
56 | var opts = config.sharing;
57 |
58 | // Create dropdown menu
59 | var menu = $.map(opts.all, function(id) {
60 | var site = SITES[id];
61 |
62 | return {
63 | text: site.label,
64 | onClick: site.onClick
65 | };
66 | });
67 |
68 | // Create main button with dropdown
69 | if (menu.length > 0) {
70 | gitbook.toolbar.createButton({
71 | icon: 'fa fa-share-alt',
72 | label: 'Share',
73 | position: 'right',
74 | dropdown: [menu]
75 | });
76 | }
77 |
78 | // Direct actions to share
79 | $.each(SITES, function(sideId, site) {
80 | if (!opts[sideId]) return;
81 |
82 | gitbook.toolbar.createButton({
83 | icon: site.icon,
84 | label: site.text,
85 | position: 'right',
86 | onClick: site.onClick
87 | });
88 | });
89 | });
90 | });
91 |
--------------------------------------------------------------------------------
/gitbook/images/apple-touch-icon-precomposed-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/images/apple-touch-icon-precomposed-152.png
--------------------------------------------------------------------------------
/gitbook/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwchiu/ithome/ba815c4c33fb8030c9c9788004c27b9445b7a5b9/gitbook/images/favicon.ico
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp');
2 | const gulpLoadPlugins = require('gulp-load-plugins');
3 | const sitemap = require('gulp-sitemap');
4 |
5 | const $ = gulpLoadPlugins();
6 |
7 | gulp.task('publish', () => {
8 | console.log('Publish Gitbook (_book) to Github Pages');
9 | gulp.src('./_book/*/**/*.html', {
10 | read: false
11 | })
12 | .pipe(sitemap({
13 | siteUrl: 'http://ithome.hwchiu.com'
14 | }))
15 | .pipe(gulp.dest('./_book/'));
16 |
17 | return gulp.src('./_book/**/*')
18 | .pipe($.ghPages({
19 | origin: 'origin',
20 | branch: 'gh-pages'
21 | }));
22 | });
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ithome-ironman",
3 | "version": "1.0.0",
4 | "description": "ITHOME 鐵人 30 的文章原始檔案 ==================================",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/hwchiu/ithome-ironman.git"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "bugs": {
16 | "url": "https://github.com/hwchiu/ithome-ironman/issues"
17 | },
18 | "homepage": "https://github.com/hwchiu/ithome-ironman#readme",
19 | "dependencies": {
20 | "gulp": "^4.0.2",
21 | "gulp-gh-pages": "^0.5.4",
22 | "gulp-load-plugins": "^2.0.4"
23 | },
24 | "devDependencies": {
25 | "gulp-sitemap": "^7.6.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | http://ithome.hwchiu.com/2019/container/day2.html
6 |
7 |
8 | 2020-09-06T05:38:18.288Z
9 |
10 |
11 |
12 |
13 | http://ithome.hwchiu.com/2019/container/day3.html
14 |
15 |
16 | 2020-09-06T05:38:18.378Z
17 |
18 |
19 |
20 |
21 | http://ithome.hwchiu.com/2019/container/day4.html
22 |
23 |
24 | 2020-09-06T05:38:18.460Z
25 |
26 |
27 |
28 |
29 | http://ithome.hwchiu.com/2019/device-plugin/day23.html
30 |
31 |
32 | 2020-09-06T05:38:19.582Z
33 |
34 |
35 |
36 |
37 | http://ithome.hwchiu.com/2019/device-plugin/day24.html
38 |
39 |
40 | 2020-09-06T05:38:19.636Z
41 |
42 |
43 |
44 |
45 | http://ithome.hwchiu.com/2019/device-plugin/day25.html
46 |
47 |
48 | 2020-09-06T05:38:19.683Z
49 |
50 |
51 |
52 |
53 | http://ithome.hwchiu.com/2019/device-plugin/day26.html
54 |
55 |
56 | 2020-09-06T05:38:19.732Z
57 |
58 |
59 |
60 |
61 | http://ithome.hwchiu.com/2019/extension/day27.html
62 |
63 |
64 | 2020-09-06T05:38:19.778Z
65 |
66 |
67 |
68 |
69 | http://ithome.hwchiu.com/2019/extension/day28.html
70 |
71 |
72 | 2020-09-06T05:38:19.825Z
73 |
74 |
75 |
76 |
77 | http://ithome.hwchiu.com/2019/network/day10.html
78 |
79 |
80 | 2020-09-06T05:38:18.873Z
81 |
82 |
83 |
84 |
85 | http://ithome.hwchiu.com/2019/network/day11.html
86 |
87 |
88 | 2020-09-06T05:38:18.925Z
89 |
90 |
91 |
92 |
93 | http://ithome.hwchiu.com/2019/network/day12.html
94 |
95 |
96 | 2020-09-06T05:38:18.983Z
97 |
98 |
99 |
100 |
101 | http://ithome.hwchiu.com/2019/network/day13.html
102 |
103 |
104 | 2020-09-06T05:38:19.039Z
105 |
106 |
107 |
108 |
109 | http://ithome.hwchiu.com/2019/network/day14.html
110 |
111 |
112 | 2020-09-06T05:38:19.094Z
113 |
114 |
115 |
116 |
117 | http://ithome.hwchiu.com/2019/network/day15.html
118 |
119 |
120 | 2020-09-06T05:38:19.145Z
121 |
122 |
123 |
124 |
125 | http://ithome.hwchiu.com/2019/network/day16.html
126 |
127 |
128 | 2020-09-06T05:38:19.205Z
129 |
130 |
131 |
132 |
133 | http://ithome.hwchiu.com/2019/network/day17.html
134 |
135 |
136 | 2020-09-06T05:38:19.259Z
137 |
138 |
139 |
140 |
141 | http://ithome.hwchiu.com/2019/overview/day1.html
142 |
143 |
144 | 2020-09-06T05:38:18.210Z
145 |
146 |
147 |
148 |
149 | http://ithome.hwchiu.com/2019/runtime/day5.html
150 |
151 |
152 | 2020-09-06T05:38:18.531Z
153 |
154 |
155 |
156 |
157 | http://ithome.hwchiu.com/2019/runtime/day6.html
158 |
159 |
160 | 2020-09-06T05:38:18.611Z
161 |
162 |
163 |
164 |
165 | http://ithome.hwchiu.com/2019/runtime/day7.html
166 |
167 |
168 | 2020-09-06T05:38:18.674Z
169 |
170 |
171 |
172 |
173 | http://ithome.hwchiu.com/2019/runtime/day8.html
174 |
175 |
176 | 2020-09-06T05:38:18.743Z
177 |
178 |
179 |
180 |
181 | http://ithome.hwchiu.com/2019/runtime/day9.html
182 |
183 |
184 | 2020-09-06T05:38:18.812Z
185 |
186 |
187 |
188 |
189 | http://ithome.hwchiu.com/2019/security/day29.html
190 |
191 |
192 | 2020-09-06T05:38:19.869Z
193 |
194 |
195 |
196 |
197 | http://ithome.hwchiu.com/2019/storage/day18.html
198 |
199 |
200 | 2020-09-06T05:38:19.305Z
201 |
202 |
203 |
204 |
205 | http://ithome.hwchiu.com/2019/storage/day19.html
206 |
207 |
208 | 2020-09-06T05:38:19.352Z
209 |
210 |
211 |
212 |
213 | http://ithome.hwchiu.com/2019/storage/day20.html
214 |
215 |
216 | 2020-09-06T05:38:19.419Z
217 |
218 |
219 |
220 |
221 | http://ithome.hwchiu.com/2019/storage/day21.html
222 |
223 |
224 | 2020-09-06T05:38:19.473Z
225 |
226 |
227 |
228 |
229 | http://ithome.hwchiu.com/2019/storage/day22.html
230 |
231 |
232 | 2020-09-06T05:38:19.528Z
233 |
234 |
235 |
236 |
237 | http://ithome.hwchiu.com/2019/summary/day30.html
238 |
239 |
240 | 2020-09-06T05:38:19.911Z
241 |
242 |
243 |
--------------------------------------------------------------------------------