系列专栏声明:比较流水,主要是写一些踩坑的点,和实践中与文档差距较大的地方的思考。这个专栏的典型特征可能是 次佳实践
,争取能在大量的最佳实践中生存。
一、为什么不用 Minikube 了
用了一段时间的 Minikube,主要遇到两个问题:一是非正常重启后启动不起来,没有查出来是哪里的问题,感觉是什么资源被锁死了,非正常停机没有清理干净;二是空耗内存太多了,原本的想法是大部分应用跑在 Serverless 上所以无所谓,但实际用下来会发现还是需要一部分常驻应用的。
架构图基本和上篇是一致的,暂时先不画了,等有空再补。
二、安装 K3s
很简单的,直接一行就装好了,官方也提供了墙内源。注意这个 --docker
参数,因为我需要 Host 上跑一些额外的不方便弄进 k8s 的东西,所以指定复用 Host 上的 docker。
在用阿里云 Packer 安装时遇到了一个问题,默认用的 cgroup v1 而不是 v2,所以会报错,但不会强退,可以直接忽略。
$ curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.26.1+k3s1 INSTALL_K3S_MIRROR=cn sh -s - --docker
默认使用 root 启动的,看上去 --rootless 模式 还在实验中,所以也没有深究。即 kubectl 命令要用 sudo kubectl
,这点和 minikube 不一样。
三、使用内置的 Traefik 作为 Ingress
K3s 会直接绑定 Host 的 80 和 443 端口,没有找到相关的配置去关闭或者修改,所以要改变之前把 Host Traefik 挡在最前面的架构设计,改成让 K3s Traefik 接管外部请求。INSTALL_K3S_EXEC="server --disable traefik"
是另外的设计,并没有深究。
因此之前用 Host Traefik 解 *.example.com
的泛域名证书的方案不再适用了。需要改成每个 App 自己的 Ingress 去管理自己的证书 app01.example.com
。注意安装参数里面有一个 --tls-san
是用来处理 k8s server 和 agent 之间请求的,不是用来处理业务请求的,所以不用管它。
首先安装 cert-manager
,它会使用自己的 namespace
cert-manager:
$ curl -L "https://github.com/cert-manager/cert-manager/releases/download/v1.12.7/cert-manager.yaml" -o cert-manager.yaml
$ kubectl apply -f cert-manager.yaml
建一个 cluster-issuer.yaml
,注意是建在 default
namespace 下的,或者说和你的业务 App 建在一起:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: default
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: username@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressTemplate:
metadata:
annotations:
kubernetes.io/ingress.class: traefik
$ kubectl apply -f cluster-issuer.yaml
启动你的业务 App:
apiVersion: v1
kind: Service
metadata:
labels:
app: blog
name: blog
namespace: default
spec:
type: ClusterIP
selector:
app: blog
ports:
- port: 80
protocol: TCP
targetPort: 80
sessionAffinity: None
status:
loadBalancer: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
labels:
app: blog
name: blog
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: blog
template:
metadata:
labels:
app: blog
spec:
containers:
- image: registry.example.com/orgname/blog:1.0.0
imagePullPolicy: IfNotPresent
name: blog
resources: {}
restartPolicy: Always
准备一个强制 http 跳转到 https 的 Traefik Middleware,注意也要放在 default namespace:
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: http-redirect-to-https
namespace: default
spec:
redirectScheme:
scheme: https
permanent: true
最后设置 Certificate 和 Ingress:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: blog
namespace: default
spec:
secretName: blog
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
duration: 2160h
renewBefore: 72h
dnsNames:
- blog.example.com # 这里没有泛域名了
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: blog
namespace: default
annotations:
kubernetes.io/ingress.class: "traefik"
kubernetes.io/tls-acme: "true"
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.middlewares: default-http-redirect-to-https@kubernetescrd
# 注意这里的写法 {namespace}-{middlewareName}@kubernetescrd
spec:
rules:
- host: blog.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: blog
port:
number: 80
tls:
- hosts:
- blog.example.com
secretName: blog
然后 cert-manager 会自己去调用 letsencrypt 的 http01 challenge 获取证书,并保存在 default namespace 的 Secret
和 Certificate
中。
收工,https://blog.example.com
。
三、访问 Host 上的服务
文档 上说可以用 host.k3d.internal
,试了一下不行,改成直接用 IP 10.42.0.1
可以,没有深究。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。