服务
默认 svc 和 pod, 将 latest 全局替换成 v1, v2 ,v3 就是三个不同的版本. 给 latest 多创建了一个 svc myapp1
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---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-latest
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: myapp-latest
version: latest
template:
metadata:
labels:
app: myapp-latest
version: latest
spec:
containers:
- name: myapp
image: imwl/myapp:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myapp-latest
namespace: default
spec:
selector:
app: myapp-latest
version: latest
ports:
- name: http
targetPort: 80
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp-latest
version: latest
ports:
- name: http
targetPort: 80
port: 80
同 namespace 进 pod 测试1
2
3
4
5
6
7
8
9
10
11# curl myapp-latest
Hello MyApp | Version: latest | <a href="hostname.html">Pod Name</a>
# curl myapp-v1
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
# curl myapp-v2
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
# curl myapp-v3
Hello MyApp | Version: v3 | <a href="hostname.html">Pod Name</a>
使用 header 区分
- 新建 nginx 转发, 域名得用完整的内部域名。也可以用变量注入,当前直接用 default
nginx.conf1
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
28worker_processes 1;
events {
worker_connections 65536;
}
http {
resolver kube-dns.kube-system valid=5s; # kube-dns.kube-system 有问题动态注入 pod 里 /etc/resolv.conf 里的 ip。
server {
listen 8080;
location / {
set_by_lua_block $backend {
local version = ngx.req.get_headers()["x-version"]
if version and version ~= "" then
return "myapp-" .. version .. ".default.svc.cluster.local"
end
return "myapp.default.svc.cluster.local"
}
proxy_pass http://$backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
打包镜像 Dockerfile1
2FROM openresty/openresty:alpine-slim
COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
打包1
docker buildx build --platform linux/amd64,linux/arm64/v8 -t imwl/myapp:router --push .
或者直接使用 cm
1 | --- |
引用
1 | --- |
添加外部访问(非必要)
1 | --- |
内部域名测试
1 | myapp-router-78866ffc7b-t4s4k:/# curl myapp-router |
外部域名测试1
2
3
4
5
6
7
8
9
10
11❯ curl -H 'x-version: v1' myapp-router.grafana.eu.org
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
❯ curl -H 'x-version: v2' myapp-router.grafana.eu.org
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
❯ curl -H 'x-version: v3' myapp-router.grafana.eu.org
Hello MyApp | Version: v3 | <a href="hostname.html">Pod Name</a>
❯ curl myapp-router.grafana.eu.org
Hello MyApp | Version: latest | <a href="hostname.html">Pod Name</a>
附
myapp 镜像制作
Dockerfile1
2
3
4FROM nginx:stable-alpine-slim
COPY nginx.conf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf
COPY index.html /usr/share/nginx/html/index.html
nginx.conf1
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
31user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
default.conf
1 | server { |
index.html
修改 latest 为 v1, v2, v3 等,然后分别构建1
Hello MyApp | Version: latest | <a href="hostname.html">Pod Name</a>
构建
1 | docker buildx build --platform linux/amd64,linux/arm64/v8,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le,linux/s390x,linux/riscv64 -t imwl/myapp:latest --push . |
traefik 方式
安装
helm 安装1
2
3
4
5
6
7
8
9
10helm upgrade --install traefik traefik/traefik \
--namespace kube-system --create-namespace \
--set image.registry=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io \
--set image.repository=traefik \
--set image.pullPolicy=IfNotPresent \
--set ingressRoute.dashboard.enabled=true \
--set ingressRoute.dashboard.matchRule="PathPrefix(\`/dashboard\`) || PathPrefix(\`/api\`)" \
--set ingressRoute.dashboard.entryPoints={web} \
--set providers.kubernetesGateway.enabled=true \
--set gateway.namespacePolicy=All
使用
- 创建证书
ClusterIssuer1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http01-traefik
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-http01
solvers:
- http01:
ingress:
class: traefik
申请证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: myapp-cert
namespace: default
spec:
secretName: tls-myapp-router2.grafana.eu.org
issuerRef:
name: letsencrypt-http01-traefik
kind: ClusterIssuer
commonName: myapp-router2.grafana.eu.org
dnsNames:
- myapp-router2.grafana.eu.orggateway 使用证书
1 | --- |
- ingressroute
1 |
|
仅影响外部访问
istio 方式
- cert-manager 开启网关申请证书
https://cert-manager.io/docs/configuration/acme/http01/#using-istio-gateway-api
1 | helm upgrade --install \ |
使用 http01 的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http01-istio
spec:
acme:
email: [email protected]
privateKeySecretRef:
name: letsencrypt-http01-istio
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: shared-gateway
namespace: istio-system
kind: Gateway申请证书
1
2
3
4
5
6
7
8
9
10
11
12
13---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: tls-myapp-router3.grafana.eu.org
namespace: istio-system
spec:
secretName: tls-myapp-router3.grafana.eu.org
dnsNames:
- myapp-router3.grafana.eu.org
issuerRef:
name: letsencrypt-http01-istio
kind: ClusterIssuer网关上使用证书(通配符可以使用 *.xxx.xxx http01 方式得一个一个加)
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---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
namespace: istio-system
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: myapp-router3.grafana.eu.org
port: 443
protocol: HTTPS
hostname: "myapp-router3.grafana.eu.org"
tls:
mode: Terminate
certificateRefs:
- name: tls-myapp-router3.grafana.eu.org
kind: Secret
allowedRoutes:
namespaces:
from: Allhttproute 绑定 Gateway(只影响外网访问,内网访问还需要 VirtualService)
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
36apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: myapp
namespace: default
spec:
parentRefs:
- name: shared-gateway
namespace: istio-system
hostnames:
- myapp-router3.grafana.eu.org
rules:
- matches:
- headers:
- name: x-version
value: v1
backendRefs:
- name: myapp-v1
port: 80
- matches:
- headers:
- name: x-version
value: v2
backendRefs:
- name: myapp-v2
port: 80
- matches:
- headers:
- name: x-version
value: v3
backendRefs:
- name: myapp-v3
port: 80
- backendRefs:
- name: myapp-latest
port: 80
istio 传统方式,可以一条规则同时影响内外网
安装方式, 会安装 ingressgateway
meshConfig.enableAutoMtls=false 配合 PeerAuthentication 禁用 mTLS
1 | istioctl install \ |
使用 http01 的方式, 不能使用 gateway
1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http01-istio
spec:
acme:
email: [email protected]
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-http01-istio
solvers:
- http01:
ingress:
class: istio申请证书
1
2
3
4
5
6
7
8
9
10
11
12
13---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: tls-myapp-router3.grafana.eu.org
namespace: istio-system
spec:
secretName: tls-myapp-router3.grafana.eu.org
dnsNames:
- myapp-router3.grafana.eu.org
issuerRef:
name: letsencrypt-http01-istio
kind: ClusterIssuer网关上使用证书
1 | --- |
- VirtualService 绑定网关
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
74
75
76
77
78
79
80
81
82
83
84---
## 添加 可以让内网访问 外网的 https
## 放在 istio-system 全局
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: PERMISSIVE
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myapp
namespace: default
spec:
exportTo:
- "*" # 导出到所有命名空间
hosts:
- myapp-router3.grafana.eu.org
- myapp.default
- myapp.default.svc.cluster.local
- myapp.default.svc.cluster.local.
gateways:
- mesh # istio 保留,作用于集群内部
- istio-system/shared-gateway
http:
- match:
- headers:
x-version:
exact: v1
route:
- destination:
host: myapp-v1.default.svc.cluster.local
port:
number: 80
- match:
- headers:
x-version:
exact: v2
route:
- destination:
host: myapp-v2.default.svc.cluster.local
port:
number: 80
- match:
- headers:
x-version:
exact: v3
route:
- destination:
host: myapp-v3.default.svc.cluster.local
port:
number: 80
## 外部禁止访问
- match:
- gateways:
- istio-system/shared-gateway
uri:
prefix: /api/internal/
route:
- destination:
host: deny.default.svc.cluster.local
port:
number: 80
## 内部可以访问
- match:
- gateways:
- mesh
uri:
prefix: /api/internal/
route:
- destination:
host: myapp-latest.default.svc.cluster.local
port:
number: 80
# fallback:选一个稳定版本
- route:
- destination:
host: myapp-latest.default.svc.cluster.local
port:
number: 80
附,配合流水线
1 | #!/bin/bash |