一、k8s的二进制部署

1.环境准备:

IP                               节点

172.16.10.1         k8s-master01

172.16.10.3         k8s-master02

172.16.10.10       k8s-node01

172.16.10.20       k8s-node02

172.16.10.11           master

172.16.10.12          backup

所有节点关闭防火墙和 iptables、selinux 以及 swap

systemctl stop firewalld
systemctl disable firewalld
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X

#关闭selinux
setenforce 0
sed -i 's/enforcing/disabled/' /etc/selinux/config #永久性关闭

#关闭swap
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab

2.主机名设置

hostnamectl set-hostname master01

hostnamectl set-hostname master02

hostnamectl set-hostname node01

hostnamectl set-hostname node02

hostnamectl set-hostname master

hostnamectl set-hostname backup

su -

3.在 master 添加 hosts 并调整内核参数

#在master添加hosts
cat >> /etc/hosts << EOF
172.16.10.1 master01
172.16.10.3 master02
172.16.10.10 node01
172.16.10.20 node02
EOF

#调整内核参数
-开启网桥模式,可将网桥的流量传递给iptables链,关闭ipv6协议

cat > /etc/sysctl.d/k8s.conf << EOF

#开启网桥模式,可将网桥的流量传递给iptables链
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

#关闭ipv6协议
net.ipv6.conf.all.disable_ipv6=1
net.ipv4.ip_forward=1
EOF

sysctl --system #一次性全部加载

#时间同步
yum install ntpdate -y
ntpdate time.windows.com

crontab -e
*/30 * * * * /usr/sbin/ntpdate time.windows.com
crontab -l

4.部署etcd集群

master节点:

(1)生成证书:没有软件包执行以下命令

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -O /usr/local/bin/cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -O /usr/local/bin/cfssljson
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -O /usr/local/bin/cfssl-certinfo

(2)有软件包直接将cfssl、cfssljson、cfssl-certinfo拖入/usr/local/bin目录中

cd /usr/local/bin目录中
cfssl、cfssljson、cfssl-certinfo

chmod +x /usr/local/bin/cfssl*      #赋予执行权限

#cfssl:证书签发的工具命令
#cfssljson:将cfssl生成的证书(json格式)变为文件承载式证书
#cfssl-certinfo:验证证书的信息
#cfssl-certinfo -cert <证书名称> #查看证书的信息

准备 cfssl 证书生成工具和授权

(1)生成Etcd证书
mkdir /opt/k8s
cd /opt/k8s/

上传 etcd-cert.sh 和 etcd.sh 到 /opt/k8s/ 目录中
chmod +x etcd-cert.sh etcd.sh        #赋权

(2)创建用于生成CA证书、etcd 服务器证书以及私钥的目录
(先去etcd-cert.sh改ip地址,再运行这个脚本)
mkdir /opt/k8s/etcd-cert
mv etcd-cert.sh etcd-cert/
cd /opt/k8s/etcd-cert/

vim etcd-cert.sh

./etcd-cert.sh

上传 etcd-v3.4.9-linux-amd64.tar.gz 到 /opt/k8s 目录中,启动etcd服务

cd /opt/k8s/
tar zxvf etcd-v3.4.9-linux-amd64.tar.gz

#创建用于存放etcd配置文件,命令文件,证书的目录
mkdir -p /opt/etcd/{cfg,bin,ssl}

cd /opt/k8s/etcd-v3.4.9-linux-amd64/
mv etcd etcdctl /opt/etcd/bin/
cp /opt/k8s/etcd-cert/*.pem /opt/etcd/ssl/

#在master上运行etcd集群,进入卡住状态等待其他节点加入
cd /opt/k8s/
./etcd.sh etcd01 172.16.10.1 etcd02=https://172.16.10.10:2380,etcd03=https://172.16.10.20:2380

ps -ef | grep etcd

启动etcd服务,配置好后,传给2个node节点

scp -r /opt/etcd/ root@172.16.10.10:/opt/
scp -r /opt/etcd/ root@172.16.10.20:/opt/

scp /usr/lib/systemd/system/etcd.service root@172.16.10.10:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/etcd.service root@172.16.10.20:/usr/lib/systemd/system/

node01 节点:

修改vim /opt/etcd/cfg/etcd

systemctl start etcd

systemctl enable etcd
systemctl status etcd

node02 节点:

vim /opt/etcd/cfg/etcd

systemctl start etcd

systemctl enable etcd
systemctl status etcd

在node节点上检验节点是否启动

cd /opt/etcd/ssl

ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://172.16.10.1:2379,https://172.16.10.10:2379,https://172.16.10.20:2379" endpoint health --write-out=table

#查看etcd集群成员列表

ETCDCTL_API=3 /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://172.16.10.1:2379,https://172.16.10.10:2379,https://172.16.10.20:2379" --write-out=table member list

5.部署 docker 引擎

#所有 node 节点部署docker引擎
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io

systemctl start docker.service
systemctl enable docker.service

6.部署master组件

master01:

#上传 master.zip 和 k8s-cert.sh 到 /opt/k8s 目录中,解压 master.zip 压缩包
cd /opt/k8s/
unzip master.zip
chmod +x *.sh

#创建kubernetes工作目录
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}

#创建用于生成CA证书、相关组件的证书和私钥的目录
mkdir /opt/k8s/k8s-cert -p
mv /opt/k8s/k8s-cert.sh /opt/k8s/k8s-cert
cd /opt/k8s/k8s-cert/
./k8s-cert.sh #生成CA证书、相关组件的证书和私钥

ls *pem

#复制CA证书、apiserver相关证书和私钥到kubernetes工作目录的ssl子目录中
cp ca*pem apiserver*pem /opt/kubernetes/ssl/

#上传 kubernetes-server-linux-amd64.tar.gz 到 /opt/k8s/ 目录中,解压 kubernetes 压缩包
#下载地址:https://github.com/kubernetes/kubernetes/blob/release-1.20/CHANGELOG/CHANGELOG-1.20.md
#注:打开链接你会发现里面有很多包,下载一个server包就够了,包含了Master和Worker Node二进制文件。
cd /opt/k8s/
tar zxvf kubernetes-server-linux-amd64.tar.gz

#复制master组件的关键命令文件到kubernetes工作目录的bin子目录中
cd /opt/k8s/kubernetes/server/bin
cp kube-apiserver kubectl kube-controller-manager kube-scheduler /opt/kubernetes/bin/
ln -s /opt/kubernetes/bin/* /usr/local/bin/

#创建 bootstrap token 认证文件,apiserver 启动时会调用,然后就相当于在集群内创建了一个这个用户,接下来就可以用 RBAC 给他授权
cd /opt/k8s/
vim token.sh
#!/bin/bash
#获取随机数前16个字节内容,以十六进制格式输出,并删除其中空格
BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
#生成 token.csv 文件,按照 Token序列号,用户名,UID,用户组的格式生成
cat > /opt/kubernetes/cfg/token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF

chmod +x token.sh
./token.sh

cat /opt/kubernetes/cfg/token.csv

#二进制文件、token、证书都准备好后,开启apiserver服务
cd /opt/k8s/
vim apiserver.sh

./apiserver.sh 172.16.10.1 https://172.16.10.1:2379,https://172.16.10.10:2379,https://172.16.10.20:2379

#检查进程是否启动成功
ps aux | grep kube-apiserver

netstat -natp | grep 6443 #安全端口6443用于接收HTTPS请求,用于基于Token文件或客户端证书等认证

cd /opt/k8s/

#启动 scheduler 服务

vim scheduler.sh

./scheduler.sh
ps aux | grep kube-scheduler

#启动 controller-manager 服务

vim controller-manager.sh

./controller-manager.sh
ps aux | grep kube-controller-manager

#生成kubectl连接集群的证书

vim admin.sh

./admin.sh

#绑定默认cluster-admin管理员集群角色,授权kubectl访问集群
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous

#通过kubectl工具查看当前集群组件状态
kubectl get cs

#查看版本信息
kubectl version

7.部署 Worker Node 组件

所有 node 节点:

#创建kubernetes工作目录
mkdir -p /opt/kubernetes/{bin,cfg,ssl,logs}

#上传 node.zip 到 /opt 目录中,解压 node.zip 压缩包,获得kubelet.sh、proxy.sh
cd /opt/
unzip node.zip
chmod +x kubelet.sh proxy.sh

在 master01 节点上操作==

#把 kubelet、kube-proxy 拷贝到 node 节点
cd /opt/k8s/kubernetes/server/bin
scp kubelet kube-proxy root@172.16.10.10:/opt/kubernetes/bin/
scp kubelet kube-proxy root@172.16.10.20:/opt/kubernetes/bin/

#上传 kubeconfig.sh 文件到 /opt/k8s/kubeconfig 目录中,生成 kubeconfig 的配置文件

#上传kubeconfig.sh文件到/opt/k8s/kubeconfig目录中,生成kubelet初次加入集群引导kubeconfig文件和kube-proxy.kubeconfig文件
#kubeconfig 文件包含集群参数(CA证书、API Server 地址),客户端参数(上面生成的证书和私钥),集群context上下文参数(集群名称、用户名)。Kubenetes组件(如kubelet、kube-proxy)通过启动时指定不同的kubeconfig文件可以切换到不同的集群,连接到apiserver。
mkdir /opt/k8s/kubeconfig
cd /opt/k8s/kubeconfig
chmod +x kubeconfig.sh
./kubeconfig.sh 172.16.10.1 /opt/k8s/k8s-cert/

#把配置文件 bootstrap.kubeconfig、kube-proxy.kubeconfig 拷贝到node节点
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@172.16.10.10:/opt/kubernetes/cfg/
scp bootstrap.kubeconfig kube-proxy.kubeconfig root@172.16.10.20:/opt/kubernetes/cfg/

#RBAC授权,使用户 kubelet-bootstrap 能够有权限发起 CSR 请求
kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

#若执行失败,可先给kubectl绑定默认cluster-admin管理员集群角色,授权集群操作权限
kubectl create clusterrolebinding cluster-system-anonymous --clusterrole=cluster-admin --user=system:anonymous

 

在 node01 节点上操作

#启动 kubelet 服务
cd /opt/

vim kubelet.sh
./kubelet.sh 172.16.10.10
ps aux | grep kubelet

​//在 master01 节点上操作,通过 CSR 请求#检查到 node01 节点的 kubelet 发起的 CSR 请求,Pending 表示等待集群给该节点签发证书

kubectl get csr
#通过 CSR 请求
kubectl certificate approve RmA1K6zToOY8D4iFaxxzndsAPg_SPJ2caK7lgbPRDm8   11s
#Approved,Issued 表示已授权 CSR 请求并签发证书
kubectl get csr
#查看节点,由于网络插件还没有部署,节点会没有准备就绪 NotReady
kubectl get node

node02 节点同上

在 node01 节点上操作

#加载 ip_vs 模块
for i in $(ls /usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs|grep -o "^[^.]*");do echo $i; /sbin/modinfo -F filename $i >/dev/null 2>&1 && /sbin/modprobe $i;done

#启动proxy服务
cd /opt/
./proxy.sh 172.16.10.10
ps aux | grep kube-proxy

node02 节点同上

8.部署 CNI 网络组件

node01 节点:

#上传 cni-plugins-linux-amd64-v0.8.6.tgz 和 flannel.tar 到 /opt 目录中
cd /opt/

mkdir -p /opt/cni/bin
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin

docker load -i flannel.tar
docker images
scp -r cni/ flannel.tar 172.16.10.20:/opt

在 master01 节点上操作

#上传 kube-flannel.yml 文件到 /opt/k8s 目录中,部署 CNI 网络
cd /opt/k8s
kubectl apply -f kube-flannel.yml
kubectl get pods -n kube-system
kubectl get nodes

9.把 master01 相关主机的配置文件复制到 master02

复制并修改 kube-apiserver

scp -r /opt/kubernetes/ master02:/opt

master02节点:

vim /opt/kubernetes/cfg/kube-apiserver

ln -s /opt/kubernetes/bin/* /usr/local/bin/

master01节点:

复制etcd

scp -r /opt/etcd/ master02:/opt

复制家目录下的.kube

scp -r .kube/ master02:/root

kubectl get nodes

复制system 目录下的 kube*

scp -r /usr/lib/systemd/system/kube* master02:/usr/lib/systemd/system

master02节点:

systemctl start kube-apiserver.service kube-controller-manager.service kube-scheduler.service
systemctl enable kube-apiserver.service kube-controller-manager.service kube-scheduler.service

kubectl get nodes

10.负载均衡部署

#关闭防火墙和iptables
systemctl stop firewalld
systemctl disable firewalld

#关闭selinux
setenforce 0

11.部署nginx服务

配置load balancer集群双机热备负载均衡(nginx实现负载均衡,keepalived实现双机热备)

==在master、backup节点上操作==

配置nginx的官方在线yum源,配置本地nginx的yum源
cat > /etc/yum.repos.d/nginx.repo << 'EOF'
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
EOF

yum install nginx -y

修改nginx配置文件,配置四层反向代理负载均衡,指定k8s群集2台master的节点ip和6443端口
vim /etc/nginx/nginx.conf
events {
  worker_connections  1024;
}

#添加
stream {
  log_format main  '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';
   
access_log /var/log/nginx/k8s-access.log main;

  upstream k8s-apiserver {
      server 172.16.10.1:6443;
      server 172.16.10.3:6443;
  }
  server {
      listen 6443;
      proxy_pass k8s-apiserver;
  }
}

http {
......

#检查配置文件语法
nginx -t  

#启动nginx服务,查看已监听6443端口
systemctl start nginx
systemctl enable nginx
netstat -natp | grep nginx

11.部署 keepalived 服务

yum install keepalived -y   #安装

修改 keepalived 配置文件

vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
  # 接收邮件地址
  notification_email {
    acassen@firewall.loc
    failover@firewall.loc
    sysadmin@firewall.loc
  }
  # 邮件发送地址
  notification_email_from Alexandre.Cassen@firewall.loc
  smtp_server 127.0.0.1
  smtp_connect_timeout 30
  router_id NGINX_MASTER #lb01节点的为 NGINX_MASTER,lb02节点的为 NGINX_BACKUP
}

#添加一个周期性执行的脚本
vrrp_script check_nginx {
  script "/etc/nginx/check_nginx.sh" #指定检查nginx存活的脚本路径
}

vrrp_instance VI_1 {
  state MASTER #lb01节点的为 MASTER,lb02节点的为 BACKUP
  interface ens33 #指定网卡名称 ens33
  virtual_router_id 51 #指定vrid,两个节点要一致
  priority 100 #lb01节点的为 100,lb02节点的为 90
  advert_int 1
  authentication {
      auth_type PASS
      auth_pass 1111
  }
  virtual_ipaddress {
       172.16.10.100/24 #指定 VIP
  }
  track_script {
      check_nginx #指定vrrp_script配置的脚本
  }
}

创建 nginx 状态检查脚本

vim /etc/nginx/check_nginx.sh
#!/bin/bash
#egrep -cv "grep|$$" 用于过滤掉包含grep 或者 $$ 表示的当前Shell进程ID
count=$(ps -ef | grep nginx | egrep -cv "grep|$$")
if [ "$count" -eq 0 ];then
  systemctl stop keepalived
fi
chmod +x /etc/nginx/check_nginx.sh
#启动keepalived服务(一定要先启动了nginx服务,再启动keepalived服务)
systemctl start keepalived
systemctl enable keepalived

ip a #查看VIP是否生成

 

修改node节点上bootstrap.kubeconfig,kubelet.kubeconfi配置文件为 VIP

cd /opt/kubernetes/cfg/
vim bootstrap.kubeconfig
server: https://172.16.10.100:6443

vim kubelet.kubeconfig
server: https://172.16.10.100:6443

vim kube-proxy.kubeconfig
server: https://172.16.10.100:6443

#重启kubelet和kube-proxy服务
systemctl restart kubelet.service
systemctl restart kube-proxy.service

#在 lb01 上查看 nginx 和 node 、 master 节点的连接状态
netstat -natp | grep nginx

#在 master 节点上操作
cd .kube/
ls
vim config
server: https://172.16.10.100:6443

在 master01 节点上操作

#测试创建pod

kubectl run nginx --image=nginx
#查看Pod的状态信息
kubectl get pods

kubectl get pods -o wide

//READY为1/1,表示这个Pod中有1个容器

#在对应网段的node节点上操作,可以直接使用浏览器或者curl命令访问
curl 10.244.0.2

 

12.部署 Dashboard

//在 master01 节点上操作
#上传 recommended.yaml 文件到 /opt/k8s 目录中
cd /opt/k8s
vim recommended.yaml
#默认Dashboard只能集群内部访问,修改Service为NodePort类型,暴露到外部:
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 30001 #添加
type: NodePort #添加
selector:
k8s-app: kubernetes-dashboard

kubectl apply -f recommended.yaml

#创建service account并绑定默认cluster-admin管理员集群角色
kubectl create serviceaccount dashboard-admin -n kube-system
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')

#使用输出的token登录Dashboard
https://172.16.10.10:30001

点击“高级”

点击“添加例外”

点击“确认安全例外”

复制选中的部分将其输入并点击“登录”

k8s的部署的更多相关文章

  1. 持续集成之应用k8s自动部署

    持续集成之应用k8s自动部署 Intro 上次我们提到了docker容器化及自动化部署,这仅仅适合个人项目或者开发环境部署,如果要部署到生产环境,必然就需要考虑很多因素,比如访问量大了如何调整部署,如 ...

  2. k8s二进制部署

    k8s二进制部署 1.环境准备 主机名 ip地址 角色 k8s-master01 10.0.0.10 master k8s-master02 10.0.0.11 master k8s-node01 1 ...

  3. Prometheus K8S中部署Alertmanager

    Prometheus K8S中部署Alertmanager 设置告警和通知的主要步骤如下:一.部署Alertmanager二.配置Prometheus与Alertmanager通信三.配置告警 1. ...

  4. K8S CoreDNS部署失败,发现的一个问题

    K8S CoreDNS部署失败,查看错误日志,提示如下 root >> kubectl get all --all-namespaces -o wide root >> kub ...

  5. Kubernetes之在k8s中部署Java应用

    部署好了k8s以后 部署参考https://www.cnblogs.com/minseo/p/12055731.html 怎么在k8s部署应用 项目迁移到k8s平台是怎样的流程 1,制作镜像 2,控制 ...

  6. kubernetes之三 使用kubectl在k8s上部署应用

    在上一篇中,我们学习了使用minikube来搭建k8s集群.k8s集群启动后,就可以在上面部署应用了.本篇,我们就来学习如何使用kubectl在k8s上部署应用. 学习之前,可以先从下面这篇博客上了解 ...

  7. Docker & k8s 系列三:在k8s中部署单个服务实例

    本章将会讲解: pod的概念,以及如何向k8s中部署一个单体应用实例. 在上面的篇幅中,我们了解了docker,并制作.运行了docker镜像,然后将镜像发布至中央仓库了.然后又搭建了本机的k8s环境 ...

  8. 在k8s上部署日志系统elfk

    日志系统elfk 前言 经过上周的技术预研,在本周一通过开会研究,根据公司的现有业务流量和技术栈,决定选择的日志系统方案为:elasticsearch(es)+logstash(lo)+filebea ...

  9. 优化:在k8s上部署的gitlab

    gitlab组件图 gitlab在k8s上占用资源 # kubectl top pods -n default | grep git* gitlab-gitaly-0 9m 444Mi gitlab- ...

  10. 使用Rancher在K8S上部署高性能PHP应用程序

    介 绍 PHP是网络上最流行的编程语言之一,许多被广泛使用的内容管理系统都使用它开发,如WordPress和Drupal,并为现代服务器端框架(如Laravel和Symfony)提供核心代码. 尽管P ...

随机推荐

  1. RESTFul是一种风格

    只要符合RESTFul风格的,都可以叫做使用了RESTFul架构,一般的网站里传数据,都是用的?a=1&b=2...如果是RESTFul风格的话,就会是/a/1/b/2..类似于这样的方式来传 ...

  2. Flutter和iOS混编详解

    前言 下面的内容是最近在使用Flutter和我们自己项目进行混编时候的一些总结以及自己踩的一些坑,处理完了就顺便把整个过程以及一些我们可能需要注意的点全都梳理出来,希望对有需要的小伙伴有点帮助,也方便 ...

  3. 操作系统实现-loader

    博客网址:www.shicoder.top 微信:18223081347 欢迎加群聊天 :452380935 大家好呀,终于我们到了操作系统的loader部分了,loader也是操作系统中最重要的一个 ...

  4. vue - Vue路由

    至此基本上vue2.0的内容全部结束,后面还有点elementUI和vue3.0的内容过几天再来更新. 这几天要回学校去参加毕业答辩,断更几天 一.相关理解 是vue的一个插件库,专门用来实现spa( ...

  5. Event Loop 是什么?

    Event Loop 是什么? 本文写于 2020 年 12 月 6 日 广义上来说 Event Loop 并不是 JavaScript 独有的概念,他是一个计算机的通用概念. 狭义上来说,只有 No ...

  6. 二、深入学习c++需要掌握的基础知识

    一.掌握形参带默认值的函数 给定默认值的时候是从右向左给,因为函数在内存中的压栈顺序是按照形参列表的元素从右向左依次向内存中压栈 形参是否有默认值对调用效率的问题:如果有一个默认值,在函数调用的过程中 ...

  7. MySQL执行计划explain

    一.简介 分析查询慢的原因,在查询语句前加explain即可.如: 二.输出格式 2.0 测试数据 # 表user_info CREATE TABLE `user_info` ( `id` bigin ...

  8. awk内建函数

    内建函数 length() 获得字符串长度 cat score.txt Marry 2143 78 84 77 Jack 2321 66 78 45 Tom 2122 48 77 71 Mike 25 ...

  9. 安装Iftop到CentOS(YUM)

    iftop是Linux系统下实时流量监控工具. 运行环境 系统版本:CentOS Linux release 7.6.1810 (Core) 软件版本:Python 硬件要求:无 安装过程 1.安装i ...

  10. drools执行完某个规则后终止别的规则执行

    目录 1.背景 2.需求 3.实现方案 1.通过Fact判断 2.通过全局变量判断 3.通过halt方法 4.实现上述需求 4.1 drl 文件编写 4.2 运行结果 5.完整代码 1.背景 在我们开 ...