Installation

RBAC Kubernetes 安裝 helm

環境

  • Google Kubernetes Engine
  • Kubernetes version 1.12.8
  • Helm version 2.14.1

安裝 Helm without RBAC

Helm 是 Kubernetes 的管理工具,Tiller 則是 API server,至於之間的差別,Helm 是 Client 端,Tiller 是 Server 端。輸入以下指令會安裝 HelmTiller

1
helm init

官方文件建議加上 –history-max 參數,限制最大歷史指令的數量,如果沒有設定最大歷史記錄,則永遠保留歷史記錄。

1
helm init --history-max 200

##設定 RBAC

在雲端平台上,由於有安全性的問題,如果不設定 RBAC,之後可能會無法正常使用,所以需要提供足夠的權限給 tiller,輸入以下指令建立權限,ServiceAccount 的名稱為 tiller

1
2
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller

套用 tiller 的 ServiceAccount 到已經現有的上

1
kubectl patch deployment --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

安裝 Helm with RBAC

所有設定一次到位,在 helm init 的時候,加了 –service-account 參數,直接套用 ServiceAccount:

1
2
3
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
helm init --service-account tiller --history-max 200

測試

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ helm install --name my-db stable/influxdb
NAME: my-db
LAST DEPLOYED: Wed Jul 3 23:13:08 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
my-db-influxdb 1 1s

==> v1/PersistentVolumeClaim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-db-influxdb Pending standard 1s

==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
my-db-influxdb-689d74646c-6fwc4 0/1 Pending 0 1s

==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-db-influxdb ClusterIP 10.11.249.197 <none> 8086/TCP,8088/TCP 1s

==> v1beta1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
my-db-influxdb 0/1 1 0 1s

...

查看套件清單

1
2
3
$ helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
my-db 1 Wed Jul 3 23:13:08 2019 DEPLOYED influxdb-1.1.9 1.7.6 default

刪除測試檔案,–purge 參數可以徹底刪除,不留下任何記錄,名稱可以透過上面的指令查詢:

1
helm delete --purge my-db

解除安裝 Helm

1
2
3
kubectl -n kube-system delete deployment tiller-deploy
kubectl delete clusterrolebinding tiller
kubectl -n kube-system delete serviceaccount tiller

Reference

在 kubernetes 上建立 influxdb 1.7.7

環境

  • Google Kubernetes Engine
  • Kubernetes 版本為 1.12.8

建立 Secret

Kubernetes secret 可以存放重要訊息,像是使用者密碼之類,不適合暴露在外。

設定以下參數,稍後提供給 influxdb 使用:

  1. INFLUXDB_DATABASE:資料庫名稱
  2. INFLUXDB_HOST:主機名稱
  3. INFLUXDB_USERNAME:使用者名稱
  4. INFLUXDB_PASSWORD:使用者密碼
1
2
3
4
5
kubectl create secret generic influxdb-creds \
--from-literal=INFLUXDB_DATABASE=db \
--from-literal=INFLUXDB_USERNAME=root \
--from-literal=INFLUXDB_PASSWORD=root \
--from-literal=INFLUXDB_HOST=influxdb

輸入以下指令檢查參數是否設定完成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ kubectl get secrets
NAME TYPE DATA AGE
influxdb-creds Opaque 4 46m

$ kubectl describe secrets influxdb-creds
Name: influxdb-creds
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
INFLUXDB_DATABASE: 12 bytes
INFLUXDB_HOST: 8 bytes
INFLUXDB_PASSWORD: 4 bytes
INFLUXDB_USERNAME: 4 bytes

密文型態為 Opaque,裡面有四筆資料

建立儲存空間 Persistent Volume Claim (PVC)

使用 Kubernetes PVC 宣告儲存空間,將儲存空間命名為 influxdb,容量大小 2GB:

1
2
3
4
5
6
7
8
9
10
11
12
13
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
labels:
app: influxdb
name: influxdb
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi

套用設定:

1
kubectl apply -f pvc.yaml

建立 Deployment

直接使用 Docker Hub 上的 influxdb,版本為 1.7.7

1
kubectl run influx-deployment --image=influxdb:1.7.7

套用 Secret

套用先前設定的 influxdb-creds Secret,輸入以下指令進入修改模式:

1
kubectl edit deployment influxdb

spec.template.spec.containers 位置加入 kubernetes secret:

1
2
3
4
5
6
7
8
spec:
template:
spec:
containers:
- name: influxdb
envFrom:
- secretRef:
name: influxdb-creds

套用 Persistent Volume Claim (PVC)

套用先前設定的 influxdb PVC,輸入以下指令進入修改模式:

1
kubectl edit deployment influxdb

spec.template.spec.volumes 位置加入 Persistent Volume Claim (PVC):

1
2
3
4
5
6
7
spec:
template:
spec:
volumes:
- name: var-lib-influxdb
persistentVolumeClaim:
claimName: influxdb

並且在 spec.template.spec.containers.volumeMounts 位置加入 Persistent Volume (PV):

1
2
3
4
5
6
7
spec:
template:
spec:
containers:
volumeMounts:
- mountPath: /var/lib/influxdb
name: var-lib-influxdb

最後整份文件的結果會長得如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "4"
creationTimestamp: 2019-07-02T15:59:33Z
generation: 4
labels:
run: influxdb
name: influxdb
namespace: default
resourceVersion: "15136"
selfLink: /apis/apps/v1/namespaces/default/deployments/influxdb
uid: 62295880-9ce2-11e9-8f7f-42010a8000e8
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
run: influxdb
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
run: influxdb
spec:
containers:
- envFrom:
- secretRef:
name: influxdb-creds
image: docker.io/influxdb:1.7.7
imagePullPolicy: IfNotPresent
name: influxdb
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/influxdb
name: var-lib-influxdb
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: var-lib-influxdb
persistentVolumeClaim:
claimName: influxdb
status:
...

Expose Service

這裡使用 LoadBalancer 來 expose 我們的服務,需要有雲端平台的支援:

1
kubectl expose deployment influx-deployment --name=influx-service --type=LoadBalancer --port=8086 --target-port=8086

EXTERNAL-IP 顯示為 pending,則再過一陣再重輸入一次。

1
2
3
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
influxdb LoadBalancer 10.11.255.248 34.68.51.223 8086:31365/TCP 69m

看到 IP address 就代表完成了,接下來就測試看看是否能連進 server。

測試

從是否能從外部連進來:

1
2
3
4
5
6
7
$ influx --version
InfluxDB shell version: 1.7.7

$ influx -host '34.68.51.223' -port '8086' -username 'root' -password 'root'
Connected to http://34.68.51.223:8086 version 1.7.7
InfluxDB shell version: 1.7.7
>

Reference

在 Ubuntu 18.04 上安裝 Docker CE

安裝環境是在 Ubuntu 18.04 上。

安裝 Docker CE

docker.io 是 docker 的舊版本,如果先前有安裝要移除舊版本:

1
sudo apt-get remove docker docker-engine docker.io containerd runc

安裝相關套件:

1
2
3
4
5
6
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common

匯入 docker apt repository:

1
2
3
4
5
6
7
8
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

sudo apt-get update

安裝 docker ce:

1
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

建立 daemon:

1
2
3
4
5
6
7
8
9
10
11
12
13
# root
sudo cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

啟用 Docker:

1
2
sudo systemctl start docker.service
sudo systemctl enable docker.service

加入使用者權限,加完後記得要重新開啟終端機:

1
2
sudo groupadd docker
sudo usermod -aG docker $USER

安裝完成

1
docker --version

Reference

在 Ubuntu 上重新安裝 Kubernetes

介紹

Kubeadm 有提供一個指令 reset,不過他只會將有關 Kubernetes 的東西刪除,像是 flannelcni 的網路設定,則必須要手動刪除。

這裡使用的環境是:

  • Ubuntu 18.04
  • Kubernetes 1.14.1
  • Flannel 0.10.0

Problem

要讓問題重現,只需要在你安裝好 Kubernetes Cluster 之後,重設 Kubernetes 就會發生:

1
2
kubeadm reset -f
kubeadm init

這個時候你的 coredns 會一直在 pending 的狀態,而且 nodes 會一直是 NodReady:

1
2
3
4
5
6
7
8
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
akiicat NotReady master 65m v1.14.1

$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-fb8b8dccf-2t48c 0/1 Pending 0 42s
coredns-fb8b8dccf-x7f87 0/1 Pending 0 42s

看一下 kubelet 是什麼問題,猜測是之前的 CNI 沒有清除乾淨,而套用到舊的資料

1
2
3
4
$ systemctl status kubelet
...
4月 25 14:01:40 akiicat kubelet[6416]: W0425 14:01:40.779474 6416 cni.go:213] Unable to update cni config: No networks found in /etc/cni/net.d
4月 25 14:01:40 akiicat kubelet[6416]: E0425 14:01:40.901231 6416 kubelet.go:2170] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

Step by Step

接下來就一步一步的解決這個問題,首先切換成 root 權限:

1
sudo su -

先把 Kubernetes 重設,-f 參數代表強制執行 reset,不會跳出提示訊息的確認:

1
kubeadm reset -f

停止 kubeletdocker

1
2
systemctl stop kubelet
systemctl stop docker

完全刪除 cniflannel 的資料:

1
2
3
4
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf /run/flannel
rm -rf /etc/cni/

移除 cniflannel 的網路介面卡:

1
2
3
ifconfig cni0 down
brctl delbr cni0
ifconfig flannel.1 down

重新啟動 docker

1
systemctl start docker

這樣就完成了,最後檢查一下網路介面卡與 IP table 有沒有 flannelcni

1
2
ifconfig
route -n

沒有在這上面就成功了。

後續安裝可以參考我寫的這篇文章:Bare Metal 在 Ubuntu 上安裝 Kubernetes

Summary

最後要輸入指令的時候,需要對 Master 跟 Worker 執行不同的指令,以及在不同的權限下執行:

  • Master:代表主結點。
  • Node:代表 Worker 節點或子結點。

[Master, Node] 不管事 master 跟 worker 都要執行 Kubernetes Reset,在執行時要注意權限是否正確:

1
2
3
4
5
6
7
8
9
10
11
12
# root
kubeadm reset -f
systemctl stop kubelet
systemctl stop docker
rm -rf /var/lib/cni/
rm -rf /var/lib/kubelet/*
rm -rf /run/flannel
rm -rf /etc/cni/
ifconfig cni0 down
brctl delbr cni0
ifconfig flannel.1 down
systemctl start docker

[Master] 安裝 Kubernetes:

1
2
# root
kubeadm init --pod-network-cidr 10.244.0.0/16

注意要切換使用者:

1
2
3
4
5
6
# user
mkdir -p $HOME/.kube
sudo cp -f /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml

[Node] 加入 worker 節點:

1
2
3
# root
kubeadm join 192.168.0.11:6443 --token 3c564d.6q2we53btzqmf1ew \
--discovery-token-ca-cert-hash sha256:a5480dcd68ec2ff27885932ac80d33aaa0390d295d4834032cc1eb554de3d5d2

Reference

Bare Metal 在 Ubuntu 上安裝 Kubernetes

Docker

在安裝 Kubernetes 前要先安裝好 Docker,可以參考這篇:

Kubeadm

kubeadm 負責管理節點,可以透過方便的指令將電腦加入 cluster,在這裡我們先定義:

  • Master:代表主結點,負責控制與分發任務
  • Node:代表子結點,負責執行 Master 所分發的任務

[Master, Node] 安裝 Kubeadm 需要 root 權限:

1
sudo su -

[Master, Node] 安裝 kubeadm:

1
2
3
4
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
apt update
apt install -y kubeadm

apt 安裝 kubeadm 完後會連同 kubelet 跟 kubectl 一起安裝。

[Master]Master 節點上初始化 Kubernetes:

1
kubeadm init --pod-network-cidr 10.244.0.0/16

因為我們是使用 flannel,所以必須加上 --pod-network-cidr

我們這邊選擇 flannel 的是因為 flannel 支援 arm。

如果要透過 WIFI 連接網路的話,需要加上 --apiserver-advertise-address=<wifi-ip-address> 參數到 kubeadm init 指令上。

執行 kubeadm init 之後會有一行 kubeadm join,如果弄丟的話,可以執行下面指令獲得:

1
kubeadm token create --print-join-command

[Node] 然後把其他的 node 加進來:

1
2
kubeadm join 192.168.0.11:6443 --token 3c564d.6q2we53btzqmf1ew \
--discovery-token-ca-cert-hash sha256:a5480dcd68ec2ff27885932ac80d33aaa0390d295d4834032cc1eb554de3d5d2

[Master, Node] 離開 root

1
exit

Kubectl

[Master] 回到使用者模式後執行:

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

admin.conf 放置到 ~/.kube/config 就會自動抓取設定檔。

[Master] 安裝 flannel,相關文件在 CoreOS 上:

1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml

[Master] 查看目前節點:

1
2
3
4
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
akiicat Ready master 77m v1.14.1
akiicat-node2 Ready <none> 51s v1.14.1

測試

執行一些簡單的容器:

1
kubectl run kuard --image=gcr.io/kuar-demo/kuard-amd64:blue --replicas=3

查看 pods 是否有在運行

1
2
3
4
5
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kuard-6cdb64fdcd-7bfgq 1/1 Running 0 17s
kuard-6cdb64fdcd-82mtv 1/1 Running 0 17s
kuard-6cdb64fdcd-rhxp2 1/1 Running 0 17s

使用 LoadBalancer 暴露它:

1
kubectl expose deployment kuard --type=LoadBalancer --port=80 --target-port=8080

查看 Service

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl describe service/kuard
Name: kuard
...
Type: LoadBalancer
IP: 10.109.141.84
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 30034/TCP
Endpoints: 10.244.1.5:8080,10.244.1.6:8080,10.244.1.7:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>

使用 curl 連到 pod 的 endpoint:

1
2
3
$ curl 10.244.1.5:8080
Hostname: kuard-1-6cdb64fdcd-7bfgq
...

Trouble Shooting

Swap Error

當你用 root 權限執行 kubeadm init 時,會出現 ERROR Swap 的錯誤:

1
2
3
4
5
6
7
8
9
# kubeadm init --pod-network-cidr 10.244.0.0/16
[init] Using Kubernetes version: v1.14.1
[preflight] Running pre-flight checks
[preflight] WARNING: Couldn't create the interface used for talking to the container runtime: docker is required for container runtime: exec: "docker": executable file not found in $PATH
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
[ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[ERROR Swap]: running with swap on is not supported. Please disable swap
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`

如果啟用 swap 的話,當你記憶體不夠用的時候,OS 會先把暫時沒有用的資料存到硬碟裡,又稱作為 swap out。相反,OS 需要用到剛剛存在硬碟裡的資料,則會把資料再載入回記憶體裡面,又稱作為 swap in。

使用 Kubenetes 的時候需要停用 swap 這個功能:

1
swapoff -a

相關討論在 Github 的 issue 上。

上面的設定在重新開機之後就會失效 swap,要將 swap 完全關掉的話,需編輯 /etc/fstab 這個檔案,將 mount point 在 / 的項目註解掉:

1
2
# /etc/fstab
# UUID=10e56f7b-7b40-4b10-8029-642badc59ce9 / ext4 errors=remount-ro 0 1

exec format error

由於 CPU 有分 Intel 跟 Arm 的架構,這個問題會發生是因為 Docker image files 是基於某個特定的架構。也就是說,在 Intel 上建立的 Docker file 只能在 Intel 上執行;在 Arm32 上建立的 Docker file 只能在 Arm32 上執行。

所以當你使用 kubectl logs 查看某個 pod 出現如下的錯誤時:

1
2
$ kubectl logs pod/kuard-777c5775cd-lg7kc
standard_init_linux.go:207: exec user process caused "exec format error"

確認你的 Docker image 有支援你 CPU 的架構

Stackoverflow 上的討論

Reference