我们不应该期望k8s Pod是健壮的,而是要假设Pod中的容器很可能因为各种原因发生故障而死掉。Deployment等Controller会通过动态的创建和销毁Pod来保证应用整体的健壮性。换句话说,Pod是脆弱的,但应用是健壮的。
每个Pod都有自己的IP地址,当Controller用新的Pod替代发生故障的Pod时,新Pod会分配新的IP地址,这就产生了一个问题:如果一组Pod对外提供服务,它们的IP很有可能发生变化,那么客户端如何找到并访问这个服务呢?答案就是Service。
一、创建Service
K8s Service从逻辑上代表一组Pod,具体是哪些Pod则是由label来挑选的。Service有自己的IP,而且这个IP是不变的。客户端只需要访问Service的IP,k8s则负责建立和维护Service与Pod的映射关系。无论后端Pod如何变化,对客户端不会有任何影响,因为Service没有变。
(1)创建deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd-deployment
labels:
app: httpd
spec:
replicas: 3
selector:
matchLabels:
app: httpd
template:
metadata:
labels:
app: httpd
spec:
containers:
- name: httpd
image: httpd:latest
ports:
- containerPort: 80
(2)apply一下
zy@k8s-master:~$ kubectl apply -f httpd.yml
deployment.apps/httpd-deployment created
(3)查看pod
pod分配了各自的IP,这些IP只能被Kubernetes Cluster中的容器和节点访问。
zy@k8s-master:~$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpd-deployment-59fc85cfcd-kz4m8 1/1 Running 0 92s 10.244.1.17 k8s-node1 <none> <none>
httpd-deployment-59fc85cfcd-m2tc4 1/1 Running 0 92s 10.244.2.11 k8s-node2 <none> <none>
httpd-deployment-59fc85cfcd-nz4x5 1/1 Running 0 92s 10.244.2.12 k8s-node2 <none> <none>
(4)创建Service
编写service配置文件
apiVersion: v1
kind: Service
metadata:
name: httpd-svc
spec:
selector:
run: httpd
ports:
- protocol: TCP
port: 8080
targetPort: 80
以上代码是 Kubernetes 中的 YAML 文件,用于创建一个名为
httpd-svc
的 Service 资源。该 Service 资源会将流量路由到拥有标签run=httpd
的 Pod 上,同时将流量从端口 8080 转发到 Pod 中的端口 80。具体来说,代码的各个部分含义如下:
apiVersion: v1
: 指定 Kubernetes API 版本为 v1,也就是最基本的 API 版本。kind: Service
: 指定创建的资源类型为 Service。metadata
: 定义元数据,包括资源的名称等信息。name: httpd-svc
: 指定该 Service 资源的名称为httpd-svc
。spec
: 定义 Service 的规范,包括 Service 所要匹配的 Pod 标签以及端口信息。selector
: 指定 Service 所要匹配的 Pod 标签,这里是run=httpd
,表示该 Service 会将流量路由到所有拥有标签run=httpd
的 Pod 上。ports
: 定义 Service 的端口映射规则,包括协议、端口号和目标端口号。这里的含义是将 Service 的 8080 端口映射到 Pod 中的 80 端口上。
apply一下:
zy@k8s-master:~$ kubectl apply -f httpd-service.yml
service/httpd-svc created
查看service:
zy@k8s-master:~$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc ClusterIP 10.98.248.61 <none> 8080/TCP 3m13s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26h
(5)查看service的详细信息
y@k8s-master:~$ kubectl describe service httpd-service
Name: httpd-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=httpd,run=httpd
Type: ClusterIP
IP: 10.102.206.215
Port: http 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.21:80,10.244.1.22:80,10.244.2.16:80
Session Affinity: None
Events: <none>
endpoints罗列了三个Pod的IP和端口。我们知道Pod的IP是在容器中配置的,那么service的集群IP又是在哪里配置的呢?集群IP如何映射到pod的IP呢?答案是 iptables
二、外网如何访问Service
出来Cluster内部可以访问Service,很多情况下我们也希望应用的Service能够暴露给Cluster外部。K8s提供了多种类型的Service,默认是ClusterIP。
(1)ClusterIP
Service通过集群内部的IP对外提供服务,只有Cluster内的节点和pod可访问,这是默认的service类型。
(2)NodePort
service通过Cluster节点的静态端口对外提供服务。Cluster外部可以通过 <NodeIP>:<NodePort>访问Service
(3)LoadBalancer
Service利用cloud provider 特有的负载均衡对外提供服务,云提供者负责将负载均衡的流量导向Service。