はじめに
- icebergの検証も兼ねてある程度省エネ構成で作ってみたので雑にメモを投下します。
- 間違いや改善点があれば是非是非ご指摘ください。
- 自分と同じ初学者向けに書きたかったのですが、事前にmetallbやdns、ingress-controller、storageClassを用意している前提の手順になっています。
- それらの用意がない場合はhost名を
<service名>.<namespace>.svc.cluster.local:<port番号>
にしてクラスタ内でアクセスできるようにしたり、kubectl port-forward
でアクセスしたりといった代替手段を適宜使ってください。
- それらの用意がない場合はhost名を
環境構成
- Rancher
- v2.9.3
- k8s version: v1.30.6 +rke2r1
- rancherでk8sクラスタを立ててますが、kindでもdockerでも大丈夫だと思います
- 事前にingress-controllerとnfsのcsi-driverだけ入れました
- Minio
- minio-operator: Chart version 6.0.4を利用
- Hive Metastore
- postgresql: Chart version 16.2.3を利用
- hive-metastoreはChartがいくつか公開されているがメンテされてなさそうなのでimageから作成する
- Trino
- trino: Chart version 1.35.0を利用
構築手順
minio-operatorを構築
minio-operatorのhelm chartからデプロイします
- デプロイはrancherのweb UIから行ったので実際に使ったコマンドではないですが、helmを使う場合はだいたいこんな感じだろうという手順を書いています。
- 事前準備
helm repo add minio https://operator.min.io
helm repo update
helm show values minio/operator > values.yaml
- values.yamlはingress部分だけ変更してほぼデフォルト
- ingress classは事前に用意したtraefikを利用
ingress:
enabled: true
host: minio-operator.mynet
ingressClassName: traefik
path: /
pathTyep: Prefix
- デプロイ
helm upgrade minio . \
--cleanup-on-fail \
--install \
--namespace minio-operator \
--create-namespace \
-f values.yml
一通りpodが立てばオッケー
minio tenantを構築
- ここまでで立てたminio-operatorを元にテナントを作成する
- コマンドでも出来るみたいだけど今回はmanifestを作成
- 内容は以下のような感じ
- 主な設定箇所
- MINIO_ROOT_USERとMINIO_ROOT_PASSWORDは適当に設定してください
- requestAutoCertは不要なのでfalseに設定。トラブル回避のためtlsは極力無効化します
- ingressとstorageClassは事前に作成したものを設定
- minioとminio-consoleというserviceが立つみたいで、minio-consoleの方にアクセスすればwebUIに入れる
- 一つのingressで設定する場合、traefikだとMiddleWareが必要だなどとめんどくさそうなことを言われたので、ingressは2つ立てた。細かいことはこだわらない(笑)
minio-tenant.yaml
apiVersion: v1
kind: Namespace
metadata:
name: minio-tenant
---
apiVersion: v1
kind: Secret
metadata:
name: storage-configuration
namespace: minio-tenant
stringData:
config.env: |-
export MINIO_ROOT_USER="*****"
export MINIO_ROOT_PASSWORD="********"
export MINIO_STORAGE_CLASS_STANDARD="EC:2"
export MINIO_BROWSER="on"
type: Opaque
---
apiVersion: v1
data:
CONSOLE_ACCESS_KEY: Y29uc29sZQ==
CONSOLE_SECRET_KEY: Y29uc29sZTEyMw==
kind: Secret
metadata:
name: storage-user
namespace: minio-tenant
type: Opaque
---
apiVersion: minio.min.io/v2
kind: Tenant
metadata:
annotations:
prometheus.io/path: /minio/v2/metrics/cluster
prometheus.io/port: "9000"
prometheus.io/scrape: "true"
labels:
app: minio
name: minio
namespace: minio-tenant
spec:
certConfig: {}
externalCertSecret:
- name: minio-tenant-cert
type: cert-manager.io/v1
configuration:
name: storage-configuration
env: []
externalCaCertSecret: []
externalCertSecret: []
externalClientCertSecrets: []
features:
bucketDNS: false
domains: {}
image: quay.io/minio/minio:RELEASE.2024-10-02T17-50-41Z
imagePullSecret: {}
mountPath: /export
podManagementPolicy: Parallel
pools:
- affinity:
nodeAffinity: {}
podAffinity: {}
podAntiAffinity: {}
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
name: pool-0
nodeSelector: {}
resources: {}
securityContext:
fsGroup: 1000
fsGroupChangePolicy: OnRootMismatch
runAsGroup: 1000
runAsNonRoot: true
runAsUser: 1000
servers: 3
tolerations: []
topologySpreadConstraints: []
volumeClaimTemplate:
apiVersion: v1
kind: persistentvolumeclaims
metadata: {}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Ti
storageClassName: nfs-csi
status: {}
volumesPerServer: 3
priorityClassName: ""
requestAutoCert: false
serviceAccountName: ""
serviceMetadata:
consoleServiceAnnotations: {}
consoleServiceLabels: {}
minioServiceAnnotations: {}
minioServiceLabels: {}
subPath: ""
users:
- name: storage-user
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minio-console-ingress
namespace: minio-tenant
spec:
ingressClassName: "traefik"
rules:
- host: minio-console.mynet
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: minio-console
port:
number: 9090
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minio-ingress
namespace: minio-tenant
spec:
ingressClassName: "traefik"
rules:
- host: minio.mynet
http:
paths:
- backend:
service:
name: minio
port:
number: 80
path: /
pathType: Prefix
- デプロイ
kubectl apply -f minio-tenant.yaml
web UIからバケットとkeyを作成
- minio-consoleにログイン
- ingressを設定してない場合は
kubectl port-forward svc/minio-console 9090:9090
でhttp://localhost:9090 からアクセスできるようになります
- ingressを設定してない場合は
-
buckets
>Create Bucket
でバケットを作成します- 今回はicebergという名前にしました
- ついでに
Object Browser
からicebergバケット以下にwarehouse
というパスを作成しています- もし作成しない場合は以降のs3aなどでアクセス先としてwarehouseを指定していますがこれは不要になります
- アクセス設定をしてもいいですが、面倒なのでaccess policyをpublicに設定
- access keyを作成
- minio-consoleのweb UIの
Access Keys
>Create access key
を押して作成
- minio-consoleのweb UIの
postgresqlを構築
minio-operatorの構築と大体同じ感じです。postgresqlのhelm chartからデプロイします
- デプロイにはrancherのweb UIから行ったので実際に使ったコマンドではないですが、helmを使う場合はだいたいこんな感じだろうという手順を書いています
- 事前準備
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm show values bitnami/postgresql > values.yaml
- values.yamlを修正
- auth.usernameとauth.passwordに適当な値をいれる
- storageClassを一通り設定
- primary.typeをLoadBalancerに、primary.loadBalancerIPを192.168.0.151(適当なipアドレス)に設定
- metallbがない場合はほかのtypeを選択してください
- postgresqlはingressが使えないみたい
- デプロイ
helm upgrade postgresql . \
--cleanup-on-fail \
--install \
--namespace postgresql \
--create-namespace \
-f values.yml
一通りpodが立てばオッケー
hive-metastoreの構築
- 先ほど構築したpostgresqlを利用する
postgresqlのカタログ用スキーマの初期化
- 以下の手順でスキーマを初期化する必要がある
- docker imageを作成してdockerHubにpushする
- 初期化用のスクリプトさえ実行できればよいが、macだとschematoolを動かすのが大変そうだったのでイメージを作る
imageの作成
Dockerfile
FROM apache/hive:4.0.0
# Set working directory
WORKDIR /opt/hive/lib
# Download PostgreSQL JDBC driver
ADD https://repo1.maven.org/maven2/org/postgresql/postgresql/42.7.3/postgresql-42.7.3.jar .
USER root
- M1 Macbookで実行しているので以下のコマンドでイメージを作成
- -tの部分に適切な値を入れてください
docker buildx build --push --platform linux/amd64,linux/arm64 -t <リポジトリ名>/<イメージ名>:<タグ> .
初期化を実行
- 以下を作成
- ユーザ名、ip、パスワードを適切なものに設定してください
- カタログ用スキーマ名は何でもいいですが、後ほどhive-metastoreを作成する際に同じものを指定する必要があります
initialize-schema.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: hive-schema-init
spec:
template:
metadata:
labels:
app: hive-schema-init
spec:
containers:
- name: hive-schema-init
image: <リポジトリ名>/<イメージ名>:<タグ>
command: ["/bin/sh", "-c"]
args:
- |
/opt/hive/bin/schematool --verbose -initSchema -dbType postgres \
-driver org.postgresql.Driver -userName "<postgresqlのユーザ名>" -passWord "<postgresqlのパスワード>" \
-url "jdbc:postgresql://<postgresql_ip>:5432/<カタログ用スキーマ名>?user=<postgresqlのユーザ名>&password=<postgresqlのパスワード>&createDatabaseIfNotExist=true"
restartPolicy: Never
jobを実行
kubectl apply -f initialize-schema.yaml
hive-metastoreのimageの作成
- メンテされてるhelm chartがなさそうだったので、imageを作成する
- まずは以下のファイルを作成
Dockerfile
FROM openjdk:8-slim
ARG HADOOP_VERSION=3.2.0
ARG HIVE_VERSION=3.0.0
ENV HADOOP_HOME="/opt/hadoop"
ENV HIVE_HOME="/opt/hive-metastore"
ENV PATH="/opt/spark/bin:/opt/hadoop/bin:${PATH}"
RUN apt-get update && apt-get install -y curl --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
RUN curl https://archive.apache.org/dist/hadoop/core/hadoop-$HADOOP_VERSION/hadoop-$HADOOP_VERSION.tar.gz \
| tar xvz -C /opt/ \
&& ln -s /opt/hadoop-$HADOOP_VERSION /opt/hadoop \
&& rm -r /opt/hadoop/share/doc
RUN ln -s /opt/hadoop/share/hadoop/tools/lib/hadoop-aws* /opt/hadoop/share/hadoop/common/lib/ && \
ln -s /opt/hadoop/share/hadoop/tools/lib/aws-java-sdk* /opt/hadoop/share/hadoop/common/lib/
RUN curl http://apache.uvigo.es/hive/hive-standalone-metastore-${HIVE_VERSION}/hive-standalone-metastore-${HIVE_VERSION}-bin.tar.gz \
| tar xvz -C /opt/ \
&& ln -s /opt/apache-hive-metastore-${HIVE_VERSION}-bin /opt/hive-metastore
RUN curl -o ${HIVE_HOME}/lib/postgresql-42.3.3.jar -L https://jdbc.postgresql.org/download/postgresql-42.3.3.jar
RUN curl -o ${HIVE_HOME}/lib/hive-exec-${HIVE_VERSION}.jar -L https://repo1.maven.org/maven2/org/apache/hive/hive-exec/${HIVE_VERSION}/hive-exec-${HIVE_VERSION}.jar
RUN chmod +x ${HIVE_HOME}/bin/* && chmod +x ${HADOOP_HOME}/bin/*
RUN rm /opt/hadoop/share/hadoop/common/lib/slf4j-log4j12*.jar
COPY log4j2.xml /opt/hive-metastore/conf/
- ここでマウントしているlog4j2.xmlとして以下の内容のファイルを作成
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
- docker imageを作成してdockerHubにpushする
- M1 Macbookで実行しているので以下のコマンド
- -tの部分に適切な値を入れてください
docker buildx build --push --platform linux/amd64,linux/arm64 -t <リポジトリ名>/<イメージ名>:<タグ> .
hive-metastoreのpodのデプロイ
- containers.image
- 先ほど作成したimageを指定
- metastore.warehouse.dir
- minio側でデータを作成するデフォルトのディレクトリを指定
- javax.jdo.option.ConnectionURL
- postgresqlのipやhost名とカタログ用のスキーマを指定
- javax.jdo.option.ConnectionUserName
- postgresql構築時に設定したユーザ名
- javax.jdo.option.ConnectionPassword
- postgresql構築時に設定したパスワード
- fs.s3a.endpoint
- minio-tenantで作成したminioという名前のserviceを指定。
- ingressを立ててない場合は、minio..svc.clustor.local:80を指定すればアクセス可能
- fs.s3a.access.key
- minio-tenant構築時にminio-consoleのweb UIの
Access Keys
>Create access key
を押して作成したものを入力
- minio-tenant構築時にminio-consoleのweb UIの
- fs.s3a.secret.key
- minio-tenant構築時にminio-consoleのweb UIの
Access Keys
>Create access key
を押して作成したものを入力
- minio-tenant構築時にminio-consoleのweb UIの
hive-metastore.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hive-metastore
namespace: hive-metastore
spec:
replicas: 1
selector:
matchLabels:
app: hive-metastore
template:
metadata:
labels:
app: hive-metastore
spec:
containers:
- name: hive-metastore
image: "<リポジトリ名>/<イメージ名>:<タグ>"
ports:
- containerPort: 9083
env:
- name: SERVICE_NAME
value: hive-metastore
- name: DB_DRIVER
value: postgres
- name: HIVE_HOME
value: /opt/hive-metastore
- name: HADOOP_HOME
value: /opt/hadoop
volumeMounts:
- name: metastore-cfg-vol
mountPath: /opt/hive-metastore/conf/metastore-site.xml
subPath: metastore-site.xml
- name: metastore-cfg-vol
mountPath: /opt/hadoop/etc/hadoop/core-site.xml
subPath: core-site.xml
command: ["/opt/hive-metastore/bin/start-metastore"]
volumes:
- name: metastore-cfg-vol
configMap:
name: metastore-cfg
---
apiVersion: v1
kind: ConfigMap
metadata:
name: metastore-cfg
namespace: hive-metastore
data:
metastore-site.xml: |
<configuration>
<property>
<name>hive.metastore.uris</name>
<value>thrift://0.0.0.0:9083</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>org.postgresql.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:postgresql://<postgresql_ip>:5432/<カタログ用スキーマ名></value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>****</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>******</value>
</property>
<property>
<name>metastore.warehouse.dir</name>
<value>s3a://iceberg/warehouse/</value>
</property>
<property>
<name>metastore.thrift.port</name>
<value>9083</value>
</property>
</configuration>
core-site.xml: |
<configuration>
<property>
<name>fs.s3a.connection.ssl.enabled</name>
<value>true</value>
</property>
<property>
<name>fs.s3a.endpoint</name>
<value>http://minio.mynet</value>
</property>
<property>
<name>fs.s3a.fast.upload</name>
<value>true</value>
</property>
<property>
<name>fs.s3a.access.key</name>
<value>********************</value>
</property>
<property>
<name>fs.s3a.secret.key</name>
<value>***********************</value>
</property>
<property>
<name>fs.s3a.path.style.access</name>
<value>true</value>
</property>
</configuration>
---
apiVersion: v1
kind: Service
metadata:
name: hive-metastore
namespace: hive-metastore
spec:
selector:
app: hive-metastore
ports:
- port: 9083
# targetPort: 9083
type: ClusterIP
trinoを構築
- お疲れ様です。最後にtrinoを立てれば終了です。
- trinoのhelm chartからデプロイします
- デプロイにはrancherのweb UIから行ったので実際に使ったコマンドではないですが、helmを使う場合はだいたいこんな感じだろうという手順を書いています。
事前準備
helm repo add trino https://trinodb.github.io/charts/
helm repo update
helm show values trino/trino > values.yaml
valuesを修正
- icebergカタログの設定を追加
- s3.endpointはminio-tenant構築時に作成したminio serviceを指定している
- s3.regionはminioの場合はとりあえずus-east-1を入れておけばいいらしい
- s3.aws-access-keyとs3.aws-secret-keyはhive-metastoreの設定時にminioのweb UIで作成したものを書く
- file-formatは好きなものを指定してください
values.yaml
iceberg: >
connector.name=iceberg
iceberg.catalog.type=hive_metastore
hive.metastore.uri=thrift://hive-metastore.hive-metastore.svc.cluster.local:9083
fs.native-s3.enabled=true
s3.path-style-access=true
s3.endpoint=http://minio.mynet
s3.region=us-east-1
s3.aws-access-key=******
s3.aws-secret-key=******
iceberg.file-format=PARQUET
- ingress部分も必要に応じて設定してください
values.yaml
ingress:
annotations: {}
className: traefik
enabled: true
hosts:
- host: trino.mynet
paths:
- path: /
pathType: Prefix
tls: null
- 認証やtlsは設定していませんが必要に応じて設定してください
デプロイ
helm upgrade trino . \
--cleanup-on-fail \
--install \
--namespace trino \
--create-namespace \
-f values.yml
動作確認
- trinoに接続
trino --server http://trino.mynet --catalog iceberg --debug
- スキーマを作成
trino> create schema iceberg.sample_schema
-> with (location = 's3a://iceberg/warehouse/sample_schema');
CREATE SCHEMA
- テーブルを作成
trino> CREATE TABLE sample_schema.sample_table (
-> c1 INTEGER,
-> c2 DATE,
-> c3 DOUBLE
-> )
-> WITH (
-> format = 'PARQUET',
-> partitioning = ARRAY['c1', 'c2'],
-> sorted_by = ARRAY['c3'],
-> location = 's3a://iceberg/warehouse/sample_schema'
-> );
CREATE TABLE
- 確認
trino> show tables from iceberg.sample_schema;
Table
---------------
sample_table
(1 row)
Query 20241221_092930_00027_qir66, FINISHED, 3 nodes
http://trino.mynet/ui/query.html?20241221_092930_00027_qir66
Splits: 24 total, 24 done (100.00%)
CPU Time: 0.0s total, 76 rows/s, 2.7KiB/s, 54% active
Per Node: 0.0 parallelism, 1 rows/s, 57B/s
Parallelism: 0.1
Peak Memory: 358B
0.21 [1 rows, 36B] [4 rows/s, 172B/s]
- minio側にもバケットにファイルが作られている。