在 AWS 使用 Kubernetes 的 Nginx Ingress

安装 Nginx Ingress

  在 AWS 推荐使用 kops 安装 Kubernetes 集群,具体可以参见这篇文章。接着,在 Kubernetes 集群安装 Nginx Ingress:

1
$ kubectl create -f https://raw.githubusercontent.com/kubernetes/kops/master/addons/ingress-nginx/v1.6.0.yaml

  上面的操作会为 Nginx Ingress 创建一个 ELB,这个 ELB 工作在 4 层,即监听 TCP 的 80 和 443 端口:

1
2
3
$ kubectl get services ingress-nginx -n kube-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx LoadBalancer 100.64.216.197 a81aaecb30bea... 80:32128/TCP,443:31454/TCP 1m

前端代理

  Nginx Ingress 主要用来充当前端代理,它可以根据域名以及 URL 路径,将集群外部的流量路由到集群内部的 Service。下面部署一个简单的 Service:

1
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/images/echoheaders/echo-app.yaml

  接着,为这个 Service 创建一个 Ingress 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat echoheaders-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echoheaders
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: echoheaders.umlife.net
http:
paths:
- path: /
backend:
serviceName: echoheaders
servicePort: 80
$ kubectl apply -f echoheaders-ingress.yaml

  可以查看这个 Ingress 对应的 ELB 地址:

1
2
3
$ kubectl get ing -o wide
NAME HOSTS ADDRESS PORTS AGE
echoheaders echoheaders.umlife.net a81aaecb30bea11e8a3ea0295ea9b1d4-315454571.cn-north-1.elb.amazonaws.com.cn 80 6m

  可以使用下面的命令检验 Ingress 是否正常工作:

1
$ curl -H "Host: echoheaders.umlife.net" http://a81aaecb30bea11e8a3ea0295ea9b1d4-315454571.cn-north-1.elb.amazonaws.com.cn

使用 Let’s Encrypt 和 kube-lego 配置 HTTPS 证书

  可以使用 kube-lego 自动创建和更新 Let’s Encrypt 的证书,下面是 kube-lego 的安装步骤:

1
2
3
4
5
6
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/kube-lego/master/examples/nginx/lego/00-namespace.yaml
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/kube-lego/master/examples/nginx/lego/configmap.yaml
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/kube-lego/master/examples/nginx/lego/service-account.yaml
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/kube-lego/master/examples/nginx/lego/cluster-role.yaml
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/kube-lego/master/examples/nginx/lego/cluster-role-binding.yaml
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/kube-lego/master/examples/nginx/lego/deployment.yaml

  在 DNS 服务器增加一条 CNAME 记录,将echoheaders.umlife.net解析到 ELB 的地址。接着,修改 Ingress 的配置,让 kube-lego 自动生成证书,并且在证书过期时,能够自动更新证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ cat echoheaders-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echoheaders
annotations:
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- echoheaders.umlife.net
secretName: echoheaders-tls
rules:
- host: echoheaders.umlife.net
http:
paths:
- path: /
backend:
serviceName: echoheaders
servicePort: 80
$ kubectl apply -f echoheaders-ingress.yaml

  在浏览器访问echoheaders.umlife.net,就可以看到已经配置好 HTTPS 证书了。

配置 HTTP 基本认证

  在配置 HTTP 认证之前,需要生成 htpasswd 文件:

1
$ htpasswd -bc auth my-name my-password

  接着,创建一个 Secret 配置:

1
$ kubectl create secret generic my-basic-auth --from-file=auth

  最后,修改 Ingress 的配置:

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
$ cat echoheaders-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echoheaders
annotations:
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/auth-type: basic
ingress.kubernetes.io/auth-secret: my-basic-auth
spec:
tls:
- hosts:
- echoheaders.umlife.net
secretName: echoheaders-tls
rules:
- host: echoheaders.umlife.net
http:
paths:
- path: /
backend:
serviceName: echoheaders
servicePort: 80
$ kubectl apply -f echoheaders-ingress.yaml

  在浏览器打开echoheaders.umlife.net,输入认证信息之后,就可以访问页面了。

手动配置 HTTPS 证书

  除了使用 Let’s Encrypt 自动生成证书之外,还可以手动配置 HTTPS 证书。下面的命令创建一个 Secret 配置,用来存储证书:

1
$ kubectl create secret tls umlife.net-tls --key STAR_umlife_net.key --cert STAR_umlife_net.full.crt

  修改 Ingress 的配置,让它使用我们自己提供的证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cat echoheaders-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: echoheaders
annotations:
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/auth-type: basic
ingress.kubernetes.io/auth-secret: my-basic-auth
spec:
tls:
- hosts:
- echoheaders.umlife.net
secretName: umlife.net-tls
rules:
- host: echoheaders.umlife.net
http:
paths:
- path: /
backend:
serviceName: echoheaders
servicePort: 80
$ kubectl apply -f echoheaders-ingress.yaml

使用 OpenTracing 追踪调用链

  借助 OpenTracing,我们可以从一个完整调用链中,分析出是哪个环节耗时最长。首先需要安装 Zipkin:

1
$ kubectl create -f https://raw.githubusercontent.com/rnburn/zipkin-date-server/master/kubernetes/zipkin.yaml

  默认情况下,Nginx Ingress 没有开启 OpenTracing 的功能,我们可以修改 Ingress 的配置,开启 OpenTracing 功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cat ingress-nginx-conf.yaml
apiVersion: v1
data:
use-proxy-protocol: "true"
enable-opentracing: "true"
zipkin-collector-host: zipkin.default.svc.cluster.local
kind: ConfigMap
metadata:
labels:
k8s-addon: ingress-nginx.addons.k8s.io
name: ingress-nginx
namespace: kube-ingress
$ kubectl replace -f ingress-nginx-conf.yaml

  最后,为 Zipkin 创建一个 Ingress 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat zipkin-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: zipkin
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: zipkin.umlife.net
http:
paths:
- path: /
backend:
serviceName: zipkin
servicePort: 9411
$ kubectl apply -f zipkin-ingress.yaml

  在 DNS 服务器增加 CNAME 记录,将zipkin.umlife.net解析到 Nginx Ingress 的 ELB 地址,就可以通过浏览器访问 Zipkin 了。
  上面的配置只会让 Nginx Ingress 上报数据给 Zipkin,如果 Upstream Service 也需要上报数据给 Zipkin,那么需要在代码中增加数据上报功能。例如在 Golang 程序中上报数据给 Zipkin,可以参考这个程序 zipkin-date-server

参考资料