目录:网上冲浪指南

如何在一台 1 核 1G 的服务器上部署 Kubernetes

2020/03/03

K3s 是一个非常轻量的 Kubernets 替代品,你甚至能够运行在 500M 内存的设备上部署 K3s。刚好最近我的工作也会慢慢变得跟 Kubernetes 相关,所以决定在之前购买的一台 1 核 1G 的 VPS 上部署一个 K3s 来熟悉一下 Kubernetes 生态。

Install

这里可以按照 K3s 官网给的脚本来安装:

curl -sfL https://get.k3s.io | sh -
# Check for Ready node, takes maybe 30 seconds
k3s kubectl get node

但是我的服务器系统是 Arch Linux,所以可以很愉快的使用包管理器安装:

pacman -S k3s-bin

安装完成后可以通过下面的命令查看 Systemd Unit 文件的路径:

sudo systemctl status k3s

K3s 开箱自带了一些必备的组件,例如 flannel、CoreDNS、Traefik,这些功能的默认配置位于 /var/lib/rancher/k3s/server/manifests。但是我发现每次 K3s 重启都会覆盖我对这些配置文件的修改,所以如果需要对这些功能的默认配置进行修改的话,可以通过修改 Systemd Unit 文件自定义启动参数,从而禁用掉需要自定义的组件。例如,我想自己安装 Traefik,只需要将启动命令修改为 k3s server --no-deploy traefik

接下来我们就可以启动 K3s 了:

sudo systemctl start k3s

Configuration

经过我的折腾发现,想要修改 K3s 中 Kubernetes 的一些配置跟着 K3s 文档做大多都会以失败告终,反而跟着 Kubernetes 官方的文档来做很容易就可以实现预期的效果。

远程访问 K3s

/etc/rancher/k3s/k3s.yaml 从 VPS 上复制到自己电脑上的 ~/.kube/config 文件,然后你就可以在本地电脑上使用 kubectl 来远程管理集群了!

私有镜像仓库

这里完全可以参照 Kubernetes 的文档来操作。如果按照 K3s 提供的办法来修改 registries.toml,那么在配置有问题的时候,你就会发现 K3s 循环重启,并且占用大量的 CPU 最终导致被 VPS 商家降频

安装 Traefik

其实 K3s 的 manifests 目录下都是 helm 配置文件,K3s 默认在启动的时候会使用 helm 部署 manifests 下面的组件,例如 Traefik。我选择自己通过 helm 安装 Traefik,这样修改配置起来是最方便的,通过 helm 安装最好的方式就是查看 helm 仓库中的 README

首先我们需要准备一份 values.yaml,这是 Traefik 的 helm 模板变量:

values.yaml
ssl:
  enabled: true # 启用 https endpoint
rbac:
  enabled: true # 来自 k3s 的默认配置
kubernetes.ingressEndpoint.useDefaultPublishedService: "true" # 来自 k3s 的默认配置
resources: # 限制 Traefik 的资源使用
  limits:
    memory: 128Mi
    cpu: 100m
  requests:
    memory: 32Mi
    cpu: 50m
dashboard:
  enabled: true
  domain: traefik.your-domain.com # Traefik 面板域名
  auth:
    basic:
      aUserName: encoded-password-with-htpasswd # 安装 apache-tools 使用 htpasswd 来编码密码
acme:
  enabled: true # 启用 Let's Encrypt 证书
  staging: false # 禁用测试证书 (1)
  logging: true
  email: [email protected] # Let's Encrypt 申请证书时使用的邮箱
  challengeType: "dns-01" # 通过 DNS 的方式来验证
  dnsProvider:
    name: cloudflare (2)
    cloudflare:
      CLOUDFLARE_API_KEY: xxxx
      CLOUDFLARE_EMAIL: xxxxx
  domains:
    enabled: true
    domainsList:
      - main: "*.your-domain.com" # 为所有的子域名生成一个证书
      - sans:
        - "your-domain.com" # 根域名与子域名使用同一个证书
1 acme.staging 默认为 true,这会让 Let’s Envrypt 签发一个 FAKE 证书。当你准备好正式面对互联网的时候,记得将其设置为 false
2 这里填你的 DNS 服务商的名字,具体的支持列表请看 这里

然后就可以通过下面的两条命令来安装与修改 Traefik 了:

helm install traefik --namespace kube-system --values values.yaml stable/traefik

helm upgrade traefik stable/traefik -f values.yaml -n kube-system

部署博客系统

说起来你可能不信,我的博客系统目前一共有 3 个服务

  • pgsql 数据库

  • text-maid 文本渲染引擎

  • blog-server 博客网站

这些服务之前都是使用单个 docker-compose.yaml 来部署的,可以使用一个叫做 kompose 的工具将 docker-compose.yaml 转换成对应的 Kubernetes 配置文件。

yay -S kompose-bin

当然,直接这么转换出来的配置文件并不好使,还需要进行一些简单地修改。

创建命名空间

因为之后可能还会有更多的服务(例如站内搜索)加入,所以还是创建一个单独的命名空间来管理吧。

blog-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: blog

持久化数据库数据

K3s 自带了一个 local-path-provisioner,然而这个东西我整了半天还是没能成功挂载数据库文件,最终还是用了 Kubernetes 的本地卷存储,配置简单,也是开箱即用:

blog-data-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: blog-data-pv
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 300Mi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/path/to/blogdata"

光有 PV 还不够,还得创建一个 PVC 让 Pod 来使用刚刚创建的 PV。

blog-data-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: blog-data-pvc
  namespace: blog
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: manual
  resources:
    requests:
      storage: 200Mi

部署数据库

这里用数据库来举例说明一下我是如何部署这些服务的,前面的 kompose 为 pgsql 服务生成了两份文件:deployment.yaml 与 service.yaml,分别用来描述 pgsql 服务的部署方式以及网络访问方式,这里我将这两个文件合并到了一起,方便管理,其他的服务也进行了类似的处理,故不再赘述。

pgsql.yaml
apiVersion: v1
kind: Service
metadata:
  name: pgsql
  namespace: blog
spec:
  selector:
    app: pgsql
  ports:
    - protocol: TCP
      port: 5432

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pgsql
  namespace: blog
spec:
  selector:
    matchLabels:
      app: pgsql
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      namespace: blog
      labels:
        app: pgsql
    spec:
      containers:
      - image: postgres:12-alpine
        name: pgsql
        resources: (1)
          limits:
            memory: 256Mi
            cpu: 100m
          requests:
            memory: 32Mi
            cpu: 50m
        volumeMounts:
        - mountPath: /var/lib/postgresql/data
          name: blogdata
      restartPolicy: Always
      volumes:
      - name: blogdata
        persistentVolumeClaim:
          claimName: blog-data-pvc
1 因为服务器资源紧张,所以 limits 与 requests 之间留有较大的浮动空间,避免 pgsql 部署失败

部署 Ingress

Traefik 会在 kube-system 中监控整个 K3s 集群中的 Ingress,并为这些 Ingress 创建对应的路由,所以我们只需要在 blog 命名空间中创建一个 Ingress 就可以了。

ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: traefik-ingress
  namespace: blog
spec:
  rules:
  - host: gianthard.rocks
    http:
      paths:
      - path: /
        backend:
          serviceName: blog-server (1)
          servicePort: 80
  1. 因为在同一个命名空间内,所以不需要使用命名空间前缀就可以访问对应的服务

部署成功后,你可以登录 Traefik 的面板查看这个 Ingress 的相关信息:

cWo8QWA

容器、镜像管理

K3s 默认直接使用 containerdrunC 来管理容器以及镜像,你也可以在安装的时候切换成 Docker,不过我不准备继续用 Docker 了,所以也没办法继续使用 Docker 命令行工具来管理容器跟镜像。

k3s crictl

K3s 内置了一个 CRI 的客户端,可以通过 k3s crictl --help 查看相关的说明。

buildah

除了管理集群内的镜像外,有时候还需要自己构建镜像,这时候就可以使用 buildah 来完成这项工作。buildah 是一个用来构建 OCI 容器镜像的工具,可以直接使用 Dockerfile 来构建镜像,同时也支持镜像的推送、拉取功能。

目前 K3s 还不支持使用 buildah 来管理镜像与容器,所以只用 buildah 构建、推送镜像就好。

buildah 通常跟 podman 一起使用,后者是一款无需 root 权限就可以运行 OCI 容器的工具,日后有机会再深入体验。

最后

经过一番折腾,我的博客站点终于运行在了 K3s 之上,VPS 总体内存占用上升了 200M,果然再轻量的 Kubernetes 都比 Swarm 要消耗资源。为什么我要在 1 核 1G 的 VPS 上折腾 K3s,因为 K3s 就在那里。