k8s 部署cassandra 镜像制作

内置初始权限

​ 最近有个新的需求,在k8s环境上部署一个cassandra集群,并能对外提供使用,要求是要内置一张表。今日成功做完,记录一下踩坑历史。

​ 先介绍下环境,有一个k8s集群,包括一个master节点和三个worker节点。kubernetes版本: 1.16.9。docker版本:docker-ce-18.09.9。

​ 首先是通过yaml文件把Cassandra集群部署出来。kubernetes官网有cassandra的部署步骤(https://kubernetes.io/zh/docs/tutorials/stateful-application/cassandra/)。这里贴出yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#设置一个nodeport service用于对外提供服务
kind: Service
apiVersion: v1
metadata:
namespace: firstrain #命名空间
name: cassandra-client
labels:
app: cassandra
spec:
type: NodePort
ports:
- name: main
protocol: TCP
port: 9042
targetPort: 9042
nodePort:
selector:
app: cassandra
---
#设置一个无头服务用于集群内部通信
apiVersion: v1
kind: Service
metadata:
labels:
app: cassandra-headless
namespace: firstrain
name: cassandra-headless
spec:
publishNotReadyAddresses: true #使用StatefulSet的无头服务来传播其Pod的SRV记录,而不考虑它们是否准备就绪,以便于同行发现。
clusterIP: None
ports:
- port: 9042
selector:
app: cassandra
---
使用有状态应用部署cassandra
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cassandra
namespace: firstrain
labels:
app: cassandra
spec:
replicas: 3 #集群个数
serviceName: cassandra-headless
selector:
matchLabels:
app: cassandra
template:
metadata:
labels:
app: cassandra
spec:
terminationGracePeriodSeconds: 1800 #terminationGracePeriodSeconds等待时间后,K8S会强制结束老POD
containers:
- name: cassandra
image: gcr.io/google-samples/cassandra:v14 #此处请修改自己harbor镜像仓库的镜像
imagePullPolicy: Always
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "2Gi"
cpu: "1000m"
ports:
- containerPort: 7000
name: intra-node
- containerPort: 7001
name: tls-intra-node
- containerPort: 7199
name: jmx
- containerPort: 9042
name: cql
securityContext:
capabilities:
add:
- IPC_LOCK
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- nodetool drain
env:
- name: MAX_HEAP_SIZE
value: 512M
- name: HEAP_NEWSIZE
value: 100M
- name: CASSANDRA_SEEDS #seed节点,格式为:pod名称.无头服务名称.命名空间.svc.cluster.local。可只指定一个
value: "cassandra-0.cassandra-headless.firstrain.svc.cluster.local"
- name: CASSANDRA_CLUSTER_NAME
value: "Cassandra"
- name: CASSANDRA_DC
value: "DC1"
- name: CASSANDRA_RACK
value: "Rack1"
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
readinessProbe: # 存活探针
exec:
command:
- /bin/bash
- -c
- /ready-probe.sh
initialDelaySeconds: 15
timeoutSeconds: 5
volumeMounts:
- name: cassandra-data
mountPath: /cassandra_data
#使用pvc
volumeClaimTemplates:
- metadata:
name: cassandra-data
labels:
type: stateful
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: storageclass-default
resources:
requests:
storage: 10Gi

kubectl apply -f cassandra-create.yaml成功创建出一个statefulset应用,使用kubectl get po -n firstrain可查看到创建的3个容器,kubectl get svc -n fristran 查看随机生成的随机nodeport端口,使用Nosql manager for Cassandra连接集群发现不需要用户名即可登陆。

使用kubectl exec -it cassandra-0 -n firstrain bash进入容器,cassandra的配置文件位于/etc/cassandra/cassandra.yaml。配置文件已写清楚,因此改变authenticator值为PasswordAuthenticator即可。

1
2
3
4
5
6
7
8
9
10
# Authentication backend, implementing IAuthenticator; used to identify users
# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthenticator,
# PasswordAuthenticator}.
#
# - AllowAllAuthenticator performs no checks - set it to disable authentication.
# - PasswordAuthenticator relies on username/password pairs to authenticate
# users. It keeps usernames and hashed passwords in system_auth.credentials table.
# Please increase system_auth keyspace replication factor if you use this authenticator.
# If using PasswordAuthenticator, CassandraRoleManager must also be used (see below)
authenticator: AllowAllAuthenticator

由于该容器使用的ubuntu,内部无vim等基础命令。在k8s master集群中使用kubectl cp firstrain/cassandra-0:/etc/cassandra/cassandra.yaml /home/cassandra.yaml从容器中拷贝出该文件,改变其值。然后使用dockerfile构建初步镜像以做尝试。将cassandra.yaml和DockerFile放在同一个文件夹下。构建镜像:**docker build -t cassandra:v14-user .**。

以下为DockerFile。

1
2
FROM gcr.io/google-samples/cassandra:v14
ADD cassandra.yaml /etc/cassandra/cassandra.yaml

将构建的镜像上传到harbor中,接下来修改创建cassandra集群的yaml镜像源。在创建前使用kubectl delete -f cassandra-create.yaml删除之前创建的资源。pvc需自己手动删除。

然后kubectl apply -f cassandra-create.yaml创建集群,再次使用客户端连接cassandr集群,此时会连接失败,因为未指定用户名密码

image-20200904221702542

cassandra镜像默认的用户名和密码为:-u cassandra -p cassandra。

内置keyspaces

​ 接下来要实现内置keyspaces,

一、初步想法

​ 在创建集群是指定cassandra的数据目录为/cassandra_data。进入集群内部即可查看到根目录下的/cassandra_data。data目录下即为keyspaces,因此只要在构建镜像时在/cassandra_data/data目录中打入一个目录seaweedfs,那么该镜像即可内置seaweedfs库。这次省去打镜像和测试步骤,结果不成功,搭建出来的cassandra集群无seaweedfs库。通过docker inspect 镜像发现在创建容器时运行了run.sh的脚本

image-20200904223813400

初步怀疑是否时run.sh的脚本中执行了初始化数据库的命令。将run.sh脚本拷贝出来查看后发现只在最后一步执行了一个脚本

image-20200904224014184

查看对应位置发现是:/usr/local/apache-cassandra-3.11.2/bin/cassandra下,查看该脚本也未发现初始化数据库命令。

二 、安装环境

​ 接下来想法:试图通过cqlsh命令添加keyspaces,但是该容器内并未有python环境。

​ 首先是打算通过二进制包的方式在制作镜像时打进去,但是在执行make & make install命令时缺少gcc的依赖,而gcc依赖又需要npm依赖,这些在容器中均没有,因此考虑第二种方式,因为容器能够联网,因此改变方向,在线安装。

构建的容器使用的时ubuntu,因此安装方式为apt-get,apt-get的镜像源地址为/etc/apt/sources.list,默认使用的时debain源,在国外,速度很慢。要改镜像源首先要apt-get update,然后apt-get install -y vim,之后更换镜像,这里推荐使用清华的源,不建议阿里云的,具体原因时由于在构建镜像安装python2.7时会有依赖错误的情况。

1
2
3
4
5
6
7
8
9
10
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main restricted
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates main restricted
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial universe
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates universe
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-updates multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-backports main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security main restricted
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security universe
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial-security multiverse

更新了sources.list后还要再执行一遍apt-get update,之后即可安装python环境apt-get install python2.7apt-get install python-pip

安装好环境后执行cqlsh,报如下错误,缺少cqlshlib的依赖包。

image-20200904231756936

第一反应肯定是pip安一个,pip install cqlshlib报错如下

image-20200904232029428

之后我通过dockerhub的Cassandra镜像启动了一个容器,从里面拷贝了出cqllib包,然后倒入到容器中,依旧不能解决模块缺失问题。再stack overflow中也未找到解决方案,同事说缺少cqlsh。使用** pip install cqlsh**解决模块缺失问题。

nodetool status查看集群ip

image-20200904233012577

cqlsh 179.20.2.182 -u cassandra -p cassandra连接其中一个,报错如下

image-20200904233827247

cqlsh 179.20.2.182 -u cassandra -p cassandra –cqlversion=3.4.4指定cqlsh版本即可,成功执行sql

image-20200904234057072

三,内置keyspaces

在容器构建时会执行run.sh脚本,因此我们在run.sh中插入一个sql文件并执行,即可完成keyspaces的构建。

在启动服务前异步执行一个initdb.sh的脚本,由于cql不能通过管道命令执行sql语句,只能通过文件执行,因此需要再写一个sql文件。

image-20200904234405758

1
2
3
4
5
6
7
8
9
#!/bin/bash

# Create default keyspace for single node cluster
CQL="cqlsh localhost -u cassandra -p cassandra --cqlversion=3.4.4 --file="/home/seaweedfs.sql""
echo "start"
until $CQL ; do
echo "cqlsh: Cassandra is unavailable - retry later"
sleep 2
done &

四、构建镜像

这一步也是踩过很多坑。先贴Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
FROM yourimage

RUN rm -rf /etc/apt/sources.list && mkdir /root/.pip/

COPY sources.list /etc/apt/

COPY seaweedfs.sql /home

COPY run.sh /

COPY initdb.sh /

RUN chmod 777 /run.sh \
&& chmod 777 /initdb.sh \
&& chmod 777 /home/seaweedfs.sql

RUN apt-get update; exit 0

RUN apt-get install -y gnupg2 --allow-unauthenticated \
&& apt-get -f install \
&& apt-get install -y vim --allow-unauthenticated \
&& apt-get install -y python2.7 --allow-unauthenticated \
&& apt-get install -y python-pip --allow-unauthenticated \
&& pip install cqlsh

将需要的文件拷贝其中并授权。

source.list:镜像源。这一步踩坑在于使用了阿里的镜像源后,apt-get install python2.7会有依赖错误,具体原因未知。

使用apt-get update,这一步踩坑点在于apt-get update过程中会有不影响的错误,需在后面加入;exit 0来忽略错误。

使用-y参数时请在后面加上–allow-unauthenticated否则会报无权限错误。

上面三个RUN命令请不要合再一起写,否则会报错如下,意思是你使用的镜像源未被认证,当单独执行apt-get update时在更新仓库时会自动注册上去。

image-20200904235453326

之后成功build镜像,验证成功,内置了一个keyspaces

涉及命令

1
2
3
4
5
6
7
8
9
# kubectl cp 源文件 目标文件。容器与本机文件可互拷,容器需指定namespace:namespace/pod name:拷贝位置
kubectl cp /root/cassandra.yaml firstrain/cassandra-0:/opt/cassandra.yaml

#查看容器的元数据
docker inspect images

#构建容器,指定name:tag。
docker build -t cassandra:v14-mine