k8s之HTTP請求負載分發


一、導讀

對於基於HTTP的服務來說,不同的URL地址經常對應不同的后端服務或者虛擬服務器,通常的做法是在應用前添加一個反向代理服務器Nginx,進行請求的負載轉發,在Spring Cloud這個微服務框架中,使用zuul網關實現此功能。

而對於k8s集群來說,當然也是可以用Nginx實現請求的轉發,但對於一個成熟的容器編排工具,k8s內置了一個HTTP請求負載分發的組件,就是Ingress Controll。另外,k8s的Service也是具有負載均衡能力的組件。

 

二、用法

在定義Ingress之前,需要先部署Ingress Controller,以實現所有后端Service提供一個統一的入口。Ingress Controller需要實現基於不同Http URL向后轉發的負載分發規則 。

在K8s中,Ingress Controller將以Pod的形式運行,監控apiserver的/ingress接口后端的backend services,如果service發生變化,則Ingress Controller應自動更新其轉發規則。

1、創建Ingress Controller

其實Ingress底層就可以用Nginx實現,Ingress Controller會監聽ApiServer,獲取全部的Ingress定義,然后根據定義生成Nginx的配置文件。

下面使用nginx-ingress-controller鏡像來創建Ingress Controller。

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx-ingress
  namespace: ingress
  labels:
    app: nginx-ingress
spec:
  replicas: 1
  template:
    metadata:
      name: nginx-ingress
      labels:
        app: nginx-ingress
    spec:
      serviceAccountName: ingress-sc
      containers:
      - name: nginx-ingress
        image: imagia/nginx-ingress-controller:0.32.0
        imagePullPolicy: IfNotPresent
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        ports:
        - containerPort: 80
          hostPort: 80
        - containerPort: 443
          hostPort: 443

  

這里為Nginx容器設置了hostPort,將容器應用監聽的80和443端口 號映射到物理機上,使得客戶端應用可以通過URL地址“http://物理機 IP:80”或“https://物理機IP:443”來訪問該Ingress Controller。這使得Nginx 類似於通過NodePort映射到物理機的Service,成為代替kube-proxy的 HTTP層的Load Balancer:

2、創建Ingress

下面的Ingress定義了將/user的請求轉發至user-svc的Service上,將/order的請求轉發至order-svc的Service上。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myweb-ingress
  namespace: ingress
spec:
  rules:
  - host: myweb.com
    http:
      paths:
      - path: /api/user
        backend:
          serviceName: user-svc
          servicePort: 8081
      - path: /api/order
        backend:
          serviceName: order-svc
          servicePort: 8082

  

Ingress的策略配置:

(1)所有請求都轉發到單個Service上

此時不用配置rules

spec:
  backend:
    serviceName: user
    servicePort: 8080

  

(2)同一域名,不同url轉發到不同的服務上

比如域名都是myweb.com,/api/user轉發到user服務,/api/order轉發到 order服務。

spec:
  rules:
  - host: myweb.com
    http:
      paths:
      - path: /api/user
        backend:
          serviceName: user-svc
          servicePort: 8081
      - path: /api/order
        backend:
          serviceName: order-svc
          servicePort: 8082

  

(3)不同域名

域名為myweb1.com的請求轉發到user服務,域名為myweb2.com的請求轉發到order服務

spec:
  rules:
  - host: myweb1.com
    http:
      paths:
      - backend:
          serviceName: user-svc
          servicePort: 8081
  - host: myweb2.com
    http:
      paths:
      - backend:
          serviceName: order-svc
          servicePort: 8082

  

(4)不使用域名

這種配置用於一個網站不使用域名直接提供服務的場景,此時通過 任意一台運行ingress-controller的Node都能訪問到后端的服務。

spec:
  rules:
  - http:
      paths:
      - path: /api/user
        backend:
          serviceName: user-svc
          servicePort: 8081

  

【注】使用無域名的Ingress轉發規則時,將默認禁用非安全 HTTP,強制啟用HTTPS。

三、案例

1、簡介

創建一個命名空間:ingress,啟動兩個服務,一個是user,一個是order,利用Ingress-controller將請求/api/user轉發到user服務,將請求/api/order轉發到order服務。

2、創建服務

(1)創建簡單springboot應用

只有兩個api接口,分別是/api/order和/api/user,然后打成jar包上傳至服務器

 

 

(2)將上述jar包創建為鏡像

將jar包、jdk安裝包和Dockerfile放在同一個目錄

 

Dockerfile文件內容如下:

FROM centos:7


LABEL author=lsy


ENV path=/usr/soft


RUN mkdir ${path}


WORKDIR ${path}


ADD jdk-8u191-linux-x64.tar.gz ${path}


ENV JAVA_HOME=${path}/jdk1.8.0_191
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH=$JAVA_HOME/bin:$PATH


COPY service-1.0.jar ${path}


EXPOSE 8080


CMD  java -jar service-1.0.jar

  

使用命令創建鏡像:

docker build ./ -t  cnode-1:5000/ingress-service:v1.0

  

鏡像創建完成后記得上傳到docker私有倉庫

(3)在ingress命名空間啟動相應的ReplicationController和Service

user-rc.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: user-rc
  namespace: ingress
  labels:
    name: user-rc
spec:
  replicas: 1
  selector:
    name: user-rc
  template:
    metadata:
      name: user-rc
      labels:
        name: user-rc
    spec:
      containers:
      - name: user-rc
        image: cnode-1:5000/ingress-service:v1.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

  

user-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: user-svc
  namespace: ingress
spec:
  selector:
    name: user-rc
  ports:
  - port: 8081
    targetPort: 8080

  

order-rc.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: order-rc
  namespace: ingress
  labels:
    name: order-rc
spec:
  replicas: 1
  selector:
    name: order-rc
  template:
    metadata:
      name: order-rc
      labels:
        name: order-rc
    spec:
      containers:
      - name: order-rc
        image: cnode-1:5000/ingress-service:v1.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

  

order-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: order-svc
  namespace: ingress
spec:
  selector:
    name: order-rc
  ports:
  - port: 8082
    targetPort: 8080

  

分別使用kubectl create 命令創建上述資源

(4)在ingress命名空間中創建ServiceAccount

創建ServiceAccount和ClusterRoleBinding,如果不創建的話,Ingress-controller會使用默認名為default的ServiceAccount,default權限很弱,獲取不到相應的資源信息,這樣Ingress-controller會啟動失敗。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    name: ingress-sc
  name: ingress-sc
  namespace: ingress


---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: ingress
  labels:
    name: ingress-crb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: ingress-sc
  namespace: ingress

  

(5)創建Ingress Controller

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx-ingress
  namespace: ingress
  labels:
    app: nginx-ingress
spec:
  replicas: 1
  template:
    metadata:
      name: nginx-ingress
      labels:
        app: nginx-ingress
    spec:
      serviceAccountName: ingress-sc
      containers:
      - name: nginx-ingress
        image: imagia/nginx-ingress-controller:0.32.0
        imagePullPolicy: IfNotPresent
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        ports:
        - containerPort: 80
          hostPort: 80
        - containerPort: 443
          hostPort: 443

  

創建完后查看:

 

【注】環境變量POD_NAME和POD_NAMESPACE是必須要設置的,不然會報錯。

(6)創建Ingress

也就是規則設置,將請求地址為/api/user轉發至user服務,請求地址為/api/order的轉發至order服務。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myweb-ingress
  namespace: ingress
spec:
  rules:
  - host: myweb.com
    http:
      paths:
      - path: /api/user
        backend:
          serviceName: user-svc
          servicePort: 8081
      - path: /api/order
        backend:
          serviceName: order-svc
          servicePort: 8082

  

創建完后查看:

 

可以看到,它的Hosts是myweb.com,物理機地址是192.168.197.120,端口為80.

如果ADDRESS列為空, 則通常說明Nginx未能正確連接到后端Service,需要排錯。

【注】為什么只有一個ip,是因為這個RC只有一個Pod,調度到cnode-2這台機運行,如果想要每台機器都有一個,建議使用DaemonSet類型的Controller

此時查看ingress-controller的Pod的日志:

先獲取Pod的名字

 

然后查看日志:

 

 

從上圖可以看到,當ingress創建之后,ingress-controller會自動去加載,然后生成對應的nginx的conf文件。

進入容器查看nginx的配置文件:文件是/etc/nginx/nginx.conf

 

(7)測試效果

由於並沒有上述設置的myweb.com這個域名,所以需要進行解析。

curl --resolve myweb.com:80:192.168.197.120 http://myweb.com:80/api/order

  

訪問order服務:

 

查看日志:可以看到是轉發到order-svc這個Service上了

192.168.197.100 - - [31/Oct/2020:07:40:46 +0000] "GET /api/order HTTP/1.1" 200 21 "-" "curl/7.29.0" 82 0.004 [ingress-order-svc-8082] [] 10.36.0.4:8080 21 0.004 200 0f7dfb1134644ee2ceb7a7d364ddfe45

  

訪問user服務:

 

查看日志:可以看到是轉發到user-svc這個Service上了

192.168.197.100 - - [31/Oct/2020:07:42:16 +0000] "GET /api/user HTTP/1.1" 200 20 "-" "curl/7.29.0" 81 0.011 [ingress-user-svc-8081] [] 10.44.0.3:8080 20 0.010 200 46f66ab540c41590a74bbea66bd65ea8

  

===============================

我是Liusy,一個喜歡健身的程序員。

歡迎關注【上古偽神】,一起交流Java技術及健身,一起成為Java大神。

來都來了,關注一波再溜唄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM