翻看了不少的kubernetes的安裝教程,也反覆作了一些實驗,深感教程之複雜,因此決定寫一個極簡版本的安裝教程,目標在於用盡量少的參數啓動服務,而且剖析各組件關係,而後再在此基礎上逐步添加參數,實現功能完備;html
說明:node
先大概知道一下架構,借用一張圖,來源:https://www.kubernetes.org.cn/4047.htmllinux
etcd | 3.3.8 |
docker | 18.03.1-ce |
flannel | 0.10.0 |
kubernetes | 1.10.5 |
etcd是一個基礎組件,沒有太複雜的依賴關係,沒什麼好說的;nginx
docker見以前的docker安裝流程;git
flannel見以前的flannel安裝流程;github
到官方changelog裏找downloads:https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.10.mdweb
只下載server和node包就夠了,client包只有一個kubectl工具,在前兩個裏都有帶;docker
server有三個組件,apiserver是接口服務,對接etcd,作存儲邏輯的封裝,後面跟着controller-manager和scheduler,作一些後臺控制邏輯;json
整個server作的事情全都圍繞etcd轉,因此根本不須要系統的root權限,普通用戶足夠;bootstrap
解壓server包,程序都解壓到了kubernetes/server/bin路徑:
$ tar vfxz kubernetes-server-linux-amd64.tar.gz # 解壓 $ ls kubernetes/server/bin #看一下
$ cd kubernetes/server # 就在這個路徑下作server服務的管理
bin/kube-apiserver \
--cert-dir=etc/kubernetes/cert \ --insecure-bind-address=0.0.0.0 \ --insecure-port=18080 \ --service-cluster-ip-range=10.0.0.0/16 \ --etcd-servers=http://<etcd>:2379 \ --logtostderr=true
參數說明:
apiserver啓動後,在cert-dir下出現了自動建立的證書和密鑰:
$ file etc/kubernetes/cert/* etc/kubernetes/cert/apiserver.crt: PEM certificate etc/kubernetes/cert/apiserver.key: PEM RSA private key
在etcd上出現了一些數據:
# ETCDCTL_API=3 etcdctl get / --prefix --keys-only /registry/apiregistration.k8s.io/apiservices/v1. /registry/apiregistration.k8s.io/apiservices/v1.apps /registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.autoscaling /registry/apiregistration.k8s.io/apiservices/v1.batch /registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.apps /registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.batch /registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.extensions /registry/apiregistration.k8s.io/apiservices/v1beta1.policy /registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io /registry/apiregistration.k8s.io/apiservices/v1beta2.apps /registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling /registry/namespaces/default /registry/namespaces/kube-public /registry/namespaces/kube-system /registry/ranges/serviceips /registry/ranges/servicenodeports /registry/services/endpoints/default/kubernetes /registry/services/specs/default/kubernetes
忽略掉前面的/register/apixxx,來看一下後面這些東西:
apiserver提供了restapi以獲取和管理在etcd上的集羣狀態信息;kubectl就是這個restapi的客戶端;
由於咱們的服務端口不在默認的8080上,因此使用時要加一個-s參數:
查看namespace:
$ bin/kubectl -s 127.0.0.1:18080 get ns # 查看三個namespace,與etcd的/registry/namespaces對應 NAME STATUS AGE default Active 1h kube-public Active 1h kube-system Active 1h
查看service:
$ bin/kubectl -s 127.0.0.1:18080 get svc # 查看service,與/registry/services/specs/default/kubernetes對應 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 1h
查看endpionts:
$ bin/kubectl -s 127.0.0.1:18080 get ep #查看endpoints,與/registry/services/endpoints/default/kubernetes對應 NAME ENDPOINTS AGE kubernetes xxxxx:6443 1h
注:這個命令雖然能夠啓動controller-manager,但後續會出現一些問題,須要再添加參數,見「測試」部分對controller-manaer的調整;
bin/kube-controller-manager \ --master=127.0.0.1:18080 \ --logtostderr=true
查看etcd,多出現一些節點:
/registry/events/kube-system/kube-controller-manager.153c40f68e70e209 /registry/serviceaccounts/default/default /registry/serviceaccounts/kube-public/default /registry/serviceaccounts/kube-system/default /registry/services/endpoints/kube-system/kube-controller-manager
多出一個event,三個serviceaccounts(三個namespace下的default),以及一個endpoints;
event就不看了,來看一下service account:
$ bin/kubectl -s 127.0.0.1:18080 get sa NAME SECRETS AGE default 0 3m
這裏的SECRETS爲0,代表沒有爲這個service account生成secret,這個也是與安全相關的東西,先忽略,後面會遇到問題,而後咱們再回來處理它;
再看一下endpoint:
$ bin/kubectl -s 127.0.0.1:18080 get ep --namespace kube-system NAME ENDPOINTS AGE kube-controller-manager <none> 7m
由於kube-controller-manager在kube-system下,因此須要多加一個namespace參數;
bin/kube-scheduler \ --master=127.0.0.1:18080
查看etcd,多出現一些節點:
/registry/events/kube-system/kube-scheduler.153c41b5b3052d28 /registry/services/endpoints/kube-system/kube-scheduler
再看一下endpoints
$ bin/kubectl -s 127.0.0.1:18080 get ep --namespkube-system NAME ENDPOINTS AGE kube-controller-manager <none> 15m kube-scheduler <none> 1m
$ bin/kubectl -s 127.0.0.1:18080 get cs NAME STATUS MESSAGE ERROR controller-manager Healthy ok scheduler Healthy ok etcd-0 Healthy {"health":"true"}
至此,server就算部署好了
本想node的兩個服務組件也用非root用戶的,但試下來發現不行,kubelet須要與docker交互,而kube-proxy則要改iptables,都須要提供root權限;
解壓node包,程序都解壓到了kubernetes/node/bin路徑:
# tar vfxz kubernetes-node-linux-amd64.tar.gz #解壓 # ls kubernetes/node/bin/ # 看一下 # cd kubernetes/node # 就在這個路徑下進行node服務的管理
kubelet的參數太多了,可能爲了簡化kubelet的啓動腳本吧,引入了兩個配置文件,兩個,兩個......並且除這兩個文件外還要設置其它參數,設置其它參數,其它參數......faint
先生成訪問apiserver須要用的kubeconfig文件:
# KUBE_APISERVER="http://<apiserver>:18080" #
# bin/kubectl config set-cluster kubernetes \ --server=$KUBE_APISERVER \ --kubeconfig=etc/kubernetes/kubelet.kubeconfig #
# bin/kubectl config set-context default \ --cluster=kubernetes \ --user=default-noauth \ --kubeconfig=etc/kubernetes/kubelet.kubeconfig #
# bin/kubectl config use-context default --kubeconfig=etc/kubernetes/kubelet.kubeconfig #
# bin/kubectl config view --kubeconfig=etc/kubernetes/kubelet.kubeconfig apiVersion: v1 clusters: - cluster: server: http://<apiserver>:18080 name: kubernetes contexts: - context: cluster: kubernetes user: "" name: default current-context: default kind: Config preferences: {} users: []
這個配置文件就聲明瞭一個以http://<apiserver>:18080爲入口的名爲「kubernetes」的集羣,以及一個匿名訪問「kubernetes」集羣的名爲「default」的上下文,並聲明使用這個"default"上下文;
寫kubelet自身須要的配置文件(這個文件能夠是yaml或json格式,由於不少教程用了json格式,因此這裏我用一下yaml格式):
# cat etc/kubernetes/kubelet.config.yaml kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 cgroupDriver: cgroupfs
kind和apiVersion都是定死的,可見https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/,以及代碼的這裏:https://github.com/kubernetes/kubernetes/blob/release-1.10/pkg/kubelet/apis/kubeletconfig/v1beta1/register.go;
cgroupDriver須要與docker的真實狀況相符,經過如下命令查看:
# docker info|grep 'Cgroup Driver' Cgroup Driver: cgroupfs
啓動kubelet:
bin/kubelet \ --cert-dir=etc/kubernetes/cert \ --kubeconfig=etc/kubernetes/kubelet.kubeconfig \ --config=etc/kubernetes/kubelet.config.yaml \ --pod-infra-container-image=<registry>/rhel7/pod-infrastructure:latest \ --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice \ --logtostderr=true
參數說明:
在cert-dir下出現了自動建立的證書和密鑰:
# file etc/kubernetes/cert/* etc/kubernetes/cert/kubelet.crt: PEM certificate etc/kubernetes/cert/kubelet.key: PEM RSA private key
多說一句,這個證書是node本身簽發的,確定得不到apiserver的承認;固然由於我在這裏不作安全集羣,這就無所謂;但在安全集羣裏,kubelet的證書會由controller-manager簽發;
在etcd上出現了一些新的數據,除去events外,就一個最重要的minions數據:
/registry/minions/<node>
$ bin/kubectl -s 127.0.0.1:18080 get node NAME STATUS ROLES AGE VERSION <node> Ready <none> 38m v1.10.5
bin/kube-proxy \ --master=<apiserver>:18080 \ --proxy-mode=iptables \ --logtostderr=true
參數說明:
至此,node部署完成;
到apiserver上,執行如下命令,運行一個標準的nginx容器,爲了省時間,我也把它拉下來,push到私有registry上了:
$ bin/kubectl -s 127.0.0.1:18080 run nginx --image=<registry>/nginx/nginx --port=80
pod啓動失敗,報錯:No API token found for service account "default"
以前遺留了一個問題,見service_account_without_secrets:
因而調整一下controller-manager的參數,加上--service-account-private-key-file和--root-ca-file參數,重啓controller-manager:
$ bin/kube-controller-manager \ --master=127.0.0.1:18080 \ --service-account-private-key-file=etc/kubernetes/cert/apiserver.key \ --root-ca-file=etc/kubernetes/cert/apiserver.crt \ --logtostderr=true
再看一下service account的狀況,secrets已經不是0了:
$ bin/kubectl -s 127.0.0.1:18080 get sa NAME SECRETS AGE default 1 2h
再從新試一下啓動nginx,並查看狀態;
$ bin/kubectl -s 127.0.0.1:18080 run nginx --image=<registry>/nginx/nginx --port=80 # 啓動
$ $ bin/kubectl -s 127.0.0.1:18080 get deploy # 查看deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 1 1 1 1 1m
$ $ bin/kubectl -s 127.0.0.1:18080 describe deploy nginx|grep NewReplicaSet # 查看deploy詳情 Progressing True NewReplicaSetAvailable NewReplicaSet: nginx-55cc995fdb (1/1 replicas created)
$ $ bin/kubectl -s 127.0.0.1:18080 describe replicasets nginx-55cc995fdb |tail -1 # 查看replicaset詳情 Normal SuccessfulCreate 10m replicaset-controller Created pod: nginx-55cc995fdb-27t7z
$ $ bin/kubectl -s 127.0.0.1:18080 get pod nginx-55cc995fdb-27t7z -o wide # 查看pod NAME READY STATUS RESTARTS AGE IP NODE nginx-55cc995fdb-27t7z 1/1 Running 0 11m 172.10.63.2 <node>
再到node上看一下容器狀態:
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3e5e69a69950 <registry>/nginx/nginx "nginx -g 'daemon of…" 28 seconds ago Up 27 seconds k8s_nginx_nginx-55cc995fdb-27t7z_default_1ca63ddd-7ab5-11e8-be61-3440b59f0098_0 ec311fee295d <registry>/rhel7/pod-infrastructure:latest "/pod" 28 seconds ago Up 27 seconds k8s_POD_nginx-55cc995fdb-27t7z_default_1ca63ddd-7ab5-11e8-be61-3440b59f0098_0
看以看到,同時啓動了兩個容器,一個是pod-infrastructure,另外一個是nginx;若是進入這兩個容器內看一下的話,會發現它們的ip地址是同一個;
總結一下啓動應用時這些資源的關係:
若是啓動的應用自己是個服務的話,還須要將服務地址暴露出來,在server(master)上運行:
$ bin/kubectl -s 127.0.0.1:18080 expose deployment nginx --type=NodePort --name=example-service service "example-service" exposed $ $ bin/kubectl -s 127.0.0.1:18080 describe services example-service Name: example-service Namespace: default Labels: run=nginx Annotations: <none> Selector: run=nginx Type: NodePort IP: 10.0.158.97 Port: <unset> 80/TCP TargetPort: 80/TCP NodePort: <unset> 30152/TCP Endpoints: 172.10.63.2:80 Session Affinity: None External Traffic Policy: Cluster Events: <none>
從後面的服務描述中獲得如下信息:
在server(master)上訪問node的30152端口,nginx服務正常:
$ curl <node>:30152 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
在node上訪問10.0.158.97:80,nginx也服務正常;查看一下node的iptables,會發現有一條規則將target爲10.0.158.97:80的流量轉發到了本機的30152端口;這是kueb-proxy作的事情;
在另外一個節點(能夠不是kubernetes node,只要求啓用了與node相同的flanneld)或容器(能夠不是kubernetes pod,只要求容器所在節點啓用了與node相同的flanneld)內訪問172.10.63.2:80,nginx也服務正常;這就是flanneld作的事情了;
重點參考如下三篇: