1 为什么有这个设计
Tip
我们前面这个那个的pod 各种搞, 是时候让外面的用户来访问我们通过pod 提供的服务了
为什么?
- 像deploy 部署的一组pod 为我们提供服务, 如果其中一个pod 重建了,ip修改了, 如何访问到呢?
- 就像我们去就餐, 我们不需要知道具体为你提供服务的人的名字, 只需要叫服务员,就会有人来提供服务.
就是很多pod在前端的一个负载均衡调度器 service 先到的endpoint controller 然后通过找到对应的pod
2 clusterIP
Tip
Service的默认类型,服务被发布至仅集群内部可见的虚拟IP地址上
deploy-nginx2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: deploy-nginx
name: deploy-nginx2
spec:
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app: pod-deploy-nginx2
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app: pod-deploy-nginx2
spec:
restartPolicy: Always
containers:
- image: nginx:1.14.2-alpine
imagePullPolicy: IfNotPresent
name: c-deploy-nginx
ports:
- containerPort: 80
name: web
protocol: TCPsvc-deploy-nginx.yaml
kind: Service
apiVersion: v1
metadata:
name: svc-deploy-nginx
spec:
selector: # 关联哪些 pod ,上面我们deploy 创建的pod 就有这个标签
app: pod-deploy-nginx2
# clusterIP: 10.96.1.11 # 可以指定一个你要的ip,默认是随机分配的一个
type: ClusterIP
ports:
- protocol: TCP
port: 8800 # service 端口
targetPort: web # 想要关联的pod 它们暴露的端口 可以写80 , 或者像这样 使用上面pod定义的端口名称# 创建 svc, 必须和pod 在同一个namespace
k apply -f svc-deploy-nginx.yaml
k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-deploy-nginx ClusterIP 10.99.229.242 <none> 80/TCP 6m38s
# 服务选择pod的控制器不断扫描与标签选择匹配的 Pod,然后将所有更新发布到也称为 “svc-deploy-nginx” 同名的 Endpoint 对象
# ep endpoint
k get ep
NAME ENDPOINTS AGE
svc-deploy-nginx 10.244.1.77:80,10.244.2.78:80 2m59s
# 同名ep中关联的2个 ip地址 正是 2个pod的ip
k get po -l app=pod-deploy-nginx2 -o wide
NAME READY STATUS RESTARTS AGE IP NODE
deploy-nginx2-57cfcdb8c7-6nhzj 1/1 Running 0 11m 10.244.2.78 node2
deploy-nginx2-57cfcdb8c7-sqpr4 1/1 Running 0 11m 10.244.1.77 node1
# 直接访问 svc的ip和端口 ,就能访问到后面实际pod里的nginx 服务了. 而且负载均衡
# 访问svc, 会通过ep 找到对应的pod ip地址
curl 10.99.229.242:8800
# 进入pod 容器
cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
ping svc-deploy-nginx
wget svc-deploy-nginx:8800 #ok的
wget svc-deploy-nginx.default.svc.cluster.local:8800
# 删除pod 后, deploy 重建了pod ,然后ep 会重现关联新的pod ip
# 删除svc 会将关联的ep也删除3 nodePort
ClusterIP 只能在集群内部访问 (默认)
映射一个端口 给node, 外部可以直接访问node的端口
svc-nginx-node-port.yaml
# 看到随机端口
k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-nginx-node-port NodePort 10.105.50.239 <none> 80:30046/TCP 1s
k get no -o wide
# 现在可以用任意一个node 的ip :30046 来访问pod服务
控制随机使用的nodePort
/etc/kubernetes/manifests/kube-apiserver.yaml- 在spec.containers.command 最后一行添加,比如
- --service-node-port-range=40000-40100 - 等待 kube-apiserver 重启完成,稍微等等,
systemctl status kubelet
4 代理 k8s 外部应用
Tip
- 比如我们一个golang web服务, 需要连接外部的mysql或redis ,这就需要维护它们的ip地址
- 我们希望在生产环境中使用某个固定的名称而非IP地址来访问这些外部的中间件服务
- 某个项目正在迁移至k8s集群,但是一部分服务仍然在集群外部,此时可以使用service代理至 k8s 集群外部的服务 - 假定一个场景. 我们要从原先传统的服务迁移到k8s, a服务和b服务, 里面a访问b 是直接用的ip地址比如192.168.1.100:8080 (比如在a的配置文件里有这个ip地址 ) - 我们先迁移了a, b服务暂时还在外部,未来某一个时间可能才会迁移到k8s, 我们大概就会修改a的配置里的b ip地址, 过段时间 b迁移到 k8s,我们又要修改 这个ip地址, 然后重启 a服务,,, 我们不想要这么麻烦,
svc-nginx-external.yaml
kubectl apply -f svc-nginx-external.yaml
# 查看是否有关联的ep , 这里我们还没关联ep
k describe svc svc-nginx-external |grep -i endpoint
# kubectl get ep 是没有自动创建的. 因为我们创建的svc没有没有selector, 就没关联pod
# 之所以我们以前能通过svc 访问到 pod 的ip ,是根据 ep的设置
# 那么现在我们手动创建一个ep,让ep指向外部的ip ,不就行了.
ep-single.yaml
之前弄完后一直连接不了
原因是 svc ports 里设置了name, ep里没有设置, 必须设置,且name名字一样才可以.
5 ExternalName
5.1 外部域名
Tip
- 通过svc访问外部的域名(就是给外部服务域名起一个别名)
- ports 字段设置是无效的,因为这里就是域名的映射
5.2 内部svc 起个别名
kind: Service
apiVersion: v1
metadata:
name: svc-external-name-another-svc
namespace: test
spec:
type: ExternalName
# 这里写我们已经创建的svc的name, 作为已经它的一个svc别名
#externalName: svc-deploy-nginx.default.svc.cluster.local 这里这样 就相当于给不同ns的svc 起个别名一样.
# 要全, svc.cluster.local 不能省略, 本身全的 ,你在哪个ns下的pod 都能访问 ,每个pod里的 /etc/resolv.conf
externalName: svc-deploy-nginx.default.svc.cluster.local# 首先 pod 里能通过 svc-deploy-nginx 访问
k exec -it deploy-nginx2-667f55f99f-frtxh -- wget svc-deploy-nginx:8800
# test 命名空间下的pod里访问default命名空间下的 svc name, 你需要 指定 命名空间, .default
k exec -n test -it deploy-nginx-test-65cb6bf5f6-8mrxw -- wget svc-deploy-nginx.default:8800
# 直接访问, 其它namespace的svc 的别名, 就不需要带上 namespace
k exec -n test deploy-nginx-test-65cb6bf5f6-8mrxw -- wget svc-external-name-another-svc:88005.3 headless svc
svc-headless-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-headless-nginx
labels:
app: svc-headless-nginx
spec:
ports:
- port: 80
name: web
#它的 clusterIP 字段的值是:None,即:这个 Service,没有一个 VIP 作为“头”。
#这也就是 Headless 的含义。所以,这个 Service 被创建后并不会被分配一个 VIP,
#而是会 以 DNS 记录的方式暴露出它所代理的 Pod。
clusterIP: None
selector:
app: pod-deploy-nginx26 几个注意的问题
6.1 pod 健康检查失败
Tip
前面我们说过, pod 就绪探针失败, 会将pod 切断流量
svc-pod-readiness.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: pod-readiness-liveness
name: pod-readiness-liveness
spec:
containers:
- name: c-readiness-liveness
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
readinessProbe:
exec:
command:
- sh
- -c
- cat /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
---
kind: Service
apiVersion: v1
metadata:
name: svc-pod-readiness
spec:
selector:
test: pod-readiness-liveness
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 806.2 svc指定的selector 没有pod
kind: Service
apiVersion: v1
metadata:
name: svc-selector-no-pod
spec:
selector:
app: pod-deploy-nginx3
type: ClusterIP
ports:
- protocol: TCP
port: 8800
targetPort: 80
Tip
会创建同名的ep, 只是ep里的ENDPOINTS 没有ip,是空的.