最近有个新的需求,在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:
登录后复制
#设置一个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即可。
登录后复制
# 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。
登录后复制
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集群,此时会连接失败,因为未指定用户名密码
cassandra镜像默认的用户名和密码为:-u cassandra -p cassandra。
接下来要实现内置keyspaces,
在创建集群是指定cassandra的数据目录为/cassandra_data。进入集群内部即可查看到根目录下的/cassandra_data。data目录下即为keyspaces,因此只要在构建镜像时在/cassandra_data/data目录中打入一个目录seaweedfs,那么该镜像即可内置seaweedfs库。这次省去打镜像和测试步骤,结果不成功,搭建出来的cassandra集群无seaweedfs库。通过docker inspect 镜像发现在创建容器时运行了run.sh的脚本
初步怀疑是否时run.sh的脚本中执行了初始化数据库的命令。将run.sh脚本拷贝出来查看后发现只在最后一步执行了一个脚本
查看对应位置发现是:/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时会有依赖错误的情况。
登录后复制
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.7,apt-get install python-pip
安装好环境后执行cqlsh,报如下错误,缺少cqlshlib的依赖包。
第一反应肯定是pip安一个,pip install cqlshlib报错如下
之后我通过dockerhub的Cassandra镜像启动了一个容器,从里面拷贝了出cqllib包,然后倒入到容器中,依旧不能解决模块缺失问题。再stack overflow中也未找到解决方案,同事说缺少cqlsh。使用** pip install cqlsh**解决模块缺失问题。
nodetool status查看集群ip
cqlsh 179.20.2.182 -u cassandra -p cassandra连接其中一个,报错如下
cqlsh 179.20.2.182 -u cassandra -p cassandra --cqlversinotallow=3.4.4指定cqlsh版本即可,成功执行sql
在容器构建时会执行run.sh脚本,因此我们在run.sh中插入一个sql文件并执行,即可完成keyspaces的构建。
在启动服务前异步执行一个initdb.sh的脚本,由于cql不能通过管道命令执行sql语句,只能通过文件执行,因此需要再写一个sql文件。
登录后复制
#!/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
登录后复制
FROM 10.0.100.59:5000/cassandra:v14
RUN rm -rf /etc/apt/sources.list
ADD cassandra.yaml /etc/cassandra/cassandra.yaml
COPY sources.list /etc/apt/
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 \
&& rm -rf /usr/local/bin/cqlsh
RUN rm -rf /usr/local/bin/cqlsh
COPY cqlsh /usr/local/bin/
RUN chown -R root:staff /usr/local/bin/cqlsh && chmod 755 /usr/local/bin/cqlsh
将需要的文件拷贝其中并授权。
source.list:镜像源。这一步踩坑在于使用了阿里的镜像源后,apt-get install python2.7会有依赖错误,具体原因未知。
使用apt-get update,这一步踩坑点在于apt-get update过程中会有不影响的错误,需在后面加入;exit 0来忽略错误。
使用-y参数时请在后面加上–allow-unauthenticated否则会报无权限错误。
上面三个RUN命令请不要合再一起写,否则会报错如下,意思是你使用的镜像源未被认证,当单独执行apt-get update时在更新仓库时会自动注册上去。
之后成功build镜像,验证成功,内置了一个keyspaces
cqlsh中修改默认cqlversion=3.4.4并授权
登录后复制
# 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
整理的一些关于【 k8s,kubernetes】的项目学习资料(附讲解~~),需要自取:
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删