使用Skaffold构建和部署适用于K8s的GROWI Elasticsearch和HackMD

本文是“Kubernetes2 Advent Calendar 2020”第8天的文章。谢谢。

这篇文章是关于在Kubernetes上使用Rook/Ceph的块存储和对象存储来扩展GROWI Wiki的功能的续篇。

太长;没读。

我使用Skaffold在Kubernetes上构建并部署了带有”Elasticsearch和HackMD”的GROWI。

zaki-lknr/growi-on-k8s:运行在Kubernetes上的GROWI Wiki

引言

我們在前幾天,Rook和我們的夥伴們在「2020年度雲原生存儲器Advent Calendar」的第三天投稿了以下的文章。

使用Rook/Ceph的块存储和对象存储在Kubernetes上运行GROWI Wiki – Qiita

在这篇文章中,由于无法解决vm.max_map_count错误并将其作为对象存储文章的附带内容,GROWI的Elasticsearch集成(也许是一个选项)被省略掉了。所以现在让我们重新设置Elasticsearch并尝试部署可用于搜索的GROWI on Kubernetes。

使用Elasticsearch来实现GROWI.

建议使用Docker Compose版本的GROWI来定义基于Elasticsearch的使用。

安装日语插件。

为了在GROWI中使用,我们将安装以下的日语插件。

    • analysis-kuromoji

 

    analysis-icu

如果能够在Helm图表的配置中搞定就最好了,但根据README插件安装部分的说明,似乎需要构建镜像,所以我会进行构建。

如果使用Bitnami的图表,可能可以直接通过设置插件来使用,而无需构建,但尚未经过确认。

Docker文件

将使用存储在GROWI存储库中的Docker Compose所使用的Dockerfile作为基础。
但是,尽管使用此内容构建了镜像,但直接将其部署到Kubernetes中会导致启动失败,出现以下错误。

ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

重点是通过容器启动时的卷设置插入elasticsearch.yml文件进行配置。
在Kubernetes中,除非事先使用NFS等准备好的文件作为持久卷进行挂载,否则(可能)无法在容器启动时执行此操作,因此将其内置在映像中并进行构建。

因此,Dockerfile的样子如下。

FROM docker.elastic.co/elasticsearch/elasticsearch:6.8.10

RUN bin/elasticsearch-plugin install analysis-kuromoji
RUN bin/elasticsearch-plugin install analysis-icu

COPY elasticsearch.yml /usr/share/elasticsearch/config/elasticsearch.yml

以下是elasticsearch.yml的副本映射图。

http.host: 0.0.0.0

# for elasticsearch-head
http.cors.enabled: true
http.cors.allow-origin: "*"

使用Skaffold进行构建和推送和部署(开发模式)。

在本地构建Docker映像,并将其推送到Docker Hub,在Kubernetes集群中拉取。
由于手动重复这个过程有点麻烦,所以这次我使用了一个名为Skaffold的构建工具,它可以将所有这些步骤一次性完成。
(我早就把“尝试Skaffold”这个任务放在了那里,所以顺便在这里试一下。)

尝试使用Google发布的容器应用开发辅助工具”Skaffold”和”Kaniko” | さくらのナレッジ

Skaffold配置

快速入门 | Skaffold

如果是Linux系统,安装只需要下载二进制文件并将其放置在正确配置了环境变量的路径(如/usr/local/bin等)即可。
为了使用Skaffold命令,需要进行以下准备工作。

    1. 确保已登录docker,并且可以使用skaffold执行用户帐户推送到容器注册表。

确保已设置$HOME/.kube/config,并且可以使用skaffold执行用户帐户使用kubectl将清单部署到集群。

以下是两个要点(关于2,可以采用与Helm和istioctl相同的方法。大概)。

如果要进行docker push操作,并且想要使用Docker Hub作为容器 registry,您需要先创建一个帐户并准备好要推送的目标存储库。

image.png

构建和部署Skaffold的设置

在与之前提到的Dockerfile和Dockerfile引用的外部文件elasticsearch.yml(用于复制到镜像中)相同的目录中(为了简化配置),创建以下的”用于部署的Kubernetes部署文件”和”Skaffold定义文件”。

使用Kubernetes的部署清单文件没有任何特殊,所以可以省略。
例如,可以使用Deployment进行如下配置(稍后已更改为StatefulSet)。

关于 skaffold.yaml,作为构建/推送/部署单个图像的最小描述,可以这样写。

apiVersion: skaffold/v1
kind: Config
build:
  artifacts:
  - image: zakihmkc/growi-elasticsearch
    context: ./
    docker:
      dockerfile: ./Dockerfile
deploy:
  kubectl:
    manifests:
    - ./k8s-deploy.yaml

请查阅参考资料以获取详细信息。

skaffold.yaml文件 | Skaffold

重点是在build部分的artifacts中,通过设置构建图像的名称==推送的存储库名称来指定,从docker build到docker push都可以一次完成。
构建的context和docker.dockerfile与使用Docker Compose构建时相同,需要指定目录和Dockerfile。在将文件分开为”开发”、”暂存”和”生产”等时,这非常有用。

另外,在deploy部分指定推送的图像到集群的部署清单文件,成功推送后会自动完成部署处理。

要以dev模式运行,请指定dev子命令来执行。
为了给相同名称的dev添加临时标签以构建映像,需要添加-t dev,虽然这样命名有些困惑。

[zaki@cloud-dev elasticsearch]$ ls
Dockerfile  elasticsearch.yml  k8s-deploy.yaml  skaffold.yaml
[zaki@cloud-dev elasticsearch]$ skaffold dev -t dev 
Listing files to watch...
 - zakihmkc/growi-elasticsearch
Generating tags...
 - zakihmkc/growi-elasticsearch -> zakihmkc/growi-elasticsearch:dev
Checking cache...
 - zakihmkc/growi-elasticsearch: Not found. Building
Building [zakihmkc/growi-elasticsearch]...
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM docker.elastic.co/elasticsearch/elasticsearch:6.8.10
 ---> ffa00077159c
Step 2/4 : RUN bin/elasticsearch-plugin install analysis-kuromoji
 ---> Using cache
 ---> 6966b4d5e5bf
Step 3/4 : RUN bin/elasticsearch-plugin install analysis-icu
 ---> Using cache
 ---> 7e8711478ef2
Step 4/4 : COPY elasticsearch.yml /usr/share/elasticsearch/config/elasticsearch.yml
 ---> 11556383ec5f
Successfully built 11556383ec5f
Successfully tagged zakihmkc/growi-elasticsearch:dev
The push refers to repository [docker.io/zakihmkc/growi-elasticsearch]
06e6281e2c86: Preparing
c2255a3188da: Preparing

[... snip ...]

edf3aa290fb3: Layer already exists
06e6281e2c86: Pushed
dev: digest: sha256:c260d4c6f595b15163c9f7a3d88fcb6f790995f9f63ac519baaa94af49bc5bf2 size: 2421
Tags used in deployment:
 - zakihmkc/growi-elasticsearch -> zakihmkc/growi-elasticsearch:dev@sha256:c260d4c6f595b15163c9f7a3d88fcb6f790995f9f63ac519baaa94af49bc5bf2
Starting deploy...
 - deployment.apps/elasticsearch created
 - service/elasticsearch created
Waiting for deployments to stabilize...
 - deployment/elasticsearch: creating container elasticsearch
    - pod/elasticsearch-76d9c6d6f6-nqtjs: creating container elasticsearch
 - deployment/elasticsearch is ready.
Deployments stabilized in 5.595258289s
Press Ctrl+C to exit
Watching for changes...
[elasticsearch] [2020-12-04T14:10:06,213][INFO ][o.e.e.NodeEnvironment    ] [TQOy5aT] using [1] data paths, mounts [[/ (rootfs)]], net usable_space [42.1gb], net total_space [58.9gb], types [rootfs]
[elasticsearch] [2020-12-04T14:10:06,215][INFO ][o.e.e.NodeEnvironment    ] [TQOy5aT] heap size [1gb], compressed ordinary object pointers [true]
[elasticsearch] [2020-12-04T14:10:06,218][INFO ][o.e.n.Node               ] [TQOy5aT] node name derived from node ID [TQOy5aTYQuKGZ35Crwr6Iw]; set [node.name] to override
[elasticsearch] [2020-12-04T14:10:06,218][INFO ][o.e.n.Node               ] [TQOy5aT] version[6.8.10], pid[1], build[default/docker/537cb22/2020-05-28T14:47:19.882936Z], OS[Linux/3.10.0-1127.13.1.el7.x86_64/amd64], JVM[AdoptOpenJDK/OpenJDK 64-Bit Server VM/14.0.1/14.0.1+7]
[elasticsearch] [2020-12-04T14:10:06,218][INFO ][o.e.n.Node               ] [TQOy5aT] JVM arguments [-Xms1g, -Xmx1g, -XX:+UseG1GC, -XX:G1ReservePercent=25, -XX:InitiatingHeapOccupancyPercent=30, -Des.networkaddress.cache.ttl=60, -Des.networkaddress.cache.negative.ttl=10, -XX:+AlwaysPreTouch, -Xss1m, -Djava.awt.headless=true, -Dfile.encoding=UTF-8, -Djna.nosys=true, -XX:-OmitStackTraceInFastThrow, -XX:+ShowCodeDetailsInExceptionMessages, -Dio.netty.noUnsafe=true, -Dio.netty.noKeySetOptimization=true, -Dio.netty.recycler.maxCapacityPerThread=0, -Dlog4j.shutdownHookEnabled=false, -Dlog4j2.disable.jmx=true, -Djava.io.tmpdir=/tmp/elasticsearch-16478887452689113828, -XX:+HeapDumpOnOutOfMemoryError, -XX:HeapDumpPath=data, -XX:ErrorFile=logs/hs_err_pid%p.log, -Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m, -Djava.locale.providers=COMPAT, -XX:UseAVX=2, -Des.cgroups.hierarchy.override=/, -Des.path.home=/usr/share/elasticsearch, -Des.path.conf=/usr/share/elasticsearch/config, -Des.distribution.flavor=default, -Des.distribution.type=docker]
[elasticsearch] [2020-12-04T14:10:09,582][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [aggs-matrix-stats]
[elasticsearch] [2020-12-04T14:10:09,582][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [analysis-common]
[elasticsearch] [2020-12-04T14:10:09,582][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [ingest-common]
[elasticsearch] [2020-12-04T14:10:09,582][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [ingest-geoip]
[elasticsearch] [2020-12-04T14:10:09,582][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [ingest-user-agent]
[elasticsearch] [2020-12-04T14:10:09,583][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [lang-expression]
[elasticsearch] [2020-12-04T14:10:09,583][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [lang-mustache]
[elasticsearch] [2020-12-04T14:10:09,583][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [lang-painless]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [mapper-extras]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [parent-join]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [percolator]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [rank-eval]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [reindex]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [repository-url]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [transport-netty4]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [tribe]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-ccr]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-core]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-deprecation]
[elasticsearch] [2020-12-04T14:10:09,584][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-graph]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-ilm]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-logstash]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-ml]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-monitoring]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-rollup]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-security]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-sql]
[elasticsearch] [2020-12-04T14:10:09,585][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-upgrade]
[elasticsearch] [2020-12-04T14:10:09,586][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded module [x-pack-watcher]
[elasticsearch] [2020-12-04T14:10:09,595][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded plugin [analysis-icu]
[elasticsearch] [2020-12-04T14:10:09,595][INFO ][o.e.p.PluginsService     ] [TQOy5aT] loaded plugin [analysis-kuromoji]
[elasticsearch] [2020-12-04T14:10:16,226][INFO ][o.e.x.s.a.s.FileRolesStore] [TQOy5aT] parsed [0] roles from file [/usr/share/elasticsearch/config/roles.yml]
[elasticsearch] [2020-12-04T14:10:17,251][INFO ][o.e.x.m.p.l.CppLogMessageHandler] [TQOy5aT] [controller/79] [Main.cc@109] controller (64 bit): Version 6.8.10 (Build a5f7163bca0250) Copyright (c) 2020 Elasticsearch BV
[elasticsearch] [2020-12-04T14:10:17,994][INFO ][o.e.d.DiscoveryModule    ] [TQOy5aT] using discovery type [zen] and host providers [settings]
[elasticsearch] [2020-12-04T14:10:18,943][INFO ][o.e.n.Node               ] [TQOy5aT] initialized
[elasticsearch] [2020-12-04T14:10:18,943][INFO ][o.e.n.Node               ] [TQOy5aT] starting ...
[elasticsearch] [2020-12-04T14:10:19,069][INFO ][o.e.t.TransportService   ] [TQOy5aT] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}
[elasticsearch] [2020-12-04T14:10:19,086][WARN ][o.e.b.BootstrapChecks    ] [TQOy5aT] max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
[elasticsearch] [2020-12-04T14:10:22,134][INFO ][o.e.c.s.MasterService    ] [TQOy5aT] zen-disco-elected-as-master ([0] nodes joined), reason: new_master {TQOy5aT}{TQOy5aTYQuKGZ35Crwr6Iw}{mDuQTY1KS1q1Es7e0DDjLA}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=8181829632, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true}
[elasticsearch] [2020-12-04T14:10:22,138][INFO ][o.e.c.s.ClusterApplierService] [TQOy5aT] new_master {TQOy5aT}{TQOy5aTYQuKGZ35Crwr6Iw}{mDuQTY1KS1q1Es7e0DDjLA}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=8181829632, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true}, reason: apply cluster state (from master [master {TQOy5aT}{TQOy5aTYQuKGZ35Crwr6Iw}{mDuQTY1KS1q1Es7e0DDjLA}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=8181829632, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true} committed version [1] source [zen-disco-elected-as-master ([0] nodes joined)]])
[elasticsearch] [2020-12-04T14:10:22,197][INFO ][o.e.h.n.Netty4HttpServerTransport] [TQOy5aT] publish_address {10.244.127.102:9200}, bound_addresses {0.0.0.0:9200}
[elasticsearch] [2020-12-04T14:10:22,197][INFO ][o.e.n.Node               ] [TQOy5aT] started
[elasticsearch] [2020-12-04T14:10:22,223][WARN ][o.e.x.s.a.s.m.NativeRoleMappingStore] [TQOy5aT] Failed to clear cache for realms [[]]
[elasticsearch] [2020-12-04T14:10:22,262][INFO ][o.e.g.GatewayService     ] [TQOy5aT] recovered [0] indices into cluster_state
[elasticsearch] [2020-12-04T14:10:22,874][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.watches] for index patterns [.watches*]
[elasticsearch] [2020-12-04T14:10:22,941][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.watch-history-9] for index patterns [.watcher-history-9*]
[elasticsearch] [2020-12-04T14:10:22,964][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.triggered_watches] for index patterns [.triggered_watches*]
[elasticsearch] [2020-12-04T14:10:22,992][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.monitoring-logstash] for index patterns [.monitoring-logstash-6-*]
[elasticsearch] [2020-12-04T14:10:23,044][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.monitoring-es] for index patterns [.monitoring-es-6-*]
[elasticsearch] [2020-12-04T14:10:23,092][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.monitoring-alerts] for index patterns [.monitoring-alerts-6]
[elasticsearch] [2020-12-04T14:10:23,255][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.monitoring-beats] for index patterns [.monitoring-beats-6-*]
[elasticsearch] [2020-12-04T14:10:23,310][INFO ][o.e.c.m.MetaDataIndexTemplateService] [TQOy5aT] adding template [.monitoring-kibana] for index patterns [.monitoring-kibana-6-*]
[elasticsearch] [2020-12-04T14:10:23,479][INFO ][o.e.l.LicenseService     ] [TQOy5aT] license [93d6e9a7-978d-4035-8052-e26c27e49afe] mode [basic] - valid

在这里显示停止,但是这里有kubectl logs -f命令的日志输出。
如果另一个终端中执行kubectl get pod命令,则会显示以下结果。

[zaki@cloud-dev elasticsearch]$ kubectl get pod
NAME                             READY   STATUS    RESTARTS   AGE
elasticsearch-76d9c6d6f6-nqtjs   1/1     Running   0          5m41s

我正在正常运作。

因为这不是日志的最后,所以可能不太容易理解,但我认为这个日志很可能是启动成功的标志。(很可能)

[elasticsearch] [2020-12-04T14:10:22,197][INFO ][o.e.h.n.Netty4HttpServerTransport] [TQOy5aT] publish_address {10.244.127.102:9200}, bound_addresses {0.0.0.0:9200}
[elasticsearch] [2020-12-04T14:10:22,197][INFO ][o.e.n.Node               ] [TQOy5aT] started

这是正在运行的镜像的标签,但附加了散列值。

[zaki@cloud-dev elasticsearch]$ kubectl get pod elasticsearch-76d9c6d6f6-nqtjs -o jsonpath='{.spec.containers[].image}'; echo
zakihmkc/growi-elasticsearch:dev@sha256:c260d4c6f595b15163c9f7a3d88fcb6f790995f9f63ac519baaa94af49bc5bf2

因为确认到构建的图像正在正常运行,所以将使用Ctrl-c停止。

[elasticsearch] [2020-12-04T14:10:23,479][INFO ][o.e.l.LicenseService     ] [TQOy5aT] license [93d6e9a7-978d-4035-8052-e26c27e49afe] mode [basic] - valid
^CCleaning up...
 - deployment.apps "elasticsearch" deleted
 - service "elasticsearch" deleted
There is a new version (1.17.1) of Skaffold available. Download it from:
  https://github.com/GoogleContainerTools/skaffold/releases/tag/v1.17.1

然后Pod也停止了。
真方便啊。

[zaki@cloud-dev elasticsearch]$ kubectl get pod
NAME                             READY   STATUS        RESTARTS   AGE
elasticsearch-76d9c6d6f6-nqtjs   1/1     Terminating   0          11m

推广的形象就是这样。

image.png

而且,Skaffold的开发模式更方便之处在于,在等待停止状态期间,只需按下Ctrl-c,然后更改Dockerfile或部署清单,即可自动检测文件更改并重新构建和重新部署,这样在开发过程中,可以省去部署工作所需的时间,可以集中精力于开发。

使用run模式进行构建、推送和部署

我将参数从“dev”更改为“run”。
顺便试试将标签设为类似于发布版本的样子。

[zaki@cloud-dev elasticsearch]$ skaffold run -t 6.8.10-ja
Generating tags...
 - zakihmkc/growi-elasticsearch -> zakihmkc/growi-elasticsearch:6.8.10-ja
Checking cache...
 - zakihmkc/growi-elasticsearch: Found. Tagging
Tags used in deployment:
 - zakihmkc/growi-elasticsearch -> zakihmkc/growi-elasticsearch:6.8.10-ja@sha256:c260d4c6f595b15163c9f7a3d88fcb6f790995f9f63ac519baaa94af49bc5bf2
Starting deploy...
 - deployment.apps/elasticsearch created
 - service/elasticsearch created
Waiting for deployments to stabilize...
 - deployment/elasticsearch is ready.
Deployments stabilized in 3.40209576s
You can also run [skaffold run --tail] to get the logs
There is a new version (1.17.1) of Skaffold available. Download it from:
  https://github.com/GoogleContainerTools/skaffold/releases/tag/v1.17.1

[zaki@cloud-dev elasticsearch]$ 

由于处理在后台进行,所以会返回提示。

[zaki@cloud-dev elasticsearch]$ kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
elasticsearch-89688ff58-tw969   1/1     Running   0          13s

新的标签也被推送了。(内容没有改变,所以与dev相同)

image.png

运行模式下删除部署的Pod。

要停止和删除,请执行skaffold delete命令。

[zaki@cloud-dev elasticsearch]$ skaffold delete 
Cleaning up...
 - deployment.apps "elasticsearch" deleted
 - service "elasticsearch" deleted

StatefulSet的版本

我一开始就应该这么做的时候, 迁移到了StatefulSet重新部署工作负载。

此外,在运行时,通过附加 -n <命名空间> 参数来指定部署目标为与GROWI核心相同的命名空间。

[zaki@cloud-dev elasticsearch (features/elasticsearch)]$ skaffold run -t 6.8.10-ja -n growi-on-k8s
Generating tags...
 - zakihmkc/growi-elasticsearch -> zakihmkc/growi-elasticsearch:6.8.10-ja
Checking cache...
 - zakihmkc/growi-elasticsearch: Found Remotely
Tags used in deployment:
 - zakihmkc/growi-elasticsearch -> zakihmkc/growi-elasticsearch:6.8.10-ja@sha256:c260d4c6f595b15163c9f7a3d88fcb6f790995f9f63ac519baaa94af49bc5bf2
Starting deploy...
 - statefulset.apps/elasticsearch created
 - service/elasticsearch created
Waiting for deployments to stabilize...
Deployments stabilized in 10.508539ms
You can also run [skaffold run --tail] to get the logs
There is a new version (1.17.1) of Skaffold available. Download it from:
  https://github.com/GoogleContainerTools/skaffold/releases/tag/v1.17.1

[zaki@cloud-dev elasticsearch (features/elasticsearch)]$ kc get pod,svc,pvc -n growi-on-k8s 
NAME                            READY   STATUS              RESTARTS   AGE
pod/elasticsearch-0             0/1     ContainerCreating   0          9s
pod/growi-app-fd6fcdd9d-vsdjj   1/1     Running             14         7d
pod/growi-mongo-0               1/1     Running             3          7d

NAME                    TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)          AGE
service/elasticsearch   ClusterIP      10.99.155.247    <none>          9200/TCP         9s
service/growi-app       LoadBalancer   10.96.23.173     192.168.0.185   3000:32644/TCP   7d
service/growi-mongo     ClusterIP      10.106.230.143   <none>          27017/TCP        7d

NAME                                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
persistentvolumeclaim/es-data-elasticsearch-0      Bound    pvc-f052985f-b3a9-408f-8343-d09b1cbf8ff7   8Gi        RWO            rook-ceph-block   9s
persistentvolumeclaim/mongo-config-growi-mongo-0   Bound    pvc-6b29acb4-bad6-4b01-9135-4302bf1f35d3   256Mi      RWO            rook-ceph-block   7d1h
persistentvolumeclaim/mongo-db-growi-mongo-0       Bound    pvc-21ea3319-5487-4b10-83d3-a9c076d30b28   4Gi        RWO            rook-ceph-block   7d1h

GROWI Wiki的Elasticsearch设置

如果没有Elasticsearch的配置,请按照以下方法进行操作。

image.png

要将GROWI与Elasticsearch集成,需要根据Docker Compose版本的docker-compose.yml文件设置环境变量ELASTICSEARCH_URI,将其设置为Elasticsearch的URL。
在Kubernetes环境中,由于使用Service进行Pod之间的通信,因此需要将Service名称(elasticsearch)进行记录。

宣言的内容是这样的

      containers:
      - image: weseek/growi:4
        name: growi-app
        env:
          - name: MONGO_URI
            value: mongodb://growi-mongo:27017/growi
          - name: ELASTICSEARCH_URI
            value: http://elasticsearch:9200/growi
          - name: PASSWORD_SEED
            value: changeme

如果重新使用此清单进行部署,则屏幕顶部将显示搜索字段。

image.png

显示设置菜单中的“全文搜索管理”选项,看到Elasticsearch已启用。

image.png

现在,GROWI和Elasticsearch已经进行了协作设置,可以开始使用搜索功能了。

使用HackMD来进行GROWI的增强功能

在GROWI的Wiki中,默认情况下,不允许多个用户同时编辑同一页面。
(如果不小心发生了这种情况,之后尝试保存的用户会发生冲突,需要手动进行合并操作。)

然而,通过与HackMD协作,我们可以实现协同编辑功能(虽然需要进行图像构建,但我们已经使用带有日语插件的Elasticsearch进行了图像构建,所以可以直接进行)在Kubernetes上运行GROWI。

    • HackMD で同時多人数編集を利用する | GROWI Docs

 

    HackMD(CodiMD)連携 | GROWI Docs

HackMD的整合也已經公開了官方的Docker Compose。
對於當前的docker-compose.yml內容進行整理,如下所示。

    1. 部署MariaDB

 

    1. 构建GROWI所使用的HackMD镜像

 

    1. 部署GROWI所使用的HackMD

以下是环境变量:

访问GROWI主体的URL
MariaDB连接地址

使HackMD独立可通过浏览器访问

添加GROWI主体的环境变量

GROWI主体(pod)所看到的HackMD的URL
通过浏览器访问HackMD时的URL

MariaDB is a relational database management system.

我也觉得可以在Helm或其他地方单独安装,但是在GROWI的docker-compose.yml文件中有字符集参数设置,所以我基于这个来创建清单。

  mariadb:
    image: mariadb:10.3
    command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci
    environment:
      - MYSQL_USER=hackmd
      - MYSQL_PASSWORD=hackmdpass
      - MYSQL_DATABASE=hackmd
      - MYSQL_RANDOM_ROOT_PASSWORD=true

如果直接将其转换为Kubernetes的清单文件,并且在部署时会遇到以下错误。

2020-12-05  0:45:49 0 [Note] mysqld (mysqld 10.3.27-MariaDB-1:10.3.27+maria~focal) starting as process 1 ...
mysqld: Please consult the Knowledge Base to find out how to run mysqld as root!
2020-12-05  0:45:49 0 [ERROR] Aborting

重點在於”command”部分。

在Kubernetes的清单中,使用args而不是command会有效运行。

    spec:
      containers:
      - image: mariadb:10.3
        name: hackmd
        args:
          - mysqld
          - --character-set-server=utf8
          - --collation-server=utf8_general_ci
        env:
          - name: MYSQL_USER
            value: hackmd
          - name: MYSQL_PASSWORD

使用HackMD进行图像构建和部署的GROWI。

我們可以使用Skaffold進行這個。Dockerfile和在構建時用於映像的設置文件等都可以直接使用官方提供的公開版本。

除了这些文件之外,还需准备以下文件,与Elasticsearch的构建相同。

    • Kubernetesのマニフェスト

 

    skaffol.yaml

由于需要设置GROWI主体(通过浏览器访问时)的URL,所以需要设置环境变量。

由于构建/推送/部署的步骤和内容与Elasticsearch相同,所以将省略。请参考GitHub上的文件集合。

成功部署后,可以使用类型为LoadBalancer的资源对外公开,然后通过浏览器访问如下所示。

image.png

在进行GROWI设置时,需要确认用于从浏览器访问的URL。

GROWI Wiki的HackMD设置

如前所述,由於GROWI還需要設置HackMD的位置,因此需要添加環境變數。
HACKMD_URI_FOR_SERVER與Elasticsearch相同,用於描述從GROWI的pod到HackMD的pod之間的pod間通信的Service名稱。
HACKMD_URI用於設置從瀏覽器訪問HackMD時的URL。

      containers:
      - image: weseek/growi:4
        name: growi-app
        env:
          - name: MONGO_URI
            value: mongodb://growi-mongo:27017/growi
          - name: ELASTICSEARCH_URI
            value: http://elasticsearch:9200/growi
          - name: PASSWORD_SEED
            value: changeme
          - name: HACKMD_URI_FOR_SERVER
            value: http://hackmd:3000
          - name: HACKMD_URI
            value: http://192.168.0.186:3000

以这个设置重新部署GROWI主体,并通过浏览器访问,在页面编辑界面旁边按下”HackMD”按钮。

image.png

然后,将显示用于开始编辑的按钮,通过使用HackMD。

image.png

按下按钮时,

image.png

那个……?

很遗憾,我无法找到原因,但是在Chrome和Edge都无法访问,但是在Firefox上可以访问。

image.png

在启动另一个浏览器并访问时,右上角的在线人数将变为2,同时显示每个浏览器的编辑状态(例如光标等)。

image.png

顺便说一句,如果是使用Docker Compose版本,那么即使在Chrome上也可以访问。根据本次使用type:LoadBalancer的Kubernetes环境来看,GROWI和HackMD在浏览器中看起来部署在不同的IP地址(主机)上,而且也不支持HTTPS,所以我认为可能是Chrome的安全功能限制造成的。不过在这方面我已经无能为力了。(根据kubectl logs命令查看,GROWI和HackMD都没有显示出任何类似的错误日志)

在Chrome的开发者工具中,看起来是这样的,出现了”AUTH failed: No cookie transmitted.”这个错误。

image.png

总结和任务

通过使用Skaffold,可以一次完成容器镜像的构建/推送/部署,因此非常高效。
特别是在dev模式下,它会自动检测文件的更改,从重新构建镜像到部署到集群,让你可以专注于代码的编写。

通过在Kubernetes上部署Elasticsearch和HackMD,实现了对GROWI的搜索和并发编辑功能。由于我们使用了type: LoadBalancer来公开GROWI和HackMD,所以无法确认在Chrome访问时是否会产生预期的行为,但使用Ingress或其他方法可能会改善这个问题。

另外,LoadBalancer类型的缺点是在部署之前无法知道外部访问地址,因此在首次部署GROWI主体和HackMD之前无法设置彼此的外部访问地址。这也有改进的空间,可以考虑使用Ingress,也可以考虑使用ExternalDNS,我想进行评估。

我将Kubernetes集群中的自宅服务连接到了FQDN上- 的的.log。


(仅供参考) 错误模式

弹性搜索

[elasticsearch] ERROR: [1] bootstrap checks failed
[elasticsearch] [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

这个错误是

FROM docker.elastic.co/elasticsearch/elasticsearch:6.8.10

RUN bin/elasticsearch-plugin install analysis-kuromoji
RUN bin/elasticsearch-plugin install analysis-icu

在Kubernetes上部署了一个使用这个Dockerfile的自定义镜像,其中安装了日语插件。

将以下文件放置在/usr/share/elasticsearch/config/elasticsearch.yml,即可避免该问题。

http.host: 0.0.0.0

# for elasticsearch-head
http.cors.enabled: true
http.cors.allow-origin: "*"

MariaDB (MySQL的一个替代产品)

使用Docker Compose的command部分进行部署时,会应用原本镜像中指定的docker-entrypoint.sh和command参数一起,但是在Kubernetes的pod参数中使用command时,似乎会覆盖docker-entrypoint.sh的信息,并直接执行mysqld导致启动失败。

当使用Docker Compose提供的MariaDB容器进行正常操作时,可以通过docker inspect命令查看其参数,具体如下所示。

{
            "Cmd": [
                "mysqld",
                "--character-set-server=utf8",
                "--collation-server=utf8_general_ci"
            ],
            "Image": "mariadb:10.3",
            "Volumes": {
                "/var/lib/mysql": {}
            },
            "WorkingDir": "",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
}

如果在Kubernetes中使用指定的命令设置字符集等,则会出现错误消息。

2020-12-05  0:45:49 0 [Note] mysqld (mysqld 10.3.27-MariaDB-1:10.3.27+maria~focal) starting as process 1 ...
mysqld: Please consult the Knowledge Base to find out how to run mysqld as root!
2020-12-05  0:45:49 0 [ERROR] Aborting

如果在以上留言中搜索,可能会找到解决方法(基本上看起来不是容器环境)。添加–user=root选项。

2020-12-05  0:46:37 0 [ERROR] Could not open mysql.plugin table. Some plugins may be not loaded
2020-12-05  0:46:37 0 [ERROR] Can't open and lock privilege tables: Table 'mysql.servers' doesn't exist
2020-12-05  0:46:37 0 [Note] Server socket created on IP: '::'.
2020-12-05  0:46:37 0 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.user' doesn't exist

找到附近类似的避免方法并搜索

          - --user=mysql
          - --datadir=/var/lib/mysql

即使进行设置更改也没有改善。

与在Docker Compose中的操作状态进行比较,使用命令时没有使用docker-entrypoint.sh进行启动,因此失败了。

如果仅仅使用Docker单独执行mysqld,也会遇到同样的错误导致启动失败。

$ docker run -it --rm --name mariadb mariadb:10.3 bash
root@b8a277c49a9d:/# mysqld --character-set-server=utf8 --collation-server=utf8_general_ci
2020-12-05 11:27:44 0 [Note] mysqld (mysqld 10.3.27-MariaDB-1:10.3.27+maria~focal) starting as process 8 ...
mysqld: Please consult the Knowledge Base to find out how to run mysqld as root!
2020-12-05 11:27:44 0 [ERROR] Aborting

请提供参考资料

    • GROWI

weseek/growi-docker-compose: growi-docker-compose – The fastest way to boot All-in-One GROWI

HackMD

growi-docker-compose/examples/integrate-with-hackmd at master · weseek/growi-docker-compose
growi-docker-compose/hackmd at master · weseek/growi-docker-compose

广告
将在 10 秒后关闭
bannerAds