我是在騰訊雲CentOS的2臺伺服器上,在不翻牆的情況下使用kubeadm(最簡單的部署工具)搭建K8S叢集。其中,容器網路使用flannel,最終安裝好可以外網訪問的2.0.4版本的dashboard。不走彎路的話,4步即可完成:
1、準備系統環境對這2臺新購的雲虛擬機器,都需要安裝docker:
yum install docker -y
安裝kubeadm前,需要先新增kubeadm的yum源:
cat > /etc/yum.repos.d/kubernetes.repo <<EOF[kubernetes]name=Kubernetesbaseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64enabled=1gpgcheck=0repo_gpgcheck=0EOF
接著安裝目前最新版的kubeadm:
yum install kubeadm-1.20.1-0.x86_64
其中,kubeadm依賴的kubelet(K8S最核心的元件)、kubectl、kubernetes-cni網路外掛等會自動安裝。
最後啟用這2個服務:
systemctl enable kubelet.servicesystemctl start docker.service
騰訊雲主機預設已經將bridge-nf-call-iptables和ip_forward置為1,如果你的主機值為0,需要先將功能開啟:
sysctl -w net.bridge.bridge-nf-call-iptables=1sysctl -w net.ipv4.ip_forward=1
接著,針對部署K8S master節點的主機,還需要做些工作。由於騰訊雲預設的主機名並不是域名格式(不符合master節點要求),所以需要修改為你自定義的域名。這需要2個步驟:
將設計好的主機名寫入/etc/hostname檔案;將/etc/hosts中原主機名替換掉。2、部署master節點kubeadm的init命令即可初始化以單節點部署的master。為了避免翻牆,我 使用了 registry.aliyuncs.com/google_containers 源 。雖然可以在kubeadm命令列中輸入源,比如:
kubeadm init --image-repository registry.aliyuncs.com/google_containers
但將其寫入資源編排檔案更易維護,我將其命名為kubeadm.yaml:
apiVersion: kubeadm.k8s.io/v1beta2imageRepository: registry.aliyuncs.com/google_containerskind: ClusterConfigurationkubernetesVersion: v1.20.1networking: podSubnet: 10.244.0.0/16controllerManager: ExtraArgs: horizontal-pod-autoscaler-use-rest-clients: "true" horizontal-pod-autoscaler-sync-period: "10s" node-monitor-grace-period: "10s"
注意,這個編排檔案有4個細節:
10.244.0.0/16controllerManager
接著,使用編排檔案執行init命令:
kubeadm init --config ./kubeadm.yaml
注意,執行成功後kubeadm會返回類似下面的字樣:
Your Kubernetes control-plane has initialized successfully!
之後,還有2條重要的資訊:
1、後續kubectl預設控制叢集時,需要使用到CA金鑰,透過TLS協議保障通訊的安全性。我們要透過下面3行命令複製金鑰資訊,這樣,kubectl執行時會首先訪問當前使用者的.kube目錄,使用這些授權資訊訪問叢集:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
2、之後新增worker節點時,要透過token才能保障安全性。因此,先把顯示的這行命令儲存下來:
kubeadm join 172.27.0.11:6443 --token xxxxxxxxxxxx \ --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxx
3.部署flannel網路
flannel網路需要指定IP地址段,在上一步中已經透過編排檔案設定為 10.244.0.0/16 。部署flannel只需要一行命令:
kubectl apply -f ./kube-flannel.yml
其中,由於原本可以直接下載的檔案必須翻牆,所以我把檔案內容列在下方,儲存為上述命令的kube-flannel.yml檔案(參見第5小節):
此時,呼叫get pods命令,可以看到master節點的元件和flannel網路都牌Running狀態:
[root@k8s]# kubectl get pods -n kube-systemNAME READY STATUS RESTARTS AGEcoredns-7f89b7bc75-g8c42 1/1 Running 0 118scoredns-7f89b7bc75-z2p7c 1/1 Running 0 118setcd-taohui.tech 1/1 Running 0 2m6skube-apiserver-taohui.tech 1/1 Running 0 2m6skube-controller-manager-taohui.tech 1/1 Running 0 2m6skube-flannel-ds-kfzrg 1/1 Running 0 13skube-proxy-qbdz5 1/1 Running 0 118skube-scheduler-taohui.tech 1/1 Running 0 2m6s
接著,登入另一臺伺服器上,透過之前儲存的kubeadm join命令,將其加入K8S叢集。透過get nodes命令可以看到叢集中已有2個節點:
# kubectl get nodesNAME STATUS ROLES AGE VERSIONtaohui.tech Ready control-plane,master 14h v1.20.0workernode Ready <none> 12h v1.20.1
至此叢集部署成功!如果有引數錯誤需要修改,你也可以在reset後重新init叢集:
kubeadm reset
4.部署dashboard的
我們可以用以WEB頁面的視覺化dashboard,監控叢集的狀態。部署時同樣面臨翻牆和版本匹配的問題,這裡我將2個映象源替換後儲存為dashboard.yaml編排檔案(參見第6小節):
kubectl apply -f dashboard.yaml
執行成功後,你可以檢視到service:
# kubectl get svc -n kubernetes-dashboardNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEdashboard-metrics-scraper ClusterIP 10.100.6.83 <none> 8000/TCP 13hkubernetes-dashboard ClusterIP 10.99.243.226 <none> 443/TCP 13h
注意,dashboard預設不允許外網訪問。即使我們透過kubectl proxy允許外網訪問,但dashboard又只允許HTTPS訪問,這樣kubeadm init時自簽名的CA證書是不被瀏覽器承認的。我採用的方案是Nginx作為反向代理,使用Lets Encrypt提供的有效證書對外提供服務,再經由proxy_pass指令反向代理到kubectl proxy上,例如:
kubectl proxy --port=8888 --accept-hosts='^*$'
此時,本地可經由8888訪問到dashboard。再透過Nginx訪問它:
proxy_pass http://localhost:8888;
這樣,當在外網根據我的域名訪問如下URL:
https://mydomain/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login
就會展現2種登陸方式:
接下來採用token方式。首先要建立管理員帳戶:
cat <<EOF | kubectl apply -f -apiVersion: v1kind: ServiceAccountmetadata: name: admin-user namespace: kubernetes-dashboardEOF
執行完後,serviceaccount/admin-user使用者已經建立。接著,將使用者繫結已經存在的叢集管理員角色:
cat <<EOF | kubectl apply -f -apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: admin-userroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-adminsubjects:- kind: ServiceAccount name: admin-user namespace: kubernetes-dashboardEOF
最後,獲取可使用者於訪問的token:
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')
將token貼上到登入頁面,就可以看到dashboard了(下圖是node頁面):
5、用於部署flannel網路的資源編排檔案---apiVersion: policy/v1beta1kind: PodSecurityPolicymetadata: name: psp.flannel.unprivileged annotations: seccomp.security.alpha.kubernetes.io/allowedProfileNames: docker/default seccomp.security.alpha.kubernetes.io/defaultProfileName: docker/default apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/defaultspec: privileged: false volumes: - configMap - secret - emptyDir - hostPath allowedHostPaths: - pathPrefix: "/etc/cni/net.d" - pathPrefix: "/etc/kube-flannel" - pathPrefix: "/run/flannel" readOnlyRootFilesystem: false # Users and groups runAsUser: rule: RunAsAny supplementalGroups: rule: RunAsAny fsGroup: rule: RunAsAny # Privilege Escalation allowPrivilegeEscalation: false defaultAllowPrivilegeEscalation: false # Capabilities allowedCapabilities: ['NET_ADMIN', 'NET_RAW'] defaultAddCapabilities: [] requiredDropCapabilities: [] # Host namespaces hostPID: false hostIPC: false hostNetwork: true hostPorts: - min: 0 max: 65535 # SELinux seLinux: # SELinux is unused in CaaSP rule: 'RunAsAny'---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: name: flannelrules:- apiGroups: ['extensions'] resources: ['podsecuritypolicies'] verbs: ['use'] resourceNames: ['psp.flannel.unprivileged']- apiGroups: - "" resources: - pods verbs: - get- apiGroups: - "" resources: - nodes verbs: - list - watch- apiGroups: - "" resources: - nodes/status verbs: - patch---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata: name: flannelroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: flannelsubjects:- kind: ServiceAccount name: flannel namespace: kube-system---apiVersion: v1kind: ServiceAccountmetadata: name: flannel namespace: kube-system---kind: ConfigMapapiVersion: v1metadata: name: kube-flannel-cfg namespace: kube-system labels: tier: node app: flanneldata: cni-conf.json: | { "name": "cbr0", "cniVersion": "0.3.1", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ] } net-conf.json: | { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan" } }---apiVersion: apps/v1kind: DaemonSetmetadata: name: kube-flannel-ds namespace: kube-system labels: tier: node app: flannelspec: selector: matchLabels: app: flannel template: metadata: labels: tier: node app: flannel spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux hostNetwork: true priorityClassName: system-node-critical tolerations: - operator: Exists effect: NoSchedule serviceAccountName: flannel initContainers: - name: install-cni image: quay.io/coreos/flannel:v0.13.1-rc1 command: - cp args: - -f - /etc/kube-flannel/cni-conf.json - /etc/cni/net.d/10-flannel.conflist volumeMounts: - name: cni mountPath: /etc/cni/net.d - name: flannel-cfg mountPath: /etc/kube-flannel/ containers: - name: kube-flannel image: quay.io/coreos/flannel:v0.13.1-rc1 command: - /opt/bin/flanneld args: - --ip-masq - --kube-subnet-mgr resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "100m" memory: "50Mi" securityContext: privileged: false capabilities: add: ["NET_ADMIN", "NET_RAW"] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace volumeMounts: - name: run mountPath: /run/flannel - name: flannel-cfg mountPath: /etc/kube-flannel/ volumes: - name: run hostPath: path: /run/flannel - name: cni hostPath: path: /etc/cni/net.d - name: flannel-cfg configMap: name: kube-flannel-cfg
6、用於部署dashboard的資源編排檔案dashboard.yaml# Copyright 2017 The Kubernetes Authors.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.apiVersion: v1kind: Namespacemetadata: name: kubernetes-dashboard---apiVersion: v1kind: ServiceAccountmetadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard---kind: ServiceapiVersion: v1metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboardspec: ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard---apiVersion: v1kind: Secretmetadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-certs namespace: kubernetes-dashboardtype: Opaque---apiVersion: v1kind: Secretmetadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-csrf namespace: kubernetes-dashboardtype: Opaquedata: csrf: ""---apiVersion: v1kind: Secretmetadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-key-holder namespace: kubernetes-dashboardtype: Opaque---kind: ConfigMapapiVersion: v1metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-settings namespace: kubernetes-dashboard---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboardrules: # Allow Dashboard to get, update and delete Dashboard exclusive secrets. - apiGroups: [""] resources: ["secrets"] resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"] verbs: ["get", "update", "delete"] # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. - apiGroups: [""] resources: ["configmaps"] resourceNames: ["kubernetes-dashboard-settings"] verbs: ["get", "update"] # Allow Dashboard to get metrics. - apiGroups: [""] resources: ["services"] resourceNames: ["heapster", "dashboard-metrics-scraper"] verbs: ["proxy"] - apiGroups: [""] resources: ["services/proxy"] resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"] verbs: ["get"]---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboardrules: # Allow Metrics Scraper to get metrics from the Metrics server - apiGroups: ["metrics.k8s.io"] resources: ["pods", "nodes"] verbs: ["get", "list", "watch"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboardroleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboardsubjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: kubernetes-dashboardroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-dashboardsubjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard---kind: DeploymentapiVersion: apps/v1metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboardspec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: kubernetes-dashboard template: metadata: labels: k8s-app: kubernetes-dashboard spec: containers: - name: kubernetes-dashboard image: registry.cn-shanghai.aliyuncs.com/jieee/dashboard:v2.0.4 imagePullPolicy: Always ports: - containerPort: 8443 protocol: TCP args: - --auto-generate-certificates - --namespace=kubernetes-dashboard # Uncomment the following line to manually specify Kubernetes API server Host # If not specified, Dashboard will attempt to auto discover the API server and connect # to it. Uncomment only if the default does not work. # - --apiserver-host=http://my-address:port volumeMounts: - name: kubernetes-dashboard-certs mountPath: /certs # Create on-disk volume to store exec logs - mountPath: /tmp name: tmp-volume livenessProbe: httpGet: scheme: HTTPS path: / port: 8443 initialDelaySeconds: 30 timeoutSeconds: 30 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 volumes: - name: kubernetes-dashboard-certs secret: secretName: kubernetes-dashboard-certs - name: tmp-volume emptyDir: {} serviceAccountName: kubernetes-dashboard nodeSelector: "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule---kind: ServiceapiVersion: v1metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboardspec: ports: - port: 8000 targetPort: 8000 selector: k8s-app: dashboard-metrics-scraper---kind: DeploymentapiVersion: apps/v1metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboardspec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: dashboard-metrics-scraper template: metadata: labels: k8s-app: dashboard-metrics-scraper annotations: seccomp.security.alpha.kubernetes.io/pod: 'runtime/default' spec: containers: - name: dashboard-metrics-scraper image: registry.cn-shanghai.aliyuncs.com/jieee/metrics-scraper:v1.0.4 ports: - containerPort: 8000 protocol: TCP livenessProbe: httpGet: scheme: HTTP path: / port: 8000 initialDelaySeconds: 30 timeoutSeconds: 30 volumeMounts: - mountPath: /tmp name: tmp-volume securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1001 runAsGroup: 2001 serviceAccountName: kubernetes-dashboard nodeSelector: "kubernetes.io/os": linux # Comment the following tolerations if Dashboard must not be deployed on master tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule volumes: - name: tmp-volume emptyDir: {}
來源:https://www.tuicool.com/articles/ZfUZneY