Apache Ranger with Trino on Kubernetes

Pongthep Vijite
DAMAGeek
Published in
8 min readDec 31, 2021

หมายเหตุ ผู้อ่านสามารถดู table of contents ของ Data Engineering from Noob to Newbie ได้ที่ http://bit.ly/2P7isEw

จากบทความของ Aakash Nand (https://towardsdatascience.com/integrating-trino-and-apache-ranger-b808f6b96ad8) ที่ได้เพิ่ม Trino plugin เข้าไปใน Apache Ranger 2.1.0 เพื่อแทนที่ Presto plugin โดยมีการแสดงตัวอย่างการ setup และใช้งานบน docker environment ซึ่งเป้าหมายของเราในบทความนี้คือการนำ code ชุดเดียวกันนี้มาต่อยอดเพื่อใช้งานใน Kubernetes กันครับ

Note: ในส่วนของการแทนที่ Presto ด้วย Trino ผมก็ไม่มั่นใจสาเหตุเหมือนกัน เพราะแม้ชื่อเดิมของ Trino คือ Prestosql แต่ตัว Presto DB (https://prestodb.io/) ก็ยังคงพัฒนาต่อภายใต้ Facebook ที่เป็นแกนนำ แต่ถึงอย่างไรโดยส่วนตัวก็เลือกใช้ Trino มากกว่า Presto DB ในส่วนนี้เลยไม่ค่อยมีผลกระทบเท่าไร ใครสนใจ review code การเปลี่ยนนี้สามารถส่องตัวอย่างได้ที่ https://github.com/aakashnand/ranger/commit/a916d0c08e2e015951e88f3999d19f1617a62ee7

สำหรับใครที่ไม่อยากเสียเวลา build Ranger พร้อม Trino plugin จาก source code สามารถใช้ของสำเร็จรูปที่ Aakash Nand ทำการ build เรียบร้อยแล้วได้จาก https://github.com/aakashnand/trino-ranger-demo/releases/tag/trino-ranger-demo-v1.0 และข้ามไปยังตอน build docker image ได้เลยครับ

แต่สาเหตุผลที่ผมเลือกที่จะ build จาก source code เนื่องจากอยาก recheck ว่า code ที่ Aakash Nand จัดทำสามารถ build และใช้งานได้จริงเผื่อในกรณีที่เราต้องการต่อยอดในส่วนอื่นๆ ซึ่งในอนาคตคาดว่า Trino plugin นี้จะถูกรวมเข้ากับ code หลักของ Ranger เอง โดยตอนนี้ Trino plugin สำหรับ Ranger version 2.1.0 กำลังเปิดเป็น ticket อยู่ที่ https://issues.apache.org/jira/browse/RANGER-3182 และในปัจจุบันเหมือนมีการพัฒนาเพื่อรองรับ Ranger 2.2.0 ที่พึ่งออกมาไม่นานนี้แล้วแต่ plugin ยังอยู่ในสถานะ RC รวมถึง Ranger 3.0.0 ซึ่งอยู่ใน branch master ที่ยังเป็น snapshot อยู่

Build package จาก source code

ตัว environment ที่ผมใช้ในการ build ครั้งนี้มีรายละเอียดดังนี้

os version
java version
maven version

เราจะเริ่มด้วยการ clone git repo และทำการย้าย branch จาก master ที่กำลัง dev Ranger 3.0.0 ไปที่ branch ซึ่งมี Trino plugin อยู่ ซึ่ง branch ที่สมบูรณ์ที่สุดจะเป็น ranger-2.1.0-trino

clone git repo

จากนั้นก็ทำการ build package โดยใช้คำสั่ง ซึ่งในขั้นตอนนี้จะใช้เวลาพอสมควรเลยทีเดียว

sudo mvn clean compile package install -pl ‘!hive-agent’ -DskipTests -Denforcer.skip=true
maven พังที่ package ranger-distro

จากรูปข้างบนนี้เมื่อรอไประยะนึง maven จะมาพังที่ตอน build ranger-distro อันนี้ต้องยอมรับตามตรงว่ายังไม่ทราบสาเหตุและวิธีแก้ที่แน่ชัด แต่สิ่งนึงที่ทำแล้ว work คือ rebuild ใหม่อีกครั้งแต่ครั้งนี้เราจะระบุให้เริ่มการ build ที่ ranger-distro เลย

sudo mvn clean compile package install -pl ‘!hive-agent’ -DskipTests -Denforcer.skip=true -rf :ranger-distro -X

ซึ่งมันก็จะ build ได้สำเร็จ

package ranger-distro ถูก build เรียบร้อย

แต่มันก็ไม่ใช่ทุกครั้งที่จะสำเร็จ เพราะในบ้างครั้งการ rebuild ็กกลับ show error ตามรูปด้านล่าง และพอลอง rebuild อีกครั้งกลับสำเร็จสะงั้น ซึ่งใจจุดนี้เราต้องระวังหากนำไปใช้สำหรับงาน production และหวังว่าพอ plugin ตัวนี้ได้ถูกรวมเข้ากับ Ranger อย่างเป็นทางการแล้วจะได้รับการแก้ไข เพราะเท่าที่เคยลอง build Ranger ของ official จะไม่เจอปัญหานี้เลย

rebuild package ranger-distro อีกครั้งแต่ไม่สำเร็จ

เมื่อการ rebuild package ranger-distro สำเร็จแล้ว เราจำเป็นต้อง rebuild ทั้งหมดใหม่อีกครั้ง จนกว่าจะ success แบบรวดเดียว 60 packages ดังรูปด้านล่าง ไม่เช่นนั้น package ที่เราจะนำไปใช้จะไม่สมบูรณ์ T_T

build apache ranger เสร็จสมบูรณ์

Build docker image

เพื่อทำการ build Docker image เราจะสร้าง folder ที่ชื่อว่า apache-ranger-k8s และภายใน folder นี้จะทำการสร้าง sub folder ที่ชื่อ ranger-packages โดยเราจะทำการ copy admin package จากที่เรา build เสร็จไปในขั้นตอนก่อนหน้ามาไว้ใน folder นี้แล้ว extract tar.gz

1.สร้าง folder
mkdir ~/apache-ranger-k8s
cd ~/apache-ranger-k8s2.สร้าง sub folder
mkdir ranger-packages
cd ranger-packages3.copy package
cp -r ~/ranger/target/ranger-2.1.0-admin.tar.gz .
4.extract tar.gz
tar zxvf ranger-2.1.0-admin.tar.gz
5.กลับไปที่ root project folder
cd ..

ขั้นตอนต่อไปเราจะทำการสร้าง file ที่ชื่อว่า install.properties ซึ่งเป็น file ที่ใช้ในการติดตั้ง apache ranger ซึ่งจากบทความของ Aakash Nand เค้าเลือกใช้ postgresql เป็น DB แต่ในบทความนี้เราจะเลือก mysql แทนเพื่อเพิ่มความแตกต่างของการทดลอง โดยตัว ranger เองรองรับ DB อยู่ด้วยกัน 5 ตัวคือ mysql, oracle, postgres, mssql และ sqlalchemy

ตัว file install.properties จะอ้างอิงจาก https://github.com/aakashnand/trino-ranger-demo/blob/main/ranger-admin/install.properties และมีการเพิ่มเติมดังนี้

install.properties part 1
install.properties part 2
install.properties part 3

ขั้นตอนต่อไปเราจะทำการสร้าง file ที่ชื่อ ranger-entrypoint.sh อ้างอิงจาก https://github.com/takezoe/ranger-docker/blob/master/ranger-admin/ranger-entrypoint.sh โดยไม่มีการแก้ไขใดๆ ซึ่ง ranger-docker เป็นอีก 1 git repo ที่มีการทำให้ ranger สามารถ run บน docker ได้ ผมได้เจอ repo นี้มาก่อนที่จะได้เจอบทความของ Aakash Nand สะระยะนึง นั้นจึงเป็นอีกสามารถที่ติดการใช้งาน mysql เป็น DB ของ ranger

ขั้นตอนสุดท้ายคือการสร้าง Dockerfile ซึ่งผมดัดแปลงรวมร่างมาจากทั้งของ Aakash Nand และของ Takezoe โดยในครั้งแรกที่ลองผมใช้ของ Takezoe เป็นหลักแต่จำไม่ได้ว่าเจอ error อะไรจึงได้มีการผสม config ของ Aakash Nand เข้าไปด้วย จึงออกมาเป็นดังนี้

FROM phusion/baseimage:focal-1.0.0ARG RANGER_VERSION=2.1.0RUN apt-get clean
RUN apt-get update
ADD https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.26/mysql-connector-java-8.0.26.jar /optRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -y install sudo wget bc python apt-transport-https gnupg
RUN sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0xB1998361219BD9C9
RUN curl -O https://cdn.azul.com/zulu/bin/zulu-repo_1.0.0-2_all.deb
RUN sudo apt-get -y install ./zulu-repo_1.0.0-2_all.deb && sudo apt-get -y update && sudo apt-get -y install zulu11-jdk
WORKDIR /root
ENV JAVA_HOME=/usr/lib/jvm/zulu11
COPY ranger-entrypoint.sh /opt
COPY ranger-packages/ranger-${RANGER_VERSION}-admin /opt/ranger-${RANGER_VERSION}-admin/
WORKDIR /optRUN chmod +x /opt/ranger-entrypoint.shENV RANGER_HOME=/opt/ranger-${RANGER_VERSION}-adminCOPY install.properties /opt/ranger-${RANGER_VERSION}-admin/EXPOSE 6080ENTRYPOINT ["/opt/ranger-entrypoint.sh"]

จากนั้นทำการ build docker image กันได้เลย

docker build -t pongthep/apache-ranger-2_1-k8s:0.0.1 .

ต่อด้วยการ push เข้า dockerhub เพื่อไว้ใช้ใน k8s

docker push pongthep/apache-ranger-2_1-k8s:0.0.1

ขั้นตอนต่อไปเราจะมาทำการ build docker image ของ Trino กัน โดยในส่วนนี้จะมีการนำ plugin ของ Trino ที่เราได้มาจากขั้นตอนการ build Ranger packages มาใช้งานกัน เริ่มแรกด้วยการสร้าง folder ที่ชื่อ trino

mkdir ~/trinocd ~/trino

จากนั้นทำการ copy Trino plugin มาจาก Ranger จากนั้น extract tar.gz

cp ~/ranger/target/ranger-2.1.0-trino-plugin.tar.gz .tar zxvf ranger-2.1.0-trino-plugin.tar.gz

ขั้นตอนต่อไปเราจะทำการสร้าง file ขึ้นมา 3 files ที่จำเป็นสำหรับการสร้าง docker image ของ Trino ดังนี้

1.enable-trino-plugin.sh อ้างอิงมาจาก https://github.com/aakashnand/trino-ranger-demo/blob/main/trino/enable-trino-plugin.sh

2.install.properties อ้างอิงมาจาก https://github.com/aakashnand/trino-ranger-demo/blob/main/trino/install.properties

3. Dockerfile

FROM trinodb/trino:362USER rootADD ranger-2.1.0-trino-plugin /opt/ranger-2.1.0-trino-plugin/ADD enable-trino-plugin.sh /opt/ranger-2.1.0-trino-plugin/
ADD install.properties /opt/ranger-2.1.0-trino-plugin
RUN /opt/ranger-2.1.0-trino-plugin/enable-trino-plugin.shRUN chmod 777 /data/trinoUSER trinoENTRYPOINT ["/usr/lib/trino/bin/run-trino"]

เมื่อครบแล้วภายใน folder trino ก็จะมี file ดังรูปด้านล่างนี้

trino folder

จากนั้นก็ทำการ build docker image และ upload

docker build -t pongthep/trino-ranger-k8s:0.0.1 .docker push pongthep/trino-ranger-k8s:0.0.1

และเพื่อตรวจสอบว่าทุกอย่างที่เราทำการ build กันมานั้นสามารถใช้งานได้จริงตามในบทความ เราจะมาทำการสร้าง docker compose เพื่อ run local กัน โดยผมได้ทำการผสมรวมระหว่าง docker compose ของ Aakash Nand และของ Takezoe เช่นเดิม (สายยำ :P) ในส่วนของ mysql นั้นใช้ config จาก https://github.com/takezoe/ranger-docker/tree/master/ranger-mysql ได้เลยครับ

version: '3.7'
services:
ranger-admin:
image: pongthep/apache-ranger-2_1-k8s:0.0.1
container_name: ranger-admin
ports:
- 6080:6080
depends_on:
- ranger-mysql
- elasticsearch
ranger-mysql:
image: mysql:8.0.26
container_name: ranger-mysql
ports:
- 3306:3306
volumes:
- ./ranger-mysql:/etc/mysql/conf.d
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: rangeradmin
MYSQL_PASSWORD: rangeradmin
MYSQL_DATABASE: ranger
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
container_name: es01
hostname: es01
environment:
discovery.type: single-node
xpack.security.enabled: "false"
ports:
- 9200:9200
trino:
image: pongthep/trino-ranger-k8s:0.0.1
hostname: trino
user: root
container_name: trino
depends_on:
- ranger-admin
ports:
- 8080:8080

เมื่อทำการ run docker compose เรียบร้อยเราก็จะมาทำการส่องรอดู logs ของ ranger เรากันด้วยคำสั่ง

docker logs --follow ranger-admin

จนขึ้น logs ตามรูปด้านล่างก็ถือว่า docker image ของ apache ranger เรานั้นได้ run อย่างสมบูรณ์

logs ของ apache ranger

ต่อไปเราจะมาทำการตรวจสอบว่า Apache Ranger ของเรานั้นได้ทำการเชื่อม Trino ได้อย่างสมบูรณ์หรือไม่โดยการเข้าไปที่ web ui ของ ranger ผ่านทาง port 6080 ภายใน local ซึ่งเราจะพบกับหน้า login ตามรูปด้านล่าง ให้เราทำการใส่ user เป็น admin และ password เป็น ranger1234

ranger login ui

ขั้นตอนไปทำการ add Trino service ตาม steps ดังนี้

add Trino service
service detail

หากเราทำการ test connection เรียบร้อยแล้วให้ไปยัง audit ui เพื่อตรวจสอบว่า Trino เราได้ทำการส่ง audit log ไปยัง elasticsearch ตามในบทความถูกต้องหรือไม่ ซึ่งก็จะต้องแสดงผลตามรูปด้านล่าง

audit ui

จากจุดนี้ถือว่าการ build Ranger พร้อมทั้ง Trino plugin จาก source code ของเราเสร็จสมบูรณ์แล้ว ต่อไปก็จะเป็นการ deploy ลง ใน k8s

Deploy on Kubernetes

ในการ deploy ลง k8s นั้นเราจะแบ่งส่วนการติดตั้งออกเป็น 4 ส่วนดังนี้

  1. mysql
  2. elasticsearch (https://artifacthub.io/packages/helm/elastic/elasticsearch/7.12.1)
  3. apache ranger
  4. trino

เรามาเริ่มที่การ deploy mysql กันเลย โดยเราจะสร้าง file ชื่อว่า mysql-deployment.yaml จากนั้นทำการ deploy

kubectl apply -f  mysql-deployment.yaml

ต่อมาเราจะมาติดตั้ง elasticsearch กันโดยเราก็จะเริ่มจาก download values.yaml ซึ่งเราจะเปลี่ยนแปลงในส่วนเดียวนั้นคือ masterService

change masterService

จากนั้นใช้คำสั่ง helm install

helm install elasticsearch elastic/elasticsearch --values values-elasticsearch.yaml -n ranger

ถึงตรงนี้เราก็พร้อมที่จะ deploy Ranger กันแล้วโดยที่เราจะทำการสร้าง file ที่ชื่อว่า ranger-deployment.yaml จากนั้นก็ทำการ deploy

kubectl apply -f  ranger-deployment.yaml
ranger service ทำงาน

และหากใครใช้ LENS ก็สามารถทดลองทำ port forward เพื่อตรวจสอบ ranger ที่เราติดตั้งไปได้เลย

ตรวจสอบ ranger

service สุดท้ายที่เราจะทำการติดตั้งลงใน k8s นั้นก็คือ Trino ซึ่งทาง Trino เองก็ได้จัดเตรียม helm chart ไว้เพื่อง่ายต่อการ install https://github.com/trinodb/charts แต่หลังจากทดสอบด้วยการนำ image ที่เราได้ build ไปก่อนหน้ามาใช้งาน กลับพบปัญหาหลายอย่าง ตัวอย่างเช่น script ที่ใช้ install apache ranger plugin ใน Trino ต้องการสิทธ์ root รวมถึงปัญหา “Read-only file system” หลังจาก deploy ลง k8s แล้ว ผมจึงขอ build Trino docker image ใหม่เพื่อใช้สำหรับ deploy ลงใน k8s โดยเฉพาะซึ่งตั้งต้นจะอ้างอิงจาก git repo ของผมเอง https://github.com/pongthep/trino-ranger-k8s/tree/main/docker-image/trino ซึ่งเมื่อทำการ clone เรียบร้อยแล้ว เราจำเป็นต้อง download Trino server package โดยเรายังคงใช้ version 362 จากนั้นทำการ extract

tar zxvf trino-server-362.tar.gz

copy Trino plugin มาจากที่เรา build apache Ranger จากนั้น extract tar.gz

cp ~/ranger/target/ranger-2.1.0-trino-plugin.tar.gz .tar zxvf ranger-2.1.0-trino-plugin.tar.gz

จากนั้นทำซํ้าในขั้นตอนก่อนหน้าคือ update file enable-trino-plugin.sh และ install.properties

1.enable-trino-plugin.sh อ้างอิงมาจาก https://github.com/aakashnand/trino-ranger-demo/blob/main/trino/enable-trino-plugin.sh

2.install.properties อ้างอิงมาจาก https://github.com/aakashnand/trino-ranger-demo/blob/main/trino/install.properties

จากนั้นทำการ build init docker image ซึ่ง docker image ตัวนี้จะ pack lib ทุกอย่างที่จำเป็นต้องใช้ใน trino coordinator เหตุผลที่ต้องทำ init docker เพื่อในตอนที่เรา deploy k8s ตัว folder ของ Trino เราจะสร้างใน emptyDir เพื่อให้สามารถ read/write ได้เพื่อไม่โดน error “Read-only file system”

docker build -t pongthep/trino-k8s-init:1.0.0 -f Init.Dockerfile .docker push pongthep/trino-k8s-init:1.0.0

step ต่อไปเราก็จะทำการ build coordinator docker image ของ Trino

docker build -t pongthep/trino-k8s-coordinator:1.0.0 -f Coordinator.Dockerfile .docker push pongthep/trino-k8s-coordinator:1.0.0

จากนั้นทำจะทำการ deploy Trino Coordinator โดยใช้ file deployment

kubectl apply -f deployment-coordinator.yaml

เมื่อ deploy เรียบร้อยแล้วเราก็ทำการ check log หากเราพบ log ของ ranger async ด้านล่างถือว่าการเชื่อมต่อกับ Ranger สมบูรณ์แล้ว

trino coordinator logs

แต่ Trino ยังคงทำงานไม่ได้ถ้ายังไม่มี worker เรามาเริ่มจากการ build docker image ของ worker กันเลย

docker build -t pongthep/trino-k8s-worker:1.0.0 -f Worker.Dockerfile .docker push pongthep/trino-k8s-worker:1.0.0

ต่อมาก็ deploy ตัว file deployment

kubectl apply -f deployment-worker.yaml

จาก deploy worker แล้วก็ check ใน k8s namespace กับ ui ของ Trino อีกครั้ง

check Trino deployment

ขั้นตอนการตรวจสอบต่อไปคือเข้า ui ของ apache ranger เพื่อ add Trino service

add trino service และ ตรวจสอบ audit log

--

--