一、上集回顧
1、Service 3種模型:userspace,iptables,ipvs
2、Service類型
ClusterIP,NodePort
NodePort:client -> NodeIP:NodePort -> ClusterIP:ServicePort -> PodIP:containerPort
LoadBalancer
ExternelName
No ClusterIP: Hedless Service
serviceName -> PodIP
二、ingress
1、在客戶端訪問我們k8s服務時,四層調度器本身是沒有辦法解除ssl會話的,這就意味着客戶端必須與后端服務器(pod)之間直接建立ssl會話,這里還有個顯著的問題在於如果調度器在ssl會話建立以后的下一個請求被調度到第二台服務器上那么這個ssl還要重新建立,因此我們只要認為內部網絡是安全的那么我們可以把會話在前端調度器上卸載,但是四層調度是不能卸載的,因此我們需要七層的負載均衡機制。因此如果他們是http服務我們又期望構建https,那么我們只需要他在互聯網上這個不安全的網絡中傳輸實現https,內網中使用http,因此我們需要使用卸載器,但是我們Service調度時,無論是iptables還是ipvs都只是四層調度,因此也就意味着如果你想要在k8s上運行一個應用基於https提供服務,我們就必須得在后端每一個pod上配置https,因為只有這樣他們才會建立起https聯系,所以我們現在也期望在接入那一層上就能夠卸載ssl,向內部調度時就不再是ssl了。對這種需求,k8s采用一種很獨特的方式來實現,我們在整個集群中,在進行調度時后端被代理的pod資源是不配置https的,就是明文的http,但是我使用一個獨特的調度器(運行在pod中),對於此pod來講,其是一個運行在七層(用戶空間)的正常的應用程序,比如nginx,haproxy等,當用戶試圖訪問某一服務時,我們不讓他先去到達前端的service,而是先到這個pod,然后pod與pod之間不需要service而是直接通信來完成反向代理,我們用一個pod來反代至后端我們真正提供服務的pod,此前我們用service代理的,現在用pod,而這個pod如果需要被訪問到那么還是需要經過service,因此客戶端經過此pod的service調度以后,與我們專門配置了https的此pod進行交互,這里的service我們定義成nodePort,依然沒有什么問題,依然老路徑還是存在的,但是等到達這個pod以后由此pod直接代理至兩個明文的pod,因此此pod就成為https的會話卸載器了。如果這種方式進行調度那么調度方式如下: client --> LB --> nodePort --> service -->會話卸載器pod --> 后端pod 這種方式性能肯定會非常非常差,如圖。
2、其實我們還可以這樣干,可以讓我們pod直接共享我們節點的網絡名稱空間,於是,上述中的會話卸載器pod我們可以直接讓他共享節點網絡名稱空間,這就意味着其監聽着宿主機的地址,這樣我們客戶端的請求就可以之間到達這個pod,然后再由他進行調度。
3、在一個節點上運行的容器,容器可以使用自己的虛擬網絡,也可以共享宿主機的網絡,如果這個容器共享宿主機的網絡也就意味着這個容器內的進程一旦監聽套接字時它監聽的是宿主機的地址,相當於一個進程運行在宿主機上一樣的,這樣一來這個pod在每個節點上就只能運行一個了,一般來講集群中只有一個,那么其只需要運行在集群的某一個節點即可,但是如果 監聽在節點的端口時就會有問題,service時無論訪問哪一個節點的端口都行,因為你訪問哪一個節點的nodePort他都能通過它的ip地址送達到后端pod上,但是現在這個Pod要監聽節點的網絡名稱空間,並且通過這個節點的網絡名稱空間直達這個pod,那么如果運行這種類型的pod那么就一定只能運行在一個節點上,訪問時客戶端就只能訪問這個節點,並且如果這個節點掛了呢?
4、要解決這個問題,我們可以用DaemonSet控制器,它可以在每個節點上都運行相應的pod 副本並且只運行一個,這樣假如我們有三個節點那么我們三個節點上都可以運行這個pod。這樣就都能實現代理和負載均衡,但是又回到了調度到哪一個節點都可以的問題,這樣無論哪個節點掛掉了都還是可以訪問到,但是如果我們有太多的節點那么每個節點都運行一個這樣的pod就太占資源。daemonset還可以讓pod運行在有限的節點的范圍上(部分節點),於是再將來做k8s集群時可以這樣干,比如我們有三千個節點,那么我們專門拿三個節點出來做pod的接入式的負載均衡的專用主機,並且給這三個節點打上污點讓其它pod無法調度上來,然后我們就定義這個DaemonSet控制器上的pod只運行在這三個節點上各自運行一份並且能容忍這些污點,所以這三個主機在集群中只允許這一個類型的pod,專門負責為集群接入外部的七層調度的流量。而這個pod在k8s中有個專門的稱呼叫 Ingress Controller。這個Ingress Controller比較獨特,之前講的DaemonSet,deployment,replacSet等控制器都不一樣,DaemonSet deployment,replaciSet等等都是作為Controller manager的一部分存在,眾多控制器都是作為Controller manager的一個子組件作為其組成部分組成的。而Ingress Controller卻是自己獨立運行的一個或一組pod資源,它通常就是一個應用程序,這個應用程序就是擁有七層代理能力和調度能力的應用程序,目前k8s上的選擇有四種,其中最不受待見的就是Haproxy,一般默認是nginx,現在在服務網格中大家比較傾向Envoy,當然還有其它與nginx相競爭的據說本來就是為微服務而生的Traefik,所以用Ingress Controller時會發現我們有三種選擇:
a、nginx:這是后來改造的
b、Traefik:這種設計就是為微服務這種動態生成而生的
c、Envoy :去做微服務的大家都比較傾向於Envoy
5、作為調度器,有時候要調度不只一個后端服務,假如有一個調度器pod,后端有一組pod提供電商服務,第二組pod提供了社交服務,第三組pod提供了論壇服務,第四組pod提供了網關服務。那么我們這四組http服務怎么能夠分別調度呢?
a、從nginx的角度來講,接入服務端時我們通過uptream_server即可,但是接入客戶端時我們應該如何標識這四種不同的請求呢,首先我們可以在nginx上做四個虛擬主機,在四個主機名上做四個主機,每一個主機名對應一組后端的pod。那萬一我們沒那么多主機名呢?此時我們可以通過不同的路徑來做url映射,然后每一組路徑就映射到一組后端pod上,但是pod存在生命周期,隨時都可能掛掉替換為一個新pod,新pod的ip就會變了,另外我們pod的應用的規模也可以動態伸縮的,我們簡單改一下副本數其數量也會變,這種一變前面代理的配置也就無效了,我們service通過關聯標簽來解決這個問題,而且service隨時 watch着api server上的api時刻來關注自己關聯的slector的資源是否變動了,只要變動我們api server就會立即通知service然后service立即改變。 所以service通過label selector始終關聯着對應label能適配的后端pod,無論怎么變都能應付而且能及時作出反應,那么此處nginx運行在pod中也就意味着這個配置是在pod內部並且后端pod隨時還會發生變動,Ingress 也會時刻watch着api 中的后端pod資源的改變。那它怎么知道這是哪個pod資源呢?Ingress Controller自己沒有這個能力,它並不知道目前符合自己條件關聯的被代理的pod資源有哪些,它必須借助於service來實現,我們要想定義一個這種調度能力功能其實還是需要建service,這個service通過label selector關聯至后端的pod上來,但這個service不是被當做被代理時的中間節點,它僅僅是幫忙分類的,這個service 關聯了幾個pod那么我們就將這幾個pod配置寫在這個upstream中,調度時是不會經過service的,service在此處僅僅是幫忙分組的,分完組以后我們需要得到的也不是service的IP,而是pod的ip,因此此時可以使用headless service,但是這個service卻沒有用,是不是headless都無所謂,它只要幫忙完成分組知道找哪幾個pod就可以了,pod一變,service對應的資源也就變了,問題是變了后這個結果怎么反應到這個配置文件中來,此時需要依賴於一個專門的資源 Ingress。
6、在k8s上有一種特殊的資源叫Ingress,Ingress 和Ingress Controller是兩回事,我們定義一個Ingress 時就是說了它其實就是定義我們期望這個Ingress Controller是如何給我們建一個前端(可能是一個虛擬主機,也可能是一個url映射)接入層,同時又給我們定義一個后端upstream_server,這個upstream_server中有幾個主機 Ingress是通過這個service 得到的,並且Ingress有一個特點,作為資源來講他可以通過編輯注入到Ingress Controller里面來,直接把它注入並保存為配置文件,而且一旦Ingress發現Service選定的后端的pod資源發生改變了,這個改變一定會及時返回到Ingress中,這個Ingress會及時注入到這個前端調度器pod中,就是注入到upstream配置文件中,而且還能觸發這個pod中的主容器中的進程重載配置文件。所以我們要想使用這個功能我們需要在集群中:
a、要有個service去對后端某一個特定類型的pod資源進行分類,這個service只是起分類作用的。
b、Ingress基於這個分類識別出有幾個pod,並且識別其ip地址是什么,並且將這個ip地址返回的結果生成配置信息注入到upstream_server(以nginx為例),但是nginx又不是特別適用這個場景,每次變動都在重載,如果是Traefik和Envoy 等天生就是為這種場景而生的,只要動了就加載生效,不需要重載。(它可以監控這個配置文件發生變化,只要發生變化就會動態重載)。
7、如果我們想要使用代理,我們應該怎么做?
a、需要先部署一個Ingress Controller,然后部署一個pod進來,這個pod可能本來是空的,沒有什么有效的東西,接下來我們要根據自己的需要 通過虛擬主機的方式或者通過url代理的方式來配置一個前端,然后再根據我們Service收集到的后端pod的IP定義成upstream_server,把這些信息反應在Ingress當中由Ingress動態注入到Ingress Controller中才可以
b、從圖中我們可以看到,當訪問我們服務時首先由外部的負載均衡器將請求調度到我們nodePort的Service上,而nodePort上的Service再將請求調度至我們內部的一個pod 叫IngressController上來,Ingress Controller根據Ingress中的定義(虛擬主機或url),每一個主機名對應后面的一組pod資源(通過service分組),因此此處用到兩組Service,第一個Service是幫集群接入外部流量的(當然也可以不用,可以把這個Ingress Controller pod運行為共享網絡節點網絡名稱空間方式並且將其定義為Dameset方式運行在特定節點上就可以了),那么我們在定義pod資源時只需要在pod的一個配置選項中加入hostnetwork即可。第二個Service只用來做pod歸組不被調度時使用。
c、接下來我們要使用ingress的功能得先去安裝部署Ingress Controller 這個pod,而后再定義Ingress,而后再定義后端pod生成Service,然后再建立關聯關系。
三、Ingress 定義
1、Ingress 也是標准的kubernetes資源對象,因此也擁有相應的對象屬性。
[root@k8smaster ~]# kubectl explain ingress.spec KIND: Ingress VERSION: extensions/v1beta1 RESOURCE: spec <Object> DESCRIPTION: Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status IngressSpec describes the Ingress the user wishes to exist. FIELDS: backend <Object> #定義后端主機,定義后端有哪幾個pod,其屬性有serviceName和sericePort A default backend capable of servicing requests that don't match any rule. At least one of 'backend' or 'rules' must be specified. This field is optional to allow the loadbalancer controller or defaulting logic to specify a global default. rules <[]Object> #定義規則,分為主機和http,http又有paths路徑定義調度到哪兒去。 (即主機調度和路徑調度兩種方式) A list of host rules used to configure the Ingress. If unspecified, or no rule matches, all traffic is sent to the default backend. tls <[]Object> TLS configuration. Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI.
[root@k8smaster ~]# kubectl explain ingress.spec.backend KIND: Ingress VERSION: extensions/v1beta1 RESOURCE: backend <Object> DESCRIPTION: A default backend capable of servicing requests that don't match any rule. At least one of 'backend' or 'rules' must be specified. This field is optional to allow the loadbalancer controller or defaulting logic to specify a global default. IngressBackend describes all endpoints for a given service and port. FIELDS: serviceName <string> -required- #backend正是靠我們service的定義來找到我們后端相關聯的有哪幾個pod資源的,一旦pod資源發生變化這個service就發生變化,service變化Ingress就變化,
Ingress變化就開始注入到Ingress Controller中去。
Specifies the name of the referenced service. servicePort <string> -required- Specifies the port of the referenced service.
2、部署Ingress,k8s集群由master,node和附件組成,一共有四個核心附件:
a、dns
b、Heapster
c、Dashboard
d、Ingress Controller
四、Ingress創建
1、首先下載github上對應的yaml文件
[root@k8smaster ingress-nginx]# for file in namespace.yaml configmap.yaml rbac.yaml tcp-services-configmap.yaml with-rbac.yaml udp-services-configmap.yaml default-backend.yaml; \ > do wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.17.1/deploy/$file; done ...
2、將下載yaml文件創建使用
[root@k8smaster ingress-nginx]# ls configmap.yaml namespace.yaml rbac.yaml tcp-services-configmap.yaml udp-services-configmap.yaml with-rbac.yaml [root@k8smaster ingress-nginx]# kubectl apply -f namespace.yaml namespace/ingress-nginx created [root@k8smaster ingress-nginx]# kubectl apply -f ./ configmap/nginx-configuration created namespace/ingress-nginx configured serviceaccount/nginx-ingress-serviceaccount created clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created role.rbac.authorization.k8s.io/nginx-ingress-role created rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created configmap/tcp-services created configmap/udp-services created deployment.extensions/nginx-ingress-controller created
也可直接使用一次性部署yaml文件
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
[root@k8smaster ingress-nginx]# kubectl get pods -n ingress-nginx -o wide NAME READY STATUS RESTARTS AGE IP NODE default-http-backend-846b65fb5f-ggwwp 1/1 Running 0 29m 10.244.1.77 k8snode1 nginx-ingress-controller-d658896cd-nqt4b 1/1 Running 21 2h 10.244.2.76 k8snode2
3、嘗試創建Ingress,為了讓某個Ingress能顯現真正的效果來我們要做一些前提准備,比如我們要部署幾個后端被代理的應用
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress annotations: #此屬性至關重要,因為在annotations中我們必須指明ingress controller類型是nginx nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: /testpath backend: serviceName: test servicePort: 80
4、直接部署在裸機上時要額外加上一項叫做service-nodeport.yaml,如果不加上這一項會發現ingress controller部署完以后在集群內部可以被訪問,在集群外部是無法被訪問到的,因為ingress controller無法接入外部的流量,如果要接入流量則需要再部署一個nodePort的service,或者也可以將ingress controller部署為直接共享節點網絡名稱空間的方式,但這個時候我們需要手動改造with-rbac.yaml這個文件中的kind 類型由Deployent改為DaemonSet,然后去掉replicas,然后在pod template上的spec中加一項hostnetwork用於共享宿主機的網絡名稱空間,當然需要保證監聽的端口不被沖突。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
5、接下來可以嘗試使用ingress規則來應用
a、首先創建一組應用pod和對應的service
[root@k8smaster ingress]# cat deploy-demo.yaml apiVersion: v1 kind: Service metadata: name: myapp namespace: default spec: selector: app: myapp release: canary ports: - name: http targetPort: 80 port: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v2 ports: - name: http containerPort: 80
b、創建nodePort service
[root@k8smaster ingress-nginx]# cat service-nodeport.yaml apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx spec: type: NodePort ports: - name: http #服務為http port: 80 #service端口為80 targetPort: 80 #容器端口為80 protocol: TCP nodePort: 30080 - name: https port: 443 #service 端口為443 targetPort: 443 #容器端口為443 protocol: TCP nodePort: 30443 selector: app: ingress-nginx --- [root@k8smaster ingress-nginx]# kubectl apply -f ./ configmap/nginx-configuration unchanged deployment.extensions/default-http-backend unchanged service/default-http-backend unchanged namespace/ingress-nginx configured serviceaccount/nginx-ingress-serviceaccount unchanged clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole configured role.rbac.authorization.k8s.io/nginx-ingress-role unchanged rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding unchanged clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding configured service/ingress-nginx created configmap/tcp-services unchanged configmap/udp-services unchanged deployment.extensions/nginx-ingress-controller unchanged
[root@k8smaster ingress]# kubectl get pods -n ingress-nginx -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE LABELS
default-http-backend-846b65fb5f-ggwwp 1/1 Running 1 1d 10.244.1.82 k8snode1 app=default-http-backend,pod-template-hash=4026219619
nginx-ingress-controller-d658896cd-nqt4b 1/1 Running 22 1d 10.244.2.81 k8snode2 app=ingress-nginx,pod-template-hash=821445278
此時訪問我們節點端口顯示 default backend - 404 ,此時表示我們調度器已經正常工作。
c、此時將步驟a中創建的myapp Deploymet開始使用我們b中這個Service發布出去而不在我們里面同時創建的這個service上自己改成nodePort發布出去了
[root@k8smaster ingress]# cat ingress-myapp.yaml apiVersion: extensions/v1beta1 Kind: Ingress metadata: name: ingress-myapp namespaces: default annotations: #進行說明我們接下來要用到的規則是nginx,就是靠annotations來識別類型的,只有進行注解了才能轉化為對應的與controller相匹配的規則 kubernetes.io/ingress.class: "nginx" spec: rules: #定義把誰轉到誰那兒去 - host: myapp.wohaoshuai.com #要確保在外部通過互聯網訪問時能解析此主機名,並且解析結果剛好能到達我們Service nodePort映射的主機上去 http: #定義前后端路徑 paths: #不給默認為/ - path: #前端路徑,空表示默認的/ backend: #匹配后端service serviceName: myapp servicePort: 80 [root@k8smaster ingress]# kubectl apply -f ingress-myapp.yaml ingress.extensions/ingress-myapp created [root@k8smaster ingress]# kubectl get ingress NAME HOSTS ADDRESS PORTS AGE ingress-myapp myapp.wohaoshuai.com 80 10s [root@k8smaster ingress]# kubectl describe ingress ingress-myapp Name: ingress-myapp Namespace: default Address: Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- myapp.wohaoshuai.com myapp:80 (<none>) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"ingress-my app","namespace":"default"},"spec":{"rules":[{"host":"myapp.wohaoshuai.com","http":{"paths":[{"backend":{"serviceName":"myapp","servicePort":80},"path":null}]}}]}} kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 30s nginx-ingress-controller Ingress default/ingress-myapp
d、上述創建完成的ingress一旦應用其會自動注入到ingress controller中去,也就是說其會自動轉換成nginx的配置文件(從下面信息中可看到),訪問myapp.wohaoshuai.com:30080即可
[root@k8smaster ingress]# kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE default-http-backend-846b65fb5f-ggwwp 1/1 Running 0 1h nginx-ingress-controller-d658896cd-nqt4b 1/1 Running 21 4h [root@k8smaster ingress]# kubectl exec -it nginx-ingress-controller-d658896cd-nqt4b /bin/bash -n ingress-nginx www-data@nginx-ingress-controller-d658896cd-nqt4b:/etc/nginx$ ls fastcgi.conf fastcgi_params.default koi-win mime.types.default nginx.conf owasp-modsecurity-crs template win-utf fastcgi.conf.default geoip lua modsecurity nginx.conf.default scgi_params uwsgi_params fastcgi_params koi-utf mime.types modules opentracing.json scgi_params.default uwsgi_params.default www-data@nginx-ingress-controller-d658896cd-nqt4b:/etc/nginx$ cat nginx.conf|grep wohaoshuai ## start server myapp.wohaoshuai.com server_name myapp.wohaoshuai.com ; ## end server myapp.wohaoshuai.com
從上面配置文件中可以看出svc只是起到了識別后端pod信息的作用而不起調度作用
五、創建一個真正可用的ingress 實例
1、我們現在做這么一個東西,本來我們起了兩到三個tomcat pod,每個pod監聽自己的8080和8009端口,因此我們在三個pod之前做一個Service作為一個固定訪問端點代理,但是這個Service待會兒不會用到,它只是用來識別而已,我們Service對應的8080和8009端口對應后端pod的8080和8009端口。我們定義一個deployment來部署這三個tomcat,用來監聽8080和8009端口,然后定義一個Service把8080和8009暴露出去,但是沒有真正向集群外部暴露,因為其是cluster IP類型的,他只是用來被前端等會兒叫ingress controller定義ingress規則向里面映射的時候所識別后端有哪幾個Pod而已。
2、創建Deployment 和 Service,然后創建ingress
[root@k8smaster ingress]# cat tomcat-deploy.yaml apiVersion: v1 kind: Service metadata: name: tomcat namespace: default spec: selector: app: tomcat release: canary ports: - name: http targetPort: 8080 port: 8080 - name: ajp targetPort: 8009 port: 8009 --- apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: tomcat release: canary template: metadata: labels: app: tomcat release: canary spec: containers: - name: myapp image: tomcat:8.5.32-jre8-alpine ports: - name: http containerPort: 8080 - name: ajp containerPort: 8009 [root@k8smaster ingress]# kubectl apply -f tomcat-deploy.yaml service/tomcat created deployment.apps/tomcat-deploy created [root@k8smaster ingress]# cat ingress-tomcat.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-tomcat namespace: default annotations: #進行說明我們接下來要用到的規則是nginx,就是靠annotations來識別類型的,只有進行注解了才能轉化為對應的與controller相匹配的規則 kubernetes.io/ingress.class: "nginx" spec: rules: #定義把誰轉到誰那兒去 - host: tomcat.wohaoshuai.com #要確保在外部通過互聯網訪問時能解析此主機名,並且解析結果剛好能到達我們Service nodePort映射的主機上去 http: #定義前后端路徑 paths: #不給默認為/ - path: #前端路徑,空表示默認的/ backend: #匹配后端service serviceName: tomcat servicePort: 8080 #我們沒有指ingress所以默認ingress是80端口 [root@k8smaster ingress]# kubectl apply -f ingress-tomcat.yaml ingress.extensions/ingress-myapp configured
創建完成后在各節點host文件添加tomcat.lwohaoshuai.com解析訪問 tomcat.wohaoshuai.com:30080即可
3、如果我們想要創建https的虛擬主機就稍微要麻煩一點,第一,這個虛擬主機要工作為https服務的話在nginx上這個虛擬主機得是ssl虛擬主機配置為ssl虛擬主機則需要證書和私鑰,而這個證書和私鑰我們需要將其創建為特定格式才能提供給我們的ingress.那么現在我們做一組證書和私鑰並且把它們作為一個獨特的對象,這個叫secret。
a、創建私鑰和證書
[root@k8smaster ingress]# openssl genrsa -out tls.key 2048 #創建私鑰 Generating RSA private key, 2048 bit long modulus ..+++ ........................................+++ e is 65537 (0x10001) [root@k8smaster ingress]# ls deploy-demo.yaml ingress-myapp.yaml ingress-tomcat.yaml tls.key tomcat-deploy.yaml [root@k8smaster ingress]# openssl req -new -x509 -key tls.key -out tls.crt(自簽證書) -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.wohaoshuai.com(國家為CN,所在的省為北京,地址為北京,組織為DevOps,此外,證書中應該包含的名字應該和此前定義的域名一致,為tomcat.wohaoshuai.com) #創建自簽證書 [root@k8smaster ingress]# ls deploy-demo.yaml ingress-myapp.yaml ingress-tomcat.yaml tls.crt tls.key tomcat-deploy.yaml
b、注意生成的證書是不能直接貼到nginx的pod中去的,我們需要把它先轉成特殊格式,這個特殊格式叫secret,它也是標准的k8s集群對象,它可以直接注入到pod中被pod所引用。因此接下來我們需要把它做成secret
[root@k8smaster ingress]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key secret/tomcat-ingress-secret created [root@k8smaster ingress]# kubectl get secret NAME TYPE DATA AGE default-token-jvtl7 kubernetes.io/service-account-token 3 36d tomcat-ingress-secret kubernetes.io/tls 2 15s [root@k8smaster ingress]# kubectl describe secret tomcat-ingress-secret Name: tomcat-ingress-secret Namespace: default Labels: <none> Annotations: <none> Type: kubernetes.io/tls Data ==== tls.crt: 1306 bytes tls.key: 1679 bytes
c、創建完以后我們就可以拿這個secret在ingress.spec.rules中定義了
[root@k8smaster ingress]# kubectl explain ingress.spec.tls KIND: Ingress VERSION: extensions/v1beta1 RESOURCE: tls <[]Object> DESCRIPTION: TLS configuration. Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI. IngressTLS describes the transport layer security associated with an Ingress. FIELDS: hosts <[]string> #表示把哪個主機做成tls格式的 Hosts are a list of hosts included in the TLS certificate. The values in this list must match the name/s used in the tlsSecret. Defaults to the wildcard host setting for the loadbalancer controller fulfilling this Ingress, if left unspecified. secretName <string> #用哪個secret來獲取證書,私鑰等相關信息 SecretName is the name of the secret used to terminate SSL traffic on 443. Field is left optional to allow SSL routing based on SNI hostname alone. If the SNI host in a listener conflicts with the "Host" header field used by an IngressRule, the SNI host is used for termination and value of the Host header is used for routing.
[root@k8smaster ingress]# kubectl apply -f ingress-tomcat-tls.yaml ingress.extensions/ingress-tomcat-tls created [root@k8smaster ingress]# cat ingress-tomcat-tls.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-tomcat-tls namespace: default annotations: #進行說明我們接下來要用到的規則是nginx,就是靠annotations來識別類型的,只有進行注解了才能轉化為對應的與controller相匹配的規則 kubernetes.io/ingress.class: "nginx" spec: tls: - hosts: - tomcat.wohaoshuai.com secretName: tomcat-ingress-secret rules: #定義把誰轉到誰那兒去 - host: tomcat.wohaoshuai.com #要確保在外部通過互聯網訪問時能解析此主機名,並且解析結果剛好能到達我們Service nodePort映射的主機上去 http: #定義前后端路徑 paths: #不給默認為/ - path: #前端路徑,空表示默認的/ backend: #匹配后端service serviceName: tomcat servicePort: 8080 #我們沒有指ingress所以默認ingress是80端口 [root@k8smaster ingress]# kubectl get ingress NAME HOSTS ADDRESS PORTS AGE ingress-myapp myapp.wohaoshuai.com 80 20h ingress-tomcat tomcat.wohaoshuai.com 80 18h ingress-tomcat-tls tomcat.wohaoshuai.com 80, 443 33s [root@k8smaster ingress]# kubectl describe ingress ingress-tomcat-tls Name: ingress-tomcat-tls Namespace: default Address: Default backend: default-http-backend:80 (<none>) TLS: tomcat-ingress-secret terminates tomcat.wohaoshuai.com Rules: Host Path Backends ---- ---- -------- tomcat.wohaoshuai.com tomcat:8080 (<none>) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx"},"name":"ingress-to mcat-tls","namespace":"default"},"spec":{"rules":[{"host":"tomcat.wohaoshuai.com","http":{"paths":[{"backend":{"serviceName":"tomcat","servicePort":8080},"path":null}]}}],"tls":[{"hosts":["tomcat.wohaoshuai.com"],"secretName":"tomcat-ingress-secret"}]}} kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 1m nginx-ingress-controller Ingress default/ingress-tomcat-tls [root@k8smaster ingress]# kubectl exec -it nginx-ingress-controller-d658896cd-nqt4b /bin/bash -n ingress-nginx www-data@nginx-ingress-controller-d658896cd-nqt4b:/etc/nginx$ cat nginx.conf|grep ssl
通過https://tomcat.wohaoshuai.com:30443訪問即可。可以看到我們ssl主機建立起來了,但是我們后端pod並沒有提供任何ssl功能