Cloudera Hue をCDHから切り離してDockerで運用出来ないか検討してみる
1日遅れになってしまいましたが、、、
この記事は MicroAd (マイクロアド) Advent Calendar 2020 - Qiita の20日目の記事です。
昨日は dai08srhg - Qiita のEmbulkの話でした。
(´-`).。oO(EmbulkはHiveやHDFS系のプラグインがアップデートあると嬉しいなぁと思う今日この頃)
qiita.com
さて、本題ですが、今回はHueとDockerを使った話です。 Cloudera Hueは、 CDHに含まれているコンポーネントの一つ ですが、Hueは他のコンポーネントに比べて他のコンポーネントと協調して動作するものではなく基本的にクラスタのクライアントな立ち位置となります。
また、Hueはこのところ積極的なアップデートがあるので常に最新を使いたい!が、CDHはその都度追従してくれるわけでも無い状態です。そこで今回は、CDHから切り離して、Hue On Dockerで代わりが出来ないか考えてみます。
Hue自身については、12/23の以下のアドカレでアップデート情報があるので気になる方はご覧になって下さい。
前提
- CDHを使っている(v6.3.2 を今回の題材にしているが、v5系でも良いはず)
- Hueを動かすDockerホストには管理者しかリモートログイン出来ず、利用者はWebUIのみとする
- Cloudera Navigator、Navigator Optimizerの利用は対象外(私が利用できないので検証出来ない為)
- HTTPS対応は今回対象外とする(検証環境を用意するには時間が足りないので…)
- LDAP、SAML認証については、対象外(検証環境を用意するには時間が足りないので…)
- この辺を参考にしたらよさそう→ Hue Security | 6.3.x | Cloudera Documentation
- HueでつかうSparkについては、Livyが用意出来なかったので見送り
Kubernetesでの稼働は見送り(時間足らんかった…)
- Helmは hue/tools/kubernetes at master · cloudera/hue にあるのでそちらを参考にしたら良さそう
CDHにHueを入れてるけど、最新のHueに上げたくてウズウズしている
Docker でHueを動かしてみる
hue/tools/docker/hue at master · cloudera/hue に docker-compose.yml
があるのでそちらを参考にします。
また、Dockerfileもあります1 が、 Makefile を読むと分かるように単純にdocker buildするだけではダメそうなので、今回はbuild済みのDockerHubにある コンテナイメージ を使う方向で進めます。
早速、Docker Composeは以下の様にしてます。
version: '3.8' services: hue: image: gethue/hue:20201215-135001 # ・・・★1 hostname: hue container_name: hue ports: - "8888:8888" volumes: - ./conf/hue/z-hue.ini:/usr/share/hue/desktop/conf/z-hue.ini # ・・・★2 - ./conf/hue/log.conf:/usr/share/hue/desktop/conf/log.conf - ./conf/hive-conf/:/etc/hive/conf/ # ・・・★3 depends_on: - database networks: - backend extra_hosts: # ・・・★4 - "my-cdh-namenode-vip.example.com:192.0.2.1" - "my-cdh-hiveserver2.example.com:192.0.2.2" - "my-cdh-m01.example.com:192.0.2.3" - "my-cdh-m02.example.com:192.0.2.4" - "my-cdh-m03.example.com:192.0.2.5" - "my-cdh-w01.example.com:192.0.2.6" # 外部RDBでもOK database: # ・・・★5 image: mysql:8.0 hostname: database container_name: database env_file: - ./env/database.env command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --init-connect='SET NAMES UTF8;' --innodb-flush-log-at-trx-commit=0 volumes: - ./db/data:/var/lib/mysql # ・・・★6 - ./db/sql:/docker-entrypoint-initdb.d # ・・・★7 # - ./db/my.cnf:/etc/mysql/conf.d/my.cnf # 必要ならここでチューニングしてください networks: - backend networks: backend:
起動時の注意
実行する手順は、 初回だけ以下の様にdatabaseだけ先に起動して、初回起動時にHueのデータベースを作成してからHueを起動します。
$ docker-compose up --no-start $ docker-compose start database $ docker-compose up -d
2回目以降は、 docker-compose up -d
のみでOKです。
では、Docker Composeを見ていきます。
利用するコンテナイメージについて
★1について、hueのイメージは、latest
から変更しています。理由は簡単で、HueのDockerhubにあるイメージは定期的に更新しているので latest
を使ってしまうと、ある日突然、動かなくなるなんて事にならないように、ある日の場所を固定するようにしています。
ただ、タグが 20201215-135001
とソースのどの時点か分かり難いので、本番で運用するなら、自前でmake使ってbuildする際に、Hueのバージョンとコミットハッシュをタグに仕込むなどの工夫をした方が良さそうです。
この辺は 以下の記事が参考になります。
Hueの設定ファイルの運用について
★2について、ホスト上のファイルをそのまま置き換える様にしています。
初回時は色々と設定をいじるので直接置き換える方が楽なのでこのようにしています。
また、マウントするのは hue.ini
ではなく z-hue.ini
であるところが注意です。
z-hue.ini
はデフォルト値からの変更分だけ設定するたけで良いためです。 hue.ini
としてしまうと全ての設定値を入れる必要があるのでとても面倒です。
ただ、このままだと、実行するホストに設定ファイルを持っていくようにするなどの対応がひつようになりますので、取り回しが面倒です。本番運用の際は、変更する設定値は固定されるはずなので、 Hueが起動時に実行するスクリプト にて、envsubstで環境変数で差し替え出来るようにするなどの工夫が必要になる3 と考えます。
z-hue.ini の中身自体は、ここでは言及しませんが、CDHで使っているHueの設定を参考に変更していけばよいです。 また、すべての設定値については、 hue/hue.ini at master · cloudera/hue · GitHub にすべて上がってるのでこちらが参考になります。
また、設定が正しいかについては、docker-composeで出力しているログだけでなく、WebUIの管理画面から以下の様に問題が発生していないかチェックしてください。
★3のHiveの設定ですが、これは、Cloudera ManagerからHiveのクライアント設定をダウンロードしたものを置くようにしています。
また、これは、 hue.iniで hive_conf_dir にて利用しているものです。流石にこれをenvsubstで差し替えするのは苦行すぎるので、イメージに含めるか、 startup.sh
にて取得する処理を書くなど工夫がひつようになりそうです(もしくはVolumeコンテナにしてマウントして使うとか)。
/etc/hosts
について
★4で追加しているhostsですが、設定ファイルで参照している対象のHadoopのクラスタのホスト分だけ追加しています。
Hueから参照する外部DBについて
★5について、今回はComposeにMySQLをふくめていますが、本番運用時には、これまで使ってきたHueのデータベースがあるはずなので、そちらをHueから参照したらよいです。
起動する度に揮発しないように ★6でMySQLのデータ領域をホストから直接マウントして永続化しています。
★7の ./db/sql:/docker-entrypoint-initdb.d
についてですが、MySQLを初回起動する際に実行するSQLクエリを置いています。
初回時にHueで使うデータベースを作成する必要があるためです。 ただ、こちらは初回起動時(= /var/lib/mysql
が空っぽの場合)のみ実行となります。起動時に毎回実行するクエリじゃないのでお気をつけ下さい。忘れてるとハマリます。
その他の考慮ポイント
Hueの負荷分散について
現行のCDHのHueがLBを使って負荷分散している場合は、 How to Add a Hue Load Balancer | 6.3.x | Cloudera Documentation のとおり、簡単にHueのロール追加してLBからアクセスするだけなので簡単ですが、自前でやるにはその辺りも自分で用意が必要になります。
後、Configure Hue for High Availability | 6.3.x | Cloudera Documentation あたりも。
Hueの監視について
CDHから切り離すということは、自前で監視も必要になります。
Hueからのメール通知は z-hue.ini
の [desktop]
セクションの django_server_email
や django_email_backend
に設定したら良いですが、
Hueのアプリログの監視だったり、リソースの監視も必要です。
Loggingについて
Hueアプリログについては、Hueではfluentdの方法を以下で紹介しています。 Logs - Cloud :: Hue SQL Assistant Documentation
他にも今回の場合は、 Dockerの機能を使ってloggingの設定をするなど考えられます。Syslogに転送とか。 設定方法や詳細については、以下を参考にしてください。
- Compose file version 3 reference | Docker Documentation
- Configure logging drivers | Docker Documentation
また、長期運用する際、アプリログでホストのDiskを溢れさせないように最低でも、Docker daemonの設定 daemon.json を変更して、最大ファイルサイズや世代管理などを設定するか4 、Docker ComposeファイルのHueサービスに設定するか5して下さい。
Metricsについて
リソース監視については、 以下の通り、[desktop]
セクションの enable_prometheus=true
とする事でメトリックがPromethus向けのエンドポイント http://hue-server:8888/metrics
から取得出来るのでこれを使えば良さそうです。
こんな感じのものが取れます
詳細
# HELP django_db_new_connection_errors_total Counter of connection failures by database and by vendor. # TYPE django_db_new_connection_errors_total counter # HELP process_virtual_memory_bytes Virtual memory size in bytes. # TYPE process_virtual_memory_bytes gauge process_virtual_memory_bytes 1.896771584e+09 # HELP process_resident_memory_bytes Resident memory size in bytes. # TYPE process_resident_memory_bytes gauge process_resident_memory_bytes 2.1581824e+08 # HELP process_start_time_seconds Start time of the process since unix epoch in seconds. # TYPE process_start_time_seconds gauge process_start_time_seconds 1.60849601239e+09 # HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. # TYPE process_cpu_seconds_total counter process_cpu_seconds_total 85.46000000000001 # HELP process_open_fds Number of open file descriptors. # TYPE process_open_fds gauge process_open_fds 19.0 # HELP process_max_fds Maximum number of open file descriptors. # TYPE process_max_fds gauge process_max_fds 1.048576e+06 # HELP django_http_ajax_requests_total Count of AJAX requests. # TYPE django_http_ajax_requests_total counter django_http_ajax_requests_total 922.0 # HELP django_http_ajax_requests_created Count of AJAX requests. # TYPE django_http_ajax_requests_created gauge django_http_ajax_requests_created 1.608496022301734e+09 # HELP django_http_responses_body_total_bytes Histogram of responses by body size. # TYPE django_http_responses_body_total_bytes histogram django_http_responses_body_total_bytes_bucket{le="0.0"} 22.0 django_http_responses_body_total_bytes_bucket{le="1.0"} 22.0 django_http_responses_body_total_bytes_bucket{le="2.0"} 22.0 django_http_responses_body_total_bytes_bucket{le="4.0"} 22.0 django_http_responses_body_total_bytes_bucket{le="8.0"} 22.0 django_http_responses_body_total_bytes_bucket{le="16.0"} 739.0 django_http_responses_body_total_bytes_bucket{le="32.0"} 750.0 django_http_responses_body_total_bytes_bucket{le="64.0"} 752.0 django_http_responses_body_total_bytes_bucket{le="128.0"} 755.0 django_http_responses_body_total_bytes_bucket{le="256.0"} 811.0 django_http_responses_body_total_bytes_bucket{le="512.0"} 824.0 django_http_responses_body_total_bytes_bucket{le="1024.0"} 834.0 django_http_responses_body_total_bytes_bucket{le="2048.0"} 843.0 django_http_responses_body_total_bytes_bucket{le="4096.0"} 848.0 django_http_responses_body_total_bytes_bucket{le="8192.0"} 859.0 django_http_responses_body_total_bytes_bucket{le="16384.0"} 864.0 django_http_responses_body_total_bytes_bucket{le="32768.0"} 864.0 django_http_responses_body_total_bytes_bucket{le="65536.0"} 869.0 django_http_responses_body_total_bytes_bucket{le="131072.0"} 885.0 django_http_responses_body_total_bytes_bucket{le="262144.0"} 910.0 django_http_responses_body_total_bytes_bucket{le="524288.0"} 911.0 django_http_responses_body_total_bytes_bucket{le="1.048576e+06"} 911.0 django_http_responses_body_total_bytes_bucket{le="2.097152e+06"} 911.0 django_http_responses_body_total_bytes_bucket{le="4.194304e+06"} 911.0 django_http_responses_body_total_bytes_bucket{le="8.388608e+06"} 911.0 django_http_responses_body_total_bytes_bucket{le="1.6777216e+07"} 911.0 django_http_responses_body_total_bytes_bucket{le="3.3554432e+07"} 911.0 django_http_responses_body_total_bytes_bucket{le="6.7108864e+07"} 911.0 django_http_responses_body_total_bytes_bucket{le="1.34217728e+08"} 911.0 django_http_responses_body_total_bytes_bucket{le="2.68435456e+08"} 911.0 django_http_responses_body_total_bytes_bucket{le="5.36870912e+08"} 911.0 django_http_responses_body_total_bytes_bucket{le="+Inf"} 911.0 django_http_responses_body_total_bytes_count 911.0 django_http_responses_body_total_bytes_sum 6.98808e+06 # HELP django_http_responses_body_total_bytes_created Histogram of responses by body size. # TYPE django_http_responses_body_total_bytes_created gauge django_http_responses_body_total_bytes_created 1.608496022302478e+09 # HELP django_http_requests_latency_including_middlewares_seconds Histogram of requests processing time (including middleware processing time). # TYPE django_http_requests_latency_including_middlewares_seconds histogram django_http_requests_latency_including_middlewares_seconds_bucket{le="0.005"} 0.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.01"} 2.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.025"} 18.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.05"} 95.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.075"} 773.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.1"} 878.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.25"} 1100.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.5"} 1146.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="0.75"} 1166.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="1.0"} 1172.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="2.5"} 1184.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="5.0"} 1184.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="7.5"} 1185.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="10.0"} 1185.0 django_http_requests_latency_including_middlewares_seconds_bucket{le="+Inf"} 1185.0 django_http_requests_latency_including_middlewares_seconds_count 1185.0 django_http_requests_latency_including_middlewares_seconds_sum 145.3799285888672 # HELP django_http_requests_latency_including_middlewares_seconds_created Histogram of requests processing time (including middleware processing time). # TYPE django_http_requests_latency_including_middlewares_seconds_created gauge django_http_requests_latency_including_middlewares_seconds_created 1.608496022301204e+09 # HELP django_db_execute_total Counter of executed statements by database and by vendor, including bulk executions. # TYPE django_db_execute_total counter django_db_execute_total{alias="default",vendor="mysql"} 4671.0 # HELP django_db_execute_created Counter of executed statements by database and by vendor, including bulk executions. # TYPE django_db_execute_created gauge django_db_execute_created{alias="default",vendor="mysql"} 1.608496025350343e+09 # HELP django_db_new_connections_total Counter of created connections by database and by vendor. # TYPE django_db_new_connections_total counter django_db_new_connections_total{alias="default",vendor="mysql"} 1234.0 # HELP django_db_new_connections_created Counter of created connections by database and by vendor. # TYPE django_db_new_connections_created gauge django_db_new_connections_created{alias="default",vendor="mysql"} 1.608496025331346e+09 # HELP django_db_execute_many_total Counter of executed statements in bulk operations by database and by vendor. # TYPE django_db_execute_many_total counter # HELP hue_queries_numbers Hue - numbers of queries # TYPE hue_queries_numbers gauge hue_queries_numbers 0.0 # HELP django_http_requests_total_by_method_total Count of requests by method. # TYPE django_http_requests_total_by_method_total counter django_http_requests_total_by_method_total{method="GET"} 418.0 django_http_requests_total_by_method_total{method="POST"} 768.0 # HELP django_http_requests_total_by_method_created Count of requests by method. # TYPE django_http_requests_total_by_method_created gauge django_http_requests_total_by_method_created{method="GET"} 1.608498263366093e+09 django_http_requests_total_by_method_created{method="POST"} 1.608498266610787e+09 # HELP django_db_errors_total Counter of execution errors by database, vendor and exception type. # TYPE django_db_errors_total counter # HELP hue_local_active_users Hue Active Users in Local Instance # TYPE hue_local_active_users gauge hue_local_active_users 1.0 # HELP python_info Python platform information # TYPE python_info gauge python_info{implementation="CPython",major="2",minor="7",patchlevel="17",version="2.7.17"} 1.0 # HELP django_http_responses_total_by_status_total Count of responses by status. # TYPE django_http_responses_total_by_status_total counter django_http_responses_total_by_status_total{status="302"} 22.0 django_http_responses_total_by_status_total{status="404"} 5.0 django_http_responses_total_by_status_total{status="500"} 11.0 django_http_responses_total_by_status_total{status="200"} 1147.0 # HELP django_http_responses_total_by_status_created Count of responses by status. # TYPE django_http_responses_total_by_status_created gauge django_http_responses_total_by_status_created{status="302"} 1.608498266638196e+09 django_http_responses_total_by_status_created{status="404"} 1.608500670664722e+09 django_http_responses_total_by_status_created{status="500"} 1.60849828267096e+09 django_http_responses_total_by_status_created{status="200"} 1.608498263373063e+09 # HELP hue_active_users Hue Active Users in All Instances # TYPE hue_active_users gauge hue_active_users 1.0
ドキュメントでは以下で紹介しています。 Metrics - Cloud :: Hue SQL Assistant Documentation
また、管理画面でキレイにして確認出来るようになってました。 http://hue-server:8888/hue/desktop/metrics
Tracingについて
Tracingについては、Jeagerを内包しているようなので、こちらも面白そうです(あらやだイケメン)。
詳細は Tracing - Cloud :: Hue SQL Assistant Documentation を参照下さい。
さいごに
セキュアにしたい!とか、可用性を十分に担保しないといけないという要件がないのなら、
個人的にはHueをCDHから切り離してDockerつかって運用でも十分いけるんじゃないかなぁと考えました。
また、今回見送った点については、別に出来ないってこともないです。
他にも出来れば、複数のクラスタを扱えるように出来たら良いけど、上手い事出来ないものか🤔ヤリカタワカラン
以上、「Cloudera Hue をCDHから切り離してDockerで運用出来ないか検討してみる」でした。
-
Dockerfile やPython3版の Dockerfile.py3 が用意されています。↩
-
digdagサーバをコンテナで動かしてジョブもコンテナで動かす際の設定例 - Qiita の
entrypoint.sh
が参考になります。
差し替え用の設定ファイル(/etc/digdag/server.properties
)をイメージに含めておいて、entrypoint.sh
で実行する際にenvsubstで置き換えるイメージです。
Hueの場合は、差し替え用設定ファイルを/usr/share/hue/z-hue.ini.template
辺りに置いといて、 startup.sh にてenvsubstでz-hue.ini
に置き換えます。↩ -
Configure the default logging driver - Configure logging drivers | Docker Documentation↩
-
例えば logging - Compose file version 3 reference | Docker Documentation にあるとおり、docker-compose.yml の services.hue.loggingとして追加するとか。↩