k8s结合istio实现灰度发布
实现细节
准备镜像
这里使用nginx提供一个简单的页面,然后打包成一个镜像,标记tag为v1,修改页面,再次打包镜像,标记tag为v2,以此镜像做此次的示例
Dockerfile
# cat Dockerfile
FROM nginx:latest
COPY index.html /usr/share/nginx/html/
EXPOSE 80
页面
cat index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文档标题</title>
</head>
<body>
<h1>灰度发布</h1>
<p>版本:v1</p> #打完之后修改此文件,更改为v2,再次构建镜像
</body>
</html>
构建镜像
v1:
docker build -t harbor.yscloud.com/baseimg/nginx-server:v1 .
docker push harbor.yscloud.com/baseimg/nginx-server:v1
v2:
docker build -t harbor.yscloud.com/baseimg/nginx-server:v2 .
docker push harbor.yscloud.com/baseimg/nginx-server:v2
开启自动边车注入
就一条命令即可开启自动边车注入:
kubectl label namespace default istio-injection=enabled
查看开启后的状态:
# kubectl get namespace -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 10d enabled
istio-system Active 3d6h
kube-node-lease Active 10d
kube-public Active 10d
kube-system Active 10d
手动边车注入方法
istioctl kube-inject -f app-deploy-v1.yaml | kubectl apply -f -
准备yaml文件
整理流程:
1、先构建两个版本的deployment app-deploy-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server-v1
spec:
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: nginx-server
version: v1
template:
metadata:
labels:
app: nginx-server
version: v1
spec:
containers:
- name: nginx-server
image: harbor.yscloud.com/baseimg/nginx-server:v1
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1
memory: 1024Mi
requests:
cpu: 100m
memory: 100Mi
imagePullSecrets:
- name: mima
app-deploy-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server-v2
spec:
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
selector:
matchLabels:
app: nginx-server
version: v2
template:
metadata:
labels:
app: nginx-server
version: v2
spec:
containers:
- name: nginx-server
image: harbor.yscloud.com/baseimg/nginx-server:v2
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1
memory: 1024Mi
requests:
cpu: 100m
memory: 100Mi
imagePullSecrets:
- name: mima
注意:这里的新老版本的version标签一定不能一样,因为我们做的灰度发布就是根据标签进行选择pod进行访问的。
2、创建service app-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-server
labels:
app: nginx-server
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: nginx-server
sessionAffinity: None
这里要注意selector这个标签选择器,我们这里设置的标签app: nginx-server
,即所有的流量都会通过svc这个控制器流入到所有包含app: nginx-server
的pod里。
3、创建路由规则 app-destination-rule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: nginx-server
spec:
host: nginx-server
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
这里定义路由规则,定义两个版本,分别为v1和v2,这两个版本,又分别指定了一个标签,即我们说的路由规则,v1这个版本的流量是入到version: v1
,v2则入到version: v2
这个pod中
4、创建入口网关
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: nginx-server-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "nginx.yscloud.com"
这个是流量的入口,指定了hosts,这里可以写*
,也可以写具体的域名
5、创建virtualservice app-virtualservice.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx-server
spec:
hosts:
- "nginx.yscloud.com"
gateways:
- nginx-server-gateway
http:
- route:
- destination:
host: nginx-server
subset: v1
port:
number: 80
weight: 90
- destination:
host: nginx-server
subset: v2
port:
number: 80
weight: 10
timeout: 60s
retries:
attempts: 3
perTryTimeout: 2s
这个首先要绑定gateway,将流量绑定过来,然后根据destinationrule设置的规则,配置该如何请求,然后根据设置的规则,进行流量拆分,例如这里就是设置的90%的流量分发到v1版本的pod,10%的流量分发到v2。
写好yaml文件后,首先把nginx-server启动起来,即对应的两个deployment文件和service文件,然后启动destinationrule这个规则文件,最后再启动gateway和virtualservice文件。
配置https
生成自签名的证书
生成私钥
# openssl genrsa -out server.key 1024
Generating RSA private key, 1024 bit long modulus
.....++++++
............................++++++
e is 65537 (0x10001)
根据私钥生成证书申请文件csr
# openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Beijing
Locality Name (eg, city) [Default City]:Beijing
Organization Name (eg, company) [Default Company Ltd]:Onair
Organizational Unit Name (eg, section) []:Onair
Common Name (eg, your name or your server's hostname) []:nginx.yscloud.com
Email Address []:chenfei@cdvcloud.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:Onair
使用私钥对证书申请进行签名,生成证书
# openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650
Signature ok
subject=/C=CN/ST=Beijing/L=Beijing/O=Onair/OU=Onair/CN=nginx.yscloud.com/emailAddress=chenfei@cdvcloud.com
Getting Private key
配置nginx
这里需要说明下,我们服务部署完成后,所有的准备都完成后,会面临一个问题,就是外部如何访问我们的这个服务,k8s集群有几种方式可以将集群里的服务通过NodePort,Ingress,LoadBalance等映射出来,同样的istio也是通过这种方式(IngressGateway)
# kubectl get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.98.48.40 <pending> 15020:31572/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:30148/TCP,15030:31944/TCP,15031:31757/TCP,15032:30403/TCP,15443:31539/TCP 5d5h
可以看到,80端口被映射到了31380,所以我们的nginx配置如下:
upstream nginx-server {
server 192.168.1.119:31380;
server 192.168.1.120:31380;
}
server {
listen 80;
server_name nginx.yscloud.com;
location / {
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; #获取真实ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #获取代理者的真实ip
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffer_size 128k;
proxy_buffers 2 256k;
proxy_headers_hash_max_size 512;
proxy_headers_hash_bucket_size 64;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_pass http://nginx-server;
}
}
server {
listen 443;
server_name nginx.yscloud.com;
ssl on;
ssl_certificate /k8s/tls/server.crt;
ssl_certificate_key /k8s/tls/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; #获取真实ip
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #获取代理者的真实ip
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
proxy_buffer_size 128k;
proxy_buffers 2 256k;
proxy_headers_hash_max_size 512;
proxy_headers_hash_bucket_size 64;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_pass http://nginx-server;
}
}
需要注意的是: 在进行代理的时候,header里一定有host信息,即proxy_set_header Host $host;
测试
内网环境可以访问nginx.yscloud.com
这个域名,会看v1和v2出现的比例大概为9:1
如果不能访问,则需要指定DNS地址:192.168.0.88
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法