在Kubernetes(K8s)中,Service是一种核心资源对象,主要用于将一组Pod抽象为网络服务,提供稳定的访问入口和负载均衡功能
1.其核心作用包括
2.负载均衡
将请求均匀分发到后端多个Pod副本,提高系统扩展性和可靠性
支持轮询、最少连接数等多种调度策略
3.故障隔离
4.网络抽象
对内:屏蔽Pod细节,客户端只需访问Service的Cluster IP
对外:通过Ingress配合可将HTTP/HTTPS流量路由到Service
5.服务类型
ClusterIP(默认):集群内部访问
NodePort:通过节点端口暴露服务
LoadBalancer:集成云提供商负载均衡器
ExternalName:映射外部服务
Service通过kube-proxy组件实现流量转发,支持userspace(用户空间代理)和iptables/IPVS等模式 ,是K8s微服务架构的关键组件
yml# 定义Kubernetes API版本和资源类型
apiVersion: apps/v1 # 使用apps/v1版本的API
kind: Deployment # 定义这是一个Deployment资源
# 元数据部分
metadata:
name: example-app # Deployment的名称为example-app
labels: # 为Deployment添加标签
name: songxuan01 # 键值对标签,标识这个应用
# Deployment的规格定义
spec:
replicas: 3 # 指定需要运行的Pod副本数量为3个
# 选择器,用于匹配要管理的Pod
selector:
matchLabels:
name: songxuan01 # 选择带有name=songxuan01标签的Pod
# Pod模板,定义如何创建Pod
template:
metadata:
labels:
name: songxuan01 # 为Pod添加标签,与selector匹配
spec:
# 容器定义
containers:
- name: nginx # 容器名称
image: nginx:1.19 # 使用nginx 1.19版本的镜像
ports:
- containerPort: 80 # 容器暴露的端口号
# 亲和性调度规则
affinity:
nodeAffinity: # 节点亲和性规则
# 必须满足的条件(硬性要求)
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: name # 节点区域标签
operator: In # 操作符,表示值必须在指定列表中
values:
- songxuan01 # 必须部署在songxuan01
# 优先满足的条件(软性偏好)
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80 # 权重为80(相对权重)
preference:
matchExpressions:
- key: name # 磁盘类型标签
operator: In
values:
- songxuan02 # 优先选择有songxuan02磁盘的节点
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP # 协议选择TCP
port: 80 # Service暴露的端口
targetPort: 80 # Pod中Nginx容器监听的端口
type: NodePort # Service类型为NodePort 通过节点端口暴露服务
通过该yml文件配置了service服务,属于该命名空间下的pod都能互相访问
创建一个测试的pod用于测试
ymlapiVersion: apps/v1
kind: Deployment
metadata:
name: xuan
labels:
app: xuan
spec:
replicas: 1
selector:
matchLabels:
app: xuan
template:
metadata:
name: xuan
labels:
app: xuan
spec:
containers:
- name: alpine
image: alpine:3.18
command: ["/bin/sh", "-c"]
args: ["apk add --no-cache curl && while true; do sleep 30; done"]
imagePullPolicy: IfNotPresent
restartPolicy: Always
当我进入测试pod去访问NGINX做了service的pod是能成功访问的(pod内部访问)
当我用浏览器访问外部暴露端口时也是成功的
访问pod分配的是哪个工作节点的IP(该pod策略分配的是NODE1,IP就是192.168.201.101),外部端口没有固定是随机分配的固定在 30000-32767 之间
yml# 定义Kubernetes API版本和资源类型
apiVersion: apps/v1 # 使用apps/v1版本的API
kind: Deployment # 定义这是一个Deployment资源
# 元数据部分
metadata:
name: example-app # Deployment的名称为example-app
labels: # 为Deployment添加标签
name: songxuan01 # 键值对标签,标识这个应用
# Deployment的规格定义
spec:
replicas: 3 # 指定需要运行的Pod副本数量为3个
# 选择器,用于匹配要管理的Pod
selector:
matchLabels:
name: songxuan01 # 选择带有name=songxuan01标签的Pod
# Pod模板,定义如何创建Pod
template:
metadata:
labels:
name: songxuan01 # 为Pod添加标签,与selector匹配
spec:
# 容器定义
containers:
- name: nginx # 容器名称
image: nginx:1.19 # 使用nginx 1.19版本的镜像
ports:
- containerPort: 80 # 容器暴露的端口号
# 亲和性调度规则
affinity:
nodeAffinity: # 节点亲和性规则
# 必须满足的条件(硬性要求)
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: name # 节点区域标签
operator: In # 操作符,表示值必须在指定列表中
values:
- songxuan01 # 必须部署在songxuan01
# 优先满足的条件(软性偏好)
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80 # 权重为80(相对权重)
preference:
matchExpressions:
- key: name # 磁盘类型标签
operator: In
values:
- songxuan02 # 优先选择有songxuan02磁盘的节点
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP # 协议选择TCP
port: 8080 # Service暴露的端口
targetPort: 80 # Pod中Nginx容器监听的端口
name: songxuan01
nodePort: 30001 # 通过节点端口暴露服务
- protocol: TCP
port: 8081
targetPort: 80
name: songxuan02
nodePort: 30002
type: NodePort # Service类型为NodePort 通过节点端口暴露服务
多端口访问指定的30001和30002
直接用回之前StatefulSet搭建NFS服务的
yml# ==================== 命名空间配置 ====================
apiVersion: v1 # Kubernetes核心API版本标识
kind: Namespace # 声明资源类型为命名空间
metadata: # 资源元数据开始
name: ems # 定义命名空间名称为ems(Enterprise Management System)
---
# ==================== 存储类配置 ====================
apiVersion: storage.k8s.io/v1 # 存储类API版本标识
kind: StorageClass # 声明资源类型为存储类
metadata: # 资源元数据开始
name: mysql-nfs-sc # 存储类命名(MySQL专用NFS存储类)
namespace: ems # 归属ems命名空间
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 指定NFS子目录动态供应器
parameters: # 供应器参数配置开始
onDelete: "remain" # 数据保留策略:删除时不清理
---
# ==================== 有状态应用配置 ====================
apiVersion: apps/v1 # 应用API版本标识
kind: StatefulSet # 声明资源类型为有状态副本集
metadata: # 资源元数据开始
name: mysql # StatefulSet名称
namespace: ems # 归属ems命名空间
labels: # 标签集合开始
app: mysql # 应用标识标签
spec: # 规格定义开始
serviceName: mysql-headless # 关联的无头服务名(用于DNS解析)
replicas: 1 # 副本数配置(MySQL单实例部署)
template: # Pod模板定义开始
metadata: # Pod元数据开始
labels: # Pod标签集合开始
app: mysql # 应用标识标签(需与selector匹配)
spec: # Pod规格定义开始
containers: # 容器定义列表开始
- name: mysql # 容器名称标识
image: mysql/mysql-server:8.0 # 官方MySQL 8.0镜像
ports: # 端口映射列表开始
- containerPort: 3306 # MySQL服务默认端口
env: # 环境变量列表开始
- name: MYSQL_ROOT_PASSWORD # root密码变量名
value: "root" # 密码明文值(测试环境使用)
volumeMounts: # 存储卷挂载列表开始
- name: data # 引用下方PVC模板名称
mountPath: /var/lib/mysql # MySQL数据存储路径
volumeClaimTemplates: # PVC模板列表开始
- metadata: # PVC元数据开始
name: data # PVC资源名称
spec: # PVC规格定义开始
accessModes: [ "ReadWriteMany" ] # 存储访问模式(多节点读写)
storageClassName: "mysql-nfs-sc" # 绑定前文定义的存储类
resources: # 资源请求定义开始
requests: # 资源请求参数开始
storage: 2Gi # 存储空间大小请求值
selector: # Pod选择器定义开始
matchLabels: # 标签匹配规则开始
app: mysql # 需匹配的Pod标签键值
---
# ==================== 无头服务配置 ====================
apiVersion: v1 # 服务API版本标识
kind: Service # 声明资源类型为服务
metadata: # 资源元数据开始
name: mysql-headless # 无头服务名称
namespace: ems # 归属ems命名空间
spec: # 规格定义开始
ports: # 端口映射列表开始
- port: 3306 # MySQL服务默认端口
clusterIP: None # 无头服务标识(无集群IP)
selector: # Pod选择器定义开始
app: mysql # 需匹配的Pod标签
再创建一个属于该命名空间的yml做测试
ymlapiVersion: apps/v1
kind: Deployment
metadata:
namespace: ems
name: xuan
labels:
app: xuan
spec:
replicas: 1
selector:
matchLabels:
app: xuan
template:
metadata:
name: xuan
labels:
app: xuan
spec:
containers:
- name: alpine
image: alpine:3.18
command: ["/bin/sh", "-c"]
args: ["apk add --no-cache curl busybox-extras && while true; do sleep 30; done"]
imagePullPolicy: IfNotPresent
restartPolicy: Always
telnet 内部网络Mysql的3306端口,发现数据库拒绝访问,说明端口是能访问到的
本文作者:松轩(^U^)
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!