0. 简介
Kubernetes(简称k8s,即k和s之间有8个字母)是一个可移植的、可拓展的开源平台,使用声明式配置并依据配置信息自动执行容器化管理。
我研究生毕业的第一份工作,是在一个汽车配套软件公司从事嵌入式Linux开发,那时候的开发模式是在开发机上使用交叉编译工具链编译出可执行的程序,导到arm板上直接运行。所以从整个流程上来说,交叉编译工具链的版本、所依赖的库、以及各种依赖环境都必须copy到对应的板子上才能运行,若涉及到整个生产的流程,那就会更麻烦。后来去了一家AI企业做后端开发后,才慢慢接触到容器化部署,这就使得开发环境、测试环境和生产环境的部署变得轻松和敏捷。其实我的这种经历,也就对应了应用程序部署方式的发展趋势:
- 传统部署:直接部署在物理机上,无法明确应用程序的边界,也很难合理地分配资源;其次是程序迁移时也很困难;
- 虚拟化部署:应用程序被虚拟机互相隔离,限制了程序之间的非法访问;也能更好地实现规模化的部署;但是虚拟机比较重,其自身消耗的资源就比较多;
- 容器化部署:相比于虚拟化部署,其降低了隔离层级,共享了操作系统,更加轻量。
综上,容器化是一种很好的程序部署方案,在生产环境中,我们需要管理容器化的应用程序,确保其健康运行,而k8s就是针对此类问题而提供的容器化编排解决方案,其提供的特性有服务发现 、负载均衡 、存储编排 、自动发布和回滚 、自愈以及密钥和配置管理等。
1. 学习环境搭建
1.1 k8s替代工具的选择
几乎不会有人在本地部署一个完整的k8s集群,一般会采用一些替代工具,比如kind、minikube或者k3s等,可参考Minikube vs.kind vs.k3s-我应该用哪一个?,这里我选择的是kind。
安装kind
kind的安装可以参考Installation,我是Mac系统,直接运行:
bash
brew install kind
安装kubectl
kubectl是k8s的命令行工具,可以用来部署应用、监测和管理集群资源以及查看日志。安装参考kubectl:
bash
brew install kubectl
2. 使用kind创建集群
创建很简单,可参考Cluster,但是需要注意的是,应该是国内墙的原因,直接执行kind create cluster
可能并不能拉去下镜像,即使能够访问外网,也会长时间卡在 Ensuring node image (kindest/node:v1.27.3)
这个步骤,这个时候需要手动去拉取镜像(注意要拉取具体版本,在我的环境中直接运行docker pull kindest/node
也拉不到):
bash
docker pull kindest/node:v1.27.3
简单集群
在kind的镜像拉取成功后,可以直接使用kind create cluster
创建,生成的cluster名称默认为kind
,可以使用kind delete cluster --name kind
进行删除。
bash
~ kind create cluster
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.27.3) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Thanks for using kind! 😊
然后执行以下指令,会发现创建了一个control-plane
的节点:
bash
~ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kind-kind kind-kind kind-kind
~ kubectl get node
NAME STATUS ROLES AGE VERSION
kind-control-plane Ready control-plane 75s v1.27.3
多节点集群
一般而言,我们的k8s集群不会是只有一个节点,虽然我们使用kind在开发机上进行集群搭建,但是集群节点本质上是跑在docker上的,所以我们也可以模拟多节点集群。
首先,我们使用yaml记录搭建集群的配置:
yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
# port forward 80 on the host to 80 on this node
extraPortMappings:
- containerPort: 30950
hostPort: 80
# optional: set the bind address on the host
# 0.0.0.0 is the current default
listenAddress: "127.0.0.1"
# optional: set the protocol to one of TCP, UDP, SCTP.
# TCP is the default
protocol: TCP
- role: worker
- role: worker
- role: worker
然后使用以下命令创建多节点集群:
bash
~ kind create cluster --name multi --config ./multi-node.yaml
Creating cluster "multi" ...
✓ Ensuring node image (kindest/node:v1.27.3) 🖼
✓ Preparing nodes 📦 📦 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-multi"
You can now use your cluster with:
kubectl cluster-info --context kind-multi
Thanks for using kind! 😊
然后查看容器,可以看到创建了一个控制节点,三个工作节点。
bash
~ docker ps | grep multi
dc3218f93fb8 kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes multi-worker2
12dca63de042 kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes multi-worker
9895ed46d75a kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes 127.0.0.1:57884->6443/tcp, 127.0.0.1:80->30950/tcp multi-control-plane
2b1bfd3ccdac kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes multi-worker3
端口映射 - type: NodePort
由于 kind 是把 node 运行在 docker 里的, 因此即使在 k8s 集群中使用 nodePort 方式将服务暴露出来,在宿主机上依旧无法访问。
因为这里暴露的 nodePort 其实是 docker 容器的端口,如果 docker 容器启动时没有将端口映射出来依旧无法访问
所以我们需要端口映射来实现服务的访问,我们先创建nodePort.yaml
如下,然后执行kubectl apply -f nodePort.yaml
即可创建对应的Service和Pod(这些概念后续介绍):
yaml
kind: Pod
apiVersion: v1
metadata:
name: foo
labels:
app: foo
spec:
containers:
- name: foo
image: hashicorp/http-echo:latest
args:
- "-text=foo"
---
apiVersion: v1
kind: Service
metadata:
name: foo
spec:
type: NodePort
ports:
- name: http
nodePort: 30950
port: 5678 # image默认输出5678
selector:
app: foo
然后等待节点运行后,执行以下命令,即可实现服务的基本访问。
bash
~ curl 127.0.0.1:80
foo
端口映射 - type: LoadBalancer
其实我们也可以通过负载均衡的服务,首先创建loadBalancer.yaml
:
yaml
kind: Pod
apiVersion: v1
metadata:
name: foo
labels:
app: foo
spec:
containers:
- name: foo
image: hashicorp/http-echo:latest
args:
- "-text=foo"
---
kind: Pod
apiVersion: v1
metadata:
name: bar
labels:
app: foo
spec:
containers:
- name: bar
image: hashicorp/http-echo:latest
args:
- "-text=bar"
---
apiVersion: v1
kind: Service
metadata:
name: foo
spec:
type: LoadBalancer
ports:
- name: http
nodePort: 30950
port: 5678 # image默认输出5678
selector:
app: foo
然后部署Pod和Service:
bash
~ kubectl apply -f loadBalancer.yaml
pod/foo created
pod/bar created
service/foo created
~ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
bar 1/1 Running 0 5s 10.244.1.3 multi-worker2 <none> <none>
foo 1/1 Running 0 5s 10.244.3.4 multi-worker3 <none> <none>
~ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
foo LoadBalancer 10.96.180.193 <pending> 5678:30950/TCP 36s app=foo
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 29m <none>
然后验证:
bash
~ for _ in {1..10}; do
curl localhost:80
done
foo
foo
bar
foo
bar
bar
bar
foo
foo
foo
很神奇的是我这里操作没有按照kind LoadBalancer中介绍的需要先安装MetalLB
。
HA 集群
有时候,我们也可以创建出多个control-plane的集群,可以认为是HA的(但是在我们的环境当然是假的HA),其创建脚本如下:
yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
- role: worker
执行kind create cluster --name ha --config ./ha.yaml
,值得注意的是,其还会生成一个名为ha-external-load-balancer
的负载均衡器:
bash
~ docker ps | grep ha
8589a7ac8dba kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes ha-worker
bf21f798101e kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes 127.0.0.1:59785->6443/tcp ha-control-plane3
b5cc29441183 kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes ha-worker2
f8cd63326cc2 kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes 127.0.0.1:59786->6443/tcp ha-control-plane
839aa0b6e287 kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes 127.0.0.1:59787->6443/tcp ha-control-plane2
a172a98e244f kindest/node:v1.27.3 "/usr/local/bin/entr..." 2 minutes ago Up 2 minutes ha-worker3
f68e5c42edac kindest/haproxy:v20230606-42a2262b "haproxy -W -db -f /..." 2 minutes ago Up 2 minutes 127.0.0.1:59788->6443/tcp ha-external-load-balancer
这个负载均衡器我的理解如下,在这里感谢Kubernetes教程(十五)---使用 kind 在本地快速部署一个 k8s集群,以下结论也是和他的讨论中得出的,毕竟我花了一天的时间去搜索怎么配置这个ha-external-load-balancer
,以求其达到对服务负载均衡的效果,但是很大可能应该是想错了。
ha-external-load-balancer
是针对于control-plane节点的HA,指的是所有kubectl指令会先打到这个HAProxy,然后再分发到各个control-plane节点;- 如果要做自定义服务的负载均衡,还是要根据service自带的LoadBalancer来做;