0 环境说明

泰山2000 arm64架构服务器。

操作系统openEuler 20.03。

内核:Linux 4.19.90-2112.8.0.0131.oe1.aarch64

1 关闭防火墙

默认openEuler会安装并启动firewalld防火墙,需要提前关闭,否则在后续操作中可能会出现无法连接主机的问题。

systemctl stop firewalld
systemctl disable firewalld

2 部署rancher

使用rancher安装。

首先安装docker:

wget -O /etc/yum.repos.d/openEulerOS.repo https://repo.huaweicloud.com/repository/conf/openeuler_aarch64.repo

yum clean all

yum makecache

yum install docker

然后运行rancher的docker镜像进行集群管理。

docker run --privileged -d --restart=unless-stopped -p 3080:80 -p 3443:443 rancher/rancher:v2.5.15

注意这里一定不能使用2.6.x版本,否则集群部署遇到问题的时候不方便得到kubeconfig.json文件。

安装镜像之后,需要等待一会儿,最终会变成ready状态。

创建自定义集群,然后选择k8s版本为1.18。注意:下面选择Network(网络插件)要改成Flannel!!!,如果使用默认的canel,会拉取不到arm64对应版本的镜像导致部署失败,即使按照下面安装问题中解决了部署的问题,插件也无法正常使用,会出现不同节点不能ping通其他节点上部署的pod的情况。

参考文章https://cloud.tencent.com/developer/article/1768489

安装问题

Runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

原因:

先从cluster的overview界面右上角那里拿到kubeconfig file的内容,存入~/.kube/config中,之后kubectl就可以访问这个未完成的集群了。使用kubectl get pod -n kube-system命令查看集群中kube-system的pod运行情况,发现是一个pod卡住了。通过kubectl describe pod 命令查看这个pod的信息,发现其镜像是rancher/mirrored-calico-node:v3.13.4,然而去docker hub上查找发现,Calico该版本没有arm64的image,因此pod卡在ImagePullBackOff上。

解决方案:

kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml

手动安装一个calico之后,就正常了。

如果后续不需要该节点作为集群的节点,可以用以下脚本清理:

#!/bin/sh
docker rm -f $(docker ps -qa)
docker volume rm $(docker volume ls -q)
cleanupdirs="/var/lib/etcd /etc/kubernetes /etc/cni /opt/cni /var/lib/cni /var/run/calico /opt/rke"
for dir in $cleanupdirs; do
  echo "Removing $dir"
  rm -rf $dir
done

遇到其他问题时,首先冷静想想,是否是因为Docker镜像没有对应的arm64版本

获取kubeconfig.json

在rancher的界面上,cluster的overview处右上角有kubeconfig文件按钮。点击按钮,复制所有文件内容,并覆盖写入~/.kube/config文件,之后就可以使用kubectl访问和操作集群。

获取api token

首先绑定角色。kubectl create -f admin-role.yml

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: admin
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: admin
  namespace: kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin
  namespace: kube-system
  labels:
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile

然后运行kubectl -n kube-system get secret|grep admin-token 会出现一个admin-token-xxx

最后运行kubectl -n kube-system describe secret admin-token-xxx,将显示出的非常长的一串token复制出来。

参考文章https://jimmysong.io/kubernetes-handbook/guide/auth-with-kubeconfig-or-token.html

通过rancher安装的k8s集群中已经有metrics,因此可以直接使用java fabric8 api进行访问和使用。

工具安装

  1. kubens 快速切换namespace。

添加rancher节点

在新的节点主机上首先要关闭防火墙

然后在Rancher上找到Registration Cmd。复制后一定要加上 -e CATTLE_NODE_NAME=xxx来指定主机名,将新的节点加入到集群中。

还有一点需要注意的是,如果只添加work角色,会导致一直卡在等待注册(原因还不明)。

3 GlusterFS配置持久化卷

提前安装glusterfs和heketi,并配置好。

安装启动glusterfs:

yum install glusterfs
systemctl start glusterd
systemctl enable glusterd

安装heketi:https://github.com/heketi/heketi。只需要解压将可执行文件放入/usr/local/bin即可。

配置heketi:参考 https://claws.top/2022/07/18/glusterfs/#%E5%AE%89%E8%A3%85%E9%85%8D%E7%BD%AEheketi。配置好节点和device即可,无需自己创建volume,k8s会根据需要请求heketi创建volume。

创建k8s的StorageClass:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: seecoder-paas
provisioner: kubernetes.io/glusterfs
reclaimPolicy: Retain
allowVolumeExpansion: true
parameters:
  resturl: "http://172.29.7.102:5080" #glusterfs service url
  restauthenabled: "true"
  restuser: "admin"
  restuserkey: "WJNJqeGZGBJC6k1kaRxd"
  volumetype: "none"

注意,如果是单节点部署的glusterfs,必须要使用volumetype: "none"选项,否则创建持久卷会失败。

4 部署PaaS

数据库

先运行一个mysql数据库,供后端使用。

这里采用docker部署:

mkdir -p /mnt/mysql-data && docker run --restart=always -p 3306:3306 -p 33060:33060 --name my-mysql -v /mnt/mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql

然后新建seecoder_paas数据库备用。

后端

安装java。

docker仓库地址:

http://nexus.seecoder.cn/

在application.yml里面使用的docker仓库地址应该为 nexus.seecoder.cn:8092

需要将这个http网址加入到docker的配置文件的insecure中,否则在拉取镜像时会报错。另外还需要配置一个镜像站点,否则部署时拉取镜像会很慢。修改所有部署节点的/etc/docker/daemon.json如下所示:

{
  "registry-mirrors":["https://8eemjwlo.mirror.aliyuncs.com"],
  "insecure-registries":["nexus.seecoder.cn:8092"]
}

可以使用app.sh进行部署,需要对脚本文件中的一些变量进行修改。脚本使用同目录下的config.yml作为后端SpringBoot的配置文件。

运行目录中,要新建docker-config.json文件并填入以下内容,paas构建镜像后,会读取其中的账号密码并将镜像推送到私有的镜像仓库中:

{
  "auths": {
    "172.19.51.6:8092": {
      "username": "admin",
      "password": "NJU67nexus"
    }
  }
}

必须要新建seec的namespace,应用才可以正常部署。

kubectl create -f ns.yml

apiVersion: v1
kind: Namespace
metadata:
  name: seec

前端

使用nginx静态部署。如果部署前端的机器上面运行有集群,则需要避开80和443端口。

Nginx

由于含有websocket连接,需要进行特殊分流配置。

参考的nginx配置文件如下:

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}
upstream websocket {
    server 127.0.0.1:8080;
}
server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2 ;
        root /srv/paas-ui/dist;
        server_name paas-test-seec.claws.top;
 ssl_certificate_key /root/cert/paas-test-seec.claws.top/cert.key;
 ssl_certificate /root/cert/paas-test-seec.claws.top/fullchain.cer;

  location ~ /ws {
      proxy_pass http://websocket;
      proxy_read_timeout 3h;
      proxy_send_timeout 3h;

      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
  }
  location ~ / {
    if ($request_uri ~* (api)) {
        proxy_pass http://127.0.0.1:8080;
    }
    try_files $uri $uri/ /index.html;
  }
}

终端问题

无法连接:服务器nginx必须使用ssl加密,因为前端里面写死的wss。

连接之后出现unable to start container process: open /dev/pts/0: operation not permitted: unknown错误:在服务器上运行kubectl exec仍然有问题,重启pod解决。

5 配置ingress相关

rancher建立集群的时候,如果全部采用默认选项,就会自动开启一个nginx ingress controller,但是会占用宿主机原有的80和443端口。

paas的配置文件中deployment-host就是域名后缀的内容,先将这里设置好,然后解析泛域名到自己的服务器,就可以正常通过域名前缀和后缀的组合得到完整域名访问服务了。此时证书还是不正确的。

配置证书首先需要去OHTTPS上面申请一个泛域名证书,然后来到rancher的控制台,在seec的命名空间下添加一个新的secret,插入tls.crt(证书内容)和tls.key(证书私钥)两个值之后保存。如果rancher里面不能直接给seec插入,则需要先把seec命名空间加入到default的project的下面。最后在后端的config.yaml中修改secret-name,改成该证书secret的名字即可。

ingress 部署后访问时可能会出现 504Gateway Time-out的错误,是因为两个节点互相不能访问到对方节点上部署的pod。

6 后续维护Q&A

  1. Q:运行环境时出现镜像架构不正确的问题。A:检查镜像(尤其是build使用的基本镜像)是否是官方镜像,有出现类似java:8-jre-alpine的镜像不是官方镜像(可能是阿里的一个什么镜像),manifest书写不规范导致arm64的机器也可以pullamd64版本的镜像,但是后续运行就出现问题了。一定要使用官方镜像,防止出现架构不符的问题导致环境部署失败!