0%

Kubernetes 批量部署 Splash 服务

做爬虫的小伙伴可能听说过 Splash,它可以提供动态页面渲染服务,如果我们要爬的某些页面是 JavaScript 渲染而成的,此时我们直接用 requests 或 Scrapy 来爬是没法直接爬到的,此时我们可以借助于 Splash 来帮我们把 JavaScript 渲染后的真实页面结果拿下来。 不过 Splash 在大批量爬虫使用的时候坑不少,Splash 可能用着用着可能就内存炸了,如果只是单纯启 Docker 服务又不好 Scale,另外也不方便当前服务的使用状态,比如内存占用、CPU 消耗等等。 最近把 Splash 迁移到了 Kubernetes 上面,正好上面的问题就一带解决了。 我们既可以方便地扩容,又可以设置超额重启,又可以方便地观察到当前服务使用情况。 下面简单记录一下我把 Splash 迁移到 Kubernetes 上面的过程,真的迁移过来之后省了很多麻烦,推荐大家也可以试试。 好,下面正式开始介绍。

必备条件

首先,我们需要有一个 Kubernetes 集群,可以自己搭建,也可以使用 Minikube 或者用阿里云、腾讯云、Azure 等服务商直接提供的 Kubernetes 服务。 另外我们需要能使用 kubectl 连接和控制当前的集群,同时需要安装好 helm 并配置好 stable 版本的 Charts,在这里我使用的是 Helm 2.x。 在这里列一些参考资料:

  • 搭建 Kubernetes 集群:https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
  • Minikube:https://kubernetes.io/zh/docs/setup/learning-environment/minikube/
  • Helm V2 安装和使用:https://v2.helm.sh/docs/
  • Charts:https://github.com/helm/charts

上面的内容准备就绪之后,我们就可以开始 Kubernetes 搭建 Splash 服务的流程了。

整体流程

  • 创建 NameSpace
  • 创建 Service
  • 创建 Deployment
  • 安装 Ingress Controller
  • 配置域名解析
  • 配置 Authentication
  • 配置 HTTPS

上面就是本节所要介绍的基本内容,下面我们开始吧。

创建 NameSpace

首先我们将 Splash 安装在一个独立的 Namespace 下面,名字就叫做 splash 吧。 yaml 内容如下:

1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
name: splash

这样就声明了一个 NameSpace,名字叫做 splash。

创建 Service

Service 的创建也很简单,我们注意声明好 namespace 和端口等信息即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
labels:
app: splash
name: splash
namespace: splash
spec:
ports:
- name: "8050"
port: 8050
targetPort: 8050
selector:
app: splash
status:
loadBalancer: {}

在这里选择了端口号 port 8050,即服务运行的端口为 8050。targetPort 也是 8050,这个代表 Pod 里面容器的运行端口。另外声明了 labels 和 selector 的内容,大家可以稍作了解。

创建 Deployment

接下来,就是最关键的了,我们使用 scrapinghub/splash 这个 Docker 镜像来创建一个 Deployment,yaml 文件如下:

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
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: splash
name: splash
namespace: splash
spec:
replicas: 3
selector:
matchLabels:
app: splash
revisionHistoryLimit: 1
strategy: {}
template:
metadata:
labels:
app: splash
spec:
containers:
- image: scrapinghub/splash
name: splash
ports:
- containerPort: 8050
resources:
requests:
memory: "1Gi"
cpu: "1"
limits:
memory: "4Gi"
cpu: "4"
restartPolicy: Always
status: {}

这里也有几个比较关键的点:

  • metadata.labels:这里需要和 Service 里面的 selector 对应起来。
  • spec.template.spec.containers[]:这里声明 splash 的镜像,用的是 latest 镜像 scrapinghub/splash;端口地址用的 8050;restartPolicy 使用的是 Always,这样 Splash 如果崩溃了会自动重启;resources 设置了使用的内存和 CPU 的请求和限制值,这里大家可以根据机器和爬取需求自行修改。
  • spec.replicas:运行的实例个数,这里设置为了 3,这样就会启动 3 个 Splash ,Service 会对其负载均衡。

好了,写了上面三个 yaml,我们可以将其合并到一个 yaml 文件里面,如 deployment.yml,然后执行:

1
kubectl apply -f deployment.yml

这样我们就可以观察到 NameSpace、Service、Deployment 都创建成功了,Pod 随之也创建成功了。 image-20200129211026981

安装 Ingress Controller

接下来我们想要配置一个域名解析,并配置好 HTTPS。 首先我们需要安装 Ingress,这里我们使用 Helm 2.x 安装,使用的 Charts 为:https://github.com/helm/charts/tree/master/stable/nginx-ingress。 这里我们稍作修改,指定 NameSpace 和镜像即可:

1
helm install --name ingress-splash --namespace splash --set defaultBackend.image.repository=mirrorgooglecontainers/defaultbackend-amd64 stable/nginx-ingress

这里我们将镜像修改了一下,避免国内 Kubernetes 无法拉取镜像的问题。 OK,安装好了之后,可以看到 Ingress Controller 就安装成功了。

域名解析

域名解析就好配置了,直接将域名配置到 Ingress Controller Service 的 External IP 上面即可。 image-20200129211154610

配置 Authentication

Splash 部署完了之后,默认是没有 Authentication 的,如果直接暴露在公网中,是可以被他人直接使用的。 所以我们需要对其配置 Authentication,并配置 Ingress 域名解析。 这里 Authentication 我们使用 HTTP Basic Auth 就好了,要配置这个,我们需要先新建一个 Secret。 那么 Secret 怎么创建呢,我们先用 htpasswd 生成一个秘钥文件,用户名为 splash:

1
htpasswd -c auth splash

执行完了之后本地会生成一个 auth 文件,我们用这个 auth 文件创建一个 Secret 即可:

1
kubectl create secret generic basic-auth --from-file=auth --namespace splash

这样 Secret 就创建好啦,用户名就是 splash,密码就是刚才创建秘钥文件时输入的密码。 上面更详细的介绍参见:https://kubernetes.github.io/ingress-nginx/examples/auth/basic/ 好,然后我们创建 Ingress。 新建 ingress.yml 文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-splash
namespace: splash
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
spec:
rules:
- host: <domain>
http:
paths:
- backend:
serviceName: splash
servicePort: 8050
path: /

这里 metadata.annotations 里面声明了三个选项,就是设定 HTTP Basic Auth 的。 注意这里 spec.rules[].host 的内容换成自己的域名。 好,然后执行即可:

1
kubectl apply -f ingress.yml

OK,这样 Ingress 也创建好啦。 现在我们只需要访问 http://<domain> 即可访问到 Splash 服务啦。 初次访问需要输入用户名和密码,如图所示。 image-20200129213029854 登录完成之后就可以看到 Splash 的界面了,如图所示。 image-20200129212035193

HTTPS

这时候整个 Endpoint 是 HTTP 协议,会被提示不安全,如果我们想要配置 HTTPS,还需要申请一个证书。 证书可以到阿里云、腾讯云等等服务商申请即可。 申请完了,我们可以得到 crt 和 key 两个文件。 接下来我们首先需要配置一个 tls 类型的 Secret,命令如下:

1
kubectl create secret tls tls-splash -n splash --cert <cert_name>.crt --key <cert_name>.key

这里 <cert_name> 替换成你申请的证书文件名即可。 这样我们就创建了一个名字为 tls-splash 的 Secret,下面我们开始使用。 修改 ingress.yml 文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-splash
namespace: splash
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- <domain>
secretName: tls-splash
rules:
- host: <domain>
http:
paths:
- backend:
serviceName: splash
servicePort: 8050
path: /

这里主要修改的点有两个,一个是增加了 ssl 重定向,这样如果我们以 HTTP 访问过去,就会被跳转到 HTTPS 的地址。另外就是 spec.tls 字段了,这里声明 hosts 和 secretName 即可。 OK,重新应用:

1
kubectl apply -f ingress.yml

大功告成,现在我们就可以使用 https://<domain> 来访问我们的 Splash 服务了。

测试

最后,输入个网址测试下吧,如百度,渲染成功,如图所示。 image-20200129213130109 以上,便是 Kubernetes 搭建 Splash 的方法。 希望对大家有帮助。