Published on

Mở đầu với Apache Zeppelin và Spark trên Kubernetes

Mở đầu

Ở các bài viết trước về chủ đề Microsoft Hyper-V mình đã giới thiệu cách cài đặt và thiết lập một Kubernetes cluster đồng thời đưa ra một vài ví dụ đơn giản để minh chứng là mô hình này hoạt động. Các bài viết hết sức tóm tắt cách mình thực hiện chứ không trình bày quá nhiều vào các lý thuyết và khái niệm nên một số tên gọi hoặc kiến thức nào không rõ bạn có thể tìm kiếm trên Google.

Tiếp tục hôm nay mình sẽ giới thiệu cách cài đặt Apache Zepplin sử dụng Spark Interpreter trên Kubernetes. Dành cho bạn nào chưa biết:

  • Apache Zeppelin là một công cụ hỗ trợ phân tích dữ liệu một cách trực quan, hỗ trợ nhiều loại ngôn ngữ khác nhau (Python, Scala, SQL, ...) tương tự như Jupyter Notebook.
  • Apache Spark là một framework được thiết kế để tính toán nhanh trong xử lý dữ liệu quy mô lớn. Apache Spark là một công cụ xử lý phân tán (distributed processing engine) nhưng nó không đi kèm với trình quản lý tài nguyên cụm (inbuilt cluster resource manager) và hệ thống lưu trữ phân tán sẵn có (distributed storage system) mà phải cắm vào một trình quản lý cụm và hệ thống lưu trữ.

Khi kết hợp với Apache Spark, Zeppelin giúp phân tích dữ liệu lớn (Big Data) một cách nhanh chóng.

Mình đã có hơn 2 năm làm trong dự án Airbus Skywise khá là ấn tượng với Big Data platform: Foundry, công nghệ sử dụng chủ yếu là Hadoop + Spark. Rất tiếc công việc chủ yếu là sử dụng các công cụ của platform để phân tích, xử lý dữ liệu mà không có cơ hội làm việc với DEV team để tìm hiểu sâu thêm về Architecture của nó.

Thông thường để triển khai Apache Spark thì chúng ta thường sử dụng một vài loại cluster manager sau:

  • Standalone (chủ yếu dùng trong môi trường DEV, hoặc dùng để nghiên cứu tìm hiểu về Spark)
  • Apache Mesos
  • Hadoop YARN

Những năm gần đây với sự phát triển và phổ biến của Kubernetes thì Spark cũng đã hỗ trợ chạy trên K8s.

Bây giờ mình sẽ triển khai Zeppelin sử dụng Spark (PySpark) Interpreter trên Kuberetes:

  • Apache Spark 3.1.2 được cài sẵn PySpark
  • Zeppelin 0.10.0

Build lại docker Spark

Đầu tiên, mình không sử dụng docker image chính chủ mà tự build lại với 1 chỉnh sửa nhỏ nhằm sử dụng phiên bản python3.7. Các bạn download Spark tại trang web https://spark.apache.org/downloads.html và chọn phiên bản: spark-3.1.2-bin-hadoop3.2.tgz sau đỏ giải nén.

Mở file kubernetes/dockerfiles/spark/Dockerfile và chọn java_image_tage11-jre-slim-buster (Ban đầu là 11-jre-slim)

...
ARG java_image_tag=11-jre-slim-buster

FROM openjdk:${java_image_tag}

ARG spark_uid=185
...

Lý do mình sửa thành 11-jre-slim-buster là để các bước sau, spark sẽ sử dụng phiên bản python 3.7 cùng phiên bản python trong Zeppelin.

Sau khi sửa xong thì mở terminal và cd vào thư mục bin và chạy lệnh:

docker-image-tool.sh -r nvtienanh -t latest -p kubernetes/dockerfiles/spark/bindings/python/Dockerfile build

Lệnh này sẽ build lại 2 docker image:

  • nvtienanh/spark:latest
  • nvtienanh/spark-py:latest

Sau khi build xong thì đẩy lên docker hub:

docker image push nvtienanh/spark:latest
docker image push nvtienanh/spark-py:latest

Lưu ý:

  • Nhớ cài đặt Docker trên máy tính thì mới build được nhé.
  • Sửa tên nvtienanh thành docker hub user của bạn.
  • Phải login vào docker hub thì mới push image lên docker hub được.

Cài đặt Zeppelin

Zeppelin storage

Mình sử dụng NFS Persistent Volume nhằm mục đích lưu trữ các file cấu hình, dữ liệu các notebook bên ngoài tránh bị mất đi khi deploy lại hoặc pod restart.

Các bạn có thể sử dụng Persistent Volume khác nếu không có NFS Persistent Volume.

Download file storage.yaml về và sửa your-nfs-server-ip thành NFS server IP của bạn. Sau khi deploy file này thì sẽ tạo ra 3 PVC:

  • zeppelin-notebook-pvc: lưu các notebook
  • zeppelin-custom-k8s-pvc: lưu các config k8s của zeppelin
  • zeppelin-server-conf-pvc: lưu các config khác của zeppelin

Xem thêm bài viết Thiết lập và dụng NFS Persistent Volume trên Kubernetes để hiểu rõ hơn về NFS PVC.

Zeppelin deployment

Tiếp theo mình chỉ sửa 1 chút từ file gốc zeppelin-server.yaml. Trong SERVICE_DOMAIN: cập nhật yourdomain.com thành domain của bạn.

Zeppelin Ingress

Chúng ta cần deploy ingress để có thể truy cập vào Zeppelin thông qua domain yourdomain.com đã khai báo trước đó.

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: zeppelin-server
  namespace: spark
  labels:
    app.kubernetes.io/name: zeppelin-server
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/add-base-url: 'true'
    nginx.ingress.kubernetes.io/proxy-body-size: '0'
spec:
  tls:
    - hosts:
        - yourdomain.com
      secretName: ssl-yourdomain.com
  rules:
    - host: yourdomain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: zeppelin-server
                port:
                  number: 80

SSL cho tên miền

Tiếp theo file clusterissuer.yaml sẽ cho phép chúng ta tạo chứng chỉ SSL Let's Encrypt. Download file yaml về và cập nhật yourname@email.com thành email của bạn.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: yourname@email.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    solvers:
      - http01:
          ingress:
            class: nginx

Sau khi dùng kubectl apply thì file này sẽ tạo Cluster Issuer tên letsencrypt-prod. Chúng ta chỉ cần deploy file này 1 lần, và mọi Ingress trong cluster đều có thể sử dụng nó để tạo ssl cho host tương ứng.

Cấu hình ban đầu

100-interpreter-spec.yaml

File này chính là Pod template để ZeppelinServer khởi tạo / thu hồi khi sử dụng Spark, chi tiết có thể đọc thêm tại đây

Downloadfile 100-interpreter-spec.yaml sau đó upload vào zeppelin-custom-k8s-pvc. Do mình dùng NFS Persistent Volume nên mình chỉ cần kết nối đến NFS server và đẩy 100-interpreter-spec.yaml vào /nfs/zeppelin/custom-k8s/interpreter.

shiro.ini

Dưới đây là file shiro.ini cung cấp thiết lập cơ bản, chỉ cho user admin sử dụng yourpassword đăng nhập vào Web UI của Zeppelin.

[users]
admin = youpassword, admin
# Sample LDAP configuration, for user Authentication, currently tested for single Realm

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
### Enables 'HttpOnly' flag in Zeppelin cookies
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = JSESSIONID
cookie.httpOnly = true
### Uncomment the below line only when Zeppelin is running over HTTPS
#cookie.secure = true
sessionManager.sessionIdCookie = $cookie
securityManager.sessionManager = $sessionManager
# 86,400,000 milliseconds = 24 hour
securityManager.sessionManager.globalSessionTimeout = 86400000
shiro.loginUrl = /api/login

[roles]
admin = *

[urls]
/api/version = anon
/api/cluster/address = anon
/api/interpreter/setting/restart/** = authc
/api/interpreter/** = authc, roles[admin]
/api/notebook-repositories/** = authc, roles[admin]
/api/configurations/** = authc, roles[admin]
/api/credential/** = authc, roles[admin]
/api/admin/** = authc, roles[admin]
#/** = anon
/** = authc

Tương tự như 100-interpreter-spec.yaml, lần này chúng ta cần upload shiro.ini vào zeppelin-server-conf-pvc bằng cách kết nối tới NFS server và đẩu file shiro.ini vào /nfs/zeppelin/conf

Lưu ý: Nếu bạn không sử dụng NFS PVC thì có nhiều cách khác để đẩy file vào Persistent Volume như sử dụng configmap và mount vào container.

Deploy Zeppelin

Tới đây mình giả sử là bạn đã thay đổi các yaml file theo thông tin của bạn, upload các file 100-interpreter-spec.yamlshiro.ini vào NFS storage.

kubectl create namespace spark
kubectl apply -f storage.yaml
kubectl apply -f zeppelin-server.yaml
kubectl apply -f ingress.yaml
kubectl apply -f clusterissuer.yaml

Sau khi deploy thành công thì bạn có thể truy cập vào zeppelin webui tại địa chỉ: yourdomain.com.

Thiết lập Spark Interpreter

Vào phần Interpreter, tìm Spark sau đó thêm các config sau:

  • zeppelin.k8s.spark.useIngress loại checkbox và tick vào
  • zeppelin.k8s.interpreter.serviceAccount: zeppelin-server
  • zeppelin.k8s.interpreter.container.imagePullPolicy: Always
  • zeppelin.k8s.spark.container.imagePullPolicy: Always

Sửa các config,

  • PYSPARK_PYTHON: python3
  • PYSPARK_DRIVER_PYTHON: python3

Restart lại Interpreter, thử chạy đoạn code sau:

%pyspark
import sys
sys.version_info
df = spark.createDataFrame(
    [
        (1, "foo"),  # create your data here, be consistent in the types.
        (2, "bar"),
    ],
    ["id", "label"]  # add your column names here
)

df.printSchema()
z.show(df)

Bạn có thể click vào SPARK JOB để kiểm tra các job đã và đang chạy

Khi quan sát trên Kubernetes Dashboard thì thấy rằng các pod của spark đã được khởi tạo và chạy thành công

Trên đây là những hướng dẫn cơ bản để kết hợp Zepplin chạy Spark Interpreter trên Kubernetes hy vọng có thể giúp bạn tiết kiệm thời gian học tập nghiên cứu và ứng dụng vào các dự án của mình.

Mọi liên hệ và hợp tác phát triển có thể liên hệ qua hello@nvtienanh.info

Trích dẫn

Trong bài viết tôi có trích dẫn nội dung từ một số nguồn: