1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オンプレk8s上でicebergを使うための環境構築

Last updated at Posted at 2024-12-21

はじめに

  • icebergの検証も兼ねてある程度省エネ構成で作ってみたので雑にメモを投下します。
  • 間違いや改善点があれば是非是非ご指摘ください。
  • 自分と同じ初学者向けに書きたかったのですが、事前にmetallbやdns、ingress-controller、storageClassを用意している前提の手順になっています。
    • それらの用意がない場合はhost名を<service名>.<namespace>.svc.cluster.local:<port番号>にしてクラスタ内でアクセスできるようにしたり、kubectl port-forwardでアクセスしたりといった代替手段を適宜使ってください。

環境構成

  • Rancher
    • v2.9.3
    • k8s version: v1.30.6 +rke2r1
    • rancherでk8sクラスタを立ててますが、kindでもdockerでも大丈夫だと思います
    • 事前にingress-controllerとnfsのcsi-driverだけ入れました
  • Minio
  • 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 からアクセスできるようになります
  • buckets>Create Bucketでバケットを作成します
    • 今回はicebergという名前にしました
    • ついでにObject Browserからicebergバケット以下にwarehouseというパスを作成しています
      • もし作成しない場合は以降のs3aなどでアクセス先としてwarehouseを指定していますがこれは不要になります
    • アクセス設定をしてもいいですが、面倒なのでaccess policyをpublicに設定
  • access keyを作成
    • minio-consoleのweb UIのAccess Keys>Create access keyを押して作成

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を押して作成したものを入力
  • fs.s3a.secret.key
    • minio-tenant構築時にminio-consoleのweb UIのAccess Keys>Create access keyを押して作成したものを入力
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側にもバケットにファイルが作られている。
1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?