小服务器部署 K3s 并部署微服务实践
一、为什么是 K3s
我有一台 2C2G 的云服务器,跑一些个人项目。想用来学习一下 k8s,顺便把我跑的那些项目都迁到 k8s 上,但是看了一下性能要求,估计是撑不住,后来我发现了一个叫 k3s 的东西。
k3s 是 Rancher 推出的轻量级 Kubernetes 发行版,我理解就是 low 一些的 k8s,保留了核心功能,性能消耗会低很多。虽然感觉还是有点压力,因为它还要求要关闭虚拟内存,但跑通应该问题不大。
二、名词学习:Pod、Service、Namespace
虽然 K3s 兼容 Kubernetes API,但我之前对 k8s 本身也只停留在"知道是管容器的"这个层面。借着这个机会,认真学了一遍核心概念。
2.1 Namespace:逻辑隔离
Namespace 是 Kubernetes 里最基础的隔离单元。一个集群里可以划分多个 Namespace,资源互不干扰。
# 创建 namespace
kubectl create namespace simpfamily挺好理解的,可以用 Namespace 按环境(dev / prod)或按项目拆分,执行命令例如kubectl get pods 的时候加上 -n 参数来表示指定某个 Namespace 下的东西进行操作。
apiVersion: v1
kind: Namespace
metadata:
name: simpfamily2.2 Pod:最小部署单元
Pod 是 Kubernetes 里能调度的最小单元。对于 docker-compose,每个容器直接裸跑;在 k8s 里,一个 Pod 可以包含一个或多个容器,共享网络和存储。
但实际很少直接创建 Pod,而是用 Deployment 来管理,因为 Deployment 提供了自愈、扩缩容、滚动更新等核心能力:
apiVersion: apps/v1
kind: Deployment
metadata:
name: simpfamily-ledger
namespace: simpfamily
spec:
replicas: 1
selector:
matchLabels:
app: simpfamily-ledger
template:
metadata:
labels:
app: simpfamily-ledger
spec:
containers:
- name: ledger
image: xxxx
ports:
- containerPort: 8080
env:
- name: DB_URL
value: "mysql://..."例如通过调整 replicas,就可以控制服务扩缩容,非常方便。如果某个 pod 挂了,也会自动重启,直至有 replicas 数量的 pod。
2.3 Service:稳定的网络入口
Pod 是会飘的——滚动更新、节点故障、手动删除重建,Pod 的 IP 都会变。Service 就是给一组 Pod 提供一个稳定的虚拟 IP 和 DNS 名称。
apiVersion: v1
kind: Service
metadata:
name: simpfamily-ledger-svc
namespace: simpfamily
spec:
selector:
app: simpfamily-ledger
ports:
- port: 80
targetPort: 8080
type: ClusterIPService 通过 selector 匹配 pod 的 labels,流量自动转发到对应的 pod。其他服务只需要访问 simpfamily-ledger-svc 就行,不用关心 pod 在哪里。
三、编写配置文件
有了上面的基础,我开始写一个完整的微服务部署配置。
3.1 ConfigMap 和 Secret
配置和敏感信息需要分开管理。非敏感配置用 ConfigMap,密码、证书用 Secret:
apiVersion: v1
kind: ConfigMap
metadata:
name: simpfamily-config
namespace: simpfamily
data:
APP_ENV: "production"
LOG_LEVEL: "info"
JAEGER_ENDPOINT: "http://jaeger-collector.monitoring:14268/api/traces"
---
apiVersion: v1
kind: Secret
metadata:
name: simpfamily-secret
namespace: simpfamily
type: Opaque
stringData:
DB_PASSWORD: "password"
JWT_SECRET: "jwt-secret"3.2 Ingress:对外暴露服务
要让外部访问服务,需要 Ingress。K3s 自带 Traefik 作为默认 Ingress Controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simpfamily-ingress
namespace: simpfamily
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: traefik
tls:
- hosts:
- api.simplife.tech
secretName: simpfamily-tls
rules:
- host: api.simplife.tech
http:
paths:
- path: /ledger
pathType: Prefix
backend:
service:
name: simpfamily-ledger-svc
port:
number: 80四、部署 HTTPS 证书
证书我用了 cert-manager,它会在集群内自动申请和续期 Let’s Encrypt 证书。
配置 ClusterIssuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- http01:
ingress:
class: traefik搞定之后,Ingress 的 tls 段会自动触发 cert-manager 去申请证书。证书生成后存在 Secret 里,Traefik 会自动使用。
# 查看证书状态
$ kubectl get certificate -n simpfamily
NAME READY SECRET AGE
simpfamily-tls True simpfamily-tls 12h整个过程全自动,到期前 cert-manager 会自动续期。比自己手动跑 certbot、挂 cron 任务省心太多了。
五、微服务上线
部署完成后,通过 Ingress 域名访问,服务正常运行。
期间遇到了内存打满的情况,重启服务器才解决,且多次出现,刚开始时候占用内存1.4G,过个几周就会撑爆,后面查到有人也出现过这个问题,是有个东西有 bug 要升级一下,忘了当时升级的啥了,总之是解决了。