我们不应该期望Kubernetes Pod是健壮的,而是要假设Pod 中的容器很可能因为各种原因发生故障而死掉。Deployment 等Controller 会通过动态创建和销毁Pod来保证应用整体的健壮性。换句话说,Pod是脆弱的,但应用是健壮的。每个Pod都有自己的IP地址。当Controller 用新Pod 替代发生故障的Pod 时,新Pod会分配到新的IP地址。这样就产生了一个问题:如果一组Pod对外提供服务(比如HTTP),它们的IP很有可能发生变化,那么客户
端如何找到并访问这个服务呢?
Kubernetes给出的解决方案是Service。Service服务也是Kubernetes里的核心资源对象之一。
下面动手创建一个Service来加深对它的理解。创建一 个名为http0822-svc.yaml的定义文件,内容如下:
kind: Service # ②
apiVersion: v1 # ①
metadata:
name: httpd0822-svc
spec:
ports: # ⑤
- name: http-80
protocol: TCP
port: 80
targetPort: 80
selector: # ④
app: httpd0822
type: ClusterIP
①v1是Service 的apiVersion。
②指明当前资源的类型为Service。
③Service 的名字为httpd-svc.
④selector 指明挑选那些label 为run: httpd的Pod作为Service 的后端。
⑤将Service 的80 端口映射到Pod的80端口,使用TCP协议。
应用执行并显示:
kubectl apply -f http0822-svc.yaml
# kubectl get ep
NAME ENDPOINTS AGE
httpd0822-svc > 2s
kubernetes 192.168.3.81:6443 215d
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd0822-svc ClusterIP 10.254.177.175 > 80/TCP 78s
kubernetes ClusterIP 10.254.0.1 > 443/TCP 215d
ENDPOINTS显示none,是由于没有匹配的标签,没有对应的Pod, 而且直接访问curl 10.254.177.175无法访问。
创建一个deployment,写service对应Pod的标签。
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpd0822
spec:
replicas: 3
selector:
matchLabels:
app: httpd0822
template:
metadata:
labels:
app: httpd0822
spec:
containers:
- image: httpd
name: httpd0822
restartPolicy: Always
运行:
kubectl apply -f httpd0822.yaml
生成的pod及看到endpoint有对应的IP地址:
# kubectl get pod
NAME READY STATUS RESTARTS AGE
httpd0822-7dc59d86f6-44qpr 1/1 Running 0 66s
httpd0822-7dc59d86f6-lttv7 1/1 Running 0 66s
httpd0822-7dc59d86f6-vwcxc 1/1 Running 0 66s
# kubectl get ep
NAME ENDPOINTS AGE
httpd0822-svc 10.255.30.0:80,10.255.30.3:80,10.255.30.40:80 110m
kubernetes 192.168.3.81:6443 216d
看到可以正常访问了:
# curl 10.254.177.175
>>>It works!
>>
在Cluster中,除了可以通过Cluster IP访问Service, Kubernetes 还提供了更为方便的DNS访问。kubeadm部署时会默认安装coredns 组件,如下所示:
# kubectl get deploy -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
calico-kube-controllers 1/1 1 1 33d
coredns 2/2 2 2 33d
kube-dns是一个DNS服务器。每当有新的Service 被创建,coredns会添加该Service的 DNS。 Cluster的 Pod 可以通过 .
同命名空间:
# kubectl exec -it busybox0822 -- sh
# nslookup httpd0822-svc
Server: 10.254.0.10
Address 1: 10.254.0.10 kube-dns.kube-system.svc.cluster.local
Name: httpd0822-svc
Address 1: 10.254.177.175 httpd0822-svc.default.svc.cluster.local
不同命名空间:(下面命名空间为default访问命令空间test的svc)
# kubectl exec -it busybox0822 -- sh
/ # nslookup httpd0823-svc
Server: 10.254.0.10
Address 1: 10.254.0.10 kube-dns.kube-system.svc.cluster.local
nslookup: can't resolve 'httpd0823-svc'
/ # nslookup httpd0823-svc.test
Server: 10.254.0.10
Address 1: 10.254.0.10 kube-dns.kube-system.svc.cluster.local
Name: httpd0823-svc.test
Address 1: 10.254.80.55 httpd0823-svc.test.svc.cluster.local
完整的DNS记录是:
.
# nslookup httpd0823-svc.test.svc.cluster.local
Server: 10.254.0.10
Address 1: 10.254.0.10 kube-dns.kube-system.svc.cluster.local
Name: httpd0823-svc.test.svc.cluster.local
Address 1: 10.254.80.55 httpd0823-svc.test.svc.cluster.local
Kubernetes 提供了多种类型的Service, 默认是ClusterIP。
(1) ClusterIP
Service通过Cluster内部的IP对外提供服务,只有cluster内的节点和pod可访问,这是默认的Service 类型,前面实验中的Service 都是ClusterIP。
(2) NodePort
Service 通过cluster节点的静态端口对外提供服务。Cluster外部可以通过:访问service。
通过Cluster节点的静态端口对外提供服务。Cluster外部可以通过
: ìj [i] Service.
修改httpd0822-svc成NodePort
kind: Service # ②
apiVersion: v1 # ①
metadata:
name: httpd0822-svc
spec:
ports: # ⑤
- name: http-80
protocol: TCP
port: 80
targetPort: 80
selector: # ④
app: httpd0822
type: NodePort
重新应用:
# kubectl apply -f http0822-svc.yaml
service/httpd0823-svc configured
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpd0822-svc NodePort 10.254.177.175 > 80:31188/TCP 26h
kubernetes ClusterIP 10.254.0.1 > 443/TCP 217d
Kubernetes依然会为httpd-svc 分配-一个ClusterIP, 不同的是:
(1) EXTERNAL-IP为nodes, 表示可通过Cluster 每个节点自身的IP访问Service。
(2) PORT(S)为80:31188。 80 是ClusterIP 监听的端口,31188 则是节点上监听的端口。Kubernetes 会从30000 ~ 32767中分配-一个可用的端口,每个节点都会监听此端口并将请求转发给Service, 如下所示:
# ss -lpnt | grep 31188
LISTEN 0 4096 *:31188 *:* users:(("kube-proxy",pid=2871,fd=10))
访问:
]# curl http://192.168.3.81:31188
>>>It works!
>>
题目:请重新配置现有的部署front-end以及添加名为http的端口规范来公开现有容器nginx 的端口80/tcp。
创建一个名为front-end-svc的新服务,以公开容器端口http。
配置此服务,以通过在排定的节点上的NodePort来公开各个Pods
kubectl create deployment --image=nginx --port=80 front-end
kubectl edit deployment front-end修改port的名字
.....
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
name: http
protocol: TCP
.......
kubectl expose deployment front-end --port=80 --target-port=80 --type="NodePort" --name=front-end-svc