[TOC]

一、背景

1.1 需求

我们有这样的一个需求,就是把 Pod 集群升级为 https,目前的办法就是要么每个容器配置 https,然后前端通过 Service 进行调度,但是这样配置起来会比较麻烦,以及每个容器的建立都通过 https ,也增加了建立连接的负担。

我们需要一种这样的改造,就是客户端连接到 Service 是通过 https,而 Service 向后端 Pod 的调度通过 http,这样可以极大的优化我们的集群,这里我们就需要用到 Kubernetes 的另外一种资源 Ingress

Kubernetes 使用 ingress 配置 https 集群(十五)

1.2 Ingress

Ingress 就是一个负载均衡的应用,它和 Service 的不同之处在于,Service 只可以支持 4 层的负载均衡,而 Ingress 是支持 7 层的负载均衡,支持 http 和 https,包括通过主机名的访问已经路径访问的过滤。

那为什么不直接使用 Nginx?这是因为在 K8S 集群中,如果每加入一个服务,我们都在 Nginx 中添加一个配置,其实是一个重复性的体力活,只要是重复性的体力活,我们都应该通过技术将它干掉。

Ingress就可以解决上面的问题,其包含两个组件Ingress ControllerIngress

  • Ingress:将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可;
  • Ingress Controller:将新加入的 Ingress 转化成 Nginx 的配置文件并使之生效,包含 Contour、F5、HAProxy、Istio、Kong、Nginx、Traefik,官方推荐我们使用 Nginx。

Kubernetes 使用 ingress 配置 https 集群(十五)

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

不过我这里使用阿里云的官方免费证书,大家可以到阿里云进行申请。
Kubernetes 使用 ingress 配置 https 集群(十五)

Kubernetes 使用 ingress 配置 https 集群(十五)
制作好证书之后下载即可,里面包含公钥和私钥。

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 域名解析。
Kubernetes 使用 ingress 配置 https 集群(十五)

四、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