antony@notes:~/kubernetes$ cat "Kubernetes-First-Steps.md"
Kubernetes-First-Steps
Kubernetes-First-Steps
:::warning
:::spoiler 目錄
[TOC]
:::
建立 K8S 應用物件方式
kubectl run(命令式 Imperative) - Manage K8s object (POD, Controller, Service) using CLI- 透過以上命令式建立 pod 能做到的功能是有限的。
- e.g., 像要讓 pod 到指定 node 去 run 是做不到的; K8S 還有很多物件是無法用
kubeclt run的方法產生 kubectl run(Imperative) 這命令適合做概念性(物件的雛形)驗證 (Proof of Concept;POC)- 結論 :
kubeclt run的方法 對於 K8S 能產生和設定多少物件是有限的
kubectl create/apply(聲明式 Declarative) - By defining K8s objects in yaml file- K8S 產生物件的正規做法,但有個必要條件,須先設計 yaml 檔,才能產生對應的物件
kubectl create(Declarative) 與 yaml 設定檔適合建立複雜的企業應用服務
- “Imperative” is a command - like “create 42 widgets”.
- “Declarative” is a statement of the desired end result - like “I want 42 widgets to exist”.
- For creating multiple complex object, declarative approach is preferred as it follows Infrastructure as a Code approach. However, imperative approach is also useful when we want to do quick POC and save yourself from writing yaml files. Let’s take a look at some imperative commands.
Using Namespace
- 在 K8S 裡的 Namespace ,可以想像成大樓裡的辦公室,裡面可以有很多人 (Container),辦公室中還可以有很多桌子、椅子和影印機…等物件(pod, deployment, Service…等)
- Partition Cluster resources.
- Kubernetes Namespaces can be used to divide a cluster into logical partitions allowing a single large Kubernetes cluster to be used by multiple users and teams, or a single user with multiple applications. Each user, team, or application running in a Namespace, is isolated from every other user, team, or application in other Namespaces and they operate as if they are the sole user of the cluster (note that Namespaces do not provide network segmentation).
- Namespaces 有以下幾個特點
- 在同一個 Kubernetes Cluster 中,每個 Namespaces 的名稱都是要獨特的
- 當一個 Namespaces 被刪除時,在該 Namespace 裡的所有物件也會被刪除
- 注意!只會刪除 K8S 產生的物件,如果 K8S 的物件有產生檔案或目錄是不會被刪除的。
- 可以透過 Resource Quotas 限制一個 Namespaces 所可以存取的資源
- 不只限制可用的運算資源,還能限制 K8S 的物件
- 有防火牆的機制,可以允許或禁止 pod 連到另一個 Namespace 的 pod ,或是讓一個 pod 可以上網
- 結論 : K8S 的物件一定要指定一個 Namespace 給它 run。開發應用系統必定會建立專案目錄, 設計 K8S Application 需在 Namespace, 來運作
檢視 K8S 當前所有 Namespace 的資訊
$ kubectl get ns
NAME STATUS AGE
default Active 10d
kube-flannel Active 10d
kube-node-lease Active 10d
kube-public Active 10d
kube-system Active 10ddefault,預設的 Namespaces 名稱為 default,過去我們產生的物件像是, Deployment, Services 等若沒特別指定 Namespace 都是存放在名稱為 default 的 namespaces 中。kube-public,是個特殊的 namespace,存放在裡面的物件可被所有的使用者讀取。
$ kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-6d4b75cb6d-tslq8 1/1 Running 5 10d
coredns-6d4b75cb6d-vqz9h 1/1 Running 5 10d
etcd-m1 1/1 Running 5 10d
kube-apiserver-m1 1/1 Running 5 10d
kube-controller-manager-m1 1/1 Running 5 10d
kube-proxy-274g9 1/1 Running 4 10d
kube-proxy-kqlrm 1/1 Running 4 10d
kube-proxy-zw6sb 1/1 Running 5 10d
kube-scheduler-m1 1/1 Running 5 10dkube-system,在 Kubernetes 中,較特別的資源都會存放在 kube-system 這個 namespace。若是用kubectl get all -n kube-system查看,可以發現 kube-dns 或是 kube-apiserver…等維運系統的 pod 都是存放在該 namepsace 中。- Namespace 參考文章連結 : https://ithelp.ithome.com.tw/m/articles/10197186
K8S default Namespace
$ kubectl create deployment --image quay.io/cloudwalker/nginx demo-nginx
deployment.apps/demo-nginx created
$ kubectl describe deployment demo-nginx | grep Namespace
Namespace: default
$ kubectl create deployment --image quay.io/cloudwalker/nginx demo-nginx
Error from server (AlreadyExists): deployments.apps "demo-nginx" already exists
$ kubectl create deployment --image quay.io/cloudwalker/nginx demo-nginx -n kube-publicAssigning Pods to Namespace
# 建立工作目錄
$ mkdir -p ~/wulin/yaml; cd ~/wulin
# 建立新的 namespace
$ kubectl create namespace myoffice
namespace/myoffice created
# 檢查有無建立成功
$ kubectl get namespace
NAME STATUS AGE
default Active 10d
kube-flannel Active 10d
kube-node-lease Active 10d
kube-public Active 10d
kube-system Active 10d
myoffice Active 2s
# 刪除 myoffice namespace
$ kubectl delete namespace myoffice
# 再次建立 myoffice namespace
$ kubeclt create namespace myoffice
# 檢查
$ kubectl get namespace建立 pod
$ kubectl run n1 --image=quay.io/cloudwalker/alpine -n myoffice -- sleep infinitykubectl run,用指定 image 產生 podn1,pod 的名字-n myoffice,指定等等的 pod 會建在 myoffice 這個 namespace-- sleep infinity,--後面放的是 Container 要執行的程式 ,這裡是sleep infinity- forever sleeping ( never awake until escape )
檢視 pod 的狀態
$ kg pods
NAME READY STATUS RESTARTS AGE
gocgi 1/1 Running 1 20h
mydb 1/1 Running 1 21h
pod1 1/1 Running 1 16h- 這裡看到的是在 default namespace 的 pod 資訊
$ kg pods -n myoffice
NAME READY STATUS RESTARTS AGE
n1 1/1 Running 0 22m- 這裡看到的是 myoffice 這個 namespace 裡面 pod 資訊
$ kubectl exec -it n1 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
Error from server (NotFound): pods "n1" not found- 錯誤訊息翻譯:
kubectl exec [POD] [COMMAND],這個用法以被棄用,且即將在未來的版本被刪除- 要使用
kubectl exec [POD] -- [COMMAND],Command 前面要加-- Error from server (NotFound): pods "n1" not found,找不到 n1 這台 pod,因未指定 Namespace 的話,預設會到 default 這個 namespace 裡面找有沒有 n1 這個 pod
- 用法須更正為:
kubectl exec -it n1 -n myoffice -- sh
$ kubectl exec -it -n myoffice n1 -- sh
/ # ping -c 1 www.hinet.net
PING www.hinet.net (163.28.83.113): 56 data bytes
ping: permission denied (are you root?)
# 檢視 NameServer 是誰
/ # cat /etc/resolv.conf
search myoffice.svc.k8s.org svc.k8s.org k8s.org localdomain
nameserver 10.98.0.10
options ndots:5
/ # exitnameserver 10.98.0.10,這是 K8S 的 DNS Server- 它會幫我們把
www.hinet.net這個名稱丟到網路去問,最後解析出163.28.83.113這個 IP 位址 ping: permission denied (are you root?),權限不足,Linux Capaibility 不給權限
用 yaml 檔建立 pod
$ nano ~/wulin/yaml/pod-n2.yamlapiVersion: v1
kind: Pod
metadata:
name: n2
namespace: myoffice
labels:
name: n2
spec:
hostname: n2
containers:
- image: quay.io/cloudwalker/busybox
command:
- sleep
- "60"
name: n2kind,指定要建立 pod 這個物件metadata,設定重要資訊name: n2,pod 名字 : n2namespace,設定 pod 所在的 namespace : myofficelabels,pod 上貼一個標籤
spec,設定 pod 內部的結構hostname: n2,設定 Container 的 hostname,多個 Container 也會共用同一個 hostnamecontaienrs,設定 Container 的資訊command,container 要先執行的命令- yaml 檔中的
command:這個宣告, 會覆蓋掉 image 的內定命令, 包括 entrypoint 指定的命令
- yaml 檔中的
name,設定 Container 在系統上的名稱
apply 它
$ kubectl apply -f ~/wulin/yaml/pod-n2.yaml檢查是否符合預期
$ kubectl get pods -n myoffice
NAME READY STATUS RESTARTS AGE
n1 1/1 Running 0 61m
n2 1/1 Running 0 14s切換 Namespace
$ kubectl config set-context --current --namespace=myofficeset-context,進入 K8S 的路口set-context,入口的意思,進入商業辦公大樓的大門--current,入口指定預設的入口,因為進入的方法有很多種,我們就走預設的入口--namespace=myoffice,進到 myoffice 這個 namespace
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
n1 1/1 Running 0 25m
n2 1/1 Running 5 (105s ago) 8m32s
$ cat ~/.kube/config | grep -A 6 contexts:
contexts:
- context:
cluster: kubernetes
namespace: myoffice
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes~/.kube/config,進入 K8S 這棟大樓的磁卡 (裡面記錄著使用者在 K8S 的名字和識別代號,及擁有多大的權限可以對 K8S 的物件進行訪問…等資訊)contexts,大樓的入口,後面加s是因為可能會有很多入口context,大樓的入口cluster: kubernetes,大樓的名字 :kubernetesnamespace: myoffice,大樓裡的辦公室名字:myofficeuser: kubernetes-admin,使用者進入大樓辦公室用的身分名稱
$ cat ~/.kube/config | grep users -A1
users:
- name: kubernetes-admin- 在 K8S 系統中,我們 bigred 的帳號,是 kubernetes-admin (由
~/.kube/config這個檔案得知)
OpenSSH 實務應用
Container Image 設計與建立
在 m1 終端機, 執行以下命令
$ mkdir -p ~/wulin/{sshd,fbs}
$ echo $'FROM quay.io/cloudwalker/alpine
RUN apk update && apk upgrade && apk add --no-cache nano sudo wget curl \
tree elinks bash shadow procps util-linux git coreutils binutils \
findutils grep openssh-server tzdata && \
# 設定時區
cp /usr/share/zoneinfo/Asia/Taipei /etc/localtime && \
ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key && \
echo -e \'Welcome to ALP sshd 6000\\n\' > /etc/motd && \
# 建立管理者帳號 bigred
adduser -s /bin/bash -h /home/bigred -G wheel -D bigred && \
echo "%wheel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
echo -e \'bigred\\nbigred\\n\' | passwd bigred &>/dev/null && \
rm /sbin/reboot && rm /usr/bin/killall
EXPOSE 22
ENTRYPOINT ["/usr/sbin/sshd"]
CMD ["-D"]' > ~/wulin/sshd/DockerfileENTRYPOINT ["/usr/sbin/sshd"],強制宣告等下 run 的 Container 等等只能跑/usr/sbin/sshd這個命令CMD ["-D"],上面命令的參數
Container Image 建立與測試
$ sudo podman build -t alp.sshd ~/wulin/sshd/
$ sudo podman images | grep alp.sshd
localhost/alp.sshd latest 01424a71e3d6 3 minutes ago 67.6 MB
$ sudo podman run --name a1 -h a1 -d -p 22100:22 alp.sshd
220ce94e636ce9270604bd31a7dd5d515be6008ab6351295cd10a66da5d978d1
$ ssh bigred@$IP -p 22100
bigred@192.168.61.4 s password: bigred
Welcome to ALP sshd 6000
a1:~$ git version
git version 2.30.2
a1:~$ exit
$ sudo podman rm -f a1第一次接觸 Kubernetes App
建立 K8S 應用物件方式
kubectl run(命令式 Imperative) - Manage K8s object (POD, Controller, Service) using CLIkubectl create/apply(聲明式 Declarative) - By defining K8s objects in yaml file- yaml ,全名 : Yet Another Markup Language ( 因為不用再看到 xml 檔了 )
For creating multiple complex object, declarative approach is preferred as it follows Infrastructure as a Code approach. However, imperative approach is also useful when we want to do quick POC and save yourself from writing yaml files. Let’s take a look at some imperative commands.
kubectl run (Imperative) 這命令適合做概念性驗證 (Proof of Concept;POC), kubectl create (Declarative) 與 yaml 設定檔適合建立複雜的企業應用服務
建立 Demo App
# 建立一個 pod ,image 用的是 alp.sshd
$ kubectl run demo --image=alp.sshd
[註] 從 1.18 這個版本開始, 上面命令只會產生 pod, 不再會產生 deployment object 及 replicaset controller.
# 為何 pod 會建立失敗 ? ErrImagePull ?
$ kg pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo 0/1 ErrImagePull 0 13s 10.244.2.5 w2 <none> <none>
# 因為在我們的工作主機上,沒有這片 image,所以先刪除 pod
# --force ,強制刪除
$ kubectl delete pods demo --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "demo" force deleted
# 打包 alp.sshd 這個 image
$ sudo podman save alp.sshd > alp.sshd.tar
# 將打包檔拷貝到 w1 和 w2 主機
$ scp alp.sshd.tar w1:alp.sshd.tar; scp alp.sshd.tar w2:alp.sshd.tar
# 在 w1 和 w2 主機,將打包檔的 image 還原
$ ssh w1 'sudo podman load < alp.sshd.tar'
$ ssh w2 'sudo podman load < alp.sshd.tar'
# 再 run 一次 pod
# --image-pull-policy IfNotPresent ,如果本地端有 image 就不用上網下載了
$ kubectl run demo --image-pull-policy IfNotPresent --image=localhost/alp.sshd
pod/demo created
# 以下命令會失敗的原因是因為, image 前面不加 localhost ,就會上網飆到 docker.io/library 抓 image
$ kubectl run demo --image=alp.sshd
# 其實不加 --image-pull-policy IfNotPresent 也會過
$ kubectl run demo --image=localhost/alp.sshd
# 檢查是否符合預期
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo 1/1 Running 0 3m12s 10.244.2.2 w2 <none> <none>建立 OpenSSH Pod
編輯 sshd yaml 檔
$ nano ~/wulin/sshd/pod-sshd.yamlapiVersion: v1
kind: Pod
metadata:
name: pod-sshd
spec:
containers:
- name: mysshd
image: localhost/alp.sshd
imagePullPolicy: IfNotPresent
command:
- /bin/bash
- -c
- |
adduser -s /bin/bash -h /home/rbean rbean
echo -e 'rbean\nrbean\n' | passwd rbean
/usr/sbin/sshd -D- 在 K8S yaml 檔的
command能破格 Dockerfile 設定的ENTRYPOINT,讓 Container 跑command宣告的命令 - 但是 Container run 的程式還是要在前景執行
- 所以
command最後還是要宣告/usr/sbin/sshd -D,讓 Container 有個SSH Server一直在前景執行的命令 /bin/bash -c,c的意思是 command,合起來就是讓 bash 貝殼程式跑下面的命令|,這裡的 pipe 意思是會保留以下宣告命令的格式,有空格就空格,有換行就換行,通通保留,如果沒有宣告,貝殼程式會把下面 3 行命令當成一行
用 apply 產生 pod
$ kubectl apply -f ~/wulin/sshd/pod-sshd.yaml檢查 pod 狀態
$ kg po pod-sshd -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-sshd 1/1 Running 0 2m 10.244.1.37 w1 <none> <none>SSH 連線測試 pod 功能
$ ssh rbean@10.244.1.37
rbean@10.244.1.37s password:
Welcome to ALP sshd 6000
# 建立 zzz 目錄
pod-sshd:~$ mkdir zzz
pod-sshd:~$ ls -ld zzz
drwxr-sr-x 2 rbean rbean 4096 Sep 1 09:49 zzz
pod-sshd:~$ exit
logout
Connection to 10.244.1.37 closed.刪除 pod
$ kubectl delete pod pod-sshd
pod "pod-sshd" deleted再次建立 pod
$ kubectl apply -f ~/wulin/sshd/pod-sshd.yaml
pod/pod-sshd created連進 pod 檢視 zzz 目錄是否還在 ?
$ kubectl get pod pod-sshd -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-sshd 1/1 Running 0 73s 10.244.1.38 w1 <none> <none>
# 用 rbean 帳號連進 pod
$ ssh rbean@10.244.1.38
Warning: Permanently added '10.244.1.38' (RSA) to the list of known hosts.
rbean@10.244.1.38s password:
Welcome to ALP sshd 6000
# 檢視剛剛建立的目錄
pod-sshd:~$ ls -l
total 0- 結論 : pod 只要沒有動用 volume ,當 pod 被刪除時,資料通通消失
將 pod 所在的 w1 這台機器重開機
$ ssh w1 'sudo reboot'再次檢視 pod 狀態
$ kubectl get pods pod-sshd -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-sshd 1/1 Running 1 20m 10.244.1.39 w1 <none> <none>- 發現 pod 重新建立,Pod_IP 變了,資料也沒啦 !
- 在 K8S 的系統中,只要 node 主機重開,它上面 run 的 pod 都會浴火重生(重建),pod 沒有 volume 的話,資料通通再見 !
Access Kubernetes Pods from outside
編輯 yaml 檔
$ nano ~/wulin/yaml/podhostport.yamlapiVersion: v1
kind: Pod
metadata:
name: podhostport
spec:
containers:
- name: wk01
image: quay.io/cloudwalker/alpine.sshd
imagePullPolicy: IfNotPresent
ports:
- containerPort: 22
hostPort: 22101
securityContext:
capabilities:
add: ["AUDIT_WRITE", "SYS_CHROOT", "CAP_NET_RAW"]
command: ["/usr/sbin/sshd"]
args: ["-D"]
nodeSelector:
kubernetes.io/hostname: w1image:,Container 的 image 可以換裝成localhost/alp.sshdhostport: 22101,kube-proxy會在 pod 所在主機開一個 22101 的 port,對應到 pod 裡 Container 開的 22 port,效能優於kubectl port-forward- :::spoiler hostport 示意圖
::: nodeselector,透過 node 上的 labels 來決定 pod 要建在哪台 node 上
讓 mydb pod 也用 hostport 開
先建立工作目錄
$ mkdir -p ~/wulin/mydb/編輯 yaml 檔
$ nano wulin/mydb/pod-mydb.yamlapiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: mydb
name: mydb
spec:
containers:
- image: localhost/mydb
name: mydb
ports:
- containerPort: 3306
hostPort: 3306
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}產生 pod
$ ka -f wulin/mydb/pod-mydb.yaml
pod/mydb created檢視 Linux capabilities
- Linux capabilities ,規範 Container 可以做什麼事,而規範 Container 等同於規範 pod
$ crio-status config
output :
...
default_capabilities = ["CHOWN", "DAC_OVERRIDE", "FSETID", "FOWNER", "SETGID", "SETUID", "SETPCAP", "NET_BIND_SERVICE", "AUDIT_WRITE", "SYS_CHROOT", "KILL"]
...NET_BIND_SERVICE,如果 Container 要開的 port number 小於 1024 ,會需要有這個 CapabilitiesSSH通訊協定一定會需要 “AUDIT_WRITE”, “SYS_CHROOT” 這兩個 Capabilities,才能讓 CRI-O 做出來的 Container run openssh 的時候,能夠讓 openssh Server 與外部連接,給別人從外面連進來,如果沒有以上兩個 Capabilities ,即使要用 root 去登入也沒用。設定後要記得重新開機。
CRI-O 規範 Linux capabilities 的檔案
$ sudo nano /etc/crio/crio.conf
output :
[crio.runtime]
.......
default_capabilities = [
"CHOWN",
"DAC_OVERRIDE",
"FSETID",
"FOWNER",
"SETGID",
"SETUID",
"SETPCAP",
"NET_BIND_SERVICE",
"AUDIT_WRITE",
"SYS_CHROOT",
"KILL"
]
.......++讓 demo 這個 pod 安裝 libcap 套件++
$ kubectl exec demo -- sudo apk add libcap--,兩個-後面接的命令就是要給 pod 執行
如果這行安裝失敗,可以進入 pod 的 Container 將 nameserver 的設定檔 (
/etc/resolv.conf),新增一行nameserver 8.8.8.8
++查看 demo 這個 pod 裡面的 Container 裡面有哪些 Linux capabilities++
$ kubectl exec demo -- sudo capsh --print
output :
Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_sys_chroot,cap_audit_write=ep
...連接與移除 Demo App
# K8S 叢集內連接 demo app,k8s 叢集內部的網路連線全程都會加密
# -it ,給一個虛擬終端機
# -- bash ,跑 bash 貝殼程式
$ kubectl exec -it pods/demo -- bash
bash-5.1# exit
# 檢視 demo 這個 pod 的 IP 位址
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo 1/1 Running 0 26m 10.244.2.2 w2 <none> <none>
# ssh 連進 demo 這個 pod
bigred@m1:~$ ssh bigred@10.244.2.2
Warning: Permanently added '10.244.2.2' (RSA) to the list of known hosts.
bigred@10.244.2.2 s password:
Welcome to ALP sshd 6000
# 離開 pod
demo:~$ exit
# K8S 叢集外連接 demo app
# --address 只能指定 Master 的 IP 位址
$ kubectl port-forward --address $IP pods/demo 22100:22 &
[1] 27780
# 在 Windows 系統的 cmd 視窗, 執行以下命令
$ ssh bigred@<alp.m1 IP> -p 22100
Handling connection for 22100
bigred@192.168.61.4 s password: bigred
Welcome to ALP sshd 6000
# 離開 pod
demo:~$ exit
# 移除 pod
$ kubectl delete pod demo以上動作運作架構圖

第一次接觸 YAML File
建立 OpenSSH Pod
# 建立專案目錄,編輯 yaml 檔
$ cd ~/wulin; nano sshd/pod-sshd.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-sshd
spec:
containers:
- name: mysshd
image: localhost/alp.sshd
imagePullPolicy: IfNotPresentapiVersion: v1,這行是跟 API Server 說,我們的 yaml 檔是 v1 ,這行的設定由 K8s 的版本來決定kind: Pod, 設定 K8s 的物件metadata: name: pod-sshd ---> 設定 pod 的名字 spec: containers: - name: mysshd ---> 設定 Container 的名稱 image: localhost/alp.sshd ---> 設定 Container 用哪片 image imagePullPolicy: IfNotPresent ---> 如果本地端有這片 image,不用上網下載imagePullPolicy: Never,不要上網下載 image
# apply yaml 檔,建立 pod
$ kubectl apply -f sshd/pod-sshd.yaml
# 檢查是否符合預期
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo 1/1 Running 0 126m 10.244.2.2 w2 <none> <none>
pod-sshd 1/1 Running 0 13s 10.244.1.3 w1 <none> <none>10.244.1.3,看到這個 IP 位址 ,就知道 Flannel 網路套件在做事,將我們的 pod 分配到第一台工作機
再次修改 yaml 檔
$ nano sshd/pod-sshd.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-sshd
spec:
containers:
- name: mysshd
image: localhost/alp.sshd
imagePullPolicy: IfNotPresent
command:
- /bin/bash
- -c
- |
adduser -s /bin/bash -h /home/rbean rbean
echo -e 'rbean\nrbean\n' | passwd rbean
/usr/sbin/sshd -Dcommand:,在 K8s 的 yaml 檔中宣告一段等下 Container 要跑的 shell script ,即使 Container 的 image 本身有ENTRYPOINT ["/usr/sbin/sshd"],一樣會被破格,強制要跑命令
建立 File Browser Server
$ cd ~/wulin/
$ nano fbs/Dockerfile
FROM quay.io/cloudwalker/alpine
RUN apk update && apk upgrade && apk add --no-cache nano sudo wget curl \
tree elinks bash shadow procps util-linux coreutils binutils findutils grep && \
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash && \
# 設定 filebrowser
filebrowser config init --port 4000 --address "" --log "/tmp/fbs" --root="/srv" && \
# 建立管理者帳號
filebrowser users add admin "admin" --perm.admin=true
CMD ["filebrowser"]curl -fsSL 'URL/get.sh' | bash,利用 curl 命令將網站上的程式輸出在螢幕,但是| bash,會將輸出在螢幕的程式碼丟給重裝貝殼執行,這樣做的好處是不會留下紀錄。-f,下載失敗不會輸出錯誤訊息-s,Silent mode
filebrowser config init,將網站初始化--port 4000,網站的 port number : 4000--address "",任何 IP 位址的來源都能與我連線--log "/tmp/fbs",網站 log 檔的存放檔案--root="/srv",使用者丟檔案到網站後存放的目錄區,可自行設定
filebrowser users add,建立帳號admin "admin",帳號 :admin,密碼 :admin--perm.admin=true,打開管理員的權限
build image
$ sudo podman build -t alp.myfbs fbs/
# 檢查是否符合預期
$ sudo podman images | grep fbs
localhost/alp.myfbs latest 24d1b68d43f8 About a minute ago 74.3 MB手動部署 alp.myfbs Image
# 備份 Image
$ sudo podman save localhost/alp.myfbs > alpine.myfbs.tar
$ scp alpine.myfbs.tar w1:~; scp alpine.myfbs.tar w2:~
$ ssh w1 'sudo podman load < alpine.myfbs.tar'; ssh w2 'sudo podman load < alpine.myfbs.tar'建立 File Browser Server Pod
# 編輯 yaml 檔
$ nano fbs/pod-fbs.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-fbs
labels:
name: pod-fbs
spec:
containers:
- name: myfbs
image: localhost/alp.myfbs
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4000用 yaml 檔 建立 pod
$ kubectl apply -f fbs/pod-fbs.yaml檢查 pod 的 4000 port 有無開啟
# 看 pod 的 IP
$ kg pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-fbs 1/1 Running 0 2m30s 10.244.1.6 w1 <none> <none>
# 網貓測 4000 port
$ nc -w 1 10.244.1.6 4000
$ echo $?
0建立 File Browser Server Service
$ nano fbs/svc-fbs.yaml
kind: Service
apiVersion: v1
metadata:
name: svc-fbs
spec:
externalIPs:
- 192.168.61.4
selector:
name: pod-fbs
ports:
- port: 8080
targetPort: 4000selector:,選擇有貼 pod-fbs 這個標籤的 podexternalIPs:,設定對外服務的 IP 位址ports: - port: 8080 ---> 對外的 port number targetPort: 4000 ---> pod 開的 port number
建立 service/svc-fbs 服務
$ kubectl apply -f fbs/svc-fbs.yaml檢查是否符合預期
$ kubectl get all -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/pod-fbs 1/1 Running 0 14m 10.244.1.6 w1 <none> <none>
pod/pod-sshd 1/1 Running 0 39m 10.244.2.4 w2 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.98.0.1 <none> 443/TCP 4h5m <none>
service/svc-fbs ClusterIP 10.98.0.230 192.168.61.4 8080/TCP 83s name=pod-fbs看 pod 的標籤
$ kubectl get pods --show-labels
AME READY STATUS RESTARTS AGE LABELS
pod-fbs 1/1 Running 0 20m name=pod-fbs
pod-sshd 1/1 Running 0 44m <none>FBS 架構示意圖

- 多建立 Service 這個物件的原因是因為,K8S 的 pod 很容易浴火重生,一旦重建, pod IP 會發生變動,如果這時候我們 pod 是一個網站,這個網站的 IP 位址時不時更換,會搞死人。
- 所以這時候需要透過 Service ,服務的 IP 在 K8S 中是固定的,不會因為主機重開,Service IP 就變動,所以只要讓 Service 透過 labels 綁住我們的 pod ,這樣即使 pod 浴火重生,也沒關係,我們一樣可以靠 Service 連的到我們的 pod
提問 : 如何得知檔案丟到網站後,存放在哪?
答 : pod-fbs 的 container 裡 /srv 目錄下
# 進入 pod
$ kubectl exec -it pod/pod-fbs -- bash
# 檢查是否符合預期
bash-5.1# ls -al srv
total 12
drwxr-xr-x 1 root root 4096 Jul 31 06:46 .
dr-xr-xr-x 1 root root 4096 Jul 31 06:23 ..
drwxr-xr-x 3 root root 4096 Jul 31 06:46 ALP3
bash-5.1# touch srv/zzz.txt
bash-5.1# ls -al srv/
total 12
drwxr-xr-x 1 root root 4096 Jul 31 06:51 .
dr-xr-xr-x 1 root root 4096 Jul 31 06:23 ..
drwxr-xr-x 3 root root 4096 Jul 31 06:46 ALP3
-rw-r--r-- 1 root root 0 Jul 31 06:51 zzz.txt
災難篇
如果刪除 pod ,裡面存放的內容就不見了 ! ! !
$ kubectl delete pod pod-fbs
pod "pod-fbs" deleted
$ kubectl delete svc svc-fbs
service "svc-fbs" deleted對於 K8s 的 Storage 怎麼處理 ?
對 pod 的 yaml 檔新增 hostPath PV
編輯 yaml 檔
$ nano fbs/pod-fbs.yamlapiVersion: v1
kind: Pod
metadata:
name: pod-fbs
labels:
name: pod-fbs
spec:
containers:
- name: myfbs
image: localhost/alp.myfbs
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4000
volumeMounts:
- mountPath: /srv
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /tmpvolumeMounts,設定 Container 的目錄要將哪個目錄掛載到volumes的目錄mountPath,要掛載的目錄
volumes,下面可以宣告儲存體的設定hostPath,volume 的型態path: /tmp,這是一個在 Linux 系統的/tmp目錄,但注意 ! 這個目錄重開機裡面的內容會消失 (這是 Linux/tmp目錄的規則)。
- K8s 官網 hostPath 範例連結
- 如果刪除 pod 再重建一次, pod 可能會跑到別台 node 主機,如何解決 ? 答 : 針對第一次建立 pod 時,如果 pod 在 node 1 主機上,則每次重建 pod 時,就要安排在這台 node 主機上
apiVersion: v1
kind: Pod
metadata:
name: pod-fbs
labels:
name: pod-fbs
spec:
containers:
- name: myfbs
image: localhost/alp.myfbs
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4000
volumeMounts:
- mountPath: /srv
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /tmp
nodeSelector:
kubernetes.io/hostname: w2