Redash 沢山作らないといけないとなった時に GKE でやろうとしたら何箇所か手こずったのでメモ書き。
(随時追加)
前提
- 1 から構成用の yaml ファイルを作るのは辛いので Kompose で Redash のソースに含まれている
docker-compose.production.yml
を変換して使う - 当然 HTTPS
- 作り直しても IP 変わらないように static な IP を指定する
- postgresql のデータは永続化する
$ kompose convert -f docker-compose.production.yml
tl;dr
ざっくりこんな感じの docker-compose.yaml 作って前述の通り何箇所か修正すれば良い。
$ cat docker-compose.yaml
version: '2'
services:
redash:
image: redash/redash:latest
command: server
depends_on:
- postgres
- redis
ports:
- "5000:5000"
environment:
PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
REDASH_COOKIE_SECRET: **************
REDASH_WEB_WORKERS: 4
labels:
kompose.service.type: NodePort
kompose.service.expose: "redash.example.com"
kompose.service.expose.tls-secret: <tls-secret-resource-name>
restart: always
worker:
image: redash/redash:latest
command: scheduler
environment:
PYTHONUNBUFFERED: 0
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
QUEUES: "queries,scheduled_queries,celery"
WORKERS_COUNT: 2
restart: always
redis:
image: redis:3.0-alpine
ports:
- "6379:6379"
restart: always
postgres:
image: postgres:9.5.6-alpine
ports:
- "5432:5432"
labels:
kompose.volume.size: 1Gi
environment:
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- "postgres:/var/lib/postgresql/data"
restart: always
$ kompose convert -f docker-compose.yml --stdout\
| yq -y ".items[]"\
| yq -y "select(.kind == \"Ingress\").metadata.annotations[\"kubernetes.io/ingress.allow-http\"] = \"false\""\
| yq -y "select(.kind == \"Ingress\").metadata.annotations[\"kubernetes.io/ingress.global-static-ip-name\"] = \"<static-ip-label>\""\
| yq -y "select(.kind == \"Deployment\" and .metadata.name == \"redash\").spec.template.spec.containers[0].readinessProbe = {httpGet:{path:\"/static/images/favicon-32x32.png\",port:5000}}"\
| tee gke.yaml
1. Kompose して起動すると Deployment の Name がとても衝突しやすい名称
docker-composer.yaml に記載されたサービス名?が Deployment の Name として使用される変換ロジックなのでさもありなん。
$ kompose up -f docker-compose.production.yml
で起動するだけならさらっとできるけどそんな理由で却下。
A. Namespace を指定する
$ # Ex.
$ kompose convert -f docker-compose.production.yml -o <redash-on-gke.yml>
$ kubectl apply -n <namespace> -f <redash-on-gke.yml>
とか
2. Redash サーバーのフロントに立ってる Worker コンテナが起動しない
こんなエラー
$ kubectl logs $(basename $(kubectl get pod -o name -n <namespace> -l 'io.kompose.service==worker'))
Starting scheduler and 2 workers for queues: queries,scheduled_queries,celery...
[2018-08-28 06:14:10,224][PID:1][INFO][root] Generating grammar tables from /usr/lib/python2.7/lib2to3/Grammar.txt
[2018-08-28 06:14:10,270][PID:1][INFO][root] Generating grammar tables from /usr/lib/python2.7/lib2to3/PatternGrammar.txt
Traceback (most recent call last):
File "/usr/local/bin/celery", line 11, in <module>
...
redis.exceptions.ConnectionError: Error -2 connecting to redis:6379. Name or service not known.
A. Service redis
を作る
元の docker-compose.yml で redis は ports
が指定されていません。
docker で起動するならそれでも問題ないですが、 GKE で起動するにはクラスター内の別 Pod と通信するための仕様に沿う必要があります。
クラスター内の別 Pod と通信するには Service を用意してあげる必要があります。
また Redis でエラーになってますが、どうせ PostgreSQL も同じことになるので一緒に対応します。
@@ -36,5 +36,9 @@ services:
redis:
image: redis:3.0-alpine
+ ports:
+ - "6379:6379"
restart: always
postgres:
image: postgres:9.5.6-alpine
+ ports:
+ - "5432:5432"
3. Redash サーバーのフロントに立ってる Nginx コンテナも起動しない
こんなエラー
$ kubectl logs $(basename $(kubectl get pod -o name -n <namespace> -l 'io.kompose.service==nginx'))
2018/08/28 06:12:26 [emerg] 1#1: host not found in upstream "redash:5000" in /etc/nginx/conf.d/default.conf:2
nginx: [emerg] host not found in upstream "redash:5000" in /etc/nginx/conf.d/default.conf:2
A-1. server
を redash
に変更する
GKE では metadata.name
がクラスタ内で使用できるホスト名となる。
kompose を介す場合は docker-compose.yml の services に記載したサービス名が該当する。
@@ -7,5 +7,5 @@
workers.
version: '2'
services:
- server:
+ redash:
image: redash/redash:latest
A-2. nginx
を使用しない
後述するがそもそも HTTPS 対応において nginx
は不要となる。
そのため docker-compose.yml からこの段階で nginx
を削除してしまう。
そうすればエラーも何もなくなる。
@@ -33,10 +37,1 @@ services:
restart: always
- nginx:
- image: redash/nginx:latest
- ports:
- - "80:80"
- depends_on:
- - server
- links:
- - server:redash
- restart: always
A-3. 両方やる
どっちにしろ server
という名称は用途が分からなくなるので redash
に変えてしまうのはあり、という話。
4. Redash サーバーのフロントに立ってる Nginx コンテナだと HTTPS に (多分) できない
HTTP で良ければ nginx
の Service のタイプを LoadBalancer
にすれば可能。
kompose 経由で指定する場合は labels に kompose.service.type: LoadBalancer
を追加する
@@ -53,4 +53,6 @@ services:
- server
links:
- server:redash
+ labels:
+ kompose.service.type: LoadBalancer
restart: always
ただ HTTPS にする方法がなさそう。
A. Ingress を利用する
Ingress という機能がある。
kompose 経由で証明書を使うように指定すると自動的に Ingress を使うための設定も吐き出させれる。
nginx
は前述の通り消してしまい、 redash
の labels に以下を追加すると SSL 証明書まで設定された HTTPS 通信が実現できる。
Ingress はデフォルトで HTTP ポートも開けるのでこの段階では redash には HTTP/HTTPS の両方でアクセスできる。(HTTP を塞ぐ方法は後述)
また Ingress は実際には GCP Load Balancing backend service
@@ -21,4 +21,7 @@ services:
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
REDASH_COOKIE_SECRET: veryverysecret
REDASH_WEB_WORKERS: 4
+ labels:
+ kompose.service.expose: "redash.example.com"
+ kompose.service.expose.tls-secret: <tls-secret-resource-name>
restart: always
-
kompose.service.expose: ...
は SNI のホスト名として使用されるが不要なら"true"
にしておく -
kompose.service.expose.tls-secret: <tls-secret-resource-name>
で証明書を指定する
証明書を <tls-secret-resource-name>
を GKE に登録するには
こればかりは秘密鍵を含むので kompose を利用することも出来ない。
$ kubectl create secret tls <tls-secret-resource-name> -n <namespace> --key=privkey.pem --cert=fullchain.pem
5. Ingress で HTTP を塞ぐ
Kompose は対応していないので生成した <redash-on-gke.yml> を書き換える。
具体的には Ingress の metadata.annotations
に "kubernetes.io/ingress.allow-http": "false"
を追加する。
6. Ingress から Service に届かない
待てども繋がるようにならない。
これはいくつか理由がある。
ここが一番手間だった。
A-1. Service を NodePort にする
Ingress から Service に通信するには NodePort にする必要がある。
@@ -24,2 +24,3 @@ services:
labels:
+ kompose.service.type: NodePort
kompose.service.expose: "redash.example.com"
A-2. Ingress のヘルスチェックが通るようにする必要がある。
Ingress は勝手にヘルスチェックしてステータスコード 200 を要求する。
ヘルスチェックするデフォルトのパスは /
だが、 redash の /
にリクエストすると /login
へのリダイレクトになって 302
となるのでヘルスチェックが成功しない。
Kompose は対応していないので生成した <redash-on-gke.yml> を書き換える。
具体的には Deployment redash
の spec.template.spec.containers[*]
に readinessProbe
を追加する。
@@ -131,6 +131,10 @@ items:
ports:
- containerPort: 5000
resources: {}
+ readinessProbe:
+ httpGet:
+ path: /static/images/favicon-32x32.png
+ port: 5000
restartPolicy: Always
/login
にするとログイン画面のアクセスのリミットに引っかかるので画像ファイルへのアクセスにすると良いと思う。
A-3. GCE Load Balancing Backend Services のリソース数上限を上げる
GKE ダッシュボード上でサービスを見る と以下のような警告が Ingress に対して出ている。
googleapi: Error 403: Quota 'BACKEND_SERVICES' exceeded. Limit: 3.0 globally., quotaExceeded
で実際調べて見ると上限に達している。
$ gcloud compute project-info describe --project <project-name> | grep BACKEND_SERVICES -B1 -A1
- limit: 3.0
metric: BACKEND_SERVICES
usage: 3.0
これはもうリソース数上限を上げるか他の Ingress と共用するかしかない。
A-4. PostgreSQL に redash 用のデータを構築する
Ingress から Service に届くようになったはずだけどまだ画面が表示されないはず。
以下のようなエラーとなると思う。
$ kubectl logs $(basename $(kubectl get pod -o name -n <namespace> -l 'io.kompose.service==postgres'))
...
ERROR: relation "queries" does not exist at character 979
これは DB の構築がまだであるためなので redash サーバー経由で postgres のデータベースを構築する。
$ kubectl exec -it --namespace=<namespace> $(basename $(kubectl get pod -o name -n <namespace> -l 'io.kompose.service==redash')) -- /app/bin/docker-entrypoint create_db
7. static な IP を指定したい
A. GCP で払い出しておいた IP を指定することができる。
$ gcloud compute addresses create <static-ip-label> --global
で IP を払い出しておく。
これも docker-compose.yml の段階でどうにかすることは現状できないようなので、 <redash-on-gke.yml> を書き換える。
具体的には Ingress の metadata.annotations["kubernetes.io/ingress.global-static-ip-name"] = "<static-ip-label>"
を追加する。
8. データの永続化をしたい
A. volumes を使えば勝手に PersistentVolumeClaim が生成される
@@ -46,6 +46,10 @@ services:
image: postgres:9.5.6-alpine
ports:
- "5432:5432"
- # volumes:
- # - /opt/postgres-data:/var/lib/postgresql/data
+ labels:
+ kompose.volume.size: 1Gi
+ environment:
+ PGDATA: "/var/lib/postgresql/data/db-files/"
+ volumes:
+ - "postgres:/var/lib/postgresql/data"
restart: always
- volumes がコメントアウトされていてローカルディスクを使用するようになっているので、 docker-compose.yml でコメントアウトを外す
- 指定した「:」 の左側が PersistentVolumeClaim の名前となるので絶対パスから修正する
- GKE でマウントした直下にはシステム上のファイルが生成されてしまい空のディレクトリにならないため postgres の初期化ができない
- そのため環境変数 PGDATA で postgres のデータフォルダの階層を変更する
- デフォルトの
PGDATA=/var/lib/postgresql/data
のままで、マウント先を/var/lib/postgresql
としても仕様なのか pod 再構築時に必ず初期化してしまって永続化できない
- kompose.volume.size を使用するとディスクサイズが指定可能
心の声
全部指定したいな...
ソース読んで見ますかね。