k8ssvc

  • svc是什么

  • 创建svc

  • 服务发现,clusterip/变量/dns方式

  • 服务的发布,nodeport,loadbalance/ingress

一、svc

1、svc基础

1、svc介绍

  • svc定义了pod的逻辑集合和访问该集合的策略,是真实服务的抽象,service提供了一个统一的服务访问入口以及服务代理和发现机制,用户不需要了解pod是如何运行的,service是通过标签来找到pod组

  • service在整个集群中负责网络服务的,因为pod是不可靠的,可能会被停止或者重启,一但发生重启,ip地址就会发生变化,service就是通过kube-proxy进行网络的控制,pod的ip发生变化上层的业务并不会中断,因为是通过标签进行控制的,kube-proxy是采用负载均衡实现网络服务的

2、创建一个nginx容器

bash 复制代码
[root@k-master svc]# kubectl run n1 --image nginx --image-pull-policy IfNotPresent --dry-run=client -o yaml > n1.yaml
[root@k-master svc]# ls
n1.yaml
[root@k-master svc]# kubectl apply -f n1.yaml 
pod/n1 created
[root@k-master svc]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE      NOMINATED NODE   READINESS GATES
n1     1/1     Running   0          9s    10.244.82.165   k-node1   <none>           <none>

# 创建一个pod,会获取到一个地址,这个pod地址就是创建k8s集群的时候定义的

# pod用这个ip与其他的pod的ip进行访问

# 集群内部服务的ip地址
[root@k-master svc]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   16d

# ClusterIP 集群内部可用,,所有组件和pod都通过这个svc与api-server进行通信
  • nginx创建出来后,没有创建svc的话,外面的主机是访问不到的,但是k8s集群可以访问到
bash 复制代码
[root@k-master svc]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP              NODE      NOMINATED NODE   READINESS GATES
n1     1/1     Running   0          6m45s   10.244.82.165   k-node1   <none>           <none>
[root@k-master svc]# curl 10.244.82.165
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# k8s节点可以访问到pod

# 但是外面的其他主机访问不到的

# 就需要创建nodeport暴露宿主机的端口,访问宿主机ip和宿主机的端口,从而访问内部的pod服务

3、容器做个端口映射(hostPort)

bash 复制代码
[root@k-master svc]# cat n1.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: n1
  name: n1
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: n1
    ports:
    - containerPort: 80 # 容器的监听的端口是80
      hostPort: 5000  # 映射到主机的5000端口,会自动的修改iptables规则
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}


[root@k-master svc]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP              NODE      NOMINATED NODE   READINESS GATES
n1     1/1     Running   0          4s    10.244.82.161   k-node1   <none>           <none>

# 浏览器访问
http://192.168.50.101:5000/

# 在node1上面查看端口映射
[root@k-node1 ~]# iptables -S -t nat|grep '5000 -j'
-A CNI-HOSTPORT-DNAT -p tcp -m comment --comment "dnat name: \"k8s-pod-network\" id: \"f649f99e0c48438052497ccc9de48bf524bf0d52c217ffc464c9b13d45d98d3f\"" -m multiport --dports 5000 -j CNI-DN-410cd4f2b8823751dd68e
-A CNI-DN-410cd4f2b8823751dd68e -s 10.244.82.161/32 -p tcp -m tcp --dport 5000 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-410cd4f2b8823751dd68e -s 127.0.0.1/32 -p tcp -m tcp --dport 5000 -j CNI-HOSTPORT-SETMARK
-A CNI-DN-410cd4f2b8823751dd68e -p tcp -m tcp --dport 5000 -j DNAT --to-destination 10.244.82.161:80
  • 但是了这种很麻烦
bash 复制代码
# 但是了这种很麻烦

# 如果节点是2个,创建一个deployment,副本数为3个

# 这样的话,就会有一个处于pending的状态了,就是端口被占用了

# 并且没有负载均衡,因为访问模式是主机ip+端口,因此访问一个主机,另外一个主机是空闲的

# 就麻烦

2、svc的访问流程

  • 创建svc的访问流程

  • 外部用户请求访问主机+端口

  • service接收流量,通过pod所在物理主机上的kube-proxy将请求转发到后端pod(具有标签的)

    • kube-proxy有2种模式,ipvs和iptables模式
  • pod处理请求,流量到达容器的80端口

  • 也能实现负载均衡(最外层的)

  • 是通过标签关联的pod

bash 复制代码
# 每个节点有一个
[root@k-master svc]# kubectl get pod -n kube-system 
NAME                               READY   STATUS    RESTARTS        AGE
coredns-5bbd96d687-rsnp6           1/1     Running   15 (112m ago)   16d
coredns-5bbd96d687-svq2d           1/1     Running   15 (112m ago)   16d
etcd-k-master                      1/1     Running   15 (112m ago)   16d
kube-apiserver-k-master            1/1     Running   15 (112m ago)   16d
kube-controller-manager-k-master   1/1     Running   15 (112m ago)   16d
kube-proxy-fgct4                   1/1     Running   16 (112m ago)   16d
kube-proxy-lfsvb                   1/1     Running   15 (112m ago)   16d
kube-proxy-mk56p                   1/1     Running   15 (112m ago)   16d
kube-scheduler-k-master            1/1     Running   15 (112m ago)   16d
metrics-server-7b8674ccdc-fdp29    1/1     Running   13 (112m ago)   15d
[root@k-master svc]# 

3、创建一个简单的svc

1、创建deployment个svc

  • 创建deployment,副本数为3个
bash 复制代码
[root@k-master svc]# kubectl get deploy,pod
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/d-nginx   3/3     3            3           16s

NAME                           READY   STATUS    RESTARTS   AGE
pod/d-nginx-59f7778498-2fzkf   1/1     Running   0          16s
pod/d-nginx-59f7778498-9d2v7   1/1     Running   0          16s
pod/d-nginx-59f7778498-fhzgn   1/1     Running   0          16s

# 修改nginx网页目录,后续访问的时候可以区分开来
[root@k-master svc]# kubectl get pod 
NAME                       READY   STATUS    RESTARTS   AGE
d-nginx-59f7778498-2fzkf   1/1     Running   0          5m
d-nginx-59f7778498-9d2v7   1/1     Running   0          5m
d-nginx-59f7778498-fhzgn   1/1     Running   0          5m
[root@k-master svc]# kubectl exec -ti d-nginx-59f7778498-2fzkf -- /bin/bash
root@d-nginx-59f7778498-2fzkf:/# cd /usr/share/nginx/html/
root@d-nginx-59f7778498-2fzkf:/usr/share/nginx/html# ls
50x.html  index.html
root@d-nginx-59f7778498-2fzkf:/usr/share/nginx/html# echo 1 > index.html 
root@d-nginx-59f7778498-2fzkf:/usr/share/nginx/html# exit
exit
[root@k-master svc]# kubectl exec -ti d-nginx-59f7778498-9d2v7  -- /bin/bash
root@d-nginx-59f7778498-9d2v7:/# echo 2 > /usr/share/nginx/html/index.html 
root@d-nginx-59f7778498-9d2v7:/# exit
exit
[root@k-master svc]# kubectl exec -ti d-nginx-59f7778498-fhzgn -- /bin/bash
root@d-nginx-59f7778498-fhzgn:/# echo 3 > /usr/share/nginx/html/index.html 
root@d-nginx-59f7778498-fhzgn:/# exit
exit
  • 创建svc,没有指定svc的名字,默认使用就是deploy的名字

  • svc自己有一个端口,targetport是pod开放的端口

bash 复制代码
[root@k-master svc]# kubectl expose --name svc1 deployment d-nginx --port 5500 --target-port 80 --dry-run=client -o yaml > svc1.yaml


[root@k-master svc]# cat svc1.yaml 
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: d-nginx
  name: svc1
spec:
  ports:
  - port: 5500
    protocol: TCP
    targetPort: 80
  selector:  # 标签选择器
    app: d-nginx
status:
  loadBalancer: {}

# 集群内部的svc都会分配一个ip和端口,都是虚拟出来的,clusterip类型,这个就是内部访问的
[root@k-master svc]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    16d
svc1         ClusterIP   10.104.191.252   <none>        5500/TCP   2s

# matser访问
[root@k-master svc]# curl 10.104.191.252:5500
2
[root@k-master svc]# curl 10.104.191.252:5500
3
[root@k-master svc]# curl 10.104.191.252:5500
1


# 不能ping 这个svc,因为没有开放icmp,但是可以wget或者curl访问
  • 但是了,上面的svc是ClusterIP类型的,外面的主机访问不到的

2、svc标签选择

  • 自动的识别具有相同标签的pod并且关联

  • 通过标签来定位pod

bash 复制代码
[root@k-master svc]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     SELECTOR
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    16d     <none>
svc1         ClusterIP   10.104.191.252   <none>        5500/TCP   7m45s   app=d-nginx


[root@k-master svc]# kubectl describe endpoints svc1 
Name:         svc1
Namespace:    default
Labels:       app=d-nginx
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2025-08-05T09:52:48Z
Subsets:
  Addresses:          10.244.108.18,10.244.82.163,10.244.82.169
  NotReadyAddresses:  <none>
  Ports:
    Name     Port  Protocol
    ----     ----  --------
    <unset>  80    TCP

Events:  <none>
[root@k-master svc]# kubectl get pod --show-labels 
NAME                       READY   STATUS    RESTARTS   AGE   LABELS
d-nginx-59f7778498-2fzkf   1/1     Running   0          18m   app=d-nginx,pod-template-hash=59f7778498
d-nginx-59f7778498-9d2v7   1/1     Running   0          18m   app=d-nginx,pod-template-hash=59f7778498
d-nginx-59f7778498-fhzgn   1/1     Running   0          18m   app=d-nginx,pod-template-hash=59f7778498

4、服务发现

  • pod与pod之间是怎么通信的

1、ClusterIP

  • 是直接通过这个ClusterIP的ip地址实现的

  • 默认情况下,创建的svc是不能ping通的,因为这是一个虚拟的网络接口,没有真正的mac地址,没有开放icmp协议,kube-proxy开放tcp和udp协议

1、wordpress与mysql

  • wordpress与mysql,之前是直接连接的

  • 现在的话对于mysql创建一个svc-mysql,因此,wordpress连接svc-mysql就能连接到mysql,不需要知道mysql地址

  • 有个问题wordpress的pod怎么发现的mysql-svc的ip的地址, 是通过ClusterIP发现的,通过这个可以访问到mysql

  • wordpress也是内网的,创建一个wordpress-svc,暴露出来

  • 从而外部就能访问到了

  • 有三种模式,clusterip,变量方式,dns方式

bash 复制代码
客户端
  |
  |
wordpress-svc
  |
  |
wordpress
  |
  |
mysql-svc
  |
  |
mysql

2、创建一个mysql

bash 复制代码
# 创建mysql个svc

kubectl run db --image mysql --image-pull-policy IfNotPresent --env="MYSQL_ROOT_PASSWORD=abc123" --env="MYSQL_DATABASE=wordpress" --dry-run=client -o yaml > db.yaml

# expose暴露pod的端口,port是svc的端口,target-port是容器暴露的端口
[root@k-master svc]# kubectl expose pod db --name db --port 3306 --target-port 3306
service/db exposed
# 创建出来的默认是ClusterIP类型
[root@k-master svc]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
db           ClusterIP   10.98.174.106   <none>        3306/TCP   3s
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    16d

[root@k-master svc]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE     SELECTOR
db           ClusterIP   10.98.174.106   <none>        3306/TCP   7m56s   run=db
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    16d     <none>

# 就可以通过svc来登录mysql了,集群内部访问
[root@k-master svc]# mysql -uroot -pabc123 -h 10.98.174.106

3、创建一个wordpress

bash 复制代码
# 连接数据库的地址为mysql-svc

[root@k-master svc]# kubectl run blog --image wordpress --image-pull-policy IfNotPresent --env="WORDPRESS_DB_HOST=10.98.174.106" --env="WORDPRESS_DB_USER=root" --env="WORDPRESS_DB_PASSWORD=abc123" --env="WORDPRESS_DB_NAME=wordpress" --dry-run=client -o yaml > blog.yaml

[root@k-master svc]# kubectl get pod 
NAME   READY   STATUS    RESTARTS   AGE
blog   1/1     Running   0          30s
db     1/1     Running   0          18m
  • 上面的wordpress创建成功了,但是了客户端是访问不到的,因为都是内网的,因此需要暴露wordpress的端口,NodePort类型svc

  • mysql-svc是ClusterIP的,但是wordpress是NodePort类型的,客户端就能访问了

bash 复制代码
[root@k-master svc]# kubectl expose pod blog --name blog --port 80 --target-port 80 --type NodePort
service/blog exposed
[root@k-master svc]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
blog         NodePort    10.99.53.20     <none>        80:32254/TCP   3s
db           ClusterIP   10.98.174.106   <none>        3306/TCP       15m
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        16d


# 这样客户端就能通过访问任意一个主机的ip+32254端口就能实现访问了
  • 因此的话,客户端只要能与k8s节点能够互相通信的话,就能实现访问wordpress了

  • 浏览器访问

bash 复制代码
192.168.50.100:32254

2、变量的方式

  • 一个时间轴的方式

  • 先创建一个svc1,再创建一个pod1,这样的话,pod1里面的环境变量会包含这个svc1,然后在创建svc2,pod1不包含,因为是后创建的

  • 再次创建pod2的时候,就会包含之前的svc1,svc2了

  • 加载的是同一个名称空间下面的svc,不同名称空间是隔离的,不会加载其他名称空间的svc

bash 复制代码
# 创建一个临时容器就能查看到之前创建的svc了
[root@k-master svc]# kubectl run pod1 --image nginx --image-pull-policy IfNotPresent --rm -ti -- bash
If you don't see a command prompt, try pressing enter.
root@pod1:/# env | grep -i blog
BLOG_PORT=tcp://10.99.53.20:80
BLOG_PORT_80_TCP_PROTO=tcp
BLOG_SERVICE_HOST=10.99.53.20
BLOG_SERVICE_PORT=80
BLOG_PORT_80_TCP_ADDR=10.99.53.20
BLOG_PORT_80_TCP=tcp://10.99.53.20:80
BLOG_PORT_80_TCP_PORT=80
  • 之前创建wordpress的时候需要指定mysql-svc的ip地址,因此现在使用环境变量的方式来指定mysql-svc的ip地址

  • 这样的话,mysql-svc的ip地址的变化就不影响了

  • DB_SERVICE_HOST 是记录svc-mysql的ip地址

bash 复制代码
[root@k-master svc]# cat blog.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: blog
  name: blog
spec:
  containers:
  - env:
    - name: WORDPRESS_DB_HOST
      value: $(DB_SERVICE_HOST)   # 引用环境变量
    - name: WORDPRESS_DB_USER
      value: root
    - name: WORDPRESS_DB_PASSWORD
      value: abc123
    - name: WORDPRESS_DB_NAME
      value: wordpress
    image: wordpress
    imagePullPolicy: IfNotPresent
    name: blog
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
  • 这种就是通过变量的方式来实现服务发现

3、DNS方式(非常的好用)

  • 在kube-system名称空间下面,有dns的pod

  • 在创建svc的时候,svc会在dns上自动注册,对于dns而言就知道了svc的ip地址了

  • 创建svc,创建pod,pod可以直接通过svc的服务名来访问,就不需要知道svc的ClusterIP地址了

  • 一个pod的完整的域名是 pod-hostname.service-name.namespace.svc.cluster.local

bash 复制代码
# 创建一个nginxpod和svc
[root@k-master svc]# kubectl get pod,svc
NAME       READY   STATUS    RESTARTS   AGE
pod/blog   1/1     Running   0          21m
pod/db     1/1     Running   0          72m
pod/pod1   1/1     Running   0          37s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/blog         NodePort    10.99.53.20     <none>        80:32254/TCP   50m
service/db           ClusterIP   10.98.174.106   <none>        3306/TCP       66m
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        16d
service/nginx-svc    ClusterIP   10.101.32.16    <none>        80/TCP         4s


# 创建一个临时容器,访问nginx-svc就能下载对应的文件了
# 访问nginx-svc就能访问后端的pod了
# 直接通过服务名来实现的访问,因为有dns的记录,不需要知道nginx-svc的地址

# 在访问nginx-svc的时候给dns服务器,解析ip地址,从而实现了访问
[root@k-master svc]# kubectl run busybox1 --image busybox --image-pull-policy IfNotPresent --rm -ti -- sh
If you don't see a command prompt, try pressing enter.
/ # wget nginx-svc
Connecting to nginx-svc (10.101.32.16:80)
saving to 'index.html'
index.html           100% |**********************|   615  0:00:00 ETA
'index.html' saved
/ # 


# 访问nginx-svc就能转发到10.96.0.10对应的dnsPod,上面有记录nginx-svc的ip地址,从而实现了解析nginx-svc的ip地址,实现了访问

/ # cat /etc/resolv.conf 
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
  • 但是了a空间的pod不能解析b空间的svc,有名称空间的隔离性

  • 但是了也是可以访问的,需要带上完整的域名

bash 复制代码
# 在test空间下创建pod和svc
[root@k-master svc]# kubectl expose pod pod1 --name t1 --port 80 --target-port 80 -n test
service/t1 exposed
[root@k-master svc]# kubectl get pod,svc -n test
NAME       READY   STATUS    RESTARTS   AGE
pod/pod1   1/1     Running   0          35s

NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/t1   ClusterIP   10.105.212.6   <none>        80/TCP    7s

# 在default空间访问,默认是访问到的

/ # wget t1
wget: bad address 't1'

# 可以通过svc.名称空间来实现不同空间下的方式
/ # wget t1.test
Connecting to t1.test (10.105.212.6:80)
saving to 'index.html'
index.html           100% |************************************************************************************************************************************|   615  0:00:00 ETA
'index.html' saved
/ # 
  • 回到上面的wordpress实验
bash 复制代码
# 删除wordpress的pod

# 可以直接输出svc名称来实现访问
[root@k-master svc]# cat blog.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: blog
  name: blog
spec:
  containers:
  - env:
    - name: WORDPRESS_DB_HOST
      value: db  # 直接使用mysql-svc的名称,就能实现解析成ip地址,实现访问
    - name: WORDPRESS_DB_USER
      value: root
    - name: WORDPRESS_DB_PASSWORD
      value: abc123
    - name: WORDPRESS_DB_NAME
      value: wordpress
    image: wordpress
    imagePullPolicy: IfNotPresent
    name: blog
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
  • pod之间使用svc来进行访问
bash 复制代码
# 创建2个nginx pod 和2个svc
[root@k-master svc]# kubectl get pod,svc
NAME     READY   STATUS    RESTARTS   AGE
pod/n1   1/1     Running   0          3m21s
pod/n2   1/1     Running   0          2m46s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   17d
service/n1-svc       ClusterIP   10.101.93.97    <none>        80/TCP    2m21s
service/n2-svc       ClusterIP   10.105.67.195   <none>        80/TCP    2m11s

[root@k-master svc]# kubectl exec -ti n1  -- /bin/bash
# 在同一个名称空间下面,可以直接访问服务名称来实现通信
root@n1:/# curl n2-svc
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>

# 因为n1的dns是集群内部的dns服务器,创建svc会在这个dns服务器上面进行注册,因此n1去dns服务器找到了这个域名对应的ip地址,从而实现了访问
root@n1:/# cat /etc/resolv.conf 
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

4、服务发现总结

  • 上面的wordpress与mysql的连接有多种方式,也就是服务发

  • 通过dns发现,在同一个名称空间下面可以直接访问svc的名称就能实现访问了svc对应的pod

  • 第二个通过变量,后创建的pod会加载同一个空间下的svc,因此就有一个环境变量记录了svc的ip地址,通过这个svc的变量名称来实现了访问

  • 第三个使用ClusterIP,来实现了访问了pod

  • 都是集群内部之间互相通信的,pod与pod之间进行访问的方式

  • 但是了,客户端是不能进行访问到的,因为都是集群内网的

  • pod之间的访问,可以通过svc来进行访问,因为svc后台关联的就是pod,不需要访问pod,即可

5、服务发布

1、NodePort

  • 之前的ClusterIP是集群内部进行访问的,因此web客户端不能进行访问集群内部的服务

  • NodePort就是做一个端口映射,访问物理主机+端口就能访问到集群内部的服务了

  • 创建出来后,每个物理主机都有这个端口,并不是只有这一个主机

  • 生成一个3w以上的端口

bash 复制代码
[root@k-master svc]# kubectl get deployments.apps,pod
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   3/3     3            3           2m23s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-57cc89bc77-dqrjr   1/1     Running   0          2m23s
pod/nginx-57cc89bc77-lxq2h   1/1     Running   0          2m23s
pod/nginx-57cc89bc77-p7tst   1/1     Running   0          2m23s


[root@k-master svc]# kubectl expose deployment nginx --name nginx-svc --port 80 --target-port 80 --type NodePort
service/nginx-svc exposed

# 启用了30081端口,这个端口可以修改的NodePort指定的
[root@k-master svc]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        17d
nginx-svc    NodePort    10.100.250.171   <none>        80:30081/TCP   82s

# 每个主机都开放了这个端口
[root@k-master svc]# iptables -S -t nat | grep 30081
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx-svc" -m tcp --dport 30081 -j KUBE-EXT-HL5LMXD5JFHQZ6LN


# 浏览器访问
http://192.168.50.100:30081/
http://192.168.50.101:30081/
http://192.168.50.102:30081/
  • 访问的流程

    • 先访问主机ip+端口

    • 会转发到svc的ip+端口(充当一个负载均衡器)

    • 然后转发到后端关联的pod,从而实现了访问

2、LoadBalance

  • 默认的情况下,集群内部的主机是不会暴露在互联网上的,前面还有负载均衡器,防火墙等等,可以把防火墙或者LB的端口80暴露出去,然后80端口转发到指定端口上面去,通过DNS指定到防火墙或者LB上

  • loadbanlance 有一个公网的ip地址,创建svc类型为LB,会从公网地址池中分配一个公网ip地址

bash 复制代码
[root@k-master svc]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        17d
nginx-svc    NodePort    10.100.250.171   <none>        80:30081/TCP   46m

# external-ip就是公网ip

1、使用第三方插件来模拟LB

  • 下载文件
bash 复制代码
[root@k-master svc]# wget  https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml

kubectl apply -f metallb-native.yaml

[root@k-master svc]# kubectl get pod -n metallb-system 
NAME                          READY   STATUS    RESTARTS   AGE
controller-68bf958bf9-5pzb5   1/1     Running   0          7m35s
speaker-2l6nf                 1/1     Running   0          7m35s
speaker-m5cqg                 1/1     Running   0          7m35s
speaker-pvxm4                 1/1     Running   0          7m35s

2、创建地址池和绑定

bash 复制代码
# 安装一个网络计算工具
yum -y install sipcalc

[root@k-master svc]# sipcalc 192.168.50.100/24
-[ipv4 : 192.168.50.100/24] - 0

[CIDR]
Host address		- 192.168.50.100
Host address (decimal)	- 3232248420
Host address (hex)	- C0A83264
Network address		- 192.168.50.0
Network mask		- 255.255.255.0
Network mask (bits)	- 24
Network mask (hex)	- FFFFFF00
Broadcast address	- 192.168.50.255
Cisco wildcard		- 0.0.0.255
Addresses in network	- 256
Network range		- 192.168.50.0 - 192.168.50.255
Usable range		- 192.168.50.1 - 192.168.50.254
bash 复制代码
# 创建地址池

[root@k-master svc]# cat pools.yaml 
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.50.200-192.168.50.220

# 创建实例绑定地址池
[root@k-master svc]# cat l2.yaml 
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system
spec:
  ipAddressPools:
  - first-pool

[root@k-master svc]# kubectl get ipaddresspools.metallb.io  -n metallb-system 
NAME         AUTO ASSIGN   AVOID BUGGY IPS   ADDRESSES
first-pool   true          false             ["192.168.50.200-192.168.50.220"]

3、创建svc

  • 自动分配地址
bash 复制代码
# 因为是LoadBalancer,所以会自动的分配外部ip地址,从之前创建的地址池中分配一个地址
# 如果是对外提供的,就需要使用公网ip
[root@k-master svc]# kubectl expose deployment nginx --name svc666 --port 80 --target-port 80 --type LoadBalancer
service/svc666 exposed
[root@k-master svc]# kubectl get svc
NAME         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1      <none>           443/TCP        17d
svc666       LoadBalancer   10.99.233.85   192.168.50.200   80:31439/TCP   3s

4、访问

bash 复制代码
# 直接访问这个模拟出来的公网ip地址就能访问到后端关联的pod
# 不需要添加端口
# 如果购买了域名的话,可以使用域名访问

[root@k-master svc]# curl 192.168.50.200
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

3、Ingress

  • 上面的NodePort的创建,如果需要创建很多的话,就需要占用很多的端口,安全风险就很大

  • 是一个管理从集群外部到集群内部服务的http和https路由

  • 只需要一个公网ip,所有的外部流量从这个入口进入

  • 智能路由的功能,请求的主机名和路径将流量分发到后端不同的service

bash 复制代码
# 流量的分发靠的就是这个ingress-nginx-controller和自己配置的ingress规则

[root@k-master ingress]# kubectl get pod -n ingress-nginx 
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-gj9cg        0/1     Completed   0          84m
ingress-nginx-admission-patch-txm4g         0/1     Completed   0          84m
ingress-nginx-controller-6465b759fb-fsc4s   1/1     Running     0          84m

1、正向代理

  • pc电脑访问华为云的过程中,有一个代理,一般用于出去

2、反向代理

  • 用户访问百度的时候,反向代理关联的是服务器,而不是自己的pc电脑

3、ingress定义

  • 可以定义规则

  • 访问不同的域名转向不同的后台

  • 访问1.com指向server1

  • 访问2.com指向server2

4、创建三个pod和三个svc

  • 使用的nginx镜像是

  • 创建三个nginx的pod

bash 复制代码
[root@k-master ~]# kubectl run n1 --image nginx --image-pull-policy IfNotPresent 
pod/n1 created
[root@k-master ~]# kubectl run n2 --image nginx --image-pull-policy IfNotPresent 
pod/n2 created
[root@k-master ~]# kubectl run n3 --image nginx --image-pull-policy IfNotPresent 
pod/n3 created
[root@k-master ~]# kubectl get pod 
NAME   READY   STATUS    RESTARTS   AGE
n1     1/1     Running   0          9s
n2     1/1     Running   0          6s
n3     1/1     Running   0          3s

# 修改访问页面

[root@k-master ~]# kubectl exec -ti n1 -- /bin/bash
root@n1:/# cd /usr/share/nginx/html/
root@n1:/usr/share/nginx/html# ls
50x.html  index.html
root@n1:/usr/share/nginx/html# echo n1 > index.html 
root@n1:/usr/share/nginx/html# exit
exit
[root@k-master ~]# kubectl exec -ti n2 -- /bin/bash
root@n2:/# cd /usr/share/nginx/html/
root@n2:/usr/share/nginx/html# ls
50x.html  index.html
root@n2:/usr/share/nginx/html# echo n2 > index.html 

[root@k-master ~]# kubectl exec -ti n3 -- /bin/bash
root@n3:/# ls
bin   docker-entrypoint.d   home   media  proc	sbin  tmp
boot  docker-entrypoint.sh  lib    mnt	  root	srv   usr
dev   etc		    lib64  opt	  run	sys   var
root@n3:/# cd /usr/share/nginx/html/
root@n3:/usr/share/nginx/html# ls
50x.html  index.html

# 在html下面创建一个abc目录,并且创建一个index.html,模拟不同的页面
root@n3:/usr/share/nginx/html# mkdir abc
root@n3:/usr/share/nginx/html# ls
50x.html  abc  index.html
root@n3:/usr/share/nginx/html# cd abc/
root@n3:/usr/share/nginx/html/abc# ls
root@n3:/usr/share/nginx/html/abc# echo n3-abc > index.html
root@n3:/usr/share/nginx/html/abc# ls
index.html
root@n3:/usr/share/nginx/html/abc# exit
exit
bash 复制代码
[root@k-master ~]# kubectl expose pod n1 --name svcn1 --port 80 --target-port 80
service/svcn1 exposed
[root@k-master ~]# kubectl expose pod n2 --name svcn2 --port 80 --target-port 80
service/svcn2 exposed
[root@k-master ~]# kubectl expose pod n3 --name svcn3 --port 80 --target-port 80
service/svcn3 exposed
[root@k-master ~]# kubectl get svc
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1        <none>           443/TCP        35d
svc666       LoadBalancer   10.99.233.85     192.168.50.200   80:31439/TCP   17d
svcn1        ClusterIP      10.106.109.188   <none>           80/TCP         20s
svcn2        ClusterIP      10.99.5.184      <none>           80/TCP         9s
svcn3        ClusterIP      10.101.42.143    <none>           80/TCP         3s

5、使用ingress-nginx镜像

bash 复制代码
[root@k-master ingress]# kubectl apply -f ingress-deploy.yaml namespace/ingress-nginx created
serviceaccount/ingress-nginx created
serviceaccount/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
configmap/ingress-nginx-controller created
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created

# 会有一个名称空间,pod
[root@k-master ingress]# kubectl get pod -n ingress-nginx 
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-gj9cg        0/1     Completed   0          110s
ingress-nginx-admission-patch-txm4g         0/1     Completed   0          110s
ingress-nginx-controller-6465b759fb-fsc4s   1/1     Running     0          110s

[root@k-master ingress]# kubectl get deployments.apps -n ingress-nginx 
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
ingress-nginx-controller   1/1     1            1           2m58s


# 有这些svc的服务
[root@k-master ingress]# kubectl get svc -n ingress-nginx 
NAME                                 TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.101.96.191   192.168.50.201   80:31626/TCP,443:31346/TCP   119s
ingress-nginx-controller-admission   ClusterIP      10.98.162.172   <none>           443/TCP                      119s
[root@k-master ingress]# 
  • 使用的是LB这个svc,就能实现访问了ingress-nginx-controller了

6、定义ingress规则

  • 访问哪一个域名指向哪一个svc,从而实现哪一个网站
bash 复制代码
[root@k-master ingress]# cat in.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
spec:
  rules:
  - host: www.meme1.com   
    http:
      paths:
      - path: /             
        pathType: Prefix
        backend:
          service:
            name: svcn1 
            port:
              number: 80   
  - host: www.meme2.com    
    http:
      paths:
      - path: /             
        pathType: Prefix
        backend:
          service:
            name: svcn2
            port:
              number: 80
     - path: /abc
       pathType: Prefix
       backend:
         service:
           name: svcn3
           port:
             number: 80    


# 访问 meme1.com 指向的是svcn1

# 访问meme2.com 指向的是svcn2

# 访问meme2.com/abc 只想的是svcn3
  • 创建class类,使用默认的ingress,否则会报错
bash 复制代码
[root@k-master ingress]# kubectl edit ingressclasses.networking.k8s.io 
ingressclass.networking.k8s.io/nginx edited


      8   annotations:
      9     ingressclasses.kubernetes.io/is-default-class: "true"
  • 运行ingress规则
bash 复制代码
[root@k-master ingress]# kubectl apply -f in.yaml 
ingress.networking.k8s.io/my-app-ingress created

[root@k-master ingress]# kubectl get ingress
NAME             CLASS    HOSTS                         ADDRESS   PORTS   AGE
my-app-ingress   <none>   www.meme1.com,www.meme2.com             80      36s


[root@k-master ingress]# kubectl get ingress
NAME             CLASS    HOSTS                         ADDRESS   PORTS   AGE
my-app-ingress   <none>   www.meme1.com,www.meme2.com             80      36s
[root@k-master ingress]# kubectl describe ingress
Name:             my-app-ingress
Labels:           <none>
Namespace:        default
Address:          
Ingress Class:    <none>
Default backend:  <default>
Rules:
  Host           Path  Backends
  ----           ----  --------
  www.meme1.com  
                 /   svcn1:80 (10.244.82.155:80)
  www.meme2.com  
                 /      svcn2:80 (10.244.82.148:80)
                 /abc   svcn3:80 (10.244.108.41:80)
Annotations:     <none>
Events:          <none>
bash 复制代码
# 记录ingress-nginx-controller中的node1的ip地址为192.168.50.101

[root@k-master ingress]# kubectl get pod -n ingress-nginx  -o wide
NAME                                        READY   STATUS      RESTARTS   AGE   IP              NODE      NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create-gj9cg        0/1     Completed   0          30m   10.244.108.42   k-node2   <none>           <none>
ingress-nginx-admission-patch-txm4g         0/1     Completed   0          30m   10.244.82.149   k-node1   <none>           <none>
ingress-nginx-controller-6465b759fb-fsc4s   1/1     Running     0          30m   10.244.82.146   k-node1   <none>           <none>

7、浏览器访问

  • 需要的就是这个LB的svc的ip地址与域名进行绑定

  • 通过这个地址就能实现访问了ingress-nginx-controller了

bash 复制代码
http://www.meme2.com/abc/ 

http://www.meme1.com/

8、ingress访问的整个流程

  • 客户端访问域名,dns解析为LB的ip地址

  • 访问LB对应的后端ingress-nginx-controller这个pod

  • 然后根据自己编写的ingress规则,实现访问后端的pod

  • LB是这个集群的大门,获取了一个稳定的公网ip,外面访问的唯一入口

  • ingress controller 是一个智能路由器,守在大门内部,根据详细的ingress规则指挥流量去往不同的服务

  • ingress规则是路由表,定义了什么样的请求,哪一个域名,哪一个路径,被送到哪一个后端服务

  • 后端服务是终点站,负责接收智能路由器的流量,转发给对应的pod

  • ingress-controller会监控所有名称空间下面的所有的ingress规则