一、背景
1.1 需求
我們有這樣的一個需求,就是把 Pod 集群升級為 https,目前的辦法就是要么每個容器配置 https,然后前端通過 Service 進行調度,但是這樣配置起來會比較麻煩,以及每個容器的建立都通過 https ,也增加了建立連接的負擔。
我們需要一種這樣的改造,就是客戶端連接到 Service 是通過 https,而 Service 向后端 Pod 的調度通過 http,這樣可以極大的優化我們的集群,這里我們就需要用到 Kubernetes 的另外一種資源 Ingress。
1.2 Ingress
Ingress 就是一個負載均衡的應用,它和 Service 的不同之處在於,Service 只可以支持 4 層的負載均衡,而 Ingress 是支持 7 層的負載均衡,支持 http 和 https,包括通過主機名的訪問已經路徑訪問的過濾。
那為什么不直接使用 Nginx?這是因為在 K8S 集群中,如果每加入一個服務,我們都在 Nginx 中添加一個配置,其實是一個重復性的體力活,只要是重復性的體力活,我們都應該通過技術將它干掉。
Ingress就可以解決上面的問題,其包含兩個組件Ingress Controller
和Ingress
:
Ingress:將Nginx的配置抽象成一個Ingress對象,每添加一個新的服務只需寫一個新的Ingress的yaml文件即可;
Ingress Controller:將新加入的 Ingress 轉化成 Nginx 的配置文件並使之生效,包含 Contour、F5、HAProxy、Istio、Kong、Nginx、Traefik,官方推薦我們使用 Nginx。
1.3 環境介紹
我們是采用了三台服務器的一個集群,部署文檔請查看我之前的博文。
IP | 角色 |
---|---|
192.168.1.200 | k8s-master |
192.168.1.201 | k8s-node01 |
192.168.1.202 | k8s-node02 |
[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 117s v1.13.0
node01 Ready <none> 52s v1.13.0
node02 Ready <none> 42s v1.13.0
二、安裝部署
我們這里只針對上面架構圖中的域名www.wzlinux.com
改造成https。
我們將以官方的標准腳本為基礎進行搭建,參考請戳官方文檔。官方文檔中要求執行如下命令:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
2.1、創建后端 Pod 應用
我們創建一個控制器wzlinux-deploy.yaml
,內容如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: wzlinux-dep
spec:
replicas: 3
template:
metadata:
labels:
run: wzlinux
spec:
containers:
- name: wzlinux
image: wangzan18/mytest:v1
ports:
- containerPort: 8080
創建好之后查看如下:
[root@master ingress]# kubectl get pod
NAME READY STATUS RESTARTS AGE
wzlinux-dep-78d5d86c7c-fj8f5 1/1 Running 0 53m
wzlinux-dep-78d5d86c7c-hr6gd 1/1 Running 0 53m
wzlinux-dep-78d5d86c7c-jqf59 1/1 Running 0 53m
2.2 創建后端 Pod Service
測試好 Pod 一些正常之后,我們為這一組 Pod 創建一個 Service,文件wzlinux-svc.yaml
內容如下:
apiVersion: v1
kind: Service
metadata:
name: wzlinux-svc
spec:
selector:
run: wzlinux
ports:
- port: 80
targetPort: 8080
這個 Service 並不是我們用了代理訪問 Pod 的,只是用來ingress-controller
來進行選擇控制使用的,所以上圖描述為虛線。
[root@master ingress]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 58m
wzlinux-svc ClusterIP 10.106.219.230 <none> 8080/TCP 50m
[root@master ingress]# curl 10.106.219.230:8080
Hello Kubernetes bootcamp! | Running on: wzlinux-dep-78d5d86c7c-fj8f5 | v=1
2.3、創建 ingress 資源
為了實現過濾以及 https 功能,我們需要創建 ingress 資源文件,ingress controller 把其中的資源加載到 nginx 里面,資源文件wzlinux-ingress.yaml
文件內容如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wzlinux-ingress
spec:
rules:
- host: www.wzlinux.com
http:
paths:
- path:
backend:
serviceName: wzlinux-svc
servicePort: 8080
我們這里先不改為 https,先使用虛擬主機域名過濾模式,創建好資源之后查看
[root@master ingress]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
wzlinux-ingress www.wzlinux.com 80 37m
可以看到配置了域名www.wzlinux.com
,其他地址訪問將返回404。
2.4、為 Nginx Pod 創建 Service
我們可以查看部署的 Nginx Pod 容器,我們設定的 ingress 資源會被 controller 更新到里面,我們可以查看如下:
[root@master ingress]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-766c77b7d4-dlcpf 1/1 Running 0 31m
為了是外網可以訪問到這個 Nginx Pod,我們需要為其再創建一個 Service,文件ingress-nginx.yaml
,文件內容如下:
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: ingress-nginx
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
- name: https
port: 443
targetPort: 443
nodePort: 30443
selector:
app.kubernetes.io/name: ingress-nginx
測試是否正常,記得在/etc/hosts
中把域名執行的IP改為node節點的地址。
[root@master ~]# curl 192.168.1.200:30080
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.15.6</center>
</body>
</html>
[root@master ~]# curl www.wzlinux.com:30080
Hello Kubernetes bootcamp! | Running on: wzlinux-dep-78d5d86c7c-hr6gd | v=1
可以看到通過域名訪問正常調度到后端,其他地址訪問返回404,目前整個流程已經測試完成,下面我們升級為 https。
三、升級為 https
3.1 首先我們要制作證書
關於證書大家可以使用 openssl 制作,創建私有:
openssl genrsa -out wzlinux.key 2048
制作自簽證書。
openssl req -new -x509 -key wzlinux.key -out wzlinux.crt -subj /C=CN/ST=Shanghai/L=Shanghai/O=DevOps/CN=www.wzlinux.com
不過我這里使用阿里雲的官方免費證書,大家可以到阿里雲進行申請。
制作好證書之后下載即可,里面包含公鑰和私鑰。
3.2、創建 secret 資源
可以使用 yaml 文件創建,文件名稱wzlinux-secret.yaml
內容如下:
apiVersion: v1
kind: Secret
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
metadata:
name: wzlinux-secret
namespace: default
type: Opaque
因為編碼的密碼太長,我們這里直接使用命令行進行創建吧,操作比較簡單。
kubectl create secret tls wzlinux-secret --cert=wzlinux.crt --key=wzlinux.key
查看創建好的 secret。
[root@master ingress]# kubectl describe secret wzlinux-secret
Name: wzlinux-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1996 bytes
tls.key: 1675 bytes
3.3 更改 ingress 資源
重新編輯wzlinux-ingress.yaml
,增加一個 tls 字段:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wzlinux-ingress
spec:
tls:
- hosts:
- www.wzlinux.com
secretName: wzlinux-secret
rules:
- host: www.wzlinux.com
http:
paths:
- path:
backend:
serviceName: wzlinux-svc
servicePort: 8080
3.4 瀏覽器訪問驗證
打開瀏覽器,記得修改好 hosts 域名解析。
四、ingress 資源介紹
4.1、通過訪問路徑過濾
foo.bar.com -> 178.91.123.132 -> / foo service1:4200
/ bar service2:8080
配置文件我們設置為如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080
4.2、基於名稱解析的虛擬主機
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
配置文件內容格式如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: first.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: second.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
- http:
paths:
- backend:
serviceName: service3
servicePort: 80
4.3、https
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- sslexample.foo.com
secretName: testsecret-tls
rules:
- host: sslexample.foo.com
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 80