入门
使用 minikube
Minikube 是一种轻量级的Kubernetes 实现,可在本地计算机上创建VM 并部署仅包含一个节点的简单集群。
推荐先使用 minikube 单机体验基本功能, kubernetes.io/zh-cn/docs/... ,后面调试时仍然需要使用 minikube 来对比理解。
安装 minikube 后
ruby
minicube start
minikube dashboard
//Opening http://127.0.0.1:51200/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...
// 端口随机
对minikube 初始化的 dashboard , 不用处理权限问题和登录,直接打开使用。如果裸机搭建,一上来这个 dashboard 的权限登录配置会极其复杂劝退。
页面主要是对各种类的 resource 的增删改查,命令不熟悉时很有帮助。
准备 docker 镜像
本处创建阿里云的镜像用于调试
bash
// 两个版本,用于测试更新
registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v1
registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v2
简单 node 服务,8080端口,http 输出当前节点 ip 和 hostname,v2 会显示 v2
perl
index page / index page v2
IP lo10.244.0.158, hostname: test-k8s-5cc7cf6cf9-8d84m
部署服务
创建 namespace,方便管理和清理
arduino
kubectl create namespace test
如果系统方便安装 kubectx , 可安装后 kubens test 切换 namespace ,不方便安装则后续命令加上 -n test 指定 namespace 为 test。
本地创建 yaml 配置文件,用于 kubectl apply -f file.yaml 启动,等同于命令行创建。
appV1.yaml
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test-k8s
# 部署名字
name: test-k8s
spec:
replicas: 3
# 用来查找关联的 Pod,所有标签都匹配才行
selector:
matchLabels:
app: test-k8s
# 定义 Pod 相关数据
template:
metadata:
labels:
app: test-k8s
spec:
# 定义容器,可以多个
containers:
- name: test-k8s # 容器名字
image: registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v1 # 镜像
从下往上看:
- 单个
pod
是 k8s 部署的最小单元,包含一个或多个 container,代表一个应用。比如 wordpress docker 部署,单个部署就会有 wordpress+mysql 两个 containers。 - pod 有 metadata,用于给上级抽象集合 selector,然后集群操作
- replicas: 3 会创建一个
ReplicaSet
集合,它包含相同的 pods。 这里就是创建了 3个 一样的pod,包含在一个ReplicaSet
里。 - 最上面,创建一个
Deployment
,指向创建的ReplicaSet
kubectl 创建
bash
kubectl apply -f ./yaml/deploy/appv1.yaml -n test
在 dashboard 找到单个 Deployment
, 点进去下拉找到指向的 ReplicaSet
,点进去下拉找到创建的 3个 pod 。
访问 minikube 网络
minikube 跑在 docker 里,存在网络隔离。有两种方式访问 minikube 网络:
- minikube ssh ,进到容器 bash
- minikube tunnel
这里使用 minikube ssh,尝试访问单个 pod ,dashboard 进入某一个pod的详情。
在 minikube ssh 进入bash后 curl pod 的 ip 地址,可以访问到单个 pod。
创建 Service
Service API 是 Kubernetes 的组成部分,它是一种抽象,帮助你将 Pod 集合在网络上公开出去。 每个 Service 对象定义端点的一个逻辑集合(通常这些端点就是 Pod)以及如何访问到这些 Pod 的策略。
创建 service.yaml
yaml
apiVersion: v1
kind: Service
metadata:
name: deploy-service
spec:
selector:
# 找有本属性的 pods
app: test-k8s
# ClusterIP 集群内可访问,NodePort 节点可访问,LoadBalancer 负载均衡模式(需要负载均衡器才可用)
type: NodePort
ports:
- port: 8080 # 本 Service 的端口
targetPort: 8080 # 容器端口
nodePort: 31123 # 节点端口,范围固定 30000 ~ 32767
bash
kubectl apply -f ./yaml/deploy/service.yaml -n test
kubectl get svc -n test
在 minikube ssh 里可以curl 到 servcie 暴露的服务,并且有负载均衡 ,可以看到均匀打到 166,167,168 三个 pod 上。
也可用 minikube service 自动打开页面,浏览器访问体验。
js
minikube service deploy-service -n test
创建 Ingress 体验灰度发布
先创建新的使用 v2 img 的 deployment 和 service ,创建单文件 appServiceV2.yaml
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: test-k8s-v2
# 部署名字
name: test-k8s-v2
spec:
replicas: 3
# 用来查找关联的 Pod,所有标签都匹配才行
selector:
matchLabels:
app: test-k8s-v2
# 定义 Pod 相关数据
template:
metadata:
labels:
app: test-k8s-v2
spec:
# 定义容器,可以多个
containers:
- name: test-k8s-v2 # 容器名字
image: registry.cn-hangzhou.aliyuncs.com/marquezyang/common:v2 # 镜像
---
apiVersion: v1
kind: Service
metadata:
name: test-k8s-v2
spec:
selector:
app: test-k8s-v2
# 默认 ClusterIP 集群内可访问,NodePort 节点可访问,LoadBalancer 负载均衡模式(需要负载均衡器才可用)
type: NodePort
ports:
- port: 8080 # 本 Service 的端口
targetPort: 8080 # 容器端口
nodePort: 32000 # 节点端口,范围固定 30000 ~ 32767
bash
kubectl apply -f ./yaml/deploy/appServiceV2.yaml -n test
kubectl get svc -n test
此时有两个 service , 分别是 v1 和 v2。
测试一下 v2 的 service
js
minikube service test-k8s-v2 -n test
// 自动打开浏览器页面
本地体验,浏览器多刷新几次 tab , 可以看到均匀打到不同的 IP (pod) 上,且页面显示 v2。
此时,已有 v1 v2 两个稳定的 url 负载均衡打到各自的 pod 上。此时想要一个 canary 效果,页面一半流量 v1 一半v2,则本地起一个 nginx 也能实现。但 k8s 已经提供了这功能的封装,为 Ingress。
Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。 Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。
先安装 ingress
bash
minikube addons enable ingress
创建 ingress1.yaml
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: k8s-test
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: deploy-service #注意这 Service 名字
port:
number: 8080
ingress2.yaml
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: k8s-test-v2-canary
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/canary: 'true' #启用灰度发布功能
nginx.ingress.kubernetes.io/canary-weight: '50'
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-k8s-v2
port:
number: 8080
bash
kubectl apply -f ./yaml/deploy/ingress1.yaml -n test
kubectl apply -f ./yaml/deploy/ingress2.yaml -n test
kubectl get ingress -n test
此时 ADDRESS 为 minikube ip 的值 192.168.58.2 (docker 内网地址,本机不可达),表示已经成功。并且 ingress 默认 80,443端口。 在 minikube ssh 进 bash 后多次 curl localhost (80)
可见均匀打到 v1 ,v2 ,而且也均匀打到各个 IP (pod) 上。达到我们预期的灰度发布效果,生产环境灰度发布效果也基本复现了。 (这里也可以 minikube tunnel 后浏览器访问 localhost 体验,注意解除本地 80 端口占用。)
最后清理现场 kubectl delete namespace test 即可。如果之前没创建 namespace ,则清理就不那么方便。而 k8s 这套性能占用其实挺高,我的私有云虚拟机完全遭不住,可以及时关闭。
裸机搭建
创建虚拟机
本人沿用了私有云的 ESXi 虚拟机系统,创建了3个 CentOS 7 虚拟机,每个至少 2c4g 以上。可以本地安装虚拟机,也可以考虑租云服务商集群。
创建集群
一般为了理解,多节点裸机集群在初次都推荐手动搭建。但实际上还是用 kubeadm init , 仍然是机械化的复制命令,在这被网络和系统配置卡住没啥意义,推荐使用一键脚本搭建:
进入 192.168.31.153 终端,执行
ini
export MASTER_NODES="192.168.31.153"
export WORKER_NODES="192.168.31.151,192.168.31.152"
export SSH_USER="root"
export SSH_PASSWORD="xxx"
export SSH_PORT="22"
export KUBE_VERSION="1.20.6"
bash kainstall-centos.sh init --version 1.24.8
Kubernetes 通过将容器放入在节点(Node)上运行的 Pod 中来执行你的工作负载。 节点可以是一个虚拟机或者物理机器,取决于所在的集群配置。 每个节点包含运行 Pod 所需的服务; 这些节点由控制面负责管理。
上文使用 minikube 为本机 docker 里的单节点。而实际上节点(node)定义符合一般网络用语,可以指单个机器。假如当前集群有两个 work node ,一个 deployment 希望创建四个 pod , 则这四个 pod 就会均匀部署在两个 Node (机器)上。
搭建完成后查看
arduino
kubectl get nodes
内网 IP 为
192.168.31.153 k8s-master-node1
192.168.31.151 k8s-worker-node1
192.168.31.152 k8s-worker-node2
使用 dashboard
脚本已经安装了 dashboard ,但 rbac 配置较为麻烦。
scss
// 在master 192.168.31.153 使用 tmux ,使用 kubectl proxy
yum install tmux
tmux
//new session
kubectl proxy --address='0.0.0.0' --accept-hosts='^*$' --port=8001
ctrl+b d
//quit se
发现需要登录,且限制只能 https 或localhost 才能登录。这里给出绕过办法。
安装dashboard 一般使用远程yaml ,如
bash
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
把这个下载到本地,比如 dashboard.yaml ,搜索 'args' ,只有一处,加上两行
yaml
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.7.0
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
- --enable-skip-login #add
- --disable-settings-authorizer #add
此时登录页面可以 skip , 但进去后没有任何数据权限。需要参考这个 issue github.com/kubernetes/...
创建 admin.yaml , 复制上面评论中的配置,kubectl apply -f , 然后未登录 dashboard 可用。
部署服务
复用上文 minikube 示例中的 yaml 创建两个 deployment ,service 注意此时设备性能大概率远不如之前单机,可以把pod 数量设置的少些。
可以看到,单个 Service 指向的pod 分别在 node1 , node2 , 即两台不同的机器。 在 153 terminal 能直接连通两个 service ip
部署 Ingress
同是复用上文的 yaml , 创建灰度 Ingress,知道 nginx 在 192.168.31.151 这个 node 节点。
但此时 curl 192.168.31.151 无法连接,输入
arduino
kubectl get service -n ingress-nginx
ingress-nginx 没有 external-ip ,就使用 Cluster-ip 测试。多次 curl 10.96.103.254
可见均匀打到 v1 ,v2 ,而且也均匀打到各个 IP (pod) 上。且此时各 Pod 实际上分布在两台虚拟机中,符合预期。
此时 Nginx 在 node1 上,可以测试把 node2 关机,同时在 master 里持续 curl , 可以发现仍然可访问部署 node1 的 pod , 即容灾高可用。再将 node2 开机,集群恢复。
总结
还未搭建更复杂的场景,比如数据持久化,有状态的应用的部署。但经过上述折腾,我们已经对 k8s 中 pod
,deployment
,service
,ingress
,node
的概念非常清楚了,也成功搭建了集群并体验了灰度发布功能,可以说彻底解锁了 k8s 的技能树。今后系统推荐的相关文章都将会成为它的养分,持续成长,最终长成参天大树。
写文章本身也是一个学习的过程,也请读者能指出文章中的疏忽错漏之处。如果本文对你有所帮助,欢迎点赞收藏。