# Kubernetes 安裝文件 <!-- ## 目前環境架構 **單一Master,配上多Worker,下階段再進行。** ![](https://i.imgur.com/s0anT9X.png) ## 基礎設定 環境規格,系統OS:ubuntu18.04 | Name | CPU | RAM | IP | Storage | | ----------- | ------ | --- |:-------------:| ------- | | k8s-master | 4 vCPU | 16G | 192.168.100.3 | 50G | | k8s-worker1 | 4 vCPU | 16G | 192.168.100.4 | 60G | 更新所有機器之/etc/hosts,加入IP & hostname ``` 192.168.100.3 k8s-master 192.168.100.4 k8s-worker1 ``` --> ## 前置作業(所有node都必須符合) ### 網路環境需求 ![](https://i.imgur.com/NKhoHlQ.png) ### 安裝相關套件與環境設定 ``` $ sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common ``` 安裝docker,建議參考[docker安裝教學](https://docs.docker.com/engine/install/ubuntu/) 如果是安裝1.22.x之前的版本,Docker 請多下列設定: ```bash! sudo mkdir /etc/docker cat <<EOF | sudo tee /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" } EOF ### Note: overlay2 is the preferred storage driver for systems running Linux kernel version 4.0 or higher, or RHEL or CentOS using version 3.10.0-514 and above. sudo systemctl enable docker sudo systemctl daemon-reload sudo systemctl restart docker ``` 關閉swap: ``` # swapoff -a # sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab ``` note:在此步驟如諾是全新之VM或實體機器,建議先重開機一次,讓swap先產生再關閉。 設定IP 轉發 (如若網路環境較複雜有公有IP 或VIP 再進行設定 [參考連結](https://www.itread01.com/content/1535183902.html)): ``` cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf br_netfilter EOF cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sudo sysctl --system ``` ### 如果需要nvidia docker #### 安裝nvidia driver (再有gpu的node上) Add nvidia ubuntu repo ```bash sudo add-apt-repository ppa:graphics-drivers/ppa sudo apt update ``` install nvidia graph driver ```bash sudo apt install nvidia-driver-510 ``` #### 安裝 nvidia docker Setup the package repository and the GPG key ```bash= distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list ``` ```shell= $ sudo apt-get update $ sudo apt-get install -y nvidia-docker2 ``` edit docker daemon.json ```json= { "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } }, "exec-opts": ["native.cgroupdriver=systemd"] } ``` 為什麼使用 exec-opts 請看 [詳解](https://blog.51cto.com/riverxyz/2537914)也可以避免掉這個錯誤產生 ``` The HTTP call equal to 'curl -sSL http://localhost:10248/healthz' failed with error: Get "http://localhost:10248/healthz": dial tcp 127.0.0.1:10248: connect: connection refused. ``` 關於kubernetes version 可參考 [releases](https://kubernetes.io/releases/) ## Controlpanel Install ### Configure Kubernetes Package Repository & Install kubeadm kubectl kubelet [官方文件](https://v1-22.docs.kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/) ``` $ sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg $ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF $ sudo apt-get update $ export KUBE_VERSION="1.22.9" $ sudo apt-get update && sudo apt-get install -y kubelet=${KUBE_VERSION}-00 kubeadm=${KUBE_VERSION}-00 kubectl=${KUBE_VERSION}-00 $ sudo apt-mark hold kubeadm kubectl kubelet $ mkdir -p /etc/kubernetes/manifests/ ``` 建立一個yaml檔案,命名為kubeadm-config.yaml ```yaml= apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.22.9 controlPlaneEndpoint: "${you_ip}" --- kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 cgroupDriver: systemd serverTLSBootstrap: true ``` ### Kubeadm Init ``` $ sudo kubeadm init --config=kubeadm-config.yaml ``` 這步驟結束後,會出現join的命令,請複製起來於Worker中使用 設定使用者執行權限: ``` $ mkdir -p $HOME/.kube $ cp -rp /etc/kubernetes/admin.conf $HOME/.kube/config $ chown $(id -u):$(id -g) $HOME/.kube/config` ``` 查看node狀態: ``` $ kubectl get nodes ``` ## 部署CNI的部分: ### 選項一 calico ``` $ wget https://docs.projectcalico.org/v3.19/manifests/calico.yaml ``` ``` $ sed -i 's/192.168.0.0\/16/10.244.0.0\/16/g' calico.yaml //這裡IP 要於yaml設定的 podSubnet 醫治 ``` 修改yaml內容 將Auto-detect the BGP IP address下內容註解 改為IP_AUTODETECTION_METHOD,並指定為出口網卡 ```yaml= # Auto-detect the BGP IP address. #- name: IP # value: "autodetect" //By Jack - name: IP_AUTODETECTION_METHOD value: "interface=ens5" ``` ``` $ kubectl apply -f calico.yaml ``` 查看 kube-system 所有Pods,是否都正常運行 ![](https://i.imgur.com/f9DNSdw.png) ### 選項二 cilium 請看[官方文件](https://docs.cilium.io/en/v1.9/gettingstarted/kubeproxy-free/)並使用helm安裝,如果想使用cilium來取代kube-proxy,要請在安裝kubeadmin的時候 --skip-phases=addon/kube-proxy,如果已經先init可以執行 ```shell= $ kubectl -n kube-system delete ds kube-proxy $ iptables-restore <(iptables-save | grep -v KUBE) ``` #### Join Token ``` $ kubeadm token create --print-join-command ``` ## Worker Node 安裝 [Kubeadm官方文件](https://v1-17.docs.kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/) ### 1. Configure Kubernetes Package Repository ```bash $ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add $ sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main" $ echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list ``` ### 2. Install Kubeadm ``` $ export KUBE_VERSION==<version> $ sudo apt-get update && sudo apt-get install -y kubelet=${KUBE_VERSION}-00 kubeadm=${KUBE_VERSION}-00 kubectl=${KUBE_VERSION}-00 ``` ### 3. Add Worker Nodes to the Cluster * go to Master node to get below information and execute it on Worker node ``` sudo kubeadm join <master_node_ip>:<port> --token <token> --discovery-token-ca-cert-hash <discovery-token-ca-cert-hash> ``` ### 5. Check Worker node status on master ``` $ kubectl get nodes ``` ## Add on Kubernetes Dashboard [官方文件](https://github.com/kubernetes/dashboard) ``` kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-rc7/aio/deploy/recommended.yaml ``` #### 產生認證token [官方文件](https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control/creating-sample-user.md) **建置yaml** ```yaml= apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard ``` 部屬Service ``` $ kubectl apply -f dashboard-adminuser.yaml ``` 產生token ``` sudo kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') ``` ![](https://i.imgur.com/c9D6tae.png) ### Issue 剛建置完畢的Dashbord,會因為憑證不合法的緣故,Chrome無法開啟,[官方解法](https://github.com/kubernetes/dashboard/blob/master/docs/user/installation.md#recommended-setup) #### 建置secret (請先準備好憑證) ``` $ kubectl create secret generic kubernetes-dashboard-certs --from-file=$HOME/certs -n kubernetes-dashboard ``` #### 修改yaml ```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: v1 kind: Namespace metadata: name: kubernetes-dashboard --- apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-certs namespace: kubernetes-dashboard type: Opaque --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-csrf namespace: kubernetes-dashboard type: Opaque data: csrf: "" --- apiVersion: v1 kind: Secret metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-key-holder namespace: kubernetes-dashboard type: Opaque --- kind: ConfigMap apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard-settings namespace: kubernetes-dashboard --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard rules: # 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: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard rules: # 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/v1 kind: RoleBinding metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: kubernetes-dashboard subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kubernetes-dashboard --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: k8s-app: kubernetes-dashboard template: metadata: labels: k8s-app: kubernetes-dashboard spec: containers: - name: kubernetes-dashboard image: kubernetesui/dashboard:v2.0.0-beta8 imagePullPolicy: Always ports: - containerPort: 8443 protocol: TCP args: - --tls-cert-file=/dashboard.crt - --tls-key-file=/dashboard.key #- --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=https://192.168.100.3:6443 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: "beta.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: Service apiVersion: v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: ports: - port: 8000 targetPort: 8000 selector: k8s-app: dashboard-metrics-scraper --- kind: Deployment apiVersion: apps/v1 metadata: labels: k8s-app: dashboard-metrics-scraper name: dashboard-metrics-scraper namespace: kubernetes-dashboard spec: 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: kubernetesui/metrics-scraper:v1.0.1 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: "beta.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: {} ``` ### 修改Service 並將內部 Cluster Ip 修改為 NodePort ``` kubectl edit service kubernetes-dashboard -n kubernetes-dashboard ``` ## Add docker private registry in K8s ### 1. 建立daemon.json後重啟docker服務 (如果private registry 沒有憑證才需要此不) /etc/docker/daemon.json ```bash= { "live-restore": true, "insecure-registries": ["<host ip>:5000"] } ``` ### 2. 建立保管docker登入資訊的Secret * 欲從private registry pull image的namespace都需建立secret ```bash= kubectl create secret docker-registry regcred / --docker-server=<your-registry-server> / --docker-username=<your-name> / --docker-password=<your-pword> / --docker-email=<your-email> -n <namespace> ``` * 建立成功後可以使用以下指令匯出該yaml檔 ```bash= kubectl get secret regcred --output=yaml ``` ### 3. 由於是Private Registry,因此需要先在所有Node執行步驟一 ### 4. 建立一個Pod測試 ```bash= apiVersion: v1 kind: Pod metadata: name: private-reg namespace: <namespace> spec: containers: - name: private-reg-container image: <your-private-image> imagePullSecrets: - name: regcred ``` ## Kubernetes Service and Deployment 範例yaml ```yaml= apiVersion: v1 kind: Service metadata: name: you_serice_name labels: app: you_serice_labels spec: type: NodePort ports: - port: you_exports protocol: TCP targetPort: you_container_service_ports selector: app: wiws_web --- apiVersion: apps/v1 kind: Deployment metadata: name: you_serice_name spec: selector: matchLabels: app: you_serice_labels replicas: 1 template: metadata: labels: app: you_serice_labels version: you_service_version spec: containers: - name: wiwsweb-test image: docker_private_registry_url/you_image_name:tag resources: limits: cpu: you_service_vcpu_core(ex. "1") memory: you_service_memory (ex. 2Gi) ports: - containerPort: you_service_ports ``` ## Import 至 Rancher ### 安裝rancher ``` $ docker run -d --restart=unless-stopped -v ${host_paht}:/var/lib/rancher:rw --privileged -p 80:80 -p 443:443 rancher/rancher:v2.5.8 ``` 等待30s~1m之後,選取Add Cluster ![](https://i.imgur.com/6Zjq3Vb.png) 在選取Other Cluster,輸入名子與選項後,會出現Import Cluster,執行命令。 ![](https://i.imgur.com/e85WUxX.png) ![](https://i.imgur.com/kJFL4u4.png) ### 一些錯誤處理的文章推薦 https://www.cnblogs.com/yangzp/p/15620155.html ###### tags:`Kubernetes` `k8s`