This page looks best with JavaScript enabled

Kubernetes 部署小记

 ·  ☕ 4 min read  ·  ✍️ 鱼子盖饭 · 👀... views

服务器快到期了,上面的博客,以及自用的 Bitwarden、Standardnotes、Aria2 等开源应用都需要迁移,其实只需要把数据同步过去就行了,但为了紧跟时代步伐,探索学习新技术,因此决定采用 k8s 来部署

官网的介绍看起来就十分的 Powerful ,让人跃跃欲试哈哈!

QQ截图20200430105201.jpg

以前也曾想学习下 k8s,被配置文件劝退,一长串的选项,虽然有注释,感觉学习成本还是很高。。

但用过 Docker Compose 之后,对容器编排有了一定认识,再来看 k8s 的配置文件,就熟悉多了,结构也清晰了

服务器环境

新服务器是 GCP 的 g1-small,作为 Master 节点

  • 1vCPU
  • 1.7G 内存
  • Ubuntu 18.04

配置 k8s 环境

参考文章:kubernetes-tutorial

安装 minikube

下载最新版

1
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

安装 kubectl

1
curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/

启动 minikube

k8s 1.18 需要安装 conntrack

1
sudo apt install conntrack

然后执行

1
sudo minikube start --vm-driver=none --extra-config=kubeadm.ignore-preflight-errors=NumCPU
  • --vm-driver=none 使用自己的环境,Linux 下不依赖虚拟机启动
  • --extra-config=kubeadm.ignore-preflight-errors=NumCPU k8s 需要至少 2 核的 CPU 来运行,但 1 核也是能跑的,忽略掉

QQ截图20200430112210.jpg

持久卷 Persistent Volumn(PV)

参考文章:在K8S中使用Local持久卷

容器内产生的数据会随着容器被 kill 掉而消失,将本地目录作为卷挂载到容器内部,可以将容器内的数据持久化

k8s 支持多种类型的卷,包括云存储,这里我用本地目录创建 PV

StorageClass

首先编写 Local 的 Storage Class 配置文件 storage-class.yaml:

1
2
3
4
5
6
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
    name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

执行命令以创建:

1
sudo kubectl create -f storage-class.yml

PersistentVolumn

PV 是系统管理员设置的存储,它是群集的一部分,是一种资源,有独立于 Pod 的生命周期

为了在本地将每个服务的目录区分开,我单独为每个服务创建了一个 PV,这个 PV 将用于 standardfile 服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: PersistentVolume
metadata:
    name: local-pv-sf
spec:
    capacity:
        storage: 5Gi
    accessModes:
    - ReadWriteOnce
    persistentVolumeReclaimPolicy: Retain
    storageClassName: local-storage
    local:
        path: /data/pv/sf
    nodeAffinity:
        required:
            nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                  - prpr
...
  • storage PV 的大小
  • path 作为挂载的本地目录,需要先手动创建
  • nodeAffinity Local PV 必须配置的一项,value 为节点名,可执行 sudo kubectl get nodes 查看

PersistentVolumnClaim

PVC 是用户存储的请求。它与 Pod 相似,Pod 消耗节点的 CPU 和内存资源,PVC 则消耗 PV 资源,可以生命特定的容量大小和访问模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: pvc-sf
spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: local-storage
    resources:
        requests:
            storage: 5Gi
  • 我将该 PVC 命名为 pvc-sf 供下面 standardfile 服务使用

服务

以 standardfile 为例,该服务为 Standard Notes 提供同步服务,需要暴露端口和挂载卷

Pod

首先配置 Pod 模板,Pod 是 k8s 中可以调度的最小单位,可以包含多个容器,这里我只需要一个容器就够了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
...
metadata:
    labels:
        app: standardfile
spec:
    containers:
    - image: standardfile:latest
        imagePullPolicy: Never
        name: standardfile
        ports:
        - containerPort: 8888
            name: standardfile
        volumeMounts:
        - mountPath: "/data"
            name: storage
    restartPolicy: Always
    volumes:
        - name: storage
            persistentVolumeClaim:
                claimName: pvc-sf
  • standardfile:latest 这个镜像由我自己在本地构建
  • imagePullPolicy: Never 只从本地获取镜像
  • containerPort 指定容器的 8888 端口
  • volumeMounts 将名为 storage 的卷挂载到容器内的 /data 目录
  • volumes 申请一个名为 pvc-sf 的持久卷,并命名为 storage

Deployment

然后是 Deployment 的一些选项,表明该如何运行 Pod:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: apps/v1
kind: Deployment
metadata:
    name: standardfile
spec:
    replicas: 1
    selector:
        matchLabels:
        app: standardfile
    template:
...
  • replicas 创建多少个 Pod 副本,k8s 将始终保持该数量的 Pod 可用,用于横向扩展和负载均衡
  • selector 选择部署的 Pod
  • template 也就是上面的 Pod 模板

Service

最后是服务:

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Service
metadata:
    name: standardfile
spec:
    ports:
    - port: 8888
    selector:
        app: standardfile
  • ports 该服务监听 8888 端口
  • selector 该服务部署名为 standardfile 的 Deployment

创建

由于之前创建的 PV 和 PVC 都是为该服务使用的,因此我将它们的配置加了进来,完整的 standardfile-service.yaml 就是下面这个样子:

 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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
apiVersion: v1
kind: Service
metadata:
    name: standardfile
spec:
    ports:
    - port: 8888
    selector:
        app: standardfile
---
apiVersion: apps/v1
kind: Deployment
metadata:
    name: standardfile
spec:
    replicas: 1
    selector:
        matchLabels:
            app: standardfile
    template:
        metadata:
            labels:
                app: standardfile
        spec:
            containers:
            - image: standardfile:latest
              imagePullPolicy: Never
              name: standardfile
              ports:
              - containerPort: 8888
                name: standardfile
              volumeMounts:
              - mountPath: "/data"
                name: storage
            restartPolicy: Always
            volumes:
                - name: storage
                  persistentVolumeClaim:
                  claimName: pvc-sf
---
apiVersion: v1
kind: PersistentVolume
metadata:
    name: local-pv-sf
spec:
    capacity:
        storage: 5Gi
    accessModes:
    - ReadWriteOnce
    persistentVolumeReclaimPolicy: Retain
    storageClassName: local-storage
    local:
        path: /data/pv/sf
    nodeAffinity:
        required:
            nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                  - prpr
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: pvc-sf
spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: local-storage
    resources:
        requests:
            storage: 5Gi

按照官方的说法,默认的选项没必要写上去,保持最小配置就是最好的

1
sudo kubectl apply -f standardfile-service.yaml

即可将 Service、Deployment、PV、PVC 一起创建

查看状态:

1
2
sudo kubectl get pod/deployment/service/pv/pvc
sudo kubectl describe pod/deployment/service/pv/pvc

扩展

其它类似服务比如 Bitwarden、Nginx 等也可以通过修改名称、端口、挂载路径等值直接使用该 yaml 配置

Ingress

服务创建好之后,由于 IP 地址是由 k8s 分配的,没有到公网的路由,因此外部需要通过 Ingress 访问内部服务

Ingress 公开了从集群外部到集群内 services 的HTTP和HTTPS路由,流量路由由 Ingress 资源上定义的规则控制,同时 Ingress 还能提供 TLS 和负载均衡

我采用的是 k8s 维护的 ingress-nginx 控制器

为 TLS 证书创建 Secret

k8s 的密钥等保密信息都不直接卸载配置文件里,而是通过 Secret 传递

证书的申请方法我依然用的是这个 通过 Let’s Encrypt 自己申请了个 CA 证书 (是真的好用)

根据申请下来的证书路径创建 Secret,首先是用于主域名的 tls-prpr

1
sudo kubectl create secret tls tls-prpr --cert /path/to/cert --key /path/to/key

然后是用于子域名的 tls-sub-prpr

1
sudo kubectl create secret tls tls-sub-prpr --cert /path/to/cert --key /path/to/key

编写配置文件

编辑 ingress.yaml,我用的另一个域名 shiranui.dance 做的测试

 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
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: prpr-ingress
  #  annotations:
  #    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - sn.shiranui.dance
    - cloud.shiranui.dance
    - web.shiranui.dance
    secretName: tls-sub-prpr
  rules:
  - host: sn.shiranui.dance
    http:
      paths:
      - path: /
        backend:
          serviceName: standardfile
          servicePort: 8888
  - host: cloud.shiranui.dance
    http:
      paths:
      - path: /
        backend:
          serviceName: v2ray
          servicePort: 43210
  - host: web.shiranui.dance
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 8080

创建 Ingress

启用 Ingress:

1
sudo minikube addons enable ingress

创建 Ingress:

1
sudo kubectl create -f ingress.yaml

查看 Ingress:

1
sudo kubectl describe ingress prpr-ingress

QQ截图20200430141202.jpg

一共测试了三个服务,其中 web 是 k8s 的一个用例,返回一个页面

QQ截图20200430141529.jpg

说明证书也成功启用!

结语

总算是跑起来了,这两天看了大量的的文档和文章,英语阅读能力也进步了很多哈哈

有些时候实现一个目标有简单模式和困难模式,不应该害怕折腾,每一次挣扎都是成长。

Get into trouble, make mistakes.

附上一张 Dashboard

2020-04-29_22-31.jpg


鱼子盖饭
WRITTEN BY
鱼子盖饭
Get into trouble, make mistakes.


What's on this Page