文章目录
- 【2025-01-16已更新】
- K3S服务安装过程
- 1. 准备工作
- 2. 集群数据库方案
- 3. 高可用网络配置
- 4. 安装K3S
- 5. 安装并指定私有镜像库
- 6. 高可用安装Rancher
- 7. 设置keepalived检测脚本
- 8. cattle-cluster-agent和cattle-node-agent几乎一定会处理的问题
- 结束
- +1:完全离线安装
- +2:在K3S集群加入一个Agent节点
- +3. 更换rancher的默认镜像库地址
- +4. 删除rancher
- +5. 修改ETCD节点信息
- +6. 修改K3S_DATASTORE_ENDPOINT
- +7. 高可用安装情况下修改80和443端口(本章节网上找不到,纯属原创精华)
- +8. 在Rancher上手动创建Ingress
- +9. 修改max-pods
- +10. IP修改后,以灾难恢复方式重建ETCD
- +11. 修改k3s-serving证书有效期为10年(或自定义时间)
【2025-01-16已更新】
K3S服务安装过程
适用于centos7+,x86或arm都一样
在每个server节点上执行一次。
核心思想说明:
对于一个小型环境,因为k3s的server节点高可用,最少只需要2个节点(使用外部数据库)
对于中型环境,那么可以考虑更多的server节点,以及其他数据库方案(比如etcd、三节点mysql),方案上选择较多。
开始安装过程
以下工作以3台节点:172.16.149.122(k3s01),172.16.149.123(k3s02),172.16.149.124(k3s03),VIP172.16.149.139为例
1. 准备工作
每台机器上执行
1.1. disable firewall
systemctl stop firewalld
systemctl disable firewalld
1.2. disable selinux
setenforce 0
sed -i s#SELINUX=enforcing#SELINUX=disabled# /etc/selinux/config
重启机器
1.3. disable swap(仅列出,可以暂不执行,效果不明)
swapoff -a
# 找到fstab中,swap defaults那一行,行首加一个注释
sed -i ‘s/.*swap.defaults./#&/g’ /etc/fstab
1.4. 修改主机名,并修改hosts
hostnamectl set-hostname k3s01(节点2为k3s02)
echo -e “172.16.149.122\tk3s01” | tee -a /etc/hosts
echo -e “172.16.149.123\tks302” | tee -a /etc/hosts
1.5. 安装docker
用rancher提供的方式安装
curl https://releases.rancher.com/install-docker/19.03.sh | sh
|
或者用docker其他方式安装
1.5.1. 修改Docker loglimit。非常重要!
因为docker中的程序syslog,默认会使用emptyDir主机存储,
也就是会在/var/lib/kubernetes/中的产生很多ephemeral-storage
内容。
如果不设置,后续会遇到
The node was low on resource: ephemeral-storage. Container xxxx which exceeds its request of xxx
这种问题。
解决办法可以参考这里
vi /etc/docker/daemon.json
设置以下内容,用于限制log的ephemeral-storage大小:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
1.5.2. 修改Docker limit。非常重要!
如果后续要在该集群上安装mongodb,那么必须设置docker limit参数。
如果不设置,mongodb将因为ulimit的问题,导致不断重启
在日志中一般会发现:
Failed to mlock: Cannot allocate locked memory…
配置方法(参考这里):
- 执行 systemctl status docker ; systemctl status containerd(arm版本的老docker可能会使用containerd底层)。找到他们的配置文件地址
假如上述服务的配置地址分别是:/usr/lib/systemd/system/docker.service,/usr/lib/systemd/system/containerd.service- 添加
LimitMEMLOCK=infinity
find / -iname “docker.service” 找到docker服务
vi ${目录}/docker.service
如果有contaninerd find / -iname “containerd.service”
vi ${目录}/containerd.service
在[Service]一节增加LimitMEMLOCK=infinity
1.5.3. 强制使用overlay2存储引擎
vi /etc/docker/daemon.json
设置以下内容,
{
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
1.5.4. 修改docker数据目录(可选)
某些机器,由于/var/lib/docker/目录空间不大,可以考虑迁移该目录到其他地方
比如迁移到 /home下
systemctl stop docker
mkdir -p /home/docker
rsync -avz /var/lib/docker /home/docker (需要安装rsync)
vi /etc/systemd/system/docker.service.d/devicemapper.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --graph=/home/docker
将上述内容写入
:wq!
1.5.5. 修改启动参数,更改iptables规则(可选)
这里 可以看到,有时候存在一种情况
“查阅了不少资料才看到docker 1.13 版本对iptables的规则进行了改动,默认FORWARD 链的规则为DROP ,带来的问题主要一旦DROP后,不同主机间就不能正常通信了(kubernetes的网络使用flannel的情况)”
因此,这里先让docker启动的时候搞一搞事情
find / -iname “docker.service”
vi ${目录}/docker.service
在[Service]一节追加
[Service]
............
ExecStartPost=iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT
1.5.6. 重启docker
systemctl stop docker
systemctl daemon-reload
如果有containerd,systemctl stop containerd
systemctl daemon-reload
如果有containerd,systemctl start containerd
systemctl start docker
1.6. 节点优化(可选)
- 节点内核调优
echo "
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward=1
net.ipv4.conf.all.forwarding=1
net.ipv4.neigh.default.gc_thresh1=4096
net.ipv4.neigh.default.gc_thresh2=6144
net.ipv4.neigh.default.gc_thresh3=8192
net.ipv4.neigh.default.gc_interval=60
net.ipv4.neigh.default.gc_stale_time=120
# 参考 https://github.com/prometheus/node_exporter#disabled-by-default
kernel.perf_event_paranoid=-1
#sysctls for k8s node config
net.ipv4.tcp_slow_start_after_idle=0
net.core.rmem_max=16777216
fs.inotify.max_user_watches=524288
kernel.softlockup_all_cpu_backtrace=1
kernel.softlockup_panic=0
kernel.watchdog_thresh=30
fs.file-max=2097152
fs.inotify.max_user_instances=8192
fs.inotify.max_queued_events=16384
vm.max_map_count=262144
fs.may_detach_mounts=1
net.core.netdev_max_backlog=16384
net.ipv4.tcp_wmem=4096 12582912 16777216
net.core.wmem_max=16777216
net.core.somaxconn=32768
net.ipv4.ip_forward=1
net.ipv4.tcp_max_syn_backlog=8096
net.ipv4.tcp_rmem=4096 12582912 16777216
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
kernel.yama.ptrace_scope=0
vm.swappiness=0
# 可以控制core文件的文件名中是否添加pid作为扩展。
kernel.core_uses_pid=1
# Do not accept source routing
net.ipv4.conf.default.accept_source_route=0
net.ipv4.conf.all.accept_source_route=0
# Promote secondary addresses when the primary address is removed
net.ipv4.conf.default.promote_secondaries=1
net.ipv4.conf.all.promote_secondaries=1
# Enable hard and soft link protection
fs.protected_hardlinks=1
fs.protected_symlinks=1
# 源路由验证
# see details in https://help.aliyun.com/knowledge_detail/39428.html
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce=2
net.ipv4.conf.all.arp_announce=2
# see details in https://help.aliyun.com/knowledge_detail/41334.html
net.ipv4.tcp_max_tw_buckets=5000
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_synack_retries=2
kernel.sysrq=1
# 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse=1
# 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。注意,net.ipv4.tcp_timestamps默认为开启,tcp_tw_recycle此选项也开启后,tcp timestamp机制就会激活,在部分场景下,需要关闭tcp_timestamps功能,见下方此选项的说明。
net.ipv4.tcp_tw_recycle=1
# tcp缓存时间戳
net.ipv4.tcp_timestamps=0
" >> /etc/sysctl.conf
- nofile
cat >> /etc/security/limits.conf <<EOF
* soft nofile 65535
* hard nofile 65536
EOF
- 关闭网卡offload(
谨慎操作)
如果出现【主机上】nodeport访问慢的问题,尝试执行以下内容
特别注意:
1)eth0代表主机网卡,应该按照实际情况修改
2)只有在默认使用flannel网络的情况下执行
ethtool -K eth0 rx off tx off sg off tso off
ethtool -K flannel.1 rx off tx off sg off tso off
1.7 设置系统时间和时区(多节点)
使用Xshell工具(或其他工具),在每个节点上同时执行
- 查看当前系统的时区
timedatectl list-timezones
- 选择一个合适的时区来进行设置。一般我们选择
Asia/Shanghai
timedatectl set-timezone "Asia/Shanghai"
- 设置系统时间
由于我们的安装环境一般都没有时钟同步服务器,因此手动设置时间
timedatectl set-time "具体的时间。格式为 2022-03-14 12:23:01"
1.8. 为Redis提供优化(可选)
redis运行中,可能会提示:
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel.
This will create latency and memory usage issues with Redis.
To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root,
and add it to your /etc/rc.local in order to retain the setting after a reboot.
Redis must be restarted after THP is disabled.
所以可以在节点安装k3s之前执行如下:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.local
2. 集群数据库方案
2.1 使用etcd(推荐)
# [member]
#etcd实例名称,每个节点不一样
ETCD_NAME=etcd1
#etcd数据保存目录
ETCD_DATA_DIR="/var/lib/etcd"
#供外部客户端使用的url
ETCD_LISTEN_CLIENT_URLS="http://本机IP:2379,http://127.0.0.1:2379"
#广播给外部客户端使用的url
ETCD_ADVERTISE_CLIENT_URLS="http://本机IP:2379"
#[cluster]
#集群内部通信使用的URL
ETCD_LISTEN_PEER_URLS="http://本机IP:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://本机IP:2380"
#广播给集群内其他成员访问的URL
ETCD_INITIAL_CLUSTER="[ETCD_NAME]=http://本机IP:2380[,[其他节点ETCD_NAME]=http://其他节点IP:2380]"
#初始集群成员列表
#用于指示本次是否为新建集群。有两个取值new和existing。如果填为existing,该
#member启动时会尝试与其他member交互。集群初次建立时,要填为new,经尝试最后
#一个节点填existing也正常,其他节点不能填为existing。集群运行过程中,一个
#member故障后恢复时填为existing,经尝试填为new也正常。全没问题的
ETCD_INITIAL_CLUSTER_STATE="new|existing"
#集群的名称
ETCD_INITIAL_CLUSTER_TOKEN="sobey-arm-etcd-cluster"
- systemctl restart etcd
- etcdctl member list检查集群情况
- etcdctl cluster-health
member eabc202e74d53d3 is healthy: got healthy result from http://172.16.149.124:2379
member b6e44ea4f023b88a is healthy: got healthy result from http://172.16.149.122:2379
member e50821dfde62301e is healthy: got healthy result from http://172.16.149.123:2379
一些情况:
1.在部署etcd集群时,尝试启动etcd1时,出现报错
Apr 12 01:06:49 k8s-master etcd[3092]: health check for peer 618d69366dd8cee3 could not connect: dial tcp 192.168.81.12:2380: getsockopt: connection refused
Apr 12 01:06:49 k8s-master etcd[3092]: health check for peer acd2ba924953b1ec could not connect: dial tcp 192.168.81.60:2380: getsockopt: connection refused
Apr 12 01:06:48 k8s-master etcd[3092]: publish error: etcdserver: request timed out
分析是因为etcd1的配置文件/etc/etcd/etcd.conf中的ETCD_INITIAL_CLUSTER_STATE是new,而在配置中ETCD_INITIAL_CLUSTER写入了etcd2/3的IP:PORT,这时etcd1尝试去连接etcd2、etcd3,但是etcd2、3的etcd服务此时还未启动,因此需要先启动etcd2和3的etcd服务,再去启动etcd1。
2.在初次部署etcd完成后,尝试执行etcdctl cluster-health命令来查询集群的运行状态,但是报错
cluster may be unhealthy: failed to list members
Error: client: etcd cluster is unavailable or misconfigured; error #0: dial tcp 127.0.0.1:2379: getsockopt: connection refused
; error #1: dial tcp 127.0.0.1:4001: getsockopt: connection refused
error #0: dial tcp 127.0.0.1:2379: getsockopt: connection refused
error #1: dial tcp 127.0.0.1:4001: getsockopt: connection refused
在etcd配置文件中的ETCD_LISTEN_CLIENT_URLS项,只写入了http://192.168.81.60:2379,而没有写入http://127.0.0.1:2379,加入后即可正常查询。
note:初始集群成员列表 其他机器为existing。或者参考2中所述的方式,用yml一次性启动
2.2 使用mysql双机热备(实验性)
基本目标:使用docker host模式部署在两个server节点上部署mysql。配置参考这里,形成双机主主热备的mysql高可用集群
我们在两个节点,172.16.149.122,172.16.149.123 上先安装各自的mysql,这里我们直接采用docker方式安装
2.2.1 准备工作
- docker pull mysql:latest(版本自己考虑,要求5.7以上,比如:docker pull mysql:5.7.32)
对于ARM机器官方版本只有8.0,docker pull mysql/mysql-server:8.0-aarch64- 先启动一个容器,把/etc/my.cnf拷贝出来备用,这个我们要放到主机上
docker run -itd --name mysqltest mysql
mkdir -p /sobey/dbu/mysql
docker cp mysqltest:/etc/my.cnf /sobey/dbu/mysql/my.cnf- 配置好主机数据目录
mkdir -p /sobey/dbu/mysql/datas- 删除这个容器
docker stop mysqltest
docker rm mysqltest
2.2.2 正式安装
2.2.2.1 修改配置文件
vi /sobey/dbu/mysql/my.cnf。
这里有一个特殊的地放:把目录改为/var/games,主要是为了映射数据到主机。因为/var/games是存在且未用的,否则只有重新编辑镜像,然后创建一个存放data的目录,如果不创建,mysql会报错没有创建目录
datadir=/var/games
socket=/var/lib/mysql/mysql.sock
log-error=/var/games/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
user=mysql
# 配置server-id 每个MySQL实例的server-id都不能相同
server-id=1 # 两个节点的server-id必须不同
# MySQL的日志文件的名字
log-bin=mysql_log_bin
# 作为从库时 更新操作是否写入日志 on:写入 其他数据库以此数据库做主库时才能进行同步
log-slave-updates=on
auto_increment_offset=1 # 设置奇偶自增id,节点1设置为1,节点2设置为2
auto_increment_increment=2
# MySQL系统库的数据不需要同步 我们这里写了3个 更加保险
# 同步数据时忽略一下数据库 但是必须在使用use db的情况下才会忽略;如果没有使用use db 比如create user 数据还是会同步的
replicate-ignore-db=information_schema
replicate-ignore-db=mysql
replicate-ignore-db=performance_schema
replicate-ignore-db=sys
# 使用通配符忽略MySQL系统库的表 这样在create user时也不会进行同步了
replicate_wild_ignore_table=information_schema.%
replicate_wild_ignore_table=mysql.%
replicate_wild_ignore_table=performance_schema.%
replicate_wild_ignore_table=sys.%
# MySQL系统库的日志不计入binlog 这样更加保险了
binlog-ignore-db=information_schema
binlog-ignore-db=mysql
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
上面比较特殊的点:
- 节点1和节点2的server-id必须不一样
server-id=1 - 节点1自增长ID
auto_increment_offset = 1
auto_increment_increment = 2 #奇数ID - 节点2自增加ID
auto_increment_offset = 2
auto_increment_increment = 2 #偶数ID
2.2.2.2 正式启动容器,映射端口、my.cnf、data存放目录.
- docker run -itd --name k3smysql -p 3306:3306 -v /sobey/dbu/mysql/my.cnf:/etc/my.cnf -v /sobey/dbu/mysql/datas:/var/games --net=host -e MYSQL_ROOT_PASSWORD=[这里填root密码] mysql
- docker ps检查一下安装情况,用客户端连接看看情况
- 进入容器,修改root用户允许远程访问
docker exec -it k3smysql /bin/sh
mysql -u root -p
输入root密码,进入后
修改远程权限,具体查一下5.x和8.0+是不一样的,这里因为是用8.0,所以
use mysql;
update user set host=‘%’ where user=‘root’;
flush privileges;- 如果是8.0的数据库,默认使用的是caching_sha2_passsword作为验证plugin,会导致很多客户端报错,有两个办法处理:
- a) 在my.cnf中设置
default_authentication_plugin=mysql_native_password- b) 按照3的方法进入mysql
ALTER USER ‘root’@‘%’ IDENTIFIED BY ‘root的密码’ PASSWORD EXPIRE NEVER;
ALTER USER ‘root’@‘%’ IDENTIFIED WITH mysql_native_password BY ‘root的密码’;
FLUSH PRIVILEGES;
其实只有第二句有意义
2.2.2.3 设置主主
接下来开始配置双机主主模式,这里需要在每个节点上的mysql容器中执行一次不同的操作。其实主主模式就是配置两个主从,先配置(节点1)->(节点2)的主从,然后再反过来配置(节点2)->(节点1)的主从,这样主主的模式就配置好了
2.2.2.3.1 先设置(节点1)->(节点2)的主从
第一步:登录节点1的数据库,并执行如下命令:
- 创建用于数据同步的账号 使用mysql_native_password的方式加密,用户名密码根据喜好决定
CREATE USER ‘replicauser’@‘%’ IDENTIFIED WITH mysql_native_password BY ‘replicauser’;- 对replicauser授予备份的权限
GRANT REPLICATION SLAVE ON *.* TO ‘replicauser’@‘%’;- 刷新权限
FLUSH PRIVILEGES;- 查看MySQL主节点的状态
SHOW MASTER STATUS;±------------------±--------±-------------±--------------------------------------------±-----------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
±------------------±--------±-------------±--------------------------------------------±-----------------+
| mysql_master.000001 | 516 | | information_schema,mysql,performance_schema,sys | |
±------------------±--------±-------------±--------------------------------------------±-----------------+
1 row in set上面得到的File和Position必须记好
第二步:再登录到节点2的数据库,执行如下命令:
#设置节点2的主节点和同步信息
CHANGE MASTER TO MASTER_HOST=‘节点1的ip’,MASTER_PORT=3306,MASTER_USER=‘replicauser也就是上面创建的那个user’,MASTER_PASSWORD=‘replicauser对应的密码’,MASTER_LOG_FILE=‘第一步show master status得到的File’,MASTER_LOG_POS=第一步show master status得到的Postion;
# 开启从库
START SLAVE;
第三步:检查。在节点2上面执行
mysql> SHOW SLAVE STATUS\G;# 查看从库的状态
如果在结果中看到
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
说明OK
===========
如果结果中看到 Slave_IO_Running: No
首先检查网络是否通
其次就是看Last_SQL_Error的信息
如果Last_SQL_Error中有“Could not find first log file name in binary log index file”这种信息
就做如下操作:
- 在[节点2]的mysql,执行:stop slave;
- 在[节点1]的mysql,执行:
a)flush logs;
b) show master status; 也就是第一步中的第4点,重新得到最新的File和Position- 切换回[节点2]的mysql,执行:
a)CHANGE MASTER TO MASTER_LOG_FILE=‘最新的File’,MASTER_LOG_POS=最新的Position;
b) start slave;- SHOW SLAVE STATUS\G;# 查看从库的状态
如果在结果中看到
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
这样,(节点1)->(节点2)的主从就搭建好了。
2.2.2.3.2 设置(节点2)->(节点1)的主从
- 先通过客户端在节点1上执行一个建库建表动作,验证节点1->节点2的同步已经成功
- 登录节点2的mysql,执行和节点1第一步相同的命令,创建用户,并且得到File和Position
- 切换到节点1上执行前面第二步相同的操作,只是IP换成节点2的,将节点1设置为节点2的从
- 在节点1上执行检查动作和处理手段
至此,Mysql双机主主就配置完了。
3. 高可用网络配置
在官方文档上,希望通过一个负载均衡+一个DNS来解决高可用及负载均衡。
负载均衡的目标是接管多个rancher主节点上Traefik Ingress提供的80和443
DNS是解决集群中多个主节点上的负载均衡提供统一入口
因为我们是多机主节点部署方案,并且希望集中式部署所有组件,因此,我们有如下选择:
- [DNS]<---->[负载均衡1|80 443,负载均衡2|80 443]<–>[节点1|80 443,节点N|80 443]
- [DNS]<---->[(负载均衡1|8880 8443,节点1|80 443),(负载均衡2|8880 443,节点N|80 443)]
- [DNS]<---->[节点1|80 443,节点N|80 443]
在一个小型化的集群环境中,选择方案3,并且DNS用keepalived主备安装提供VIP来支持。这样其实就只是让多主节点成为一个多机热备的环境,不必提供负载均衡,目的就是让rancher的server节点高可用而已,而不让rancher server节点负载均衡。如果要负载均衡,采用nginx方案
如果是个中型环境,可以考虑在集群外部nginx做L4负载均衡接管mysql(或etcd)、80、443,同时选择方案1或2。
3.1. 安装nginx(可选)
安装nginx应该是在server节点上服务化安装,但是:由于nginx的 Linux packages,对于arm的支持,都是较高的系统版本,比如centos8、debian10+。不过其docker版本倒是可以很好的无感安装,所以通过docker host网络方式安装nginx
因为rancher需要L4代理,因此nginx的版本要高于1.9才行。https://docs.rancher.cn/docs/rancher2/installation/options/nginx/_index/。 这里有个非常重要的提示:官方安装目标是nginx接管rancher的Traefix提供的80和443,那么就建议nginx单独找机器安装,否则端口冲突。而我们希望集中安装在节点上,那么就要注意,nginx的80转发和443转发,需要修改为8880(或其他)->80,8443(或其他)->443
。
直接参考hub https://hub.docker.com/_/nginx
docker pull nginx
启动的时候,把配置文件目录给映射到主机上便于后续修改,同时映射一个用于存放日志的地方。然后,在主机上设置一个K3S官方提供的配置文件
- mkdir -p /sobey/dbu/nginx/conf.d
- mkdir -p /sobey/dbu/nginx/logs
- vi /sobey/dbu/nginx/sobey.conf 将内容设置为下面这段配置,注意IP_NODE_1,2…x要修改为正确的server节点IP
user nginx;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_processes 4;
worker_rlimit_nofile 40000;
events {
worker_connections 8192;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
stream {
log_format info '$remote_addr [$time_local] ' '$protocol $status $bytes_sent $bytes_received' '$session_time "$upstream_addr" ' '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /var/log/nginx/stream-access.log info;
upstream rancher_servers_http {
least_conn;
server <IP_NODE_1>:80 max_fails=3 fail_timeout=5s;
server <IP_NODE_2>:80 max_fails=3 fail_timeout=5s;
}
server {
listen 8880;
proxy_pass rancher_servers_http;
}
upstream rancher_servers_https {
least_conn;
server <IP_NODE_1>:443 max_fails=3 fail_timeout=5s;
server <IP_NODE_2>:443 max_fails=3 fail_timeout=5s;
}
server {
listen 8443;
proxy_pass rancher_servers_https;
}
upstream mysql_server {
}
server {
listen 3307;
proxy_pass rancher_servers_https;
}
}
- vi /sobey/dbu/nginx/conf.d/default.conf 设置为下面的内容。因为映射了conf.d目录,所以要设置一个default.conf文件,由于上面用stream方式监听了80,所以http方式的默认端口改为58080(或其他)
server {
listen 58080;
listen [::]:58080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
- docker run --name nginx --net=host -v /sobey/dbu/nginx/conf.d:/etc/nginx/conf.d -v /sobey/dbu/nginx/logs:/var/log/nginx -v /sobey/dbu/nginx/sobey.conf:/etc/nginx/nginx.conf -d nginx
3.2. 安装keepalived
keepalived解决给双机主节点提供VIP,替代DNS的作用
keepalived需要自定义检测脚本来提供切换依据,而检测脚本应该要检测rancher、K3S,但是由于安装K3S需要指定一个外部数据库,因此这里我们先配置并启动keepalived,让他暂时只起到提供VIP的能力。等K3S和Rancher安装完以后,再设置etcd(或Mysql)、K3S和Rancher的检测脚本,然后重启keepalived
开始安装,在每个节点上都安装Keepalived,执行命令如下:
yum -y install keepalived
将配置文件写入
vi /etc/keepalived/keepalived.conf
注意里面的VIP地址
要修改为实际的地址
! Configuration File for keepalived
global_defs {
vrrp_garp_master_refresh 60
router_id sobeydbuk3s
}
vrrp_script chk_mysql_and_rancher {
script /sobey/dbu/keep_check.sh
interval 2
weight -10
}
vrrp_instance VIP {
state BACKUP
interface eth0
dont_track_primary
track_interface {
eth0
}
virtual_router_id 39
garp_master_delay 3
priority 101 #不同节点填写不同的权重
preempt_delay 5
mcast_src_ip 节点本机IP地址
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
track_script {
chk_mysql_and_rancher
}
virtual_ipaddress {
VIP地址 dev eth0 scope global
}
}
同时创建一个检测文件备用
vi /sobey/dbu/keep_check.sh
#!/bin/bash
exit 0
chmod +x /sobey/dbu/keep_check.sh
在两个节点启动keepalived
systemctl start keepalived
至此,准备工作做完
4. 安装K3S
安装命令可以使用环境变量的方式进行安装参数设置及3中所述的启动参数设置
这里描述了应该如何使用环境变量
主要参考的是
- 使用外部数据库实现高可用安装,这里我们采用是的etcd方案,前面已经安装好了。在启动k3s的时候,要带上外部数据库地址,这里(datastore)有配置说明
- 这里(instal-option)给出了在线安装时候,shell脚本可以设置的重要环境变量
- 其他额外的需要的启动参数,可以在这里(server-config)看到所有的项
完整在线安装命令就不写了,参考官方即可(注意如果是使用Mysql,其连接信息应该是VIP)。
这里主要讲下载后手动安装
基于脚本的离线安装
- 下载k3s安装脚本
wget https://get.k3s.io > k3s.sh
或者
curl -o k3s.sh https://get.k3s.io
- 获取二进制文件和镜像文件
去https://github.com/rancher/k3s/releases下载
写这篇文章的时候,最新是1.19,但是请下载1.18,因为这里> https://github.com/rancher/k3s/issues/2548有个问题
1)下载二进制文件拷贝到目标主机的/usr/local/bin中,注意,命名一定要是k3s
比如这里下载的是k3s-arm64
wget -O k3s https://github.com/rancher/k3s/releases/download/v1.18.12%2Bk3s1/k3s-arm64
chmod +x k3s
cp ./k3s /usr/local/bin/
2)下载air-gap
镜像文件拷贝到/var/lib/rancher/k3s/agent/images/中
mkdir -p /var/lib/rancher/k3s/agent/images/
下载tar,比如这里下载的是k3s-airgap-images-arm64.tar
wget https://github.com/rancher/k3s/releases/download/v1.18.12%2Bk3s1/k3s-airgap-images-arm64.tar
cp ./k3s-airgap-images-arm64.tar /var/lib/rancher/k3s/agent/images/
docker load < /var/lib/rancher/k3s/agent/images/k3s-airgap-images-arm64.tar
- 添加环境变量并执行安装
#跳过selinux
INSTALL_K3S_SELINUX_WARN=true
#跳过二进制文件下载
export INSTALL_K3S_SKIP_DOWNLOAD=true
#设置k3s的二进制文件地址,默认是/usr/local/bin,如果步骤2已经放到这个目录,则可以不用设置
export INSTALL_K3S_BIN_DIR=2中下载文件所在的目录
#K3S_DATASTORE_ENDPOINT代表的是外部数据库的连接,这里使用的是etcd的。如果用其他方案,参考官网说明
export K3S_DATASTORE_ENDPOINT=“http://[etcd1.ip]:2379,http://[etcd2.ip]:2379,http://[etcd3.ip]:2379”
export INSTALL_K3S_EXEC=“server --docker --kubelet-arg max-pods=200”
sh k3s.sh
或者
INSTALL_K3S_SELINUX_WARN=true INSTALL_K3S_SKIP_DOWNLOAD=true \
INSTALL_K3S_EXEC=‘server --docker --kubelet-arg max-pods=200’
K3S_DATASTORE_ENDPOINT=‘http://[etcd1.ip]:2379,http://[etcd2.ip]:2379,http://[etcd3.ip]:2379’ ./k3s.sh
其中:–kubelet-arg=max-pods=200表示,每个节点上最多支持200个POD(Kubernetes默认是110个)
–kubelet-arg的作用是设置kubelet参数,在官网这里有描述。其正确格式可以从这里和这里参考
kubelet参数可以参考K8S的官网
PS: 特别说明:如果启动后需要修改max-pods,参见+9 修改max-pods
这里面特别有几个坑说一下:
1.尽量使用K3S_DATASTORE_ENDPOINT这种方式指定连接参数。如果链接的是mysql数据库,如果参考官网上的内容或其他网络内容,采用启动参数方式指定,会遇到unknown network tcp这种日怪的错误,根本原因是,官网内容中的启动参数中,mysql连接串前后不能用双引号!!!已经提了issue
2.尽量使用1.18版本,因为这里(https://github.com/rancher/k3s/issues/2548)有个错误,我已经遇到了,我在(https://github.com/rancher/k3s/issues/2553)这里提了相同的问题
检查以下安装结果
k3s kubectl get nodes
===========================
NAME STATUS ROLES AGE VERSION
k3s01 Ready master 3m14s v1.18.12+k3s1
k3s02 Ready master 2m17s v1.18.12+k3s1
k3s03 Ready master 2m17s v1.18.12+k3s1
可能出现的问题
如果启动失败,K3S的默认日志在journalctl中,通过journalclt -xe -u k3s
可以查看
如果遇到说
no default routes found
这种问题,参考这里和这里,我们需要设置
1、 可能需要设置ip route
在每个节点上ip route add default via 节点IP
2、 如果还出现了无法启动,且日志中不停出现tls handshake error, 127.0.0.1
类似信息
启动参数中加入--flannel-iface <网卡名称> --node-ip 节点IP
样例:
INSTALL_K3S_SELINUX_WARN=true INSTALL_K3S_SKIP_DOWNLOAD=true \
INSTALL_K3S_EXEC=‘server --docker --kubelet-arg max-pods=200 --flannel-iface <网卡名称> --node-ip 节点IP’
K3S_DATASTORE_ENDPOINT=‘http://[etcd1.ip]:2379,http://[etcd2.ip]:2379,http://[etcd3.ip]:2379’ ./k3s.sh
打节点标签(可选)
标签根据实际情况打
k3s kubectl label nodes [节点名(比如k3s01)] env-executor=true env-ficus=true env-java-executor=true env-python-executor=true env-python-ai-executor=true env-java-media-executor=true env-usercenter=true env-schedule=true
一个需要了解的说明
一个k3s server节点,默认情况下也会在当前节点启动agent,也就是既是server也是agent。如果有明确的部署要求,则可以通过–disable-agent,安装一个裸 server
至此,双主节点K3S环境已经准备好
5. 安装并指定私有镜像库
5.1. 安装私有镜像库(可选)
由于我们本身有一个明确的私有镜像库,因此这步对我们的实施来说基本上都可以考虑忽略。
如果是在客户那边需要独立部署一个私有库,那么就找一个机器安装即可。
搜索“docker 安装私有镜像库”或“Harbor”,参考安装
5.2. 配置K3S Server连接到私有镜像库
在每个K3S Server节点上执行
#拷贝签名文件和根证书
mkdir -p /sobey/dbu/tls
上传私有镜像库签名文件和证书到该目录中
#编辑K3S证书配置信息
vi /etc/rancher/k3s/registries.yaml
mirrors:
docker.io:
endpoint:
- "https://images.sobey.com:5000"# 私有镜像库地址
configs:
"images.sobey.com:5000":
auth:
username: admin # 这是私有镜像仓库的用户名
password: sobeyhive # 这是私有镜像仓库的密码
tls:
cert_file: /sobey/dbu/tls/ficus_crt.crt # 镜像仓库中使用的cert文件的路径。
key_file: /sobey/dbu/tls/ficus_crt.key # 镜像仓库中使用的key文件的路径。
ca_file: /sobey/dbu/tls/rootCA.crt # 镜像仓库中使用的ca文件的路径。
如果是内网环境,并且没有DNS服务,那么需要手动修改hosts
echo -e “xx.xx.xx.xx \t images.sobey.com” | tee -a /etc/hosts
重启k3s
systemctl restart k3s
6. 高可用安装Rancher
我们的目标就是在K3S Server双节点安装基于K3S ENV的高可用Rancker。单机Docker安装不在这里讨论。
选择rancher版本为2.4.10_release。因为这个版本开始,kubernetes1.18作为默认支持,并且修复了一些bug。
4中安装K3S的时候,由于有红色字体的因素,因为我们就选择2.4.10_release作为安装目标。
在每个K3S Server节点上执行
6.1. 准备rancher 2.4.10 以及相关的docker镜像
在hub上找到正确的镜像,这里以arm64作为样例
docker pull rancher/rancher:v2.4.10-linux-arm64
#因为此时没有设置镜像库,因此设置标签为images.sobey.com/rancher/rancher:v2.4.10
后续helm渲染需要
docker tag rancher/rancher:v2.4.10-linux-arm64images.sobey.com/rancher/rancher:v2.4.10
由于rancher需要依赖一些其他的软件,也需要安装起来。因此,这里还需要进行这部分镜像的拉取。
具体有哪些,可以从这里,了解到,我们需要准备一些离线镜像。
一种方法是通过rancher-images.txt
找到所需要软件镜像列表,然后在hub上找到这些镜像的正确版本,依次pull下来。
当然,在一般环境中,可以不太关心每一个镜像的实际情况,也可以通过官方给出的方式直接处理
#根据上面的地址,到官方下载对应的脚本和数据文件。也可以到国内镜像下
- rancher-images.txt
- rancher-load-images.sh
- rancher-save-images.sh
#拷贝上述文件到目标机器同一目录下
mkdir -p /sobey/rancher_install
cd /sobey/rancher_install
#拷贝进这个目录
curl -O https://github.com/rancher/rancher/releases/download/v2.4.10/rancher-images.txt
curl -O https://github.com/rancher/rancher/releases/download/v2.4.10/rancher-load-images.sh
curl -O https://github.com/rancher/rancher/releases/download/v2.4.10/rancher-save-images.sh
#按照 这里2、收集 cert-manager 镜像
所描述的方式执行
#去重
sort -u rancher-images.txt -o rancher-images.txt
#添加镜像拉取
chmod +x rancher-save-images.sh
./rancher-save-images.sh --image-list ./rancher-images.txt
#完成时,当前目录会输出名为rancher-images.tar.gz的压缩包
#同时,这些镜像已经save到本地镜像列表中,可以通过docker images查看
特别的:
如果是私有库,可以通过脚本将镜像推送到私有库
chmod +x rancher-load-images.sh
./rancher-load-images.sh --image-list ./rancher-images.txt --registry 私库地址
有可能是没有官方的平台版本,比入arm64。也可能其他原因导致的失败
针对这些failed的,要手动拉取 docker pull xxxxxx
如果是因为平台不对,那么可以去hub.docker.com中,查询民间的镜像,拉取后手动修改标签
情况一:官方压根儿没有相应的版本
这里以arm64上面rancher/configmap-reload:v0.3.0-rancher2为例
在arm64上面,会看到Image pull failed: rancher/configmap-reload:v0.3.0-rancher2
于是执行:docker pull rancher/configmap-reload:v0.3.0-rancher2
结果发现没有此镜像,原因是它没有官方的arm64版本,因此去hub.docker.com中查询configmap-reload
结果发现比较流行的jimmidyson/configmap-reload
于是执行:docker pull jimmidyson/configmap-reload:v0.3.0
完成后,打标签:docker tag jimmidyson/configmap-reload:v0.3.0 rancher/configmap-reload:v0.3.0-rancher2
情况二:官方有较近版本
1、rancher/coredns-coredns:1.6.2
我们发现官方上,1.6.3就支持了arm64,这种代差非常小,从官方issue里面可知差别不大
于是执行:docker pull rancher/coredns-coredns:1.6.3
docker tag rancher/coredns-coredns:1.6.3 rancher/coredns-coredns:1.6.2
情况三:有一些确实搞不定的,可能只有靠手动build了
截至此时,2.4.10中,arm64上面无法pull的有
rancher/fluentd:v0.1.19,rancher/istio-coredns-plugin:0.2-istio-1.1, rancher/istio-kubectl:1.5.10,rancher/kubernetes-external-dns:v0.7.3,rancher/thanosio-thanos:v0.15.0
但是目测这些都是和istio有关,而目前我们还不会大规模使用istio,因此可以暂时忽略
或者,export出来,拷贝到Agent节点上
最笨的,将这个Faild List拷贝出来,在Agent上按红色的说明执行一次
如果【没有推送到私有镜像库】,那么,我们应该对【需要的镜像】进行docker tag处理。
比如docker tag rancher/rancher:v2.4.10-linux-arm64 images.sobey.com/rancher/rancher:v2.4.10 因为没有私库,只有做一次相当于人工pull的操作。
——需要的镜像,意思是rancher本身,或者rancher运行起来之后,界面上提示无法pull的镜像
下面后续的操作,其实可以只在一台节点上操作。当然,也可以根据实际情况,每个节点都操作一次。
6.2. 准备Rancher Server证书
6.2.1. 从DBU人员手中获取证书
从DBU人员手中获取到Rancher访问需要的证书(和5.2中的是两个不同的证书),默认情况下会得到名为“dbu_rancher_crt”的证书,默认我们设置的DNS为dburancher.sobey.com
#拷贝签名文件和根证书
mkdir -p /sobey/dbu/tls/rancher
上传签名文件和证书到该目录中
6.2.2. 自建证书
- 拷贝下面的内容到 /root/mktls.sh
#!/bin/bash -e
help ()
{
echo ' ================================================================ '
echo ' --ssl-domain: 生成ssl证书需要的主域名,如不指定则默认为www.rancher.local,如果是ip访问服务,则可忽略;'
echo ' --ssl-trusted-ip: 一般ssl证书只信任域名的访问请求,有时候需要使用ip去访问server,那么需要给ssl证书添加扩展IP,多个IP用逗号隔开;'
echo ' --ssl-trusted-domain: 如果想多个域名访问,则添加扩展域名(SSL_TRUSTED_DOMAIN),多个扩展域名用逗号隔开;'
echo ' --ssl-size: ssl加密位数,默认2048;'
echo ' --ssl-cn: 国家代码(2个字母的代号),默认CN;'
echo ' --ssl-date: 有效天数;'
echo ' --ca-key: 指定根证书的key。如果不指定,则生成 '
echo ' --ca-cert: 指定根证书。如果不指定,则生成 '
echo ' --ca-domain: 指定cadomain,如果不指定,则默认cattle-ca'
echo ' 使用示例:'
echo ' ./create_self-signed-cert.sh --ssl-domain=www.test.com --ssl-trusted-domain=www.test2.com \ '
echo ' --ssl-trusted-ip=1.1.1.1,2.2.2.2,3.3.3.3 --ssl-size=2048 --ssl-date=3650'
echo ' ================================================================'
}
case "$1" in
-h|--help) help; exit;;
esac
if [[ $1 == '' ]];then
help;
exit;
fi
CMDOPTS="$*"
for OPTS in $CMDOPTS;
do
key=$(echo ${OPTS} | awk -F"=" '{print $1}' )
value=$(echo ${OPTS} | awk -F"=" '{print $2}' )
case "$key" in
--ssl-domain) SSL_DOMAIN=$value ;;
--ssl-trusted-ip) SSL_TRUSTED_IP=$value ;;
--ssl-trusted-domain) SSL_TRUSTED_DOMAIN=$value ;;
--ssl-size) SSL_SIZE=$value ;;
--ssl-date) SSL_DATE=$value ;;
--ca-date) CA_DATE=$value ;;
--ssl-cn) CN=$value ;;
--ca-key) CA_KEY_INPUT=$value ;;
--ca-cert) CA_CERT_INPUT=$value ;;
--ca-domain) CA_DOMAIN=$value ;;
esac
done
# CA相关配置
CA_DATE=${CA_DATE:-3650}
CA_DOMAIN=${CA_DOMAIN:-'cattle-ca'}
# ssl相关配置
SSL_CONFIG=${SSL_CONFIG:-$PWD/openssl.cnf}
SSL_DOMAIN=${SSL_DOMAIN:-'www.rancher.local'}
SSL_DATE=${SSL_DATE:-3650}
SSL_SIZE=${SSL_SIZE:-2048}
## 国家代码(2个字母的代号),默认CN;
CN=${CN:-CN}
SSL_KEY=$SSL_DOMAIN.key
SSL_CSR=$SSL_DOMAIN.csr
SSL_CERT=$SSL_DOMAIN.crt
echo -e "\033[32m ---------------------------- \033[0m"
echo -e "\033[32m | 生成 SSL Cert | \033[0m"
echo -e "\033[32m ---------------------------- \033[0m"
if [ -n "$CA_KEY_INPUT" ] && [[ -e ./${CA_KEY_INPUT} ]]; then
echo -e "\033[32m ====> 1. 发现已存在CA私钥,使用该私钥 \033[0m"
CA_KEY="$CA_KEY_INPUT"
else
echo -e "\033[32m ====> 1. 生成新的CA私钥 ${CA_KEY} \033[0m"
CA_KEY="./cakey.pem"
openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
fi
if [ -n "$CA_CERT_INPUT" ] && [[ -e ./${CA_CERT_INPUT} ]]; then
echo -e "\033[32m ====> 2. 发现已存在CA证书,使用该证书 \033[0m"
if [ -z "$CA_KEY_INPUT" ]; then
echo -e "\033[32m ====> 指定了CA证书,必须指定--ca-key \033[0m"
exit 1
fi
CA_CERT="$CA_CERT_INPUT"
else
echo -e "\033[32m ====> 2. 生成新的CA证书 ${CA_CERT} \033[0m"
CA_CERT="./cacerts.pem"
openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
fi
echo -e "\033[32m ====> 3. 生成Openssl配置文件 ${SSL_CONFIG} \033[0m"
cat > ${SSL_CONFIG} <<-EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOF
if [[ -n ${SSL_TRUSTED_IP} || -n ${SSL_TRUSTED_DOMAIN} ]]; then
cat >> ${SSL_CONFIG} <<-EOF
subjectAltName = @alt_names
[alt_names]
EOF
IFS=","
dns=(${SSL_TRUSTED_DOMAIN})
dns+=(${SSL_DOMAIN})
for i in "${!dns[@]}"; do
echo DNS.$((i+1)) = ${dns[$i]} >> ${SSL_CONFIG}
done
if [[ -n ${SSL_TRUSTED_IP} ]]; then
ip=(${SSL_TRUSTED_IP})
for i in "${!ip[@]}"; do
echo IP.$((i+1)) = ${ip[$i]} >> ${SSL_CONFIG}
done
fi
fi
echo -e "\033[32m ====> 4. 生成服务SSL KEY ${SSL_KEY} \033[0m"
openssl genrsa -out ${SSL_KEY} ${SSL_SIZE}
echo -e "\033[32m ====> 5. 生成服务SSL CSR ${SSL_CSR} \033[0m"
openssl req -sha256 -new -key ${SSL_KEY} -out ${SSL_CSR} -subj "/C=${CN}/CN=${SSL_DOMAIN}" -config ${SSL_CONFIG}
echo -e "\033[32m ====> 6. 生成服务SSL CERT ${SSL_CERT} \033[0m"
openssl x509 -sha256 -req -in ${SSL_CSR} -CA ${CA_CERT} -CAkey ${CA_KEY} -CAcreateserial -out ${SSL_CERT} -days ${SSL_DATE} -extensions v3_req -extfile ${SSL_CONFIG}
echo -e "\033[32m ====> 7. 证书制作完成 \033[0m"
echo
echo -e "\033[32m ====> 8. 以YAML格式输出结果 \033[0m"
echo "----------------------------------------------------------"
echo "ca_key: |"
cat $CA_KEY | sed 's/^/ /'
echo
echo "ca_cert: |"
cat $CA_CERT | sed 's/^/ /'
echo
echo "ssl_key: |"
cat $SSL_KEY | sed 's/^/ /'
echo
echo "ssl_csr: |"
cat $SSL_CSR | sed 's/^/ /'
echo
echo "ssl_cert: |"
cat $SSL_CERT | sed 's/^/ /'
echo
echo -e "\033[32m ====> 9. 附加CA证书到Cert文件 \033[0m"
cat ${CA_CERT} >> ${SSL_CERT}
echo "ssl_cert: |"
cat $SSL_CERT | sed 's/^/ /'
echo
echo -e "\033[32m ====> 10. 重命名服务证书 \033[0m"
echo "cp ${SSL_DOMAIN}.key tls.key"
cp ${SSL_DOMAIN}.key tls.key
echo "cp ${SSL_DOMAIN}.crt tls.crt"
cp ${SSL_DOMAIN}.crt tls.crt
- 使用参数执行上述脚本
–ssl-domain: 生成ssl证书需要的主域名,如不指定则默认为www.rancher.local,如果是ip访问服务,则可忽略;
–ssl-trusted-ip: 一般ssl证书只信任域名的访问请求,有时候需要使用ip去访问server,那么需要给ssl证书添加扩展IP,多个IP用逗号隔开;
–ssl-trusted-domain: 如果想多个域名访问,则添加扩展域名(TRUSTED_DOMAIN),多个TRUSTED_DOMAIN用逗号隔开;至少有一个和ssl-domain一样
–ssl-size: ssl加密位数,默认2048;
–ssl-cn: 国家代码(2个字母的代号),默认CN;
–ssl-date: 有效天数;
#使用示例:
./mktls.sh --ssl-domain=dburancher.sobey.com --ssl-trusted-domain=dburancher.sobey.com --ssl-trusted-ip=172.16.149.139,172.16.149.122,172.16.149.123,172.16.149.124 --ssl-size=2048 --ssl-date=3650
- 查看结果
ls -l
#可以看到
cacerts.pem #根证书,部署rancher会使用
cacerts.srl
cakey.pem
mktls.sh
openssl.cnf
tls.crt #证书,部署rancher渲染会使用
tls.key #证书密钥,部署rancher渲染会使用
uosrancher.test.com.crt #和tls.crt 是一个东西
uosrancher.test.com.csr
uosrancher.test.com.key #和tls.key 是一个东西
6.2.2.1. 将Charts仓库和镜像仓库的根证书加入到自建根证书(可选)
在使用自建rancher证书的情况下,如果Charts仓库和镜像仓库使用了其他证书,并且其他证书是从其他根证书签发,以harbor.sobey.com的证书为例,其签发根证书为rootCA.pem
那么,需要将rootCA.pem的内容加入到当前生成的根证书中
- 从渠道拿到rootCA.pem
- cat rootCA.pem | tee -a /sobey/dbu/tls/rancher/cacerts.pem
或者,用官网的说明,由于rancher要访问自定义的仓库或商店,那么需要按此附加授信CA
- 在6.3.2的2渲染charts中,增加参数
--set additionalTrustedCAs=true
- 从渠道拿到rootCA.pem(可能有多个),将其复制到一个名为ca-additional.pem的文件中
cat rootCA.pem | tee -a ca-additional.pem(如果还有多个,则依次创建)
然后在k3s中创建ca-additional密文
kubectl -n cattle-system create secret generic tls-ca-additional --from-file=ca-additional.pem=./ca-additional.pem
6.2.3. 使用已经签发好的证书(可选)
如果用户自己具备证书,那么可以使用用户提供的证书
只需要拷贝用户的证书文件和证书key文件即可。但是,需要注意:
- 证书文件必须是PEM格式
- 证书key文件必须是PKCS1格式
具体可以参考这里来处理
6.3. 准备Helm和rancher 2.4.10 charts
Helm 是安装 Rancher 高可用集群时会用到的工具。
Helm 是 Kubernetes 的软件包管理工具。Helm chart 为 Kubernetes YAML manifest 文件提供了模板语法。通过 Helm,可以创建可配置的 Deployment YAML,而不是只能用静态的 YAML。
6.3.1. 下载Helm
在每个server节点上执行
由于rancher官方推荐使用3.0以上的helm,因此在helm 3.4.0下载一个合适的版本
使用wget或curl下载对应的版本
tar -zxvf helm-v3.4.0-linux-$ARCH.tar.gz -C $target_dir
在解压目中找到helm程序,移动到需要的目录中
mv t a r g e t d i r / h e l m / u s r / l o c a l / b i n / h e l m < b r > ∗ 注意上面的 target_dir/helm /usr/local/bin/helm<br> *注意上面的 targetdir/helm/usr/local/bin/helm<br>∗注意上面的符号对应的都是要按实际情况修改的*
6.3.2. 拉取rancher charts
- 在节点外的机器上拉取rancher charts
这里我们没有创建和注册charts repo,也没有像官网所述去regsitry一个rancher的charts repo,而是直接通过URL拉取一个完整的rancher-charts到本地后使用
- 在任意一个可以上网的环境中,安装helm
- helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
- helm pull rancher-stable/rancher --version 2.4.10
- 将上述下载好的2.4.10 rancher charts tar文件,拷贝到在6.1拉取镜像的时候创建好的/sobey/rancher_install中
cp xxxx.tar.gz /sobey/rancher_install/
- 然后开始渲染charts
进入对应的目录,执行helm命令
cd /sobey/rancher_install
#按照官方说明,渲染charts模板
helm template rancher ./rancher-<VERSION>.tgz --output-dir . \
–namespace cattle-system \
–set hostname=<RANCHER.YOURDOMAIN.COM>
–set rancherImage=<IMAGE> \
–set rancherImageTag=<IMAGE_VERSION> \
–set ingress.tls.source=secret \
#【注意】,如果是使用已经签发的证书,这里【不设置】privateCA
–set privateCA=true \
#这个参数特别说明一下,如果是测试环境,可以考虑不设置。但是生产环境还是应该设置好。其作用
#就是设置rancher的system-default-registry。
#按理说生产环境的镜像库,应该包含所有需要的镜像,rancher管理的k3s默认会从镜像库地址拉取镜像,除非本地有对应的镜像
#如果不设置,那么就是从hub.docker.com拉取,除非本地有对应的镜像
–set systemDefaultRegistry=<REGISTRY.YOURDOMAIN.COM:PORT>
–set useBundledSystemChart=true
PS: set参数的时候,提醒一下,注意6.2.2.1. 中的内容
占位符 | 描述 |
---|---|
<VERSION> | Rancher 版本,这里是2.4.10 |
<RANCHER.YOURDOMAIN.COM> | 官方叫负载均衡器对应的 DNS,也就是6.2中rancher集群证书的域名,默认是dburancher.sobey.com |
<REGISTRY.YOURDOMAIN.COM:PORT> | 私有镜像库对应的 DNS,参见5.2,我们默认是images.sobey.com:5000 |
<IMAGE> | Rancher镜像名,官方给出的是<REGISTRY.YOURDOMAIN.COM:PORT>/rancher/rancher,因为它是从私有镜像库拉取,而我们因为在6.1中已经导入了rancher镜像,同时我们也没有在6.1中执行这里要求的推送镜像到私库,因此这里直接写导入到本地的镜像 |
<IMAGE_VERSION> | Rancher镜像版本,这里是v2.4.10。在6.1中设置了这个tag。当然,也可以不设置,直接指定为实际的tag |
一个完整的样例:helm template rancher ./rancher-2.4.10.tgz --output-dir . --namespace cattle-system --set hostname=dburancher.sobey.com --set rancherImage=rancher/rancher --set rancherImageTag=v2.4.10 --set ingress.tls.source=secret --set privateCA=true --set systemDefaultRegistry=images.sobey.com --set useBundledSystemChart=true
完成以后,在当前目录应该看到一个rancher目录,里面有生成的templates/各种yaml
6.4. 正式安装rancher
6.4.1. 在K3S中创建rancher的命名空间
在任意一个server节点中执行
k3s kubectl create namespace cattle-system
6.4.2. 设置rancher server的证书
参考官方说明,设置6.2中准备好的证书
在任意一个server节点中执行
#设置证书
k3s kubectl -n cattle-system create secret tls tls-rancher-ingress --cert=/sobey/dbu/tls/rancher/dbu_rancher_crt.crt --key=/sobey/dbu/tls/rancher/dbu_rancher_crt.key
#设置根证书
cp /sobey/dbu/tls/rancher/rootCA.crt /sobey/dbu/tls/rancher/rootCA.pem
k3s kubectl -n cattle-system create secret generic tls-ca --from-file=cacerts.pem=/sobey/dbu/tls/rancher/rootCA.pem
6.4.3 最后一步,安装rancher
进入6.1创建的/sobey/rancher_install目录
此目录在6.3.2还拉取了charts,并且生成了最终的包含所有yaml的rancher目录
在任意一个节点上操作
cd /sobey/rancher_install
k3s kubectl -n cattle-system apply -R -f ./rancher
最后的检查
k3s kubectl -n cattle-system rollout status deploy/rancher
#应该显示如下信息
Waiting for deployment “rancher” rollout to finish: 0 of 3 updated replicas are available…
Waiting for deployment “rancher” rollout to finish: 1 of 3 updated replicas are available…
Waiting for deployment spec update to be observed…
Waiting for deployment “rancher” rollout to finish: 1 of 3 updated replicas are available…
Waiting for deployment “rancher” rollout to finish: 2 of 3 updated replicas are available…
deployment “rancher” successfully rolled out
k3s kubectl get pods --namespace=cattle-system
#应该看到类似的信息
NAME READY STATUS RESTARTS AGE
rancher-7d688cbccb-9cldj 1/1 Running 1 5m54s
rancher-7d688cbccb-5jlcb 1/1 Running 0 5m54s
rancher-7d688cbccb-5zcmt 1/1 Running 0 5m54s
6.4.4. 验证
打开浏览器,设置hosts指向 dburancher.sobey.com(这是6.2证书的域名),访问rancher界面
如果要达成通过IP直接访问rancher,那么此时请不要配置任何rancher界面上的内容,直接看下面6.5
6.5. 配置通过IP直接访问多节点rancher(可选)
某些情况下,我们希望可以通过IP(比如VIP)直接访问rancher,而不需要配置域名。
我们可以通过配置L4负载均衡的方式来达成
在+7这一章节,我们可以知道,K3S通过L4负载均衡(svclb)可以直接开放引导主机流量到集群中
因此,如果需要直接通过IP访问,我们可以创建一个L4负载均衡
apiVersion: v1
kind: Service
metadata:
annotations:
field.cattle.io/targetDnsRecordIds: '["cattle-system:rancher"]'
labels:
cattle.io/creator: rancheripl4
name: traefik-ip-entrypoint-l4
namespace: cattle-system
spec:
externalTrafficPolicy: Cluster
ports:
- name: http
port: 30080
protocol: TCP
targetPort: 80
- name: https
port: 30443
protocol: TCP
targetPort: 443
sessionAffinity: None
type: LoadBalancer
拷贝以上内容,到某个主机的目录中,比如 ~/service-rancher-ip.yaml
注意,其中可能会修改的地方,是port字段。它表示通过IP的哪个端口来访问rancher
然后,在该主机上执行:
k3s kubectl apply -f ~/service-rancher-ip.yaml
如果正常,k3s会创建一个l4负载均衡,并且将主机的30080和30443引导到rancher的集群服务上。
6.5.1. 验证
打开浏览器,输入 http://${VIP}:30080
,访问rancher界面
7. 设置keepalived检测脚本
在3.2中,安装keepavlived,预留了一个keep_check.sh脚本。
这里我们需要设置这个检查脚本,用于keepalived的检测切换,何海强给了我们一段脚本
在每台server节点上执行(或scp拷贝)
vi /sobey/dbu/keep_check.sh
#!/bin/bash
KA_CHECK=$(ps -A -o pid,cmd|grep "keep_check.sh"|grep -v $$|grep -v grep|wc -l)
if [ "$KA_CHECK" -gt "1" ]; then
exit 0
fi
bin=$(cd $(dirname $0); pwd)
LOG_FILE="$bin/ka_check.log"
CONTAINER_NAME="k3smysql"
MYSQL_HEALTH_STATUS=$(docker inspect --format '{{.State.Health.Status}}' $CONTAINER_NAME)
if [ "$MYSQL_HEALTH_STATUS" = "healthy" ]; then
K3S_HEALTH_STATUS=$(systemctl is-active k3s)
if [ "$K3S_HEALTH_STATUS" = "active" ]; then
COMPONENT_HEALTH_STATUS=$(kubectl get cs|awk '/Healthy/{print $2}'|wc -l)
if [ "$COMPONENT_HEALTH_STATUS" != "2" ]; then
echo "$(date):
$(kubectl get cs)" >>$LOG_FILE
exit 1
fi
else
echo "$(date): K3S_HEALTH_STATUS = $K3S_HEALTH_STATUS" >>$LOG_FILE
exit 1
fi
else
echo "$(date): MYSQL_HEALTH_STATUS = $MYSQL_HEALTH_STATUS" >>$LOG_FILE
exit 1
fi
8. cattle-cluster-agent和cattle-node-agent几乎一定会处理的问题
8.1. 域名解析问题
我们看到cattle-cluster-agent和cattle-node-agent工作负载不能正常启动
从日志上看到,ERROR: https://xxxx/ping is not accessible (Could not resolve host: rancher.my.org)
或者,我们看到某些配置的域名无法访问,比如应用商店里面配置了一个harbor.sobey.com,无法连接,这些都是域名解析导致。
一般来说是这个地方导致的问题可以参照解决。
或者,点击工作负载的“编辑”—>“显示高级选项”–>“网络”—>手动设置hosts映射,将dburancher.sobey.com正确的映射到VIP地址上
但是,最好的一个办法是:
1、打开rancher,找到System下面的coredns工作负载。
2、可以看到coredns工作负载关联了一个coredns配置映射(config-map)。或者直接从“资源”–>“配置映射”中找到它
3、修改这个coredns的配置映射中的NodeHosts配置项,类似hosts文件一样修改它即可
这样,整个集群内,都可以通过此coredns进行域名解析
8.2. Ingress导致的证书解析错误
Traefik Ingress导致的证书问题
经过1的处理,在日志中看到
Issuer of last certificate found in chain does not match with CA certificate Issuer......
cattle-cluster-agent Server certificate is not valid......
并且日志堆栈中显示了一个压根儿没见过的CA信息
原因是因为默认开启了Traefik(安装的时候没有–disable Traefik)——在命名空间kube-system工作负载列表中可以看到部署了Traefik。
Traefik默认接管了K3S的L4入口,官网这里进行了说明,这里在介绍集群外部负载均衡入口配置的时候也说明了,因此,集群内部会通过此入口进行80和443的流量处理。
根据其yaml可以看到,它关联了一个名为 traefik-default-cert的SSL配置
- configMap:
defaultMode: 420
name: traefik
name: config
- name: ssl
secret:
defaultMode: 420
secretName: traefik-default-cert
status:
正因为这个SSL配置的证书信息并没有指定为我们自己的证书,而内部的通讯走的是集群内部的80和443,也就是经过Traefik,因此提示了证书问题导致无法启动。
处理方法:
#删除现有的 traefik-default-cert
k3s kubectl -n kube-system delete secret traefik-default-cert
#重新关联证书(这里的证书是6.2准备的)
k3s kubectl -n kube-system create secret generic traefik-default-cert --from-file=tls.crt=/sobey/dbu/tls/rancher/dbu_rancher_crt.crt --from-file=tls.key=/sobey/dbu/tls/rancher/dbu_rancher_crt.key
或者,手动拷贝crt和key的内容,在rancher中点击“资源”—>“密文”,找到traefik-default-cert进行修改
完成以后,在工作负载中重新部署Traefik
、catlle-cluster-agent
、cattle-node-agent
8.3. 某些CA证书无法验证,报X509错误
某些情况下,比如public证书过期了,甚至于,我们就想用自己的自签名证书
会看到容器中报错类似:X509: unknown autority zzzzzz
处理办法:
1、将
CA
证书内容(注意,是CA证书,也就是根证书),拷贝到/etc/kubernetes/ssl/certs/serverca
文件中
2、编辑cattle-cluster-agent
,参考cattle-node-agent
的数据卷:k8s-ssl
手动配置数据卷
3、编辑cattle-cluster-agent
和cattle-node-agent
,删除环境变量
中的CA_CHECK_SUM
这样即可解决SSL证书验证问题
结束
至此,基于Mysql主主的双节点高可用K3S+Rancher集群就部署完成了
+1:完全离线安装
上面的整个过程,多少都利用了在线处理。
如果要完整的离线安装,主要是通过这几个点来达成:
- 但凡需要yum install的地方
【联网机】---->yum install---->【rpm包】---->copy---->【不能联网机】---->yum localinstall
以nginx举例,创建一个你喜欢的目录,我这里是
mkdir -p /usr/local/rpms/nginx
下载包
yum install --downloadonly --downloaddir=/usr/local/rpms/nginx nginx
将下载的包拷贝到目标机/usr/local/rpms/nginx/
yum localinstall /usr/local/rpms/nginx/*.rpm
- 但凡需要docker pull的地方
方法一)和上面相似,先到一个联网机"docker pull需要的镜像",然后"docker export这个镜像",拷贝镜像到目标机,在目标机上执行"docker load < 镜像"
方法二)利用一个私有,可访问的Harbor作为镜像库
- 但凡是wget或curl下载的,在联网机下载好以后拷贝即可
+1.1. 已经准备好的离线包(以标准centos为例,UOS特殊处理)
可以从DBU开发人员那里拿到离线包,离线包包含如下内容:
/1.yum-utils
;/2.docker
;/3.etcd
;/4.k3s
;/5.rancher
安装方式
- yum localinstal -y /1.yum-utils/*.rpm
- yum localinstal -y /2.docker/*.rpm
- yum localinstal -y /3.etcd/*.rpm,参考2.1 安装etcd进行etcd安装
- 使用/4.k3s目录中的内容,参考4. 安装K3S进行k3s的安装
- 使用/5.rancher目录中的内容,参考6. 高可用安装rancher进行rancher的安装。
5.1. 其中helm相关内容在/5.rancher/helm中
5.2. 另外注意,由于离线包中已经存在rancher-images.tar.gz,因此,只需要docker load即可
+2:在K3S集群加入一个Agent节点
由于我们是采用的
创建双主机K3S-->K3S部署rancher
这种方式构建的部署方案,按照官方的说法,这仅仅是“高可用部署rancher”而已。也就是说,相当于我们为了部署一个高可用的rancher,所以部署了一个K3S而已。
按照官方建议,应该是用这个高可用的rancher,重新去创建一个新的集群来作为运行时集群
相当于
(Rancher【on K3S】)---->manage—>(new Cluster)
然而,我们在我们面对的一般项目中,更希望一体化运行,也就是
(Rancher【K3S】)-------
^ |
|_______
因此,我们目前需要手动的添加Agent节点到集群中
+2.1. 节点环境准备
准备一个节点,然后安装必须的东西
- 执行本文“1. 准备工作”中的所有内容
- 写入VIP域名解析
echo -e “xxxx.xxx.xx.xx \t dburancher.sobey.com” | tee -a /etc/hosts
- 将本文“4. 安装K3S”中在server节点上放置的的
k3s.sh
、K3S
、k3s-airgap-images-$ARCH.tar
文件拷贝过来(因为我们一般在root目录下操作,所以先放到这里面)
scp root@172.16.149.122:/root/* /root/
- 将文件放置到目标位置,并做比较要的步骤处理
cp /root/k3s /usr/local/bin/
chmod +x /usr/local/bin/k3s
mkdir -p /var/lib/rancher/k3s/agent/images/
cp ./k3s-airgap-images- A R C H . t a r / v a r / l i b / r a n c h e r / k 3 s / a g e n t / i m a g e s / d o c k e r l o a d < / v a r / l i b / r a n c h e r / k 3 s / a g e n t / i m a g e s / k 3 s − a i r g a p − i m a g e s − ARCH.tar /var/lib/rancher/k3s/agent/images/ docker load < /var/lib/rancher/k3s/agent/images/k3s-airgap-images- ARCH.tar/var/lib/rancher/k3s/agent/images/dockerload</var/lib/rancher/k3s/agent/images/k3s−airgap−images−ARCH.tar
yum install -y container-selinux selinux-policy-base(可选,如果安装报相应的错误,就按此处理)
yum install -y https://rpm.rancher.io/k3s/stable/common/centos/7/noarch/k3s-selinux-0.2-1.el7_8.noarch.rpm(可选,如果安装报相应的错误,就按此处理)
5(可选). load必要的镜像
如果6.1中推送了私库,那么本操作跳过。
如果在本文“6.1”中,没有推送镜像到私库,那么,将server节点上准备好的/sobey/rancher_install/rancher-images.tar.gz拷贝过来,然后load。
mkdir -p /sobey/rancher_install/
scp root@172.16.149.122:/sobey/rancher_install/rancher-images.tar.gz /sobey/rancher_install/rancher-images.tar.gz
docker load < /sobey/rancher_install/rancher-images.tar.gz
#针对6.1红色字体部分,如果没有上传相应的镜像到私有库,那么就只有拷贝,如果没有拷贝,那么就获取Failed List按红色字体说明执行一次
- 按照本文“5.2”的步骤,配置镜像库
#拷贝签名文件和根证书
mkdir -p /sobey/dbu/tls
scp root@172.16.149.122:/sobey/dbu/tls/* /sobey/dbu/tls/
#编辑K3S证书配置信息
mkdir -p /etc/rancher/k3s
vi /etc/rancher/k3s/registries.yaml
mirrors:
docker.io:
endpoint:
- "https://images.sobey.com:5000"# 私有镜像库地址
configs:
"images.sobey.com:5000":
auth:
username: admin # 这是私有镜像仓库的用户名
password: sobeyhive # 这是私有镜像仓库的密码
tls:
cert_file: /sobey/dbu/tls/ficus_crt.crt # 镜像仓库中使用的cert文件的路径。
key_file: /sobey/dbu/tls/ficus_crt.key # 镜像仓库中使用的key文件的路径。
ca_file: /sobey/dbu/tls/rootCA.crt # 镜像仓库中使用的ca文件的路径
- 如果是内网环境,并且没有DNS服务,那么需要手动修改hosts
echo -e “xx.xx.xx.xx \t images.sobey.com” | tee -a /etc/hosts
+2.2. 启动Agent节点
- 获取token
参考官网说明,获取token
scp root@172.16.149.122:/var/lib/rancher/k3s/server/node-token /root/k3s_server_token
- 启动Agent
cd root
INSTALL_K3S_SKIP_DOWNLOAD=true K3S_TOKEN_FILE=‘/root/k3s_server_token’ K3S_URL=‘https://dburancher.sobey.com:6443’ INSTALL_K3S_EXEC=‘agent --docker --kubelet-arg=max-pods=200’./k3s.sh
其中–kubelet-arg=max-pods=200参考:4. 安装K3S 这一节的说明
- 打节点标签(可选)
标签根据实际情况打不同的标签
k3s kubectl label nodes [节点名] env-executor=true env-java-executor=true env-python-executor=true env-python-ai-executor=true env-java-media-executor=true
+3. 更换rancher的默认镜像库地址
在某些情况下,可能会更换rancher的镜像库地址。
- 修改每个主机的hosts文件,IP指向正确的镜像库域名
- 在rancher中找到rancher的工作负载,“编辑”–>“修改环境变量”,将CATTLE_SYSTEM_DEFAULT_REGISTRY修改为正确的镜像库域名(或者删除——参见6.3.2helm命令部分的说明)
+4. 删除rancher
某些情况下可能会删除rancher,操作方式
1、根据这里的说明,下载对应的system-tools
2、在某个机器上操作
如果这个机器是server节点以外的机器,则先拷贝节点的/etc/rancher/k3s/k3s.yaml
到准备好的路径
./system-tools remove --kubeconfig <KUBECONFIG>
其中KUBECONFIG就是/etc/rancher/k3s/k3s.yaml
拷贝后的路径
3、彻底清除kubernetes的namespace
2执行以后,通过 k3s kubectl get namespaces
,看到对应的namespace还是Terminating状态
此时,在server节点上执行
KUBE_EDITOR=“vi” kubectl edit namespaces <namespace>
其中 <namespace>是需要删除的 namespace
找到
finalizers:
- controller.cattle.io/namespace-auth
将其改为
finalizers: []
保存即可,此时将删除namespace
如果上述处理删除不掉,则通过终极大法:
- k3s kubectl get namespace <namespace-to-delete> -o json > tmp.json
- vi tmp.json,删除任何"finalizers"里面的"kubernetes"
#开启一个代理终端,主要是避免环境变量问题- k3s kubectl proxy
#应该会看到Starting to serve on 127.0.0.1:8001- 打开另一个ssh终端
#在新打开的终端执行- curl -k -H “Content-Type: application/json” -X PUT --data-binary @tmp.json http://127.0.0.1:8001/api/v1/namespaces/annoying-namespace-to-delete/finalize
+5. 修改ETCD节点信息
某些情况下,可能要切换ETCD地址,比如主机IP变更。
假设变更的节点为etcd1
操作方式:
- 列出etcd节点
etcdctl member list
可以看到
eabc202e74d53d3: name=etcd3 peerURLs=http://172.16.149.124:2380 clientURLs=http://172.16.149.124:2379 isLeader=false
8fa08b2e4744707e: name=etcd1 peerURLs=http://172.16.149.128:2380 clientURLs=http://172.16.149.128:2379 isLeader=false
e50821dfde62301e: name=etcd2 peerURLs=http://172.16.149.123:2380 clientURLs=http://172.16.149.123:2379 isLeader=true
- 删除etcd1
etcdctl member remove 8fa08b2e4744707e
- 在etcd1上停止etcd服务
systemctl stop etcd
- etcd1的IP改好以后,重新加入节点
在etcd2或etcd3上操作
etcdctl member add etcd1 http://xxxxxx:2380
此时,会看到一些要求你配置的信息
-
参考4中给出的信息,修改etcd1的
/etc/etcd/etcd.conf
-
重启etcd1的etcd服务
+6. 修改K3S_DATASTORE_ENDPOINT
因为+5
的原因,或某些其他原因,比如要切换一个ETCD集群,或完全切换为Mysql
我们需要修改K3S_DATASTORE_ENDPOINT
修改方式:
vi /etc/systemd/system/k3s.service.env
修改里面的存储地址
systemctl restart k3s
+7. 高可用安装情况下修改80和443端口(本章节网上找不到,纯属原创精华)
如果是单机安装,直接docker的-p就可以解决,但是高可用部署,由于是部署在K3S环境中,因此,不能简单的处理。必须通过修改K3S集群的流量控制入口(说白了,就是Ingress和LoadBanlencer)来处理。
这里,必须先搞清楚(我花了很多时间搞清楚)K3S的流量控制艺术,在搞清楚艺术之前,还得了解Ingress和IngressController,针对Ingress和IngressController,写的最好的文章是我认为写的最好的一篇。
有了Ingress和IngressController的认知之后,我们来看K3S的流量艺术。
- K3S默认会安装Traefik作为IngressController,接管集群内80和443的流量。如果看到写的最好的文章,我们就知道,一般情况下,其实IngressController本身并不会(除非特殊的启用hostPort)并不会在主机上监听端口,它依然属于集群内部。
- 从写的最好的文章我们知道,让IngressController能够对外服务,可以有三种做法:1)给IngressController开一个NodePort服务;2)IngressController作为DaemonSet部署,暴露hostPort;3)给IngressController暴露一个LoadBalancer服务;
其实说白了,就是想办法让IngressController这个容器,能够对外暴露服务端口。
不过,K3S没有采用上面三种做法,它使用了一个特别的办法,在官网我们可以得知(官网中文翻译根本看不懂,难啃),它采用了DaemonSet部署特殊的Klipper Load Balancer进程的方式,来给Traefik Ingress Controller提供流量导入
。 - 2所述的流量导入,可以简单图解为:
[client]----->(主机port)<—iptables监听—>[DaemonSet-Klipper]—iptables转发—>[集群内Traefik]
也就是说,K3S通过在每个节点部署Klipper,然后以iptables路由的方式,将节点流量转发到内部的IngressController。 - 我们可以在节点中通过
k3s kubectl get svc -n kube-system
k3s kubectl get pods -n kube-system
k3s kubectl get daemonset -n kube-system
k3s kubectl edit daemonset svclb-traefik -n kube-system
逐一验证2中所述的官网描述以及通过写的最好的文章所了解到的信息
有了上面的艺术刨析,我们就知道,端口的改造,重点是修改 Daemonset:svclb-traefik,我们从Klipper的github核心文件可以了解到,它是通过iptables来处理流量的。里面使用了一些环境变量来设置入口端口和转发信息
于是:
- k3s kubectl edit daemonset svclb-traefik -n kube-system
- 修改里面的环境变量端口以及容器端口,主要是环境变量部分
- 等待相关POD自动更新
或者,因为了解了刚才的艺术过程。
同样是在官网-ServiceLB如何工作这一节,我们可以得知——由于它使用了
Klipper Load Balancer
,因此,你在K3S上创建一个L4负载均衡(即type: LoadBalancer服务)
,K3S会自动启动一个Klipper Load Balancer,在主机上打开L4负载均衡中设置的服务端口,通过iptables转发你的请求到这个L4负载均衡上面,然后由L4负载均衡再转发到配置的内部端口上。基于这个信息,那么
- 打开服务发现,创建一个L4负载均衡,其目标选择POD:traefik
- 设置L4负载均衡的服务端口为需要的端口
- 保存,等待K3S自动构建svclb-traefik-xxxx
+8. 在Rancher上手动创建Ingress
注意: 此部分前提条件是,集群中部署了IngressContorller且正常运行。
如果是按照此文档部署K3S,默认情况下,会安装Traefik作为IngressContorller。
此时,假设我们要对minio进行Ingress路由发布,操作方式如下:
1、确认minio所在的命名空间
假设命名空间为:minio-ha
2(可选)、为此命名空间安装证书
k3s kubectl -n minio-ha create secret tls ypt-ingress --cert=/root/cert/tls.crt --key=/root/cert/tls.key
其中,minio-ha
是命名空间,ypt-ingress
是证书名(可按实际情况随意起名),后面的路径是6.4.2中安装的证书相关文件,应该在节点上
3、登录rancher
3.1、进入项目
3.2、选择工作负载
—>选择负载均衡
—>添加规则
3.2、设置对应的名称
3.3、选择minio所在的命名空间,这里是minio-ha
3.4、选择自定义域名
---->填写安装集群时证书对应的域名
3.5、添加规则
—>填写合适的路径,比如/minio
。选择正确的服务或pod,以及端口
3.6、展开SSL/TLS证书
—>如果2设置了证书,则选择该证书
3.7、标签
可不设置,或按情况设置
至此,集群外可以用过 https://域名:端口/minio
访问到minio的服务
特别说明:
默认情况下,Ingress规则会将路由地址(比如上面的/minio)直接转发到后端服务,如果有些服务必须使用“根路径”或“特别路径”访问,比如minio只能识别/index
那么,处理办法是:
在annonation(也就是“注释”)中,添加一个注释:
traefik.ingress.kubernetes.io/rewrite-target: /index
其中traefik是IngressController的名称(意思是也可能是nginx)
+9. 修改max-pods
如果启动K3S的时候没有指定max-pods(默认110),那么可以手动修改
在需要修改的每个节点上执行
- systemctl stop k3s
- vi /etc/systemd/system/k3s.service
这里假设需要修改为200个- 修改 ExecStart=/usr/local/bin/k3s server --docker --kubelet-arg max-pod=200
- systemctl daemon-reload
- systemctl start k3s
其中参数 --kubelet-arg 是官网提供的参数,其正确格式可以从这里和这里参考
+10. IP修改后,以灾难恢复方式重建ETCD
某些情况下,节点的IP被改变了,此时需要重建ETCD
主要参考官网说明,这里我把完整的试错后的经验记录下来
1、重新启动ETCD单节点
因为此时etcd已经无法正常启动,必须先从一个节点以灾难恢复方式重启
- 在准备恢复的节点上修改/etc/etcd/etcd.conf,ETCD_INITIAL_CLUSTER去掉其他节点的信息,只保留当前节点的新IP信息
并且将里面的所有与IP内容相关的内容修改为正确的新IP- 修改/usr/lib/systemd/system/etcd.service,在ExecStart中,加入
--force-new-cluster
参数- systemctl daemon-reload && systemctl start etcd
如果一切正常,ETCD会启动。可通过etcd member list查看情况
2、修改当前节点的peerURLs配置信息
- ETCDCTL_API=3 etcdctl member update {上一步etcd member list得到的memberid} --peer-urls=http://新的地址:2380
- 修改/usr/lib/systemd/system/etcd.service,在ExecStart中去掉
--force-new-cluster
- systemctl stop etcd
- systemctl daemon-reload && systemctl start etcd
至此,新的ETCD单节点就重建成功
3、重新加入其他etcd节点
- 在本节点上执行ETCDCTL_API=3 etcdctl member add {etcdname} --peer-urls=http://{加入节点的地址}
- 拿到上一步返回的环境变量
在前其他ETCD节点上,修改各自的/etc/etcd/etcd.conf,将里面的所有与IP内容相关的内容修改为正确的新IP
将得到的环境变量修改到/etc/etcd/etcd.conf对应的地方- 在其他ETCD节点上rm -fr /var/lib/etcd/* && systemctl start etcd
4、修改所有节点的配置
依次修改每个节点的/etc/etcd/etcd.conf,将其ETCD_INITIAL_CLUSTER修改为完整的节点信息
依次重启
+11. 修改k3s-serving证书有效期为10年(或自定义时间)
由于k3s默认的证书有效期是1年,官方有说明 如何更换
不过,按官方更换,无法生效,应该参考这里
# 在某个节点执行
kubectl --insecure-skip-tls-verify=true delete secret k3s-serving -n kube-system
# 在所有节点执行
rm -rf /var/lib/rancher/k3s/server/tls/dynamic-cert.json
systemctl restart k3s
这样对于长期项目的维护不方便。因此,这里提供了一个生成新证书的手段,来处理这个事情
操作方式:
- 进入rancher,找到
集群->system->证书列表->k3s-serving
- 点开
k3s-serving
,拷贝域名
中的所有内容做准备- 使用6.2.2章节所使用的证书制作脚本,开一个新目录执行该脚本。其中参数要注意
–ca-key,指定k3s的根证书key,默认文件在 /var/lib/rancher/k3s/server/tls/server-ca.key
–ca-cert,指定k3s根证书,默认在 /var/lib/rancher/k3s/server/tls/server-ca.crt
–ssl-domain,需要指定为’k3s’
–ssl-trusted-domain,需要指定为第二步拷贝的内容中,除了k3s的所有域名
–ssl-trusted-ip,需要指定为第二步拷贝的内容中的所有ip样例参考为:./mktls.sh --ssl-domain=k3s --ssl-trusted-domain=kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster.local,localhost --ssl-trusted-ip=10.43.0.1,127.0.0.1,172.16.148.200,172.16.148.201,172.16.148.203,172.16.148.204 --ssl-size=2048 --ssl-date=3650 --ca-key=./CAK.key --ca-cert=./CA.crt
- 编辑
k3s-serving
,把生成的key和pem内容,更新对应的内容
至此,就完成了证书更新,妈妈再也不用担心k3s过期了