大数据之spark on k8s
spark on k8s架构解析
1.k8s的优点
k8s是一个开源的容器集群管理系统,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。
1、故障迁移
2、资源调度
3、资源隔离
4、负载均衡
5、跨平台部署
2.k8s集群架构
Master Node
k8s 集群控制节点,对集群进行调度管理,接受集群外用户去集群操作请求;
Master Node 由 API Server、Scheduler、ClusterState Store(ETCD 数据库)和Controller MangerServer 所组成
- API Server。K8S的请求入口服务。API Server负责接收K8S所有请求(来自UI界面或者CLI命令行工具),然后,API Server根据用户的具体请求,去通知其他组件干活。
- Scheduler。K8S所有Worker Node的集群资源调度器。当用户要部署服务时,它通过watch监视pod的创建,负责将pod调度到合适的node节点。
- Controller Manager。K8S所有Worker Node的监控器。Controller Manager有很多具体的Controller,Controller负责监控和调整在Worker Node上部署的服务的状态,比如用户要求A服务部署2个副本,那么当其中一个服务挂了的时候,Controller会马上调整,让Scheduler再选择一个Worker Node重新部署服务。
- etcd。K8S的存储服务。数据持久存储化,存储集群中包括node,pod,rc,service等数据;还存储了K8S的关键配置和用户配置,K8S中仅API Server才具备读写权限,其他组件必须通过API Server的接口才能读写数据。
Worker Node
- 集群工作节点,运行用户业务应用容器;
- Worker Node 包含 kubelet、kube proxy 和 ContainerRuntime
- Kubelet。Worker Node的监视器,以及与Master Node的通讯器。Kubelet是Master Node安插在Worker Node上的“眼线”,它会定期向Master Node汇报自己Node上运行的服务的状态,并接受来自Master Node的指示采取调整措施。kubelet负责镜像和pod的管理,主要负责同容器运行时(比如Docker项目)打交道。而这个交互所依赖的,是一个称作CRI(Container Runtime Interface)的远程调用接口。
- Kube-Proxy。K8S的网络代理。Kube-Proxy负责Node在K8S的网络通讯、以及对外部网络流量的负载均衡。kube-proxy是service服务实现的抽象,负责维护和转发pod的路由,实现集群内部和外部网络的访问。
- Container Runtime。Worker Node的运行环境。即安装了容器化所需的软件环境确保容器化程序能够跑起来,比如Docker Engine。大白话就是帮忙装好了Docker运行环境,负责实现container生命周期管理。
3.Spark on K8s工作原理
具体流程,包括以下几步:
①:用户使用kubectl 创建 SparkApplication 对象,提交sparkApplication的请求到api-server,并把sparkApplication的CRD持久化到etcd;
②:SparkApplication controller 从 kube-api server 接收到有对象请求,创建 submission (实际上就是 参数化以后的 spark-submit 命令),然后发送给 submission runner。
③:Submission runner 提交 app 到 k8s 集群,并创建 driver pod。一旦 driver pod 正常运行,则由 driver pod 创建 executor pod。 当应用正常运行时,spark pod monitor 监听 application 的 pod 状态,(通过kubectl可以通过list、status看到)并将pod 状态的更新发送给 controller,由 controller 负责调用 kube-api 更新 spark application 的状态(实际上是更新 SparkApplication CRD 的状态字段)。
④:mutating adminission webhook创建svc,可以查看spark web ui
k8s安装
1.环境准备
# 关闭防火墙 systemctl stop firewalld systemctl disable firewalld # 关闭selinux sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久 setenforce 0 # 临时 # 关闭swap swapoff -a # 临时 sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久 # 根据规划设置主机名 hostnamectl set-hostname <hostname> # 在master添加hosts cat >> /etc/hosts << EOF 192.168.10.102 hadoop102 192.168.10.103 hadoop103 192.168.10.104 hadoop104 EOF # 将桥接的IPv4流量传递到iptables的链 cat > /etc/sysctl.d/k8s.conf << EOF net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF sysctl --system # 生效 # 时间同步 yum install ntpdate -y ntpdate time.windows.com
2. 所有节点安装Docker/kubeadm/kubelet
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo $ yum -y install docker-ce-18.06.1.ce-3.el7 $ systemctl enable docker && systemctl start docker $ docker --version Docker version 18.06.1-ce, build e68fc7a
$ cat > /etc/docker/daemon.json << EOF { "registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"] } EOF $ systemctl restart docker
3.添加阿里云YUM软件源
$ cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF
4.安装kubeadm,kubelet和kubectl
默认安装的是最新版本,我们这里指定版本号部署
$ yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0 $ systemctl enable kubele
5.部署Kubernetes Master
在主节点(hadoop102)进行初始化
$ kubeadm init \ --apiserver-advertise-address=192.168.10.102 \ #主节点ip地址 --image-repository registry.aliyuncs.com/google_containers \ --kubernetes-version v1.18.0 \ --service-cidr=10.96.0.0/12 \ --pod-network-cidr=10.244.0.0/16
由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址。
使用主节点初始化时生成的kubectl工具在其他节点执行并查看节点信息:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config $ kubectl get node
6.加入Kubernetes Node
在hadoop104/hadoop104执行。
向集群添加新节点,执行在kubeadm init输出的kubeadm join命令:
$ kubeadm join 192.168.10.102:6443 --token esce21.q6hetwm8si29qxwn \ --discovery-token-ca-cert-hash sha256:00603a05805807501d7181c3d60b478788408cfe6cedefedb1f97569708be9c5
默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,操作如下:
kubeadm token create --print-join-command
kubeadm token create --print-join-command
7.部署CNI网络插件
wget kube-flannel.yml的时候显示连接失败
是因为网站被墙了,建议在/etc/hosts文件添加一条
199.232.68.133 raw.githubusercontent.com
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
默认镜像地址无法访问,sed命令修改为docker hub镜像仓库。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE kube-flannel-ds-amd64-2pc95 1/1 Running 0 72s
spark私有镜像制作
1.搭建本地私有镜像仓库
yum install docker-registry ##安装docker-registry docker run --name registry -d -p 5000:5000 --restart=always -v /opt/registry:/var/lib/registry registry
利用官网registry镜像运行一个私有镜像仓库容器,自定义名称registry,-d默认是本机,-p指定映射端口5000,-v是指定安装目录,默认是该容器的/var/lib/registry下,自定义修改目录/opt/registry,后续push上来的自定义镜像都在/opt/registry这个目录下。
2.构建spark3.0.0 on k8s镜像
下载安装spark3.0.0安装包并解压
tar -zxvf spark-3.0.0-bin-hadoop3.2.tgz -C /opt/module cd /opt/module/spark-3.0.0-bin-hadoop3.2/bin
通过dockerFile构建spark镜像并上传到自己的镜像仓库
./bin/docker-image-tool.sh -r <repo> -t my-tag build # repo仓库名称 my-tag版本号 docker images #可以看到已经构建好的镜像
验证私有镜像仓库的镜像推送和拉取。
docker push 192.168.10.102:5000/spark #将自定义镜像spark推送到私有镜像仓库192.168.10.102:5000 docker rmi 192.168.10.102:5000/spark #为了避免干扰验证结果,先把本地tag的自定义镜像删除 docker pull 192.168.10.102:5000/spark #从私有镜像仓库拉取自定义镜像 docker images #查看本地镜像,应该可以再次看到192.168.10.102:5000/spark镜像
也可以通过浏览器访问私有镜像仓库,通过http://[ip地址]:[端口]/v2/_catalog 访问。
3.配置spark用户权限
kubectl create serviceaccount spark kubectl create clusterrolebinding spark-role --clusterrole=edit --serviceaccount=default:spark --namespace=default ##在spark-submit中添加 --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark
配置spark历史服务器
apiVersion: apps/v1 kind: Deployment metadata: name: spark-history-server namespace: default spec: selector: matchLabels: run: spark-history-server replicas: 1 template: metadata: labels: run: spark-history-server spec: containers: - image: 192.168.10.102:5000/spark name: spark-history-server args: ["/opt/spark/bin/spark-class", "org.apache.spark.deploy.history.HistoryServer"] ports: - containerPort: 18080 name: http env: - name: SPARK_HISTORY_OPTS value: "-Dspark.history.fs.logDirectory=hdfs://192.168.10.102:8020/sparkhistory" --- apiVersion: v1 kind: Service metadata: name: spark-hs-svc namespace: default spec: ports: - port: 18080 protocol: TCP targetPort: 18080 nodePort: 10080 selector: run: spark-history-server type: NodePort status: loadBalancer: {}
在k8s上运行sparkdemo
bin/spark-submit \ --master k8s://https://192.168.10.102:6443 \ --deploy-mode cluster \ --name spark-pi \ --class org.apache.spark.examples.SparkPi \ --conf spark.eventLog.enabled=true \ --conf spark.eventLog.dir=hdfs://192.168.10.102:8020/sparkhistory \ --conf spark.kubernetes.authenticate.driver.serviceAccountName=spark \ --conf spark.executor.instances=2 \ --conf spark.kubernetes.container.image=192.168.10.102:5000/spark \ local:///opt/spark/examples/jars/spark-examples_2.12-3.0.0.jar