kubernetes 创建 charts 的示例

本文记录将 eclipse 的物联网开源应用 kapua 容器化为 kubernetes charts 的要点。 项目demo也在我的github上面:kelvinblood/kapua-kubernetes

一 docker-compose

首先我们在官网上 https://www.eclipse.org/kapua/getting-started.php 看到 kapua 的启动命令:

$ docker run -td --name kapua-sql -p 8181:8181 -p 3306:3306 kapua/kapua-sql:0.3.2

$ docker run -td --name kapua-elasticsearch -p 9200:9200 -p 9300:9300 elasticsearch:5.4.0 -Ecluster.name=kapua-datastore -Ediscovery.type=single-node -Etransport.host=_site_ -Etransport.ping_schedule=-1 -Etransport.tcp.connect_timeout=30s

$ docker run -td --name kapua-broker --link kapua-sql:db --link kapua-elasticsearch:es --env commons.db.schema.update=true -p 1883:1883 -p 61614:61614 kapua/kapua-broker:0.3.2

$ docker run -td --name kapua-console --link kapua-sql:db --link kapua-broker:broker --link kapua-elasticsearch:es --env commons.db.schema.update=true -p 8080:8080 kapua/kapua-console:0.3.2

$ docker run -td --name kapua-api --link kapua-sql:db --link kapua-broker:broker --link kapua-elasticsearch:es --env commons.db.schema.update=true -p 8081:8080 kapua/kapua-api:0.3.2

在这里可以看到 kapua 一共分成五个组件:

  • sql
  • es
  • broker
  • console
  • api

我们先将这几个命令行组合起了成为一个 docker-compose 文件,便于管理:

version: '2'
services:
  kapua-sql:
    image: iot/kapua-sql:0.3.2
    restart: always

  kapua-elasticsearch:
    image: elasticsearch:5.4.0
    restart: always
    command:
    - -Ecluster.name=kapua-datastore
    - -Ediscovery.type=single-node
    - -Etransport.host=_site_
    - -Etransport.ping_schedule=-1
    - -Etransport.tcp.connect_timeout=30s

  kapua-broker:
    image: iot/kapua-broker:0.3.2
    restart: always
    links:
      - kapua-sql:db
      - kapua-elasticsearch:es
    environment:
      - commons.db.schema.update=true
      - DB_PORT_3306_TCP_PORT=3306
    ports:
      - "1883:1883"
      - "61614:61614"

  kapua-console:
    image: iot/kapua-console:0.3.2
    restart: always
    links:
      - kapua-sql:db
      - kapua-elasticsearch:es
      - kapua-broker:broker
    environment:
      - commons.db.schema.update=true
    ports:
      - "8080:8080"

  kapua-api:
    image: iot/kapua-api:0.3.2
    restart: always
    links:
      - kapua-sql:db
      - kapua-elasticsearch:es
      - kapua-broker:broker
    environment:
      - commons.db.schema.update=true
    ports:
      - "8080:8080"

有了这个文件,在单机上我们可以直接使用 docker-compose up -d 部署应用。


kubernetes 无法添加节点

今天在新增kubernetes节点时,发现无法新增节点,这篇文章记录下解决的情况。

新增节点

k8s新增节点时通过 token 验证,并带上ca证书的ha值。默认token的有效期为24小时。

# 重新生成新的token
kubeadm token create
kubeadm token list

# 获取ca证书sha256编码hash值
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

# 节点加入集群
kubeadm join 172.10.1.100:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx --ignore-preflight-errors Swap

遇到问题

因为已经安装过好几次,只有这一次有问题,故而发现了本次安装不一样的地方:

在获取ca证书的hash值时,这次出现了这样的输出:

openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der> /dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
writing RSA key

最后一行命令添加节点时输出如下:

[discovery] Trying to connect to API Server "10.128.0.4:6443"
[discovery] Created cluster-info discovery client, requesting info from "https://10.128.0.4:6443"
[discovery] Failed to connect to API Server "10.128.0.4:6443": cluster CA found in cluster-info configmap is invalid: public key sha256:9b263f52d90b62458a6a6c6.......02ddc34bf26e1ac not pinned

提示直接给出了另一个hash值。

解决问题

一个非常简单的方式解决:

将错误提示的hash值代替原先获得的hash值即可。

按常理来说,是不应该出现这样的问题的。显而易见是第二步获取hash值出了问题。对比以前使用的命令行,一下就找出了原因:

文档经过多次复制粘贴,命令行已经不完整了。参考官方文档https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-join/中的命令,重新运行得到正确的命令行:

openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

参考资料


防止容器因 jvm 占用资源过多被杀死而频繁重启

本文记录 jvm 和 elasticsearch 在容器中的设置要点。

JVM

不完全翻译自https://blog.csanchez.org/2017/05/31/running-a-jvm-in-a-container-without-getting-killed/

JDK 8u131 在 JDK 9 中有一个特性,可以在 Docker 容器运行时能够检测到多少内存的能力,这个功能在我看来,颇为流氓。

在容器内部运行 JVM,它在大多数情况下将如何默认最大堆为主机内存的1/4,而非容器内存的1/4。如果对 Java 容器中的jvm虚拟机不做任何限制,当我们同时运行几个 java 容器时,很容易导致服务器的内存耗尽、负载飙升而宕机;而如果我们对容器直接进行限制,就会导致内核在某个时候杀死 jvm 容器而导致频繁重启。

例如:

$ docker run -m 100MB openjdk:8u121 java -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 444.50M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

下面我们尝试 JDK 8u131 中的实验性参数 -XX:+UseCGroupMemoryLimitForHeap

$ docker run -m 100MB openjdk:8u131 java \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+UseCGroupMemoryLimitForHeap \
  -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 44.50M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

JVM能够检测容器只有100MB,并将最大堆设置为44M。

下面尝试一个更大的容器

$ docker run -m 1GB openjdk:8u131 java \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+UseCGroupMemoryLimitForHeap \
  -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 228.00M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

嗯,现在容器有1GB,但JVM仅使用228M作为最大堆。

除了JVM正在容器中运行以外,我们是否还可以优化它呢?

$ docker run -m 1GB openjdk:8u131 java \
  -XX:+UnlockExperimentalVMOptions \
  -XX:+UseCGroupMemoryLimitForHeap \
  -XX:MaxRAMFraction=1 -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 910.50M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

使用-XX:MaxRAMFraction 我们告诉JVM使用可用内存/ MaxRAMFraction作为最大堆。使用-XX:MaxRAMFraction=1我们几乎所有可用的内存作为最大堆。

elasticsearch

不完全翻译自https://www.elastic.co/guide/en/elasticsearch/reference/5.4/heap-size.html

Elasticsearch 将通过Xms(最小堆大小)和Xmx(最大堆大小)设置来分配 jvm.options 指定的整个堆,默认使用最小和最大大小为2 GB的堆。这些设置的值取决于服务器上可用的内存。在生产环境时,要确保 Elasticsearch 有足够的可用堆。

一些好的经验是:

  • 将最小堆大小(Xms)和最大堆大小(Xmx)设置为彼此相等。

  • Elasticsearch 可用的堆越多,可用于缓存的内存就越多。但太多的堆会导致一直进行垃圾回收。

  • 将 Xmx 设置为不超过物理内存的50%,以确保有足够的物理内存留给内核文件系统缓存。

  • 不要将 Xmx 设置为J VM 用于压缩对象指针(压缩oops)的临界值以上,接近32 GB。可以通过在日志中查找一行来验证您是否处于限制之下,如下所示:

    heap size [1.9gb], compressed ordinary object pointers [true]
    
  • Even better, try to stay below the threshold for zero-based compressed oops; the exact cutoff varies but 26 GB is safe on most systems, but can be as large as 30 GB on some systems. You can verify that you are under the limit by starting Elasticsearch with the JVM options -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode and looking for a line like the following:

    heap address: 0x000000011be00000, size: 27648 MB, zero based Compressed Oops
    

    showing that zero-based compressed oops are enabled instead of

    heap address: 0x0000000118400000, size: 28672 MB, Compressed Oops with base: 0x00000001183ff000
    

以下是如何通过jvm.options文件设置堆大小的示例:

-Xms2g 
-Xmx2g 

也可以通过环境变量设置堆大小。

ES_JAVA_OPTS ="- Xms2g -Xmx2g"./bin/elasticsearch 
ES_JAVA_OPTS ="- Xms4000m -Xmx4000m"./bin/elasticsearch 

参考资料


Linux:集群工具ClusterShell

ClusterShell 是一个轻量级的运维工具,可以在一台机器上向多台机器发送指令,轻松实现类似《黑客帝国》中批量关闭电厂的效果:

ClusterShell每天在Linux超级计算机(拥有超过5000个计算节点)上使用。使用很简单,只要在主控机上配置好子节点的ssh密钥登陆,同时做好节点配置即可,非常便捷。这篇文章介绍它的安装和简单使用。

安装

yum install -y clustershell
// or
apt-get install clustershell

配置

在/etc/clustershell目录下,手动创建groups文件

$ vim /etc/clustershell/groups

all: a1 host1 host2
name:host3 host4
adm: example0
oss: example4 example5
mds: example6
io: example[4-6]
compute: example[32-159]
gpu: example[156-159]
hadoop: z[1-4]

# 需要注意的是all 是必须配置的。

hadoop: z[1-4],是指定hadoop组中有四个节点,分别是z1,z2,z3,z4。

其它的配置也类似,可以加入多个组,使用的时候通过-g hadoop来选择。

命令

clush -a 全部 等于 clush -g all
clush -g 指定组
clush -w 操作主机名字,多个主机之间用逗号隔开
clush -g 组名 -c  --dest 文件群发     (-c等于--copy)

注意:clush 是不支持环境变量的 $PATH

实例

输出所有节点的信息

$ clush -a "uptime"
$ clush -b -a "uptime"

删除指定节点的文件

$ clush -w z2,z3,z4 rm -rf /mnt/zhao/soft/jdk

集群分发文件

$ clush -b -g hadoop --copy /mnt/zhao/package/jdk-7u79-linux-x64.tar.gz --dest /mnt/zhao/package/

集群查看文件

查看所有hadoop组中/mnt/zhao/package/目录下的文件,输出结果合并。

$ clush -b -g hadoop ls /mnt/zhao/package/

交互模式

启动clush,后面不带命令,就进入交互模式:

$ clush -w hadoop

参考资料


解决 Firefox is already running, but is not responding 错误

远程vnc的时候,发现firefox没办法启动,报了这个错误:

Firefox is already running, but is not responding. To open a new window, you must first close the existing Firefox process, or restart your system.

即使将 Firefox 的进程全部杀死,仍然会报这个错误。

解决方法如下:

在linux的终端输入:

firefox -profilemanager 

# 或者
firefox -p

在出现的页面中将当前出错的 Profile 删除掉,然后新建个即可。