第六章: 通过Service访问Pod
不应该直接使用Pod的ID地址作为对外提供服务的接口,应为一旦Pod重启,IP地址就变化了,解决方案是使用Service。
6.1 创建Service
K8s service从逻辑上代表了一组Pod,具体是哪些Pod则由label来挑选的。
service有自己的IP,而且这个IP是不变的,客户端只需要访问Service的IP,K8s负责建立和维护service和Pod的映射关系。无论Pod如何变化,对客户端无影响。
httpd.yml
vim httpd.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: httpd
spec:
replicas: 3
template:
metadata:
labels:
run: httpd # 定义label给service用
spec:
containers:
- name: httpd
image: httpd
ports:
- containerPort: 80 # port对外暴露的端口
部署之后,可以直接通过IP地址访问Pod:
$kubectl apply -f httpd.yml
$kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpd-69cb5b9fdd-9vtrp 1/1 Running 0 5m11s 10.244.3.119 k8s-node-122132073 <none> <none>
httpd-69cb5b9fdd-crtfm 1/1 Running 0 5m11s 10.244.3.118 k8s-node-122132073 <none> <none>
httpd-69cb5b9fdd-k9xbv 1/1 Running 0 5m11s 10.244.4.35 k8s-node-122132072 <none> <none>
#测试
$curl 10.244.3.119:80
<html><body><h1>It works!</h1></body></html>
定义service 配置
vim httpd-svc.yml
apiVersion: v1
kind: Service
metadata:
name: httpd-svc # service 名字
spec:
selector:
run: httpd # selector指明挑选 label为run:httpd 的Pod作为Service的后端。
ports:
- protocol: TCP
port: 8080 # service的端口; service的8080端口映射到Pod的80端口
targetPort: 80 # Port的端口
~~
**部署service**
~~
$kubectl apply -f httpd-svc.yml
$service/httpd-svc created
$kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc ClusterIP 10.10.60.67 <none> 8080/TCP 5s
#测试
curl 10.10.60.67:8080
<html><body><h1>It works!</h1></body></html>
通过kubectl describe可以查看httpd-svc与pod的对应关系:
kubectl describe service httpd-svc
Name: httpd-svc
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"httpd-svc","namespace":"default"},"spec":{"ports":[{"port":8080,"...
Selector: run=httpd
Type: ClusterIP
IP: 10.10.60.67
Port: <unset> 8080/TCP
TargetPort: 80/TCP
Endpoints: 10.244.3.118:80,10.244.3.119:80,10.244.4.35:80
Session Affinity: None
Events: <none>
6.2 Cluster IP底层实现
Cluster IP 是一个虚拟IP,是由K8s节点上的iptables规则管理的。使用类似轮询的方法访问Pod。
$iptables -L
$iptables-save #打印出规则
6.3 DNS访问service
在Cluster中,除了可以通过Cluster IP访问 services, K8s还提供了更为方便的DNS访问。
kubeadm部署时会默认安装kube-dns组件。
kube-dns是一个DNS服务器。每当有新的Service被创建,kube-dns会添加该service的DNS记录。
Cluster中的Pod可以通过
比如可以用httpd-svc.default(service name. namespace name) 访问service httpd-svc.(注意: 这是在port里访问)
$kubectl get deployment -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 8d
$kubectl run busybox --rm -ti --image=busybox /bin/sh
#
$wget httpd-svc:8080 ## 因为都属于同一个namespace default, 说与可以省略default
Connecting to httpd-svc:8080 (10.10.60.67:8080)
saving to 'index.html'
index.html 100% |*************************| 45 0:00:00 ETA
'index.html' saved
$nslookup httpd-svc
Server: 10.10.0.10
Address: 10.10.0.10:53
httpd2.yml
$vim httpd2.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: httpd2
namespace: kube-public
spec:
replicas: 2
template:
metadata:
labels:
run: httpd2 # 定义label给service用
spec:
containers:
- name: httpd2
image: httpd
ports:
- containerPort: 80 # port对外暴露的端口
---
apiVersion: v1
kind: Service
metadata:
name: httpd2-svc # service 名字
namespace: kube-public
spec:
selector:
run: httpd2 # selector指明挑选 label为run:httpd2 的Pod作为Service的后端。
ports:
- protocol: TCP
port: 8080 # service的端口; service的8080端口映射到Pod的80端口
targetPort: 80 # Port的端口
布署httpd2
$kubectl apply -f httpd2.yml
$kubectl get service -n kube-public
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd2-svc ClusterIP 10.10.64.178 <none> 8080/TCP 11m
#需要加上namespace
$wget httpd2-svc.kube-public:8080
Connecting to httpd2-svc.kube-public:8080 (10.10.64.178:8080)
saving to 'index.html'
index.html 100% |*******************************| 45 0:00:00 ETA
'index.html' saved
6.4 外网如何访问service
- ClusterIp:
Service通过Cluster内部的IP对外提供服务,只有Cluster内节点和Pod可以访问,这是默认的Service类型。 - NodePort:
Service通过Cluster节点的静态端口对外提供服务。Cluster外部可以通过<NodeIp>.<NodePort>访问Service. - LoadBalancer:
Service利用cloud provider特有的load balancer对外提供服务。
实践一下NodePort
$kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc ClusterIP 10.10.60.67 <none> 8080/TCP 43m
$修改httpd-svc.yml
vim httpd-svc.yml
spec:
type: NodePort #指定为NodePort
$kubectl apply -f httpd-svc.yml
#Type栏变为NodePortPort栏会多出32686
$kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc NodePort 10.10.60.67 <none> 8080:32686/TCP 46m
这时可以通过node_ip:23686访问
$ netstat -an |grep 32686
tcp6 0 0 :::32686 :::* LISTEN
#这时可以通过node_ip:23686访问
$kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd-svc NodePort 10.10.60.67 <none> 8080:32686/TCP 56m
#这时可以通过node_ip:23686访问
$ curl k8s-node-122132072:32686 #也可用node_ip
<html><body><h1>It works!</h1></body></html>
$ curl 10.10.60.67:8080
<html><body><h1>It works!</h1></body></html>
vim httpd-svc.yml
apiVersion: v1
kind: Service
metadata:
name: httpd-svc # service 名字
spec:
type: NodePort
selector:
run: httpd # selector指明挑选 label为run:httpd 的Pod作为Service的后端。
ports:
- protocol: TCP
nodePort: 30000 # node监听Port
port: 8080 # service的端口; service的8080端口映射到Pod的80端口
targetPort: 80 # Port的端口
$curl k8s-node-122132072:30000
<html><body><h1>It works!</h1></body></html>