---
url: /diary/k8s/03/index.md
description: Kubernetes 学习笔记第三篇，K8S 集群部署实践，包括 Deployment、Service、Ingress 等资源的配置与应用发布。
---
> \[!note]
> 接上文

## 部署应用到集群中

### 部署应用yaml文件

仍以 `hexo` 镜像部署为例

1. 新建`hexo-deployment.yaml`文件，内容如下：

   ```yaml
   apiVersion: apps/v1
   kind: Deployment #部署类型 Deployment
   metadata:
     name: hexo-deployment #部署名称 
     labels:
       app: hexo #应用名称
   spec:
     replicas: 3 #实例 即部署多少个
     selector:
       matchLabels:
         app: hexo # 用来查找关联的 Pod，所有标签都匹配才行
     template:
       metadata:
         labels:
           app: hexo
       spec:
         containers:
         - name: hexo #容器名称
           image: taskbjorn/hexo #镜像
           ports:
           - containerPort: 4000 #hexo访问端口
   ```
2. 部署

   ```shell
   [root@master k8s]# kubectl apply -f hexo-deployment.yaml
   deployment.apps/hexo-deployment created
   ```
3. 查看启动情况

   ```shell
   [root@master service]# kubectl get pods
   NAME                               READY   STATUS    RESTARTS   AGE
   hexo-deployment-7d7d578cbd-2sjrj   1/1     Running   0          37m
   hexo-deployment-7d7d578cbd-5gk52   1/1     Running   0          37m
   hexo-deployment-7d7d578cbd-7x76w   1/1     Running   0          37m
   hexo-deployment-7d7d578cbd-d7kpl   1/1     Running   0          37m

   #包含系统应用
   [root@master service]# kubectl get pod --all-namespaces -o wide
   NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE   IP                NODE     NOMINATED NODE   READINESS GATES
   default       hexo-deployment-7d7d578cbd-2sjrj   1/1     Running   0          36m   10.244.2.2        node2    <none>           <none>
   default       hexo-deployment-7d7d578cbd-5gk52   1/1     Running   0          36m   10.244.2.3        node2    <none>           <none>
   default       hexo-deployment-7d7d578cbd-7x76w   1/1     Running   0          36m   10.244.1.3        node1    <none>           <none>
   default       hexo-deployment-7d7d578cbd-d7kpl   1/1     Running   0          36m   10.244.1.2        node1    <none>           <none>
   kube-system   coredns-6d8c4cb4d-5mkjb            1/1     Running   0          39m   10.244.0.2        master   <none>           <none>
   kube-system   coredns-6d8c4cb4d-9b2n5            1/1     Running   0          39m   10.244.0.3        master   <none>           <none>
   kube-system   etcd-master                        1/1     Running   5          40m   192.168.171.130   master   <none>           <none>
   kube-system   kube-apiserver-master              1/1     Running   5          40m   192.168.171.130   master   <none>           <none>
   kube-system   kube-controller-manager-master     1/1     Running   0          40m   192.168.171.130   master   <none>           <none>
   kube-system   kube-flannel-ds-7rccn              1/1     Running   0          38m   192.168.171.131   node1    <none>           <none>
   kube-system   kube-flannel-ds-fnnz2              1/1     Running   0          38m   192.168.171.132   node2    <none>           <none>
   kube-system   kube-flannel-ds-frcq8              1/1     Running   0          39m   192.168.171.130   master   <none>           <none>
   kube-system   kube-proxy-h8bgs                   1/1     Running   0          39m   192.168.171.130   master   <none>           <none>
   kube-system   kube-proxy-nxnn6                   1/1     Running   0          38m   192.168.171.131   node1    <none>           <none>
   kube-system   kube-proxy-wgv67                   1/1     Running   0          38m   192.168.171.132   node2    <none>           <none>
   kube-system   kube-scheduler-master              1/1     Running   5          40m   192.168.171.130   master   <none>           <none>
   ```

   `running`代表启动成功。

### Service

#### 特性

* service 通过label 关联对应的pod
* service 不会因为pod变化而变化
* 提供负载均衡，自动转发到不容的pod
* 可对集群外部提供端口的访问
* 集群内可以通过服务名称访问

#### 创建Service

1. 创建一个 Service，通过标签 `hexo` 跟对应的 Pod 关联上，这里保存文件名为 `hexo-service.yaml`:

   ```shell
   apiVersion: v1
   kind: Service
   metadata:
     name: hexo-service
   spec:
     selector:
       app: hexo
     type: NodePort
     ports:
       - port: 4000        # 本 Service 的端口
         targetPort: 4000  # 容器端口
         nodePort: 31000   # 节点端口 范围固定 30000-32767
   ```
2. 启用service

   ```shell
   [root@master service]# kubectl apply -f hexo-service.yaml
   service/hexo-service created
   ```
3. 查看service

   ```shell
   [root@master service]# kubectl get svc
   NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
   hexo-service   NodePort    10.110.151.215   <none>        4000:31000/TCP   42m
   kubernetes     ClusterIP   10.96.0.1        <none>        443/TCP          47m
   ```
4. 外部访问

   ```shell
   [root@master service]# curl 192.168.171.130:31000
   <!DOCTYPE html>
   <html>
   <head>
     <meta charset="utf-8">



     <title>Hexo</title>
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
     <meta property="og:type" content="website">
   <meta property="og:title" content="Hexo">
   <meta property="og:url" content="http://example.com/index.html">
   #以下省略
   ```

   ```shell
   [root@node1 ~]# curl 192.168.171.131:31000
   <!DOCTYPE html>
   <html>
   <head>
     <meta charset="utf-8">


     <title>Hexo</title>
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta property="og:type" content="website">
   <meta property="og:title" content="Hexo">
   #以下省略
   ```

   ```shell
   [root@node1 ~]# curl 192.168.171.132:31000
   <!DOCTYPE html>
   <html>
   <head>
     <meta charset="utf-8">


     <title>Hexo</title>
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta property="og:type" content="website">
   <meta property="og:title" content="Hexo">
   <meta property="og:url" content="http://example.com/index.html">
   <meta property="og:site_name" content="Hexo">
   <meta property="og:locale" content="en_US">
   <meta property="article:author" content="John Doe">
   #以下省略
   ```

## 部署K8S dashboard

`Kubernetes Dashboard` is a general purpose, ==web-based== `UI` for `Kubernetes clusters`. It allows users to manage applications
running in the cluster and troubleshoot them, as well as manage the cluster itself.

`Kubernetes 仪表板` 是 `Kubernetes 集群`的基于 ==Web== 的通用 `UI`。它允许用户管理集群中运行的应用程序并对其进行故障排除，以及管理集群本身。

### 安装

#### 官方

```shell
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
```

> \[!note]
> 上述为官方安装方法，可能有很多问题，推荐使用下种方法

#### 推荐

将以下内容写入文件`recommended.yaml` 后使用 `kubectl apple -f recommended.yaml` 命令执行

```yaml :collapsed-lines
# 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:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001 #映射到host的30001端口
  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.2.0
          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
        #type: master
      # 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.6
          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: { }
```

其中，修改了service对外映射端口到 `30001`。

查看dashboard 所在节点：

```shell
[root@master service]# kubectl get pod --namespace=kubernetes-dashboard -o wide
NAME                                         READY   STATUS             RESTARTS        AGE   IP           NODE    NOMINATED NODE   READINESS GATES
dashboard-metrics-scraper-577dc49767-zhwbt   0/1     CrashLoopBackOff   7 (4m23s ago)   20m   10.244.2.7   node2   <none>           <none>
kubernetes-dashboard-6bd77794f-fvbw2         1/1     Running            0               20m   10.244.1.9   node1   <none>           <none>
```
