Service 對(duì)象
為什么需要 service
每個(gè) pod 都有自己的 ip 地址搭幻,但是在 Deployment 中,在同一時(shí)刻運(yùn)行的 pod 集合可能與稍后運(yùn)行該應(yīng)用程序的 pod 集合不同窟社。這導(dǎo)致了一個(gè)問題券勺,如果一組 Pod(稱為后端)為集群內(nèi)的其他 pod (稱為前端)提供功能,那么前端如何找出并跟蹤要連接的 ip 地址灿里,以便前端可以使用后端部分呢关炼?
Service 概念
將運(yùn)行在一組 pods 上的應(yīng)用程序公開為網(wǎng)絡(luò)服務(wù)的抽象方法。
使用 kubernetes 服務(wù)無需修改應(yīng)用程序即可使用通用的服務(wù)發(fā)現(xiàn)機(jī)制钠四。kubernetes 為 pods 提供自己的 ip 地址盗扒,并為一組 pod 提供相同的 DNS 名,并且可以在它們之間進(jìn)行負(fù)載均衡缀去。
定義 service
service 在 kubernetes 中是一個(gè) REST 對(duì)象侣灶,和 pod 類似。像所有的 REST 對(duì)象一樣缕碎,service 定義可以基于 POST 方式褥影,請(qǐng)求 API server 創(chuàng)建新的實(shí)例。
創(chuàng)建一個(gè) service
vim service.yaml
apiVersion: v1
kind: Service
metadata:
# service 的名稱咏雌,將來會(huì)被用作請(qǐng)求的域名來被集群的內(nèi)部或外部對(duì)象使用
name: my-service
spec:
# 匹配 pod
selector:
app: MyApp
ports:
- protocol: TCP
# service 的端口
port: 80
# 容器的端口
targetPort: 9376
kubectl create -f service.yaml
查看 service 信息
kubectl get svc
可以看到:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 47h
my-service ClusterIP 10.1.22.99 <none> 80/TCP 74s
用 service 暴露 pod 服務(wù)地址
創(chuàng)建一個(gè) Deployment凡怎,包含兩個(gè) nginx pod 校焦,具有一個(gè)容器端口80:
vim nginx-deplyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
# 篩選
selector:
# 根據(jù)標(biāo)簽匹配
matchLabels:
# 標(biāo)簽
run: my-nginx
# pod 的數(shù)量
replicas: 2
# 模板
template:
metadata:
# 標(biāo)簽
labels:
run: my-nginx
spec:
# 容器
containers:
- name: my-nginx
image: registry.cn-beijing.aliyuncs.com/qingfeng666/nginx:latest
ports:
- containerPort: 80
kubectl create -f nginx-deplyment.yaml
kubectl get po
可以看到:
my-nginx-76d78c9795-5jzjg 1/1 Running 0 2m13s
my-nginx-76d78c9795-frcmq 1/1 Running 0 2m13s
查看 pod 的 ip 地址
kubectl get pods -l run=my-nginx -o yaml | grep podIP
上面的參數(shù)
-
-l
表示:label
-
-o
表示:output
可以看到:
podIP: 10.244.1.44
podIP: 10.244.2.5
不直接訪問 pod ,通過 service 訪問 pod统倒。創(chuàng)建 service :
vim nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
kubectl create -f nginx-service.yaml
kubectl get svc
查看 service 的描述信息
kubectl describe svc my-nginx
可以看到:
Name: my-nginx
Namespace: default
Labels: run=my-nginx
Annotations: <none>
Selector: run=my-nginx
Type: ClusterIP
IP: 10.1.12.12
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.44:80,10.244.2.5:80
Session Affinity: None
Events: <none>
curl 10.1.12.12:80
可以看到:
Welcome to nginx!
集群內(nèi) pod 通信機(jī)制
Kubernetes 支持兩種基本的服務(wù)發(fā)現(xiàn)模式:環(huán)境變量和 DNS
環(huán)境變量
當(dāng) pod 運(yùn)行在 node 上寨典,kubelet 會(huì)為每個(gè)活躍的 service 添加一組環(huán)境變量。它同時(shí)支持 Docker Links房匆,簡單的 {SVCNAME}_SERVICE_HOST
和 {SVCNAME}_SERVICE_PORT
變量耸成。這里 service 的名稱需要大寫,橫線被轉(zhuǎn)換成下劃線浴鸿。
舉個(gè)例子井氢,一個(gè)名稱是 my-nginx
的 service 暴露了 TCP 端口 80,同時(shí)給它分配了 Cluster IP 地址 10.1.180.155 岳链,這個(gè) service 生成了如下環(huán)境變量:
MY_NGINX_PORT_80_TCP_PORT=80
MY_NGINX_PORT_80_TCP_PROTO=tcp
MY_NGINX_PORT_80_TCP_ADDR=10.1.180.155
Service 要比 pod 先創(chuàng)建花竞,才能把環(huán)境變量寫入 pod
創(chuàng)建 service:
kubectl create -f nginx-service.yaml
創(chuàng)建 Deployment:
kubectl create -f nginx-deplyment.yaml
查看 pod :
kubectl get po
進(jìn)入 pod:
kubectl exec -it my-nginx-76d78c9795-5jzjg sh
打印環(huán)境變量:
printenv
# printenv |grep MY_NGINX
MY_NGINX_PORT=tcp://10.1.99.100:80
MY_NGINX_SERVICE_PORT=80
MY_NGINX_PORT_80_TCP_ADDR=10.1.99.100
MY_NGINX_PORT_80_TCP_PORT=80
MY_NGINX_PORT_80_TCP_PROTO=tcp
MY_NGINX_PORT_80_TCP=tcp://10.1.99.100:80
MY_NGINX_SERVICE_HOST=10.1.99.100
DNS
可以通過使用附加組件為 kubernetes 集群設(shè)置 DNS 服務(wù)
支持集群的 DNS 服務(wù)器(例如 CoreDNS)監(jiān)視 kubetnetes API 中的新服務(wù),并為每個(gè)服務(wù)創(chuàng)建一組 DNS 記錄掸哑。如果在整個(gè)集群中都啟用了 DNS 约急,則所有 pod 都應(yīng)該能夠通過其 DNS 名稱自動(dòng)解析服務(wù)。
舉個(gè)例子举户, 如果在 kubernetes 命名空間 my-ns
中有一個(gè)名為 my-service
的新服務(wù)烤宙,則控制節(jié)點(diǎn)和 DNS 服務(wù)共同為 my-service.my-ns
創(chuàng)建 DNS 紀(jì)錄。my-ns
命名空間中的 pod 應(yīng)該能夠通過對(duì) my-service
進(jìn)行名稱查找來找到它俭嘁。(my-service.my-ns
也可以)
其他命名空間中的 pod 必須將名稱限定為 my-service.my-ns
躺枕。這些名稱將解析為為服務(wù)分配的集群 ip 。
Service 創(chuàng)建 DNS 紀(jì)錄
Kubernetes DNS 在集群上調(diào)度 DNS Pod 和服務(wù)供填,并配置 kubelet 以告知各個(gè)容器使用 DNS 服務(wù)的 IP 來解析 DNS 名稱拐云。
創(chuàng)建一個(gè) service 和兩個(gè) pod:
vim dns.yaml
apiVersion: v1
kind: Service
metadata:
name: default-subdomain
spec:
selector:
name: busybox
clusterIP: None
ports:
- name: foo
port: 1234
targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
name: busybox
spec:
hostname: busybox-1
subdomain: default-subdomain
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
---
apiVersion: v1
kind: Pod
metadata:
name: busybox2
labels:
name: busybox
spec:
hostname: busybox-2
subdomain: default-subdomain
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
hostname
表示 pod 的主機(jī)名
subdomain
表示 pod 的子域名
kubectl create -f dns.yaml
可以看到:
service/default-subdomain created
pod/busybox1 created
pod/busybox2 created
查看 pod
kubectl get po
可以看到:
NAME READY STATUS RESTARTS AGE
busybox1 1/1 Running 0 2m14s
busybox2 1/1 Running 0 2m14s
進(jìn)入 pod 查看域名:
[root@node1 ~]# kubectl exec -it busybox2 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # hostname
busybox-2
/ # hostname -f
busybox-2.default-subdomain.default.svc.cluster.local
/ # exit
[root@node1 ~]#
從集群外部訪問 service
從集群外部訪問 service 的方法:
-
ClusterIP
僅僅使用一個(gè)集群內(nèi)部的 IP 地址--這是默認(rèn)值。選擇這個(gè)值意味著這個(gè)服務(wù)你只想在集群內(nèi)部被訪問到近她。
-
NodePort
在集群內(nèi)部 IP 的基礎(chǔ)上叉瘩,在集群的每一個(gè)節(jié)點(diǎn)的端口上開放這個(gè)服務(wù)。你可以在任意 NodePort 地址上訪問到這個(gè)服務(wù)粘捎。
-
LoadBalancer
在使用一個(gè)集群內(nèi)部地址和在 NodePort 上開放一個(gè) service 的基礎(chǔ)上薇缅,還可以向云提供者申請(qǐng)一個(gè)負(fù)載均衡器,將流量轉(zhuǎn)發(fā)到已經(jīng)以 NodePort 的形式開放的 service 上攒磨。
創(chuàng)建 nginx pod 和 NodePort 類型的 service
vim nodeport.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx-deployment
spec:
ports:
- port: 80
name: nginx-service80
protocol: TCP
targetPort: 80
nodePort: 30001
selector:
app: nginx
type: NodePort
創(chuàng)建
kubectl create -f nodeport.yaml
可以看到
deployment.apps/nginx-deployment created
service/nginx-deployment created
kubectl get all
可以看到
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-6799fc88d8-lh9m5 1/1 Running 0 104s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 6d5h
service/nginx-deployment NodePort 10.1.238.159 <none> 80:30001/TCP 104s
通過瀏覽器訪問:192.168.190.132:30001
(ip 是節(jié)點(diǎn)的 )
可以看到:
Welcome to nginx!
訪問的流程:
節(jié)點(diǎn) ip:30001 > service:80 > pod:80
Ingress
Ingress 是對(duì)集群中服務(wù)的外部訪問進(jìn)行管理的 API 對(duì)象泳桦,典型的訪問方式是:HTTP
Ingress 公開了從集群外部到集群內(nèi)部的 HTTP 和 HTTPS 路由,流量路由由 Ingress 資源上定義的規(guī)則控制
創(chuàng)建一個(gè) Ingress 資源
vim minimal-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
- 可選的
host
娩缰。上面的例子中沒有指定 host灸撰,因此該規(guī)則適用于通過指定 IP 地址的所有入站 HTTP 通信。如果提供了 host ,則規(guī)則(rules)適用于該 host 浮毯。 - 路徑列表
paths
完疫。每個(gè)路徑都有一個(gè)由 serviceName 和 servicePort 定義的關(guān)聯(lián)后端。在負(fù)載均衡器將流量定向到引用的服務(wù)之前债蓝,主機(jī)和路徑都必須匹配傳入請(qǐng)求的內(nèi)容壳鹤。 - 后端
backend
。是 service 文檔中所述的服務(wù)和端口名稱的組合饰迹。與規(guī)則的 host 和 paths 匹配的 Ingress 的 HTTP (和 HTTPS)請(qǐng)求將發(fā)送到列出的 backend 器虾。
安裝 Nginx Ingress 控制器
vim ingress-nginx-controller.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-configuration
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: tcp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
kind: ConfigMap
apiVersion: v1
metadata:
name: udp-services
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
- "networking.k8s.io"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: ingress-nginx
---
kind: Service
apiVersion: v1
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
clusterIP: 10.1.211.240
externalTrafficPolicy: Cluster
ports:
- name: http
nodePort: 31686
port: 80
protocol: TCP
targetPort: http
- name: https
nodePort: 30036
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
sessionAffinity: None
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx-ingress-controller
image: registry.aliyuncs.com/google_containers/nginx-ingress-controller:0.26.1
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
securityContext:
allowPrivilegeEscalation: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
---
創(chuàng)建
kubectl apply -f ingress-nginx-controller.yaml
查看,指定 namespace
kubectl get all -n ingress-nginx
可以看到
NAME READY STATUS RESTARTS AGE
pod/nginx-ingress-controller-95598b695-4j5nw 1/1 Running 0 84s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx NodePort 10.1.211.240 <none> 80:31686/TCP,443:30036/TCP 84s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-ingress-controller 1/1 1 1 84s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-ingress-controller-95598b695 1 1 1 84s
檢查部署版本
POD_NAMESPACE=ingress-nginx
POD_NAME=$(kubectl get pods -n $POD_NAMESPACE -l app.kubernetes.io/name=ingress-nginx --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD_NAME -n $POD_NAMESPACE -- /nginx-ingress-controller --version
可以看到
NGINX Ingress controller
Release: 0.26.1
Build: git-2de5a893a
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: openresty/1.15.8.2
Nginx Ingress 控制器實(shí)踐
部署一個(gè) hello world 服務(wù)
-
創(chuàng)建一個(gè) Deployment
kubectl create deployment web --image=registry.cn-beijing.aliyuncs.com/qingfeng666/hello-app:1.0
可以看到:
deployment.apps/web created
-
把 Deployment 暴露出來
kubectl expose deployment web --type=NodePort --port=8080
expose
這里會(huì)創(chuàng)建一個(gè) NodePort 類型的 service 蹦锋,端口是 8080可以看到:
service/web exposed
查看 service
kubectl get svc
可以看到:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE web NodePort 10.1.163.170 <none> 8080:31886/TCP 93s
-
使用節(jié)點(diǎn) ip 加端口 31886 訪問
curl node1:31886
可以看到:
Hello, world! Version: 1.0.0 Hostname: web-6db77f5fdb-kh7ks
創(chuàng)建一個(gè) Ingress 資源
vim example-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: hello-world.info
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 8080
創(chuàng)建
kubectl apply -f example-ingress.yaml
可以看到:
ingress.networking.k8s.io/example-ingress created
查看 Ingress
kubectl get ing
可以看到
NAME CLASS HOSTS ADDRESS PORTS AGE
example-ingress <none> hello-world.info 10.1.211.240 80 42s
添加域名
vim /etc/hosts
添加
10.1.211.240 hello-world.info
驗(yàn)證 Ingress 能夠轉(zhuǎn)發(fā)請(qǐng)求
curl hello-world.info
可以看到
Hello, world!
Version: 1.0.0
Hostname: web-6db77f5fdb-kh7ks