2023年3月

ingress 暴露服务

在上一篇中,我们部署了一个 Go 应用,在这一小节中,我们将增加其副本并且做负载均衡。

在最开始我们一共有三台节点,其中一台跑 Rancher,一台 Master 和一台 Node,既然是负载,那肯定是需要将 pod 运行在两个节点上,所以我们需要新增一个主机节点,由于我的电脑内存即将吃紧所以对其配置进行了调整。

机器ip配置备注
CentOS7192.168.0.1992cpu 4G ramRancher
CentOS7192.168.0.2102cpu 4G ramMaster
CentOS7192.168.0.2112cpu 2G ramNode
CentOS7192.168.0.2121cpu 2G ramNode

我的那一台电脑一共是有 16G 已经无法再增加节点了,所以我们为了模拟多节点,我们只能通过削减其他虚拟机的配置空闲出来一些资源,然后新建一个虚拟机。

我们重复第一章的内容,然后将其加入节点。

2023-03-04T12:00:55.png

我们找到集群,然后点击编辑,在页面的最下方,还有增加节点的方法。

2023-03-04T12:01:05.png

2023-03-04T12:01:13.png

当皆甜增加完成后,我们来调整在上一章节中部署的 goapi 应用。

2023-03-04T12:01:26.png

我们 Deployment 部署位 2 个 Pods,同时将端口映射修改为了 NodePort

2023-03-04T12:01:36.png

我们可以看到在两个节点上都调度了 pod,但是出现了报错,这是因为在 worker 宿主机上没有我们设置的目录,我们只需要将可执行文件以相同位置上传上去即可,后续更好的解决方案肯定是 CICD,我会在后面的章节进行讲解。

2023-03-04T12:01:55.png

上传完成后,很快就完成了部署。

2023-03-04T12:02:05.png

由于节点选择的事 NodePort 我们只能通过节点的 IP 地址来对应用进行访问,这很明显不是我们想要的效果,我们一般对外提供服务都是使用域名的形式,然后通过反向代理进行负载均衡到我们的后台计算节点。

在 k8s 中如果想要实现这一效果我们就需要使用 ingress 对外暴露我们的服务。

Ingress 相当于一个 7 层的负载均衡,我们可以理解为是一个反向代理并定义规则的一个 api 对象。Ingress Controller 通过监听 ingress api 转换为各自的配置(常用的有 nginx-ingress,trafik-ingress)。

我们点击负载均衡,然后添加规则。

2023-03-04T12:02:15.png
2023-03-04T12:02:35.png

k8s 为我们提供了一个域名后缀,但是我们通常不会使用,我们来使用自定义域名,其中端口号就是我们要暴露的 80 的端口,我们对外访问的时候,选择的也是这个。

由于是在虚拟集中创建的集群,所以我们绑定域名最简单的方案是修改本地 host 文件,域名直接指向任意一个 worker 节点(Ingress 通过边缘节点对外提供服务,所以如果在生产环境,建议利用 keeplived + lvs 对外提供服务,避免单点故障)。

# maksim.website vitralbox
192.168.0.211 goapi.maksim.website

新件号 ingress 后我们等待完成状态。

2023-03-04T12:02:50.png

2023-03-04T12:02:58.png

2023-03-04T12:03:07.png

我们特意将 woker2 节点上的代码进行了修改,为的就是能够演示出 worker 的样子。

配置 SSL 证书

我们的线上服务一般都会有配置证书的需求,在 Rancher 中配置证书非常容易,我们只需要在资源中选择密文,在选择证书,添加证书即可。

2023-03-05T08:16:05.png

这里需要注意,我们需要进入到 project 下才可以看到资源文件夹。

2023-03-05T08:16:15.png

作用域我们需要注意,这里选择为整个项目或者单个命名空间生效,在这里,我们选择了 myweb。

证书的神情,可以到阿里云免费的 SSL 证书。

添加完证书后,我们修改 goapi 的负载均衡,找到 SSL/TLS 证书选项卡,点击添加证书。

2023-03-05T08:16:33.png

2023-03-05T08:16:51.png

选择我们的证书后,填写对应的域名。点击保存。

2023-03-05T08:15:21.png

当我们访问后就会发现证书已经生效了,在浏览器中显示以增强安全性。

路径重写

当我们要去做路径重写的时候,其实只需要做两项配置即可,如果在 nginx 中我们还需要修改配置文件,然后在 reload,其实 k8s 中的重写和 nginx 基本一致,因为其底层使用的就是 nginx。

例如我们的 goapi这个项目,如果我们想通过 https://goapi.maksim.website/api 来访问我们的接口。我们可以像下面这样操作。

2023-03-05T08:31:25.png

我们先是增加重写规则,表示将 /api/转发到项目上 (.*)代表了分组,也就是我们的重写部分,然后在标签和注释中增加注释。

2023-03-05T08:31:51.png

nginx.ingress.kubernetes.io/rewrite-target = /$1

我们去访问项目。

2023-03-05T08:32:03.png

这个时候我们发现已经是 404 状态了,增加 /api/ 再来看一下。

2023-03-05T08:32:12.png

项目可以访问了。

我们要部署的程序很简单,我们使用 gin 对外提供一个接口返回 helloworld。

2023-03-04T09:50:41.png

然后利用交叉编译生成 go 的执行文件。

2023-03-04T09:51:19.png

我们在 ide 中点击开始按钮后,自动的帮我们生成了myserver可执行文件,我们将这个文件上传到 work 节点的 /data/k8s-volume/myapp 目录下。

scp build/myserver [email protected]:/data/k8s-volume/myapp

2023-03-04T09:51:33.png

接下来,我们来部署 GoAPI,我们还是点击部署工作负载。

2023-03-04T09:51:45.png

我们现将 workloads 的基础信息填写上。

2023-03-04T09:52:04.png

这一次我们选择 HostPort 直接将容器的端口与所在节点的端口进行映射,这种模式下和我们 docker -p xx:xx 的效果是一样的。

和 docker 一样,我们也可以将容器内的目录映射到宿主机上,在这里我们选择主机映射。

2023-03-04T09:52:23.png

通过配置,我们将容器 /app 目录下的内容映射到我们的宿主机上,目前我们只有一个 work 节点。

因为我们是吧运行程序上传到了服务器上,所以我们需要利用 k8s 来帮助我们的容器。

2023-03-04T09:52:33.png

这一步其实就相当于我们的 docker run。

Untitled

点击部署后,我们需要等待片刻。

如果部署失败,我们可以点进工程内进行查看失败原因。

2023-03-04T09:52:56.png

在事件中显示了失败原因,在拉取apline 的时候出现失败。原来是我们的镜像名写错了,那么修改镜像名称。

2023-03-04T09:53:10.png

修改后,将会新的 pod 来替换老 pod。

2023-03-04T09:53:23.png

好了,现在已经部署成功了,我们来进行访问。

2023-03-04T09:53:35.png
2023-03-04T09:53:48.png

我们再来尝试,192.168.0.210:8080 能否访问。

2023-03-04T09:54:12.png

我们可以看到 Master 节点是不会转发这次请求的,这就是 NodePort 和 HostPort 的区别。

本文的目的是帮助开发者快速了解 基于 Rancher 的 k8s 管理以及部署工作,我们将介绍 Rancher2.x 的基本使用,目前暂不涉及运维层面,请不要将这个文章中所涉及的内容直接搬运到生产环境,毕竟部署起来和稳定运行时两回事,

k8s 本身部署还是很复杂的,部署起来会碰到很多坑,如果使用 Rancher 那就特别简单了,即使你不去特意学习 k8s 也能部署。

先说一下环境,我们先准备三台虚拟主机,如果有钱的话,也可以买两台服务器,我这里使用的是 17 年生成的小米 Pro 笔记本,I7 处理器,16G 内存,已经满足了试验环境的搭建。

机器ip配置备注
CentOS7192.168.0.1992cpu 4G ramRancher
CentOS7192.168.0.2102cpu 4G ramMaster
CentOS7192.168.0.2112cpu 4G ramNode

这里建议一台机器专门跑 Rancher ,跑 k8s 的节点,最好配4G 以上的内存,要不然会很卡。这三台节点,需要内网可以进行访问。

我们接下来开始准备工作,在每个节点上分别执行下面的命令

#0. 安装必备软件
yum -y install wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo ntp libaio-devel wget vim ncurses-devel autoconf automake zlib-devel  python-devel epel-release openssh-server socat  ipvsadm conntrack ntpdate
#1. 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
#2. 关闭 SElinux
sed -i  's/SELINUX=enforcing/SELINUX=disabled/'  /etc/sysconfig/selinux
sed -i  's/SELINUX=enforcing/SELINUX=disabled/g'  /etc/selinux/config
#3. 关闭 swap
sed -i 's/.*swap.*/#&/' /etc/fstab
#4. 重启
reboot -f
#5. 安装 docker
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
#6. 启动并且设置自启动
systemctl enable docker
systemctl start docker

#7. 配置阿里云代理,这里我隐藏了自己的,这东西免费,自己可以去阿里云进行申请。
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 8.编辑时间同步,要不然 etcd 可能会报错,很麻烦
crontab -e
 
* */1 * * * /usr/sbin/ntpdate   cn.pool.ntp.org

在 rancher 虚拟机上部署单节点 rancher。


# 创建目录
mkdir -p /data/rancher
# 创建 docker 容器
docker run -d --restart=unless-stopped -p 8080:80 -p 8843:443 -v /data/rancher:/var/lib/rancher rancher/rancher:v2.4.5
在这里,我们使用的 rancher 单节点模式,如果是用于生产,请使用高可用的 rancher,要不然 rancher 也是有可能出现故障的。
我这里使用的 2.4.5 版本,这是因为我在工作和学习中使用的都是这个版本,就目前文章截止最新版本应该是已经到了 2.6。

启动时我们需要等待一会。我们可以用 docker logs -f 命令来监控日志输出。

访问https://192.168.0.199:8843/ 即可看到这个页面。

2023-03-04T08:07:31.png

我们设置自己的密码,就会跳转到主页,接下来,我们创建集群。

2023-03-04T08:07:57.png

我们在右下角可以更改系统语言。

2023-03-04T08:08:07.png

接下来,我们点击添加集群。

2023-03-04T08:08:50.png

Rancher 不光可以帮助我们建立新的集群,还可以在已有集群的基础上进行导入。

2023-03-04T08:08:23.png

在这里,我们选择自定义后填写集群名称,直接点击下一步,我们使用默认配置即可。

2023-03-04T08:09:29.png

2023-03-04T08:09:42.png

如果是增加 Master 节点,那么这三个我们都需要勾上。

这里需要注意,复制的时候要把 localhost 改成能够进行通信的 ip。

sudo docker run -d --privileged --restart=unless-stopped --net=host -v /etc/kubernetes:/etc/kubernetes -v /var/run:/var/run rancher/rancher-agent:v2.4.5 --server https://192.168.0.106:8843 --token 8bgdphz9mk9xbbdkrhvsqh6v5zh9gkc55276w5l7m8xlwkgr8xmz4w --ca-checksum 3db552d02da1618d971233431766d57485777d558395dbba6dc2c185ca3bc1b8 --etcd --controlplane

2023-03-04T08:10:04.png

我们分别添加完成后需要等待片刻,如果中途卡在 etcd 上,可以尝试下面的方法。

docker stop $(docker ps -aq)
docker system prune -f
docker volume rm $(docker volume ls -q)
docker image rm $(docker image ls -q)
rm -rf /etc/ceph \
       /etc/cni \
       /etc/kubernetes \
       /opt/cni \
       /opt/rke \
       /run/secrets/kubernetes.io \
       /run/calico \
       /run/flannel \
       /var/lib/calico \
       /var/lib/etcd \
       /var/lib/cni \
       /var/lib/kubelet \
       /var/lib/rancher/rke/log \
       /var/log/containers \
       /var/log/pods \
       /var/run/calico

这块我第一次安装的时候折腾了将近两个小时。

2023-03-04T08:10:17.png

当环境没有问题后,我们来部署一个 nginx,首先我们来创建一个项目

2023-03-04T08:10:39.png

2023-03-04T08:10:49.png

我们可以看到有几个默认的 Project,在这里我们就需要来了解一下什么是 namespace 了。

Namespace 是对一组资源和对象的抽象几何,用来将系统内部的对象划分为不同的项目组或者用户组。常用来隔离不同的用户,比如 k8s 自带的服务一般都运行在 kube-system namespace中。

2023-03-04T08:10:59.png

我们先创建一个项目。

2023-03-04T08:12:55.png

接着再增加一个 namespace,之后在左上角我们就可以进入到自己的项目了。

2023-03-04T08:11:41.png
2023-03-04T08:11:49.png

在这里我们可以创建四个内容:Workloads,Load Balancing, Service Discovery,Volumes。

workloads

工作负载是在 Kubernetes 上运行的应用程序。

在 Kubernetes 中,无论你的负载是由单个组件还是由多个一同工作的组件构成, 你都可以在一组 Pod 中运行它。 在 Kubernetes 中,Pod 代表的是集群上处于运行状态的一组 容器 的集合。

2023-03-04T07:55:54.png

Pod 是所有业务类型的基础,也是 k8s 管理的最小单位,可以理解为它是一个或多个容器的组合。

接下来,我们利用 workloads 来创建 nginx。

在这里我们先使用 NodePort,这代表在所有节点(虚拟机)上开放一个特定的端口,任何发送到该端口的流量都被转发到对应的服务上,端口范围胡思 30000~32767。

2023-03-04T07:55:41.png

2023-03-04T07:55:27.png

当显示 Active 的时候就证明已经部署好了,我们可以到 work 节点查看一下。

2023-03-04T07:55:06.png

访问 ip 查看是否能够访问。

2023-03-04T07:54:49.png

如果说访问不了可以尝试一下解决方案

# 安装 iptables
yum install iptables-services -y
# 关闭 iptables 防火墙
service iptables stop   && systemctl disable iptables

# 修改内核参数
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
# 生效配置
sysctl --system

#设置网桥包 iptables

echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 >/proc/sys/net/bridge/bridge-nf-call-ip6tables

echo """
vm.swappiness = 0
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
""" > /etc/sysctl.conf

#生效配置
sysctl -p

#开启ipvs,不开启ipvs将会使用iptables,但是效率低,所以官网推荐需要开通ipvs内核
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
#!/bin/bash
ipvs_modules="ip_vs ip_vs_lc ip_vs_wlc ip_vs_rr ip_vs_wrr ip_vs_lblc ip_vs_lblcr ip_vs_dh ip_vs_sh ip_vs_fo ip_vs_nq ip_vs_sed ip_vs_ftp nf_conntrack"
for kernel_module in \${ipvs_modules}; do
 /sbin/modinfo -F filename \${kernel_module} > /dev/null 2>&1
 if [ $? -eq 0 ]; then
 /sbin/modprobe \${kernel_module}
 fi
done
EOF

chmod 755 /etc/sysconfig/modules/ipvs.modules && bash
/etc/sysconfig/modules/ipvs.modules && lsmod | grep ip_vs