学习k8s的路上。。。
本次实践是本地部署了minikube 单节点的k8s 环境,minikube是一个虚拟机环境,只有一个节点,节点ip:172.17.0.2 ,自己打包了一个镜像 jalcge/k8s ,镜像里开放端口8080 ,服务是3个副本,支持滚动更新,给容器传参数进行滚动更新,启动服务后,http外部访问。
hostNetwork、hostPort、NodePort、LoadBalancer、Ingress
外部访问大多是使用service
• ClusterIP:默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问。
• NodePort:将Service通过指定的Node上的端口暴露给外部,访问任意一个 NodeIP:nodePort都将路由到ClusterIP。
• LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部的负载均 衡器,并将请求转发到 :NodePort,此模式只能在云服务器上使用。
• ExternalName:将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定)。
基础 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8stest # deployment 名称
namespace:
spec:
minReadySeconds: 5 # pod启动后等待5s后提供外部服务,防止服务未启动
strategy: # 策略
type: RollingUpdate # 支持滚动更新设置
rollingUpdate:
maxSurge: 1 # 启动一个新的pod后 才删除 一个pod
maxUnavailable: 1 # 当maxSurge不为0时,该值也不能为0,最好和maxSurge保持一致
selector: # 标签选择
matchLabels:
app: jalcge # #选择label:app=jalcge的容器生成pod实例
replicas: 3 # 副本数量
template:
metadata:
labels:
app: jalcge
spec:
containers:
- name: jalcge
image: jalcge/k8s:latest
args: # 给容器传参数方法 command: ["1.0"] 和 args
- '1.0'
imagePullPolicy: Always # Always:总是拉取远程仓库镜像 IfNotPresent:默认值,本地有就不拉取 Never:只使用本地镜像不拉取
ports:
- containerPort: 8080 # 容器的开放端口
在Pod中使用hostNetwork:true 配置, pod中的容器直接暴露在宿主机的网络环境中,这时PodIp就是其Node的IP,可以直接通过宿主机的网络访问pod中的应用程序,可以在宿主机中直接访问 NodeIp 来访问pod 服务。
注:
1, 次方法局限性太大,直接暴露 k8s节点的ip ,不安全作为web访问。
2, 对于同Deployment下的hostNetwork: true启动的Pod,每个node上只能启动一个。
也就是说Pod启动副本数不可以多于“目标node”的数量,“目标node”指的是在启动Pod时选定的node,若未选定(没有指定nodeSelector),“目标node”的数量就是集群中全部的可用的node的数量。当副本数大于“目标node”的数量时,多出来的Pod会一直处于Pending状态,因为schedule已经找不到可以调度的node了。
开始下面示例:myapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8stest
namespace:
spec:
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: jalcge
replicas: 3
template:
metadata:
labels:
app: jalcge
spec:
hostNetwork: true # 将pod暴露在宿主机环境中,这时Pod的PodIP就是其所在Node的IP,
# 可以直接在外部 http://NodeIP:容器端口/ 直接访问,无需service 缺点是不稳定且 副本数要和节点数一致,多余的副本会一直处于 Pending状态
containers:
- name: jalcge
image: jalcge/k8s:latest
args:
- '1.0'
imagePullPolicy: Always
ports:
- containerPort: 8080
创建deployment :
kubectl create -f myapp.yaml
baily@baily ~ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
k8stest 1/3 3 1 121m
baily@baily ~ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
k8stest-9cb5887f6-267gm 1/1 Running 0 9m34s 172.17.0.2 minikube
k8stest-9cb5887f6-lbr28 0/1 Pending 0 9m34s
k8stest-9cb5887f6-wfwz5 0/1 Pending 0 9m34s
baily@baily ~ curl http://172.17.0.2:8080/ # 访问服务节点ip:容器端口 http://172.17.0.2:8080/
This is version:1.0 running in pod minikube
baily@baily ~ kubectl delete deployment k8stest # 删除deployment 会删除3个副本pod
deployment.apps "k8stest" deleted
这是一种直接定义Pod网络的方式。
在pod 配置 hostPort :容器端口,hostPort是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的IP加上hostPort访问Pod了。hostPort的设置对象是容器,将容器的端口通过hostIP:hostPort的方式暴露出来。
这样做有个缺点,因为Pod重新调度的时候该Pod被调度到的宿主机可能会变动,这样就变化了,用户必须自己维护一个Pod与所在宿主机的对应关系。
使用了 hostPort 的容器只能调度到端口不冲突的 Node 上,除非有必要(比如运行一些系统级的 daemon 服务),不建议使用端口映射功能。如果需要对外暴露服务,建议使用 NodePort Service。
开始下面示例:myapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8stest
namespace:
spec:
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
selector:
matchLabels:
app: jalcge
replicas: 3
template:
metadata:
labels:
app: jalcge
spec:
containers:
- name: jalcge
image: jalcge/k8s:latest
args:
- '1.0'
imagePullPolicy: Always
ports:
- containerPort: 8080
hostPort: 8080 # hostPort的设置对象是容器,将容器的端口通过hostIP:hostPort的方式暴露出来。
创建deployment :
kubectl create -f myapp.yaml
说明:因为本次实践使用的是 minikube, 存在虚拟机隔离,节点的宿主机不是本地,是minikube虚拟机,所以本地直接访问是不行的。
baily@baily ~ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
k8stest-84cdb4d8c-88b4r 0/1 Pending 0 10m
k8stest-84cdb4d8c-fqh68 0/1 Pending 0 10m
k8stest-84cdb4d8c-lgkkz 1/1 Running 0 10m 172.18.0.5 minikube
baily@baily ~ curl http://127.0.0.1:8080/ # 本地访问失败
curl: (7) Failed to connect to 127.0.0.1 port 8080: 拒绝连接
baily@baily ~ minikube ssh # 进入minikube 虚拟机
docker@minikube:~$
docker@minikube:~$ curl http://127.0.0.1:8080/ # 在虚拟机本地访问
This is version:1.0 running in pod k8stest-84cdb4d8c-lgkkz
baily@baily ~ kubectl delete deployment k8stest # 删除deployment 会删除3个副本pod
deployment.apps "k8stest" deleted
NodePort在kubenretes里是一个广泛应用的服务暴露方式。外部流量访问K8s的一种方式,即nodeIP:nodePort,是提供给外部流量访问K8s集群资源的一种方式。
NodePort的设置对象是service,默认情况下service只能在集群内部通过ClusterIP访问。创建NodePort service时,用户可以指定范围为30000-32767的端口,对该端口的访问就能通过 kube-proxy 代理到service后端的pod中。
此方法需要新建service ,先创建deployment 和 pod ,使用最开始的基础 deployment
kubectl create -f myapp.yaml
baily@baily ~ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
k8stest 3/3 3 3 49m
baily@baily ~ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
k8stest-fc685cb98-kwwtd 1/1 Running 0 50m 172.18.0.7 minikube
k8stest-fc685cb98-qfhg9 1/1 Running 0 50m 172.18.0.6 minikube
k8stest-fc685cb98-wp69q 1/1 Running 0 50m 172.18.0.5 minikube
创建service , app_service.yaml 文件:
apiVersion: v1 # v1是service的apiversion
kind: Service # 当前资源的类型为 Service。
metadata:
name: mysvc # Service 的名字
namespace: default
spec:
selector: # 重要:选择器 label为容器名称 jalcge 的pod作为Service对象,不是pod或deployment的名称
app: jalcge
ports:
- nodePort: 30009 # nodePort 默认30000-32767 外部通过节点ip:port 访问 ,不设置会自动分配
port: 8010 # k8s内部pod间,服务调用的端口
targetPort: 8080 # 容器的端口
protocol: TCP
type: NodePort # LoadBalancer:使用负载均衡器 映射外部ip,NodePort:外部通过节点ip:nodePort 访问
执行 :
kubectl create -f app_service.yaml
也可以不写 service的yaml 文件创建,直接使用命令创建, 如:
kubectl expose deployment k8stest --type=NodePort --port=8080 --name=mysvc
baily@baily ~ kubectl get svc # 获取service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 45d
mysvc NodePort 10.106.217.119 8010:30009/TCP 18s
minikube service mysvc # minikube 访问服务命令
|-----------|-------|-------------|-------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-------|-------------|-------------------------|
| default | mysvc | 8010 | http://172.17.0.2:30009 |
|-----------|-------|-------------|-------------------------|
正通过默认浏览器打开服务 default/mysvc...
正在现有的浏览器会话中打开。
[0415/164931.086972:ERROR:nacl_helper_linux.cc(308)] NaCl helper process running without a sandbox!
Most likely you need to configure your SUID sandbox correctly
baily@baily ~ kubectl delete svc mysvc # 删除服务
service "mysvc" deleted
baily@baily ~ kubectl delete deployment k8stest # 删除deployment 及 pod
deployment.apps "k8stest" deleted
只能在service上定义,是公有云提供的负载均衡器,如AWS、Azure、CloudStack、GCE等,适用于公有云上的Kubernetes服务。
在那些支持外部负载均衡器的云提供者上面,将type字段设置为"LoadBalancer"会为你的Service设置好一个负载均衡器。该负载均衡器的实际的创建是异步进行的,并且该设置好均衡器会在该Service的status.loadBalancer字段中显示出来。
这时候,你可以指定一个 LoadBalancer 类型的 Service。在service提交后,Kubernetes就会调用 CloudProvider 在公有云上为你创建 一个负载均衡服务,并且把被代理的 Pod 的 IP地址配置给负载均衡服务做后端。
此方法需要新建service ,先创建deployment 和 pod ,使用最开始的基础 deployment ,
kubectl create -f myapp.yaml
baily@baily ~ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
k8stest 3/3 3 3 49m
baily@baily ~ kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
k8stest-fc685cb98-kwwtd 1/1 Running 0 50m 172.18.0.7 minikube
k8stest-fc685cb98-qfhg9 1/1 Running 0 50m 172.18.0.6 minikube
k8stest-fc685cb98-wp69q 1/1 Running 0 50m 172.18.0.5 minikube
创建service , app_service.yaml 文件:
apiVersion: v1 # v1是service的apiversion
kind: Service # 当前资源的类型为 Service。
metadata:
name: mysvc # Service 的名字
namespace: default
selfLink: /api/v1/namespaces/default/services/mysvc
spec:
externalTrafficPolicy: Cluster
selector: # 选择器 label 为容器app jalcge 的pod作为Service对象,不是pod或deployment
app: jalcge
ports:
- port: 8080 # k8s内部pod间,服务调用的端口,没有targetPort: 8080 默认 port和容器端口一样 是 8080
protocol: TCP
sessionAffinity: None
type: LoadBalancer # LoadBalancer:使用负载均衡器 映射外部ip,NodePort:外部通过节点ip:nodePort 访问
执行 :
kubectl create -f app_service.yaml
也可以不写 service的yaml 文件创建,直接使用命令创建, 如:
kubectl expose deployment k8stest --type=LoadBalancer --port=8080 --name=mysvc
baily@baily ~ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 443/TCP 45d
mysvc LoadBalancer 10.100.28.40 8080:31349/TCP 25s
baily@baily ~ minikube service mysvc
|-----------|-------|-------------|-------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-------|-------------|-------------------------|
| default | mysvc | 8080 | http://172.17.0.2:31349 |
|-----------|-------|-------------|-------------------------|
正通过默认浏览器打开服务 default/mysvc...
正在现有的浏览器会话中打开。
[0415/173307.465364:ERROR:nacl_helper_linux.cc(308)] NaCl helper process running without a sandbox!
Most likely you need to configure your SUID sandbox correctly
外部访问:
正常情况是 service 信息里的 EXTERNAL-IP 会被负载均衡器映射一个可用ip , 使用这个IP和端口31349 在外部访问, 现在一直处于pending状态 ,是minikube 没有负载均衡器 ,一直等待状态。
此次还是使用 minikube 虚拟机的ip 也是节点ip 访问:
清理:
baily@baily ~ kubectl delete svc mysvc # 删除服务
service "mysvc" deleted
baily@baily ~ kubectl delete deployment k8stest # 删除deployment 及 pod
deployment.apps "k8stest" deleted
ingress controller是由K8s管理的负载均衡容器,它的镜像包含一个nginx或HAProxy负载均衡器和一个控制器守护进程。
Ingress是自kubernetes1.1版本后引入的资源类型。必须要部署Ingress controller才能创建Ingress资源,Ingress controller是以一种插件的形式提供。Ingress controller 是部署在Kubernetes之上的Docker容器。它的Docker镜像包含一个像nginx或HAProxy的负载均衡器和一个控制器守护进程。控制器守护程序从Kubernetes接收所需的Ingress配置。它会生成一个nginx或HAProxy配置文件,并重新启动负载平衡器进程以使更改生效。换句话说,Ingress controller是由Kubernetes管理的负载均衡器。
Kubernetes Ingress提供了负载平衡器的典型特性:HTTP路由,粘性会话,SSL终止,SSL直通,TCP和UDP负载平衡等。目前并不是所有的Ingress controller都实现了这些功能,需要查看具体的Ingress controller文档。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: influxdb
spec:
rules:
- host: influxdb.kube.example.com
http:
paths:
- backend:
serviceName: influxdb
servicePort: 8086
外部访问URL http://influxdb.kube.example.com/ping 访问该服务,入口就是80端口,然后Ingress controller直接将流量转发给后端Pod,不需再经过kube-proxy的转发,比LoadBalancer方式更高效。
总的来说Ingress是一个非常灵活和越来越得到厂商支持的服务暴露方式,包括Nginx、HAProxy、Traefik,还有各种Service Mesh,而其它服务暴露方式可以更适用于服务调试、特殊应用的部署。